blob: 5f4e58d93fdd908f3ffe4a95e71966e1ddad2a1e [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>
29#include <linux/smp_lock.h>
30#include <linux/vfs.h>
Miklos Szeredi564cd132008-02-08 04:21:46 -080031#include <linux/mount.h>
32#include <linux/seq_file.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
62static void ncp_destroy_inode(struct inode *inode)
63{
64 kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
65}
66
Alexey Dobriyan51cc5062008-07-25 19:45:34 -070067static void init_once(void *foo)
Linus Torvalds1da177e2005-04-16 15:20:36 -070068{
69 struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
70
Christoph Lametera35afb82007-05-16 22:10:57 -070071 mutex_init(&ei->open_mutex);
72 inode_init_once(&ei->vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070073}
Paul Mundt20c2df82007-07-20 10:11:58 +090074
Linus Torvalds1da177e2005-04-16 15:20:36 -070075static int init_inodecache(void)
76{
77 ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
78 sizeof(struct ncp_inode_info),
Paul Jacksonfffb60f2006-03-24 03:16:06 -080079 0, (SLAB_RECLAIM_ACCOUNT|
80 SLAB_MEM_SPREAD),
Paul Mundt20c2df82007-07-20 10:11:58 +090081 init_once);
Linus Torvalds1da177e2005-04-16 15:20:36 -070082 if (ncp_inode_cachep == NULL)
83 return -ENOMEM;
84 return 0;
85}
86
87static void destroy_inodecache(void)
88{
Alexey Dobriyan1a1d92c2006-09-27 01:49:40 -070089 kmem_cache_destroy(ncp_inode_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090}
91
92static int ncp_remount(struct super_block *sb, int *flags, char* data)
93{
94 *flags |= MS_NODIRATIME;
95 return 0;
96}
97
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -080098static const struct super_operations ncp_sops =
Linus Torvalds1da177e2005-04-16 15:20:36 -070099{
100 .alloc_inode = ncp_alloc_inode,
101 .destroy_inode = ncp_destroy_inode,
102 .drop_inode = generic_delete_inode,
Al Viro94ee8492010-06-07 00:45:56 -0400103 .evict_inode = ncp_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 .put_super = ncp_put_super,
105 .statfs = ncp_statfs,
106 .remount_fs = ncp_remount,
Miklos Szeredi564cd132008-02-08 04:21:46 -0800107 .show_options = ncp_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108};
109
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110/*
111 * Fill in the ncpfs-specific information in the inode.
112 */
113static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
114{
115 NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
116 NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
117 NCP_FINFO(inode)->volNumber = nwinfo->volume;
118}
119
120void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
121{
122 ncp_update_dirent(inode, nwinfo);
123 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
124 NCP_FINFO(inode)->access = nwinfo->access;
125 memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
126 sizeof(nwinfo->file_handle));
127 DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
128 nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
129 NCP_FINFO(inode)->dirEntNum);
130}
131
132static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
133{
134 /* NFS namespace mode overrides others if it's set. */
135 DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n",
136 nwi->entryName, nwi->nfs.mode);
137 if (nwi->nfs.mode) {
138 /* XXX Security? */
139 inode->i_mode = nwi->nfs.mode;
140 }
141
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200142 inode->i_blocks = (i_size_read(inode) + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144 inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate);
145 inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate);
146 inode->i_atime.tv_sec = ncp_date_dos2unix(0, nwi->lastAccessDate);
147 inode->i_atime.tv_nsec = 0;
148 inode->i_mtime.tv_nsec = 0;
149 inode->i_ctime.tv_nsec = 0;
150}
151
152static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
153{
154 struct nw_info_struct *nwi = &nwinfo->i;
155 struct ncp_server *server = NCP_SERVER(inode);
156
157 if (nwi->attributes & aDIR) {
158 inode->i_mode = server->m.dir_mode;
159 /* for directories dataStreamSize seems to be some
160 Object ID ??? */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200161 i_size_write(inode, NCP_BLOCK_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 } else {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200163 u32 size;
164
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 inode->i_mode = server->m.file_mode;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200166 size = le32_to_cpu(nwi->dataStreamSize);
167 i_size_write(inode, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168#ifdef CONFIG_NCPFS_EXTRAS
169 if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS))
170 && (nwi->attributes & aSHARED)) {
171 switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
172 case aHIDDEN:
173 if (server->m.flags & NCP_MOUNT_SYMLINKS) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200174 if (/* (size >= NCP_MIN_SYMLINK_SIZE)
175 && */ (size <= NCP_MAX_SYMLINK_SIZE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
177 NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
178 break;
179 }
180 }
181 /* FALLTHROUGH */
182 case 0:
183 if (server->m.flags & NCP_MOUNT_EXTRAS)
184 inode->i_mode |= S_IRUGO;
185 break;
186 case aSYSTEM:
187 if (server->m.flags & NCP_MOUNT_EXTRAS)
188 inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO;
189 break;
190 /* case aSYSTEM|aHIDDEN: */
191 default:
192 /* reserved combination */
193 break;
194 }
195 }
196#endif
197 }
198 if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
199}
200
201void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
202{
203 NCP_FINFO(inode)->flags = 0;
204 if (!atomic_read(&NCP_FINFO(inode)->opened)) {
205 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
206 ncp_update_attrs(inode, nwinfo);
207 }
208
209 ncp_update_dates(inode, &nwinfo->i);
210 ncp_update_dirent(inode, nwinfo);
211}
212
213/*
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200214 * Fill in the inode based on the ncp_entry_info structure. Used only for brand new inodes.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 */
216static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
217{
218 struct ncp_server *server = NCP_SERVER(inode);
219
220 NCP_FINFO(inode)->flags = 0;
221
222 ncp_update_attrs(inode, nwinfo);
223
224 DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
225
226 inode->i_nlink = 1;
227 inode->i_uid = server->m.uid;
228 inode->i_gid = server->m.gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229
230 ncp_update_dates(inode, &nwinfo->i);
231 ncp_update_inode(inode, nwinfo);
232}
233
234#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800235static const struct inode_operations ncp_symlink_inode_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 .readlink = generic_readlink,
237 .follow_link = page_follow_link_light,
238 .put_link = page_put_link,
239 .setattr = ncp_notify_change,
240};
241#endif
242
243/*
244 * Get a new inode.
245 */
246struct inode *
247ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
248{
249 struct inode *inode;
250
251 if (info == NULL) {
252 printk(KERN_ERR "ncp_iget: info is NULL\n");
253 return NULL;
254 }
255
256 inode = new_inode(sb);
257 if (inode) {
258 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
259
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200260 inode->i_mapping->backing_dev_info = sb->s_bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 inode->i_ino = info->ino;
262 ncp_set_attr(inode, info);
263 if (S_ISREG(inode->i_mode)) {
264 inode->i_op = &ncp_file_inode_operations;
265 inode->i_fop = &ncp_file_operations;
266 } else if (S_ISDIR(inode->i_mode)) {
267 inode->i_op = &ncp_dir_inode_operations;
268 inode->i_fop = &ncp_dir_operations;
269#ifdef CONFIG_NCPFS_NFS_NS
270 } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
271 init_special_inode(inode, inode->i_mode,
272 new_decode_dev(info->i.nfs.rdev));
273#endif
274#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
275 } else if (S_ISLNK(inode->i_mode)) {
276 inode->i_op = &ncp_symlink_inode_operations;
277 inode->i_data.a_ops = &ncp_symlink_aops;
278#endif
279 } else {
280 make_bad_inode(inode);
281 }
282 insert_inode_hash(inode);
283 } else
284 printk(KERN_ERR "ncp_iget: iget failed!\n");
285 return inode;
286}
287
288static void
Al Viro94ee8492010-06-07 00:45:56 -0400289ncp_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290{
Mark Fashehfef26652005-09-09 13:01:31 -0700291 truncate_inode_pages(&inode->i_data, 0);
Al Viro94ee8492010-06-07 00:45:56 -0400292 end_writeback(inode);
Mark Fashehfef26652005-09-09 13:01:31 -0700293
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 if (S_ISDIR(inode->i_mode)) {
Al Viro94ee8492010-06-07 00:45:56 -0400295 DDPRINTK("ncp_evict_inode: put directory %ld\n", inode->i_ino);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 }
297
298 if (ncp_make_closed(inode) != 0) {
299 /* We can't do anything but complain. */
Al Viro94ee8492010-06-07 00:45:56 -0400300 printk(KERN_ERR "ncp_evict_inode: could not close\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302}
303
304static void ncp_stop_tasks(struct ncp_server *server) {
305 struct sock* sk = server->ncp_sock->sk;
306
307 sk->sk_error_report = server->error_report;
308 sk->sk_data_ready = server->data_ready;
309 sk->sk_write_space = server->write_space;
310 del_timer_sync(&server->timeout_tm);
311 flush_scheduled_work();
312}
313
Miklos Szeredi564cd132008-02-08 04:21:46 -0800314static int ncp_show_options(struct seq_file *seq, struct vfsmount *mnt)
315{
316 struct ncp_server *server = NCP_SBP(mnt->mnt_sb);
317 unsigned int tmp;
318
319 if (server->m.uid != 0)
320 seq_printf(seq, ",uid=%u", server->m.uid);
321 if (server->m.gid != 0)
322 seq_printf(seq, ",gid=%u", server->m.gid);
323 if (server->m.mounted_uid != 0)
324 seq_printf(seq, ",owner=%u", server->m.mounted_uid);
325 tmp = server->m.file_mode & S_IALLUGO;
326 if (tmp != NCP_DEFAULT_FILE_MODE)
327 seq_printf(seq, ",mode=0%o", tmp);
328 tmp = server->m.dir_mode & S_IALLUGO;
329 if (tmp != NCP_DEFAULT_DIR_MODE)
330 seq_printf(seq, ",dirmode=0%o", tmp);
331 if (server->m.time_out != NCP_DEFAULT_TIME_OUT * HZ / 100) {
332 tmp = server->m.time_out * 100 / HZ;
333 seq_printf(seq, ",timeout=%u", tmp);
334 }
335 if (server->m.retry_count != NCP_DEFAULT_RETRY_COUNT)
336 seq_printf(seq, ",retry=%u", server->m.retry_count);
337 if (server->m.flags != 0)
338 seq_printf(seq, ",flags=%lu", server->m.flags);
339 if (server->m.wdog_pid != NULL)
340 seq_printf(seq, ",wdogpid=%u", pid_vnr(server->m.wdog_pid));
341
342 return 0;
343}
344
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345static const struct ncp_option ncp_opts[] = {
346 { "uid", OPT_INT, 'u' },
347 { "gid", OPT_INT, 'g' },
348 { "owner", OPT_INT, 'o' },
349 { "mode", OPT_INT, 'm' },
350 { "dirmode", OPT_INT, 'd' },
351 { "timeout", OPT_INT, 't' },
352 { "retry", OPT_INT, 'r' },
353 { "flags", OPT_INT, 'f' },
354 { "wdogpid", OPT_INT, 'w' },
355 { "ncpfd", OPT_INT, 'n' },
356 { "infofd", OPT_INT, 'i' }, /* v5 */
357 { "version", OPT_INT, 'v' },
358 { NULL, 0, 0 } };
359
360static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
361 int optval;
362 char *optarg;
363 unsigned long optint;
364 int version = 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800365 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
367 data->flags = 0;
368 data->int_flags = 0;
369 data->mounted_uid = 0;
Eric W. Biederman21542272006-12-13 00:35:11 -0800370 data->wdog_pid = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 data->ncp_fd = ~0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800372 data->time_out = NCP_DEFAULT_TIME_OUT;
373 data->retry_count = NCP_DEFAULT_RETRY_COUNT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 data->uid = 0;
375 data->gid = 0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800376 data->file_mode = NCP_DEFAULT_FILE_MODE;
377 data->dir_mode = NCP_DEFAULT_DIR_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 data->info_fd = -1;
379 data->mounted_vol[0] = 0;
380
381 while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
Eric W. Biederman1de24122006-12-13 00:35:13 -0800382 ret = optval;
383 if (ret < 0)
384 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 switch (optval) {
386 case 'u':
387 data->uid = optint;
388 break;
389 case 'g':
390 data->gid = optint;
391 break;
392 case 'o':
393 data->mounted_uid = optint;
394 break;
395 case 'm':
396 data->file_mode = optint;
397 break;
398 case 'd':
399 data->dir_mode = optint;
400 break;
401 case 't':
402 data->time_out = optint;
403 break;
404 case 'r':
405 data->retry_count = optint;
406 break;
407 case 'f':
408 data->flags = optint;
409 break;
410 case 'w':
Eric W. Biederman21542272006-12-13 00:35:11 -0800411 data->wdog_pid = find_get_pid(optint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 break;
413 case 'n':
414 data->ncp_fd = optint;
415 break;
416 case 'i':
417 data->info_fd = optint;
418 break;
419 case 'v':
Eric W. Biederman1de24122006-12-13 00:35:13 -0800420 ret = -ECHRNG;
421 if (optint < NCP_MOUNT_VERSION_V4)
422 goto err;
423 if (optint > NCP_MOUNT_VERSION_V5)
424 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 version = optint;
426 break;
427
428 }
429 }
430 return 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800431err:
432 put_pid(data->wdog_pid);
433 data->wdog_pid = NULL;
434 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435}
436
437static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
438{
439 struct ncp_mount_data_kernel data;
440 struct ncp_server *server;
441 struct file *ncp_filp;
442 struct inode *root_inode;
443 struct inode *sock_inode;
444 struct socket *sock;
445 int error;
446 int default_bufsize;
447#ifdef CONFIG_NCPFS_PACKET_SIGNING
448 int options;
449#endif
450 struct ncp_entry_info finfo;
451
Eric W. Biederman1de24122006-12-13 00:35:13 -0800452 data.wdog_pid = NULL;
Panagiotis Issarisf8314dc2006-09-27 01:49:37 -0700453 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 if (!server)
455 return -ENOMEM;
456 sb->s_fs_info = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457
458 error = -EFAULT;
459 if (raw_data == NULL)
460 goto out;
461 switch (*(int*)raw_data) {
462 case NCP_MOUNT_VERSION:
463 {
464 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
465
466 data.flags = md->flags;
467 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
468 data.mounted_uid = md->mounted_uid;
Eric W. Biederman21542272006-12-13 00:35:11 -0800469 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 data.ncp_fd = md->ncp_fd;
471 data.time_out = md->time_out;
472 data.retry_count = md->retry_count;
473 data.uid = md->uid;
474 data.gid = md->gid;
475 data.file_mode = md->file_mode;
476 data.dir_mode = md->dir_mode;
477 data.info_fd = -1;
478 memcpy(data.mounted_vol, md->mounted_vol,
479 NCP_VOLNAME_LEN+1);
480 }
481 break;
482 case NCP_MOUNT_VERSION_V4:
483 {
484 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
485
486 data.flags = md->flags;
487 data.int_flags = 0;
488 data.mounted_uid = md->mounted_uid;
Eric W. Biederman21542272006-12-13 00:35:11 -0800489 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 data.ncp_fd = md->ncp_fd;
491 data.time_out = md->time_out;
492 data.retry_count = md->retry_count;
493 data.uid = md->uid;
494 data.gid = md->gid;
495 data.file_mode = md->file_mode;
496 data.dir_mode = md->dir_mode;
497 data.info_fd = -1;
498 data.mounted_vol[0] = 0;
499 }
500 break;
501 default:
502 error = -ECHRNG;
503 if (memcmp(raw_data, "vers", 4) == 0) {
504 error = ncp_parse_options(&data, raw_data);
505 }
506 if (error)
507 goto out;
508 break;
509 }
510 error = -EBADF;
511 ncp_filp = fget(data.ncp_fd);
512 if (!ncp_filp)
513 goto out;
514 error = -ENOTSOCK;
Josef Sipek92e5bae2006-12-08 02:37:22 -0800515 sock_inode = ncp_filp->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 if (!S_ISSOCK(sock_inode->i_mode))
517 goto out_fput;
518 sock = SOCKET_I(sock_inode);
519 if (!sock)
520 goto out_fput;
521
522 if (sock->type == SOCK_STREAM)
523 default_bufsize = 0xF000;
524 else
525 default_bufsize = 1024;
526
527 sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
528 sb->s_maxbytes = 0xFFFFFFFFU;
529 sb->s_blocksize = 1024; /* Eh... Is this correct? */
530 sb->s_blocksize_bits = 10;
531 sb->s_magic = NCP_SUPER_MAGIC;
532 sb->s_op = &ncp_sops;
Jens Axboef1970c72010-04-22 12:31:11 +0200533 sb->s_bdi = &server->bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
535 server = NCP_SBP(sb);
536 memset(server, 0, sizeof(*server));
537
Jens Axboef1970c72010-04-22 12:31:11 +0200538 error = bdi_setup_and_register(&server->bdi, "ncpfs", BDI_CAP_MAP_COPY);
539 if (error)
540 goto out_bdi;
541
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 server->ncp_filp = ncp_filp;
543 server->ncp_sock = sock;
544
545 if (data.info_fd != -1) {
546 struct socket *info_sock;
547
548 error = -EBADF;
549 server->info_filp = fget(data.info_fd);
550 if (!server->info_filp)
551 goto out_fput;
552 error = -ENOTSOCK;
Josef Sipek92e5bae2006-12-08 02:37:22 -0800553 sock_inode = server->info_filp->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 if (!S_ISSOCK(sock_inode->i_mode))
555 goto out_fput2;
556 info_sock = SOCKET_I(sock_inode);
557 if (!info_sock)
558 goto out_fput2;
559 error = -EBADFD;
560 if (info_sock->type != SOCK_STREAM)
561 goto out_fput2;
562 server->info_sock = info_sock;
563 }
564
565/* server->lock = 0; */
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800566 mutex_init(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 server->packet = NULL;
568/* server->buffer_size = 0; */
569/* server->conn_status = 0; */
570/* server->root_dentry = NULL; */
571/* server->root_setuped = 0; */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200572 mutex_init(&server->root_setup_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573#ifdef CONFIG_NCPFS_PACKET_SIGNING
574/* server->sign_wanted = 0; */
575/* server->sign_active = 0; */
576#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200577 init_rwsem(&server->auth_rwsem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 server->auth.auth_type = NCP_AUTH_NONE;
579/* server->auth.object_name_len = 0; */
580/* server->auth.object_name = NULL; */
581/* server->auth.object_type = 0; */
582/* server->priv.len = 0; */
583/* server->priv.data = NULL; */
584
585 server->m = data;
586 /* Althought anything producing this is buggy, it happens
587 now because of PATH_MAX changes.. */
588 if (server->m.time_out < 1) {
589 server->m.time_out = 10;
590 printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
591 }
592 server->m.time_out = server->m.time_out * HZ / 100;
593 server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
594 server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
595
596#ifdef CONFIG_NCPFS_NLS
597 /* load the default NLS charsets */
598 server->nls_vol = load_nls_default();
599 server->nls_io = load_nls_default();
600#endif /* CONFIG_NCPFS_NLS */
601
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200602 atomic_set(&server->dentry_ttl, 0); /* no caching */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
604 INIT_LIST_HEAD(&server->tx.requests);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800605 mutex_init(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 server->tx.creq = NULL;
607 server->rcv.creq = NULL;
608 server->data_ready = sock->sk->sk_data_ready;
609 server->write_space = sock->sk->sk_write_space;
610 server->error_report = sock->sk->sk_error_report;
611 sock->sk->sk_user_data = server;
612
613 init_timer(&server->timeout_tm);
614#undef NCP_PACKET_SIZE
615#define NCP_PACKET_SIZE 131072
616 error = -ENOMEM;
617 server->packet_size = NCP_PACKET_SIZE;
618 server->packet = vmalloc(NCP_PACKET_SIZE);
619 if (server->packet == NULL)
620 goto out_nls;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100621 server->txbuf = vmalloc(NCP_PACKET_SIZE);
622 if (server->txbuf == NULL)
623 goto out_packet;
624 server->rxbuf = vmalloc(NCP_PACKET_SIZE);
625 if (server->rxbuf == NULL)
626 goto out_txbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627
628 sock->sk->sk_data_ready = ncp_tcp_data_ready;
629 sock->sk->sk_error_report = ncp_tcp_error_report;
630 if (sock->type == SOCK_STREAM) {
631 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
632 server->rcv.len = 10;
633 server->rcv.state = 0;
David Howellsc4028952006-11-22 14:57:56 +0000634 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
635 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 sock->sk->sk_write_space = ncp_tcp_write_space;
637 } else {
David Howellsc4028952006-11-22 14:57:56 +0000638 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
639 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 server->timeout_tm.data = (unsigned long)server;
641 server->timeout_tm.function = ncpdgram_timeout_call;
642 }
643
644 ncp_lock_server(server);
645 error = ncp_connect(server);
646 ncp_unlock_server(server);
647 if (error < 0)
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100648 goto out_rxbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
650
651 error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */
652#ifdef CONFIG_NCPFS_PACKET_SIGNING
653 if (ncp_negotiate_size_and_options(server, default_bufsize,
654 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
655 {
656 if (options != NCP_DEFAULT_OPTIONS)
657 {
658 if (ncp_negotiate_size_and_options(server,
659 default_bufsize,
660 options & 2,
661 &(server->buffer_size), &options) != 0)
662
663 {
664 goto out_disconnect;
665 }
666 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200667 ncp_lock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 if (options & 2)
669 server->sign_wanted = 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200670 ncp_unlock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671 }
672 else
673#endif /* CONFIG_NCPFS_PACKET_SIGNING */
674 if (ncp_negotiate_buffersize(server, default_bufsize,
675 &(server->buffer_size)) != 0)
676 goto out_disconnect;
677 DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
678
679 memset(&finfo, 0, sizeof(finfo));
680 finfo.i.attributes = aDIR;
681 finfo.i.dataStreamSize = 0; /* ignored */
682 finfo.i.dirEntNum = 0;
683 finfo.i.DosDirNum = 0;
684#ifdef CONFIG_NCPFS_SMALLDOS
685 finfo.i.NSCreator = NW_NS_DOS;
686#endif
687 finfo.volume = NCP_NUMBER_OF_VOLUMES;
688 /* set dates of mountpoint to Jan 1, 1986; 00:00 */
689 finfo.i.creationTime = finfo.i.modifyTime
690 = cpu_to_le16(0x0000);
691 finfo.i.creationDate = finfo.i.modifyDate
692 = finfo.i.lastAccessDate
693 = cpu_to_le16(0x0C21);
694 finfo.i.nameLen = 0;
695 finfo.i.entryName[0] = '\0';
696
697 finfo.opened = 0;
698 finfo.ino = 2; /* tradition */
699
700 server->name_space[finfo.volume] = NW_NS_DOS;
701
702 error = -ENOMEM;
703 root_inode = ncp_iget(sb, &finfo);
704 if (!root_inode)
705 goto out_disconnect;
706 DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
707 sb->s_root = d_alloc_root(root_inode);
708 if (!sb->s_root)
709 goto out_no_root;
710 sb->s_root->d_op = &ncp_root_dentry_operations;
711 return 0;
712
713out_no_root:
714 iput(root_inode);
715out_disconnect:
716 ncp_lock_server(server);
717 ncp_disconnect(server);
718 ncp_unlock_server(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100719out_rxbuf:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 ncp_stop_tasks(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100721 vfree(server->rxbuf);
722out_txbuf:
723 vfree(server->txbuf);
724out_packet:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 vfree(server->packet);
726out_nls:
727#ifdef CONFIG_NCPFS_NLS
728 unload_nls(server->nls_io);
729 unload_nls(server->nls_vol);
730#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200731 mutex_destroy(&server->rcv.creq_mutex);
732 mutex_destroy(&server->root_setup_lock);
733 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734out_fput2:
735 if (server->info_filp)
736 fput(server->info_filp);
737out_fput:
Jens Axboef1970c72010-04-22 12:31:11 +0200738 bdi_destroy(&server->bdi);
739out_bdi:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
741 *
Matthew Whitworthe956b4b2010-06-27 14:34:30 +0100742 * The previously used put_filp(ncp_filp); was bogus, since
743 * it doesn't perform proper unlocking.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 */
745 fput(ncp_filp);
746out:
Eric W. Biederman1de24122006-12-13 00:35:13 -0800747 put_pid(data.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 sb->s_fs_info = NULL;
749 kfree(server);
750 return error;
751}
752
753static void ncp_put_super(struct super_block *sb)
754{
755 struct ncp_server *server = NCP_SBP(sb);
756
757 ncp_lock_server(server);
758 ncp_disconnect(server);
759 ncp_unlock_server(server);
760
761 ncp_stop_tasks(server);
762
763#ifdef CONFIG_NCPFS_NLS
764 /* unload the NLS charsets */
Thomas Gleixner6d729e42009-08-16 21:05:08 +0000765 unload_nls(server->nls_vol);
766 unload_nls(server->nls_io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767#endif /* CONFIG_NCPFS_NLS */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200768 mutex_destroy(&server->rcv.creq_mutex);
769 mutex_destroy(&server->root_setup_lock);
770 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
772 if (server->info_filp)
773 fput(server->info_filp);
774 fput(server->ncp_filp);
Eric W. Biederman21542272006-12-13 00:35:11 -0800775 kill_pid(server->m.wdog_pid, SIGTERM, 1);
776 put_pid(server->m.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777
Jens Axboef1970c72010-04-22 12:31:11 +0200778 bdi_destroy(&server->bdi);
Pekka Enberg44db77f2006-01-14 13:21:12 -0800779 kfree(server->priv.data);
780 kfree(server->auth.object_name);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100781 vfree(server->rxbuf);
782 vfree(server->txbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 vfree(server->packet);
784 sb->s_fs_info = NULL;
785 kfree(server);
786}
787
David Howells726c3342006-06-23 02:02:58 -0700788static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789{
790 struct dentry* d;
791 struct inode* i;
792 struct ncp_inode_info* ni;
793 struct ncp_server* s;
794 struct ncp_volume_info vi;
David Howells726c3342006-06-23 02:02:58 -0700795 struct super_block *sb = dentry->d_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 int err;
797 __u8 dh;
798
799 d = sb->s_root;
800 if (!d) {
801 goto dflt;
802 }
803 i = d->d_inode;
804 if (!i) {
805 goto dflt;
806 }
807 ni = NCP_FINFO(i);
808 if (!ni) {
809 goto dflt;
810 }
811 s = NCP_SBP(sb);
812 if (!s) {
813 goto dflt;
814 }
815 if (!s->m.mounted_vol[0]) {
816 goto dflt;
817 }
818
819 err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
820 if (err) {
821 goto dflt;
822 }
823 err = ncp_get_directory_info(s, dh, &vi);
824 ncp_dirhandle_free(s, dh);
825 if (err) {
826 goto dflt;
827 }
828 buf->f_type = NCP_SUPER_MAGIC;
829 buf->f_bsize = vi.sectors_per_block * 512;
830 buf->f_blocks = vi.total_blocks;
831 buf->f_bfree = vi.free_blocks;
832 buf->f_bavail = vi.free_blocks;
833 buf->f_files = vi.total_dir_entries;
834 buf->f_ffree = vi.available_dir_entries;
835 buf->f_namelen = 12;
836 return 0;
837
838 /* We cannot say how much disk space is left on a mounted
839 NetWare Server, because free space is distributed over
840 volumes, and the current user might have disk quotas. So
841 free space is not that simple to determine. Our decision
842 here is to err conservatively. */
843
844dflt:;
845 buf->f_type = NCP_SUPER_MAGIC;
846 buf->f_bsize = NCP_BLOCK_SIZE;
847 buf->f_blocks = 0;
848 buf->f_bfree = 0;
849 buf->f_bavail = 0;
850 buf->f_namelen = 12;
851 return 0;
852}
853
854int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
855{
856 struct inode *inode = dentry->d_inode;
857 int result = 0;
858 __le32 info_mask;
859 struct nw_modify_dos_info info;
860 struct ncp_server *server;
861
862 result = -EIO;
863
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 server = NCP_SERVER(inode);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200865 if (!server) /* How this could happen? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 goto out;
867
868 /* ageing the dentry to force validation */
869 ncp_age_dentry(server, dentry);
870
871 result = inode_change_ok(inode, attr);
872 if (result < 0)
873 goto out;
874
875 result = -EPERM;
876 if (((attr->ia_valid & ATTR_UID) &&
877 (attr->ia_uid != server->m.uid)))
878 goto out;
879
880 if (((attr->ia_valid & ATTR_GID) &&
881 (attr->ia_gid != server->m.gid)))
882 goto out;
883
884 if (((attr->ia_valid & ATTR_MODE) &&
885 (attr->ia_mode &
886 ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
887 goto out;
888
889 info_mask = 0;
890 memset(&info, 0, sizeof(info));
891
892#if 1
893 if ((attr->ia_valid & ATTR_MODE) != 0)
894 {
895 umode_t newmode = attr->ia_mode;
896
897 info_mask |= DM_ATTRIBUTES;
898
899 if (S_ISDIR(inode->i_mode)) {
900 newmode &= server->m.dir_mode;
901 } else {
902#ifdef CONFIG_NCPFS_EXTRAS
903 if (server->m.flags & NCP_MOUNT_EXTRAS) {
904 /* any non-default execute bit set */
905 if (newmode & ~server->m.file_mode & S_IXUGO)
906 info.attributes |= aSHARED | aSYSTEM;
907 /* read for group/world and not in default file_mode */
908 else if (newmode & ~server->m.file_mode & S_IRUGO)
909 info.attributes |= aSHARED;
910 } else
911#endif
912 newmode &= server->m.file_mode;
913 }
914 if (newmode & S_IWUGO)
915 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
916 else
917 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
918
919#ifdef CONFIG_NCPFS_NFS_NS
920 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
921 result = ncp_modify_nfs_info(server,
922 NCP_FINFO(inode)->volNumber,
923 NCP_FINFO(inode)->dirEntNum,
924 attr->ia_mode, 0);
925 if (result != 0)
926 goto out;
927 info.attributes &= ~(aSHARED | aSYSTEM);
928 {
929 /* mark partial success */
930 struct iattr tmpattr;
931
932 tmpattr.ia_valid = ATTR_MODE;
933 tmpattr.ia_mode = attr->ia_mode;
934
Christoph Hellwig10257742010-06-04 11:30:02 +0200935 setattr_copy(inode, &tmpattr);
936 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 }
938 }
939#endif
940 }
941#endif
942
943 /* Do SIZE before attributes, otherwise mtime together with size does not work...
944 */
945 if ((attr->ia_valid & ATTR_SIZE) != 0) {
946 int written;
947
948 DPRINTK("ncpfs: trying to change size to %ld\n",
949 attr->ia_size);
950
951 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
952 result = -EACCES;
953 goto out;
954 }
955 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
956 attr->ia_size, 0, "", &written);
957
958 /* According to ndir, the changes only take effect after
959 closing the file */
960 ncp_inode_close(inode);
961 result = ncp_make_closed(inode);
962 if (result)
963 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +0200964
965 if (attr->ia_size != i_size_read(inode)) {
966 result = vmtruncate(inode, attr->ia_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 if (result)
968 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +0200969 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 }
971 }
972 if ((attr->ia_valid & ATTR_CTIME) != 0) {
973 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
974 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
975 &info.creationTime, &info.creationDate);
976 }
977 if ((attr->ia_valid & ATTR_MTIME) != 0) {
978 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
979 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
980 &info.modifyTime, &info.modifyDate);
981 }
982 if ((attr->ia_valid & ATTR_ATIME) != 0) {
983 __le16 dummy;
984 info_mask |= (DM_LAST_ACCESS_DATE);
985 ncp_date_unix2dos(attr->ia_atime.tv_sec,
986 &dummy, &info.lastAccessDate);
987 }
988 if (info_mask != 0) {
989 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
990 inode, info_mask, &info);
991 if (result != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
993 /* NetWare seems not to allow this. I
994 do not know why. So, just tell the
995 user everything went fine. This is
996 a terrible hack, but I do not know
997 how to do this correctly. */
998 result = 0;
999 } else
1000 goto out;
1001 }
1002#ifdef CONFIG_NCPFS_STRONG
1003 if ((!result) && (info_mask & DM_ATTRIBUTES))
1004 NCP_FINFO(inode)->nwattr = info.attributes;
1005#endif
1006 }
Christoph Hellwig10257742010-06-04 11:30:02 +02001007 if (result)
1008 goto out;
1009
1010 setattr_copy(inode, attr);
1011 mark_inode_dirty(inode);
1012
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013out:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001014 if (result > 0)
1015 result = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 return result;
1017}
1018
David Howells454e2392006-06-23 02:02:57 -07001019static int ncp_get_sb(struct file_system_type *fs_type,
1020 int flags, const char *dev_name, void *data, struct vfsmount *mnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021{
David Howells454e2392006-06-23 02:02:57 -07001022 return get_sb_nodev(fs_type, flags, data, ncp_fill_super, mnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023}
1024
1025static struct file_system_type ncp_fs_type = {
1026 .owner = THIS_MODULE,
1027 .name = "ncpfs",
1028 .get_sb = ncp_get_sb,
1029 .kill_sb = kill_anon_super,
Miklos Szeredi564cd132008-02-08 04:21:46 -08001030 .fs_flags = FS_BINARY_MOUNTDATA,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031};
1032
1033static int __init init_ncp_fs(void)
1034{
1035 int err;
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001036 DPRINTK("ncpfs: init_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 err = init_inodecache();
1039 if (err)
1040 goto out1;
1041 err = register_filesystem(&ncp_fs_type);
1042 if (err)
1043 goto out;
1044 return 0;
1045out:
1046 destroy_inodecache();
1047out1:
1048 return err;
1049}
1050
1051static void __exit exit_ncp_fs(void)
1052{
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001053 DPRINTK("ncpfs: exit_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 unregister_filesystem(&ncp_fs_type);
1055 destroy_inodecache();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056}
1057
1058module_init(init_ncp_fs)
1059module_exit(exit_ncp_fs)
1060MODULE_LICENSE("GPL");