Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394...
[linux-2.6] / fs / ncpfs / inode.c
1 /*
2  *  inode.c
3  *
4  *  Copyright (C) 1995, 1996 by Volker Lendecke
5  *  Modified for big endian by J.F. Chadima and David S. Miller
6  *  Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
7  *  Modified 1998 Wolfram Pienkoss for NLS
8  *  Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
9  *
10  */
11
12 #include <linux/module.h>
13
14 #include <asm/system.h>
15 #include <asm/uaccess.h>
16 #include <asm/byteorder.h>
17
18 #include <linux/time.h>
19 #include <linux/kernel.h>
20 #include <linux/mm.h>
21 #include <linux/string.h>
22 #include <linux/stat.h>
23 #include <linux/errno.h>
24 #include <linux/file.h>
25 #include <linux/fcntl.h>
26 #include <linux/slab.h>
27 #include <linux/vmalloc.h>
28 #include <linux/init.h>
29 #include <linux/smp_lock.h>
30 #include <linux/vfs.h>
31
32 #include <linux/ncp_fs.h>
33
34 #include <net/sock.h>
35
36 #include "ncplib_kernel.h"
37 #include "getopt.h"
38
39 static void ncp_delete_inode(struct inode *);
40 static void ncp_put_super(struct super_block *);
41 static int  ncp_statfs(struct dentry *, struct kstatfs *);
42
43 static struct kmem_cache * ncp_inode_cachep;
44
45 static struct inode *ncp_alloc_inode(struct super_block *sb)
46 {
47         struct ncp_inode_info *ei;
48         ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, GFP_KERNEL);
49         if (!ei)
50                 return NULL;
51         return &ei->vfs_inode;
52 }
53
54 static void ncp_destroy_inode(struct inode *inode)
55 {
56         kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
57 }
58
59 static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
60 {
61         struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
62
63         mutex_init(&ei->open_mutex);
64         inode_init_once(&ei->vfs_inode);
65 }
66  
67 static int init_inodecache(void)
68 {
69         ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
70                                              sizeof(struct ncp_inode_info),
71                                              0, (SLAB_RECLAIM_ACCOUNT|
72                                                 SLAB_MEM_SPREAD),
73                                              init_once, NULL);
74         if (ncp_inode_cachep == NULL)
75                 return -ENOMEM;
76         return 0;
77 }
78
79 static void destroy_inodecache(void)
80 {
81         kmem_cache_destroy(ncp_inode_cachep);
82 }
83
84 static int ncp_remount(struct super_block *sb, int *flags, char* data)
85 {
86         *flags |= MS_NODIRATIME;
87         return 0;
88 }
89
90 static const struct super_operations ncp_sops =
91 {
92         .alloc_inode    = ncp_alloc_inode,
93         .destroy_inode  = ncp_destroy_inode,
94         .drop_inode     = generic_delete_inode,
95         .delete_inode   = ncp_delete_inode,
96         .put_super      = ncp_put_super,
97         .statfs         = ncp_statfs,
98         .remount_fs     = ncp_remount,
99 };
100
101 extern struct dentry_operations ncp_root_dentry_operations;
102 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
103 extern const struct address_space_operations ncp_symlink_aops;
104 extern int ncp_symlink(struct inode*, struct dentry*, const char*);
105 #endif
106
107 /*
108  * Fill in the ncpfs-specific information in the inode.
109  */
110 static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
111 {
112         NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
113         NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
114         NCP_FINFO(inode)->volNumber = nwinfo->volume;
115 }
116
117 void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
118 {
119         ncp_update_dirent(inode, nwinfo);
120         NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
121         NCP_FINFO(inode)->access = nwinfo->access;
122         memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
123                         sizeof(nwinfo->file_handle));
124         DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
125                 nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
126                 NCP_FINFO(inode)->dirEntNum);
127 }
128
129 static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
130 {
131         /* NFS namespace mode overrides others if it's set. */
132         DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n",
133                 nwi->entryName, nwi->nfs.mode);
134         if (nwi->nfs.mode) {
135                 /* XXX Security? */
136                 inode->i_mode = nwi->nfs.mode;
137         }
138
139         inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
140
141         inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate);
142         inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate);
143         inode->i_atime.tv_sec = ncp_date_dos2unix(0, nwi->lastAccessDate);
144         inode->i_atime.tv_nsec = 0;
145         inode->i_mtime.tv_nsec = 0;
146         inode->i_ctime.tv_nsec = 0;
147 }
148
149 static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
150 {
151         struct nw_info_struct *nwi = &nwinfo->i;
152         struct ncp_server *server = NCP_SERVER(inode);
153
154         if (nwi->attributes & aDIR) {
155                 inode->i_mode = server->m.dir_mode;
156                 /* for directories dataStreamSize seems to be some
157                    Object ID ??? */
158                 inode->i_size = NCP_BLOCK_SIZE;
159         } else {
160                 inode->i_mode = server->m.file_mode;
161                 inode->i_size = le32_to_cpu(nwi->dataStreamSize);
162 #ifdef CONFIG_NCPFS_EXTRAS
163                 if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS)) 
164                  && (nwi->attributes & aSHARED)) {
165                         switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
166                                 case aHIDDEN:
167                                         if (server->m.flags & NCP_MOUNT_SYMLINKS) {
168                                                 if (/* (inode->i_size >= NCP_MIN_SYMLINK_SIZE)
169                                                  && */ (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) {
170                                                         inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
171                                                         NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
172                                                         break;
173                                                 }
174                                         }
175                                         /* FALLTHROUGH */
176                                 case 0:
177                                         if (server->m.flags & NCP_MOUNT_EXTRAS)
178                                                 inode->i_mode |= S_IRUGO;
179                                         break;
180                                 case aSYSTEM:
181                                         if (server->m.flags & NCP_MOUNT_EXTRAS)
182                                                 inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO;
183                                         break;
184                                 /* case aSYSTEM|aHIDDEN: */
185                                 default:
186                                         /* reserved combination */
187                                         break;
188                         }
189                 }
190 #endif
191         }
192         if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
193 }
194
195 void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
196 {
197         NCP_FINFO(inode)->flags = 0;
198         if (!atomic_read(&NCP_FINFO(inode)->opened)) {
199                 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
200                 ncp_update_attrs(inode, nwinfo);
201         }
202
203         ncp_update_dates(inode, &nwinfo->i);
204         ncp_update_dirent(inode, nwinfo);
205 }
206
207 /*
208  * Fill in the inode based on the ncp_entry_info structure.
209  */
210 static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
211 {
212         struct ncp_server *server = NCP_SERVER(inode);
213
214         NCP_FINFO(inode)->flags = 0;
215         
216         ncp_update_attrs(inode, nwinfo);
217
218         DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
219
220         inode->i_nlink = 1;
221         inode->i_uid = server->m.uid;
222         inode->i_gid = server->m.gid;
223
224         ncp_update_dates(inode, &nwinfo->i);
225         ncp_update_inode(inode, nwinfo);
226 }
227
228 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
229 static const struct inode_operations ncp_symlink_inode_operations = {
230         .readlink       = generic_readlink,
231         .follow_link    = page_follow_link_light,
232         .put_link       = page_put_link,
233         .setattr        = ncp_notify_change,
234 };
235 #endif
236
237 /*
238  * Get a new inode.
239  */
240 struct inode * 
241 ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
242 {
243         struct inode *inode;
244
245         if (info == NULL) {
246                 printk(KERN_ERR "ncp_iget: info is NULL\n");
247                 return NULL;
248         }
249
250         inode = new_inode(sb);
251         if (inode) {
252                 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
253
254                 inode->i_ino = info->ino;
255                 ncp_set_attr(inode, info);
256                 if (S_ISREG(inode->i_mode)) {
257                         inode->i_op = &ncp_file_inode_operations;
258                         inode->i_fop = &ncp_file_operations;
259                 } else if (S_ISDIR(inode->i_mode)) {
260                         inode->i_op = &ncp_dir_inode_operations;
261                         inode->i_fop = &ncp_dir_operations;
262 #ifdef CONFIG_NCPFS_NFS_NS
263                 } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
264                         init_special_inode(inode, inode->i_mode,
265                                 new_decode_dev(info->i.nfs.rdev));
266 #endif
267 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
268                 } else if (S_ISLNK(inode->i_mode)) {
269                         inode->i_op = &ncp_symlink_inode_operations;
270                         inode->i_data.a_ops = &ncp_symlink_aops;
271 #endif
272                 } else {
273                         make_bad_inode(inode);
274                 }
275                 insert_inode_hash(inode);
276         } else
277                 printk(KERN_ERR "ncp_iget: iget failed!\n");
278         return inode;
279 }
280
281 static void
282 ncp_delete_inode(struct inode *inode)
283 {
284         truncate_inode_pages(&inode->i_data, 0);
285
286         if (S_ISDIR(inode->i_mode)) {
287                 DDPRINTK("ncp_delete_inode: put directory %ld\n", inode->i_ino);
288         }
289
290         if (ncp_make_closed(inode) != 0) {
291                 /* We can't do anything but complain. */
292                 printk(KERN_ERR "ncp_delete_inode: could not close\n");
293         }
294         clear_inode(inode);
295 }
296
297 static void ncp_stop_tasks(struct ncp_server *server) {
298         struct sock* sk = server->ncp_sock->sk;
299                 
300         sk->sk_error_report = server->error_report;
301         sk->sk_data_ready   = server->data_ready;
302         sk->sk_write_space  = server->write_space;
303         del_timer_sync(&server->timeout_tm);
304         flush_scheduled_work();
305 }
306
307 static const struct ncp_option ncp_opts[] = {
308         { "uid",        OPT_INT,        'u' },
309         { "gid",        OPT_INT,        'g' },
310         { "owner",      OPT_INT,        'o' },
311         { "mode",       OPT_INT,        'm' },
312         { "dirmode",    OPT_INT,        'd' },
313         { "timeout",    OPT_INT,        't' },
314         { "retry",      OPT_INT,        'r' },
315         { "flags",      OPT_INT,        'f' },
316         { "wdogpid",    OPT_INT,        'w' },
317         { "ncpfd",      OPT_INT,        'n' },
318         { "infofd",     OPT_INT,        'i' },  /* v5 */
319         { "version",    OPT_INT,        'v' },
320         { NULL,         0,              0 } };
321
322 static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
323         int optval;
324         char *optarg;
325         unsigned long optint;
326         int version = 0;
327         int ret;
328
329         data->flags = 0;
330         data->int_flags = 0;
331         data->mounted_uid = 0;
332         data->wdog_pid = NULL;
333         data->ncp_fd = ~0;
334         data->time_out = 10;
335         data->retry_count = 20;
336         data->uid = 0;
337         data->gid = 0;
338         data->file_mode = 0600;
339         data->dir_mode = 0700;
340         data->info_fd = -1;
341         data->mounted_vol[0] = 0;
342         
343         while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
344                 ret = optval;
345                 if (ret < 0)
346                         goto err;
347                 switch (optval) {
348                         case 'u':
349                                 data->uid = optint;
350                                 break;
351                         case 'g':
352                                 data->gid = optint;
353                                 break;
354                         case 'o':
355                                 data->mounted_uid = optint;
356                                 break;
357                         case 'm':
358                                 data->file_mode = optint;
359                                 break;
360                         case 'd':
361                                 data->dir_mode = optint;
362                                 break;
363                         case 't':
364                                 data->time_out = optint;
365                                 break;
366                         case 'r':
367                                 data->retry_count = optint;
368                                 break;
369                         case 'f':
370                                 data->flags = optint;
371                                 break;
372                         case 'w':
373                                 data->wdog_pid = find_get_pid(optint);
374                                 break;
375                         case 'n':
376                                 data->ncp_fd = optint;
377                                 break;
378                         case 'i':
379                                 data->info_fd = optint;
380                                 break;
381                         case 'v':
382                                 ret = -ECHRNG;
383                                 if (optint < NCP_MOUNT_VERSION_V4)
384                                         goto err;
385                                 if (optint > NCP_MOUNT_VERSION_V5)
386                                         goto err;
387                                 version = optint;
388                                 break;
389                         
390                 }
391         }
392         return 0;
393 err:
394         put_pid(data->wdog_pid);
395         data->wdog_pid = NULL;
396         return ret;
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         data.wdog_pid = NULL;
415         server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
416         if (!server)
417                 return -ENOMEM;
418         sb->s_fs_info = 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 = find_get_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 = find_get_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 (memcmp(raw_data, "vers", 4) == 0) {
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_path.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_path.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         mutex_init(&server->mutex);
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         mutex_init(&server->rcv.creq_mutex);
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         server->txbuf = vmalloc(NCP_PACKET_SIZE);
577         if (server->txbuf == NULL)
578                 goto out_packet;
579         server->rxbuf = vmalloc(NCP_PACKET_SIZE);
580         if (server->rxbuf == NULL)
581                 goto out_txbuf;
582
583         sock->sk->sk_data_ready   = ncp_tcp_data_ready;
584         sock->sk->sk_error_report = ncp_tcp_error_report;
585         if (sock->type == SOCK_STREAM) {
586                 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
587                 server->rcv.len = 10;
588                 server->rcv.state = 0;
589                 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
590                 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
591                 sock->sk->sk_write_space = ncp_tcp_write_space;
592         } else {
593                 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
594                 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
595                 server->timeout_tm.data = (unsigned long)server;
596                 server->timeout_tm.function = ncpdgram_timeout_call;
597         }
598
599         ncp_lock_server(server);
600         error = ncp_connect(server);
601         ncp_unlock_server(server);
602         if (error < 0)
603                 goto out_rxbuf;
604         DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
605
606         error = -EMSGSIZE;      /* -EREMOTESIDEINCOMPATIBLE */
607 #ifdef CONFIG_NCPFS_PACKET_SIGNING
608         if (ncp_negotiate_size_and_options(server, default_bufsize,
609                 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
610         {
611                 if (options != NCP_DEFAULT_OPTIONS)
612                 {
613                         if (ncp_negotiate_size_and_options(server, 
614                                 default_bufsize,
615                                 options & 2, 
616                                 &(server->buffer_size), &options) != 0)
617                                 
618                         {
619                                 goto out_disconnect;
620                         }
621                 }
622                 if (options & 2)
623                         server->sign_wanted = 1;
624         }
625         else 
626 #endif  /* CONFIG_NCPFS_PACKET_SIGNING */
627         if (ncp_negotiate_buffersize(server, default_bufsize,
628                                      &(server->buffer_size)) != 0)
629                 goto out_disconnect;
630         DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
631
632         memset(&finfo, 0, sizeof(finfo));
633         finfo.i.attributes      = aDIR;
634         finfo.i.dataStreamSize  = 0;    /* ignored */
635         finfo.i.dirEntNum       = 0;
636         finfo.i.DosDirNum       = 0;
637 #ifdef CONFIG_NCPFS_SMALLDOS
638         finfo.i.NSCreator       = NW_NS_DOS;
639 #endif
640         finfo.volume            = NCP_NUMBER_OF_VOLUMES;
641         /* set dates of mountpoint to Jan 1, 1986; 00:00 */
642         finfo.i.creationTime    = finfo.i.modifyTime
643                                 = cpu_to_le16(0x0000);
644         finfo.i.creationDate    = finfo.i.modifyDate
645                                 = finfo.i.lastAccessDate
646                                 = cpu_to_le16(0x0C21);
647         finfo.i.nameLen         = 0;
648         finfo.i.entryName[0]    = '\0';
649
650         finfo.opened            = 0;
651         finfo.ino               = 2;    /* tradition */
652
653         server->name_space[finfo.volume] = NW_NS_DOS;
654
655         error = -ENOMEM;
656         root_inode = ncp_iget(sb, &finfo);
657         if (!root_inode)
658                 goto out_disconnect;
659         DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
660         sb->s_root = d_alloc_root(root_inode);
661         if (!sb->s_root)
662                 goto out_no_root;
663         sb->s_root->d_op = &ncp_root_dentry_operations;
664         return 0;
665
666 out_no_root:
667         iput(root_inode);
668 out_disconnect:
669         ncp_lock_server(server);
670         ncp_disconnect(server);
671         ncp_unlock_server(server);
672 out_rxbuf:
673         ncp_stop_tasks(server);
674         vfree(server->rxbuf);
675 out_txbuf:
676         vfree(server->txbuf);
677 out_packet:
678         vfree(server->packet);
679 out_nls:
680 #ifdef CONFIG_NCPFS_NLS
681         unload_nls(server->nls_io);
682         unload_nls(server->nls_vol);
683 #endif
684 out_fput2:
685         if (server->info_filp)
686                 fput(server->info_filp);
687 out_fput:
688         /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
689          * 
690          * The previously used put_filp(ncp_filp); was bogous, since
691          * it doesn't proper unlocking.
692          */
693         fput(ncp_filp);
694 out:
695         put_pid(data.wdog_pid);
696         sb->s_fs_info = NULL;
697         kfree(server);
698         return error;
699 }
700
701 static void ncp_put_super(struct super_block *sb)
702 {
703         struct ncp_server *server = NCP_SBP(sb);
704
705         ncp_lock_server(server);
706         ncp_disconnect(server);
707         ncp_unlock_server(server);
708
709         ncp_stop_tasks(server);
710
711 #ifdef CONFIG_NCPFS_NLS
712         /* unload the NLS charsets */
713         if (server->nls_vol)
714         {
715                 unload_nls(server->nls_vol);
716                 server->nls_vol = NULL;
717         }
718         if (server->nls_io)
719         {
720                 unload_nls(server->nls_io);
721                 server->nls_io = NULL;
722         }
723 #endif /* CONFIG_NCPFS_NLS */
724
725         if (server->info_filp)
726                 fput(server->info_filp);
727         fput(server->ncp_filp);
728         kill_pid(server->m.wdog_pid, SIGTERM, 1);
729         put_pid(server->m.wdog_pid);
730
731         kfree(server->priv.data);
732         kfree(server->auth.object_name);
733         vfree(server->rxbuf);
734         vfree(server->txbuf);
735         vfree(server->packet);
736         sb->s_fs_info = NULL;
737         kfree(server);
738 }
739
740 static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
741 {
742         struct dentry* d;
743         struct inode* i;
744         struct ncp_inode_info* ni;
745         struct ncp_server* s;
746         struct ncp_volume_info vi;
747         struct super_block *sb = dentry->d_sb;
748         int err;
749         __u8 dh;
750         
751         d = sb->s_root;
752         if (!d) {
753                 goto dflt;
754         }
755         i = d->d_inode;
756         if (!i) {
757                 goto dflt;
758         }
759         ni = NCP_FINFO(i);
760         if (!ni) {
761                 goto dflt;
762         }
763         s = NCP_SBP(sb);
764         if (!s) {
765                 goto dflt;
766         }
767         if (!s->m.mounted_vol[0]) {
768                 goto dflt;
769         }
770
771         err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
772         if (err) {
773                 goto dflt;
774         }
775         err = ncp_get_directory_info(s, dh, &vi);
776         ncp_dirhandle_free(s, dh);
777         if (err) {
778                 goto dflt;
779         }
780         buf->f_type = NCP_SUPER_MAGIC;
781         buf->f_bsize = vi.sectors_per_block * 512;
782         buf->f_blocks = vi.total_blocks;
783         buf->f_bfree = vi.free_blocks;
784         buf->f_bavail = vi.free_blocks;
785         buf->f_files = vi.total_dir_entries;
786         buf->f_ffree = vi.available_dir_entries;
787         buf->f_namelen = 12;
788         return 0;
789
790         /* We cannot say how much disk space is left on a mounted
791            NetWare Server, because free space is distributed over
792            volumes, and the current user might have disk quotas. So
793            free space is not that simple to determine. Our decision
794            here is to err conservatively. */
795
796 dflt:;
797         buf->f_type = NCP_SUPER_MAGIC;
798         buf->f_bsize = NCP_BLOCK_SIZE;
799         buf->f_blocks = 0;
800         buf->f_bfree = 0;
801         buf->f_bavail = 0;
802         buf->f_namelen = 12;
803         return 0;
804 }
805
806 int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
807 {
808         struct inode *inode = dentry->d_inode;
809         int result = 0;
810         __le32 info_mask;
811         struct nw_modify_dos_info info;
812         struct ncp_server *server;
813
814         result = -EIO;
815
816         lock_kernel();  
817
818         server = NCP_SERVER(inode);
819         if ((!server) || !ncp_conn_valid(server))
820                 goto out;
821
822         /* ageing the dentry to force validation */
823         ncp_age_dentry(server, dentry);
824
825         result = inode_change_ok(inode, attr);
826         if (result < 0)
827                 goto out;
828
829         result = -EPERM;
830         if (((attr->ia_valid & ATTR_UID) &&
831              (attr->ia_uid != server->m.uid)))
832                 goto out;
833
834         if (((attr->ia_valid & ATTR_GID) &&
835              (attr->ia_gid != server->m.gid)))
836                 goto out;
837
838         if (((attr->ia_valid & ATTR_MODE) &&
839              (attr->ia_mode &
840               ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
841                 goto out;
842
843         info_mask = 0;
844         memset(&info, 0, sizeof(info));
845
846 #if 1 
847         if ((attr->ia_valid & ATTR_MODE) != 0)
848         {
849                 umode_t newmode = attr->ia_mode;
850
851                 info_mask |= DM_ATTRIBUTES;
852
853                 if (S_ISDIR(inode->i_mode)) {
854                         newmode &= server->m.dir_mode;
855                 } else {
856 #ifdef CONFIG_NCPFS_EXTRAS                      
857                         if (server->m.flags & NCP_MOUNT_EXTRAS) {
858                                 /* any non-default execute bit set */
859                                 if (newmode & ~server->m.file_mode & S_IXUGO)
860                                         info.attributes |= aSHARED | aSYSTEM;
861                                 /* read for group/world and not in default file_mode */
862                                 else if (newmode & ~server->m.file_mode & S_IRUGO)
863                                         info.attributes |= aSHARED;
864                         } else
865 #endif
866                                 newmode &= server->m.file_mode;                 
867                 }
868                 if (newmode & S_IWUGO)
869                         info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
870                 else
871                         info.attributes |=  (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
872
873 #ifdef CONFIG_NCPFS_NFS_NS
874                 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
875                         result = ncp_modify_nfs_info(server,
876                                                      NCP_FINFO(inode)->volNumber,
877                                                      NCP_FINFO(inode)->dirEntNum,
878                                                      attr->ia_mode, 0);
879                         if (result != 0)
880                                 goto out;
881                         info.attributes &= ~(aSHARED | aSYSTEM);
882                         {
883                                 /* mark partial success */
884                                 struct iattr tmpattr;
885                                 
886                                 tmpattr.ia_valid = ATTR_MODE;
887                                 tmpattr.ia_mode = attr->ia_mode;
888
889                                 result = inode_setattr(inode, &tmpattr);
890                                 if (result)
891                                         goto out;
892                         }
893                 }
894 #endif
895         }
896 #endif
897
898         /* Do SIZE before attributes, otherwise mtime together with size does not work...
899          */
900         if ((attr->ia_valid & ATTR_SIZE) != 0) {
901                 int written;
902
903                 DPRINTK("ncpfs: trying to change size to %ld\n",
904                         attr->ia_size);
905
906                 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
907                         result = -EACCES;
908                         goto out;
909                 }
910                 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
911                           attr->ia_size, 0, "", &written);
912
913                 /* According to ndir, the changes only take effect after
914                    closing the file */
915                 ncp_inode_close(inode);
916                 result = ncp_make_closed(inode);
917                 if (result)
918                         goto out;
919                 {
920                         struct iattr tmpattr;
921                         
922                         tmpattr.ia_valid = ATTR_SIZE;
923                         tmpattr.ia_size = attr->ia_size;
924                         
925                         result = inode_setattr(inode, &tmpattr);
926                         if (result)
927                                 goto out;
928                 }
929         }
930         if ((attr->ia_valid & ATTR_CTIME) != 0) {
931                 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
932                 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
933                              &info.creationTime, &info.creationDate);
934         }
935         if ((attr->ia_valid & ATTR_MTIME) != 0) {
936                 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
937                 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
938                                   &info.modifyTime, &info.modifyDate);
939         }
940         if ((attr->ia_valid & ATTR_ATIME) != 0) {
941                 __le16 dummy;
942                 info_mask |= (DM_LAST_ACCESS_DATE);
943                 ncp_date_unix2dos(attr->ia_atime.tv_sec,
944                                   &dummy, &info.lastAccessDate);
945         }
946         if (info_mask != 0) {
947                 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
948                                       inode, info_mask, &info);
949                 if (result != 0) {
950                         result = -EACCES;
951
952                         if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
953                                 /* NetWare seems not to allow this. I
954                                    do not know why. So, just tell the
955                                    user everything went fine. This is
956                                    a terrible hack, but I do not know
957                                    how to do this correctly. */
958                                 result = 0;
959                         } else
960                                 goto out;
961                 }
962 #ifdef CONFIG_NCPFS_STRONG              
963                 if ((!result) && (info_mask & DM_ATTRIBUTES))
964                         NCP_FINFO(inode)->nwattr = info.attributes;
965 #endif
966         }
967         if (!result)
968                 result = inode_setattr(inode, attr);
969 out:
970         unlock_kernel();
971         return result;
972 }
973
974 static int ncp_get_sb(struct file_system_type *fs_type,
975         int flags, const char *dev_name, void *data, struct vfsmount *mnt)
976 {
977         return get_sb_nodev(fs_type, flags, data, ncp_fill_super, mnt);
978 }
979
980 static struct file_system_type ncp_fs_type = {
981         .owner          = THIS_MODULE,
982         .name           = "ncpfs",
983         .get_sb         = ncp_get_sb,
984         .kill_sb        = kill_anon_super,
985 };
986
987 static int __init init_ncp_fs(void)
988 {
989         int err;
990         DPRINTK("ncpfs: init_module called\n");
991
992         err = init_inodecache();
993         if (err)
994                 goto out1;
995         err = register_filesystem(&ncp_fs_type);
996         if (err)
997                 goto out;
998         return 0;
999 out:
1000         destroy_inodecache();
1001 out1:
1002         return err;
1003 }
1004
1005 static void __exit exit_ncp_fs(void)
1006 {
1007         DPRINTK("ncpfs: cleanup_module called\n");
1008         unregister_filesystem(&ncp_fs_type);
1009         destroy_inodecache();
1010 }
1011
1012 module_init(init_ncp_fs)
1013 module_exit(exit_ncp_fs)
1014 MODULE_LICENSE("GPL");