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