blob: f4c5bbafd73f716f29ce5a0009a64f2a740ed345 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * inode.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 Wolfram Pienkoss for NLS
8 * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
9 *
10 */
11
Joe Perchesb41f8b82014-04-08 16:04:14 -070012#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/module.h>
15
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <asm/uaccess.h>
17#include <asm/byteorder.h>
18
19#include <linux/time.h>
20#include <linux/kernel.h>
21#include <linux/mm.h>
22#include <linux/string.h>
23#include <linux/stat.h>
24#include <linux/errno.h>
25#include <linux/file.h>
26#include <linux/fcntl.h>
27#include <linux/slab.h>
28#include <linux/vmalloc.h>
29#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/vfs.h>
Miklos Szeredi564cd132008-02-08 04:21:46 -080031#include <linux/mount.h>
32#include <linux/seq_file.h>
Nick Piggin34286d62011-01-07 17:49:57 +110033#include <linux/namei.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <net/sock.h>
36
Al Viro32c419d2011-01-12 17:37:47 -050037#include "ncp_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include "getopt.h"
39
Miklos Szeredi564cd132008-02-08 04:21:46 -080040#define NCP_DEFAULT_FILE_MODE 0600
41#define NCP_DEFAULT_DIR_MODE 0700
42#define NCP_DEFAULT_TIME_OUT 10
43#define NCP_DEFAULT_RETRY_COUNT 20
44
Al Viro94ee8492010-06-07 00:45:56 -040045static void ncp_evict_inode(struct inode *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070046static void ncp_put_super(struct super_block *);
David Howells726c3342006-06-23 02:02:58 -070047static int ncp_statfs(struct dentry *, struct kstatfs *);
Al Viro34c80b12011-12-08 21:32:45 -050048static int ncp_show_options(struct seq_file *, struct dentry *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Christoph Lametere18b8902006-12-06 20:33:20 -080050static struct kmem_cache * ncp_inode_cachep;
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52static struct inode *ncp_alloc_inode(struct super_block *sb)
53{
54 struct ncp_inode_info *ei;
Christoph Lametere94b1762006-12-06 20:33:17 -080055 ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 if (!ei)
57 return NULL;
58 return &ei->vfs_inode;
59}
60
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +110061static void ncp_i_callback(struct rcu_head *head)
62{
63 struct inode *inode = container_of(head, struct inode, i_rcu);
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +110064 kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
65}
66
Linus Torvalds1da177e2005-04-16 15:20:36 -070067static void ncp_destroy_inode(struct inode *inode)
68{
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +110069 call_rcu(&inode->i_rcu, ncp_i_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -070070}
71
Alexey Dobriyan51cc5062008-07-25 19:45:34 -070072static void init_once(void *foo)
Linus Torvalds1da177e2005-04-16 15:20:36 -070073{
74 struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
75
Christoph Lametera35afb82007-05-16 22:10:57 -070076 mutex_init(&ei->open_mutex);
77 inode_init_once(&ei->vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078}
Paul Mundt20c2df82007-07-20 10:11:58 +090079
Linus Torvalds1da177e2005-04-16 15:20:36 -070080static int init_inodecache(void)
81{
82 ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
83 sizeof(struct ncp_inode_info),
Paul Jacksonfffb60f2006-03-24 03:16:06 -080084 0, (SLAB_RECLAIM_ACCOUNT|
85 SLAB_MEM_SPREAD),
Paul Mundt20c2df82007-07-20 10:11:58 +090086 init_once);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 if (ncp_inode_cachep == NULL)
88 return -ENOMEM;
89 return 0;
90}
91
92static void destroy_inodecache(void)
93{
Kirill A. Shutemov8c0a8532012-09-26 11:33:07 +100094 /*
95 * Make sure all delayed rcu free inodes are flushed before we
96 * destroy cache.
97 */
98 rcu_barrier();
Alexey Dobriyan1a1d92c2006-09-27 01:49:40 -070099 kmem_cache_destroy(ncp_inode_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100}
101
102static int ncp_remount(struct super_block *sb, int *flags, char* data)
103{
Theodore Ts'o02b99842014-03-13 10:14:33 -0400104 sync_filesystem(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 *flags |= MS_NODIRATIME;
106 return 0;
107}
108
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800109static const struct super_operations ncp_sops =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110{
111 .alloc_inode = ncp_alloc_inode,
112 .destroy_inode = ncp_destroy_inode,
113 .drop_inode = generic_delete_inode,
Al Viro94ee8492010-06-07 00:45:56 -0400114 .evict_inode = ncp_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 .put_super = ncp_put_super,
116 .statfs = ncp_statfs,
117 .remount_fs = ncp_remount,
Miklos Szeredi564cd132008-02-08 04:21:46 -0800118 .show_options = ncp_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119};
120
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121/*
122 * Fill in the ncpfs-specific information in the inode.
123 */
124static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
125{
126 NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
127 NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
128 NCP_FINFO(inode)->volNumber = nwinfo->volume;
129}
130
131void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
132{
133 ncp_update_dirent(inode, nwinfo);
134 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
135 NCP_FINFO(inode)->access = nwinfo->access;
136 memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
137 sizeof(nwinfo->file_handle));
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700138 ncp_dbg(1, "updated %s, volnum=%d, dirent=%u\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
140 NCP_FINFO(inode)->dirEntNum);
141}
142
143static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
144{
145 /* NFS namespace mode overrides others if it's set. */
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700146 ncp_dbg(1, "(%s) nfs.mode=0%o\n", nwi->entryName, nwi->nfs.mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 if (nwi->nfs.mode) {
148 /* XXX Security? */
149 inode->i_mode = nwi->nfs.mode;
150 }
151
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200152 inode->i_blocks = (i_size_read(inode) + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153
154 inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate);
155 inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate);
156 inode->i_atime.tv_sec = ncp_date_dos2unix(0, nwi->lastAccessDate);
157 inode->i_atime.tv_nsec = 0;
158 inode->i_mtime.tv_nsec = 0;
159 inode->i_ctime.tv_nsec = 0;
160}
161
162static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
163{
164 struct nw_info_struct *nwi = &nwinfo->i;
165 struct ncp_server *server = NCP_SERVER(inode);
166
167 if (nwi->attributes & aDIR) {
168 inode->i_mode = server->m.dir_mode;
169 /* for directories dataStreamSize seems to be some
170 Object ID ??? */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200171 i_size_write(inode, NCP_BLOCK_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 } else {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200173 u32 size;
174
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 inode->i_mode = server->m.file_mode;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200176 size = le32_to_cpu(nwi->dataStreamSize);
177 i_size_write(inode, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178#ifdef CONFIG_NCPFS_EXTRAS
179 if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS))
180 && (nwi->attributes & aSHARED)) {
181 switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
182 case aHIDDEN:
183 if (server->m.flags & NCP_MOUNT_SYMLINKS) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200184 if (/* (size >= NCP_MIN_SYMLINK_SIZE)
185 && */ (size <= NCP_MAX_SYMLINK_SIZE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
187 NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
188 break;
189 }
190 }
191 /* FALLTHROUGH */
192 case 0:
193 if (server->m.flags & NCP_MOUNT_EXTRAS)
194 inode->i_mode |= S_IRUGO;
195 break;
196 case aSYSTEM:
197 if (server->m.flags & NCP_MOUNT_EXTRAS)
198 inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO;
199 break;
200 /* case aSYSTEM|aHIDDEN: */
201 default:
202 /* reserved combination */
203 break;
204 }
205 }
206#endif
207 }
208 if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
209}
210
211void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
212{
213 NCP_FINFO(inode)->flags = 0;
214 if (!atomic_read(&NCP_FINFO(inode)->opened)) {
215 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
216 ncp_update_attrs(inode, nwinfo);
217 }
218
219 ncp_update_dates(inode, &nwinfo->i);
220 ncp_update_dirent(inode, nwinfo);
221}
222
223/*
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200224 * Fill in the inode based on the ncp_entry_info structure. Used only for brand new inodes.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 */
226static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
227{
228 struct ncp_server *server = NCP_SERVER(inode);
229
230 NCP_FINFO(inode)->flags = 0;
231
232 ncp_update_attrs(inode, nwinfo);
233
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700234 ncp_dbg(2, "inode->i_mode = %u\n", inode->i_mode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
Miklos Szeredibfe86842011-10-28 14:13:29 +0200236 set_nlink(inode, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 inode->i_uid = server->m.uid;
238 inode->i_gid = server->m.gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
240 ncp_update_dates(inode, &nwinfo->i);
241 ncp_update_inode(inode, nwinfo);
242}
243
244#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800245static const struct inode_operations ncp_symlink_inode_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 .readlink = generic_readlink,
247 .follow_link = page_follow_link_light,
248 .put_link = page_put_link,
249 .setattr = ncp_notify_change,
250};
251#endif
252
253/*
254 * Get a new inode.
255 */
256struct inode *
257ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
258{
259 struct inode *inode;
260
261 if (info == NULL) {
Joe Perchesb41f8b82014-04-08 16:04:14 -0700262 pr_err("%s: info is NULL\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 return NULL;
264 }
265
266 inode = new_inode(sb);
267 if (inode) {
268 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
269
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200270 inode->i_mapping->backing_dev_info = sb->s_bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 inode->i_ino = info->ino;
272 ncp_set_attr(inode, info);
273 if (S_ISREG(inode->i_mode)) {
274 inode->i_op = &ncp_file_inode_operations;
275 inode->i_fop = &ncp_file_operations;
276 } else if (S_ISDIR(inode->i_mode)) {
277 inode->i_op = &ncp_dir_inode_operations;
278 inode->i_fop = &ncp_dir_operations;
279#ifdef CONFIG_NCPFS_NFS_NS
280 } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
281 init_special_inode(inode, inode->i_mode,
282 new_decode_dev(info->i.nfs.rdev));
283#endif
284#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
285 } else if (S_ISLNK(inode->i_mode)) {
286 inode->i_op = &ncp_symlink_inode_operations;
287 inode->i_data.a_ops = &ncp_symlink_aops;
288#endif
289 } else {
290 make_bad_inode(inode);
291 }
292 insert_inode_hash(inode);
293 } else
Joe Perchesb41f8b82014-04-08 16:04:14 -0700294 pr_err("%s: iget failed!\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 return inode;
296}
297
298static void
Al Viro94ee8492010-06-07 00:45:56 -0400299ncp_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300{
Johannes Weiner91b0abe2014-04-03 14:47:49 -0700301 truncate_inode_pages_final(&inode->i_data);
Jan Karadbd57682012-05-03 14:48:02 +0200302 clear_inode(inode);
Mark Fashehfef26652005-09-09 13:01:31 -0700303
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 if (S_ISDIR(inode->i_mode)) {
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700305 ncp_dbg(2, "put directory %ld\n", inode->i_ino);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 }
307
308 if (ncp_make_closed(inode) != 0) {
309 /* We can't do anything but complain. */
Joe Perchesb41f8b82014-04-08 16:04:14 -0700310 pr_err("%s: could not close\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312}
313
314static void ncp_stop_tasks(struct ncp_server *server) {
315 struct sock* sk = server->ncp_sock->sk;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200316
317 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 sk->sk_error_report = server->error_report;
319 sk->sk_data_ready = server->data_ready;
320 sk->sk_write_space = server->write_space;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200321 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 del_timer_sync(&server->timeout_tm);
Tejun Heo5d8e4bd2010-12-24 15:59:06 +0100323
Tejun Heo43829732012-08-20 14:51:24 -0700324 flush_work(&server->rcv.tq);
Tejun Heo5d8e4bd2010-12-24 15:59:06 +0100325 if (sk->sk_socket->type == SOCK_STREAM)
Tejun Heo43829732012-08-20 14:51:24 -0700326 flush_work(&server->tx.tq);
Tejun Heo5d8e4bd2010-12-24 15:59:06 +0100327 else
Tejun Heo43829732012-08-20 14:51:24 -0700328 flush_work(&server->timeout_tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329}
330
Al Viro34c80b12011-12-08 21:32:45 -0500331static int ncp_show_options(struct seq_file *seq, struct dentry *root)
Miklos Szeredi564cd132008-02-08 04:21:46 -0800332{
Al Viro34c80b12011-12-08 21:32:45 -0500333 struct ncp_server *server = NCP_SBP(root->d_sb);
Miklos Szeredi564cd132008-02-08 04:21:46 -0800334 unsigned int tmp;
335
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800336 if (!uid_eq(server->m.uid, GLOBAL_ROOT_UID))
337 seq_printf(seq, ",uid=%u",
338 from_kuid_munged(&init_user_ns, server->m.uid));
339 if (!gid_eq(server->m.gid, GLOBAL_ROOT_GID))
340 seq_printf(seq, ",gid=%u",
341 from_kgid_munged(&init_user_ns, server->m.gid));
342 if (!uid_eq(server->m.mounted_uid, GLOBAL_ROOT_UID))
343 seq_printf(seq, ",owner=%u",
344 from_kuid_munged(&init_user_ns, server->m.mounted_uid));
Miklos Szeredi564cd132008-02-08 04:21:46 -0800345 tmp = server->m.file_mode & S_IALLUGO;
346 if (tmp != NCP_DEFAULT_FILE_MODE)
347 seq_printf(seq, ",mode=0%o", tmp);
348 tmp = server->m.dir_mode & S_IALLUGO;
349 if (tmp != NCP_DEFAULT_DIR_MODE)
350 seq_printf(seq, ",dirmode=0%o", tmp);
351 if (server->m.time_out != NCP_DEFAULT_TIME_OUT * HZ / 100) {
352 tmp = server->m.time_out * 100 / HZ;
353 seq_printf(seq, ",timeout=%u", tmp);
354 }
355 if (server->m.retry_count != NCP_DEFAULT_RETRY_COUNT)
356 seq_printf(seq, ",retry=%u", server->m.retry_count);
357 if (server->m.flags != 0)
358 seq_printf(seq, ",flags=%lu", server->m.flags);
359 if (server->m.wdog_pid != NULL)
360 seq_printf(seq, ",wdogpid=%u", pid_vnr(server->m.wdog_pid));
361
362 return 0;
363}
364
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365static const struct ncp_option ncp_opts[] = {
366 { "uid", OPT_INT, 'u' },
367 { "gid", OPT_INT, 'g' },
368 { "owner", OPT_INT, 'o' },
369 { "mode", OPT_INT, 'm' },
370 { "dirmode", OPT_INT, 'd' },
371 { "timeout", OPT_INT, 't' },
372 { "retry", OPT_INT, 'r' },
373 { "flags", OPT_INT, 'f' },
374 { "wdogpid", OPT_INT, 'w' },
375 { "ncpfd", OPT_INT, 'n' },
376 { "infofd", OPT_INT, 'i' }, /* v5 */
377 { "version", OPT_INT, 'v' },
378 { NULL, 0, 0 } };
379
380static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
381 int optval;
382 char *optarg;
383 unsigned long optint;
384 int version = 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800385 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
387 data->flags = 0;
388 data->int_flags = 0;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800389 data->mounted_uid = GLOBAL_ROOT_UID;
Eric W. Biederman21542272006-12-13 00:35:11 -0800390 data->wdog_pid = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 data->ncp_fd = ~0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800392 data->time_out = NCP_DEFAULT_TIME_OUT;
393 data->retry_count = NCP_DEFAULT_RETRY_COUNT;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800394 data->uid = GLOBAL_ROOT_UID;
395 data->gid = GLOBAL_ROOT_GID;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800396 data->file_mode = NCP_DEFAULT_FILE_MODE;
397 data->dir_mode = NCP_DEFAULT_DIR_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 data->info_fd = -1;
399 data->mounted_vol[0] = 0;
400
401 while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
Eric W. Biederman1de24122006-12-13 00:35:13 -0800402 ret = optval;
403 if (ret < 0)
404 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 switch (optval) {
406 case 'u':
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800407 data->uid = make_kuid(current_user_ns(), optint);
Wei Yongjun4fbeb192013-07-04 21:43:32 +0800408 if (!uid_valid(data->uid)) {
409 ret = -EINVAL;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800410 goto err;
Wei Yongjun4fbeb192013-07-04 21:43:32 +0800411 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 break;
413 case 'g':
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800414 data->gid = make_kgid(current_user_ns(), optint);
Wei Yongjun4fbeb192013-07-04 21:43:32 +0800415 if (!gid_valid(data->gid)) {
416 ret = -EINVAL;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800417 goto err;
Wei Yongjun4fbeb192013-07-04 21:43:32 +0800418 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 break;
420 case 'o':
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800421 data->mounted_uid = make_kuid(current_user_ns(), optint);
Wei Yongjun4fbeb192013-07-04 21:43:32 +0800422 if (!uid_valid(data->mounted_uid)) {
423 ret = -EINVAL;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800424 goto err;
Wei Yongjun4fbeb192013-07-04 21:43:32 +0800425 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 break;
427 case 'm':
428 data->file_mode = optint;
429 break;
430 case 'd':
431 data->dir_mode = optint;
432 break;
433 case 't':
434 data->time_out = optint;
435 break;
436 case 'r':
437 data->retry_count = optint;
438 break;
439 case 'f':
440 data->flags = optint;
441 break;
442 case 'w':
Eric W. Biederman21542272006-12-13 00:35:11 -0800443 data->wdog_pid = find_get_pid(optint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 break;
445 case 'n':
446 data->ncp_fd = optint;
447 break;
448 case 'i':
449 data->info_fd = optint;
450 break;
451 case 'v':
Eric W. Biederman1de24122006-12-13 00:35:13 -0800452 ret = -ECHRNG;
453 if (optint < NCP_MOUNT_VERSION_V4)
454 goto err;
455 if (optint > NCP_MOUNT_VERSION_V5)
456 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 version = optint;
458 break;
459
460 }
461 }
462 return 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800463err:
464 put_pid(data->wdog_pid);
465 data->wdog_pid = NULL;
466 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467}
468
469static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
470{
471 struct ncp_mount_data_kernel data;
472 struct ncp_server *server;
473 struct file *ncp_filp;
474 struct inode *root_inode;
475 struct inode *sock_inode;
476 struct socket *sock;
477 int error;
478 int default_bufsize;
479#ifdef CONFIG_NCPFS_PACKET_SIGNING
480 int options;
481#endif
482 struct ncp_entry_info finfo;
483
Andrew Morton2a5cac12011-05-24 17:13:42 -0700484 memset(&data, 0, sizeof(data));
Panagiotis Issarisf8314dc2006-09-27 01:49:37 -0700485 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 if (!server)
487 return -ENOMEM;
488 sb->s_fs_info = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
490 error = -EFAULT;
491 if (raw_data == NULL)
492 goto out;
493 switch (*(int*)raw_data) {
494 case NCP_MOUNT_VERSION:
495 {
496 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
497
498 data.flags = md->flags;
499 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800500 data.mounted_uid = make_kuid(current_user_ns(), md->mounted_uid);
Eric W. Biederman21542272006-12-13 00:35:11 -0800501 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 data.ncp_fd = md->ncp_fd;
503 data.time_out = md->time_out;
504 data.retry_count = md->retry_count;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800505 data.uid = make_kuid(current_user_ns(), md->uid);
506 data.gid = make_kgid(current_user_ns(), md->gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 data.file_mode = md->file_mode;
508 data.dir_mode = md->dir_mode;
509 data.info_fd = -1;
510 memcpy(data.mounted_vol, md->mounted_vol,
511 NCP_VOLNAME_LEN+1);
512 }
513 break;
514 case NCP_MOUNT_VERSION_V4:
515 {
516 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
517
518 data.flags = md->flags;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800519 data.mounted_uid = make_kuid(current_user_ns(), md->mounted_uid);
Eric W. Biederman21542272006-12-13 00:35:11 -0800520 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 data.ncp_fd = md->ncp_fd;
522 data.time_out = md->time_out;
523 data.retry_count = md->retry_count;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800524 data.uid = make_kuid(current_user_ns(), md->uid);
525 data.gid = make_kgid(current_user_ns(), md->gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 data.file_mode = md->file_mode;
527 data.dir_mode = md->dir_mode;
528 data.info_fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 }
530 break;
531 default:
532 error = -ECHRNG;
533 if (memcmp(raw_data, "vers", 4) == 0) {
534 error = ncp_parse_options(&data, raw_data);
535 }
536 if (error)
537 goto out;
538 break;
539 }
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800540 error = -EINVAL;
541 if (!uid_valid(data.mounted_uid) || !uid_valid(data.uid) ||
542 !gid_valid(data.gid))
543 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 error = -EBADF;
545 ncp_filp = fget(data.ncp_fd);
546 if (!ncp_filp)
547 goto out;
548 error = -ENOTSOCK;
Al Viro496ad9a2013-01-23 17:07:38 -0500549 sock_inode = file_inode(ncp_filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 if (!S_ISSOCK(sock_inode->i_mode))
551 goto out_fput;
552 sock = SOCKET_I(sock_inode);
553 if (!sock)
554 goto out_fput;
555
556 if (sock->type == SOCK_STREAM)
557 default_bufsize = 0xF000;
558 else
559 default_bufsize = 1024;
560
561 sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
562 sb->s_maxbytes = 0xFFFFFFFFU;
563 sb->s_blocksize = 1024; /* Eh... Is this correct? */
564 sb->s_blocksize_bits = 10;
565 sb->s_magic = NCP_SUPER_MAGIC;
566 sb->s_op = &ncp_sops;
Al Viro0378c402011-01-12 17:25:03 -0500567 sb->s_d_op = &ncp_dentry_operations;
Jens Axboef1970c72010-04-22 12:31:11 +0200568 sb->s_bdi = &server->bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569
570 server = NCP_SBP(sb);
571 memset(server, 0, sizeof(*server));
572
Jens Axboef1970c72010-04-22 12:31:11 +0200573 error = bdi_setup_and_register(&server->bdi, "ncpfs", BDI_CAP_MAP_COPY);
574 if (error)
Djalal Harouni759c3612011-12-13 02:47:29 +0100575 goto out_fput;
Jens Axboef1970c72010-04-22 12:31:11 +0200576
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 server->ncp_filp = ncp_filp;
578 server->ncp_sock = sock;
579
580 if (data.info_fd != -1) {
581 struct socket *info_sock;
582
583 error = -EBADF;
584 server->info_filp = fget(data.info_fd);
585 if (!server->info_filp)
Djalal Harouni759c3612011-12-13 02:47:29 +0100586 goto out_bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 error = -ENOTSOCK;
Al Viro496ad9a2013-01-23 17:07:38 -0500588 sock_inode = file_inode(server->info_filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 if (!S_ISSOCK(sock_inode->i_mode))
590 goto out_fput2;
591 info_sock = SOCKET_I(sock_inode);
592 if (!info_sock)
593 goto out_fput2;
594 error = -EBADFD;
595 if (info_sock->type != SOCK_STREAM)
596 goto out_fput2;
597 server->info_sock = info_sock;
598 }
599
600/* server->lock = 0; */
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800601 mutex_init(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 server->packet = NULL;
603/* server->buffer_size = 0; */
604/* server->conn_status = 0; */
605/* server->root_dentry = NULL; */
606/* server->root_setuped = 0; */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200607 mutex_init(&server->root_setup_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608#ifdef CONFIG_NCPFS_PACKET_SIGNING
609/* server->sign_wanted = 0; */
610/* server->sign_active = 0; */
611#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200612 init_rwsem(&server->auth_rwsem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 server->auth.auth_type = NCP_AUTH_NONE;
614/* server->auth.object_name_len = 0; */
615/* server->auth.object_name = NULL; */
616/* server->auth.object_type = 0; */
617/* server->priv.len = 0; */
618/* server->priv.data = NULL; */
619
620 server->m = data;
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300621 /* Although anything producing this is buggy, it happens
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 now because of PATH_MAX changes.. */
623 if (server->m.time_out < 1) {
624 server->m.time_out = 10;
Joe Perchesb41f8b82014-04-08 16:04:14 -0700625 pr_info("You need to recompile your ncpfs utils..\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 }
627 server->m.time_out = server->m.time_out * HZ / 100;
628 server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
629 server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
630
631#ifdef CONFIG_NCPFS_NLS
632 /* load the default NLS charsets */
633 server->nls_vol = load_nls_default();
634 server->nls_io = load_nls_default();
635#endif /* CONFIG_NCPFS_NLS */
636
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200637 atomic_set(&server->dentry_ttl, 0); /* no caching */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
639 INIT_LIST_HEAD(&server->tx.requests);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800640 mutex_init(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641 server->tx.creq = NULL;
642 server->rcv.creq = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
644 init_timer(&server->timeout_tm);
645#undef NCP_PACKET_SIZE
646#define NCP_PACKET_SIZE 131072
647 error = -ENOMEM;
648 server->packet_size = NCP_PACKET_SIZE;
649 server->packet = vmalloc(NCP_PACKET_SIZE);
650 if (server->packet == NULL)
651 goto out_nls;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100652 server->txbuf = vmalloc(NCP_PACKET_SIZE);
653 if (server->txbuf == NULL)
654 goto out_packet;
655 server->rxbuf = vmalloc(NCP_PACKET_SIZE);
656 if (server->rxbuf == NULL)
657 goto out_txbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200659 lock_sock(sock->sk);
660 server->data_ready = sock->sk->sk_data_ready;
661 server->write_space = sock->sk->sk_write_space;
662 server->error_report = sock->sk->sk_error_report;
663 sock->sk->sk_user_data = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 sock->sk->sk_data_ready = ncp_tcp_data_ready;
665 sock->sk->sk_error_report = ncp_tcp_error_report;
666 if (sock->type == SOCK_STREAM) {
667 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
668 server->rcv.len = 10;
669 server->rcv.state = 0;
David Howellsc4028952006-11-22 14:57:56 +0000670 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
671 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 sock->sk->sk_write_space = ncp_tcp_write_space;
673 } else {
David Howellsc4028952006-11-22 14:57:56 +0000674 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
675 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 server->timeout_tm.data = (unsigned long)server;
677 server->timeout_tm.function = ncpdgram_timeout_call;
678 }
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200679 release_sock(sock->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
681 ncp_lock_server(server);
682 error = ncp_connect(server);
683 ncp_unlock_server(server);
684 if (error < 0)
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100685 goto out_rxbuf;
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700686 ncp_dbg(1, "NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
688 error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */
689#ifdef CONFIG_NCPFS_PACKET_SIGNING
690 if (ncp_negotiate_size_and_options(server, default_bufsize,
691 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
692 {
693 if (options != NCP_DEFAULT_OPTIONS)
694 {
695 if (ncp_negotiate_size_and_options(server,
696 default_bufsize,
697 options & 2,
698 &(server->buffer_size), &options) != 0)
699
700 {
701 goto out_disconnect;
702 }
703 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200704 ncp_lock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 if (options & 2)
706 server->sign_wanted = 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200707 ncp_unlock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 }
709 else
710#endif /* CONFIG_NCPFS_PACKET_SIGNING */
711 if (ncp_negotiate_buffersize(server, default_bufsize,
712 &(server->buffer_size)) != 0)
713 goto out_disconnect;
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700714 ncp_dbg(1, "bufsize = %d\n", server->buffer_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
716 memset(&finfo, 0, sizeof(finfo));
717 finfo.i.attributes = aDIR;
718 finfo.i.dataStreamSize = 0; /* ignored */
719 finfo.i.dirEntNum = 0;
720 finfo.i.DosDirNum = 0;
721#ifdef CONFIG_NCPFS_SMALLDOS
722 finfo.i.NSCreator = NW_NS_DOS;
723#endif
724 finfo.volume = NCP_NUMBER_OF_VOLUMES;
725 /* set dates of mountpoint to Jan 1, 1986; 00:00 */
726 finfo.i.creationTime = finfo.i.modifyTime
727 = cpu_to_le16(0x0000);
728 finfo.i.creationDate = finfo.i.modifyDate
729 = finfo.i.lastAccessDate
730 = cpu_to_le16(0x0C21);
731 finfo.i.nameLen = 0;
732 finfo.i.entryName[0] = '\0';
733
734 finfo.opened = 0;
735 finfo.ino = 2; /* tradition */
736
737 server->name_space[finfo.volume] = NW_NS_DOS;
738
739 error = -ENOMEM;
740 root_inode = ncp_iget(sb, &finfo);
741 if (!root_inode)
742 goto out_disconnect;
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700743 ncp_dbg(1, "root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
Al Viro48fde702012-01-08 22:15:13 -0500744 sb->s_root = d_make_root(root_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 if (!sb->s_root)
Al Viro48fde702012-01-08 22:15:13 -0500746 goto out_disconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 return 0;
748
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749out_disconnect:
750 ncp_lock_server(server);
751 ncp_disconnect(server);
752 ncp_unlock_server(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100753out_rxbuf:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 ncp_stop_tasks(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100755 vfree(server->rxbuf);
756out_txbuf:
757 vfree(server->txbuf);
758out_packet:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 vfree(server->packet);
760out_nls:
761#ifdef CONFIG_NCPFS_NLS
762 unload_nls(server->nls_io);
763 unload_nls(server->nls_vol);
764#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200765 mutex_destroy(&server->rcv.creq_mutex);
766 mutex_destroy(&server->root_setup_lock);
767 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768out_fput2:
769 if (server->info_filp)
770 fput(server->info_filp);
Jens Axboef1970c72010-04-22 12:31:11 +0200771out_bdi:
Djalal Harouni759c3612011-12-13 02:47:29 +0100772 bdi_destroy(&server->bdi);
773out_fput:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
775 *
Matthew Whitworthe956b4b2010-06-27 14:34:30 +0100776 * The previously used put_filp(ncp_filp); was bogus, since
777 * it doesn't perform proper unlocking.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 */
779 fput(ncp_filp);
780out:
Eric W. Biederman1de24122006-12-13 00:35:13 -0800781 put_pid(data.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 sb->s_fs_info = NULL;
783 kfree(server);
784 return error;
785}
786
Al Viro1dcddd42013-10-03 13:22:44 -0400787static void delayed_free(struct rcu_head *p)
788{
789 struct ncp_server *server = container_of(p, struct ncp_server, rcu);
790#ifdef CONFIG_NCPFS_NLS
791 /* unload the NLS charsets */
792 unload_nls(server->nls_vol);
793 unload_nls(server->nls_io);
794#endif /* CONFIG_NCPFS_NLS */
795 kfree(server);
796}
797
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798static void ncp_put_super(struct super_block *sb)
799{
800 struct ncp_server *server = NCP_SBP(sb);
801
802 ncp_lock_server(server);
803 ncp_disconnect(server);
804 ncp_unlock_server(server);
805
806 ncp_stop_tasks(server);
807
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200808 mutex_destroy(&server->rcv.creq_mutex);
809 mutex_destroy(&server->root_setup_lock);
810 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
812 if (server->info_filp)
813 fput(server->info_filp);
814 fput(server->ncp_filp);
Eric W. Biederman21542272006-12-13 00:35:11 -0800815 kill_pid(server->m.wdog_pid, SIGTERM, 1);
816 put_pid(server->m.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817
Jens Axboef1970c72010-04-22 12:31:11 +0200818 bdi_destroy(&server->bdi);
Pekka Enberg44db77f2006-01-14 13:21:12 -0800819 kfree(server->priv.data);
820 kfree(server->auth.object_name);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100821 vfree(server->rxbuf);
822 vfree(server->txbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 vfree(server->packet);
Al Viro1dcddd42013-10-03 13:22:44 -0400824 call_rcu(&server->rcu, delayed_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825}
826
David Howells726c3342006-06-23 02:02:58 -0700827static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828{
829 struct dentry* d;
830 struct inode* i;
831 struct ncp_inode_info* ni;
832 struct ncp_server* s;
833 struct ncp_volume_info vi;
David Howells726c3342006-06-23 02:02:58 -0700834 struct super_block *sb = dentry->d_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 int err;
836 __u8 dh;
837
838 d = sb->s_root;
839 if (!d) {
840 goto dflt;
841 }
842 i = d->d_inode;
843 if (!i) {
844 goto dflt;
845 }
846 ni = NCP_FINFO(i);
847 if (!ni) {
848 goto dflt;
849 }
850 s = NCP_SBP(sb);
851 if (!s) {
852 goto dflt;
853 }
854 if (!s->m.mounted_vol[0]) {
855 goto dflt;
856 }
857
858 err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
859 if (err) {
860 goto dflt;
861 }
862 err = ncp_get_directory_info(s, dh, &vi);
863 ncp_dirhandle_free(s, dh);
864 if (err) {
865 goto dflt;
866 }
867 buf->f_type = NCP_SUPER_MAGIC;
868 buf->f_bsize = vi.sectors_per_block * 512;
869 buf->f_blocks = vi.total_blocks;
870 buf->f_bfree = vi.free_blocks;
871 buf->f_bavail = vi.free_blocks;
872 buf->f_files = vi.total_dir_entries;
873 buf->f_ffree = vi.available_dir_entries;
874 buf->f_namelen = 12;
875 return 0;
876
877 /* We cannot say how much disk space is left on a mounted
878 NetWare Server, because free space is distributed over
879 volumes, and the current user might have disk quotas. So
880 free space is not that simple to determine. Our decision
881 here is to err conservatively. */
882
883dflt:;
884 buf->f_type = NCP_SUPER_MAGIC;
885 buf->f_bsize = NCP_BLOCK_SIZE;
886 buf->f_blocks = 0;
887 buf->f_bfree = 0;
888 buf->f_bavail = 0;
889 buf->f_namelen = 12;
890 return 0;
891}
892
893int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
894{
895 struct inode *inode = dentry->d_inode;
896 int result = 0;
897 __le32 info_mask;
898 struct nw_modify_dos_info info;
899 struct ncp_server *server;
900
901 result = -EIO;
902
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 server = NCP_SERVER(inode);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200904 if (!server) /* How this could happen? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 goto out;
906
Al Viro338b2f52013-06-15 05:53:23 +0400907 result = -EPERM;
908 if (IS_DEADDIR(dentry->d_inode))
909 goto out;
910
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 /* ageing the dentry to force validation */
912 ncp_age_dentry(server, dentry);
913
914 result = inode_change_ok(inode, attr);
915 if (result < 0)
916 goto out;
917
918 result = -EPERM;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800919 if ((attr->ia_valid & ATTR_UID) && !uid_eq(attr->ia_uid, server->m.uid))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 goto out;
921
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800922 if ((attr->ia_valid & ATTR_GID) && !gid_eq(attr->ia_gid, server->m.gid))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 goto out;
924
925 if (((attr->ia_valid & ATTR_MODE) &&
926 (attr->ia_mode &
927 ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
928 goto out;
929
930 info_mask = 0;
931 memset(&info, 0, sizeof(info));
932
933#if 1
934 if ((attr->ia_valid & ATTR_MODE) != 0)
935 {
936 umode_t newmode = attr->ia_mode;
937
938 info_mask |= DM_ATTRIBUTES;
939
940 if (S_ISDIR(inode->i_mode)) {
941 newmode &= server->m.dir_mode;
942 } else {
943#ifdef CONFIG_NCPFS_EXTRAS
944 if (server->m.flags & NCP_MOUNT_EXTRAS) {
945 /* any non-default execute bit set */
946 if (newmode & ~server->m.file_mode & S_IXUGO)
947 info.attributes |= aSHARED | aSYSTEM;
948 /* read for group/world and not in default file_mode */
949 else if (newmode & ~server->m.file_mode & S_IRUGO)
950 info.attributes |= aSHARED;
951 } else
952#endif
953 newmode &= server->m.file_mode;
954 }
955 if (newmode & S_IWUGO)
956 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
957 else
958 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
959
960#ifdef CONFIG_NCPFS_NFS_NS
961 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
962 result = ncp_modify_nfs_info(server,
963 NCP_FINFO(inode)->volNumber,
964 NCP_FINFO(inode)->dirEntNum,
965 attr->ia_mode, 0);
966 if (result != 0)
967 goto out;
968 info.attributes &= ~(aSHARED | aSYSTEM);
969 {
970 /* mark partial success */
971 struct iattr tmpattr;
972
973 tmpattr.ia_valid = ATTR_MODE;
974 tmpattr.ia_mode = attr->ia_mode;
975
Christoph Hellwig10257742010-06-04 11:30:02 +0200976 setattr_copy(inode, &tmpattr);
977 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 }
979 }
980#endif
981 }
982#endif
983
984 /* Do SIZE before attributes, otherwise mtime together with size does not work...
985 */
986 if ((attr->ia_valid & ATTR_SIZE) != 0) {
987 int written;
988
Joe Perchesd3b73ca2014-04-08 16:04:15 -0700989 ncp_dbg(1, "trying to change size to %ld\n", attr->ia_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
991 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
992 result = -EACCES;
993 goto out;
994 }
995 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
996 attr->ia_size, 0, "", &written);
997
998 /* According to ndir, the changes only take effect after
999 closing the file */
1000 ncp_inode_close(inode);
1001 result = ncp_make_closed(inode);
1002 if (result)
1003 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +02001004
1005 if (attr->ia_size != i_size_read(inode)) {
Marco Stornelli3e7a8062012-12-15 11:57:03 +01001006 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +02001007 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 }
1009 }
1010 if ((attr->ia_valid & ATTR_CTIME) != 0) {
1011 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
1012 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
1013 &info.creationTime, &info.creationDate);
1014 }
1015 if ((attr->ia_valid & ATTR_MTIME) != 0) {
1016 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
1017 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
1018 &info.modifyTime, &info.modifyDate);
1019 }
1020 if ((attr->ia_valid & ATTR_ATIME) != 0) {
1021 __le16 dummy;
1022 info_mask |= (DM_LAST_ACCESS_DATE);
1023 ncp_date_unix2dos(attr->ia_atime.tv_sec,
1024 &dummy, &info.lastAccessDate);
1025 }
1026 if (info_mask != 0) {
1027 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
1028 inode, info_mask, &info);
1029 if (result != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
1031 /* NetWare seems not to allow this. I
1032 do not know why. So, just tell the
1033 user everything went fine. This is
1034 a terrible hack, but I do not know
1035 how to do this correctly. */
1036 result = 0;
1037 } else
1038 goto out;
1039 }
1040#ifdef CONFIG_NCPFS_STRONG
1041 if ((!result) && (info_mask & DM_ATTRIBUTES))
1042 NCP_FINFO(inode)->nwattr = info.attributes;
1043#endif
1044 }
Christoph Hellwig10257742010-06-04 11:30:02 +02001045 if (result)
1046 goto out;
1047
1048 setattr_copy(inode, attr);
1049 mark_inode_dirty(inode);
1050
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051out:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001052 if (result > 0)
1053 result = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 return result;
1055}
1056
Al Viro3c26ff62010-07-25 11:46:36 +04001057static struct dentry *ncp_mount(struct file_system_type *fs_type,
1058 int flags, const char *dev_name, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059{
Al Viro3c26ff62010-07-25 11:46:36 +04001060 return mount_nodev(fs_type, flags, data, ncp_fill_super);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061}
1062
1063static struct file_system_type ncp_fs_type = {
1064 .owner = THIS_MODULE,
1065 .name = "ncpfs",
Al Viro3c26ff62010-07-25 11:46:36 +04001066 .mount = ncp_mount,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 .kill_sb = kill_anon_super,
Miklos Szeredi564cd132008-02-08 04:21:46 -08001068 .fs_flags = FS_BINARY_MOUNTDATA,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069};
Eric W. Biederman7f78e032013-03-02 19:39:14 -08001070MODULE_ALIAS_FS("ncpfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
1072static int __init init_ncp_fs(void)
1073{
1074 int err;
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001075 ncp_dbg(1, "called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 err = init_inodecache();
1078 if (err)
1079 goto out1;
1080 err = register_filesystem(&ncp_fs_type);
1081 if (err)
1082 goto out;
1083 return 0;
1084out:
1085 destroy_inodecache();
1086out1:
1087 return err;
1088}
1089
1090static void __exit exit_ncp_fs(void)
1091{
Joe Perchesd3b73ca2014-04-08 16:04:15 -07001092 ncp_dbg(1, "called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 unregister_filesystem(&ncp_fs_type);
1094 destroy_inodecache();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095}
1096
1097module_init(init_ncp_fs)
1098module_exit(exit_ncp_fs)
1099MODULE_LICENSE("GPL");