blob: 1acdad7fcec7cda8ca5aa9e88b92cce45b960c37 [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
334 if (server->m.uid != 0)
335 seq_printf(seq, ",uid=%u", server->m.uid);
336 if (server->m.gid != 0)
337 seq_printf(seq, ",gid=%u", server->m.gid);
338 if (server->m.mounted_uid != 0)
339 seq_printf(seq, ",owner=%u", server->m.mounted_uid);
340 tmp = server->m.file_mode & S_IALLUGO;
341 if (tmp != NCP_DEFAULT_FILE_MODE)
342 seq_printf(seq, ",mode=0%o", tmp);
343 tmp = server->m.dir_mode & S_IALLUGO;
344 if (tmp != NCP_DEFAULT_DIR_MODE)
345 seq_printf(seq, ",dirmode=0%o", tmp);
346 if (server->m.time_out != NCP_DEFAULT_TIME_OUT * HZ / 100) {
347 tmp = server->m.time_out * 100 / HZ;
348 seq_printf(seq, ",timeout=%u", tmp);
349 }
350 if (server->m.retry_count != NCP_DEFAULT_RETRY_COUNT)
351 seq_printf(seq, ",retry=%u", server->m.retry_count);
352 if (server->m.flags != 0)
353 seq_printf(seq, ",flags=%lu", server->m.flags);
354 if (server->m.wdog_pid != NULL)
355 seq_printf(seq, ",wdogpid=%u", pid_vnr(server->m.wdog_pid));
356
357 return 0;
358}
359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360static const struct ncp_option ncp_opts[] = {
361 { "uid", OPT_INT, 'u' },
362 { "gid", OPT_INT, 'g' },
363 { "owner", OPT_INT, 'o' },
364 { "mode", OPT_INT, 'm' },
365 { "dirmode", OPT_INT, 'd' },
366 { "timeout", OPT_INT, 't' },
367 { "retry", OPT_INT, 'r' },
368 { "flags", OPT_INT, 'f' },
369 { "wdogpid", OPT_INT, 'w' },
370 { "ncpfd", OPT_INT, 'n' },
371 { "infofd", OPT_INT, 'i' }, /* v5 */
372 { "version", OPT_INT, 'v' },
373 { NULL, 0, 0 } };
374
375static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
376 int optval;
377 char *optarg;
378 unsigned long optint;
379 int version = 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800380 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381
382 data->flags = 0;
383 data->int_flags = 0;
384 data->mounted_uid = 0;
Eric W. Biederman21542272006-12-13 00:35:11 -0800385 data->wdog_pid = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 data->ncp_fd = ~0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800387 data->time_out = NCP_DEFAULT_TIME_OUT;
388 data->retry_count = NCP_DEFAULT_RETRY_COUNT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 data->uid = 0;
390 data->gid = 0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800391 data->file_mode = NCP_DEFAULT_FILE_MODE;
392 data->dir_mode = NCP_DEFAULT_DIR_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 data->info_fd = -1;
394 data->mounted_vol[0] = 0;
395
396 while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
Eric W. Biederman1de24122006-12-13 00:35:13 -0800397 ret = optval;
398 if (ret < 0)
399 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 switch (optval) {
401 case 'u':
402 data->uid = optint;
403 break;
404 case 'g':
405 data->gid = optint;
406 break;
407 case 'o':
408 data->mounted_uid = optint;
409 break;
410 case 'm':
411 data->file_mode = optint;
412 break;
413 case 'd':
414 data->dir_mode = optint;
415 break;
416 case 't':
417 data->time_out = optint;
418 break;
419 case 'r':
420 data->retry_count = optint;
421 break;
422 case 'f':
423 data->flags = optint;
424 break;
425 case 'w':
Eric W. Biederman21542272006-12-13 00:35:11 -0800426 data->wdog_pid = find_get_pid(optint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 break;
428 case 'n':
429 data->ncp_fd = optint;
430 break;
431 case 'i':
432 data->info_fd = optint;
433 break;
434 case 'v':
Eric W. Biederman1de24122006-12-13 00:35:13 -0800435 ret = -ECHRNG;
436 if (optint < NCP_MOUNT_VERSION_V4)
437 goto err;
438 if (optint > NCP_MOUNT_VERSION_V5)
439 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 version = optint;
441 break;
442
443 }
444 }
445 return 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800446err:
447 put_pid(data->wdog_pid);
448 data->wdog_pid = NULL;
449 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450}
451
452static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
453{
454 struct ncp_mount_data_kernel data;
455 struct ncp_server *server;
456 struct file *ncp_filp;
457 struct inode *root_inode;
458 struct inode *sock_inode;
459 struct socket *sock;
460 int error;
461 int default_bufsize;
462#ifdef CONFIG_NCPFS_PACKET_SIGNING
463 int options;
464#endif
465 struct ncp_entry_info finfo;
466
Andrew Morton2a5cac12011-05-24 17:13:42 -0700467 memset(&data, 0, sizeof(data));
Panagiotis Issarisf8314dc2006-09-27 01:49:37 -0700468 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 if (!server)
470 return -ENOMEM;
471 sb->s_fs_info = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472
473 error = -EFAULT;
474 if (raw_data == NULL)
475 goto out;
476 switch (*(int*)raw_data) {
477 case NCP_MOUNT_VERSION:
478 {
479 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
480
481 data.flags = md->flags;
482 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
483 data.mounted_uid = md->mounted_uid;
Eric W. Biederman21542272006-12-13 00:35:11 -0800484 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 data.ncp_fd = md->ncp_fd;
486 data.time_out = md->time_out;
487 data.retry_count = md->retry_count;
488 data.uid = md->uid;
489 data.gid = md->gid;
490 data.file_mode = md->file_mode;
491 data.dir_mode = md->dir_mode;
492 data.info_fd = -1;
493 memcpy(data.mounted_vol, md->mounted_vol,
494 NCP_VOLNAME_LEN+1);
495 }
496 break;
497 case NCP_MOUNT_VERSION_V4:
498 {
499 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
500
501 data.flags = md->flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 data.mounted_uid = md->mounted_uid;
Eric W. Biederman21542272006-12-13 00:35:11 -0800503 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 data.ncp_fd = md->ncp_fd;
505 data.time_out = md->time_out;
506 data.retry_count = md->retry_count;
507 data.uid = md->uid;
508 data.gid = md->gid;
509 data.file_mode = md->file_mode;
510 data.dir_mode = md->dir_mode;
511 data.info_fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 }
513 break;
514 default:
515 error = -ECHRNG;
516 if (memcmp(raw_data, "vers", 4) == 0) {
517 error = ncp_parse_options(&data, raw_data);
518 }
519 if (error)
520 goto out;
521 break;
522 }
523 error = -EBADF;
524 ncp_filp = fget(data.ncp_fd);
525 if (!ncp_filp)
526 goto out;
527 error = -ENOTSOCK;
Josef Sipek92e5bae2006-12-08 02:37:22 -0800528 sock_inode = ncp_filp->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 if (!S_ISSOCK(sock_inode->i_mode))
530 goto out_fput;
531 sock = SOCKET_I(sock_inode);
532 if (!sock)
533 goto out_fput;
534
535 if (sock->type == SOCK_STREAM)
536 default_bufsize = 0xF000;
537 else
538 default_bufsize = 1024;
539
540 sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
541 sb->s_maxbytes = 0xFFFFFFFFU;
542 sb->s_blocksize = 1024; /* Eh... Is this correct? */
543 sb->s_blocksize_bits = 10;
544 sb->s_magic = NCP_SUPER_MAGIC;
545 sb->s_op = &ncp_sops;
Al Viro0378c402011-01-12 17:25:03 -0500546 sb->s_d_op = &ncp_dentry_operations;
Jens Axboef1970c72010-04-22 12:31:11 +0200547 sb->s_bdi = &server->bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
549 server = NCP_SBP(sb);
550 memset(server, 0, sizeof(*server));
551
Jens Axboef1970c72010-04-22 12:31:11 +0200552 error = bdi_setup_and_register(&server->bdi, "ncpfs", BDI_CAP_MAP_COPY);
553 if (error)
Djalal Harouni759c3612011-12-13 02:47:29 +0100554 goto out_fput;
Jens Axboef1970c72010-04-22 12:31:11 +0200555
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 server->ncp_filp = ncp_filp;
557 server->ncp_sock = sock;
558
559 if (data.info_fd != -1) {
560 struct socket *info_sock;
561
562 error = -EBADF;
563 server->info_filp = fget(data.info_fd);
564 if (!server->info_filp)
Djalal Harouni759c3612011-12-13 02:47:29 +0100565 goto out_bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 error = -ENOTSOCK;
Josef Sipek92e5bae2006-12-08 02:37:22 -0800567 sock_inode = server->info_filp->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 if (!S_ISSOCK(sock_inode->i_mode))
569 goto out_fput2;
570 info_sock = SOCKET_I(sock_inode);
571 if (!info_sock)
572 goto out_fput2;
573 error = -EBADFD;
574 if (info_sock->type != SOCK_STREAM)
575 goto out_fput2;
576 server->info_sock = info_sock;
577 }
578
579/* server->lock = 0; */
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800580 mutex_init(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 server->packet = NULL;
582/* server->buffer_size = 0; */
583/* server->conn_status = 0; */
584/* server->root_dentry = NULL; */
585/* server->root_setuped = 0; */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200586 mutex_init(&server->root_setup_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587#ifdef CONFIG_NCPFS_PACKET_SIGNING
588/* server->sign_wanted = 0; */
589/* server->sign_active = 0; */
590#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200591 init_rwsem(&server->auth_rwsem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 server->auth.auth_type = NCP_AUTH_NONE;
593/* server->auth.object_name_len = 0; */
594/* server->auth.object_name = NULL; */
595/* server->auth.object_type = 0; */
596/* server->priv.len = 0; */
597/* server->priv.data = NULL; */
598
599 server->m = data;
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300600 /* Although anything producing this is buggy, it happens
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 now because of PATH_MAX changes.. */
602 if (server->m.time_out < 1) {
603 server->m.time_out = 10;
604 printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
605 }
606 server->m.time_out = server->m.time_out * HZ / 100;
607 server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
608 server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
609
610#ifdef CONFIG_NCPFS_NLS
611 /* load the default NLS charsets */
612 server->nls_vol = load_nls_default();
613 server->nls_io = load_nls_default();
614#endif /* CONFIG_NCPFS_NLS */
615
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200616 atomic_set(&server->dentry_ttl, 0); /* no caching */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
618 INIT_LIST_HEAD(&server->tx.requests);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800619 mutex_init(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 server->tx.creq = NULL;
621 server->rcv.creq = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622
623 init_timer(&server->timeout_tm);
624#undef NCP_PACKET_SIZE
625#define NCP_PACKET_SIZE 131072
626 error = -ENOMEM;
627 server->packet_size = NCP_PACKET_SIZE;
628 server->packet = vmalloc(NCP_PACKET_SIZE);
629 if (server->packet == NULL)
630 goto out_nls;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100631 server->txbuf = vmalloc(NCP_PACKET_SIZE);
632 if (server->txbuf == NULL)
633 goto out_packet;
634 server->rxbuf = vmalloc(NCP_PACKET_SIZE);
635 if (server->rxbuf == NULL)
636 goto out_txbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200638 lock_sock(sock->sk);
639 server->data_ready = sock->sk->sk_data_ready;
640 server->write_space = sock->sk->sk_write_space;
641 server->error_report = sock->sk->sk_error_report;
642 sock->sk->sk_user_data = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 sock->sk->sk_data_ready = ncp_tcp_data_ready;
644 sock->sk->sk_error_report = ncp_tcp_error_report;
645 if (sock->type == SOCK_STREAM) {
646 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
647 server->rcv.len = 10;
648 server->rcv.state = 0;
David Howellsc4028952006-11-22 14:57:56 +0000649 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
650 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 sock->sk->sk_write_space = ncp_tcp_write_space;
652 } else {
David Howellsc4028952006-11-22 14:57:56 +0000653 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
654 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 server->timeout_tm.data = (unsigned long)server;
656 server->timeout_tm.function = ncpdgram_timeout_call;
657 }
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200658 release_sock(sock->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
660 ncp_lock_server(server);
661 error = ncp_connect(server);
662 ncp_unlock_server(server);
663 if (error < 0)
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100664 goto out_rxbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
666
667 error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */
668#ifdef CONFIG_NCPFS_PACKET_SIGNING
669 if (ncp_negotiate_size_and_options(server, default_bufsize,
670 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
671 {
672 if (options != NCP_DEFAULT_OPTIONS)
673 {
674 if (ncp_negotiate_size_and_options(server,
675 default_bufsize,
676 options & 2,
677 &(server->buffer_size), &options) != 0)
678
679 {
680 goto out_disconnect;
681 }
682 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200683 ncp_lock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 if (options & 2)
685 server->sign_wanted = 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200686 ncp_unlock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 }
688 else
689#endif /* CONFIG_NCPFS_PACKET_SIGNING */
690 if (ncp_negotiate_buffersize(server, default_bufsize,
691 &(server->buffer_size)) != 0)
692 goto out_disconnect;
693 DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
694
695 memset(&finfo, 0, sizeof(finfo));
696 finfo.i.attributes = aDIR;
697 finfo.i.dataStreamSize = 0; /* ignored */
698 finfo.i.dirEntNum = 0;
699 finfo.i.DosDirNum = 0;
700#ifdef CONFIG_NCPFS_SMALLDOS
701 finfo.i.NSCreator = NW_NS_DOS;
702#endif
703 finfo.volume = NCP_NUMBER_OF_VOLUMES;
704 /* set dates of mountpoint to Jan 1, 1986; 00:00 */
705 finfo.i.creationTime = finfo.i.modifyTime
706 = cpu_to_le16(0x0000);
707 finfo.i.creationDate = finfo.i.modifyDate
708 = finfo.i.lastAccessDate
709 = cpu_to_le16(0x0C21);
710 finfo.i.nameLen = 0;
711 finfo.i.entryName[0] = '\0';
712
713 finfo.opened = 0;
714 finfo.ino = 2; /* tradition */
715
716 server->name_space[finfo.volume] = NW_NS_DOS;
717
718 error = -ENOMEM;
719 root_inode = ncp_iget(sb, &finfo);
720 if (!root_inode)
721 goto out_disconnect;
722 DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
Al Viro48fde702012-01-08 22:15:13 -0500723 sb->s_root = d_make_root(root_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 if (!sb->s_root)
Al Viro48fde702012-01-08 22:15:13 -0500725 goto out_disconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 return 0;
727
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728out_disconnect:
729 ncp_lock_server(server);
730 ncp_disconnect(server);
731 ncp_unlock_server(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100732out_rxbuf:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 ncp_stop_tasks(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100734 vfree(server->rxbuf);
735out_txbuf:
736 vfree(server->txbuf);
737out_packet:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 vfree(server->packet);
739out_nls:
740#ifdef CONFIG_NCPFS_NLS
741 unload_nls(server->nls_io);
742 unload_nls(server->nls_vol);
743#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200744 mutex_destroy(&server->rcv.creq_mutex);
745 mutex_destroy(&server->root_setup_lock);
746 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747out_fput2:
748 if (server->info_filp)
749 fput(server->info_filp);
Jens Axboef1970c72010-04-22 12:31:11 +0200750out_bdi:
Djalal Harouni759c3612011-12-13 02:47:29 +0100751 bdi_destroy(&server->bdi);
752out_fput:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
754 *
Matthew Whitworthe956b4b2010-06-27 14:34:30 +0100755 * The previously used put_filp(ncp_filp); was bogus, since
756 * it doesn't perform proper unlocking.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 */
758 fput(ncp_filp);
759out:
Eric W. Biederman1de24122006-12-13 00:35:13 -0800760 put_pid(data.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 sb->s_fs_info = NULL;
762 kfree(server);
763 return error;
764}
765
766static void ncp_put_super(struct super_block *sb)
767{
768 struct ncp_server *server = NCP_SBP(sb);
769
770 ncp_lock_server(server);
771 ncp_disconnect(server);
772 ncp_unlock_server(server);
773
774 ncp_stop_tasks(server);
775
776#ifdef CONFIG_NCPFS_NLS
777 /* unload the NLS charsets */
Thomas Gleixner6d729e42009-08-16 21:05:08 +0000778 unload_nls(server->nls_vol);
779 unload_nls(server->nls_io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780#endif /* CONFIG_NCPFS_NLS */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200781 mutex_destroy(&server->rcv.creq_mutex);
782 mutex_destroy(&server->root_setup_lock);
783 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
785 if (server->info_filp)
786 fput(server->info_filp);
787 fput(server->ncp_filp);
Eric W. Biederman21542272006-12-13 00:35:11 -0800788 kill_pid(server->m.wdog_pid, SIGTERM, 1);
789 put_pid(server->m.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790
Jens Axboef1970c72010-04-22 12:31:11 +0200791 bdi_destroy(&server->bdi);
Pekka Enberg44db77f2006-01-14 13:21:12 -0800792 kfree(server->priv.data);
793 kfree(server->auth.object_name);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100794 vfree(server->rxbuf);
795 vfree(server->txbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 vfree(server->packet);
797 sb->s_fs_info = NULL;
798 kfree(server);
799}
800
David Howells726c3342006-06-23 02:02:58 -0700801static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802{
803 struct dentry* d;
804 struct inode* i;
805 struct ncp_inode_info* ni;
806 struct ncp_server* s;
807 struct ncp_volume_info vi;
David Howells726c3342006-06-23 02:02:58 -0700808 struct super_block *sb = dentry->d_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 int err;
810 __u8 dh;
811
812 d = sb->s_root;
813 if (!d) {
814 goto dflt;
815 }
816 i = d->d_inode;
817 if (!i) {
818 goto dflt;
819 }
820 ni = NCP_FINFO(i);
821 if (!ni) {
822 goto dflt;
823 }
824 s = NCP_SBP(sb);
825 if (!s) {
826 goto dflt;
827 }
828 if (!s->m.mounted_vol[0]) {
829 goto dflt;
830 }
831
832 err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
833 if (err) {
834 goto dflt;
835 }
836 err = ncp_get_directory_info(s, dh, &vi);
837 ncp_dirhandle_free(s, dh);
838 if (err) {
839 goto dflt;
840 }
841 buf->f_type = NCP_SUPER_MAGIC;
842 buf->f_bsize = vi.sectors_per_block * 512;
843 buf->f_blocks = vi.total_blocks;
844 buf->f_bfree = vi.free_blocks;
845 buf->f_bavail = vi.free_blocks;
846 buf->f_files = vi.total_dir_entries;
847 buf->f_ffree = vi.available_dir_entries;
848 buf->f_namelen = 12;
849 return 0;
850
851 /* We cannot say how much disk space is left on a mounted
852 NetWare Server, because free space is distributed over
853 volumes, and the current user might have disk quotas. So
854 free space is not that simple to determine. Our decision
855 here is to err conservatively. */
856
857dflt:;
858 buf->f_type = NCP_SUPER_MAGIC;
859 buf->f_bsize = NCP_BLOCK_SIZE;
860 buf->f_blocks = 0;
861 buf->f_bfree = 0;
862 buf->f_bavail = 0;
863 buf->f_namelen = 12;
864 return 0;
865}
866
867int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
868{
869 struct inode *inode = dentry->d_inode;
870 int result = 0;
871 __le32 info_mask;
872 struct nw_modify_dos_info info;
873 struct ncp_server *server;
874
875 result = -EIO;
876
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 server = NCP_SERVER(inode);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200878 if (!server) /* How this could happen? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 goto out;
880
881 /* ageing the dentry to force validation */
882 ncp_age_dentry(server, dentry);
883
884 result = inode_change_ok(inode, attr);
885 if (result < 0)
886 goto out;
887
888 result = -EPERM;
889 if (((attr->ia_valid & ATTR_UID) &&
890 (attr->ia_uid != server->m.uid)))
891 goto out;
892
893 if (((attr->ia_valid & ATTR_GID) &&
894 (attr->ia_gid != server->m.gid)))
895 goto out;
896
897 if (((attr->ia_valid & ATTR_MODE) &&
898 (attr->ia_mode &
899 ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
900 goto out;
901
902 info_mask = 0;
903 memset(&info, 0, sizeof(info));
904
905#if 1
906 if ((attr->ia_valid & ATTR_MODE) != 0)
907 {
908 umode_t newmode = attr->ia_mode;
909
910 info_mask |= DM_ATTRIBUTES;
911
912 if (S_ISDIR(inode->i_mode)) {
913 newmode &= server->m.dir_mode;
914 } else {
915#ifdef CONFIG_NCPFS_EXTRAS
916 if (server->m.flags & NCP_MOUNT_EXTRAS) {
917 /* any non-default execute bit set */
918 if (newmode & ~server->m.file_mode & S_IXUGO)
919 info.attributes |= aSHARED | aSYSTEM;
920 /* read for group/world and not in default file_mode */
921 else if (newmode & ~server->m.file_mode & S_IRUGO)
922 info.attributes |= aSHARED;
923 } else
924#endif
925 newmode &= server->m.file_mode;
926 }
927 if (newmode & S_IWUGO)
928 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
929 else
930 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
931
932#ifdef CONFIG_NCPFS_NFS_NS
933 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
934 result = ncp_modify_nfs_info(server,
935 NCP_FINFO(inode)->volNumber,
936 NCP_FINFO(inode)->dirEntNum,
937 attr->ia_mode, 0);
938 if (result != 0)
939 goto out;
940 info.attributes &= ~(aSHARED | aSYSTEM);
941 {
942 /* mark partial success */
943 struct iattr tmpattr;
944
945 tmpattr.ia_valid = ATTR_MODE;
946 tmpattr.ia_mode = attr->ia_mode;
947
Christoph Hellwig10257742010-06-04 11:30:02 +0200948 setattr_copy(inode, &tmpattr);
949 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 }
951 }
952#endif
953 }
954#endif
955
956 /* Do SIZE before attributes, otherwise mtime together with size does not work...
957 */
958 if ((attr->ia_valid & ATTR_SIZE) != 0) {
959 int written;
960
961 DPRINTK("ncpfs: trying to change size to %ld\n",
962 attr->ia_size);
963
964 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
965 result = -EACCES;
966 goto out;
967 }
968 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
969 attr->ia_size, 0, "", &written);
970
971 /* According to ndir, the changes only take effect after
972 closing the file */
973 ncp_inode_close(inode);
974 result = ncp_make_closed(inode);
975 if (result)
976 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +0200977
978 if (attr->ia_size != i_size_read(inode)) {
Marco Stornelli3e7a8062012-12-15 11:57:03 +0100979 truncate_setsize(inode, attr->ia_size);
Christoph Hellwig10257742010-06-04 11:30:02 +0200980 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 }
982 }
983 if ((attr->ia_valid & ATTR_CTIME) != 0) {
984 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
985 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
986 &info.creationTime, &info.creationDate);
987 }
988 if ((attr->ia_valid & ATTR_MTIME) != 0) {
989 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
990 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
991 &info.modifyTime, &info.modifyDate);
992 }
993 if ((attr->ia_valid & ATTR_ATIME) != 0) {
994 __le16 dummy;
995 info_mask |= (DM_LAST_ACCESS_DATE);
996 ncp_date_unix2dos(attr->ia_atime.tv_sec,
997 &dummy, &info.lastAccessDate);
998 }
999 if (info_mask != 0) {
1000 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
1001 inode, info_mask, &info);
1002 if (result != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
1004 /* NetWare seems not to allow this. I
1005 do not know why. So, just tell the
1006 user everything went fine. This is
1007 a terrible hack, but I do not know
1008 how to do this correctly. */
1009 result = 0;
1010 } else
1011 goto out;
1012 }
1013#ifdef CONFIG_NCPFS_STRONG
1014 if ((!result) && (info_mask & DM_ATTRIBUTES))
1015 NCP_FINFO(inode)->nwattr = info.attributes;
1016#endif
1017 }
Christoph Hellwig10257742010-06-04 11:30:02 +02001018 if (result)
1019 goto out;
1020
1021 setattr_copy(inode, attr);
1022 mark_inode_dirty(inode);
1023
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024out:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001025 if (result > 0)
1026 result = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 return result;
1028}
1029
Al Viro3c26ff62010-07-25 11:46:36 +04001030static struct dentry *ncp_mount(struct file_system_type *fs_type,
1031 int flags, const char *dev_name, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032{
Al Viro3c26ff62010-07-25 11:46:36 +04001033 return mount_nodev(fs_type, flags, data, ncp_fill_super);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034}
1035
1036static struct file_system_type ncp_fs_type = {
1037 .owner = THIS_MODULE,
1038 .name = "ncpfs",
Al Viro3c26ff62010-07-25 11:46:36 +04001039 .mount = ncp_mount,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 .kill_sb = kill_anon_super,
Miklos Szeredi564cd132008-02-08 04:21:46 -08001041 .fs_flags = FS_BINARY_MOUNTDATA,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042};
1043
1044static int __init init_ncp_fs(void)
1045{
1046 int err;
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001047 DPRINTK("ncpfs: init_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 err = init_inodecache();
1050 if (err)
1051 goto out1;
1052 err = register_filesystem(&ncp_fs_type);
1053 if (err)
1054 goto out;
1055 return 0;
1056out:
1057 destroy_inodecache();
1058out1:
1059 return err;
1060}
1061
1062static void __exit exit_ncp_fs(void)
1063{
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001064 DPRINTK("ncpfs: exit_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 unregister_filesystem(&ncp_fs_type);
1066 destroy_inodecache();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067}
1068
1069module_init(init_ncp_fs)
1070module_exit(exit_ncp_fs)
1071MODULE_LICENSE("GPL");