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