Import 2.3.1pre2
[davej-history.git] / fs / ncpfs / dir.c
blob8fc3a0994039d8932c6b85413d036f0541d21802
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 int c_lock = 0;
42 static DECLARE_WAIT_QUEUE_HEAD(c_wait);
44 static int ncp_read_volume_list(struct ncp_server *, int, int,
45 struct ncp_dirent *);
46 static int ncp_do_readdir(struct ncp_server *, struct dentry *, int, int,
47 struct ncp_dirent *);
49 static ssize_t ncp_dir_read(struct file *, char *, size_t, loff_t *);
50 static int ncp_readdir(struct file *, void *, filldir_t);
52 static int ncp_create(struct inode *, struct dentry *, int);
53 static struct dentry *ncp_lookup(struct inode *, struct dentry *);
54 static int ncp_unlink(struct inode *, struct dentry *);
55 static int ncp_mkdir(struct inode *, struct dentry *, int);
56 static int ncp_rmdir(struct inode *, struct dentry *);
57 static int ncp_rename(struct inode *, struct dentry *,
58 struct inode *, struct dentry *);
59 #ifdef CONFIG_NCPFS_EXTRAS
60 extern int ncp_symlink(struct inode *, struct dentry *, const char *);
61 #endif
63 static struct file_operations ncp_dir_operations =
65 NULL, /* lseek - default */
66 ncp_dir_read, /* read - bad */
67 NULL, /* write - bad */
68 ncp_readdir, /* readdir */
69 NULL, /* poll - default */
70 ncp_ioctl, /* ioctl */
71 NULL, /* mmap */
72 NULL, /* no special open code */
73 NULL, /* flush */
74 NULL, /* no special release code */
75 NULL /* fsync */
78 struct inode_operations ncp_dir_inode_operations =
80 &ncp_dir_operations, /* default directory file ops */
81 ncp_create, /* create */
82 ncp_lookup, /* lookup */
83 NULL, /* link */
84 ncp_unlink, /* unlink */
85 #ifdef CONFIG_NCPFS_EXTRAS
86 ncp_symlink, /* symlink */
87 #else
88 NULL, /* symlink */
89 #endif
90 ncp_mkdir, /* mkdir */
91 ncp_rmdir, /* rmdir */
92 NULL, /* mknod */
93 ncp_rename, /* rename */
94 NULL, /* readlink */
95 NULL, /* follow link */
96 NULL, /* readpage */
97 NULL, /* writepage */
98 NULL, /* bmap */
99 NULL, /* truncate */
100 NULL, /* permission */
101 NULL, /* smap */
102 NULL, /* updatepage */
103 NULL, /* revalidate */
106 static ssize_t
107 ncp_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
109 return -EISDIR;
113 * Dentry operations routines
115 static int ncp_lookup_validate(struct dentry *, int);
116 static int ncp_hash_dentry(struct dentry *, struct qstr *);
117 static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *);
118 static void ncp_delete_dentry(struct dentry *);
120 struct dentry_operations ncp_dentry_operations =
122 ncp_lookup_validate, /* d_revalidate(struct dentry *, int) */
123 ncp_hash_dentry, /* d_hash */
124 ncp_compare_dentry, /* d_compare */
125 ncp_delete_dentry /* d_delete(struct dentry *) */
130 * XXX: It would be better to use the tolower from linux/ctype.h,
131 * but _ctype is needed and it is not exported.
133 #define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)-('A'-'a') : (c))
136 * Note: leave the hash unchanged if the directory
137 * is case-sensitive.
139 static int
140 ncp_hash_dentry(struct dentry *dentry, struct qstr *this)
142 unsigned long hash;
143 int i;
145 if (!ncp_case_sensitive(dentry->d_inode)) {
146 hash = init_name_hash();
147 for (i=0; i<this->len ; i++)
148 hash = partial_name_hash(tolower(this->name[i]),hash);
149 this->hash = end_name_hash(hash);
151 return 0;
154 static int
155 ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
157 int i;
159 if (a->len != b->len) return 1;
161 if (ncp_case_sensitive(dentry->d_inode))
162 return strncmp(a->name, b->name, a->len);
164 for (i=0; i<a->len; i++)
165 if (tolower(a->name[i]) != tolower(b->name[i]))
166 return 1;
168 return 0;
172 * This is the callback from dput() when d_count is going to 0.
173 * We use this to unhash dentries with bad inodes and close files.
175 static void
176 ncp_delete_dentry(struct dentry * dentry)
178 struct inode *inode = dentry->d_inode;
180 if (inode)
182 if (is_bad_inode(inode))
184 d_drop(dentry);
187 * Lock the superblock, then recheck the dentry count.
188 * (Somebody might have used it again ...)
190 if (dentry->d_count == 1 && NCP_FINFO(inode)->opened) {
191 #ifdef NCPFS_PARANOIA
192 printk(KERN_DEBUG "ncp_delete_dentry: closing file %s/%s\n",
193 dentry->d_parent->d_name.name, dentry->d_name.name);
194 #endif
195 ncp_make_closed(inode);
197 } else
199 /* N.B. Unhash negative dentries? */
204 * Generate a unique inode number.
206 ino_t ncp_invent_inos(unsigned long n)
208 static ino_t ino = 2;
210 if (ino + 2*n < ino)
212 /* wrap around */
213 ino = 2;
215 ino += n;
216 return ino;
219 static inline int
220 ncp_single_volume(struct ncp_server *server)
222 return (server->m.mounted_vol[0] != '\0');
225 static inline int ncp_is_server_root(struct inode *inode)
227 return (!ncp_single_volume(NCP_SERVER(inode)) &&
228 inode == inode->i_sb->s_root->d_inode);
231 static inline void ncp_lock_dircache(void)
233 while (c_lock)
234 sleep_on(&c_wait);
235 c_lock = 1;
238 static inline void ncp_unlock_dircache(void)
240 c_lock = 0;
241 wake_up(&c_wait);
246 * This is the callback when the dcache has a lookup hit.
250 #ifdef CONFIG_NCPFS_STRONG
251 /* try to delete a readonly file (NW R bit set) */
253 static int
254 ncp_force_unlink(struct inode *dir, struct dentry* dentry)
256 int res=0x9c,res2;
257 struct nw_modify_dos_info info;
258 __u32 old_nwattr;
259 struct inode *inode;
261 memset(&info, 0, sizeof(info));
263 /* remove the Read-Only flag on the NW server */
264 inode = dentry->d_inode;
266 old_nwattr = NCP_FINFO(inode)->nwattr;
267 info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT);
268 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
269 if (res2)
270 goto leave_me;
272 /* now try again the delete operation */
273 res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
275 if (res) /* delete failed, set R bit again */
277 info.attributes = old_nwattr;
278 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
279 if (res2)
280 goto leave_me;
282 leave_me:
283 return(res);
285 #endif /* CONFIG_NCPFS_STRONG */
287 #ifdef CONFIG_NCPFS_STRONG
288 static int
289 ncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name,
290 struct inode *new_dir, struct dentry* new_dentry, char *_new_name)
292 struct nw_modify_dos_info info;
293 int res=0x90,res2;
294 struct inode *old_inode = old_dentry->d_inode;
295 __u32 old_nwattr = NCP_FINFO(old_inode)->nwattr;
296 __u32 new_nwattr = 0; /* shut compiler warning */
297 int old_nwattr_changed = 0;
298 int new_nwattr_changed = 0;
300 memset(&info, 0, sizeof(info));
302 /* remove the Read-Only flag on the NW server */
304 info.attributes = old_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
305 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
306 if (!res2)
307 old_nwattr_changed = 1;
308 if (new_dentry && new_dentry->d_inode) {
309 new_nwattr = NCP_FINFO(new_dentry->d_inode)->nwattr;
310 info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
311 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
312 if (!res2)
313 new_nwattr_changed = 1;
315 /* now try again the rename operation */
316 /* but only if something really happened */
317 if (new_nwattr_changed || old_nwattr_changed) {
318 res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
319 old_dir, _old_name,
320 new_dir, _new_name);
322 if (res)
323 goto leave_me;
324 /* file was successfully renamed, so:
325 do not set attributes on old file - it no longer exists
326 copy attributes from old file to new */
327 new_nwattr_changed = old_nwattr_changed;
328 new_nwattr = old_nwattr;
329 old_nwattr_changed = 0;
331 leave_me:;
332 if (old_nwattr_changed) {
333 info.attributes = old_nwattr;
334 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
335 /* ignore errors */
337 if (new_nwattr_changed) {
338 info.attributes = new_nwattr;
339 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
340 /* ignore errors */
342 return(res);
344 #endif /* CONFIG_NCPFS_STRONG */
347 static int
348 ncp_lookup_validate(struct dentry * dentry, int flags)
350 struct ncp_server *server;
351 struct inode *dir = dentry->d_parent->d_inode;
352 int down_case = 0;
353 int val = 0,res;
354 int len = dentry->d_name.len;
355 struct ncpfs_inode_info finfo;
356 __u8 __name[dentry->d_name.len + 1];
358 if (!dentry->d_inode) {
359 DPRINTK(KERN_DEBUG "ncp_lookup_validate: called with dentry->d_inode already NULL.\n");
360 return 0;
363 if (!dir || !S_ISDIR(dir->i_mode)) {
364 printk(KERN_WARNING "ncp_lookup_validate: inode is NULL or not a directory.\n");
365 goto finished;
367 server = NCP_SERVER(dir);
369 if (!ncp_conn_valid(server))
370 goto finished;
372 strncpy(__name, dentry->d_name.name, len);
373 __name[len] = '\0';
374 #ifdef NCPFS_PARANOIA
375 printk(KERN_DEBUG "ncp_lookup_validate: %s, len %d\n", __name, len);
376 #endif
378 /* If the file is in the dir cache, we do not have to ask the
379 server. */
381 #ifdef NCPFS_PARANOIA
382 printk(KERN_DEBUG "ncp_lookup_validate: server lookup for %s/%s\n",
383 dentry->d_parent->d_name.name, __name);
384 #endif
385 if (ncp_is_server_root(dir))
387 io2vol(server, __name, 1);
388 down_case = 1;
389 res = ncp_lookup_volume(server, __name,
390 &(finfo.nw_info.i));
391 } else
393 down_case = !ncp_preserve_case(dir);
394 io2vol(server, __name, down_case);
395 res = ncp_obtain_info(server, dir, __name,
396 &(finfo.nw_info.i));
398 #ifdef NCPFS_PARANOIA
399 printk(KERN_DEBUG "ncp_lookup_validate: looked for %s/%s, res=%d\n",
400 dentry->d_parent->d_name.name, __name, res);
401 #endif
403 * If we didn't find it, or if it has a different dirEntNum to
404 * what we remember, it's not valid any more.
406 if (!res) {
407 if (finfo.nw_info.i.dirEntNum == NCP_FINFO(dentry->d_inode)->dirEntNum)
408 val=1;
409 #ifdef NCPFS_PARANOIA
410 else
411 printk(KERN_DEBUG "ncp_lookup_validate: found, but dirEntNum changed\n");
412 #endif
413 vol2io(server, finfo.nw_info.i.entryName,
414 !ncp_preserve_entry_case(dir,
415 finfo.nw_info.i.NSCreator));
416 ncp_update_inode2(dentry->d_inode, &finfo.nw_info);
418 if (!val) ncp_invalid_dir_cache(dir);
420 finished:
421 #ifdef NCPFS_PARANOIA
422 printk(KERN_DEBUG "ncp_lookup_validate: result=%d\n", val);
423 #endif
425 return val;
429 static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
431 struct dentry *dentry = filp->f_dentry;
432 struct inode *inode = dentry->d_inode;
433 struct ncp_server *server = NCP_SERVER(inode);
434 struct ncp_dirent *entry = NULL;
435 int result, i, index = 0;
437 DDPRINTK(KERN_DEBUG "ncp_readdir: reading %s/%s, pos=%d\n",
438 dentry->d_parent->d_name.name, dentry->d_name.name,
439 (int) filp->f_pos);
440 DDPRINTK(KERN_DEBUG "ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
441 inode->i_ino, c_ino);
443 result = -EIO;
444 if (!ncp_conn_valid(server))
445 goto out;
447 ncp_lock_dircache();
448 result = -ENOMEM;
449 if (c_entry == NULL) {
450 i = sizeof(struct ncp_dirent) * NCP_READDIR_CACHE_SIZE;
451 c_entry = (struct ncp_dirent *) vmalloc(i);
452 if (c_entry == NULL) {
453 printk(KERN_WARNING "ncp_readdir: no MEMORY for cache\n");
454 goto finished;
458 result = 0;
459 if (filp->f_pos == 0) {
460 ncp_invalid_dir_cache(inode);
461 if (filldir(dirent, ".", 1, 0, inode->i_ino) < 0) {
462 goto finished;
464 filp->f_pos = 1;
466 if (filp->f_pos == 1) {
467 if (filldir(dirent, "..", 2, 1,
468 dentry->d_parent->d_inode->i_ino) < 0) {
469 goto finished;
471 filp->f_pos = 2;
474 if ((inode->i_dev == c_dev) && (inode->i_ino == c_ino)) {
475 for (i = 0; i < c_size; i++) {
476 if (filp->f_pos == c_entry[i].f_pos) {
477 entry = &c_entry[i];
478 c_last_returned_index = i;
479 index = i;
480 break;
483 if ((entry == NULL) && c_seen_eof) {
484 goto finished;
487 if (entry == NULL) {
488 int entries;
489 DDPRINTK(KERN_DEBUG "ncp_readdir: Not found in cache.\n");
491 if (ncp_is_server_root(inode)) {
492 entries = ncp_read_volume_list(server, filp->f_pos,
493 NCP_READDIR_CACHE_SIZE, c_entry);
494 DPRINTK(KERN_DEBUG "ncp_read_volume_list returned %d\n", entries);
496 } else {
497 entries = ncp_do_readdir(server, dentry, filp->f_pos,
498 NCP_READDIR_CACHE_SIZE, c_entry);
499 DPRINTK(KERN_DEBUG "ncp_readdir: returned %d\n", entries);
502 if (entries < 0) {
503 c_dev = 0;
504 c_ino = 0;
505 result = entries;
506 goto finished;
508 if (entries > 0) {
509 c_seen_eof = (entries < NCP_READDIR_CACHE_SIZE);
510 c_dev = inode->i_dev;
511 c_ino = inode->i_ino;
512 c_size = entries;
513 entry = c_entry;
514 c_last_returned_index = 0;
515 index = 0;
517 for (i = 0; i < c_size; i++)
519 vol2io(server, c_entry[i].i.entryName,
520 !ncp_preserve_entry_case(inode,
521 c_entry[i].i.NSCreator));
525 if (entry == NULL) {
526 /* Nothing found, even from a ncp call */
527 goto finished;
530 while (index < c_size) {
531 ino_t ino;
532 struct qstr qname;
534 DDPRINTK(KERN_DEBUG "ncp_readdir: entry->path= %s\n", entry->i.entryName);
535 DDPRINTK(KERN_DEBUG "ncp_readdir: entry->f_pos = %ld\n", entry->f_pos);
537 /* For getwd() we have to return the correct
538 * inode in d_ino if the inode is currently in
539 * use. Otherwise the inode number does not
540 * matter. (You can argue a lot about this..)
542 qname.name = entry->i.entryName;
543 qname.len = entry->i.nameLen;
544 ino = find_inode_number(dentry, &qname);
545 if (!ino)
546 ino = ncp_invent_inos(1);
548 if (filldir(dirent, entry->i.entryName, entry->i.nameLen,
549 entry->f_pos, ino) < 0) {
550 break;
552 if ((inode->i_dev != c_dev)
553 || (inode->i_ino != c_ino)
554 || (entry->f_pos != filp->f_pos)) {
555 /* Someone has destroyed the cache while we slept
556 in filldir */
557 break;
559 filp->f_pos += 1;
560 index += 1;
561 entry += 1;
563 finished:
564 ncp_unlock_dircache();
565 out:
566 return result;
569 static int
570 ncp_read_volume_list(struct ncp_server *server, int fpos,
571 int cache_size, struct ncp_dirent *entry)
573 int i, total_count = 2;
574 struct ncp_volume_info info;
576 DPRINTK(KERN_DEBUG "ncp_read_volume_list: pos=%d\n", fpos);
577 #if 1
578 if (fpos < 2) {
579 printk(KERN_ERR "OOPS, we expect fpos >= 2");
580 fpos = 2;
582 #endif
584 for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
586 if (ncp_get_volume_info_with_number(server, i, &info) != 0)
587 goto out;
588 if (!strlen(info.volume_name))
589 continue;
591 if (total_count < fpos) {
592 DPRINTK(KERN_DEBUG "ncp_read_volume_list: skipped vol: %s\n",
593 info.volume_name);
594 } else if (total_count >= fpos + cache_size) {
595 goto out;
596 } else {
597 DPRINTK(KERN_DEBUG "ncp_read_volume_list: found vol: %s\n",
598 info.volume_name);
600 if (ncp_lookup_volume(server, info.volume_name,
601 &(entry->i)) != 0) {
602 DPRINTK(KERN_DEBUG "ncpfs: could not lookup vol %s\n",
603 info.volume_name);
604 continue;
606 entry->f_pos = total_count;
607 entry += 1;
609 total_count += 1;
611 out:
612 return (total_count - fpos);
615 static int ncp_do_readdir(struct ncp_server *server, struct dentry *dentry,
616 int fpos, int cache_size, struct ncp_dirent *entry)
618 struct inode *dir = dentry->d_inode;
619 static struct inode *last_dir;
620 static int total_count;
621 static struct nw_search_sequence seq;
622 int err;
624 #if 1
625 if (fpos < 2) {
626 printk(KERN_ERR "OOPS, we expect fpos >= 2");
627 fpos = 2;
629 #endif
630 DPRINTK(KERN_DEBUG "ncp_do_readdir: %s/%s, fpos=%d\n",
631 dentry->d_parent->d_name.name, dentry->d_name.name, fpos);
633 if (fpos == 2) {
634 last_dir = NULL;
635 total_count = 2;
637 if ((fpos != total_count) || (dir != last_dir))
639 total_count = 2;
640 last_dir = dir;
642 #ifdef NCPFS_PARANOIA
643 printk(KERN_DEBUG "ncp_do_readdir: init %s, volnum=%d, dirent=%u\n",
644 dentry->d_name.name, NCP_FINFO(dir)->volNumber, NCP_FINFO(dir)->dirEntNum);
645 #endif
646 err = ncp_initialize_search(server, dir, &seq);
647 if (err)
649 DPRINTK(KERN_DEBUG "ncp_do_readdir: init failed, err=%d\n", err);
650 goto out;
654 while (total_count < fpos + cache_size) {
655 err = ncp_search_for_file_or_subdir(server, &seq, &(entry->i));
656 if (err) {
657 DPRINTK(KERN_DEBUG "ncp_do_readdir: search failed, err=%d\n", err);
658 goto out;
660 if (total_count < fpos) {
661 DPRINTK(KERN_DEBUG "ncp_do_readdir: skipped file: %s/%s\n",
662 dentry->d_name.name, entry->i.entryName);
663 } else {
664 DDPRINTK(KERN_DEBUG "ncp_do_r: file: %s, f_pos=%d,total_count=%d",
665 entry->i.entryName, fpos, total_count);
666 entry->s = seq;
667 entry->f_pos = total_count;
668 entry += 1;
670 total_count += 1;
672 out:
673 return (total_count - fpos);
676 void ncp_init_dir_cache(void)
678 c_dev = 0;
679 c_ino = 0;
680 c_entry = NULL;
683 void ncp_invalid_dir_cache(struct inode *ino)
685 if ((ino->i_dev == c_dev) && (ino->i_ino == c_ino)) {
686 c_dev = 0;
687 c_ino = 0;
688 c_seen_eof = 0;
692 void ncp_free_dir_cache(void)
694 DPRINTK(KERN_DEBUG "ncp_free_dir_cache: enter\n");
696 if (c_entry == NULL) {
697 return;
699 vfree(c_entry);
700 c_entry = NULL;
702 DPRINTK(KERN_DEBUG "ncp_free_dir_cache: exit\n");
705 int ncp_conn_logged_in(struct ncp_server *server)
707 int result;
709 if (ncp_single_volume(server)) {
710 struct dentry* dent;
712 result = -ENOENT;
713 io2vol(server, server->m.mounted_vol, 1);
714 if (ncp_lookup_volume(server, server->m.mounted_vol,
715 &(server->root.finfo.i)) != 0) {
716 #ifdef NCPFS_PARANOIA
717 printk(KERN_DEBUG "ncp_conn_logged_in: %s not found\n", server->m.mounted_vol);
718 #endif
719 goto out;
721 vol2io(server, server->root.finfo.i.entryName, 1);
722 dent = server->root_dentry;
723 if (dent) {
724 struct inode* ino = dent->d_inode;
725 if (ino) {
726 NCP_FINFO(ino)->volNumber = server->root.finfo.i.volNumber;
727 NCP_FINFO(ino)->dirEntNum = server->root.finfo.i.dirEntNum;
728 NCP_FINFO(ino)->DosDirNum = server->root.finfo.i.DosDirNum;
729 } else {
730 DPRINTK(KERN_DEBUG "ncpfs: sb->root_dentry->d_inode == NULL!\n");
732 } else {
733 DPRINTK(KERN_DEBUG "ncpfs: sb->root_dentry == NULL!\n");
736 result = 0;
738 out:
739 return result;
742 static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry)
744 struct ncp_server *server;
745 struct inode *inode = NULL;
746 int found_in_cache, down_case = 0;
747 int error;
748 int len = dentry->d_name.len;
749 struct ncpfs_inode_info finfo;
750 __u8 __name[dentry->d_name.len + 1];
752 server = NCP_SERVER(dir);
754 error = -EIO;
755 if (!ncp_conn_valid(server))
756 goto finished;
758 strncpy(__name, dentry->d_name.name, len);
759 __name[len] = '\0';
760 #ifdef NCPFS_PARANOIA
761 printk(KERN_DEBUG "ncp_lookup: %s, len %d\n", __name, len);
762 #endif
764 /* If the file is in the dir cache, we do not have to ask the
765 server. */
767 found_in_cache = 0;
768 ncp_lock_dircache();
770 if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino))
772 int first = c_last_returned_index;
773 int i;
775 i = first;
776 do {
777 #ifdef NCPFS_PARANOIA
778 printk(KERN_DEBUG "ncp_lookup: trying index: %d, name: %s\n", i, c_entry[i].i.entryName);
779 #endif
780 if (strcmp(c_entry[i].i.entryName, __name) == 0) {
781 #ifdef NCPFS_PARANOIA
782 printk(KERN_DEBUG "ncp_lookup: found in cache!\n");
783 #endif
784 finfo.nw_info.i = c_entry[i].i;
785 found_in_cache = 1;
786 break;
788 i = (i + 1) % c_size;
789 } while (i != first);
791 ncp_unlock_dircache();
793 if (found_in_cache == 0)
795 int res;
797 #ifdef NCPFS_PARANOIA
798 printk(KERN_DEBUG "ncp_lookup: server lookup for %s/%s\n",
799 dentry->d_parent->d_name.name, __name);
800 #endif
801 if (ncp_is_server_root(dir))
803 io2vol(server, __name, 1);
804 down_case = 1;
805 res = ncp_lookup_volume(server, __name,
806 &(finfo.nw_info.i));
807 } else
809 down_case = !ncp_preserve_case(dir);
810 io2vol(server, __name, down_case);
811 res = ncp_obtain_info(server, dir, __name,
812 &(finfo.nw_info.i));
814 #ifdef NCPFS_PARANOIA
815 printk(KERN_DEBUG "ncp_lookup: looked for %s/%s, res=%d\n",
816 dentry->d_parent->d_name.name, __name, res);
817 #endif
819 * If we didn't find an entry, make a negative dentry.
821 if (res != 0) {
822 goto add_entry;
823 } else vol2io(server, finfo.nw_info.i.entryName,
824 !ncp_preserve_entry_case(dir,
825 finfo.nw_info.i.NSCreator));
829 * Create an inode for the entry.
831 finfo.nw_info.opened = 0;
832 finfo.ino = ncp_invent_inos(1);
833 error = -EACCES;
834 inode = ncp_iget(dir->i_sb, &finfo);
835 if (inode)
837 add_entry:
838 dentry->d_op = &ncp_dentry_operations;
839 d_add(dentry, inode);
840 error = 0;
843 finished:
844 #ifdef NCPFS_PARANOIA
845 printk(KERN_DEBUG "ncp_lookup: result=%d\n", error);
846 #endif
847 return ERR_PTR(error);
851 * This code is common to create, mkdir, and mknod.
853 static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
854 struct ncpfs_inode_info *finfo)
856 struct inode *inode;
857 int error = -EINVAL;
859 ncp_invalid_dir_cache(dir);
861 finfo->ino = ncp_invent_inos(1);
862 inode = ncp_iget(dir->i_sb, finfo);
863 if (!inode)
864 goto out_close;
865 d_instantiate(dentry,inode);
866 error = 0;
867 out:
868 return error;
870 out_close:
871 #ifdef NCPFS_PARANOIA
872 printk(KERN_DEBUG "ncp_instantiate: %s/%s failed, closing file\n",
873 dentry->d_parent->d_name.name, dentry->d_name.name);
874 #endif
875 ncp_close_file(NCP_SERVER(dir), finfo->nw_info.file_handle);
876 goto out;
879 int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
880 int attributes)
882 int error, result;
883 struct ncpfs_inode_info finfo;
884 __u8 _name[dentry->d_name.len + 1];
886 #ifdef NCPFS_PARANOIA
887 printk(KERN_DEBUG "ncp_create_new: creating %s/%s, mode=%x\n",
888 dentry->d_parent->d_name.name, dentry->d_name.name, mode);
889 #endif
890 error = -EIO;
891 if (!ncp_conn_valid(NCP_SERVER(dir)))
892 goto out;
894 strncpy(_name, dentry->d_name.name, dentry->d_name.len);
895 _name[dentry->d_name.len] = '\0';
897 io2vol(NCP_SERVER(dir), _name, !ncp_preserve_case(dir));
899 error = -EACCES;
900 result = ncp_open_create_file_or_subdir(NCP_SERVER(dir), dir, _name,
901 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
902 attributes, AR_READ | AR_WRITE, &finfo.nw_info);
903 if (!result) {
904 finfo.nw_info.access = O_RDWR;
905 error = ncp_instantiate(dir, dentry, &finfo);
906 } else {
907 if (result == 0x87) error = -ENAMETOOLONG;
908 DPRINTK(KERN_DEBUG "ncp_create: %s/%s failed\n",
909 dentry->d_parent->d_name.name, dentry->d_name.name);
912 out:
913 return error;
916 static int ncp_create(struct inode *dir, struct dentry *dentry, int mode)
918 return ncp_create_new(dir, dentry, mode, 0);
921 static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
923 int error;
924 struct ncpfs_inode_info finfo;
925 __u8 _name[dentry->d_name.len + 1];
927 DPRINTK(KERN_DEBUG "ncp_mkdir: making %s/%s\n",
928 dentry->d_parent->d_name.name, dentry->d_name.name);
929 error = -EIO;
930 if (!ncp_conn_valid(NCP_SERVER(dir)))
931 goto out;
933 strncpy(_name, dentry->d_name.name, dentry->d_name.len);
934 _name[dentry->d_name.len] = '\0';
935 io2vol(NCP_SERVER(dir), _name, !ncp_preserve_case(dir));
937 error = -EACCES;
938 if (ncp_open_create_file_or_subdir(NCP_SERVER(dir), dir, _name,
939 OC_MODE_CREATE, aDIR, 0xffff,
940 &finfo.nw_info) == 0)
942 error = ncp_instantiate(dir, dentry, &finfo);
944 out:
945 return error;
948 static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
950 int error, result;
951 __u8 _name[dentry->d_name.len + 1];
953 DPRINTK(KERN_DEBUG "ncp_rmdir: removing %s/%s\n",
954 dentry->d_parent->d_name.name, dentry->d_name.name);
956 error = -EIO;
957 if (!ncp_conn_valid(NCP_SERVER(dir)))
958 goto out;
960 error = -EBUSY;
961 if (!list_empty(&dentry->d_hash))
962 goto out;
964 strncpy(_name, dentry->d_name.name, dentry->d_name.len);
965 _name[dentry->d_name.len] = '\0';
967 io2vol(NCP_SERVER(dir), _name, !ncp_preserve_case(dir));
968 result = ncp_del_file_or_subdir(NCP_SERVER(dir), dir, _name);
969 switch (result) {
970 case 0x00:
971 ncp_invalid_dir_cache(dir);
972 error = 0;
973 break;
974 case 0x85: /* unauthorized to delete file */
975 case 0x8A: /* unauthorized to delete file */
976 error = -EACCES;
977 break;
978 case 0x8F:
979 case 0x90: /* read only */
980 error = -EPERM;
981 break;
982 case 0x9F: /* in use by another client */
983 error = -EBUSY;
984 break;
985 case 0xA0: /* directory not empty */
986 error = -ENOTEMPTY;
987 break;
988 case 0xFF: /* someone deleted file */
989 error = -ENOENT;
990 break;
991 default:
992 error = -EACCES;
993 break;
995 out:
996 return error;
999 static int ncp_unlink(struct inode *dir, struct dentry *dentry)
1001 struct inode *inode = dentry->d_inode;
1002 int error;
1004 DPRINTK(KERN_DEBUG "ncp_unlink: unlinking %s/%s\n",
1005 dentry->d_parent->d_name.name, dentry->d_name.name);
1007 error = -EIO;
1008 if (!ncp_conn_valid(NCP_SERVER(dir)))
1009 goto out;
1012 * Check whether to close the file ...
1014 if (inode && NCP_FINFO(inode)->opened) {
1015 #ifdef NCPFS_PARANOIA
1016 printk(KERN_DEBUG "ncp_unlink: closing file\n");
1017 #endif
1018 ncp_make_closed(inode);
1021 error = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
1022 #ifdef CONFIG_NCPFS_STRONG
1023 /* 9C is Invalid path.. It should be 8F, 90 - read only, but
1024 it is not :-( */
1025 if (error == 0x9C && NCP_SERVER(dir)->m.flags & NCP_MOUNT_STRONG) { /* R/O */
1026 error = ncp_force_unlink(dir, dentry);
1028 #endif
1029 switch (error) {
1030 case 0x00:
1031 DPRINTK(KERN_DEBUG "ncp: removed %s/%s\n",
1032 dentry->d_parent->d_name.name, dentry->d_name.name);
1033 ncp_invalid_dir_cache(dir);
1034 d_delete(dentry);
1035 break;
1036 case 0x85:
1037 case 0x8A:
1038 error = -EACCES;
1039 break;
1040 case 0x8D: /* some files in use */
1041 case 0x8E: /* all files in use */
1042 error = -EBUSY;
1043 break;
1044 case 0x8F: /* some read only */
1045 case 0x90: /* all read only */
1046 case 0x9C: /* !!! returned when in-use or read-only by NW4 */
1047 error = -EPERM;
1048 break;
1049 case 0xFF:
1050 error = -ENOENT;
1051 break;
1052 default:
1053 error = -EACCES;
1054 break;
1057 out:
1058 return error;
1061 static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
1062 struct inode *new_dir, struct dentry *new_dentry)
1064 int old_len = old_dentry->d_name.len;
1065 int new_len = new_dentry->d_name.len;
1066 int error;
1067 char _old_name[old_dentry->d_name.len + 1];
1068 char _new_name[new_dentry->d_name.len + 1];
1070 DPRINTK(KERN_DEBUG "ncp_rename: %s/%s to %s/%s\n",
1071 old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
1072 new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
1074 error = -EIO;
1075 if (!ncp_conn_valid(NCP_SERVER(old_dir)))
1076 goto out;
1078 strncpy(_old_name, old_dentry->d_name.name, old_len);
1079 _old_name[old_len] = '\0';
1080 io2vol(NCP_SERVER(old_dir), _old_name, !ncp_preserve_case(old_dir));
1082 strncpy(_new_name, new_dentry->d_name.name, new_len);
1083 _new_name[new_len] = '\0';
1084 io2vol(NCP_SERVER(new_dir), _new_name, !ncp_preserve_case(new_dir));
1086 error = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
1087 old_dir, _old_name,
1088 new_dir, _new_name);
1089 #ifdef CONFIG_NCPFS_STRONG
1090 if ((error == 0x90 || error == -EACCES) && NCP_SERVER(old_dir)->m.flags & NCP_MOUNT_STRONG) { /* RO */
1091 error = ncp_force_rename(old_dir, old_dentry, _old_name,
1092 new_dir, new_dentry, _new_name);
1094 #endif
1095 switch (error) {
1096 case 0x00:
1097 DPRINTK(KERN_DEBUG "ncp renamed %s -> %s.\n",
1098 old_dentry->d_name.name,new_dentry->d_name.name);
1099 ncp_invalid_dir_cache(old_dir);
1100 ncp_invalid_dir_cache(new_dir);
1101 /* d_move(old_dentry, new_dentry); */
1102 break;
1103 case 0x9E:
1104 error = -ENAMETOOLONG;
1105 break;
1106 case 0xFF:
1107 error = -ENOENT;
1108 break;
1109 default:
1110 error = -EACCES;
1111 break;
1113 out:
1114 return error;
1117 /* The following routines are taken directly from msdos-fs */
1119 /* Linear day numbers of the respective 1sts in non-leap years. */
1121 static int day_n[] =
1122 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
1123 /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
1126 extern struct timezone sys_tz;
1128 static int utc2local(int time)
1130 return time - sys_tz.tz_minuteswest * 60;
1133 static int local2utc(int time)
1135 return time + sys_tz.tz_minuteswest * 60;
1138 /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
1140 ncp_date_dos2unix(unsigned short time, unsigned short date)
1142 int month, year, secs;
1144 /* first subtract and mask after that... Otherwise, if
1145 date == 0, bad things happen */
1146 month = ((date >> 5) - 1) & 15;
1147 year = date >> 9;
1148 secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
1149 86400 * ((date & 31) - 1 + day_n[month] + (year / 4) +
1150 year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
1151 /* days since 1.1.70 plus 80's leap day */
1152 return local2utc(secs);
1156 /* Convert linear UNIX date to a MS-DOS time/date pair. */
1157 void
1158 ncp_date_unix2dos(int unix_date, unsigned short *time, unsigned short *date)
1160 int day, year, nl_day, month;
1162 unix_date = utc2local(unix_date);
1163 *time = (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
1164 (((unix_date / 3600) % 24) << 11);
1165 day = unix_date / 86400 - 3652;
1166 year = day / 365;
1167 if ((year + 3) / 4 + 365 * year > day)
1168 year--;
1169 day -= (year + 3) / 4 + 365 * year;
1170 if (day == 59 && !(year & 3)) {
1171 nl_day = day;
1172 month = 2;
1173 } else {
1174 nl_day = (year & 3) || day <= 59 ? day : day - 1;
1175 for (month = 0; month < 12; month++)
1176 if (day_n[month] > nl_day)
1177 break;
1179 *date = nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9);