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