vserver 1.9.3
[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/config.h>
13 #include <linux/module.h>
14
15 #include <asm/system.h>
16 #include <asm/uaccess.h>
17 #include <asm/byteorder.h>
18
19 #include <linux/time.h>
20 #include <linux/kernel.h>
21 #include <linux/mm.h>
22 #include <linux/string.h>
23 #include <linux/stat.h>
24 #include <linux/errno.h>
25 #include <linux/file.h>
26 #include <linux/fcntl.h>
27 #include <linux/slab.h>
28 #include <linux/vmalloc.h>
29 #include <linux/init.h>
30 #include <linux/smp_lock.h>
31 #include <linux/vfs.h>
32
33 #include <linux/ncp_fs.h>
34
35 #include <net/sock.h>
36
37 #include "ncplib_kernel.h"
38 #include "getopt.h"
39
40 static void ncp_delete_inode(struct inode *);
41 static void ncp_put_super(struct super_block *);
42 static int  ncp_statfs(struct super_block *, struct kstatfs *);
43
44 static kmem_cache_t * ncp_inode_cachep;
45
46 static struct inode *ncp_alloc_inode(struct super_block *sb)
47 {
48         struct ncp_inode_info *ei;
49         ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, SLAB_KERNEL);
50         if (!ei)
51                 return NULL;
52         return &ei->vfs_inode;
53 }
54
55 static void ncp_destroy_inode(struct inode *inode)
56 {
57         kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
58 }
59
60 static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
61 {
62         struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
63
64         if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
65             SLAB_CTOR_CONSTRUCTOR) {
66                 init_MUTEX(&ei->open_sem);
67                 inode_init_once(&ei->vfs_inode);
68         }
69 }
70  
71 static int init_inodecache(void)
72 {
73         ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
74                                              sizeof(struct ncp_inode_info),
75                                              0, SLAB_RECLAIM_ACCOUNT,
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         if (kmem_cache_destroy(ncp_inode_cachep))
85                 printk(KERN_INFO "ncp_inode_cache: not all structures were freed\n");
86 }
87
88 static int ncp_remount(struct super_block *sb, int *flags, char* data)
89 {
90         *flags |= MS_NODIRATIME;
91         return 0;
92 }
93
94 static struct super_operations ncp_sops =
95 {
96         .alloc_inode    = ncp_alloc_inode,
97         .destroy_inode  = ncp_destroy_inode,
98         .drop_inode     = generic_delete_inode,
99         .delete_inode   = ncp_delete_inode,
100         .put_super      = ncp_put_super,
101         .statfs         = ncp_statfs,
102         .remount_fs     = ncp_remount,
103 };
104
105 extern struct dentry_operations ncp_root_dentry_operations;
106 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
107 extern struct address_space_operations ncp_symlink_aops;
108 extern int ncp_symlink(struct inode*, struct dentry*, const char*);
109 #endif
110
111 /*
112  * Fill in the ncpfs-specific information in the inode.
113  */
114 static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
115 {
116         NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
117         NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
118         NCP_FINFO(inode)->volNumber = nwinfo->volume;
119 }
120
121 void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
122 {
123         ncp_update_dirent(inode, nwinfo);
124         NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
125         NCP_FINFO(inode)->access = nwinfo->access;
126         memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
127                         sizeof(nwinfo->file_handle));
128         DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
129                 nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
130                 NCP_FINFO(inode)->dirEntNum);
131 }
132
133 static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
134 {
135         /* NFS namespace mode overrides others if it's set. */
136         DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n",
137                 nwi->entryName, nwi->nfs.mode);
138         if (nwi->nfs.mode) {
139                 /* XXX Security? */
140                 inode->i_mode = nwi->nfs.mode;
141         }
142
143         inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
144
145         inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate);
146         inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate);
147         inode->i_atime.tv_sec = ncp_date_dos2unix(0, nwi->lastAccessDate);
148         inode->i_atime.tv_nsec = 0;
149         inode->i_mtime.tv_nsec = 0;
150         inode->i_ctime.tv_nsec = 0;
151 }
152
153 static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
154 {
155         struct nw_info_struct *nwi = &nwinfo->i;
156         struct ncp_server *server = NCP_SERVER(inode);
157
158         if (nwi->attributes & aDIR) {
159                 inode->i_mode = server->m.dir_mode;
160                 /* for directories dataStreamSize seems to be some
161                    Object ID ??? */
162                 inode->i_size = NCP_BLOCK_SIZE;
163         } else {
164                 inode->i_mode = server->m.file_mode;
165                 inode->i_size = le32_to_cpu(nwi->dataStreamSize);
166 #ifdef CONFIG_NCPFS_EXTRAS
167                 if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS)) 
168                  && (nwi->attributes & aSHARED)) {
169                         switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
170                                 case aHIDDEN:
171                                         if (server->m.flags & NCP_MOUNT_SYMLINKS) {
172                                                 if (/* (inode->i_size >= NCP_MIN_SYMLINK_SIZE)
173                                                  && */ (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) {
174                                                         inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
175                                                         NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
176                                                         break;
177                                                 }
178                                         }
179                                         /* FALLTHROUGH */
180                                 case 0:
181                                         if (server->m.flags & NCP_MOUNT_EXTRAS)
182                                                 inode->i_mode |= S_IRUGO;
183                                         break;
184                                 case aSYSTEM:
185                                         if (server->m.flags & NCP_MOUNT_EXTRAS)
186                                                 inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO;
187                                         break;
188                                 /* case aSYSTEM|aHIDDEN: */
189                                 default:
190                                         /* reserved combination */
191                                         break;
192                         }
193                 }
194 #endif
195         }
196         if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
197 }
198
199 void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
200 {
201         NCP_FINFO(inode)->flags = 0;
202         if (!atomic_read(&NCP_FINFO(inode)->opened)) {
203                 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
204                 ncp_update_attrs(inode, nwinfo);
205         }
206
207         ncp_update_dates(inode, &nwinfo->i);
208         ncp_update_dirent(inode, nwinfo);
209 }
210
211 /*
212  * Fill in the inode based on the ncp_entry_info structure.
213  */
214 static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
215 {
216         struct ncp_server *server = NCP_SERVER(inode);
217
218         NCP_FINFO(inode)->flags = 0;
219         
220         ncp_update_attrs(inode, nwinfo);
221
222         DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
223
224         inode->i_nlink = 1;
225         inode->i_uid = server->m.uid;
226         inode->i_gid = server->m.gid;
227         inode->i_blksize = NCP_BLOCK_SIZE;
228
229         ncp_update_dates(inode, &nwinfo->i);
230         ncp_update_inode(inode, nwinfo);
231 }
232
233 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
234 static struct inode_operations ncp_symlink_inode_operations = {
235         .readlink       = generic_readlink,
236         .follow_link    = page_follow_link_light,
237         .put_link       = page_put_link,
238         .setattr        = ncp_notify_change,
239 };
240 #endif
241
242 /*
243  * Get a new inode.
244  */
245 struct inode * 
246 ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
247 {
248         struct inode *inode;
249
250         if (info == NULL) {
251                 printk(KERN_ERR "ncp_iget: info is NULL\n");
252                 return NULL;
253         }
254
255         inode = new_inode(sb);
256         if (inode) {
257                 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
258
259                 inode->i_ino = info->ino;
260                 ncp_set_attr(inode, info);
261                 if (S_ISREG(inode->i_mode)) {
262                         inode->i_op = &ncp_file_inode_operations;
263                         inode->i_fop = &ncp_file_operations;
264                 } else if (S_ISDIR(inode->i_mode)) {
265                         inode->i_op = &ncp_dir_inode_operations;
266                         inode->i_fop = &ncp_dir_operations;
267 #ifdef CONFIG_NCPFS_NFS_NS
268                 } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
269                         init_special_inode(inode, inode->i_mode,
270                                 new_decode_dev(info->i.nfs.rdev));
271 #endif
272 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
273                 } else if (S_ISLNK(inode->i_mode)) {
274                         inode->i_op = &ncp_symlink_inode_operations;
275                         inode->i_data.a_ops = &ncp_symlink_aops;
276 #endif
277                 } else {
278                         make_bad_inode(inode);
279                 }
280                 insert_inode_hash(inode);
281         } else
282                 printk(KERN_ERR "ncp_iget: iget failed!\n");
283         return inode;
284 }
285
286 static void
287 ncp_delete_inode(struct inode *inode)
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 = -1;
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 = 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 = kmalloc(sizeof(struct ncp_server), GFP_KERNEL);
413         if (!server)
414                 return -ENOMEM;
415         sb->s_fs_info = server;
416         memset(server, 0, sizeof(struct ncp_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         init_MUTEX(&server->sem);
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         init_MUTEX(&server->rcv.creq_sem);
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         if (server->priv.data) 
718                 ncp_kfree_s(server->priv.data, server->priv.len);
719         if (server->auth.object_name)
720                 ncp_kfree_s(server->auth.object_name, server->auth.object_name_len);
721         vfree(server->packet);
722         sb->s_fs_info = NULL;
723         kfree(server);
724 }
725
726 static int ncp_statfs(struct super_block *sb, struct kstatfs *buf)
727 {
728         struct dentry* d;
729         struct inode* i;
730         struct ncp_inode_info* ni;
731         struct ncp_server* s;
732         struct ncp_volume_info vi;
733         int err;
734         __u8 dh;
735         
736         d = sb->s_root;
737         if (!d) {
738                 goto dflt;
739         }
740         i = d->d_inode;
741         if (!i) {
742                 goto dflt;
743         }
744         ni = NCP_FINFO(i);
745         if (!ni) {
746                 goto dflt;
747         }
748         s = NCP_SBP(sb);
749         if (!s) {
750                 goto dflt;
751         }
752         if (!s->m.mounted_vol[0]) {
753                 goto dflt;
754         }
755
756         err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
757         if (err) {
758                 goto dflt;
759         }
760         err = ncp_get_directory_info(s, dh, &vi);
761         ncp_dirhandle_free(s, dh);
762         if (err) {
763                 goto dflt;
764         }
765         buf->f_type = NCP_SUPER_MAGIC;
766         buf->f_bsize = vi.sectors_per_block * 512;
767         buf->f_blocks = vi.total_blocks;
768         buf->f_bfree = vi.free_blocks;
769         buf->f_bavail = vi.free_blocks;
770         buf->f_files = vi.total_dir_entries;
771         buf->f_ffree = vi.available_dir_entries;
772         buf->f_namelen = 12;
773         return 0;
774
775         /* We cannot say how much disk space is left on a mounted
776            NetWare Server, because free space is distributed over
777            volumes, and the current user might have disk quotas. So
778            free space is not that simple to determine. Our decision
779            here is to err conservatively. */
780
781 dflt:;
782         buf->f_type = NCP_SUPER_MAGIC;
783         buf->f_bsize = NCP_BLOCK_SIZE;
784         buf->f_blocks = 0;
785         buf->f_bfree = 0;
786         buf->f_bavail = 0;
787         buf->f_namelen = 12;
788         return 0;
789 }
790
791 int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
792 {
793         struct inode *inode = dentry->d_inode;
794         int result = 0;
795         __le32 info_mask;
796         struct nw_modify_dos_info info;
797         struct ncp_server *server;
798
799         result = -EIO;
800
801         lock_kernel();  
802
803         server = NCP_SERVER(inode);
804         if ((!server) || !ncp_conn_valid(server))
805                 goto out;
806
807         /* ageing the dentry to force validation */
808         ncp_age_dentry(server, dentry);
809
810         result = inode_change_ok(inode, attr);
811         if (result < 0)
812                 goto out;
813
814         result = -EPERM;
815         if (((attr->ia_valid & ATTR_UID) &&
816              (attr->ia_uid != server->m.uid)))
817                 goto out;
818
819         if (((attr->ia_valid & ATTR_GID) &&
820              (attr->ia_gid != server->m.gid)))
821                 goto out;
822
823         if (((attr->ia_valid & ATTR_MODE) &&
824              (attr->ia_mode &
825               ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
826                 goto out;
827
828         info_mask = 0;
829         memset(&info, 0, sizeof(info));
830
831 #if 1 
832         if ((attr->ia_valid & ATTR_MODE) != 0)
833         {
834                 umode_t newmode = attr->ia_mode;
835
836                 info_mask |= DM_ATTRIBUTES;
837
838                 if (S_ISDIR(inode->i_mode)) {
839                         newmode &= server->m.dir_mode;
840                 } else {
841 #ifdef CONFIG_NCPFS_EXTRAS                      
842                         if (server->m.flags & NCP_MOUNT_EXTRAS) {
843                                 /* any non-default execute bit set */
844                                 if (newmode & ~server->m.file_mode & S_IXUGO)
845                                         info.attributes |= aSHARED | aSYSTEM;
846                                 /* read for group/world and not in default file_mode */
847                                 else if (newmode & ~server->m.file_mode & S_IRUGO)
848                                         info.attributes |= aSHARED;
849                         } else
850 #endif
851                                 newmode &= server->m.file_mode;                 
852                 }
853                 if (newmode & S_IWUGO)
854                         info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
855                 else
856                         info.attributes |=  (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
857
858 #ifdef CONFIG_NCPFS_NFS_NS
859                 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
860                         result = ncp_modify_nfs_info(server,
861                                                      NCP_FINFO(inode)->volNumber,
862                                                      NCP_FINFO(inode)->dirEntNum,
863                                                      attr->ia_mode, 0);
864                         if (result != 0)
865                                 goto out;
866                         info.attributes &= ~(aSHARED | aSYSTEM);
867                         {
868                                 /* mark partial success */
869                                 struct iattr tmpattr;
870                                 
871                                 tmpattr.ia_valid = ATTR_MODE;
872                                 tmpattr.ia_mode = attr->ia_mode;
873
874                                 result = inode_setattr(inode, &tmpattr);
875                                 if (result)
876                                         goto out;
877                         }
878                 }
879 #endif
880         }
881 #endif
882
883         /* Do SIZE before attributes, otherwise mtime together with size does not work...
884          */
885         if ((attr->ia_valid & ATTR_SIZE) != 0) {
886                 int written;
887
888                 DPRINTK("ncpfs: trying to change size to %ld\n",
889                         attr->ia_size);
890
891                 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
892                         result = -EACCES;
893                         goto out;
894                 }
895                 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
896                           attr->ia_size, 0, "", &written);
897
898                 /* According to ndir, the changes only take effect after
899                    closing the file */
900                 ncp_inode_close(inode);
901                 result = ncp_make_closed(inode);
902                 if (result)
903                         goto out;
904                 {
905                         struct iattr tmpattr;
906                         
907                         tmpattr.ia_valid = ATTR_SIZE;
908                         tmpattr.ia_size = attr->ia_size;
909                         
910                         result = inode_setattr(inode, &tmpattr);
911                         if (result)
912                                 goto out;
913                 }
914         }
915         if ((attr->ia_valid & ATTR_CTIME) != 0) {
916                 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
917                 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
918                              &info.creationTime, &info.creationDate);
919         }
920         if ((attr->ia_valid & ATTR_MTIME) != 0) {
921                 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
922                 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
923                                   &info.modifyTime, &info.modifyDate);
924         }
925         if ((attr->ia_valid & ATTR_ATIME) != 0) {
926                 __le16 dummy;
927                 info_mask |= (DM_LAST_ACCESS_DATE);
928                 ncp_date_unix2dos(attr->ia_atime.tv_sec,
929                                   &dummy, &info.lastAccessDate);
930         }
931         if (info_mask != 0) {
932                 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
933                                       inode, info_mask, &info);
934                 if (result != 0) {
935                         result = -EACCES;
936
937                         if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
938                                 /* NetWare seems not to allow this. I
939                                    do not know why. So, just tell the
940                                    user everything went fine. This is
941                                    a terrible hack, but I do not know
942                                    how to do this correctly. */
943                                 result = 0;
944                         } else
945                                 goto out;
946                 }
947 #ifdef CONFIG_NCPFS_STRONG              
948                 if ((!result) && (info_mask & DM_ATTRIBUTES))
949                         NCP_FINFO(inode)->nwattr = info.attributes;
950 #endif
951         }
952         if (!result)
953                 result = inode_setattr(inode, attr);
954 out:
955         unlock_kernel();
956         return result;
957 }
958
959 #ifdef DEBUG_NCP_MALLOC
960 int ncp_malloced;
961 int ncp_current_malloced;
962 #endif
963
964 static struct super_block *ncp_get_sb(struct file_system_type *fs_type,
965         int flags, const char *dev_name, void *data)
966 {
967         return get_sb_nodev(fs_type, flags, data, ncp_fill_super);
968 }
969
970 static struct file_system_type ncp_fs_type = {
971         .owner          = THIS_MODULE,
972         .name           = "ncpfs",
973         .get_sb         = ncp_get_sb,
974         .kill_sb        = kill_anon_super,
975 };
976
977 static int __init init_ncp_fs(void)
978 {
979         int err;
980         DPRINTK("ncpfs: init_module called\n");
981
982 #ifdef DEBUG_NCP_MALLOC
983         ncp_malloced = 0;
984         ncp_current_malloced = 0;
985 #endif
986         err = init_inodecache();
987         if (err)
988                 goto out1;
989         err = register_filesystem(&ncp_fs_type);
990         if (err)
991                 goto out;
992         return 0;
993 out:
994         destroy_inodecache();
995 out1:
996         return err;
997 }
998
999 static void __exit exit_ncp_fs(void)
1000 {
1001         DPRINTK("ncpfs: cleanup_module called\n");
1002         unregister_filesystem(&ncp_fs_type);
1003         destroy_inodecache();
1004 #ifdef DEBUG_NCP_MALLOC
1005         PRINTK("ncp_malloced: %d\n", ncp_malloced);
1006         PRINTK("ncp_current_malloced: %d\n", ncp_current_malloced);
1007 #endif
1008 }
1009
1010 module_init(init_ncp_fs)
1011 module_exit(exit_ncp_fs)
1012 MODULE_LICENSE("GPL");