blob: 8bfd2c44c2d2bfaddda9411e4f71eca4a15cc02b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * dir.c
3 *
4 * Copyright (C) 1995, 1996 by Volker Lendecke
5 * Modified for big endian by J.F. Chadima and David S. Miller
6 * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
7 * Modified 1998, 1999 Wolfram Pienkoss for NLS
8 * Modified 1999 Wolfram Pienkoss for directory caching
9 * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
10 *
11 */
12
Linus Torvalds1da177e2005-04-16 15:20:36 -070013
14#include <linux/time.h>
15#include <linux/errno.h>
16#include <linux/stat.h>
17#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/vmalloc.h>
19#include <linux/mm.h>
Nick Piggin34286d62011-01-07 17:49:57 +110020#include <linux/namei.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <asm/uaccess.h>
22#include <asm/byteorder.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
Al Viro32c419d2011-01-12 17:37:47 -050024#include "ncp_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
Al Viro76f582a2013-05-22 15:11:27 -040026static void ncp_read_volume_list(struct file *, struct dir_context *,
Linus Torvalds1da177e2005-04-16 15:20:36 -070027 struct ncp_cache_control *);
Al Viro76f582a2013-05-22 15:11:27 -040028static void ncp_do_readdir(struct file *, struct dir_context *,
Linus Torvalds1da177e2005-04-16 15:20:36 -070029 struct ncp_cache_control *);
30
Al Viro76f582a2013-05-22 15:11:27 -040031static int ncp_readdir(struct file *, struct dir_context *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
Al Viroebfc3b42012-06-10 18:05:36 -040033static int ncp_create(struct inode *, struct dentry *, umode_t, bool);
Al Viro00cd8dd2012-06-10 17:13:09 -040034static struct dentry *ncp_lookup(struct inode *, struct dentry *, unsigned int);
Linus Torvalds1da177e2005-04-16 15:20:36 -070035static int ncp_unlink(struct inode *, struct dentry *);
Al Viro18bb1db2011-07-26 01:41:39 -040036static int ncp_mkdir(struct inode *, struct dentry *, umode_t);
Linus Torvalds1da177e2005-04-16 15:20:36 -070037static int ncp_rmdir(struct inode *, struct dentry *);
38static int ncp_rename(struct inode *, struct dentry *,
39 struct inode *, struct dentry *);
40static int ncp_mknod(struct inode * dir, struct dentry *dentry,
Al Viro1a67aaf2011-07-26 01:52:52 -040041 umode_t mode, dev_t rdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
43extern int ncp_symlink(struct inode *, struct dentry *, const char *);
44#else
45#define ncp_symlink NULL
46#endif
47
Arjan van de Ven4b6f5d22006-03-28 01:56:42 -080048const struct file_operations ncp_dir_operations =
Linus Torvalds1da177e2005-04-16 15:20:36 -070049{
jan Blunckca572722010-05-26 14:44:53 -070050 .llseek = generic_file_llseek,
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 .read = generic_read_dir,
Al Viro76f582a2013-05-22 15:11:27 -040052 .iterate = ncp_readdir,
John Kacur93d84b62010-05-05 15:15:37 +020053 .unlocked_ioctl = ncp_ioctl,
Petr Vandrovec54f67f62006-09-30 23:27:55 -070054#ifdef CONFIG_COMPAT
55 .compat_ioctl = ncp_compat_ioctl,
56#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070057};
58
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -080059const struct inode_operations ncp_dir_inode_operations =
Linus Torvalds1da177e2005-04-16 15:20:36 -070060{
61 .create = ncp_create,
62 .lookup = ncp_lookup,
63 .unlink = ncp_unlink,
64 .symlink = ncp_symlink,
65 .mkdir = ncp_mkdir,
66 .rmdir = ncp_rmdir,
67 .mknod = ncp_mknod,
68 .rename = ncp_rename,
69 .setattr = ncp_notify_change,
70};
71
72/*
73 * Dentry operations routines
74 */
Al Viro0b728e12012-06-10 16:03:43 -040075static int ncp_lookup_validate(struct dentry *, unsigned int);
Linus Torvaldsda53be12013-05-21 15:22:44 -070076static int ncp_hash_dentry(const struct dentry *, struct qstr *);
77static int ncp_compare_dentry(const struct dentry *, const struct dentry *,
Nick Piggin621e1552011-01-07 17:49:27 +110078 unsigned int, const char *, const struct qstr *);
Nick Pigginfe15ce42011-01-07 17:49:23 +110079static int ncp_delete_dentry(const struct dentry *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
Al Viro0378c402011-01-12 17:25:03 -050081const struct dentry_operations ncp_dentry_operations =
Linus Torvalds1da177e2005-04-16 15:20:36 -070082{
83 .d_revalidate = ncp_lookup_validate,
84 .d_hash = ncp_hash_dentry,
85 .d_compare = ncp_compare_dentry,
86 .d_delete = ncp_delete_dentry,
87};
88
Petr Vandrovec2e54eb92010-09-27 01:47:33 +020089#define ncp_namespace(i) (NCP_SERVER(i)->name_space[NCP_FINFO(i)->volNumber])
90
91static inline int ncp_preserve_entry_case(struct inode *i, __u32 nscreator)
92{
93#ifdef CONFIG_NCPFS_SMALLDOS
94 int ns = ncp_namespace(i);
95
96 if ((ns == NW_NS_DOS)
97#ifdef CONFIG_NCPFS_OS2_NS
98 || ((ns == NW_NS_OS2) && (nscreator == NW_NS_DOS))
99#endif /* CONFIG_NCPFS_OS2_NS */
100 )
101 return 0;
102#endif /* CONFIG_NCPFS_SMALLDOS */
103 return 1;
104}
105
106#define ncp_preserve_case(i) (ncp_namespace(i) != NW_NS_DOS)
107
Nick Piggin621e1552011-01-07 17:49:27 +1100108static inline int ncp_case_sensitive(const struct inode *i)
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200109{
110#ifdef CONFIG_NCPFS_NFS_NS
Nick Piggin621e1552011-01-07 17:49:27 +1100111 return ncp_namespace(i) == NW_NS_NFS;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200112#else
113 return 0;
114#endif /* CONFIG_NCPFS_NFS_NS */
115}
116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117/*
118 * Note: leave the hash unchanged if the directory
119 * is case-sensitive.
Linus Torvaldsda53be12013-05-21 15:22:44 -0700120 *
121 * Accessing the parent inode can be racy under RCU pathwalking.
122 * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
123 * the callers will handle races.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 */
125static int
Linus Torvaldsda53be12013-05-21 15:22:44 -0700126ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127{
Linus Torvaldsda53be12013-05-21 15:22:44 -0700128 struct inode *inode = ACCESS_ONCE(dentry->d_inode);
129
130 if (!inode)
131 return 0;
132
Nick Pigginb1e6a012011-01-07 17:49:28 +1100133 if (!ncp_case_sensitive(inode)) {
Nick Piggin621e1552011-01-07 17:49:27 +1100134 struct super_block *sb = dentry->d_sb;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200135 struct nls_table *t;
136 unsigned long hash;
137 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
Nick Piggin621e1552011-01-07 17:49:27 +1100139 t = NCP_IO_TABLE(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 hash = init_name_hash();
141 for (i=0; i<this->len ; i++)
142 hash = partial_name_hash(ncp_tolower(t, this->name[i]),
143 hash);
144 this->hash = end_name_hash(hash);
145 }
146 return 0;
147}
148
Linus Torvaldsda53be12013-05-21 15:22:44 -0700149/*
150 * Accessing the parent inode can be racy under RCU pathwalking.
151 * Use ACCESS_ONCE() to make sure we use _one_ particular inode,
152 * the callers will handle races.
153 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154static int
Linus Torvaldsda53be12013-05-21 15:22:44 -0700155ncp_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
Nick Piggin621e1552011-01-07 17:49:27 +1100156 unsigned int len, const char *str, const struct qstr *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157{
Linus Torvaldsda53be12013-05-21 15:22:44 -0700158 struct inode *pinode;
159
Nick Piggin621e1552011-01-07 17:49:27 +1100160 if (len != name->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 return 1;
162
Linus Torvaldsda53be12013-05-21 15:22:44 -0700163 pinode = ACCESS_ONCE(parent->d_inode);
164 if (!pinode)
165 return 1;
166
Nick Piggin621e1552011-01-07 17:49:27 +1100167 if (ncp_case_sensitive(pinode))
168 return strncmp(str, name->name, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169
Nick Piggin621e1552011-01-07 17:49:27 +1100170 return ncp_strnicmp(NCP_IO_TABLE(pinode->i_sb), str, name->name, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171}
172
173/*
174 * This is the callback from dput() when d_count is going to 0.
175 * We use this to unhash dentries with bad inodes.
176 * Closing files can be safely postponed until iput() - it's done there anyway.
177 */
178static int
Nick Pigginfe15ce42011-01-07 17:49:23 +1100179ncp_delete_dentry(const struct dentry * dentry)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180{
181 struct inode *inode = dentry->d_inode;
182
183 if (inode) {
184 if (is_bad_inode(inode))
185 return 1;
186 } else
187 {
188 /* N.B. Unhash negative dentries? */
189 }
190 return 0;
191}
192
193static inline int
194ncp_single_volume(struct ncp_server *server)
195{
196 return (server->m.mounted_vol[0] != '\0');
197}
198
199static inline int ncp_is_server_root(struct inode *inode)
200{
201 return (!ncp_single_volume(NCP_SERVER(inode)) &&
202 inode == inode->i_sb->s_root->d_inode);
203}
204
205
206/*
207 * This is the callback when the dcache has a lookup hit.
208 */
209
210
211#ifdef CONFIG_NCPFS_STRONG
212/* try to delete a readonly file (NW R bit set) */
213
214static int
215ncp_force_unlink(struct inode *dir, struct dentry* dentry)
216{
217 int res=0x9c,res2;
218 struct nw_modify_dos_info info;
219 __le32 old_nwattr;
220 struct inode *inode;
221
222 memset(&info, 0, sizeof(info));
223
224 /* remove the Read-Only flag on the NW server */
225 inode = dentry->d_inode;
226
227 old_nwattr = NCP_FINFO(inode)->nwattr;
228 info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT);
229 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
230 if (res2)
231 goto leave_me;
232
233 /* now try again the delete operation */
234 res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
235
236 if (res) /* delete failed, set R bit again */
237 {
238 info.attributes = old_nwattr;
239 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
240 if (res2)
241 goto leave_me;
242 }
243leave_me:
244 return(res);
245}
246#endif /* CONFIG_NCPFS_STRONG */
247
248#ifdef CONFIG_NCPFS_STRONG
249static int
250ncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name,
251 struct inode *new_dir, struct dentry* new_dentry, char *_new_name)
252{
253 struct nw_modify_dos_info info;
254 int res=0x90,res2;
255 struct inode *old_inode = old_dentry->d_inode;
256 __le32 old_nwattr = NCP_FINFO(old_inode)->nwattr;
257 __le32 new_nwattr = 0; /* shut compiler warning */
258 int old_nwattr_changed = 0;
259 int new_nwattr_changed = 0;
260
261 memset(&info, 0, sizeof(info));
262
263 /* remove the Read-Only flag on the NW server */
264
265 info.attributes = old_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
266 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
267 if (!res2)
268 old_nwattr_changed = 1;
269 if (new_dentry && new_dentry->d_inode) {
270 new_nwattr = NCP_FINFO(new_dentry->d_inode)->nwattr;
271 info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
272 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
273 if (!res2)
274 new_nwattr_changed = 1;
275 }
276 /* now try again the rename operation */
277 /* but only if something really happened */
278 if (new_nwattr_changed || old_nwattr_changed) {
279 res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
280 old_dir, _old_name,
281 new_dir, _new_name);
282 }
283 if (res)
284 goto leave_me;
285 /* file was successfully renamed, so:
286 do not set attributes on old file - it no longer exists
287 copy attributes from old file to new */
288 new_nwattr_changed = old_nwattr_changed;
289 new_nwattr = old_nwattr;
290 old_nwattr_changed = 0;
291
292leave_me:;
293 if (old_nwattr_changed) {
294 info.attributes = old_nwattr;
295 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
296 /* ignore errors */
297 }
298 if (new_nwattr_changed) {
299 info.attributes = new_nwattr;
300 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
301 /* ignore errors */
302 }
303 return(res);
304}
305#endif /* CONFIG_NCPFS_STRONG */
306
307
308static int
Al Viro0b728e12012-06-10 16:03:43 -0400309ncp_lookup_validate(struct dentry *dentry, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310{
311 struct ncp_server *server;
312 struct dentry *parent;
313 struct inode *dir;
314 struct ncp_entry_info finfo;
315 int res, val = 0, len;
316 __u8 __name[NCP_MAXPATHLEN + 1];
317
Al Viro0378c402011-01-12 17:25:03 -0500318 if (dentry == dentry->d_sb->s_root)
319 return 1;
320
Al Viro0b728e12012-06-10 16:03:43 -0400321 if (flags & LOOKUP_RCU)
Nick Piggin34286d62011-01-07 17:49:57 +1100322 return -ECHILD;
323
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 parent = dget_parent(dentry);
325 dir = parent->d_inode;
326
327 if (!dentry->d_inode)
328 goto finished;
329
330 server = NCP_SERVER(dir);
331
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 /*
333 * Inspired by smbfs:
334 * The default validation is based on dentry age:
335 * We set the max age at mount time. (But each
336 * successful server lookup renews the timestamp.)
337 */
338 val = NCP_TEST_AGE(server, dentry);
339 if (val)
340 goto finished;
341
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;
391 struct list_head *next;
392
393 if (d_validate(dent, parent)) {
394 if (dent->d_name.len <= NCP_MAXPATHLEN &&
395 (unsigned long)dent->d_fsdata == fpos) {
396 if (!dent->d_inode) {
397 dput(dent);
398 dent = NULL;
399 }
400 return dent;
401 }
402 dput(dent);
403 }
404
405 /* If a pointer is invalid, we search the dentry. */
Nick Piggin2fd6b7f2011-01-07 17:49:34 +1100406 spin_lock(&parent->d_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 next = parent->d_subdirs.next;
408 while (next != &parent->d_subdirs) {
Eric Dumazet5160ee62006-01-08 01:03:32 -0800409 dent = list_entry(next, struct dentry, d_u.d_child);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 if ((unsigned long)dent->d_fsdata == fpos) {
411 if (dent->d_inode)
Nick Piggindc0474b2011-01-07 17:49:43 +1100412 dget(dent);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 else
414 dent = NULL;
Nick Piggin2fd6b7f2011-01-07 17:49:34 +1100415 spin_unlock(&parent->d_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 goto out;
417 }
418 next = next->next;
419 }
Nick Piggin2fd6b7f2011-01-07 17:49:34 +1100420 spin_unlock(&parent->d_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 return NULL;
422
423out:
424 return dent;
425}
426
427static time_t ncp_obtain_mtime(struct dentry *dentry)
428{
429 struct inode *inode = dentry->d_inode;
430 struct ncp_server *server = NCP_SERVER(inode);
431 struct nw_info_struct i;
432
433 if (!ncp_conn_valid(server) || ncp_is_server_root(inode))
434 return 0;
435
436 if (ncp_obtain_info(server, inode, NULL, &i))
437 return 0;
438
439 return ncp_date_dos2unix(i.modifyTime, i.modifyDate);
440}
441
Al Viro76f582a2013-05-22 15:11:27 -0400442static int ncp_readdir(struct file *file, struct dir_context *ctx)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443{
Al Viro76f582a2013-05-22 15:11:27 -0400444 struct dentry *dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 struct inode *inode = dentry->d_inode;
446 struct page *page = NULL;
447 struct ncp_server *server = NCP_SERVER(inode);
448 union ncp_dir_cache *cache = NULL;
449 struct ncp_cache_control ctl;
450 int result, mtime_valid = 0;
451 time_t mtime = 0;
452
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 ctl.page = NULL;
454 ctl.cache = NULL;
455
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700456 ncp_dbg(2, "reading %pD2, pos=%d\n", file, (int)ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
458 result = -EIO;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200459 /* Do not generate '.' and '..' when server is dead. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 if (!ncp_conn_valid(server))
461 goto out;
462
463 result = 0;
Al Viro76f582a2013-05-22 15:11:27 -0400464 if (!dir_emit_dots(file, ctx))
465 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
467 page = grab_cache_page(&inode->i_data, 0);
468 if (!page)
469 goto read_really;
470
471 ctl.cache = cache = kmap(page);
472 ctl.head = cache->head;
473
474 if (!PageUptodate(page) || !ctl.head.eof)
475 goto init_cache;
476
Al Viro76f582a2013-05-22 15:11:27 -0400477 if (ctx->pos == 2) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 if (jiffies - ctl.head.time >= NCP_MAX_AGE(server))
479 goto init_cache;
480
481 mtime = ncp_obtain_mtime(dentry);
482 mtime_valid = 1;
483 if ((!mtime) || (mtime != ctl.head.mtime))
484 goto init_cache;
485 }
486
Al Viro76f582a2013-05-22 15:11:27 -0400487 if (ctx->pos > ctl.head.end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 goto finished;
489
Al Viro76f582a2013-05-22 15:11:27 -0400490 ctl.fpos = ctx->pos + (NCP_DIRCACHE_START - 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 ctl.ofs = ctl.fpos / NCP_DIRCACHE_SIZE;
492 ctl.idx = ctl.fpos % NCP_DIRCACHE_SIZE;
493
494 for (;;) {
495 if (ctl.ofs != 0) {
496 ctl.page = find_lock_page(&inode->i_data, ctl.ofs);
497 if (!ctl.page)
498 goto invalid_cache;
499 ctl.cache = kmap(ctl.page);
500 if (!PageUptodate(ctl.page))
501 goto invalid_cache;
502 }
503 while (ctl.idx < NCP_DIRCACHE_SIZE) {
504 struct dentry *dent;
Al Viro76f582a2013-05-22 15:11:27 -0400505 bool over;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506
507 dent = ncp_dget_fpos(ctl.cache->dentry[ctl.idx],
Al Viro76f582a2013-05-22 15:11:27 -0400508 dentry, ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 if (!dent)
510 goto invalid_cache;
Al Viro76f582a2013-05-22 15:11:27 -0400511 over = !dir_emit(ctx, dent->d_name.name,
512 dent->d_name.len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 dent->d_inode->i_ino, DT_UNKNOWN);
514 dput(dent);
Al Viro76f582a2013-05-22 15:11:27 -0400515 if (over)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 goto finished;
Al Viro76f582a2013-05-22 15:11:27 -0400517 ctx->pos += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 ctl.idx += 1;
Al Viro76f582a2013-05-22 15:11:27 -0400519 if (ctx->pos > ctl.head.end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 goto finished;
521 }
522 if (ctl.page) {
523 kunmap(ctl.page);
524 SetPageUptodate(ctl.page);
525 unlock_page(ctl.page);
526 page_cache_release(ctl.page);
527 ctl.page = NULL;
528 }
529 ctl.idx = 0;
530 ctl.ofs += 1;
531 }
532invalid_cache:
533 if (ctl.page) {
534 kunmap(ctl.page);
535 unlock_page(ctl.page);
536 page_cache_release(ctl.page);
537 ctl.page = NULL;
538 }
539 ctl.cache = cache;
540init_cache:
541 ncp_invalidate_dircache_entries(dentry);
542 if (!mtime_valid) {
543 mtime = ncp_obtain_mtime(dentry);
544 mtime_valid = 1;
545 }
546 ctl.head.mtime = mtime;
547 ctl.head.time = jiffies;
548 ctl.head.eof = 0;
549 ctl.fpos = 2;
550 ctl.ofs = 0;
551 ctl.idx = NCP_DIRCACHE_START;
552 ctl.filled = 0;
553 ctl.valid = 1;
554read_really:
555 if (ncp_is_server_root(inode)) {
Al Viro76f582a2013-05-22 15:11:27 -0400556 ncp_read_volume_list(file, ctx, &ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 } else {
Al Viro76f582a2013-05-22 15:11:27 -0400558 ncp_do_readdir(file, ctx, &ctl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 }
560 ctl.head.end = ctl.fpos - 1;
561 ctl.head.eof = ctl.valid;
562finished:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200563 if (ctl.page) {
564 kunmap(ctl.page);
565 SetPageUptodate(ctl.page);
566 unlock_page(ctl.page);
567 page_cache_release(ctl.page);
568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 if (page) {
570 cache->head = ctl.head;
571 kunmap(page);
572 SetPageUptodate(page);
573 unlock_page(page);
574 page_cache_release(page);
575 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 return result;
578}
579
580static int
Al Viro76f582a2013-05-22 15:11:27 -0400581ncp_fill_cache(struct file *file, struct dir_context *ctx,
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200582 struct ncp_cache_control *ctrl, struct ncp_entry_info *entry,
583 int inval_childs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584{
Al Viro76f582a2013-05-22 15:11:27 -0400585 struct dentry *newdent, *dentry = file->f_path.dentry;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200586 struct inode *dir = dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 struct ncp_cache_control ctl = *ctrl;
588 struct qstr qname;
589 int valid = 0;
590 int hashed = 0;
591 ino_t ino = 0;
592 __u8 __name[NCP_MAXPATHLEN + 1];
593
594 qname.len = sizeof(__name);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200595 if (ncp_vol2io(NCP_SERVER(dir), __name, &qname.len,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 entry->i.entryName, entry->i.nameLen,
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200597 !ncp_preserve_entry_case(dir, entry->i.NSCreator)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 return 1; /* I'm not sure */
599
600 qname.name = __name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
Al Viro4f522a22013-02-11 23:20:37 -0500602 newdent = d_hash_and_lookup(dentry, &qname);
603 if (unlikely(IS_ERR(newdent)))
604 goto end_advance;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 if (!newdent) {
606 newdent = d_alloc(dentry, &qname);
607 if (!newdent)
608 goto end_advance;
609 } else {
610 hashed = 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200611
612 /* If case sensitivity changed for this volume, all entries below this one
613 should be thrown away. This entry itself is not affected, as its case
614 sensitivity is controlled by its own parent. */
615 if (inval_childs)
616 shrink_dcache_parent(newdent);
617
618 /*
Nick Pigginfb2d5b82011-01-07 17:49:26 +1100619 * NetWare's OS2 namespace is case preserving yet case
620 * insensitive. So we update dentry's name as received from
621 * server. Parent dir's i_mutex is locked because we're in
622 * readdir.
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200623 */
Nick Pigginfb2d5b82011-01-07 17:49:26 +1100624 dentry_update_name_case(newdent, &qname);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 }
626
627 if (!newdent->d_inode) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200628 struct inode *inode;
629
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 entry->opened = 0;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200631 entry->ino = iunique(dir->i_sb, 2);
632 inode = ncp_iget(dir->i_sb, entry);
633 if (inode) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200634 d_instantiate(newdent, inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 if (!hashed)
636 d_rehash(newdent);
637 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200638 } else {
639 struct inode *inode = newdent->d_inode;
640
Nick Pigginfb2d5b82011-01-07 17:49:26 +1100641 mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200642 ncp_update_inode2(inode, entry);
643 mutex_unlock(&inode->i_mutex);
644 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645
646 if (newdent->d_inode) {
647 ino = newdent->d_inode->i_ino;
648 newdent->d_fsdata = (void *) ctl.fpos;
649 ncp_new_dentry(newdent);
650 }
651
652 if (ctl.idx >= NCP_DIRCACHE_SIZE) {
653 if (ctl.page) {
654 kunmap(ctl.page);
655 SetPageUptodate(ctl.page);
656 unlock_page(ctl.page);
657 page_cache_release(ctl.page);
658 }
659 ctl.cache = NULL;
660 ctl.idx -= NCP_DIRCACHE_SIZE;
661 ctl.ofs += 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200662 ctl.page = grab_cache_page(&dir->i_data, ctl.ofs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 if (ctl.page)
664 ctl.cache = kmap(ctl.page);
665 }
666 if (ctl.cache) {
667 ctl.cache->dentry[ctl.idx] = newdent;
668 valid = 1;
669 }
670 dput(newdent);
671end_advance:
672 if (!valid)
673 ctl.valid = 0;
Al Viro76f582a2013-05-22 15:11:27 -0400674 if (!ctl.filled && (ctl.fpos == ctx->pos)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 if (!ino)
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200676 ino = iunique(dir->i_sb, 2);
Al Viro76f582a2013-05-22 15:11:27 -0400677 ctl.filled = !dir_emit(ctx, qname.name, qname.len,
678 ino, DT_UNKNOWN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 if (!ctl.filled)
Al Viro76f582a2013-05-22 15:11:27 -0400680 ctx->pos += 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 }
682 ctl.fpos += 1;
683 ctl.idx += 1;
684 *ctrl = ctl;
685 return (ctl.valid || !ctl.filled);
686}
687
688static void
Al Viro76f582a2013-05-22 15:11:27 -0400689ncp_read_volume_list(struct file *file, struct dir_context *ctx,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 struct ncp_cache_control *ctl)
691{
Al Viro76f582a2013-05-22 15:11:27 -0400692 struct dentry *dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 struct inode *inode = dentry->d_inode;
694 struct ncp_server *server = NCP_SERVER(inode);
695 struct ncp_volume_info info;
696 struct ncp_entry_info entry;
697 int i;
698
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700699 ncp_dbg(1, "pos=%ld\n", (unsigned long)ctx->pos);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700
701 for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200702 int inval_dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
704 if (ncp_get_volume_info_with_number(server, i, &info) != 0)
705 return;
706 if (!strlen(info.volume_name))
707 continue;
708
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700709 ncp_dbg(1, "found vol: %s\n", info.volume_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
711 if (ncp_lookup_volume(server, info.volume_name,
712 &entry.i)) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700713 ncp_dbg(1, "could not lookup vol %s\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 info.volume_name);
715 continue;
716 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200717 inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 entry.volume = entry.i.volNumber;
Al Viro76f582a2013-05-22 15:11:27 -0400719 if (!ncp_fill_cache(file, ctx, ctl, &entry, inval_dentry))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 return;
721 }
722}
723
724static void
Al Viro76f582a2013-05-22 15:11:27 -0400725ncp_do_readdir(struct file *file, struct dir_context *ctx,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 struct ncp_cache_control *ctl)
727{
Al Viro76f582a2013-05-22 15:11:27 -0400728 struct dentry *dentry = file->f_path.dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 struct inode *dir = dentry->d_inode;
730 struct ncp_server *server = NCP_SERVER(dir);
731 struct nw_search_sequence seq;
732 struct ncp_entry_info entry;
733 int err;
734 void* buf;
735 int more;
736 size_t bufsize;
737
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700738 ncp_dbg(1, "%pD2, fpos=%ld\n", file, (unsigned long)ctx->pos);
Al Viro84eb3532013-09-16 10:59:55 -0400739 PPRINTK("ncp_do_readdir: init %pD, volnum=%d, dirent=%u\n",
740 file, NCP_FINFO(dir)->volNumber, NCP_FINFO(dir)->dirEntNum);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
742 err = ncp_initialize_search(server, dir, &seq);
743 if (err) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700744 ncp_dbg(1, "init failed, err=%d\n", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 return;
746 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 /* We MUST NOT use server->buffer_size handshaked with server if we are
748 using UDP, as for UDP server uses max. buffer size determined by
749 MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes).
750 So we use 128KB, just to be sure, as there is no way how to know
751 this value in advance. */
752 bufsize = 131072;
753 buf = vmalloc(bufsize);
754 if (!buf)
755 return;
756 do {
757 int cnt;
758 char* rpl;
759 size_t rpls;
760
761 err = ncp_search_for_fileset(server, &seq, &more, &cnt, buf, bufsize, &rpl, &rpls);
762 if (err) /* Error */
763 break;
764 if (!cnt) /* prevent endless loop */
765 break;
766 while (cnt--) {
767 size_t onerpl;
768
769 if (rpls < offsetof(struct nw_info_struct, entryName))
770 break; /* short packet */
771 ncp_extract_file_info(rpl, &entry.i);
772 onerpl = offsetof(struct nw_info_struct, entryName) + entry.i.nameLen;
773 if (rpls < onerpl)
774 break; /* short packet */
775 (void)ncp_obtain_nfs_info(server, &entry.i);
776 rpl += onerpl;
777 rpls -= onerpl;
778 entry.volume = entry.i.volNumber;
Al Viro76f582a2013-05-22 15:11:27 -0400779 if (!ncp_fill_cache(file, ctx, ctl, &entry, 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 break;
781 }
782 } while (more);
783 vfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 return;
785}
786
787int ncp_conn_logged_in(struct super_block *sb)
788{
789 struct ncp_server* server = NCP_SBP(sb);
790 int result;
791
792 if (ncp_single_volume(server)) {
793 int len;
794 struct dentry* dent;
795 __u32 volNumber;
796 __le32 dirEntNum;
797 __le32 DosDirNum;
798 __u8 __name[NCP_MAXPATHLEN + 1];
799
800 len = sizeof(__name);
801 result = ncp_io2vol(server, __name, &len, server->m.mounted_vol,
802 strlen(server->m.mounted_vol), 1);
803 if (result)
804 goto out;
805 result = -ENOENT;
806 if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) {
807 PPRINTK("ncp_conn_logged_in: %s not found\n",
808 server->m.mounted_vol);
809 goto out;
810 }
811 dent = sb->s_root;
812 if (dent) {
813 struct inode* ino = dent->d_inode;
814 if (ino) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200815 ncp_update_known_namespace(server, volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 NCP_FINFO(ino)->volNumber = volNumber;
817 NCP_FINFO(ino)->dirEntNum = dirEntNum;
818 NCP_FINFO(ino)->DosDirNum = DosDirNum;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200819 result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 } else {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700821 ncp_dbg(1, "sb->s_root->d_inode == NULL!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 }
823 } else {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700824 ncp_dbg(1, "sb->s_root == NULL!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200826 } else
827 result = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
829out:
830 return result;
831}
832
Al Viro00cd8dd2012-06-10 17:13:09 -0400833static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834{
835 struct ncp_server *server = NCP_SERVER(dir);
836 struct inode *inode = NULL;
837 struct ncp_entry_info finfo;
838 int error, res, len;
839 __u8 __name[NCP_MAXPATHLEN + 1];
840
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 error = -EIO;
842 if (!ncp_conn_valid(server))
843 goto finished;
844
Al Viro84eb3532013-09-16 10:59:55 -0400845 PPRINTK("ncp_lookup: server lookup for %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
847 len = sizeof(__name);
848 if (ncp_is_server_root(dir)) {
849 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
850 dentry->d_name.len, 1);
851 if (!res)
852 res = ncp_lookup_volume(server, __name, &(finfo.i));
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200853 if (!res)
854 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 } else {
856 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
857 dentry->d_name.len, !ncp_preserve_case(dir));
858 if (!res)
859 res = ncp_obtain_info(server, dir, __name, &(finfo.i));
860 }
Al Viro84eb3532013-09-16 10:59:55 -0400861 PPRINTK("ncp_lookup: looked for %pd2, res=%d\n", dentry, res);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 /*
863 * If we didn't find an entry, make a negative dentry.
864 */
865 if (res)
866 goto add_entry;
867
868 /*
869 * Create an inode for the entry.
870 */
871 finfo.opened = 0;
872 finfo.ino = iunique(dir->i_sb, 2);
873 finfo.volume = finfo.i.volNumber;
874 error = -EACCES;
875 inode = ncp_iget(dir->i_sb, &finfo);
876
877 if (inode) {
878 ncp_new_dentry(dentry);
879add_entry:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 d_add(dentry, inode);
881 error = 0;
882 }
883
884finished:
885 PPRINTK("ncp_lookup: result=%d\n", error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 return ERR_PTR(error);
887}
888
889/*
890 * This code is common to create, mkdir, and mknod.
891 */
892static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
893 struct ncp_entry_info *finfo)
894{
895 struct inode *inode;
896 int error = -EINVAL;
897
898 finfo->ino = iunique(dir->i_sb, 2);
899 inode = ncp_iget(dir->i_sb, finfo);
900 if (!inode)
901 goto out_close;
902 d_instantiate(dentry,inode);
903 error = 0;
904out:
905 return error;
906
907out_close:
Al Viro84eb3532013-09-16 10:59:55 -0400908 PPRINTK("ncp_instantiate: %pd2 failed, closing file\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 ncp_close_file(NCP_SERVER(dir), finfo->file_handle);
910 goto out;
911}
912
Al Viro5eee25c2011-07-26 03:12:16 -0400913int ncp_create_new(struct inode *dir, struct dentry *dentry, umode_t mode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 dev_t rdev, __le32 attributes)
915{
916 struct ncp_server *server = NCP_SERVER(dir);
917 struct ncp_entry_info finfo;
918 int error, result, len;
919 int opmode;
920 __u8 __name[NCP_MAXPATHLEN + 1];
921
Al Viro84eb3532013-09-16 10:59:55 -0400922 PPRINTK("ncp_create_new: creating %pd2, mode=%hx\n", dentry, mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 ncp_age_dentry(server, dentry);
925 len = sizeof(__name);
926 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
927 dentry->d_name.len, !ncp_preserve_case(dir));
928 if (error)
929 goto out;
930
931 error = -EACCES;
932
933 if (S_ISREG(mode) &&
934 (server->m.flags & NCP_MOUNT_EXTRAS) &&
935 (mode & S_IXUGO))
936 attributes |= aSYSTEM | aSHARED;
937
938 result = ncp_open_create_file_or_subdir(server, dir, __name,
939 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
940 attributes, AR_READ | AR_WRITE, &finfo);
941 opmode = O_RDWR;
942 if (result) {
943 result = ncp_open_create_file_or_subdir(server, dir, __name,
944 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
945 attributes, AR_WRITE, &finfo);
946 if (result) {
947 if (result == 0x87)
948 error = -ENAMETOOLONG;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200949 else if (result < 0)
950 error = result;
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700951 ncp_dbg(1, "%pd2 failed\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 goto out;
953 }
954 opmode = O_WRONLY;
955 }
956 finfo.access = opmode;
957 if (ncp_is_nfs_extras(server, finfo.volume)) {
958 finfo.i.nfs.mode = mode;
959 finfo.i.nfs.rdev = new_encode_dev(rdev);
960 if (ncp_modify_nfs_info(server, finfo.volume,
961 finfo.i.dirEntNum,
962 mode, new_encode_dev(rdev)) != 0)
963 goto out;
964 }
965
966 error = ncp_instantiate(dir, dentry, &finfo);
967out:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 return error;
969}
970
Al Viro4acdaf22011-07-26 01:42:34 -0400971static int ncp_create(struct inode *dir, struct dentry *dentry, umode_t mode,
Al Viroebfc3b42012-06-10 18:05:36 -0400972 bool excl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973{
974 return ncp_create_new(dir, dentry, mode, 0, 0);
975}
976
Al Viro18bb1db2011-07-26 01:41:39 -0400977static int ncp_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978{
979 struct ncp_entry_info finfo;
980 struct ncp_server *server = NCP_SERVER(dir);
981 int error, len;
982 __u8 __name[NCP_MAXPATHLEN + 1];
983
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700984 ncp_dbg(1, "making %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 ncp_age_dentry(server, dentry);
987 len = sizeof(__name);
988 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
989 dentry->d_name.len, !ncp_preserve_case(dir));
990 if (error)
991 goto out;
992
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200993 error = ncp_open_create_file_or_subdir(server, dir, __name,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 OC_MODE_CREATE, aDIR,
995 cpu_to_le16(0xffff),
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200996 &finfo);
997 if (error == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 if (ncp_is_nfs_extras(server, finfo.volume)) {
999 mode |= S_IFDIR;
1000 finfo.i.nfs.mode = mode;
1001 if (ncp_modify_nfs_info(server,
1002 finfo.volume,
1003 finfo.i.dirEntNum,
1004 mode, 0) != 0)
1005 goto out;
1006 }
1007 error = ncp_instantiate(dir, dentry, &finfo);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001008 } else if (error > 0) {
1009 error = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 }
1011out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 return error;
1013}
1014
1015static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
1016{
1017 struct ncp_server *server = NCP_SERVER(dir);
1018 int error, result, len;
1019 __u8 __name[NCP_MAXPATHLEN + 1];
1020
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001021 ncp_dbg(1, "removing %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 len = sizeof(__name);
1024 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
1025 dentry->d_name.len, !ncp_preserve_case(dir));
1026 if (error)
1027 goto out;
1028
1029 result = ncp_del_file_or_subdir(server, dir, __name);
1030 switch (result) {
1031 case 0x00:
1032 error = 0;
1033 break;
1034 case 0x85: /* unauthorized to delete file */
1035 case 0x8A: /* unauthorized to delete file */
1036 error = -EACCES;
1037 break;
1038 case 0x8F:
1039 case 0x90: /* read only */
1040 error = -EPERM;
1041 break;
1042 case 0x9F: /* in use by another client */
1043 error = -EBUSY;
1044 break;
1045 case 0xA0: /* directory not empty */
1046 error = -ENOTEMPTY;
1047 break;
1048 case 0xFF: /* someone deleted file */
1049 error = -ENOENT;
1050 break;
1051 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001052 error = result < 0 ? result : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 break;
1054 }
1055out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 return error;
1057}
1058
1059static int ncp_unlink(struct inode *dir, struct dentry *dentry)
1060{
1061 struct inode *inode = dentry->d_inode;
1062 struct ncp_server *server;
1063 int error;
1064
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 server = NCP_SERVER(dir);
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001066 ncp_dbg(1, "unlinking %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 /*
1069 * Check whether to close the file ...
1070 */
1071 if (inode) {
1072 PPRINTK("ncp_unlink: closing file\n");
1073 ncp_make_closed(inode);
1074 }
1075
1076 error = ncp_del_file_or_subdir2(server, dentry);
1077#ifdef CONFIG_NCPFS_STRONG
1078 /* 9C is Invalid path.. It should be 8F, 90 - read only, but
1079 it is not :-( */
1080 if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */
1081 error = ncp_force_unlink(dir, dentry);
1082 }
1083#endif
1084 switch (error) {
1085 case 0x00:
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001086 ncp_dbg(1, "removed %pd2\n", dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 break;
1088 case 0x85:
1089 case 0x8A:
1090 error = -EACCES;
1091 break;
1092 case 0x8D: /* some files in use */
1093 case 0x8E: /* all files in use */
1094 error = -EBUSY;
1095 break;
1096 case 0x8F: /* some read only */
1097 case 0x90: /* all read only */
1098 case 0x9C: /* !!! returned when in-use or read-only by NW4 */
1099 error = -EPERM;
1100 break;
1101 case 0xFF:
1102 error = -ENOENT;
1103 break;
1104 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001105 error = error < 0 ? error : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 break;
1107 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 return error;
1109}
1110
1111static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
1112 struct inode *new_dir, struct dentry *new_dentry)
1113{
1114 struct ncp_server *server = NCP_SERVER(old_dir);
1115 int error;
1116 int old_len, new_len;
1117 __u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1];
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);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 break;
1152 case 0x9E:
1153 error = -ENAMETOOLONG;
1154 break;
1155 case 0xFF:
1156 error = -ENOENT;
1157 break;
1158 default:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001159 error = error < 0 ? error : -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 break;
1161 }
1162out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 return error;
1164}
1165
1166static int ncp_mknod(struct inode * dir, struct dentry *dentry,
Al Viro1a67aaf2011-07-26 01:52:52 -04001167 umode_t mode, dev_t rdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168{
1169 if (!new_valid_dev(rdev))
1170 return -EINVAL;
1171 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
1186
1187extern struct timezone sys_tz;
1188
1189static int utc2local(int time)
1190{
1191 return time - sys_tz.tz_minuteswest * 60;
1192}
1193
1194static int local2utc(int time)
1195{
1196 return time + sys_tz.tz_minuteswest * 60;
1197}
1198
1199/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
1200int
1201ncp_date_dos2unix(__le16 t, __le16 d)
1202{
1203 unsigned short time = le16_to_cpu(t), date = le16_to_cpu(d);
1204 int month, year, secs;
1205
1206 /* first subtract and mask after that... Otherwise, if
1207 date == 0, bad things happen */
1208 month = ((date >> 5) - 1) & 15;
1209 year = date >> 9;
1210 secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
1211 86400 * ((date & 31) - 1 + day_n[month] + (year / 4) +
1212 year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
1213 /* days since 1.1.70 plus 80's leap day */
1214 return local2utc(secs);
1215}
1216
1217
1218/* Convert linear UNIX date to a MS-DOS time/date pair. */
1219void
1220ncp_date_unix2dos(int unix_date, __le16 *time, __le16 *date)
1221{
1222 int day, year, nl_day, month;
1223
1224 unix_date = utc2local(unix_date);
1225 *time = cpu_to_le16(
1226 (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
1227 (((unix_date / 3600) % 24) << 11));
1228 day = unix_date / 86400 - 3652;
1229 year = day / 365;
1230 if ((year + 3) / 4 + 365 * year > day)
1231 year--;
1232 day -= (year + 3) / 4 + 365 * year;
1233 if (day == 59 && !(year & 3)) {
1234 nl_day = day;
1235 month = 2;
1236 } else {
1237 nl_day = (year & 3) || day <= 59 ? day : day - 1;
Roel Kluinc5df5912009-09-22 16:45:54 -07001238 for (month = 1; month < 12; month++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 if (day_n[month] > nl_day)
1240 break;
1241 }
1242 *date = cpu_to_le16(nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
1243}