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