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