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