blob: 60047dbeb38d8254f347f103cb49fa6d547074d9 [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
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +110061static void ncp_i_callback(struct rcu_head *head)
62{
63 struct inode *inode = container_of(head, struct inode, i_rcu);
64 INIT_LIST_HEAD(&inode->i_dentry);
65 kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
66}
67
Linus Torvalds1da177e2005-04-16 15:20:36 -070068static void ncp_destroy_inode(struct inode *inode)
69{
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +110070 call_rcu(&inode->i_rcu, ncp_i_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -070071}
72
Alexey Dobriyan51cc5062008-07-25 19:45:34 -070073static void init_once(void *foo)
Linus Torvalds1da177e2005-04-16 15:20:36 -070074{
75 struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
76
Christoph Lametera35afb82007-05-16 22:10:57 -070077 mutex_init(&ei->open_mutex);
78 inode_init_once(&ei->vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079}
Paul Mundt20c2df82007-07-20 10:11:58 +090080
Linus Torvalds1da177e2005-04-16 15:20:36 -070081static int init_inodecache(void)
82{
83 ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
84 sizeof(struct ncp_inode_info),
Paul Jacksonfffb60f2006-03-24 03:16:06 -080085 0, (SLAB_RECLAIM_ACCOUNT|
86 SLAB_MEM_SPREAD),
Paul Mundt20c2df82007-07-20 10:11:58 +090087 init_once);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 if (ncp_inode_cachep == NULL)
89 return -ENOMEM;
90 return 0;
91}
92
93static void destroy_inodecache(void)
94{
Alexey Dobriyan1a1d92c2006-09-27 01:49:40 -070095 kmem_cache_destroy(ncp_inode_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096}
97
98static int ncp_remount(struct super_block *sb, int *flags, char* data)
99{
100 *flags |= MS_NODIRATIME;
101 return 0;
102}
103
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800104static const struct super_operations ncp_sops =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105{
106 .alloc_inode = ncp_alloc_inode,
107 .destroy_inode = ncp_destroy_inode,
108 .drop_inode = generic_delete_inode,
Al Viro94ee8492010-06-07 00:45:56 -0400109 .evict_inode = ncp_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 .put_super = ncp_put_super,
111 .statfs = ncp_statfs,
112 .remount_fs = ncp_remount,
Miklos Szeredi564cd132008-02-08 04:21:46 -0800113 .show_options = ncp_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114};
115
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116/*
117 * Fill in the ncpfs-specific information in the inode.
118 */
119static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
120{
121 NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
122 NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
123 NCP_FINFO(inode)->volNumber = nwinfo->volume;
124}
125
126void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
127{
128 ncp_update_dirent(inode, nwinfo);
129 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
130 NCP_FINFO(inode)->access = nwinfo->access;
131 memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
132 sizeof(nwinfo->file_handle));
133 DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
134 nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
135 NCP_FINFO(inode)->dirEntNum);
136}
137
138static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
139{
140 /* NFS namespace mode overrides others if it's set. */
141 DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n",
142 nwi->entryName, nwi->nfs.mode);
143 if (nwi->nfs.mode) {
144 /* XXX Security? */
145 inode->i_mode = nwi->nfs.mode;
146 }
147
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200148 inode->i_blocks = (i_size_read(inode) + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
150 inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate);
151 inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate);
152 inode->i_atime.tv_sec = ncp_date_dos2unix(0, nwi->lastAccessDate);
153 inode->i_atime.tv_nsec = 0;
154 inode->i_mtime.tv_nsec = 0;
155 inode->i_ctime.tv_nsec = 0;
156}
157
158static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
159{
160 struct nw_info_struct *nwi = &nwinfo->i;
161 struct ncp_server *server = NCP_SERVER(inode);
162
163 if (nwi->attributes & aDIR) {
164 inode->i_mode = server->m.dir_mode;
165 /* for directories dataStreamSize seems to be some
166 Object ID ??? */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200167 i_size_write(inode, NCP_BLOCK_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 } else {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200169 u32 size;
170
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 inode->i_mode = server->m.file_mode;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200172 size = le32_to_cpu(nwi->dataStreamSize);
173 i_size_write(inode, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174#ifdef CONFIG_NCPFS_EXTRAS
175 if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS))
176 && (nwi->attributes & aSHARED)) {
177 switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
178 case aHIDDEN:
179 if (server->m.flags & NCP_MOUNT_SYMLINKS) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200180 if (/* (size >= NCP_MIN_SYMLINK_SIZE)
181 && */ (size <= NCP_MAX_SYMLINK_SIZE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
183 NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
184 break;
185 }
186 }
187 /* FALLTHROUGH */
188 case 0:
189 if (server->m.flags & NCP_MOUNT_EXTRAS)
190 inode->i_mode |= S_IRUGO;
191 break;
192 case aSYSTEM:
193 if (server->m.flags & NCP_MOUNT_EXTRAS)
194 inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO;
195 break;
196 /* case aSYSTEM|aHIDDEN: */
197 default:
198 /* reserved combination */
199 break;
200 }
201 }
202#endif
203 }
204 if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
205}
206
207void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
208{
209 NCP_FINFO(inode)->flags = 0;
210 if (!atomic_read(&NCP_FINFO(inode)->opened)) {
211 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
212 ncp_update_attrs(inode, nwinfo);
213 }
214
215 ncp_update_dates(inode, &nwinfo->i);
216 ncp_update_dirent(inode, nwinfo);
217}
218
219/*
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200220 * Fill in the inode based on the ncp_entry_info structure. Used only for brand new inodes.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 */
222static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
223{
224 struct ncp_server *server = NCP_SERVER(inode);
225
226 NCP_FINFO(inode)->flags = 0;
227
228 ncp_update_attrs(inode, nwinfo);
229
230 DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
231
232 inode->i_nlink = 1;
233 inode->i_uid = server->m.uid;
234 inode->i_gid = server->m.gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
236 ncp_update_dates(inode, &nwinfo->i);
237 ncp_update_inode(inode, nwinfo);
238}
239
240#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800241static const struct inode_operations ncp_symlink_inode_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 .readlink = generic_readlink,
243 .follow_link = page_follow_link_light,
244 .put_link = page_put_link,
245 .setattr = ncp_notify_change,
246};
247#endif
248
249/*
250 * Get a new inode.
251 */
252struct inode *
253ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
254{
255 struct inode *inode;
256
257 if (info == NULL) {
258 printk(KERN_ERR "ncp_iget: info is NULL\n");
259 return NULL;
260 }
261
262 inode = new_inode(sb);
263 if (inode) {
264 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
265
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200266 inode->i_mapping->backing_dev_info = sb->s_bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 inode->i_ino = info->ino;
268 ncp_set_attr(inode, info);
269 if (S_ISREG(inode->i_mode)) {
270 inode->i_op = &ncp_file_inode_operations;
271 inode->i_fop = &ncp_file_operations;
272 } else if (S_ISDIR(inode->i_mode)) {
273 inode->i_op = &ncp_dir_inode_operations;
274 inode->i_fop = &ncp_dir_operations;
275#ifdef CONFIG_NCPFS_NFS_NS
276 } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
277 init_special_inode(inode, inode->i_mode,
278 new_decode_dev(info->i.nfs.rdev));
279#endif
280#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
281 } else if (S_ISLNK(inode->i_mode)) {
282 inode->i_op = &ncp_symlink_inode_operations;
283 inode->i_data.a_ops = &ncp_symlink_aops;
284#endif
285 } else {
286 make_bad_inode(inode);
287 }
288 insert_inode_hash(inode);
289 } else
290 printk(KERN_ERR "ncp_iget: iget failed!\n");
291 return inode;
292}
293
294static void
Al Viro94ee8492010-06-07 00:45:56 -0400295ncp_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296{
Mark Fashehfef26652005-09-09 13:01:31 -0700297 truncate_inode_pages(&inode->i_data, 0);
Al Viro94ee8492010-06-07 00:45:56 -0400298 end_writeback(inode);
Mark Fashehfef26652005-09-09 13:01:31 -0700299
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 if (S_ISDIR(inode->i_mode)) {
Al Viro94ee8492010-06-07 00:45:56 -0400301 DDPRINTK("ncp_evict_inode: put directory %ld\n", inode->i_ino);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 }
303
304 if (ncp_make_closed(inode) != 0) {
305 /* We can't do anything but complain. */
Al Viro94ee8492010-06-07 00:45:56 -0400306 printk(KERN_ERR "ncp_evict_inode: could not close\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308}
309
310static void ncp_stop_tasks(struct ncp_server *server) {
311 struct sock* sk = server->ncp_sock->sk;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200312
313 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 sk->sk_error_report = server->error_report;
315 sk->sk_data_ready = server->data_ready;
316 sk->sk_write_space = server->write_space;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200317 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 del_timer_sync(&server->timeout_tm);
319 flush_scheduled_work();
320}
321
Miklos Szeredi564cd132008-02-08 04:21:46 -0800322static int ncp_show_options(struct seq_file *seq, struct vfsmount *mnt)
323{
324 struct ncp_server *server = NCP_SBP(mnt->mnt_sb);
325 unsigned int tmp;
326
327 if (server->m.uid != 0)
328 seq_printf(seq, ",uid=%u", server->m.uid);
329 if (server->m.gid != 0)
330 seq_printf(seq, ",gid=%u", server->m.gid);
331 if (server->m.mounted_uid != 0)
332 seq_printf(seq, ",owner=%u", server->m.mounted_uid);
333 tmp = server->m.file_mode & S_IALLUGO;
334 if (tmp != NCP_DEFAULT_FILE_MODE)
335 seq_printf(seq, ",mode=0%o", tmp);
336 tmp = server->m.dir_mode & S_IALLUGO;
337 if (tmp != NCP_DEFAULT_DIR_MODE)
338 seq_printf(seq, ",dirmode=0%o", tmp);
339 if (server->m.time_out != NCP_DEFAULT_TIME_OUT * HZ / 100) {
340 tmp = server->m.time_out * 100 / HZ;
341 seq_printf(seq, ",timeout=%u", tmp);
342 }
343 if (server->m.retry_count != NCP_DEFAULT_RETRY_COUNT)
344 seq_printf(seq, ",retry=%u", server->m.retry_count);
345 if (server->m.flags != 0)
346 seq_printf(seq, ",flags=%lu", server->m.flags);
347 if (server->m.wdog_pid != NULL)
348 seq_printf(seq, ",wdogpid=%u", pid_vnr(server->m.wdog_pid));
349
350 return 0;
351}
352
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353static const struct ncp_option ncp_opts[] = {
354 { "uid", OPT_INT, 'u' },
355 { "gid", OPT_INT, 'g' },
356 { "owner", OPT_INT, 'o' },
357 { "mode", OPT_INT, 'm' },
358 { "dirmode", OPT_INT, 'd' },
359 { "timeout", OPT_INT, 't' },
360 { "retry", OPT_INT, 'r' },
361 { "flags", OPT_INT, 'f' },
362 { "wdogpid", OPT_INT, 'w' },
363 { "ncpfd", OPT_INT, 'n' },
364 { "infofd", OPT_INT, 'i' }, /* v5 */
365 { "version", OPT_INT, 'v' },
366 { NULL, 0, 0 } };
367
368static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
369 int optval;
370 char *optarg;
371 unsigned long optint;
372 int version = 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800373 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
375 data->flags = 0;
376 data->int_flags = 0;
377 data->mounted_uid = 0;
Eric W. Biederman21542272006-12-13 00:35:11 -0800378 data->wdog_pid = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 data->ncp_fd = ~0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800380 data->time_out = NCP_DEFAULT_TIME_OUT;
381 data->retry_count = NCP_DEFAULT_RETRY_COUNT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 data->uid = 0;
383 data->gid = 0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800384 data->file_mode = NCP_DEFAULT_FILE_MODE;
385 data->dir_mode = NCP_DEFAULT_DIR_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 data->info_fd = -1;
387 data->mounted_vol[0] = 0;
388
389 while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
Eric W. Biederman1de24122006-12-13 00:35:13 -0800390 ret = optval;
391 if (ret < 0)
392 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 switch (optval) {
394 case 'u':
395 data->uid = optint;
396 break;
397 case 'g':
398 data->gid = optint;
399 break;
400 case 'o':
401 data->mounted_uid = optint;
402 break;
403 case 'm':
404 data->file_mode = optint;
405 break;
406 case 'd':
407 data->dir_mode = optint;
408 break;
409 case 't':
410 data->time_out = optint;
411 break;
412 case 'r':
413 data->retry_count = optint;
414 break;
415 case 'f':
416 data->flags = optint;
417 break;
418 case 'w':
Eric W. Biederman21542272006-12-13 00:35:11 -0800419 data->wdog_pid = find_get_pid(optint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 break;
421 case 'n':
422 data->ncp_fd = optint;
423 break;
424 case 'i':
425 data->info_fd = optint;
426 break;
427 case 'v':
Eric W. Biederman1de24122006-12-13 00:35:13 -0800428 ret = -ECHRNG;
429 if (optint < NCP_MOUNT_VERSION_V4)
430 goto err;
431 if (optint > NCP_MOUNT_VERSION_V5)
432 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 version = optint;
434 break;
435
436 }
437 }
438 return 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800439err:
440 put_pid(data->wdog_pid);
441 data->wdog_pid = NULL;
442 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443}
444
445static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
446{
447 struct ncp_mount_data_kernel data;
448 struct ncp_server *server;
449 struct file *ncp_filp;
450 struct inode *root_inode;
451 struct inode *sock_inode;
452 struct socket *sock;
453 int error;
454 int default_bufsize;
455#ifdef CONFIG_NCPFS_PACKET_SIGNING
456 int options;
457#endif
458 struct ncp_entry_info finfo;
459
Eric W. Biederman1de24122006-12-13 00:35:13 -0800460 data.wdog_pid = NULL;
Panagiotis Issarisf8314dc2006-09-27 01:49:37 -0700461 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 if (!server)
463 return -ENOMEM;
464 sb->s_fs_info = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
466 error = -EFAULT;
467 if (raw_data == NULL)
468 goto out;
469 switch (*(int*)raw_data) {
470 case NCP_MOUNT_VERSION:
471 {
472 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
473
474 data.flags = md->flags;
475 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
476 data.mounted_uid = md->mounted_uid;
Eric W. Biederman21542272006-12-13 00:35:11 -0800477 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 data.ncp_fd = md->ncp_fd;
479 data.time_out = md->time_out;
480 data.retry_count = md->retry_count;
481 data.uid = md->uid;
482 data.gid = md->gid;
483 data.file_mode = md->file_mode;
484 data.dir_mode = md->dir_mode;
485 data.info_fd = -1;
486 memcpy(data.mounted_vol, md->mounted_vol,
487 NCP_VOLNAME_LEN+1);
488 }
489 break;
490 case NCP_MOUNT_VERSION_V4:
491 {
492 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
493
494 data.flags = md->flags;
495 data.int_flags = 0;
496 data.mounted_uid = md->mounted_uid;
Eric W. Biederman21542272006-12-13 00:35:11 -0800497 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 data.ncp_fd = md->ncp_fd;
499 data.time_out = md->time_out;
500 data.retry_count = md->retry_count;
501 data.uid = md->uid;
502 data.gid = md->gid;
503 data.file_mode = md->file_mode;
504 data.dir_mode = md->dir_mode;
505 data.info_fd = -1;
506 data.mounted_vol[0] = 0;
507 }
508 break;
509 default:
510 error = -ECHRNG;
511 if (memcmp(raw_data, "vers", 4) == 0) {
512 error = ncp_parse_options(&data, raw_data);
513 }
514 if (error)
515 goto out;
516 break;
517 }
518 error = -EBADF;
519 ncp_filp = fget(data.ncp_fd);
520 if (!ncp_filp)
521 goto out;
522 error = -ENOTSOCK;
Josef Sipek92e5bae2006-12-08 02:37:22 -0800523 sock_inode = ncp_filp->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 if (!S_ISSOCK(sock_inode->i_mode))
525 goto out_fput;
526 sock = SOCKET_I(sock_inode);
527 if (!sock)
528 goto out_fput;
529
530 if (sock->type == SOCK_STREAM)
531 default_bufsize = 0xF000;
532 else
533 default_bufsize = 1024;
534
535 sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
536 sb->s_maxbytes = 0xFFFFFFFFU;
537 sb->s_blocksize = 1024; /* Eh... Is this correct? */
538 sb->s_blocksize_bits = 10;
539 sb->s_magic = NCP_SUPER_MAGIC;
540 sb->s_op = &ncp_sops;
Jens Axboef1970c72010-04-22 12:31:11 +0200541 sb->s_bdi = &server->bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
543 server = NCP_SBP(sb);
544 memset(server, 0, sizeof(*server));
545
Jens Axboef1970c72010-04-22 12:31:11 +0200546 error = bdi_setup_and_register(&server->bdi, "ncpfs", BDI_CAP_MAP_COPY);
547 if (error)
548 goto out_bdi;
549
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 server->ncp_filp = ncp_filp;
551 server->ncp_sock = sock;
552
553 if (data.info_fd != -1) {
554 struct socket *info_sock;
555
556 error = -EBADF;
557 server->info_filp = fget(data.info_fd);
558 if (!server->info_filp)
559 goto out_fput;
560 error = -ENOTSOCK;
Josef Sipek92e5bae2006-12-08 02:37:22 -0800561 sock_inode = server->info_filp->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 if (!S_ISSOCK(sock_inode->i_mode))
563 goto out_fput2;
564 info_sock = SOCKET_I(sock_inode);
565 if (!info_sock)
566 goto out_fput2;
567 error = -EBADFD;
568 if (info_sock->type != SOCK_STREAM)
569 goto out_fput2;
570 server->info_sock = info_sock;
571 }
572
573/* server->lock = 0; */
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800574 mutex_init(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 server->packet = NULL;
576/* server->buffer_size = 0; */
577/* server->conn_status = 0; */
578/* server->root_dentry = NULL; */
579/* server->root_setuped = 0; */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200580 mutex_init(&server->root_setup_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581#ifdef CONFIG_NCPFS_PACKET_SIGNING
582/* server->sign_wanted = 0; */
583/* server->sign_active = 0; */
584#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200585 init_rwsem(&server->auth_rwsem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 server->auth.auth_type = NCP_AUTH_NONE;
587/* server->auth.object_name_len = 0; */
588/* server->auth.object_name = NULL; */
589/* server->auth.object_type = 0; */
590/* server->priv.len = 0; */
591/* server->priv.data = NULL; */
592
593 server->m = data;
594 /* Althought anything producing this is buggy, it happens
595 now because of PATH_MAX changes.. */
596 if (server->m.time_out < 1) {
597 server->m.time_out = 10;
598 printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
599 }
600 server->m.time_out = server->m.time_out * HZ / 100;
601 server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
602 server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
603
604#ifdef CONFIG_NCPFS_NLS
605 /* load the default NLS charsets */
606 server->nls_vol = load_nls_default();
607 server->nls_io = load_nls_default();
608#endif /* CONFIG_NCPFS_NLS */
609
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200610 atomic_set(&server->dentry_ttl, 0); /* no caching */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611
612 INIT_LIST_HEAD(&server->tx.requests);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800613 mutex_init(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 server->tx.creq = NULL;
615 server->rcv.creq = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
617 init_timer(&server->timeout_tm);
618#undef NCP_PACKET_SIZE
619#define NCP_PACKET_SIZE 131072
620 error = -ENOMEM;
621 server->packet_size = NCP_PACKET_SIZE;
622 server->packet = vmalloc(NCP_PACKET_SIZE);
623 if (server->packet == NULL)
624 goto out_nls;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100625 server->txbuf = vmalloc(NCP_PACKET_SIZE);
626 if (server->txbuf == NULL)
627 goto out_packet;
628 server->rxbuf = vmalloc(NCP_PACKET_SIZE);
629 if (server->rxbuf == NULL)
630 goto out_txbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200632 lock_sock(sock->sk);
633 server->data_ready = sock->sk->sk_data_ready;
634 server->write_space = sock->sk->sk_write_space;
635 server->error_report = sock->sk->sk_error_report;
636 sock->sk->sk_user_data = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 sock->sk->sk_data_ready = ncp_tcp_data_ready;
638 sock->sk->sk_error_report = ncp_tcp_error_report;
639 if (sock->type == SOCK_STREAM) {
640 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
641 server->rcv.len = 10;
642 server->rcv.state = 0;
David Howellsc4028952006-11-22 14:57:56 +0000643 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
644 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 sock->sk->sk_write_space = ncp_tcp_write_space;
646 } else {
David Howellsc4028952006-11-22 14:57:56 +0000647 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
648 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 server->timeout_tm.data = (unsigned long)server;
650 server->timeout_tm.function = ncpdgram_timeout_call;
651 }
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200652 release_sock(sock->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
654 ncp_lock_server(server);
655 error = ncp_connect(server);
656 ncp_unlock_server(server);
657 if (error < 0)
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100658 goto out_rxbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
660
661 error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */
662#ifdef CONFIG_NCPFS_PACKET_SIGNING
663 if (ncp_negotiate_size_and_options(server, default_bufsize,
664 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
665 {
666 if (options != NCP_DEFAULT_OPTIONS)
667 {
668 if (ncp_negotiate_size_and_options(server,
669 default_bufsize,
670 options & 2,
671 &(server->buffer_size), &options) != 0)
672
673 {
674 goto out_disconnect;
675 }
676 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200677 ncp_lock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 if (options & 2)
679 server->sign_wanted = 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200680 ncp_unlock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 }
682 else
683#endif /* CONFIG_NCPFS_PACKET_SIGNING */
684 if (ncp_negotiate_buffersize(server, default_bufsize,
685 &(server->buffer_size)) != 0)
686 goto out_disconnect;
687 DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
688
689 memset(&finfo, 0, sizeof(finfo));
690 finfo.i.attributes = aDIR;
691 finfo.i.dataStreamSize = 0; /* ignored */
692 finfo.i.dirEntNum = 0;
693 finfo.i.DosDirNum = 0;
694#ifdef CONFIG_NCPFS_SMALLDOS
695 finfo.i.NSCreator = NW_NS_DOS;
696#endif
697 finfo.volume = NCP_NUMBER_OF_VOLUMES;
698 /* set dates of mountpoint to Jan 1, 1986; 00:00 */
699 finfo.i.creationTime = finfo.i.modifyTime
700 = cpu_to_le16(0x0000);
701 finfo.i.creationDate = finfo.i.modifyDate
702 = finfo.i.lastAccessDate
703 = cpu_to_le16(0x0C21);
704 finfo.i.nameLen = 0;
705 finfo.i.entryName[0] = '\0';
706
707 finfo.opened = 0;
708 finfo.ino = 2; /* tradition */
709
710 server->name_space[finfo.volume] = NW_NS_DOS;
711
712 error = -ENOMEM;
713 root_inode = ncp_iget(sb, &finfo);
714 if (!root_inode)
715 goto out_disconnect;
716 DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
717 sb->s_root = d_alloc_root(root_inode);
718 if (!sb->s_root)
719 goto out_no_root;
720 sb->s_root->d_op = &ncp_root_dentry_operations;
721 return 0;
722
723out_no_root:
724 iput(root_inode);
725out_disconnect:
726 ncp_lock_server(server);
727 ncp_disconnect(server);
728 ncp_unlock_server(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100729out_rxbuf:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 ncp_stop_tasks(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100731 vfree(server->rxbuf);
732out_txbuf:
733 vfree(server->txbuf);
734out_packet:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 vfree(server->packet);
736out_nls:
737#ifdef CONFIG_NCPFS_NLS
738 unload_nls(server->nls_io);
739 unload_nls(server->nls_vol);
740#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200741 mutex_destroy(&server->rcv.creq_mutex);
742 mutex_destroy(&server->root_setup_lock);
743 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744out_fput2:
745 if (server->info_filp)
746 fput(server->info_filp);
747out_fput:
Jens Axboef1970c72010-04-22 12:31:11 +0200748 bdi_destroy(&server->bdi);
749out_bdi:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
751 *
Matthew Whitworthe956b4b2010-06-27 14:34:30 +0100752 * The previously used put_filp(ncp_filp); was bogus, since
753 * it doesn't perform proper unlocking.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 */
755 fput(ncp_filp);
756out:
Eric W. Biederman1de24122006-12-13 00:35:13 -0800757 put_pid(data.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 sb->s_fs_info = NULL;
759 kfree(server);
760 return error;
761}
762
763static void ncp_put_super(struct super_block *sb)
764{
765 struct ncp_server *server = NCP_SBP(sb);
766
767 ncp_lock_server(server);
768 ncp_disconnect(server);
769 ncp_unlock_server(server);
770
771 ncp_stop_tasks(server);
772
773#ifdef CONFIG_NCPFS_NLS
774 /* unload the NLS charsets */
Thomas Gleixner6d729e42009-08-16 21:05:08 +0000775 unload_nls(server->nls_vol);
776 unload_nls(server->nls_io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777#endif /* CONFIG_NCPFS_NLS */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200778 mutex_destroy(&server->rcv.creq_mutex);
779 mutex_destroy(&server->root_setup_lock);
780 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781
782 if (server->info_filp)
783 fput(server->info_filp);
784 fput(server->ncp_filp);
Eric W. Biederman21542272006-12-13 00:35:11 -0800785 kill_pid(server->m.wdog_pid, SIGTERM, 1);
786 put_pid(server->m.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
Jens Axboef1970c72010-04-22 12:31:11 +0200788 bdi_destroy(&server->bdi);
Pekka Enberg44db77f2006-01-14 13:21:12 -0800789 kfree(server->priv.data);
790 kfree(server->auth.object_name);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100791 vfree(server->rxbuf);
792 vfree(server->txbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 vfree(server->packet);
794 sb->s_fs_info = NULL;
795 kfree(server);
796}
797
David Howells726c3342006-06-23 02:02:58 -0700798static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799{
800 struct dentry* d;
801 struct inode* i;
802 struct ncp_inode_info* ni;
803 struct ncp_server* s;
804 struct ncp_volume_info vi;
David Howells726c3342006-06-23 02:02:58 -0700805 struct super_block *sb = dentry->d_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 int err;
807 __u8 dh;
808
809 d = sb->s_root;
810 if (!d) {
811 goto dflt;
812 }
813 i = d->d_inode;
814 if (!i) {
815 goto dflt;
816 }
817 ni = NCP_FINFO(i);
818 if (!ni) {
819 goto dflt;
820 }
821 s = NCP_SBP(sb);
822 if (!s) {
823 goto dflt;
824 }
825 if (!s->m.mounted_vol[0]) {
826 goto dflt;
827 }
828
829 err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
830 if (err) {
831 goto dflt;
832 }
833 err = ncp_get_directory_info(s, dh, &vi);
834 ncp_dirhandle_free(s, dh);
835 if (err) {
836 goto dflt;
837 }
838 buf->f_type = NCP_SUPER_MAGIC;
839 buf->f_bsize = vi.sectors_per_block * 512;
840 buf->f_blocks = vi.total_blocks;
841 buf->f_bfree = vi.free_blocks;
842 buf->f_bavail = vi.free_blocks;
843 buf->f_files = vi.total_dir_entries;
844 buf->f_ffree = vi.available_dir_entries;
845 buf->f_namelen = 12;
846 return 0;
847
848 /* We cannot say how much disk space is left on a mounted
849 NetWare Server, because free space is distributed over
850 volumes, and the current user might have disk quotas. So
851 free space is not that simple to determine. Our decision
852 here is to err conservatively. */
853
854dflt:;
855 buf->f_type = NCP_SUPER_MAGIC;
856 buf->f_bsize = NCP_BLOCK_SIZE;
857 buf->f_blocks = 0;
858 buf->f_bfree = 0;
859 buf->f_bavail = 0;
860 buf->f_namelen = 12;
861 return 0;
862}
863
864int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
865{
866 struct inode *inode = dentry->d_inode;
867 int result = 0;
868 __le32 info_mask;
869 struct nw_modify_dos_info info;
870 struct ncp_server *server;
871
872 result = -EIO;
873
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 server = NCP_SERVER(inode);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200875 if (!server) /* How this could happen? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 goto out;
877
878 /* ageing the dentry to force validation */
879 ncp_age_dentry(server, dentry);
880
881 result = inode_change_ok(inode, attr);
882 if (result < 0)
883 goto out;
884
885 result = -EPERM;
886 if (((attr->ia_valid & ATTR_UID) &&
887 (attr->ia_uid != server->m.uid)))
888 goto out;
889
890 if (((attr->ia_valid & ATTR_GID) &&
891 (attr->ia_gid != server->m.gid)))
892 goto out;
893
894 if (((attr->ia_valid & ATTR_MODE) &&
895 (attr->ia_mode &
896 ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
897 goto out;
898
899 info_mask = 0;
900 memset(&info, 0, sizeof(info));
901
902#if 1
903 if ((attr->ia_valid & ATTR_MODE) != 0)
904 {
905 umode_t newmode = attr->ia_mode;
906
907 info_mask |= DM_ATTRIBUTES;
908
909 if (S_ISDIR(inode->i_mode)) {
910 newmode &= server->m.dir_mode;
911 } else {
912#ifdef CONFIG_NCPFS_EXTRAS
913 if (server->m.flags & NCP_MOUNT_EXTRAS) {
914 /* any non-default execute bit set */
915 if (newmode & ~server->m.file_mode & S_IXUGO)
916 info.attributes |= aSHARED | aSYSTEM;
917 /* read for group/world and not in default file_mode */
918 else if (newmode & ~server->m.file_mode & S_IRUGO)
919 info.attributes |= aSHARED;
920 } else
921#endif
922 newmode &= server->m.file_mode;
923 }
924 if (newmode & S_IWUGO)
925 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
926 else
927 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
928
929#ifdef CONFIG_NCPFS_NFS_NS
930 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
931 result = ncp_modify_nfs_info(server,
932 NCP_FINFO(inode)->volNumber,
933 NCP_FINFO(inode)->dirEntNum,
934 attr->ia_mode, 0);
935 if (result != 0)
936 goto out;
937 info.attributes &= ~(aSHARED | aSYSTEM);
938 {
939 /* mark partial success */
940 struct iattr tmpattr;
941
942 tmpattr.ia_valid = ATTR_MODE;
943 tmpattr.ia_mode = attr->ia_mode;
944
Christoph Hellwig10257742010-06-04 11:30:02 +0200945 setattr_copy(inode, &tmpattr);
946 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 }
948 }
949#endif
950 }
951#endif
952
953 /* Do SIZE before attributes, otherwise mtime together with size does not work...
954 */
955 if ((attr->ia_valid & ATTR_SIZE) != 0) {
956 int written;
957
958 DPRINTK("ncpfs: trying to change size to %ld\n",
959 attr->ia_size);
960
961 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
962 result = -EACCES;
963 goto out;
964 }
965 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
966 attr->ia_size, 0, "", &written);
967
968 /* According to ndir, the changes only take effect after
969 closing the file */
970 ncp_inode_close(inode);
971 result = ncp_make_closed(inode);
972 if (result)
973 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +0200974
975 if (attr->ia_size != i_size_read(inode)) {
976 result = vmtruncate(inode, attr->ia_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 if (result)
978 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +0200979 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 }
981 }
982 if ((attr->ia_valid & ATTR_CTIME) != 0) {
983 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
984 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
985 &info.creationTime, &info.creationDate);
986 }
987 if ((attr->ia_valid & ATTR_MTIME) != 0) {
988 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
989 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
990 &info.modifyTime, &info.modifyDate);
991 }
992 if ((attr->ia_valid & ATTR_ATIME) != 0) {
993 __le16 dummy;
994 info_mask |= (DM_LAST_ACCESS_DATE);
995 ncp_date_unix2dos(attr->ia_atime.tv_sec,
996 &dummy, &info.lastAccessDate);
997 }
998 if (info_mask != 0) {
999 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
1000 inode, info_mask, &info);
1001 if (result != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
1003 /* NetWare seems not to allow this. I
1004 do not know why. So, just tell the
1005 user everything went fine. This is
1006 a terrible hack, but I do not know
1007 how to do this correctly. */
1008 result = 0;
1009 } else
1010 goto out;
1011 }
1012#ifdef CONFIG_NCPFS_STRONG
1013 if ((!result) && (info_mask & DM_ATTRIBUTES))
1014 NCP_FINFO(inode)->nwattr = info.attributes;
1015#endif
1016 }
Christoph Hellwig10257742010-06-04 11:30:02 +02001017 if (result)
1018 goto out;
1019
1020 setattr_copy(inode, attr);
1021 mark_inode_dirty(inode);
1022
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023out:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001024 if (result > 0)
1025 result = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 return result;
1027}
1028
Al Viro3c26ff62010-07-25 11:46:36 +04001029static struct dentry *ncp_mount(struct file_system_type *fs_type,
1030 int flags, const char *dev_name, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031{
Al Viro3c26ff62010-07-25 11:46:36 +04001032 return mount_nodev(fs_type, flags, data, ncp_fill_super);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033}
1034
1035static struct file_system_type ncp_fs_type = {
1036 .owner = THIS_MODULE,
1037 .name = "ncpfs",
Al Viro3c26ff62010-07-25 11:46:36 +04001038 .mount = ncp_mount,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 .kill_sb = kill_anon_super,
Miklos Szeredi564cd132008-02-08 04:21:46 -08001040 .fs_flags = FS_BINARY_MOUNTDATA,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041};
1042
1043static int __init init_ncp_fs(void)
1044{
1045 int err;
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001046 DPRINTK("ncpfs: init_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 err = init_inodecache();
1049 if (err)
1050 goto out1;
1051 err = register_filesystem(&ncp_fs_type);
1052 if (err)
1053 goto out;
1054 return 0;
1055out:
1056 destroy_inodecache();
1057out1:
1058 return err;
1059}
1060
1061static void __exit exit_ncp_fs(void)
1062{
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001063 DPRINTK("ncpfs: exit_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 unregister_filesystem(&ncp_fs_type);
1065 destroy_inodecache();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066}
1067
1068module_init(init_ncp_fs)
1069module_exit(exit_ncp_fs)
1070MODULE_LICENSE("GPL");