1/* 2 * dir.c 3 * 4 * Copyright (C) 1995, 1996 by Volker Lendecke 5 * Modified for big endian by J.F. Chadima and David S. Miller 6 * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache 7 * Modified 1998, 1999 Wolfram Pienkoss for NLS 8 * Modified 1999 Wolfram Pienkoss for directory caching 9 * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info 10 * 11 */ 12 13 14#include <linux/time.h> 15#include <linux/errno.h> 16#include <linux/stat.h> 17#include <linux/kernel.h> 18#include <linux/vmalloc.h> 19#include <linux/mm.h> 20#include <asm/uaccess.h> 21#include <asm/byteorder.h> 22#include <linux/smp_lock.h> 23 24#include <linux/ncp_fs.h> 25 26#include "ncplib_kernel.h" 27 28static void ncp_read_volume_list(struct file *, void *, filldir_t, 29 struct ncp_cache_control *); 30static void ncp_do_readdir(struct file *, void *, filldir_t, 31 struct ncp_cache_control *); 32 33static int ncp_readdir(struct file *, void *, filldir_t); 34 35static int ncp_create(struct inode *, struct dentry *, int, struct nameidata *); 36static struct dentry *ncp_lookup(struct inode *, struct dentry *, struct nameidata *); 37static int ncp_unlink(struct inode *, struct dentry *); 38static int ncp_mkdir(struct inode *, struct dentry *, int); 39static int ncp_rmdir(struct inode *, struct dentry *); 40static int ncp_rename(struct inode *, struct dentry *, 41 struct inode *, struct dentry *); 42static int ncp_mknod(struct inode * dir, struct dentry *dentry, 43 int mode, dev_t rdev); 44#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) 45extern int ncp_symlink(struct inode *, struct dentry *, const char *); 46#else 47#define ncp_symlink NULL 48#endif 49 50const struct file_operations ncp_dir_operations = 51{ 52 .llseek = generic_file_llseek, 53 .read = generic_read_dir, 54 .readdir = ncp_readdir, 55 .unlocked_ioctl = ncp_ioctl, 56#ifdef CONFIG_COMPAT 57 .compat_ioctl = ncp_compat_ioctl, 58#endif 59}; 60 61const struct inode_operations ncp_dir_inode_operations = 62{ 63 .create = ncp_create, 64 .lookup = ncp_lookup, 65 .unlink = ncp_unlink, 66 .symlink = ncp_symlink, 67 .mkdir = ncp_mkdir, 68 .rmdir = ncp_rmdir, 69 .mknod = ncp_mknod, 70 .rename = ncp_rename, 71 .setattr = ncp_notify_change, 72}; 73 74/* 75 * Dentry operations routines 76 */ 77static int ncp_lookup_validate(struct dentry *, struct nameidata *); 78static int ncp_hash_dentry(struct dentry *, struct qstr *); 79static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *); 80static int ncp_delete_dentry(struct dentry *); 81 82static const struct dentry_operations ncp_dentry_operations = 83{ 84 .d_revalidate = ncp_lookup_validate, 85 .d_hash = ncp_hash_dentry, 86 .d_compare = ncp_compare_dentry, 87 .d_delete = ncp_delete_dentry, 88}; 89 90const struct dentry_operations ncp_root_dentry_operations = 91{ 92 .d_hash = ncp_hash_dentry, 93 .d_compare = ncp_compare_dentry, 94 .d_delete = ncp_delete_dentry, 95}; 96 97 98/* 99 * Note: leave the hash unchanged if the directory 100 * is case-sensitive. 101 */ 102static int 103ncp_hash_dentry(struct dentry *dentry, struct qstr *this) 104{ 105 struct nls_table *t; 106 unsigned long hash; 107 int i; 108 109 t = NCP_IO_TABLE(dentry); 110 111 if (!ncp_case_sensitive(dentry->d_inode)) { 112 hash = init_name_hash(); 113 for (i=0; i<this->len ; i++) 114 hash = partial_name_hash(ncp_tolower(t, this->name[i]), 115 hash); 116 this->hash = end_name_hash(hash); 117 } 118 return 0; 119} 120 121static int 122ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) 123{ 124 if (a->len != b->len) 125 return 1; 126 127 if (ncp_case_sensitive(dentry->d_inode)) 128 return strncmp(a->name, b->name, a->len); 129 130 return ncp_strnicmp(NCP_IO_TABLE(dentry), a->name, b->name, a->len); 131} 132 133/* 134 * This is the callback from dput() when d_count is going to 0. 135 * We use this to unhash dentries with bad inodes. 136 * Closing files can be safely postponed until iput() - it's done there anyway. 137 */ 138static int 139ncp_delete_dentry(struct dentry * dentry) 140{ 141 struct inode *inode = dentry->d_inode; 142 143 if (inode) { 144 if (is_bad_inode(inode)) 145 return 1; 146 } else 147 { 148 /* N.B. Unhash negative dentries? */ 149 } 150 return 0; 151} 152 153static inline int 154ncp_single_volume(struct ncp_server *server) 155{ 156 return (server->m.mounted_vol[0] != '\0'); 157} 158 159static inline int ncp_is_server_root(struct inode *inode) 160{ 161 return (!ncp_single_volume(NCP_SERVER(inode)) && 162 inode == inode->i_sb->s_root->d_inode); 163} 164 165 166/* 167 * This is the callback when the dcache has a lookup hit. 168 */ 169 170 171#ifdef CONFIG_NCPFS_STRONG 172/* try to delete a readonly file (NW R bit set) */ 173 174static int 175ncp_force_unlink(struct inode *dir, struct dentry* dentry) 176{ 177 int res=0x9c,res2; 178 struct nw_modify_dos_info info; 179 __le32 old_nwattr; 180 struct inode *inode; 181 182 memset(&info, 0, sizeof(info)); 183 184 /* remove the Read-Only flag on the NW server */ 185 inode = dentry->d_inode; 186 187 old_nwattr = NCP_FINFO(inode)->nwattr; 188 info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT); 189 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info); 190 if (res2) 191 goto leave_me; 192 193 /* now try again the delete operation */ 194 res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry); 195 196 if (res) /* delete failed, set R bit again */ 197 { 198 info.attributes = old_nwattr; 199 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info); 200 if (res2) 201 goto leave_me; 202 } 203leave_me: 204 return(res); 205} 206#endif /* CONFIG_NCPFS_STRONG */ 207 208#ifdef CONFIG_NCPFS_STRONG 209static int 210ncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name, 211 struct inode *new_dir, struct dentry* new_dentry, char *_new_name) 212{ 213 struct nw_modify_dos_info info; 214 int res=0x90,res2; 215 struct inode *old_inode = old_dentry->d_inode; 216 __le32 old_nwattr = NCP_FINFO(old_inode)->nwattr; 217 __le32 new_nwattr = 0; /* shut compiler warning */ 218 int old_nwattr_changed = 0; 219 int new_nwattr_changed = 0; 220 221 memset(&info, 0, sizeof(info)); 222 223 /* remove the Read-Only flag on the NW server */ 224 225 info.attributes = old_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); 226 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info); 227 if (!res2) 228 old_nwattr_changed = 1; 229 if (new_dentry && new_dentry->d_inode) { 230 new_nwattr = NCP_FINFO(new_dentry->d_inode)->nwattr; 231 info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); 232 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info); 233 if (!res2) 234 new_nwattr_changed = 1; 235 } 236 /* now try again the rename operation */ 237 /* but only if something really happened */ 238 if (new_nwattr_changed || old_nwattr_changed) { 239 res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir), 240 old_dir, _old_name, 241 new_dir, _new_name); 242 } 243 if (res) 244 goto leave_me; 245 /* file was successfully renamed, so: 246 do not set attributes on old file - it no longer exists 247 copy attributes from old file to new */ 248 new_nwattr_changed = old_nwattr_changed; 249 new_nwattr = old_nwattr; 250 old_nwattr_changed = 0; 251 252leave_me:; 253 if (old_nwattr_changed) { 254 info.attributes = old_nwattr; 255 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info); 256 /* ignore errors */ 257 } 258 if (new_nwattr_changed) { 259 info.attributes = new_nwattr; 260 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info); 261 /* ignore errors */ 262 } 263 return(res); 264} 265#endif /* CONFIG_NCPFS_STRONG */ 266 267 268static int 269__ncp_lookup_validate(struct dentry *dentry) 270{ 271 struct ncp_server *server; 272 struct dentry *parent; 273 struct inode *dir; 274 struct ncp_entry_info finfo; 275 int res, val = 0, len; 276 __u8 __name[NCP_MAXPATHLEN + 1]; 277 278 parent = dget_parent(dentry); 279 dir = parent->d_inode; 280 281 if (!dentry->d_inode) 282 goto finished; 283 284 server = NCP_SERVER(dir); 285 286 if (!ncp_conn_valid(server)) 287 goto finished; 288 289 /* 290 * Inspired by smbfs: 291 * The default validation is based on dentry age: 292 * We set the max age at mount time. (But each 293 * successful server lookup renews the timestamp.) 294 */ 295 val = NCP_TEST_AGE(server, dentry); 296 if (val) 297 goto finished; 298 299 DDPRINTK("ncp_lookup_validate: %s/%s not valid, age=%ld, server lookup\n", 300 dentry->d_parent->d_name.name, dentry->d_name.name, 301 NCP_GET_AGE(dentry)); 302 303 len = sizeof(__name); 304 if (ncp_is_server_root(dir)) { 305 res = ncp_io2vol(server, __name, &len, dentry->d_name.name, 306 dentry->d_name.len, 1); 307 if (!res) 308 res = ncp_lookup_volume(server, __name, &(finfo.i)); 309 } else { 310 res = ncp_io2vol(server, __name, &len, dentry->d_name.name, 311 dentry->d_name.len, !ncp_preserve_case(dir)); 312 if (!res) 313 res = ncp_obtain_info(server, dir, __name, &(finfo.i)); 314 } 315 finfo.volume = finfo.i.volNumber; 316 DDPRINTK("ncp_lookup_validate: looked for %s/%s, res=%d\n", 317 dentry->d_parent->d_name.name, __name, res); 318 /* 319 * If we didn't find it, or if it has a different dirEntNum to 320 * what we remember, it's not valid any more. 321 */ 322 if (!res) { 323 if (finfo.i.dirEntNum == NCP_FINFO(dentry->d_inode)->dirEntNum) { 324 ncp_new_dentry(dentry); 325 val=1; 326 } else 327 DDPRINTK("ncp_lookup_validate: found, but dirEntNum changed\n"); 328 329 ncp_update_inode2(dentry->d_inode, &finfo); 330 } 331 332finished: 333 DDPRINTK("ncp_lookup_validate: result=%d\n", val); 334 dput(parent); 335 return val; 336} 337 338static int 339ncp_lookup_validate(struct dentry * dentry, struct nameidata *nd) 340{ 341 int res; 342 lock_kernel(); 343 res = __ncp_lookup_validate(dentry); 344 unlock_kernel(); 345 return res; 346} 347 348static struct dentry * 349ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) 350{ 351 struct dentry *dent = dentry; 352 struct list_head *next; 353 354 if (d_validate(dent, parent)) { 355 if (dent->d_name.len <= NCP_MAXPATHLEN && 356 (unsigned long)dent->d_fsdata == fpos) { 357 if (!dent->d_inode) { 358 dput(dent); 359 dent = NULL; 360 } 361 return dent; 362 } 363 dput(dent); 364 } 365 366 /* If a pointer is invalid, we search the dentry. */ 367 spin_lock(&dcache_lock); 368 next = parent->d_subdirs.next; 369 while (next != &parent->d_subdirs) { 370 dent = list_entry(next, struct dentry, d_u.d_child); 371 if ((unsigned long)dent->d_fsdata == fpos) { 372 if (dent->d_inode) 373 dget_locked(dent); 374 else 375 dent = NULL; 376 spin_unlock(&dcache_lock); 377 goto out; 378 } 379 next = next->next; 380 } 381 spin_unlock(&dcache_lock); 382 return NULL; 383 384out: 385 return dent; 386} 387 388static time_t ncp_obtain_mtime(struct dentry *dentry) 389{ 390 struct inode *inode = dentry->d_inode; 391 struct ncp_server *server = NCP_SERVER(inode); 392 struct nw_info_struct i; 393 394 if (!ncp_conn_valid(server) || ncp_is_server_root(inode)) 395 return 0; 396 397 if (ncp_obtain_info(server, inode, NULL, &i)) 398 return 0; 399 400 return ncp_date_dos2unix(i.modifyTime, i.modifyDate); 401} 402 403static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir) 404{ 405 struct dentry *dentry = filp->f_path.dentry; 406 struct inode *inode = dentry->d_inode; 407 struct page *page = NULL; 408 struct ncp_server *server = NCP_SERVER(inode); 409 union ncp_dir_cache *cache = NULL; 410 struct ncp_cache_control ctl; 411 int result, mtime_valid = 0; 412 time_t mtime = 0; 413 414 lock_kernel(); 415 416 ctl.page = NULL; 417 ctl.cache = NULL; 418 419 DDPRINTK("ncp_readdir: reading %s/%s, pos=%d\n", 420 dentry->d_parent->d_name.name, dentry->d_name.name, 421 (int) filp->f_pos); 422 423 result = -EIO; 424 if (!ncp_conn_valid(server)) 425 goto out; 426 427 result = 0; 428 if (filp->f_pos == 0) { 429 if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR)) 430 goto out; 431 filp->f_pos = 1; 432 } 433 if (filp->f_pos == 1) { 434 if (filldir(dirent, "..", 2, 1, parent_ino(dentry), DT_DIR)) 435 goto out; 436 filp->f_pos = 2; 437 } 438 439 page = grab_cache_page(&inode->i_data, 0); 440 if (!page) 441 goto read_really; 442 443 ctl.cache = cache = kmap(page); 444 ctl.head = cache->head; 445 446 if (!PageUptodate(page) || !ctl.head.eof) 447 goto init_cache; 448 449 if (filp->f_pos == 2) { 450 if (jiffies - ctl.head.time >= NCP_MAX_AGE(server)) 451 goto init_cache; 452 453 mtime = ncp_obtain_mtime(dentry); 454 mtime_valid = 1; 455 if ((!mtime) || (mtime != ctl.head.mtime)) 456 goto init_cache; 457 } 458 459 if (filp->f_pos > ctl.head.end) 460 goto finished; 461 462 ctl.fpos = filp->f_pos + (NCP_DIRCACHE_START - 2); 463 ctl.ofs = ctl.fpos / NCP_DIRCACHE_SIZE; 464 ctl.idx = ctl.fpos % NCP_DIRCACHE_SIZE; 465 466 for (;;) { 467 if (ctl.ofs != 0) { 468 ctl.page = find_lock_page(&inode->i_data, ctl.ofs); 469 if (!ctl.page) 470 goto invalid_cache; 471 ctl.cache = kmap(ctl.page); 472 if (!PageUptodate(ctl.page)) 473 goto invalid_cache; 474 } 475 while (ctl.idx < NCP_DIRCACHE_SIZE) { 476 struct dentry *dent; 477 int res; 478 479 dent = ncp_dget_fpos(ctl.cache->dentry[ctl.idx], 480 dentry, filp->f_pos); 481 if (!dent) 482 goto invalid_cache; 483 res = filldir(dirent, dent->d_name.name, 484 dent->d_name.len, filp->f_pos, 485 dent->d_inode->i_ino, DT_UNKNOWN); 486 dput(dent); 487 if (res) 488 goto finished; 489 filp->f_pos += 1; 490 ctl.idx += 1; 491 if (filp->f_pos > ctl.head.end) 492 goto finished; 493 } 494 if (ctl.page) { 495 kunmap(ctl.page); 496 SetPageUptodate(ctl.page); 497 unlock_page(ctl.page); 498 page_cache_release(ctl.page); 499 ctl.page = NULL; 500 } 501 ctl.idx = 0; 502 ctl.ofs += 1; 503 } 504invalid_cache: 505 if (ctl.page) { 506 kunmap(ctl.page); 507 unlock_page(ctl.page); 508 page_cache_release(ctl.page); 509 ctl.page = NULL; 510 } 511 ctl.cache = cache; 512init_cache: 513 ncp_invalidate_dircache_entries(dentry); 514 if (!mtime_valid) { 515 mtime = ncp_obtain_mtime(dentry); 516 mtime_valid = 1; 517 } 518 ctl.head.mtime = mtime; 519 ctl.head.time = jiffies; 520 ctl.head.eof = 0; 521 ctl.fpos = 2; 522 ctl.ofs = 0; 523 ctl.idx = NCP_DIRCACHE_START; 524 ctl.filled = 0; 525 ctl.valid = 1; 526read_really: 527 if (ncp_is_server_root(inode)) { 528 ncp_read_volume_list(filp, dirent, filldir, &ctl); 529 } else { 530 ncp_do_readdir(filp, dirent, filldir, &ctl); 531 } 532 ctl.head.end = ctl.fpos - 1; 533 ctl.head.eof = ctl.valid; 534finished: 535 if (page) { 536 cache->head = ctl.head; 537 kunmap(page); 538 SetPageUptodate(page); 539 unlock_page(page); 540 page_cache_release(page); 541 } 542 if (ctl.page) { 543 kunmap(ctl.page); 544 SetPageUptodate(ctl.page); 545 unlock_page(ctl.page); 546 page_cache_release(ctl.page); 547 } 548out: 549 unlock_kernel(); 550 return result; 551} 552 553static int 554ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, 555 struct ncp_cache_control *ctrl, struct ncp_entry_info *entry) 556{ 557 struct dentry *newdent, *dentry = filp->f_path.dentry; 558 struct inode *newino, *inode = dentry->d_inode; 559 struct ncp_cache_control ctl = *ctrl; 560 struct qstr qname; 561 int valid = 0; 562 int hashed = 0; 563 ino_t ino = 0; 564 __u8 __name[NCP_MAXPATHLEN + 1]; 565 566 qname.len = sizeof(__name); 567 if (ncp_vol2io(NCP_SERVER(inode), __name, &qname.len, 568 entry->i.entryName, entry->i.nameLen, 569 !ncp_preserve_entry_case(inode, entry->i.NSCreator))) 570 return 1; /* I'm not sure */ 571 572 qname.name = __name; 573 qname.hash = full_name_hash(qname.name, qname.len); 574 575 if (dentry->d_op && dentry->d_op->d_hash) 576 if (dentry->d_op->d_hash(dentry, &qname) != 0) 577 goto end_advance; 578 579 newdent = d_lookup(dentry, &qname); 580 581 if (!newdent) { 582 newdent = d_alloc(dentry, &qname); 583 if (!newdent) 584 goto end_advance; 585 } else { 586 hashed = 1; 587 memcpy((char *) newdent->d_name.name, qname.name, 588 newdent->d_name.len); 589 } 590 591 if (!newdent->d_inode) { 592 entry->opened = 0; 593 entry->ino = iunique(inode->i_sb, 2); 594 newino = ncp_iget(inode->i_sb, entry); 595 if (newino) { 596 newdent->d_op = &ncp_dentry_operations; 597 d_instantiate(newdent, newino); 598 if (!hashed) 599 d_rehash(newdent); 600 } 601 } else 602 ncp_update_inode2(newdent->d_inode, entry); 603 604 if (newdent->d_inode) { 605 ino = newdent->d_inode->i_ino; 606 newdent->d_fsdata = (void *) ctl.fpos; 607 ncp_new_dentry(newdent); 608 } 609 610 if (ctl.idx >= NCP_DIRCACHE_SIZE) { 611 if (ctl.page) { 612 kunmap(ctl.page); 613 SetPageUptodate(ctl.page); 614 unlock_page(ctl.page); 615 page_cache_release(ctl.page); 616 } 617 ctl.cache = NULL; 618 ctl.idx -= NCP_DIRCACHE_SIZE; 619 ctl.ofs += 1; 620 ctl.page = grab_cache_page(&inode->i_data, ctl.ofs); 621 if (ctl.page) 622 ctl.cache = kmap(ctl.page); 623 } 624 if (ctl.cache) { 625 ctl.cache->dentry[ctl.idx] = newdent; 626 valid = 1; 627 } 628 dput(newdent); 629end_advance: 630 if (!valid) 631 ctl.valid = 0; 632 if (!ctl.filled && (ctl.fpos == filp->f_pos)) { 633 if (!ino) 634 ino = find_inode_number(dentry, &qname); 635 if (!ino) 636 ino = iunique(inode->i_sb, 2); 637 ctl.filled = filldir(dirent, qname.name, qname.len, 638 filp->f_pos, ino, DT_UNKNOWN); 639 if (!ctl.filled) 640 filp->f_pos += 1; 641 } 642 ctl.fpos += 1; 643 ctl.idx += 1; 644 *ctrl = ctl; 645 return (ctl.valid || !ctl.filled); 646} 647 648static void 649ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir, 650 struct ncp_cache_control *ctl) 651{ 652 struct dentry *dentry = filp->f_path.dentry; 653 struct inode *inode = dentry->d_inode; 654 struct ncp_server *server = NCP_SERVER(inode); 655 struct ncp_volume_info info; 656 struct ncp_entry_info entry; 657 int i; 658 659 DPRINTK("ncp_read_volume_list: pos=%ld\n", 660 (unsigned long) filp->f_pos); 661 662 for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) { 663 664 if (ncp_get_volume_info_with_number(server, i, &info) != 0) 665 return; 666 if (!strlen(info.volume_name)) 667 continue; 668 669 DPRINTK("ncp_read_volume_list: found vol: %s\n", 670 info.volume_name); 671 672 if (ncp_lookup_volume(server, info.volume_name, 673 &entry.i)) { 674 DPRINTK("ncpfs: could not lookup vol %s\n", 675 info.volume_name); 676 continue; 677 } 678 entry.volume = entry.i.volNumber; 679 if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry)) 680 return; 681 } 682} 683 684static void 685ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir, 686 struct ncp_cache_control *ctl) 687{ 688 struct dentry *dentry = filp->f_path.dentry; 689 struct inode *dir = dentry->d_inode; 690 struct ncp_server *server = NCP_SERVER(dir); 691 struct nw_search_sequence seq; 692 struct ncp_entry_info entry; 693 int err; 694 void* buf; 695 int more; 696 size_t bufsize; 697 698 DPRINTK("ncp_do_readdir: %s/%s, fpos=%ld\n", 699 dentry->d_parent->d_name.name, dentry->d_name.name, 700 (unsigned long) filp->f_pos); 701 PPRINTK("ncp_do_readdir: init %s, volnum=%d, dirent=%u\n", 702 dentry->d_name.name, NCP_FINFO(dir)->volNumber, 703 NCP_FINFO(dir)->dirEntNum); 704 705 err = ncp_initialize_search(server, dir, &seq); 706 if (err) { 707 DPRINTK("ncp_do_readdir: init failed, err=%d\n", err); 708 return; 709 } 710 /* We MUST NOT use server->buffer_size handshaked with server if we are 711 using UDP, as for UDP server uses max. buffer size determined by 712 MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes). 713 So we use 128KB, just to be sure, as there is no way how to know 714 this value in advance. */ 715 bufsize = 131072; 716 buf = vmalloc(bufsize); 717 if (!buf) 718 return; 719 do { 720 int cnt; 721 char* rpl; 722 size_t rpls; 723 724 err = ncp_search_for_fileset(server, &seq, &more, &cnt, buf, bufsize, &rpl, &rpls); 725 if (err) /* Error */ 726 break; 727 if (!cnt) /* prevent endless loop */ 728 break; 729 while (cnt--) { 730 size_t onerpl; 731 732 if (rpls < offsetof(struct nw_info_struct, entryName)) 733 break; /* short packet */ 734 ncp_extract_file_info(rpl, &entry.i); 735 onerpl = offsetof(struct nw_info_struct, entryName) + entry.i.nameLen; 736 if (rpls < onerpl) 737 break; /* short packet */ 738 (void)ncp_obtain_nfs_info(server, &entry.i); 739 rpl += onerpl; 740 rpls -= onerpl; 741 entry.volume = entry.i.volNumber; 742 if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry)) 743 break; 744 } 745 } while (more); 746 vfree(buf); 747 return; 748} 749 750int ncp_conn_logged_in(struct super_block *sb) 751{ 752 struct ncp_server* server = NCP_SBP(sb); 753 int result; 754 755 if (ncp_single_volume(server)) { 756 int len; 757 struct dentry* dent; 758 __u32 volNumber; 759 __le32 dirEntNum; 760 __le32 DosDirNum; 761 __u8 __name[NCP_MAXPATHLEN + 1]; 762 763 len = sizeof(__name); 764 result = ncp_io2vol(server, __name, &len, server->m.mounted_vol, 765 strlen(server->m.mounted_vol), 1); 766 if (result) 767 goto out; 768 result = -ENOENT; 769 if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) { 770 PPRINTK("ncp_conn_logged_in: %s not found\n", 771 server->m.mounted_vol); 772 goto out; 773 } 774 dent = sb->s_root; 775 if (dent) { 776 struct inode* ino = dent->d_inode; 777 if (ino) { 778 NCP_FINFO(ino)->volNumber = volNumber; 779 NCP_FINFO(ino)->dirEntNum = dirEntNum; 780 NCP_FINFO(ino)->DosDirNum = DosDirNum; 781 } else { 782 DPRINTK("ncpfs: sb->s_root->d_inode == NULL!\n"); 783 } 784 } else { 785 DPRINTK("ncpfs: sb->s_root == NULL!\n"); 786 } 787 } 788 result = 0; 789 790out: 791 return result; 792} 793 794static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) 795{ 796 struct ncp_server *server = NCP_SERVER(dir); 797 struct inode *inode = NULL; 798 struct ncp_entry_info finfo; 799 int error, res, len; 800 __u8 __name[NCP_MAXPATHLEN + 1]; 801 802 lock_kernel(); 803 error = -EIO; 804 if (!ncp_conn_valid(server)) 805 goto finished; 806 807 PPRINTK("ncp_lookup: server lookup for %s/%s\n", 808 dentry->d_parent->d_name.name, dentry->d_name.name); 809 810 len = sizeof(__name); 811 if (ncp_is_server_root(dir)) { 812 res = ncp_io2vol(server, __name, &len, dentry->d_name.name, 813 dentry->d_name.len, 1); 814 if (!res) 815 res = ncp_lookup_volume(server, __name, &(finfo.i)); 816 } else { 817 res = ncp_io2vol(server, __name, &len, dentry->d_name.name, 818 dentry->d_name.len, !ncp_preserve_case(dir)); 819 if (!res) 820 res = ncp_obtain_info(server, dir, __name, &(finfo.i)); 821 } 822 PPRINTK("ncp_lookup: looked for %s/%s, res=%d\n", 823 dentry->d_parent->d_name.name, __name, res); 824 /* 825 * If we didn't find an entry, make a negative dentry. 826 */ 827 if (res) 828 goto add_entry; 829 830 /* 831 * Create an inode for the entry. 832 */ 833 finfo.opened = 0; 834 finfo.ino = iunique(dir->i_sb, 2); 835 finfo.volume = finfo.i.volNumber; 836 error = -EACCES; 837 inode = ncp_iget(dir->i_sb, &finfo); 838 839 if (inode) { 840 ncp_new_dentry(dentry); 841add_entry: 842 dentry->d_op = &ncp_dentry_operations; 843 d_add(dentry, inode); 844 error = 0; 845 } 846 847finished: 848 PPRINTK("ncp_lookup: result=%d\n", error); 849 unlock_kernel(); 850 return ERR_PTR(error); 851} 852 853/* 854 * This code is common to create, mkdir, and mknod. 855 */ 856static int ncp_instantiate(struct inode *dir, struct dentry *dentry, 857 struct ncp_entry_info *finfo) 858{ 859 struct inode *inode; 860 int error = -EINVAL; 861 862 finfo->ino = iunique(dir->i_sb, 2); 863 inode = ncp_iget(dir->i_sb, finfo); 864 if (!inode) 865 goto out_close; 866 d_instantiate(dentry,inode); 867 error = 0; 868out: 869 return error; 870 871out_close: 872 PPRINTK("ncp_instantiate: %s/%s failed, closing file\n", 873 dentry->d_parent->d_name.name, dentry->d_name.name); 874 ncp_close_file(NCP_SERVER(dir), finfo->file_handle); 875 goto out; 876} 877 878int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode, 879 dev_t rdev, __le32 attributes) 880{ 881 struct ncp_server *server = NCP_SERVER(dir); 882 struct ncp_entry_info finfo; 883 int error, result, len; 884 int opmode; 885 __u8 __name[NCP_MAXPATHLEN + 1]; 886 887 PPRINTK("ncp_create_new: creating %s/%s, mode=%x\n", 888 dentry->d_parent->d_name.name, dentry->d_name.name, mode); 889 890 error = -EIO; 891 lock_kernel(); 892 if (!ncp_conn_valid(server)) 893 goto out; 894 895 ncp_age_dentry(server, dentry); 896 len = sizeof(__name); 897 error = ncp_io2vol(server, __name, &len, dentry->d_name.name, 898 dentry->d_name.len, !ncp_preserve_case(dir)); 899 if (error) 900 goto out; 901 902 error = -EACCES; 903 904 if (S_ISREG(mode) && 905 (server->m.flags & NCP_MOUNT_EXTRAS) && 906 (mode & S_IXUGO)) 907 attributes |= aSYSTEM | aSHARED; 908 909 result = ncp_open_create_file_or_subdir(server, dir, __name, 910 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE, 911 attributes, AR_READ | AR_WRITE, &finfo); 912 opmode = O_RDWR; 913 if (result) { 914 result = ncp_open_create_file_or_subdir(server, dir, __name, 915 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE, 916 attributes, AR_WRITE, &finfo); 917 if (result) { 918 if (result == 0x87) 919 error = -ENAMETOOLONG; 920 DPRINTK("ncp_create: %s/%s failed\n", 921 dentry->d_parent->d_name.name, dentry->d_name.name); 922 goto out; 923 } 924 opmode = O_WRONLY; 925 } 926 finfo.access = opmode; 927 if (ncp_is_nfs_extras(server, finfo.volume)) { 928 finfo.i.nfs.mode = mode; 929 finfo.i.nfs.rdev = new_encode_dev(rdev); 930 if (ncp_modify_nfs_info(server, finfo.volume, 931 finfo.i.dirEntNum, 932 mode, new_encode_dev(rdev)) != 0) 933 goto out; 934 } 935 936 error = ncp_instantiate(dir, dentry, &finfo); 937out: 938 unlock_kernel(); 939 return error; 940} 941 942static int ncp_create(struct inode *dir, struct dentry *dentry, int mode, 943 struct nameidata *nd) 944{ 945 return ncp_create_new(dir, dentry, mode, 0, 0); 946} 947 948static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode) 949{ 950 struct ncp_entry_info finfo; 951 struct ncp_server *server = NCP_SERVER(dir); 952 int error, len; 953 __u8 __name[NCP_MAXPATHLEN + 1]; 954 955 DPRINTK("ncp_mkdir: making %s/%s\n", 956 dentry->d_parent->d_name.name, dentry->d_name.name); 957 958 error = -EIO; 959 lock_kernel(); 960 if (!ncp_conn_valid(server)) 961 goto out; 962 963 ncp_age_dentry(server, dentry); 964 len = sizeof(__name); 965 error = ncp_io2vol(server, __name, &len, dentry->d_name.name, 966 dentry->d_name.len, !ncp_preserve_case(dir)); 967 if (error) 968 goto out; 969 970 error = -EACCES; 971 if (ncp_open_create_file_or_subdir(server, dir, __name, 972 OC_MODE_CREATE, aDIR, 973 cpu_to_le16(0xffff), 974 &finfo) == 0) 975 { 976 if (ncp_is_nfs_extras(server, finfo.volume)) { 977 mode |= S_IFDIR; 978 finfo.i.nfs.mode = mode; 979 if (ncp_modify_nfs_info(server, 980 finfo.volume, 981 finfo.i.dirEntNum, 982 mode, 0) != 0) 983 goto out; 984 } 985 error = ncp_instantiate(dir, dentry, &finfo); 986 } 987out: 988 unlock_kernel(); 989 return error; 990} 991 992static int ncp_rmdir(struct inode *dir, struct dentry *dentry) 993{ 994 struct ncp_server *server = NCP_SERVER(dir); 995 int error, result, len; 996 __u8 __name[NCP_MAXPATHLEN + 1]; 997 998 DPRINTK("ncp_rmdir: removing %s/%s\n", 999 dentry->d_parent->d_name.name, dentry->d_name.name); 1000 1001 error = -EIO; 1002 lock_kernel(); 1003 if (!ncp_conn_valid(server)) 1004 goto out; 1005 1006 error = -EBUSY; 1007 if (!d_unhashed(dentry)) 1008 goto out; 1009 1010 len = sizeof(__name); 1011 error = ncp_io2vol(server, __name, &len, dentry->d_name.name, 1012 dentry->d_name.len, !ncp_preserve_case(dir)); 1013 if (error) 1014 goto out; 1015 1016 result = ncp_del_file_or_subdir(server, dir, __name); 1017 switch (result) { 1018 case 0x00: 1019 error = 0; 1020 break; 1021 case 0x85: /* unauthorized to delete file */ 1022 case 0x8A: /* unauthorized to delete file */ 1023 error = -EACCES; 1024 break; 1025 case 0x8F: 1026 case 0x90: /* read only */ 1027 error = -EPERM; 1028 break; 1029 case 0x9F: /* in use by another client */ 1030 error = -EBUSY; 1031 break; 1032 case 0xA0: /* directory not empty */ 1033 error = -ENOTEMPTY; 1034 break; 1035 case 0xFF: /* someone deleted file */ 1036 error = -ENOENT; 1037 break; 1038 default: 1039 error = -EACCES; 1040 break; 1041 } 1042out: 1043 unlock_kernel(); 1044 return error; 1045} 1046 1047static int ncp_unlink(struct inode *dir, struct dentry *dentry) 1048{ 1049 struct inode *inode = dentry->d_inode; 1050 struct ncp_server *server; 1051 int error; 1052 1053 lock_kernel(); 1054 server = NCP_SERVER(dir); 1055 DPRINTK("ncp_unlink: unlinking %s/%s\n", 1056 dentry->d_parent->d_name.name, dentry->d_name.name); 1057 1058 error = -EIO; 1059 if (!ncp_conn_valid(server)) 1060 goto out; 1061 1062 /* 1063 * Check whether to close the file ... 1064 */ 1065 if (inode) { 1066 PPRINTK("ncp_unlink: closing file\n"); 1067 ncp_make_closed(inode); 1068 } 1069 1070 error = ncp_del_file_or_subdir2(server, dentry); 1071#ifdef CONFIG_NCPFS_STRONG 1072 /* 9C is Invalid path.. It should be 8F, 90 - read only, but 1073 it is not :-( */ 1074 if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */ 1075 error = ncp_force_unlink(dir, dentry); 1076 } 1077#endif 1078 switch (error) { 1079 case 0x00: 1080 DPRINTK("ncp: removed %s/%s\n", 1081 dentry->d_parent->d_name.name, dentry->d_name.name); 1082 break; 1083 case 0x85: 1084 case 0x8A: 1085 error = -EACCES; 1086 break; 1087 case 0x8D: /* some files in use */ 1088 case 0x8E: /* all files in use */ 1089 error = -EBUSY; 1090 break; 1091 case 0x8F: /* some read only */ 1092 case 0x90: /* all read only */ 1093 case 0x9C: /* !!! returned when in-use or read-only by NW4 */ 1094 error = -EPERM; 1095 break; 1096 case 0xFF: 1097 error = -ENOENT; 1098 break; 1099 default: 1100 error = -EACCES; 1101 break; 1102 } 1103 1104out: 1105 unlock_kernel(); 1106 return error; 1107} 1108 1109static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry, 1110 struct inode *new_dir, struct dentry *new_dentry) 1111{ 1112 struct ncp_server *server = NCP_SERVER(old_dir); 1113 int error; 1114 int old_len, new_len; 1115 __u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1]; 1116 1117 DPRINTK("ncp_rename: %s/%s to %s/%s\n", 1118 old_dentry->d_parent->d_name.name, old_dentry->d_name.name, 1119 new_dentry->d_parent->d_name.name, new_dentry->d_name.name); 1120 1121 error = -EIO; 1122 lock_kernel(); 1123 if (!ncp_conn_valid(server)) 1124 goto out; 1125 1126 ncp_age_dentry(server, old_dentry); 1127 ncp_age_dentry(server, new_dentry); 1128 1129 old_len = sizeof(__old_name); 1130 error = ncp_io2vol(server, __old_name, &old_len, 1131 old_dentry->d_name.name, old_dentry->d_name.len, 1132 !ncp_preserve_case(old_dir)); 1133 if (error) 1134 goto out; 1135 1136 new_len = sizeof(__new_name); 1137 error = ncp_io2vol(server, __new_name, &new_len, 1138 new_dentry->d_name.name, new_dentry->d_name.len, 1139 !ncp_preserve_case(new_dir)); 1140 if (error) 1141 goto out; 1142 1143 error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name, 1144 new_dir, __new_name); 1145#ifdef CONFIG_NCPFS_STRONG 1146 if ((error == 0x90 || error == 0x8B || error == -EACCES) && 1147 server->m.flags & NCP_MOUNT_STRONG) { /* RO */ 1148 error = ncp_force_rename(old_dir, old_dentry, __old_name, 1149 new_dir, new_dentry, __new_name); 1150 } 1151#endif 1152 switch (error) { 1153 case 0x00: 1154 DPRINTK("ncp renamed %s -> %s.\n", 1155 old_dentry->d_name.name,new_dentry->d_name.name); 1156 break; 1157 case 0x9E: 1158 error = -ENAMETOOLONG; 1159 break; 1160 case 0xFF: 1161 error = -ENOENT; 1162 break; 1163 default: 1164 error = -EACCES; 1165 break; 1166 } 1167out: 1168 unlock_kernel(); 1169 return error; 1170} 1171 1172static int ncp_mknod(struct inode * dir, struct dentry *dentry, 1173 int mode, dev_t rdev) 1174{ 1175 if (!new_valid_dev(rdev)) 1176 return -EINVAL; 1177 if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) { 1178 DPRINTK(KERN_DEBUG "ncp_mknod: mode = 0%o\n", mode); 1179 return ncp_create_new(dir, dentry, mode, rdev, 0); 1180 } 1181 return -EPERM; /* Strange, but true */ 1182} 1183 1184/* The following routines are taken directly from msdos-fs */ 1185 1186/* Linear day numbers of the respective 1sts in non-leap years. */ 1187 1188static int day_n[] = 1189{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0}; 1190/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ 1191 1192 1193extern struct timezone sys_tz; 1194 1195static int utc2local(int time) 1196{ 1197 return time - sys_tz.tz_minuteswest * 60; 1198} 1199 1200static int local2utc(int time) 1201{ 1202 return time + sys_tz.tz_minuteswest * 60; 1203} 1204 1205/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ 1206int 1207ncp_date_dos2unix(__le16 t, __le16 d) 1208{ 1209 unsigned short time = le16_to_cpu(t), date = le16_to_cpu(d); 1210 int month, year, secs; 1211 1212 /* first subtract and mask after that... Otherwise, if 1213 date == 0, bad things happen */ 1214 month = ((date >> 5) - 1) & 15; 1215 year = date >> 9; 1216 secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 + 1217 86400 * ((date & 31) - 1 + day_n[month] + (year / 4) + 1218 year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653); 1219 /* days since 1.1.70 plus 80's leap day */ 1220 return local2utc(secs); 1221} 1222 1223 1224/* Convert linear UNIX date to a MS-DOS time/date pair. */ 1225void 1226ncp_date_unix2dos(int unix_date, __le16 *time, __le16 *date) 1227{ 1228 int day, year, nl_day, month; 1229 1230 unix_date = utc2local(unix_date); 1231 *time = cpu_to_le16( 1232 (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) + 1233 (((unix_date / 3600) % 24) << 11)); 1234 day = unix_date / 86400 - 3652; 1235 year = day / 365; 1236 if ((year + 3) / 4 + 365 * year > day) 1237 year--; 1238 day -= (year + 3) / 4 + 365 * year; 1239 if (day == 59 && !(year & 3)) { 1240 nl_day = day; 1241 month = 2; 1242 } else { 1243 nl_day = (year & 3) || day <= 59 ? day : day - 1; 1244 for (month = 1; month < 12; month++) 1245 if (day_n[month] > nl_day) 1246 break; 1247 } 1248 *date = cpu_to_le16(nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9)); 1249} 1250