[PATCH] ncpfs: Use struct pid to track the userspace watchdog process
[powerpc.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 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 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
331         data->flags = 0;
332         data->int_flags = 0;
333         data->mounted_uid = 0;
334         data->wdog_pid = NULL;
335         data->ncp_fd = ~0;
336         data->time_out = 10;
337         data->retry_count = 20;
338         data->uid = 0;
339         data->gid = 0;
340         data->file_mode = 0600;
341         data->dir_mode = 0700;
342         data->info_fd = -1;
343         data->mounted_vol[0] = 0;
344         
345         while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
346                 if (optval < 0)
347                         return optval;
348                 switch (optval) {
349                         case 'u':
350                                 data->uid = optint;
351                                 break;
352                         case 'g':
353                                 data->gid = optint;
354                                 break;
355                         case 'o':
356                                 data->mounted_uid = optint;
357                                 break;
358                         case 'm':
359                                 data->file_mode = optint;
360                                 break;
361                         case 'd':
362                                 data->dir_mode = optint;
363                                 break;
364                         case 't':
365                                 data->time_out = optint;
366                                 break;
367                         case 'r':
368                                 data->retry_count = optint;
369                                 break;
370                         case 'f':
371                                 data->flags = optint;
372                                 break;
373                         case 'w':
374                                 data->wdog_pid = find_get_pid(optint);
375                                 break;
376                         case 'n':
377                                 data->ncp_fd = optint;
378                                 break;
379                         case 'i':
380                                 data->info_fd = optint;
381                                 break;
382                         case 'v':
383                                 if (optint < NCP_MOUNT_VERSION_V4) {
384                                         return -ECHRNG;
385                                 }
386                                 if (optint > NCP_MOUNT_VERSION_V5) {
387                                         return -ECHRNG;
388                                 }
389                                 version = optint;
390                                 break;
391                         
392                 }
393         }
394         return 0;
395 }
396
397 static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
398 {
399         struct ncp_mount_data_kernel data;
400         struct ncp_server *server;
401         struct file *ncp_filp;
402         struct inode *root_inode;
403         struct inode *sock_inode;
404         struct socket *sock;
405         int error;
406         int default_bufsize;
407 #ifdef CONFIG_NCPFS_PACKET_SIGNING
408         int options;
409 #endif
410         struct ncp_entry_info finfo;
411
412         server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
413         if (!server)
414                 return -ENOMEM;
415         sb->s_fs_info = server;
416
417         error = -EFAULT;
418         if (raw_data == NULL)
419                 goto out;
420         switch (*(int*)raw_data) {
421                 case NCP_MOUNT_VERSION:
422                         {
423                                 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
424
425                                 data.flags = md->flags;
426                                 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
427                                 data.mounted_uid = md->mounted_uid;
428                                 data.wdog_pid = find_get_pid(md->wdog_pid);
429                                 data.ncp_fd = md->ncp_fd;
430                                 data.time_out = md->time_out;
431                                 data.retry_count = md->retry_count;
432                                 data.uid = md->uid;
433                                 data.gid = md->gid;
434                                 data.file_mode = md->file_mode;
435                                 data.dir_mode = md->dir_mode;
436                                 data.info_fd = -1;
437                                 memcpy(data.mounted_vol, md->mounted_vol,
438                                         NCP_VOLNAME_LEN+1);
439                         }
440                         break;
441                 case NCP_MOUNT_VERSION_V4:
442                         {
443                                 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
444
445                                 data.flags = md->flags;
446                                 data.int_flags = 0;
447                                 data.mounted_uid = md->mounted_uid;
448                                 data.wdog_pid = find_get_pid(md->wdog_pid);
449                                 data.ncp_fd = md->ncp_fd;
450                                 data.time_out = md->time_out;
451                                 data.retry_count = md->retry_count;
452                                 data.uid = md->uid;
453                                 data.gid = md->gid;
454                                 data.file_mode = md->file_mode;
455                                 data.dir_mode = md->dir_mode;
456                                 data.info_fd = -1;
457                                 data.mounted_vol[0] = 0;
458                         }
459                         break;
460                 default:
461                         error = -ECHRNG;
462                         if (memcmp(raw_data, "vers", 4) == 0) {
463                                 error = ncp_parse_options(&data, raw_data);
464                         }
465                         if (error)
466                                 goto out;
467                         break;
468         }
469         error = -EBADF;
470         ncp_filp = fget(data.ncp_fd);
471         if (!ncp_filp)
472                 goto out;
473         error = -ENOTSOCK;
474         sock_inode = ncp_filp->f_path.dentry->d_inode;
475         if (!S_ISSOCK(sock_inode->i_mode))
476                 goto out_fput;
477         sock = SOCKET_I(sock_inode);
478         if (!sock)
479                 goto out_fput;
480                 
481         if (sock->type == SOCK_STREAM)
482                 default_bufsize = 0xF000;
483         else
484                 default_bufsize = 1024;
485
486         sb->s_flags |= MS_NODIRATIME;   /* probably even noatime */
487         sb->s_maxbytes = 0xFFFFFFFFU;
488         sb->s_blocksize = 1024; /* Eh...  Is this correct? */
489         sb->s_blocksize_bits = 10;
490         sb->s_magic = NCP_SUPER_MAGIC;
491         sb->s_op = &ncp_sops;
492
493         server = NCP_SBP(sb);
494         memset(server, 0, sizeof(*server));
495
496         server->ncp_filp = ncp_filp;
497         server->ncp_sock = sock;
498         
499         if (data.info_fd != -1) {
500                 struct socket *info_sock;
501
502                 error = -EBADF;
503                 server->info_filp = fget(data.info_fd);
504                 if (!server->info_filp)
505                         goto out_fput;
506                 error = -ENOTSOCK;
507                 sock_inode = server->info_filp->f_path.dentry->d_inode;
508                 if (!S_ISSOCK(sock_inode->i_mode))
509                         goto out_fput2;
510                 info_sock = SOCKET_I(sock_inode);
511                 if (!info_sock)
512                         goto out_fput2;
513                 error = -EBADFD;
514                 if (info_sock->type != SOCK_STREAM)
515                         goto out_fput2;
516                 server->info_sock = info_sock;
517         }
518
519 /*      server->lock = 0;       */
520         mutex_init(&server->mutex);
521         server->packet = NULL;
522 /*      server->buffer_size = 0;        */
523 /*      server->conn_status = 0;        */
524 /*      server->root_dentry = NULL;     */
525 /*      server->root_setuped = 0;       */
526 #ifdef CONFIG_NCPFS_PACKET_SIGNING
527 /*      server->sign_wanted = 0;        */
528 /*      server->sign_active = 0;        */
529 #endif
530         server->auth.auth_type = NCP_AUTH_NONE;
531 /*      server->auth.object_name_len = 0;       */
532 /*      server->auth.object_name = NULL;        */
533 /*      server->auth.object_type = 0;           */
534 /*      server->priv.len = 0;                   */
535 /*      server->priv.data = NULL;               */
536
537         server->m = data;
538         /* Althought anything producing this is buggy, it happens
539            now because of PATH_MAX changes.. */
540         if (server->m.time_out < 1) {
541                 server->m.time_out = 10;
542                 printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
543         }
544         server->m.time_out = server->m.time_out * HZ / 100;
545         server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
546         server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
547
548 #ifdef CONFIG_NCPFS_NLS
549         /* load the default NLS charsets */
550         server->nls_vol = load_nls_default();
551         server->nls_io = load_nls_default();
552 #endif /* CONFIG_NCPFS_NLS */
553
554         server->dentry_ttl = 0; /* no caching */
555
556         INIT_LIST_HEAD(&server->tx.requests);
557         mutex_init(&server->rcv.creq_mutex);
558         server->tx.creq         = NULL;
559         server->rcv.creq        = NULL;
560         server->data_ready      = sock->sk->sk_data_ready;
561         server->write_space     = sock->sk->sk_write_space;
562         server->error_report    = sock->sk->sk_error_report;
563         sock->sk->sk_user_data  = server;
564
565         init_timer(&server->timeout_tm);
566 #undef NCP_PACKET_SIZE
567 #define NCP_PACKET_SIZE 131072
568         error = -ENOMEM;
569         server->packet_size = NCP_PACKET_SIZE;
570         server->packet = vmalloc(NCP_PACKET_SIZE);
571         if (server->packet == NULL)
572                 goto out_nls;
573
574         sock->sk->sk_data_ready   = ncp_tcp_data_ready;
575         sock->sk->sk_error_report = ncp_tcp_error_report;
576         if (sock->type == SOCK_STREAM) {
577                 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
578                 server->rcv.len = 10;
579                 server->rcv.state = 0;
580                 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
581                 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
582                 sock->sk->sk_write_space = ncp_tcp_write_space;
583         } else {
584                 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
585                 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
586                 server->timeout_tm.data = (unsigned long)server;
587                 server->timeout_tm.function = ncpdgram_timeout_call;
588         }
589
590         ncp_lock_server(server);
591         error = ncp_connect(server);
592         ncp_unlock_server(server);
593         if (error < 0)
594                 goto out_packet;
595         DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
596
597         error = -EMSGSIZE;      /* -EREMOTESIDEINCOMPATIBLE */
598 #ifdef CONFIG_NCPFS_PACKET_SIGNING
599         if (ncp_negotiate_size_and_options(server, default_bufsize,
600                 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
601         {
602                 if (options != NCP_DEFAULT_OPTIONS)
603                 {
604                         if (ncp_negotiate_size_and_options(server, 
605                                 default_bufsize,
606                                 options & 2, 
607                                 &(server->buffer_size), &options) != 0)
608                                 
609                         {
610                                 goto out_disconnect;
611                         }
612                 }
613                 if (options & 2)
614                         server->sign_wanted = 1;
615         }
616         else 
617 #endif  /* CONFIG_NCPFS_PACKET_SIGNING */
618         if (ncp_negotiate_buffersize(server, default_bufsize,
619                                      &(server->buffer_size)) != 0)
620                 goto out_disconnect;
621         DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
622
623         memset(&finfo, 0, sizeof(finfo));
624         finfo.i.attributes      = aDIR;
625         finfo.i.dataStreamSize  = 0;    /* ignored */
626         finfo.i.dirEntNum       = 0;
627         finfo.i.DosDirNum       = 0;
628 #ifdef CONFIG_NCPFS_SMALLDOS
629         finfo.i.NSCreator       = NW_NS_DOS;
630 #endif
631         finfo.volume            = NCP_NUMBER_OF_VOLUMES;
632         /* set dates of mountpoint to Jan 1, 1986; 00:00 */
633         finfo.i.creationTime    = finfo.i.modifyTime
634                                 = cpu_to_le16(0x0000);
635         finfo.i.creationDate    = finfo.i.modifyDate
636                                 = finfo.i.lastAccessDate
637                                 = cpu_to_le16(0x0C21);
638         finfo.i.nameLen         = 0;
639         finfo.i.entryName[0]    = '\0';
640
641         finfo.opened            = 0;
642         finfo.ino               = 2;    /* tradition */
643
644         server->name_space[finfo.volume] = NW_NS_DOS;
645
646         error = -ENOMEM;
647         root_inode = ncp_iget(sb, &finfo);
648         if (!root_inode)
649                 goto out_disconnect;
650         DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
651         sb->s_root = d_alloc_root(root_inode);
652         if (!sb->s_root)
653                 goto out_no_root;
654         sb->s_root->d_op = &ncp_root_dentry_operations;
655         return 0;
656
657 out_no_root:
658         iput(root_inode);
659 out_disconnect:
660         ncp_lock_server(server);
661         ncp_disconnect(server);
662         ncp_unlock_server(server);
663 out_packet:
664         ncp_stop_tasks(server);
665         vfree(server->packet);
666 out_nls:
667 #ifdef CONFIG_NCPFS_NLS
668         unload_nls(server->nls_io);
669         unload_nls(server->nls_vol);
670 #endif
671 out_fput2:
672         if (server->info_filp)
673                 fput(server->info_filp);
674 out_fput:
675         /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
676          * 
677          * The previously used put_filp(ncp_filp); was bogous, since
678          * it doesn't proper unlocking.
679          */
680         fput(ncp_filp);
681 out:
682         sb->s_fs_info = NULL;
683         kfree(server);
684         return error;
685 }
686
687 static void ncp_put_super(struct super_block *sb)
688 {
689         struct ncp_server *server = NCP_SBP(sb);
690
691         ncp_lock_server(server);
692         ncp_disconnect(server);
693         ncp_unlock_server(server);
694
695         ncp_stop_tasks(server);
696
697 #ifdef CONFIG_NCPFS_NLS
698         /* unload the NLS charsets */
699         if (server->nls_vol)
700         {
701                 unload_nls(server->nls_vol);
702                 server->nls_vol = NULL;
703         }
704         if (server->nls_io)
705         {
706                 unload_nls(server->nls_io);
707                 server->nls_io = NULL;
708         }
709 #endif /* CONFIG_NCPFS_NLS */
710
711         if (server->info_filp)
712                 fput(server->info_filp);
713         fput(server->ncp_filp);
714         kill_pid(server->m.wdog_pid, SIGTERM, 1);
715         put_pid(server->m.wdog_pid);
716
717         kfree(server->priv.data);
718         kfree(server->auth.object_name);
719         vfree(server->packet);
720         sb->s_fs_info = NULL;
721         kfree(server);
722 }
723
724 static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
725 {
726         struct dentry* d;
727         struct inode* i;
728         struct ncp_inode_info* ni;
729         struct ncp_server* s;
730         struct ncp_volume_info vi;
731         struct super_block *sb = dentry->d_sb;
732         int err;
733         __u8 dh;
734         
735         d = sb->s_root;
736         if (!d) {
737                 goto dflt;
738         }
739         i = d->d_inode;
740         if (!i) {
741                 goto dflt;
742         }
743         ni = NCP_FINFO(i);
744         if (!ni) {
745                 goto dflt;
746         }
747         s = NCP_SBP(sb);
748         if (!s) {
749                 goto dflt;
750         }
751         if (!s->m.mounted_vol[0]) {
752                 goto dflt;
753         }
754
755         err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
756         if (err) {
757                 goto dflt;
758         }
759         err = ncp_get_directory_info(s, dh, &vi);
760         ncp_dirhandle_free(s, dh);
761         if (err) {
762                 goto dflt;
763         }
764         buf->f_type = NCP_SUPER_MAGIC;
765         buf->f_bsize = vi.sectors_per_block * 512;
766         buf->f_blocks = vi.total_blocks;
767         buf->f_bfree = vi.free_blocks;
768         buf->f_bavail = vi.free_blocks;
769         buf->f_files = vi.total_dir_entries;
770         buf->f_ffree = vi.available_dir_entries;
771         buf->f_namelen = 12;
772         return 0;
773
774         /* We cannot say how much disk space is left on a mounted
775            NetWare Server, because free space is distributed over
776            volumes, and the current user might have disk quotas. So
777            free space is not that simple to determine. Our decision
778            here is to err conservatively. */
779
780 dflt:;
781         buf->f_type = NCP_SUPER_MAGIC;
782         buf->f_bsize = NCP_BLOCK_SIZE;
783         buf->f_blocks = 0;
784         buf->f_bfree = 0;
785         buf->f_bavail = 0;
786         buf->f_namelen = 12;
787         return 0;
788 }
789
790 int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
791 {
792         struct inode *inode = dentry->d_inode;
793         int result = 0;
794         __le32 info_mask;
795         struct nw_modify_dos_info info;
796         struct ncp_server *server;
797
798         result = -EIO;
799
800         lock_kernel();  
801
802         server = NCP_SERVER(inode);
803         if ((!server) || !ncp_conn_valid(server))
804                 goto out;
805
806         /* ageing the dentry to force validation */
807         ncp_age_dentry(server, dentry);
808
809         result = inode_change_ok(inode, attr);
810         if (result < 0)
811                 goto out;
812
813         result = -EPERM;
814         if (((attr->ia_valid & ATTR_UID) &&
815              (attr->ia_uid != server->m.uid)))
816                 goto out;
817
818         if (((attr->ia_valid & ATTR_GID) &&
819              (attr->ia_gid != server->m.gid)))
820                 goto out;
821
822         if (((attr->ia_valid & ATTR_MODE) &&
823              (attr->ia_mode &
824               ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
825                 goto out;
826
827         info_mask = 0;
828         memset(&info, 0, sizeof(info));
829
830 #if 1 
831         if ((attr->ia_valid & ATTR_MODE) != 0)
832         {
833                 umode_t newmode = attr->ia_mode;
834
835                 info_mask |= DM_ATTRIBUTES;
836
837                 if (S_ISDIR(inode->i_mode)) {
838                         newmode &= server->m.dir_mode;
839                 } else {
840 #ifdef CONFIG_NCPFS_EXTRAS                      
841                         if (server->m.flags & NCP_MOUNT_EXTRAS) {
842                                 /* any non-default execute bit set */
843                                 if (newmode & ~server->m.file_mode & S_IXUGO)
844                                         info.attributes |= aSHARED | aSYSTEM;
845                                 /* read for group/world and not in default file_mode */
846                                 else if (newmode & ~server->m.file_mode & S_IRUGO)
847                                         info.attributes |= aSHARED;
848                         } else
849 #endif
850                                 newmode &= server->m.file_mode;                 
851                 }
852                 if (newmode & S_IWUGO)
853                         info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
854                 else
855                         info.attributes |=  (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
856
857 #ifdef CONFIG_NCPFS_NFS_NS
858                 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
859                         result = ncp_modify_nfs_info(server,
860                                                      NCP_FINFO(inode)->volNumber,
861                                                      NCP_FINFO(inode)->dirEntNum,
862                                                      attr->ia_mode, 0);
863                         if (result != 0)
864                                 goto out;
865                         info.attributes &= ~(aSHARED | aSYSTEM);
866                         {
867                                 /* mark partial success */
868                                 struct iattr tmpattr;
869                                 
870                                 tmpattr.ia_valid = ATTR_MODE;
871                                 tmpattr.ia_mode = attr->ia_mode;
872
873                                 result = inode_setattr(inode, &tmpattr);
874                                 if (result)
875                                         goto out;
876                         }
877                 }
878 #endif
879         }
880 #endif
881
882         /* Do SIZE before attributes, otherwise mtime together with size does not work...
883          */
884         if ((attr->ia_valid & ATTR_SIZE) != 0) {
885                 int written;
886
887                 DPRINTK("ncpfs: trying to change size to %ld\n",
888                         attr->ia_size);
889
890                 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
891                         result = -EACCES;
892                         goto out;
893                 }
894                 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
895                           attr->ia_size, 0, "", &written);
896
897                 /* According to ndir, the changes only take effect after
898                    closing the file */
899                 ncp_inode_close(inode);
900                 result = ncp_make_closed(inode);
901                 if (result)
902                         goto out;
903                 {
904                         struct iattr tmpattr;
905                         
906                         tmpattr.ia_valid = ATTR_SIZE;
907                         tmpattr.ia_size = attr->ia_size;
908                         
909                         result = inode_setattr(inode, &tmpattr);
910                         if (result)
911                                 goto out;
912                 }
913         }
914         if ((attr->ia_valid & ATTR_CTIME) != 0) {
915                 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
916                 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
917                              &info.creationTime, &info.creationDate);
918         }
919         if ((attr->ia_valid & ATTR_MTIME) != 0) {
920                 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
921                 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
922                                   &info.modifyTime, &info.modifyDate);
923         }
924         if ((attr->ia_valid & ATTR_ATIME) != 0) {
925                 __le16 dummy;
926                 info_mask |= (DM_LAST_ACCESS_DATE);
927                 ncp_date_unix2dos(attr->ia_atime.tv_sec,
928                                   &dummy, &info.lastAccessDate);
929         }
930         if (info_mask != 0) {
931                 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
932                                       inode, info_mask, &info);
933                 if (result != 0) {
934                         result = -EACCES;
935
936                         if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
937                                 /* NetWare seems not to allow this. I
938                                    do not know why. So, just tell the
939                                    user everything went fine. This is
940                                    a terrible hack, but I do not know
941                                    how to do this correctly. */
942                                 result = 0;
943                         } else
944                                 goto out;
945                 }
946 #ifdef CONFIG_NCPFS_STRONG              
947                 if ((!result) && (info_mask & DM_ATTRIBUTES))
948                         NCP_FINFO(inode)->nwattr = info.attributes;
949 #endif
950         }
951         if (!result)
952                 result = inode_setattr(inode, attr);
953 out:
954         unlock_kernel();
955         return result;
956 }
957
958 static int ncp_get_sb(struct file_system_type *fs_type,
959         int flags, const char *dev_name, void *data, struct vfsmount *mnt)
960 {
961         return get_sb_nodev(fs_type, flags, data, ncp_fill_super, mnt);
962 }
963
964 static struct file_system_type ncp_fs_type = {
965         .owner          = THIS_MODULE,
966         .name           = "ncpfs",
967         .get_sb         = ncp_get_sb,
968         .kill_sb        = kill_anon_super,
969 };
970
971 static int __init init_ncp_fs(void)
972 {
973         int err;
974         DPRINTK("ncpfs: init_module called\n");
975
976         err = init_inodecache();
977         if (err)
978                 goto out1;
979         err = register_filesystem(&ncp_fs_type);
980         if (err)
981                 goto out;
982         return 0;
983 out:
984         destroy_inodecache();
985 out1:
986         return err;
987 }
988
989 static void __exit exit_ncp_fs(void)
990 {
991         DPRINTK("ncpfs: cleanup_module called\n");
992         unregister_filesystem(&ncp_fs_type);
993         destroy_inodecache();
994 }
995
996 module_init(init_ncp_fs)
997 module_exit(exit_ncp_fs)
998 MODULE_LICENSE("GPL");