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