blob: d290545aa0c4b98c932e316c7dd4fcf3961b1126 [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;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200306
307 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 sk->sk_error_report = server->error_report;
309 sk->sk_data_ready = server->data_ready;
310 sk->sk_write_space = server->write_space;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200311 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 del_timer_sync(&server->timeout_tm);
313 flush_scheduled_work();
314}
315
Miklos Szeredi564cd132008-02-08 04:21:46 -0800316static int ncp_show_options(struct seq_file *seq, struct vfsmount *mnt)
317{
318 struct ncp_server *server = NCP_SBP(mnt->mnt_sb);
319 unsigned int tmp;
320
321 if (server->m.uid != 0)
322 seq_printf(seq, ",uid=%u", server->m.uid);
323 if (server->m.gid != 0)
324 seq_printf(seq, ",gid=%u", server->m.gid);
325 if (server->m.mounted_uid != 0)
326 seq_printf(seq, ",owner=%u", server->m.mounted_uid);
327 tmp = server->m.file_mode & S_IALLUGO;
328 if (tmp != NCP_DEFAULT_FILE_MODE)
329 seq_printf(seq, ",mode=0%o", tmp);
330 tmp = server->m.dir_mode & S_IALLUGO;
331 if (tmp != NCP_DEFAULT_DIR_MODE)
332 seq_printf(seq, ",dirmode=0%o", tmp);
333 if (server->m.time_out != NCP_DEFAULT_TIME_OUT * HZ / 100) {
334 tmp = server->m.time_out * 100 / HZ;
335 seq_printf(seq, ",timeout=%u", tmp);
336 }
337 if (server->m.retry_count != NCP_DEFAULT_RETRY_COUNT)
338 seq_printf(seq, ",retry=%u", server->m.retry_count);
339 if (server->m.flags != 0)
340 seq_printf(seq, ",flags=%lu", server->m.flags);
341 if (server->m.wdog_pid != NULL)
342 seq_printf(seq, ",wdogpid=%u", pid_vnr(server->m.wdog_pid));
343
344 return 0;
345}
346
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347static const struct ncp_option ncp_opts[] = {
348 { "uid", OPT_INT, 'u' },
349 { "gid", OPT_INT, 'g' },
350 { "owner", OPT_INT, 'o' },
351 { "mode", OPT_INT, 'm' },
352 { "dirmode", OPT_INT, 'd' },
353 { "timeout", OPT_INT, 't' },
354 { "retry", OPT_INT, 'r' },
355 { "flags", OPT_INT, 'f' },
356 { "wdogpid", OPT_INT, 'w' },
357 { "ncpfd", OPT_INT, 'n' },
358 { "infofd", OPT_INT, 'i' }, /* v5 */
359 { "version", OPT_INT, 'v' },
360 { NULL, 0, 0 } };
361
362static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
363 int optval;
364 char *optarg;
365 unsigned long optint;
366 int version = 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800367 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
369 data->flags = 0;
370 data->int_flags = 0;
371 data->mounted_uid = 0;
Eric W. Biederman21542272006-12-13 00:35:11 -0800372 data->wdog_pid = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 data->ncp_fd = ~0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800374 data->time_out = NCP_DEFAULT_TIME_OUT;
375 data->retry_count = NCP_DEFAULT_RETRY_COUNT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 data->uid = 0;
377 data->gid = 0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800378 data->file_mode = NCP_DEFAULT_FILE_MODE;
379 data->dir_mode = NCP_DEFAULT_DIR_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 data->info_fd = -1;
381 data->mounted_vol[0] = 0;
382
383 while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
Eric W. Biederman1de24122006-12-13 00:35:13 -0800384 ret = optval;
385 if (ret < 0)
386 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 switch (optval) {
388 case 'u':
389 data->uid = optint;
390 break;
391 case 'g':
392 data->gid = optint;
393 break;
394 case 'o':
395 data->mounted_uid = optint;
396 break;
397 case 'm':
398 data->file_mode = optint;
399 break;
400 case 'd':
401 data->dir_mode = optint;
402 break;
403 case 't':
404 data->time_out = optint;
405 break;
406 case 'r':
407 data->retry_count = optint;
408 break;
409 case 'f':
410 data->flags = optint;
411 break;
412 case 'w':
Eric W. Biederman21542272006-12-13 00:35:11 -0800413 data->wdog_pid = find_get_pid(optint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 break;
415 case 'n':
416 data->ncp_fd = optint;
417 break;
418 case 'i':
419 data->info_fd = optint;
420 break;
421 case 'v':
Eric W. Biederman1de24122006-12-13 00:35:13 -0800422 ret = -ECHRNG;
423 if (optint < NCP_MOUNT_VERSION_V4)
424 goto err;
425 if (optint > NCP_MOUNT_VERSION_V5)
426 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 version = optint;
428 break;
429
430 }
431 }
432 return 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800433err:
434 put_pid(data->wdog_pid);
435 data->wdog_pid = NULL;
436 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437}
438
439static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
440{
441 struct ncp_mount_data_kernel data;
442 struct ncp_server *server;
443 struct file *ncp_filp;
444 struct inode *root_inode;
445 struct inode *sock_inode;
446 struct socket *sock;
447 int error;
448 int default_bufsize;
449#ifdef CONFIG_NCPFS_PACKET_SIGNING
450 int options;
451#endif
452 struct ncp_entry_info finfo;
453
Eric W. Biederman1de24122006-12-13 00:35:13 -0800454 data.wdog_pid = NULL;
Panagiotis Issarisf8314dc2006-09-27 01:49:37 -0700455 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 if (!server)
457 return -ENOMEM;
458 sb->s_fs_info = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
460 error = -EFAULT;
461 if (raw_data == NULL)
462 goto out;
463 switch (*(int*)raw_data) {
464 case NCP_MOUNT_VERSION:
465 {
466 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
467
468 data.flags = md->flags;
469 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
470 data.mounted_uid = md->mounted_uid;
Eric W. Biederman21542272006-12-13 00:35:11 -0800471 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 data.ncp_fd = md->ncp_fd;
473 data.time_out = md->time_out;
474 data.retry_count = md->retry_count;
475 data.uid = md->uid;
476 data.gid = md->gid;
477 data.file_mode = md->file_mode;
478 data.dir_mode = md->dir_mode;
479 data.info_fd = -1;
480 memcpy(data.mounted_vol, md->mounted_vol,
481 NCP_VOLNAME_LEN+1);
482 }
483 break;
484 case NCP_MOUNT_VERSION_V4:
485 {
486 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
487
488 data.flags = md->flags;
489 data.int_flags = 0;
490 data.mounted_uid = md->mounted_uid;
Eric W. Biederman21542272006-12-13 00:35:11 -0800491 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 data.ncp_fd = md->ncp_fd;
493 data.time_out = md->time_out;
494 data.retry_count = md->retry_count;
495 data.uid = md->uid;
496 data.gid = md->gid;
497 data.file_mode = md->file_mode;
498 data.dir_mode = md->dir_mode;
499 data.info_fd = -1;
500 data.mounted_vol[0] = 0;
501 }
502 break;
503 default:
504 error = -ECHRNG;
505 if (memcmp(raw_data, "vers", 4) == 0) {
506 error = ncp_parse_options(&data, raw_data);
507 }
508 if (error)
509 goto out;
510 break;
511 }
512 error = -EBADF;
513 ncp_filp = fget(data.ncp_fd);
514 if (!ncp_filp)
515 goto out;
516 error = -ENOTSOCK;
Josef Sipek92e5bae2006-12-08 02:37:22 -0800517 sock_inode = ncp_filp->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 if (!S_ISSOCK(sock_inode->i_mode))
519 goto out_fput;
520 sock = SOCKET_I(sock_inode);
521 if (!sock)
522 goto out_fput;
523
524 if (sock->type == SOCK_STREAM)
525 default_bufsize = 0xF000;
526 else
527 default_bufsize = 1024;
528
529 sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
530 sb->s_maxbytes = 0xFFFFFFFFU;
531 sb->s_blocksize = 1024; /* Eh... Is this correct? */
532 sb->s_blocksize_bits = 10;
533 sb->s_magic = NCP_SUPER_MAGIC;
534 sb->s_op = &ncp_sops;
Jens Axboef1970c72010-04-22 12:31:11 +0200535 sb->s_bdi = &server->bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536
537 server = NCP_SBP(sb);
538 memset(server, 0, sizeof(*server));
539
Jens Axboef1970c72010-04-22 12:31:11 +0200540 error = bdi_setup_and_register(&server->bdi, "ncpfs", BDI_CAP_MAP_COPY);
541 if (error)
542 goto out_bdi;
543
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 server->ncp_filp = ncp_filp;
545 server->ncp_sock = sock;
546
547 if (data.info_fd != -1) {
548 struct socket *info_sock;
549
550 error = -EBADF;
551 server->info_filp = fget(data.info_fd);
552 if (!server->info_filp)
553 goto out_fput;
554 error = -ENOTSOCK;
Josef Sipek92e5bae2006-12-08 02:37:22 -0800555 sock_inode = server->info_filp->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 if (!S_ISSOCK(sock_inode->i_mode))
557 goto out_fput2;
558 info_sock = SOCKET_I(sock_inode);
559 if (!info_sock)
560 goto out_fput2;
561 error = -EBADFD;
562 if (info_sock->type != SOCK_STREAM)
563 goto out_fput2;
564 server->info_sock = info_sock;
565 }
566
567/* server->lock = 0; */
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800568 mutex_init(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 server->packet = NULL;
570/* server->buffer_size = 0; */
571/* server->conn_status = 0; */
572/* server->root_dentry = NULL; */
573/* server->root_setuped = 0; */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200574 mutex_init(&server->root_setup_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575#ifdef CONFIG_NCPFS_PACKET_SIGNING
576/* server->sign_wanted = 0; */
577/* server->sign_active = 0; */
578#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200579 init_rwsem(&server->auth_rwsem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 server->auth.auth_type = NCP_AUTH_NONE;
581/* server->auth.object_name_len = 0; */
582/* server->auth.object_name = NULL; */
583/* server->auth.object_type = 0; */
584/* server->priv.len = 0; */
585/* server->priv.data = NULL; */
586
587 server->m = data;
588 /* Althought anything producing this is buggy, it happens
589 now because of PATH_MAX changes.. */
590 if (server->m.time_out < 1) {
591 server->m.time_out = 10;
592 printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
593 }
594 server->m.time_out = server->m.time_out * HZ / 100;
595 server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
596 server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
597
598#ifdef CONFIG_NCPFS_NLS
599 /* load the default NLS charsets */
600 server->nls_vol = load_nls_default();
601 server->nls_io = load_nls_default();
602#endif /* CONFIG_NCPFS_NLS */
603
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200604 atomic_set(&server->dentry_ttl, 0); /* no caching */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605
606 INIT_LIST_HEAD(&server->tx.requests);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800607 mutex_init(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608 server->tx.creq = NULL;
609 server->rcv.creq = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610
611 init_timer(&server->timeout_tm);
612#undef NCP_PACKET_SIZE
613#define NCP_PACKET_SIZE 131072
614 error = -ENOMEM;
615 server->packet_size = NCP_PACKET_SIZE;
616 server->packet = vmalloc(NCP_PACKET_SIZE);
617 if (server->packet == NULL)
618 goto out_nls;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100619 server->txbuf = vmalloc(NCP_PACKET_SIZE);
620 if (server->txbuf == NULL)
621 goto out_packet;
622 server->rxbuf = vmalloc(NCP_PACKET_SIZE);
623 if (server->rxbuf == NULL)
624 goto out_txbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200626 lock_sock(sock->sk);
627 server->data_ready = sock->sk->sk_data_ready;
628 server->write_space = sock->sk->sk_write_space;
629 server->error_report = sock->sk->sk_error_report;
630 sock->sk->sk_user_data = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 sock->sk->sk_data_ready = ncp_tcp_data_ready;
632 sock->sk->sk_error_report = ncp_tcp_error_report;
633 if (sock->type == SOCK_STREAM) {
634 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
635 server->rcv.len = 10;
636 server->rcv.state = 0;
David Howellsc4028952006-11-22 14:57:56 +0000637 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
638 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 sock->sk->sk_write_space = ncp_tcp_write_space;
640 } else {
David Howellsc4028952006-11-22 14:57:56 +0000641 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
642 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 server->timeout_tm.data = (unsigned long)server;
644 server->timeout_tm.function = ncpdgram_timeout_call;
645 }
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200646 release_sock(sock->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
648 ncp_lock_server(server);
649 error = ncp_connect(server);
650 ncp_unlock_server(server);
651 if (error < 0)
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100652 goto out_rxbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
654
655 error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */
656#ifdef CONFIG_NCPFS_PACKET_SIGNING
657 if (ncp_negotiate_size_and_options(server, default_bufsize,
658 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
659 {
660 if (options != NCP_DEFAULT_OPTIONS)
661 {
662 if (ncp_negotiate_size_and_options(server,
663 default_bufsize,
664 options & 2,
665 &(server->buffer_size), &options) != 0)
666
667 {
668 goto out_disconnect;
669 }
670 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200671 ncp_lock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 if (options & 2)
673 server->sign_wanted = 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200674 ncp_unlock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 }
676 else
677#endif /* CONFIG_NCPFS_PACKET_SIGNING */
678 if (ncp_negotiate_buffersize(server, default_bufsize,
679 &(server->buffer_size)) != 0)
680 goto out_disconnect;
681 DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
682
683 memset(&finfo, 0, sizeof(finfo));
684 finfo.i.attributes = aDIR;
685 finfo.i.dataStreamSize = 0; /* ignored */
686 finfo.i.dirEntNum = 0;
687 finfo.i.DosDirNum = 0;
688#ifdef CONFIG_NCPFS_SMALLDOS
689 finfo.i.NSCreator = NW_NS_DOS;
690#endif
691 finfo.volume = NCP_NUMBER_OF_VOLUMES;
692 /* set dates of mountpoint to Jan 1, 1986; 00:00 */
693 finfo.i.creationTime = finfo.i.modifyTime
694 = cpu_to_le16(0x0000);
695 finfo.i.creationDate = finfo.i.modifyDate
696 = finfo.i.lastAccessDate
697 = cpu_to_le16(0x0C21);
698 finfo.i.nameLen = 0;
699 finfo.i.entryName[0] = '\0';
700
701 finfo.opened = 0;
702 finfo.ino = 2; /* tradition */
703
704 server->name_space[finfo.volume] = NW_NS_DOS;
705
706 error = -ENOMEM;
707 root_inode = ncp_iget(sb, &finfo);
708 if (!root_inode)
709 goto out_disconnect;
710 DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
711 sb->s_root = d_alloc_root(root_inode);
712 if (!sb->s_root)
713 goto out_no_root;
714 sb->s_root->d_op = &ncp_root_dentry_operations;
715 return 0;
716
717out_no_root:
718 iput(root_inode);
719out_disconnect:
720 ncp_lock_server(server);
721 ncp_disconnect(server);
722 ncp_unlock_server(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100723out_rxbuf:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 ncp_stop_tasks(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100725 vfree(server->rxbuf);
726out_txbuf:
727 vfree(server->txbuf);
728out_packet:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 vfree(server->packet);
730out_nls:
731#ifdef CONFIG_NCPFS_NLS
732 unload_nls(server->nls_io);
733 unload_nls(server->nls_vol);
734#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200735 mutex_destroy(&server->rcv.creq_mutex);
736 mutex_destroy(&server->root_setup_lock);
737 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738out_fput2:
739 if (server->info_filp)
740 fput(server->info_filp);
741out_fput:
Jens Axboef1970c72010-04-22 12:31:11 +0200742 bdi_destroy(&server->bdi);
743out_bdi:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
745 *
Matthew Whitworthe956b4b2010-06-27 14:34:30 +0100746 * The previously used put_filp(ncp_filp); was bogus, since
747 * it doesn't perform proper unlocking.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 */
749 fput(ncp_filp);
750out:
Eric W. Biederman1de24122006-12-13 00:35:13 -0800751 put_pid(data.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 sb->s_fs_info = NULL;
753 kfree(server);
754 return error;
755}
756
757static void ncp_put_super(struct super_block *sb)
758{
759 struct ncp_server *server = NCP_SBP(sb);
760
761 ncp_lock_server(server);
762 ncp_disconnect(server);
763 ncp_unlock_server(server);
764
765 ncp_stop_tasks(server);
766
767#ifdef CONFIG_NCPFS_NLS
768 /* unload the NLS charsets */
Thomas Gleixner6d729e42009-08-16 21:05:08 +0000769 unload_nls(server->nls_vol);
770 unload_nls(server->nls_io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771#endif /* CONFIG_NCPFS_NLS */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200772 mutex_destroy(&server->rcv.creq_mutex);
773 mutex_destroy(&server->root_setup_lock);
774 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775
776 if (server->info_filp)
777 fput(server->info_filp);
778 fput(server->ncp_filp);
Eric W. Biederman21542272006-12-13 00:35:11 -0800779 kill_pid(server->m.wdog_pid, SIGTERM, 1);
780 put_pid(server->m.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
Jens Axboef1970c72010-04-22 12:31:11 +0200782 bdi_destroy(&server->bdi);
Pekka Enberg44db77f2006-01-14 13:21:12 -0800783 kfree(server->priv.data);
784 kfree(server->auth.object_name);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100785 vfree(server->rxbuf);
786 vfree(server->txbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 vfree(server->packet);
788 sb->s_fs_info = NULL;
789 kfree(server);
790}
791
David Howells726c3342006-06-23 02:02:58 -0700792static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793{
794 struct dentry* d;
795 struct inode* i;
796 struct ncp_inode_info* ni;
797 struct ncp_server* s;
798 struct ncp_volume_info vi;
David Howells726c3342006-06-23 02:02:58 -0700799 struct super_block *sb = dentry->d_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 int err;
801 __u8 dh;
802
803 d = sb->s_root;
804 if (!d) {
805 goto dflt;
806 }
807 i = d->d_inode;
808 if (!i) {
809 goto dflt;
810 }
811 ni = NCP_FINFO(i);
812 if (!ni) {
813 goto dflt;
814 }
815 s = NCP_SBP(sb);
816 if (!s) {
817 goto dflt;
818 }
819 if (!s->m.mounted_vol[0]) {
820 goto dflt;
821 }
822
823 err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
824 if (err) {
825 goto dflt;
826 }
827 err = ncp_get_directory_info(s, dh, &vi);
828 ncp_dirhandle_free(s, dh);
829 if (err) {
830 goto dflt;
831 }
832 buf->f_type = NCP_SUPER_MAGIC;
833 buf->f_bsize = vi.sectors_per_block * 512;
834 buf->f_blocks = vi.total_blocks;
835 buf->f_bfree = vi.free_blocks;
836 buf->f_bavail = vi.free_blocks;
837 buf->f_files = vi.total_dir_entries;
838 buf->f_ffree = vi.available_dir_entries;
839 buf->f_namelen = 12;
840 return 0;
841
842 /* We cannot say how much disk space is left on a mounted
843 NetWare Server, because free space is distributed over
844 volumes, and the current user might have disk quotas. So
845 free space is not that simple to determine. Our decision
846 here is to err conservatively. */
847
848dflt:;
849 buf->f_type = NCP_SUPER_MAGIC;
850 buf->f_bsize = NCP_BLOCK_SIZE;
851 buf->f_blocks = 0;
852 buf->f_bfree = 0;
853 buf->f_bavail = 0;
854 buf->f_namelen = 12;
855 return 0;
856}
857
858int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
859{
860 struct inode *inode = dentry->d_inode;
861 int result = 0;
862 __le32 info_mask;
863 struct nw_modify_dos_info info;
864 struct ncp_server *server;
865
866 result = -EIO;
867
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 server = NCP_SERVER(inode);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200869 if (!server) /* How this could happen? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 goto out;
871
872 /* ageing the dentry to force validation */
873 ncp_age_dentry(server, dentry);
874
875 result = inode_change_ok(inode, attr);
876 if (result < 0)
877 goto out;
878
879 result = -EPERM;
880 if (((attr->ia_valid & ATTR_UID) &&
881 (attr->ia_uid != server->m.uid)))
882 goto out;
883
884 if (((attr->ia_valid & ATTR_GID) &&
885 (attr->ia_gid != server->m.gid)))
886 goto out;
887
888 if (((attr->ia_valid & ATTR_MODE) &&
889 (attr->ia_mode &
890 ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
891 goto out;
892
893 info_mask = 0;
894 memset(&info, 0, sizeof(info));
895
896#if 1
897 if ((attr->ia_valid & ATTR_MODE) != 0)
898 {
899 umode_t newmode = attr->ia_mode;
900
901 info_mask |= DM_ATTRIBUTES;
902
903 if (S_ISDIR(inode->i_mode)) {
904 newmode &= server->m.dir_mode;
905 } else {
906#ifdef CONFIG_NCPFS_EXTRAS
907 if (server->m.flags & NCP_MOUNT_EXTRAS) {
908 /* any non-default execute bit set */
909 if (newmode & ~server->m.file_mode & S_IXUGO)
910 info.attributes |= aSHARED | aSYSTEM;
911 /* read for group/world and not in default file_mode */
912 else if (newmode & ~server->m.file_mode & S_IRUGO)
913 info.attributes |= aSHARED;
914 } else
915#endif
916 newmode &= server->m.file_mode;
917 }
918 if (newmode & S_IWUGO)
919 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
920 else
921 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
922
923#ifdef CONFIG_NCPFS_NFS_NS
924 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
925 result = ncp_modify_nfs_info(server,
926 NCP_FINFO(inode)->volNumber,
927 NCP_FINFO(inode)->dirEntNum,
928 attr->ia_mode, 0);
929 if (result != 0)
930 goto out;
931 info.attributes &= ~(aSHARED | aSYSTEM);
932 {
933 /* mark partial success */
934 struct iattr tmpattr;
935
936 tmpattr.ia_valid = ATTR_MODE;
937 tmpattr.ia_mode = attr->ia_mode;
938
Christoph Hellwig10257742010-06-04 11:30:02 +0200939 setattr_copy(inode, &tmpattr);
940 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 }
942 }
943#endif
944 }
945#endif
946
947 /* Do SIZE before attributes, otherwise mtime together with size does not work...
948 */
949 if ((attr->ia_valid & ATTR_SIZE) != 0) {
950 int written;
951
952 DPRINTK("ncpfs: trying to change size to %ld\n",
953 attr->ia_size);
954
955 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
956 result = -EACCES;
957 goto out;
958 }
959 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
960 attr->ia_size, 0, "", &written);
961
962 /* According to ndir, the changes only take effect after
963 closing the file */
964 ncp_inode_close(inode);
965 result = ncp_make_closed(inode);
966 if (result)
967 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +0200968
969 if (attr->ia_size != i_size_read(inode)) {
970 result = vmtruncate(inode, attr->ia_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 if (result)
972 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +0200973 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 }
975 }
976 if ((attr->ia_valid & ATTR_CTIME) != 0) {
977 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
978 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
979 &info.creationTime, &info.creationDate);
980 }
981 if ((attr->ia_valid & ATTR_MTIME) != 0) {
982 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
983 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
984 &info.modifyTime, &info.modifyDate);
985 }
986 if ((attr->ia_valid & ATTR_ATIME) != 0) {
987 __le16 dummy;
988 info_mask |= (DM_LAST_ACCESS_DATE);
989 ncp_date_unix2dos(attr->ia_atime.tv_sec,
990 &dummy, &info.lastAccessDate);
991 }
992 if (info_mask != 0) {
993 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
994 inode, info_mask, &info);
995 if (result != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
997 /* NetWare seems not to allow this. I
998 do not know why. So, just tell the
999 user everything went fine. This is
1000 a terrible hack, but I do not know
1001 how to do this correctly. */
1002 result = 0;
1003 } else
1004 goto out;
1005 }
1006#ifdef CONFIG_NCPFS_STRONG
1007 if ((!result) && (info_mask & DM_ATTRIBUTES))
1008 NCP_FINFO(inode)->nwattr = info.attributes;
1009#endif
1010 }
Christoph Hellwig10257742010-06-04 11:30:02 +02001011 if (result)
1012 goto out;
1013
1014 setattr_copy(inode, attr);
1015 mark_inode_dirty(inode);
1016
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017out:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001018 if (result > 0)
1019 result = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 return result;
1021}
1022
Al Viro3c26ff62010-07-25 11:46:36 +04001023static struct dentry *ncp_mount(struct file_system_type *fs_type,
1024 int flags, const char *dev_name, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025{
Al Viro3c26ff62010-07-25 11:46:36 +04001026 return mount_nodev(fs_type, flags, data, ncp_fill_super);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027}
1028
1029static struct file_system_type ncp_fs_type = {
1030 .owner = THIS_MODULE,
1031 .name = "ncpfs",
Al Viro3c26ff62010-07-25 11:46:36 +04001032 .mount = ncp_mount,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 .kill_sb = kill_anon_super,
Miklos Szeredi564cd132008-02-08 04:21:46 -08001034 .fs_flags = FS_BINARY_MOUNTDATA,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035};
1036
1037static int __init init_ncp_fs(void)
1038{
1039 int err;
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001040 DPRINTK("ncpfs: init_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 err = init_inodecache();
1043 if (err)
1044 goto out1;
1045 err = register_filesystem(&ncp_fs_type);
1046 if (err)
1047 goto out;
1048 return 0;
1049out:
1050 destroy_inodecache();
1051out1:
1052 return err;
1053}
1054
1055static void __exit exit_ncp_fs(void)
1056{
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001057 DPRINTK("ncpfs: exit_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 unregister_filesystem(&ncp_fs_type);
1059 destroy_inodecache();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060}
1061
1062module_init(init_ncp_fs)
1063module_exit(exit_ncp_fs)
1064MODULE_LICENSE("GPL");