blob: 49df0e7f8379149c3f113506afdc5c8ee7db51a4 [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 *);
Al Viro34c80b12011-12-08 21:32:45 -050047static int ncp_show_options(struct seq_file *, struct dentry *);
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);
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +110063 kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
64}
65
Linus Torvalds1da177e2005-04-16 15:20:36 -070066static void ncp_destroy_inode(struct inode *inode)
67{
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +110068 call_rcu(&inode->i_rcu, ncp_i_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -070069}
70
Alexey Dobriyan51cc5062008-07-25 19:45:34 -070071static void init_once(void *foo)
Linus Torvalds1da177e2005-04-16 15:20:36 -070072{
73 struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
74
Christoph Lametera35afb82007-05-16 22:10:57 -070075 mutex_init(&ei->open_mutex);
76 inode_init_once(&ei->vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077}
Paul Mundt20c2df82007-07-20 10:11:58 +090078
Linus Torvalds1da177e2005-04-16 15:20:36 -070079static int init_inodecache(void)
80{
81 ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
82 sizeof(struct ncp_inode_info),
Paul Jacksonfffb60f2006-03-24 03:16:06 -080083 0, (SLAB_RECLAIM_ACCOUNT|
84 SLAB_MEM_SPREAD),
Paul Mundt20c2df82007-07-20 10:11:58 +090085 init_once);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 if (ncp_inode_cachep == NULL)
87 return -ENOMEM;
88 return 0;
89}
90
91static void destroy_inodecache(void)
92{
Alexey Dobriyan1a1d92c2006-09-27 01:49:40 -070093 kmem_cache_destroy(ncp_inode_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -070094}
95
96static int ncp_remount(struct super_block *sb, int *flags, char* data)
97{
98 *flags |= MS_NODIRATIME;
99 return 0;
100}
101
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800102static const struct super_operations ncp_sops =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103{
104 .alloc_inode = ncp_alloc_inode,
105 .destroy_inode = ncp_destroy_inode,
106 .drop_inode = generic_delete_inode,
Al Viro94ee8492010-06-07 00:45:56 -0400107 .evict_inode = ncp_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 .put_super = ncp_put_super,
109 .statfs = ncp_statfs,
110 .remount_fs = ncp_remount,
Miklos Szeredi564cd132008-02-08 04:21:46 -0800111 .show_options = ncp_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112};
113
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114/*
115 * Fill in the ncpfs-specific information in the inode.
116 */
117static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
118{
119 NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
120 NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
121 NCP_FINFO(inode)->volNumber = nwinfo->volume;
122}
123
124void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
125{
126 ncp_update_dirent(inode, nwinfo);
127 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
128 NCP_FINFO(inode)->access = nwinfo->access;
129 memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
130 sizeof(nwinfo->file_handle));
131 DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
132 nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
133 NCP_FINFO(inode)->dirEntNum);
134}
135
136static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
137{
138 /* NFS namespace mode overrides others if it's set. */
139 DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n",
140 nwi->entryName, nwi->nfs.mode);
141 if (nwi->nfs.mode) {
142 /* XXX Security? */
143 inode->i_mode = nwi->nfs.mode;
144 }
145
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200146 inode->i_blocks = (i_size_read(inode) + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
148 inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate);
149 inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate);
150 inode->i_atime.tv_sec = ncp_date_dos2unix(0, nwi->lastAccessDate);
151 inode->i_atime.tv_nsec = 0;
152 inode->i_mtime.tv_nsec = 0;
153 inode->i_ctime.tv_nsec = 0;
154}
155
156static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
157{
158 struct nw_info_struct *nwi = &nwinfo->i;
159 struct ncp_server *server = NCP_SERVER(inode);
160
161 if (nwi->attributes & aDIR) {
162 inode->i_mode = server->m.dir_mode;
163 /* for directories dataStreamSize seems to be some
164 Object ID ??? */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200165 i_size_write(inode, NCP_BLOCK_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 } else {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200167 u32 size;
168
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 inode->i_mode = server->m.file_mode;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200170 size = le32_to_cpu(nwi->dataStreamSize);
171 i_size_write(inode, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172#ifdef CONFIG_NCPFS_EXTRAS
173 if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS))
174 && (nwi->attributes & aSHARED)) {
175 switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
176 case aHIDDEN:
177 if (server->m.flags & NCP_MOUNT_SYMLINKS) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200178 if (/* (size >= NCP_MIN_SYMLINK_SIZE)
179 && */ (size <= NCP_MAX_SYMLINK_SIZE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
181 NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
182 break;
183 }
184 }
185 /* FALLTHROUGH */
186 case 0:
187 if (server->m.flags & NCP_MOUNT_EXTRAS)
188 inode->i_mode |= S_IRUGO;
189 break;
190 case aSYSTEM:
191 if (server->m.flags & NCP_MOUNT_EXTRAS)
192 inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO;
193 break;
194 /* case aSYSTEM|aHIDDEN: */
195 default:
196 /* reserved combination */
197 break;
198 }
199 }
200#endif
201 }
202 if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
203}
204
205void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
206{
207 NCP_FINFO(inode)->flags = 0;
208 if (!atomic_read(&NCP_FINFO(inode)->opened)) {
209 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
210 ncp_update_attrs(inode, nwinfo);
211 }
212
213 ncp_update_dates(inode, &nwinfo->i);
214 ncp_update_dirent(inode, nwinfo);
215}
216
217/*
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200218 * Fill in the inode based on the ncp_entry_info structure. Used only for brand new inodes.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 */
220static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
221{
222 struct ncp_server *server = NCP_SERVER(inode);
223
224 NCP_FINFO(inode)->flags = 0;
225
226 ncp_update_attrs(inode, nwinfo);
227
228 DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
229
Miklos Szeredibfe86842011-10-28 14:13:29 +0200230 set_nlink(inode, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 inode->i_uid = server->m.uid;
232 inode->i_gid = server->m.gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
234 ncp_update_dates(inode, &nwinfo->i);
235 ncp_update_inode(inode, nwinfo);
236}
237
238#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800239static const struct inode_operations ncp_symlink_inode_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 .readlink = generic_readlink,
241 .follow_link = page_follow_link_light,
242 .put_link = page_put_link,
243 .setattr = ncp_notify_change,
244};
245#endif
246
247/*
248 * Get a new inode.
249 */
250struct inode *
251ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
252{
253 struct inode *inode;
254
255 if (info == NULL) {
256 printk(KERN_ERR "ncp_iget: info is NULL\n");
257 return NULL;
258 }
259
260 inode = new_inode(sb);
261 if (inode) {
262 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
263
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200264 inode->i_mapping->backing_dev_info = sb->s_bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 inode->i_ino = info->ino;
266 ncp_set_attr(inode, info);
267 if (S_ISREG(inode->i_mode)) {
268 inode->i_op = &ncp_file_inode_operations;
269 inode->i_fop = &ncp_file_operations;
270 } else if (S_ISDIR(inode->i_mode)) {
271 inode->i_op = &ncp_dir_inode_operations;
272 inode->i_fop = &ncp_dir_operations;
273#ifdef CONFIG_NCPFS_NFS_NS
274 } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
275 init_special_inode(inode, inode->i_mode,
276 new_decode_dev(info->i.nfs.rdev));
277#endif
278#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
279 } else if (S_ISLNK(inode->i_mode)) {
280 inode->i_op = &ncp_symlink_inode_operations;
281 inode->i_data.a_ops = &ncp_symlink_aops;
282#endif
283 } else {
284 make_bad_inode(inode);
285 }
286 insert_inode_hash(inode);
287 } else
288 printk(KERN_ERR "ncp_iget: iget failed!\n");
289 return inode;
290}
291
292static void
Al Viro94ee8492010-06-07 00:45:56 -0400293ncp_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294{
Mark Fashehfef26652005-09-09 13:01:31 -0700295 truncate_inode_pages(&inode->i_data, 0);
Al Viro94ee8492010-06-07 00:45:56 -0400296 end_writeback(inode);
Mark Fashehfef26652005-09-09 13:01:31 -0700297
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 if (S_ISDIR(inode->i_mode)) {
Al Viro94ee8492010-06-07 00:45:56 -0400299 DDPRINTK("ncp_evict_inode: put directory %ld\n", inode->i_ino);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 }
301
302 if (ncp_make_closed(inode) != 0) {
303 /* We can't do anything but complain. */
Al Viro94ee8492010-06-07 00:45:56 -0400304 printk(KERN_ERR "ncp_evict_inode: could not close\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306}
307
308static void ncp_stop_tasks(struct ncp_server *server) {
309 struct sock* sk = server->ncp_sock->sk;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200310
311 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 sk->sk_error_report = server->error_report;
313 sk->sk_data_ready = server->data_ready;
314 sk->sk_write_space = server->write_space;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200315 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 del_timer_sync(&server->timeout_tm);
Tejun Heo5d8e4bd2010-12-24 15:59:06 +0100317
318 flush_work_sync(&server->rcv.tq);
319 if (sk->sk_socket->type == SOCK_STREAM)
320 flush_work_sync(&server->tx.tq);
321 else
322 flush_work_sync(&server->timeout_tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323}
324
Al Viro34c80b12011-12-08 21:32:45 -0500325static int ncp_show_options(struct seq_file *seq, struct dentry *root)
Miklos Szeredi564cd132008-02-08 04:21:46 -0800326{
Al Viro34c80b12011-12-08 21:32:45 -0500327 struct ncp_server *server = NCP_SBP(root->d_sb);
Miklos Szeredi564cd132008-02-08 04:21:46 -0800328 unsigned int tmp;
329
330 if (server->m.uid != 0)
331 seq_printf(seq, ",uid=%u", server->m.uid);
332 if (server->m.gid != 0)
333 seq_printf(seq, ",gid=%u", server->m.gid);
334 if (server->m.mounted_uid != 0)
335 seq_printf(seq, ",owner=%u", server->m.mounted_uid);
336 tmp = server->m.file_mode & S_IALLUGO;
337 if (tmp != NCP_DEFAULT_FILE_MODE)
338 seq_printf(seq, ",mode=0%o", tmp);
339 tmp = server->m.dir_mode & S_IALLUGO;
340 if (tmp != NCP_DEFAULT_DIR_MODE)
341 seq_printf(seq, ",dirmode=0%o", tmp);
342 if (server->m.time_out != NCP_DEFAULT_TIME_OUT * HZ / 100) {
343 tmp = server->m.time_out * 100 / HZ;
344 seq_printf(seq, ",timeout=%u", tmp);
345 }
346 if (server->m.retry_count != NCP_DEFAULT_RETRY_COUNT)
347 seq_printf(seq, ",retry=%u", server->m.retry_count);
348 if (server->m.flags != 0)
349 seq_printf(seq, ",flags=%lu", server->m.flags);
350 if (server->m.wdog_pid != NULL)
351 seq_printf(seq, ",wdogpid=%u", pid_vnr(server->m.wdog_pid));
352
353 return 0;
354}
355
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356static const struct ncp_option ncp_opts[] = {
357 { "uid", OPT_INT, 'u' },
358 { "gid", OPT_INT, 'g' },
359 { "owner", OPT_INT, 'o' },
360 { "mode", OPT_INT, 'm' },
361 { "dirmode", OPT_INT, 'd' },
362 { "timeout", OPT_INT, 't' },
363 { "retry", OPT_INT, 'r' },
364 { "flags", OPT_INT, 'f' },
365 { "wdogpid", OPT_INT, 'w' },
366 { "ncpfd", OPT_INT, 'n' },
367 { "infofd", OPT_INT, 'i' }, /* v5 */
368 { "version", OPT_INT, 'v' },
369 { NULL, 0, 0 } };
370
371static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
372 int optval;
373 char *optarg;
374 unsigned long optint;
375 int version = 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800376 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
378 data->flags = 0;
379 data->int_flags = 0;
380 data->mounted_uid = 0;
Eric W. Biederman21542272006-12-13 00:35:11 -0800381 data->wdog_pid = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 data->ncp_fd = ~0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800383 data->time_out = NCP_DEFAULT_TIME_OUT;
384 data->retry_count = NCP_DEFAULT_RETRY_COUNT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 data->uid = 0;
386 data->gid = 0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800387 data->file_mode = NCP_DEFAULT_FILE_MODE;
388 data->dir_mode = NCP_DEFAULT_DIR_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 data->info_fd = -1;
390 data->mounted_vol[0] = 0;
391
392 while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
Eric W. Biederman1de24122006-12-13 00:35:13 -0800393 ret = optval;
394 if (ret < 0)
395 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 switch (optval) {
397 case 'u':
398 data->uid = optint;
399 break;
400 case 'g':
401 data->gid = optint;
402 break;
403 case 'o':
404 data->mounted_uid = optint;
405 break;
406 case 'm':
407 data->file_mode = optint;
408 break;
409 case 'd':
410 data->dir_mode = optint;
411 break;
412 case 't':
413 data->time_out = optint;
414 break;
415 case 'r':
416 data->retry_count = optint;
417 break;
418 case 'f':
419 data->flags = optint;
420 break;
421 case 'w':
Eric W. Biederman21542272006-12-13 00:35:11 -0800422 data->wdog_pid = find_get_pid(optint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 break;
424 case 'n':
425 data->ncp_fd = optint;
426 break;
427 case 'i':
428 data->info_fd = optint;
429 break;
430 case 'v':
Eric W. Biederman1de24122006-12-13 00:35:13 -0800431 ret = -ECHRNG;
432 if (optint < NCP_MOUNT_VERSION_V4)
433 goto err;
434 if (optint > NCP_MOUNT_VERSION_V5)
435 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 version = optint;
437 break;
438
439 }
440 }
441 return 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800442err:
443 put_pid(data->wdog_pid);
444 data->wdog_pid = NULL;
445 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446}
447
448static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
449{
450 struct ncp_mount_data_kernel data;
451 struct ncp_server *server;
452 struct file *ncp_filp;
453 struct inode *root_inode;
454 struct inode *sock_inode;
455 struct socket *sock;
456 int error;
457 int default_bufsize;
458#ifdef CONFIG_NCPFS_PACKET_SIGNING
459 int options;
460#endif
461 struct ncp_entry_info finfo;
462
Andrew Morton2a5cac12011-05-24 17:13:42 -0700463 memset(&data, 0, sizeof(data));
Panagiotis Issarisf8314dc2006-09-27 01:49:37 -0700464 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 if (!server)
466 return -ENOMEM;
467 sb->s_fs_info = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
469 error = -EFAULT;
470 if (raw_data == NULL)
471 goto out;
472 switch (*(int*)raw_data) {
473 case NCP_MOUNT_VERSION:
474 {
475 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
476
477 data.flags = md->flags;
478 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
479 data.mounted_uid = md->mounted_uid;
Eric W. Biederman21542272006-12-13 00:35:11 -0800480 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 data.ncp_fd = md->ncp_fd;
482 data.time_out = md->time_out;
483 data.retry_count = md->retry_count;
484 data.uid = md->uid;
485 data.gid = md->gid;
486 data.file_mode = md->file_mode;
487 data.dir_mode = md->dir_mode;
488 data.info_fd = -1;
489 memcpy(data.mounted_vol, md->mounted_vol,
490 NCP_VOLNAME_LEN+1);
491 }
492 break;
493 case NCP_MOUNT_VERSION_V4:
494 {
495 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
496
497 data.flags = md->flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 data.mounted_uid = md->mounted_uid;
Eric W. Biederman21542272006-12-13 00:35:11 -0800499 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 data.ncp_fd = md->ncp_fd;
501 data.time_out = md->time_out;
502 data.retry_count = md->retry_count;
503 data.uid = md->uid;
504 data.gid = md->gid;
505 data.file_mode = md->file_mode;
506 data.dir_mode = md->dir_mode;
507 data.info_fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 }
509 break;
510 default:
511 error = -ECHRNG;
512 if (memcmp(raw_data, "vers", 4) == 0) {
513 error = ncp_parse_options(&data, raw_data);
514 }
515 if (error)
516 goto out;
517 break;
518 }
519 error = -EBADF;
520 ncp_filp = fget(data.ncp_fd);
521 if (!ncp_filp)
522 goto out;
523 error = -ENOTSOCK;
Josef Sipek92e5bae2006-12-08 02:37:22 -0800524 sock_inode = ncp_filp->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 if (!S_ISSOCK(sock_inode->i_mode))
526 goto out_fput;
527 sock = SOCKET_I(sock_inode);
528 if (!sock)
529 goto out_fput;
530
531 if (sock->type == SOCK_STREAM)
532 default_bufsize = 0xF000;
533 else
534 default_bufsize = 1024;
535
536 sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
537 sb->s_maxbytes = 0xFFFFFFFFU;
538 sb->s_blocksize = 1024; /* Eh... Is this correct? */
539 sb->s_blocksize_bits = 10;
540 sb->s_magic = NCP_SUPER_MAGIC;
541 sb->s_op = &ncp_sops;
Al Viro0378c402011-01-12 17:25:03 -0500542 sb->s_d_op = &ncp_dentry_operations;
Jens Axboef1970c72010-04-22 12:31:11 +0200543 sb->s_bdi = &server->bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
545 server = NCP_SBP(sb);
546 memset(server, 0, sizeof(*server));
547
Jens Axboef1970c72010-04-22 12:31:11 +0200548 error = bdi_setup_and_register(&server->bdi, "ncpfs", BDI_CAP_MAP_COPY);
549 if (error)
Djalal Harouni759c3612011-12-13 02:47:29 +0100550 goto out_fput;
Jens Axboef1970c72010-04-22 12:31:11 +0200551
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 server->ncp_filp = ncp_filp;
553 server->ncp_sock = sock;
554
555 if (data.info_fd != -1) {
556 struct socket *info_sock;
557
558 error = -EBADF;
559 server->info_filp = fget(data.info_fd);
560 if (!server->info_filp)
Djalal Harouni759c3612011-12-13 02:47:29 +0100561 goto out_bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 error = -ENOTSOCK;
Josef Sipek92e5bae2006-12-08 02:37:22 -0800563 sock_inode = server->info_filp->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 if (!S_ISSOCK(sock_inode->i_mode))
565 goto out_fput2;
566 info_sock = SOCKET_I(sock_inode);
567 if (!info_sock)
568 goto out_fput2;
569 error = -EBADFD;
570 if (info_sock->type != SOCK_STREAM)
571 goto out_fput2;
572 server->info_sock = info_sock;
573 }
574
575/* server->lock = 0; */
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800576 mutex_init(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 server->packet = NULL;
578/* server->buffer_size = 0; */
579/* server->conn_status = 0; */
580/* server->root_dentry = NULL; */
581/* server->root_setuped = 0; */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200582 mutex_init(&server->root_setup_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583#ifdef CONFIG_NCPFS_PACKET_SIGNING
584/* server->sign_wanted = 0; */
585/* server->sign_active = 0; */
586#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200587 init_rwsem(&server->auth_rwsem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 server->auth.auth_type = NCP_AUTH_NONE;
589/* server->auth.object_name_len = 0; */
590/* server->auth.object_name = NULL; */
591/* server->auth.object_type = 0; */
592/* server->priv.len = 0; */
593/* server->priv.data = NULL; */
594
595 server->m = data;
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300596 /* Although anything producing this is buggy, it happens
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 now because of PATH_MAX changes.. */
598 if (server->m.time_out < 1) {
599 server->m.time_out = 10;
600 printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
601 }
602 server->m.time_out = server->m.time_out * HZ / 100;
603 server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
604 server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
605
606#ifdef CONFIG_NCPFS_NLS
607 /* load the default NLS charsets */
608 server->nls_vol = load_nls_default();
609 server->nls_io = load_nls_default();
610#endif /* CONFIG_NCPFS_NLS */
611
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200612 atomic_set(&server->dentry_ttl, 0); /* no caching */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613
614 INIT_LIST_HEAD(&server->tx.requests);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800615 mutex_init(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 server->tx.creq = NULL;
617 server->rcv.creq = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
619 init_timer(&server->timeout_tm);
620#undef NCP_PACKET_SIZE
621#define NCP_PACKET_SIZE 131072
622 error = -ENOMEM;
623 server->packet_size = NCP_PACKET_SIZE;
624 server->packet = vmalloc(NCP_PACKET_SIZE);
625 if (server->packet == NULL)
626 goto out_nls;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100627 server->txbuf = vmalloc(NCP_PACKET_SIZE);
628 if (server->txbuf == NULL)
629 goto out_packet;
630 server->rxbuf = vmalloc(NCP_PACKET_SIZE);
631 if (server->rxbuf == NULL)
632 goto out_txbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200634 lock_sock(sock->sk);
635 server->data_ready = sock->sk->sk_data_ready;
636 server->write_space = sock->sk->sk_write_space;
637 server->error_report = sock->sk->sk_error_report;
638 sock->sk->sk_user_data = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 sock->sk->sk_data_ready = ncp_tcp_data_ready;
640 sock->sk->sk_error_report = ncp_tcp_error_report;
641 if (sock->type == SOCK_STREAM) {
642 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
643 server->rcv.len = 10;
644 server->rcv.state = 0;
David Howellsc4028952006-11-22 14:57:56 +0000645 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
646 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 sock->sk->sk_write_space = ncp_tcp_write_space;
648 } else {
David Howellsc4028952006-11-22 14:57:56 +0000649 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
650 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 server->timeout_tm.data = (unsigned long)server;
652 server->timeout_tm.function = ncpdgram_timeout_call;
653 }
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200654 release_sock(sock->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656 ncp_lock_server(server);
657 error = ncp_connect(server);
658 ncp_unlock_server(server);
659 if (error < 0)
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100660 goto out_rxbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
662
663 error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */
664#ifdef CONFIG_NCPFS_PACKET_SIGNING
665 if (ncp_negotiate_size_and_options(server, default_bufsize,
666 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
667 {
668 if (options != NCP_DEFAULT_OPTIONS)
669 {
670 if (ncp_negotiate_size_and_options(server,
671 default_bufsize,
672 options & 2,
673 &(server->buffer_size), &options) != 0)
674
675 {
676 goto out_disconnect;
677 }
678 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200679 ncp_lock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 if (options & 2)
681 server->sign_wanted = 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200682 ncp_unlock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 }
684 else
685#endif /* CONFIG_NCPFS_PACKET_SIGNING */
686 if (ncp_negotiate_buffersize(server, default_bufsize,
687 &(server->buffer_size)) != 0)
688 goto out_disconnect;
689 DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
690
691 memset(&finfo, 0, sizeof(finfo));
692 finfo.i.attributes = aDIR;
693 finfo.i.dataStreamSize = 0; /* ignored */
694 finfo.i.dirEntNum = 0;
695 finfo.i.DosDirNum = 0;
696#ifdef CONFIG_NCPFS_SMALLDOS
697 finfo.i.NSCreator = NW_NS_DOS;
698#endif
699 finfo.volume = NCP_NUMBER_OF_VOLUMES;
700 /* set dates of mountpoint to Jan 1, 1986; 00:00 */
701 finfo.i.creationTime = finfo.i.modifyTime
702 = cpu_to_le16(0x0000);
703 finfo.i.creationDate = finfo.i.modifyDate
704 = finfo.i.lastAccessDate
705 = cpu_to_le16(0x0C21);
706 finfo.i.nameLen = 0;
707 finfo.i.entryName[0] = '\0';
708
709 finfo.opened = 0;
710 finfo.ino = 2; /* tradition */
711
712 server->name_space[finfo.volume] = NW_NS_DOS;
713
714 error = -ENOMEM;
715 root_inode = ncp_iget(sb, &finfo);
716 if (!root_inode)
717 goto out_disconnect;
718 DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
Al Viro48fde702012-01-08 22:15:13 -0500719 sb->s_root = d_make_root(root_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 if (!sb->s_root)
Al Viro48fde702012-01-08 22:15:13 -0500721 goto out_disconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 return 0;
723
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724out_disconnect:
725 ncp_lock_server(server);
726 ncp_disconnect(server);
727 ncp_unlock_server(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100728out_rxbuf:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 ncp_stop_tasks(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100730 vfree(server->rxbuf);
731out_txbuf:
732 vfree(server->txbuf);
733out_packet:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 vfree(server->packet);
735out_nls:
736#ifdef CONFIG_NCPFS_NLS
737 unload_nls(server->nls_io);
738 unload_nls(server->nls_vol);
739#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200740 mutex_destroy(&server->rcv.creq_mutex);
741 mutex_destroy(&server->root_setup_lock);
742 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743out_fput2:
744 if (server->info_filp)
745 fput(server->info_filp);
Jens Axboef1970c72010-04-22 12:31:11 +0200746out_bdi:
Djalal Harouni759c3612011-12-13 02:47:29 +0100747 bdi_destroy(&server->bdi);
748out_fput:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
750 *
Matthew Whitworthe956b4b2010-06-27 14:34:30 +0100751 * The previously used put_filp(ncp_filp); was bogus, since
752 * it doesn't perform proper unlocking.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 */
754 fput(ncp_filp);
755out:
Eric W. Biederman1de24122006-12-13 00:35:13 -0800756 put_pid(data.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 sb->s_fs_info = NULL;
758 kfree(server);
759 return error;
760}
761
762static void ncp_put_super(struct super_block *sb)
763{
764 struct ncp_server *server = NCP_SBP(sb);
765
766 ncp_lock_server(server);
767 ncp_disconnect(server);
768 ncp_unlock_server(server);
769
770 ncp_stop_tasks(server);
771
772#ifdef CONFIG_NCPFS_NLS
773 /* unload the NLS charsets */
Thomas Gleixner6d729e42009-08-16 21:05:08 +0000774 unload_nls(server->nls_vol);
775 unload_nls(server->nls_io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776#endif /* CONFIG_NCPFS_NLS */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200777 mutex_destroy(&server->rcv.creq_mutex);
778 mutex_destroy(&server->root_setup_lock);
779 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
781 if (server->info_filp)
782 fput(server->info_filp);
783 fput(server->ncp_filp);
Eric W. Biederman21542272006-12-13 00:35:11 -0800784 kill_pid(server->m.wdog_pid, SIGTERM, 1);
785 put_pid(server->m.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786
Jens Axboef1970c72010-04-22 12:31:11 +0200787 bdi_destroy(&server->bdi);
Pekka Enberg44db77f2006-01-14 13:21:12 -0800788 kfree(server->priv.data);
789 kfree(server->auth.object_name);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100790 vfree(server->rxbuf);
791 vfree(server->txbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 vfree(server->packet);
793 sb->s_fs_info = NULL;
794 kfree(server);
795}
796
David Howells726c3342006-06-23 02:02:58 -0700797static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798{
799 struct dentry* d;
800 struct inode* i;
801 struct ncp_inode_info* ni;
802 struct ncp_server* s;
803 struct ncp_volume_info vi;
David Howells726c3342006-06-23 02:02:58 -0700804 struct super_block *sb = dentry->d_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 int err;
806 __u8 dh;
807
808 d = sb->s_root;
809 if (!d) {
810 goto dflt;
811 }
812 i = d->d_inode;
813 if (!i) {
814 goto dflt;
815 }
816 ni = NCP_FINFO(i);
817 if (!ni) {
818 goto dflt;
819 }
820 s = NCP_SBP(sb);
821 if (!s) {
822 goto dflt;
823 }
824 if (!s->m.mounted_vol[0]) {
825 goto dflt;
826 }
827
828 err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
829 if (err) {
830 goto dflt;
831 }
832 err = ncp_get_directory_info(s, dh, &vi);
833 ncp_dirhandle_free(s, dh);
834 if (err) {
835 goto dflt;
836 }
837 buf->f_type = NCP_SUPER_MAGIC;
838 buf->f_bsize = vi.sectors_per_block * 512;
839 buf->f_blocks = vi.total_blocks;
840 buf->f_bfree = vi.free_blocks;
841 buf->f_bavail = vi.free_blocks;
842 buf->f_files = vi.total_dir_entries;
843 buf->f_ffree = vi.available_dir_entries;
844 buf->f_namelen = 12;
845 return 0;
846
847 /* We cannot say how much disk space is left on a mounted
848 NetWare Server, because free space is distributed over
849 volumes, and the current user might have disk quotas. So
850 free space is not that simple to determine. Our decision
851 here is to err conservatively. */
852
853dflt:;
854 buf->f_type = NCP_SUPER_MAGIC;
855 buf->f_bsize = NCP_BLOCK_SIZE;
856 buf->f_blocks = 0;
857 buf->f_bfree = 0;
858 buf->f_bavail = 0;
859 buf->f_namelen = 12;
860 return 0;
861}
862
863int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
864{
865 struct inode *inode = dentry->d_inode;
866 int result = 0;
867 __le32 info_mask;
868 struct nw_modify_dos_info info;
869 struct ncp_server *server;
870
871 result = -EIO;
872
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 server = NCP_SERVER(inode);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200874 if (!server) /* How this could happen? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 goto out;
876
877 /* ageing the dentry to force validation */
878 ncp_age_dentry(server, dentry);
879
880 result = inode_change_ok(inode, attr);
881 if (result < 0)
882 goto out;
883
884 result = -EPERM;
885 if (((attr->ia_valid & ATTR_UID) &&
886 (attr->ia_uid != server->m.uid)))
887 goto out;
888
889 if (((attr->ia_valid & ATTR_GID) &&
890 (attr->ia_gid != server->m.gid)))
891 goto out;
892
893 if (((attr->ia_valid & ATTR_MODE) &&
894 (attr->ia_mode &
895 ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
896 goto out;
897
898 info_mask = 0;
899 memset(&info, 0, sizeof(info));
900
901#if 1
902 if ((attr->ia_valid & ATTR_MODE) != 0)
903 {
904 umode_t newmode = attr->ia_mode;
905
906 info_mask |= DM_ATTRIBUTES;
907
908 if (S_ISDIR(inode->i_mode)) {
909 newmode &= server->m.dir_mode;
910 } else {
911#ifdef CONFIG_NCPFS_EXTRAS
912 if (server->m.flags & NCP_MOUNT_EXTRAS) {
913 /* any non-default execute bit set */
914 if (newmode & ~server->m.file_mode & S_IXUGO)
915 info.attributes |= aSHARED | aSYSTEM;
916 /* read for group/world and not in default file_mode */
917 else if (newmode & ~server->m.file_mode & S_IRUGO)
918 info.attributes |= aSHARED;
919 } else
920#endif
921 newmode &= server->m.file_mode;
922 }
923 if (newmode & S_IWUGO)
924 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
925 else
926 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
927
928#ifdef CONFIG_NCPFS_NFS_NS
929 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
930 result = ncp_modify_nfs_info(server,
931 NCP_FINFO(inode)->volNumber,
932 NCP_FINFO(inode)->dirEntNum,
933 attr->ia_mode, 0);
934 if (result != 0)
935 goto out;
936 info.attributes &= ~(aSHARED | aSYSTEM);
937 {
938 /* mark partial success */
939 struct iattr tmpattr;
940
941 tmpattr.ia_valid = ATTR_MODE;
942 tmpattr.ia_mode = attr->ia_mode;
943
Christoph Hellwig10257742010-06-04 11:30:02 +0200944 setattr_copy(inode, &tmpattr);
945 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 }
947 }
948#endif
949 }
950#endif
951
952 /* Do SIZE before attributes, otherwise mtime together with size does not work...
953 */
954 if ((attr->ia_valid & ATTR_SIZE) != 0) {
955 int written;
956
957 DPRINTK("ncpfs: trying to change size to %ld\n",
958 attr->ia_size);
959
960 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
961 result = -EACCES;
962 goto out;
963 }
964 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
965 attr->ia_size, 0, "", &written);
966
967 /* According to ndir, the changes only take effect after
968 closing the file */
969 ncp_inode_close(inode);
970 result = ncp_make_closed(inode);
971 if (result)
972 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +0200973
974 if (attr->ia_size != i_size_read(inode)) {
975 result = vmtruncate(inode, attr->ia_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 if (result)
977 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +0200978 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 }
980 }
981 if ((attr->ia_valid & ATTR_CTIME) != 0) {
982 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
983 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
984 &info.creationTime, &info.creationDate);
985 }
986 if ((attr->ia_valid & ATTR_MTIME) != 0) {
987 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
988 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
989 &info.modifyTime, &info.modifyDate);
990 }
991 if ((attr->ia_valid & ATTR_ATIME) != 0) {
992 __le16 dummy;
993 info_mask |= (DM_LAST_ACCESS_DATE);
994 ncp_date_unix2dos(attr->ia_atime.tv_sec,
995 &dummy, &info.lastAccessDate);
996 }
997 if (info_mask != 0) {
998 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
999 inode, info_mask, &info);
1000 if (result != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
1002 /* NetWare seems not to allow this. I
1003 do not know why. So, just tell the
1004 user everything went fine. This is
1005 a terrible hack, but I do not know
1006 how to do this correctly. */
1007 result = 0;
1008 } else
1009 goto out;
1010 }
1011#ifdef CONFIG_NCPFS_STRONG
1012 if ((!result) && (info_mask & DM_ATTRIBUTES))
1013 NCP_FINFO(inode)->nwattr = info.attributes;
1014#endif
1015 }
Christoph Hellwig10257742010-06-04 11:30:02 +02001016 if (result)
1017 goto out;
1018
1019 setattr_copy(inode, attr);
1020 mark_inode_dirty(inode);
1021
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022out:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001023 if (result > 0)
1024 result = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 return result;
1026}
1027
Al Viro3c26ff62010-07-25 11:46:36 +04001028static struct dentry *ncp_mount(struct file_system_type *fs_type,
1029 int flags, const char *dev_name, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030{
Al Viro3c26ff62010-07-25 11:46:36 +04001031 return mount_nodev(fs_type, flags, data, ncp_fill_super);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032}
1033
1034static struct file_system_type ncp_fs_type = {
1035 .owner = THIS_MODULE,
1036 .name = "ncpfs",
Al Viro3c26ff62010-07-25 11:46:36 +04001037 .mount = ncp_mount,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 .kill_sb = kill_anon_super,
Miklos Szeredi564cd132008-02-08 04:21:46 -08001039 .fs_flags = FS_BINARY_MOUNTDATA,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040};
1041
1042static int __init init_ncp_fs(void)
1043{
1044 int err;
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001045 DPRINTK("ncpfs: init_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 err = init_inodecache();
1048 if (err)
1049 goto out1;
1050 err = register_filesystem(&ncp_fs_type);
1051 if (err)
1052 goto out;
1053 return 0;
1054out:
1055 destroy_inodecache();
1056out1:
1057 return err;
1058}
1059
1060static void __exit exit_ncp_fs(void)
1061{
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001062 DPRINTK("ncpfs: exit_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 unregister_filesystem(&ncp_fs_type);
1064 destroy_inodecache();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065}
1066
1067module_init(init_ncp_fs)
1068module_exit(exit_ncp_fs)
1069MODULE_LICENSE("GPL");