blob: c320ac52353e458723f46613893bcc0423ccc463 [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
Al Viro84eb3532013-09-16 10:59:55 -0400342 DDPRINTK("ncp_lookup_validate: %pd2 not valid, age=%ld, server lookup\n",
343 dentry, NCP_GET_AGE(dentry));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
345 len = sizeof(__name);
346 if (ncp_is_server_root(dir)) {
347 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
348 dentry->d_name.len, 1);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200349 if (!res) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 res = ncp_lookup_volume(server, __name, &(finfo.i));
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200351 if (!res)
352 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
353 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 } else {
355 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
356 dentry->d_name.len, !ncp_preserve_case(dir));
357 if (!res)
358 res = ncp_obtain_info(server, dir, __name, &(finfo.i));
359 }
360 finfo.volume = finfo.i.volNumber;
Al Viro84eb3532013-09-16 10:59:55 -0400361 DDPRINTK("ncp_lookup_validate: looked for %pd/%s, res=%d\n",
362 dentry->d_parent, __name, res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 /*
364 * If we didn't find it, or if it has a different dirEntNum to
365 * what we remember, it's not valid any more.
366 */
367 if (!res) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200368 struct inode *inode = dentry->d_inode;
369
370 mutex_lock(&inode->i_mutex);
371 if (finfo.i.dirEntNum == NCP_FINFO(inode)->dirEntNum) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 ncp_new_dentry(dentry);
373 val=1;
374 } else
375 DDPRINTK("ncp_lookup_validate: found, but dirEntNum changed\n");
376
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200377 ncp_update_inode2(inode, &finfo);
378 mutex_unlock(&inode->i_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 }
380
381finished:
382 DDPRINTK("ncp_lookup_validate: result=%d\n", val);
383 dput(parent);
384 return val;
385}
386
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387static struct dentry *
388ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
389{
390 struct dentry *dent = dentry;
391 struct list_head *next;
392
393 if (d_validate(dent, parent)) {
394 if (dent->d_name.len <= NCP_MAXPATHLEN &&
395 (unsigned long)dent->d_fsdata == fpos) {
396 if (!dent->d_inode) {
397 dput(dent);
398 dent = NULL;
399 }
400 return dent;
401 }
402 dput(dent);
403 }
404
405 /* If a pointer is invalid, we search the dentry. */
Nick Piggin2fd6b7f2011-01-07 17:49:34 +1100406 spin_lock(&parent->d_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 next = parent->d_subdirs.next;
408 while (next != &parent->d_subdirs) {
Eric Dumazet5160ee62006-01-08 01:03:32 -0800409 dent = list_entry(next, struct dentry, d_u.d_child);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 if ((unsigned long)dent->d_fsdata == fpos) {
411 if (dent->d_inode)
Nick Piggindc0474b2011-01-07 17:49:43 +1100412 dget(dent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 else
414 dent = NULL;
Nick Piggin2fd6b7f2011-01-07 17:49:34 +1100415 spin_unlock(&parent->d_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 goto out;
417 }
418 next = next->next;
419 }
Nick Piggin2fd6b7f2011-01-07 17:49:34 +1100420 spin_unlock(&parent->d_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 return NULL;
422
423out:
424 return dent;
425}
426
427static time_t ncp_obtain_mtime(struct dentry *dentry)
428{
429 struct inode *inode = dentry->d_inode;
430 struct ncp_server *server = NCP_SERVER(inode);
431 struct nw_info_struct i;
432
433 if (!ncp_conn_valid(server) || ncp_is_server_root(inode))
434 return 0;
435
436 if (ncp_obtain_info(server, inode, NULL, &i))
437 return 0;
438
439 return ncp_date_dos2unix(i.modifyTime, i.modifyDate);
440}
441
Al Viro76f582a2013-05-22 15:11:27 -0400442static int ncp_readdir(struct file *file, struct dir_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443{
Al Viro76f582a2013-05-22 15:11:27 -0400444 struct dentry *dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 struct inode *inode = dentry->d_inode;
446 struct page *page = NULL;
447 struct ncp_server *server = NCP_SERVER(inode);
448 union ncp_dir_cache *cache = NULL;
449 struct ncp_cache_control ctl;
450 int result, mtime_valid = 0;
451 time_t mtime = 0;
452
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 ctl.page = NULL;
454 ctl.cache = NULL;
455
Al Viro84eb3532013-09-16 10:59:55 -0400456 DDPRINTK("ncp_readdir: reading %pD2, pos=%d\n", file,
Al Viro76f582a2013-05-22 15:11:27 -0400457 (int) ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
459 result = -EIO;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200460 /* Do not generate '.' and '..' when server is dead. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 if (!ncp_conn_valid(server))
462 goto out;
463
464 result = 0;
Al Viro76f582a2013-05-22 15:11:27 -0400465 if (!dir_emit_dots(file, ctx))
466 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
468 page = grab_cache_page(&inode->i_data, 0);
469 if (!page)
470 goto read_really;
471
472 ctl.cache = cache = kmap(page);
473 ctl.head = cache->head;
474
475 if (!PageUptodate(page) || !ctl.head.eof)
476 goto init_cache;
477
Al Viro76f582a2013-05-22 15:11:27 -0400478 if (ctx->pos == 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 if (jiffies - ctl.head.time >= NCP_MAX_AGE(server))
480 goto init_cache;
481
482 mtime = ncp_obtain_mtime(dentry);
483 mtime_valid = 1;
484 if ((!mtime) || (mtime != ctl.head.mtime))
485 goto init_cache;
486 }
487
Al Viro76f582a2013-05-22 15:11:27 -0400488 if (ctx->pos > ctl.head.end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 goto finished;
490
Al Viro76f582a2013-05-22 15:11:27 -0400491 ctl.fpos = ctx->pos + (NCP_DIRCACHE_START - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 ctl.ofs = ctl.fpos / NCP_DIRCACHE_SIZE;
493 ctl.idx = ctl.fpos % NCP_DIRCACHE_SIZE;
494
495 for (;;) {
496 if (ctl.ofs != 0) {
497 ctl.page = find_lock_page(&inode->i_data, ctl.ofs);
498 if (!ctl.page)
499 goto invalid_cache;
500 ctl.cache = kmap(ctl.page);
501 if (!PageUptodate(ctl.page))
502 goto invalid_cache;
503 }
504 while (ctl.idx < NCP_DIRCACHE_SIZE) {
505 struct dentry *dent;
Al Viro76f582a2013-05-22 15:11:27 -0400506 bool over;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
508 dent = ncp_dget_fpos(ctl.cache->dentry[ctl.idx],
Al Viro76f582a2013-05-22 15:11:27 -0400509 dentry, ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 if (!dent)
511 goto invalid_cache;
Al Viro76f582a2013-05-22 15:11:27 -0400512 over = !dir_emit(ctx, dent->d_name.name,
513 dent->d_name.len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 dent->d_inode->i_ino, DT_UNKNOWN);
515 dput(dent);
Al Viro76f582a2013-05-22 15:11:27 -0400516 if (over)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 goto finished;
Al Viro76f582a2013-05-22 15:11:27 -0400518 ctx->pos += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 ctl.idx += 1;
Al Viro76f582a2013-05-22 15:11:27 -0400520 if (ctx->pos > ctl.head.end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 goto finished;
522 }
523 if (ctl.page) {
524 kunmap(ctl.page);
525 SetPageUptodate(ctl.page);
526 unlock_page(ctl.page);
527 page_cache_release(ctl.page);
528 ctl.page = NULL;
529 }
530 ctl.idx = 0;
531 ctl.ofs += 1;
532 }
533invalid_cache:
534 if (ctl.page) {
535 kunmap(ctl.page);
536 unlock_page(ctl.page);
537 page_cache_release(ctl.page);
538 ctl.page = NULL;
539 }
540 ctl.cache = cache;
541init_cache:
542 ncp_invalidate_dircache_entries(dentry);
543 if (!mtime_valid) {
544 mtime = ncp_obtain_mtime(dentry);
545 mtime_valid = 1;
546 }
547 ctl.head.mtime = mtime;
548 ctl.head.time = jiffies;
549 ctl.head.eof = 0;
550 ctl.fpos = 2;
551 ctl.ofs = 0;
552 ctl.idx = NCP_DIRCACHE_START;
553 ctl.filled = 0;
554 ctl.valid = 1;
555read_really:
556 if (ncp_is_server_root(inode)) {
Al Viro76f582a2013-05-22 15:11:27 -0400557 ncp_read_volume_list(file, ctx, &ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 } else {
Al Viro76f582a2013-05-22 15:11:27 -0400559 ncp_do_readdir(file, ctx, &ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 }
561 ctl.head.end = ctl.fpos - 1;
562 ctl.head.eof = ctl.valid;
563finished:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200564 if (ctl.page) {
565 kunmap(ctl.page);
566 SetPageUptodate(ctl.page);
567 unlock_page(ctl.page);
568 page_cache_release(ctl.page);
569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 if (page) {
571 cache->head = ctl.head;
572 kunmap(page);
573 SetPageUptodate(page);
574 unlock_page(page);
575 page_cache_release(page);
576 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 return result;
579}
580
581static int
Al Viro76f582a2013-05-22 15:11:27 -0400582ncp_fill_cache(struct file *file, struct dir_context *ctx,
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200583 struct ncp_cache_control *ctrl, struct ncp_entry_info *entry,
584 int inval_childs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585{
Al Viro76f582a2013-05-22 15:11:27 -0400586 struct dentry *newdent, *dentry = file->f_path.dentry;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200587 struct inode *dir = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 struct ncp_cache_control ctl = *ctrl;
589 struct qstr qname;
590 int valid = 0;
591 int hashed = 0;
592 ino_t ino = 0;
593 __u8 __name[NCP_MAXPATHLEN + 1];
594
595 qname.len = sizeof(__name);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200596 if (ncp_vol2io(NCP_SERVER(dir), __name, &qname.len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 entry->i.entryName, entry->i.nameLen,
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200598 !ncp_preserve_entry_case(dir, entry->i.NSCreator)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 return 1; /* I'm not sure */
600
601 qname.name = __name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
Al Viro4f522a22013-02-11 23:20:37 -0500603 newdent = d_hash_and_lookup(dentry, &qname);
604 if (unlikely(IS_ERR(newdent)))
605 goto end_advance;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 if (!newdent) {
607 newdent = d_alloc(dentry, &qname);
608 if (!newdent)
609 goto end_advance;
610 } else {
611 hashed = 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200612
613 /* If case sensitivity changed for this volume, all entries below this one
614 should be thrown away. This entry itself is not affected, as its case
615 sensitivity is controlled by its own parent. */
616 if (inval_childs)
617 shrink_dcache_parent(newdent);
618
619 /*
Nick Pigginfb2d5b82011-01-07 17:49:26 +1100620 * NetWare's OS2 namespace is case preserving yet case
621 * insensitive. So we update dentry's name as received from
622 * server. Parent dir's i_mutex is locked because we're in
623 * readdir.
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200624 */
Nick Pigginfb2d5b82011-01-07 17:49:26 +1100625 dentry_update_name_case(newdent, &qname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 }
627
628 if (!newdent->d_inode) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200629 struct inode *inode;
630
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 entry->opened = 0;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200632 entry->ino = iunique(dir->i_sb, 2);
633 inode = ncp_iget(dir->i_sb, entry);
634 if (inode) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200635 d_instantiate(newdent, inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 if (!hashed)
637 d_rehash(newdent);
638 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200639 } else {
640 struct inode *inode = newdent->d_inode;
641
Nick Pigginfb2d5b82011-01-07 17:49:26 +1100642 mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200643 ncp_update_inode2(inode, entry);
644 mutex_unlock(&inode->i_mutex);
645 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
647 if (newdent->d_inode) {
648 ino = newdent->d_inode->i_ino;
649 newdent->d_fsdata = (void *) ctl.fpos;
650 ncp_new_dentry(newdent);
651 }
652
653 if (ctl.idx >= NCP_DIRCACHE_SIZE) {
654 if (ctl.page) {
655 kunmap(ctl.page);
656 SetPageUptodate(ctl.page);
657 unlock_page(ctl.page);
658 page_cache_release(ctl.page);
659 }
660 ctl.cache = NULL;
661 ctl.idx -= NCP_DIRCACHE_SIZE;
662 ctl.ofs += 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200663 ctl.page = grab_cache_page(&dir->i_data, ctl.ofs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 if (ctl.page)
665 ctl.cache = kmap(ctl.page);
666 }
667 if (ctl.cache) {
668 ctl.cache->dentry[ctl.idx] = newdent;
669 valid = 1;
670 }
671 dput(newdent);
672end_advance:
673 if (!valid)
674 ctl.valid = 0;
Al Viro76f582a2013-05-22 15:11:27 -0400675 if (!ctl.filled && (ctl.fpos == ctx->pos)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 if (!ino)
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200677 ino = iunique(dir->i_sb, 2);
Al Viro76f582a2013-05-22 15:11:27 -0400678 ctl.filled = !dir_emit(ctx, qname.name, qname.len,
679 ino, DT_UNKNOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 if (!ctl.filled)
Al Viro76f582a2013-05-22 15:11:27 -0400681 ctx->pos += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 }
683 ctl.fpos += 1;
684 ctl.idx += 1;
685 *ctrl = ctl;
686 return (ctl.valid || !ctl.filled);
687}
688
689static void
Al Viro76f582a2013-05-22 15:11:27 -0400690ncp_read_volume_list(struct file *file, struct dir_context *ctx,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 struct ncp_cache_control *ctl)
692{
Al Viro76f582a2013-05-22 15:11:27 -0400693 struct dentry *dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 struct inode *inode = dentry->d_inode;
695 struct ncp_server *server = NCP_SERVER(inode);
696 struct ncp_volume_info info;
697 struct ncp_entry_info entry;
698 int i;
699
700 DPRINTK("ncp_read_volume_list: pos=%ld\n",
Al Viro76f582a2013-05-22 15:11:27 -0400701 (unsigned long) ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
703 for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200704 int inval_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
706 if (ncp_get_volume_info_with_number(server, i, &info) != 0)
707 return;
708 if (!strlen(info.volume_name))
709 continue;
710
711 DPRINTK("ncp_read_volume_list: found vol: %s\n",
712 info.volume_name);
713
714 if (ncp_lookup_volume(server, info.volume_name,
715 &entry.i)) {
716 DPRINTK("ncpfs: could not lookup vol %s\n",
717 info.volume_name);
718 continue;
719 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200720 inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 entry.volume = entry.i.volNumber;
Al Viro76f582a2013-05-22 15:11:27 -0400722 if (!ncp_fill_cache(file, ctx, ctl, &entry, inval_dentry))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 return;
724 }
725}
726
727static void
Al Viro76f582a2013-05-22 15:11:27 -0400728ncp_do_readdir(struct file *file, struct dir_context *ctx,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 struct ncp_cache_control *ctl)
730{
Al Viro76f582a2013-05-22 15:11:27 -0400731 struct dentry *dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 struct inode *dir = dentry->d_inode;
733 struct ncp_server *server = NCP_SERVER(dir);
734 struct nw_search_sequence seq;
735 struct ncp_entry_info entry;
736 int err;
737 void* buf;
738 int more;
739 size_t bufsize;
740
Al Viro84eb3532013-09-16 10:59:55 -0400741 DPRINTK("ncp_do_readdir: %pD2, fpos=%ld\n", file,
Al Viro76f582a2013-05-22 15:11:27 -0400742 (unsigned long) ctx->pos);
Al Viro84eb3532013-09-16 10:59:55 -0400743 PPRINTK("ncp_do_readdir: init %pD, volnum=%d, dirent=%u\n",
744 file, NCP_FINFO(dir)->volNumber, NCP_FINFO(dir)->dirEntNum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745
746 err = ncp_initialize_search(server, dir, &seq);
747 if (err) {
748 DPRINTK("ncp_do_readdir: init failed, err=%d\n", err);
749 return;
750 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 /* We MUST NOT use server->buffer_size handshaked with server if we are
752 using UDP, as for UDP server uses max. buffer size determined by
753 MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes).
754 So we use 128KB, just to be sure, as there is no way how to know
755 this value in advance. */
756 bufsize = 131072;
757 buf = vmalloc(bufsize);
758 if (!buf)
759 return;
760 do {
761 int cnt;
762 char* rpl;
763 size_t rpls;
764
765 err = ncp_search_for_fileset(server, &seq, &more, &cnt, buf, bufsize, &rpl, &rpls);
766 if (err) /* Error */
767 break;
768 if (!cnt) /* prevent endless loop */
769 break;
770 while (cnt--) {
771 size_t onerpl;
772
773 if (rpls < offsetof(struct nw_info_struct, entryName))
774 break; /* short packet */
775 ncp_extract_file_info(rpl, &entry.i);
776 onerpl = offsetof(struct nw_info_struct, entryName) + entry.i.nameLen;
777 if (rpls < onerpl)
778 break; /* short packet */
779 (void)ncp_obtain_nfs_info(server, &entry.i);
780 rpl += onerpl;
781 rpls -= onerpl;
782 entry.volume = entry.i.volNumber;
Al Viro76f582a2013-05-22 15:11:27 -0400783 if (!ncp_fill_cache(file, ctx, ctl, &entry, 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 break;
785 }
786 } while (more);
787 vfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 return;
789}
790
791int ncp_conn_logged_in(struct super_block *sb)
792{
793 struct ncp_server* server = NCP_SBP(sb);
794 int result;
795
796 if (ncp_single_volume(server)) {
797 int len;
798 struct dentry* dent;
799 __u32 volNumber;
800 __le32 dirEntNum;
801 __le32 DosDirNum;
802 __u8 __name[NCP_MAXPATHLEN + 1];
803
804 len = sizeof(__name);
805 result = ncp_io2vol(server, __name, &len, server->m.mounted_vol,
806 strlen(server->m.mounted_vol), 1);
807 if (result)
808 goto out;
809 result = -ENOENT;
810 if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) {
811 PPRINTK("ncp_conn_logged_in: %s not found\n",
812 server->m.mounted_vol);
813 goto out;
814 }
815 dent = sb->s_root;
816 if (dent) {
817 struct inode* ino = dent->d_inode;
818 if (ino) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200819 ncp_update_known_namespace(server, volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 NCP_FINFO(ino)->volNumber = volNumber;
821 NCP_FINFO(ino)->dirEntNum = dirEntNum;
822 NCP_FINFO(ino)->DosDirNum = DosDirNum;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200823 result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 } else {
825 DPRINTK("ncpfs: sb->s_root->d_inode == NULL!\n");
826 }
827 } else {
828 DPRINTK("ncpfs: sb->s_root == NULL!\n");
829 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200830 } else
831 result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
833out:
834 return result;
835}
836
Al Viro00cd8dd2012-06-10 17:13:09 -0400837static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838{
839 struct ncp_server *server = NCP_SERVER(dir);
840 struct inode *inode = NULL;
841 struct ncp_entry_info finfo;
842 int error, res, len;
843 __u8 __name[NCP_MAXPATHLEN + 1];
844
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 error = -EIO;
846 if (!ncp_conn_valid(server))
847 goto finished;
848
Al Viro84eb3532013-09-16 10:59:55 -0400849 PPRINTK("ncp_lookup: server lookup for %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
851 len = sizeof(__name);
852 if (ncp_is_server_root(dir)) {
853 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
854 dentry->d_name.len, 1);
855 if (!res)
856 res = ncp_lookup_volume(server, __name, &(finfo.i));
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200857 if (!res)
858 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 } else {
860 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
861 dentry->d_name.len, !ncp_preserve_case(dir));
862 if (!res)
863 res = ncp_obtain_info(server, dir, __name, &(finfo.i));
864 }
Al Viro84eb3532013-09-16 10:59:55 -0400865 PPRINTK("ncp_lookup: looked for %pd2, res=%d\n", dentry, res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 /*
867 * If we didn't find an entry, make a negative dentry.
868 */
869 if (res)
870 goto add_entry;
871
872 /*
873 * Create an inode for the entry.
874 */
875 finfo.opened = 0;
876 finfo.ino = iunique(dir->i_sb, 2);
877 finfo.volume = finfo.i.volNumber;
878 error = -EACCES;
879 inode = ncp_iget(dir->i_sb, &finfo);
880
881 if (inode) {
882 ncp_new_dentry(dentry);
883add_entry:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 d_add(dentry, inode);
885 error = 0;
886 }
887
888finished:
889 PPRINTK("ncp_lookup: result=%d\n", error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 return ERR_PTR(error);
891}
892
893/*
894 * This code is common to create, mkdir, and mknod.
895 */
896static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
897 struct ncp_entry_info *finfo)
898{
899 struct inode *inode;
900 int error = -EINVAL;
901
902 finfo->ino = iunique(dir->i_sb, 2);
903 inode = ncp_iget(dir->i_sb, finfo);
904 if (!inode)
905 goto out_close;
906 d_instantiate(dentry,inode);
907 error = 0;
908out:
909 return error;
910
911out_close:
Al Viro84eb3532013-09-16 10:59:55 -0400912 PPRINTK("ncp_instantiate: %pd2 failed, closing file\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 ncp_close_file(NCP_SERVER(dir), finfo->file_handle);
914 goto out;
915}
916
Al Viro5eee25c2011-07-26 03:12:16 -0400917int ncp_create_new(struct inode *dir, struct dentry *dentry, umode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 dev_t rdev, __le32 attributes)
919{
920 struct ncp_server *server = NCP_SERVER(dir);
921 struct ncp_entry_info finfo;
922 int error, result, len;
923 int opmode;
924 __u8 __name[NCP_MAXPATHLEN + 1];
925
Al Viro84eb3532013-09-16 10:59:55 -0400926 PPRINTK("ncp_create_new: creating %pd2, mode=%hx\n", dentry, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 ncp_age_dentry(server, dentry);
929 len = sizeof(__name);
930 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
931 dentry->d_name.len, !ncp_preserve_case(dir));
932 if (error)
933 goto out;
934
935 error = -EACCES;
936
937 if (S_ISREG(mode) &&
938 (server->m.flags & NCP_MOUNT_EXTRAS) &&
939 (mode & S_IXUGO))
940 attributes |= aSYSTEM | aSHARED;
941
942 result = ncp_open_create_file_or_subdir(server, dir, __name,
943 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
944 attributes, AR_READ | AR_WRITE, &finfo);
945 opmode = O_RDWR;
946 if (result) {
947 result = ncp_open_create_file_or_subdir(server, dir, __name,
948 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
949 attributes, AR_WRITE, &finfo);
950 if (result) {
951 if (result == 0x87)
952 error = -ENAMETOOLONG;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200953 else if (result < 0)
954 error = result;
Al Viro84eb3532013-09-16 10:59:55 -0400955 DPRINTK("ncp_create: %pd2 failed\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 goto out;
957 }
958 opmode = O_WRONLY;
959 }
960 finfo.access = opmode;
961 if (ncp_is_nfs_extras(server, finfo.volume)) {
962 finfo.i.nfs.mode = mode;
963 finfo.i.nfs.rdev = new_encode_dev(rdev);
964 if (ncp_modify_nfs_info(server, finfo.volume,
965 finfo.i.dirEntNum,
966 mode, new_encode_dev(rdev)) != 0)
967 goto out;
968 }
969
970 error = ncp_instantiate(dir, dentry, &finfo);
971out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 return error;
973}
974
Al Viro4acdaf22011-07-26 01:42:34 -0400975static int ncp_create(struct inode *dir, struct dentry *dentry, umode_t mode,
Al Viroebfc3b42012-06-10 18:05:36 -0400976 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977{
978 return ncp_create_new(dir, dentry, mode, 0, 0);
979}
980
Al Viro18bb1db2011-07-26 01:41:39 -0400981static int ncp_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982{
983 struct ncp_entry_info finfo;
984 struct ncp_server *server = NCP_SERVER(dir);
985 int error, len;
986 __u8 __name[NCP_MAXPATHLEN + 1];
987
Al Viro84eb3532013-09-16 10:59:55 -0400988 DPRINTK("ncp_mkdir: making %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 ncp_age_dentry(server, dentry);
991 len = sizeof(__name);
992 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
993 dentry->d_name.len, !ncp_preserve_case(dir));
994 if (error)
995 goto out;
996
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200997 error = ncp_open_create_file_or_subdir(server, dir, __name,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 OC_MODE_CREATE, aDIR,
999 cpu_to_le16(0xffff),
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001000 &finfo);
1001 if (error == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 if (ncp_is_nfs_extras(server, finfo.volume)) {
1003 mode |= S_IFDIR;
1004 finfo.i.nfs.mode = mode;
1005 if (ncp_modify_nfs_info(server,
1006 finfo.volume,
1007 finfo.i.dirEntNum,
1008 mode, 0) != 0)
1009 goto out;
1010 }
1011 error = ncp_instantiate(dir, dentry, &finfo);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001012 } else if (error > 0) {
1013 error = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 }
1015out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 return error;
1017}
1018
1019static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
1020{
1021 struct ncp_server *server = NCP_SERVER(dir);
1022 int error, result, len;
1023 __u8 __name[NCP_MAXPATHLEN + 1];
1024
Al Viro84eb3532013-09-16 10:59:55 -04001025 DPRINTK("ncp_rmdir: removing %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 len = sizeof(__name);
1028 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
1029 dentry->d_name.len, !ncp_preserve_case(dir));
1030 if (error)
1031 goto out;
1032
1033 result = ncp_del_file_or_subdir(server, dir, __name);
1034 switch (result) {
1035 case 0x00:
1036 error = 0;
1037 break;
1038 case 0x85: /* unauthorized to delete file */
1039 case 0x8A: /* unauthorized to delete file */
1040 error = -EACCES;
1041 break;
1042 case 0x8F:
1043 case 0x90: /* read only */
1044 error = -EPERM;
1045 break;
1046 case 0x9F: /* in use by another client */
1047 error = -EBUSY;
1048 break;
1049 case 0xA0: /* directory not empty */
1050 error = -ENOTEMPTY;
1051 break;
1052 case 0xFF: /* someone deleted file */
1053 error = -ENOENT;
1054 break;
1055 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001056 error = result < 0 ? result : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 break;
1058 }
1059out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 return error;
1061}
1062
1063static int ncp_unlink(struct inode *dir, struct dentry *dentry)
1064{
1065 struct inode *inode = dentry->d_inode;
1066 struct ncp_server *server;
1067 int error;
1068
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 server = NCP_SERVER(dir);
Al Viro84eb3532013-09-16 10:59:55 -04001070 DPRINTK("ncp_unlink: unlinking %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 /*
1073 * Check whether to close the file ...
1074 */
1075 if (inode) {
1076 PPRINTK("ncp_unlink: closing file\n");
1077 ncp_make_closed(inode);
1078 }
1079
1080 error = ncp_del_file_or_subdir2(server, dentry);
1081#ifdef CONFIG_NCPFS_STRONG
1082 /* 9C is Invalid path.. It should be 8F, 90 - read only, but
1083 it is not :-( */
1084 if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */
1085 error = ncp_force_unlink(dir, dentry);
1086 }
1087#endif
1088 switch (error) {
1089 case 0x00:
Al Viro84eb3532013-09-16 10:59:55 -04001090 DPRINTK("ncp: removed %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 break;
1092 case 0x85:
1093 case 0x8A:
1094 error = -EACCES;
1095 break;
1096 case 0x8D: /* some files in use */
1097 case 0x8E: /* all files in use */
1098 error = -EBUSY;
1099 break;
1100 case 0x8F: /* some read only */
1101 case 0x90: /* all read only */
1102 case 0x9C: /* !!! returned when in-use or read-only by NW4 */
1103 error = -EPERM;
1104 break;
1105 case 0xFF:
1106 error = -ENOENT;
1107 break;
1108 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001109 error = error < 0 ? error : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 break;
1111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 return error;
1113}
1114
1115static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
1116 struct inode *new_dir, struct dentry *new_dentry)
1117{
1118 struct ncp_server *server = NCP_SERVER(old_dir);
1119 int error;
1120 int old_len, new_len;
1121 __u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1];
1122
Al Viro84eb3532013-09-16 10:59:55 -04001123 DPRINTK("ncp_rename: %pd2 to %pd2\n", old_dentry, new_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 ncp_age_dentry(server, old_dentry);
1126 ncp_age_dentry(server, new_dentry);
1127
1128 old_len = sizeof(__old_name);
1129 error = ncp_io2vol(server, __old_name, &old_len,
1130 old_dentry->d_name.name, old_dentry->d_name.len,
1131 !ncp_preserve_case(old_dir));
1132 if (error)
1133 goto out;
1134
1135 new_len = sizeof(__new_name);
1136 error = ncp_io2vol(server, __new_name, &new_len,
1137 new_dentry->d_name.name, new_dentry->d_name.len,
1138 !ncp_preserve_case(new_dir));
1139 if (error)
1140 goto out;
1141
1142 error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name,
1143 new_dir, __new_name);
1144#ifdef CONFIG_NCPFS_STRONG
1145 if ((error == 0x90 || error == 0x8B || error == -EACCES) &&
1146 server->m.flags & NCP_MOUNT_STRONG) { /* RO */
1147 error = ncp_force_rename(old_dir, old_dentry, __old_name,
1148 new_dir, new_dentry, __new_name);
1149 }
1150#endif
1151 switch (error) {
1152 case 0x00:
Al Viro84eb3532013-09-16 10:59:55 -04001153 DPRINTK("ncp renamed %pd -> %pd.\n",
1154 old_dentry, new_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 break;
1156 case 0x9E:
1157 error = -ENAMETOOLONG;
1158 break;
1159 case 0xFF:
1160 error = -ENOENT;
1161 break;
1162 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001163 error = error < 0 ? error : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 break;
1165 }
1166out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 return error;
1168}
1169
1170static int ncp_mknod(struct inode * dir, struct dentry *dentry,
Al Viro1a67aaf2011-07-26 01:52:52 -04001171 umode_t mode, dev_t rdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172{
1173 if (!new_valid_dev(rdev))
1174 return -EINVAL;
1175 if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) {
Al Viro1a67aaf2011-07-26 01:52:52 -04001176 DPRINTK(KERN_DEBUG "ncp_mknod: mode = 0%ho\n", mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 return ncp_create_new(dir, dentry, mode, rdev, 0);
1178 }
1179 return -EPERM; /* Strange, but true */
1180}
1181
1182/* The following routines are taken directly from msdos-fs */
1183
1184/* Linear day numbers of the respective 1sts in non-leap years. */
1185
1186static int day_n[] =
1187{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
1188/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
1189
1190
1191extern struct timezone sys_tz;
1192
1193static int utc2local(int time)
1194{
1195 return time - sys_tz.tz_minuteswest * 60;
1196}
1197
1198static int local2utc(int time)
1199{
1200 return time + sys_tz.tz_minuteswest * 60;
1201}
1202
1203/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
1204int
1205ncp_date_dos2unix(__le16 t, __le16 d)
1206{
1207 unsigned short time = le16_to_cpu(t), date = le16_to_cpu(d);
1208 int month, year, secs;
1209
1210 /* first subtract and mask after that... Otherwise, if
1211 date == 0, bad things happen */
1212 month = ((date >> 5) - 1) & 15;
1213 year = date >> 9;
1214 secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
1215 86400 * ((date & 31) - 1 + day_n[month] + (year / 4) +
1216 year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
1217 /* days since 1.1.70 plus 80's leap day */
1218 return local2utc(secs);
1219}
1220
1221
1222/* Convert linear UNIX date to a MS-DOS time/date pair. */
1223void
1224ncp_date_unix2dos(int unix_date, __le16 *time, __le16 *date)
1225{
1226 int day, year, nl_day, month;
1227
1228 unix_date = utc2local(unix_date);
1229 *time = cpu_to_le16(
1230 (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
1231 (((unix_date / 3600) % 24) << 11));
1232 day = unix_date / 86400 - 3652;
1233 year = day / 365;
1234 if ((year + 3) / 4 + 365 * year > day)
1235 year--;
1236 day -= (year + 3) / 4 + 365 * year;
1237 if (day == 59 && !(year & 3)) {
1238 nl_day = day;
1239 month = 2;
1240 } else {
1241 nl_day = (year & 3) || day <= 59 ? day : day - 1;
Roel Kluinc5df5912009-09-22 16:45:54 -07001242 for (month = 1; month < 12; month++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 if (day_n[month] > nl_day)
1244 break;
1245 }
1246 *date = cpu_to_le16(nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
1247}