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