blob: cbd1a61c110a38ca7a3e1d1e2de8b237e810b92e [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
14#include <asm/system.h>
15#include <asm/uaccess.h>
16#include <asm/byteorder.h>
17
18#include <linux/time.h>
19#include <linux/kernel.h>
20#include <linux/mm.h>
21#include <linux/string.h>
22#include <linux/stat.h>
23#include <linux/errno.h>
24#include <linux/file.h>
25#include <linux/fcntl.h>
26#include <linux/slab.h>
27#include <linux/vmalloc.h>
28#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/vfs.h>
Miklos Szeredi564cd132008-02-08 04:21:46 -080030#include <linux/mount.h>
31#include <linux/seq_file.h>
Nick Piggin34286d62011-01-07 17:49:57 +110032#include <linux/namei.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <net/sock.h>
35
Al Viro32c419d2011-01-12 17:37:47 -050036#include "ncp_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include "getopt.h"
38
Miklos Szeredi564cd132008-02-08 04:21:46 -080039#define NCP_DEFAULT_FILE_MODE 0600
40#define NCP_DEFAULT_DIR_MODE 0700
41#define NCP_DEFAULT_TIME_OUT 10
42#define NCP_DEFAULT_RETRY_COUNT 20
43
Al Viro94ee8492010-06-07 00:45:56 -040044static void ncp_evict_inode(struct inode *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070045static void ncp_put_super(struct super_block *);
David Howells726c3342006-06-23 02:02:58 -070046static int ncp_statfs(struct dentry *, struct kstatfs *);
Miklos Szeredi564cd132008-02-08 04:21:46 -080047static int ncp_show_options(struct seq_file *, struct vfsmount *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
Christoph Lametere18b8902006-12-06 20:33:20 -080049static struct kmem_cache * ncp_inode_cachep;
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
51static struct inode *ncp_alloc_inode(struct super_block *sb)
52{
53 struct ncp_inode_info *ei;
Christoph Lametere94b1762006-12-06 20:33:17 -080054 ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070055 if (!ei)
56 return NULL;
57 return &ei->vfs_inode;
58}
59
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +110060static void ncp_i_callback(struct rcu_head *head)
61{
62 struct inode *inode = container_of(head, struct inode, i_rcu);
63 INIT_LIST_HEAD(&inode->i_dentry);
64 kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
65}
66
Linus Torvalds1da177e2005-04-16 15:20:36 -070067static void ncp_destroy_inode(struct inode *inode)
68{
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +110069 call_rcu(&inode->i_rcu, ncp_i_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -070070}
71
Alexey Dobriyan51cc5062008-07-25 19:45:34 -070072static void init_once(void *foo)
Linus Torvalds1da177e2005-04-16 15:20:36 -070073{
74 struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
75
Christoph Lametera35afb82007-05-16 22:10:57 -070076 mutex_init(&ei->open_mutex);
77 inode_init_once(&ei->vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078}
Paul Mundt20c2df82007-07-20 10:11:58 +090079
Linus Torvalds1da177e2005-04-16 15:20:36 -070080static int init_inodecache(void)
81{
82 ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
83 sizeof(struct ncp_inode_info),
Paul Jacksonfffb60f2006-03-24 03:16:06 -080084 0, (SLAB_RECLAIM_ACCOUNT|
85 SLAB_MEM_SPREAD),
Paul Mundt20c2df82007-07-20 10:11:58 +090086 init_once);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 if (ncp_inode_cachep == NULL)
88 return -ENOMEM;
89 return 0;
90}
91
92static void destroy_inodecache(void)
93{
Alexey Dobriyan1a1d92c2006-09-27 01:49:40 -070094 kmem_cache_destroy(ncp_inode_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -070095}
96
97static int ncp_remount(struct super_block *sb, int *flags, char* data)
98{
99 *flags |= MS_NODIRATIME;
100 return 0;
101}
102
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800103static const struct super_operations ncp_sops =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104{
105 .alloc_inode = ncp_alloc_inode,
106 .destroy_inode = ncp_destroy_inode,
107 .drop_inode = generic_delete_inode,
Al Viro94ee8492010-06-07 00:45:56 -0400108 .evict_inode = ncp_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 .put_super = ncp_put_super,
110 .statfs = ncp_statfs,
111 .remount_fs = ncp_remount,
Miklos Szeredi564cd132008-02-08 04:21:46 -0800112 .show_options = ncp_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113};
114
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115/*
116 * Fill in the ncpfs-specific information in the inode.
117 */
118static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
119{
120 NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
121 NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
122 NCP_FINFO(inode)->volNumber = nwinfo->volume;
123}
124
125void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
126{
127 ncp_update_dirent(inode, nwinfo);
128 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
129 NCP_FINFO(inode)->access = nwinfo->access;
130 memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
131 sizeof(nwinfo->file_handle));
132 DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
133 nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
134 NCP_FINFO(inode)->dirEntNum);
135}
136
137static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
138{
139 /* NFS namespace mode overrides others if it's set. */
140 DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n",
141 nwi->entryName, nwi->nfs.mode);
142 if (nwi->nfs.mode) {
143 /* XXX Security? */
144 inode->i_mode = nwi->nfs.mode;
145 }
146
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200147 inode->i_blocks = (i_size_read(inode) + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
149 inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate);
150 inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate);
151 inode->i_atime.tv_sec = ncp_date_dos2unix(0, nwi->lastAccessDate);
152 inode->i_atime.tv_nsec = 0;
153 inode->i_mtime.tv_nsec = 0;
154 inode->i_ctime.tv_nsec = 0;
155}
156
157static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
158{
159 struct nw_info_struct *nwi = &nwinfo->i;
160 struct ncp_server *server = NCP_SERVER(inode);
161
162 if (nwi->attributes & aDIR) {
163 inode->i_mode = server->m.dir_mode;
164 /* for directories dataStreamSize seems to be some
165 Object ID ??? */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200166 i_size_write(inode, NCP_BLOCK_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 } else {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200168 u32 size;
169
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 inode->i_mode = server->m.file_mode;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200171 size = le32_to_cpu(nwi->dataStreamSize);
172 i_size_write(inode, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173#ifdef CONFIG_NCPFS_EXTRAS
174 if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS))
175 && (nwi->attributes & aSHARED)) {
176 switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
177 case aHIDDEN:
178 if (server->m.flags & NCP_MOUNT_SYMLINKS) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200179 if (/* (size >= NCP_MIN_SYMLINK_SIZE)
180 && */ (size <= NCP_MAX_SYMLINK_SIZE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
182 NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
183 break;
184 }
185 }
186 /* FALLTHROUGH */
187 case 0:
188 if (server->m.flags & NCP_MOUNT_EXTRAS)
189 inode->i_mode |= S_IRUGO;
190 break;
191 case aSYSTEM:
192 if (server->m.flags & NCP_MOUNT_EXTRAS)
193 inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO;
194 break;
195 /* case aSYSTEM|aHIDDEN: */
196 default:
197 /* reserved combination */
198 break;
199 }
200 }
201#endif
202 }
203 if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
204}
205
206void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
207{
208 NCP_FINFO(inode)->flags = 0;
209 if (!atomic_read(&NCP_FINFO(inode)->opened)) {
210 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
211 ncp_update_attrs(inode, nwinfo);
212 }
213
214 ncp_update_dates(inode, &nwinfo->i);
215 ncp_update_dirent(inode, nwinfo);
216}
217
218/*
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200219 * Fill in the inode based on the ncp_entry_info structure. Used only for brand new inodes.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 */
221static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
222{
223 struct ncp_server *server = NCP_SERVER(inode);
224
225 NCP_FINFO(inode)->flags = 0;
226
227 ncp_update_attrs(inode, nwinfo);
228
229 DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
230
Miklos Szeredibfe86842011-10-28 14:13:29 +0200231 set_nlink(inode, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 inode->i_uid = server->m.uid;
233 inode->i_gid = server->m.gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
235 ncp_update_dates(inode, &nwinfo->i);
236 ncp_update_inode(inode, nwinfo);
237}
238
239#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800240static const struct inode_operations ncp_symlink_inode_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 .readlink = generic_readlink,
242 .follow_link = page_follow_link_light,
243 .put_link = page_put_link,
244 .setattr = ncp_notify_change,
245};
246#endif
247
248/*
249 * Get a new inode.
250 */
251struct inode *
252ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
253{
254 struct inode *inode;
255
256 if (info == NULL) {
257 printk(KERN_ERR "ncp_iget: info is NULL\n");
258 return NULL;
259 }
260
261 inode = new_inode(sb);
262 if (inode) {
263 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
264
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200265 inode->i_mapping->backing_dev_info = sb->s_bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 inode->i_ino = info->ino;
267 ncp_set_attr(inode, info);
268 if (S_ISREG(inode->i_mode)) {
269 inode->i_op = &ncp_file_inode_operations;
270 inode->i_fop = &ncp_file_operations;
271 } else if (S_ISDIR(inode->i_mode)) {
272 inode->i_op = &ncp_dir_inode_operations;
273 inode->i_fop = &ncp_dir_operations;
274#ifdef CONFIG_NCPFS_NFS_NS
275 } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
276 init_special_inode(inode, inode->i_mode,
277 new_decode_dev(info->i.nfs.rdev));
278#endif
279#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
280 } else if (S_ISLNK(inode->i_mode)) {
281 inode->i_op = &ncp_symlink_inode_operations;
282 inode->i_data.a_ops = &ncp_symlink_aops;
283#endif
284 } else {
285 make_bad_inode(inode);
286 }
287 insert_inode_hash(inode);
288 } else
289 printk(KERN_ERR "ncp_iget: iget failed!\n");
290 return inode;
291}
292
293static void
Al Viro94ee8492010-06-07 00:45:56 -0400294ncp_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295{
Mark Fashehfef26652005-09-09 13:01:31 -0700296 truncate_inode_pages(&inode->i_data, 0);
Al Viro94ee8492010-06-07 00:45:56 -0400297 end_writeback(inode);
Mark Fashehfef26652005-09-09 13:01:31 -0700298
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 if (S_ISDIR(inode->i_mode)) {
Al Viro94ee8492010-06-07 00:45:56 -0400300 DDPRINTK("ncp_evict_inode: put directory %ld\n", inode->i_ino);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 }
302
303 if (ncp_make_closed(inode) != 0) {
304 /* We can't do anything but complain. */
Al Viro94ee8492010-06-07 00:45:56 -0400305 printk(KERN_ERR "ncp_evict_inode: could not close\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307}
308
309static void ncp_stop_tasks(struct ncp_server *server) {
310 struct sock* sk = server->ncp_sock->sk;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200311
312 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 sk->sk_error_report = server->error_report;
314 sk->sk_data_ready = server->data_ready;
315 sk->sk_write_space = server->write_space;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200316 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 del_timer_sync(&server->timeout_tm);
Tejun Heo5d8e4bd2010-12-24 15:59:06 +0100318
319 flush_work_sync(&server->rcv.tq);
320 if (sk->sk_socket->type == SOCK_STREAM)
321 flush_work_sync(&server->tx.tq);
322 else
323 flush_work_sync(&server->timeout_tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324}
325
Miklos Szeredi564cd132008-02-08 04:21:46 -0800326static int ncp_show_options(struct seq_file *seq, struct vfsmount *mnt)
327{
328 struct ncp_server *server = NCP_SBP(mnt->mnt_sb);
329 unsigned int tmp;
330
331 if (server->m.uid != 0)
332 seq_printf(seq, ",uid=%u", server->m.uid);
333 if (server->m.gid != 0)
334 seq_printf(seq, ",gid=%u", server->m.gid);
335 if (server->m.mounted_uid != 0)
336 seq_printf(seq, ",owner=%u", server->m.mounted_uid);
337 tmp = server->m.file_mode & S_IALLUGO;
338 if (tmp != NCP_DEFAULT_FILE_MODE)
339 seq_printf(seq, ",mode=0%o", tmp);
340 tmp = server->m.dir_mode & S_IALLUGO;
341 if (tmp != NCP_DEFAULT_DIR_MODE)
342 seq_printf(seq, ",dirmode=0%o", tmp);
343 if (server->m.time_out != NCP_DEFAULT_TIME_OUT * HZ / 100) {
344 tmp = server->m.time_out * 100 / HZ;
345 seq_printf(seq, ",timeout=%u", tmp);
346 }
347 if (server->m.retry_count != NCP_DEFAULT_RETRY_COUNT)
348 seq_printf(seq, ",retry=%u", server->m.retry_count);
349 if (server->m.flags != 0)
350 seq_printf(seq, ",flags=%lu", server->m.flags);
351 if (server->m.wdog_pid != NULL)
352 seq_printf(seq, ",wdogpid=%u", pid_vnr(server->m.wdog_pid));
353
354 return 0;
355}
356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357static const struct ncp_option ncp_opts[] = {
358 { "uid", OPT_INT, 'u' },
359 { "gid", OPT_INT, 'g' },
360 { "owner", OPT_INT, 'o' },
361 { "mode", OPT_INT, 'm' },
362 { "dirmode", OPT_INT, 'd' },
363 { "timeout", OPT_INT, 't' },
364 { "retry", OPT_INT, 'r' },
365 { "flags", OPT_INT, 'f' },
366 { "wdogpid", OPT_INT, 'w' },
367 { "ncpfd", OPT_INT, 'n' },
368 { "infofd", OPT_INT, 'i' }, /* v5 */
369 { "version", OPT_INT, 'v' },
370 { NULL, 0, 0 } };
371
372static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
373 int optval;
374 char *optarg;
375 unsigned long optint;
376 int version = 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800377 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
379 data->flags = 0;
380 data->int_flags = 0;
381 data->mounted_uid = 0;
Eric W. Biederman21542272006-12-13 00:35:11 -0800382 data->wdog_pid = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 data->ncp_fd = ~0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800384 data->time_out = NCP_DEFAULT_TIME_OUT;
385 data->retry_count = NCP_DEFAULT_RETRY_COUNT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 data->uid = 0;
387 data->gid = 0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800388 data->file_mode = NCP_DEFAULT_FILE_MODE;
389 data->dir_mode = NCP_DEFAULT_DIR_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 data->info_fd = -1;
391 data->mounted_vol[0] = 0;
392
393 while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
Eric W. Biederman1de24122006-12-13 00:35:13 -0800394 ret = optval;
395 if (ret < 0)
396 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 switch (optval) {
398 case 'u':
399 data->uid = optint;
400 break;
401 case 'g':
402 data->gid = optint;
403 break;
404 case 'o':
405 data->mounted_uid = optint;
406 break;
407 case 'm':
408 data->file_mode = optint;
409 break;
410 case 'd':
411 data->dir_mode = optint;
412 break;
413 case 't':
414 data->time_out = optint;
415 break;
416 case 'r':
417 data->retry_count = optint;
418 break;
419 case 'f':
420 data->flags = optint;
421 break;
422 case 'w':
Eric W. Biederman21542272006-12-13 00:35:11 -0800423 data->wdog_pid = find_get_pid(optint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 break;
425 case 'n':
426 data->ncp_fd = optint;
427 break;
428 case 'i':
429 data->info_fd = optint;
430 break;
431 case 'v':
Eric W. Biederman1de24122006-12-13 00:35:13 -0800432 ret = -ECHRNG;
433 if (optint < NCP_MOUNT_VERSION_V4)
434 goto err;
435 if (optint > NCP_MOUNT_VERSION_V5)
436 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 version = optint;
438 break;
439
440 }
441 }
442 return 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800443err:
444 put_pid(data->wdog_pid);
445 data->wdog_pid = NULL;
446 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447}
448
449static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
450{
451 struct ncp_mount_data_kernel data;
452 struct ncp_server *server;
453 struct file *ncp_filp;
454 struct inode *root_inode;
455 struct inode *sock_inode;
456 struct socket *sock;
457 int error;
458 int default_bufsize;
459#ifdef CONFIG_NCPFS_PACKET_SIGNING
460 int options;
461#endif
462 struct ncp_entry_info finfo;
463
Andrew Morton2a5cac12011-05-24 17:13:42 -0700464 memset(&data, 0, sizeof(data));
Panagiotis Issarisf8314dc2006-09-27 01:49:37 -0700465 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 if (!server)
467 return -ENOMEM;
468 sb->s_fs_info = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
470 error = -EFAULT;
471 if (raw_data == NULL)
472 goto out;
473 switch (*(int*)raw_data) {
474 case NCP_MOUNT_VERSION:
475 {
476 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
477
478 data.flags = md->flags;
479 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
480 data.mounted_uid = md->mounted_uid;
Eric W. Biederman21542272006-12-13 00:35:11 -0800481 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 data.ncp_fd = md->ncp_fd;
483 data.time_out = md->time_out;
484 data.retry_count = md->retry_count;
485 data.uid = md->uid;
486 data.gid = md->gid;
487 data.file_mode = md->file_mode;
488 data.dir_mode = md->dir_mode;
489 data.info_fd = -1;
490 memcpy(data.mounted_vol, md->mounted_vol,
491 NCP_VOLNAME_LEN+1);
492 }
493 break;
494 case NCP_MOUNT_VERSION_V4:
495 {
496 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
497
498 data.flags = md->flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 data.mounted_uid = 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;
504 data.uid = md->uid;
505 data.gid = md->gid;
506 data.file_mode = md->file_mode;
507 data.dir_mode = md->dir_mode;
508 data.info_fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 }
510 break;
511 default:
512 error = -ECHRNG;
513 if (memcmp(raw_data, "vers", 4) == 0) {
514 error = ncp_parse_options(&data, raw_data);
515 }
516 if (error)
517 goto out;
518 break;
519 }
520 error = -EBADF;
521 ncp_filp = fget(data.ncp_fd);
522 if (!ncp_filp)
523 goto out;
524 error = -ENOTSOCK;
Josef Sipek92e5bae2006-12-08 02:37:22 -0800525 sock_inode = ncp_filp->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 if (!S_ISSOCK(sock_inode->i_mode))
527 goto out_fput;
528 sock = SOCKET_I(sock_inode);
529 if (!sock)
530 goto out_fput;
531
532 if (sock->type == SOCK_STREAM)
533 default_bufsize = 0xF000;
534 else
535 default_bufsize = 1024;
536
537 sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
538 sb->s_maxbytes = 0xFFFFFFFFU;
539 sb->s_blocksize = 1024; /* Eh... Is this correct? */
540 sb->s_blocksize_bits = 10;
541 sb->s_magic = NCP_SUPER_MAGIC;
542 sb->s_op = &ncp_sops;
Al Viro0378c402011-01-12 17:25:03 -0500543 sb->s_d_op = &ncp_dentry_operations;
Jens Axboef1970c72010-04-22 12:31:11 +0200544 sb->s_bdi = &server->bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
546 server = NCP_SBP(sb);
547 memset(server, 0, sizeof(*server));
548
Jens Axboef1970c72010-04-22 12:31:11 +0200549 error = bdi_setup_and_register(&server->bdi, "ncpfs", BDI_CAP_MAP_COPY);
550 if (error)
Djalal Harouni759c3612011-12-13 02:47:29 +0100551 goto out_fput;
Jens Axboef1970c72010-04-22 12:31:11 +0200552
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 server->ncp_filp = ncp_filp;
554 server->ncp_sock = sock;
555
556 if (data.info_fd != -1) {
557 struct socket *info_sock;
558
559 error = -EBADF;
560 server->info_filp = fget(data.info_fd);
561 if (!server->info_filp)
Djalal Harouni759c3612011-12-13 02:47:29 +0100562 goto out_bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 error = -ENOTSOCK;
Josef Sipek92e5bae2006-12-08 02:37:22 -0800564 sock_inode = server->info_filp->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 if (!S_ISSOCK(sock_inode->i_mode))
566 goto out_fput2;
567 info_sock = SOCKET_I(sock_inode);
568 if (!info_sock)
569 goto out_fput2;
570 error = -EBADFD;
571 if (info_sock->type != SOCK_STREAM)
572 goto out_fput2;
573 server->info_sock = info_sock;
574 }
575
576/* server->lock = 0; */
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800577 mutex_init(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 server->packet = NULL;
579/* server->buffer_size = 0; */
580/* server->conn_status = 0; */
581/* server->root_dentry = NULL; */
582/* server->root_setuped = 0; */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200583 mutex_init(&server->root_setup_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584#ifdef CONFIG_NCPFS_PACKET_SIGNING
585/* server->sign_wanted = 0; */
586/* server->sign_active = 0; */
587#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200588 init_rwsem(&server->auth_rwsem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 server->auth.auth_type = NCP_AUTH_NONE;
590/* server->auth.object_name_len = 0; */
591/* server->auth.object_name = NULL; */
592/* server->auth.object_type = 0; */
593/* server->priv.len = 0; */
594/* server->priv.data = NULL; */
595
596 server->m = data;
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300597 /* Although anything producing this is buggy, it happens
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 now because of PATH_MAX changes.. */
599 if (server->m.time_out < 1) {
600 server->m.time_out = 10;
601 printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
602 }
603 server->m.time_out = server->m.time_out * HZ / 100;
604 server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
605 server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
606
607#ifdef CONFIG_NCPFS_NLS
608 /* load the default NLS charsets */
609 server->nls_vol = load_nls_default();
610 server->nls_io = load_nls_default();
611#endif /* CONFIG_NCPFS_NLS */
612
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200613 atomic_set(&server->dentry_ttl, 0); /* no caching */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
615 INIT_LIST_HEAD(&server->tx.requests);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800616 mutex_init(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 server->tx.creq = NULL;
618 server->rcv.creq = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
620 init_timer(&server->timeout_tm);
621#undef NCP_PACKET_SIZE
622#define NCP_PACKET_SIZE 131072
623 error = -ENOMEM;
624 server->packet_size = NCP_PACKET_SIZE;
625 server->packet = vmalloc(NCP_PACKET_SIZE);
626 if (server->packet == NULL)
627 goto out_nls;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100628 server->txbuf = vmalloc(NCP_PACKET_SIZE);
629 if (server->txbuf == NULL)
630 goto out_packet;
631 server->rxbuf = vmalloc(NCP_PACKET_SIZE);
632 if (server->rxbuf == NULL)
633 goto out_txbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200635 lock_sock(sock->sk);
636 server->data_ready = sock->sk->sk_data_ready;
637 server->write_space = sock->sk->sk_write_space;
638 server->error_report = sock->sk->sk_error_report;
639 sock->sk->sk_user_data = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 sock->sk->sk_data_ready = ncp_tcp_data_ready;
641 sock->sk->sk_error_report = ncp_tcp_error_report;
642 if (sock->type == SOCK_STREAM) {
643 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
644 server->rcv.len = 10;
645 server->rcv.state = 0;
David Howellsc4028952006-11-22 14:57:56 +0000646 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
647 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 sock->sk->sk_write_space = ncp_tcp_write_space;
649 } else {
David Howellsc4028952006-11-22 14:57:56 +0000650 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
651 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 server->timeout_tm.data = (unsigned long)server;
653 server->timeout_tm.function = ncpdgram_timeout_call;
654 }
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200655 release_sock(sock->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
657 ncp_lock_server(server);
658 error = ncp_connect(server);
659 ncp_unlock_server(server);
660 if (error < 0)
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100661 goto out_rxbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
663
664 error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */
665#ifdef CONFIG_NCPFS_PACKET_SIGNING
666 if (ncp_negotiate_size_and_options(server, default_bufsize,
667 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
668 {
669 if (options != NCP_DEFAULT_OPTIONS)
670 {
671 if (ncp_negotiate_size_and_options(server,
672 default_bufsize,
673 options & 2,
674 &(server->buffer_size), &options) != 0)
675
676 {
677 goto out_disconnect;
678 }
679 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200680 ncp_lock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 if (options & 2)
682 server->sign_wanted = 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200683 ncp_unlock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 }
685 else
686#endif /* CONFIG_NCPFS_PACKET_SIGNING */
687 if (ncp_negotiate_buffersize(server, default_bufsize,
688 &(server->buffer_size)) != 0)
689 goto out_disconnect;
690 DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
691
692 memset(&finfo, 0, sizeof(finfo));
693 finfo.i.attributes = aDIR;
694 finfo.i.dataStreamSize = 0; /* ignored */
695 finfo.i.dirEntNum = 0;
696 finfo.i.DosDirNum = 0;
697#ifdef CONFIG_NCPFS_SMALLDOS
698 finfo.i.NSCreator = NW_NS_DOS;
699#endif
700 finfo.volume = NCP_NUMBER_OF_VOLUMES;
701 /* set dates of mountpoint to Jan 1, 1986; 00:00 */
702 finfo.i.creationTime = finfo.i.modifyTime
703 = cpu_to_le16(0x0000);
704 finfo.i.creationDate = finfo.i.modifyDate
705 = finfo.i.lastAccessDate
706 = cpu_to_le16(0x0C21);
707 finfo.i.nameLen = 0;
708 finfo.i.entryName[0] = '\0';
709
710 finfo.opened = 0;
711 finfo.ino = 2; /* tradition */
712
713 server->name_space[finfo.volume] = NW_NS_DOS;
714
715 error = -ENOMEM;
716 root_inode = ncp_iget(sb, &finfo);
717 if (!root_inode)
718 goto out_disconnect;
719 DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
720 sb->s_root = d_alloc_root(root_inode);
721 if (!sb->s_root)
722 goto out_no_root;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 return 0;
724
725out_no_root:
726 iput(root_inode);
727out_disconnect:
728 ncp_lock_server(server);
729 ncp_disconnect(server);
730 ncp_unlock_server(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100731out_rxbuf:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 ncp_stop_tasks(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100733 vfree(server->rxbuf);
734out_txbuf:
735 vfree(server->txbuf);
736out_packet:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 vfree(server->packet);
738out_nls:
739#ifdef CONFIG_NCPFS_NLS
740 unload_nls(server->nls_io);
741 unload_nls(server->nls_vol);
742#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200743 mutex_destroy(&server->rcv.creq_mutex);
744 mutex_destroy(&server->root_setup_lock);
745 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746out_fput2:
747 if (server->info_filp)
748 fput(server->info_filp);
Jens Axboef1970c72010-04-22 12:31:11 +0200749out_bdi:
Djalal Harouni759c3612011-12-13 02:47:29 +0100750 bdi_destroy(&server->bdi);
751out_fput:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
753 *
Matthew Whitworthe956b4b2010-06-27 14:34:30 +0100754 * The previously used put_filp(ncp_filp); was bogus, since
755 * it doesn't perform proper unlocking.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 */
757 fput(ncp_filp);
758out:
Eric W. Biederman1de24122006-12-13 00:35:13 -0800759 put_pid(data.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 sb->s_fs_info = NULL;
761 kfree(server);
762 return error;
763}
764
765static void ncp_put_super(struct super_block *sb)
766{
767 struct ncp_server *server = NCP_SBP(sb);
768
769 ncp_lock_server(server);
770 ncp_disconnect(server);
771 ncp_unlock_server(server);
772
773 ncp_stop_tasks(server);
774
775#ifdef CONFIG_NCPFS_NLS
776 /* unload the NLS charsets */
Thomas Gleixner6d729e42009-08-16 21:05:08 +0000777 unload_nls(server->nls_vol);
778 unload_nls(server->nls_io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779#endif /* CONFIG_NCPFS_NLS */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200780 mutex_destroy(&server->rcv.creq_mutex);
781 mutex_destroy(&server->root_setup_lock);
782 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783
784 if (server->info_filp)
785 fput(server->info_filp);
786 fput(server->ncp_filp);
Eric W. Biederman21542272006-12-13 00:35:11 -0800787 kill_pid(server->m.wdog_pid, SIGTERM, 1);
788 put_pid(server->m.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789
Jens Axboef1970c72010-04-22 12:31:11 +0200790 bdi_destroy(&server->bdi);
Pekka Enberg44db77f2006-01-14 13:21:12 -0800791 kfree(server->priv.data);
792 kfree(server->auth.object_name);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100793 vfree(server->rxbuf);
794 vfree(server->txbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 vfree(server->packet);
796 sb->s_fs_info = NULL;
797 kfree(server);
798}
799
David Howells726c3342006-06-23 02:02:58 -0700800static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801{
802 struct dentry* d;
803 struct inode* i;
804 struct ncp_inode_info* ni;
805 struct ncp_server* s;
806 struct ncp_volume_info vi;
David Howells726c3342006-06-23 02:02:58 -0700807 struct super_block *sb = dentry->d_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 int err;
809 __u8 dh;
810
811 d = sb->s_root;
812 if (!d) {
813 goto dflt;
814 }
815 i = d->d_inode;
816 if (!i) {
817 goto dflt;
818 }
819 ni = NCP_FINFO(i);
820 if (!ni) {
821 goto dflt;
822 }
823 s = NCP_SBP(sb);
824 if (!s) {
825 goto dflt;
826 }
827 if (!s->m.mounted_vol[0]) {
828 goto dflt;
829 }
830
831 err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
832 if (err) {
833 goto dflt;
834 }
835 err = ncp_get_directory_info(s, dh, &vi);
836 ncp_dirhandle_free(s, dh);
837 if (err) {
838 goto dflt;
839 }
840 buf->f_type = NCP_SUPER_MAGIC;
841 buf->f_bsize = vi.sectors_per_block * 512;
842 buf->f_blocks = vi.total_blocks;
843 buf->f_bfree = vi.free_blocks;
844 buf->f_bavail = vi.free_blocks;
845 buf->f_files = vi.total_dir_entries;
846 buf->f_ffree = vi.available_dir_entries;
847 buf->f_namelen = 12;
848 return 0;
849
850 /* We cannot say how much disk space is left on a mounted
851 NetWare Server, because free space is distributed over
852 volumes, and the current user might have disk quotas. So
853 free space is not that simple to determine. Our decision
854 here is to err conservatively. */
855
856dflt:;
857 buf->f_type = NCP_SUPER_MAGIC;
858 buf->f_bsize = NCP_BLOCK_SIZE;
859 buf->f_blocks = 0;
860 buf->f_bfree = 0;
861 buf->f_bavail = 0;
862 buf->f_namelen = 12;
863 return 0;
864}
865
866int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
867{
868 struct inode *inode = dentry->d_inode;
869 int result = 0;
870 __le32 info_mask;
871 struct nw_modify_dos_info info;
872 struct ncp_server *server;
873
874 result = -EIO;
875
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 server = NCP_SERVER(inode);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200877 if (!server) /* How this could happen? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 goto out;
879
880 /* ageing the dentry to force validation */
881 ncp_age_dentry(server, dentry);
882
883 result = inode_change_ok(inode, attr);
884 if (result < 0)
885 goto out;
886
887 result = -EPERM;
888 if (((attr->ia_valid & ATTR_UID) &&
889 (attr->ia_uid != server->m.uid)))
890 goto out;
891
892 if (((attr->ia_valid & ATTR_GID) &&
893 (attr->ia_gid != server->m.gid)))
894 goto out;
895
896 if (((attr->ia_valid & ATTR_MODE) &&
897 (attr->ia_mode &
898 ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
899 goto out;
900
901 info_mask = 0;
902 memset(&info, 0, sizeof(info));
903
904#if 1
905 if ((attr->ia_valid & ATTR_MODE) != 0)
906 {
907 umode_t newmode = attr->ia_mode;
908
909 info_mask |= DM_ATTRIBUTES;
910
911 if (S_ISDIR(inode->i_mode)) {
912 newmode &= server->m.dir_mode;
913 } else {
914#ifdef CONFIG_NCPFS_EXTRAS
915 if (server->m.flags & NCP_MOUNT_EXTRAS) {
916 /* any non-default execute bit set */
917 if (newmode & ~server->m.file_mode & S_IXUGO)
918 info.attributes |= aSHARED | aSYSTEM;
919 /* read for group/world and not in default file_mode */
920 else if (newmode & ~server->m.file_mode & S_IRUGO)
921 info.attributes |= aSHARED;
922 } else
923#endif
924 newmode &= server->m.file_mode;
925 }
926 if (newmode & S_IWUGO)
927 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
928 else
929 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
930
931#ifdef CONFIG_NCPFS_NFS_NS
932 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
933 result = ncp_modify_nfs_info(server,
934 NCP_FINFO(inode)->volNumber,
935 NCP_FINFO(inode)->dirEntNum,
936 attr->ia_mode, 0);
937 if (result != 0)
938 goto out;
939 info.attributes &= ~(aSHARED | aSYSTEM);
940 {
941 /* mark partial success */
942 struct iattr tmpattr;
943
944 tmpattr.ia_valid = ATTR_MODE;
945 tmpattr.ia_mode = attr->ia_mode;
946
Christoph Hellwig10257742010-06-04 11:30:02 +0200947 setattr_copy(inode, &tmpattr);
948 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 }
950 }
951#endif
952 }
953#endif
954
955 /* Do SIZE before attributes, otherwise mtime together with size does not work...
956 */
957 if ((attr->ia_valid & ATTR_SIZE) != 0) {
958 int written;
959
960 DPRINTK("ncpfs: trying to change size to %ld\n",
961 attr->ia_size);
962
963 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
964 result = -EACCES;
965 goto out;
966 }
967 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
968 attr->ia_size, 0, "", &written);
969
970 /* According to ndir, the changes only take effect after
971 closing the file */
972 ncp_inode_close(inode);
973 result = ncp_make_closed(inode);
974 if (result)
975 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +0200976
977 if (attr->ia_size != i_size_read(inode)) {
978 result = vmtruncate(inode, attr->ia_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 if (result)
980 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +0200981 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 }
983 }
984 if ((attr->ia_valid & ATTR_CTIME) != 0) {
985 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
986 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
987 &info.creationTime, &info.creationDate);
988 }
989 if ((attr->ia_valid & ATTR_MTIME) != 0) {
990 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
991 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
992 &info.modifyTime, &info.modifyDate);
993 }
994 if ((attr->ia_valid & ATTR_ATIME) != 0) {
995 __le16 dummy;
996 info_mask |= (DM_LAST_ACCESS_DATE);
997 ncp_date_unix2dos(attr->ia_atime.tv_sec,
998 &dummy, &info.lastAccessDate);
999 }
1000 if (info_mask != 0) {
1001 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
1002 inode, info_mask, &info);
1003 if (result != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
1005 /* NetWare seems not to allow this. I
1006 do not know why. So, just tell the
1007 user everything went fine. This is
1008 a terrible hack, but I do not know
1009 how to do this correctly. */
1010 result = 0;
1011 } else
1012 goto out;
1013 }
1014#ifdef CONFIG_NCPFS_STRONG
1015 if ((!result) && (info_mask & DM_ATTRIBUTES))
1016 NCP_FINFO(inode)->nwattr = info.attributes;
1017#endif
1018 }
Christoph Hellwig10257742010-06-04 11:30:02 +02001019 if (result)
1020 goto out;
1021
1022 setattr_copy(inode, attr);
1023 mark_inode_dirty(inode);
1024
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025out:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001026 if (result > 0)
1027 result = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 return result;
1029}
1030
Al Viro3c26ff62010-07-25 11:46:36 +04001031static struct dentry *ncp_mount(struct file_system_type *fs_type,
1032 int flags, const char *dev_name, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033{
Al Viro3c26ff62010-07-25 11:46:36 +04001034 return mount_nodev(fs_type, flags, data, ncp_fill_super);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035}
1036
1037static struct file_system_type ncp_fs_type = {
1038 .owner = THIS_MODULE,
1039 .name = "ncpfs",
Al Viro3c26ff62010-07-25 11:46:36 +04001040 .mount = ncp_mount,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 .kill_sb = kill_anon_super,
Miklos Szeredi564cd132008-02-08 04:21:46 -08001042 .fs_flags = FS_BINARY_MOUNTDATA,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043};
1044
1045static int __init init_ncp_fs(void)
1046{
1047 int err;
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001048 DPRINTK("ncpfs: init_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 err = init_inodecache();
1051 if (err)
1052 goto out1;
1053 err = register_filesystem(&ncp_fs_type);
1054 if (err)
1055 goto out;
1056 return 0;
1057out:
1058 destroy_inodecache();
1059out1:
1060 return err;
1061}
1062
1063static void __exit exit_ncp_fs(void)
1064{
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001065 DPRINTK("ncpfs: exit_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 unregister_filesystem(&ncp_fs_type);
1067 destroy_inodecache();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068}
1069
1070module_init(init_ncp_fs)
1071module_exit(exit_ncp_fs)
1072MODULE_LICENSE("GPL");