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