blob: 87484fb8d1773b07e42c6ec63a7ec50533fd0b60 [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 Pigginfa0d7e32011-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 Pigginfa0d7e32011-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 Pigginfa0d7e32011-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{
Alexey Dobriyan1a1d92c2006-09-27 01:49:40 -070092 kmem_cache_destroy(ncp_inode_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -070093}
94
95static int ncp_remount(struct super_block *sb, int *flags, char* data)
96{
97 *flags |= MS_NODIRATIME;
98 return 0;
99}
100
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800101static const struct super_operations ncp_sops =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102{
103 .alloc_inode = ncp_alloc_inode,
104 .destroy_inode = ncp_destroy_inode,
105 .drop_inode = generic_delete_inode,
Al Viro94ee8492010-06-07 00:45:56 -0400106 .evict_inode = ncp_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 .put_super = ncp_put_super,
108 .statfs = ncp_statfs,
109 .remount_fs = ncp_remount,
Miklos Szeredi564cd132008-02-08 04:21:46 -0800110 .show_options = ncp_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111};
112
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113/*
114 * Fill in the ncpfs-specific information in the inode.
115 */
116static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
117{
118 NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
119 NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
120 NCP_FINFO(inode)->volNumber = nwinfo->volume;
121}
122
123void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
124{
125 ncp_update_dirent(inode, nwinfo);
126 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
127 NCP_FINFO(inode)->access = nwinfo->access;
128 memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
129 sizeof(nwinfo->file_handle));
130 DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
131 nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
132 NCP_FINFO(inode)->dirEntNum);
133}
134
135static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
136{
137 /* NFS namespace mode overrides others if it's set. */
138 DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n",
139 nwi->entryName, nwi->nfs.mode);
140 if (nwi->nfs.mode) {
141 /* XXX Security? */
142 inode->i_mode = nwi->nfs.mode;
143 }
144
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200145 inode->i_blocks = (i_size_read(inode) + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146
147 inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate);
148 inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate);
149 inode->i_atime.tv_sec = ncp_date_dos2unix(0, nwi->lastAccessDate);
150 inode->i_atime.tv_nsec = 0;
151 inode->i_mtime.tv_nsec = 0;
152 inode->i_ctime.tv_nsec = 0;
153}
154
155static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
156{
157 struct nw_info_struct *nwi = &nwinfo->i;
158 struct ncp_server *server = NCP_SERVER(inode);
159
160 if (nwi->attributes & aDIR) {
161 inode->i_mode = server->m.dir_mode;
162 /* for directories dataStreamSize seems to be some
163 Object ID ??? */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200164 i_size_write(inode, NCP_BLOCK_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 } else {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200166 u32 size;
167
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 inode->i_mode = server->m.file_mode;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200169 size = le32_to_cpu(nwi->dataStreamSize);
170 i_size_write(inode, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171#ifdef CONFIG_NCPFS_EXTRAS
172 if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS))
173 && (nwi->attributes & aSHARED)) {
174 switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
175 case aHIDDEN:
176 if (server->m.flags & NCP_MOUNT_SYMLINKS) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200177 if (/* (size >= NCP_MIN_SYMLINK_SIZE)
178 && */ (size <= NCP_MAX_SYMLINK_SIZE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
180 NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
181 break;
182 }
183 }
184 /* FALLTHROUGH */
185 case 0:
186 if (server->m.flags & NCP_MOUNT_EXTRAS)
187 inode->i_mode |= S_IRUGO;
188 break;
189 case aSYSTEM:
190 if (server->m.flags & NCP_MOUNT_EXTRAS)
191 inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO;
192 break;
193 /* case aSYSTEM|aHIDDEN: */
194 default:
195 /* reserved combination */
196 break;
197 }
198 }
199#endif
200 }
201 if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
202}
203
204void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
205{
206 NCP_FINFO(inode)->flags = 0;
207 if (!atomic_read(&NCP_FINFO(inode)->opened)) {
208 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
209 ncp_update_attrs(inode, nwinfo);
210 }
211
212 ncp_update_dates(inode, &nwinfo->i);
213 ncp_update_dirent(inode, nwinfo);
214}
215
216/*
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200217 * Fill in the inode based on the ncp_entry_info structure. Used only for brand new inodes.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 */
219static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
220{
221 struct ncp_server *server = NCP_SERVER(inode);
222
223 NCP_FINFO(inode)->flags = 0;
224
225 ncp_update_attrs(inode, nwinfo);
226
227 DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
228
Miklos Szeredibfe86842011-10-28 14:13:29 +0200229 set_nlink(inode, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 inode->i_uid = server->m.uid;
231 inode->i_gid = server->m.gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
233 ncp_update_dates(inode, &nwinfo->i);
234 ncp_update_inode(inode, nwinfo);
235}
236
237#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800238static const struct inode_operations ncp_symlink_inode_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 .readlink = generic_readlink,
240 .follow_link = page_follow_link_light,
241 .put_link = page_put_link,
242 .setattr = ncp_notify_change,
243};
244#endif
245
246/*
247 * Get a new inode.
248 */
249struct inode *
250ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
251{
252 struct inode *inode;
253
254 if (info == NULL) {
255 printk(KERN_ERR "ncp_iget: info is NULL\n");
256 return NULL;
257 }
258
259 inode = new_inode(sb);
260 if (inode) {
261 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
262
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200263 inode->i_mapping->backing_dev_info = sb->s_bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 inode->i_ino = info->ino;
265 ncp_set_attr(inode, info);
266 if (S_ISREG(inode->i_mode)) {
267 inode->i_op = &ncp_file_inode_operations;
268 inode->i_fop = &ncp_file_operations;
269 } else if (S_ISDIR(inode->i_mode)) {
270 inode->i_op = &ncp_dir_inode_operations;
271 inode->i_fop = &ncp_dir_operations;
272#ifdef CONFIG_NCPFS_NFS_NS
273 } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
274 init_special_inode(inode, inode->i_mode,
275 new_decode_dev(info->i.nfs.rdev));
276#endif
277#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
278 } else if (S_ISLNK(inode->i_mode)) {
279 inode->i_op = &ncp_symlink_inode_operations;
280 inode->i_data.a_ops = &ncp_symlink_aops;
281#endif
282 } else {
283 make_bad_inode(inode);
284 }
285 insert_inode_hash(inode);
286 } else
287 printk(KERN_ERR "ncp_iget: iget failed!\n");
288 return inode;
289}
290
291static void
Al Viro94ee8492010-06-07 00:45:56 -0400292ncp_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293{
Mark Fashehfef26652005-09-09 13:01:31 -0700294 truncate_inode_pages(&inode->i_data, 0);
Al Viro94ee8492010-06-07 00:45:56 -0400295 end_writeback(inode);
Mark Fashehfef26652005-09-09 13:01:31 -0700296
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 if (S_ISDIR(inode->i_mode)) {
Al Viro94ee8492010-06-07 00:45:56 -0400298 DDPRINTK("ncp_evict_inode: put directory %ld\n", inode->i_ino);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 }
300
301 if (ncp_make_closed(inode) != 0) {
302 /* We can't do anything but complain. */
Al Viro94ee8492010-06-07 00:45:56 -0400303 printk(KERN_ERR "ncp_evict_inode: could not close\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305}
306
307static void ncp_stop_tasks(struct ncp_server *server) {
308 struct sock* sk = server->ncp_sock->sk;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200309
310 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 sk->sk_error_report = server->error_report;
312 sk->sk_data_ready = server->data_ready;
313 sk->sk_write_space = server->write_space;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200314 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 del_timer_sync(&server->timeout_tm);
Tejun Heo5d8e4bd2010-12-24 15:59:06 +0100316
317 flush_work_sync(&server->rcv.tq);
318 if (sk->sk_socket->type == SOCK_STREAM)
319 flush_work_sync(&server->tx.tq);
320 else
321 flush_work_sync(&server->timeout_tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322}
323
Al Viro34c80b12011-12-08 21:32:45 -0500324static int ncp_show_options(struct seq_file *seq, struct dentry *root)
Miklos Szeredi564cd132008-02-08 04:21:46 -0800325{
Al Viro34c80b12011-12-08 21:32:45 -0500326 struct ncp_server *server = NCP_SBP(root->d_sb);
Miklos Szeredi564cd132008-02-08 04:21:46 -0800327 unsigned int tmp;
328
329 if (server->m.uid != 0)
330 seq_printf(seq, ",uid=%u", server->m.uid);
331 if (server->m.gid != 0)
332 seq_printf(seq, ",gid=%u", server->m.gid);
333 if (server->m.mounted_uid != 0)
334 seq_printf(seq, ",owner=%u", server->m.mounted_uid);
335 tmp = server->m.file_mode & S_IALLUGO;
336 if (tmp != NCP_DEFAULT_FILE_MODE)
337 seq_printf(seq, ",mode=0%o", tmp);
338 tmp = server->m.dir_mode & S_IALLUGO;
339 if (tmp != NCP_DEFAULT_DIR_MODE)
340 seq_printf(seq, ",dirmode=0%o", tmp);
341 if (server->m.time_out != NCP_DEFAULT_TIME_OUT * HZ / 100) {
342 tmp = server->m.time_out * 100 / HZ;
343 seq_printf(seq, ",timeout=%u", tmp);
344 }
345 if (server->m.retry_count != NCP_DEFAULT_RETRY_COUNT)
346 seq_printf(seq, ",retry=%u", server->m.retry_count);
347 if (server->m.flags != 0)
348 seq_printf(seq, ",flags=%lu", server->m.flags);
349 if (server->m.wdog_pid != NULL)
350 seq_printf(seq, ",wdogpid=%u", pid_vnr(server->m.wdog_pid));
351
352 return 0;
353}
354
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355static const struct ncp_option ncp_opts[] = {
356 { "uid", OPT_INT, 'u' },
357 { "gid", OPT_INT, 'g' },
358 { "owner", OPT_INT, 'o' },
359 { "mode", OPT_INT, 'm' },
360 { "dirmode", OPT_INT, 'd' },
361 { "timeout", OPT_INT, 't' },
362 { "retry", OPT_INT, 'r' },
363 { "flags", OPT_INT, 'f' },
364 { "wdogpid", OPT_INT, 'w' },
365 { "ncpfd", OPT_INT, 'n' },
366 { "infofd", OPT_INT, 'i' }, /* v5 */
367 { "version", OPT_INT, 'v' },
368 { NULL, 0, 0 } };
369
370static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
371 int optval;
372 char *optarg;
373 unsigned long optint;
374 int version = 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800375 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376
377 data->flags = 0;
378 data->int_flags = 0;
379 data->mounted_uid = 0;
Eric W. Biederman21542272006-12-13 00:35:11 -0800380 data->wdog_pid = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 data->ncp_fd = ~0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800382 data->time_out = NCP_DEFAULT_TIME_OUT;
383 data->retry_count = NCP_DEFAULT_RETRY_COUNT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 data->uid = 0;
385 data->gid = 0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800386 data->file_mode = NCP_DEFAULT_FILE_MODE;
387 data->dir_mode = NCP_DEFAULT_DIR_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 data->info_fd = -1;
389 data->mounted_vol[0] = 0;
390
391 while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
Eric W. Biederman1de24122006-12-13 00:35:13 -0800392 ret = optval;
393 if (ret < 0)
394 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 switch (optval) {
396 case 'u':
397 data->uid = optint;
398 break;
399 case 'g':
400 data->gid = optint;
401 break;
402 case 'o':
403 data->mounted_uid = optint;
404 break;
405 case 'm':
406 data->file_mode = optint;
407 break;
408 case 'd':
409 data->dir_mode = optint;
410 break;
411 case 't':
412 data->time_out = optint;
413 break;
414 case 'r':
415 data->retry_count = optint;
416 break;
417 case 'f':
418 data->flags = optint;
419 break;
420 case 'w':
Eric W. Biederman21542272006-12-13 00:35:11 -0800421 data->wdog_pid = find_get_pid(optint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 break;
423 case 'n':
424 data->ncp_fd = optint;
425 break;
426 case 'i':
427 data->info_fd = optint;
428 break;
429 case 'v':
Eric W. Biederman1de24122006-12-13 00:35:13 -0800430 ret = -ECHRNG;
431 if (optint < NCP_MOUNT_VERSION_V4)
432 goto err;
433 if (optint > NCP_MOUNT_VERSION_V5)
434 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 version = optint;
436 break;
437
438 }
439 }
440 return 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800441err:
442 put_pid(data->wdog_pid);
443 data->wdog_pid = NULL;
444 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445}
446
447static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
448{
449 struct ncp_mount_data_kernel data;
450 struct ncp_server *server;
451 struct file *ncp_filp;
452 struct inode *root_inode;
453 struct inode *sock_inode;
454 struct socket *sock;
455 int error;
456 int default_bufsize;
457#ifdef CONFIG_NCPFS_PACKET_SIGNING
458 int options;
459#endif
460 struct ncp_entry_info finfo;
461
Andrew Morton2a5cac12011-05-24 17:13:42 -0700462 memset(&data, 0, sizeof(data));
Panagiotis Issarisf8314dc2006-09-27 01:49:37 -0700463 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 if (!server)
465 return -ENOMEM;
466 sb->s_fs_info = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
468 error = -EFAULT;
469 if (raw_data == NULL)
470 goto out;
471 switch (*(int*)raw_data) {
472 case NCP_MOUNT_VERSION:
473 {
474 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
475
476 data.flags = md->flags;
477 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
478 data.mounted_uid = md->mounted_uid;
Eric W. Biederman21542272006-12-13 00:35:11 -0800479 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 data.ncp_fd = md->ncp_fd;
481 data.time_out = md->time_out;
482 data.retry_count = md->retry_count;
483 data.uid = md->uid;
484 data.gid = md->gid;
485 data.file_mode = md->file_mode;
486 data.dir_mode = md->dir_mode;
487 data.info_fd = -1;
488 memcpy(data.mounted_vol, md->mounted_vol,
489 NCP_VOLNAME_LEN+1);
490 }
491 break;
492 case NCP_MOUNT_VERSION_V4:
493 {
494 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
495
496 data.flags = md->flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 data.mounted_uid = md->mounted_uid;
Eric W. Biederman21542272006-12-13 00:35:11 -0800498 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 data.ncp_fd = md->ncp_fd;
500 data.time_out = md->time_out;
501 data.retry_count = md->retry_count;
502 data.uid = md->uid;
503 data.gid = md->gid;
504 data.file_mode = md->file_mode;
505 data.dir_mode = md->dir_mode;
506 data.info_fd = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 }
508 break;
509 default:
510 error = -ECHRNG;
511 if (memcmp(raw_data, "vers", 4) == 0) {
512 error = ncp_parse_options(&data, raw_data);
513 }
514 if (error)
515 goto out;
516 break;
517 }
518 error = -EBADF;
519 ncp_filp = fget(data.ncp_fd);
520 if (!ncp_filp)
521 goto out;
522 error = -ENOTSOCK;
Josef Sipek92e5bae2006-12-08 02:37:22 -0800523 sock_inode = ncp_filp->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 if (!S_ISSOCK(sock_inode->i_mode))
525 goto out_fput;
526 sock = SOCKET_I(sock_inode);
527 if (!sock)
528 goto out_fput;
529
530 if (sock->type == SOCK_STREAM)
531 default_bufsize = 0xF000;
532 else
533 default_bufsize = 1024;
534
535 sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
536 sb->s_maxbytes = 0xFFFFFFFFU;
537 sb->s_blocksize = 1024; /* Eh... Is this correct? */
538 sb->s_blocksize_bits = 10;
539 sb->s_magic = NCP_SUPER_MAGIC;
540 sb->s_op = &ncp_sops;
Al Viro0378c402011-01-12 17:25:03 -0500541 sb->s_d_op = &ncp_dentry_operations;
Jens Axboef1970c72010-04-22 12:31:11 +0200542 sb->s_bdi = &server->bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
544 server = NCP_SBP(sb);
545 memset(server, 0, sizeof(*server));
546
Jens Axboef1970c72010-04-22 12:31:11 +0200547 error = bdi_setup_and_register(&server->bdi, "ncpfs", BDI_CAP_MAP_COPY);
548 if (error)
Djalal Harouni759c3612011-12-13 02:47:29 +0100549 goto out_fput;
Jens Axboef1970c72010-04-22 12:31:11 +0200550
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 server->ncp_filp = ncp_filp;
552 server->ncp_sock = sock;
553
554 if (data.info_fd != -1) {
555 struct socket *info_sock;
556
557 error = -EBADF;
558 server->info_filp = fget(data.info_fd);
559 if (!server->info_filp)
Djalal Harouni759c3612011-12-13 02:47:29 +0100560 goto out_bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 error = -ENOTSOCK;
Josef Sipek92e5bae2006-12-08 02:37:22 -0800562 sock_inode = server->info_filp->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 if (!S_ISSOCK(sock_inode->i_mode))
564 goto out_fput2;
565 info_sock = SOCKET_I(sock_inode);
566 if (!info_sock)
567 goto out_fput2;
568 error = -EBADFD;
569 if (info_sock->type != SOCK_STREAM)
570 goto out_fput2;
571 server->info_sock = info_sock;
572 }
573
574/* server->lock = 0; */
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800575 mutex_init(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 server->packet = NULL;
577/* server->buffer_size = 0; */
578/* server->conn_status = 0; */
579/* server->root_dentry = NULL; */
580/* server->root_setuped = 0; */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200581 mutex_init(&server->root_setup_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582#ifdef CONFIG_NCPFS_PACKET_SIGNING
583/* server->sign_wanted = 0; */
584/* server->sign_active = 0; */
585#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200586 init_rwsem(&server->auth_rwsem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 server->auth.auth_type = NCP_AUTH_NONE;
588/* server->auth.object_name_len = 0; */
589/* server->auth.object_name = NULL; */
590/* server->auth.object_type = 0; */
591/* server->priv.len = 0; */
592/* server->priv.data = NULL; */
593
594 server->m = data;
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300595 /* Although anything producing this is buggy, it happens
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 now because of PATH_MAX changes.. */
597 if (server->m.time_out < 1) {
598 server->m.time_out = 10;
599 printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
600 }
601 server->m.time_out = server->m.time_out * HZ / 100;
602 server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
603 server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
604
605#ifdef CONFIG_NCPFS_NLS
606 /* load the default NLS charsets */
607 server->nls_vol = load_nls_default();
608 server->nls_io = load_nls_default();
609#endif /* CONFIG_NCPFS_NLS */
610
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200611 atomic_set(&server->dentry_ttl, 0); /* no caching */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
613 INIT_LIST_HEAD(&server->tx.requests);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800614 mutex_init(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 server->tx.creq = NULL;
616 server->rcv.creq = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
618 init_timer(&server->timeout_tm);
619#undef NCP_PACKET_SIZE
620#define NCP_PACKET_SIZE 131072
621 error = -ENOMEM;
622 server->packet_size = NCP_PACKET_SIZE;
623 server->packet = vmalloc(NCP_PACKET_SIZE);
624 if (server->packet == NULL)
625 goto out_nls;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100626 server->txbuf = vmalloc(NCP_PACKET_SIZE);
627 if (server->txbuf == NULL)
628 goto out_packet;
629 server->rxbuf = vmalloc(NCP_PACKET_SIZE);
630 if (server->rxbuf == NULL)
631 goto out_txbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200633 lock_sock(sock->sk);
634 server->data_ready = sock->sk->sk_data_ready;
635 server->write_space = sock->sk->sk_write_space;
636 server->error_report = sock->sk->sk_error_report;
637 sock->sk->sk_user_data = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 sock->sk->sk_data_ready = ncp_tcp_data_ready;
639 sock->sk->sk_error_report = ncp_tcp_error_report;
640 if (sock->type == SOCK_STREAM) {
641 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
642 server->rcv.len = 10;
643 server->rcv.state = 0;
David Howellsc4028952006-11-22 14:57:56 +0000644 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
645 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 sock->sk->sk_write_space = ncp_tcp_write_space;
647 } else {
David Howellsc4028952006-11-22 14:57:56 +0000648 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
649 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 server->timeout_tm.data = (unsigned long)server;
651 server->timeout_tm.function = ncpdgram_timeout_call;
652 }
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200653 release_sock(sock->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
655 ncp_lock_server(server);
656 error = ncp_connect(server);
657 ncp_unlock_server(server);
658 if (error < 0)
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100659 goto out_rxbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
661
662 error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */
663#ifdef CONFIG_NCPFS_PACKET_SIGNING
664 if (ncp_negotiate_size_and_options(server, default_bufsize,
665 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
666 {
667 if (options != NCP_DEFAULT_OPTIONS)
668 {
669 if (ncp_negotiate_size_and_options(server,
670 default_bufsize,
671 options & 2,
672 &(server->buffer_size), &options) != 0)
673
674 {
675 goto out_disconnect;
676 }
677 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200678 ncp_lock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 if (options & 2)
680 server->sign_wanted = 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200681 ncp_unlock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 }
683 else
684#endif /* CONFIG_NCPFS_PACKET_SIGNING */
685 if (ncp_negotiate_buffersize(server, default_bufsize,
686 &(server->buffer_size)) != 0)
687 goto out_disconnect;
688 DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
689
690 memset(&finfo, 0, sizeof(finfo));
691 finfo.i.attributes = aDIR;
692 finfo.i.dataStreamSize = 0; /* ignored */
693 finfo.i.dirEntNum = 0;
694 finfo.i.DosDirNum = 0;
695#ifdef CONFIG_NCPFS_SMALLDOS
696 finfo.i.NSCreator = NW_NS_DOS;
697#endif
698 finfo.volume = NCP_NUMBER_OF_VOLUMES;
699 /* set dates of mountpoint to Jan 1, 1986; 00:00 */
700 finfo.i.creationTime = finfo.i.modifyTime
701 = cpu_to_le16(0x0000);
702 finfo.i.creationDate = finfo.i.modifyDate
703 = finfo.i.lastAccessDate
704 = cpu_to_le16(0x0C21);
705 finfo.i.nameLen = 0;
706 finfo.i.entryName[0] = '\0';
707
708 finfo.opened = 0;
709 finfo.ino = 2; /* tradition */
710
711 server->name_space[finfo.volume] = NW_NS_DOS;
712
713 error = -ENOMEM;
714 root_inode = ncp_iget(sb, &finfo);
715 if (!root_inode)
716 goto out_disconnect;
717 DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
Al Viro48fde702012-01-08 22:15:13 -0500718 sb->s_root = d_make_root(root_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 if (!sb->s_root)
Al Viro48fde702012-01-08 22:15:13 -0500720 goto out_disconnect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 return 0;
722
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723out_disconnect:
724 ncp_lock_server(server);
725 ncp_disconnect(server);
726 ncp_unlock_server(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100727out_rxbuf:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 ncp_stop_tasks(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100729 vfree(server->rxbuf);
730out_txbuf:
731 vfree(server->txbuf);
732out_packet:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 vfree(server->packet);
734out_nls:
735#ifdef CONFIG_NCPFS_NLS
736 unload_nls(server->nls_io);
737 unload_nls(server->nls_vol);
738#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200739 mutex_destroy(&server->rcv.creq_mutex);
740 mutex_destroy(&server->root_setup_lock);
741 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742out_fput2:
743 if (server->info_filp)
744 fput(server->info_filp);
Jens Axboef1970c72010-04-22 12:31:11 +0200745out_bdi:
Djalal Harouni759c3612011-12-13 02:47:29 +0100746 bdi_destroy(&server->bdi);
747out_fput:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
749 *
Matthew Whitworthe956b4b2010-06-27 14:34:30 +0100750 * The previously used put_filp(ncp_filp); was bogus, since
751 * it doesn't perform proper unlocking.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 */
753 fput(ncp_filp);
754out:
Eric W. Biederman1de24122006-12-13 00:35:13 -0800755 put_pid(data.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 sb->s_fs_info = NULL;
757 kfree(server);
758 return error;
759}
760
761static void ncp_put_super(struct super_block *sb)
762{
763 struct ncp_server *server = NCP_SBP(sb);
764
765 ncp_lock_server(server);
766 ncp_disconnect(server);
767 ncp_unlock_server(server);
768
769 ncp_stop_tasks(server);
770
771#ifdef CONFIG_NCPFS_NLS
772 /* unload the NLS charsets */
Thomas Gleixner6d729e42009-08-16 21:05:08 +0000773 unload_nls(server->nls_vol);
774 unload_nls(server->nls_io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775#endif /* CONFIG_NCPFS_NLS */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200776 mutex_destroy(&server->rcv.creq_mutex);
777 mutex_destroy(&server->root_setup_lock);
778 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
780 if (server->info_filp)
781 fput(server->info_filp);
782 fput(server->ncp_filp);
Eric W. Biederman21542272006-12-13 00:35:11 -0800783 kill_pid(server->m.wdog_pid, SIGTERM, 1);
784 put_pid(server->m.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785
Jens Axboef1970c72010-04-22 12:31:11 +0200786 bdi_destroy(&server->bdi);
Pekka Enberg44db77f2006-01-14 13:21:12 -0800787 kfree(server->priv.data);
788 kfree(server->auth.object_name);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100789 vfree(server->rxbuf);
790 vfree(server->txbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 vfree(server->packet);
792 sb->s_fs_info = NULL;
793 kfree(server);
794}
795
David Howells726c3342006-06-23 02:02:58 -0700796static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797{
798 struct dentry* d;
799 struct inode* i;
800 struct ncp_inode_info* ni;
801 struct ncp_server* s;
802 struct ncp_volume_info vi;
David Howells726c3342006-06-23 02:02:58 -0700803 struct super_block *sb = dentry->d_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 int err;
805 __u8 dh;
806
807 d = sb->s_root;
808 if (!d) {
809 goto dflt;
810 }
811 i = d->d_inode;
812 if (!i) {
813 goto dflt;
814 }
815 ni = NCP_FINFO(i);
816 if (!ni) {
817 goto dflt;
818 }
819 s = NCP_SBP(sb);
820 if (!s) {
821 goto dflt;
822 }
823 if (!s->m.mounted_vol[0]) {
824 goto dflt;
825 }
826
827 err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
828 if (err) {
829 goto dflt;
830 }
831 err = ncp_get_directory_info(s, dh, &vi);
832 ncp_dirhandle_free(s, dh);
833 if (err) {
834 goto dflt;
835 }
836 buf->f_type = NCP_SUPER_MAGIC;
837 buf->f_bsize = vi.sectors_per_block * 512;
838 buf->f_blocks = vi.total_blocks;
839 buf->f_bfree = vi.free_blocks;
840 buf->f_bavail = vi.free_blocks;
841 buf->f_files = vi.total_dir_entries;
842 buf->f_ffree = vi.available_dir_entries;
843 buf->f_namelen = 12;
844 return 0;
845
846 /* We cannot say how much disk space is left on a mounted
847 NetWare Server, because free space is distributed over
848 volumes, and the current user might have disk quotas. So
849 free space is not that simple to determine. Our decision
850 here is to err conservatively. */
851
852dflt:;
853 buf->f_type = NCP_SUPER_MAGIC;
854 buf->f_bsize = NCP_BLOCK_SIZE;
855 buf->f_blocks = 0;
856 buf->f_bfree = 0;
857 buf->f_bavail = 0;
858 buf->f_namelen = 12;
859 return 0;
860}
861
862int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
863{
864 struct inode *inode = dentry->d_inode;
865 int result = 0;
866 __le32 info_mask;
867 struct nw_modify_dos_info info;
868 struct ncp_server *server;
869
870 result = -EIO;
871
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 server = NCP_SERVER(inode);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200873 if (!server) /* How this could happen? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 goto out;
875
876 /* ageing the dentry to force validation */
877 ncp_age_dentry(server, dentry);
878
879 result = inode_change_ok(inode, attr);
880 if (result < 0)
881 goto out;
882
883 result = -EPERM;
884 if (((attr->ia_valid & ATTR_UID) &&
885 (attr->ia_uid != server->m.uid)))
886 goto out;
887
888 if (((attr->ia_valid & ATTR_GID) &&
889 (attr->ia_gid != server->m.gid)))
890 goto out;
891
892 if (((attr->ia_valid & ATTR_MODE) &&
893 (attr->ia_mode &
894 ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
895 goto out;
896
897 info_mask = 0;
898 memset(&info, 0, sizeof(info));
899
900#if 1
901 if ((attr->ia_valid & ATTR_MODE) != 0)
902 {
903 umode_t newmode = attr->ia_mode;
904
905 info_mask |= DM_ATTRIBUTES;
906
907 if (S_ISDIR(inode->i_mode)) {
908 newmode &= server->m.dir_mode;
909 } else {
910#ifdef CONFIG_NCPFS_EXTRAS
911 if (server->m.flags & NCP_MOUNT_EXTRAS) {
912 /* any non-default execute bit set */
913 if (newmode & ~server->m.file_mode & S_IXUGO)
914 info.attributes |= aSHARED | aSYSTEM;
915 /* read for group/world and not in default file_mode */
916 else if (newmode & ~server->m.file_mode & S_IRUGO)
917 info.attributes |= aSHARED;
918 } else
919#endif
920 newmode &= server->m.file_mode;
921 }
922 if (newmode & S_IWUGO)
923 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
924 else
925 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
926
927#ifdef CONFIG_NCPFS_NFS_NS
928 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
929 result = ncp_modify_nfs_info(server,
930 NCP_FINFO(inode)->volNumber,
931 NCP_FINFO(inode)->dirEntNum,
932 attr->ia_mode, 0);
933 if (result != 0)
934 goto out;
935 info.attributes &= ~(aSHARED | aSYSTEM);
936 {
937 /* mark partial success */
938 struct iattr tmpattr;
939
940 tmpattr.ia_valid = ATTR_MODE;
941 tmpattr.ia_mode = attr->ia_mode;
942
Christoph Hellwig10257742010-06-04 11:30:02 +0200943 setattr_copy(inode, &tmpattr);
944 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 }
946 }
947#endif
948 }
949#endif
950
951 /* Do SIZE before attributes, otherwise mtime together with size does not work...
952 */
953 if ((attr->ia_valid & ATTR_SIZE) != 0) {
954 int written;
955
956 DPRINTK("ncpfs: trying to change size to %ld\n",
957 attr->ia_size);
958
959 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
960 result = -EACCES;
961 goto out;
962 }
963 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
964 attr->ia_size, 0, "", &written);
965
966 /* According to ndir, the changes only take effect after
967 closing the file */
968 ncp_inode_close(inode);
969 result = ncp_make_closed(inode);
970 if (result)
971 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +0200972
973 if (attr->ia_size != i_size_read(inode)) {
974 result = vmtruncate(inode, attr->ia_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 if (result)
976 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +0200977 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 }
979 }
980 if ((attr->ia_valid & ATTR_CTIME) != 0) {
981 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
982 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
983 &info.creationTime, &info.creationDate);
984 }
985 if ((attr->ia_valid & ATTR_MTIME) != 0) {
986 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
987 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
988 &info.modifyTime, &info.modifyDate);
989 }
990 if ((attr->ia_valid & ATTR_ATIME) != 0) {
991 __le16 dummy;
992 info_mask |= (DM_LAST_ACCESS_DATE);
993 ncp_date_unix2dos(attr->ia_atime.tv_sec,
994 &dummy, &info.lastAccessDate);
995 }
996 if (info_mask != 0) {
997 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
998 inode, info_mask, &info);
999 if (result != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
1001 /* NetWare seems not to allow this. I
1002 do not know why. So, just tell the
1003 user everything went fine. This is
1004 a terrible hack, but I do not know
1005 how to do this correctly. */
1006 result = 0;
1007 } else
1008 goto out;
1009 }
1010#ifdef CONFIG_NCPFS_STRONG
1011 if ((!result) && (info_mask & DM_ATTRIBUTES))
1012 NCP_FINFO(inode)->nwattr = info.attributes;
1013#endif
1014 }
Christoph Hellwig10257742010-06-04 11:30:02 +02001015 if (result)
1016 goto out;
1017
1018 setattr_copy(inode, attr);
1019 mark_inode_dirty(inode);
1020
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021out:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001022 if (result > 0)
1023 result = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 return result;
1025}
1026
Al Viro3c26ff62010-07-25 11:46:36 +04001027static struct dentry *ncp_mount(struct file_system_type *fs_type,
1028 int flags, const char *dev_name, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029{
Al Viro3c26ff62010-07-25 11:46:36 +04001030 return mount_nodev(fs_type, flags, data, ncp_fill_super);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031}
1032
1033static struct file_system_type ncp_fs_type = {
1034 .owner = THIS_MODULE,
1035 .name = "ncpfs",
Al Viro3c26ff62010-07-25 11:46:36 +04001036 .mount = ncp_mount,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 .kill_sb = kill_anon_super,
Miklos Szeredi564cd132008-02-08 04:21:46 -08001038 .fs_flags = FS_BINARY_MOUNTDATA,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039};
1040
1041static int __init init_ncp_fs(void)
1042{
1043 int err;
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001044 DPRINTK("ncpfs: init_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 err = init_inodecache();
1047 if (err)
1048 goto out1;
1049 err = register_filesystem(&ncp_fs_type);
1050 if (err)
1051 goto out;
1052 return 0;
1053out:
1054 destroy_inodecache();
1055out1:
1056 return err;
1057}
1058
1059static void __exit exit_ncp_fs(void)
1060{
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001061 DPRINTK("ncpfs: exit_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 unregister_filesystem(&ncp_fs_type);
1063 destroy_inodecache();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064}
1065
1066module_init(init_ncp_fs)
1067module_exit(exit_ncp_fs)
1068MODULE_LICENSE("GPL");