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