blob: 5f86e8080178893f7fe8ff2e1f2cfd7d2d51c406 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/module.h>
13
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <asm/uaccess.h>
15#include <asm/byteorder.h>
16
17#include <linux/time.h>
18#include <linux/kernel.h>
19#include <linux/mm.h>
20#include <linux/string.h>
21#include <linux/stat.h>
22#include <linux/errno.h>
23#include <linux/file.h>
24#include <linux/fcntl.h>
25#include <linux/slab.h>
26#include <linux/vmalloc.h>
27#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <linux/vfs.h>
Miklos Szeredi564cd132008-02-08 04:21:46 -080029#include <linux/mount.h>
30#include <linux/seq_file.h>
Nick Piggin34286d62011-01-07 17:49:57 +110031#include <linux/namei.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <net/sock.h>
34
Al Viro32c419d2011-01-12 17:37:47 -050035#include "ncp_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include "getopt.h"
37
Miklos Szeredi564cd132008-02-08 04:21:46 -080038#define NCP_DEFAULT_FILE_MODE 0600
39#define NCP_DEFAULT_DIR_MODE 0700
40#define NCP_DEFAULT_TIME_OUT 10
41#define NCP_DEFAULT_RETRY_COUNT 20
42
Al Viro94ee8492010-06-07 00:45:56 -040043static void ncp_evict_inode(struct inode *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070044static void ncp_put_super(struct super_block *);
David Howells726c3342006-06-23 02:02:58 -070045static int ncp_statfs(struct dentry *, struct kstatfs *);
Al Viro34c80b12011-12-08 21:32:45 -050046static int ncp_show_options(struct seq_file *, struct dentry *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
Christoph Lametere18b8902006-12-06 20:33:20 -080048static struct kmem_cache * ncp_inode_cachep;
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
50static struct inode *ncp_alloc_inode(struct super_block *sb)
51{
52 struct ncp_inode_info *ei;
Christoph Lametere94b1762006-12-06 20:33:17 -080053 ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 if (!ei)
55 return NULL;
56 return &ei->vfs_inode;
57}
58
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +110059static void ncp_i_callback(struct rcu_head *head)
60{
61 struct inode *inode = container_of(head, struct inode, i_rcu);
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +110062 kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
63}
64
Linus Torvalds1da177e2005-04-16 15:20:36 -070065static void ncp_destroy_inode(struct inode *inode)
66{
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +110067 call_rcu(&inode->i_rcu, ncp_i_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -070068}
69
Alexey Dobriyan51cc5062008-07-25 19:45:34 -070070static void init_once(void *foo)
Linus Torvalds1da177e2005-04-16 15:20:36 -070071{
72 struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
73
Christoph Lametera35afb82007-05-16 22:10:57 -070074 mutex_init(&ei->open_mutex);
75 inode_init_once(&ei->vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076}
Paul Mundt20c2df82007-07-20 10:11:58 +090077
Linus Torvalds1da177e2005-04-16 15:20:36 -070078static int init_inodecache(void)
79{
80 ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
81 sizeof(struct ncp_inode_info),
Paul Jacksonfffb60f2006-03-24 03:16:06 -080082 0, (SLAB_RECLAIM_ACCOUNT|
83 SLAB_MEM_SPREAD),
Paul Mundt20c2df82007-07-20 10:11:58 +090084 init_once);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 if (ncp_inode_cachep == NULL)
86 return -ENOMEM;
87 return 0;
88}
89
90static void destroy_inodecache(void)
91{
Kirill A. Shutemov8c0a8532012-09-26 11:33:07 +100092 /*
93 * Make sure all delayed rcu free inodes are flushed before we
94 * destroy cache.
95 */
96 rcu_barrier();
Alexey Dobriyan1a1d92c2006-09-27 01:49:40 -070097 kmem_cache_destroy(ncp_inode_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098}
99
100static int ncp_remount(struct super_block *sb, int *flags, char* data)
101{
Theodore Ts'o02b99842014-03-13 10:14:33 -0400102 sync_filesystem(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 *flags |= MS_NODIRATIME;
104 return 0;
105}
106
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800107static const struct super_operations ncp_sops =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108{
109 .alloc_inode = ncp_alloc_inode,
110 .destroy_inode = ncp_destroy_inode,
111 .drop_inode = generic_delete_inode,
Al Viro94ee8492010-06-07 00:45:56 -0400112 .evict_inode = ncp_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 .put_super = ncp_put_super,
114 .statfs = ncp_statfs,
115 .remount_fs = ncp_remount,
Miklos Szeredi564cd132008-02-08 04:21:46 -0800116 .show_options = ncp_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117};
118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119/*
120 * Fill in the ncpfs-specific information in the inode.
121 */
122static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
123{
124 NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
125 NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
126 NCP_FINFO(inode)->volNumber = nwinfo->volume;
127}
128
129void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
130{
131 ncp_update_dirent(inode, nwinfo);
132 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
133 NCP_FINFO(inode)->access = nwinfo->access;
134 memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
135 sizeof(nwinfo->file_handle));
136 DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
137 nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
138 NCP_FINFO(inode)->dirEntNum);
139}
140
141static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
142{
143 /* NFS namespace mode overrides others if it's set. */
144 DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n",
145 nwi->entryName, nwi->nfs.mode);
146 if (nwi->nfs.mode) {
147 /* XXX Security? */
148 inode->i_mode = nwi->nfs.mode;
149 }
150
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200151 inode->i_blocks = (i_size_read(inode) + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152
153 inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate);
154 inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate);
155 inode->i_atime.tv_sec = ncp_date_dos2unix(0, nwi->lastAccessDate);
156 inode->i_atime.tv_nsec = 0;
157 inode->i_mtime.tv_nsec = 0;
158 inode->i_ctime.tv_nsec = 0;
159}
160
161static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
162{
163 struct nw_info_struct *nwi = &nwinfo->i;
164 struct ncp_server *server = NCP_SERVER(inode);
165
166 if (nwi->attributes & aDIR) {
167 inode->i_mode = server->m.dir_mode;
168 /* for directories dataStreamSize seems to be some
169 Object ID ??? */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200170 i_size_write(inode, NCP_BLOCK_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 } else {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200172 u32 size;
173
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 inode->i_mode = server->m.file_mode;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200175 size = le32_to_cpu(nwi->dataStreamSize);
176 i_size_write(inode, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177#ifdef CONFIG_NCPFS_EXTRAS
178 if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS))
179 && (nwi->attributes & aSHARED)) {
180 switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
181 case aHIDDEN:
182 if (server->m.flags & NCP_MOUNT_SYMLINKS) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200183 if (/* (size >= NCP_MIN_SYMLINK_SIZE)
184 && */ (size <= NCP_MAX_SYMLINK_SIZE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
186 NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
187 break;
188 }
189 }
190 /* FALLTHROUGH */
191 case 0:
192 if (server->m.flags & NCP_MOUNT_EXTRAS)
193 inode->i_mode |= S_IRUGO;
194 break;
195 case aSYSTEM:
196 if (server->m.flags & NCP_MOUNT_EXTRAS)
197 inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO;
198 break;
199 /* case aSYSTEM|aHIDDEN: */
200 default:
201 /* reserved combination */
202 break;
203 }
204 }
205#endif
206 }
207 if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
208}
209
210void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
211{
212 NCP_FINFO(inode)->flags = 0;
213 if (!atomic_read(&NCP_FINFO(inode)->opened)) {
214 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
215 ncp_update_attrs(inode, nwinfo);
216 }
217
218 ncp_update_dates(inode, &nwinfo->i);
219 ncp_update_dirent(inode, nwinfo);
220}
221
222/*
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200223 * Fill in the inode based on the ncp_entry_info structure. Used only for brand new inodes.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 */
225static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
226{
227 struct ncp_server *server = NCP_SERVER(inode);
228
229 NCP_FINFO(inode)->flags = 0;
230
231 ncp_update_attrs(inode, nwinfo);
232
233 DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
234
Miklos Szeredibfe86842011-10-28 14:13:29 +0200235 set_nlink(inode, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 inode->i_uid = server->m.uid;
237 inode->i_gid = server->m.gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
239 ncp_update_dates(inode, &nwinfo->i);
240 ncp_update_inode(inode, nwinfo);
241}
242
243#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800244static const struct inode_operations ncp_symlink_inode_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 .readlink = generic_readlink,
246 .follow_link = page_follow_link_light,
247 .put_link = page_put_link,
248 .setattr = ncp_notify_change,
249};
250#endif
251
252/*
253 * Get a new inode.
254 */
255struct inode *
256ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
257{
258 struct inode *inode;
259
260 if (info == NULL) {
261 printk(KERN_ERR "ncp_iget: info is NULL\n");
262 return NULL;
263 }
264
265 inode = new_inode(sb);
266 if (inode) {
267 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
268
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200269 inode->i_mapping->backing_dev_info = sb->s_bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 inode->i_ino = info->ino;
271 ncp_set_attr(inode, info);
272 if (S_ISREG(inode->i_mode)) {
273 inode->i_op = &ncp_file_inode_operations;
274 inode->i_fop = &ncp_file_operations;
275 } else if (S_ISDIR(inode->i_mode)) {
276 inode->i_op = &ncp_dir_inode_operations;
277 inode->i_fop = &ncp_dir_operations;
278#ifdef CONFIG_NCPFS_NFS_NS
279 } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
280 init_special_inode(inode, inode->i_mode,
281 new_decode_dev(info->i.nfs.rdev));
282#endif
283#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
284 } else if (S_ISLNK(inode->i_mode)) {
285 inode->i_op = &ncp_symlink_inode_operations;
286 inode->i_data.a_ops = &ncp_symlink_aops;
287#endif
288 } else {
289 make_bad_inode(inode);
290 }
291 insert_inode_hash(inode);
292 } else
293 printk(KERN_ERR "ncp_iget: iget failed!\n");
294 return inode;
295}
296
297static void
Al Viro94ee8492010-06-07 00:45:56 -0400298ncp_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299{
Mark Fashehfef26652005-09-09 13:01:31 -0700300 truncate_inode_pages(&inode->i_data, 0);
Jan Karadbd57682012-05-03 14:48:02 +0200301 clear_inode(inode);
Mark Fashehfef26652005-09-09 13:01:31 -0700302
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 if (S_ISDIR(inode->i_mode)) {
Al Viro94ee8492010-06-07 00:45:56 -0400304 DDPRINTK("ncp_evict_inode: put directory %ld\n", inode->i_ino);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 }
306
307 if (ncp_make_closed(inode) != 0) {
308 /* We can't do anything but complain. */
Al Viro94ee8492010-06-07 00:45:56 -0400309 printk(KERN_ERR "ncp_evict_inode: could not close\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311}
312
313static void ncp_stop_tasks(struct ncp_server *server) {
314 struct sock* sk = server->ncp_sock->sk;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200315
316 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 sk->sk_error_report = server->error_report;
318 sk->sk_data_ready = server->data_ready;
319 sk->sk_write_space = server->write_space;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200320 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 del_timer_sync(&server->timeout_tm);
Tejun Heo5d8e4bd2010-12-24 15:59:06 +0100322
Tejun Heo43829732012-08-20 14:51:24 -0700323 flush_work(&server->rcv.tq);
Tejun Heo5d8e4bd2010-12-24 15:59:06 +0100324 if (sk->sk_socket->type == SOCK_STREAM)
Tejun Heo43829732012-08-20 14:51:24 -0700325 flush_work(&server->tx.tq);
Tejun Heo5d8e4bd2010-12-24 15:59:06 +0100326 else
Tejun Heo43829732012-08-20 14:51:24 -0700327 flush_work(&server->timeout_tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328}
329
Al Viro34c80b12011-12-08 21:32:45 -0500330static int ncp_show_options(struct seq_file *seq, struct dentry *root)
Miklos Szeredi564cd132008-02-08 04:21:46 -0800331{
Al Viro34c80b12011-12-08 21:32:45 -0500332 struct ncp_server *server = NCP_SBP(root->d_sb);
Miklos Szeredi564cd132008-02-08 04:21:46 -0800333 unsigned int tmp;
334
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800335 if (!uid_eq(server->m.uid, GLOBAL_ROOT_UID))
336 seq_printf(seq, ",uid=%u",
337 from_kuid_munged(&init_user_ns, server->m.uid));
338 if (!gid_eq(server->m.gid, GLOBAL_ROOT_GID))
339 seq_printf(seq, ",gid=%u",
340 from_kgid_munged(&init_user_ns, server->m.gid));
341 if (!uid_eq(server->m.mounted_uid, GLOBAL_ROOT_UID))
342 seq_printf(seq, ",owner=%u",
343 from_kuid_munged(&init_user_ns, server->m.mounted_uid));
Miklos Szeredi564cd132008-02-08 04:21:46 -0800344 tmp = server->m.file_mode & S_IALLUGO;
345 if (tmp != NCP_DEFAULT_FILE_MODE)
346 seq_printf(seq, ",mode=0%o", tmp);
347 tmp = server->m.dir_mode & S_IALLUGO;
348 if (tmp != NCP_DEFAULT_DIR_MODE)
349 seq_printf(seq, ",dirmode=0%o", tmp);
350 if (server->m.time_out != NCP_DEFAULT_TIME_OUT * HZ / 100) {
351 tmp = server->m.time_out * 100 / HZ;
352 seq_printf(seq, ",timeout=%u", tmp);
353 }
354 if (server->m.retry_count != NCP_DEFAULT_RETRY_COUNT)
355 seq_printf(seq, ",retry=%u", server->m.retry_count);
356 if (server->m.flags != 0)
357 seq_printf(seq, ",flags=%lu", server->m.flags);
358 if (server->m.wdog_pid != NULL)
359 seq_printf(seq, ",wdogpid=%u", pid_vnr(server->m.wdog_pid));
360
361 return 0;
362}
363
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364static const struct ncp_option ncp_opts[] = {
365 { "uid", OPT_INT, 'u' },
366 { "gid", OPT_INT, 'g' },
367 { "owner", OPT_INT, 'o' },
368 { "mode", OPT_INT, 'm' },
369 { "dirmode", OPT_INT, 'd' },
370 { "timeout", OPT_INT, 't' },
371 { "retry", OPT_INT, 'r' },
372 { "flags", OPT_INT, 'f' },
373 { "wdogpid", OPT_INT, 'w' },
374 { "ncpfd", OPT_INT, 'n' },
375 { "infofd", OPT_INT, 'i' }, /* v5 */
376 { "version", OPT_INT, 'v' },
377 { NULL, 0, 0 } };
378
379static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
380 int optval;
381 char *optarg;
382 unsigned long optint;
383 int version = 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800384 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385
386 data->flags = 0;
387 data->int_flags = 0;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800388 data->mounted_uid = GLOBAL_ROOT_UID;
Eric W. Biederman21542272006-12-13 00:35:11 -0800389 data->wdog_pid = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 data->ncp_fd = ~0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800391 data->time_out = NCP_DEFAULT_TIME_OUT;
392 data->retry_count = NCP_DEFAULT_RETRY_COUNT;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800393 data->uid = GLOBAL_ROOT_UID;
394 data->gid = GLOBAL_ROOT_GID;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800395 data->file_mode = NCP_DEFAULT_FILE_MODE;
396 data->dir_mode = NCP_DEFAULT_DIR_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 data->info_fd = -1;
398 data->mounted_vol[0] = 0;
399
400 while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
Eric W. Biederman1de24122006-12-13 00:35:13 -0800401 ret = optval;
402 if (ret < 0)
403 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 switch (optval) {
405 case 'u':
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800406 data->uid = make_kuid(current_user_ns(), optint);
Wei Yongjun4fbeb192013-07-04 21:43:32 +0800407 if (!uid_valid(data->uid)) {
408 ret = -EINVAL;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800409 goto err;
Wei Yongjun4fbeb192013-07-04 21:43:32 +0800410 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 break;
412 case 'g':
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800413 data->gid = make_kgid(current_user_ns(), optint);
Wei Yongjun4fbeb192013-07-04 21:43:32 +0800414 if (!gid_valid(data->gid)) {
415 ret = -EINVAL;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800416 goto err;
Wei Yongjun4fbeb192013-07-04 21:43:32 +0800417 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 break;
419 case 'o':
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800420 data->mounted_uid = make_kuid(current_user_ns(), optint);
Wei Yongjun4fbeb192013-07-04 21:43:32 +0800421 if (!uid_valid(data->mounted_uid)) {
422 ret = -EINVAL;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800423 goto err;
Wei Yongjun4fbeb192013-07-04 21:43:32 +0800424 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 break;
426 case 'm':
427 data->file_mode = optint;
428 break;
429 case 'd':
430 data->dir_mode = optint;
431 break;
432 case 't':
433 data->time_out = optint;
434 break;
435 case 'r':
436 data->retry_count = optint;
437 break;
438 case 'f':
439 data->flags = optint;
440 break;
441 case 'w':
Eric W. Biederman21542272006-12-13 00:35:11 -0800442 data->wdog_pid = find_get_pid(optint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 break;
444 case 'n':
445 data->ncp_fd = optint;
446 break;
447 case 'i':
448 data->info_fd = optint;
449 break;
450 case 'v':
Eric W. Biederman1de24122006-12-13 00:35:13 -0800451 ret = -ECHRNG;
452 if (optint < NCP_MOUNT_VERSION_V4)
453 goto err;
454 if (optint > NCP_MOUNT_VERSION_V5)
455 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 version = optint;
457 break;
458
459 }
460 }
461 return 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800462err:
463 put_pid(data->wdog_pid);
464 data->wdog_pid = NULL;
465 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466}
467
468static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
469{
470 struct ncp_mount_data_kernel data;
471 struct ncp_server *server;
472 struct file *ncp_filp;
473 struct inode *root_inode;
474 struct inode *sock_inode;
475 struct socket *sock;
476 int error;
477 int default_bufsize;
478#ifdef CONFIG_NCPFS_PACKET_SIGNING
479 int options;
480#endif
481 struct ncp_entry_info finfo;
482
Andrew Morton2a5cac12011-05-24 17:13:42 -0700483 memset(&data, 0, sizeof(data));
Panagiotis Issarisf8314dc2006-09-27 01:49:37 -0700484 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 if (!server)
486 return -ENOMEM;
487 sb->s_fs_info = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
489 error = -EFAULT;
490 if (raw_data == NULL)
491 goto out;
492 switch (*(int*)raw_data) {
493 case NCP_MOUNT_VERSION:
494 {
495 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
496
497 data.flags = md->flags;
498 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800499 data.mounted_uid = make_kuid(current_user_ns(), md->mounted_uid);
Eric W. Biederman21542272006-12-13 00:35:11 -0800500 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 data.ncp_fd = md->ncp_fd;
502 data.time_out = md->time_out;
503 data.retry_count = md->retry_count;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800504 data.uid = make_kuid(current_user_ns(), md->uid);
505 data.gid = make_kgid(current_user_ns(), md->gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 data.file_mode = md->file_mode;
507 data.dir_mode = md->dir_mode;
508 data.info_fd = -1;
509 memcpy(data.mounted_vol, md->mounted_vol,
510 NCP_VOLNAME_LEN+1);
511 }
512 break;
513 case NCP_MOUNT_VERSION_V4:
514 {
515 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
516
517 data.flags = md->flags;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800518 data.mounted_uid = make_kuid(current_user_ns(), md->mounted_uid);
Eric W. Biederman21542272006-12-13 00:35:11 -0800519 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 data.ncp_fd = md->ncp_fd;
521 data.time_out = md->time_out;
522 data.retry_count = md->retry_count;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800523 data.uid = make_kuid(current_user_ns(), md->uid);
524 data.gid = make_kgid(current_user_ns(), md->gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 data.file_mode = md->file_mode;
526 data.dir_mode = md->dir_mode;
527 data.info_fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 }
529 break;
530 default:
531 error = -ECHRNG;
532 if (memcmp(raw_data, "vers", 4) == 0) {
533 error = ncp_parse_options(&data, raw_data);
534 }
535 if (error)
536 goto out;
537 break;
538 }
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800539 error = -EINVAL;
540 if (!uid_valid(data.mounted_uid) || !uid_valid(data.uid) ||
541 !gid_valid(data.gid))
542 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 error = -EBADF;
544 ncp_filp = fget(data.ncp_fd);
545 if (!ncp_filp)
546 goto out;
547 error = -ENOTSOCK;
Al Viro496ad9a2013-01-23 17:07:38 -0500548 sock_inode = file_inode(ncp_filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 if (!S_ISSOCK(sock_inode->i_mode))
550 goto out_fput;
551 sock = SOCKET_I(sock_inode);
552 if (!sock)
553 goto out_fput;
554
555 if (sock->type == SOCK_STREAM)
556 default_bufsize = 0xF000;
557 else
558 default_bufsize = 1024;
559
560 sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
561 sb->s_maxbytes = 0xFFFFFFFFU;
562 sb->s_blocksize = 1024; /* Eh... Is this correct? */
563 sb->s_blocksize_bits = 10;
564 sb->s_magic = NCP_SUPER_MAGIC;
565 sb->s_op = &ncp_sops;
Al Viro0378c402011-01-12 17:25:03 -0500566 sb->s_d_op = &ncp_dentry_operations;
Jens Axboef1970c72010-04-22 12:31:11 +0200567 sb->s_bdi = &server->bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
569 server = NCP_SBP(sb);
570 memset(server, 0, sizeof(*server));
571
Jens Axboef1970c72010-04-22 12:31:11 +0200572 error = bdi_setup_and_register(&server->bdi, "ncpfs", BDI_CAP_MAP_COPY);
573 if (error)
Djalal Harouni759c3612011-12-13 02:47:29 +0100574 goto out_fput;
Jens Axboef1970c72010-04-22 12:31:11 +0200575
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 server->ncp_filp = ncp_filp;
577 server->ncp_sock = sock;
578
579 if (data.info_fd != -1) {
580 struct socket *info_sock;
581
582 error = -EBADF;
583 server->info_filp = fget(data.info_fd);
584 if (!server->info_filp)
Djalal Harouni759c3612011-12-13 02:47:29 +0100585 goto out_bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 error = -ENOTSOCK;
Al Viro496ad9a2013-01-23 17:07:38 -0500587 sock_inode = file_inode(server->info_filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 if (!S_ISSOCK(sock_inode->i_mode))
589 goto out_fput2;
590 info_sock = SOCKET_I(sock_inode);
591 if (!info_sock)
592 goto out_fput2;
593 error = -EBADFD;
594 if (info_sock->type != SOCK_STREAM)
595 goto out_fput2;
596 server->info_sock = info_sock;
597 }
598
599/* server->lock = 0; */
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800600 mutex_init(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 server->packet = NULL;
602/* server->buffer_size = 0; */
603/* server->conn_status = 0; */
604/* server->root_dentry = NULL; */
605/* server->root_setuped = 0; */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200606 mutex_init(&server->root_setup_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607#ifdef CONFIG_NCPFS_PACKET_SIGNING
608/* server->sign_wanted = 0; */
609/* server->sign_active = 0; */
610#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200611 init_rwsem(&server->auth_rwsem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 server->auth.auth_type = NCP_AUTH_NONE;
613/* server->auth.object_name_len = 0; */
614/* server->auth.object_name = NULL; */
615/* server->auth.object_type = 0; */
616/* server->priv.len = 0; */
617/* server->priv.data = NULL; */
618
619 server->m = data;
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300620 /* Although anything producing this is buggy, it happens
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 now because of PATH_MAX changes.. */
622 if (server->m.time_out < 1) {
623 server->m.time_out = 10;
624 printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
625 }
626 server->m.time_out = server->m.time_out * HZ / 100;
627 server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
628 server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
629
630#ifdef CONFIG_NCPFS_NLS
631 /* load the default NLS charsets */
632 server->nls_vol = load_nls_default();
633 server->nls_io = load_nls_default();
634#endif /* CONFIG_NCPFS_NLS */
635
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200636 atomic_set(&server->dentry_ttl, 0); /* no caching */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
638 INIT_LIST_HEAD(&server->tx.requests);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800639 mutex_init(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 server->tx.creq = NULL;
641 server->rcv.creq = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
643 init_timer(&server->timeout_tm);
644#undef NCP_PACKET_SIZE
645#define NCP_PACKET_SIZE 131072
646 error = -ENOMEM;
647 server->packet_size = NCP_PACKET_SIZE;
648 server->packet = vmalloc(NCP_PACKET_SIZE);
649 if (server->packet == NULL)
650 goto out_nls;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100651 server->txbuf = vmalloc(NCP_PACKET_SIZE);
652 if (server->txbuf == NULL)
653 goto out_packet;
654 server->rxbuf = vmalloc(NCP_PACKET_SIZE);
655 if (server->rxbuf == NULL)
656 goto out_txbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200658 lock_sock(sock->sk);
659 server->data_ready = sock->sk->sk_data_ready;
660 server->write_space = sock->sk->sk_write_space;
661 server->error_report = sock->sk->sk_error_report;
662 sock->sk->sk_user_data = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 sock->sk->sk_data_ready = ncp_tcp_data_ready;
664 sock->sk->sk_error_report = ncp_tcp_error_report;
665 if (sock->type == SOCK_STREAM) {
666 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
667 server->rcv.len = 10;
668 server->rcv.state = 0;
David Howellsc4028952006-11-22 14:57:56 +0000669 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
670 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 sock->sk->sk_write_space = ncp_tcp_write_space;
672 } else {
David Howellsc4028952006-11-22 14:57:56 +0000673 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
674 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 server->timeout_tm.data = (unsigned long)server;
676 server->timeout_tm.function = ncpdgram_timeout_call;
677 }
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200678 release_sock(sock->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
680 ncp_lock_server(server);
681 error = ncp_connect(server);
682 ncp_unlock_server(server);
683 if (error < 0)
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100684 goto out_rxbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
686
687 error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */
688#ifdef CONFIG_NCPFS_PACKET_SIGNING
689 if (ncp_negotiate_size_and_options(server, default_bufsize,
690 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
691 {
692 if (options != NCP_DEFAULT_OPTIONS)
693 {
694 if (ncp_negotiate_size_and_options(server,
695 default_bufsize,
696 options & 2,
697 &(server->buffer_size), &options) != 0)
698
699 {
700 goto out_disconnect;
701 }
702 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200703 ncp_lock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 if (options & 2)
705 server->sign_wanted = 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200706 ncp_unlock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 }
708 else
709#endif /* CONFIG_NCPFS_PACKET_SIGNING */
710 if (ncp_negotiate_buffersize(server, default_bufsize,
711 &(server->buffer_size)) != 0)
712 goto out_disconnect;
713 DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
714
715 memset(&finfo, 0, sizeof(finfo));
716 finfo.i.attributes = aDIR;
717 finfo.i.dataStreamSize = 0; /* ignored */
718 finfo.i.dirEntNum = 0;
719 finfo.i.DosDirNum = 0;
720#ifdef CONFIG_NCPFS_SMALLDOS
721 finfo.i.NSCreator = NW_NS_DOS;
722#endif
723 finfo.volume = NCP_NUMBER_OF_VOLUMES;
724 /* set dates of mountpoint to Jan 1, 1986; 00:00 */
725 finfo.i.creationTime = finfo.i.modifyTime
726 = cpu_to_le16(0x0000);
727 finfo.i.creationDate = finfo.i.modifyDate
728 = finfo.i.lastAccessDate
729 = cpu_to_le16(0x0C21);
730 finfo.i.nameLen = 0;
731 finfo.i.entryName[0] = '\0';
732
733 finfo.opened = 0;
734 finfo.ino = 2; /* tradition */
735
736 server->name_space[finfo.volume] = NW_NS_DOS;
737
738 error = -ENOMEM;
739 root_inode = ncp_iget(sb, &finfo);
740 if (!root_inode)
741 goto out_disconnect;
742 DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
Al Viro48fde702012-01-08 22:15:13 -0500743 sb->s_root = d_make_root(root_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 if (!sb->s_root)
Al Viro48fde702012-01-08 22:15:13 -0500745 goto out_disconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 return 0;
747
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748out_disconnect:
749 ncp_lock_server(server);
750 ncp_disconnect(server);
751 ncp_unlock_server(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100752out_rxbuf:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 ncp_stop_tasks(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100754 vfree(server->rxbuf);
755out_txbuf:
756 vfree(server->txbuf);
757out_packet:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 vfree(server->packet);
759out_nls:
760#ifdef CONFIG_NCPFS_NLS
761 unload_nls(server->nls_io);
762 unload_nls(server->nls_vol);
763#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200764 mutex_destroy(&server->rcv.creq_mutex);
765 mutex_destroy(&server->root_setup_lock);
766 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767out_fput2:
768 if (server->info_filp)
769 fput(server->info_filp);
Jens Axboef1970c72010-04-22 12:31:11 +0200770out_bdi:
Djalal Harouni759c3612011-12-13 02:47:29 +0100771 bdi_destroy(&server->bdi);
772out_fput:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
774 *
Matthew Whitworthe956b4b2010-06-27 14:34:30 +0100775 * The previously used put_filp(ncp_filp); was bogus, since
776 * it doesn't perform proper unlocking.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 */
778 fput(ncp_filp);
779out:
Eric W. Biederman1de24122006-12-13 00:35:13 -0800780 put_pid(data.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 sb->s_fs_info = NULL;
782 kfree(server);
783 return error;
784}
785
Al Viro1dcddd42013-10-03 13:22:44 -0400786static void delayed_free(struct rcu_head *p)
787{
788 struct ncp_server *server = container_of(p, struct ncp_server, rcu);
789#ifdef CONFIG_NCPFS_NLS
790 /* unload the NLS charsets */
791 unload_nls(server->nls_vol);
792 unload_nls(server->nls_io);
793#endif /* CONFIG_NCPFS_NLS */
794 kfree(server);
795}
796
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797static void ncp_put_super(struct super_block *sb)
798{
799 struct ncp_server *server = NCP_SBP(sb);
800
801 ncp_lock_server(server);
802 ncp_disconnect(server);
803 ncp_unlock_server(server);
804
805 ncp_stop_tasks(server);
806
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200807 mutex_destroy(&server->rcv.creq_mutex);
808 mutex_destroy(&server->root_setup_lock);
809 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
811 if (server->info_filp)
812 fput(server->info_filp);
813 fput(server->ncp_filp);
Eric W. Biederman21542272006-12-13 00:35:11 -0800814 kill_pid(server->m.wdog_pid, SIGTERM, 1);
815 put_pid(server->m.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816
Jens Axboef1970c72010-04-22 12:31:11 +0200817 bdi_destroy(&server->bdi);
Pekka Enberg44db77f2006-01-14 13:21:12 -0800818 kfree(server->priv.data);
819 kfree(server->auth.object_name);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100820 vfree(server->rxbuf);
821 vfree(server->txbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 vfree(server->packet);
Al Viro1dcddd42013-10-03 13:22:44 -0400823 call_rcu(&server->rcu, delayed_free);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824}
825
David Howells726c3342006-06-23 02:02:58 -0700826static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827{
828 struct dentry* d;
829 struct inode* i;
830 struct ncp_inode_info* ni;
831 struct ncp_server* s;
832 struct ncp_volume_info vi;
David Howells726c3342006-06-23 02:02:58 -0700833 struct super_block *sb = dentry->d_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 int err;
835 __u8 dh;
836
837 d = sb->s_root;
838 if (!d) {
839 goto dflt;
840 }
841 i = d->d_inode;
842 if (!i) {
843 goto dflt;
844 }
845 ni = NCP_FINFO(i);
846 if (!ni) {
847 goto dflt;
848 }
849 s = NCP_SBP(sb);
850 if (!s) {
851 goto dflt;
852 }
853 if (!s->m.mounted_vol[0]) {
854 goto dflt;
855 }
856
857 err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
858 if (err) {
859 goto dflt;
860 }
861 err = ncp_get_directory_info(s, dh, &vi);
862 ncp_dirhandle_free(s, dh);
863 if (err) {
864 goto dflt;
865 }
866 buf->f_type = NCP_SUPER_MAGIC;
867 buf->f_bsize = vi.sectors_per_block * 512;
868 buf->f_blocks = vi.total_blocks;
869 buf->f_bfree = vi.free_blocks;
870 buf->f_bavail = vi.free_blocks;
871 buf->f_files = vi.total_dir_entries;
872 buf->f_ffree = vi.available_dir_entries;
873 buf->f_namelen = 12;
874 return 0;
875
876 /* We cannot say how much disk space is left on a mounted
877 NetWare Server, because free space is distributed over
878 volumes, and the current user might have disk quotas. So
879 free space is not that simple to determine. Our decision
880 here is to err conservatively. */
881
882dflt:;
883 buf->f_type = NCP_SUPER_MAGIC;
884 buf->f_bsize = NCP_BLOCK_SIZE;
885 buf->f_blocks = 0;
886 buf->f_bfree = 0;
887 buf->f_bavail = 0;
888 buf->f_namelen = 12;
889 return 0;
890}
891
892int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
893{
894 struct inode *inode = dentry->d_inode;
895 int result = 0;
896 __le32 info_mask;
897 struct nw_modify_dos_info info;
898 struct ncp_server *server;
899
900 result = -EIO;
901
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 server = NCP_SERVER(inode);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200903 if (!server) /* How this could happen? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 goto out;
905
Al Viro338b2f52013-06-15 05:53:23 +0400906 result = -EPERM;
907 if (IS_DEADDIR(dentry->d_inode))
908 goto out;
909
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 /* ageing the dentry to force validation */
911 ncp_age_dentry(server, dentry);
912
913 result = inode_change_ok(inode, attr);
914 if (result < 0)
915 goto out;
916
917 result = -EPERM;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800918 if ((attr->ia_valid & ATTR_UID) && !uid_eq(attr->ia_uid, server->m.uid))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 goto out;
920
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800921 if ((attr->ia_valid & ATTR_GID) && !gid_eq(attr->ia_gid, server->m.gid))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 goto out;
923
924 if (((attr->ia_valid & ATTR_MODE) &&
925 (attr->ia_mode &
926 ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
927 goto out;
928
929 info_mask = 0;
930 memset(&info, 0, sizeof(info));
931
932#if 1
933 if ((attr->ia_valid & ATTR_MODE) != 0)
934 {
935 umode_t newmode = attr->ia_mode;
936
937 info_mask |= DM_ATTRIBUTES;
938
939 if (S_ISDIR(inode->i_mode)) {
940 newmode &= server->m.dir_mode;
941 } else {
942#ifdef CONFIG_NCPFS_EXTRAS
943 if (server->m.flags & NCP_MOUNT_EXTRAS) {
944 /* any non-default execute bit set */
945 if (newmode & ~server->m.file_mode & S_IXUGO)
946 info.attributes |= aSHARED | aSYSTEM;
947 /* read for group/world and not in default file_mode */
948 else if (newmode & ~server->m.file_mode & S_IRUGO)
949 info.attributes |= aSHARED;
950 } else
951#endif
952 newmode &= server->m.file_mode;
953 }
954 if (newmode & S_IWUGO)
955 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
956 else
957 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
958
959#ifdef CONFIG_NCPFS_NFS_NS
960 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
961 result = ncp_modify_nfs_info(server,
962 NCP_FINFO(inode)->volNumber,
963 NCP_FINFO(inode)->dirEntNum,
964 attr->ia_mode, 0);
965 if (result != 0)
966 goto out;
967 info.attributes &= ~(aSHARED | aSYSTEM);
968 {
969 /* mark partial success */
970 struct iattr tmpattr;
971
972 tmpattr.ia_valid = ATTR_MODE;
973 tmpattr.ia_mode = attr->ia_mode;
974
Christoph Hellwig10257742010-06-04 11:30:02 +0200975 setattr_copy(inode, &tmpattr);
976 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 }
978 }
979#endif
980 }
981#endif
982
983 /* Do SIZE before attributes, otherwise mtime together with size does not work...
984 */
985 if ((attr->ia_valid & ATTR_SIZE) != 0) {
986 int written;
987
988 DPRINTK("ncpfs: trying to change size to %ld\n",
989 attr->ia_size);
990
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;
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001075 DPRINTK("ncpfs: init_ncp_fs 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{
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001092 DPRINTK("ncpfs: exit_ncp_fs 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");