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