blob: 0e7f00298213f3249b34f8564609c762d2e765ed [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
Al Viro76f582a2013-05-22 15:11:27 -040026static void ncp_read_volume_list(struct file *, struct dir_context *,
Linus Torvalds1da177e2005-04-16 15:20:36 -070027 struct ncp_cache_control *);
Al Viro76f582a2013-05-22 15:11:27 -040028static void ncp_do_readdir(struct file *, struct dir_context *,
Linus Torvalds1da177e2005-04-16 15:20:36 -070029 struct ncp_cache_control *);
30
Al Viro76f582a2013-05-22 15:11:27 -040031static int ncp_readdir(struct file *, struct dir_context *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
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,
Al Viro76f582a2013-05-22 15:11:27 -040052 .iterate = 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
Al Viro76f582a2013-05-22 15:11:27 -0400427static int ncp_readdir(struct file *file, struct dir_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428{
Al Viro76f582a2013-05-22 15:11:27 -0400429 struct dentry *dentry = file->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,
Al Viro76f582a2013-05-22 15:11:27 -0400443 (int) ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444
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;
Al Viro76f582a2013-05-22 15:11:27 -0400451 if (!dir_emit_dots(file, ctx))
452 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453
454 page = grab_cache_page(&inode->i_data, 0);
455 if (!page)
456 goto read_really;
457
458 ctl.cache = cache = kmap(page);
459 ctl.head = cache->head;
460
461 if (!PageUptodate(page) || !ctl.head.eof)
462 goto init_cache;
463
Al Viro76f582a2013-05-22 15:11:27 -0400464 if (ctx->pos == 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 if (jiffies - ctl.head.time >= NCP_MAX_AGE(server))
466 goto init_cache;
467
468 mtime = ncp_obtain_mtime(dentry);
469 mtime_valid = 1;
470 if ((!mtime) || (mtime != ctl.head.mtime))
471 goto init_cache;
472 }
473
Al Viro76f582a2013-05-22 15:11:27 -0400474 if (ctx->pos > ctl.head.end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 goto finished;
476
Al Viro76f582a2013-05-22 15:11:27 -0400477 ctl.fpos = ctx->pos + (NCP_DIRCACHE_START - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 ctl.ofs = ctl.fpos / NCP_DIRCACHE_SIZE;
479 ctl.idx = ctl.fpos % NCP_DIRCACHE_SIZE;
480
481 for (;;) {
482 if (ctl.ofs != 0) {
483 ctl.page = find_lock_page(&inode->i_data, ctl.ofs);
484 if (!ctl.page)
485 goto invalid_cache;
486 ctl.cache = kmap(ctl.page);
487 if (!PageUptodate(ctl.page))
488 goto invalid_cache;
489 }
490 while (ctl.idx < NCP_DIRCACHE_SIZE) {
491 struct dentry *dent;
Al Viro76f582a2013-05-22 15:11:27 -0400492 bool over;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493
494 dent = ncp_dget_fpos(ctl.cache->dentry[ctl.idx],
Al Viro76f582a2013-05-22 15:11:27 -0400495 dentry, ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 if (!dent)
497 goto invalid_cache;
Al Viro76f582a2013-05-22 15:11:27 -0400498 over = !dir_emit(ctx, dent->d_name.name,
499 dent->d_name.len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 dent->d_inode->i_ino, DT_UNKNOWN);
501 dput(dent);
Al Viro76f582a2013-05-22 15:11:27 -0400502 if (over)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 goto finished;
Al Viro76f582a2013-05-22 15:11:27 -0400504 ctx->pos += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 ctl.idx += 1;
Al Viro76f582a2013-05-22 15:11:27 -0400506 if (ctx->pos > ctl.head.end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 goto finished;
508 }
509 if (ctl.page) {
510 kunmap(ctl.page);
511 SetPageUptodate(ctl.page);
512 unlock_page(ctl.page);
513 page_cache_release(ctl.page);
514 ctl.page = NULL;
515 }
516 ctl.idx = 0;
517 ctl.ofs += 1;
518 }
519invalid_cache:
520 if (ctl.page) {
521 kunmap(ctl.page);
522 unlock_page(ctl.page);
523 page_cache_release(ctl.page);
524 ctl.page = NULL;
525 }
526 ctl.cache = cache;
527init_cache:
528 ncp_invalidate_dircache_entries(dentry);
529 if (!mtime_valid) {
530 mtime = ncp_obtain_mtime(dentry);
531 mtime_valid = 1;
532 }
533 ctl.head.mtime = mtime;
534 ctl.head.time = jiffies;
535 ctl.head.eof = 0;
536 ctl.fpos = 2;
537 ctl.ofs = 0;
538 ctl.idx = NCP_DIRCACHE_START;
539 ctl.filled = 0;
540 ctl.valid = 1;
541read_really:
542 if (ncp_is_server_root(inode)) {
Al Viro76f582a2013-05-22 15:11:27 -0400543 ncp_read_volume_list(file, ctx, &ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 } else {
Al Viro76f582a2013-05-22 15:11:27 -0400545 ncp_do_readdir(file, ctx, &ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 }
547 ctl.head.end = ctl.fpos - 1;
548 ctl.head.eof = ctl.valid;
549finished:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200550 if (ctl.page) {
551 kunmap(ctl.page);
552 SetPageUptodate(ctl.page);
553 unlock_page(ctl.page);
554 page_cache_release(ctl.page);
555 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 if (page) {
557 cache->head = ctl.head;
558 kunmap(page);
559 SetPageUptodate(page);
560 unlock_page(page);
561 page_cache_release(page);
562 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 return result;
565}
566
567static int
Al Viro76f582a2013-05-22 15:11:27 -0400568ncp_fill_cache(struct file *file, struct dir_context *ctx,
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200569 struct ncp_cache_control *ctrl, struct ncp_entry_info *entry,
570 int inval_childs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571{
Al Viro76f582a2013-05-22 15:11:27 -0400572 struct dentry *newdent, *dentry = file->f_path.dentry;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200573 struct inode *dir = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 struct ncp_cache_control ctl = *ctrl;
575 struct qstr qname;
576 int valid = 0;
577 int hashed = 0;
578 ino_t ino = 0;
579 __u8 __name[NCP_MAXPATHLEN + 1];
580
581 qname.len = sizeof(__name);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200582 if (ncp_vol2io(NCP_SERVER(dir), __name, &qname.len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 entry->i.entryName, entry->i.nameLen,
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200584 !ncp_preserve_entry_case(dir, entry->i.NSCreator)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 return 1; /* I'm not sure */
586
587 qname.name = __name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
Al Viro4f522a22013-02-11 23:20:37 -0500589 newdent = d_hash_and_lookup(dentry, &qname);
590 if (unlikely(IS_ERR(newdent)))
591 goto end_advance;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 if (!newdent) {
593 newdent = d_alloc(dentry, &qname);
594 if (!newdent)
595 goto end_advance;
596 } else {
597 hashed = 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200598
599 /* If case sensitivity changed for this volume, all entries below this one
600 should be thrown away. This entry itself is not affected, as its case
601 sensitivity is controlled by its own parent. */
602 if (inval_childs)
603 shrink_dcache_parent(newdent);
604
605 /*
Nick Pigginfb2d5b82011-01-07 17:49:26 +1100606 * NetWare's OS2 namespace is case preserving yet case
607 * insensitive. So we update dentry's name as received from
608 * server. Parent dir's i_mutex is locked because we're in
609 * readdir.
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200610 */
Nick Pigginfb2d5b82011-01-07 17:49:26 +1100611 dentry_update_name_case(newdent, &qname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 }
613
614 if (!newdent->d_inode) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200615 struct inode *inode;
616
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 entry->opened = 0;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200618 entry->ino = iunique(dir->i_sb, 2);
619 inode = ncp_iget(dir->i_sb, entry);
620 if (inode) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200621 d_instantiate(newdent, inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 if (!hashed)
623 d_rehash(newdent);
624 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200625 } else {
626 struct inode *inode = newdent->d_inode;
627
Nick Pigginfb2d5b82011-01-07 17:49:26 +1100628 mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200629 ncp_update_inode2(inode, entry);
630 mutex_unlock(&inode->i_mutex);
631 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
633 if (newdent->d_inode) {
634 ino = newdent->d_inode->i_ino;
635 newdent->d_fsdata = (void *) ctl.fpos;
636 ncp_new_dentry(newdent);
637 }
638
639 if (ctl.idx >= NCP_DIRCACHE_SIZE) {
640 if (ctl.page) {
641 kunmap(ctl.page);
642 SetPageUptodate(ctl.page);
643 unlock_page(ctl.page);
644 page_cache_release(ctl.page);
645 }
646 ctl.cache = NULL;
647 ctl.idx -= NCP_DIRCACHE_SIZE;
648 ctl.ofs += 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200649 ctl.page = grab_cache_page(&dir->i_data, ctl.ofs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 if (ctl.page)
651 ctl.cache = kmap(ctl.page);
652 }
653 if (ctl.cache) {
654 ctl.cache->dentry[ctl.idx] = newdent;
655 valid = 1;
656 }
657 dput(newdent);
658end_advance:
659 if (!valid)
660 ctl.valid = 0;
Al Viro76f582a2013-05-22 15:11:27 -0400661 if (!ctl.filled && (ctl.fpos == ctx->pos)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 if (!ino)
663 ino = find_inode_number(dentry, &qname);
664 if (!ino)
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200665 ino = iunique(dir->i_sb, 2);
Al Viro76f582a2013-05-22 15:11:27 -0400666 ctl.filled = !dir_emit(ctx, qname.name, qname.len,
667 ino, DT_UNKNOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 if (!ctl.filled)
Al Viro76f582a2013-05-22 15:11:27 -0400669 ctx->pos += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 }
671 ctl.fpos += 1;
672 ctl.idx += 1;
673 *ctrl = ctl;
674 return (ctl.valid || !ctl.filled);
675}
676
677static void
Al Viro76f582a2013-05-22 15:11:27 -0400678ncp_read_volume_list(struct file *file, struct dir_context *ctx,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 struct ncp_cache_control *ctl)
680{
Al Viro76f582a2013-05-22 15:11:27 -0400681 struct dentry *dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 struct inode *inode = dentry->d_inode;
683 struct ncp_server *server = NCP_SERVER(inode);
684 struct ncp_volume_info info;
685 struct ncp_entry_info entry;
686 int i;
687
688 DPRINTK("ncp_read_volume_list: pos=%ld\n",
Al Viro76f582a2013-05-22 15:11:27 -0400689 (unsigned long) ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690
691 for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200692 int inval_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
694 if (ncp_get_volume_info_with_number(server, i, &info) != 0)
695 return;
696 if (!strlen(info.volume_name))
697 continue;
698
699 DPRINTK("ncp_read_volume_list: found vol: %s\n",
700 info.volume_name);
701
702 if (ncp_lookup_volume(server, info.volume_name,
703 &entry.i)) {
704 DPRINTK("ncpfs: could not lookup vol %s\n",
705 info.volume_name);
706 continue;
707 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200708 inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 entry.volume = entry.i.volNumber;
Al Viro76f582a2013-05-22 15:11:27 -0400710 if (!ncp_fill_cache(file, ctx, ctl, &entry, inval_dentry))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 return;
712 }
713}
714
715static void
Al Viro76f582a2013-05-22 15:11:27 -0400716ncp_do_readdir(struct file *file, struct dir_context *ctx,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 struct ncp_cache_control *ctl)
718{
Al Viro76f582a2013-05-22 15:11:27 -0400719 struct dentry *dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 struct inode *dir = dentry->d_inode;
721 struct ncp_server *server = NCP_SERVER(dir);
722 struct nw_search_sequence seq;
723 struct ncp_entry_info entry;
724 int err;
725 void* buf;
726 int more;
727 size_t bufsize;
728
729 DPRINTK("ncp_do_readdir: %s/%s, fpos=%ld\n",
730 dentry->d_parent->d_name.name, dentry->d_name.name,
Al Viro76f582a2013-05-22 15:11:27 -0400731 (unsigned long) ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 PPRINTK("ncp_do_readdir: init %s, volnum=%d, dirent=%u\n",
733 dentry->d_name.name, NCP_FINFO(dir)->volNumber,
734 NCP_FINFO(dir)->dirEntNum);
735
736 err = ncp_initialize_search(server, dir, &seq);
737 if (err) {
738 DPRINTK("ncp_do_readdir: init failed, err=%d\n", err);
739 return;
740 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 /* We MUST NOT use server->buffer_size handshaked with server if we are
742 using UDP, as for UDP server uses max. buffer size determined by
743 MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes).
744 So we use 128KB, just to be sure, as there is no way how to know
745 this value in advance. */
746 bufsize = 131072;
747 buf = vmalloc(bufsize);
748 if (!buf)
749 return;
750 do {
751 int cnt;
752 char* rpl;
753 size_t rpls;
754
755 err = ncp_search_for_fileset(server, &seq, &more, &cnt, buf, bufsize, &rpl, &rpls);
756 if (err) /* Error */
757 break;
758 if (!cnt) /* prevent endless loop */
759 break;
760 while (cnt--) {
761 size_t onerpl;
762
763 if (rpls < offsetof(struct nw_info_struct, entryName))
764 break; /* short packet */
765 ncp_extract_file_info(rpl, &entry.i);
766 onerpl = offsetof(struct nw_info_struct, entryName) + entry.i.nameLen;
767 if (rpls < onerpl)
768 break; /* short packet */
769 (void)ncp_obtain_nfs_info(server, &entry.i);
770 rpl += onerpl;
771 rpls -= onerpl;
772 entry.volume = entry.i.volNumber;
Al Viro76f582a2013-05-22 15:11:27 -0400773 if (!ncp_fill_cache(file, ctx, ctl, &entry, 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 break;
775 }
776 } while (more);
777 vfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 return;
779}
780
781int ncp_conn_logged_in(struct super_block *sb)
782{
783 struct ncp_server* server = NCP_SBP(sb);
784 int result;
785
786 if (ncp_single_volume(server)) {
787 int len;
788 struct dentry* dent;
789 __u32 volNumber;
790 __le32 dirEntNum;
791 __le32 DosDirNum;
792 __u8 __name[NCP_MAXPATHLEN + 1];
793
794 len = sizeof(__name);
795 result = ncp_io2vol(server, __name, &len, server->m.mounted_vol,
796 strlen(server->m.mounted_vol), 1);
797 if (result)
798 goto out;
799 result = -ENOENT;
800 if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) {
801 PPRINTK("ncp_conn_logged_in: %s not found\n",
802 server->m.mounted_vol);
803 goto out;
804 }
805 dent = sb->s_root;
806 if (dent) {
807 struct inode* ino = dent->d_inode;
808 if (ino) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200809 ncp_update_known_namespace(server, volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 NCP_FINFO(ino)->volNumber = volNumber;
811 NCP_FINFO(ino)->dirEntNum = dirEntNum;
812 NCP_FINFO(ino)->DosDirNum = DosDirNum;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200813 result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 } else {
815 DPRINTK("ncpfs: sb->s_root->d_inode == NULL!\n");
816 }
817 } else {
818 DPRINTK("ncpfs: sb->s_root == NULL!\n");
819 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200820 } else
821 result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
823out:
824 return result;
825}
826
Al Viro00cd8dd2012-06-10 17:13:09 -0400827static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828{
829 struct ncp_server *server = NCP_SERVER(dir);
830 struct inode *inode = NULL;
831 struct ncp_entry_info finfo;
832 int error, res, len;
833 __u8 __name[NCP_MAXPATHLEN + 1];
834
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 error = -EIO;
836 if (!ncp_conn_valid(server))
837 goto finished;
838
839 PPRINTK("ncp_lookup: server lookup for %s/%s\n",
840 dentry->d_parent->d_name.name, dentry->d_name.name);
841
842 len = sizeof(__name);
843 if (ncp_is_server_root(dir)) {
844 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
845 dentry->d_name.len, 1);
846 if (!res)
847 res = ncp_lookup_volume(server, __name, &(finfo.i));
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200848 if (!res)
849 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 } else {
851 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
852 dentry->d_name.len, !ncp_preserve_case(dir));
853 if (!res)
854 res = ncp_obtain_info(server, dir, __name, &(finfo.i));
855 }
856 PPRINTK("ncp_lookup: looked for %s/%s, res=%d\n",
857 dentry->d_parent->d_name.name, __name, res);
858 /*
859 * If we didn't find an entry, make a negative dentry.
860 */
861 if (res)
862 goto add_entry;
863
864 /*
865 * Create an inode for the entry.
866 */
867 finfo.opened = 0;
868 finfo.ino = iunique(dir->i_sb, 2);
869 finfo.volume = finfo.i.volNumber;
870 error = -EACCES;
871 inode = ncp_iget(dir->i_sb, &finfo);
872
873 if (inode) {
874 ncp_new_dentry(dentry);
875add_entry:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 d_add(dentry, inode);
877 error = 0;
878 }
879
880finished:
881 PPRINTK("ncp_lookup: result=%d\n", error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 return ERR_PTR(error);
883}
884
885/*
886 * This code is common to create, mkdir, and mknod.
887 */
888static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
889 struct ncp_entry_info *finfo)
890{
891 struct inode *inode;
892 int error = -EINVAL;
893
894 finfo->ino = iunique(dir->i_sb, 2);
895 inode = ncp_iget(dir->i_sb, finfo);
896 if (!inode)
897 goto out_close;
898 d_instantiate(dentry,inode);
899 error = 0;
900out:
901 return error;
902
903out_close:
904 PPRINTK("ncp_instantiate: %s/%s failed, closing file\n",
905 dentry->d_parent->d_name.name, dentry->d_name.name);
906 ncp_close_file(NCP_SERVER(dir), finfo->file_handle);
907 goto out;
908}
909
Al Viro5eee25c2011-07-26 03:12:16 -0400910int ncp_create_new(struct inode *dir, struct dentry *dentry, umode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 dev_t rdev, __le32 attributes)
912{
913 struct ncp_server *server = NCP_SERVER(dir);
914 struct ncp_entry_info finfo;
915 int error, result, len;
916 int opmode;
917 __u8 __name[NCP_MAXPATHLEN + 1];
918
Al Viro5eee25c2011-07-26 03:12:16 -0400919 PPRINTK("ncp_create_new: creating %s/%s, mode=%hx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 dentry->d_parent->d_name.name, dentry->d_name.name, mode);
921
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 ncp_age_dentry(server, dentry);
923 len = sizeof(__name);
924 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
925 dentry->d_name.len, !ncp_preserve_case(dir));
926 if (error)
927 goto out;
928
929 error = -EACCES;
930
931 if (S_ISREG(mode) &&
932 (server->m.flags & NCP_MOUNT_EXTRAS) &&
933 (mode & S_IXUGO))
934 attributes |= aSYSTEM | aSHARED;
935
936 result = ncp_open_create_file_or_subdir(server, dir, __name,
937 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
938 attributes, AR_READ | AR_WRITE, &finfo);
939 opmode = O_RDWR;
940 if (result) {
941 result = ncp_open_create_file_or_subdir(server, dir, __name,
942 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
943 attributes, AR_WRITE, &finfo);
944 if (result) {
945 if (result == 0x87)
946 error = -ENAMETOOLONG;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200947 else if (result < 0)
948 error = result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 DPRINTK("ncp_create: %s/%s failed\n",
950 dentry->d_parent->d_name.name, dentry->d_name.name);
951 goto out;
952 }
953 opmode = O_WRONLY;
954 }
955 finfo.access = opmode;
956 if (ncp_is_nfs_extras(server, finfo.volume)) {
957 finfo.i.nfs.mode = mode;
958 finfo.i.nfs.rdev = new_encode_dev(rdev);
959 if (ncp_modify_nfs_info(server, finfo.volume,
960 finfo.i.dirEntNum,
961 mode, new_encode_dev(rdev)) != 0)
962 goto out;
963 }
964
965 error = ncp_instantiate(dir, dentry, &finfo);
966out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 return error;
968}
969
Al Viro4acdaf22011-07-26 01:42:34 -0400970static int ncp_create(struct inode *dir, struct dentry *dentry, umode_t mode,
Al Viroebfc3b42012-06-10 18:05:36 -0400971 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972{
973 return ncp_create_new(dir, dentry, mode, 0, 0);
974}
975
Al Viro18bb1db2011-07-26 01:41:39 -0400976static int ncp_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977{
978 struct ncp_entry_info finfo;
979 struct ncp_server *server = NCP_SERVER(dir);
980 int error, len;
981 __u8 __name[NCP_MAXPATHLEN + 1];
982
983 DPRINTK("ncp_mkdir: making %s/%s\n",
984 dentry->d_parent->d_name.name, dentry->d_name.name);
985
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 ncp_age_dentry(server, dentry);
987 len = sizeof(__name);
988 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
989 dentry->d_name.len, !ncp_preserve_case(dir));
990 if (error)
991 goto out;
992
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200993 error = ncp_open_create_file_or_subdir(server, dir, __name,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 OC_MODE_CREATE, aDIR,
995 cpu_to_le16(0xffff),
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200996 &finfo);
997 if (error == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 if (ncp_is_nfs_extras(server, finfo.volume)) {
999 mode |= S_IFDIR;
1000 finfo.i.nfs.mode = mode;
1001 if (ncp_modify_nfs_info(server,
1002 finfo.volume,
1003 finfo.i.dirEntNum,
1004 mode, 0) != 0)
1005 goto out;
1006 }
1007 error = ncp_instantiate(dir, dentry, &finfo);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001008 } else if (error > 0) {
1009 error = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 }
1011out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 return error;
1013}
1014
1015static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
1016{
1017 struct ncp_server *server = NCP_SERVER(dir);
1018 int error, result, len;
1019 __u8 __name[NCP_MAXPATHLEN + 1];
1020
1021 DPRINTK("ncp_rmdir: removing %s/%s\n",
1022 dentry->d_parent->d_name.name, dentry->d_name.name);
1023
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 len = sizeof(__name);
1025 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
1026 dentry->d_name.len, !ncp_preserve_case(dir));
1027 if (error)
1028 goto out;
1029
1030 result = ncp_del_file_or_subdir(server, dir, __name);
1031 switch (result) {
1032 case 0x00:
1033 error = 0;
1034 break;
1035 case 0x85: /* unauthorized to delete file */
1036 case 0x8A: /* unauthorized to delete file */
1037 error = -EACCES;
1038 break;
1039 case 0x8F:
1040 case 0x90: /* read only */
1041 error = -EPERM;
1042 break;
1043 case 0x9F: /* in use by another client */
1044 error = -EBUSY;
1045 break;
1046 case 0xA0: /* directory not empty */
1047 error = -ENOTEMPTY;
1048 break;
1049 case 0xFF: /* someone deleted file */
1050 error = -ENOENT;
1051 break;
1052 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001053 error = result < 0 ? result : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 break;
1055 }
1056out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 return error;
1058}
1059
1060static int ncp_unlink(struct inode *dir, struct dentry *dentry)
1061{
1062 struct inode *inode = dentry->d_inode;
1063 struct ncp_server *server;
1064 int error;
1065
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 server = NCP_SERVER(dir);
1067 DPRINTK("ncp_unlink: unlinking %s/%s\n",
1068 dentry->d_parent->d_name.name, dentry->d_name.name);
1069
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 /*
1071 * Check whether to close the file ...
1072 */
1073 if (inode) {
1074 PPRINTK("ncp_unlink: closing file\n");
1075 ncp_make_closed(inode);
1076 }
1077
1078 error = ncp_del_file_or_subdir2(server, dentry);
1079#ifdef CONFIG_NCPFS_STRONG
1080 /* 9C is Invalid path.. It should be 8F, 90 - read only, but
1081 it is not :-( */
1082 if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */
1083 error = ncp_force_unlink(dir, dentry);
1084 }
1085#endif
1086 switch (error) {
1087 case 0x00:
1088 DPRINTK("ncp: removed %s/%s\n",
1089 dentry->d_parent->d_name.name, dentry->d_name.name);
1090 break;
1091 case 0x85:
1092 case 0x8A:
1093 error = -EACCES;
1094 break;
1095 case 0x8D: /* some files in use */
1096 case 0x8E: /* all files in use */
1097 error = -EBUSY;
1098 break;
1099 case 0x8F: /* some read only */
1100 case 0x90: /* all read only */
1101 case 0x9C: /* !!! returned when in-use or read-only by NW4 */
1102 error = -EPERM;
1103 break;
1104 case 0xFF:
1105 error = -ENOENT;
1106 break;
1107 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001108 error = error < 0 ? error : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 break;
1110 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 return error;
1112}
1113
1114static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
1115 struct inode *new_dir, struct dentry *new_dentry)
1116{
1117 struct ncp_server *server = NCP_SERVER(old_dir);
1118 int error;
1119 int old_len, new_len;
1120 __u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1];
1121
1122 DPRINTK("ncp_rename: %s/%s to %s/%s\n",
1123 old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
1124 new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
1125
Sage Weil76cc071a2011-05-27 13:42:10 -07001126 if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode)) {
1127 /*
1128 * fail with EBUSY if there are still references to this
1129 * directory.
1130 */
Sage Weile4eaac02011-05-24 13:06:07 -07001131 dentry_unhash(new_dentry);
Sage Weil76cc071a2011-05-27 13:42:10 -07001132 error = -EBUSY;
1133 if (!d_unhashed(new_dentry))
1134 goto out;
1135 }
Sage Weile4eaac02011-05-24 13:06:07 -07001136
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 ncp_age_dentry(server, old_dentry);
1138 ncp_age_dentry(server, new_dentry);
1139
1140 old_len = sizeof(__old_name);
1141 error = ncp_io2vol(server, __old_name, &old_len,
1142 old_dentry->d_name.name, old_dentry->d_name.len,
1143 !ncp_preserve_case(old_dir));
1144 if (error)
1145 goto out;
1146
1147 new_len = sizeof(__new_name);
1148 error = ncp_io2vol(server, __new_name, &new_len,
1149 new_dentry->d_name.name, new_dentry->d_name.len,
1150 !ncp_preserve_case(new_dir));
1151 if (error)
1152 goto out;
1153
1154 error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name,
1155 new_dir, __new_name);
1156#ifdef CONFIG_NCPFS_STRONG
1157 if ((error == 0x90 || error == 0x8B || error == -EACCES) &&
1158 server->m.flags & NCP_MOUNT_STRONG) { /* RO */
1159 error = ncp_force_rename(old_dir, old_dentry, __old_name,
1160 new_dir, new_dentry, __new_name);
1161 }
1162#endif
1163 switch (error) {
1164 case 0x00:
1165 DPRINTK("ncp renamed %s -> %s.\n",
1166 old_dentry->d_name.name,new_dentry->d_name.name);
1167 break;
1168 case 0x9E:
1169 error = -ENAMETOOLONG;
1170 break;
1171 case 0xFF:
1172 error = -ENOENT;
1173 break;
1174 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001175 error = error < 0 ? error : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 break;
1177 }
1178out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 return error;
1180}
1181
1182static int ncp_mknod(struct inode * dir, struct dentry *dentry,
Al Viro1a67aaf2011-07-26 01:52:52 -04001183 umode_t mode, dev_t rdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184{
1185 if (!new_valid_dev(rdev))
1186 return -EINVAL;
1187 if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) {
Al Viro1a67aaf2011-07-26 01:52:52 -04001188 DPRINTK(KERN_DEBUG "ncp_mknod: mode = 0%ho\n", mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 return ncp_create_new(dir, dentry, mode, rdev, 0);
1190 }
1191 return -EPERM; /* Strange, but true */
1192}
1193
1194/* The following routines are taken directly from msdos-fs */
1195
1196/* Linear day numbers of the respective 1sts in non-leap years. */
1197
1198static int day_n[] =
1199{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
1200/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
1201
1202
1203extern struct timezone sys_tz;
1204
1205static int utc2local(int time)
1206{
1207 return time - sys_tz.tz_minuteswest * 60;
1208}
1209
1210static int local2utc(int time)
1211{
1212 return time + sys_tz.tz_minuteswest * 60;
1213}
1214
1215/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
1216int
1217ncp_date_dos2unix(__le16 t, __le16 d)
1218{
1219 unsigned short time = le16_to_cpu(t), date = le16_to_cpu(d);
1220 int month, year, secs;
1221
1222 /* first subtract and mask after that... Otherwise, if
1223 date == 0, bad things happen */
1224 month = ((date >> 5) - 1) & 15;
1225 year = date >> 9;
1226 secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
1227 86400 * ((date & 31) - 1 + day_n[month] + (year / 4) +
1228 year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
1229 /* days since 1.1.70 plus 80's leap day */
1230 return local2utc(secs);
1231}
1232
1233
1234/* Convert linear UNIX date to a MS-DOS time/date pair. */
1235void
1236ncp_date_unix2dos(int unix_date, __le16 *time, __le16 *date)
1237{
1238 int day, year, nl_day, month;
1239
1240 unix_date = utc2local(unix_date);
1241 *time = cpu_to_le16(
1242 (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
1243 (((unix_date / 3600) % 24) << 11));
1244 day = unix_date / 86400 - 3652;
1245 year = day / 365;
1246 if ((year + 3) / 4 + 365 * year > day)
1247 year--;
1248 day -= (year + 3) / 4 + 365 * year;
1249 if (day == 59 && !(year & 3)) {
1250 nl_day = day;
1251 month = 2;
1252 } else {
1253 nl_day = (year & 3) || day <= 59 ? day : day - 1;
Roel Kluinc5df5912009-09-22 16:45:54 -07001254 for (month = 1; month < 12; month++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 if (day_n[month] > nl_day)
1256 break;
1257 }
1258 *date = cpu_to_le16(nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
1259}