blob: 26910c8154da1be65c0318eb088d5d69d3e08baf [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{
102 *flags |= MS_NODIRATIME;
103 return 0;
104}
105
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800106static const struct super_operations ncp_sops =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107{
108 .alloc_inode = ncp_alloc_inode,
109 .destroy_inode = ncp_destroy_inode,
110 .drop_inode = generic_delete_inode,
Al Viro94ee8492010-06-07 00:45:56 -0400111 .evict_inode = ncp_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 .put_super = ncp_put_super,
113 .statfs = ncp_statfs,
114 .remount_fs = ncp_remount,
Miklos Szeredi564cd132008-02-08 04:21:46 -0800115 .show_options = ncp_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116};
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118/*
119 * Fill in the ncpfs-specific information in the inode.
120 */
121static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
122{
123 NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
124 NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
125 NCP_FINFO(inode)->volNumber = nwinfo->volume;
126}
127
128void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
129{
130 ncp_update_dirent(inode, nwinfo);
131 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
132 NCP_FINFO(inode)->access = nwinfo->access;
133 memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
134 sizeof(nwinfo->file_handle));
135 DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
136 nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
137 NCP_FINFO(inode)->dirEntNum);
138}
139
140static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
141{
142 /* NFS namespace mode overrides others if it's set. */
143 DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n",
144 nwi->entryName, nwi->nfs.mode);
145 if (nwi->nfs.mode) {
146 /* XXX Security? */
147 inode->i_mode = nwi->nfs.mode;
148 }
149
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200150 inode->i_blocks = (i_size_read(inode) + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151
152 inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate);
153 inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate);
154 inode->i_atime.tv_sec = ncp_date_dos2unix(0, nwi->lastAccessDate);
155 inode->i_atime.tv_nsec = 0;
156 inode->i_mtime.tv_nsec = 0;
157 inode->i_ctime.tv_nsec = 0;
158}
159
160static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
161{
162 struct nw_info_struct *nwi = &nwinfo->i;
163 struct ncp_server *server = NCP_SERVER(inode);
164
165 if (nwi->attributes & aDIR) {
166 inode->i_mode = server->m.dir_mode;
167 /* for directories dataStreamSize seems to be some
168 Object ID ??? */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200169 i_size_write(inode, NCP_BLOCK_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 } else {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200171 u32 size;
172
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 inode->i_mode = server->m.file_mode;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200174 size = le32_to_cpu(nwi->dataStreamSize);
175 i_size_write(inode, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176#ifdef CONFIG_NCPFS_EXTRAS
177 if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS))
178 && (nwi->attributes & aSHARED)) {
179 switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
180 case aHIDDEN:
181 if (server->m.flags & NCP_MOUNT_SYMLINKS) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200182 if (/* (size >= NCP_MIN_SYMLINK_SIZE)
183 && */ (size <= NCP_MAX_SYMLINK_SIZE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
185 NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
186 break;
187 }
188 }
189 /* FALLTHROUGH */
190 case 0:
191 if (server->m.flags & NCP_MOUNT_EXTRAS)
192 inode->i_mode |= S_IRUGO;
193 break;
194 case aSYSTEM:
195 if (server->m.flags & NCP_MOUNT_EXTRAS)
196 inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO;
197 break;
198 /* case aSYSTEM|aHIDDEN: */
199 default:
200 /* reserved combination */
201 break;
202 }
203 }
204#endif
205 }
206 if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
207}
208
209void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
210{
211 NCP_FINFO(inode)->flags = 0;
212 if (!atomic_read(&NCP_FINFO(inode)->opened)) {
213 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
214 ncp_update_attrs(inode, nwinfo);
215 }
216
217 ncp_update_dates(inode, &nwinfo->i);
218 ncp_update_dirent(inode, nwinfo);
219}
220
221/*
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200222 * Fill in the inode based on the ncp_entry_info structure. Used only for brand new inodes.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 */
224static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
225{
226 struct ncp_server *server = NCP_SERVER(inode);
227
228 NCP_FINFO(inode)->flags = 0;
229
230 ncp_update_attrs(inode, nwinfo);
231
232 DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
233
Miklos Szeredibfe86842011-10-28 14:13:29 +0200234 set_nlink(inode, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 inode->i_uid = server->m.uid;
236 inode->i_gid = server->m.gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
238 ncp_update_dates(inode, &nwinfo->i);
239 ncp_update_inode(inode, nwinfo);
240}
241
242#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800243static const struct inode_operations ncp_symlink_inode_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 .readlink = generic_readlink,
245 .follow_link = page_follow_link_light,
246 .put_link = page_put_link,
247 .setattr = ncp_notify_change,
248};
249#endif
250
251/*
252 * Get a new inode.
253 */
254struct inode *
255ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
256{
257 struct inode *inode;
258
259 if (info == NULL) {
260 printk(KERN_ERR "ncp_iget: info is NULL\n");
261 return NULL;
262 }
263
264 inode = new_inode(sb);
265 if (inode) {
266 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
267
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200268 inode->i_mapping->backing_dev_info = sb->s_bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 inode->i_ino = info->ino;
270 ncp_set_attr(inode, info);
271 if (S_ISREG(inode->i_mode)) {
272 inode->i_op = &ncp_file_inode_operations;
273 inode->i_fop = &ncp_file_operations;
274 } else if (S_ISDIR(inode->i_mode)) {
275 inode->i_op = &ncp_dir_inode_operations;
276 inode->i_fop = &ncp_dir_operations;
277#ifdef CONFIG_NCPFS_NFS_NS
278 } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
279 init_special_inode(inode, inode->i_mode,
280 new_decode_dev(info->i.nfs.rdev));
281#endif
282#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
283 } else if (S_ISLNK(inode->i_mode)) {
284 inode->i_op = &ncp_symlink_inode_operations;
285 inode->i_data.a_ops = &ncp_symlink_aops;
286#endif
287 } else {
288 make_bad_inode(inode);
289 }
290 insert_inode_hash(inode);
291 } else
292 printk(KERN_ERR "ncp_iget: iget failed!\n");
293 return inode;
294}
295
296static void
Al Viro94ee8492010-06-07 00:45:56 -0400297ncp_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298{
Mark Fashehfef26652005-09-09 13:01:31 -0700299 truncate_inode_pages(&inode->i_data, 0);
Jan Karadbd57682012-05-03 14:48:02 +0200300 clear_inode(inode);
Mark Fashehfef26652005-09-09 13:01:31 -0700301
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 if (S_ISDIR(inode->i_mode)) {
Al Viro94ee8492010-06-07 00:45:56 -0400303 DDPRINTK("ncp_evict_inode: put directory %ld\n", inode->i_ino);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 }
305
306 if (ncp_make_closed(inode) != 0) {
307 /* We can't do anything but complain. */
Al Viro94ee8492010-06-07 00:45:56 -0400308 printk(KERN_ERR "ncp_evict_inode: could not close\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310}
311
312static void ncp_stop_tasks(struct ncp_server *server) {
313 struct sock* sk = server->ncp_sock->sk;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200314
315 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 sk->sk_error_report = server->error_report;
317 sk->sk_data_ready = server->data_ready;
318 sk->sk_write_space = server->write_space;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200319 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 del_timer_sync(&server->timeout_tm);
Tejun Heo5d8e4bd2010-12-24 15:59:06 +0100321
Tejun Heo43829732012-08-20 14:51:24 -0700322 flush_work(&server->rcv.tq);
Tejun Heo5d8e4bd2010-12-24 15:59:06 +0100323 if (sk->sk_socket->type == SOCK_STREAM)
Tejun Heo43829732012-08-20 14:51:24 -0700324 flush_work(&server->tx.tq);
Tejun Heo5d8e4bd2010-12-24 15:59:06 +0100325 else
Tejun Heo43829732012-08-20 14:51:24 -0700326 flush_work(&server->timeout_tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327}
328
Al Viro34c80b12011-12-08 21:32:45 -0500329static int ncp_show_options(struct seq_file *seq, struct dentry *root)
Miklos Szeredi564cd132008-02-08 04:21:46 -0800330{
Al Viro34c80b12011-12-08 21:32:45 -0500331 struct ncp_server *server = NCP_SBP(root->d_sb);
Miklos Szeredi564cd132008-02-08 04:21:46 -0800332 unsigned int tmp;
333
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800334 if (!uid_eq(server->m.uid, GLOBAL_ROOT_UID))
335 seq_printf(seq, ",uid=%u",
336 from_kuid_munged(&init_user_ns, server->m.uid));
337 if (!gid_eq(server->m.gid, GLOBAL_ROOT_GID))
338 seq_printf(seq, ",gid=%u",
339 from_kgid_munged(&init_user_ns, server->m.gid));
340 if (!uid_eq(server->m.mounted_uid, GLOBAL_ROOT_UID))
341 seq_printf(seq, ",owner=%u",
342 from_kuid_munged(&init_user_ns, server->m.mounted_uid));
Miklos Szeredi564cd132008-02-08 04:21:46 -0800343 tmp = server->m.file_mode & S_IALLUGO;
344 if (tmp != NCP_DEFAULT_FILE_MODE)
345 seq_printf(seq, ",mode=0%o", tmp);
346 tmp = server->m.dir_mode & S_IALLUGO;
347 if (tmp != NCP_DEFAULT_DIR_MODE)
348 seq_printf(seq, ",dirmode=0%o", tmp);
349 if (server->m.time_out != NCP_DEFAULT_TIME_OUT * HZ / 100) {
350 tmp = server->m.time_out * 100 / HZ;
351 seq_printf(seq, ",timeout=%u", tmp);
352 }
353 if (server->m.retry_count != NCP_DEFAULT_RETRY_COUNT)
354 seq_printf(seq, ",retry=%u", server->m.retry_count);
355 if (server->m.flags != 0)
356 seq_printf(seq, ",flags=%lu", server->m.flags);
357 if (server->m.wdog_pid != NULL)
358 seq_printf(seq, ",wdogpid=%u", pid_vnr(server->m.wdog_pid));
359
360 return 0;
361}
362
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363static const struct ncp_option ncp_opts[] = {
364 { "uid", OPT_INT, 'u' },
365 { "gid", OPT_INT, 'g' },
366 { "owner", OPT_INT, 'o' },
367 { "mode", OPT_INT, 'm' },
368 { "dirmode", OPT_INT, 'd' },
369 { "timeout", OPT_INT, 't' },
370 { "retry", OPT_INT, 'r' },
371 { "flags", OPT_INT, 'f' },
372 { "wdogpid", OPT_INT, 'w' },
373 { "ncpfd", OPT_INT, 'n' },
374 { "infofd", OPT_INT, 'i' }, /* v5 */
375 { "version", OPT_INT, 'v' },
376 { NULL, 0, 0 } };
377
378static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
379 int optval;
380 char *optarg;
381 unsigned long optint;
382 int version = 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800383 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
385 data->flags = 0;
386 data->int_flags = 0;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800387 data->mounted_uid = GLOBAL_ROOT_UID;
Eric W. Biederman21542272006-12-13 00:35:11 -0800388 data->wdog_pid = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 data->ncp_fd = ~0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800390 data->time_out = NCP_DEFAULT_TIME_OUT;
391 data->retry_count = NCP_DEFAULT_RETRY_COUNT;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800392 data->uid = GLOBAL_ROOT_UID;
393 data->gid = GLOBAL_ROOT_GID;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800394 data->file_mode = NCP_DEFAULT_FILE_MODE;
395 data->dir_mode = NCP_DEFAULT_DIR_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 data->info_fd = -1;
397 data->mounted_vol[0] = 0;
398
399 while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
Eric W. Biederman1de24122006-12-13 00:35:13 -0800400 ret = optval;
401 if (ret < 0)
402 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 switch (optval) {
404 case 'u':
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800405 data->uid = make_kuid(current_user_ns(), optint);
406 if (!uid_valid(data->uid))
407 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 break;
409 case 'g':
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800410 data->gid = make_kgid(current_user_ns(), optint);
411 if (!gid_valid(data->gid))
412 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 break;
414 case 'o':
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800415 data->mounted_uid = make_kuid(current_user_ns(), optint);
416 if (!uid_valid(data->mounted_uid))
417 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 break;
419 case 'm':
420 data->file_mode = optint;
421 break;
422 case 'd':
423 data->dir_mode = optint;
424 break;
425 case 't':
426 data->time_out = optint;
427 break;
428 case 'r':
429 data->retry_count = optint;
430 break;
431 case 'f':
432 data->flags = optint;
433 break;
434 case 'w':
Eric W. Biederman21542272006-12-13 00:35:11 -0800435 data->wdog_pid = find_get_pid(optint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 break;
437 case 'n':
438 data->ncp_fd = optint;
439 break;
440 case 'i':
441 data->info_fd = optint;
442 break;
443 case 'v':
Eric W. Biederman1de24122006-12-13 00:35:13 -0800444 ret = -ECHRNG;
445 if (optint < NCP_MOUNT_VERSION_V4)
446 goto err;
447 if (optint > NCP_MOUNT_VERSION_V5)
448 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 version = optint;
450 break;
451
452 }
453 }
454 return 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800455err:
456 put_pid(data->wdog_pid);
457 data->wdog_pid = NULL;
458 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459}
460
461static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
462{
463 struct ncp_mount_data_kernel data;
464 struct ncp_server *server;
465 struct file *ncp_filp;
466 struct inode *root_inode;
467 struct inode *sock_inode;
468 struct socket *sock;
469 int error;
470 int default_bufsize;
471#ifdef CONFIG_NCPFS_PACKET_SIGNING
472 int options;
473#endif
474 struct ncp_entry_info finfo;
475
Andrew Morton2a5cac12011-05-24 17:13:42 -0700476 memset(&data, 0, sizeof(data));
Panagiotis Issarisf8314dc2006-09-27 01:49:37 -0700477 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 if (!server)
479 return -ENOMEM;
480 sb->s_fs_info = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481
482 error = -EFAULT;
483 if (raw_data == NULL)
484 goto out;
485 switch (*(int*)raw_data) {
486 case NCP_MOUNT_VERSION:
487 {
488 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
489
490 data.flags = md->flags;
491 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800492 data.mounted_uid = make_kuid(current_user_ns(), md->mounted_uid);
Eric W. Biederman21542272006-12-13 00:35:11 -0800493 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 data.ncp_fd = md->ncp_fd;
495 data.time_out = md->time_out;
496 data.retry_count = md->retry_count;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800497 data.uid = make_kuid(current_user_ns(), md->uid);
498 data.gid = make_kgid(current_user_ns(), md->gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 data.file_mode = md->file_mode;
500 data.dir_mode = md->dir_mode;
501 data.info_fd = -1;
502 memcpy(data.mounted_vol, md->mounted_vol,
503 NCP_VOLNAME_LEN+1);
504 }
505 break;
506 case NCP_MOUNT_VERSION_V4:
507 {
508 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
509
510 data.flags = md->flags;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800511 data.mounted_uid = make_kuid(current_user_ns(), md->mounted_uid);
Eric W. Biederman21542272006-12-13 00:35:11 -0800512 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 data.ncp_fd = md->ncp_fd;
514 data.time_out = md->time_out;
515 data.retry_count = md->retry_count;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800516 data.uid = make_kuid(current_user_ns(), md->uid);
517 data.gid = make_kgid(current_user_ns(), md->gid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 data.file_mode = md->file_mode;
519 data.dir_mode = md->dir_mode;
520 data.info_fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 }
522 break;
523 default:
524 error = -ECHRNG;
525 if (memcmp(raw_data, "vers", 4) == 0) {
526 error = ncp_parse_options(&data, raw_data);
527 }
528 if (error)
529 goto out;
530 break;
531 }
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800532 error = -EINVAL;
533 if (!uid_valid(data.mounted_uid) || !uid_valid(data.uid) ||
534 !gid_valid(data.gid))
535 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 error = -EBADF;
537 ncp_filp = fget(data.ncp_fd);
538 if (!ncp_filp)
539 goto out;
540 error = -ENOTSOCK;
Al Viro496ad9a2013-01-23 17:07:38 -0500541 sock_inode = file_inode(ncp_filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 if (!S_ISSOCK(sock_inode->i_mode))
543 goto out_fput;
544 sock = SOCKET_I(sock_inode);
545 if (!sock)
546 goto out_fput;
547
548 if (sock->type == SOCK_STREAM)
549 default_bufsize = 0xF000;
550 else
551 default_bufsize = 1024;
552
553 sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
554 sb->s_maxbytes = 0xFFFFFFFFU;
555 sb->s_blocksize = 1024; /* Eh... Is this correct? */
556 sb->s_blocksize_bits = 10;
557 sb->s_magic = NCP_SUPER_MAGIC;
558 sb->s_op = &ncp_sops;
Al Viro0378c402011-01-12 17:25:03 -0500559 sb->s_d_op = &ncp_dentry_operations;
Jens Axboef1970c72010-04-22 12:31:11 +0200560 sb->s_bdi = &server->bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
562 server = NCP_SBP(sb);
563 memset(server, 0, sizeof(*server));
564
Jens Axboef1970c72010-04-22 12:31:11 +0200565 error = bdi_setup_and_register(&server->bdi, "ncpfs", BDI_CAP_MAP_COPY);
566 if (error)
Djalal Harouni759c3612011-12-13 02:47:29 +0100567 goto out_fput;
Jens Axboef1970c72010-04-22 12:31:11 +0200568
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 server->ncp_filp = ncp_filp;
570 server->ncp_sock = sock;
571
572 if (data.info_fd != -1) {
573 struct socket *info_sock;
574
575 error = -EBADF;
576 server->info_filp = fget(data.info_fd);
577 if (!server->info_filp)
Djalal Harouni759c3612011-12-13 02:47:29 +0100578 goto out_bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 error = -ENOTSOCK;
Al Viro496ad9a2013-01-23 17:07:38 -0500580 sock_inode = file_inode(server->info_filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 if (!S_ISSOCK(sock_inode->i_mode))
582 goto out_fput2;
583 info_sock = SOCKET_I(sock_inode);
584 if (!info_sock)
585 goto out_fput2;
586 error = -EBADFD;
587 if (info_sock->type != SOCK_STREAM)
588 goto out_fput2;
589 server->info_sock = info_sock;
590 }
591
592/* server->lock = 0; */
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800593 mutex_init(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 server->packet = NULL;
595/* server->buffer_size = 0; */
596/* server->conn_status = 0; */
597/* server->root_dentry = NULL; */
598/* server->root_setuped = 0; */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200599 mutex_init(&server->root_setup_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600#ifdef CONFIG_NCPFS_PACKET_SIGNING
601/* server->sign_wanted = 0; */
602/* server->sign_active = 0; */
603#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200604 init_rwsem(&server->auth_rwsem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 server->auth.auth_type = NCP_AUTH_NONE;
606/* server->auth.object_name_len = 0; */
607/* server->auth.object_name = NULL; */
608/* server->auth.object_type = 0; */
609/* server->priv.len = 0; */
610/* server->priv.data = NULL; */
611
612 server->m = data;
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300613 /* Although anything producing this is buggy, it happens
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 now because of PATH_MAX changes.. */
615 if (server->m.time_out < 1) {
616 server->m.time_out = 10;
617 printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
618 }
619 server->m.time_out = server->m.time_out * HZ / 100;
620 server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
621 server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
622
623#ifdef CONFIG_NCPFS_NLS
624 /* load the default NLS charsets */
625 server->nls_vol = load_nls_default();
626 server->nls_io = load_nls_default();
627#endif /* CONFIG_NCPFS_NLS */
628
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200629 atomic_set(&server->dentry_ttl, 0); /* no caching */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630
631 INIT_LIST_HEAD(&server->tx.requests);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800632 mutex_init(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 server->tx.creq = NULL;
634 server->rcv.creq = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
636 init_timer(&server->timeout_tm);
637#undef NCP_PACKET_SIZE
638#define NCP_PACKET_SIZE 131072
639 error = -ENOMEM;
640 server->packet_size = NCP_PACKET_SIZE;
641 server->packet = vmalloc(NCP_PACKET_SIZE);
642 if (server->packet == NULL)
643 goto out_nls;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100644 server->txbuf = vmalloc(NCP_PACKET_SIZE);
645 if (server->txbuf == NULL)
646 goto out_packet;
647 server->rxbuf = vmalloc(NCP_PACKET_SIZE);
648 if (server->rxbuf == NULL)
649 goto out_txbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200651 lock_sock(sock->sk);
652 server->data_ready = sock->sk->sk_data_ready;
653 server->write_space = sock->sk->sk_write_space;
654 server->error_report = sock->sk->sk_error_report;
655 sock->sk->sk_user_data = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 sock->sk->sk_data_ready = ncp_tcp_data_ready;
657 sock->sk->sk_error_report = ncp_tcp_error_report;
658 if (sock->type == SOCK_STREAM) {
659 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
660 server->rcv.len = 10;
661 server->rcv.state = 0;
David Howellsc4028952006-11-22 14:57:56 +0000662 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
663 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 sock->sk->sk_write_space = ncp_tcp_write_space;
665 } else {
David Howellsc4028952006-11-22 14:57:56 +0000666 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
667 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 server->timeout_tm.data = (unsigned long)server;
669 server->timeout_tm.function = ncpdgram_timeout_call;
670 }
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200671 release_sock(sock->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672
673 ncp_lock_server(server);
674 error = ncp_connect(server);
675 ncp_unlock_server(server);
676 if (error < 0)
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100677 goto out_rxbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
679
680 error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */
681#ifdef CONFIG_NCPFS_PACKET_SIGNING
682 if (ncp_negotiate_size_and_options(server, default_bufsize,
683 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
684 {
685 if (options != NCP_DEFAULT_OPTIONS)
686 {
687 if (ncp_negotiate_size_and_options(server,
688 default_bufsize,
689 options & 2,
690 &(server->buffer_size), &options) != 0)
691
692 {
693 goto out_disconnect;
694 }
695 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200696 ncp_lock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 if (options & 2)
698 server->sign_wanted = 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200699 ncp_unlock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 }
701 else
702#endif /* CONFIG_NCPFS_PACKET_SIGNING */
703 if (ncp_negotiate_buffersize(server, default_bufsize,
704 &(server->buffer_size)) != 0)
705 goto out_disconnect;
706 DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
707
708 memset(&finfo, 0, sizeof(finfo));
709 finfo.i.attributes = aDIR;
710 finfo.i.dataStreamSize = 0; /* ignored */
711 finfo.i.dirEntNum = 0;
712 finfo.i.DosDirNum = 0;
713#ifdef CONFIG_NCPFS_SMALLDOS
714 finfo.i.NSCreator = NW_NS_DOS;
715#endif
716 finfo.volume = NCP_NUMBER_OF_VOLUMES;
717 /* set dates of mountpoint to Jan 1, 1986; 00:00 */
718 finfo.i.creationTime = finfo.i.modifyTime
719 = cpu_to_le16(0x0000);
720 finfo.i.creationDate = finfo.i.modifyDate
721 = finfo.i.lastAccessDate
722 = cpu_to_le16(0x0C21);
723 finfo.i.nameLen = 0;
724 finfo.i.entryName[0] = '\0';
725
726 finfo.opened = 0;
727 finfo.ino = 2; /* tradition */
728
729 server->name_space[finfo.volume] = NW_NS_DOS;
730
731 error = -ENOMEM;
732 root_inode = ncp_iget(sb, &finfo);
733 if (!root_inode)
734 goto out_disconnect;
735 DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
Al Viro48fde702012-01-08 22:15:13 -0500736 sb->s_root = d_make_root(root_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 if (!sb->s_root)
Al Viro48fde702012-01-08 22:15:13 -0500738 goto out_disconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 return 0;
740
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741out_disconnect:
742 ncp_lock_server(server);
743 ncp_disconnect(server);
744 ncp_unlock_server(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100745out_rxbuf:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 ncp_stop_tasks(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100747 vfree(server->rxbuf);
748out_txbuf:
749 vfree(server->txbuf);
750out_packet:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 vfree(server->packet);
752out_nls:
753#ifdef CONFIG_NCPFS_NLS
754 unload_nls(server->nls_io);
755 unload_nls(server->nls_vol);
756#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200757 mutex_destroy(&server->rcv.creq_mutex);
758 mutex_destroy(&server->root_setup_lock);
759 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760out_fput2:
761 if (server->info_filp)
762 fput(server->info_filp);
Jens Axboef1970c72010-04-22 12:31:11 +0200763out_bdi:
Djalal Harouni759c3612011-12-13 02:47:29 +0100764 bdi_destroy(&server->bdi);
765out_fput:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
767 *
Matthew Whitworthe956b4b2010-06-27 14:34:30 +0100768 * The previously used put_filp(ncp_filp); was bogus, since
769 * it doesn't perform proper unlocking.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 */
771 fput(ncp_filp);
772out:
Eric W. Biederman1de24122006-12-13 00:35:13 -0800773 put_pid(data.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 sb->s_fs_info = NULL;
775 kfree(server);
776 return error;
777}
778
779static void ncp_put_super(struct super_block *sb)
780{
781 struct ncp_server *server = NCP_SBP(sb);
782
783 ncp_lock_server(server);
784 ncp_disconnect(server);
785 ncp_unlock_server(server);
786
787 ncp_stop_tasks(server);
788
789#ifdef CONFIG_NCPFS_NLS
790 /* unload the NLS charsets */
Thomas Gleixner6d729e42009-08-16 21:05:08 +0000791 unload_nls(server->nls_vol);
792 unload_nls(server->nls_io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793#endif /* CONFIG_NCPFS_NLS */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200794 mutex_destroy(&server->rcv.creq_mutex);
795 mutex_destroy(&server->root_setup_lock);
796 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797
798 if (server->info_filp)
799 fput(server->info_filp);
800 fput(server->ncp_filp);
Eric W. Biederman21542272006-12-13 00:35:11 -0800801 kill_pid(server->m.wdog_pid, SIGTERM, 1);
802 put_pid(server->m.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803
Jens Axboef1970c72010-04-22 12:31:11 +0200804 bdi_destroy(&server->bdi);
Pekka Enberg44db77f2006-01-14 13:21:12 -0800805 kfree(server->priv.data);
806 kfree(server->auth.object_name);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100807 vfree(server->rxbuf);
808 vfree(server->txbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 vfree(server->packet);
810 sb->s_fs_info = NULL;
811 kfree(server);
812}
813
David Howells726c3342006-06-23 02:02:58 -0700814static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815{
816 struct dentry* d;
817 struct inode* i;
818 struct ncp_inode_info* ni;
819 struct ncp_server* s;
820 struct ncp_volume_info vi;
David Howells726c3342006-06-23 02:02:58 -0700821 struct super_block *sb = dentry->d_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 int err;
823 __u8 dh;
824
825 d = sb->s_root;
826 if (!d) {
827 goto dflt;
828 }
829 i = d->d_inode;
830 if (!i) {
831 goto dflt;
832 }
833 ni = NCP_FINFO(i);
834 if (!ni) {
835 goto dflt;
836 }
837 s = NCP_SBP(sb);
838 if (!s) {
839 goto dflt;
840 }
841 if (!s->m.mounted_vol[0]) {
842 goto dflt;
843 }
844
845 err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
846 if (err) {
847 goto dflt;
848 }
849 err = ncp_get_directory_info(s, dh, &vi);
850 ncp_dirhandle_free(s, dh);
851 if (err) {
852 goto dflt;
853 }
854 buf->f_type = NCP_SUPER_MAGIC;
855 buf->f_bsize = vi.sectors_per_block * 512;
856 buf->f_blocks = vi.total_blocks;
857 buf->f_bfree = vi.free_blocks;
858 buf->f_bavail = vi.free_blocks;
859 buf->f_files = vi.total_dir_entries;
860 buf->f_ffree = vi.available_dir_entries;
861 buf->f_namelen = 12;
862 return 0;
863
864 /* We cannot say how much disk space is left on a mounted
865 NetWare Server, because free space is distributed over
866 volumes, and the current user might have disk quotas. So
867 free space is not that simple to determine. Our decision
868 here is to err conservatively. */
869
870dflt:;
871 buf->f_type = NCP_SUPER_MAGIC;
872 buf->f_bsize = NCP_BLOCK_SIZE;
873 buf->f_blocks = 0;
874 buf->f_bfree = 0;
875 buf->f_bavail = 0;
876 buf->f_namelen = 12;
877 return 0;
878}
879
880int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
881{
882 struct inode *inode = dentry->d_inode;
883 int result = 0;
884 __le32 info_mask;
885 struct nw_modify_dos_info info;
886 struct ncp_server *server;
887
888 result = -EIO;
889
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 server = NCP_SERVER(inode);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200891 if (!server) /* How this could happen? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 goto out;
893
894 /* ageing the dentry to force validation */
895 ncp_age_dentry(server, dentry);
896
897 result = inode_change_ok(inode, attr);
898 if (result < 0)
899 goto out;
900
901 result = -EPERM;
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800902 if ((attr->ia_valid & ATTR_UID) && !uid_eq(attr->ia_uid, server->m.uid))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 goto out;
904
Eric W. Biederman1ac7fd82012-02-07 16:28:28 -0800905 if ((attr->ia_valid & ATTR_GID) && !gid_eq(attr->ia_gid, server->m.gid))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 goto out;
907
908 if (((attr->ia_valid & ATTR_MODE) &&
909 (attr->ia_mode &
910 ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
911 goto out;
912
913 info_mask = 0;
914 memset(&info, 0, sizeof(info));
915
916#if 1
917 if ((attr->ia_valid & ATTR_MODE) != 0)
918 {
919 umode_t newmode = attr->ia_mode;
920
921 info_mask |= DM_ATTRIBUTES;
922
923 if (S_ISDIR(inode->i_mode)) {
924 newmode &= server->m.dir_mode;
925 } else {
926#ifdef CONFIG_NCPFS_EXTRAS
927 if (server->m.flags & NCP_MOUNT_EXTRAS) {
928 /* any non-default execute bit set */
929 if (newmode & ~server->m.file_mode & S_IXUGO)
930 info.attributes |= aSHARED | aSYSTEM;
931 /* read for group/world and not in default file_mode */
932 else if (newmode & ~server->m.file_mode & S_IRUGO)
933 info.attributes |= aSHARED;
934 } else
935#endif
936 newmode &= server->m.file_mode;
937 }
938 if (newmode & S_IWUGO)
939 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
940 else
941 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
942
943#ifdef CONFIG_NCPFS_NFS_NS
944 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
945 result = ncp_modify_nfs_info(server,
946 NCP_FINFO(inode)->volNumber,
947 NCP_FINFO(inode)->dirEntNum,
948 attr->ia_mode, 0);
949 if (result != 0)
950 goto out;
951 info.attributes &= ~(aSHARED | aSYSTEM);
952 {
953 /* mark partial success */
954 struct iattr tmpattr;
955
956 tmpattr.ia_valid = ATTR_MODE;
957 tmpattr.ia_mode = attr->ia_mode;
958
Christoph Hellwig10257742010-06-04 11:30:02 +0200959 setattr_copy(inode, &tmpattr);
960 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 }
962 }
963#endif
964 }
965#endif
966
967 /* Do SIZE before attributes, otherwise mtime together with size does not work...
968 */
969 if ((attr->ia_valid & ATTR_SIZE) != 0) {
970 int written;
971
972 DPRINTK("ncpfs: trying to change size to %ld\n",
973 attr->ia_size);
974
975 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
976 result = -EACCES;
977 goto out;
978 }
979 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
980 attr->ia_size, 0, "", &written);
981
982 /* According to ndir, the changes only take effect after
983 closing the file */
984 ncp_inode_close(inode);
985 result = ncp_make_closed(inode);
986 if (result)
987 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +0200988
989 if (attr->ia_size != i_size_read(inode)) {
Marco Stornelli3e7a8062012-12-15 11:57:03 +0100990 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200991 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 }
993 }
994 if ((attr->ia_valid & ATTR_CTIME) != 0) {
995 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
996 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
997 &info.creationTime, &info.creationDate);
998 }
999 if ((attr->ia_valid & ATTR_MTIME) != 0) {
1000 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
1001 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
1002 &info.modifyTime, &info.modifyDate);
1003 }
1004 if ((attr->ia_valid & ATTR_ATIME) != 0) {
1005 __le16 dummy;
1006 info_mask |= (DM_LAST_ACCESS_DATE);
1007 ncp_date_unix2dos(attr->ia_atime.tv_sec,
1008 &dummy, &info.lastAccessDate);
1009 }
1010 if (info_mask != 0) {
1011 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
1012 inode, info_mask, &info);
1013 if (result != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
1015 /* NetWare seems not to allow this. I
1016 do not know why. So, just tell the
1017 user everything went fine. This is
1018 a terrible hack, but I do not know
1019 how to do this correctly. */
1020 result = 0;
1021 } else
1022 goto out;
1023 }
1024#ifdef CONFIG_NCPFS_STRONG
1025 if ((!result) && (info_mask & DM_ATTRIBUTES))
1026 NCP_FINFO(inode)->nwattr = info.attributes;
1027#endif
1028 }
Christoph Hellwig10257742010-06-04 11:30:02 +02001029 if (result)
1030 goto out;
1031
1032 setattr_copy(inode, attr);
1033 mark_inode_dirty(inode);
1034
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035out:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001036 if (result > 0)
1037 result = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 return result;
1039}
1040
Al Viro3c26ff62010-07-25 11:46:36 +04001041static struct dentry *ncp_mount(struct file_system_type *fs_type,
1042 int flags, const char *dev_name, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043{
Al Viro3c26ff62010-07-25 11:46:36 +04001044 return mount_nodev(fs_type, flags, data, ncp_fill_super);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045}
1046
1047static struct file_system_type ncp_fs_type = {
1048 .owner = THIS_MODULE,
1049 .name = "ncpfs",
Al Viro3c26ff62010-07-25 11:46:36 +04001050 .mount = ncp_mount,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 .kill_sb = kill_anon_super,
Miklos Szeredi564cd132008-02-08 04:21:46 -08001052 .fs_flags = FS_BINARY_MOUNTDATA,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053};
Eric W. Biederman7f78e032013-03-02 19:39:14 -08001054MODULE_ALIAS_FS("ncpfs");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055
1056static int __init init_ncp_fs(void)
1057{
1058 int err;
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001059 DPRINTK("ncpfs: init_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 err = init_inodecache();
1062 if (err)
1063 goto out1;
1064 err = register_filesystem(&ncp_fs_type);
1065 if (err)
1066 goto out;
1067 return 0;
1068out:
1069 destroy_inodecache();
1070out1:
1071 return err;
1072}
1073
1074static void __exit exit_ncp_fs(void)
1075{
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001076 DPRINTK("ncpfs: exit_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 unregister_filesystem(&ncp_fs_type);
1078 destroy_inodecache();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079}
1080
1081module_init(init_ncp_fs)
1082module_exit(exit_ncp_fs)
1083MODULE_LICENSE("GPL");