blob: 31532330d016e561922e525a94abaaad88df7654 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
33#include <linux/ncp_fs.h>
34
35#include <net/sock.h>
36
37#include "ncplib_kernel.h"
38#include "getopt.h"
39
Miklos Szeredi564cd132008-02-08 04:21:46 -080040#define NCP_DEFAULT_FILE_MODE 0600
41#define NCP_DEFAULT_DIR_MODE 0700
42#define NCP_DEFAULT_TIME_OUT 10
43#define NCP_DEFAULT_RETRY_COUNT 20
44
Al Viro94ee8492010-06-07 00:45:56 -040045static void ncp_evict_inode(struct inode *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070046static void ncp_put_super(struct super_block *);
David Howells726c3342006-06-23 02:02:58 -070047static int ncp_statfs(struct dentry *, struct kstatfs *);
Miklos Szeredi564cd132008-02-08 04:21:46 -080048static int ncp_show_options(struct seq_file *, struct vfsmount *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Christoph Lametere18b8902006-12-06 20:33:20 -080050static struct kmem_cache * ncp_inode_cachep;
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52static struct inode *ncp_alloc_inode(struct super_block *sb)
53{
54 struct ncp_inode_info *ei;
Christoph Lametere94b1762006-12-06 20:33:17 -080055 ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 if (!ei)
57 return NULL;
58 return &ei->vfs_inode;
59}
60
61static void ncp_destroy_inode(struct inode *inode)
62{
63 kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
64}
65
Alexey Dobriyan51cc5062008-07-25 19:45:34 -070066static void init_once(void *foo)
Linus Torvalds1da177e2005-04-16 15:20:36 -070067{
68 struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
69
Christoph Lametera35afb82007-05-16 22:10:57 -070070 mutex_init(&ei->open_mutex);
71 inode_init_once(&ei->vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070072}
Paul Mundt20c2df82007-07-20 10:11:58 +090073
Linus Torvalds1da177e2005-04-16 15:20:36 -070074static int init_inodecache(void)
75{
76 ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
77 sizeof(struct ncp_inode_info),
Paul Jacksonfffb60f2006-03-24 03:16:06 -080078 0, (SLAB_RECLAIM_ACCOUNT|
79 SLAB_MEM_SPREAD),
Paul Mundt20c2df82007-07-20 10:11:58 +090080 init_once);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 if (ncp_inode_cachep == NULL)
82 return -ENOMEM;
83 return 0;
84}
85
86static void destroy_inodecache(void)
87{
Alexey Dobriyan1a1d92c2006-09-27 01:49:40 -070088 kmem_cache_destroy(ncp_inode_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089}
90
91static int ncp_remount(struct super_block *sb, int *flags, char* data)
92{
93 *flags |= MS_NODIRATIME;
94 return 0;
95}
96
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -080097static const struct super_operations ncp_sops =
Linus Torvalds1da177e2005-04-16 15:20:36 -070098{
99 .alloc_inode = ncp_alloc_inode,
100 .destroy_inode = ncp_destroy_inode,
101 .drop_inode = generic_delete_inode,
Al Viro94ee8492010-06-07 00:45:56 -0400102 .evict_inode = ncp_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 .put_super = ncp_put_super,
104 .statfs = ncp_statfs,
105 .remount_fs = ncp_remount,
Miklos Szeredi564cd132008-02-08 04:21:46 -0800106 .show_options = ncp_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107};
108
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109/*
110 * Fill in the ncpfs-specific information in the inode.
111 */
112static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
113{
114 NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
115 NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
116 NCP_FINFO(inode)->volNumber = nwinfo->volume;
117}
118
119void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
120{
121 ncp_update_dirent(inode, nwinfo);
122 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
123 NCP_FINFO(inode)->access = nwinfo->access;
124 memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
125 sizeof(nwinfo->file_handle));
126 DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
127 nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
128 NCP_FINFO(inode)->dirEntNum);
129}
130
131static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
132{
133 /* NFS namespace mode overrides others if it's set. */
134 DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n",
135 nwi->entryName, nwi->nfs.mode);
136 if (nwi->nfs.mode) {
137 /* XXX Security? */
138 inode->i_mode = nwi->nfs.mode;
139 }
140
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200141 inode->i_blocks = (i_size_read(inode) + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
143 inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate);
144 inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate);
145 inode->i_atime.tv_sec = ncp_date_dos2unix(0, nwi->lastAccessDate);
146 inode->i_atime.tv_nsec = 0;
147 inode->i_mtime.tv_nsec = 0;
148 inode->i_ctime.tv_nsec = 0;
149}
150
151static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
152{
153 struct nw_info_struct *nwi = &nwinfo->i;
154 struct ncp_server *server = NCP_SERVER(inode);
155
156 if (nwi->attributes & aDIR) {
157 inode->i_mode = server->m.dir_mode;
158 /* for directories dataStreamSize seems to be some
159 Object ID ??? */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200160 i_size_write(inode, NCP_BLOCK_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 } else {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200162 u32 size;
163
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 inode->i_mode = server->m.file_mode;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200165 size = le32_to_cpu(nwi->dataStreamSize);
166 i_size_write(inode, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167#ifdef CONFIG_NCPFS_EXTRAS
168 if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS))
169 && (nwi->attributes & aSHARED)) {
170 switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
171 case aHIDDEN:
172 if (server->m.flags & NCP_MOUNT_SYMLINKS) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200173 if (/* (size >= NCP_MIN_SYMLINK_SIZE)
174 && */ (size <= NCP_MAX_SYMLINK_SIZE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
176 NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
177 break;
178 }
179 }
180 /* FALLTHROUGH */
181 case 0:
182 if (server->m.flags & NCP_MOUNT_EXTRAS)
183 inode->i_mode |= S_IRUGO;
184 break;
185 case aSYSTEM:
186 if (server->m.flags & NCP_MOUNT_EXTRAS)
187 inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO;
188 break;
189 /* case aSYSTEM|aHIDDEN: */
190 default:
191 /* reserved combination */
192 break;
193 }
194 }
195#endif
196 }
197 if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
198}
199
200void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
201{
202 NCP_FINFO(inode)->flags = 0;
203 if (!atomic_read(&NCP_FINFO(inode)->opened)) {
204 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
205 ncp_update_attrs(inode, nwinfo);
206 }
207
208 ncp_update_dates(inode, &nwinfo->i);
209 ncp_update_dirent(inode, nwinfo);
210}
211
212/*
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200213 * Fill in the inode based on the ncp_entry_info structure. Used only for brand new inodes.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 */
215static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
216{
217 struct ncp_server *server = NCP_SERVER(inode);
218
219 NCP_FINFO(inode)->flags = 0;
220
221 ncp_update_attrs(inode, nwinfo);
222
223 DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
224
225 inode->i_nlink = 1;
226 inode->i_uid = server->m.uid;
227 inode->i_gid = server->m.gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
229 ncp_update_dates(inode, &nwinfo->i);
230 ncp_update_inode(inode, nwinfo);
231}
232
233#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800234static const struct inode_operations ncp_symlink_inode_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 .readlink = generic_readlink,
236 .follow_link = page_follow_link_light,
237 .put_link = page_put_link,
238 .setattr = ncp_notify_change,
239};
240#endif
241
242/*
243 * Get a new inode.
244 */
245struct inode *
246ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
247{
248 struct inode *inode;
249
250 if (info == NULL) {
251 printk(KERN_ERR "ncp_iget: info is NULL\n");
252 return NULL;
253 }
254
255 inode = new_inode(sb);
256 if (inode) {
257 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
258
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200259 inode->i_mapping->backing_dev_info = sb->s_bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 inode->i_ino = info->ino;
261 ncp_set_attr(inode, info);
262 if (S_ISREG(inode->i_mode)) {
263 inode->i_op = &ncp_file_inode_operations;
264 inode->i_fop = &ncp_file_operations;
265 } else if (S_ISDIR(inode->i_mode)) {
266 inode->i_op = &ncp_dir_inode_operations;
267 inode->i_fop = &ncp_dir_operations;
268#ifdef CONFIG_NCPFS_NFS_NS
269 } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
270 init_special_inode(inode, inode->i_mode,
271 new_decode_dev(info->i.nfs.rdev));
272#endif
273#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
274 } else if (S_ISLNK(inode->i_mode)) {
275 inode->i_op = &ncp_symlink_inode_operations;
276 inode->i_data.a_ops = &ncp_symlink_aops;
277#endif
278 } else {
279 make_bad_inode(inode);
280 }
281 insert_inode_hash(inode);
282 } else
283 printk(KERN_ERR "ncp_iget: iget failed!\n");
284 return inode;
285}
286
287static void
Al Viro94ee8492010-06-07 00:45:56 -0400288ncp_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289{
Mark Fashehfef26652005-09-09 13:01:31 -0700290 truncate_inode_pages(&inode->i_data, 0);
Al Viro94ee8492010-06-07 00:45:56 -0400291 end_writeback(inode);
Mark Fashehfef26652005-09-09 13:01:31 -0700292
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 if (S_ISDIR(inode->i_mode)) {
Al Viro94ee8492010-06-07 00:45:56 -0400294 DDPRINTK("ncp_evict_inode: put directory %ld\n", inode->i_ino);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 }
296
297 if (ncp_make_closed(inode) != 0) {
298 /* We can't do anything but complain. */
Al Viro94ee8492010-06-07 00:45:56 -0400299 printk(KERN_ERR "ncp_evict_inode: could not close\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301}
302
303static void ncp_stop_tasks(struct ncp_server *server) {
304 struct sock* sk = server->ncp_sock->sk;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200305
306 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 sk->sk_error_report = server->error_report;
308 sk->sk_data_ready = server->data_ready;
309 sk->sk_write_space = server->write_space;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200310 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 del_timer_sync(&server->timeout_tm);
Tejun Heo5d8e4bd2010-12-24 15:59:06 +0100312
313 flush_work_sync(&server->rcv.tq);
314 if (sk->sk_socket->type == SOCK_STREAM)
315 flush_work_sync(&server->tx.tq);
316 else
317 flush_work_sync(&server->timeout_tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318}
319
Miklos Szeredi564cd132008-02-08 04:21:46 -0800320static int ncp_show_options(struct seq_file *seq, struct vfsmount *mnt)
321{
322 struct ncp_server *server = NCP_SBP(mnt->mnt_sb);
323 unsigned int tmp;
324
325 if (server->m.uid != 0)
326 seq_printf(seq, ",uid=%u", server->m.uid);
327 if (server->m.gid != 0)
328 seq_printf(seq, ",gid=%u", server->m.gid);
329 if (server->m.mounted_uid != 0)
330 seq_printf(seq, ",owner=%u", server->m.mounted_uid);
331 tmp = server->m.file_mode & S_IALLUGO;
332 if (tmp != NCP_DEFAULT_FILE_MODE)
333 seq_printf(seq, ",mode=0%o", tmp);
334 tmp = server->m.dir_mode & S_IALLUGO;
335 if (tmp != NCP_DEFAULT_DIR_MODE)
336 seq_printf(seq, ",dirmode=0%o", tmp);
337 if (server->m.time_out != NCP_DEFAULT_TIME_OUT * HZ / 100) {
338 tmp = server->m.time_out * 100 / HZ;
339 seq_printf(seq, ",timeout=%u", tmp);
340 }
341 if (server->m.retry_count != NCP_DEFAULT_RETRY_COUNT)
342 seq_printf(seq, ",retry=%u", server->m.retry_count);
343 if (server->m.flags != 0)
344 seq_printf(seq, ",flags=%lu", server->m.flags);
345 if (server->m.wdog_pid != NULL)
346 seq_printf(seq, ",wdogpid=%u", pid_vnr(server->m.wdog_pid));
347
348 return 0;
349}
350
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351static const struct ncp_option ncp_opts[] = {
352 { "uid", OPT_INT, 'u' },
353 { "gid", OPT_INT, 'g' },
354 { "owner", OPT_INT, 'o' },
355 { "mode", OPT_INT, 'm' },
356 { "dirmode", OPT_INT, 'd' },
357 { "timeout", OPT_INT, 't' },
358 { "retry", OPT_INT, 'r' },
359 { "flags", OPT_INT, 'f' },
360 { "wdogpid", OPT_INT, 'w' },
361 { "ncpfd", OPT_INT, 'n' },
362 { "infofd", OPT_INT, 'i' }, /* v5 */
363 { "version", OPT_INT, 'v' },
364 { NULL, 0, 0 } };
365
366static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
367 int optval;
368 char *optarg;
369 unsigned long optint;
370 int version = 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800371 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372
373 data->flags = 0;
374 data->int_flags = 0;
375 data->mounted_uid = 0;
Eric W. Biederman21542272006-12-13 00:35:11 -0800376 data->wdog_pid = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 data->ncp_fd = ~0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800378 data->time_out = NCP_DEFAULT_TIME_OUT;
379 data->retry_count = NCP_DEFAULT_RETRY_COUNT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 data->uid = 0;
381 data->gid = 0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800382 data->file_mode = NCP_DEFAULT_FILE_MODE;
383 data->dir_mode = NCP_DEFAULT_DIR_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 data->info_fd = -1;
385 data->mounted_vol[0] = 0;
386
387 while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
Eric W. Biederman1de24122006-12-13 00:35:13 -0800388 ret = optval;
389 if (ret < 0)
390 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 switch (optval) {
392 case 'u':
393 data->uid = optint;
394 break;
395 case 'g':
396 data->gid = optint;
397 break;
398 case 'o':
399 data->mounted_uid = optint;
400 break;
401 case 'm':
402 data->file_mode = optint;
403 break;
404 case 'd':
405 data->dir_mode = optint;
406 break;
407 case 't':
408 data->time_out = optint;
409 break;
410 case 'r':
411 data->retry_count = optint;
412 break;
413 case 'f':
414 data->flags = optint;
415 break;
416 case 'w':
Eric W. Biederman21542272006-12-13 00:35:11 -0800417 data->wdog_pid = find_get_pid(optint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 break;
419 case 'n':
420 data->ncp_fd = optint;
421 break;
422 case 'i':
423 data->info_fd = optint;
424 break;
425 case 'v':
Eric W. Biederman1de24122006-12-13 00:35:13 -0800426 ret = -ECHRNG;
427 if (optint < NCP_MOUNT_VERSION_V4)
428 goto err;
429 if (optint > NCP_MOUNT_VERSION_V5)
430 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 version = optint;
432 break;
433
434 }
435 }
436 return 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800437err:
438 put_pid(data->wdog_pid);
439 data->wdog_pid = NULL;
440 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441}
442
443static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
444{
445 struct ncp_mount_data_kernel data;
446 struct ncp_server *server;
447 struct file *ncp_filp;
448 struct inode *root_inode;
449 struct inode *sock_inode;
450 struct socket *sock;
451 int error;
452 int default_bufsize;
453#ifdef CONFIG_NCPFS_PACKET_SIGNING
454 int options;
455#endif
456 struct ncp_entry_info finfo;
457
Eric W. Biederman1de24122006-12-13 00:35:13 -0800458 data.wdog_pid = NULL;
Panagiotis Issarisf8314dc2006-09-27 01:49:37 -0700459 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 if (!server)
461 return -ENOMEM;
462 sb->s_fs_info = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
464 error = -EFAULT;
465 if (raw_data == NULL)
466 goto out;
467 switch (*(int*)raw_data) {
468 case NCP_MOUNT_VERSION:
469 {
470 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
471
472 data.flags = md->flags;
473 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
474 data.mounted_uid = md->mounted_uid;
Eric W. Biederman21542272006-12-13 00:35:11 -0800475 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476 data.ncp_fd = md->ncp_fd;
477 data.time_out = md->time_out;
478 data.retry_count = md->retry_count;
479 data.uid = md->uid;
480 data.gid = md->gid;
481 data.file_mode = md->file_mode;
482 data.dir_mode = md->dir_mode;
483 data.info_fd = -1;
484 memcpy(data.mounted_vol, md->mounted_vol,
485 NCP_VOLNAME_LEN+1);
486 }
487 break;
488 case NCP_MOUNT_VERSION_V4:
489 {
490 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
491
492 data.flags = md->flags;
493 data.int_flags = 0;
494 data.mounted_uid = md->mounted_uid;
Eric W. Biederman21542272006-12-13 00:35:11 -0800495 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 data.ncp_fd = md->ncp_fd;
497 data.time_out = md->time_out;
498 data.retry_count = md->retry_count;
499 data.uid = md->uid;
500 data.gid = md->gid;
501 data.file_mode = md->file_mode;
502 data.dir_mode = md->dir_mode;
503 data.info_fd = -1;
504 data.mounted_vol[0] = 0;
505 }
506 break;
507 default:
508 error = -ECHRNG;
509 if (memcmp(raw_data, "vers", 4) == 0) {
510 error = ncp_parse_options(&data, raw_data);
511 }
512 if (error)
513 goto out;
514 break;
515 }
516 error = -EBADF;
517 ncp_filp = fget(data.ncp_fd);
518 if (!ncp_filp)
519 goto out;
520 error = -ENOTSOCK;
Josef Sipek92e5bae2006-12-08 02:37:22 -0800521 sock_inode = ncp_filp->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 if (!S_ISSOCK(sock_inode->i_mode))
523 goto out_fput;
524 sock = SOCKET_I(sock_inode);
525 if (!sock)
526 goto out_fput;
527
528 if (sock->type == SOCK_STREAM)
529 default_bufsize = 0xF000;
530 else
531 default_bufsize = 1024;
532
533 sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
534 sb->s_maxbytes = 0xFFFFFFFFU;
535 sb->s_blocksize = 1024; /* Eh... Is this correct? */
536 sb->s_blocksize_bits = 10;
537 sb->s_magic = NCP_SUPER_MAGIC;
538 sb->s_op = &ncp_sops;
Jens Axboef1970c72010-04-22 12:31:11 +0200539 sb->s_bdi = &server->bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
541 server = NCP_SBP(sb);
542 memset(server, 0, sizeof(*server));
543
Jens Axboef1970c72010-04-22 12:31:11 +0200544 error = bdi_setup_and_register(&server->bdi, "ncpfs", BDI_CAP_MAP_COPY);
545 if (error)
546 goto out_bdi;
547
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 server->ncp_filp = ncp_filp;
549 server->ncp_sock = sock;
550
551 if (data.info_fd != -1) {
552 struct socket *info_sock;
553
554 error = -EBADF;
555 server->info_filp = fget(data.info_fd);
556 if (!server->info_filp)
557 goto out_fput;
558 error = -ENOTSOCK;
Josef Sipek92e5bae2006-12-08 02:37:22 -0800559 sock_inode = server->info_filp->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 if (!S_ISSOCK(sock_inode->i_mode))
561 goto out_fput2;
562 info_sock = SOCKET_I(sock_inode);
563 if (!info_sock)
564 goto out_fput2;
565 error = -EBADFD;
566 if (info_sock->type != SOCK_STREAM)
567 goto out_fput2;
568 server->info_sock = info_sock;
569 }
570
571/* server->lock = 0; */
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800572 mutex_init(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 server->packet = NULL;
574/* server->buffer_size = 0; */
575/* server->conn_status = 0; */
576/* server->root_dentry = NULL; */
577/* server->root_setuped = 0; */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200578 mutex_init(&server->root_setup_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579#ifdef CONFIG_NCPFS_PACKET_SIGNING
580/* server->sign_wanted = 0; */
581/* server->sign_active = 0; */
582#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200583 init_rwsem(&server->auth_rwsem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 server->auth.auth_type = NCP_AUTH_NONE;
585/* server->auth.object_name_len = 0; */
586/* server->auth.object_name = NULL; */
587/* server->auth.object_type = 0; */
588/* server->priv.len = 0; */
589/* server->priv.data = NULL; */
590
591 server->m = data;
592 /* Althought anything producing this is buggy, it happens
593 now because of PATH_MAX changes.. */
594 if (server->m.time_out < 1) {
595 server->m.time_out = 10;
596 printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
597 }
598 server->m.time_out = server->m.time_out * HZ / 100;
599 server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
600 server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
601
602#ifdef CONFIG_NCPFS_NLS
603 /* load the default NLS charsets */
604 server->nls_vol = load_nls_default();
605 server->nls_io = load_nls_default();
606#endif /* CONFIG_NCPFS_NLS */
607
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200608 atomic_set(&server->dentry_ttl, 0); /* no caching */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
610 INIT_LIST_HEAD(&server->tx.requests);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800611 mutex_init(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 server->tx.creq = NULL;
613 server->rcv.creq = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
615 init_timer(&server->timeout_tm);
616#undef NCP_PACKET_SIZE
617#define NCP_PACKET_SIZE 131072
618 error = -ENOMEM;
619 server->packet_size = NCP_PACKET_SIZE;
620 server->packet = vmalloc(NCP_PACKET_SIZE);
621 if (server->packet == NULL)
622 goto out_nls;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100623 server->txbuf = vmalloc(NCP_PACKET_SIZE);
624 if (server->txbuf == NULL)
625 goto out_packet;
626 server->rxbuf = vmalloc(NCP_PACKET_SIZE);
627 if (server->rxbuf == NULL)
628 goto out_txbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200630 lock_sock(sock->sk);
631 server->data_ready = sock->sk->sk_data_ready;
632 server->write_space = sock->sk->sk_write_space;
633 server->error_report = sock->sk->sk_error_report;
634 sock->sk->sk_user_data = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 sock->sk->sk_data_ready = ncp_tcp_data_ready;
636 sock->sk->sk_error_report = ncp_tcp_error_report;
637 if (sock->type == SOCK_STREAM) {
638 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
639 server->rcv.len = 10;
640 server->rcv.state = 0;
David Howellsc4028952006-11-22 14:57:56 +0000641 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
642 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 sock->sk->sk_write_space = ncp_tcp_write_space;
644 } else {
David Howellsc4028952006-11-22 14:57:56 +0000645 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
646 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 server->timeout_tm.data = (unsigned long)server;
648 server->timeout_tm.function = ncpdgram_timeout_call;
649 }
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200650 release_sock(sock->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
652 ncp_lock_server(server);
653 error = ncp_connect(server);
654 ncp_unlock_server(server);
655 if (error < 0)
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100656 goto out_rxbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
658
659 error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */
660#ifdef CONFIG_NCPFS_PACKET_SIGNING
661 if (ncp_negotiate_size_and_options(server, default_bufsize,
662 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
663 {
664 if (options != NCP_DEFAULT_OPTIONS)
665 {
666 if (ncp_negotiate_size_and_options(server,
667 default_bufsize,
668 options & 2,
669 &(server->buffer_size), &options) != 0)
670
671 {
672 goto out_disconnect;
673 }
674 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200675 ncp_lock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 if (options & 2)
677 server->sign_wanted = 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200678 ncp_unlock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 }
680 else
681#endif /* CONFIG_NCPFS_PACKET_SIGNING */
682 if (ncp_negotiate_buffersize(server, default_bufsize,
683 &(server->buffer_size)) != 0)
684 goto out_disconnect;
685 DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
686
687 memset(&finfo, 0, sizeof(finfo));
688 finfo.i.attributes = aDIR;
689 finfo.i.dataStreamSize = 0; /* ignored */
690 finfo.i.dirEntNum = 0;
691 finfo.i.DosDirNum = 0;
692#ifdef CONFIG_NCPFS_SMALLDOS
693 finfo.i.NSCreator = NW_NS_DOS;
694#endif
695 finfo.volume = NCP_NUMBER_OF_VOLUMES;
696 /* set dates of mountpoint to Jan 1, 1986; 00:00 */
697 finfo.i.creationTime = finfo.i.modifyTime
698 = cpu_to_le16(0x0000);
699 finfo.i.creationDate = finfo.i.modifyDate
700 = finfo.i.lastAccessDate
701 = cpu_to_le16(0x0C21);
702 finfo.i.nameLen = 0;
703 finfo.i.entryName[0] = '\0';
704
705 finfo.opened = 0;
706 finfo.ino = 2; /* tradition */
707
708 server->name_space[finfo.volume] = NW_NS_DOS;
709
710 error = -ENOMEM;
711 root_inode = ncp_iget(sb, &finfo);
712 if (!root_inode)
713 goto out_disconnect;
714 DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
715 sb->s_root = d_alloc_root(root_inode);
716 if (!sb->s_root)
717 goto out_no_root;
718 sb->s_root->d_op = &ncp_root_dentry_operations;
719 return 0;
720
721out_no_root:
722 iput(root_inode);
723out_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);
745out_fput:
Jens Axboef1970c72010-04-22 12:31:11 +0200746 bdi_destroy(&server->bdi);
747out_bdi:
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");