blob: f0e3e9e747dd72aaa756611cb0c881d19b902d5a [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 *);
Al Viro5e993e22014-12-24 21:41:47 -050080static void ncp_d_prune(struct dentry *dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
Al Viro0378c402011-01-12 17:25:03 -050082const struct dentry_operations ncp_dentry_operations =
Linus Torvalds1da177e2005-04-16 15:20:36 -070083{
84 .d_revalidate = ncp_lookup_validate,
85 .d_hash = ncp_hash_dentry,
86 .d_compare = ncp_compare_dentry,
87 .d_delete = ncp_delete_dentry,
Al Viro5e993e22014-12-24 21:41:47 -050088 .d_prune = ncp_d_prune,
Linus Torvalds1da177e2005-04-16 15:20:36 -070089};
90
Petr Vandrovec2e54eb92010-09-27 01:47:33 +020091#define ncp_namespace(i) (NCP_SERVER(i)->name_space[NCP_FINFO(i)->volNumber])
92
93static inline int ncp_preserve_entry_case(struct inode *i, __u32 nscreator)
94{
95#ifdef CONFIG_NCPFS_SMALLDOS
96 int ns = ncp_namespace(i);
97
98 if ((ns == NW_NS_DOS)
99#ifdef CONFIG_NCPFS_OS2_NS
100 || ((ns == NW_NS_OS2) && (nscreator == NW_NS_DOS))
101#endif /* CONFIG_NCPFS_OS2_NS */
102 )
103 return 0;
104#endif /* CONFIG_NCPFS_SMALLDOS */
105 return 1;
106}
107
108#define ncp_preserve_case(i) (ncp_namespace(i) != NW_NS_DOS)
109
Nick Piggin621e1552011-01-07 17:49:27 +1100110static inline int ncp_case_sensitive(const struct inode *i)
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200111{
112#ifdef CONFIG_NCPFS_NFS_NS
Nick Piggin621e1552011-01-07 17:49:27 +1100113 return ncp_namespace(i) == NW_NS_NFS;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200114#else
115 return 0;
116#endif /* CONFIG_NCPFS_NFS_NS */
117}
118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119/*
120 * Note: leave the hash unchanged if the directory
121 * is case-sensitive.
Linus Torvaldsda53be12013-05-21 15:22:44 -0700122 *
123 * Accessing the parent inode can be racy under RCU pathwalking.
124 * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
125 * the callers will handle races.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 */
127static int
Linus Torvaldsda53be12013-05-21 15:22:44 -0700128ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129{
David Howells2b0143b2015-03-17 22:25:59 +0000130 struct inode *inode = d_inode_rcu(dentry);
Linus Torvaldsda53be12013-05-21 15:22:44 -0700131
132 if (!inode)
133 return 0;
134
Nick Pigginb1e6a012011-01-07 17:49:28 +1100135 if (!ncp_case_sensitive(inode)) {
Nick Piggin621e1552011-01-07 17:49:27 +1100136 struct super_block *sb = dentry->d_sb;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200137 struct nls_table *t;
138 unsigned long hash;
139 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140
Nick Piggin621e1552011-01-07 17:49:27 +1100141 t = NCP_IO_TABLE(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 hash = init_name_hash();
143 for (i=0; i<this->len ; i++)
144 hash = partial_name_hash(ncp_tolower(t, this->name[i]),
145 hash);
146 this->hash = end_name_hash(hash);
147 }
148 return 0;
149}
150
Linus Torvaldsda53be12013-05-21 15:22:44 -0700151/*
152 * Accessing the parent inode can be racy under RCU pathwalking.
153 * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
154 * the callers will handle races.
155 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156static int
Linus Torvaldsda53be12013-05-21 15:22:44 -0700157ncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
Nick Piggin621e1552011-01-07 17:49:27 +1100158 unsigned int len, const char *str, const struct qstr *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159{
Linus Torvaldsda53be12013-05-21 15:22:44 -0700160 struct inode *pinode;
161
Nick Piggin621e1552011-01-07 17:49:27 +1100162 if (len != name->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 return 1;
164
David Howells2b0143b2015-03-17 22:25:59 +0000165 pinode = d_inode_rcu(parent);
Linus Torvaldsda53be12013-05-21 15:22:44 -0700166 if (!pinode)
167 return 1;
168
Nick Piggin621e1552011-01-07 17:49:27 +1100169 if (ncp_case_sensitive(pinode))
170 return strncmp(str, name->name, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
Nick Piggin621e1552011-01-07 17:49:27 +1100172 return ncp_strnicmp(NCP_IO_TABLE(pinode->i_sb), str, name->name, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173}
174
175/*
176 * This is the callback from dput() when d_count is going to 0.
177 * We use this to unhash dentries with bad inodes.
178 * Closing files can be safely postponed until iput() - it's done there anyway.
179 */
180static int
Nick Pigginfe15ce42011-01-07 17:49:23 +1100181ncp_delete_dentry(const struct dentry * dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182{
David Howells2b0143b2015-03-17 22:25:59 +0000183 struct inode *inode = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
185 if (inode) {
186 if (is_bad_inode(inode))
187 return 1;
188 } else
189 {
190 /* N.B. Unhash negative dentries? */
191 }
192 return 0;
193}
194
195static inline int
196ncp_single_volume(struct ncp_server *server)
197{
198 return (server->m.mounted_vol[0] != '\0');
199}
200
201static inline int ncp_is_server_root(struct inode *inode)
202{
Al Viroa7400222014-10-21 15:20:42 -0400203 return !ncp_single_volume(NCP_SERVER(inode)) &&
204 is_root_inode(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205}
206
207
208/*
209 * This is the callback when the dcache has a lookup hit.
210 */
211
212
213#ifdef CONFIG_NCPFS_STRONG
214/* try to delete a readonly file (NW R bit set) */
215
216static int
217ncp_force_unlink(struct inode *dir, struct dentry* dentry)
218{
219 int res=0x9c,res2;
220 struct nw_modify_dos_info info;
221 __le32 old_nwattr;
222 struct inode *inode;
223
224 memset(&info, 0, sizeof(info));
225
226 /* remove the Read-Only flag on the NW server */
David Howells2b0143b2015-03-17 22:25:59 +0000227 inode = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
229 old_nwattr = NCP_FINFO(inode)->nwattr;
230 info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT);
231 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
232 if (res2)
233 goto leave_me;
234
235 /* now try again the delete operation */
236 res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
237
238 if (res) /* delete failed, set R bit again */
239 {
240 info.attributes = old_nwattr;
241 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
242 if (res2)
243 goto leave_me;
244 }
245leave_me:
246 return(res);
247}
248#endif /* CONFIG_NCPFS_STRONG */
249
250#ifdef CONFIG_NCPFS_STRONG
251static int
252ncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name,
253 struct inode *new_dir, struct dentry* new_dentry, char *_new_name)
254{
255 struct nw_modify_dos_info info;
256 int res=0x90,res2;
David Howells2b0143b2015-03-17 22:25:59 +0000257 struct inode *old_inode = d_inode(old_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 __le32 old_nwattr = NCP_FINFO(old_inode)->nwattr;
259 __le32 new_nwattr = 0; /* shut compiler warning */
260 int old_nwattr_changed = 0;
261 int new_nwattr_changed = 0;
262
263 memset(&info, 0, sizeof(info));
264
265 /* remove the Read-Only flag on the NW server */
266
267 info.attributes = old_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
268 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
269 if (!res2)
270 old_nwattr_changed = 1;
David Howells2b0143b2015-03-17 22:25:59 +0000271 if (new_dentry && d_really_is_positive(new_dentry)) {
272 new_nwattr = NCP_FINFO(d_inode(new_dentry))->nwattr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
274 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
275 if (!res2)
276 new_nwattr_changed = 1;
277 }
278 /* now try again the rename operation */
279 /* but only if something really happened */
280 if (new_nwattr_changed || old_nwattr_changed) {
281 res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
282 old_dir, _old_name,
283 new_dir, _new_name);
284 }
285 if (res)
286 goto leave_me;
287 /* file was successfully renamed, so:
288 do not set attributes on old file - it no longer exists
289 copy attributes from old file to new */
290 new_nwattr_changed = old_nwattr_changed;
291 new_nwattr = old_nwattr;
292 old_nwattr_changed = 0;
293
294leave_me:;
295 if (old_nwattr_changed) {
296 info.attributes = old_nwattr;
297 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
298 /* ignore errors */
299 }
300 if (new_nwattr_changed) {
301 info.attributes = new_nwattr;
302 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
303 /* ignore errors */
304 }
305 return(res);
306}
307#endif /* CONFIG_NCPFS_STRONG */
308
309
310static int
Al Viro0b728e12012-06-10 16:03:43 -0400311ncp_lookup_validate(struct dentry *dentry, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312{
313 struct ncp_server *server;
314 struct dentry *parent;
315 struct inode *dir;
316 struct ncp_entry_info finfo;
317 int res, val = 0, len;
318 __u8 __name[NCP_MAXPATHLEN + 1];
319
Al Viro0378c402011-01-12 17:25:03 -0500320 if (dentry == dentry->d_sb->s_root)
321 return 1;
322
Al Viro0b728e12012-06-10 16:03:43 -0400323 if (flags & LOOKUP_RCU)
Nick Piggin34286d62011-01-07 17:49:57 +1100324 return -ECHILD;
325
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 parent = dget_parent(dentry);
David Howells2b0143b2015-03-17 22:25:59 +0000327 dir = d_inode(parent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328
David Howells2b0143b2015-03-17 22:25:59 +0000329 if (d_really_is_negative(dentry))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 goto finished;
331
332 server = NCP_SERVER(dir);
333
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 /*
335 * Inspired by smbfs:
336 * The default validation is based on dentry age:
337 * We set the max age at mount time. (But each
338 * successful server lookup renews the timestamp.)
339 */
340 val = NCP_TEST_AGE(server, dentry);
341 if (val)
342 goto finished;
343
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700344 ncp_dbg(2, "%pd2 not valid, age=%ld, server lookup\n",
Al Viro84eb3532013-09-16 10:59:55 -0400345 dentry, NCP_GET_AGE(dentry));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346
347 len = sizeof(__name);
348 if (ncp_is_server_root(dir)) {
349 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
350 dentry->d_name.len, 1);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200351 if (!res) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 res = ncp_lookup_volume(server, __name, &(finfo.i));
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200353 if (!res)
354 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
355 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 } else {
357 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
358 dentry->d_name.len, !ncp_preserve_case(dir));
359 if (!res)
360 res = ncp_obtain_info(server, dir, __name, &(finfo.i));
361 }
362 finfo.volume = finfo.i.volNumber;
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700363 ncp_dbg(2, "looked for %pd/%s, res=%d\n",
Al Viro84eb3532013-09-16 10:59:55 -0400364 dentry->d_parent, __name, res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 /*
366 * If we didn't find it, or if it has a different dirEntNum to
367 * what we remember, it's not valid any more.
368 */
369 if (!res) {
David Howells2b0143b2015-03-17 22:25:59 +0000370 struct inode *inode = d_inode(dentry);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200371
372 mutex_lock(&inode->i_mutex);
373 if (finfo.i.dirEntNum == NCP_FINFO(inode)->dirEntNum) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 ncp_new_dentry(dentry);
375 val=1;
376 } else
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700377 ncp_dbg(2, "found, but dirEntNum changed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200379 ncp_update_inode2(inode, &finfo);
380 mutex_unlock(&inode->i_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 }
382
383finished:
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700384 ncp_dbg(2, "result=%d\n", val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 dput(parent);
386 return val;
387}
388
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389static time_t ncp_obtain_mtime(struct dentry *dentry)
390{
David Howells2b0143b2015-03-17 22:25:59 +0000391 struct inode *inode = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 struct ncp_server *server = NCP_SERVER(inode);
393 struct nw_info_struct i;
394
395 if (!ncp_conn_valid(server) || ncp_is_server_root(inode))
396 return 0;
397
398 if (ncp_obtain_info(server, inode, NULL, &i))
399 return 0;
400
401 return ncp_date_dos2unix(i.modifyTime, i.modifyDate);
402}
403
Al Viro5e993e22014-12-24 21:41:47 -0500404static inline void
405ncp_invalidate_dircache_entries(struct dentry *parent)
406{
David Howells2b0143b2015-03-17 22:25:59 +0000407 struct ncp_server *server = NCP_SERVER(d_inode(parent));
Al Viro5e993e22014-12-24 21:41:47 -0500408 struct dentry *dentry;
409
410 spin_lock(&parent->d_lock);
411 list_for_each_entry(dentry, &parent->d_subdirs, d_child) {
412 dentry->d_fsdata = NULL;
413 ncp_age_dentry(server, dentry);
414 }
415 spin_unlock(&parent->d_lock);
416}
417
Al Viro76f582a2013-05-22 15:11:27 -0400418static int ncp_readdir(struct file *file, struct dir_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419{
Al Viro76f582a2013-05-22 15:11:27 -0400420 struct dentry *dentry = file->f_path.dentry;
David Howells2b0143b2015-03-17 22:25:59 +0000421 struct inode *inode = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 struct page *page = NULL;
423 struct ncp_server *server = NCP_SERVER(inode);
424 union ncp_dir_cache *cache = NULL;
425 struct ncp_cache_control ctl;
426 int result, mtime_valid = 0;
427 time_t mtime = 0;
428
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 ctl.page = NULL;
430 ctl.cache = NULL;
431
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700432 ncp_dbg(2, "reading %pD2, pos=%d\n", file, (int)ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433
434 result = -EIO;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200435 /* Do not generate '.' and '..' when server is dead. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 if (!ncp_conn_valid(server))
437 goto out;
438
439 result = 0;
Al Viro76f582a2013-05-22 15:11:27 -0400440 if (!dir_emit_dots(file, ctx))
441 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
443 page = grab_cache_page(&inode->i_data, 0);
444 if (!page)
445 goto read_really;
446
447 ctl.cache = cache = kmap(page);
448 ctl.head = cache->head;
449
450 if (!PageUptodate(page) || !ctl.head.eof)
451 goto init_cache;
452
Al Viro76f582a2013-05-22 15:11:27 -0400453 if (ctx->pos == 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 if (jiffies - ctl.head.time >= NCP_MAX_AGE(server))
455 goto init_cache;
456
457 mtime = ncp_obtain_mtime(dentry);
458 mtime_valid = 1;
459 if ((!mtime) || (mtime != ctl.head.mtime))
460 goto init_cache;
461 }
462
Al Viro76f582a2013-05-22 15:11:27 -0400463 if (ctx->pos > ctl.head.end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 goto finished;
465
Al Viro76f582a2013-05-22 15:11:27 -0400466 ctl.fpos = ctx->pos + (NCP_DIRCACHE_START - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 ctl.ofs = ctl.fpos / NCP_DIRCACHE_SIZE;
468 ctl.idx = ctl.fpos % NCP_DIRCACHE_SIZE;
469
470 for (;;) {
471 if (ctl.ofs != 0) {
472 ctl.page = find_lock_page(&inode->i_data, ctl.ofs);
473 if (!ctl.page)
474 goto invalid_cache;
475 ctl.cache = kmap(ctl.page);
476 if (!PageUptodate(ctl.page))
477 goto invalid_cache;
478 }
479 while (ctl.idx < NCP_DIRCACHE_SIZE) {
480 struct dentry *dent;
Al Viro76f582a2013-05-22 15:11:27 -0400481 bool over;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
Al Viro5e993e22014-12-24 21:41:47 -0500483 spin_lock(&dentry->d_lock);
484 if (!(NCP_FINFO(inode)->flags & NCPI_DIR_CACHE)) {
485 spin_unlock(&dentry->d_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 goto invalid_cache;
Al Viro5e993e22014-12-24 21:41:47 -0500487 }
488 dent = ctl.cache->dentry[ctl.idx];
489 if (unlikely(!lockref_get_not_dead(&dent->d_lockref))) {
490 spin_unlock(&dentry->d_lock);
491 goto invalid_cache;
492 }
493 spin_unlock(&dentry->d_lock);
David Howells2b0143b2015-03-17 22:25:59 +0000494 if (d_really_is_negative(dent)) {
Al Viro5e993e22014-12-24 21:41:47 -0500495 dput(dent);
496 goto invalid_cache;
497 }
Al Viro76f582a2013-05-22 15:11:27 -0400498 over = !dir_emit(ctx, dent->d_name.name,
499 dent->d_name.len,
David Howells2b0143b2015-03-17 22:25:59 +0000500 d_inode(dent)->i_ino, DT_UNKNOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 dput(dent);
Al Viro76f582a2013-05-22 15:11:27 -0400502 if (over)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 goto finished;
Al Viro76f582a2013-05-22 15:11:27 -0400504 ctx->pos += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 ctl.idx += 1;
Al Viro76f582a2013-05-22 15:11:27 -0400506 if (ctx->pos > ctl.head.end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 goto finished;
508 }
509 if (ctl.page) {
510 kunmap(ctl.page);
511 SetPageUptodate(ctl.page);
512 unlock_page(ctl.page);
513 page_cache_release(ctl.page);
514 ctl.page = NULL;
515 }
516 ctl.idx = 0;
517 ctl.ofs += 1;
518 }
519invalid_cache:
520 if (ctl.page) {
521 kunmap(ctl.page);
522 unlock_page(ctl.page);
523 page_cache_release(ctl.page);
524 ctl.page = NULL;
525 }
526 ctl.cache = cache;
527init_cache:
528 ncp_invalidate_dircache_entries(dentry);
529 if (!mtime_valid) {
530 mtime = ncp_obtain_mtime(dentry);
531 mtime_valid = 1;
532 }
533 ctl.head.mtime = mtime;
534 ctl.head.time = jiffies;
535 ctl.head.eof = 0;
536 ctl.fpos = 2;
537 ctl.ofs = 0;
538 ctl.idx = NCP_DIRCACHE_START;
539 ctl.filled = 0;
540 ctl.valid = 1;
541read_really:
Al Viro5e993e22014-12-24 21:41:47 -0500542 spin_lock(&dentry->d_lock);
543 NCP_FINFO(inode)->flags |= NCPI_DIR_CACHE;
544 spin_unlock(&dentry->d_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 if (ncp_is_server_root(inode)) {
Al Viro76f582a2013-05-22 15:11:27 -0400546 ncp_read_volume_list(file, ctx, &ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 } else {
Al Viro76f582a2013-05-22 15:11:27 -0400548 ncp_do_readdir(file, ctx, &ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 }
550 ctl.head.end = ctl.fpos - 1;
551 ctl.head.eof = ctl.valid;
552finished:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200553 if (ctl.page) {
554 kunmap(ctl.page);
555 SetPageUptodate(ctl.page);
556 unlock_page(ctl.page);
557 page_cache_release(ctl.page);
558 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 if (page) {
560 cache->head = ctl.head;
561 kunmap(page);
562 SetPageUptodate(page);
563 unlock_page(page);
564 page_cache_release(page);
565 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 return result;
568}
569
Al Viro5e993e22014-12-24 21:41:47 -0500570static void ncp_d_prune(struct dentry *dentry)
571{
572 if (!dentry->d_fsdata) /* not referenced from page cache */
573 return;
David Howells2b0143b2015-03-17 22:25:59 +0000574 NCP_FINFO(d_inode(dentry->d_parent))->flags &= ~NCPI_DIR_CACHE;
Al Viro5e993e22014-12-24 21:41:47 -0500575}
576
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577static int
Al Viro76f582a2013-05-22 15:11:27 -0400578ncp_fill_cache(struct file *file, struct dir_context *ctx,
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200579 struct ncp_cache_control *ctrl, struct ncp_entry_info *entry,
580 int inval_childs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581{
Al Viro76f582a2013-05-22 15:11:27 -0400582 struct dentry *newdent, *dentry = file->f_path.dentry;
David Howells2b0143b2015-03-17 22:25:59 +0000583 struct inode *dir = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 struct ncp_cache_control ctl = *ctrl;
585 struct qstr qname;
586 int valid = 0;
587 int hashed = 0;
588 ino_t ino = 0;
589 __u8 __name[NCP_MAXPATHLEN + 1];
590
591 qname.len = sizeof(__name);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200592 if (ncp_vol2io(NCP_SERVER(dir), __name, &qname.len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 entry->i.entryName, entry->i.nameLen,
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200594 !ncp_preserve_entry_case(dir, entry->i.NSCreator)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 return 1; /* I'm not sure */
596
597 qname.name = __name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598
Al Viro4f522a22013-02-11 23:20:37 -0500599 newdent = d_hash_and_lookup(dentry, &qname);
Viresh Kumara1c83682015-08-12 15:59:44 +0530600 if (IS_ERR(newdent))
Al Viro4f522a22013-02-11 23:20:37 -0500601 goto end_advance;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 if (!newdent) {
603 newdent = d_alloc(dentry, &qname);
604 if (!newdent)
605 goto end_advance;
606 } else {
607 hashed = 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200608
609 /* If case sensitivity changed for this volume, all entries below this one
610 should be thrown away. This entry itself is not affected, as its case
611 sensitivity is controlled by its own parent. */
612 if (inval_childs)
613 shrink_dcache_parent(newdent);
614
615 /*
Nick Pigginfb2d5b82011-01-07 17:49:26 +1100616 * NetWare's OS2 namespace is case preserving yet case
617 * insensitive. So we update dentry's name as received from
618 * server. Parent dir's i_mutex is locked because we're in
619 * readdir.
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200620 */
Nick Pigginfb2d5b82011-01-07 17:49:26 +1100621 dentry_update_name_case(newdent, &qname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 }
623
David Howells2b0143b2015-03-17 22:25:59 +0000624 if (d_really_is_negative(newdent)) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200625 struct inode *inode;
626
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 entry->opened = 0;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200628 entry->ino = iunique(dir->i_sb, 2);
629 inode = ncp_iget(dir->i_sb, entry);
630 if (inode) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200631 d_instantiate(newdent, inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 if (!hashed)
633 d_rehash(newdent);
Al Viro5e993e22014-12-24 21:41:47 -0500634 } else {
635 spin_lock(&dentry->d_lock);
636 NCP_FINFO(inode)->flags &= ~NCPI_DIR_CACHE;
637 spin_unlock(&dentry->d_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200639 } else {
David Howells2b0143b2015-03-17 22:25:59 +0000640 struct inode *inode = d_inode(newdent);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200641
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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 if (ctl.idx >= NCP_DIRCACHE_SIZE) {
648 if (ctl.page) {
649 kunmap(ctl.page);
650 SetPageUptodate(ctl.page);
651 unlock_page(ctl.page);
652 page_cache_release(ctl.page);
653 }
654 ctl.cache = NULL;
655 ctl.idx -= NCP_DIRCACHE_SIZE;
656 ctl.ofs += 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200657 ctl.page = grab_cache_page(&dir->i_data, ctl.ofs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 if (ctl.page)
659 ctl.cache = kmap(ctl.page);
660 }
661 if (ctl.cache) {
David Howells2b0143b2015-03-17 22:25:59 +0000662 if (d_really_is_positive(newdent)) {
Al Viro5e993e22014-12-24 21:41:47 -0500663 newdent->d_fsdata = newdent;
664 ctl.cache->dentry[ctl.idx] = newdent;
David Howells2b0143b2015-03-17 22:25:59 +0000665 ino = d_inode(newdent)->i_ino;
Al Viro5e993e22014-12-24 21:41:47 -0500666 ncp_new_dentry(newdent);
667 }
668 valid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 }
670 dput(newdent);
671end_advance:
672 if (!valid)
673 ctl.valid = 0;
Al Viro76f582a2013-05-22 15:11:27 -0400674 if (!ctl.filled && (ctl.fpos == ctx->pos)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 if (!ino)
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200676 ino = iunique(dir->i_sb, 2);
Al Viro76f582a2013-05-22 15:11:27 -0400677 ctl.filled = !dir_emit(ctx, qname.name, qname.len,
678 ino, DT_UNKNOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 if (!ctl.filled)
Al Viro76f582a2013-05-22 15:11:27 -0400680 ctx->pos += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 }
682 ctl.fpos += 1;
683 ctl.idx += 1;
684 *ctrl = ctl;
685 return (ctl.valid || !ctl.filled);
686}
687
688static void
Al Viro76f582a2013-05-22 15:11:27 -0400689ncp_read_volume_list(struct file *file, struct dir_context *ctx,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 struct ncp_cache_control *ctl)
691{
Al Viroa67f7972014-10-31 02:41:28 -0400692 struct inode *inode = file_inode(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 struct ncp_server *server = NCP_SERVER(inode);
694 struct ncp_volume_info info;
695 struct ncp_entry_info entry;
696 int i;
697
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700698 ncp_dbg(1, "pos=%ld\n", (unsigned long)ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
700 for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200701 int inval_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
703 if (ncp_get_volume_info_with_number(server, i, &info) != 0)
704 return;
705 if (!strlen(info.volume_name))
706 continue;
707
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700708 ncp_dbg(1, "found vol: %s\n", info.volume_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709
710 if (ncp_lookup_volume(server, info.volume_name,
711 &entry.i)) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700712 ncp_dbg(1, "could not lookup vol %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 info.volume_name);
714 continue;
715 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200716 inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 entry.volume = entry.i.volNumber;
Al Viro76f582a2013-05-22 15:11:27 -0400718 if (!ncp_fill_cache(file, ctx, ctl, &entry, inval_dentry))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 return;
720 }
721}
722
723static void
Al Viro76f582a2013-05-22 15:11:27 -0400724ncp_do_readdir(struct file *file, struct dir_context *ctx,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 struct ncp_cache_control *ctl)
726{
Al Viroa67f7972014-10-31 02:41:28 -0400727 struct inode *dir = file_inode(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 struct ncp_server *server = NCP_SERVER(dir);
729 struct nw_search_sequence seq;
730 struct ncp_entry_info entry;
731 int err;
732 void* buf;
733 int more;
734 size_t bufsize;
735
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700736 ncp_dbg(1, "%pD2, fpos=%ld\n", file, (unsigned long)ctx->pos);
Joe Perchese45ca8b2014-04-08 16:04:16 -0700737 ncp_vdbg("init %pD, volnum=%d, dirent=%u\n",
738 file, NCP_FINFO(dir)->volNumber, NCP_FINFO(dir)->dirEntNum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739
740 err = ncp_initialize_search(server, dir, &seq);
741 if (err) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700742 ncp_dbg(1, "init failed, err=%d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 return;
744 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 /* We MUST NOT use server->buffer_size handshaked with server if we are
746 using UDP, as for UDP server uses max. buffer size determined by
747 MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes).
748 So we use 128KB, just to be sure, as there is no way how to know
749 this value in advance. */
750 bufsize = 131072;
751 buf = vmalloc(bufsize);
752 if (!buf)
753 return;
754 do {
755 int cnt;
756 char* rpl;
757 size_t rpls;
758
759 err = ncp_search_for_fileset(server, &seq, &more, &cnt, buf, bufsize, &rpl, &rpls);
760 if (err) /* Error */
761 break;
762 if (!cnt) /* prevent endless loop */
763 break;
764 while (cnt--) {
765 size_t onerpl;
766
767 if (rpls < offsetof(struct nw_info_struct, entryName))
768 break; /* short packet */
769 ncp_extract_file_info(rpl, &entry.i);
770 onerpl = offsetof(struct nw_info_struct, entryName) + entry.i.nameLen;
771 if (rpls < onerpl)
772 break; /* short packet */
773 (void)ncp_obtain_nfs_info(server, &entry.i);
774 rpl += onerpl;
775 rpls -= onerpl;
776 entry.volume = entry.i.volNumber;
Al Viro76f582a2013-05-22 15:11:27 -0400777 if (!ncp_fill_cache(file, ctx, ctl, &entry, 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 break;
779 }
780 } while (more);
781 vfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 return;
783}
784
785int ncp_conn_logged_in(struct super_block *sb)
786{
787 struct ncp_server* server = NCP_SBP(sb);
788 int result;
789
790 if (ncp_single_volume(server)) {
791 int len;
792 struct dentry* dent;
793 __u32 volNumber;
794 __le32 dirEntNum;
795 __le32 DosDirNum;
796 __u8 __name[NCP_MAXPATHLEN + 1];
797
798 len = sizeof(__name);
799 result = ncp_io2vol(server, __name, &len, server->m.mounted_vol,
800 strlen(server->m.mounted_vol), 1);
801 if (result)
802 goto out;
803 result = -ENOENT;
804 if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) {
Joe Perchese45ca8b2014-04-08 16:04:16 -0700805 ncp_vdbg("%s not found\n", server->m.mounted_vol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 goto out;
807 }
808 dent = sb->s_root;
809 if (dent) {
David Howells2b0143b2015-03-17 22:25:59 +0000810 struct inode* ino = d_inode(dent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 if (ino) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200812 ncp_update_known_namespace(server, volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 NCP_FINFO(ino)->volNumber = volNumber;
814 NCP_FINFO(ino)->dirEntNum = dirEntNum;
815 NCP_FINFO(ino)->DosDirNum = DosDirNum;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200816 result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 } else {
David Howells2b0143b2015-03-17 22:25:59 +0000818 ncp_dbg(1, "d_inode(sb->s_root) == NULL!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 }
820 } else {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700821 ncp_dbg(1, "sb->s_root == NULL!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200823 } else
824 result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
826out:
827 return result;
828}
829
Al Viro00cd8dd2012-06-10 17:13:09 -0400830static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831{
832 struct ncp_server *server = NCP_SERVER(dir);
833 struct inode *inode = NULL;
834 struct ncp_entry_info finfo;
835 int error, res, len;
836 __u8 __name[NCP_MAXPATHLEN + 1];
837
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 error = -EIO;
839 if (!ncp_conn_valid(server))
840 goto finished;
841
Joe Perchese45ca8b2014-04-08 16:04:16 -0700842 ncp_vdbg("server lookup for %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843
844 len = sizeof(__name);
845 if (ncp_is_server_root(dir)) {
846 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
847 dentry->d_name.len, 1);
848 if (!res)
849 res = ncp_lookup_volume(server, __name, &(finfo.i));
Dan Carpenterffddc5f2014-04-08 16:04:19 -0700850 if (!res)
851 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 } else {
853 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
854 dentry->d_name.len, !ncp_preserve_case(dir));
855 if (!res)
856 res = ncp_obtain_info(server, dir, __name, &(finfo.i));
857 }
Joe Perchese45ca8b2014-04-08 16:04:16 -0700858 ncp_vdbg("looked for %pd2, res=%d\n", dentry, res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 /*
860 * If we didn't find an entry, make a negative dentry.
861 */
862 if (res)
863 goto add_entry;
864
865 /*
866 * Create an inode for the entry.
867 */
868 finfo.opened = 0;
869 finfo.ino = iunique(dir->i_sb, 2);
870 finfo.volume = finfo.i.volNumber;
871 error = -EACCES;
872 inode = ncp_iget(dir->i_sb, &finfo);
873
874 if (inode) {
875 ncp_new_dentry(dentry);
876add_entry:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 d_add(dentry, inode);
878 error = 0;
879 }
880
881finished:
Joe Perchese45ca8b2014-04-08 16:04:16 -0700882 ncp_vdbg("result=%d\n", error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 return ERR_PTR(error);
884}
885
886/*
887 * This code is common to create, mkdir, and mknod.
888 */
889static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
890 struct ncp_entry_info *finfo)
891{
892 struct inode *inode;
893 int error = -EINVAL;
894
895 finfo->ino = iunique(dir->i_sb, 2);
896 inode = ncp_iget(dir->i_sb, finfo);
897 if (!inode)
898 goto out_close;
899 d_instantiate(dentry,inode);
900 error = 0;
901out:
902 return error;
903
904out_close:
Joe Perchese45ca8b2014-04-08 16:04:16 -0700905 ncp_vdbg("%pd2 failed, closing file\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 ncp_close_file(NCP_SERVER(dir), finfo->file_handle);
907 goto out;
908}
909
Al Viro5eee25c2011-07-26 03:12:16 -0400910int ncp_create_new(struct inode *dir, struct dentry *dentry, umode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 dev_t rdev, __le32 attributes)
912{
913 struct ncp_server *server = NCP_SERVER(dir);
914 struct ncp_entry_info finfo;
915 int error, result, len;
916 int opmode;
917 __u8 __name[NCP_MAXPATHLEN + 1];
918
Joe Perchese45ca8b2014-04-08 16:04:16 -0700919 ncp_vdbg("creating %pd2, mode=%hx\n", dentry, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 ncp_age_dentry(server, dentry);
922 len = sizeof(__name);
923 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
924 dentry->d_name.len, !ncp_preserve_case(dir));
925 if (error)
926 goto out;
927
928 error = -EACCES;
929
930 if (S_ISREG(mode) &&
931 (server->m.flags & NCP_MOUNT_EXTRAS) &&
932 (mode & S_IXUGO))
933 attributes |= aSYSTEM | aSHARED;
934
935 result = ncp_open_create_file_or_subdir(server, dir, __name,
936 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
937 attributes, AR_READ | AR_WRITE, &finfo);
938 opmode = O_RDWR;
939 if (result) {
940 result = ncp_open_create_file_or_subdir(server, dir, __name,
941 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
942 attributes, AR_WRITE, &finfo);
943 if (result) {
944 if (result == 0x87)
945 error = -ENAMETOOLONG;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200946 else if (result < 0)
947 error = result;
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700948 ncp_dbg(1, "%pd2 failed\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 goto out;
950 }
951 opmode = O_WRONLY;
952 }
953 finfo.access = opmode;
954 if (ncp_is_nfs_extras(server, finfo.volume)) {
955 finfo.i.nfs.mode = mode;
956 finfo.i.nfs.rdev = new_encode_dev(rdev);
957 if (ncp_modify_nfs_info(server, finfo.volume,
958 finfo.i.dirEntNum,
959 mode, new_encode_dev(rdev)) != 0)
960 goto out;
961 }
962
963 error = ncp_instantiate(dir, dentry, &finfo);
964out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 return error;
966}
967
Al Viro4acdaf22011-07-26 01:42:34 -0400968static int ncp_create(struct inode *dir, struct dentry *dentry, umode_t mode,
Al Viroebfc3b42012-06-10 18:05:36 -0400969 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970{
971 return ncp_create_new(dir, dentry, mode, 0, 0);
972}
973
Al Viro18bb1db2011-07-26 01:41:39 -0400974static int ncp_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975{
976 struct ncp_entry_info finfo;
977 struct ncp_server *server = NCP_SERVER(dir);
978 int error, len;
979 __u8 __name[NCP_MAXPATHLEN + 1];
980
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700981 ncp_dbg(1, "making %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 ncp_age_dentry(server, dentry);
984 len = sizeof(__name);
985 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
986 dentry->d_name.len, !ncp_preserve_case(dir));
987 if (error)
988 goto out;
989
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200990 error = ncp_open_create_file_or_subdir(server, dir, __name,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 OC_MODE_CREATE, aDIR,
992 cpu_to_le16(0xffff),
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200993 &finfo);
994 if (error == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 if (ncp_is_nfs_extras(server, finfo.volume)) {
996 mode |= S_IFDIR;
997 finfo.i.nfs.mode = mode;
998 if (ncp_modify_nfs_info(server,
999 finfo.volume,
1000 finfo.i.dirEntNum,
1001 mode, 0) != 0)
1002 goto out;
1003 }
1004 error = ncp_instantiate(dir, dentry, &finfo);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001005 } else if (error > 0) {
1006 error = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 }
1008out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 return error;
1010}
1011
1012static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
1013{
1014 struct ncp_server *server = NCP_SERVER(dir);
1015 int error, result, len;
1016 __u8 __name[NCP_MAXPATHLEN + 1];
1017
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001018 ncp_dbg(1, "removing %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 len = sizeof(__name);
1021 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
1022 dentry->d_name.len, !ncp_preserve_case(dir));
1023 if (error)
1024 goto out;
1025
1026 result = ncp_del_file_or_subdir(server, dir, __name);
1027 switch (result) {
1028 case 0x00:
1029 error = 0;
1030 break;
1031 case 0x85: /* unauthorized to delete file */
1032 case 0x8A: /* unauthorized to delete file */
1033 error = -EACCES;
1034 break;
1035 case 0x8F:
1036 case 0x90: /* read only */
1037 error = -EPERM;
1038 break;
1039 case 0x9F: /* in use by another client */
1040 error = -EBUSY;
1041 break;
1042 case 0xA0: /* directory not empty */
1043 error = -ENOTEMPTY;
1044 break;
1045 case 0xFF: /* someone deleted file */
1046 error = -ENOENT;
1047 break;
1048 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001049 error = result < 0 ? result : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 break;
1051 }
1052out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 return error;
1054}
1055
1056static int ncp_unlink(struct inode *dir, struct dentry *dentry)
1057{
David Howells2b0143b2015-03-17 22:25:59 +00001058 struct inode *inode = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 struct ncp_server *server;
1060 int error;
1061
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 server = NCP_SERVER(dir);
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001063 ncp_dbg(1, "unlinking %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 /*
1066 * Check whether to close the file ...
1067 */
1068 if (inode) {
Joe Perchese45ca8b2014-04-08 16:04:16 -07001069 ncp_vdbg("closing file\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 ncp_make_closed(inode);
1071 }
1072
1073 error = ncp_del_file_or_subdir2(server, dentry);
1074#ifdef CONFIG_NCPFS_STRONG
1075 /* 9C is Invalid path.. It should be 8F, 90 - read only, but
1076 it is not :-( */
1077 if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */
1078 error = ncp_force_unlink(dir, dentry);
1079 }
1080#endif
1081 switch (error) {
1082 case 0x00:
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001083 ncp_dbg(1, "removed %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 break;
1085 case 0x85:
1086 case 0x8A:
1087 error = -EACCES;
1088 break;
1089 case 0x8D: /* some files in use */
1090 case 0x8E: /* all files in use */
1091 error = -EBUSY;
1092 break;
1093 case 0x8F: /* some read only */
1094 case 0x90: /* all read only */
1095 case 0x9C: /* !!! returned when in-use or read-only by NW4 */
1096 error = -EPERM;
1097 break;
1098 case 0xFF:
1099 error = -ENOENT;
1100 break;
1101 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001102 error = error < 0 ? error : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 break;
1104 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 return error;
1106}
1107
1108static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
1109 struct inode *new_dir, struct dentry *new_dentry)
1110{
1111 struct ncp_server *server = NCP_SERVER(old_dir);
1112 int error;
1113 int old_len, new_len;
1114 __u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1];
1115
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001116 ncp_dbg(1, "%pd2 to %pd2\n", old_dentry, new_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 ncp_age_dentry(server, old_dentry);
1119 ncp_age_dentry(server, new_dentry);
1120
1121 old_len = sizeof(__old_name);
1122 error = ncp_io2vol(server, __old_name, &old_len,
1123 old_dentry->d_name.name, old_dentry->d_name.len,
1124 !ncp_preserve_case(old_dir));
1125 if (error)
1126 goto out;
1127
1128 new_len = sizeof(__new_name);
1129 error = ncp_io2vol(server, __new_name, &new_len,
1130 new_dentry->d_name.name, new_dentry->d_name.len,
1131 !ncp_preserve_case(new_dir));
1132 if (error)
1133 goto out;
1134
1135 error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name,
1136 new_dir, __new_name);
1137#ifdef CONFIG_NCPFS_STRONG
1138 if ((error == 0x90 || error == 0x8B || error == -EACCES) &&
1139 server->m.flags & NCP_MOUNT_STRONG) { /* RO */
1140 error = ncp_force_rename(old_dir, old_dentry, __old_name,
1141 new_dir, new_dentry, __new_name);
1142 }
1143#endif
1144 switch (error) {
1145 case 0x00:
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001146 ncp_dbg(1, "renamed %pd -> %pd\n",
1147 old_dentry, new_dentry);
Al Viro3f4a9492015-06-06 09:15:55 -04001148 ncp_d_prune(old_dentry);
1149 ncp_d_prune(new_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 break;
1151 case 0x9E:
1152 error = -ENAMETOOLONG;
1153 break;
1154 case 0xFF:
1155 error = -ENOENT;
1156 break;
1157 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001158 error = error < 0 ? error : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 break;
1160 }
1161out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 return error;
1163}
1164
1165static int ncp_mknod(struct inode * dir, struct dentry *dentry,
Al Viro1a67aaf2011-07-26 01:52:52 -04001166 umode_t mode, dev_t rdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001169 ncp_dbg(1, "mode = 0%ho\n", mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 return ncp_create_new(dir, dentry, mode, rdev, 0);
1171 }
1172 return -EPERM; /* Strange, but true */
1173}
1174
1175/* The following routines are taken directly from msdos-fs */
1176
1177/* Linear day numbers of the respective 1sts in non-leap years. */
1178
1179static int day_n[] =
1180{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
1181/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
1182
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183static int utc2local(int time)
1184{
1185 return time - sys_tz.tz_minuteswest * 60;
1186}
1187
1188static int local2utc(int time)
1189{
1190 return time + sys_tz.tz_minuteswest * 60;
1191}
1192
1193/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
1194int
1195ncp_date_dos2unix(__le16 t, __le16 d)
1196{
1197 unsigned short time = le16_to_cpu(t), date = le16_to_cpu(d);
1198 int month, year, secs;
1199
1200 /* first subtract and mask after that... Otherwise, if
1201 date == 0, bad things happen */
1202 month = ((date >> 5) - 1) & 15;
1203 year = date >> 9;
1204 secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
1205 86400 * ((date & 31) - 1 + day_n[month] + (year / 4) +
1206 year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
1207 /* days since 1.1.70 plus 80's leap day */
1208 return local2utc(secs);
1209}
1210
1211
1212/* Convert linear UNIX date to a MS-DOS time/date pair. */
1213void
1214ncp_date_unix2dos(int unix_date, __le16 *time, __le16 *date)
1215{
1216 int day, year, nl_day, month;
1217
1218 unix_date = utc2local(unix_date);
1219 *time = cpu_to_le16(
1220 (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
1221 (((unix_date / 3600) % 24) << 11));
1222 day = unix_date / 86400 - 3652;
1223 year = day / 365;
1224 if ((year + 3) / 4 + 365 * year > day)
1225 year--;
1226 day -= (year + 3) / 4 + 365 * year;
1227 if (day == 59 && !(year & 3)) {
1228 nl_day = day;
1229 month = 2;
1230 } else {
1231 nl_day = (year & 3) || day <= 59 ? day : day - 1;
Roel Kluinc5df5912009-09-22 16:45:54 -07001232 for (month = 1; month < 12; month++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 if (day_n[month] > nl_day)
1234 break;
1235 }
1236 *date = cpu_to_le16(nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
1237}