blob: 102278ed38bd01715c674254c3b35e91abf5e00e [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>
20#include <asm/uaccess.h>
21#include <asm/byteorder.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
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
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -080049const struct file_operations ncp_dir_operations =
Linus Torvalds1da177e2005-04-16 15:20:36 -070050{
jan Blunckca572722010-05-26 14:44:53 -070051 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 .read = generic_read_dir,
53 .readdir = ncp_readdir,
John Kacur93d84b62010-05-05 15:15:37 +020054 .unlocked_ioctl = ncp_ioctl,
Petr Vandrovec54f67f62006-09-30 23:27:55 -070055#ifdef CONFIG_COMPAT
56 .compat_ioctl = ncp_compat_ioctl,
57#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070058};
59
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -080060const struct inode_operations ncp_dir_inode_operations =
Linus Torvalds1da177e2005-04-16 15:20:36 -070061{
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 *);
Nick Pigginb1e6a012011-01-07 17:49:28 +110077static int ncp_hash_dentry(const struct dentry *, const struct inode *,
78 struct qstr *);
Nick Piggin621e1552011-01-07 17:49:27 +110079static 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 *);
Nick Pigginfe15ce42011-01-07 17:49:23 +110082static int ncp_delete_dentry(const struct dentry *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
Al Viroe16404e2009-02-20 05:55:13 +000084static const struct dentry_operations ncp_dentry_operations =
Linus Torvalds1da177e2005-04-16 15:20:36 -070085{
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
Al Viroe16404e2009-02-20 05:55:13 +000092const struct dentry_operations ncp_root_dentry_operations =
Linus Torvalds1da177e2005-04-16 15:20:36 -070093{
94 .d_hash = ncp_hash_dentry,
95 .d_compare = ncp_compare_dentry,
96 .d_delete = ncp_delete_dentry,
97};
98
99
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200100#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
Nick Piggin621e1552011-01-07 17:49:27 +1100119static inline int ncp_case_sensitive(const struct inode *i)
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200120{
121#ifdef CONFIG_NCPFS_NFS_NS
Nick Piggin621e1552011-01-07 17:49:27 +1100122 return ncp_namespace(i) == NW_NS_NFS;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200123#else
124 return 0;
125#endif /* CONFIG_NCPFS_NFS_NS */
126}
127
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128/*
129 * Note: leave the hash unchanged if the directory
130 * is case-sensitive.
131 */
132static int
Nick Pigginb1e6a012011-01-07 17:49:28 +1100133ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode,
134 struct qstr *this)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135{
Nick Pigginb1e6a012011-01-07 17:49:28 +1100136 if (!ncp_case_sensitive(inode)) {
Nick Piggin621e1552011-01-07 17:49:27 +1100137 struct super_block *sb = dentry->d_sb;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200138 struct nls_table *t;
139 unsigned long hash;
140 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
Nick Piggin621e1552011-01-07 17:49:27 +1100142 t = NCP_IO_TABLE(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 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
Nick Piggin621e1552011-01-07 17:49:27 +1100153ncp_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)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156{
Nick Piggin621e1552011-01-07 17:49:27 +1100157 if (len != name->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 return 1;
159
Nick Piggin621e1552011-01-07 17:49:27 +1100160 if (ncp_case_sensitive(pinode))
161 return strncmp(str, name->name, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
Nick Piggin621e1552011-01-07 17:49:27 +1100163 return ncp_strnicmp(NCP_IO_TABLE(pinode->i_sb), str, name->name, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164}
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
Nick Pigginfe15ce42011-01-07 17:49:23 +1100172ncp_delete_dentry(const struct dentry * dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173{
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
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200302ncp_lookup_validate(struct dentry *dentry, struct nameidata *nd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 /*
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);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200337 if (!res) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 res = ncp_lookup_volume(server, __name, &(finfo.i));
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200339 if (!res)
340 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
341 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 } 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) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200356 struct inode *inode = dentry->d_inode;
357
358 mutex_lock(&inode->i_mutex);
359 if (finfo.i.dirEntNum == NCP_FINFO(inode)->dirEntNum) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 ncp_new_dentry(dentry);
361 val=1;
362 } else
363 DDPRINTK("ncp_lookup_validate: found, but dirEntNum changed\n");
364
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200365 ncp_update_inode2(inode, &finfo);
366 mutex_unlock(&inode->i_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 }
368
369finished:
370 DDPRINTK("ncp_lookup_validate: result=%d\n", val);
371 dput(parent);
372 return val;
373}
374
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375static 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);
Nick Piggin2fd6b7f2011-01-07 17:49:34 +1100395 spin_lock(&parent->d_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 next = parent->d_subdirs.next;
397 while (next != &parent->d_subdirs) {
Eric Dumazet5160ee62006-01-08 01:03:32 -0800398 dent = list_entry(next, struct dentry, d_u.d_child);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 if ((unsigned long)dent->d_fsdata == fpos) {
400 if (dent->d_inode)
401 dget_locked(dent);
402 else
403 dent = NULL;
Nick Piggin2fd6b7f2011-01-07 17:49:34 +1100404 spin_unlock(&parent->d_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 spin_unlock(&dcache_lock);
406 goto out;
407 }
408 next = next->next;
409 }
Nick Piggin2fd6b7f2011-01-07 17:49:34 +1100410 spin_unlock(&parent->d_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 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{
Josef Sipek92e5bae2006-12-08 02:37:22 -0800435 struct dentry *dentry = filp->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 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;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200452 /* Do not generate '.' and '..' when server is dead. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 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:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200564 if (ctl.page) {
565 kunmap(ctl.page);
566 SetPageUptodate(ctl.page);
567 unlock_page(ctl.page);
568 page_cache_release(ctl.page);
569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 if (page) {
571 cache->head = ctl.head;
572 kunmap(page);
573 SetPageUptodate(page);
574 unlock_page(page);
575 page_cache_release(page);
576 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 return result;
579}
580
581static int
582ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200583 struct ncp_cache_control *ctrl, struct ncp_entry_info *entry,
584 int inval_childs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585{
Josef Sipek92e5bae2006-12-08 02:37:22 -0800586 struct dentry *newdent, *dentry = filp->f_path.dentry;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200587 struct inode *dir = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 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);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200596 if (ncp_vol2io(NCP_SERVER(dir), __name, &qname.len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 entry->i.entryName, entry->i.nameLen,
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200598 !ncp_preserve_entry_case(dir, entry->i.NSCreator)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 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)
Nick Pigginb1e6a012011-01-07 17:49:28 +1100605 if (dentry->d_op->d_hash(dentry, dentry->d_inode, &qname) != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 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;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200616
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 /*
Nick Pigginfb2d5b82011-01-07 17:49:26 +1100624 * 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.
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200628 */
Nick Pigginfb2d5b82011-01-07 17:49:26 +1100629 dentry_update_name_case(newdent, &qname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 }
631
632 if (!newdent->d_inode) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200633 struct inode *inode;
634
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 entry->opened = 0;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200636 entry->ino = iunique(dir->i_sb, 2);
637 inode = ncp_iget(dir->i_sb, entry);
638 if (inode) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 newdent->d_op = &ncp_dentry_operations;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200640 d_instantiate(newdent, inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 if (!hashed)
642 d_rehash(newdent);
643 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200644 } else {
645 struct inode *inode = newdent->d_inode;
646
Nick Pigginfb2d5b82011-01-07 17:49:26 +1100647 mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200648 ncp_update_inode2(inode, entry);
649 mutex_unlock(&inode->i_mutex);
650 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
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;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200668 ctl.page = grab_cache_page(&dir->i_data, ctl.ofs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 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)
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200684 ino = iunique(dir->i_sb, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 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{
Josef Sipek92e5bae2006-12-08 02:37:22 -0800700 struct dentry *dentry = filp->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 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++) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200711 int inval_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712
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 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200727 inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 entry.volume = entry.i.volNumber;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200729 if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry, inval_dentry))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 return;
731 }
732}
733
734static void
735ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir,
736 struct ncp_cache_control *ctl)
737{
Josef Sipek92e5bae2006-12-08 02:37:22 -0800738 struct dentry *dentry = filp->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 /* 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;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200792 if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry, 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 break;
794 }
795 } while (more);
796 vfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 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) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200828 ncp_update_known_namespace(server, volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 NCP_FINFO(ino)->volNumber = volNumber;
830 NCP_FINFO(ino)->dirEntNum = dirEntNum;
831 NCP_FINFO(ino)->DosDirNum = DosDirNum;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200832 result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 } else {
834 DPRINTK("ncpfs: sb->s_root->d_inode == NULL!\n");
835 }
836 } else {
837 DPRINTK("ncpfs: sb->s_root == NULL!\n");
838 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200839 } else
840 result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841
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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 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));
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200867 if (!res)
868 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 } 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 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;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200967 else if (result < 0)
968 error = result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 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:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 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
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 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
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001013 error = ncp_open_create_file_or_subdir(server, dir, __name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 OC_MODE_CREATE, aDIR,
1015 cpu_to_le16(0xffff),
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001016 &finfo);
1017 if (error == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 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);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001028 } else if (error > 0) {
1029 error = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 }
1031out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 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
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 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:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001077 error = result < 0 ? result : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 break;
1079 }
1080out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 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
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 server = NCP_SERVER(dir);
1091 DPRINTK("ncp_unlink: unlinking %s/%s\n",
1092 dentry->d_parent->d_name.name, dentry->d_name.name);
1093
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 /*
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:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001132 error = error < 0 ? error : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 break;
1134 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 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
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 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:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001188 error = error < 0 ? error : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 break;
1190 }
1191out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 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;
Roel Kluinc5df5912009-09-22 16:45:54 -07001267 for (month = 1; month < 12; month++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 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}