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