]> bbs.cooldavid.org Git - net-next-2.6.git/blame - fs/ncpfs/inode.c
mm: Remove slab destructors from kmem_cache_create().
[net-next-2.6.git] / fs / ncpfs / inode.c
CommitLineData
1da177e4
LT
1/*
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
1da177e4
LT
12#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>
31
32#include <linux/ncp_fs.h>
33
34#include <net/sock.h>
35
36#include "ncplib_kernel.h"
37#include "getopt.h"
38
39static void ncp_delete_inode(struct inode *);
40static void ncp_put_super(struct super_block *);
726c3342 41static int ncp_statfs(struct dentry *, struct kstatfs *);
1da177e4 42
e18b890b 43static struct kmem_cache * ncp_inode_cachep;
1da177e4
LT
44
45static struct inode *ncp_alloc_inode(struct super_block *sb)
46{
47 struct ncp_inode_info *ei;
e94b1766 48 ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, GFP_KERNEL);
1da177e4
LT
49 if (!ei)
50 return NULL;
51 return &ei->vfs_inode;
52}
53
54static void ncp_destroy_inode(struct inode *inode)
55{
56 kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
57}
58
e18b890b 59static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
1da177e4
LT
60{
61 struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
62
a35afb83
CL
63 mutex_init(&ei->open_mutex);
64 inode_init_once(&ei->vfs_inode);
1da177e4 65}
20c2df83 66
1da177e4
LT
67static int init_inodecache(void)
68{
69 ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
70 sizeof(struct ncp_inode_info),
fffb60f9
PJ
71 0, (SLAB_RECLAIM_ACCOUNT|
72 SLAB_MEM_SPREAD),
20c2df83 73 init_once);
1da177e4
LT
74 if (ncp_inode_cachep == NULL)
75 return -ENOMEM;
76 return 0;
77}
78
79static void destroy_inodecache(void)
80{
1a1d92c1 81 kmem_cache_destroy(ncp_inode_cachep);
1da177e4
LT
82}
83
84static int ncp_remount(struct super_block *sb, int *flags, char* data)
85{
86 *flags |= MS_NODIRATIME;
87 return 0;
88}
89
ee9b6d61 90static const struct super_operations ncp_sops =
1da177e4
LT
91{
92 .alloc_inode = ncp_alloc_inode,
93 .destroy_inode = ncp_destroy_inode,
94 .drop_inode = generic_delete_inode,
95 .delete_inode = ncp_delete_inode,
96 .put_super = ncp_put_super,
97 .statfs = ncp_statfs,
98 .remount_fs = ncp_remount,
99};
100
101extern struct dentry_operations ncp_root_dentry_operations;
102#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
f5e54d6e 103extern const struct address_space_operations ncp_symlink_aops;
1da177e4
LT
104extern int ncp_symlink(struct inode*, struct dentry*, const char*);
105#endif
106
107/*
108 * Fill in the ncpfs-specific information in the inode.
109 */
110static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
111{
112 NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
113 NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
114 NCP_FINFO(inode)->volNumber = nwinfo->volume;
115}
116
117void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
118{
119 ncp_update_dirent(inode, nwinfo);
120 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
121 NCP_FINFO(inode)->access = nwinfo->access;
122 memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
123 sizeof(nwinfo->file_handle));
124 DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
125 nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
126 NCP_FINFO(inode)->dirEntNum);
127}
128
129static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
130{
131 /* NFS namespace mode overrides others if it's set. */
132 DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n",
133 nwi->entryName, nwi->nfs.mode);
134 if (nwi->nfs.mode) {
135 /* XXX Security? */
136 inode->i_mode = nwi->nfs.mode;
137 }
138
139 inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
140
141 inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate);
142 inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate);
143 inode->i_atime.tv_sec = ncp_date_dos2unix(0, nwi->lastAccessDate);
144 inode->i_atime.tv_nsec = 0;
145 inode->i_mtime.tv_nsec = 0;
146 inode->i_ctime.tv_nsec = 0;
147}
148
149static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
150{
151 struct nw_info_struct *nwi = &nwinfo->i;
152 struct ncp_server *server = NCP_SERVER(inode);
153
154 if (nwi->attributes & aDIR) {
155 inode->i_mode = server->m.dir_mode;
156 /* for directories dataStreamSize seems to be some
157 Object ID ??? */
158 inode->i_size = NCP_BLOCK_SIZE;
159 } else {
160 inode->i_mode = server->m.file_mode;
161 inode->i_size = le32_to_cpu(nwi->dataStreamSize);
162#ifdef CONFIG_NCPFS_EXTRAS
163 if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS))
164 && (nwi->attributes & aSHARED)) {
165 switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
166 case aHIDDEN:
167 if (server->m.flags & NCP_MOUNT_SYMLINKS) {
168 if (/* (inode->i_size >= NCP_MIN_SYMLINK_SIZE)
169 && */ (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) {
170 inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
171 NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
172 break;
173 }
174 }
175 /* FALLTHROUGH */
176 case 0:
177 if (server->m.flags & NCP_MOUNT_EXTRAS)
178 inode->i_mode |= S_IRUGO;
179 break;
180 case aSYSTEM:
181 if (server->m.flags & NCP_MOUNT_EXTRAS)
182 inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO;
183 break;
184 /* case aSYSTEM|aHIDDEN: */
185 default:
186 /* reserved combination */
187 break;
188 }
189 }
190#endif
191 }
192 if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
193}
194
195void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
196{
197 NCP_FINFO(inode)->flags = 0;
198 if (!atomic_read(&NCP_FINFO(inode)->opened)) {
199 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
200 ncp_update_attrs(inode, nwinfo);
201 }
202
203 ncp_update_dates(inode, &nwinfo->i);
204 ncp_update_dirent(inode, nwinfo);
205}
206
207/*
208 * Fill in the inode based on the ncp_entry_info structure.
209 */
210static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
211{
212 struct ncp_server *server = NCP_SERVER(inode);
213
214 NCP_FINFO(inode)->flags = 0;
215
216 ncp_update_attrs(inode, nwinfo);
217
218 DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
219
220 inode->i_nlink = 1;
221 inode->i_uid = server->m.uid;
222 inode->i_gid = server->m.gid;
1da177e4
LT
223
224 ncp_update_dates(inode, &nwinfo->i);
225 ncp_update_inode(inode, nwinfo);
226}
227
228#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
92e1d5be 229static const struct inode_operations ncp_symlink_inode_operations = {
1da177e4
LT
230 .readlink = generic_readlink,
231 .follow_link = page_follow_link_light,
232 .put_link = page_put_link,
233 .setattr = ncp_notify_change,
234};
235#endif
236
237/*
238 * Get a new inode.
239 */
240struct inode *
241ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
242{
243 struct inode *inode;
244
245 if (info == NULL) {
246 printk(KERN_ERR "ncp_iget: info is NULL\n");
247 return NULL;
248 }
249
250 inode = new_inode(sb);
251 if (inode) {
252 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
253
254 inode->i_ino = info->ino;
255 ncp_set_attr(inode, info);
256 if (S_ISREG(inode->i_mode)) {
257 inode->i_op = &ncp_file_inode_operations;
258 inode->i_fop = &ncp_file_operations;
259 } else if (S_ISDIR(inode->i_mode)) {
260 inode->i_op = &ncp_dir_inode_operations;
261 inode->i_fop = &ncp_dir_operations;
262#ifdef CONFIG_NCPFS_NFS_NS
263 } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
264 init_special_inode(inode, inode->i_mode,
265 new_decode_dev(info->i.nfs.rdev));
266#endif
267#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
268 } else if (S_ISLNK(inode->i_mode)) {
269 inode->i_op = &ncp_symlink_inode_operations;
270 inode->i_data.a_ops = &ncp_symlink_aops;
271#endif
272 } else {
273 make_bad_inode(inode);
274 }
275 insert_inode_hash(inode);
276 } else
277 printk(KERN_ERR "ncp_iget: iget failed!\n");
278 return inode;
279}
280
281static void
282ncp_delete_inode(struct inode *inode)
283{
fef26658
MF
284 truncate_inode_pages(&inode->i_data, 0);
285
1da177e4
LT
286 if (S_ISDIR(inode->i_mode)) {
287 DDPRINTK("ncp_delete_inode: put directory %ld\n", inode->i_ino);
288 }
289
290 if (ncp_make_closed(inode) != 0) {
291 /* We can't do anything but complain. */
292 printk(KERN_ERR "ncp_delete_inode: could not close\n");
293 }
294 clear_inode(inode);
295}
296
297static void ncp_stop_tasks(struct ncp_server *server) {
298 struct sock* sk = server->ncp_sock->sk;
299
300 sk->sk_error_report = server->error_report;
301 sk->sk_data_ready = server->data_ready;
302 sk->sk_write_space = server->write_space;
303 del_timer_sync(&server->timeout_tm);
304 flush_scheduled_work();
305}
306
307static const struct ncp_option ncp_opts[] = {
308 { "uid", OPT_INT, 'u' },
309 { "gid", OPT_INT, 'g' },
310 { "owner", OPT_INT, 'o' },
311 { "mode", OPT_INT, 'm' },
312 { "dirmode", OPT_INT, 'd' },
313 { "timeout", OPT_INT, 't' },
314 { "retry", OPT_INT, 'r' },
315 { "flags", OPT_INT, 'f' },
316 { "wdogpid", OPT_INT, 'w' },
317 { "ncpfd", OPT_INT, 'n' },
318 { "infofd", OPT_INT, 'i' }, /* v5 */
319 { "version", OPT_INT, 'v' },
320 { NULL, 0, 0 } };
321
322static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
323 int optval;
324 char *optarg;
325 unsigned long optint;
326 int version = 0;
1de24126 327 int ret;
1da177e4
LT
328
329 data->flags = 0;
330 data->int_flags = 0;
331 data->mounted_uid = 0;
2154227a 332 data->wdog_pid = NULL;
1da177e4
LT
333 data->ncp_fd = ~0;
334 data->time_out = 10;
335 data->retry_count = 20;
336 data->uid = 0;
337 data->gid = 0;
338 data->file_mode = 0600;
339 data->dir_mode = 0700;
340 data->info_fd = -1;
341 data->mounted_vol[0] = 0;
342
343 while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
1de24126
EB
344 ret = optval;
345 if (ret < 0)
346 goto err;
1da177e4
LT
347 switch (optval) {
348 case 'u':
349 data->uid = optint;
350 break;
351 case 'g':
352 data->gid = optint;
353 break;
354 case 'o':
355 data->mounted_uid = optint;
356 break;
357 case 'm':
358 data->file_mode = optint;
359 break;
360 case 'd':
361 data->dir_mode = optint;
362 break;
363 case 't':
364 data->time_out = optint;
365 break;
366 case 'r':
367 data->retry_count = optint;
368 break;
369 case 'f':
370 data->flags = optint;
371 break;
372 case 'w':
2154227a 373 data->wdog_pid = find_get_pid(optint);
1da177e4
LT
374 break;
375 case 'n':
376 data->ncp_fd = optint;
377 break;
378 case 'i':
379 data->info_fd = optint;
380 break;
381 case 'v':
1de24126
EB
382 ret = -ECHRNG;
383 if (optint < NCP_MOUNT_VERSION_V4)
384 goto err;
385 if (optint > NCP_MOUNT_VERSION_V5)
386 goto err;
1da177e4
LT
387 version = optint;
388 break;
389
390 }
391 }
392 return 0;
1de24126
EB
393err:
394 put_pid(data->wdog_pid);
395 data->wdog_pid = NULL;
396 return ret;
1da177e4
LT
397}
398
399static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
400{
401 struct ncp_mount_data_kernel data;
402 struct ncp_server *server;
403 struct file *ncp_filp;
404 struct inode *root_inode;
405 struct inode *sock_inode;
406 struct socket *sock;
407 int error;
408 int default_bufsize;
409#ifdef CONFIG_NCPFS_PACKET_SIGNING
410 int options;
411#endif
412 struct ncp_entry_info finfo;
413
1de24126 414 data.wdog_pid = NULL;
f8314dc6 415 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
1da177e4
LT
416 if (!server)
417 return -ENOMEM;
418 sb->s_fs_info = server;
1da177e4
LT
419
420 error = -EFAULT;
421 if (raw_data == NULL)
422 goto out;
423 switch (*(int*)raw_data) {
424 case NCP_MOUNT_VERSION:
425 {
426 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
427
428 data.flags = md->flags;
429 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
430 data.mounted_uid = md->mounted_uid;
2154227a 431 data.wdog_pid = find_get_pid(md->wdog_pid);
1da177e4
LT
432 data.ncp_fd = md->ncp_fd;
433 data.time_out = md->time_out;
434 data.retry_count = md->retry_count;
435 data.uid = md->uid;
436 data.gid = md->gid;
437 data.file_mode = md->file_mode;
438 data.dir_mode = md->dir_mode;
439 data.info_fd = -1;
440 memcpy(data.mounted_vol, md->mounted_vol,
441 NCP_VOLNAME_LEN+1);
442 }
443 break;
444 case NCP_MOUNT_VERSION_V4:
445 {
446 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
447
448 data.flags = md->flags;
449 data.int_flags = 0;
450 data.mounted_uid = md->mounted_uid;
2154227a 451 data.wdog_pid = find_get_pid(md->wdog_pid);
1da177e4
LT
452 data.ncp_fd = md->ncp_fd;
453 data.time_out = md->time_out;
454 data.retry_count = md->retry_count;
455 data.uid = md->uid;
456 data.gid = md->gid;
457 data.file_mode = md->file_mode;
458 data.dir_mode = md->dir_mode;
459 data.info_fd = -1;
460 data.mounted_vol[0] = 0;
461 }
462 break;
463 default:
464 error = -ECHRNG;
465 if (memcmp(raw_data, "vers", 4) == 0) {
466 error = ncp_parse_options(&data, raw_data);
467 }
468 if (error)
469 goto out;
470 break;
471 }
472 error = -EBADF;
473 ncp_filp = fget(data.ncp_fd);
474 if (!ncp_filp)
475 goto out;
476 error = -ENOTSOCK;
92e5baef 477 sock_inode = ncp_filp->f_path.dentry->d_inode;
1da177e4
LT
478 if (!S_ISSOCK(sock_inode->i_mode))
479 goto out_fput;
480 sock = SOCKET_I(sock_inode);
481 if (!sock)
482 goto out_fput;
483
484 if (sock->type == SOCK_STREAM)
485 default_bufsize = 0xF000;
486 else
487 default_bufsize = 1024;
488
489 sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
490 sb->s_maxbytes = 0xFFFFFFFFU;
491 sb->s_blocksize = 1024; /* Eh... Is this correct? */
492 sb->s_blocksize_bits = 10;
493 sb->s_magic = NCP_SUPER_MAGIC;
494 sb->s_op = &ncp_sops;
495
496 server = NCP_SBP(sb);
497 memset(server, 0, sizeof(*server));
498
499 server->ncp_filp = ncp_filp;
500 server->ncp_sock = sock;
501
502 if (data.info_fd != -1) {
503 struct socket *info_sock;
504
505 error = -EBADF;
506 server->info_filp = fget(data.info_fd);
507 if (!server->info_filp)
508 goto out_fput;
509 error = -ENOTSOCK;
92e5baef 510 sock_inode = server->info_filp->f_path.dentry->d_inode;
1da177e4
LT
511 if (!S_ISSOCK(sock_inode->i_mode))
512 goto out_fput2;
513 info_sock = SOCKET_I(sock_inode);
514 if (!info_sock)
515 goto out_fput2;
516 error = -EBADFD;
517 if (info_sock->type != SOCK_STREAM)
518 goto out_fput2;
519 server->info_sock = info_sock;
520 }
521
522/* server->lock = 0; */
8e3f9045 523 mutex_init(&server->mutex);
1da177e4
LT
524 server->packet = NULL;
525/* server->buffer_size = 0; */
526/* server->conn_status = 0; */
527/* server->root_dentry = NULL; */
528/* server->root_setuped = 0; */
529#ifdef CONFIG_NCPFS_PACKET_SIGNING
530/* server->sign_wanted = 0; */
531/* server->sign_active = 0; */
532#endif
533 server->auth.auth_type = NCP_AUTH_NONE;
534/* server->auth.object_name_len = 0; */
535/* server->auth.object_name = NULL; */
536/* server->auth.object_type = 0; */
537/* server->priv.len = 0; */
538/* server->priv.data = NULL; */
539
540 server->m = data;
541 /* Althought anything producing this is buggy, it happens
542 now because of PATH_MAX changes.. */
543 if (server->m.time_out < 1) {
544 server->m.time_out = 10;
545 printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
546 }
547 server->m.time_out = server->m.time_out * HZ / 100;
548 server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
549 server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
550
551#ifdef CONFIG_NCPFS_NLS
552 /* load the default NLS charsets */
553 server->nls_vol = load_nls_default();
554 server->nls_io = load_nls_default();
555#endif /* CONFIG_NCPFS_NLS */
556
557 server->dentry_ttl = 0; /* no caching */
558
559 INIT_LIST_HEAD(&server->tx.requests);
8e3f9045 560 mutex_init(&server->rcv.creq_mutex);
1da177e4
LT
561 server->tx.creq = NULL;
562 server->rcv.creq = NULL;
563 server->data_ready = sock->sk->sk_data_ready;
564 server->write_space = sock->sk->sk_write_space;
565 server->error_report = sock->sk->sk_error_report;
566 sock->sk->sk_user_data = server;
567
568 init_timer(&server->timeout_tm);
569#undef NCP_PACKET_SIZE
570#define NCP_PACKET_SIZE 131072
571 error = -ENOMEM;
572 server->packet_size = NCP_PACKET_SIZE;
573 server->packet = vmalloc(NCP_PACKET_SIZE);
574 if (server->packet == NULL)
575 goto out_nls;
c5f93cf1
PO
576 server->txbuf = vmalloc(NCP_PACKET_SIZE);
577 if (server->txbuf == NULL)
578 goto out_packet;
579 server->rxbuf = vmalloc(NCP_PACKET_SIZE);
580 if (server->rxbuf == NULL)
581 goto out_txbuf;
1da177e4
LT
582
583 sock->sk->sk_data_ready = ncp_tcp_data_ready;
584 sock->sk->sk_error_report = ncp_tcp_error_report;
585 if (sock->type == SOCK_STREAM) {
586 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
587 server->rcv.len = 10;
588 server->rcv.state = 0;
c4028958
DH
589 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
590 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
1da177e4
LT
591 sock->sk->sk_write_space = ncp_tcp_write_space;
592 } else {
c4028958
DH
593 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
594 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
1da177e4
LT
595 server->timeout_tm.data = (unsigned long)server;
596 server->timeout_tm.function = ncpdgram_timeout_call;
597 }
598
599 ncp_lock_server(server);
600 error = ncp_connect(server);
601 ncp_unlock_server(server);
602 if (error < 0)
c5f93cf1 603 goto out_rxbuf;
1da177e4
LT
604 DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
605
606 error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */
607#ifdef CONFIG_NCPFS_PACKET_SIGNING
608 if (ncp_negotiate_size_and_options(server, default_bufsize,
609 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
610 {
611 if (options != NCP_DEFAULT_OPTIONS)
612 {
613 if (ncp_negotiate_size_and_options(server,
614 default_bufsize,
615 options & 2,
616 &(server->buffer_size), &options) != 0)
617
618 {
619 goto out_disconnect;
620 }
621 }
622 if (options & 2)
623 server->sign_wanted = 1;
624 }
625 else
626#endif /* CONFIG_NCPFS_PACKET_SIGNING */
627 if (ncp_negotiate_buffersize(server, default_bufsize,
628 &(server->buffer_size)) != 0)
629 goto out_disconnect;
630 DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
631
632 memset(&finfo, 0, sizeof(finfo));
633 finfo.i.attributes = aDIR;
634 finfo.i.dataStreamSize = 0; /* ignored */
635 finfo.i.dirEntNum = 0;
636 finfo.i.DosDirNum = 0;
637#ifdef CONFIG_NCPFS_SMALLDOS
638 finfo.i.NSCreator = NW_NS_DOS;
639#endif
640 finfo.volume = NCP_NUMBER_OF_VOLUMES;
641 /* set dates of mountpoint to Jan 1, 1986; 00:00 */
642 finfo.i.creationTime = finfo.i.modifyTime
643 = cpu_to_le16(0x0000);
644 finfo.i.creationDate = finfo.i.modifyDate
645 = finfo.i.lastAccessDate
646 = cpu_to_le16(0x0C21);
647 finfo.i.nameLen = 0;
648 finfo.i.entryName[0] = '\0';
649
650 finfo.opened = 0;
651 finfo.ino = 2; /* tradition */
652
653 server->name_space[finfo.volume] = NW_NS_DOS;
654
655 error = -ENOMEM;
656 root_inode = ncp_iget(sb, &finfo);
657 if (!root_inode)
658 goto out_disconnect;
659 DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
660 sb->s_root = d_alloc_root(root_inode);
661 if (!sb->s_root)
662 goto out_no_root;
663 sb->s_root->d_op = &ncp_root_dentry_operations;
664 return 0;
665
666out_no_root:
667 iput(root_inode);
668out_disconnect:
669 ncp_lock_server(server);
670 ncp_disconnect(server);
671 ncp_unlock_server(server);
c5f93cf1 672out_rxbuf:
1da177e4 673 ncp_stop_tasks(server);
c5f93cf1
PO
674 vfree(server->rxbuf);
675out_txbuf:
676 vfree(server->txbuf);
677out_packet:
1da177e4
LT
678 vfree(server->packet);
679out_nls:
680#ifdef CONFIG_NCPFS_NLS
681 unload_nls(server->nls_io);
682 unload_nls(server->nls_vol);
683#endif
684out_fput2:
685 if (server->info_filp)
686 fput(server->info_filp);
687out_fput:
688 /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
689 *
690 * The previously used put_filp(ncp_filp); was bogous, since
691 * it doesn't proper unlocking.
692 */
693 fput(ncp_filp);
694out:
1de24126 695 put_pid(data.wdog_pid);
1da177e4
LT
696 sb->s_fs_info = NULL;
697 kfree(server);
698 return error;
699}
700
701static void ncp_put_super(struct super_block *sb)
702{
703 struct ncp_server *server = NCP_SBP(sb);
704
705 ncp_lock_server(server);
706 ncp_disconnect(server);
707 ncp_unlock_server(server);
708
709 ncp_stop_tasks(server);
710
711#ifdef CONFIG_NCPFS_NLS
712 /* unload the NLS charsets */
713 if (server->nls_vol)
714 {
715 unload_nls(server->nls_vol);
716 server->nls_vol = NULL;
717 }
718 if (server->nls_io)
719 {
720 unload_nls(server->nls_io);
721 server->nls_io = NULL;
722 }
723#endif /* CONFIG_NCPFS_NLS */
724
725 if (server->info_filp)
726 fput(server->info_filp);
727 fput(server->ncp_filp);
2154227a
EB
728 kill_pid(server->m.wdog_pid, SIGTERM, 1);
729 put_pid(server->m.wdog_pid);
1da177e4 730
44db77f3
PE
731 kfree(server->priv.data);
732 kfree(server->auth.object_name);
c5f93cf1
PO
733 vfree(server->rxbuf);
734 vfree(server->txbuf);
1da177e4
LT
735 vfree(server->packet);
736 sb->s_fs_info = NULL;
737 kfree(server);
738}
739
726c3342 740static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
1da177e4
LT
741{
742 struct dentry* d;
743 struct inode* i;
744 struct ncp_inode_info* ni;
745 struct ncp_server* s;
746 struct ncp_volume_info vi;
726c3342 747 struct super_block *sb = dentry->d_sb;
1da177e4
LT
748 int err;
749 __u8 dh;
750
751 d = sb->s_root;
752 if (!d) {
753 goto dflt;
754 }
755 i = d->d_inode;
756 if (!i) {
757 goto dflt;
758 }
759 ni = NCP_FINFO(i);
760 if (!ni) {
761 goto dflt;
762 }
763 s = NCP_SBP(sb);
764 if (!s) {
765 goto dflt;
766 }
767 if (!s->m.mounted_vol[0]) {
768 goto dflt;
769 }
770
771 err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
772 if (err) {
773 goto dflt;
774 }
775 err = ncp_get_directory_info(s, dh, &vi);
776 ncp_dirhandle_free(s, dh);
777 if (err) {
778 goto dflt;
779 }
780 buf->f_type = NCP_SUPER_MAGIC;
781 buf->f_bsize = vi.sectors_per_block * 512;
782 buf->f_blocks = vi.total_blocks;
783 buf->f_bfree = vi.free_blocks;
784 buf->f_bavail = vi.free_blocks;
785 buf->f_files = vi.total_dir_entries;
786 buf->f_ffree = vi.available_dir_entries;
787 buf->f_namelen = 12;
788 return 0;
789
790 /* We cannot say how much disk space is left on a mounted
791 NetWare Server, because free space is distributed over
792 volumes, and the current user might have disk quotas. So
793 free space is not that simple to determine. Our decision
794 here is to err conservatively. */
795
796dflt:;
797 buf->f_type = NCP_SUPER_MAGIC;
798 buf->f_bsize = NCP_BLOCK_SIZE;
799 buf->f_blocks = 0;
800 buf->f_bfree = 0;
801 buf->f_bavail = 0;
802 buf->f_namelen = 12;
803 return 0;
804}
805
806int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
807{
808 struct inode *inode = dentry->d_inode;
809 int result = 0;
810 __le32 info_mask;
811 struct nw_modify_dos_info info;
812 struct ncp_server *server;
813
814 result = -EIO;
815
816 lock_kernel();
817
818 server = NCP_SERVER(inode);
819 if ((!server) || !ncp_conn_valid(server))
820 goto out;
821
822 /* ageing the dentry to force validation */
823 ncp_age_dentry(server, dentry);
824
825 result = inode_change_ok(inode, attr);
826 if (result < 0)
827 goto out;
828
829 result = -EPERM;
830 if (((attr->ia_valid & ATTR_UID) &&
831 (attr->ia_uid != server->m.uid)))
832 goto out;
833
834 if (((attr->ia_valid & ATTR_GID) &&
835 (attr->ia_gid != server->m.gid)))
836 goto out;
837
838 if (((attr->ia_valid & ATTR_MODE) &&
839 (attr->ia_mode &
840 ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
841 goto out;
842
843 info_mask = 0;
844 memset(&info, 0, sizeof(info));
845
846#if 1
847 if ((attr->ia_valid & ATTR_MODE) != 0)
848 {
849 umode_t newmode = attr->ia_mode;
850
851 info_mask |= DM_ATTRIBUTES;
852
853 if (S_ISDIR(inode->i_mode)) {
854 newmode &= server->m.dir_mode;
855 } else {
856#ifdef CONFIG_NCPFS_EXTRAS
857 if (server->m.flags & NCP_MOUNT_EXTRAS) {
858 /* any non-default execute bit set */
859 if (newmode & ~server->m.file_mode & S_IXUGO)
860 info.attributes |= aSHARED | aSYSTEM;
861 /* read for group/world and not in default file_mode */
862 else if (newmode & ~server->m.file_mode & S_IRUGO)
863 info.attributes |= aSHARED;
864 } else
865#endif
866 newmode &= server->m.file_mode;
867 }
868 if (newmode & S_IWUGO)
869 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
870 else
871 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
872
873#ifdef CONFIG_NCPFS_NFS_NS
874 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
875 result = ncp_modify_nfs_info(server,
876 NCP_FINFO(inode)->volNumber,
877 NCP_FINFO(inode)->dirEntNum,
878 attr->ia_mode, 0);
879 if (result != 0)
880 goto out;
881 info.attributes &= ~(aSHARED | aSYSTEM);
882 {
883 /* mark partial success */
884 struct iattr tmpattr;
885
886 tmpattr.ia_valid = ATTR_MODE;
887 tmpattr.ia_mode = attr->ia_mode;
888
889 result = inode_setattr(inode, &tmpattr);
890 if (result)
891 goto out;
892 }
893 }
894#endif
895 }
896#endif
897
898 /* Do SIZE before attributes, otherwise mtime together with size does not work...
899 */
900 if ((attr->ia_valid & ATTR_SIZE) != 0) {
901 int written;
902
903 DPRINTK("ncpfs: trying to change size to %ld\n",
904 attr->ia_size);
905
906 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
907 result = -EACCES;
908 goto out;
909 }
910 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
911 attr->ia_size, 0, "", &written);
912
913 /* According to ndir, the changes only take effect after
914 closing the file */
915 ncp_inode_close(inode);
916 result = ncp_make_closed(inode);
917 if (result)
918 goto out;
919 {
920 struct iattr tmpattr;
921
922 tmpattr.ia_valid = ATTR_SIZE;
923 tmpattr.ia_size = attr->ia_size;
924
925 result = inode_setattr(inode, &tmpattr);
926 if (result)
927 goto out;
928 }
929 }
930 if ((attr->ia_valid & ATTR_CTIME) != 0) {
931 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
932 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
933 &info.creationTime, &info.creationDate);
934 }
935 if ((attr->ia_valid & ATTR_MTIME) != 0) {
936 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
937 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
938 &info.modifyTime, &info.modifyDate);
939 }
940 if ((attr->ia_valid & ATTR_ATIME) != 0) {
941 __le16 dummy;
942 info_mask |= (DM_LAST_ACCESS_DATE);
943 ncp_date_unix2dos(attr->ia_atime.tv_sec,
944 &dummy, &info.lastAccessDate);
945 }
946 if (info_mask != 0) {
947 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
948 inode, info_mask, &info);
949 if (result != 0) {
950 result = -EACCES;
951
952 if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
953 /* NetWare seems not to allow this. I
954 do not know why. So, just tell the
955 user everything went fine. This is
956 a terrible hack, but I do not know
957 how to do this correctly. */
958 result = 0;
959 } else
960 goto out;
961 }
962#ifdef CONFIG_NCPFS_STRONG
963 if ((!result) && (info_mask & DM_ATTRIBUTES))
964 NCP_FINFO(inode)->nwattr = info.attributes;
965#endif
966 }
967 if (!result)
968 result = inode_setattr(inode, attr);
969out:
970 unlock_kernel();
971 return result;
972}
973
454e2398
DH
974static int ncp_get_sb(struct file_system_type *fs_type,
975 int flags, const char *dev_name, void *data, struct vfsmount *mnt)
1da177e4 976{
454e2398 977 return get_sb_nodev(fs_type, flags, data, ncp_fill_super, mnt);
1da177e4
LT
978}
979
980static struct file_system_type ncp_fs_type = {
981 .owner = THIS_MODULE,
982 .name = "ncpfs",
983 .get_sb = ncp_get_sb,
984 .kill_sb = kill_anon_super,
985};
986
987static int __init init_ncp_fs(void)
988{
989 int err;
990 DPRINTK("ncpfs: init_module called\n");
991
1da177e4
LT
992 err = init_inodecache();
993 if (err)
994 goto out1;
995 err = register_filesystem(&ncp_fs_type);
996 if (err)
997 goto out;
998 return 0;
999out:
1000 destroy_inodecache();
1001out1:
1002 return err;
1003}
1004
1005static void __exit exit_ncp_fs(void)
1006{
1007 DPRINTK("ncpfs: cleanup_module called\n");
1008 unregister_filesystem(&ncp_fs_type);
1009 destroy_inodecache();
1da177e4
LT
1010}
1011
1012module_init(init_ncp_fs)
1013module_exit(exit_ncp_fs)
1014MODULE_LICENSE("GPL");