blob: f22b12e7d337c37abc957ee2b4c2b204f52206b1 [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 *);
79static int ncp_delete_dentry(struct dentry *);
80
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
165ncp_delete_dentry(struct dentry * dentry)
166{
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 /*
614 * It is not as dangerous as it looks. NetWare's OS2 namespace is
615 * case preserving yet case insensitive. So we update dentry's name
616 * as received from server. We found dentry via d_lookup with our
617 * hash, so we know that hash does not change, and so replacing name
618 * should be reasonably safe.
619 */
620 if (qname.len == newdent->d_name.len &&
621 memcmp(newdent->d_name.name, qname.name, newdent->d_name.len)) {
622 struct inode *inode = newdent->d_inode;
623
624 /*
625 * Inside ncpfs all uses of d_name are either for debugging,
626 * or on functions which acquire inode mutex (mknod, creat,
627 * lookup). So grab i_mutex here, to be sure. d_path
628 * uses dcache_lock when generating path, so we should too.
629 * And finally d_compare is protected by dentry's d_lock, so
630 * here we go.
631 */
632 if (inode)
633 mutex_lock(&inode->i_mutex);
634 spin_lock(&dcache_lock);
635 spin_lock(&newdent->d_lock);
636 memcpy((char *) newdent->d_name.name, qname.name,
637 newdent->d_name.len);
638 spin_unlock(&newdent->d_lock);
639 spin_unlock(&dcache_lock);
640 if (inode)
641 mutex_unlock(&inode->i_mutex);
642 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 }
644
645 if (!newdent->d_inode) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200646 struct inode *inode;
647
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 entry->opened = 0;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200649 entry->ino = iunique(dir->i_sb, 2);
650 inode = ncp_iget(dir->i_sb, entry);
651 if (inode) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 newdent->d_op = &ncp_dentry_operations;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200653 d_instantiate(newdent, inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 if (!hashed)
655 d_rehash(newdent);
656 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200657 } else {
658 struct inode *inode = newdent->d_inode;
659
660 mutex_lock(&inode->i_mutex);
661 ncp_update_inode2(inode, entry);
662 mutex_unlock(&inode->i_mutex);
663 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
665 if (newdent->d_inode) {
666 ino = newdent->d_inode->i_ino;
667 newdent->d_fsdata = (void *) ctl.fpos;
668 ncp_new_dentry(newdent);
669 }
670
671 if (ctl.idx >= NCP_DIRCACHE_SIZE) {
672 if (ctl.page) {
673 kunmap(ctl.page);
674 SetPageUptodate(ctl.page);
675 unlock_page(ctl.page);
676 page_cache_release(ctl.page);
677 }
678 ctl.cache = NULL;
679 ctl.idx -= NCP_DIRCACHE_SIZE;
680 ctl.ofs += 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200681 ctl.page = grab_cache_page(&dir->i_data, ctl.ofs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 if (ctl.page)
683 ctl.cache = kmap(ctl.page);
684 }
685 if (ctl.cache) {
686 ctl.cache->dentry[ctl.idx] = newdent;
687 valid = 1;
688 }
689 dput(newdent);
690end_advance:
691 if (!valid)
692 ctl.valid = 0;
693 if (!ctl.filled && (ctl.fpos == filp->f_pos)) {
694 if (!ino)
695 ino = find_inode_number(dentry, &qname);
696 if (!ino)
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200697 ino = iunique(dir->i_sb, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 ctl.filled = filldir(dirent, qname.name, qname.len,
699 filp->f_pos, ino, DT_UNKNOWN);
700 if (!ctl.filled)
701 filp->f_pos += 1;
702 }
703 ctl.fpos += 1;
704 ctl.idx += 1;
705 *ctrl = ctl;
706 return (ctl.valid || !ctl.filled);
707}
708
709static void
710ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir,
711 struct ncp_cache_control *ctl)
712{
Josef Sipek92e5bae2006-12-08 02:37:22 -0800713 struct dentry *dentry = filp->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 struct inode *inode = dentry->d_inode;
715 struct ncp_server *server = NCP_SERVER(inode);
716 struct ncp_volume_info info;
717 struct ncp_entry_info entry;
718 int i;
719
720 DPRINTK("ncp_read_volume_list: pos=%ld\n",
721 (unsigned long) filp->f_pos);
722
723 for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200724 int inval_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725
726 if (ncp_get_volume_info_with_number(server, i, &info) != 0)
727 return;
728 if (!strlen(info.volume_name))
729 continue;
730
731 DPRINTK("ncp_read_volume_list: found vol: %s\n",
732 info.volume_name);
733
734 if (ncp_lookup_volume(server, info.volume_name,
735 &entry.i)) {
736 DPRINTK("ncpfs: could not lookup vol %s\n",
737 info.volume_name);
738 continue;
739 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200740 inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 entry.volume = entry.i.volNumber;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200742 if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry, inval_dentry))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 return;
744 }
745}
746
747static void
748ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir,
749 struct ncp_cache_control *ctl)
750{
Josef Sipek92e5bae2006-12-08 02:37:22 -0800751 struct dentry *dentry = filp->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 struct inode *dir = dentry->d_inode;
753 struct ncp_server *server = NCP_SERVER(dir);
754 struct nw_search_sequence seq;
755 struct ncp_entry_info entry;
756 int err;
757 void* buf;
758 int more;
759 size_t bufsize;
760
761 DPRINTK("ncp_do_readdir: %s/%s, fpos=%ld\n",
762 dentry->d_parent->d_name.name, dentry->d_name.name,
763 (unsigned long) filp->f_pos);
764 PPRINTK("ncp_do_readdir: init %s, volnum=%d, dirent=%u\n",
765 dentry->d_name.name, NCP_FINFO(dir)->volNumber,
766 NCP_FINFO(dir)->dirEntNum);
767
768 err = ncp_initialize_search(server, dir, &seq);
769 if (err) {
770 DPRINTK("ncp_do_readdir: init failed, err=%d\n", err);
771 return;
772 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 /* We MUST NOT use server->buffer_size handshaked with server if we are
774 using UDP, as for UDP server uses max. buffer size determined by
775 MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes).
776 So we use 128KB, just to be sure, as there is no way how to know
777 this value in advance. */
778 bufsize = 131072;
779 buf = vmalloc(bufsize);
780 if (!buf)
781 return;
782 do {
783 int cnt;
784 char* rpl;
785 size_t rpls;
786
787 err = ncp_search_for_fileset(server, &seq, &more, &cnt, buf, bufsize, &rpl, &rpls);
788 if (err) /* Error */
789 break;
790 if (!cnt) /* prevent endless loop */
791 break;
792 while (cnt--) {
793 size_t onerpl;
794
795 if (rpls < offsetof(struct nw_info_struct, entryName))
796 break; /* short packet */
797 ncp_extract_file_info(rpl, &entry.i);
798 onerpl = offsetof(struct nw_info_struct, entryName) + entry.i.nameLen;
799 if (rpls < onerpl)
800 break; /* short packet */
801 (void)ncp_obtain_nfs_info(server, &entry.i);
802 rpl += onerpl;
803 rpls -= onerpl;
804 entry.volume = entry.i.volNumber;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200805 if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry, 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 break;
807 }
808 } while (more);
809 vfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 return;
811}
812
813int ncp_conn_logged_in(struct super_block *sb)
814{
815 struct ncp_server* server = NCP_SBP(sb);
816 int result;
817
818 if (ncp_single_volume(server)) {
819 int len;
820 struct dentry* dent;
821 __u32 volNumber;
822 __le32 dirEntNum;
823 __le32 DosDirNum;
824 __u8 __name[NCP_MAXPATHLEN + 1];
825
826 len = sizeof(__name);
827 result = ncp_io2vol(server, __name, &len, server->m.mounted_vol,
828 strlen(server->m.mounted_vol), 1);
829 if (result)
830 goto out;
831 result = -ENOENT;
832 if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) {
833 PPRINTK("ncp_conn_logged_in: %s not found\n",
834 server->m.mounted_vol);
835 goto out;
836 }
837 dent = sb->s_root;
838 if (dent) {
839 struct inode* ino = dent->d_inode;
840 if (ino) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200841 ncp_update_known_namespace(server, volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 NCP_FINFO(ino)->volNumber = volNumber;
843 NCP_FINFO(ino)->dirEntNum = dirEntNum;
844 NCP_FINFO(ino)->DosDirNum = DosDirNum;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200845 result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 } else {
847 DPRINTK("ncpfs: sb->s_root->d_inode == NULL!\n");
848 }
849 } else {
850 DPRINTK("ncpfs: sb->s_root == NULL!\n");
851 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200852 } else
853 result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854
855out:
856 return result;
857}
858
859static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
860{
861 struct ncp_server *server = NCP_SERVER(dir);
862 struct inode *inode = NULL;
863 struct ncp_entry_info finfo;
864 int error, res, len;
865 __u8 __name[NCP_MAXPATHLEN + 1];
866
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 error = -EIO;
868 if (!ncp_conn_valid(server))
869 goto finished;
870
871 PPRINTK("ncp_lookup: server lookup for %s/%s\n",
872 dentry->d_parent->d_name.name, dentry->d_name.name);
873
874 len = sizeof(__name);
875 if (ncp_is_server_root(dir)) {
876 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
877 dentry->d_name.len, 1);
878 if (!res)
879 res = ncp_lookup_volume(server, __name, &(finfo.i));
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200880 if (!res)
881 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 } else {
883 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
884 dentry->d_name.len, !ncp_preserve_case(dir));
885 if (!res)
886 res = ncp_obtain_info(server, dir, __name, &(finfo.i));
887 }
888 PPRINTK("ncp_lookup: looked for %s/%s, res=%d\n",
889 dentry->d_parent->d_name.name, __name, res);
890 /*
891 * If we didn't find an entry, make a negative dentry.
892 */
893 if (res)
894 goto add_entry;
895
896 /*
897 * Create an inode for the entry.
898 */
899 finfo.opened = 0;
900 finfo.ino = iunique(dir->i_sb, 2);
901 finfo.volume = finfo.i.volNumber;
902 error = -EACCES;
903 inode = ncp_iget(dir->i_sb, &finfo);
904
905 if (inode) {
906 ncp_new_dentry(dentry);
907add_entry:
908 dentry->d_op = &ncp_dentry_operations;
909 d_add(dentry, inode);
910 error = 0;
911 }
912
913finished:
914 PPRINTK("ncp_lookup: result=%d\n", error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 return ERR_PTR(error);
916}
917
918/*
919 * This code is common to create, mkdir, and mknod.
920 */
921static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
922 struct ncp_entry_info *finfo)
923{
924 struct inode *inode;
925 int error = -EINVAL;
926
927 finfo->ino = iunique(dir->i_sb, 2);
928 inode = ncp_iget(dir->i_sb, finfo);
929 if (!inode)
930 goto out_close;
931 d_instantiate(dentry,inode);
932 error = 0;
933out:
934 return error;
935
936out_close:
937 PPRINTK("ncp_instantiate: %s/%s failed, closing file\n",
938 dentry->d_parent->d_name.name, dentry->d_name.name);
939 ncp_close_file(NCP_SERVER(dir), finfo->file_handle);
940 goto out;
941}
942
943int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
944 dev_t rdev, __le32 attributes)
945{
946 struct ncp_server *server = NCP_SERVER(dir);
947 struct ncp_entry_info finfo;
948 int error, result, len;
949 int opmode;
950 __u8 __name[NCP_MAXPATHLEN + 1];
951
952 PPRINTK("ncp_create_new: creating %s/%s, mode=%x\n",
953 dentry->d_parent->d_name.name, dentry->d_name.name, mode);
954
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 ncp_age_dentry(server, dentry);
956 len = sizeof(__name);
957 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
958 dentry->d_name.len, !ncp_preserve_case(dir));
959 if (error)
960 goto out;
961
962 error = -EACCES;
963
964 if (S_ISREG(mode) &&
965 (server->m.flags & NCP_MOUNT_EXTRAS) &&
966 (mode & S_IXUGO))
967 attributes |= aSYSTEM | aSHARED;
968
969 result = ncp_open_create_file_or_subdir(server, dir, __name,
970 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
971 attributes, AR_READ | AR_WRITE, &finfo);
972 opmode = O_RDWR;
973 if (result) {
974 result = ncp_open_create_file_or_subdir(server, dir, __name,
975 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
976 attributes, AR_WRITE, &finfo);
977 if (result) {
978 if (result == 0x87)
979 error = -ENAMETOOLONG;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200980 else if (result < 0)
981 error = result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 DPRINTK("ncp_create: %s/%s failed\n",
983 dentry->d_parent->d_name.name, dentry->d_name.name);
984 goto out;
985 }
986 opmode = O_WRONLY;
987 }
988 finfo.access = opmode;
989 if (ncp_is_nfs_extras(server, finfo.volume)) {
990 finfo.i.nfs.mode = mode;
991 finfo.i.nfs.rdev = new_encode_dev(rdev);
992 if (ncp_modify_nfs_info(server, finfo.volume,
993 finfo.i.dirEntNum,
994 mode, new_encode_dev(rdev)) != 0)
995 goto out;
996 }
997
998 error = ncp_instantiate(dir, dentry, &finfo);
999out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 return error;
1001}
1002
1003static int ncp_create(struct inode *dir, struct dentry *dentry, int mode,
1004 struct nameidata *nd)
1005{
1006 return ncp_create_new(dir, dentry, mode, 0, 0);
1007}
1008
1009static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
1010{
1011 struct ncp_entry_info finfo;
1012 struct ncp_server *server = NCP_SERVER(dir);
1013 int error, len;
1014 __u8 __name[NCP_MAXPATHLEN + 1];
1015
1016 DPRINTK("ncp_mkdir: making %s/%s\n",
1017 dentry->d_parent->d_name.name, dentry->d_name.name);
1018
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 ncp_age_dentry(server, dentry);
1020 len = sizeof(__name);
1021 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
1022 dentry->d_name.len, !ncp_preserve_case(dir));
1023 if (error)
1024 goto out;
1025
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001026 error = ncp_open_create_file_or_subdir(server, dir, __name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 OC_MODE_CREATE, aDIR,
1028 cpu_to_le16(0xffff),
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001029 &finfo);
1030 if (error == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 if (ncp_is_nfs_extras(server, finfo.volume)) {
1032 mode |= S_IFDIR;
1033 finfo.i.nfs.mode = mode;
1034 if (ncp_modify_nfs_info(server,
1035 finfo.volume,
1036 finfo.i.dirEntNum,
1037 mode, 0) != 0)
1038 goto out;
1039 }
1040 error = ncp_instantiate(dir, dentry, &finfo);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001041 } else if (error > 0) {
1042 error = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 }
1044out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 return error;
1046}
1047
1048static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
1049{
1050 struct ncp_server *server = NCP_SERVER(dir);
1051 int error, result, len;
1052 __u8 __name[NCP_MAXPATHLEN + 1];
1053
1054 DPRINTK("ncp_rmdir: removing %s/%s\n",
1055 dentry->d_parent->d_name.name, dentry->d_name.name);
1056
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 error = -EBUSY;
1058 if (!d_unhashed(dentry))
1059 goto out;
1060
1061 len = sizeof(__name);
1062 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
1063 dentry->d_name.len, !ncp_preserve_case(dir));
1064 if (error)
1065 goto out;
1066
1067 result = ncp_del_file_or_subdir(server, dir, __name);
1068 switch (result) {
1069 case 0x00:
1070 error = 0;
1071 break;
1072 case 0x85: /* unauthorized to delete file */
1073 case 0x8A: /* unauthorized to delete file */
1074 error = -EACCES;
1075 break;
1076 case 0x8F:
1077 case 0x90: /* read only */
1078 error = -EPERM;
1079 break;
1080 case 0x9F: /* in use by another client */
1081 error = -EBUSY;
1082 break;
1083 case 0xA0: /* directory not empty */
1084 error = -ENOTEMPTY;
1085 break;
1086 case 0xFF: /* someone deleted file */
1087 error = -ENOENT;
1088 break;
1089 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001090 error = result < 0 ? result : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 break;
1092 }
1093out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 return error;
1095}
1096
1097static int ncp_unlink(struct inode *dir, struct dentry *dentry)
1098{
1099 struct inode *inode = dentry->d_inode;
1100 struct ncp_server *server;
1101 int error;
1102
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 server = NCP_SERVER(dir);
1104 DPRINTK("ncp_unlink: unlinking %s/%s\n",
1105 dentry->d_parent->d_name.name, dentry->d_name.name);
1106
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 /*
1108 * Check whether to close the file ...
1109 */
1110 if (inode) {
1111 PPRINTK("ncp_unlink: closing file\n");
1112 ncp_make_closed(inode);
1113 }
1114
1115 error = ncp_del_file_or_subdir2(server, dentry);
1116#ifdef CONFIG_NCPFS_STRONG
1117 /* 9C is Invalid path.. It should be 8F, 90 - read only, but
1118 it is not :-( */
1119 if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */
1120 error = ncp_force_unlink(dir, dentry);
1121 }
1122#endif
1123 switch (error) {
1124 case 0x00:
1125 DPRINTK("ncp: removed %s/%s\n",
1126 dentry->d_parent->d_name.name, dentry->d_name.name);
1127 break;
1128 case 0x85:
1129 case 0x8A:
1130 error = -EACCES;
1131 break;
1132 case 0x8D: /* some files in use */
1133 case 0x8E: /* all files in use */
1134 error = -EBUSY;
1135 break;
1136 case 0x8F: /* some read only */
1137 case 0x90: /* all read only */
1138 case 0x9C: /* !!! returned when in-use or read-only by NW4 */
1139 error = -EPERM;
1140 break;
1141 case 0xFF:
1142 error = -ENOENT;
1143 break;
1144 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001145 error = error < 0 ? error : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 break;
1147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 return error;
1149}
1150
1151static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
1152 struct inode *new_dir, struct dentry *new_dentry)
1153{
1154 struct ncp_server *server = NCP_SERVER(old_dir);
1155 int error;
1156 int old_len, new_len;
1157 __u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1];
1158
1159 DPRINTK("ncp_rename: %s/%s to %s/%s\n",
1160 old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
1161 new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
1162
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 ncp_age_dentry(server, old_dentry);
1164 ncp_age_dentry(server, new_dentry);
1165
1166 old_len = sizeof(__old_name);
1167 error = ncp_io2vol(server, __old_name, &old_len,
1168 old_dentry->d_name.name, old_dentry->d_name.len,
1169 !ncp_preserve_case(old_dir));
1170 if (error)
1171 goto out;
1172
1173 new_len = sizeof(__new_name);
1174 error = ncp_io2vol(server, __new_name, &new_len,
1175 new_dentry->d_name.name, new_dentry->d_name.len,
1176 !ncp_preserve_case(new_dir));
1177 if (error)
1178 goto out;
1179
1180 error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name,
1181 new_dir, __new_name);
1182#ifdef CONFIG_NCPFS_STRONG
1183 if ((error == 0x90 || error == 0x8B || error == -EACCES) &&
1184 server->m.flags & NCP_MOUNT_STRONG) { /* RO */
1185 error = ncp_force_rename(old_dir, old_dentry, __old_name,
1186 new_dir, new_dentry, __new_name);
1187 }
1188#endif
1189 switch (error) {
1190 case 0x00:
1191 DPRINTK("ncp renamed %s -> %s.\n",
1192 old_dentry->d_name.name,new_dentry->d_name.name);
1193 break;
1194 case 0x9E:
1195 error = -ENAMETOOLONG;
1196 break;
1197 case 0xFF:
1198 error = -ENOENT;
1199 break;
1200 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001201 error = error < 0 ? error : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 break;
1203 }
1204out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 return error;
1206}
1207
1208static int ncp_mknod(struct inode * dir, struct dentry *dentry,
1209 int mode, dev_t rdev)
1210{
1211 if (!new_valid_dev(rdev))
1212 return -EINVAL;
1213 if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) {
1214 DPRINTK(KERN_DEBUG "ncp_mknod: mode = 0%o\n", mode);
1215 return ncp_create_new(dir, dentry, mode, rdev, 0);
1216 }
1217 return -EPERM; /* Strange, but true */
1218}
1219
1220/* The following routines are taken directly from msdos-fs */
1221
1222/* Linear day numbers of the respective 1sts in non-leap years. */
1223
1224static int day_n[] =
1225{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
1226/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
1227
1228
1229extern struct timezone sys_tz;
1230
1231static int utc2local(int time)
1232{
1233 return time - sys_tz.tz_minuteswest * 60;
1234}
1235
1236static int local2utc(int time)
1237{
1238 return time + sys_tz.tz_minuteswest * 60;
1239}
1240
1241/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
1242int
1243ncp_date_dos2unix(__le16 t, __le16 d)
1244{
1245 unsigned short time = le16_to_cpu(t), date = le16_to_cpu(d);
1246 int month, year, secs;
1247
1248 /* first subtract and mask after that... Otherwise, if
1249 date == 0, bad things happen */
1250 month = ((date >> 5) - 1) & 15;
1251 year = date >> 9;
1252 secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
1253 86400 * ((date & 31) - 1 + day_n[month] + (year / 4) +
1254 year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
1255 /* days since 1.1.70 plus 80's leap day */
1256 return local2utc(secs);
1257}
1258
1259
1260/* Convert linear UNIX date to a MS-DOS time/date pair. */
1261void
1262ncp_date_unix2dos(int unix_date, __le16 *time, __le16 *date)
1263{
1264 int day, year, nl_day, month;
1265
1266 unix_date = utc2local(unix_date);
1267 *time = cpu_to_le16(
1268 (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
1269 (((unix_date / 3600) % 24) << 11));
1270 day = unix_date / 86400 - 3652;
1271 year = day / 365;
1272 if ((year + 3) / 4 + 365 * year > day)
1273 year--;
1274 day -= (year + 3) / 4 + 365 * year;
1275 if (day == 59 && !(year & 3)) {
1276 nl_day = day;
1277 month = 2;
1278 } else {
1279 nl_day = (year & 3) || day <= 59 ? day : day - 1;
Roel Kluinc5df5912009-09-22 16:45:54 -07001280 for (month = 1; month < 12; month++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 if (day_n[month] > nl_day)
1282 break;
1283 }
1284 *date = cpu_to_le16(nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
1285}