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