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