8244710e97ddafff6644861f0bead0c07c02bf55
[pandora-kernel.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 kmem_cache_t * 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, SLAB_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, kmem_cache_t * 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         inode->i_blksize = NCP_BLOCK_SIZE;
227
228         ncp_update_dates(inode, &nwinfo->i);
229         ncp_update_inode(inode, nwinfo);
230 }
231
232 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
233 static struct inode_operations ncp_symlink_inode_operations = {
234         .readlink       = generic_readlink,
235         .follow_link    = page_follow_link_light,
236         .put_link       = page_put_link,
237         .setattr        = ncp_notify_change,
238 };
239 #endif
240
241 /*
242  * Get a new inode.
243  */
244 struct inode * 
245 ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
246 {
247         struct inode *inode;
248
249         if (info == NULL) {
250                 printk(KERN_ERR "ncp_iget: info is NULL\n");
251                 return NULL;
252         }
253
254         inode = new_inode(sb);
255         if (inode) {
256                 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
257
258                 inode->i_ino = info->ino;
259                 ncp_set_attr(inode, info);
260                 if (S_ISREG(inode->i_mode)) {
261                         inode->i_op = &ncp_file_inode_operations;
262                         inode->i_fop = &ncp_file_operations;
263                 } else if (S_ISDIR(inode->i_mode)) {
264                         inode->i_op = &ncp_dir_inode_operations;
265                         inode->i_fop = &ncp_dir_operations;
266 #ifdef CONFIG_NCPFS_NFS_NS
267                 } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
268                         init_special_inode(inode, inode->i_mode,
269                                 new_decode_dev(info->i.nfs.rdev));
270 #endif
271 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
272                 } else if (S_ISLNK(inode->i_mode)) {
273                         inode->i_op = &ncp_symlink_inode_operations;
274                         inode->i_data.a_ops = &ncp_symlink_aops;
275 #endif
276                 } else {
277                         make_bad_inode(inode);
278                 }
279                 insert_inode_hash(inode);
280         } else
281                 printk(KERN_ERR "ncp_iget: iget failed!\n");
282         return inode;
283 }
284
285 static void
286 ncp_delete_inode(struct inode *inode)
287 {
288         truncate_inode_pages(&inode->i_data, 0);
289
290         if (S_ISDIR(inode->i_mode)) {
291                 DDPRINTK("ncp_delete_inode: put directory %ld\n", inode->i_ino);
292         }
293
294         if (ncp_make_closed(inode) != 0) {
295                 /* We can't do anything but complain. */
296                 printk(KERN_ERR "ncp_delete_inode: could not close\n");
297         }
298         clear_inode(inode);
299 }
300
301 static void ncp_stop_tasks(struct ncp_server *server) {
302         struct sock* sk = server->ncp_sock->sk;
303                 
304         sk->sk_error_report = server->error_report;
305         sk->sk_data_ready   = server->data_ready;
306         sk->sk_write_space  = server->write_space;
307         del_timer_sync(&server->timeout_tm);
308         flush_scheduled_work();
309 }
310
311 static const struct ncp_option ncp_opts[] = {
312         { "uid",        OPT_INT,        'u' },
313         { "gid",        OPT_INT,        'g' },
314         { "owner",      OPT_INT,        'o' },
315         { "mode",       OPT_INT,        'm' },
316         { "dirmode",    OPT_INT,        'd' },
317         { "timeout",    OPT_INT,        't' },
318         { "retry",      OPT_INT,        'r' },
319         { "flags",      OPT_INT,        'f' },
320         { "wdogpid",    OPT_INT,        'w' },
321         { "ncpfd",      OPT_INT,        'n' },
322         { "infofd",     OPT_INT,        'i' },  /* v5 */
323         { "version",    OPT_INT,        'v' },
324         { NULL,         0,              0 } };
325
326 static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
327         int optval;
328         char *optarg;
329         unsigned long optint;
330         int version = 0;
331
332         data->flags = 0;
333         data->int_flags = 0;
334         data->mounted_uid = 0;
335         data->wdog_pid = -1;
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                 if (optval < 0)
348                         return optval;
349                 switch (optval) {
350                         case 'u':
351                                 data->uid = optint;
352                                 break;
353                         case 'g':
354                                 data->gid = optint;
355                                 break;
356                         case 'o':
357                                 data->mounted_uid = optint;
358                                 break;
359                         case 'm':
360                                 data->file_mode = optint;
361                                 break;
362                         case 'd':
363                                 data->dir_mode = optint;
364                                 break;
365                         case 't':
366                                 data->time_out = optint;
367                                 break;
368                         case 'r':
369                                 data->retry_count = optint;
370                                 break;
371                         case 'f':
372                                 data->flags = optint;
373                                 break;
374                         case 'w':
375                                 data->wdog_pid = optint;
376                                 break;
377                         case 'n':
378                                 data->ncp_fd = optint;
379                                 break;
380                         case 'i':
381                                 data->info_fd = optint;
382                                 break;
383                         case 'v':
384                                 if (optint < NCP_MOUNT_VERSION_V4) {
385                                         return -ECHRNG;
386                                 }
387                                 if (optint > NCP_MOUNT_VERSION_V5) {
388                                         return -ECHRNG;
389                                 }
390                                 version = optint;
391                                 break;
392                         
393                 }
394         }
395         return 0;
396 }
397
398 static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
399 {
400         struct ncp_mount_data_kernel data;
401         struct ncp_server *server;
402         struct file *ncp_filp;
403         struct inode *root_inode;
404         struct inode *sock_inode;
405         struct socket *sock;
406         int error;
407         int default_bufsize;
408 #ifdef CONFIG_NCPFS_PACKET_SIGNING
409         int options;
410 #endif
411         struct ncp_entry_info finfo;
412
413         server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
414         if (!server)
415                 return -ENOMEM;
416         sb->s_fs_info = server;
417
418         error = -EFAULT;
419         if (raw_data == NULL)
420                 goto out;
421         switch (*(int*)raw_data) {
422                 case NCP_MOUNT_VERSION:
423                         {
424                                 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
425
426                                 data.flags = md->flags;
427                                 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
428                                 data.mounted_uid = md->mounted_uid;
429                                 data.wdog_pid = md->wdog_pid;
430                                 data.ncp_fd = md->ncp_fd;
431                                 data.time_out = md->time_out;
432                                 data.retry_count = md->retry_count;
433                                 data.uid = md->uid;
434                                 data.gid = md->gid;
435                                 data.file_mode = md->file_mode;
436                                 data.dir_mode = md->dir_mode;
437                                 data.info_fd = -1;
438                                 memcpy(data.mounted_vol, md->mounted_vol,
439                                         NCP_VOLNAME_LEN+1);
440                         }
441                         break;
442                 case NCP_MOUNT_VERSION_V4:
443                         {
444                                 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
445
446                                 data.flags = md->flags;
447                                 data.int_flags = 0;
448                                 data.mounted_uid = md->mounted_uid;
449                                 data.wdog_pid = md->wdog_pid;
450                                 data.ncp_fd = md->ncp_fd;
451                                 data.time_out = md->time_out;
452                                 data.retry_count = md->retry_count;
453                                 data.uid = md->uid;
454                                 data.gid = md->gid;
455                                 data.file_mode = md->file_mode;
456                                 data.dir_mode = md->dir_mode;
457                                 data.info_fd = -1;
458                                 data.mounted_vol[0] = 0;
459                         }
460                         break;
461                 default:
462                         error = -ECHRNG;
463                         if (memcmp(raw_data, "vers", 4) == 0) {
464                                 error = ncp_parse_options(&data, raw_data);
465                         }
466                         if (error)
467                                 goto out;
468                         break;
469         }
470         error = -EBADF;
471         ncp_filp = fget(data.ncp_fd);
472         if (!ncp_filp)
473                 goto out;
474         error = -ENOTSOCK;
475         sock_inode = ncp_filp->f_dentry->d_inode;
476         if (!S_ISSOCK(sock_inode->i_mode))
477                 goto out_fput;
478         sock = SOCKET_I(sock_inode);
479         if (!sock)
480                 goto out_fput;
481                 
482         if (sock->type == SOCK_STREAM)
483                 default_bufsize = 0xF000;
484         else
485                 default_bufsize = 1024;
486
487         sb->s_flags |= MS_NODIRATIME;   /* probably even noatime */
488         sb->s_maxbytes = 0xFFFFFFFFU;
489         sb->s_blocksize = 1024; /* Eh...  Is this correct? */
490         sb->s_blocksize_bits = 10;
491         sb->s_magic = NCP_SUPER_MAGIC;
492         sb->s_op = &ncp_sops;
493
494         server = NCP_SBP(sb);
495         memset(server, 0, sizeof(*server));
496
497         server->ncp_filp = ncp_filp;
498         server->ncp_sock = sock;
499         
500         if (data.info_fd != -1) {
501                 struct socket *info_sock;
502
503                 error = -EBADF;
504                 server->info_filp = fget(data.info_fd);
505                 if (!server->info_filp)
506                         goto out_fput;
507                 error = -ENOTSOCK;
508                 sock_inode = server->info_filp->f_dentry->d_inode;
509                 if (!S_ISSOCK(sock_inode->i_mode))
510                         goto out_fput2;
511                 info_sock = SOCKET_I(sock_inode);
512                 if (!info_sock)
513                         goto out_fput2;
514                 error = -EBADFD;
515                 if (info_sock->type != SOCK_STREAM)
516                         goto out_fput2;
517                 server->info_sock = info_sock;
518         }
519
520 /*      server->lock = 0;       */
521         mutex_init(&server->mutex);
522         server->packet = NULL;
523 /*      server->buffer_size = 0;        */
524 /*      server->conn_status = 0;        */
525 /*      server->root_dentry = NULL;     */
526 /*      server->root_setuped = 0;       */
527 #ifdef CONFIG_NCPFS_PACKET_SIGNING
528 /*      server->sign_wanted = 0;        */
529 /*      server->sign_active = 0;        */
530 #endif
531         server->auth.auth_type = NCP_AUTH_NONE;
532 /*      server->auth.object_name_len = 0;       */
533 /*      server->auth.object_name = NULL;        */
534 /*      server->auth.object_type = 0;           */
535 /*      server->priv.len = 0;                   */
536 /*      server->priv.data = NULL;               */
537
538         server->m = data;
539         /* Althought anything producing this is buggy, it happens
540            now because of PATH_MAX changes.. */
541         if (server->m.time_out < 1) {
542                 server->m.time_out = 10;
543                 printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
544         }
545         server->m.time_out = server->m.time_out * HZ / 100;
546         server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
547         server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
548
549 #ifdef CONFIG_NCPFS_NLS
550         /* load the default NLS charsets */
551         server->nls_vol = load_nls_default();
552         server->nls_io = load_nls_default();
553 #endif /* CONFIG_NCPFS_NLS */
554
555         server->dentry_ttl = 0; /* no caching */
556
557         INIT_LIST_HEAD(&server->tx.requests);
558         mutex_init(&server->rcv.creq_mutex);
559         server->tx.creq         = NULL;
560         server->rcv.creq        = NULL;
561         server->data_ready      = sock->sk->sk_data_ready;
562         server->write_space     = sock->sk->sk_write_space;
563         server->error_report    = sock->sk->sk_error_report;
564         sock->sk->sk_user_data  = server;
565
566         init_timer(&server->timeout_tm);
567 #undef NCP_PACKET_SIZE
568 #define NCP_PACKET_SIZE 131072
569         error = -ENOMEM;
570         server->packet_size = NCP_PACKET_SIZE;
571         server->packet = vmalloc(NCP_PACKET_SIZE);
572         if (server->packet == NULL)
573                 goto out_nls;
574
575         sock->sk->sk_data_ready   = ncp_tcp_data_ready;
576         sock->sk->sk_error_report = ncp_tcp_error_report;
577         if (sock->type == SOCK_STREAM) {
578                 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
579                 server->rcv.len = 10;
580                 server->rcv.state = 0;
581                 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc, server);
582                 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc, server);
583                 sock->sk->sk_write_space = ncp_tcp_write_space;
584         } else {
585                 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc, server);
586                 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc, server);
587                 server->timeout_tm.data = (unsigned long)server;
588                 server->timeout_tm.function = ncpdgram_timeout_call;
589         }
590
591         ncp_lock_server(server);
592         error = ncp_connect(server);
593         ncp_unlock_server(server);
594         if (error < 0)
595                 goto out_packet;
596         DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
597
598         error = -EMSGSIZE;      /* -EREMOTESIDEINCOMPATIBLE */
599 #ifdef CONFIG_NCPFS_PACKET_SIGNING
600         if (ncp_negotiate_size_and_options(server, default_bufsize,
601                 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
602         {
603                 if (options != NCP_DEFAULT_OPTIONS)
604                 {
605                         if (ncp_negotiate_size_and_options(server, 
606                                 default_bufsize,
607                                 options & 2, 
608                                 &(server->buffer_size), &options) != 0)
609                                 
610                         {
611                                 goto out_disconnect;
612                         }
613                 }
614                 if (options & 2)
615                         server->sign_wanted = 1;
616         }
617         else 
618 #endif  /* CONFIG_NCPFS_PACKET_SIGNING */
619         if (ncp_negotiate_buffersize(server, default_bufsize,
620                                      &(server->buffer_size)) != 0)
621                 goto out_disconnect;
622         DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
623
624         memset(&finfo, 0, sizeof(finfo));
625         finfo.i.attributes      = aDIR;
626         finfo.i.dataStreamSize  = 0;    /* ignored */
627         finfo.i.dirEntNum       = 0;
628         finfo.i.DosDirNum       = 0;
629 #ifdef CONFIG_NCPFS_SMALLDOS
630         finfo.i.NSCreator       = NW_NS_DOS;
631 #endif
632         finfo.volume            = NCP_NUMBER_OF_VOLUMES;
633         /* set dates of mountpoint to Jan 1, 1986; 00:00 */
634         finfo.i.creationTime    = finfo.i.modifyTime
635                                 = cpu_to_le16(0x0000);
636         finfo.i.creationDate    = finfo.i.modifyDate
637                                 = finfo.i.lastAccessDate
638                                 = cpu_to_le16(0x0C21);
639         finfo.i.nameLen         = 0;
640         finfo.i.entryName[0]    = '\0';
641
642         finfo.opened            = 0;
643         finfo.ino               = 2;    /* tradition */
644
645         server->name_space[finfo.volume] = NW_NS_DOS;
646
647         error = -ENOMEM;
648         root_inode = ncp_iget(sb, &finfo);
649         if (!root_inode)
650                 goto out_disconnect;
651         DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
652         sb->s_root = d_alloc_root(root_inode);
653         if (!sb->s_root)
654                 goto out_no_root;
655         sb->s_root->d_op = &ncp_root_dentry_operations;
656         return 0;
657
658 out_no_root:
659         iput(root_inode);
660 out_disconnect:
661         ncp_lock_server(server);
662         ncp_disconnect(server);
663         ncp_unlock_server(server);
664 out_packet:
665         ncp_stop_tasks(server);
666         vfree(server->packet);
667 out_nls:
668 #ifdef CONFIG_NCPFS_NLS
669         unload_nls(server->nls_io);
670         unload_nls(server->nls_vol);
671 #endif
672 out_fput2:
673         if (server->info_filp)
674                 fput(server->info_filp);
675 out_fput:
676         /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
677          * 
678          * The previously used put_filp(ncp_filp); was bogous, since
679          * it doesn't proper unlocking.
680          */
681         fput(ncp_filp);
682 out:
683         sb->s_fs_info = NULL;
684         kfree(server);
685         return error;
686 }
687
688 static void ncp_put_super(struct super_block *sb)
689 {
690         struct ncp_server *server = NCP_SBP(sb);
691
692         ncp_lock_server(server);
693         ncp_disconnect(server);
694         ncp_unlock_server(server);
695
696         ncp_stop_tasks(server);
697
698 #ifdef CONFIG_NCPFS_NLS
699         /* unload the NLS charsets */
700         if (server->nls_vol)
701         {
702                 unload_nls(server->nls_vol);
703                 server->nls_vol = NULL;
704         }
705         if (server->nls_io)
706         {
707                 unload_nls(server->nls_io);
708                 server->nls_io = NULL;
709         }
710 #endif /* CONFIG_NCPFS_NLS */
711
712         if (server->info_filp)
713                 fput(server->info_filp);
714         fput(server->ncp_filp);
715         kill_proc(server->m.wdog_pid, SIGTERM, 1);
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");