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