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