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

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

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

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

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp