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