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