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