blob: 008960101520b49957a49c6de42344475280e964 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * dir.c
3 *
4 * Copyright (C) 1995, 1996 by Volker Lendecke
5 * Modified for big endian by J.F. Chadima and David S. Miller
6 * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
7 * Modified 1998, 1999 Wolfram Pienkoss for NLS
8 * Modified 1999 Wolfram Pienkoss for directory caching
9 * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
10 *
11 */
12
Linus Torvalds1da177e2005-04-16 15:20:36 -070013
14#include <linux/time.h>
15#include <linux/errno.h>
16#include <linux/stat.h>
17#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/vmalloc.h>
19#include <linux/mm.h>
Nick Piggin34286d62011-01-07 17:49:57 +110020#include <linux/namei.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <asm/uaccess.h>
22#include <asm/byteorder.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
Al Viro32c419d2011-01-12 17:37:47 -050024#include "ncp_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
Al Viro76f582a2013-05-22 15:11:27 -040026static void ncp_read_volume_list(struct file *, struct dir_context *,
Linus Torvalds1da177e2005-04-16 15:20:36 -070027 struct ncp_cache_control *);
Al Viro76f582a2013-05-22 15:11:27 -040028static void ncp_do_readdir(struct file *, struct dir_context *,
Linus Torvalds1da177e2005-04-16 15:20:36 -070029 struct ncp_cache_control *);
30
Al Viro76f582a2013-05-22 15:11:27 -040031static int ncp_readdir(struct file *, struct dir_context *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
Al Viroebfc3b42012-06-10 18:05:36 -040033static int ncp_create(struct inode *, struct dentry *, umode_t, bool);
Al Viro00cd8dd2012-06-10 17:13:09 -040034static struct dentry *ncp_lookup(struct inode *, struct dentry *, unsigned int);
Linus Torvalds1da177e2005-04-16 15:20:36 -070035static int ncp_unlink(struct inode *, struct dentry *);
Al Viro18bb1db2011-07-26 01:41:39 -040036static int ncp_mkdir(struct inode *, struct dentry *, umode_t);
Linus Torvalds1da177e2005-04-16 15:20:36 -070037static int ncp_rmdir(struct inode *, struct dentry *);
38static int ncp_rename(struct inode *, struct dentry *,
39 struct inode *, struct dentry *);
40static int ncp_mknod(struct inode * dir, struct dentry *dentry,
Al Viro1a67aaf2011-07-26 01:52:52 -040041 umode_t mode, dev_t rdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
43extern int ncp_symlink(struct inode *, struct dentry *, const char *);
44#else
45#define ncp_symlink NULL
46#endif
47
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -080048const struct file_operations ncp_dir_operations =
Linus Torvalds1da177e2005-04-16 15:20:36 -070049{
jan Blunckca572722010-05-26 14:44:53 -070050 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 .read = generic_read_dir,
Al Viro76f582a2013-05-22 15:11:27 -040052 .iterate = ncp_readdir,
John Kacur93d84b62010-05-05 15:15:37 +020053 .unlocked_ioctl = ncp_ioctl,
Petr Vandrovec54f67f62006-09-30 23:27:55 -070054#ifdef CONFIG_COMPAT
55 .compat_ioctl = ncp_compat_ioctl,
56#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070057};
58
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -080059const struct inode_operations ncp_dir_inode_operations =
Linus Torvalds1da177e2005-04-16 15:20:36 -070060{
61 .create = ncp_create,
62 .lookup = ncp_lookup,
63 .unlink = ncp_unlink,
64 .symlink = ncp_symlink,
65 .mkdir = ncp_mkdir,
66 .rmdir = ncp_rmdir,
67 .mknod = ncp_mknod,
68 .rename = ncp_rename,
69 .setattr = ncp_notify_change,
70};
71
72/*
73 * Dentry operations routines
74 */
Al Viro0b728e12012-06-10 16:03:43 -040075static int ncp_lookup_validate(struct dentry *, unsigned int);
Linus Torvaldsda53be12013-05-21 15:22:44 -070076static int ncp_hash_dentry(const struct dentry *, struct qstr *);
77static int ncp_compare_dentry(const struct dentry *, const struct dentry *,
Nick Piggin621e1552011-01-07 17:49:27 +110078 unsigned int, const char *, const struct qstr *);
Nick Pigginfe15ce42011-01-07 17:49:23 +110079static int ncp_delete_dentry(const struct dentry *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
Al Viro0378c402011-01-12 17:25:03 -050081const struct dentry_operations ncp_dentry_operations =
Linus Torvalds1da177e2005-04-16 15:20:36 -070082{
83 .d_revalidate = ncp_lookup_validate,
84 .d_hash = ncp_hash_dentry,
85 .d_compare = ncp_compare_dentry,
86 .d_delete = ncp_delete_dentry,
87};
88
Petr Vandrovec2e54eb92010-09-27 01:47:33 +020089#define ncp_namespace(i) (NCP_SERVER(i)->name_space[NCP_FINFO(i)->volNumber])
90
91static inline int ncp_preserve_entry_case(struct inode *i, __u32 nscreator)
92{
93#ifdef CONFIG_NCPFS_SMALLDOS
94 int ns = ncp_namespace(i);
95
96 if ((ns == NW_NS_DOS)
97#ifdef CONFIG_NCPFS_OS2_NS
98 || ((ns == NW_NS_OS2) && (nscreator == NW_NS_DOS))
99#endif /* CONFIG_NCPFS_OS2_NS */
100 )
101 return 0;
102#endif /* CONFIG_NCPFS_SMALLDOS */
103 return 1;
104}
105
106#define ncp_preserve_case(i) (ncp_namespace(i) != NW_NS_DOS)
107
Nick Piggin621e1552011-01-07 17:49:27 +1100108static inline int ncp_case_sensitive(const struct inode *i)
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200109{
110#ifdef CONFIG_NCPFS_NFS_NS
Nick Piggin621e1552011-01-07 17:49:27 +1100111 return ncp_namespace(i) == NW_NS_NFS;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200112#else
113 return 0;
114#endif /* CONFIG_NCPFS_NFS_NS */
115}
116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117/*
118 * Note: leave the hash unchanged if the directory
119 * is case-sensitive.
Linus Torvaldsda53be12013-05-21 15:22:44 -0700120 *
121 * Accessing the parent inode can be racy under RCU pathwalking.
122 * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
123 * the callers will handle races.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 */
125static int
Linus Torvaldsda53be12013-05-21 15:22:44 -0700126ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127{
Linus Torvaldsda53be12013-05-21 15:22:44 -0700128 struct inode *inode = ACCESS_ONCE(dentry->d_inode);
129
130 if (!inode)
131 return 0;
132
Nick Pigginb1e6a012011-01-07 17:49:28 +1100133 if (!ncp_case_sensitive(inode)) {
Nick Piggin621e1552011-01-07 17:49:27 +1100134 struct super_block *sb = dentry->d_sb;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200135 struct nls_table *t;
136 unsigned long hash;
137 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
Nick Piggin621e1552011-01-07 17:49:27 +1100139 t = NCP_IO_TABLE(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 hash = init_name_hash();
141 for (i=0; i<this->len ; i++)
142 hash = partial_name_hash(ncp_tolower(t, this->name[i]),
143 hash);
144 this->hash = end_name_hash(hash);
145 }
146 return 0;
147}
148
Linus Torvaldsda53be12013-05-21 15:22:44 -0700149/*
150 * Accessing the parent inode can be racy under RCU pathwalking.
151 * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
152 * the callers will handle races.
153 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154static int
Linus Torvaldsda53be12013-05-21 15:22:44 -0700155ncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
Nick Piggin621e1552011-01-07 17:49:27 +1100156 unsigned int len, const char *str, const struct qstr *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157{
Linus Torvaldsda53be12013-05-21 15:22:44 -0700158 struct inode *pinode;
159
Nick Piggin621e1552011-01-07 17:49:27 +1100160 if (len != name->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 return 1;
162
Linus Torvaldsda53be12013-05-21 15:22:44 -0700163 pinode = ACCESS_ONCE(parent->d_inode);
164 if (!pinode)
165 return 1;
166
Nick Piggin621e1552011-01-07 17:49:27 +1100167 if (ncp_case_sensitive(pinode))
168 return strncmp(str, name->name, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
Nick Piggin621e1552011-01-07 17:49:27 +1100170 return ncp_strnicmp(NCP_IO_TABLE(pinode->i_sb), str, name->name, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171}
172
173/*
174 * This is the callback from dput() when d_count is going to 0.
175 * We use this to unhash dentries with bad inodes.
176 * Closing files can be safely postponed until iput() - it's done there anyway.
177 */
178static int
Nick Pigginfe15ce42011-01-07 17:49:23 +1100179ncp_delete_dentry(const struct dentry * dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180{
181 struct inode *inode = dentry->d_inode;
182
183 if (inode) {
184 if (is_bad_inode(inode))
185 return 1;
186 } else
187 {
188 /* N.B. Unhash negative dentries? */
189 }
190 return 0;
191}
192
193static inline int
194ncp_single_volume(struct ncp_server *server)
195{
196 return (server->m.mounted_vol[0] != '\0');
197}
198
199static inline int ncp_is_server_root(struct inode *inode)
200{
Al Viroa7400222014-10-21 15:20:42 -0400201 return !ncp_single_volume(NCP_SERVER(inode)) &&
202 is_root_inode(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203}
204
205
206/*
207 * This is the callback when the dcache has a lookup hit.
208 */
209
210
211#ifdef CONFIG_NCPFS_STRONG
212/* try to delete a readonly file (NW R bit set) */
213
214static int
215ncp_force_unlink(struct inode *dir, struct dentry* dentry)
216{
217 int res=0x9c,res2;
218 struct nw_modify_dos_info info;
219 __le32 old_nwattr;
220 struct inode *inode;
221
222 memset(&info, 0, sizeof(info));
223
224 /* remove the Read-Only flag on the NW server */
225 inode = dentry->d_inode;
226
227 old_nwattr = NCP_FINFO(inode)->nwattr;
228 info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT);
229 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
230 if (res2)
231 goto leave_me;
232
233 /* now try again the delete operation */
234 res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
235
236 if (res) /* delete failed, set R bit again */
237 {
238 info.attributes = old_nwattr;
239 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
240 if (res2)
241 goto leave_me;
242 }
243leave_me:
244 return(res);
245}
246#endif /* CONFIG_NCPFS_STRONG */
247
248#ifdef CONFIG_NCPFS_STRONG
249static int
250ncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name,
251 struct inode *new_dir, struct dentry* new_dentry, char *_new_name)
252{
253 struct nw_modify_dos_info info;
254 int res=0x90,res2;
255 struct inode *old_inode = old_dentry->d_inode;
256 __le32 old_nwattr = NCP_FINFO(old_inode)->nwattr;
257 __le32 new_nwattr = 0; /* shut compiler warning */
258 int old_nwattr_changed = 0;
259 int new_nwattr_changed = 0;
260
261 memset(&info, 0, sizeof(info));
262
263 /* remove the Read-Only flag on the NW server */
264
265 info.attributes = old_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
266 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
267 if (!res2)
268 old_nwattr_changed = 1;
269 if (new_dentry && new_dentry->d_inode) {
270 new_nwattr = NCP_FINFO(new_dentry->d_inode)->nwattr;
271 info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
272 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
273 if (!res2)
274 new_nwattr_changed = 1;
275 }
276 /* now try again the rename operation */
277 /* but only if something really happened */
278 if (new_nwattr_changed || old_nwattr_changed) {
279 res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
280 old_dir, _old_name,
281 new_dir, _new_name);
282 }
283 if (res)
284 goto leave_me;
285 /* file was successfully renamed, so:
286 do not set attributes on old file - it no longer exists
287 copy attributes from old file to new */
288 new_nwattr_changed = old_nwattr_changed;
289 new_nwattr = old_nwattr;
290 old_nwattr_changed = 0;
291
292leave_me:;
293 if (old_nwattr_changed) {
294 info.attributes = old_nwattr;
295 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
296 /* ignore errors */
297 }
298 if (new_nwattr_changed) {
299 info.attributes = new_nwattr;
300 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
301 /* ignore errors */
302 }
303 return(res);
304}
305#endif /* CONFIG_NCPFS_STRONG */
306
307
308static int
Al Viro0b728e12012-06-10 16:03:43 -0400309ncp_lookup_validate(struct dentry *dentry, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310{
311 struct ncp_server *server;
312 struct dentry *parent;
313 struct inode *dir;
314 struct ncp_entry_info finfo;
315 int res, val = 0, len;
316 __u8 __name[NCP_MAXPATHLEN + 1];
317
Al Viro0378c402011-01-12 17:25:03 -0500318 if (dentry == dentry->d_sb->s_root)
319 return 1;
320
Al Viro0b728e12012-06-10 16:03:43 -0400321 if (flags & LOOKUP_RCU)
Nick Piggin34286d62011-01-07 17:49:57 +1100322 return -ECHILD;
323
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 parent = dget_parent(dentry);
325 dir = parent->d_inode;
326
327 if (!dentry->d_inode)
328 goto finished;
329
330 server = NCP_SERVER(dir);
331
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 /*
333 * Inspired by smbfs:
334 * The default validation is based on dentry age:
335 * We set the max age at mount time. (But each
336 * successful server lookup renews the timestamp.)
337 */
338 val = NCP_TEST_AGE(server, dentry);
339 if (val)
340 goto finished;
341
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700342 ncp_dbg(2, "%pd2 not valid, age=%ld, server lookup\n",
Al Viro84eb3532013-09-16 10:59:55 -0400343 dentry, NCP_GET_AGE(dentry));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
345 len = sizeof(__name);
346 if (ncp_is_server_root(dir)) {
347 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
348 dentry->d_name.len, 1);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200349 if (!res) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 res = ncp_lookup_volume(server, __name, &(finfo.i));
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200351 if (!res)
352 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
353 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 } else {
355 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
356 dentry->d_name.len, !ncp_preserve_case(dir));
357 if (!res)
358 res = ncp_obtain_info(server, dir, __name, &(finfo.i));
359 }
360 finfo.volume = finfo.i.volNumber;
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700361 ncp_dbg(2, "looked for %pd/%s, res=%d\n",
Al Viro84eb3532013-09-16 10:59:55 -0400362 dentry->d_parent, __name, res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 /*
364 * If we didn't find it, or if it has a different dirEntNum to
365 * what we remember, it's not valid any more.
366 */
367 if (!res) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200368 struct inode *inode = dentry->d_inode;
369
370 mutex_lock(&inode->i_mutex);
371 if (finfo.i.dirEntNum == NCP_FINFO(inode)->dirEntNum) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 ncp_new_dentry(dentry);
373 val=1;
374 } else
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700375 ncp_dbg(2, "found, but dirEntNum changed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200377 ncp_update_inode2(inode, &finfo);
378 mutex_unlock(&inode->i_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 }
380
381finished:
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700382 ncp_dbg(2, "result=%d\n", val);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 dput(parent);
384 return val;
385}
386
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387static struct dentry *
388ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
389{
390 struct dentry *dent = dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391
392 if (d_validate(dent, parent)) {
393 if (dent->d_name.len <= NCP_MAXPATHLEN &&
394 (unsigned long)dent->d_fsdata == fpos) {
395 if (!dent->d_inode) {
396 dput(dent);
397 dent = NULL;
398 }
399 return dent;
400 }
401 dput(dent);
402 }
403
404 /* If a pointer is invalid, we search the dentry. */
Nick Piggin2fd6b7f2011-01-07 17:49:34 +1100405 spin_lock(&parent->d_lock);
Al Viro946e51f2014-10-26 19:19:16 -0400406 list_for_each_entry(dent, &parent->d_subdirs, d_child) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 if ((unsigned long)dent->d_fsdata == fpos) {
408 if (dent->d_inode)
Nick Piggindc0474b2011-01-07 17:49:43 +1100409 dget(dent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 else
411 dent = NULL;
Nick Piggin2fd6b7f2011-01-07 17:49:34 +1100412 spin_unlock(&parent->d_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 goto out;
414 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 }
Nick Piggin2fd6b7f2011-01-07 17:49:34 +1100416 spin_unlock(&parent->d_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 return NULL;
418
419out:
420 return dent;
421}
422
423static time_t ncp_obtain_mtime(struct dentry *dentry)
424{
425 struct inode *inode = dentry->d_inode;
426 struct ncp_server *server = NCP_SERVER(inode);
427 struct nw_info_struct i;
428
429 if (!ncp_conn_valid(server) || ncp_is_server_root(inode))
430 return 0;
431
432 if (ncp_obtain_info(server, inode, NULL, &i))
433 return 0;
434
435 return ncp_date_dos2unix(i.modifyTime, i.modifyDate);
436}
437
Al Viro76f582a2013-05-22 15:11:27 -0400438static int ncp_readdir(struct file *file, struct dir_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439{
Al Viro76f582a2013-05-22 15:11:27 -0400440 struct dentry *dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 struct inode *inode = dentry->d_inode;
442 struct page *page = NULL;
443 struct ncp_server *server = NCP_SERVER(inode);
444 union ncp_dir_cache *cache = NULL;
445 struct ncp_cache_control ctl;
446 int result, mtime_valid = 0;
447 time_t mtime = 0;
448
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 ctl.page = NULL;
450 ctl.cache = NULL;
451
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700452 ncp_dbg(2, "reading %pD2, pos=%d\n", file, (int)ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453
454 result = -EIO;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200455 /* Do not generate '.' and '..' when server is dead. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 if (!ncp_conn_valid(server))
457 goto out;
458
459 result = 0;
Al Viro76f582a2013-05-22 15:11:27 -0400460 if (!dir_emit_dots(file, ctx))
461 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462
463 page = grab_cache_page(&inode->i_data, 0);
464 if (!page)
465 goto read_really;
466
467 ctl.cache = cache = kmap(page);
468 ctl.head = cache->head;
469
470 if (!PageUptodate(page) || !ctl.head.eof)
471 goto init_cache;
472
Al Viro76f582a2013-05-22 15:11:27 -0400473 if (ctx->pos == 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 if (jiffies - ctl.head.time >= NCP_MAX_AGE(server))
475 goto init_cache;
476
477 mtime = ncp_obtain_mtime(dentry);
478 mtime_valid = 1;
479 if ((!mtime) || (mtime != ctl.head.mtime))
480 goto init_cache;
481 }
482
Al Viro76f582a2013-05-22 15:11:27 -0400483 if (ctx->pos > ctl.head.end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 goto finished;
485
Al Viro76f582a2013-05-22 15:11:27 -0400486 ctl.fpos = ctx->pos + (NCP_DIRCACHE_START - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 ctl.ofs = ctl.fpos / NCP_DIRCACHE_SIZE;
488 ctl.idx = ctl.fpos % NCP_DIRCACHE_SIZE;
489
490 for (;;) {
491 if (ctl.ofs != 0) {
492 ctl.page = find_lock_page(&inode->i_data, ctl.ofs);
493 if (!ctl.page)
494 goto invalid_cache;
495 ctl.cache = kmap(ctl.page);
496 if (!PageUptodate(ctl.page))
497 goto invalid_cache;
498 }
499 while (ctl.idx < NCP_DIRCACHE_SIZE) {
500 struct dentry *dent;
Al Viro76f582a2013-05-22 15:11:27 -0400501 bool over;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502
503 dent = ncp_dget_fpos(ctl.cache->dentry[ctl.idx],
Al Viro76f582a2013-05-22 15:11:27 -0400504 dentry, ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 if (!dent)
506 goto invalid_cache;
Al Viro76f582a2013-05-22 15:11:27 -0400507 over = !dir_emit(ctx, dent->d_name.name,
508 dent->d_name.len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 dent->d_inode->i_ino, DT_UNKNOWN);
510 dput(dent);
Al Viro76f582a2013-05-22 15:11:27 -0400511 if (over)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 goto finished;
Al Viro76f582a2013-05-22 15:11:27 -0400513 ctx->pos += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 ctl.idx += 1;
Al Viro76f582a2013-05-22 15:11:27 -0400515 if (ctx->pos > ctl.head.end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 goto finished;
517 }
518 if (ctl.page) {
519 kunmap(ctl.page);
520 SetPageUptodate(ctl.page);
521 unlock_page(ctl.page);
522 page_cache_release(ctl.page);
523 ctl.page = NULL;
524 }
525 ctl.idx = 0;
526 ctl.ofs += 1;
527 }
528invalid_cache:
529 if (ctl.page) {
530 kunmap(ctl.page);
531 unlock_page(ctl.page);
532 page_cache_release(ctl.page);
533 ctl.page = NULL;
534 }
535 ctl.cache = cache;
536init_cache:
537 ncp_invalidate_dircache_entries(dentry);
538 if (!mtime_valid) {
539 mtime = ncp_obtain_mtime(dentry);
540 mtime_valid = 1;
541 }
542 ctl.head.mtime = mtime;
543 ctl.head.time = jiffies;
544 ctl.head.eof = 0;
545 ctl.fpos = 2;
546 ctl.ofs = 0;
547 ctl.idx = NCP_DIRCACHE_START;
548 ctl.filled = 0;
549 ctl.valid = 1;
550read_really:
551 if (ncp_is_server_root(inode)) {
Al Viro76f582a2013-05-22 15:11:27 -0400552 ncp_read_volume_list(file, ctx, &ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 } else {
Al Viro76f582a2013-05-22 15:11:27 -0400554 ncp_do_readdir(file, ctx, &ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 }
556 ctl.head.end = ctl.fpos - 1;
557 ctl.head.eof = ctl.valid;
558finished:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200559 if (ctl.page) {
560 kunmap(ctl.page);
561 SetPageUptodate(ctl.page);
562 unlock_page(ctl.page);
563 page_cache_release(ctl.page);
564 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 if (page) {
566 cache->head = ctl.head;
567 kunmap(page);
568 SetPageUptodate(page);
569 unlock_page(page);
570 page_cache_release(page);
571 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 return result;
574}
575
576static 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;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200582 struct inode *dir = dentry->d_inode;
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);
599 if (unlikely(IS_ERR(newdent)))
600 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
623 if (!newdent->d_inode) {
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);
633 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200634 } else {
635 struct inode *inode = newdent->d_inode;
636
Nick Pigginfb2d5b82011-01-07 17:49:26 +1100637 mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200638 ncp_update_inode2(inode, entry);
639 mutex_unlock(&inode->i_mutex);
640 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
642 if (newdent->d_inode) {
643 ino = newdent->d_inode->i_ino;
644 newdent->d_fsdata = (void *) ctl.fpos;
645 ncp_new_dentry(newdent);
646 }
647
648 if (ctl.idx >= NCP_DIRCACHE_SIZE) {
649 if (ctl.page) {
650 kunmap(ctl.page);
651 SetPageUptodate(ctl.page);
652 unlock_page(ctl.page);
653 page_cache_release(ctl.page);
654 }
655 ctl.cache = NULL;
656 ctl.idx -= NCP_DIRCACHE_SIZE;
657 ctl.ofs += 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200658 ctl.page = grab_cache_page(&dir->i_data, ctl.ofs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 if (ctl.page)
660 ctl.cache = kmap(ctl.page);
661 }
662 if (ctl.cache) {
663 ctl.cache->dentry[ctl.idx] = newdent;
664 valid = 1;
665 }
666 dput(newdent);
667end_advance:
668 if (!valid)
669 ctl.valid = 0;
Al Viro76f582a2013-05-22 15:11:27 -0400670 if (!ctl.filled && (ctl.fpos == ctx->pos)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 if (!ino)
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200672 ino = iunique(dir->i_sb, 2);
Al Viro76f582a2013-05-22 15:11:27 -0400673 ctl.filled = !dir_emit(ctx, qname.name, qname.len,
674 ino, DT_UNKNOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 if (!ctl.filled)
Al Viro76f582a2013-05-22 15:11:27 -0400676 ctx->pos += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 }
678 ctl.fpos += 1;
679 ctl.idx += 1;
680 *ctrl = ctl;
681 return (ctl.valid || !ctl.filled);
682}
683
684static void
Al Viro76f582a2013-05-22 15:11:27 -0400685ncp_read_volume_list(struct file *file, struct dir_context *ctx,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 struct ncp_cache_control *ctl)
687{
Al Viroa67f7972014-10-31 02:41:28 -0400688 struct inode *inode = file_inode(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 struct ncp_server *server = NCP_SERVER(inode);
690 struct ncp_volume_info info;
691 struct ncp_entry_info entry;
692 int i;
693
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700694 ncp_dbg(1, "pos=%ld\n", (unsigned long)ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695
696 for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200697 int inval_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
699 if (ncp_get_volume_info_with_number(server, i, &info) != 0)
700 return;
701 if (!strlen(info.volume_name))
702 continue;
703
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700704 ncp_dbg(1, "found vol: %s\n", info.volume_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
706 if (ncp_lookup_volume(server, info.volume_name,
707 &entry.i)) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700708 ncp_dbg(1, "could not lookup vol %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 info.volume_name);
710 continue;
711 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200712 inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 entry.volume = entry.i.volNumber;
Al Viro76f582a2013-05-22 15:11:27 -0400714 if (!ncp_fill_cache(file, ctx, ctl, &entry, inval_dentry))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 return;
716 }
717}
718
719static void
Al Viro76f582a2013-05-22 15:11:27 -0400720ncp_do_readdir(struct file *file, struct dir_context *ctx,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 struct ncp_cache_control *ctl)
722{
Al Viroa67f7972014-10-31 02:41:28 -0400723 struct inode *dir = file_inode(file);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 struct ncp_server *server = NCP_SERVER(dir);
725 struct nw_search_sequence seq;
726 struct ncp_entry_info entry;
727 int err;
728 void* buf;
729 int more;
730 size_t bufsize;
731
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700732 ncp_dbg(1, "%pD2, fpos=%ld\n", file, (unsigned long)ctx->pos);
Joe Perchese45ca8b2014-04-08 16:04:16 -0700733 ncp_vdbg("init %pD, volnum=%d, dirent=%u\n",
734 file, NCP_FINFO(dir)->volNumber, NCP_FINFO(dir)->dirEntNum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
736 err = ncp_initialize_search(server, dir, &seq);
737 if (err) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700738 ncp_dbg(1, "init failed, err=%d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 return;
740 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 /* We MUST NOT use server->buffer_size handshaked with server if we are
742 using UDP, as for UDP server uses max. buffer size determined by
743 MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes).
744 So we use 128KB, just to be sure, as there is no way how to know
745 this value in advance. */
746 bufsize = 131072;
747 buf = vmalloc(bufsize);
748 if (!buf)
749 return;
750 do {
751 int cnt;
752 char* rpl;
753 size_t rpls;
754
755 err = ncp_search_for_fileset(server, &seq, &more, &cnt, buf, bufsize, &rpl, &rpls);
756 if (err) /* Error */
757 break;
758 if (!cnt) /* prevent endless loop */
759 break;
760 while (cnt--) {
761 size_t onerpl;
762
763 if (rpls < offsetof(struct nw_info_struct, entryName))
764 break; /* short packet */
765 ncp_extract_file_info(rpl, &entry.i);
766 onerpl = offsetof(struct nw_info_struct, entryName) + entry.i.nameLen;
767 if (rpls < onerpl)
768 break; /* short packet */
769 (void)ncp_obtain_nfs_info(server, &entry.i);
770 rpl += onerpl;
771 rpls -= onerpl;
772 entry.volume = entry.i.volNumber;
Al Viro76f582a2013-05-22 15:11:27 -0400773 if (!ncp_fill_cache(file, ctx, ctl, &entry, 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 break;
775 }
776 } while (more);
777 vfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 return;
779}
780
781int ncp_conn_logged_in(struct super_block *sb)
782{
783 struct ncp_server* server = NCP_SBP(sb);
784 int result;
785
786 if (ncp_single_volume(server)) {
787 int len;
788 struct dentry* dent;
789 __u32 volNumber;
790 __le32 dirEntNum;
791 __le32 DosDirNum;
792 __u8 __name[NCP_MAXPATHLEN + 1];
793
794 len = sizeof(__name);
795 result = ncp_io2vol(server, __name, &len, server->m.mounted_vol,
796 strlen(server->m.mounted_vol), 1);
797 if (result)
798 goto out;
799 result = -ENOENT;
800 if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) {
Joe Perchese45ca8b2014-04-08 16:04:16 -0700801 ncp_vdbg("%s not found\n", server->m.mounted_vol);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 goto out;
803 }
804 dent = sb->s_root;
805 if (dent) {
806 struct inode* ino = dent->d_inode;
807 if (ino) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200808 ncp_update_known_namespace(server, volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 NCP_FINFO(ino)->volNumber = volNumber;
810 NCP_FINFO(ino)->dirEntNum = dirEntNum;
811 NCP_FINFO(ino)->DosDirNum = DosDirNum;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200812 result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 } else {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700814 ncp_dbg(1, "sb->s_root->d_inode == NULL!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 }
816 } else {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700817 ncp_dbg(1, "sb->s_root == NULL!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200819 } else
820 result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821
822out:
823 return result;
824}
825
Al Viro00cd8dd2012-06-10 17:13:09 -0400826static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827{
828 struct ncp_server *server = NCP_SERVER(dir);
829 struct inode *inode = NULL;
830 struct ncp_entry_info finfo;
831 int error, res, len;
832 __u8 __name[NCP_MAXPATHLEN + 1];
833
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 error = -EIO;
835 if (!ncp_conn_valid(server))
836 goto finished;
837
Joe Perchese45ca8b2014-04-08 16:04:16 -0700838 ncp_vdbg("server lookup for %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
840 len = sizeof(__name);
841 if (ncp_is_server_root(dir)) {
842 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
843 dentry->d_name.len, 1);
844 if (!res)
845 res = ncp_lookup_volume(server, __name, &(finfo.i));
Dan Carpenterffddc5f2014-04-08 16:04:19 -0700846 if (!res)
847 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 } else {
849 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
850 dentry->d_name.len, !ncp_preserve_case(dir));
851 if (!res)
852 res = ncp_obtain_info(server, dir, __name, &(finfo.i));
853 }
Joe Perchese45ca8b2014-04-08 16:04:16 -0700854 ncp_vdbg("looked for %pd2, res=%d\n", dentry, res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 /*
856 * If we didn't find an entry, make a negative dentry.
857 */
858 if (res)
859 goto add_entry;
860
861 /*
862 * Create an inode for the entry.
863 */
864 finfo.opened = 0;
865 finfo.ino = iunique(dir->i_sb, 2);
866 finfo.volume = finfo.i.volNumber;
867 error = -EACCES;
868 inode = ncp_iget(dir->i_sb, &finfo);
869
870 if (inode) {
871 ncp_new_dentry(dentry);
872add_entry:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 d_add(dentry, inode);
874 error = 0;
875 }
876
877finished:
Joe Perchese45ca8b2014-04-08 16:04:16 -0700878 ncp_vdbg("result=%d\n", error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 return ERR_PTR(error);
880}
881
882/*
883 * This code is common to create, mkdir, and mknod.
884 */
885static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
886 struct ncp_entry_info *finfo)
887{
888 struct inode *inode;
889 int error = -EINVAL;
890
891 finfo->ino = iunique(dir->i_sb, 2);
892 inode = ncp_iget(dir->i_sb, finfo);
893 if (!inode)
894 goto out_close;
895 d_instantiate(dentry,inode);
896 error = 0;
897out:
898 return error;
899
900out_close:
Joe Perchese45ca8b2014-04-08 16:04:16 -0700901 ncp_vdbg("%pd2 failed, closing file\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 ncp_close_file(NCP_SERVER(dir), finfo->file_handle);
903 goto out;
904}
905
Al Viro5eee25c2011-07-26 03:12:16 -0400906int ncp_create_new(struct inode *dir, struct dentry *dentry, umode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 dev_t rdev, __le32 attributes)
908{
909 struct ncp_server *server = NCP_SERVER(dir);
910 struct ncp_entry_info finfo;
911 int error, result, len;
912 int opmode;
913 __u8 __name[NCP_MAXPATHLEN + 1];
914
Joe Perchese45ca8b2014-04-08 16:04:16 -0700915 ncp_vdbg("creating %pd2, mode=%hx\n", dentry, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 ncp_age_dentry(server, dentry);
918 len = sizeof(__name);
919 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
920 dentry->d_name.len, !ncp_preserve_case(dir));
921 if (error)
922 goto out;
923
924 error = -EACCES;
925
926 if (S_ISREG(mode) &&
927 (server->m.flags & NCP_MOUNT_EXTRAS) &&
928 (mode & S_IXUGO))
929 attributes |= aSYSTEM | aSHARED;
930
931 result = ncp_open_create_file_or_subdir(server, dir, __name,
932 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
933 attributes, AR_READ | AR_WRITE, &finfo);
934 opmode = O_RDWR;
935 if (result) {
936 result = ncp_open_create_file_or_subdir(server, dir, __name,
937 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
938 attributes, AR_WRITE, &finfo);
939 if (result) {
940 if (result == 0x87)
941 error = -ENAMETOOLONG;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200942 else if (result < 0)
943 error = result;
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700944 ncp_dbg(1, "%pd2 failed\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 goto out;
946 }
947 opmode = O_WRONLY;
948 }
949 finfo.access = opmode;
950 if (ncp_is_nfs_extras(server, finfo.volume)) {
951 finfo.i.nfs.mode = mode;
952 finfo.i.nfs.rdev = new_encode_dev(rdev);
953 if (ncp_modify_nfs_info(server, finfo.volume,
954 finfo.i.dirEntNum,
955 mode, new_encode_dev(rdev)) != 0)
956 goto out;
957 }
958
959 error = ncp_instantiate(dir, dentry, &finfo);
960out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 return error;
962}
963
Al Viro4acdaf22011-07-26 01:42:34 -0400964static int ncp_create(struct inode *dir, struct dentry *dentry, umode_t mode,
Al Viroebfc3b42012-06-10 18:05:36 -0400965 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966{
967 return ncp_create_new(dir, dentry, mode, 0, 0);
968}
969
Al Viro18bb1db2011-07-26 01:41:39 -0400970static int ncp_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971{
972 struct ncp_entry_info finfo;
973 struct ncp_server *server = NCP_SERVER(dir);
974 int error, len;
975 __u8 __name[NCP_MAXPATHLEN + 1];
976
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700977 ncp_dbg(1, "making %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 ncp_age_dentry(server, dentry);
980 len = sizeof(__name);
981 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
982 dentry->d_name.len, !ncp_preserve_case(dir));
983 if (error)
984 goto out;
985
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200986 error = ncp_open_create_file_or_subdir(server, dir, __name,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987 OC_MODE_CREATE, aDIR,
988 cpu_to_le16(0xffff),
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200989 &finfo);
990 if (error == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 if (ncp_is_nfs_extras(server, finfo.volume)) {
992 mode |= S_IFDIR;
993 finfo.i.nfs.mode = mode;
994 if (ncp_modify_nfs_info(server,
995 finfo.volume,
996 finfo.i.dirEntNum,
997 mode, 0) != 0)
998 goto out;
999 }
1000 error = ncp_instantiate(dir, dentry, &finfo);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001001 } else if (error > 0) {
1002 error = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 }
1004out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 return error;
1006}
1007
1008static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
1009{
1010 struct ncp_server *server = NCP_SERVER(dir);
1011 int error, result, len;
1012 __u8 __name[NCP_MAXPATHLEN + 1];
1013
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001014 ncp_dbg(1, "removing %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 len = sizeof(__name);
1017 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
1018 dentry->d_name.len, !ncp_preserve_case(dir));
1019 if (error)
1020 goto out;
1021
1022 result = ncp_del_file_or_subdir(server, dir, __name);
1023 switch (result) {
1024 case 0x00:
1025 error = 0;
1026 break;
1027 case 0x85: /* unauthorized to delete file */
1028 case 0x8A: /* unauthorized to delete file */
1029 error = -EACCES;
1030 break;
1031 case 0x8F:
1032 case 0x90: /* read only */
1033 error = -EPERM;
1034 break;
1035 case 0x9F: /* in use by another client */
1036 error = -EBUSY;
1037 break;
1038 case 0xA0: /* directory not empty */
1039 error = -ENOTEMPTY;
1040 break;
1041 case 0xFF: /* someone deleted file */
1042 error = -ENOENT;
1043 break;
1044 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001045 error = result < 0 ? result : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 break;
1047 }
1048out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 return error;
1050}
1051
1052static int ncp_unlink(struct inode *dir, struct dentry *dentry)
1053{
1054 struct inode *inode = dentry->d_inode;
1055 struct ncp_server *server;
1056 int error;
1057
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 server = NCP_SERVER(dir);
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001059 ncp_dbg(1, "unlinking %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 /*
1062 * Check whether to close the file ...
1063 */
1064 if (inode) {
Joe Perchese45ca8b2014-04-08 16:04:16 -07001065 ncp_vdbg("closing file\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 ncp_make_closed(inode);
1067 }
1068
1069 error = ncp_del_file_or_subdir2(server, dentry);
1070#ifdef CONFIG_NCPFS_STRONG
1071 /* 9C is Invalid path.. It should be 8F, 90 - read only, but
1072 it is not :-( */
1073 if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */
1074 error = ncp_force_unlink(dir, dentry);
1075 }
1076#endif
1077 switch (error) {
1078 case 0x00:
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001079 ncp_dbg(1, "removed %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 break;
1081 case 0x85:
1082 case 0x8A:
1083 error = -EACCES;
1084 break;
1085 case 0x8D: /* some files in use */
1086 case 0x8E: /* all files in use */
1087 error = -EBUSY;
1088 break;
1089 case 0x8F: /* some read only */
1090 case 0x90: /* all read only */
1091 case 0x9C: /* !!! returned when in-use or read-only by NW4 */
1092 error = -EPERM;
1093 break;
1094 case 0xFF:
1095 error = -ENOENT;
1096 break;
1097 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001098 error = error < 0 ? error : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 break;
1100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 return error;
1102}
1103
1104static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
1105 struct inode *new_dir, struct dentry *new_dentry)
1106{
1107 struct ncp_server *server = NCP_SERVER(old_dir);
1108 int error;
1109 int old_len, new_len;
1110 __u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1];
1111
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001112 ncp_dbg(1, "%pd2 to %pd2\n", old_dentry, new_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 ncp_age_dentry(server, old_dentry);
1115 ncp_age_dentry(server, new_dentry);
1116
1117 old_len = sizeof(__old_name);
1118 error = ncp_io2vol(server, __old_name, &old_len,
1119 old_dentry->d_name.name, old_dentry->d_name.len,
1120 !ncp_preserve_case(old_dir));
1121 if (error)
1122 goto out;
1123
1124 new_len = sizeof(__new_name);
1125 error = ncp_io2vol(server, __new_name, &new_len,
1126 new_dentry->d_name.name, new_dentry->d_name.len,
1127 !ncp_preserve_case(new_dir));
1128 if (error)
1129 goto out;
1130
1131 error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name,
1132 new_dir, __new_name);
1133#ifdef CONFIG_NCPFS_STRONG
1134 if ((error == 0x90 || error == 0x8B || error == -EACCES) &&
1135 server->m.flags & NCP_MOUNT_STRONG) { /* RO */
1136 error = ncp_force_rename(old_dir, old_dentry, __old_name,
1137 new_dir, new_dentry, __new_name);
1138 }
1139#endif
1140 switch (error) {
1141 case 0x00:
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001142 ncp_dbg(1, "renamed %pd -> %pd\n",
1143 old_dentry, new_dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 break;
1145 case 0x9E:
1146 error = -ENAMETOOLONG;
1147 break;
1148 case 0xFF:
1149 error = -ENOENT;
1150 break;
1151 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001152 error = error < 0 ? error : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 break;
1154 }
1155out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 return error;
1157}
1158
1159static int ncp_mknod(struct inode * dir, struct dentry *dentry,
Al Viro1a67aaf2011-07-26 01:52:52 -04001160 umode_t mode, dev_t rdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161{
1162 if (!new_valid_dev(rdev))
1163 return -EINVAL;
1164 if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001165 ncp_dbg(1, "mode = 0%ho\n", mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 return ncp_create_new(dir, dentry, mode, rdev, 0);
1167 }
1168 return -EPERM; /* Strange, but true */
1169}
1170
1171/* The following routines are taken directly from msdos-fs */
1172
1173/* Linear day numbers of the respective 1sts in non-leap years. */
1174
1175static int day_n[] =
1176{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
1177/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
1178
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179static int utc2local(int time)
1180{
1181 return time - sys_tz.tz_minuteswest * 60;
1182}
1183
1184static int local2utc(int time)
1185{
1186 return time + sys_tz.tz_minuteswest * 60;
1187}
1188
1189/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
1190int
1191ncp_date_dos2unix(__le16 t, __le16 d)
1192{
1193 unsigned short time = le16_to_cpu(t), date = le16_to_cpu(d);
1194 int month, year, secs;
1195
1196 /* first subtract and mask after that... Otherwise, if
1197 date == 0, bad things happen */
1198 month = ((date >> 5) - 1) & 15;
1199 year = date >> 9;
1200 secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
1201 86400 * ((date & 31) - 1 + day_n[month] + (year / 4) +
1202 year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
1203 /* days since 1.1.70 plus 80's leap day */
1204 return local2utc(secs);
1205}
1206
1207
1208/* Convert linear UNIX date to a MS-DOS time/date pair. */
1209void
1210ncp_date_unix2dos(int unix_date, __le16 *time, __le16 *date)
1211{
1212 int day, year, nl_day, month;
1213
1214 unix_date = utc2local(unix_date);
1215 *time = cpu_to_le16(
1216 (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
1217 (((unix_date / 3600) % 24) << 11));
1218 day = unix_date / 86400 - 3652;
1219 year = day / 365;
1220 if ((year + 3) / 4 + 365 * year > day)
1221 year--;
1222 day -= (year + 3) / 4 + 365 * year;
1223 if (day == 59 && !(year & 3)) {
1224 nl_day = day;
1225 month = 2;
1226 } else {
1227 nl_day = (year & 3) || day <= 59 ? day : day - 1;
Roel Kluinc5df5912009-09-22 16:45:54 -07001228 for (month = 1; month < 12; month++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 if (day_n[month] > nl_day)
1230 break;
1231 }
1232 *date = cpu_to_le16(nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
1233}