blob: 8fb93b604e73a3a337a5f43ebc97b25d9f02d7f8 [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);
312 flush_scheduled_work();
313}
314
Miklos Szeredi564cd132008-02-08 04:21:46 -0800315static int ncp_show_options(struct seq_file *seq, struct vfsmount *mnt)
316{
317 struct ncp_server *server = NCP_SBP(mnt->mnt_sb);
318 unsigned int tmp;
319
320 if (server->m.uid != 0)
321 seq_printf(seq, ",uid=%u", server->m.uid);
322 if (server->m.gid != 0)
323 seq_printf(seq, ",gid=%u", server->m.gid);
324 if (server->m.mounted_uid != 0)
325 seq_printf(seq, ",owner=%u", server->m.mounted_uid);
326 tmp = server->m.file_mode & S_IALLUGO;
327 if (tmp != NCP_DEFAULT_FILE_MODE)
328 seq_printf(seq, ",mode=0%o", tmp);
329 tmp = server->m.dir_mode & S_IALLUGO;
330 if (tmp != NCP_DEFAULT_DIR_MODE)
331 seq_printf(seq, ",dirmode=0%o", tmp);
332 if (server->m.time_out != NCP_DEFAULT_TIME_OUT * HZ / 100) {
333 tmp = server->m.time_out * 100 / HZ;
334 seq_printf(seq, ",timeout=%u", tmp);
335 }
336 if (server->m.retry_count != NCP_DEFAULT_RETRY_COUNT)
337 seq_printf(seq, ",retry=%u", server->m.retry_count);
338 if (server->m.flags != 0)
339 seq_printf(seq, ",flags=%lu", server->m.flags);
340 if (server->m.wdog_pid != NULL)
341 seq_printf(seq, ",wdogpid=%u", pid_vnr(server->m.wdog_pid));
342
343 return 0;
344}
345
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346static const struct ncp_option ncp_opts[] = {
347 { "uid", OPT_INT, 'u' },
348 { "gid", OPT_INT, 'g' },
349 { "owner", OPT_INT, 'o' },
350 { "mode", OPT_INT, 'm' },
351 { "dirmode", OPT_INT, 'd' },
352 { "timeout", OPT_INT, 't' },
353 { "retry", OPT_INT, 'r' },
354 { "flags", OPT_INT, 'f' },
355 { "wdogpid", OPT_INT, 'w' },
356 { "ncpfd", OPT_INT, 'n' },
357 { "infofd", OPT_INT, 'i' }, /* v5 */
358 { "version", OPT_INT, 'v' },
359 { NULL, 0, 0 } };
360
361static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
362 int optval;
363 char *optarg;
364 unsigned long optint;
365 int version = 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800366 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
368 data->flags = 0;
369 data->int_flags = 0;
370 data->mounted_uid = 0;
Eric W. Biederman21542272006-12-13 00:35:11 -0800371 data->wdog_pid = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 data->ncp_fd = ~0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800373 data->time_out = NCP_DEFAULT_TIME_OUT;
374 data->retry_count = NCP_DEFAULT_RETRY_COUNT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 data->uid = 0;
376 data->gid = 0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800377 data->file_mode = NCP_DEFAULT_FILE_MODE;
378 data->dir_mode = NCP_DEFAULT_DIR_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 data->info_fd = -1;
380 data->mounted_vol[0] = 0;
381
382 while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
Eric W. Biederman1de24122006-12-13 00:35:13 -0800383 ret = optval;
384 if (ret < 0)
385 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 switch (optval) {
387 case 'u':
388 data->uid = optint;
389 break;
390 case 'g':
391 data->gid = optint;
392 break;
393 case 'o':
394 data->mounted_uid = optint;
395 break;
396 case 'm':
397 data->file_mode = optint;
398 break;
399 case 'd':
400 data->dir_mode = optint;
401 break;
402 case 't':
403 data->time_out = optint;
404 break;
405 case 'r':
406 data->retry_count = optint;
407 break;
408 case 'f':
409 data->flags = optint;
410 break;
411 case 'w':
Eric W. Biederman21542272006-12-13 00:35:11 -0800412 data->wdog_pid = find_get_pid(optint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 break;
414 case 'n':
415 data->ncp_fd = optint;
416 break;
417 case 'i':
418 data->info_fd = optint;
419 break;
420 case 'v':
Eric W. Biederman1de24122006-12-13 00:35:13 -0800421 ret = -ECHRNG;
422 if (optint < NCP_MOUNT_VERSION_V4)
423 goto err;
424 if (optint > NCP_MOUNT_VERSION_V5)
425 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 version = optint;
427 break;
428
429 }
430 }
431 return 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800432err:
433 put_pid(data->wdog_pid);
434 data->wdog_pid = NULL;
435 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436}
437
438static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
439{
440 struct ncp_mount_data_kernel data;
441 struct ncp_server *server;
442 struct file *ncp_filp;
443 struct inode *root_inode;
444 struct inode *sock_inode;
445 struct socket *sock;
446 int error;
447 int default_bufsize;
448#ifdef CONFIG_NCPFS_PACKET_SIGNING
449 int options;
450#endif
451 struct ncp_entry_info finfo;
452
Eric W. Biederman1de24122006-12-13 00:35:13 -0800453 data.wdog_pid = NULL;
Panagiotis Issarisf8314dc2006-09-27 01:49:37 -0700454 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 if (!server)
456 return -ENOMEM;
457 sb->s_fs_info = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
459 error = -EFAULT;
460 if (raw_data == NULL)
461 goto out;
462 switch (*(int*)raw_data) {
463 case NCP_MOUNT_VERSION:
464 {
465 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
466
467 data.flags = md->flags;
468 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
469 data.mounted_uid = md->mounted_uid;
Eric W. Biederman21542272006-12-13 00:35:11 -0800470 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 data.ncp_fd = md->ncp_fd;
472 data.time_out = md->time_out;
473 data.retry_count = md->retry_count;
474 data.uid = md->uid;
475 data.gid = md->gid;
476 data.file_mode = md->file_mode;
477 data.dir_mode = md->dir_mode;
478 data.info_fd = -1;
479 memcpy(data.mounted_vol, md->mounted_vol,
480 NCP_VOLNAME_LEN+1);
481 }
482 break;
483 case NCP_MOUNT_VERSION_V4:
484 {
485 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
486
487 data.flags = md->flags;
488 data.int_flags = 0;
489 data.mounted_uid = md->mounted_uid;
Eric W. Biederman21542272006-12-13 00:35:11 -0800490 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 data.ncp_fd = md->ncp_fd;
492 data.time_out = md->time_out;
493 data.retry_count = md->retry_count;
494 data.uid = md->uid;
495 data.gid = md->gid;
496 data.file_mode = md->file_mode;
497 data.dir_mode = md->dir_mode;
498 data.info_fd = -1;
499 data.mounted_vol[0] = 0;
500 }
501 break;
502 default:
503 error = -ECHRNG;
504 if (memcmp(raw_data, "vers", 4) == 0) {
505 error = ncp_parse_options(&data, raw_data);
506 }
507 if (error)
508 goto out;
509 break;
510 }
511 error = -EBADF;
512 ncp_filp = fget(data.ncp_fd);
513 if (!ncp_filp)
514 goto out;
515 error = -ENOTSOCK;
Josef Sipek92e5bae2006-12-08 02:37:22 -0800516 sock_inode = ncp_filp->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 if (!S_ISSOCK(sock_inode->i_mode))
518 goto out_fput;
519 sock = SOCKET_I(sock_inode);
520 if (!sock)
521 goto out_fput;
522
523 if (sock->type == SOCK_STREAM)
524 default_bufsize = 0xF000;
525 else
526 default_bufsize = 1024;
527
528 sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
529 sb->s_maxbytes = 0xFFFFFFFFU;
530 sb->s_blocksize = 1024; /* Eh... Is this correct? */
531 sb->s_blocksize_bits = 10;
532 sb->s_magic = NCP_SUPER_MAGIC;
533 sb->s_op = &ncp_sops;
Jens Axboef1970c72010-04-22 12:31:11 +0200534 sb->s_bdi = &server->bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
536 server = NCP_SBP(sb);
537 memset(server, 0, sizeof(*server));
538
Jens Axboef1970c72010-04-22 12:31:11 +0200539 error = bdi_setup_and_register(&server->bdi, "ncpfs", BDI_CAP_MAP_COPY);
540 if (error)
541 goto out_bdi;
542
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 server->ncp_filp = ncp_filp;
544 server->ncp_sock = sock;
545
546 if (data.info_fd != -1) {
547 struct socket *info_sock;
548
549 error = -EBADF;
550 server->info_filp = fget(data.info_fd);
551 if (!server->info_filp)
552 goto out_fput;
553 error = -ENOTSOCK;
Josef Sipek92e5bae2006-12-08 02:37:22 -0800554 sock_inode = server->info_filp->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 if (!S_ISSOCK(sock_inode->i_mode))
556 goto out_fput2;
557 info_sock = SOCKET_I(sock_inode);
558 if (!info_sock)
559 goto out_fput2;
560 error = -EBADFD;
561 if (info_sock->type != SOCK_STREAM)
562 goto out_fput2;
563 server->info_sock = info_sock;
564 }
565
566/* server->lock = 0; */
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800567 mutex_init(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 server->packet = NULL;
569/* server->buffer_size = 0; */
570/* server->conn_status = 0; */
571/* server->root_dentry = NULL; */
572/* server->root_setuped = 0; */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200573 mutex_init(&server->root_setup_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574#ifdef CONFIG_NCPFS_PACKET_SIGNING
575/* server->sign_wanted = 0; */
576/* server->sign_active = 0; */
577#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200578 init_rwsem(&server->auth_rwsem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 server->auth.auth_type = NCP_AUTH_NONE;
580/* server->auth.object_name_len = 0; */
581/* server->auth.object_name = NULL; */
582/* server->auth.object_type = 0; */
583/* server->priv.len = 0; */
584/* server->priv.data = NULL; */
585
586 server->m = data;
587 /* Althought anything producing this is buggy, it happens
588 now because of PATH_MAX changes.. */
589 if (server->m.time_out < 1) {
590 server->m.time_out = 10;
591 printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
592 }
593 server->m.time_out = server->m.time_out * HZ / 100;
594 server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
595 server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
596
597#ifdef CONFIG_NCPFS_NLS
598 /* load the default NLS charsets */
599 server->nls_vol = load_nls_default();
600 server->nls_io = load_nls_default();
601#endif /* CONFIG_NCPFS_NLS */
602
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200603 atomic_set(&server->dentry_ttl, 0); /* no caching */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604
605 INIT_LIST_HEAD(&server->tx.requests);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800606 mutex_init(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 server->tx.creq = NULL;
608 server->rcv.creq = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
610 init_timer(&server->timeout_tm);
611#undef NCP_PACKET_SIZE
612#define NCP_PACKET_SIZE 131072
613 error = -ENOMEM;
614 server->packet_size = NCP_PACKET_SIZE;
615 server->packet = vmalloc(NCP_PACKET_SIZE);
616 if (server->packet == NULL)
617 goto out_nls;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100618 server->txbuf = vmalloc(NCP_PACKET_SIZE);
619 if (server->txbuf == NULL)
620 goto out_packet;
621 server->rxbuf = vmalloc(NCP_PACKET_SIZE);
622 if (server->rxbuf == NULL)
623 goto out_txbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200625 lock_sock(sock->sk);
626 server->data_ready = sock->sk->sk_data_ready;
627 server->write_space = sock->sk->sk_write_space;
628 server->error_report = sock->sk->sk_error_report;
629 sock->sk->sk_user_data = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630 sock->sk->sk_data_ready = ncp_tcp_data_ready;
631 sock->sk->sk_error_report = ncp_tcp_error_report;
632 if (sock->type == SOCK_STREAM) {
633 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
634 server->rcv.len = 10;
635 server->rcv.state = 0;
David Howellsc4028952006-11-22 14:57:56 +0000636 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
637 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 sock->sk->sk_write_space = ncp_tcp_write_space;
639 } else {
David Howellsc4028952006-11-22 14:57:56 +0000640 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
641 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 server->timeout_tm.data = (unsigned long)server;
643 server->timeout_tm.function = ncpdgram_timeout_call;
644 }
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200645 release_sock(sock->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
647 ncp_lock_server(server);
648 error = ncp_connect(server);
649 ncp_unlock_server(server);
650 if (error < 0)
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100651 goto out_rxbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
653
654 error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */
655#ifdef CONFIG_NCPFS_PACKET_SIGNING
656 if (ncp_negotiate_size_and_options(server, default_bufsize,
657 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
658 {
659 if (options != NCP_DEFAULT_OPTIONS)
660 {
661 if (ncp_negotiate_size_and_options(server,
662 default_bufsize,
663 options & 2,
664 &(server->buffer_size), &options) != 0)
665
666 {
667 goto out_disconnect;
668 }
669 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200670 ncp_lock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 if (options & 2)
672 server->sign_wanted = 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200673 ncp_unlock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 }
675 else
676#endif /* CONFIG_NCPFS_PACKET_SIGNING */
677 if (ncp_negotiate_buffersize(server, default_bufsize,
678 &(server->buffer_size)) != 0)
679 goto out_disconnect;
680 DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
681
682 memset(&finfo, 0, sizeof(finfo));
683 finfo.i.attributes = aDIR;
684 finfo.i.dataStreamSize = 0; /* ignored */
685 finfo.i.dirEntNum = 0;
686 finfo.i.DosDirNum = 0;
687#ifdef CONFIG_NCPFS_SMALLDOS
688 finfo.i.NSCreator = NW_NS_DOS;
689#endif
690 finfo.volume = NCP_NUMBER_OF_VOLUMES;
691 /* set dates of mountpoint to Jan 1, 1986; 00:00 */
692 finfo.i.creationTime = finfo.i.modifyTime
693 = cpu_to_le16(0x0000);
694 finfo.i.creationDate = finfo.i.modifyDate
695 = finfo.i.lastAccessDate
696 = cpu_to_le16(0x0C21);
697 finfo.i.nameLen = 0;
698 finfo.i.entryName[0] = '\0';
699
700 finfo.opened = 0;
701 finfo.ino = 2; /* tradition */
702
703 server->name_space[finfo.volume] = NW_NS_DOS;
704
705 error = -ENOMEM;
706 root_inode = ncp_iget(sb, &finfo);
707 if (!root_inode)
708 goto out_disconnect;
709 DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
710 sb->s_root = d_alloc_root(root_inode);
711 if (!sb->s_root)
712 goto out_no_root;
713 sb->s_root->d_op = &ncp_root_dentry_operations;
714 return 0;
715
716out_no_root:
717 iput(root_inode);
718out_disconnect:
719 ncp_lock_server(server);
720 ncp_disconnect(server);
721 ncp_unlock_server(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100722out_rxbuf:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 ncp_stop_tasks(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100724 vfree(server->rxbuf);
725out_txbuf:
726 vfree(server->txbuf);
727out_packet:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 vfree(server->packet);
729out_nls:
730#ifdef CONFIG_NCPFS_NLS
731 unload_nls(server->nls_io);
732 unload_nls(server->nls_vol);
733#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200734 mutex_destroy(&server->rcv.creq_mutex);
735 mutex_destroy(&server->root_setup_lock);
736 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737out_fput2:
738 if (server->info_filp)
739 fput(server->info_filp);
740out_fput:
Jens Axboef1970c72010-04-22 12:31:11 +0200741 bdi_destroy(&server->bdi);
742out_bdi:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
744 *
Matthew Whitworthe956b4b2010-06-27 14:34:30 +0100745 * The previously used put_filp(ncp_filp); was bogus, since
746 * it doesn't perform proper unlocking.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 */
748 fput(ncp_filp);
749out:
Eric W. Biederman1de24122006-12-13 00:35:13 -0800750 put_pid(data.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 sb->s_fs_info = NULL;
752 kfree(server);
753 return error;
754}
755
756static void ncp_put_super(struct super_block *sb)
757{
758 struct ncp_server *server = NCP_SBP(sb);
759
760 ncp_lock_server(server);
761 ncp_disconnect(server);
762 ncp_unlock_server(server);
763
764 ncp_stop_tasks(server);
765
766#ifdef CONFIG_NCPFS_NLS
767 /* unload the NLS charsets */
Thomas Gleixner6d729e42009-08-16 21:05:08 +0000768 unload_nls(server->nls_vol);
769 unload_nls(server->nls_io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770#endif /* CONFIG_NCPFS_NLS */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200771 mutex_destroy(&server->rcv.creq_mutex);
772 mutex_destroy(&server->root_setup_lock);
773 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774
775 if (server->info_filp)
776 fput(server->info_filp);
777 fput(server->ncp_filp);
Eric W. Biederman21542272006-12-13 00:35:11 -0800778 kill_pid(server->m.wdog_pid, SIGTERM, 1);
779 put_pid(server->m.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780
Jens Axboef1970c72010-04-22 12:31:11 +0200781 bdi_destroy(&server->bdi);
Pekka Enberg44db77f2006-01-14 13:21:12 -0800782 kfree(server->priv.data);
783 kfree(server->auth.object_name);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100784 vfree(server->rxbuf);
785 vfree(server->txbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 vfree(server->packet);
787 sb->s_fs_info = NULL;
788 kfree(server);
789}
790
David Howells726c3342006-06-23 02:02:58 -0700791static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792{
793 struct dentry* d;
794 struct inode* i;
795 struct ncp_inode_info* ni;
796 struct ncp_server* s;
797 struct ncp_volume_info vi;
David Howells726c3342006-06-23 02:02:58 -0700798 struct super_block *sb = dentry->d_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 int err;
800 __u8 dh;
801
802 d = sb->s_root;
803 if (!d) {
804 goto dflt;
805 }
806 i = d->d_inode;
807 if (!i) {
808 goto dflt;
809 }
810 ni = NCP_FINFO(i);
811 if (!ni) {
812 goto dflt;
813 }
814 s = NCP_SBP(sb);
815 if (!s) {
816 goto dflt;
817 }
818 if (!s->m.mounted_vol[0]) {
819 goto dflt;
820 }
821
822 err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
823 if (err) {
824 goto dflt;
825 }
826 err = ncp_get_directory_info(s, dh, &vi);
827 ncp_dirhandle_free(s, dh);
828 if (err) {
829 goto dflt;
830 }
831 buf->f_type = NCP_SUPER_MAGIC;
832 buf->f_bsize = vi.sectors_per_block * 512;
833 buf->f_blocks = vi.total_blocks;
834 buf->f_bfree = vi.free_blocks;
835 buf->f_bavail = vi.free_blocks;
836 buf->f_files = vi.total_dir_entries;
837 buf->f_ffree = vi.available_dir_entries;
838 buf->f_namelen = 12;
839 return 0;
840
841 /* We cannot say how much disk space is left on a mounted
842 NetWare Server, because free space is distributed over
843 volumes, and the current user might have disk quotas. So
844 free space is not that simple to determine. Our decision
845 here is to err conservatively. */
846
847dflt:;
848 buf->f_type = NCP_SUPER_MAGIC;
849 buf->f_bsize = NCP_BLOCK_SIZE;
850 buf->f_blocks = 0;
851 buf->f_bfree = 0;
852 buf->f_bavail = 0;
853 buf->f_namelen = 12;
854 return 0;
855}
856
857int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
858{
859 struct inode *inode = dentry->d_inode;
860 int result = 0;
861 __le32 info_mask;
862 struct nw_modify_dos_info info;
863 struct ncp_server *server;
864
865 result = -EIO;
866
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 server = NCP_SERVER(inode);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200868 if (!server) /* How this could happen? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 goto out;
870
871 /* ageing the dentry to force validation */
872 ncp_age_dentry(server, dentry);
873
874 result = inode_change_ok(inode, attr);
875 if (result < 0)
876 goto out;
877
878 result = -EPERM;
879 if (((attr->ia_valid & ATTR_UID) &&
880 (attr->ia_uid != server->m.uid)))
881 goto out;
882
883 if (((attr->ia_valid & ATTR_GID) &&
884 (attr->ia_gid != server->m.gid)))
885 goto out;
886
887 if (((attr->ia_valid & ATTR_MODE) &&
888 (attr->ia_mode &
889 ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
890 goto out;
891
892 info_mask = 0;
893 memset(&info, 0, sizeof(info));
894
895#if 1
896 if ((attr->ia_valid & ATTR_MODE) != 0)
897 {
898 umode_t newmode = attr->ia_mode;
899
900 info_mask |= DM_ATTRIBUTES;
901
902 if (S_ISDIR(inode->i_mode)) {
903 newmode &= server->m.dir_mode;
904 } else {
905#ifdef CONFIG_NCPFS_EXTRAS
906 if (server->m.flags & NCP_MOUNT_EXTRAS) {
907 /* any non-default execute bit set */
908 if (newmode & ~server->m.file_mode & S_IXUGO)
909 info.attributes |= aSHARED | aSYSTEM;
910 /* read for group/world and not in default file_mode */
911 else if (newmode & ~server->m.file_mode & S_IRUGO)
912 info.attributes |= aSHARED;
913 } else
914#endif
915 newmode &= server->m.file_mode;
916 }
917 if (newmode & S_IWUGO)
918 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
919 else
920 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
921
922#ifdef CONFIG_NCPFS_NFS_NS
923 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
924 result = ncp_modify_nfs_info(server,
925 NCP_FINFO(inode)->volNumber,
926 NCP_FINFO(inode)->dirEntNum,
927 attr->ia_mode, 0);
928 if (result != 0)
929 goto out;
930 info.attributes &= ~(aSHARED | aSYSTEM);
931 {
932 /* mark partial success */
933 struct iattr tmpattr;
934
935 tmpattr.ia_valid = ATTR_MODE;
936 tmpattr.ia_mode = attr->ia_mode;
937
Christoph Hellwig10257742010-06-04 11:30:02 +0200938 setattr_copy(inode, &tmpattr);
939 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 }
941 }
942#endif
943 }
944#endif
945
946 /* Do SIZE before attributes, otherwise mtime together with size does not work...
947 */
948 if ((attr->ia_valid & ATTR_SIZE) != 0) {
949 int written;
950
951 DPRINTK("ncpfs: trying to change size to %ld\n",
952 attr->ia_size);
953
954 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
955 result = -EACCES;
956 goto out;
957 }
958 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
959 attr->ia_size, 0, "", &written);
960
961 /* According to ndir, the changes only take effect after
962 closing the file */
963 ncp_inode_close(inode);
964 result = ncp_make_closed(inode);
965 if (result)
966 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +0200967
968 if (attr->ia_size != i_size_read(inode)) {
969 result = vmtruncate(inode, attr->ia_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 if (result)
971 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +0200972 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 }
974 }
975 if ((attr->ia_valid & ATTR_CTIME) != 0) {
976 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
977 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
978 &info.creationTime, &info.creationDate);
979 }
980 if ((attr->ia_valid & ATTR_MTIME) != 0) {
981 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
982 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
983 &info.modifyTime, &info.modifyDate);
984 }
985 if ((attr->ia_valid & ATTR_ATIME) != 0) {
986 __le16 dummy;
987 info_mask |= (DM_LAST_ACCESS_DATE);
988 ncp_date_unix2dos(attr->ia_atime.tv_sec,
989 &dummy, &info.lastAccessDate);
990 }
991 if (info_mask != 0) {
992 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
993 inode, info_mask, &info);
994 if (result != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
996 /* NetWare seems not to allow this. I
997 do not know why. So, just tell the
998 user everything went fine. This is
999 a terrible hack, but I do not know
1000 how to do this correctly. */
1001 result = 0;
1002 } else
1003 goto out;
1004 }
1005#ifdef CONFIG_NCPFS_STRONG
1006 if ((!result) && (info_mask & DM_ATTRIBUTES))
1007 NCP_FINFO(inode)->nwattr = info.attributes;
1008#endif
1009 }
Christoph Hellwig10257742010-06-04 11:30:02 +02001010 if (result)
1011 goto out;
1012
1013 setattr_copy(inode, attr);
1014 mark_inode_dirty(inode);
1015
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016out:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001017 if (result > 0)
1018 result = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 return result;
1020}
1021
Al Viro3c26ff62010-07-25 11:46:36 +04001022static struct dentry *ncp_mount(struct file_system_type *fs_type,
1023 int flags, const char *dev_name, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024{
Al Viro3c26ff62010-07-25 11:46:36 +04001025 return mount_nodev(fs_type, flags, data, ncp_fill_super);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026}
1027
1028static struct file_system_type ncp_fs_type = {
1029 .owner = THIS_MODULE,
1030 .name = "ncpfs",
Al Viro3c26ff62010-07-25 11:46:36 +04001031 .mount = ncp_mount,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 .kill_sb = kill_anon_super,
Miklos Szeredi564cd132008-02-08 04:21:46 -08001033 .fs_flags = FS_BINARY_MOUNTDATA,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034};
1035
1036static int __init init_ncp_fs(void)
1037{
1038 int err;
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001039 DPRINTK("ncpfs: init_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 err = init_inodecache();
1042 if (err)
1043 goto out1;
1044 err = register_filesystem(&ncp_fs_type);
1045 if (err)
1046 goto out;
1047 return 0;
1048out:
1049 destroy_inodecache();
1050out1:
1051 return err;
1052}
1053
1054static void __exit exit_ncp_fs(void)
1055{
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001056 DPRINTK("ncpfs: exit_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 unregister_filesystem(&ncp_fs_type);
1058 destroy_inodecache();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059}
1060
1061module_init(init_ncp_fs)
1062module_exit(exit_ncp_fs)
1063MODULE_LICENSE("GPL");