Import 2.3.9pre7
[davej-history.git] / fs / ncpfs / dir.c
blob1f92a89fba2eab14de07daaf9ce4481bc811ea54
1 /*
2 * dir.c
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 Wolfram Pienkoss for NLS
9 */
11 #include <linux/config.h>
13 #include <linux/sched.h>
14 #include <linux/errno.h>
15 #include <linux/stat.h>
16 #include <linux/kernel.h>
17 #include <linux/malloc.h>
18 #include <linux/vmalloc.h>
19 #include <linux/mm.h>
20 #include <asm/uaccess.h>
21 #include <asm/byteorder.h>
22 #include <linux/errno.h>
23 #include <linux/locks.h>
25 #include <linux/ncp_fs.h>
27 #include "ncplib_kernel.h"
29 struct ncp_dirent {
30 struct nw_info_struct i;
31 struct nw_search_sequence s; /* given back for i */
32 unsigned long f_pos;
35 static kdev_t c_dev = 0;
36 static unsigned long c_ino = 0;
37 static int c_size;
38 static int c_seen_eof;
39 static int c_last_returned_index;
40 static struct ncp_dirent *c_entry = NULL;
41 static DECLARE_MUTEX(c_sem);
43 static int ncp_read_volume_list(struct ncp_server *, int, int,
44 struct ncp_dirent *);
45 static int ncp_do_readdir(struct ncp_server *, struct dentry *, int, int,
46 struct ncp_dirent *);
48 static ssize_t ncp_dir_read(struct file *, char *, size_t, loff_t *);
49 static int ncp_readdir(struct file *, void *, filldir_t);
51 static int ncp_create(struct inode *, struct dentry *, int);
52 static struct dentry *ncp_lookup(struct inode *, struct dentry *);
53 static int ncp_unlink(struct inode *, struct dentry *);
54 static int ncp_mkdir(struct inode *, struct dentry *, int);
55 static int ncp_rmdir(struct inode *, struct dentry *);
56 static int ncp_rename(struct inode *, struct dentry *,
57 struct inode *, struct dentry *);
58 #ifdef CONFIG_NCPFS_EXTRAS
59 extern int ncp_symlink(struct inode *, struct dentry *, const char *);
60 #endif
62 static struct file_operations ncp_dir_operations =
64 NULL, /* lseek - default */
65 ncp_dir_read, /* read - bad */
66 NULL, /* write - bad */
67 ncp_readdir, /* readdir */
68 NULL, /* poll - default */
69 ncp_ioctl, /* ioctl */
70 NULL, /* mmap */
71 NULL, /* no special open code */
72 NULL, /* flush */
73 NULL, /* no special release code */
74 NULL /* fsync */
77 struct inode_operations ncp_dir_inode_operations =
79 &ncp_dir_operations, /* default directory file ops */
80 ncp_create, /* create */
81 ncp_lookup, /* lookup */
82 NULL, /* link */
83 ncp_unlink, /* unlink */
84 #ifdef CONFIG_NCPFS_EXTRAS
85 ncp_symlink, /* symlink */
86 #else
87 NULL, /* symlink */
88 #endif
89 ncp_mkdir, /* mkdir */
90 ncp_rmdir, /* rmdir */
91 NULL, /* mknod */
92 ncp_rename, /* rename */
93 NULL, /* readlink */
94 NULL, /* follow link */
95 NULL, /* get_block */
96 NULL, /* readpage */
97 NULL, /* writepage */
98 NULL, /* flushpage */
99 NULL, /* truncate */
100 NULL, /* permission */
101 NULL, /* smap */
102 NULL, /* revalidate */
105 static ssize_t
106 ncp_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
108 return -EISDIR;
112 * Dentry operations routines
114 static int ncp_lookup_validate(struct dentry *, int);
115 static int ncp_hash_dentry(struct dentry *, struct qstr *);
116 static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *);
117 static void ncp_delete_dentry(struct dentry *);
119 struct dentry_operations ncp_dentry_operations =
121 ncp_lookup_validate, /* d_revalidate(struct dentry *, int) */
122 ncp_hash_dentry, /* d_hash */
123 ncp_compare_dentry, /* d_compare */
124 ncp_delete_dentry /* d_delete(struct dentry *) */
129 * XXX: It would be better to use the tolower from linux/ctype.h,
130 * but _ctype is needed and it is not exported.
132 #define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)-('A'-'a') : (c))
135 * Note: leave the hash unchanged if the directory
136 * is case-sensitive.
138 static int
139 ncp_hash_dentry(struct dentry *dentry, struct qstr *this)
141 unsigned long hash;
142 int i;
144 if (!ncp_case_sensitive(dentry->d_inode)) {
145 hash = init_name_hash();
146 for (i=0; i<this->len ; i++)
147 hash = partial_name_hash(tolower(this->name[i]),hash);
148 this->hash = end_name_hash(hash);
150 return 0;
153 static int
154 ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
156 int i;
158 if (a->len != b->len) return 1;
160 if (ncp_case_sensitive(dentry->d_inode))
161 return strncmp(a->name, b->name, a->len);
163 for (i=0; i<a->len; i++)
164 if (tolower(a->name[i]) != tolower(b->name[i]))
165 return 1;
167 return 0;
171 * This is the callback from dput() when d_count is going to 0.
172 * We use this to unhash dentries with bad inodes and close files.
174 static void
175 ncp_delete_dentry(struct dentry * dentry)
177 struct inode *inode = dentry->d_inode;
179 if (inode)
181 if (is_bad_inode(inode))
183 d_drop(dentry);
186 * Lock the superblock, then recheck the dentry count.
187 * (Somebody might have used it again ...)
189 if (dentry->d_count == 1 && NCP_FINFO(inode)->opened) {
190 #ifdef NCPFS_PARANOIA
191 printk(KERN_DEBUG "ncp_delete_dentry: closing file %s/%s\n",
192 dentry->d_parent->d_name.name, dentry->d_name.name);
193 #endif
194 ncp_make_closed(inode);
196 } else
198 /* N.B. Unhash negative dentries? */
203 * Generate a unique inode number.
205 ino_t ncp_invent_inos(unsigned long n)
207 static ino_t ino = 2;
209 if (ino + 2*n < ino)
211 /* wrap around */
212 ino = 2;
214 ino += n;
215 return ino;
218 static inline int
219 ncp_single_volume(struct ncp_server *server)
221 return (server->m.mounted_vol[0] != '\0');
224 static inline int ncp_is_server_root(struct inode *inode)
226 return (!ncp_single_volume(NCP_SERVER(inode)) &&
227 inode == inode->i_sb->s_root->d_inode);
230 static inline void ncp_lock_dircache(void)
232 down(&c_sem);
235 static inline void ncp_unlock_dircache(void)
237 up(&c_sem);
242 * This is the callback when the dcache has a lookup hit.
246 #ifdef CONFIG_NCPFS_STRONG
247 /* try to delete a readonly file (NW R bit set) */
249 static int
250 ncp_force_unlink(struct inode *dir, struct dentry* dentry)
252 int res=0x9c,res2;
253 struct nw_modify_dos_info info;
254 __u32 old_nwattr;
255 struct inode *inode;
257 memset(&info, 0, sizeof(info));
259 /* remove the Read-Only flag on the NW server */
260 inode = dentry->d_inode;
262 old_nwattr = NCP_FINFO(inode)->nwattr;
263 info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT);
264 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
265 if (res2)
266 goto leave_me;
268 /* now try again the delete operation */
269 res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
271 if (res) /* delete failed, set R bit again */
273 info.attributes = old_nwattr;
274 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
275 if (res2)
276 goto leave_me;
278 leave_me:
279 return(res);
281 #endif /* CONFIG_NCPFS_STRONG */
283 #ifdef CONFIG_NCPFS_STRONG
284 static int
285 ncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name,
286 struct inode *new_dir, struct dentry* new_dentry, char *_new_name)
288 struct nw_modify_dos_info info;
289 int res=0x90,res2;
290 struct inode *old_inode = old_dentry->d_inode;
291 __u32 old_nwattr = NCP_FINFO(old_inode)->nwattr;
292 __u32 new_nwattr = 0; /* shut compiler warning */
293 int old_nwattr_changed = 0;
294 int new_nwattr_changed = 0;
296 memset(&info, 0, sizeof(info));
298 /* remove the Read-Only flag on the NW server */
300 info.attributes = old_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
301 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
302 if (!res2)
303 old_nwattr_changed = 1;
304 if (new_dentry && new_dentry->d_inode) {
305 new_nwattr = NCP_FINFO(new_dentry->d_inode)->nwattr;
306 info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
307 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
308 if (!res2)
309 new_nwattr_changed = 1;
311 /* now try again the rename operation */
312 /* but only if something really happened */
313 if (new_nwattr_changed || old_nwattr_changed) {
314 res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
315 old_dir, _old_name,
316 new_dir, _new_name);
318 if (res)
319 goto leave_me;
320 /* file was successfully renamed, so:
321 do not set attributes on old file - it no longer exists
322 copy attributes from old file to new */
323 new_nwattr_changed = old_nwattr_changed;
324 new_nwattr = old_nwattr;
325 old_nwattr_changed = 0;
327 leave_me:;
328 if (old_nwattr_changed) {
329 info.attributes = old_nwattr;
330 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
331 /* ignore errors */
333 if (new_nwattr_changed) {
334 info.attributes = new_nwattr;
335 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
336 /* ignore errors */
338 return(res);
340 #endif /* CONFIG_NCPFS_STRONG */
343 static int
344 ncp_lookup_validate(struct dentry * dentry, int flags)
346 struct ncp_server *server;
347 struct inode *dir = dentry->d_parent->d_inode;
348 int down_case = 0;
349 int val = 0,res;
350 int len = dentry->d_name.len;
351 struct ncpfs_inode_info finfo;
352 __u8 __name[dentry->d_name.len + 1];
354 server = NCP_SERVER(dir);
356 if (!ncp_conn_valid(server))
357 goto finished;
359 strncpy(__name, dentry->d_name.name, len);
360 __name[len] = '\0';
361 #ifdef NCPFS_PARANOIA
362 printk(KERN_DEBUG "ncp_lookup_validate: %s, len %d\n", __name, len);
363 #endif
365 /* If the file is in the dir cache, we do not have to ask the
366 server. */
368 #ifdef NCPFS_PARANOIA
369 printk(KERN_DEBUG "ncp_lookup_validate: server lookup for %s/%s\n",
370 dentry->d_parent->d_name.name, __name);
371 #endif
372 if (ncp_is_server_root(dir))
374 io2vol(server, __name, 1);
375 down_case = 1;
376 res = ncp_lookup_volume(server, __name,
377 &(finfo.nw_info.i));
378 } else
380 down_case = !ncp_preserve_case(dir);
381 io2vol(server, __name, down_case);
382 res = ncp_obtain_info(server, dir, __name,
383 &(finfo.nw_info.i));
385 #ifdef NCPFS_PARANOIA
386 printk(KERN_DEBUG "ncp_lookup_validate: looked for %s/%s, res=%d\n",
387 dentry->d_parent->d_name.name, __name, res);
388 #endif
390 * If we didn't find it, or if it has a different dirEntNum to
391 * what we remember, it's not valid any more.
393 if (!res) {
394 if (finfo.nw_info.i.dirEntNum == NCP_FINFO(dentry->d_inode)->dirEntNum)
395 val=1;
396 #ifdef NCPFS_PARANOIA
397 else
398 printk(KERN_DEBUG "ncp_lookup_validate: found, but dirEntNum changed\n");
399 #endif
400 vol2io(server, finfo.nw_info.i.entryName,
401 !ncp_preserve_entry_case(dir,
402 finfo.nw_info.i.NSCreator));
403 ncp_update_inode2(dentry->d_inode, &finfo.nw_info);
405 if (!val) ncp_invalid_dir_cache(dir);
407 finished:
408 #ifdef NCPFS_PARANOIA
409 printk(KERN_DEBUG "ncp_lookup_validate: result=%d\n", val);
410 #endif
412 return val;
416 static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
418 struct dentry *dentry = filp->f_dentry;
419 struct inode *inode = dentry->d_inode;
420 struct ncp_server *server = NCP_SERVER(inode);
421 struct ncp_dirent *entry = NULL;
422 int result, i, index = 0;
424 DDPRINTK(KERN_DEBUG "ncp_readdir: reading %s/%s, pos=%d\n",
425 dentry->d_parent->d_name.name, dentry->d_name.name,
426 (int) filp->f_pos);
427 DDPRINTK(KERN_DEBUG "ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
428 inode->i_ino, c_ino);
430 result = -EIO;
431 if (!ncp_conn_valid(server))
432 goto out;
434 ncp_lock_dircache();
435 result = -ENOMEM;
436 if (c_entry == NULL) {
437 i = sizeof(struct ncp_dirent) * NCP_READDIR_CACHE_SIZE;
438 c_entry = (struct ncp_dirent *) vmalloc(i);
439 if (c_entry == NULL) {
440 printk(KERN_WARNING "ncp_readdir: no MEMORY for cache\n");
441 goto finished;
445 result = 0;
446 if (filp->f_pos == 0) {
447 ncp_invalid_dir_cache(inode);
448 if (filldir(dirent, ".", 1, 0, inode->i_ino) < 0) {
449 goto finished;
451 filp->f_pos = 1;
453 if (filp->f_pos == 1) {
454 if (filldir(dirent, "..", 2, 1,
455 dentry->d_parent->d_inode->i_ino) < 0) {
456 goto finished;
458 filp->f_pos = 2;
461 if ((inode->i_dev == c_dev) && (inode->i_ino == c_ino)) {
462 for (i = 0; i < c_size; i++) {
463 if (filp->f_pos == c_entry[i].f_pos) {
464 entry = &c_entry[i];
465 c_last_returned_index = i;
466 index = i;
467 break;
470 if ((entry == NULL) && c_seen_eof) {
471 goto finished;
474 if (entry == NULL) {
475 int entries;
476 DDPRINTK(KERN_DEBUG "ncp_readdir: Not found in cache.\n");
478 if (ncp_is_server_root(inode)) {
479 entries = ncp_read_volume_list(server, filp->f_pos,
480 NCP_READDIR_CACHE_SIZE, c_entry);
481 DPRINTK(KERN_DEBUG "ncp_read_volume_list returned %d\n", entries);
483 } else {
484 entries = ncp_do_readdir(server, dentry, filp->f_pos,
485 NCP_READDIR_CACHE_SIZE, c_entry);
486 DPRINTK(KERN_DEBUG "ncp_readdir: returned %d\n", entries);
489 if (entries < 0) {
490 c_dev = 0;
491 c_ino = 0;
492 result = entries;
493 goto finished;
495 if (entries > 0) {
496 c_seen_eof = (entries < NCP_READDIR_CACHE_SIZE);
497 c_dev = inode->i_dev;
498 c_ino = inode->i_ino;
499 c_size = entries;
500 entry = c_entry;
501 c_last_returned_index = 0;
502 index = 0;
504 for (i = 0; i < c_size; i++)
506 vol2io(server, c_entry[i].i.entryName,
507 !ncp_preserve_entry_case(inode,
508 c_entry[i].i.NSCreator));
512 if (entry == NULL) {
513 /* Nothing found, even from a ncp call */
514 goto finished;
517 while (index < c_size) {
518 ino_t ino;
519 struct qstr qname;
521 DDPRINTK(KERN_DEBUG "ncp_readdir: entry->path= %s\n", entry->i.entryName);
522 DDPRINTK(KERN_DEBUG "ncp_readdir: entry->f_pos = %ld\n", entry->f_pos);
524 /* For getwd() we have to return the correct
525 * inode in d_ino if the inode is currently in
526 * use. Otherwise the inode number does not
527 * matter. (You can argue a lot about this..)
529 qname.name = entry->i.entryName;
530 qname.len = entry->i.nameLen;
531 ino = find_inode_number(dentry, &qname);
532 if (!ino)
533 ino = ncp_invent_inos(1);
535 if (filldir(dirent, entry->i.entryName, entry->i.nameLen,
536 entry->f_pos, ino) < 0) {
537 break;
539 if ((inode->i_dev != c_dev)
540 || (inode->i_ino != c_ino)
541 || (entry->f_pos != filp->f_pos)) {
542 /* Someone has destroyed the cache while we slept
543 in filldir */
544 break;
546 filp->f_pos += 1;
547 index += 1;
548 entry += 1;
550 finished:
551 ncp_unlock_dircache();
552 out:
553 return result;
556 static int
557 ncp_read_volume_list(struct ncp_server *server, int fpos,
558 int cache_size, struct ncp_dirent *entry)
560 int i, total_count = 2;
561 struct ncp_volume_info info;
563 DPRINTK(KERN_DEBUG "ncp_read_volume_list: pos=%d\n", fpos);
564 #if 1
565 if (fpos < 2) {
566 printk(KERN_ERR "OOPS, we expect fpos >= 2");
567 fpos = 2;
569 #endif
571 for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
573 if (ncp_get_volume_info_with_number(server, i, &info) != 0)
574 goto out;
575 if (!strlen(info.volume_name))
576 continue;
578 if (total_count < fpos) {
579 DPRINTK(KERN_DEBUG "ncp_read_volume_list: skipped vol: %s\n",
580 info.volume_name);
581 } else if (total_count >= fpos + cache_size) {
582 goto out;
583 } else {
584 DPRINTK(KERN_DEBUG "ncp_read_volume_list: found vol: %s\n",
585 info.volume_name);
587 if (ncp_lookup_volume(server, info.volume_name,
588 &(entry->i)) != 0) {
589 DPRINTK(KERN_DEBUG "ncpfs: could not lookup vol %s\n",
590 info.volume_name);
591 continue;
593 entry->f_pos = total_count;
594 entry += 1;
596 total_count += 1;
598 out:
599 return (total_count - fpos);
602 static int ncp_do_readdir(struct ncp_server *server, struct dentry *dentry,
603 int fpos, int cache_size, struct ncp_dirent *entry)
605 struct inode *dir = dentry->d_inode;
606 static struct inode *last_dir;
607 static int total_count;
608 static struct nw_search_sequence seq;
609 int err;
611 #if 1
612 if (fpos < 2) {
613 printk(KERN_ERR "OOPS, we expect fpos >= 2");
614 fpos = 2;
616 #endif
617 DPRINTK(KERN_DEBUG "ncp_do_readdir: %s/%s, fpos=%d\n",
618 dentry->d_parent->d_name.name, dentry->d_name.name, fpos);
620 if (fpos == 2) {
621 last_dir = NULL;
622 total_count = 2;
624 if ((fpos != total_count) || (dir != last_dir))
626 total_count = 2;
627 last_dir = dir;
629 #ifdef NCPFS_PARANOIA
630 printk(KERN_DEBUG "ncp_do_readdir: init %s, volnum=%d, dirent=%u\n",
631 dentry->d_name.name, NCP_FINFO(dir)->volNumber, NCP_FINFO(dir)->dirEntNum);
632 #endif
633 err = ncp_initialize_search(server, dir, &seq);
634 if (err)
636 DPRINTK(KERN_DEBUG "ncp_do_readdir: init failed, err=%d\n", err);
637 goto out;
641 while (total_count < fpos + cache_size) {
642 err = ncp_search_for_file_or_subdir(server, &seq, &(entry->i));
643 if (err) {
644 DPRINTK(KERN_DEBUG "ncp_do_readdir: search failed, err=%d\n", err);
645 goto out;
647 if (total_count < fpos) {
648 DPRINTK(KERN_DEBUG "ncp_do_readdir: skipped file: %s/%s\n",
649 dentry->d_name.name, entry->i.entryName);
650 } else {
651 DDPRINTK(KERN_DEBUG "ncp_do_r: file: %s, f_pos=%d,total_count=%d",
652 entry->i.entryName, fpos, total_count);
653 entry->s = seq;
654 entry->f_pos = total_count;
655 entry += 1;
657 total_count += 1;
659 out:
660 return (total_count - fpos);
663 void ncp_init_dir_cache(void)
665 c_dev = 0;
666 c_ino = 0;
667 c_entry = NULL;
670 void ncp_invalid_dir_cache(struct inode *ino)
672 if ((ino->i_dev == c_dev) && (ino->i_ino == c_ino)) {
673 c_dev = 0;
674 c_ino = 0;
675 c_seen_eof = 0;
679 void ncp_free_dir_cache(void)
681 DPRINTK(KERN_DEBUG "ncp_free_dir_cache: enter\n");
683 if (c_entry == NULL) {
684 return;
686 vfree(c_entry);
687 c_entry = NULL;
689 DPRINTK(KERN_DEBUG "ncp_free_dir_cache: exit\n");
692 int ncp_conn_logged_in(struct ncp_server *server)
694 int result;
696 if (ncp_single_volume(server)) {
697 struct dentry* dent;
699 result = -ENOENT;
700 io2vol(server, server->m.mounted_vol, 1);
701 if (ncp_lookup_volume(server, server->m.mounted_vol,
702 &(server->root.finfo.i)) != 0) {
703 #ifdef NCPFS_PARANOIA
704 printk(KERN_DEBUG "ncp_conn_logged_in: %s not found\n", server->m.mounted_vol);
705 #endif
706 goto out;
708 vol2io(server, server->root.finfo.i.entryName, 1);
709 dent = server->root_dentry;
710 if (dent) {
711 struct inode* ino = dent->d_inode;
712 if (ino) {
713 NCP_FINFO(ino)->volNumber = server->root.finfo.i.volNumber;
714 NCP_FINFO(ino)->dirEntNum = server->root.finfo.i.dirEntNum;
715 NCP_FINFO(ino)->DosDirNum = server->root.finfo.i.DosDirNum;
716 } else {
717 DPRINTK(KERN_DEBUG "ncpfs: sb->root_dentry->d_inode == NULL!\n");
719 } else {
720 DPRINTK(KERN_DEBUG "ncpfs: sb->root_dentry == NULL!\n");
723 result = 0;
725 out:
726 return result;
729 static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry)
731 struct ncp_server *server;
732 struct inode *inode = NULL;
733 int found_in_cache, down_case = 0;
734 int error;
735 int len = dentry->d_name.len;
736 struct ncpfs_inode_info finfo;
737 __u8 __name[dentry->d_name.len + 1];
739 server = NCP_SERVER(dir);
741 error = -EIO;
742 if (!ncp_conn_valid(server))
743 goto finished;
745 strncpy(__name, dentry->d_name.name, len);
746 __name[len] = '\0';
747 #ifdef NCPFS_PARANOIA
748 printk(KERN_DEBUG "ncp_lookup: %s, len %d\n", __name, len);
749 #endif
751 /* If the file is in the dir cache, we do not have to ask the
752 server. */
754 found_in_cache = 0;
755 ncp_lock_dircache();
757 if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino))
759 int first = c_last_returned_index;
760 int i;
762 i = first;
763 do {
764 #ifdef NCPFS_PARANOIA
765 printk(KERN_DEBUG "ncp_lookup: trying index: %d, name: %s\n", i, c_entry[i].i.entryName);
766 #endif
767 if (strcmp(c_entry[i].i.entryName, __name) == 0) {
768 #ifdef NCPFS_PARANOIA
769 printk(KERN_DEBUG "ncp_lookup: found in cache!\n");
770 #endif
771 finfo.nw_info.i = c_entry[i].i;
772 found_in_cache = 1;
773 break;
775 i = (i + 1) % c_size;
776 } while (i != first);
778 ncp_unlock_dircache();
780 if (found_in_cache == 0)
782 int res;
784 #ifdef NCPFS_PARANOIA
785 printk(KERN_DEBUG "ncp_lookup: server lookup for %s/%s\n",
786 dentry->d_parent->d_name.name, __name);
787 #endif
788 if (ncp_is_server_root(dir))
790 io2vol(server, __name, 1);
791 down_case = 1;
792 res = ncp_lookup_volume(server, __name,
793 &(finfo.nw_info.i));
794 } else
796 down_case = !ncp_preserve_case(dir);
797 io2vol(server, __name, down_case);
798 res = ncp_obtain_info(server, dir, __name,
799 &(finfo.nw_info.i));
801 #ifdef NCPFS_PARANOIA
802 printk(KERN_DEBUG "ncp_lookup: looked for %s/%s, res=%d\n",
803 dentry->d_parent->d_name.name, __name, res);
804 #endif
806 * If we didn't find an entry, make a negative dentry.
808 if (res != 0) {
809 goto add_entry;
810 } else vol2io(server, finfo.nw_info.i.entryName,
811 !ncp_preserve_entry_case(dir,
812 finfo.nw_info.i.NSCreator));
816 * Create an inode for the entry.
818 finfo.nw_info.opened = 0;
819 finfo.ino = ncp_invent_inos(1);
820 error = -EACCES;
821 inode = ncp_iget(dir->i_sb, &finfo);
822 if (inode)
824 add_entry:
825 dentry->d_op = &ncp_dentry_operations;
826 d_add(dentry, inode);
827 error = 0;
830 finished:
831 #ifdef NCPFS_PARANOIA
832 printk(KERN_DEBUG "ncp_lookup: result=%d\n", error);
833 #endif
834 return ERR_PTR(error);
838 * This code is common to create, mkdir, and mknod.
840 static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
841 struct ncpfs_inode_info *finfo)
843 struct inode *inode;
844 int error = -EINVAL;
846 ncp_invalid_dir_cache(dir);
848 finfo->ino = ncp_invent_inos(1);
849 inode = ncp_iget(dir->i_sb, finfo);
850 if (!inode)
851 goto out_close;
852 d_instantiate(dentry,inode);
853 error = 0;
854 out:
855 return error;
857 out_close:
858 #ifdef NCPFS_PARANOIA
859 printk(KERN_DEBUG "ncp_instantiate: %s/%s failed, closing file\n",
860 dentry->d_parent->d_name.name, dentry->d_name.name);
861 #endif
862 ncp_close_file(NCP_SERVER(dir), finfo->nw_info.file_handle);
863 goto out;
866 int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
867 int attributes)
869 int error, result;
870 struct ncpfs_inode_info finfo;
871 __u8 _name[dentry->d_name.len + 1];
873 #ifdef NCPFS_PARANOIA
874 printk(KERN_DEBUG "ncp_create_new: creating %s/%s, mode=%x\n",
875 dentry->d_parent->d_name.name, dentry->d_name.name, mode);
876 #endif
877 error = -EIO;
878 if (!ncp_conn_valid(NCP_SERVER(dir)))
879 goto out;
881 strncpy(_name, dentry->d_name.name, dentry->d_name.len);
882 _name[dentry->d_name.len] = '\0';
884 io2vol(NCP_SERVER(dir), _name, !ncp_preserve_case(dir));
886 error = -EACCES;
887 result = ncp_open_create_file_or_subdir(NCP_SERVER(dir), dir, _name,
888 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
889 attributes, AR_READ | AR_WRITE, &finfo.nw_info);
890 if (!result) {
891 finfo.nw_info.access = O_RDWR;
892 error = ncp_instantiate(dir, dentry, &finfo);
893 } else {
894 if (result == 0x87) error = -ENAMETOOLONG;
895 DPRINTK(KERN_DEBUG "ncp_create: %s/%s failed\n",
896 dentry->d_parent->d_name.name, dentry->d_name.name);
899 out:
900 return error;
903 static int ncp_create(struct inode *dir, struct dentry *dentry, int mode)
905 return ncp_create_new(dir, dentry, mode, 0);
908 static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
910 int error;
911 struct ncpfs_inode_info finfo;
912 __u8 _name[dentry->d_name.len + 1];
914 DPRINTK(KERN_DEBUG "ncp_mkdir: making %s/%s\n",
915 dentry->d_parent->d_name.name, dentry->d_name.name);
916 error = -EIO;
917 if (!ncp_conn_valid(NCP_SERVER(dir)))
918 goto out;
920 strncpy(_name, dentry->d_name.name, dentry->d_name.len);
921 _name[dentry->d_name.len] = '\0';
922 io2vol(NCP_SERVER(dir), _name, !ncp_preserve_case(dir));
924 error = -EACCES;
925 if (ncp_open_create_file_or_subdir(NCP_SERVER(dir), dir, _name,
926 OC_MODE_CREATE, aDIR, 0xffff,
927 &finfo.nw_info) == 0)
929 error = ncp_instantiate(dir, dentry, &finfo);
931 out:
932 return error;
935 static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
937 int error, result;
938 __u8 _name[dentry->d_name.len + 1];
940 DPRINTK(KERN_DEBUG "ncp_rmdir: removing %s/%s\n",
941 dentry->d_parent->d_name.name, dentry->d_name.name);
943 error = -EIO;
944 if (!ncp_conn_valid(NCP_SERVER(dir)))
945 goto out;
947 error = -EBUSY;
948 if (!list_empty(&dentry->d_hash))
949 goto out;
951 strncpy(_name, dentry->d_name.name, dentry->d_name.len);
952 _name[dentry->d_name.len] = '\0';
954 io2vol(NCP_SERVER(dir), _name, !ncp_preserve_case(dir));
955 result = ncp_del_file_or_subdir(NCP_SERVER(dir), dir, _name);
956 switch (result) {
957 case 0x00:
958 ncp_invalid_dir_cache(dir);
959 error = 0;
960 break;
961 case 0x85: /* unauthorized to delete file */
962 case 0x8A: /* unauthorized to delete file */
963 error = -EACCES;
964 break;
965 case 0x8F:
966 case 0x90: /* read only */
967 error = -EPERM;
968 break;
969 case 0x9F: /* in use by another client */
970 error = -EBUSY;
971 break;
972 case 0xA0: /* directory not empty */
973 error = -ENOTEMPTY;
974 break;
975 case 0xFF: /* someone deleted file */
976 error = -ENOENT;
977 break;
978 default:
979 error = -EACCES;
980 break;
982 out:
983 return error;
986 static int ncp_unlink(struct inode *dir, struct dentry *dentry)
988 struct inode *inode = dentry->d_inode;
989 int error;
991 DPRINTK(KERN_DEBUG "ncp_unlink: unlinking %s/%s\n",
992 dentry->d_parent->d_name.name, dentry->d_name.name);
994 error = -EIO;
995 if (!ncp_conn_valid(NCP_SERVER(dir)))
996 goto out;
999 * Check whether to close the file ...
1001 if (inode && NCP_FINFO(inode)->opened) {
1002 #ifdef NCPFS_PARANOIA
1003 printk(KERN_DEBUG "ncp_unlink: closing file\n");
1004 #endif
1005 ncp_make_closed(inode);
1008 error = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
1009 #ifdef CONFIG_NCPFS_STRONG
1010 /* 9C is Invalid path.. It should be 8F, 90 - read only, but
1011 it is not :-( */
1012 if (error == 0x9C && NCP_SERVER(dir)->m.flags & NCP_MOUNT_STRONG) { /* R/O */
1013 error = ncp_force_unlink(dir, dentry);
1015 #endif
1016 switch (error) {
1017 case 0x00:
1018 DPRINTK(KERN_DEBUG "ncp: removed %s/%s\n",
1019 dentry->d_parent->d_name.name, dentry->d_name.name);
1020 ncp_invalid_dir_cache(dir);
1021 d_delete(dentry);
1022 break;
1023 case 0x85:
1024 case 0x8A:
1025 error = -EACCES;
1026 break;
1027 case 0x8D: /* some files in use */
1028 case 0x8E: /* all files in use */
1029 error = -EBUSY;
1030 break;
1031 case 0x8F: /* some read only */
1032 case 0x90: /* all read only */
1033 case 0x9C: /* !!! returned when in-use or read-only by NW4 */
1034 error = -EPERM;
1035 break;
1036 case 0xFF:
1037 error = -ENOENT;
1038 break;
1039 default:
1040 error = -EACCES;
1041 break;
1044 out:
1045 return error;
1048 static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
1049 struct inode *new_dir, struct dentry *new_dentry)
1051 int old_len = old_dentry->d_name.len;
1052 int new_len = new_dentry->d_name.len;
1053 int error;
1054 char _old_name[old_dentry->d_name.len + 1];
1055 char _new_name[new_dentry->d_name.len + 1];
1057 DPRINTK(KERN_DEBUG "ncp_rename: %s/%s to %s/%s\n",
1058 old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
1059 new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
1061 error = -EIO;
1062 if (!ncp_conn_valid(NCP_SERVER(old_dir)))
1063 goto out;
1065 strncpy(_old_name, old_dentry->d_name.name, old_len);
1066 _old_name[old_len] = '\0';
1067 io2vol(NCP_SERVER(old_dir), _old_name, !ncp_preserve_case(old_dir));
1069 strncpy(_new_name, new_dentry->d_name.name, new_len);
1070 _new_name[new_len] = '\0';
1071 io2vol(NCP_SERVER(new_dir), _new_name, !ncp_preserve_case(new_dir));
1073 error = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
1074 old_dir, _old_name,
1075 new_dir, _new_name);
1076 #ifdef CONFIG_NCPFS_STRONG
1077 if ((error == 0x90 || error == -EACCES) && NCP_SERVER(old_dir)->m.flags & NCP_MOUNT_STRONG) { /* RO */
1078 error = ncp_force_rename(old_dir, old_dentry, _old_name,
1079 new_dir, new_dentry, _new_name);
1081 #endif
1082 switch (error) {
1083 case 0x00:
1084 DPRINTK(KERN_DEBUG "ncp renamed %s -> %s.\n",
1085 old_dentry->d_name.name,new_dentry->d_name.name);
1086 ncp_invalid_dir_cache(old_dir);
1087 ncp_invalid_dir_cache(new_dir);
1088 /* d_move(old_dentry, new_dentry); */
1089 break;
1090 case 0x9E:
1091 error = -ENAMETOOLONG;
1092 break;
1093 case 0xFF:
1094 error = -ENOENT;
1095 break;
1096 default:
1097 error = -EACCES;
1098 break;
1100 out:
1101 return error;
1104 /* The following routines are taken directly from msdos-fs */
1106 /* Linear day numbers of the respective 1sts in non-leap years. */
1108 static int day_n[] =
1109 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
1110 /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
1113 extern struct timezone sys_tz;
1115 static int utc2local(int time)
1117 return time - sys_tz.tz_minuteswest * 60;
1120 static int local2utc(int time)
1122 return time + sys_tz.tz_minuteswest * 60;
1125 /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
1127 ncp_date_dos2unix(unsigned short time, unsigned short date)
1129 int month, year, secs;
1131 /* first subtract and mask after that... Otherwise, if
1132 date == 0, bad things happen */
1133 month = ((date >> 5) - 1) & 15;
1134 year = date >> 9;
1135 secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
1136 86400 * ((date & 31) - 1 + day_n[month] + (year / 4) +
1137 year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
1138 /* days since 1.1.70 plus 80's leap day */
1139 return local2utc(secs);
1143 /* Convert linear UNIX date to a MS-DOS time/date pair. */
1144 void
1145 ncp_date_unix2dos(int unix_date, unsigned short *time, unsigned short *date)
1147 int day, year, nl_day, month;
1149 unix_date = utc2local(unix_date);
1150 *time = (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
1151 (((unix_date / 3600) % 24) << 11);
1152 day = unix_date / 86400 - 3652;
1153 year = day / 365;
1154 if ((year + 3) / 4 + 365 * year > day)
1155 year--;
1156 day -= (year + 3) / 4 + 365 * year;
1157 if (day == 59 && !(year & 3)) {
1158 nl_day = day;
1159 month = 2;
1160 } else {
1161 nl_day = (year & 3) || day <= 59 ? day : day - 1;
1162 for (month = 0; month < 12; month++)
1163 if (day_n[month] > nl_day)
1164 break;
1166 *date = nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9);