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