~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/ncpfs/dir.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.