Linux 2.6.23.13
[linux/fpc-iii.git] / fs / ncpfs / inode.c
blob7f8536dbdedcfeb794d716539aa33cefc9b93e8d
1 /*
2 * inode.c
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
12 #include <linux/module.h>
14 #include <asm/system.h>
15 #include <asm/uaccess.h>
16 #include <asm/byteorder.h>
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>
32 #include <linux/ncp_fs.h>
34 #include <net/sock.h>
36 #include "ncplib_kernel.h"
37 #include "getopt.h"
39 static void ncp_delete_inode(struct inode *);
40 static void ncp_put_super(struct super_block *);
41 static int ncp_statfs(struct dentry *, struct kstatfs *);
43 static struct kmem_cache * ncp_inode_cachep;
45 static struct inode *ncp_alloc_inode(struct super_block *sb)
47 struct ncp_inode_info *ei;
48 ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, GFP_KERNEL);
49 if (!ei)
50 return NULL;
51 return &ei->vfs_inode;
54 static void ncp_destroy_inode(struct inode *inode)
56 kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
59 static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
61 struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
63 mutex_init(&ei->open_mutex);
64 inode_init_once(&ei->vfs_inode);
67 static int init_inodecache(void)
69 ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
70 sizeof(struct ncp_inode_info),
71 0, (SLAB_RECLAIM_ACCOUNT|
72 SLAB_MEM_SPREAD),
73 init_once);
74 if (ncp_inode_cachep == NULL)
75 return -ENOMEM;
76 return 0;
79 static void destroy_inodecache(void)
81 kmem_cache_destroy(ncp_inode_cachep);
84 static int ncp_remount(struct super_block *sb, int *flags, char* data)
86 *flags |= MS_NODIRATIME;
87 return 0;
90 static const struct super_operations ncp_sops =
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,
101 extern struct dentry_operations ncp_root_dentry_operations;
102 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
103 extern const struct address_space_operations ncp_symlink_aops;
104 extern int ncp_symlink(struct inode*, struct dentry*, const char*);
105 #endif
108 * Fill in the ncpfs-specific information in the inode.
110 static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
112 NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
113 NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
114 NCP_FINFO(inode)->volNumber = nwinfo->volume;
117 void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
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);
129 static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
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;
139 inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
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;
149 static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
151 struct nw_info_struct *nwi = &nwinfo->i;
152 struct ncp_server *server = NCP_SERVER(inode);
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;
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;
190 #endif
192 if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
195 void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
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);
203 ncp_update_dates(inode, &nwinfo->i);
204 ncp_update_dirent(inode, nwinfo);
208 * Fill in the inode based on the ncp_entry_info structure.
210 static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
212 struct ncp_server *server = NCP_SERVER(inode);
214 NCP_FINFO(inode)->flags = 0;
216 ncp_update_attrs(inode, nwinfo);
218 DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
220 inode->i_nlink = 1;
221 inode->i_uid = server->m.uid;
222 inode->i_gid = server->m.gid;
224 ncp_update_dates(inode, &nwinfo->i);
225 ncp_update_inode(inode, nwinfo);
228 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
229 static const struct inode_operations ncp_symlink_inode_operations = {
230 .readlink = generic_readlink,
231 .follow_link = page_follow_link_light,
232 .put_link = page_put_link,
233 .setattr = ncp_notify_change,
235 #endif
238 * Get a new inode.
240 struct inode *
241 ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
243 struct inode *inode;
245 if (info == NULL) {
246 printk(KERN_ERR "ncp_iget: info is NULL\n");
247 return NULL;
250 inode = new_inode(sb);
251 if (inode) {
252 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
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);
275 insert_inode_hash(inode);
276 } else
277 printk(KERN_ERR "ncp_iget: iget failed!\n");
278 return inode;
281 static void
282 ncp_delete_inode(struct inode *inode)
284 truncate_inode_pages(&inode->i_data, 0);
286 if (S_ISDIR(inode->i_mode)) {
287 DDPRINTK("ncp_delete_inode: put directory %ld\n", inode->i_ino);
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");
294 clear_inode(inode);
297 static void ncp_stop_tasks(struct ncp_server *server) {
298 struct sock* sk = server->ncp_sock->sk;
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();
307 static 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 } };
322 static 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;
327 int ret;
329 data->flags = 0;
330 data->int_flags = 0;
331 data->mounted_uid = 0;
332 data->wdog_pid = NULL;
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;
343 while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
344 ret = optval;
345 if (ret < 0)
346 goto err;
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':
373 data->wdog_pid = find_get_pid(optint);
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':
382 ret = -ECHRNG;
383 if (optint < NCP_MOUNT_VERSION_V4)
384 goto err;
385 if (optint > NCP_MOUNT_VERSION_V5)
386 goto err;
387 version = optint;
388 break;
392 return 0;
393 err:
394 put_pid(data->wdog_pid);
395 data->wdog_pid = NULL;
396 return ret;
399 static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
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;
414 data.wdog_pid = NULL;
415 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
416 if (!server)
417 return -ENOMEM;
418 sb->s_fs_info = server;
420 error = -EFAULT;
421 if (raw_data == NULL)
422 goto out;
423 switch (*(int*)raw_data) {
424 case NCP_MOUNT_VERSION:
426 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
428 data.flags = md->flags;
429 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
430 data.mounted_uid = md->mounted_uid;
431 data.wdog_pid = find_get_pid(md->wdog_pid);
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);
443 break;
444 case NCP_MOUNT_VERSION_V4:
446 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
448 data.flags = md->flags;
449 data.int_flags = 0;
450 data.mounted_uid = md->mounted_uid;
451 data.wdog_pid = find_get_pid(md->wdog_pid);
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;
462 break;
463 default:
464 error = -ECHRNG;
465 if (memcmp(raw_data, "vers", 4) == 0) {
466 error = ncp_parse_options(&data, raw_data);
468 if (error)
469 goto out;
470 break;
472 error = -EBADF;
473 ncp_filp = fget(data.ncp_fd);
474 if (!ncp_filp)
475 goto out;
476 error = -ENOTSOCK;
477 sock_inode = ncp_filp->f_path.dentry->d_inode;
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;
484 if (sock->type == SOCK_STREAM)
485 default_bufsize = 0xF000;
486 else
487 default_bufsize = 1024;
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;
496 server = NCP_SBP(sb);
497 memset(server, 0, sizeof(*server));
499 server->ncp_filp = ncp_filp;
500 server->ncp_sock = sock;
502 if (data.info_fd != -1) {
503 struct socket *info_sock;
505 error = -EBADF;
506 server->info_filp = fget(data.info_fd);
507 if (!server->info_filp)
508 goto out_fput;
509 error = -ENOTSOCK;
510 sock_inode = server->info_filp->f_path.dentry->d_inode;
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;
522 /* server->lock = 0; */
523 mutex_init(&server->mutex);
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; */
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");
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;
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 */
557 server->dentry_ttl = 0; /* no caching */
559 INIT_LIST_HEAD(&server->tx.requests);
560 mutex_init(&server->rcv.creq_mutex);
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;
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;
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;
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;
589 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
590 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
591 sock->sk->sk_write_space = ncp_tcp_write_space;
592 } else {
593 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
594 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
595 server->timeout_tm.data = (unsigned long)server;
596 server->timeout_tm.function = ncpdgram_timeout_call;
599 ncp_lock_server(server);
600 error = ncp_connect(server);
601 ncp_unlock_server(server);
602 if (error < 0)
603 goto out_rxbuf;
604 DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
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)
611 if (options != NCP_DEFAULT_OPTIONS)
613 if (ncp_negotiate_size_and_options(server,
614 default_bufsize,
615 options & 2,
616 &(server->buffer_size), &options) != 0)
619 goto out_disconnect;
622 if (options & 2)
623 server->sign_wanted = 1;
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);
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';
650 finfo.opened = 0;
651 finfo.ino = 2; /* tradition */
653 server->name_space[finfo.volume] = NW_NS_DOS;
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;
666 out_no_root:
667 iput(root_inode);
668 out_disconnect:
669 ncp_lock_server(server);
670 ncp_disconnect(server);
671 ncp_unlock_server(server);
672 out_rxbuf:
673 ncp_stop_tasks(server);
674 vfree(server->rxbuf);
675 out_txbuf:
676 vfree(server->txbuf);
677 out_packet:
678 vfree(server->packet);
679 out_nls:
680 #ifdef CONFIG_NCPFS_NLS
681 unload_nls(server->nls_io);
682 unload_nls(server->nls_vol);
683 #endif
684 out_fput2:
685 if (server->info_filp)
686 fput(server->info_filp);
687 out_fput:
688 /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
690 * The previously used put_filp(ncp_filp); was bogous, since
691 * it doesn't proper unlocking.
693 fput(ncp_filp);
694 out:
695 put_pid(data.wdog_pid);
696 sb->s_fs_info = NULL;
697 kfree(server);
698 return error;
701 static void ncp_put_super(struct super_block *sb)
703 struct ncp_server *server = NCP_SBP(sb);
705 ncp_lock_server(server);
706 ncp_disconnect(server);
707 ncp_unlock_server(server);
709 ncp_stop_tasks(server);
711 #ifdef CONFIG_NCPFS_NLS
712 /* unload the NLS charsets */
713 if (server->nls_vol)
715 unload_nls(server->nls_vol);
716 server->nls_vol = NULL;
718 if (server->nls_io)
720 unload_nls(server->nls_io);
721 server->nls_io = NULL;
723 #endif /* CONFIG_NCPFS_NLS */
725 if (server->info_filp)
726 fput(server->info_filp);
727 fput(server->ncp_filp);
728 kill_pid(server->m.wdog_pid, SIGTERM, 1);
729 put_pid(server->m.wdog_pid);
731 kfree(server->priv.data);
732 kfree(server->auth.object_name);
733 vfree(server->rxbuf);
734 vfree(server->txbuf);
735 vfree(server->packet);
736 sb->s_fs_info = NULL;
737 kfree(server);
740 static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
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;
747 struct super_block *sb = dentry->d_sb;
748 int err;
749 __u8 dh;
751 d = sb->s_root;
752 if (!d) {
753 goto dflt;
755 i = d->d_inode;
756 if (!i) {
757 goto dflt;
759 ni = NCP_FINFO(i);
760 if (!ni) {
761 goto dflt;
763 s = NCP_SBP(sb);
764 if (!s) {
765 goto dflt;
767 if (!s->m.mounted_vol[0]) {
768 goto dflt;
771 err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
772 if (err) {
773 goto dflt;
775 err = ncp_get_directory_info(s, dh, &vi);
776 ncp_dirhandle_free(s, dh);
777 if (err) {
778 goto dflt;
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;
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. */
796 dflt:;
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;
806 int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
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;
814 result = -EIO;
816 lock_kernel();
818 server = NCP_SERVER(inode);
819 if ((!server) || !ncp_conn_valid(server))
820 goto out;
822 /* ageing the dentry to force validation */
823 ncp_age_dentry(server, dentry);
825 result = inode_change_ok(inode, attr);
826 if (result < 0)
827 goto out;
829 result = -EPERM;
830 if (((attr->ia_valid & ATTR_UID) &&
831 (attr->ia_uid != server->m.uid)))
832 goto out;
834 if (((attr->ia_valid & ATTR_GID) &&
835 (attr->ia_gid != server->m.gid)))
836 goto out;
838 if (((attr->ia_valid & ATTR_MODE) &&
839 (attr->ia_mode &
840 ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
841 goto out;
843 info_mask = 0;
844 memset(&info, 0, sizeof(info));
846 #if 1
847 if ((attr->ia_valid & ATTR_MODE) != 0)
849 umode_t newmode = attr->ia_mode;
851 info_mask |= DM_ATTRIBUTES;
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;
868 if (newmode & S_IWUGO)
869 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
870 else
871 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
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);
883 /* mark partial success */
884 struct iattr tmpattr;
886 tmpattr.ia_valid = ATTR_MODE;
887 tmpattr.ia_mode = attr->ia_mode;
889 result = inode_setattr(inode, &tmpattr);
890 if (result)
891 goto out;
894 #endif
896 #endif
898 /* Do SIZE before attributes, otherwise mtime together with size does not work...
900 if ((attr->ia_valid & ATTR_SIZE) != 0) {
901 int written;
903 DPRINTK("ncpfs: trying to change size to %ld\n",
904 attr->ia_size);
906 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
907 result = -EACCES;
908 goto out;
910 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
911 attr->ia_size, 0, "", &written);
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;
920 struct iattr tmpattr;
922 tmpattr.ia_valid = ATTR_SIZE;
923 tmpattr.ia_size = attr->ia_size;
925 result = inode_setattr(inode, &tmpattr);
926 if (result)
927 goto out;
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);
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);
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);
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;
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;
962 #ifdef CONFIG_NCPFS_STRONG
963 if ((!result) && (info_mask & DM_ATTRIBUTES))
964 NCP_FINFO(inode)->nwattr = info.attributes;
965 #endif
967 if (!result)
968 result = inode_setattr(inode, attr);
969 out:
970 unlock_kernel();
971 return result;
974 static int ncp_get_sb(struct file_system_type *fs_type,
975 int flags, const char *dev_name, void *data, struct vfsmount *mnt)
977 return get_sb_nodev(fs_type, flags, data, ncp_fill_super, mnt);
980 static 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,
987 static int __init init_ncp_fs(void)
989 int err;
990 DPRINTK("ncpfs: init_module called\n");
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;
999 out:
1000 destroy_inodecache();
1001 out1:
1002 return err;
1005 static void __exit exit_ncp_fs(void)
1007 DPRINTK("ncpfs: cleanup_module called\n");
1008 unregister_filesystem(&ncp_fs_type);
1009 destroy_inodecache();
1012 module_init(init_ncp_fs)
1013 module_exit(exit_ncp_fs)
1014 MODULE_LICENSE("GPL");