blob: 9531c052d7a487a0b46d347ffed016ea06bdcd50 [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
34#include <linux/ncp_fs.h>
35
36#include <net/sock.h>
37
38#include "ncplib_kernel.h"
39#include "getopt.h"
40
Miklos Szeredi564cd132008-02-08 04:21:46 -080041#define NCP_DEFAULT_FILE_MODE 0600
42#define NCP_DEFAULT_DIR_MODE 0700
43#define NCP_DEFAULT_TIME_OUT 10
44#define NCP_DEFAULT_RETRY_COUNT 20
45
Al Viro94ee8492010-06-07 00:45:56 -040046static void ncp_evict_inode(struct inode *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070047static void ncp_put_super(struct super_block *);
David Howells726c3342006-06-23 02:02:58 -070048static int ncp_statfs(struct dentry *, struct kstatfs *);
Miklos Szeredi564cd132008-02-08 04:21:46 -080049static int ncp_show_options(struct seq_file *, struct vfsmount *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
Christoph Lametere18b8902006-12-06 20:33:20 -080051static struct kmem_cache * ncp_inode_cachep;
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53static struct inode *ncp_alloc_inode(struct super_block *sb)
54{
55 struct ncp_inode_info *ei;
Christoph Lametere94b1762006-12-06 20:33:17 -080056 ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 if (!ei)
58 return NULL;
59 return &ei->vfs_inode;
60}
61
Nick Pigginfa0d7e32011-01-07 17:49:49 +110062static void ncp_i_callback(struct rcu_head *head)
63{
64 struct inode *inode = container_of(head, struct inode, i_rcu);
65 INIT_LIST_HEAD(&inode->i_dentry);
66 kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
67}
68
Linus Torvalds1da177e2005-04-16 15:20:36 -070069static void ncp_destroy_inode(struct inode *inode)
70{
Nick Pigginfa0d7e32011-01-07 17:49:49 +110071 call_rcu(&inode->i_rcu, ncp_i_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -070072}
73
Alexey Dobriyan51cc5062008-07-25 19:45:34 -070074static void init_once(void *foo)
Linus Torvalds1da177e2005-04-16 15:20:36 -070075{
76 struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
77
Christoph Lametera35afb82007-05-16 22:10:57 -070078 mutex_init(&ei->open_mutex);
79 inode_init_once(&ei->vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080}
Paul Mundt20c2df82007-07-20 10:11:58 +090081
Linus Torvalds1da177e2005-04-16 15:20:36 -070082static int init_inodecache(void)
83{
84 ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
85 sizeof(struct ncp_inode_info),
Paul Jacksonfffb60f2006-03-24 03:16:06 -080086 0, (SLAB_RECLAIM_ACCOUNT|
87 SLAB_MEM_SPREAD),
Paul Mundt20c2df82007-07-20 10:11:58 +090088 init_once);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 if (ncp_inode_cachep == NULL)
90 return -ENOMEM;
91 return 0;
92}
93
94static void destroy_inodecache(void)
95{
Alexey Dobriyan1a1d92c2006-09-27 01:49:40 -070096 kmem_cache_destroy(ncp_inode_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097}
98
99static int ncp_remount(struct super_block *sb, int *flags, char* data)
100{
101 *flags |= MS_NODIRATIME;
102 return 0;
103}
104
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800105static const struct super_operations ncp_sops =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106{
107 .alloc_inode = ncp_alloc_inode,
108 .destroy_inode = ncp_destroy_inode,
109 .drop_inode = generic_delete_inode,
Al Viro94ee8492010-06-07 00:45:56 -0400110 .evict_inode = ncp_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 .put_super = ncp_put_super,
112 .statfs = ncp_statfs,
113 .remount_fs = ncp_remount,
Miklos Szeredi564cd132008-02-08 04:21:46 -0800114 .show_options = ncp_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115};
116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117/*
118 * Fill in the ncpfs-specific information in the inode.
119 */
120static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
121{
122 NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
123 NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
124 NCP_FINFO(inode)->volNumber = nwinfo->volume;
125}
126
127void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
128{
129 ncp_update_dirent(inode, nwinfo);
130 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
131 NCP_FINFO(inode)->access = nwinfo->access;
132 memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
133 sizeof(nwinfo->file_handle));
134 DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
135 nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
136 NCP_FINFO(inode)->dirEntNum);
137}
138
139static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
140{
141 /* NFS namespace mode overrides others if it's set. */
142 DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n",
143 nwi->entryName, nwi->nfs.mode);
144 if (nwi->nfs.mode) {
145 /* XXX Security? */
146 inode->i_mode = nwi->nfs.mode;
147 }
148
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200149 inode->i_blocks = (i_size_read(inode) + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
151 inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate);
152 inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate);
153 inode->i_atime.tv_sec = ncp_date_dos2unix(0, nwi->lastAccessDate);
154 inode->i_atime.tv_nsec = 0;
155 inode->i_mtime.tv_nsec = 0;
156 inode->i_ctime.tv_nsec = 0;
157}
158
159static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
160{
161 struct nw_info_struct *nwi = &nwinfo->i;
162 struct ncp_server *server = NCP_SERVER(inode);
163
164 if (nwi->attributes & aDIR) {
165 inode->i_mode = server->m.dir_mode;
166 /* for directories dataStreamSize seems to be some
167 Object ID ??? */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200168 i_size_write(inode, NCP_BLOCK_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 } else {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200170 u32 size;
171
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 inode->i_mode = server->m.file_mode;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200173 size = le32_to_cpu(nwi->dataStreamSize);
174 i_size_write(inode, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175#ifdef CONFIG_NCPFS_EXTRAS
176 if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS))
177 && (nwi->attributes & aSHARED)) {
178 switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
179 case aHIDDEN:
180 if (server->m.flags & NCP_MOUNT_SYMLINKS) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200181 if (/* (size >= NCP_MIN_SYMLINK_SIZE)
182 && */ (size <= NCP_MAX_SYMLINK_SIZE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
184 NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
185 break;
186 }
187 }
188 /* FALLTHROUGH */
189 case 0:
190 if (server->m.flags & NCP_MOUNT_EXTRAS)
191 inode->i_mode |= S_IRUGO;
192 break;
193 case aSYSTEM:
194 if (server->m.flags & NCP_MOUNT_EXTRAS)
195 inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO;
196 break;
197 /* case aSYSTEM|aHIDDEN: */
198 default:
199 /* reserved combination */
200 break;
201 }
202 }
203#endif
204 }
205 if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
206}
207
208void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
209{
210 NCP_FINFO(inode)->flags = 0;
211 if (!atomic_read(&NCP_FINFO(inode)->opened)) {
212 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
213 ncp_update_attrs(inode, nwinfo);
214 }
215
216 ncp_update_dates(inode, &nwinfo->i);
217 ncp_update_dirent(inode, nwinfo);
218}
219
220/*
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200221 * Fill in the inode based on the ncp_entry_info structure. Used only for brand new inodes.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 */
223static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
224{
225 struct ncp_server *server = NCP_SERVER(inode);
226
227 NCP_FINFO(inode)->flags = 0;
228
229 ncp_update_attrs(inode, nwinfo);
230
231 DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
232
233 inode->i_nlink = 1;
234 inode->i_uid = server->m.uid;
235 inode->i_gid = server->m.gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236
237 ncp_update_dates(inode, &nwinfo->i);
238 ncp_update_inode(inode, nwinfo);
239}
240
241#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800242static const struct inode_operations ncp_symlink_inode_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 .readlink = generic_readlink,
244 .follow_link = page_follow_link_light,
245 .put_link = page_put_link,
246 .setattr = ncp_notify_change,
247};
248#endif
249
250/*
251 * Get a new inode.
252 */
253struct inode *
254ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
255{
256 struct inode *inode;
257
258 if (info == NULL) {
259 printk(KERN_ERR "ncp_iget: info is NULL\n");
260 return NULL;
261 }
262
263 inode = new_inode(sb);
264 if (inode) {
265 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
266
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200267 inode->i_mapping->backing_dev_info = sb->s_bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 inode->i_ino = info->ino;
269 ncp_set_attr(inode, info);
270 if (S_ISREG(inode->i_mode)) {
271 inode->i_op = &ncp_file_inode_operations;
272 inode->i_fop = &ncp_file_operations;
273 } else if (S_ISDIR(inode->i_mode)) {
274 inode->i_op = &ncp_dir_inode_operations;
275 inode->i_fop = &ncp_dir_operations;
276#ifdef CONFIG_NCPFS_NFS_NS
277 } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
278 init_special_inode(inode, inode->i_mode,
279 new_decode_dev(info->i.nfs.rdev));
280#endif
281#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
282 } else if (S_ISLNK(inode->i_mode)) {
283 inode->i_op = &ncp_symlink_inode_operations;
284 inode->i_data.a_ops = &ncp_symlink_aops;
285#endif
286 } else {
287 make_bad_inode(inode);
288 }
289 insert_inode_hash(inode);
290 } else
291 printk(KERN_ERR "ncp_iget: iget failed!\n");
292 return inode;
293}
294
295static void
Al Viro94ee8492010-06-07 00:45:56 -0400296ncp_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297{
Mark Fashehfef26652005-09-09 13:01:31 -0700298 truncate_inode_pages(&inode->i_data, 0);
Al Viro94ee8492010-06-07 00:45:56 -0400299 end_writeback(inode);
Mark Fashehfef26652005-09-09 13:01:31 -0700300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 if (S_ISDIR(inode->i_mode)) {
Al Viro94ee8492010-06-07 00:45:56 -0400302 DDPRINTK("ncp_evict_inode: put directory %ld\n", inode->i_ino);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 }
304
305 if (ncp_make_closed(inode) != 0) {
306 /* We can't do anything but complain. */
Al Viro94ee8492010-06-07 00:45:56 -0400307 printk(KERN_ERR "ncp_evict_inode: could not close\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309}
310
311static void ncp_stop_tasks(struct ncp_server *server) {
312 struct sock* sk = server->ncp_sock->sk;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200313
314 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 sk->sk_error_report = server->error_report;
316 sk->sk_data_ready = server->data_ready;
317 sk->sk_write_space = server->write_space;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200318 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 del_timer_sync(&server->timeout_tm);
320 flush_scheduled_work();
321}
322
Miklos Szeredi564cd132008-02-08 04:21:46 -0800323static int ncp_show_options(struct seq_file *seq, struct vfsmount *mnt)
324{
325 struct ncp_server *server = NCP_SBP(mnt->mnt_sb);
326 unsigned int tmp;
327
328 if (server->m.uid != 0)
329 seq_printf(seq, ",uid=%u", server->m.uid);
330 if (server->m.gid != 0)
331 seq_printf(seq, ",gid=%u", server->m.gid);
332 if (server->m.mounted_uid != 0)
333 seq_printf(seq, ",owner=%u", server->m.mounted_uid);
334 tmp = server->m.file_mode & S_IALLUGO;
335 if (tmp != NCP_DEFAULT_FILE_MODE)
336 seq_printf(seq, ",mode=0%o", tmp);
337 tmp = server->m.dir_mode & S_IALLUGO;
338 if (tmp != NCP_DEFAULT_DIR_MODE)
339 seq_printf(seq, ",dirmode=0%o", tmp);
340 if (server->m.time_out != NCP_DEFAULT_TIME_OUT * HZ / 100) {
341 tmp = server->m.time_out * 100 / HZ;
342 seq_printf(seq, ",timeout=%u", tmp);
343 }
344 if (server->m.retry_count != NCP_DEFAULT_RETRY_COUNT)
345 seq_printf(seq, ",retry=%u", server->m.retry_count);
346 if (server->m.flags != 0)
347 seq_printf(seq, ",flags=%lu", server->m.flags);
348 if (server->m.wdog_pid != NULL)
349 seq_printf(seq, ",wdogpid=%u", pid_vnr(server->m.wdog_pid));
350
351 return 0;
352}
353
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354static const struct ncp_option ncp_opts[] = {
355 { "uid", OPT_INT, 'u' },
356 { "gid", OPT_INT, 'g' },
357 { "owner", OPT_INT, 'o' },
358 { "mode", OPT_INT, 'm' },
359 { "dirmode", OPT_INT, 'd' },
360 { "timeout", OPT_INT, 't' },
361 { "retry", OPT_INT, 'r' },
362 { "flags", OPT_INT, 'f' },
363 { "wdogpid", OPT_INT, 'w' },
364 { "ncpfd", OPT_INT, 'n' },
365 { "infofd", OPT_INT, 'i' }, /* v5 */
366 { "version", OPT_INT, 'v' },
367 { NULL, 0, 0 } };
368
369static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
370 int optval;
371 char *optarg;
372 unsigned long optint;
373 int version = 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800374 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375
376 data->flags = 0;
377 data->int_flags = 0;
378 data->mounted_uid = 0;
Eric W. Biederman21542272006-12-13 00:35:11 -0800379 data->wdog_pid = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 data->ncp_fd = ~0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800381 data->time_out = NCP_DEFAULT_TIME_OUT;
382 data->retry_count = NCP_DEFAULT_RETRY_COUNT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 data->uid = 0;
384 data->gid = 0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800385 data->file_mode = NCP_DEFAULT_FILE_MODE;
386 data->dir_mode = NCP_DEFAULT_DIR_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 data->info_fd = -1;
388 data->mounted_vol[0] = 0;
389
390 while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
Eric W. Biederman1de24122006-12-13 00:35:13 -0800391 ret = optval;
392 if (ret < 0)
393 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 switch (optval) {
395 case 'u':
396 data->uid = optint;
397 break;
398 case 'g':
399 data->gid = optint;
400 break;
401 case 'o':
402 data->mounted_uid = optint;
403 break;
404 case 'm':
405 data->file_mode = optint;
406 break;
407 case 'd':
408 data->dir_mode = optint;
409 break;
410 case 't':
411 data->time_out = optint;
412 break;
413 case 'r':
414 data->retry_count = optint;
415 break;
416 case 'f':
417 data->flags = optint;
418 break;
419 case 'w':
Eric W. Biederman21542272006-12-13 00:35:11 -0800420 data->wdog_pid = find_get_pid(optint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 break;
422 case 'n':
423 data->ncp_fd = optint;
424 break;
425 case 'i':
426 data->info_fd = optint;
427 break;
428 case 'v':
Eric W. Biederman1de24122006-12-13 00:35:13 -0800429 ret = -ECHRNG;
430 if (optint < NCP_MOUNT_VERSION_V4)
431 goto err;
432 if (optint > NCP_MOUNT_VERSION_V5)
433 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 version = optint;
435 break;
436
437 }
438 }
439 return 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800440err:
441 put_pid(data->wdog_pid);
442 data->wdog_pid = NULL;
443 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444}
445
446static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
447{
448 struct ncp_mount_data_kernel data;
449 struct ncp_server *server;
450 struct file *ncp_filp;
451 struct inode *root_inode;
452 struct inode *sock_inode;
453 struct socket *sock;
454 int error;
455 int default_bufsize;
456#ifdef CONFIG_NCPFS_PACKET_SIGNING
457 int options;
458#endif
459 struct ncp_entry_info finfo;
460
Eric W. Biederman1de24122006-12-13 00:35:13 -0800461 data.wdog_pid = NULL;
Panagiotis Issarisf8314dc2006-09-27 01:49:37 -0700462 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 if (!server)
464 return -ENOMEM;
465 sb->s_fs_info = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
467 error = -EFAULT;
468 if (raw_data == NULL)
469 goto out;
470 switch (*(int*)raw_data) {
471 case NCP_MOUNT_VERSION:
472 {
473 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
474
475 data.flags = md->flags;
476 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
477 data.mounted_uid = md->mounted_uid;
Eric W. Biederman21542272006-12-13 00:35:11 -0800478 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 data.ncp_fd = md->ncp_fd;
480 data.time_out = md->time_out;
481 data.retry_count = md->retry_count;
482 data.uid = md->uid;
483 data.gid = md->gid;
484 data.file_mode = md->file_mode;
485 data.dir_mode = md->dir_mode;
486 data.info_fd = -1;
487 memcpy(data.mounted_vol, md->mounted_vol,
488 NCP_VOLNAME_LEN+1);
489 }
490 break;
491 case NCP_MOUNT_VERSION_V4:
492 {
493 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
494
495 data.flags = md->flags;
496 data.int_flags = 0;
497 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;
507 data.mounted_vol[0] = 0;
508 }
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;
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)
549 goto out_bdi;
550
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)
560 goto out_fput;
561 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;
595 /* Althought anything producing this is buggy, it happens
596 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);
718 sb->s_root = d_alloc_root(root_inode);
719 if (!sb->s_root)
720 goto out_no_root;
Nick Pigginfb045ad2011-01-07 17:49:55 +1100721 d_set_d_op(sb->s_root, &ncp_root_dentry_operations);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 return 0;
723
724out_no_root:
725 iput(root_inode);
726out_disconnect:
727 ncp_lock_server(server);
728 ncp_disconnect(server);
729 ncp_unlock_server(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100730out_rxbuf:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 ncp_stop_tasks(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100732 vfree(server->rxbuf);
733out_txbuf:
734 vfree(server->txbuf);
735out_packet:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 vfree(server->packet);
737out_nls:
738#ifdef CONFIG_NCPFS_NLS
739 unload_nls(server->nls_io);
740 unload_nls(server->nls_vol);
741#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200742 mutex_destroy(&server->rcv.creq_mutex);
743 mutex_destroy(&server->root_setup_lock);
744 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745out_fput2:
746 if (server->info_filp)
747 fput(server->info_filp);
748out_fput:
Jens Axboef1970c72010-04-22 12:31:11 +0200749 bdi_destroy(&server->bdi);
750out_bdi:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
752 *
Matthew Whitworthe956b4b2010-06-27 14:34:30 +0100753 * The previously used put_filp(ncp_filp); was bogus, since
754 * it doesn't perform proper unlocking.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 */
756 fput(ncp_filp);
757out:
Eric W. Biederman1de24122006-12-13 00:35:13 -0800758 put_pid(data.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 sb->s_fs_info = NULL;
760 kfree(server);
761 return error;
762}
763
764static void ncp_put_super(struct super_block *sb)
765{
766 struct ncp_server *server = NCP_SBP(sb);
767
768 ncp_lock_server(server);
769 ncp_disconnect(server);
770 ncp_unlock_server(server);
771
772 ncp_stop_tasks(server);
773
774#ifdef CONFIG_NCPFS_NLS
775 /* unload the NLS charsets */
Thomas Gleixner6d729e42009-08-16 21:05:08 +0000776 unload_nls(server->nls_vol);
777 unload_nls(server->nls_io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778#endif /* CONFIG_NCPFS_NLS */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200779 mutex_destroy(&server->rcv.creq_mutex);
780 mutex_destroy(&server->root_setup_lock);
781 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782
783 if (server->info_filp)
784 fput(server->info_filp);
785 fput(server->ncp_filp);
Eric W. Biederman21542272006-12-13 00:35:11 -0800786 kill_pid(server->m.wdog_pid, SIGTERM, 1);
787 put_pid(server->m.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788
Jens Axboef1970c72010-04-22 12:31:11 +0200789 bdi_destroy(&server->bdi);
Pekka Enberg44db77f2006-01-14 13:21:12 -0800790 kfree(server->priv.data);
791 kfree(server->auth.object_name);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100792 vfree(server->rxbuf);
793 vfree(server->txbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 vfree(server->packet);
795 sb->s_fs_info = NULL;
796 kfree(server);
797}
798
David Howells726c3342006-06-23 02:02:58 -0700799static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800{
801 struct dentry* d;
802 struct inode* i;
803 struct ncp_inode_info* ni;
804 struct ncp_server* s;
805 struct ncp_volume_info vi;
David Howells726c3342006-06-23 02:02:58 -0700806 struct super_block *sb = dentry->d_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 int err;
808 __u8 dh;
809
810 d = sb->s_root;
811 if (!d) {
812 goto dflt;
813 }
814 i = d->d_inode;
815 if (!i) {
816 goto dflt;
817 }
818 ni = NCP_FINFO(i);
819 if (!ni) {
820 goto dflt;
821 }
822 s = NCP_SBP(sb);
823 if (!s) {
824 goto dflt;
825 }
826 if (!s->m.mounted_vol[0]) {
827 goto dflt;
828 }
829
830 err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
831 if (err) {
832 goto dflt;
833 }
834 err = ncp_get_directory_info(s, dh, &vi);
835 ncp_dirhandle_free(s, dh);
836 if (err) {
837 goto dflt;
838 }
839 buf->f_type = NCP_SUPER_MAGIC;
840 buf->f_bsize = vi.sectors_per_block * 512;
841 buf->f_blocks = vi.total_blocks;
842 buf->f_bfree = vi.free_blocks;
843 buf->f_bavail = vi.free_blocks;
844 buf->f_files = vi.total_dir_entries;
845 buf->f_ffree = vi.available_dir_entries;
846 buf->f_namelen = 12;
847 return 0;
848
849 /* We cannot say how much disk space is left on a mounted
850 NetWare Server, because free space is distributed over
851 volumes, and the current user might have disk quotas. So
852 free space is not that simple to determine. Our decision
853 here is to err conservatively. */
854
855dflt:;
856 buf->f_type = NCP_SUPER_MAGIC;
857 buf->f_bsize = NCP_BLOCK_SIZE;
858 buf->f_blocks = 0;
859 buf->f_bfree = 0;
860 buf->f_bavail = 0;
861 buf->f_namelen = 12;
862 return 0;
863}
864
865int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
866{
867 struct inode *inode = dentry->d_inode;
868 int result = 0;
869 __le32 info_mask;
870 struct nw_modify_dos_info info;
871 struct ncp_server *server;
872
873 result = -EIO;
874
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 server = NCP_SERVER(inode);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200876 if (!server) /* How this could happen? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 goto out;
878
879 /* ageing the dentry to force validation */
880 ncp_age_dentry(server, dentry);
881
882 result = inode_change_ok(inode, attr);
883 if (result < 0)
884 goto out;
885
886 result = -EPERM;
887 if (((attr->ia_valid & ATTR_UID) &&
888 (attr->ia_uid != server->m.uid)))
889 goto out;
890
891 if (((attr->ia_valid & ATTR_GID) &&
892 (attr->ia_gid != server->m.gid)))
893 goto out;
894
895 if (((attr->ia_valid & ATTR_MODE) &&
896 (attr->ia_mode &
897 ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
898 goto out;
899
900 info_mask = 0;
901 memset(&info, 0, sizeof(info));
902
903#if 1
904 if ((attr->ia_valid & ATTR_MODE) != 0)
905 {
906 umode_t newmode = attr->ia_mode;
907
908 info_mask |= DM_ATTRIBUTES;
909
910 if (S_ISDIR(inode->i_mode)) {
911 newmode &= server->m.dir_mode;
912 } else {
913#ifdef CONFIG_NCPFS_EXTRAS
914 if (server->m.flags & NCP_MOUNT_EXTRAS) {
915 /* any non-default execute bit set */
916 if (newmode & ~server->m.file_mode & S_IXUGO)
917 info.attributes |= aSHARED | aSYSTEM;
918 /* read for group/world and not in default file_mode */
919 else if (newmode & ~server->m.file_mode & S_IRUGO)
920 info.attributes |= aSHARED;
921 } else
922#endif
923 newmode &= server->m.file_mode;
924 }
925 if (newmode & S_IWUGO)
926 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
927 else
928 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
929
930#ifdef CONFIG_NCPFS_NFS_NS
931 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
932 result = ncp_modify_nfs_info(server,
933 NCP_FINFO(inode)->volNumber,
934 NCP_FINFO(inode)->dirEntNum,
935 attr->ia_mode, 0);
936 if (result != 0)
937 goto out;
938 info.attributes &= ~(aSHARED | aSYSTEM);
939 {
940 /* mark partial success */
941 struct iattr tmpattr;
942
943 tmpattr.ia_valid = ATTR_MODE;
944 tmpattr.ia_mode = attr->ia_mode;
945
Christoph Hellwig10257742010-06-04 11:30:02 +0200946 setattr_copy(inode, &tmpattr);
947 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 }
949 }
950#endif
951 }
952#endif
953
954 /* Do SIZE before attributes, otherwise mtime together with size does not work...
955 */
956 if ((attr->ia_valid & ATTR_SIZE) != 0) {
957 int written;
958
959 DPRINTK("ncpfs: trying to change size to %ld\n",
960 attr->ia_size);
961
962 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
963 result = -EACCES;
964 goto out;
965 }
966 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
967 attr->ia_size, 0, "", &written);
968
969 /* According to ndir, the changes only take effect after
970 closing the file */
971 ncp_inode_close(inode);
972 result = ncp_make_closed(inode);
973 if (result)
974 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +0200975
976 if (attr->ia_size != i_size_read(inode)) {
977 result = vmtruncate(inode, attr->ia_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 if (result)
979 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +0200980 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 }
982 }
983 if ((attr->ia_valid & ATTR_CTIME) != 0) {
984 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
985 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
986 &info.creationTime, &info.creationDate);
987 }
988 if ((attr->ia_valid & ATTR_MTIME) != 0) {
989 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
990 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
991 &info.modifyTime, &info.modifyDate);
992 }
993 if ((attr->ia_valid & ATTR_ATIME) != 0) {
994 __le16 dummy;
995 info_mask |= (DM_LAST_ACCESS_DATE);
996 ncp_date_unix2dos(attr->ia_atime.tv_sec,
997 &dummy, &info.lastAccessDate);
998 }
999 if (info_mask != 0) {
1000 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
1001 inode, info_mask, &info);
1002 if (result != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
1004 /* NetWare seems not to allow this. I
1005 do not know why. So, just tell the
1006 user everything went fine. This is
1007 a terrible hack, but I do not know
1008 how to do this correctly. */
1009 result = 0;
1010 } else
1011 goto out;
1012 }
1013#ifdef CONFIG_NCPFS_STRONG
1014 if ((!result) && (info_mask & DM_ATTRIBUTES))
1015 NCP_FINFO(inode)->nwattr = info.attributes;
1016#endif
1017 }
Christoph Hellwig10257742010-06-04 11:30:02 +02001018 if (result)
1019 goto out;
1020
1021 setattr_copy(inode, attr);
1022 mark_inode_dirty(inode);
1023
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024out:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001025 if (result > 0)
1026 result = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 return result;
1028}
1029
Al Viro3c26ff62010-07-25 11:46:36 +04001030static struct dentry *ncp_mount(struct file_system_type *fs_type,
1031 int flags, const char *dev_name, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032{
Al Viro3c26ff62010-07-25 11:46:36 +04001033 return mount_nodev(fs_type, flags, data, ncp_fill_super);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034}
1035
1036static struct file_system_type ncp_fs_type = {
1037 .owner = THIS_MODULE,
1038 .name = "ncpfs",
Al Viro3c26ff62010-07-25 11:46:36 +04001039 .mount = ncp_mount,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 .kill_sb = kill_anon_super,
Miklos Szeredi564cd132008-02-08 04:21:46 -08001041 .fs_flags = FS_BINARY_MOUNTDATA,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042};
1043
1044static int __init init_ncp_fs(void)
1045{
1046 int err;
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001047 DPRINTK("ncpfs: init_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 err = init_inodecache();
1050 if (err)
1051 goto out1;
1052 err = register_filesystem(&ncp_fs_type);
1053 if (err)
1054 goto out;
1055 return 0;
1056out:
1057 destroy_inodecache();
1058out1:
1059 return err;
1060}
1061
1062static void __exit exit_ncp_fs(void)
1063{
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001064 DPRINTK("ncpfs: exit_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 unregister_filesystem(&ncp_fs_type);
1066 destroy_inodecache();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067}
1068
1069module_init(init_ncp_fs)
1070module_exit(exit_ncp_fs)
1071MODULE_LICENSE("GPL");