blob: 3be047474bfc355731c08e2a6c27b40e73ce9e8b [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);
Linus Torvaldsda53be12013-05-21 15:22:44 -070076static int ncp_hash_dentry(const struct dentry *, struct qstr *);
77static int ncp_compare_dentry(const struct dentry *, const struct dentry *,
Nick Piggin621e1552011-01-07 17:49:27 +110078 unsigned int, const char *, const struct qstr *);
Nick Pigginfe15ce42011-01-07 17:49:23 +110079static int ncp_delete_dentry(const struct dentry *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
Al Viro0378c402011-01-12 17:25:03 -050081const struct dentry_operations ncp_dentry_operations =
Linus Torvalds1da177e2005-04-16 15:20:36 -070082{
83 .d_revalidate = ncp_lookup_validate,
84 .d_hash = ncp_hash_dentry,
85 .d_compare = ncp_compare_dentry,
86 .d_delete = ncp_delete_dentry,
87};
88
Petr Vandrovec2e54eb92010-09-27 01:47:33 +020089#define ncp_namespace(i) (NCP_SERVER(i)->name_space[NCP_FINFO(i)->volNumber])
90
91static inline int ncp_preserve_entry_case(struct inode *i, __u32 nscreator)
92{
93#ifdef CONFIG_NCPFS_SMALLDOS
94 int ns = ncp_namespace(i);
95
96 if ((ns == NW_NS_DOS)
97#ifdef CONFIG_NCPFS_OS2_NS
98 || ((ns == NW_NS_OS2) && (nscreator == NW_NS_DOS))
99#endif /* CONFIG_NCPFS_OS2_NS */
100 )
101 return 0;
102#endif /* CONFIG_NCPFS_SMALLDOS */
103 return 1;
104}
105
106#define ncp_preserve_case(i) (ncp_namespace(i) != NW_NS_DOS)
107
Nick Piggin621e1552011-01-07 17:49:27 +1100108static inline int ncp_case_sensitive(const struct inode *i)
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200109{
110#ifdef CONFIG_NCPFS_NFS_NS
Nick Piggin621e1552011-01-07 17:49:27 +1100111 return ncp_namespace(i) == NW_NS_NFS;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200112#else
113 return 0;
114#endif /* CONFIG_NCPFS_NFS_NS */
115}
116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117/*
118 * Note: leave the hash unchanged if the directory
119 * is case-sensitive.
Linus Torvaldsda53be12013-05-21 15:22:44 -0700120 *
121 * Accessing the parent inode can be racy under RCU pathwalking.
122 * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
123 * the callers will handle races.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 */
125static int
Linus Torvaldsda53be12013-05-21 15:22:44 -0700126ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127{
Linus Torvaldsda53be12013-05-21 15:22:44 -0700128 struct inode *inode = ACCESS_ONCE(dentry->d_inode);
129
130 if (!inode)
131 return 0;
132
Nick Pigginb1e6a012011-01-07 17:49:28 +1100133 if (!ncp_case_sensitive(inode)) {
Nick Piggin621e1552011-01-07 17:49:27 +1100134 struct super_block *sb = dentry->d_sb;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200135 struct nls_table *t;
136 unsigned long hash;
137 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
Nick Piggin621e1552011-01-07 17:49:27 +1100139 t = NCP_IO_TABLE(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 hash = init_name_hash();
141 for (i=0; i<this->len ; i++)
142 hash = partial_name_hash(ncp_tolower(t, this->name[i]),
143 hash);
144 this->hash = end_name_hash(hash);
145 }
146 return 0;
147}
148
Linus Torvaldsda53be12013-05-21 15:22:44 -0700149/*
150 * Accessing the parent inode can be racy under RCU pathwalking.
151 * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
152 * the callers will handle races.
153 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154static int
Linus Torvaldsda53be12013-05-21 15:22:44 -0700155ncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
Nick Piggin621e1552011-01-07 17:49:27 +1100156 unsigned int len, const char *str, const struct qstr *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157{
Linus Torvaldsda53be12013-05-21 15:22:44 -0700158 struct inode *pinode;
159
Nick Piggin621e1552011-01-07 17:49:27 +1100160 if (len != name->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 return 1;
162
Linus Torvaldsda53be12013-05-21 15:22:44 -0700163 pinode = ACCESS_ONCE(parent->d_inode);
164 if (!pinode)
165 return 1;
166
Nick Piggin621e1552011-01-07 17:49:27 +1100167 if (ncp_case_sensitive(pinode))
168 return strncmp(str, name->name, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
Nick Piggin621e1552011-01-07 17:49:27 +1100170 return ncp_strnicmp(NCP_IO_TABLE(pinode->i_sb), str, name->name, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171}
172
173/*
174 * This is the callback from dput() when d_count is going to 0.
175 * We use this to unhash dentries with bad inodes.
176 * Closing files can be safely postponed until iput() - it's done there anyway.
177 */
178static int
Nick Pigginfe15ce42011-01-07 17:49:23 +1100179ncp_delete_dentry(const struct dentry * dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180{
181 struct inode *inode = dentry->d_inode;
182
183 if (inode) {
184 if (is_bad_inode(inode))
185 return 1;
186 } else
187 {
188 /* N.B. Unhash negative dentries? */
189 }
190 return 0;
191}
192
193static inline int
194ncp_single_volume(struct ncp_server *server)
195{
196 return (server->m.mounted_vol[0] != '\0');
197}
198
199static inline int ncp_is_server_root(struct inode *inode)
200{
201 return (!ncp_single_volume(NCP_SERVER(inode)) &&
202 inode == inode->i_sb->s_root->d_inode);
203}
204
205
206/*
207 * This is the callback when the dcache has a lookup hit.
208 */
209
210
211#ifdef CONFIG_NCPFS_STRONG
212/* try to delete a readonly file (NW R bit set) */
213
214static int
215ncp_force_unlink(struct inode *dir, struct dentry* dentry)
216{
217 int res=0x9c,res2;
218 struct nw_modify_dos_info info;
219 __le32 old_nwattr;
220 struct inode *inode;
221
222 memset(&info, 0, sizeof(info));
223
224 /* remove the Read-Only flag on the NW server */
225 inode = dentry->d_inode;
226
227 old_nwattr = NCP_FINFO(inode)->nwattr;
228 info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT);
229 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
230 if (res2)
231 goto leave_me;
232
233 /* now try again the delete operation */
234 res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
235
236 if (res) /* delete failed, set R bit again */
237 {
238 info.attributes = old_nwattr;
239 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
240 if (res2)
241 goto leave_me;
242 }
243leave_me:
244 return(res);
245}
246#endif /* CONFIG_NCPFS_STRONG */
247
248#ifdef CONFIG_NCPFS_STRONG
249static int
250ncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name,
251 struct inode *new_dir, struct dentry* new_dentry, char *_new_name)
252{
253 struct nw_modify_dos_info info;
254 int res=0x90,res2;
255 struct inode *old_inode = old_dentry->d_inode;
256 __le32 old_nwattr = NCP_FINFO(old_inode)->nwattr;
257 __le32 new_nwattr = 0; /* shut compiler warning */
258 int old_nwattr_changed = 0;
259 int new_nwattr_changed = 0;
260
261 memset(&info, 0, sizeof(info));
262
263 /* remove the Read-Only flag on the NW server */
264
265 info.attributes = old_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
266 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
267 if (!res2)
268 old_nwattr_changed = 1;
269 if (new_dentry && new_dentry->d_inode) {
270 new_nwattr = NCP_FINFO(new_dentry->d_inode)->nwattr;
271 info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
272 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
273 if (!res2)
274 new_nwattr_changed = 1;
275 }
276 /* now try again the rename operation */
277 /* but only if something really happened */
278 if (new_nwattr_changed || old_nwattr_changed) {
279 res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
280 old_dir, _old_name,
281 new_dir, _new_name);
282 }
283 if (res)
284 goto leave_me;
285 /* file was successfully renamed, so:
286 do not set attributes on old file - it no longer exists
287 copy attributes from old file to new */
288 new_nwattr_changed = old_nwattr_changed;
289 new_nwattr = old_nwattr;
290 old_nwattr_changed = 0;
291
292leave_me:;
293 if (old_nwattr_changed) {
294 info.attributes = old_nwattr;
295 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
296 /* ignore errors */
297 }
298 if (new_nwattr_changed) {
299 info.attributes = new_nwattr;
300 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
301 /* ignore errors */
302 }
303 return(res);
304}
305#endif /* CONFIG_NCPFS_STRONG */
306
307
308static int
Al Viro0b728e12012-06-10 16:03:43 -0400309ncp_lookup_validate(struct dentry *dentry, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310{
311 struct ncp_server *server;
312 struct dentry *parent;
313 struct inode *dir;
314 struct ncp_entry_info finfo;
315 int res, val = 0, len;
316 __u8 __name[NCP_MAXPATHLEN + 1];
317
Al Viro0378c402011-01-12 17:25:03 -0500318 if (dentry == dentry->d_sb->s_root)
319 return 1;
320
Al Viro0b728e12012-06-10 16:03:43 -0400321 if (flags & LOOKUP_RCU)
Nick Piggin34286d62011-01-07 17:49:57 +1100322 return -ECHILD;
323
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 parent = dget_parent(dentry);
325 dir = parent->d_inode;
326
327 if (!dentry->d_inode)
328 goto finished;
329
330 server = NCP_SERVER(dir);
331
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 /*
333 * Inspired by smbfs:
334 * The default validation is based on dentry age:
335 * We set the max age at mount time. (But each
336 * successful server lookup renews the timestamp.)
337 */
338 val = NCP_TEST_AGE(server, dentry);
339 if (val)
340 goto finished;
341
342 DDPRINTK("ncp_lookup_validate: %s/%s not valid, age=%ld, server lookup\n",
343 dentry->d_parent->d_name.name, dentry->d_name.name,
344 NCP_GET_AGE(dentry));
345
346 len = sizeof(__name);
347 if (ncp_is_server_root(dir)) {
348 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
349 dentry->d_name.len, 1);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200350 if (!res) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 res = ncp_lookup_volume(server, __name, &(finfo.i));
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200352 if (!res)
353 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
354 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 } else {
356 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
357 dentry->d_name.len, !ncp_preserve_case(dir));
358 if (!res)
359 res = ncp_obtain_info(server, dir, __name, &(finfo.i));
360 }
361 finfo.volume = finfo.i.volNumber;
362 DDPRINTK("ncp_lookup_validate: looked for %s/%s, res=%d\n",
363 dentry->d_parent->d_name.name, __name, res);
364 /*
365 * If we didn't find it, or if it has a different dirEntNum to
366 * what we remember, it's not valid any more.
367 */
368 if (!res) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200369 struct inode *inode = dentry->d_inode;
370
371 mutex_lock(&inode->i_mutex);
372 if (finfo.i.dirEntNum == NCP_FINFO(inode)->dirEntNum) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 ncp_new_dentry(dentry);
374 val=1;
375 } else
376 DDPRINTK("ncp_lookup_validate: found, but dirEntNum changed\n");
377
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200378 ncp_update_inode2(inode, &finfo);
379 mutex_unlock(&inode->i_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 }
381
382finished:
383 DDPRINTK("ncp_lookup_validate: result=%d\n", val);
384 dput(parent);
385 return val;
386}
387
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388static struct dentry *
389ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
390{
391 struct dentry *dent = dentry;
392 struct list_head *next;
393
394 if (d_validate(dent, parent)) {
395 if (dent->d_name.len <= NCP_MAXPATHLEN &&
396 (unsigned long)dent->d_fsdata == fpos) {
397 if (!dent->d_inode) {
398 dput(dent);
399 dent = NULL;
400 }
401 return dent;
402 }
403 dput(dent);
404 }
405
406 /* If a pointer is invalid, we search the dentry. */
Nick Piggin2fd6b7f2011-01-07 17:49:34 +1100407 spin_lock(&parent->d_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 next = parent->d_subdirs.next;
409 while (next != &parent->d_subdirs) {
Eric Dumazet5160ee62006-01-08 01:03:32 -0800410 dent = list_entry(next, struct dentry, d_u.d_child);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 if ((unsigned long)dent->d_fsdata == fpos) {
412 if (dent->d_inode)
Nick Piggindc0474b2011-01-07 17:49:43 +1100413 dget(dent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 else
415 dent = NULL;
Nick Piggin2fd6b7f2011-01-07 17:49:34 +1100416 spin_unlock(&parent->d_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 goto out;
418 }
419 next = next->next;
420 }
Nick Piggin2fd6b7f2011-01-07 17:49:34 +1100421 spin_unlock(&parent->d_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 return NULL;
423
424out:
425 return dent;
426}
427
428static time_t ncp_obtain_mtime(struct dentry *dentry)
429{
430 struct inode *inode = dentry->d_inode;
431 struct ncp_server *server = NCP_SERVER(inode);
432 struct nw_info_struct i;
433
434 if (!ncp_conn_valid(server) || ncp_is_server_root(inode))
435 return 0;
436
437 if (ncp_obtain_info(server, inode, NULL, &i))
438 return 0;
439
440 return ncp_date_dos2unix(i.modifyTime, i.modifyDate);
441}
442
Al Viro76f582a2013-05-22 15:11:27 -0400443static int ncp_readdir(struct file *file, struct dir_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444{
Al Viro76f582a2013-05-22 15:11:27 -0400445 struct dentry *dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 struct inode *inode = dentry->d_inode;
447 struct page *page = NULL;
448 struct ncp_server *server = NCP_SERVER(inode);
449 union ncp_dir_cache *cache = NULL;
450 struct ncp_cache_control ctl;
451 int result, mtime_valid = 0;
452 time_t mtime = 0;
453
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 ctl.page = NULL;
455 ctl.cache = NULL;
456
457 DDPRINTK("ncp_readdir: reading %s/%s, pos=%d\n",
458 dentry->d_parent->d_name.name, dentry->d_name.name,
Al Viro76f582a2013-05-22 15:11:27 -0400459 (int) ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
461 result = -EIO;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200462 /* Do not generate '.' and '..' when server is dead. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 if (!ncp_conn_valid(server))
464 goto out;
465
466 result = 0;
Al Viro76f582a2013-05-22 15:11:27 -0400467 if (!dir_emit_dots(file, ctx))
468 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
470 page = grab_cache_page(&inode->i_data, 0);
471 if (!page)
472 goto read_really;
473
474 ctl.cache = cache = kmap(page);
475 ctl.head = cache->head;
476
477 if (!PageUptodate(page) || !ctl.head.eof)
478 goto init_cache;
479
Al Viro76f582a2013-05-22 15:11:27 -0400480 if (ctx->pos == 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 if (jiffies - ctl.head.time >= NCP_MAX_AGE(server))
482 goto init_cache;
483
484 mtime = ncp_obtain_mtime(dentry);
485 mtime_valid = 1;
486 if ((!mtime) || (mtime != ctl.head.mtime))
487 goto init_cache;
488 }
489
Al Viro76f582a2013-05-22 15:11:27 -0400490 if (ctx->pos > ctl.head.end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 goto finished;
492
Al Viro76f582a2013-05-22 15:11:27 -0400493 ctl.fpos = ctx->pos + (NCP_DIRCACHE_START - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 ctl.ofs = ctl.fpos / NCP_DIRCACHE_SIZE;
495 ctl.idx = ctl.fpos % NCP_DIRCACHE_SIZE;
496
497 for (;;) {
498 if (ctl.ofs != 0) {
499 ctl.page = find_lock_page(&inode->i_data, ctl.ofs);
500 if (!ctl.page)
501 goto invalid_cache;
502 ctl.cache = kmap(ctl.page);
503 if (!PageUptodate(ctl.page))
504 goto invalid_cache;
505 }
506 while (ctl.idx < NCP_DIRCACHE_SIZE) {
507 struct dentry *dent;
Al Viro76f582a2013-05-22 15:11:27 -0400508 bool over;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
510 dent = ncp_dget_fpos(ctl.cache->dentry[ctl.idx],
Al Viro76f582a2013-05-22 15:11:27 -0400511 dentry, ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 if (!dent)
513 goto invalid_cache;
Al Viro76f582a2013-05-22 15:11:27 -0400514 over = !dir_emit(ctx, dent->d_name.name,
515 dent->d_name.len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 dent->d_inode->i_ino, DT_UNKNOWN);
517 dput(dent);
Al Viro76f582a2013-05-22 15:11:27 -0400518 if (over)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 goto finished;
Al Viro76f582a2013-05-22 15:11:27 -0400520 ctx->pos += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 ctl.idx += 1;
Al Viro76f582a2013-05-22 15:11:27 -0400522 if (ctx->pos > ctl.head.end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 goto finished;
524 }
525 if (ctl.page) {
526 kunmap(ctl.page);
527 SetPageUptodate(ctl.page);
528 unlock_page(ctl.page);
529 page_cache_release(ctl.page);
530 ctl.page = NULL;
531 }
532 ctl.idx = 0;
533 ctl.ofs += 1;
534 }
535invalid_cache:
536 if (ctl.page) {
537 kunmap(ctl.page);
538 unlock_page(ctl.page);
539 page_cache_release(ctl.page);
540 ctl.page = NULL;
541 }
542 ctl.cache = cache;
543init_cache:
544 ncp_invalidate_dircache_entries(dentry);
545 if (!mtime_valid) {
546 mtime = ncp_obtain_mtime(dentry);
547 mtime_valid = 1;
548 }
549 ctl.head.mtime = mtime;
550 ctl.head.time = jiffies;
551 ctl.head.eof = 0;
552 ctl.fpos = 2;
553 ctl.ofs = 0;
554 ctl.idx = NCP_DIRCACHE_START;
555 ctl.filled = 0;
556 ctl.valid = 1;
557read_really:
558 if (ncp_is_server_root(inode)) {
Al Viro76f582a2013-05-22 15:11:27 -0400559 ncp_read_volume_list(file, ctx, &ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 } else {
Al Viro76f582a2013-05-22 15:11:27 -0400561 ncp_do_readdir(file, ctx, &ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 }
563 ctl.head.end = ctl.fpos - 1;
564 ctl.head.eof = ctl.valid;
565finished:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200566 if (ctl.page) {
567 kunmap(ctl.page);
568 SetPageUptodate(ctl.page);
569 unlock_page(ctl.page);
570 page_cache_release(ctl.page);
571 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 if (page) {
573 cache->head = ctl.head;
574 kunmap(page);
575 SetPageUptodate(page);
576 unlock_page(page);
577 page_cache_release(page);
578 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 return result;
581}
582
583static int
Al Viro76f582a2013-05-22 15:11:27 -0400584ncp_fill_cache(struct file *file, struct dir_context *ctx,
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200585 struct ncp_cache_control *ctrl, struct ncp_entry_info *entry,
586 int inval_childs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587{
Al Viro76f582a2013-05-22 15:11:27 -0400588 struct dentry *newdent, *dentry = file->f_path.dentry;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200589 struct inode *dir = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 struct ncp_cache_control ctl = *ctrl;
591 struct qstr qname;
592 int valid = 0;
593 int hashed = 0;
594 ino_t ino = 0;
595 __u8 __name[NCP_MAXPATHLEN + 1];
596
597 qname.len = sizeof(__name);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200598 if (ncp_vol2io(NCP_SERVER(dir), __name, &qname.len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 entry->i.entryName, entry->i.nameLen,
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200600 !ncp_preserve_entry_case(dir, entry->i.NSCreator)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 return 1; /* I'm not sure */
602
603 qname.name = __name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604
Al Viro4f522a22013-02-11 23:20:37 -0500605 newdent = d_hash_and_lookup(dentry, &qname);
606 if (unlikely(IS_ERR(newdent)))
607 goto end_advance;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 if (!newdent) {
609 newdent = d_alloc(dentry, &qname);
610 if (!newdent)
611 goto end_advance;
612 } else {
613 hashed = 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200614
615 /* If case sensitivity changed for this volume, all entries below this one
616 should be thrown away. This entry itself is not affected, as its case
617 sensitivity is controlled by its own parent. */
618 if (inval_childs)
619 shrink_dcache_parent(newdent);
620
621 /*
Nick Pigginfb2d5b82011-01-07 17:49:26 +1100622 * NetWare's OS2 namespace is case preserving yet case
623 * insensitive. So we update dentry's name as received from
624 * server. Parent dir's i_mutex is locked because we're in
625 * readdir.
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200626 */
Nick Pigginfb2d5b82011-01-07 17:49:26 +1100627 dentry_update_name_case(newdent, &qname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 }
629
630 if (!newdent->d_inode) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200631 struct inode *inode;
632
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 entry->opened = 0;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200634 entry->ino = iunique(dir->i_sb, 2);
635 inode = ncp_iget(dir->i_sb, entry);
636 if (inode) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200637 d_instantiate(newdent, inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 if (!hashed)
639 d_rehash(newdent);
640 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200641 } else {
642 struct inode *inode = newdent->d_inode;
643
Nick Pigginfb2d5b82011-01-07 17:49:26 +1100644 mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200645 ncp_update_inode2(inode, entry);
646 mutex_unlock(&inode->i_mutex);
647 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
649 if (newdent->d_inode) {
650 ino = newdent->d_inode->i_ino;
651 newdent->d_fsdata = (void *) ctl.fpos;
652 ncp_new_dentry(newdent);
653 }
654
655 if (ctl.idx >= NCP_DIRCACHE_SIZE) {
656 if (ctl.page) {
657 kunmap(ctl.page);
658 SetPageUptodate(ctl.page);
659 unlock_page(ctl.page);
660 page_cache_release(ctl.page);
661 }
662 ctl.cache = NULL;
663 ctl.idx -= NCP_DIRCACHE_SIZE;
664 ctl.ofs += 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200665 ctl.page = grab_cache_page(&dir->i_data, ctl.ofs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 if (ctl.page)
667 ctl.cache = kmap(ctl.page);
668 }
669 if (ctl.cache) {
670 ctl.cache->dentry[ctl.idx] = newdent;
671 valid = 1;
672 }
673 dput(newdent);
674end_advance:
675 if (!valid)
676 ctl.valid = 0;
Al Viro76f582a2013-05-22 15:11:27 -0400677 if (!ctl.filled && (ctl.fpos == ctx->pos)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 if (!ino)
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200679 ino = iunique(dir->i_sb, 2);
Al Viro76f582a2013-05-22 15:11:27 -0400680 ctl.filled = !dir_emit(ctx, qname.name, qname.len,
681 ino, DT_UNKNOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 if (!ctl.filled)
Al Viro76f582a2013-05-22 15:11:27 -0400683 ctx->pos += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 }
685 ctl.fpos += 1;
686 ctl.idx += 1;
687 *ctrl = ctl;
688 return (ctl.valid || !ctl.filled);
689}
690
691static void
Al Viro76f582a2013-05-22 15:11:27 -0400692ncp_read_volume_list(struct file *file, struct dir_context *ctx,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 struct ncp_cache_control *ctl)
694{
Al Viro76f582a2013-05-22 15:11:27 -0400695 struct dentry *dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 struct inode *inode = dentry->d_inode;
697 struct ncp_server *server = NCP_SERVER(inode);
698 struct ncp_volume_info info;
699 struct ncp_entry_info entry;
700 int i;
701
702 DPRINTK("ncp_read_volume_list: pos=%ld\n",
Al Viro76f582a2013-05-22 15:11:27 -0400703 (unsigned long) ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704
705 for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200706 int inval_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707
708 if (ncp_get_volume_info_with_number(server, i, &info) != 0)
709 return;
710 if (!strlen(info.volume_name))
711 continue;
712
713 DPRINTK("ncp_read_volume_list: found vol: %s\n",
714 info.volume_name);
715
716 if (ncp_lookup_volume(server, info.volume_name,
717 &entry.i)) {
718 DPRINTK("ncpfs: could not lookup vol %s\n",
719 info.volume_name);
720 continue;
721 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200722 inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 entry.volume = entry.i.volNumber;
Al Viro76f582a2013-05-22 15:11:27 -0400724 if (!ncp_fill_cache(file, ctx, ctl, &entry, inval_dentry))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 return;
726 }
727}
728
729static void
Al Viro76f582a2013-05-22 15:11:27 -0400730ncp_do_readdir(struct file *file, struct dir_context *ctx,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 struct ncp_cache_control *ctl)
732{
Al Viro76f582a2013-05-22 15:11:27 -0400733 struct dentry *dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 struct inode *dir = dentry->d_inode;
735 struct ncp_server *server = NCP_SERVER(dir);
736 struct nw_search_sequence seq;
737 struct ncp_entry_info entry;
738 int err;
739 void* buf;
740 int more;
741 size_t bufsize;
742
743 DPRINTK("ncp_do_readdir: %s/%s, fpos=%ld\n",
744 dentry->d_parent->d_name.name, dentry->d_name.name,
Al Viro76f582a2013-05-22 15:11:27 -0400745 (unsigned long) ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 PPRINTK("ncp_do_readdir: init %s, volnum=%d, dirent=%u\n",
747 dentry->d_name.name, NCP_FINFO(dir)->volNumber,
748 NCP_FINFO(dir)->dirEntNum);
749
750 err = ncp_initialize_search(server, dir, &seq);
751 if (err) {
752 DPRINTK("ncp_do_readdir: init failed, err=%d\n", err);
753 return;
754 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 /* We MUST NOT use server->buffer_size handshaked with server if we are
756 using UDP, as for UDP server uses max. buffer size determined by
757 MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes).
758 So we use 128KB, just to be sure, as there is no way how to know
759 this value in advance. */
760 bufsize = 131072;
761 buf = vmalloc(bufsize);
762 if (!buf)
763 return;
764 do {
765 int cnt;
766 char* rpl;
767 size_t rpls;
768
769 err = ncp_search_for_fileset(server, &seq, &more, &cnt, buf, bufsize, &rpl, &rpls);
770 if (err) /* Error */
771 break;
772 if (!cnt) /* prevent endless loop */
773 break;
774 while (cnt--) {
775 size_t onerpl;
776
777 if (rpls < offsetof(struct nw_info_struct, entryName))
778 break; /* short packet */
779 ncp_extract_file_info(rpl, &entry.i);
780 onerpl = offsetof(struct nw_info_struct, entryName) + entry.i.nameLen;
781 if (rpls < onerpl)
782 break; /* short packet */
783 (void)ncp_obtain_nfs_info(server, &entry.i);
784 rpl += onerpl;
785 rpls -= onerpl;
786 entry.volume = entry.i.volNumber;
Al Viro76f582a2013-05-22 15:11:27 -0400787 if (!ncp_fill_cache(file, ctx, ctl, &entry, 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 break;
789 }
790 } while (more);
791 vfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 return;
793}
794
795int ncp_conn_logged_in(struct super_block *sb)
796{
797 struct ncp_server* server = NCP_SBP(sb);
798 int result;
799
800 if (ncp_single_volume(server)) {
801 int len;
802 struct dentry* dent;
803 __u32 volNumber;
804 __le32 dirEntNum;
805 __le32 DosDirNum;
806 __u8 __name[NCP_MAXPATHLEN + 1];
807
808 len = sizeof(__name);
809 result = ncp_io2vol(server, __name, &len, server->m.mounted_vol,
810 strlen(server->m.mounted_vol), 1);
811 if (result)
812 goto out;
813 result = -ENOENT;
814 if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) {
815 PPRINTK("ncp_conn_logged_in: %s not found\n",
816 server->m.mounted_vol);
817 goto out;
818 }
819 dent = sb->s_root;
820 if (dent) {
821 struct inode* ino = dent->d_inode;
822 if (ino) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200823 ncp_update_known_namespace(server, volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 NCP_FINFO(ino)->volNumber = volNumber;
825 NCP_FINFO(ino)->dirEntNum = dirEntNum;
826 NCP_FINFO(ino)->DosDirNum = DosDirNum;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200827 result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 } else {
829 DPRINTK("ncpfs: sb->s_root->d_inode == NULL!\n");
830 }
831 } else {
832 DPRINTK("ncpfs: sb->s_root == NULL!\n");
833 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200834 } else
835 result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
837out:
838 return result;
839}
840
Al Viro00cd8dd2012-06-10 17:13:09 -0400841static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842{
843 struct ncp_server *server = NCP_SERVER(dir);
844 struct inode *inode = NULL;
845 struct ncp_entry_info finfo;
846 int error, res, len;
847 __u8 __name[NCP_MAXPATHLEN + 1];
848
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 error = -EIO;
850 if (!ncp_conn_valid(server))
851 goto finished;
852
853 PPRINTK("ncp_lookup: server lookup for %s/%s\n",
854 dentry->d_parent->d_name.name, dentry->d_name.name);
855
856 len = sizeof(__name);
857 if (ncp_is_server_root(dir)) {
858 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
859 dentry->d_name.len, 1);
860 if (!res)
861 res = ncp_lookup_volume(server, __name, &(finfo.i));
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200862 if (!res)
863 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 } else {
865 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
866 dentry->d_name.len, !ncp_preserve_case(dir));
867 if (!res)
868 res = ncp_obtain_info(server, dir, __name, &(finfo.i));
869 }
870 PPRINTK("ncp_lookup: looked for %s/%s, res=%d\n",
871 dentry->d_parent->d_name.name, __name, res);
872 /*
873 * If we didn't find an entry, make a negative dentry.
874 */
875 if (res)
876 goto add_entry;
877
878 /*
879 * Create an inode for the entry.
880 */
881 finfo.opened = 0;
882 finfo.ino = iunique(dir->i_sb, 2);
883 finfo.volume = finfo.i.volNumber;
884 error = -EACCES;
885 inode = ncp_iget(dir->i_sb, &finfo);
886
887 if (inode) {
888 ncp_new_dentry(dentry);
889add_entry:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 d_add(dentry, inode);
891 error = 0;
892 }
893
894finished:
895 PPRINTK("ncp_lookup: result=%d\n", error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 return ERR_PTR(error);
897}
898
899/*
900 * This code is common to create, mkdir, and mknod.
901 */
902static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
903 struct ncp_entry_info *finfo)
904{
905 struct inode *inode;
906 int error = -EINVAL;
907
908 finfo->ino = iunique(dir->i_sb, 2);
909 inode = ncp_iget(dir->i_sb, finfo);
910 if (!inode)
911 goto out_close;
912 d_instantiate(dentry,inode);
913 error = 0;
914out:
915 return error;
916
917out_close:
918 PPRINTK("ncp_instantiate: %s/%s failed, closing file\n",
919 dentry->d_parent->d_name.name, dentry->d_name.name);
920 ncp_close_file(NCP_SERVER(dir), finfo->file_handle);
921 goto out;
922}
923
Al Viro5eee25c2011-07-26 03:12:16 -0400924int ncp_create_new(struct inode *dir, struct dentry *dentry, umode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 dev_t rdev, __le32 attributes)
926{
927 struct ncp_server *server = NCP_SERVER(dir);
928 struct ncp_entry_info finfo;
929 int error, result, len;
930 int opmode;
931 __u8 __name[NCP_MAXPATHLEN + 1];
932
Al Viro5eee25c2011-07-26 03:12:16 -0400933 PPRINTK("ncp_create_new: creating %s/%s, mode=%hx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 dentry->d_parent->d_name.name, dentry->d_name.name, mode);
935
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 ncp_age_dentry(server, dentry);
937 len = sizeof(__name);
938 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
939 dentry->d_name.len, !ncp_preserve_case(dir));
940 if (error)
941 goto out;
942
943 error = -EACCES;
944
945 if (S_ISREG(mode) &&
946 (server->m.flags & NCP_MOUNT_EXTRAS) &&
947 (mode & S_IXUGO))
948 attributes |= aSYSTEM | aSHARED;
949
950 result = ncp_open_create_file_or_subdir(server, dir, __name,
951 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
952 attributes, AR_READ | AR_WRITE, &finfo);
953 opmode = O_RDWR;
954 if (result) {
955 result = ncp_open_create_file_or_subdir(server, dir, __name,
956 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
957 attributes, AR_WRITE, &finfo);
958 if (result) {
959 if (result == 0x87)
960 error = -ENAMETOOLONG;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200961 else if (result < 0)
962 error = result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 DPRINTK("ncp_create: %s/%s failed\n",
964 dentry->d_parent->d_name.name, dentry->d_name.name);
965 goto out;
966 }
967 opmode = O_WRONLY;
968 }
969 finfo.access = opmode;
970 if (ncp_is_nfs_extras(server, finfo.volume)) {
971 finfo.i.nfs.mode = mode;
972 finfo.i.nfs.rdev = new_encode_dev(rdev);
973 if (ncp_modify_nfs_info(server, finfo.volume,
974 finfo.i.dirEntNum,
975 mode, new_encode_dev(rdev)) != 0)
976 goto out;
977 }
978
979 error = ncp_instantiate(dir, dentry, &finfo);
980out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 return error;
982}
983
Al Viro4acdaf22011-07-26 01:42:34 -0400984static int ncp_create(struct inode *dir, struct dentry *dentry, umode_t mode,
Al Viroebfc3b42012-06-10 18:05:36 -0400985 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986{
987 return ncp_create_new(dir, dentry, mode, 0, 0);
988}
989
Al Viro18bb1db2011-07-26 01:41:39 -0400990static int ncp_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991{
992 struct ncp_entry_info finfo;
993 struct ncp_server *server = NCP_SERVER(dir);
994 int error, len;
995 __u8 __name[NCP_MAXPATHLEN + 1];
996
997 DPRINTK("ncp_mkdir: making %s/%s\n",
998 dentry->d_parent->d_name.name, dentry->d_name.name);
999
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 ncp_age_dentry(server, dentry);
1001 len = sizeof(__name);
1002 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
1003 dentry->d_name.len, !ncp_preserve_case(dir));
1004 if (error)
1005 goto out;
1006
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001007 error = ncp_open_create_file_or_subdir(server, dir, __name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 OC_MODE_CREATE, aDIR,
1009 cpu_to_le16(0xffff),
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001010 &finfo);
1011 if (error == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 if (ncp_is_nfs_extras(server, finfo.volume)) {
1013 mode |= S_IFDIR;
1014 finfo.i.nfs.mode = mode;
1015 if (ncp_modify_nfs_info(server,
1016 finfo.volume,
1017 finfo.i.dirEntNum,
1018 mode, 0) != 0)
1019 goto out;
1020 }
1021 error = ncp_instantiate(dir, dentry, &finfo);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001022 } else if (error > 0) {
1023 error = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 }
1025out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 return error;
1027}
1028
1029static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
1030{
1031 struct ncp_server *server = NCP_SERVER(dir);
1032 int error, result, len;
1033 __u8 __name[NCP_MAXPATHLEN + 1];
1034
1035 DPRINTK("ncp_rmdir: removing %s/%s\n",
1036 dentry->d_parent->d_name.name, dentry->d_name.name);
1037
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 len = sizeof(__name);
1039 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
1040 dentry->d_name.len, !ncp_preserve_case(dir));
1041 if (error)
1042 goto out;
1043
1044 result = ncp_del_file_or_subdir(server, dir, __name);
1045 switch (result) {
1046 case 0x00:
1047 error = 0;
1048 break;
1049 case 0x85: /* unauthorized to delete file */
1050 case 0x8A: /* unauthorized to delete file */
1051 error = -EACCES;
1052 break;
1053 case 0x8F:
1054 case 0x90: /* read only */
1055 error = -EPERM;
1056 break;
1057 case 0x9F: /* in use by another client */
1058 error = -EBUSY;
1059 break;
1060 case 0xA0: /* directory not empty */
1061 error = -ENOTEMPTY;
1062 break;
1063 case 0xFF: /* someone deleted file */
1064 error = -ENOENT;
1065 break;
1066 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001067 error = result < 0 ? result : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 break;
1069 }
1070out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 return error;
1072}
1073
1074static int ncp_unlink(struct inode *dir, struct dentry *dentry)
1075{
1076 struct inode *inode = dentry->d_inode;
1077 struct ncp_server *server;
1078 int error;
1079
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 server = NCP_SERVER(dir);
1081 DPRINTK("ncp_unlink: unlinking %s/%s\n",
1082 dentry->d_parent->d_name.name, dentry->d_name.name);
1083
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 /*
1085 * Check whether to close the file ...
1086 */
1087 if (inode) {
1088 PPRINTK("ncp_unlink: closing file\n");
1089 ncp_make_closed(inode);
1090 }
1091
1092 error = ncp_del_file_or_subdir2(server, dentry);
1093#ifdef CONFIG_NCPFS_STRONG
1094 /* 9C is Invalid path.. It should be 8F, 90 - read only, but
1095 it is not :-( */
1096 if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */
1097 error = ncp_force_unlink(dir, dentry);
1098 }
1099#endif
1100 switch (error) {
1101 case 0x00:
1102 DPRINTK("ncp: removed %s/%s\n",
1103 dentry->d_parent->d_name.name, dentry->d_name.name);
1104 break;
1105 case 0x85:
1106 case 0x8A:
1107 error = -EACCES;
1108 break;
1109 case 0x8D: /* some files in use */
1110 case 0x8E: /* all files in use */
1111 error = -EBUSY;
1112 break;
1113 case 0x8F: /* some read only */
1114 case 0x90: /* all read only */
1115 case 0x9C: /* !!! returned when in-use or read-only by NW4 */
1116 error = -EPERM;
1117 break;
1118 case 0xFF:
1119 error = -ENOENT;
1120 break;
1121 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001122 error = error < 0 ? error : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 break;
1124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 return error;
1126}
1127
1128static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
1129 struct inode *new_dir, struct dentry *new_dentry)
1130{
1131 struct ncp_server *server = NCP_SERVER(old_dir);
1132 int error;
1133 int old_len, new_len;
1134 __u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1];
1135
1136 DPRINTK("ncp_rename: %s/%s to %s/%s\n",
1137 old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
1138 new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
1139
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 ncp_age_dentry(server, old_dentry);
1141 ncp_age_dentry(server, new_dentry);
1142
1143 old_len = sizeof(__old_name);
1144 error = ncp_io2vol(server, __old_name, &old_len,
1145 old_dentry->d_name.name, old_dentry->d_name.len,
1146 !ncp_preserve_case(old_dir));
1147 if (error)
1148 goto out;
1149
1150 new_len = sizeof(__new_name);
1151 error = ncp_io2vol(server, __new_name, &new_len,
1152 new_dentry->d_name.name, new_dentry->d_name.len,
1153 !ncp_preserve_case(new_dir));
1154 if (error)
1155 goto out;
1156
1157 error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name,
1158 new_dir, __new_name);
1159#ifdef CONFIG_NCPFS_STRONG
1160 if ((error == 0x90 || error == 0x8B || error == -EACCES) &&
1161 server->m.flags & NCP_MOUNT_STRONG) { /* RO */
1162 error = ncp_force_rename(old_dir, old_dentry, __old_name,
1163 new_dir, new_dentry, __new_name);
1164 }
1165#endif
1166 switch (error) {
1167 case 0x00:
1168 DPRINTK("ncp renamed %s -> %s.\n",
1169 old_dentry->d_name.name,new_dentry->d_name.name);
1170 break;
1171 case 0x9E:
1172 error = -ENAMETOOLONG;
1173 break;
1174 case 0xFF:
1175 error = -ENOENT;
1176 break;
1177 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001178 error = error < 0 ? error : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 break;
1180 }
1181out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 return error;
1183}
1184
1185static int ncp_mknod(struct inode * dir, struct dentry *dentry,
Al Viro1a67aaf2011-07-26 01:52:52 -04001186 umode_t mode, dev_t rdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187{
1188 if (!new_valid_dev(rdev))
1189 return -EINVAL;
1190 if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) {
Al Viro1a67aaf2011-07-26 01:52:52 -04001191 DPRINTK(KERN_DEBUG "ncp_mknod: mode = 0%ho\n", mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 return ncp_create_new(dir, dentry, mode, rdev, 0);
1193 }
1194 return -EPERM; /* Strange, but true */
1195}
1196
1197/* The following routines are taken directly from msdos-fs */
1198
1199/* Linear day numbers of the respective 1sts in non-leap years. */
1200
1201static int day_n[] =
1202{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
1203/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
1204
1205
1206extern struct timezone sys_tz;
1207
1208static int utc2local(int time)
1209{
1210 return time - sys_tz.tz_minuteswest * 60;
1211}
1212
1213static int local2utc(int time)
1214{
1215 return time + sys_tz.tz_minuteswest * 60;
1216}
1217
1218/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
1219int
1220ncp_date_dos2unix(__le16 t, __le16 d)
1221{
1222 unsigned short time = le16_to_cpu(t), date = le16_to_cpu(d);
1223 int month, year, secs;
1224
1225 /* first subtract and mask after that... Otherwise, if
1226 date == 0, bad things happen */
1227 month = ((date >> 5) - 1) & 15;
1228 year = date >> 9;
1229 secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
1230 86400 * ((date & 31) - 1 + day_n[month] + (year / 4) +
1231 year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
1232 /* days since 1.1.70 plus 80's leap day */
1233 return local2utc(secs);
1234}
1235
1236
1237/* Convert linear UNIX date to a MS-DOS time/date pair. */
1238void
1239ncp_date_unix2dos(int unix_date, __le16 *time, __le16 *date)
1240{
1241 int day, year, nl_day, month;
1242
1243 unix_date = utc2local(unix_date);
1244 *time = cpu_to_le16(
1245 (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
1246 (((unix_date / 3600) % 24) << 11));
1247 day = unix_date / 86400 - 3652;
1248 year = day / 365;
1249 if ((year + 3) / 4 + 365 * year > day)
1250 year--;
1251 day -= (year + 3) / 4 + 365 * year;
1252 if (day == 59 && !(year & 3)) {
1253 nl_day = day;
1254 month = 2;
1255 } else {
1256 nl_day = (year & 3) || day <= 59 ? day : day - 1;
Roel Kluinc5df5912009-09-22 16:45:54 -07001257 for (month = 1; month < 12; month++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 if (day_n[month] > nl_day)
1259 break;
1260 }
1261 *date = cpu_to_le16(nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
1262}