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