BKL: Remove BKL from ncpfs
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / fs / ncpfs / dir.c
blobaac8832e919e9a56cb95af787af658fb03d8d0d1
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>
22 #include <linux/smp_lock.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(struct dentry *, struct qstr *);
79 static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *);
80 static int ncp_delete_dentry(struct dentry *);
82 static const struct dentry_operations ncp_dentry_operations =
84 .d_revalidate = ncp_lookup_validate,
85 .d_hash = ncp_hash_dentry,
86 .d_compare = ncp_compare_dentry,
87 .d_delete = ncp_delete_dentry,
90 const struct dentry_operations ncp_root_dentry_operations =
92 .d_hash = ncp_hash_dentry,
93 .d_compare = ncp_compare_dentry,
94 .d_delete = ncp_delete_dentry,
98 #define ncp_namespace(i) (NCP_SERVER(i)->name_space[NCP_FINFO(i)->volNumber])
100 static inline int ncp_preserve_entry_case(struct inode *i, __u32 nscreator)
102 #ifdef CONFIG_NCPFS_SMALLDOS
103 int ns = ncp_namespace(i);
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 */
110 return 0;
111 #endif /* CONFIG_NCPFS_SMALLDOS */
112 return 1;
115 #define ncp_preserve_case(i) (ncp_namespace(i) != NW_NS_DOS)
117 static inline int ncp_case_sensitive(struct dentry *dentry)
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 */
127 * Note: leave the hash unchanged if the directory
128 * is case-sensitive.
130 static int
131 ncp_hash_dentry(struct dentry *dentry, struct qstr *this)
133 if (!ncp_case_sensitive(dentry)) {
134 struct nls_table *t;
135 unsigned long hash;
136 int i;
138 t = NCP_IO_TABLE(dentry);
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);
145 return 0;
148 static int
149 ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
151 if (a->len != b->len)
152 return 1;
154 if (ncp_case_sensitive(dentry))
155 return strncmp(a->name, b->name, a->len);
157 return ncp_strnicmp(NCP_IO_TABLE(dentry), a->name, b->name, a->len);
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.
165 static int
166 ncp_delete_dentry(struct dentry * dentry)
168 struct inode *inode = dentry->d_inode;
170 if (inode) {
171 if (is_bad_inode(inode))
172 return 1;
173 } else
175 /* N.B. Unhash negative dentries? */
177 return 0;
180 static inline int
181 ncp_single_volume(struct ncp_server *server)
183 return (server->m.mounted_vol[0] != '\0');
186 static inline int ncp_is_server_root(struct inode *inode)
188 return (!ncp_single_volume(NCP_SERVER(inode)) &&
189 inode == inode->i_sb->s_root->d_inode);
194 * This is the callback when the dcache has a lookup hit.
198 #ifdef CONFIG_NCPFS_STRONG
199 /* try to delete a readonly file (NW R bit set) */
201 static int
202 ncp_force_unlink(struct inode *dir, struct dentry* dentry)
204 int res=0x9c,res2;
205 struct nw_modify_dos_info info;
206 __le32 old_nwattr;
207 struct inode *inode;
209 memset(&info, 0, sizeof(info));
211 /* remove the Read-Only flag on the NW server */
212 inode = dentry->d_inode;
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;
220 /* now try again the delete operation */
221 res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
223 if (res) /* delete failed, set R bit again */
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;
230 leave_me:
231 return(res);
233 #endif /* CONFIG_NCPFS_STRONG */
235 #ifdef CONFIG_NCPFS_STRONG
236 static int
237 ncp_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)
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;
248 memset(&info, 0, sizeof(info));
250 /* remove the Read-Only flag on the NW server */
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;
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);
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;
279 leave_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 */
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 */
290 return(res);
292 #endif /* CONFIG_NCPFS_STRONG */
295 static int
296 ncp_lookup_validate(struct dentry *dentry, struct nameidata *nd)
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];
305 parent = dget_parent(dentry);
306 dir = parent->d_inode;
308 if (!dentry->d_inode)
309 goto finished;
311 server = NCP_SERVER(dir);
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.)
319 val = NCP_TEST_AGE(server, dentry);
320 if (val)
321 goto finished;
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));
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);
331 if (!res) {
332 res = ncp_lookup_volume(server, __name, &(finfo.i));
333 if (!res)
334 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
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));
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);
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.
349 if (!res) {
350 struct inode *inode = dentry->d_inode;
352 mutex_lock(&inode->i_mutex);
353 if (finfo.i.dirEntNum == NCP_FINFO(inode)->dirEntNum) {
354 ncp_new_dentry(dentry);
355 val=1;
356 } else
357 DDPRINTK("ncp_lookup_validate: found, but dirEntNum changed\n");
359 ncp_update_inode2(inode, &finfo);
360 mutex_unlock(&inode->i_mutex);
363 finished:
364 DDPRINTK("ncp_lookup_validate: result=%d\n", val);
365 dput(parent);
366 return val;
369 static struct dentry *
370 ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
372 struct dentry *dent = dentry;
373 struct list_head *next;
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;
382 return dent;
384 dput(dent);
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) {
391 dent = list_entry(next, struct dentry, d_u.d_child);
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;
400 next = next->next;
402 spin_unlock(&dcache_lock);
403 return NULL;
405 out:
406 return dent;
409 static time_t ncp_obtain_mtime(struct dentry *dentry)
411 struct inode *inode = dentry->d_inode;
412 struct ncp_server *server = NCP_SERVER(inode);
413 struct nw_info_struct i;
415 if (!ncp_conn_valid(server) || ncp_is_server_root(inode))
416 return 0;
418 if (ncp_obtain_info(server, inode, NULL, &i))
419 return 0;
421 return ncp_date_dos2unix(i.modifyTime, i.modifyDate);
424 static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
426 struct dentry *dentry = filp->f_path.dentry;
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;
435 ctl.page = NULL;
436 ctl.cache = NULL;
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);
442 result = -EIO;
443 /* Do not generate '.' and '..' when server is dead. */
444 if (!ncp_conn_valid(server))
445 goto out;
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;
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;
459 page = grab_cache_page(&inode->i_data, 0);
460 if (!page)
461 goto read_really;
463 ctl.cache = cache = kmap(page);
464 ctl.head = cache->head;
466 if (!PageUptodate(page) || !ctl.head.eof)
467 goto init_cache;
469 if (filp->f_pos == 2) {
470 if (jiffies - ctl.head.time >= NCP_MAX_AGE(server))
471 goto init_cache;
473 mtime = ncp_obtain_mtime(dentry);
474 mtime_valid = 1;
475 if ((!mtime) || (mtime != ctl.head.mtime))
476 goto init_cache;
479 if (filp->f_pos > ctl.head.end)
480 goto finished;
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;
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;
495 while (ctl.idx < NCP_DIRCACHE_SIZE) {
496 struct dentry *dent;
497 int res;
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;
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;
521 ctl.idx = 0;
522 ctl.ofs += 1;
524 invalid_cache:
525 if (ctl.page) {
526 kunmap(ctl.page);
527 unlock_page(ctl.page);
528 page_cache_release(ctl.page);
529 ctl.page = NULL;
531 ctl.cache = cache;
532 init_cache:
533 ncp_invalidate_dircache_entries(dentry);
534 if (!mtime_valid) {
535 mtime = ncp_obtain_mtime(dentry);
536 mtime_valid = 1;
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;
546 read_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);
552 ctl.head.end = ctl.fpos - 1;
553 ctl.head.eof = ctl.valid;
554 finished:
555 if (ctl.page) {
556 kunmap(ctl.page);
557 SetPageUptodate(ctl.page);
558 unlock_page(ctl.page);
559 page_cache_release(ctl.page);
561 if (page) {
562 cache->head = ctl.head;
563 kunmap(page);
564 SetPageUptodate(page);
565 unlock_page(page);
566 page_cache_release(page);
568 out:
569 return result;
572 static int
573 ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
574 struct ncp_cache_control *ctrl, struct ncp_entry_info *entry,
575 int inval_childs)
577 struct dentry *newdent, *dentry = filp->f_path.dentry;
578 struct inode *dir = dentry->d_inode;
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];
586 qname.len = sizeof(__name);
587 if (ncp_vol2io(NCP_SERVER(dir), __name, &qname.len,
588 entry->i.entryName, entry->i.nameLen,
589 !ncp_preserve_entry_case(dir, entry->i.NSCreator)))
590 return 1; /* I'm not sure */
592 qname.name = __name;
593 qname.hash = full_name_hash(qname.name, qname.len);
595 if (dentry->d_op && dentry->d_op->d_hash)
596 if (dentry->d_op->d_hash(dentry, &qname) != 0)
597 goto end_advance;
599 newdent = d_lookup(dentry, &qname);
601 if (!newdent) {
602 newdent = d_alloc(dentry, &qname);
603 if (!newdent)
604 goto end_advance;
605 } else {
606 hashed = 1;
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);
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.
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;
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.
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);
646 if (!newdent->d_inode) {
647 struct inode *inode;
649 entry->opened = 0;
650 entry->ino = iunique(dir->i_sb, 2);
651 inode = ncp_iget(dir->i_sb, entry);
652 if (inode) {
653 newdent->d_op = &ncp_dentry_operations;
654 d_instantiate(newdent, inode);
655 if (!hashed)
656 d_rehash(newdent);
658 } else {
659 struct inode *inode = newdent->d_inode;
661 mutex_lock(&inode->i_mutex);
662 ncp_update_inode2(inode, entry);
663 mutex_unlock(&inode->i_mutex);
666 if (newdent->d_inode) {
667 ino = newdent->d_inode->i_ino;
668 newdent->d_fsdata = (void *) ctl.fpos;
669 ncp_new_dentry(newdent);
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);
679 ctl.cache = NULL;
680 ctl.idx -= NCP_DIRCACHE_SIZE;
681 ctl.ofs += 1;
682 ctl.page = grab_cache_page(&dir->i_data, ctl.ofs);
683 if (ctl.page)
684 ctl.cache = kmap(ctl.page);
686 if (ctl.cache) {
687 ctl.cache->dentry[ctl.idx] = newdent;
688 valid = 1;
690 dput(newdent);
691 end_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)
698 ino = iunique(dir->i_sb, 2);
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;
704 ctl.fpos += 1;
705 ctl.idx += 1;
706 *ctrl = ctl;
707 return (ctl.valid || !ctl.filled);
710 static void
711 ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir,
712 struct ncp_cache_control *ctl)
714 struct dentry *dentry = filp->f_path.dentry;
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;
721 DPRINTK("ncp_read_volume_list: pos=%ld\n",
722 (unsigned long) filp->f_pos);
724 for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
725 int inval_dentry;
727 if (ncp_get_volume_info_with_number(server, i, &info) != 0)
728 return;
729 if (!strlen(info.volume_name))
730 continue;
732 DPRINTK("ncp_read_volume_list: found vol: %s\n",
733 info.volume_name);
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;
741 inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL);
742 entry.volume = entry.i.volNumber;
743 if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry, inval_dentry))
744 return;
748 static void
749 ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir,
750 struct ncp_cache_control *ctl)
752 struct dentry *dentry = filp->f_path.dentry;
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;
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);
769 err = ncp_initialize_search(server, dir, &seq);
770 if (err) {
771 DPRINTK("ncp_do_readdir: init failed, err=%d\n", err);
772 return;
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;
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;
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;
806 if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry, 0))
807 break;
809 } while (more);
810 vfree(buf);
811 return;
814 int ncp_conn_logged_in(struct super_block *sb)
816 struct ncp_server* server = NCP_SBP(sb);
817 int result;
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];
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;
838 dent = sb->s_root;
839 if (dent) {
840 struct inode* ino = dent->d_inode;
841 if (ino) {
842 ncp_update_known_namespace(server, volNumber, NULL);
843 NCP_FINFO(ino)->volNumber = volNumber;
844 NCP_FINFO(ino)->dirEntNum = dirEntNum;
845 NCP_FINFO(ino)->DosDirNum = DosDirNum;
846 result = 0;
847 } else {
848 DPRINTK("ncpfs: sb->s_root->d_inode == NULL!\n");
850 } else {
851 DPRINTK("ncpfs: sb->s_root == NULL!\n");
853 } else
854 result = 0;
856 out:
857 return result;
860 static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
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];
868 error = -EIO;
869 if (!ncp_conn_valid(server))
870 goto finished;
872 PPRINTK("ncp_lookup: server lookup for %s/%s\n",
873 dentry->d_parent->d_name.name, dentry->d_name.name);
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));
881 if (!res)
882 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
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));
889 PPRINTK("ncp_lookup: looked for %s/%s, res=%d\n",
890 dentry->d_parent->d_name.name, __name, res);
892 * If we didn't find an entry, make a negative dentry.
894 if (res)
895 goto add_entry;
898 * Create an inode for the entry.
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);
906 if (inode) {
907 ncp_new_dentry(dentry);
908 add_entry:
909 dentry->d_op = &ncp_dentry_operations;
910 d_add(dentry, inode);
911 error = 0;
914 finished:
915 PPRINTK("ncp_lookup: result=%d\n", error);
916 return ERR_PTR(error);
920 * This code is common to create, mkdir, and mknod.
922 static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
923 struct ncp_entry_info *finfo)
925 struct inode *inode;
926 int error = -EINVAL;
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;
934 out:
935 return error;
937 out_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;
944 int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
945 dev_t rdev, __le32 attributes)
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];
953 PPRINTK("ncp_create_new: creating %s/%s, mode=%x\n",
954 dentry->d_parent->d_name.name, dentry->d_name.name, mode);
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;
963 error = -EACCES;
965 if (S_ISREG(mode) &&
966 (server->m.flags & NCP_MOUNT_EXTRAS) &&
967 (mode & S_IXUGO))
968 attributes |= aSYSTEM | aSHARED;
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;
981 else if (result < 0)
982 error = result;
983 DPRINTK("ncp_create: %s/%s failed\n",
984 dentry->d_parent->d_name.name, dentry->d_name.name);
985 goto out;
987 opmode = O_WRONLY;
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;
999 error = ncp_instantiate(dir, dentry, &finfo);
1000 out:
1001 return error;
1004 static int ncp_create(struct inode *dir, struct dentry *dentry, int mode,
1005 struct nameidata *nd)
1007 return ncp_create_new(dir, dentry, mode, 0, 0);
1010 static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
1012 struct ncp_entry_info finfo;
1013 struct ncp_server *server = NCP_SERVER(dir);
1014 int error, len;
1015 __u8 __name[NCP_MAXPATHLEN + 1];
1017 DPRINTK("ncp_mkdir: making %s/%s\n",
1018 dentry->d_parent->d_name.name, dentry->d_name.name);
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;
1027 error = ncp_open_create_file_or_subdir(server, dir, __name,
1028 OC_MODE_CREATE, aDIR,
1029 cpu_to_le16(0xffff),
1030 &finfo);
1031 if (error == 0) {
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;
1041 error = ncp_instantiate(dir, dentry, &finfo);
1042 } else if (error > 0) {
1043 error = -EACCES;
1045 out:
1046 return error;
1049 static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
1051 struct ncp_server *server = NCP_SERVER(dir);
1052 int error, result, len;
1053 __u8 __name[NCP_MAXPATHLEN + 1];
1055 DPRINTK("ncp_rmdir: removing %s/%s\n",
1056 dentry->d_parent->d_name.name, dentry->d_name.name);
1058 error = -EBUSY;
1059 if (!d_unhashed(dentry))
1060 goto out;
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;
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:
1091 error = result < 0 ? result : -EACCES;
1092 break;
1094 out:
1095 return error;
1098 static int ncp_unlink(struct inode *dir, struct dentry *dentry)
1100 struct inode *inode = dentry->d_inode;
1101 struct ncp_server *server;
1102 int error;
1104 server = NCP_SERVER(dir);
1105 DPRINTK("ncp_unlink: unlinking %s/%s\n",
1106 dentry->d_parent->d_name.name, dentry->d_name.name);
1109 * Check whether to close the file ...
1111 if (inode) {
1112 PPRINTK("ncp_unlink: closing file\n");
1113 ncp_make_closed(inode);
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);
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:
1146 error = error < 0 ? error : -EACCES;
1147 break;
1149 return error;
1152 static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
1153 struct inode *new_dir, struct dentry *new_dentry)
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];
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);
1164 ncp_age_dentry(server, old_dentry);
1165 ncp_age_dentry(server, new_dentry);
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;
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;
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);
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:
1202 error = error < 0 ? error : -EACCES;
1203 break;
1205 out:
1206 return error;
1209 static int ncp_mknod(struct inode * dir, struct dentry *dentry,
1210 int mode, dev_t rdev)
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);
1218 return -EPERM; /* Strange, but true */
1221 /* The following routines are taken directly from msdos-fs */
1223 /* Linear day numbers of the respective 1sts in non-leap years. */
1225 static 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 */
1230 extern struct timezone sys_tz;
1232 static int utc2local(int time)
1234 return time - sys_tz.tz_minuteswest * 60;
1237 static int local2utc(int time)
1239 return time + sys_tz.tz_minuteswest * 60;
1242 /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
1244 ncp_date_dos2unix(__le16 t, __le16 d)
1246 unsigned short time = le16_to_cpu(t), date = le16_to_cpu(d);
1247 int month, year, secs;
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);
1261 /* Convert linear UNIX date to a MS-DOS time/date pair. */
1262 void
1263 ncp_date_unix2dos(int unix_date, __le16 *time, __le16 *date)
1265 int day, year, nl_day, month;
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;
1281 for (month = 1; month < 12; month++)
1282 if (day_n[month] > nl_day)
1283 break;
1285 *date = cpu_to_le16(nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));