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