blob: 6df2a38275741d8dd9f2c799d2fbbd0cc889519f [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 *,
Miklos Szeredi1cd66c92016-09-27 11:03:58 +020039 struct inode *, struct dentry *, unsigned int);
Linus Torvalds1da177e2005-04-16 15:20:36 -070040static 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,
Miklos Szeredi2773bf02016-09-27 11:03:58 +020068 .rename = ncp_rename,
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 .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 *);
Al Viro6fa67e72016-07-31 16:37:25 -040077static int ncp_compare_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)) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200136 struct nls_table *t;
137 unsigned long hash;
138 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
Miklos Szeredi9a232de2016-09-27 11:03:57 +0200140 t = NCP_IO_TABLE(dentry->d_sb);
Linus Torvalds8387ff22016-06-10 07:51:30 -0700141 hash = init_name_hash(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 for (i=0; i<this->len ; i++)
143 hash = partial_name_hash(ncp_tolower(t, this->name[i]),
144 hash);
145 this->hash = end_name_hash(hash);
146 }
147 return 0;
148}
149
Linus Torvaldsda53be12013-05-21 15:22:44 -0700150/*
151 * Accessing the parent inode can be racy under RCU pathwalking.
152 * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
153 * the callers will handle races.
154 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155static int
Al Viro6fa67e72016-07-31 16:37:25 -0400156ncp_compare_dentry(const struct dentry *dentry,
Nick Piggin621e1552011-01-07 17:49:27 +1100157 unsigned int len, const char *str, const struct qstr *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158{
Linus Torvaldsda53be12013-05-21 15:22:44 -0700159 struct inode *pinode;
160
Nick Piggin621e1552011-01-07 17:49:27 +1100161 if (len != name->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 return 1;
163
Al Viro6fa67e72016-07-31 16:37:25 -0400164 pinode = d_inode_rcu(dentry->d_parent);
Linus Torvaldsda53be12013-05-21 15:22:44 -0700165 if (!pinode)
166 return 1;
167
Nick Piggin621e1552011-01-07 17:49:27 +1100168 if (ncp_case_sensitive(pinode))
169 return strncmp(str, name->name, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
Nick Piggin621e1552011-01-07 17:49:27 +1100171 return ncp_strnicmp(NCP_IO_TABLE(pinode->i_sb), str, name->name, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172}
173
174/*
175 * This is the callback from dput() when d_count is going to 0.
176 * We use this to unhash dentries with bad inodes.
177 * Closing files can be safely postponed until iput() - it's done there anyway.
178 */
179static int
Nick Pigginfe15ce42011-01-07 17:49:23 +1100180ncp_delete_dentry(const struct dentry * dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181{
David Howells2b0143b2015-03-17 22:25:59 +0000182 struct inode *inode = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
184 if (inode) {
185 if (is_bad_inode(inode))
186 return 1;
187 } else
188 {
189 /* N.B. Unhash negative dentries? */
190 }
191 return 0;
192}
193
194static inline int
195ncp_single_volume(struct ncp_server *server)
196{
197 return (server->m.mounted_vol[0] != '\0');
198}
199
200static inline int ncp_is_server_root(struct inode *inode)
201{
Al Viroa7400222014-10-21 15:20:42 -0400202 return !ncp_single_volume(NCP_SERVER(inode)) &&
203 is_root_inode(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204}
205
206
207/*
208 * This is the callback when the dcache has a lookup hit.
209 */
210
211
212#ifdef CONFIG_NCPFS_STRONG
213/* try to delete a readonly file (NW R bit set) */
214
215static int
216ncp_force_unlink(struct inode *dir, struct dentry* dentry)
217{
218 int res=0x9c,res2;
219 struct nw_modify_dos_info info;
220 __le32 old_nwattr;
221 struct inode *inode;
222
223 memset(&info, 0, sizeof(info));
224
225 /* remove the Read-Only flag on the NW server */
David Howells2b0143b2015-03-17 22:25:59 +0000226 inode = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227
228 old_nwattr = NCP_FINFO(inode)->nwattr;
229 info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT);
230 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
231 if (res2)
232 goto leave_me;
233
234 /* now try again the delete operation */
235 res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
236
237 if (res) /* delete failed, set R bit again */
238 {
239 info.attributes = old_nwattr;
240 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
241 if (res2)
242 goto leave_me;
243 }
244leave_me:
245 return(res);
246}
247#endif /* CONFIG_NCPFS_STRONG */
248
249#ifdef CONFIG_NCPFS_STRONG
250static int
251ncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name,
252 struct inode *new_dir, struct dentry* new_dentry, char *_new_name)
253{
254 struct nw_modify_dos_info info;
255 int res=0x90,res2;
David Howells2b0143b2015-03-17 22:25:59 +0000256 struct inode *old_inode = d_inode(old_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 __le32 old_nwattr = NCP_FINFO(old_inode)->nwattr;
258 __le32 new_nwattr = 0; /* shut compiler warning */
259 int old_nwattr_changed = 0;
260 int new_nwattr_changed = 0;
261
262 memset(&info, 0, sizeof(info));
263
264 /* remove the Read-Only flag on the NW server */
265
266 info.attributes = old_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
267 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
268 if (!res2)
269 old_nwattr_changed = 1;
David Howells2b0143b2015-03-17 22:25:59 +0000270 if (new_dentry && d_really_is_positive(new_dentry)) {
271 new_nwattr = NCP_FINFO(d_inode(new_dentry))->nwattr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
273 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
274 if (!res2)
275 new_nwattr_changed = 1;
276 }
277 /* now try again the rename operation */
278 /* but only if something really happened */
279 if (new_nwattr_changed || old_nwattr_changed) {
280 res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
281 old_dir, _old_name,
282 new_dir, _new_name);
283 }
284 if (res)
285 goto leave_me;
286 /* file was successfully renamed, so:
287 do not set attributes on old file - it no longer exists
288 copy attributes from old file to new */
289 new_nwattr_changed = old_nwattr_changed;
290 new_nwattr = old_nwattr;
291 old_nwattr_changed = 0;
292
293leave_me:;
294 if (old_nwattr_changed) {
295 info.attributes = old_nwattr;
296 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
297 /* ignore errors */
298 }
299 if (new_nwattr_changed) {
300 info.attributes = new_nwattr;
301 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
302 /* ignore errors */
303 }
304 return(res);
305}
306#endif /* CONFIG_NCPFS_STRONG */
307
308
309static int
Al Viro0b728e12012-06-10 16:03:43 -0400310ncp_lookup_validate(struct dentry *dentry, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311{
312 struct ncp_server *server;
313 struct dentry *parent;
314 struct inode *dir;
315 struct ncp_entry_info finfo;
316 int res, val = 0, len;
317 __u8 __name[NCP_MAXPATHLEN + 1];
318
Al Viro0378c402011-01-12 17:25:03 -0500319 if (dentry == dentry->d_sb->s_root)
320 return 1;
321
Al Viro0b728e12012-06-10 16:03:43 -0400322 if (flags & LOOKUP_RCU)
Nick Piggin34286d62011-01-07 17:49:57 +1100323 return -ECHILD;
324
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325 parent = dget_parent(dentry);
David Howells2b0143b2015-03-17 22:25:59 +0000326 dir = d_inode(parent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
David Howells2b0143b2015-03-17 22:25:59 +0000328 if (d_really_is_negative(dentry))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 goto finished;
330
331 server = NCP_SERVER(dir);
332
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 /*
334 * Inspired by smbfs:
335 * The default validation is based on dentry age:
336 * We set the max age at mount time. (But each
337 * successful server lookup renews the timestamp.)
338 */
339 val = NCP_TEST_AGE(server, dentry);
340 if (val)
341 goto finished;
342
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700343 ncp_dbg(2, "%pd2 not valid, age=%ld, server lookup\n",
Al Viro84eb3532013-09-16 10:59:55 -0400344 dentry, NCP_GET_AGE(dentry));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
346 len = sizeof(__name);
347 if (ncp_is_server_root(dir)) {
348 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
349 dentry->d_name.len, 1);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200350 if (!res) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 res = ncp_lookup_volume(server, __name, &(finfo.i));
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200352 if (!res)
353 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
354 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 } else {
356 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
357 dentry->d_name.len, !ncp_preserve_case(dir));
358 if (!res)
359 res = ncp_obtain_info(server, dir, __name, &(finfo.i));
360 }
361 finfo.volume = finfo.i.volNumber;
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700362 ncp_dbg(2, "looked for %pd/%s, res=%d\n",
Al Viro84eb3532013-09-16 10:59:55 -0400363 dentry->d_parent, __name, res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 /*
365 * If we didn't find it, or if it has a different dirEntNum to
366 * what we remember, it's not valid any more.
367 */
368 if (!res) {
David Howells2b0143b2015-03-17 22:25:59 +0000369 struct inode *inode = d_inode(dentry);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200370
Al Viro59551022016-01-22 15:40:57 -0500371 inode_lock(inode);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200372 if (finfo.i.dirEntNum == NCP_FINFO(inode)->dirEntNum) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 ncp_new_dentry(dentry);
374 val=1;
375 } else
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700376 ncp_dbg(2, "found, but dirEntNum changed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200378 ncp_update_inode2(inode, &finfo);
Al Viro59551022016-01-22 15:40:57 -0500379 inode_unlock(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 }
381
382finished:
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700383 ncp_dbg(2, "result=%d\n", val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 dput(parent);
385 return val;
386}
387
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388static time_t ncp_obtain_mtime(struct dentry *dentry)
389{
David Howells2b0143b2015-03-17 22:25:59 +0000390 struct inode *inode = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 struct ncp_server *server = NCP_SERVER(inode);
392 struct nw_info_struct i;
393
394 if (!ncp_conn_valid(server) || ncp_is_server_root(inode))
395 return 0;
396
397 if (ncp_obtain_info(server, inode, NULL, &i))
398 return 0;
399
400 return ncp_date_dos2unix(i.modifyTime, i.modifyDate);
401}
402
Al Viro5e993e22014-12-24 21:41:47 -0500403static inline void
404ncp_invalidate_dircache_entries(struct dentry *parent)
405{
David Howells2b0143b2015-03-17 22:25:59 +0000406 struct ncp_server *server = NCP_SERVER(d_inode(parent));
Al Viro5e993e22014-12-24 21:41:47 -0500407 struct dentry *dentry;
408
409 spin_lock(&parent->d_lock);
410 list_for_each_entry(dentry, &parent->d_subdirs, d_child) {
411 dentry->d_fsdata = NULL;
412 ncp_age_dentry(server, dentry);
413 }
414 spin_unlock(&parent->d_lock);
415}
416
Al Viro76f582a2013-05-22 15:11:27 -0400417static int ncp_readdir(struct file *file, struct dir_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418{
Al Viro76f582a2013-05-22 15:11:27 -0400419 struct dentry *dentry = file->f_path.dentry;
David Howells2b0143b2015-03-17 22:25:59 +0000420 struct inode *inode = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 struct page *page = NULL;
422 struct ncp_server *server = NCP_SERVER(inode);
423 union ncp_dir_cache *cache = NULL;
424 struct ncp_cache_control ctl;
425 int result, mtime_valid = 0;
426 time_t mtime = 0;
427
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428 ctl.page = NULL;
429 ctl.cache = NULL;
430
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700431 ncp_dbg(2, "reading %pD2, pos=%d\n", file, (int)ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
433 result = -EIO;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200434 /* Do not generate '.' and '..' when server is dead. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 if (!ncp_conn_valid(server))
436 goto out;
437
438 result = 0;
Al Viro76f582a2013-05-22 15:11:27 -0400439 if (!dir_emit_dots(file, ctx))
440 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
442 page = grab_cache_page(&inode->i_data, 0);
443 if (!page)
444 goto read_really;
445
446 ctl.cache = cache = kmap(page);
447 ctl.head = cache->head;
448
449 if (!PageUptodate(page) || !ctl.head.eof)
450 goto init_cache;
451
Al Viro76f582a2013-05-22 15:11:27 -0400452 if (ctx->pos == 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 if (jiffies - ctl.head.time >= NCP_MAX_AGE(server))
454 goto init_cache;
455
456 mtime = ncp_obtain_mtime(dentry);
457 mtime_valid = 1;
458 if ((!mtime) || (mtime != ctl.head.mtime))
459 goto init_cache;
460 }
461
Al Viro76f582a2013-05-22 15:11:27 -0400462 if (ctx->pos > ctl.head.end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 goto finished;
464
Al Viro76f582a2013-05-22 15:11:27 -0400465 ctl.fpos = ctx->pos + (NCP_DIRCACHE_START - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 ctl.ofs = ctl.fpos / NCP_DIRCACHE_SIZE;
467 ctl.idx = ctl.fpos % NCP_DIRCACHE_SIZE;
468
469 for (;;) {
470 if (ctl.ofs != 0) {
471 ctl.page = find_lock_page(&inode->i_data, ctl.ofs);
472 if (!ctl.page)
473 goto invalid_cache;
474 ctl.cache = kmap(ctl.page);
475 if (!PageUptodate(ctl.page))
476 goto invalid_cache;
477 }
478 while (ctl.idx < NCP_DIRCACHE_SIZE) {
479 struct dentry *dent;
Al Viro76f582a2013-05-22 15:11:27 -0400480 bool over;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
Al Viro5e993e22014-12-24 21:41:47 -0500482 spin_lock(&dentry->d_lock);
483 if (!(NCP_FINFO(inode)->flags & NCPI_DIR_CACHE)) {
484 spin_unlock(&dentry->d_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 goto invalid_cache;
Al Viro5e993e22014-12-24 21:41:47 -0500486 }
487 dent = ctl.cache->dentry[ctl.idx];
488 if (unlikely(!lockref_get_not_dead(&dent->d_lockref))) {
489 spin_unlock(&dentry->d_lock);
490 goto invalid_cache;
491 }
492 spin_unlock(&dentry->d_lock);
David Howells2b0143b2015-03-17 22:25:59 +0000493 if (d_really_is_negative(dent)) {
Al Viro5e993e22014-12-24 21:41:47 -0500494 dput(dent);
495 goto invalid_cache;
496 }
Al Viro76f582a2013-05-22 15:11:27 -0400497 over = !dir_emit(ctx, dent->d_name.name,
498 dent->d_name.len,
David Howells2b0143b2015-03-17 22:25:59 +0000499 d_inode(dent)->i_ino, DT_UNKNOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 dput(dent);
Al Viro76f582a2013-05-22 15:11:27 -0400501 if (over)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 goto finished;
Al Viro76f582a2013-05-22 15:11:27 -0400503 ctx->pos += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 ctl.idx += 1;
Al Viro76f582a2013-05-22 15:11:27 -0400505 if (ctx->pos > ctl.head.end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 goto finished;
507 }
508 if (ctl.page) {
509 kunmap(ctl.page);
510 SetPageUptodate(ctl.page);
511 unlock_page(ctl.page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300512 put_page(ctl.page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 ctl.page = NULL;
514 }
515 ctl.idx = 0;
516 ctl.ofs += 1;
517 }
518invalid_cache:
519 if (ctl.page) {
520 kunmap(ctl.page);
521 unlock_page(ctl.page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300522 put_page(ctl.page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 ctl.page = NULL;
524 }
525 ctl.cache = cache;
526init_cache:
527 ncp_invalidate_dircache_entries(dentry);
528 if (!mtime_valid) {
529 mtime = ncp_obtain_mtime(dentry);
530 mtime_valid = 1;
531 }
532 ctl.head.mtime = mtime;
533 ctl.head.time = jiffies;
534 ctl.head.eof = 0;
535 ctl.fpos = 2;
536 ctl.ofs = 0;
537 ctl.idx = NCP_DIRCACHE_START;
538 ctl.filled = 0;
539 ctl.valid = 1;
540read_really:
Al Viro5e993e22014-12-24 21:41:47 -0500541 spin_lock(&dentry->d_lock);
542 NCP_FINFO(inode)->flags |= NCPI_DIR_CACHE;
543 spin_unlock(&dentry->d_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 if (ncp_is_server_root(inode)) {
Al Viro76f582a2013-05-22 15:11:27 -0400545 ncp_read_volume_list(file, ctx, &ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 } else {
Al Viro76f582a2013-05-22 15:11:27 -0400547 ncp_do_readdir(file, ctx, &ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 }
549 ctl.head.end = ctl.fpos - 1;
550 ctl.head.eof = ctl.valid;
551finished:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200552 if (ctl.page) {
553 kunmap(ctl.page);
554 SetPageUptodate(ctl.page);
555 unlock_page(ctl.page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300556 put_page(ctl.page);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200557 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 if (page) {
559 cache->head = ctl.head;
560 kunmap(page);
561 SetPageUptodate(page);
562 unlock_page(page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300563 put_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 return result;
567}
568
Al Viro5e993e22014-12-24 21:41:47 -0500569static void ncp_d_prune(struct dentry *dentry)
570{
571 if (!dentry->d_fsdata) /* not referenced from page cache */
572 return;
David Howells2b0143b2015-03-17 22:25:59 +0000573 NCP_FINFO(d_inode(dentry->d_parent))->flags &= ~NCPI_DIR_CACHE;
Al Viro5e993e22014-12-24 21:41:47 -0500574}
575
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576static int
Al Viro76f582a2013-05-22 15:11:27 -0400577ncp_fill_cache(struct file *file, struct dir_context *ctx,
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200578 struct ncp_cache_control *ctrl, struct ncp_entry_info *entry,
579 int inval_childs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580{
Al Viro76f582a2013-05-22 15:11:27 -0400581 struct dentry *newdent, *dentry = file->f_path.dentry;
David Howells2b0143b2015-03-17 22:25:59 +0000582 struct inode *dir = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 struct ncp_cache_control ctl = *ctrl;
584 struct qstr qname;
585 int valid = 0;
586 int hashed = 0;
587 ino_t ino = 0;
588 __u8 __name[NCP_MAXPATHLEN + 1];
589
590 qname.len = sizeof(__name);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200591 if (ncp_vol2io(NCP_SERVER(dir), __name, &qname.len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 entry->i.entryName, entry->i.nameLen,
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200593 !ncp_preserve_entry_case(dir, entry->i.NSCreator)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 return 1; /* I'm not sure */
595
596 qname.name = __name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597
Al Viro4f522a22013-02-11 23:20:37 -0500598 newdent = d_hash_and_lookup(dentry, &qname);
Viresh Kumara1c83682015-08-12 15:59:44 +0530599 if (IS_ERR(newdent))
Al Viro4f522a22013-02-11 23:20:37 -0500600 goto end_advance;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 if (!newdent) {
602 newdent = d_alloc(dentry, &qname);
603 if (!newdent)
604 goto end_advance;
605 } else {
606 hashed = 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200607
608 /* If case sensitivity changed for this volume, all entries below this one
609 should be thrown away. This entry itself is not affected, as its case
610 sensitivity is controlled by its own parent. */
611 if (inval_childs)
612 shrink_dcache_parent(newdent);
613
614 /*
Nick Pigginfb2d5b82011-01-07 17:49:26 +1100615 * NetWare's OS2 namespace is case preserving yet case
616 * insensitive. So we update dentry's name as received from
617 * server. Parent dir's i_mutex is locked because we're in
618 * readdir.
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200619 */
Nick Pigginfb2d5b82011-01-07 17:49:26 +1100620 dentry_update_name_case(newdent, &qname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 }
622
David Howells2b0143b2015-03-17 22:25:59 +0000623 if (d_really_is_negative(newdent)) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200624 struct inode *inode;
625
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 entry->opened = 0;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200627 entry->ino = iunique(dir->i_sb, 2);
628 inode = ncp_iget(dir->i_sb, entry);
629 if (inode) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200630 d_instantiate(newdent, inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 if (!hashed)
632 d_rehash(newdent);
Al Viro5e993e22014-12-24 21:41:47 -0500633 } else {
634 spin_lock(&dentry->d_lock);
Al Viro803c0012016-03-07 22:17:07 -0500635 NCP_FINFO(dir)->flags &= ~NCPI_DIR_CACHE;
Al Viro5e993e22014-12-24 21:41:47 -0500636 spin_unlock(&dentry->d_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200638 } else {
David Howells2b0143b2015-03-17 22:25:59 +0000639 struct inode *inode = d_inode(newdent);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200640
Al Viro59551022016-01-22 15:40:57 -0500641 inode_lock_nested(inode, I_MUTEX_CHILD);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200642 ncp_update_inode2(inode, entry);
Al Viro59551022016-01-22 15:40:57 -0500643 inode_unlock(inode);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200644 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 if (ctl.idx >= NCP_DIRCACHE_SIZE) {
647 if (ctl.page) {
648 kunmap(ctl.page);
649 SetPageUptodate(ctl.page);
650 unlock_page(ctl.page);
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300651 put_page(ctl.page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 }
653 ctl.cache = NULL;
654 ctl.idx -= NCP_DIRCACHE_SIZE;
655 ctl.ofs += 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200656 ctl.page = grab_cache_page(&dir->i_data, ctl.ofs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 if (ctl.page)
658 ctl.cache = kmap(ctl.page);
659 }
660 if (ctl.cache) {
David Howells2b0143b2015-03-17 22:25:59 +0000661 if (d_really_is_positive(newdent)) {
Al Viro5e993e22014-12-24 21:41:47 -0500662 newdent->d_fsdata = newdent;
663 ctl.cache->dentry[ctl.idx] = newdent;
David Howells2b0143b2015-03-17 22:25:59 +0000664 ino = d_inode(newdent)->i_ino;
Al Viro5e993e22014-12-24 21:41:47 -0500665 ncp_new_dentry(newdent);
666 }
667 valid = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 }
669 dput(newdent);
670end_advance:
671 if (!valid)
672 ctl.valid = 0;
Al Viro76f582a2013-05-22 15:11:27 -0400673 if (!ctl.filled && (ctl.fpos == ctx->pos)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 if (!ino)
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200675 ino = iunique(dir->i_sb, 2);
Al Viro76f582a2013-05-22 15:11:27 -0400676 ctl.filled = !dir_emit(ctx, qname.name, qname.len,
677 ino, DT_UNKNOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 if (!ctl.filled)
Al Viro76f582a2013-05-22 15:11:27 -0400679 ctx->pos += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 }
681 ctl.fpos += 1;
682 ctl.idx += 1;
683 *ctrl = ctl;
684 return (ctl.valid || !ctl.filled);
685}
686
687static void
Al Viro76f582a2013-05-22 15:11:27 -0400688ncp_read_volume_list(struct file *file, struct dir_context *ctx,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 struct ncp_cache_control *ctl)
690{
Al Viroa67f7972014-10-31 02:41:28 -0400691 struct inode *inode = file_inode(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 struct ncp_server *server = NCP_SERVER(inode);
693 struct ncp_volume_info info;
694 struct ncp_entry_info entry;
695 int i;
696
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700697 ncp_dbg(1, "pos=%ld\n", (unsigned long)ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
699 for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200700 int inval_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
702 if (ncp_get_volume_info_with_number(server, i, &info) != 0)
703 return;
704 if (!strlen(info.volume_name))
705 continue;
706
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700707 ncp_dbg(1, "found vol: %s\n", info.volume_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
709 if (ncp_lookup_volume(server, info.volume_name,
710 &entry.i)) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700711 ncp_dbg(1, "could not lookup vol %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 info.volume_name);
713 continue;
714 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200715 inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 entry.volume = entry.i.volNumber;
Al Viro76f582a2013-05-22 15:11:27 -0400717 if (!ncp_fill_cache(file, ctx, ctl, &entry, inval_dentry))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 return;
719 }
720}
721
722static void
Al Viro76f582a2013-05-22 15:11:27 -0400723ncp_do_readdir(struct file *file, struct dir_context *ctx,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 struct ncp_cache_control *ctl)
725{
Al Viroa67f7972014-10-31 02:41:28 -0400726 struct inode *dir = file_inode(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 struct ncp_server *server = NCP_SERVER(dir);
728 struct nw_search_sequence seq;
729 struct ncp_entry_info entry;
730 int err;
731 void* buf;
732 int more;
733 size_t bufsize;
734
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700735 ncp_dbg(1, "%pD2, fpos=%ld\n", file, (unsigned long)ctx->pos);
Joe Perchese45ca8b2014-04-08 16:04:16 -0700736 ncp_vdbg("init %pD, volnum=%d, dirent=%u\n",
737 file, NCP_FINFO(dir)->volNumber, NCP_FINFO(dir)->dirEntNum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
739 err = ncp_initialize_search(server, dir, &seq);
740 if (err) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700741 ncp_dbg(1, "init failed, err=%d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 return;
743 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 /* We MUST NOT use server->buffer_size handshaked with server if we are
745 using UDP, as for UDP server uses max. buffer size determined by
746 MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes).
747 So we use 128KB, just to be sure, as there is no way how to know
748 this value in advance. */
749 bufsize = 131072;
750 buf = vmalloc(bufsize);
751 if (!buf)
752 return;
753 do {
754 int cnt;
755 char* rpl;
756 size_t rpls;
757
758 err = ncp_search_for_fileset(server, &seq, &more, &cnt, buf, bufsize, &rpl, &rpls);
759 if (err) /* Error */
760 break;
761 if (!cnt) /* prevent endless loop */
762 break;
763 while (cnt--) {
764 size_t onerpl;
765
766 if (rpls < offsetof(struct nw_info_struct, entryName))
767 break; /* short packet */
768 ncp_extract_file_info(rpl, &entry.i);
769 onerpl = offsetof(struct nw_info_struct, entryName) + entry.i.nameLen;
770 if (rpls < onerpl)
771 break; /* short packet */
772 (void)ncp_obtain_nfs_info(server, &entry.i);
773 rpl += onerpl;
774 rpls -= onerpl;
775 entry.volume = entry.i.volNumber;
Al Viro76f582a2013-05-22 15:11:27 -0400776 if (!ncp_fill_cache(file, ctx, ctl, &entry, 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 break;
778 }
779 } while (more);
780 vfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 return;
782}
783
784int ncp_conn_logged_in(struct super_block *sb)
785{
786 struct ncp_server* server = NCP_SBP(sb);
787 int result;
788
789 if (ncp_single_volume(server)) {
790 int len;
791 struct dentry* dent;
792 __u32 volNumber;
793 __le32 dirEntNum;
794 __le32 DosDirNum;
795 __u8 __name[NCP_MAXPATHLEN + 1];
796
797 len = sizeof(__name);
798 result = ncp_io2vol(server, __name, &len, server->m.mounted_vol,
799 strlen(server->m.mounted_vol), 1);
800 if (result)
801 goto out;
802 result = -ENOENT;
803 if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) {
Joe Perchese45ca8b2014-04-08 16:04:16 -0700804 ncp_vdbg("%s not found\n", server->m.mounted_vol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 goto out;
806 }
807 dent = sb->s_root;
808 if (dent) {
David Howells2b0143b2015-03-17 22:25:59 +0000809 struct inode* ino = d_inode(dent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 if (ino) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200811 ncp_update_known_namespace(server, volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 NCP_FINFO(ino)->volNumber = volNumber;
813 NCP_FINFO(ino)->dirEntNum = dirEntNum;
814 NCP_FINFO(ino)->DosDirNum = DosDirNum;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200815 result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 } else {
David Howells2b0143b2015-03-17 22:25:59 +0000817 ncp_dbg(1, "d_inode(sb->s_root) == NULL!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 }
819 } else {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700820 ncp_dbg(1, "sb->s_root == NULL!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200822 } else
823 result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
825out:
826 return result;
827}
828
Al Viro00cd8dd2012-06-10 17:13:09 -0400829static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830{
831 struct ncp_server *server = NCP_SERVER(dir);
832 struct inode *inode = NULL;
833 struct ncp_entry_info finfo;
834 int error, res, len;
835 __u8 __name[NCP_MAXPATHLEN + 1];
836
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 error = -EIO;
838 if (!ncp_conn_valid(server))
839 goto finished;
840
Joe Perchese45ca8b2014-04-08 16:04:16 -0700841 ncp_vdbg("server lookup for %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
843 len = sizeof(__name);
844 if (ncp_is_server_root(dir)) {
845 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
846 dentry->d_name.len, 1);
847 if (!res)
848 res = ncp_lookup_volume(server, __name, &(finfo.i));
Dan Carpenterffddc5f2014-04-08 16:04:19 -0700849 if (!res)
850 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 } else {
852 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
853 dentry->d_name.len, !ncp_preserve_case(dir));
854 if (!res)
855 res = ncp_obtain_info(server, dir, __name, &(finfo.i));
856 }
Joe Perchese45ca8b2014-04-08 16:04:16 -0700857 ncp_vdbg("looked for %pd2, res=%d\n", dentry, res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 /*
859 * If we didn't find an entry, make a negative dentry.
860 */
861 if (res)
862 goto add_entry;
863
864 /*
865 * Create an inode for the entry.
866 */
867 finfo.opened = 0;
868 finfo.ino = iunique(dir->i_sb, 2);
869 finfo.volume = finfo.i.volNumber;
870 error = -EACCES;
871 inode = ncp_iget(dir->i_sb, &finfo);
872
873 if (inode) {
874 ncp_new_dentry(dentry);
875add_entry:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 d_add(dentry, inode);
877 error = 0;
878 }
879
880finished:
Joe Perchese45ca8b2014-04-08 16:04:16 -0700881 ncp_vdbg("result=%d\n", error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 return ERR_PTR(error);
883}
884
885/*
886 * This code is common to create, mkdir, and mknod.
887 */
888static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
889 struct ncp_entry_info *finfo)
890{
891 struct inode *inode;
892 int error = -EINVAL;
893
894 finfo->ino = iunique(dir->i_sb, 2);
895 inode = ncp_iget(dir->i_sb, finfo);
896 if (!inode)
897 goto out_close;
898 d_instantiate(dentry,inode);
899 error = 0;
900out:
901 return error;
902
903out_close:
Joe Perchese45ca8b2014-04-08 16:04:16 -0700904 ncp_vdbg("%pd2 failed, closing file\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 ncp_close_file(NCP_SERVER(dir), finfo->file_handle);
906 goto out;
907}
908
Al Viro5eee25c2011-07-26 03:12:16 -0400909int ncp_create_new(struct inode *dir, struct dentry *dentry, umode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 dev_t rdev, __le32 attributes)
911{
912 struct ncp_server *server = NCP_SERVER(dir);
913 struct ncp_entry_info finfo;
914 int error, result, len;
915 int opmode;
916 __u8 __name[NCP_MAXPATHLEN + 1];
917
Joe Perchese45ca8b2014-04-08 16:04:16 -0700918 ncp_vdbg("creating %pd2, mode=%hx\n", dentry, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 ncp_age_dentry(server, dentry);
921 len = sizeof(__name);
922 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
923 dentry->d_name.len, !ncp_preserve_case(dir));
924 if (error)
925 goto out;
926
927 error = -EACCES;
928
929 if (S_ISREG(mode) &&
930 (server->m.flags & NCP_MOUNT_EXTRAS) &&
931 (mode & S_IXUGO))
932 attributes |= aSYSTEM | aSHARED;
933
934 result = ncp_open_create_file_or_subdir(server, dir, __name,
935 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
936 attributes, AR_READ | AR_WRITE, &finfo);
937 opmode = O_RDWR;
938 if (result) {
939 result = ncp_open_create_file_or_subdir(server, dir, __name,
940 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
941 attributes, AR_WRITE, &finfo);
942 if (result) {
943 if (result == 0x87)
944 error = -ENAMETOOLONG;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200945 else if (result < 0)
946 error = result;
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700947 ncp_dbg(1, "%pd2 failed\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 goto out;
949 }
950 opmode = O_WRONLY;
951 }
952 finfo.access = opmode;
953 if (ncp_is_nfs_extras(server, finfo.volume)) {
954 finfo.i.nfs.mode = mode;
955 finfo.i.nfs.rdev = new_encode_dev(rdev);
956 if (ncp_modify_nfs_info(server, finfo.volume,
957 finfo.i.dirEntNum,
958 mode, new_encode_dev(rdev)) != 0)
959 goto out;
960 }
961
962 error = ncp_instantiate(dir, dentry, &finfo);
963out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 return error;
965}
966
Al Viro4acdaf22011-07-26 01:42:34 -0400967static int ncp_create(struct inode *dir, struct dentry *dentry, umode_t mode,
Al Viroebfc3b42012-06-10 18:05:36 -0400968 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969{
970 return ncp_create_new(dir, dentry, mode, 0, 0);
971}
972
Al Viro18bb1db2011-07-26 01:41:39 -0400973static int ncp_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974{
975 struct ncp_entry_info finfo;
976 struct ncp_server *server = NCP_SERVER(dir);
977 int error, len;
978 __u8 __name[NCP_MAXPATHLEN + 1];
979
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700980 ncp_dbg(1, "making %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 ncp_age_dentry(server, dentry);
983 len = sizeof(__name);
984 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
985 dentry->d_name.len, !ncp_preserve_case(dir));
986 if (error)
987 goto out;
988
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200989 error = ncp_open_create_file_or_subdir(server, dir, __name,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990 OC_MODE_CREATE, aDIR,
991 cpu_to_le16(0xffff),
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200992 &finfo);
993 if (error == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 if (ncp_is_nfs_extras(server, finfo.volume)) {
995 mode |= S_IFDIR;
996 finfo.i.nfs.mode = mode;
997 if (ncp_modify_nfs_info(server,
998 finfo.volume,
999 finfo.i.dirEntNum,
1000 mode, 0) != 0)
1001 goto out;
1002 }
1003 error = ncp_instantiate(dir, dentry, &finfo);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001004 } else if (error > 0) {
1005 error = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 }
1007out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 return error;
1009}
1010
1011static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
1012{
1013 struct ncp_server *server = NCP_SERVER(dir);
1014 int error, result, len;
1015 __u8 __name[NCP_MAXPATHLEN + 1];
1016
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001017 ncp_dbg(1, "removing %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 len = sizeof(__name);
1020 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
1021 dentry->d_name.len, !ncp_preserve_case(dir));
1022 if (error)
1023 goto out;
1024
1025 result = ncp_del_file_or_subdir(server, dir, __name);
1026 switch (result) {
1027 case 0x00:
1028 error = 0;
1029 break;
1030 case 0x85: /* unauthorized to delete file */
1031 case 0x8A: /* unauthorized to delete file */
1032 error = -EACCES;
1033 break;
1034 case 0x8F:
1035 case 0x90: /* read only */
1036 error = -EPERM;
1037 break;
1038 case 0x9F: /* in use by another client */
1039 error = -EBUSY;
1040 break;
1041 case 0xA0: /* directory not empty */
1042 error = -ENOTEMPTY;
1043 break;
1044 case 0xFF: /* someone deleted file */
1045 error = -ENOENT;
1046 break;
1047 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001048 error = result < 0 ? result : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 break;
1050 }
1051out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 return error;
1053}
1054
1055static int ncp_unlink(struct inode *dir, struct dentry *dentry)
1056{
David Howells2b0143b2015-03-17 22:25:59 +00001057 struct inode *inode = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 struct ncp_server *server;
1059 int error;
1060
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 server = NCP_SERVER(dir);
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001062 ncp_dbg(1, "unlinking %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 /*
1065 * Check whether to close the file ...
1066 */
1067 if (inode) {
Joe Perchese45ca8b2014-04-08 16:04:16 -07001068 ncp_vdbg("closing file\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 ncp_make_closed(inode);
1070 }
1071
1072 error = ncp_del_file_or_subdir2(server, dentry);
1073#ifdef CONFIG_NCPFS_STRONG
1074 /* 9C is Invalid path.. It should be 8F, 90 - read only, but
1075 it is not :-( */
1076 if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */
1077 error = ncp_force_unlink(dir, dentry);
1078 }
1079#endif
1080 switch (error) {
1081 case 0x00:
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001082 ncp_dbg(1, "removed %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 break;
1084 case 0x85:
1085 case 0x8A:
1086 error = -EACCES;
1087 break;
1088 case 0x8D: /* some files in use */
1089 case 0x8E: /* all files in use */
1090 error = -EBUSY;
1091 break;
1092 case 0x8F: /* some read only */
1093 case 0x90: /* all read only */
1094 case 0x9C: /* !!! returned when in-use or read-only by NW4 */
1095 error = -EPERM;
1096 break;
1097 case 0xFF:
1098 error = -ENOENT;
1099 break;
1100 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001101 error = error < 0 ? error : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 break;
1103 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 return error;
1105}
1106
1107static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
Miklos Szeredi1cd66c92016-09-27 11:03:58 +02001108 struct inode *new_dir, struct dentry *new_dentry,
1109 unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110{
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
Miklos Szeredi1cd66c92016-09-27 11:03:58 +02001116 if (flags)
1117 return -EINVAL;
1118
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001119 ncp_dbg(1, "%pd2 to %pd2\n", old_dentry, new_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 ncp_age_dentry(server, old_dentry);
1122 ncp_age_dentry(server, new_dentry);
1123
1124 old_len = sizeof(__old_name);
1125 error = ncp_io2vol(server, __old_name, &old_len,
1126 old_dentry->d_name.name, old_dentry->d_name.len,
1127 !ncp_preserve_case(old_dir));
1128 if (error)
1129 goto out;
1130
1131 new_len = sizeof(__new_name);
1132 error = ncp_io2vol(server, __new_name, &new_len,
1133 new_dentry->d_name.name, new_dentry->d_name.len,
1134 !ncp_preserve_case(new_dir));
1135 if (error)
1136 goto out;
1137
1138 error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name,
1139 new_dir, __new_name);
1140#ifdef CONFIG_NCPFS_STRONG
1141 if ((error == 0x90 || error == 0x8B || error == -EACCES) &&
1142 server->m.flags & NCP_MOUNT_STRONG) { /* RO */
1143 error = ncp_force_rename(old_dir, old_dentry, __old_name,
1144 new_dir, new_dentry, __new_name);
1145 }
1146#endif
1147 switch (error) {
1148 case 0x00:
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001149 ncp_dbg(1, "renamed %pd -> %pd\n",
1150 old_dentry, new_dentry);
Al Viro3f4a9492015-06-06 09:15:55 -04001151 ncp_d_prune(old_dentry);
1152 ncp_d_prune(new_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 break;
1154 case 0x9E:
1155 error = -ENAMETOOLONG;
1156 break;
1157 case 0xFF:
1158 error = -ENOENT;
1159 break;
1160 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001161 error = error < 0 ? error : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 break;
1163 }
1164out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 return error;
1166}
1167
1168static int ncp_mknod(struct inode * dir, struct dentry *dentry,
Al Viro1a67aaf2011-07-26 01:52:52 -04001169 umode_t mode, dev_t rdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001172 ncp_dbg(1, "mode = 0%ho\n", mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 return ncp_create_new(dir, dentry, mode, rdev, 0);
1174 }
1175 return -EPERM; /* Strange, but true */
1176}
1177
1178/* The following routines are taken directly from msdos-fs */
1179
1180/* Linear day numbers of the respective 1sts in non-leap years. */
1181
1182static int day_n[] =
1183{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
1184/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
1185
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186static int utc2local(int time)
1187{
1188 return time - sys_tz.tz_minuteswest * 60;
1189}
1190
1191static int local2utc(int time)
1192{
1193 return time + sys_tz.tz_minuteswest * 60;
1194}
1195
1196/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
1197int
1198ncp_date_dos2unix(__le16 t, __le16 d)
1199{
1200 unsigned short time = le16_to_cpu(t), date = le16_to_cpu(d);
1201 int month, year, secs;
1202
1203 /* first subtract and mask after that... Otherwise, if
1204 date == 0, bad things happen */
1205 month = ((date >> 5) - 1) & 15;
1206 year = date >> 9;
1207 secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
1208 86400 * ((date & 31) - 1 + day_n[month] + (year / 4) +
1209 year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
1210 /* days since 1.1.70 plus 80's leap day */
1211 return local2utc(secs);
1212}
1213
1214
1215/* Convert linear UNIX date to a MS-DOS time/date pair. */
1216void
1217ncp_date_unix2dos(int unix_date, __le16 *time, __le16 *date)
1218{
1219 int day, year, nl_day, month;
1220
1221 unix_date = utc2local(unix_date);
1222 *time = cpu_to_le16(
1223 (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
1224 (((unix_date / 3600) % 24) << 11));
1225 day = unix_date / 86400 - 3652;
1226 year = day / 365;
1227 if ((year + 3) / 4 + 365 * year > day)
1228 year--;
1229 day -= (year + 3) / 4 + 365 * year;
1230 if (day == 59 && !(year & 3)) {
1231 nl_day = day;
1232 month = 2;
1233 } else {
1234 nl_day = (year & 3) || day <= 59 ? day : day - 1;
Roel Kluinc5df5912009-09-22 16:45:54 -07001235 for (month = 1; month < 12; month++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 if (day_n[month] > nl_day)
1237 break;
1238 }
1239 *date = cpu_to_le16(nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
1240}