blob: 9b39a5dd413140c6624de8680f07193227a6173d [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>
Nick Piggin34286d62011-01-07 17:49:57 +110032#include <linux/namei.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
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +110062static void ncp_i_callback(struct rcu_head *head)
63{
64 struct inode *inode = container_of(head, struct inode, i_rcu);
65 INIT_LIST_HEAD(&inode->i_dentry);
66 kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
67}
68
Linus Torvalds1da177e2005-04-16 15:20:36 -070069static void ncp_destroy_inode(struct inode *inode)
70{
Nick Pigginfa0d7e3d2011-01-07 17:49:49 +110071 call_rcu(&inode->i_rcu, ncp_i_callback);
Linus Torvalds1da177e2005-04-16 15:20:36 -070072}
73
Alexey Dobriyan51cc5062008-07-25 19:45:34 -070074static void init_once(void *foo)
Linus Torvalds1da177e2005-04-16 15:20:36 -070075{
76 struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
77
Christoph Lametera35afb82007-05-16 22:10:57 -070078 mutex_init(&ei->open_mutex);
79 inode_init_once(&ei->vfs_inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080}
Paul Mundt20c2df82007-07-20 10:11:58 +090081
Linus Torvalds1da177e2005-04-16 15:20:36 -070082static int init_inodecache(void)
83{
84 ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
85 sizeof(struct ncp_inode_info),
Paul Jacksonfffb60f2006-03-24 03:16:06 -080086 0, (SLAB_RECLAIM_ACCOUNT|
87 SLAB_MEM_SPREAD),
Paul Mundt20c2df82007-07-20 10:11:58 +090088 init_once);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 if (ncp_inode_cachep == NULL)
90 return -ENOMEM;
91 return 0;
92}
93
94static void destroy_inodecache(void)
95{
Alexey Dobriyan1a1d92c2006-09-27 01:49:40 -070096 kmem_cache_destroy(ncp_inode_cachep);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097}
98
99static int ncp_remount(struct super_block *sb, int *flags, char* data)
100{
101 *flags |= MS_NODIRATIME;
102 return 0;
103}
104
Josef 'Jeff' Sipekee9b6d62007-02-12 00:55:41 -0800105static const struct super_operations ncp_sops =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106{
107 .alloc_inode = ncp_alloc_inode,
108 .destroy_inode = ncp_destroy_inode,
109 .drop_inode = generic_delete_inode,
Al Viro94ee8492010-06-07 00:45:56 -0400110 .evict_inode = ncp_evict_inode,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 .put_super = ncp_put_super,
112 .statfs = ncp_statfs,
113 .remount_fs = ncp_remount,
Miklos Szeredi564cd132008-02-08 04:21:46 -0800114 .show_options = ncp_show_options,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115};
116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117/*
118 * Fill in the ncpfs-specific information in the inode.
119 */
120static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
121{
122 NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
123 NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
124 NCP_FINFO(inode)->volNumber = nwinfo->volume;
125}
126
127void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
128{
129 ncp_update_dirent(inode, nwinfo);
130 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
131 NCP_FINFO(inode)->access = nwinfo->access;
132 memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
133 sizeof(nwinfo->file_handle));
134 DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
135 nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
136 NCP_FINFO(inode)->dirEntNum);
137}
138
139static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
140{
141 /* NFS namespace mode overrides others if it's set. */
142 DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n",
143 nwi->entryName, nwi->nfs.mode);
144 if (nwi->nfs.mode) {
145 /* XXX Security? */
146 inode->i_mode = nwi->nfs.mode;
147 }
148
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200149 inode->i_blocks = (i_size_read(inode) + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
151 inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate);
152 inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate);
153 inode->i_atime.tv_sec = ncp_date_dos2unix(0, nwi->lastAccessDate);
154 inode->i_atime.tv_nsec = 0;
155 inode->i_mtime.tv_nsec = 0;
156 inode->i_ctime.tv_nsec = 0;
157}
158
159static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
160{
161 struct nw_info_struct *nwi = &nwinfo->i;
162 struct ncp_server *server = NCP_SERVER(inode);
163
164 if (nwi->attributes & aDIR) {
165 inode->i_mode = server->m.dir_mode;
166 /* for directories dataStreamSize seems to be some
167 Object ID ??? */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200168 i_size_write(inode, NCP_BLOCK_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 } else {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200170 u32 size;
171
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 inode->i_mode = server->m.file_mode;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200173 size = le32_to_cpu(nwi->dataStreamSize);
174 i_size_write(inode, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175#ifdef CONFIG_NCPFS_EXTRAS
176 if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS))
177 && (nwi->attributes & aSHARED)) {
178 switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
179 case aHIDDEN:
180 if (server->m.flags & NCP_MOUNT_SYMLINKS) {
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200181 if (/* (size >= NCP_MIN_SYMLINK_SIZE)
182 && */ (size <= NCP_MAX_SYMLINK_SIZE)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
184 NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
185 break;
186 }
187 }
188 /* FALLTHROUGH */
189 case 0:
190 if (server->m.flags & NCP_MOUNT_EXTRAS)
191 inode->i_mode |= S_IRUGO;
192 break;
193 case aSYSTEM:
194 if (server->m.flags & NCP_MOUNT_EXTRAS)
195 inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO;
196 break;
197 /* case aSYSTEM|aHIDDEN: */
198 default:
199 /* reserved combination */
200 break;
201 }
202 }
203#endif
204 }
205 if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
206}
207
208void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
209{
210 NCP_FINFO(inode)->flags = 0;
211 if (!atomic_read(&NCP_FINFO(inode)->opened)) {
212 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
213 ncp_update_attrs(inode, nwinfo);
214 }
215
216 ncp_update_dates(inode, &nwinfo->i);
217 ncp_update_dirent(inode, nwinfo);
218}
219
220/*
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200221 * Fill in the inode based on the ncp_entry_info structure. Used only for brand new inodes.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 */
223static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
224{
225 struct ncp_server *server = NCP_SERVER(inode);
226
227 NCP_FINFO(inode)->flags = 0;
228
229 ncp_update_attrs(inode, nwinfo);
230
231 DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
232
233 inode->i_nlink = 1;
234 inode->i_uid = server->m.uid;
235 inode->i_gid = server->m.gid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236
237 ncp_update_dates(inode, &nwinfo->i);
238 ncp_update_inode(inode, nwinfo);
239}
240
241#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -0800242static const struct inode_operations ncp_symlink_inode_operations = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243 .readlink = generic_readlink,
244 .follow_link = page_follow_link_light,
245 .put_link = page_put_link,
246 .setattr = ncp_notify_change,
247};
248#endif
249
250/*
251 * Get a new inode.
252 */
253struct inode *
254ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
255{
256 struct inode *inode;
257
258 if (info == NULL) {
259 printk(KERN_ERR "ncp_iget: info is NULL\n");
260 return NULL;
261 }
262
263 inode = new_inode(sb);
264 if (inode) {
265 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
266
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200267 inode->i_mapping->backing_dev_info = sb->s_bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 inode->i_ino = info->ino;
269 ncp_set_attr(inode, info);
270 if (S_ISREG(inode->i_mode)) {
271 inode->i_op = &ncp_file_inode_operations;
272 inode->i_fop = &ncp_file_operations;
273 } else if (S_ISDIR(inode->i_mode)) {
274 inode->i_op = &ncp_dir_inode_operations;
275 inode->i_fop = &ncp_dir_operations;
276#ifdef CONFIG_NCPFS_NFS_NS
277 } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
278 init_special_inode(inode, inode->i_mode,
279 new_decode_dev(info->i.nfs.rdev));
280#endif
281#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
282 } else if (S_ISLNK(inode->i_mode)) {
283 inode->i_op = &ncp_symlink_inode_operations;
284 inode->i_data.a_ops = &ncp_symlink_aops;
285#endif
286 } else {
287 make_bad_inode(inode);
288 }
289 insert_inode_hash(inode);
290 } else
291 printk(KERN_ERR "ncp_iget: iget failed!\n");
292 return inode;
293}
294
295static void
Al Viro94ee8492010-06-07 00:45:56 -0400296ncp_evict_inode(struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297{
Mark Fashehfef26652005-09-09 13:01:31 -0700298 truncate_inode_pages(&inode->i_data, 0);
Al Viro94ee8492010-06-07 00:45:56 -0400299 end_writeback(inode);
Mark Fashehfef26652005-09-09 13:01:31 -0700300
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 if (S_ISDIR(inode->i_mode)) {
Al Viro94ee8492010-06-07 00:45:56 -0400302 DDPRINTK("ncp_evict_inode: put directory %ld\n", inode->i_ino);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 }
304
305 if (ncp_make_closed(inode) != 0) {
306 /* We can't do anything but complain. */
Al Viro94ee8492010-06-07 00:45:56 -0400307 printk(KERN_ERR "ncp_evict_inode: could not close\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309}
310
311static void ncp_stop_tasks(struct ncp_server *server) {
312 struct sock* sk = server->ncp_sock->sk;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200313
314 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 sk->sk_error_report = server->error_report;
316 sk->sk_data_ready = server->data_ready;
317 sk->sk_write_space = server->write_space;
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200318 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 del_timer_sync(&server->timeout_tm);
Tejun Heo5d8e4bd2010-12-24 15:59:06 +0100320
321 flush_work_sync(&server->rcv.tq);
322 if (sk->sk_socket->type == SOCK_STREAM)
323 flush_work_sync(&server->tx.tq);
324 else
325 flush_work_sync(&server->timeout_tq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326}
327
Miklos Szeredi564cd132008-02-08 04:21:46 -0800328static int ncp_show_options(struct seq_file *seq, struct vfsmount *mnt)
329{
330 struct ncp_server *server = NCP_SBP(mnt->mnt_sb);
331 unsigned int tmp;
332
333 if (server->m.uid != 0)
334 seq_printf(seq, ",uid=%u", server->m.uid);
335 if (server->m.gid != 0)
336 seq_printf(seq, ",gid=%u", server->m.gid);
337 if (server->m.mounted_uid != 0)
338 seq_printf(seq, ",owner=%u", server->m.mounted_uid);
339 tmp = server->m.file_mode & S_IALLUGO;
340 if (tmp != NCP_DEFAULT_FILE_MODE)
341 seq_printf(seq, ",mode=0%o", tmp);
342 tmp = server->m.dir_mode & S_IALLUGO;
343 if (tmp != NCP_DEFAULT_DIR_MODE)
344 seq_printf(seq, ",dirmode=0%o", tmp);
345 if (server->m.time_out != NCP_DEFAULT_TIME_OUT * HZ / 100) {
346 tmp = server->m.time_out * 100 / HZ;
347 seq_printf(seq, ",timeout=%u", tmp);
348 }
349 if (server->m.retry_count != NCP_DEFAULT_RETRY_COUNT)
350 seq_printf(seq, ",retry=%u", server->m.retry_count);
351 if (server->m.flags != 0)
352 seq_printf(seq, ",flags=%lu", server->m.flags);
353 if (server->m.wdog_pid != NULL)
354 seq_printf(seq, ",wdogpid=%u", pid_vnr(server->m.wdog_pid));
355
356 return 0;
357}
358
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359static const struct ncp_option ncp_opts[] = {
360 { "uid", OPT_INT, 'u' },
361 { "gid", OPT_INT, 'g' },
362 { "owner", OPT_INT, 'o' },
363 { "mode", OPT_INT, 'm' },
364 { "dirmode", OPT_INT, 'd' },
365 { "timeout", OPT_INT, 't' },
366 { "retry", OPT_INT, 'r' },
367 { "flags", OPT_INT, 'f' },
368 { "wdogpid", OPT_INT, 'w' },
369 { "ncpfd", OPT_INT, 'n' },
370 { "infofd", OPT_INT, 'i' }, /* v5 */
371 { "version", OPT_INT, 'v' },
372 { NULL, 0, 0 } };
373
374static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
375 int optval;
376 char *optarg;
377 unsigned long optint;
378 int version = 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800379 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380
381 data->flags = 0;
382 data->int_flags = 0;
383 data->mounted_uid = 0;
Eric W. Biederman21542272006-12-13 00:35:11 -0800384 data->wdog_pid = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 data->ncp_fd = ~0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800386 data->time_out = NCP_DEFAULT_TIME_OUT;
387 data->retry_count = NCP_DEFAULT_RETRY_COUNT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 data->uid = 0;
389 data->gid = 0;
Miklos Szeredi564cd132008-02-08 04:21:46 -0800390 data->file_mode = NCP_DEFAULT_FILE_MODE;
391 data->dir_mode = NCP_DEFAULT_DIR_MODE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 data->info_fd = -1;
393 data->mounted_vol[0] = 0;
394
395 while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
Eric W. Biederman1de24122006-12-13 00:35:13 -0800396 ret = optval;
397 if (ret < 0)
398 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 switch (optval) {
400 case 'u':
401 data->uid = optint;
402 break;
403 case 'g':
404 data->gid = optint;
405 break;
406 case 'o':
407 data->mounted_uid = optint;
408 break;
409 case 'm':
410 data->file_mode = optint;
411 break;
412 case 'd':
413 data->dir_mode = optint;
414 break;
415 case 't':
416 data->time_out = optint;
417 break;
418 case 'r':
419 data->retry_count = optint;
420 break;
421 case 'f':
422 data->flags = optint;
423 break;
424 case 'w':
Eric W. Biederman21542272006-12-13 00:35:11 -0800425 data->wdog_pid = find_get_pid(optint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 break;
427 case 'n':
428 data->ncp_fd = optint;
429 break;
430 case 'i':
431 data->info_fd = optint;
432 break;
433 case 'v':
Eric W. Biederman1de24122006-12-13 00:35:13 -0800434 ret = -ECHRNG;
435 if (optint < NCP_MOUNT_VERSION_V4)
436 goto err;
437 if (optint > NCP_MOUNT_VERSION_V5)
438 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 version = optint;
440 break;
441
442 }
443 }
444 return 0;
Eric W. Biederman1de24122006-12-13 00:35:13 -0800445err:
446 put_pid(data->wdog_pid);
447 data->wdog_pid = NULL;
448 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449}
450
451static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
452{
453 struct ncp_mount_data_kernel data;
454 struct ncp_server *server;
455 struct file *ncp_filp;
456 struct inode *root_inode;
457 struct inode *sock_inode;
458 struct socket *sock;
459 int error;
460 int default_bufsize;
461#ifdef CONFIG_NCPFS_PACKET_SIGNING
462 int options;
463#endif
464 struct ncp_entry_info finfo;
465
Eric W. Biederman1de24122006-12-13 00:35:13 -0800466 data.wdog_pid = NULL;
Panagiotis Issarisf8314dc2006-09-27 01:49:37 -0700467 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 if (!server)
469 return -ENOMEM;
470 sb->s_fs_info = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471
472 error = -EFAULT;
473 if (raw_data == NULL)
474 goto out;
475 switch (*(int*)raw_data) {
476 case NCP_MOUNT_VERSION:
477 {
478 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
479
480 data.flags = md->flags;
481 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
482 data.mounted_uid = md->mounted_uid;
Eric W. Biederman21542272006-12-13 00:35:11 -0800483 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 data.ncp_fd = md->ncp_fd;
485 data.time_out = md->time_out;
486 data.retry_count = md->retry_count;
487 data.uid = md->uid;
488 data.gid = md->gid;
489 data.file_mode = md->file_mode;
490 data.dir_mode = md->dir_mode;
491 data.info_fd = -1;
492 memcpy(data.mounted_vol, md->mounted_vol,
493 NCP_VOLNAME_LEN+1);
494 }
495 break;
496 case NCP_MOUNT_VERSION_V4:
497 {
498 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
499
500 data.flags = md->flags;
501 data.int_flags = 0;
502 data.mounted_uid = md->mounted_uid;
Eric W. Biederman21542272006-12-13 00:35:11 -0800503 data.wdog_pid = find_get_pid(md->wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 data.ncp_fd = md->ncp_fd;
505 data.time_out = md->time_out;
506 data.retry_count = md->retry_count;
507 data.uid = md->uid;
508 data.gid = md->gid;
509 data.file_mode = md->file_mode;
510 data.dir_mode = md->dir_mode;
511 data.info_fd = -1;
512 data.mounted_vol[0] = 0;
513 }
514 break;
515 default:
516 error = -ECHRNG;
517 if (memcmp(raw_data, "vers", 4) == 0) {
518 error = ncp_parse_options(&data, raw_data);
519 }
520 if (error)
521 goto out;
522 break;
523 }
524 error = -EBADF;
525 ncp_filp = fget(data.ncp_fd);
526 if (!ncp_filp)
527 goto out;
528 error = -ENOTSOCK;
Josef Sipek92e5bae2006-12-08 02:37:22 -0800529 sock_inode = ncp_filp->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 if (!S_ISSOCK(sock_inode->i_mode))
531 goto out_fput;
532 sock = SOCKET_I(sock_inode);
533 if (!sock)
534 goto out_fput;
535
536 if (sock->type == SOCK_STREAM)
537 default_bufsize = 0xF000;
538 else
539 default_bufsize = 1024;
540
541 sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
542 sb->s_maxbytes = 0xFFFFFFFFU;
543 sb->s_blocksize = 1024; /* Eh... Is this correct? */
544 sb->s_blocksize_bits = 10;
545 sb->s_magic = NCP_SUPER_MAGIC;
546 sb->s_op = &ncp_sops;
Jens Axboef1970c72010-04-22 12:31:11 +0200547 sb->s_bdi = &server->bdi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
549 server = NCP_SBP(sb);
550 memset(server, 0, sizeof(*server));
551
Jens Axboef1970c72010-04-22 12:31:11 +0200552 error = bdi_setup_and_register(&server->bdi, "ncpfs", BDI_CAP_MAP_COPY);
553 if (error)
554 goto out_bdi;
555
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 server->ncp_filp = ncp_filp;
557 server->ncp_sock = sock;
558
559 if (data.info_fd != -1) {
560 struct socket *info_sock;
561
562 error = -EBADF;
563 server->info_filp = fget(data.info_fd);
564 if (!server->info_filp)
565 goto out_fput;
566 error = -ENOTSOCK;
Josef Sipek92e5bae2006-12-08 02:37:22 -0800567 sock_inode = server->info_filp->f_path.dentry->d_inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 if (!S_ISSOCK(sock_inode->i_mode))
569 goto out_fput2;
570 info_sock = SOCKET_I(sock_inode);
571 if (!info_sock)
572 goto out_fput2;
573 error = -EBADFD;
574 if (info_sock->type != SOCK_STREAM)
575 goto out_fput2;
576 server->info_sock = info_sock;
577 }
578
579/* server->lock = 0; */
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800580 mutex_init(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 server->packet = NULL;
582/* server->buffer_size = 0; */
583/* server->conn_status = 0; */
584/* server->root_dentry = NULL; */
585/* server->root_setuped = 0; */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200586 mutex_init(&server->root_setup_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587#ifdef CONFIG_NCPFS_PACKET_SIGNING
588/* server->sign_wanted = 0; */
589/* server->sign_active = 0; */
590#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200591 init_rwsem(&server->auth_rwsem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 server->auth.auth_type = NCP_AUTH_NONE;
593/* server->auth.object_name_len = 0; */
594/* server->auth.object_name = NULL; */
595/* server->auth.object_type = 0; */
596/* server->priv.len = 0; */
597/* server->priv.data = NULL; */
598
599 server->m = data;
600 /* Althought anything producing this is buggy, it happens
601 now because of PATH_MAX changes.. */
602 if (server->m.time_out < 1) {
603 server->m.time_out = 10;
604 printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
605 }
606 server->m.time_out = server->m.time_out * HZ / 100;
607 server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
608 server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
609
610#ifdef CONFIG_NCPFS_NLS
611 /* load the default NLS charsets */
612 server->nls_vol = load_nls_default();
613 server->nls_io = load_nls_default();
614#endif /* CONFIG_NCPFS_NLS */
615
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200616 atomic_set(&server->dentry_ttl, 0); /* no caching */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
618 INIT_LIST_HEAD(&server->tx.requests);
Ingo Molnar8e3f9042006-03-23 03:00:43 -0800619 mutex_init(&server->rcv.creq_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 server->tx.creq = NULL;
621 server->rcv.creq = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622
623 init_timer(&server->timeout_tm);
624#undef NCP_PACKET_SIZE
625#define NCP_PACKET_SIZE 131072
626 error = -ENOMEM;
627 server->packet_size = NCP_PACKET_SIZE;
628 server->packet = vmalloc(NCP_PACKET_SIZE);
629 if (server->packet == NULL)
630 goto out_nls;
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100631 server->txbuf = vmalloc(NCP_PACKET_SIZE);
632 if (server->txbuf == NULL)
633 goto out_packet;
634 server->rxbuf = vmalloc(NCP_PACKET_SIZE);
635 if (server->rxbuf == NULL)
636 goto out_txbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200638 lock_sock(sock->sk);
639 server->data_ready = sock->sk->sk_data_ready;
640 server->write_space = sock->sk->sk_write_space;
641 server->error_report = sock->sk->sk_error_report;
642 sock->sk->sk_user_data = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 sock->sk->sk_data_ready = ncp_tcp_data_ready;
644 sock->sk->sk_error_report = ncp_tcp_error_report;
645 if (sock->type == SOCK_STREAM) {
646 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
647 server->rcv.len = 10;
648 server->rcv.state = 0;
David Howellsc4028952006-11-22 14:57:56 +0000649 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
650 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 sock->sk->sk_write_space = ncp_tcp_write_space;
652 } else {
David Howellsc4028952006-11-22 14:57:56 +0000653 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
654 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 server->timeout_tm.data = (unsigned long)server;
656 server->timeout_tm.function = ncpdgram_timeout_call;
657 }
Petr Vandrovec2a4df5d2010-09-29 14:39:11 +0200658 release_sock(sock->sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
660 ncp_lock_server(server);
661 error = ncp_connect(server);
662 ncp_unlock_server(server);
663 if (error < 0)
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100664 goto out_rxbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
666
667 error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */
668#ifdef CONFIG_NCPFS_PACKET_SIGNING
669 if (ncp_negotiate_size_and_options(server, default_bufsize,
670 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
671 {
672 if (options != NCP_DEFAULT_OPTIONS)
673 {
674 if (ncp_negotiate_size_and_options(server,
675 default_bufsize,
676 options & 2,
677 &(server->buffer_size), &options) != 0)
678
679 {
680 goto out_disconnect;
681 }
682 }
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200683 ncp_lock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 if (options & 2)
685 server->sign_wanted = 1;
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200686 ncp_unlock_server(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 }
688 else
689#endif /* CONFIG_NCPFS_PACKET_SIGNING */
690 if (ncp_negotiate_buffersize(server, default_bufsize,
691 &(server->buffer_size)) != 0)
692 goto out_disconnect;
693 DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
694
695 memset(&finfo, 0, sizeof(finfo));
696 finfo.i.attributes = aDIR;
697 finfo.i.dataStreamSize = 0; /* ignored */
698 finfo.i.dirEntNum = 0;
699 finfo.i.DosDirNum = 0;
700#ifdef CONFIG_NCPFS_SMALLDOS
701 finfo.i.NSCreator = NW_NS_DOS;
702#endif
703 finfo.volume = NCP_NUMBER_OF_VOLUMES;
704 /* set dates of mountpoint to Jan 1, 1986; 00:00 */
705 finfo.i.creationTime = finfo.i.modifyTime
706 = cpu_to_le16(0x0000);
707 finfo.i.creationDate = finfo.i.modifyDate
708 = finfo.i.lastAccessDate
709 = cpu_to_le16(0x0C21);
710 finfo.i.nameLen = 0;
711 finfo.i.entryName[0] = '\0';
712
713 finfo.opened = 0;
714 finfo.ino = 2; /* tradition */
715
716 server->name_space[finfo.volume] = NW_NS_DOS;
717
718 error = -ENOMEM;
719 root_inode = ncp_iget(sb, &finfo);
720 if (!root_inode)
721 goto out_disconnect;
722 DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
723 sb->s_root = d_alloc_root(root_inode);
724 if (!sb->s_root)
725 goto out_no_root;
Nick Pigginfb045ad2011-01-07 17:49:55 +1100726 d_set_d_op(sb->s_root, &ncp_root_dentry_operations);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 return 0;
728
729out_no_root:
730 iput(root_inode);
731out_disconnect:
732 ncp_lock_server(server);
733 ncp_disconnect(server);
734 ncp_unlock_server(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100735out_rxbuf:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 ncp_stop_tasks(server);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100737 vfree(server->rxbuf);
738out_txbuf:
739 vfree(server->txbuf);
740out_packet:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 vfree(server->packet);
742out_nls:
743#ifdef CONFIG_NCPFS_NLS
744 unload_nls(server->nls_io);
745 unload_nls(server->nls_vol);
746#endif
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200747 mutex_destroy(&server->rcv.creq_mutex);
748 mutex_destroy(&server->root_setup_lock);
749 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750out_fput2:
751 if (server->info_filp)
752 fput(server->info_filp);
753out_fput:
Jens Axboef1970c72010-04-22 12:31:11 +0200754 bdi_destroy(&server->bdi);
755out_bdi:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
757 *
Matthew Whitworthe956b4b2010-06-27 14:34:30 +0100758 * The previously used put_filp(ncp_filp); was bogus, since
759 * it doesn't perform proper unlocking.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 */
761 fput(ncp_filp);
762out:
Eric W. Biederman1de24122006-12-13 00:35:13 -0800763 put_pid(data.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 sb->s_fs_info = NULL;
765 kfree(server);
766 return error;
767}
768
769static void ncp_put_super(struct super_block *sb)
770{
771 struct ncp_server *server = NCP_SBP(sb);
772
773 ncp_lock_server(server);
774 ncp_disconnect(server);
775 ncp_unlock_server(server);
776
777 ncp_stop_tasks(server);
778
779#ifdef CONFIG_NCPFS_NLS
780 /* unload the NLS charsets */
Thomas Gleixner6d729e42009-08-16 21:05:08 +0000781 unload_nls(server->nls_vol);
782 unload_nls(server->nls_io);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783#endif /* CONFIG_NCPFS_NLS */
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200784 mutex_destroy(&server->rcv.creq_mutex);
785 mutex_destroy(&server->root_setup_lock);
786 mutex_destroy(&server->mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
788 if (server->info_filp)
789 fput(server->info_filp);
790 fput(server->ncp_filp);
Eric W. Biederman21542272006-12-13 00:35:11 -0800791 kill_pid(server->m.wdog_pid, SIGTERM, 1);
792 put_pid(server->m.wdog_pid);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
Jens Axboef1970c72010-04-22 12:31:11 +0200794 bdi_destroy(&server->bdi);
Pekka Enberg44db77f2006-01-14 13:21:12 -0800795 kfree(server->priv.data);
796 kfree(server->auth.object_name);
Pierre Ossmanc5f93cf2007-02-19 11:34:43 +0100797 vfree(server->rxbuf);
798 vfree(server->txbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 vfree(server->packet);
800 sb->s_fs_info = NULL;
801 kfree(server);
802}
803
David Howells726c3342006-06-23 02:02:58 -0700804static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805{
806 struct dentry* d;
807 struct inode* i;
808 struct ncp_inode_info* ni;
809 struct ncp_server* s;
810 struct ncp_volume_info vi;
David Howells726c3342006-06-23 02:02:58 -0700811 struct super_block *sb = dentry->d_sb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 int err;
813 __u8 dh;
814
815 d = sb->s_root;
816 if (!d) {
817 goto dflt;
818 }
819 i = d->d_inode;
820 if (!i) {
821 goto dflt;
822 }
823 ni = NCP_FINFO(i);
824 if (!ni) {
825 goto dflt;
826 }
827 s = NCP_SBP(sb);
828 if (!s) {
829 goto dflt;
830 }
831 if (!s->m.mounted_vol[0]) {
832 goto dflt;
833 }
834
835 err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
836 if (err) {
837 goto dflt;
838 }
839 err = ncp_get_directory_info(s, dh, &vi);
840 ncp_dirhandle_free(s, dh);
841 if (err) {
842 goto dflt;
843 }
844 buf->f_type = NCP_SUPER_MAGIC;
845 buf->f_bsize = vi.sectors_per_block * 512;
846 buf->f_blocks = vi.total_blocks;
847 buf->f_bfree = vi.free_blocks;
848 buf->f_bavail = vi.free_blocks;
849 buf->f_files = vi.total_dir_entries;
850 buf->f_ffree = vi.available_dir_entries;
851 buf->f_namelen = 12;
852 return 0;
853
854 /* We cannot say how much disk space is left on a mounted
855 NetWare Server, because free space is distributed over
856 volumes, and the current user might have disk quotas. So
857 free space is not that simple to determine. Our decision
858 here is to err conservatively. */
859
860dflt:;
861 buf->f_type = NCP_SUPER_MAGIC;
862 buf->f_bsize = NCP_BLOCK_SIZE;
863 buf->f_blocks = 0;
864 buf->f_bfree = 0;
865 buf->f_bavail = 0;
866 buf->f_namelen = 12;
867 return 0;
868}
869
870int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
871{
872 struct inode *inode = dentry->d_inode;
873 int result = 0;
874 __le32 info_mask;
875 struct nw_modify_dos_info info;
876 struct ncp_server *server;
877
878 result = -EIO;
879
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 server = NCP_SERVER(inode);
Petr Vandrovec2e54eb92010-09-27 01:47:33 +0200881 if (!server) /* How this could happen? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 goto out;
883
884 /* ageing the dentry to force validation */
885 ncp_age_dentry(server, dentry);
886
887 result = inode_change_ok(inode, attr);
888 if (result < 0)
889 goto out;
890
891 result = -EPERM;
892 if (((attr->ia_valid & ATTR_UID) &&
893 (attr->ia_uid != server->m.uid)))
894 goto out;
895
896 if (((attr->ia_valid & ATTR_GID) &&
897 (attr->ia_gid != server->m.gid)))
898 goto out;
899
900 if (((attr->ia_valid & ATTR_MODE) &&
901 (attr->ia_mode &
902 ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
903 goto out;
904
905 info_mask = 0;
906 memset(&info, 0, sizeof(info));
907
908#if 1
909 if ((attr->ia_valid & ATTR_MODE) != 0)
910 {
911 umode_t newmode = attr->ia_mode;
912
913 info_mask |= DM_ATTRIBUTES;
914
915 if (S_ISDIR(inode->i_mode)) {
916 newmode &= server->m.dir_mode;
917 } else {
918#ifdef CONFIG_NCPFS_EXTRAS
919 if (server->m.flags & NCP_MOUNT_EXTRAS) {
920 /* any non-default execute bit set */
921 if (newmode & ~server->m.file_mode & S_IXUGO)
922 info.attributes |= aSHARED | aSYSTEM;
923 /* read for group/world and not in default file_mode */
924 else if (newmode & ~server->m.file_mode & S_IRUGO)
925 info.attributes |= aSHARED;
926 } else
927#endif
928 newmode &= server->m.file_mode;
929 }
930 if (newmode & S_IWUGO)
931 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
932 else
933 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
934
935#ifdef CONFIG_NCPFS_NFS_NS
936 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
937 result = ncp_modify_nfs_info(server,
938 NCP_FINFO(inode)->volNumber,
939 NCP_FINFO(inode)->dirEntNum,
940 attr->ia_mode, 0);
941 if (result != 0)
942 goto out;
943 info.attributes &= ~(aSHARED | aSYSTEM);
944 {
945 /* mark partial success */
946 struct iattr tmpattr;
947
948 tmpattr.ia_valid = ATTR_MODE;
949 tmpattr.ia_mode = attr->ia_mode;
950
Christoph Hellwig10257742010-06-04 11:30:02 +0200951 setattr_copy(inode, &tmpattr);
952 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 }
954 }
955#endif
956 }
957#endif
958
959 /* Do SIZE before attributes, otherwise mtime together with size does not work...
960 */
961 if ((attr->ia_valid & ATTR_SIZE) != 0) {
962 int written;
963
964 DPRINTK("ncpfs: trying to change size to %ld\n",
965 attr->ia_size);
966
967 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
968 result = -EACCES;
969 goto out;
970 }
971 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
972 attr->ia_size, 0, "", &written);
973
974 /* According to ndir, the changes only take effect after
975 closing the file */
976 ncp_inode_close(inode);
977 result = ncp_make_closed(inode);
978 if (result)
979 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +0200980
981 if (attr->ia_size != i_size_read(inode)) {
982 result = vmtruncate(inode, attr->ia_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 if (result)
984 goto out;
Christoph Hellwig10257742010-06-04 11:30:02 +0200985 mark_inode_dirty(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 }
987 }
988 if ((attr->ia_valid & ATTR_CTIME) != 0) {
989 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
990 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
991 &info.creationTime, &info.creationDate);
992 }
993 if ((attr->ia_valid & ATTR_MTIME) != 0) {
994 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
995 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
996 &info.modifyTime, &info.modifyDate);
997 }
998 if ((attr->ia_valid & ATTR_ATIME) != 0) {
999 __le16 dummy;
1000 info_mask |= (DM_LAST_ACCESS_DATE);
1001 ncp_date_unix2dos(attr->ia_atime.tv_sec,
1002 &dummy, &info.lastAccessDate);
1003 }
1004 if (info_mask != 0) {
1005 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
1006 inode, info_mask, &info);
1007 if (result != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
1009 /* NetWare seems not to allow this. I
1010 do not know why. So, just tell the
1011 user everything went fine. This is
1012 a terrible hack, but I do not know
1013 how to do this correctly. */
1014 result = 0;
1015 } else
1016 goto out;
1017 }
1018#ifdef CONFIG_NCPFS_STRONG
1019 if ((!result) && (info_mask & DM_ATTRIBUTES))
1020 NCP_FINFO(inode)->nwattr = info.attributes;
1021#endif
1022 }
Christoph Hellwig10257742010-06-04 11:30:02 +02001023 if (result)
1024 goto out;
1025
1026 setattr_copy(inode, attr);
1027 mark_inode_dirty(inode);
1028
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029out:
Petr Vandrovec2e54eb92010-09-27 01:47:33 +02001030 if (result > 0)
1031 result = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 return result;
1033}
1034
Al Viro3c26ff62010-07-25 11:46:36 +04001035static struct dentry *ncp_mount(struct file_system_type *fs_type,
1036 int flags, const char *dev_name, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037{
Al Viro3c26ff62010-07-25 11:46:36 +04001038 return mount_nodev(fs_type, flags, data, ncp_fill_super);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039}
1040
1041static struct file_system_type ncp_fs_type = {
1042 .owner = THIS_MODULE,
1043 .name = "ncpfs",
Al Viro3c26ff62010-07-25 11:46:36 +04001044 .mount = ncp_mount,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 .kill_sb = kill_anon_super,
Miklos Szeredi564cd132008-02-08 04:21:46 -08001046 .fs_flags = FS_BINARY_MOUNTDATA,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047};
1048
1049static int __init init_ncp_fs(void)
1050{
1051 int err;
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001052 DPRINTK("ncpfs: init_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 err = init_inodecache();
1055 if (err)
1056 goto out1;
1057 err = register_filesystem(&ncp_fs_type);
1058 if (err)
1059 goto out;
1060 return 0;
1061out:
1062 destroy_inodecache();
1063out1:
1064 return err;
1065}
1066
1067static void __exit exit_ncp_fs(void)
1068{
Robert P. J. Day7c28cba2008-02-06 01:37:09 -08001069 DPRINTK("ncpfs: exit_ncp_fs called\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 unregister_filesystem(&ncp_fs_type);
1071 destroy_inodecache();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072}
1073
1074module_init(init_ncp_fs)
1075module_exit(exit_ncp_fs)
1076MODULE_LICENSE("GPL");