]> git.karo-electronics.de Git - mv-sheeva.git/blob - fs/ncpfs/inode.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi...
[mv-sheeva.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
530         server = NCP_SBP(sb);
531         memset(server, 0, sizeof(*server));
532
533         server->ncp_filp = ncp_filp;
534         server->ncp_sock = sock;
535         
536         if (data.info_fd != -1) {
537                 struct socket *info_sock;
538
539                 error = -EBADF;
540                 server->info_filp = fget(data.info_fd);
541                 if (!server->info_filp)
542                         goto out_fput;
543                 error = -ENOTSOCK;
544                 sock_inode = server->info_filp->f_path.dentry->d_inode;
545                 if (!S_ISSOCK(sock_inode->i_mode))
546                         goto out_fput2;
547                 info_sock = SOCKET_I(sock_inode);
548                 if (!info_sock)
549                         goto out_fput2;
550                 error = -EBADFD;
551                 if (info_sock->type != SOCK_STREAM)
552                         goto out_fput2;
553                 server->info_sock = info_sock;
554         }
555
556 /*      server->lock = 0;       */
557         mutex_init(&server->mutex);
558         server->packet = NULL;
559 /*      server->buffer_size = 0;        */
560 /*      server->conn_status = 0;        */
561 /*      server->root_dentry = NULL;     */
562 /*      server->root_setuped = 0;       */
563 #ifdef CONFIG_NCPFS_PACKET_SIGNING
564 /*      server->sign_wanted = 0;        */
565 /*      server->sign_active = 0;        */
566 #endif
567         server->auth.auth_type = NCP_AUTH_NONE;
568 /*      server->auth.object_name_len = 0;       */
569 /*      server->auth.object_name = NULL;        */
570 /*      server->auth.object_type = 0;           */
571 /*      server->priv.len = 0;                   */
572 /*      server->priv.data = NULL;               */
573
574         server->m = data;
575         /* Althought anything producing this is buggy, it happens
576            now because of PATH_MAX changes.. */
577         if (server->m.time_out < 1) {
578                 server->m.time_out = 10;
579                 printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
580         }
581         server->m.time_out = server->m.time_out * HZ / 100;
582         server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
583         server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
584
585 #ifdef CONFIG_NCPFS_NLS
586         /* load the default NLS charsets */
587         server->nls_vol = load_nls_default();
588         server->nls_io = load_nls_default();
589 #endif /* CONFIG_NCPFS_NLS */
590
591         server->dentry_ttl = 0; /* no caching */
592
593         INIT_LIST_HEAD(&server->tx.requests);
594         mutex_init(&server->rcv.creq_mutex);
595         server->tx.creq         = NULL;
596         server->rcv.creq        = NULL;
597         server->data_ready      = sock->sk->sk_data_ready;
598         server->write_space     = sock->sk->sk_write_space;
599         server->error_report    = sock->sk->sk_error_report;
600         sock->sk->sk_user_data  = server;
601
602         init_timer(&server->timeout_tm);
603 #undef NCP_PACKET_SIZE
604 #define NCP_PACKET_SIZE 131072
605         error = -ENOMEM;
606         server->packet_size = NCP_PACKET_SIZE;
607         server->packet = vmalloc(NCP_PACKET_SIZE);
608         if (server->packet == NULL)
609                 goto out_nls;
610         server->txbuf = vmalloc(NCP_PACKET_SIZE);
611         if (server->txbuf == NULL)
612                 goto out_packet;
613         server->rxbuf = vmalloc(NCP_PACKET_SIZE);
614         if (server->rxbuf == NULL)
615                 goto out_txbuf;
616
617         sock->sk->sk_data_ready   = ncp_tcp_data_ready;
618         sock->sk->sk_error_report = ncp_tcp_error_report;
619         if (sock->type == SOCK_STREAM) {
620                 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
621                 server->rcv.len = 10;
622                 server->rcv.state = 0;
623                 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
624                 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
625                 sock->sk->sk_write_space = ncp_tcp_write_space;
626         } else {
627                 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
628                 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
629                 server->timeout_tm.data = (unsigned long)server;
630                 server->timeout_tm.function = ncpdgram_timeout_call;
631         }
632
633         ncp_lock_server(server);
634         error = ncp_connect(server);
635         ncp_unlock_server(server);
636         if (error < 0)
637                 goto out_rxbuf;
638         DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
639
640         error = -EMSGSIZE;      /* -EREMOTESIDEINCOMPATIBLE */
641 #ifdef CONFIG_NCPFS_PACKET_SIGNING
642         if (ncp_negotiate_size_and_options(server, default_bufsize,
643                 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
644         {
645                 if (options != NCP_DEFAULT_OPTIONS)
646                 {
647                         if (ncp_negotiate_size_and_options(server, 
648                                 default_bufsize,
649                                 options & 2, 
650                                 &(server->buffer_size), &options) != 0)
651                                 
652                         {
653                                 goto out_disconnect;
654                         }
655                 }
656                 if (options & 2)
657                         server->sign_wanted = 1;
658         }
659         else 
660 #endif  /* CONFIG_NCPFS_PACKET_SIGNING */
661         if (ncp_negotiate_buffersize(server, default_bufsize,
662                                      &(server->buffer_size)) != 0)
663                 goto out_disconnect;
664         DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
665
666         memset(&finfo, 0, sizeof(finfo));
667         finfo.i.attributes      = aDIR;
668         finfo.i.dataStreamSize  = 0;    /* ignored */
669         finfo.i.dirEntNum       = 0;
670         finfo.i.DosDirNum       = 0;
671 #ifdef CONFIG_NCPFS_SMALLDOS
672         finfo.i.NSCreator       = NW_NS_DOS;
673 #endif
674         finfo.volume            = NCP_NUMBER_OF_VOLUMES;
675         /* set dates of mountpoint to Jan 1, 1986; 00:00 */
676         finfo.i.creationTime    = finfo.i.modifyTime
677                                 = cpu_to_le16(0x0000);
678         finfo.i.creationDate    = finfo.i.modifyDate
679                                 = finfo.i.lastAccessDate
680                                 = cpu_to_le16(0x0C21);
681         finfo.i.nameLen         = 0;
682         finfo.i.entryName[0]    = '\0';
683
684         finfo.opened            = 0;
685         finfo.ino               = 2;    /* tradition */
686
687         server->name_space[finfo.volume] = NW_NS_DOS;
688
689         error = -ENOMEM;
690         root_inode = ncp_iget(sb, &finfo);
691         if (!root_inode)
692                 goto out_disconnect;
693         DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
694         sb->s_root = d_alloc_root(root_inode);
695         if (!sb->s_root)
696                 goto out_no_root;
697         sb->s_root->d_op = &ncp_root_dentry_operations;
698         return 0;
699
700 out_no_root:
701         iput(root_inode);
702 out_disconnect:
703         ncp_lock_server(server);
704         ncp_disconnect(server);
705         ncp_unlock_server(server);
706 out_rxbuf:
707         ncp_stop_tasks(server);
708         vfree(server->rxbuf);
709 out_txbuf:
710         vfree(server->txbuf);
711 out_packet:
712         vfree(server->packet);
713 out_nls:
714 #ifdef CONFIG_NCPFS_NLS
715         unload_nls(server->nls_io);
716         unload_nls(server->nls_vol);
717 #endif
718 out_fput2:
719         if (server->info_filp)
720                 fput(server->info_filp);
721 out_fput:
722         /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
723          * 
724          * The previously used put_filp(ncp_filp); was bogous, since
725          * it doesn't proper unlocking.
726          */
727         fput(ncp_filp);
728 out:
729         put_pid(data.wdog_pid);
730         sb->s_fs_info = NULL;
731         kfree(server);
732         return error;
733 }
734
735 static void ncp_put_super(struct super_block *sb)
736 {
737         struct ncp_server *server = NCP_SBP(sb);
738
739         ncp_lock_server(server);
740         ncp_disconnect(server);
741         ncp_unlock_server(server);
742
743         ncp_stop_tasks(server);
744
745 #ifdef CONFIG_NCPFS_NLS
746         /* unload the NLS charsets */
747         if (server->nls_vol)
748         {
749                 unload_nls(server->nls_vol);
750                 server->nls_vol = NULL;
751         }
752         if (server->nls_io)
753         {
754                 unload_nls(server->nls_io);
755                 server->nls_io = NULL;
756         }
757 #endif /* CONFIG_NCPFS_NLS */
758
759         if (server->info_filp)
760                 fput(server->info_filp);
761         fput(server->ncp_filp);
762         kill_pid(server->m.wdog_pid, SIGTERM, 1);
763         put_pid(server->m.wdog_pid);
764
765         kfree(server->priv.data);
766         kfree(server->auth.object_name);
767         vfree(server->rxbuf);
768         vfree(server->txbuf);
769         vfree(server->packet);
770         sb->s_fs_info = NULL;
771         kfree(server);
772 }
773
774 static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
775 {
776         struct dentry* d;
777         struct inode* i;
778         struct ncp_inode_info* ni;
779         struct ncp_server* s;
780         struct ncp_volume_info vi;
781         struct super_block *sb = dentry->d_sb;
782         int err;
783         __u8 dh;
784         
785         d = sb->s_root;
786         if (!d) {
787                 goto dflt;
788         }
789         i = d->d_inode;
790         if (!i) {
791                 goto dflt;
792         }
793         ni = NCP_FINFO(i);
794         if (!ni) {
795                 goto dflt;
796         }
797         s = NCP_SBP(sb);
798         if (!s) {
799                 goto dflt;
800         }
801         if (!s->m.mounted_vol[0]) {
802                 goto dflt;
803         }
804
805         err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
806         if (err) {
807                 goto dflt;
808         }
809         err = ncp_get_directory_info(s, dh, &vi);
810         ncp_dirhandle_free(s, dh);
811         if (err) {
812                 goto dflt;
813         }
814         buf->f_type = NCP_SUPER_MAGIC;
815         buf->f_bsize = vi.sectors_per_block * 512;
816         buf->f_blocks = vi.total_blocks;
817         buf->f_bfree = vi.free_blocks;
818         buf->f_bavail = vi.free_blocks;
819         buf->f_files = vi.total_dir_entries;
820         buf->f_ffree = vi.available_dir_entries;
821         buf->f_namelen = 12;
822         return 0;
823
824         /* We cannot say how much disk space is left on a mounted
825            NetWare Server, because free space is distributed over
826            volumes, and the current user might have disk quotas. So
827            free space is not that simple to determine. Our decision
828            here is to err conservatively. */
829
830 dflt:;
831         buf->f_type = NCP_SUPER_MAGIC;
832         buf->f_bsize = NCP_BLOCK_SIZE;
833         buf->f_blocks = 0;
834         buf->f_bfree = 0;
835         buf->f_bavail = 0;
836         buf->f_namelen = 12;
837         return 0;
838 }
839
840 int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
841 {
842         struct inode *inode = dentry->d_inode;
843         int result = 0;
844         __le32 info_mask;
845         struct nw_modify_dos_info info;
846         struct ncp_server *server;
847
848         result = -EIO;
849
850         lock_kernel();  
851
852         server = NCP_SERVER(inode);
853         if ((!server) || !ncp_conn_valid(server))
854                 goto out;
855
856         /* ageing the dentry to force validation */
857         ncp_age_dentry(server, dentry);
858
859         result = inode_change_ok(inode, attr);
860         if (result < 0)
861                 goto out;
862
863         result = -EPERM;
864         if (((attr->ia_valid & ATTR_UID) &&
865              (attr->ia_uid != server->m.uid)))
866                 goto out;
867
868         if (((attr->ia_valid & ATTR_GID) &&
869              (attr->ia_gid != server->m.gid)))
870                 goto out;
871
872         if (((attr->ia_valid & ATTR_MODE) &&
873              (attr->ia_mode &
874               ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
875                 goto out;
876
877         info_mask = 0;
878         memset(&info, 0, sizeof(info));
879
880 #if 1 
881         if ((attr->ia_valid & ATTR_MODE) != 0)
882         {
883                 umode_t newmode = attr->ia_mode;
884
885                 info_mask |= DM_ATTRIBUTES;
886
887                 if (S_ISDIR(inode->i_mode)) {
888                         newmode &= server->m.dir_mode;
889                 } else {
890 #ifdef CONFIG_NCPFS_EXTRAS                      
891                         if (server->m.flags & NCP_MOUNT_EXTRAS) {
892                                 /* any non-default execute bit set */
893                                 if (newmode & ~server->m.file_mode & S_IXUGO)
894                                         info.attributes |= aSHARED | aSYSTEM;
895                                 /* read for group/world and not in default file_mode */
896                                 else if (newmode & ~server->m.file_mode & S_IRUGO)
897                                         info.attributes |= aSHARED;
898                         } else
899 #endif
900                                 newmode &= server->m.file_mode;                 
901                 }
902                 if (newmode & S_IWUGO)
903                         info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
904                 else
905                         info.attributes |=  (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
906
907 #ifdef CONFIG_NCPFS_NFS_NS
908                 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
909                         result = ncp_modify_nfs_info(server,
910                                                      NCP_FINFO(inode)->volNumber,
911                                                      NCP_FINFO(inode)->dirEntNum,
912                                                      attr->ia_mode, 0);
913                         if (result != 0)
914                                 goto out;
915                         info.attributes &= ~(aSHARED | aSYSTEM);
916                         {
917                                 /* mark partial success */
918                                 struct iattr tmpattr;
919                                 
920                                 tmpattr.ia_valid = ATTR_MODE;
921                                 tmpattr.ia_mode = attr->ia_mode;
922
923                                 result = inode_setattr(inode, &tmpattr);
924                                 if (result)
925                                         goto out;
926                         }
927                 }
928 #endif
929         }
930 #endif
931
932         /* Do SIZE before attributes, otherwise mtime together with size does not work...
933          */
934         if ((attr->ia_valid & ATTR_SIZE) != 0) {
935                 int written;
936
937                 DPRINTK("ncpfs: trying to change size to %ld\n",
938                         attr->ia_size);
939
940                 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
941                         result = -EACCES;
942                         goto out;
943                 }
944                 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
945                           attr->ia_size, 0, "", &written);
946
947                 /* According to ndir, the changes only take effect after
948                    closing the file */
949                 ncp_inode_close(inode);
950                 result = ncp_make_closed(inode);
951                 if (result)
952                         goto out;
953                 {
954                         struct iattr tmpattr;
955                         
956                         tmpattr.ia_valid = ATTR_SIZE;
957                         tmpattr.ia_size = attr->ia_size;
958                         
959                         result = inode_setattr(inode, &tmpattr);
960                         if (result)
961                                 goto out;
962                 }
963         }
964         if ((attr->ia_valid & ATTR_CTIME) != 0) {
965                 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
966                 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
967                              &info.creationTime, &info.creationDate);
968         }
969         if ((attr->ia_valid & ATTR_MTIME) != 0) {
970                 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
971                 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
972                                   &info.modifyTime, &info.modifyDate);
973         }
974         if ((attr->ia_valid & ATTR_ATIME) != 0) {
975                 __le16 dummy;
976                 info_mask |= (DM_LAST_ACCESS_DATE);
977                 ncp_date_unix2dos(attr->ia_atime.tv_sec,
978                                   &dummy, &info.lastAccessDate);
979         }
980         if (info_mask != 0) {
981                 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
982                                       inode, info_mask, &info);
983                 if (result != 0) {
984                         result = -EACCES;
985
986                         if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
987                                 /* NetWare seems not to allow this. I
988                                    do not know why. So, just tell the
989                                    user everything went fine. This is
990                                    a terrible hack, but I do not know
991                                    how to do this correctly. */
992                                 result = 0;
993                         } else
994                                 goto out;
995                 }
996 #ifdef CONFIG_NCPFS_STRONG              
997                 if ((!result) && (info_mask & DM_ATTRIBUTES))
998                         NCP_FINFO(inode)->nwattr = info.attributes;
999 #endif
1000         }
1001         if (!result)
1002                 result = inode_setattr(inode, attr);
1003 out:
1004         unlock_kernel();
1005         return result;
1006 }
1007
1008 static int ncp_get_sb(struct file_system_type *fs_type,
1009         int flags, const char *dev_name, void *data, struct vfsmount *mnt)
1010 {
1011         return get_sb_nodev(fs_type, flags, data, ncp_fill_super, mnt);
1012 }
1013
1014 static struct file_system_type ncp_fs_type = {
1015         .owner          = THIS_MODULE,
1016         .name           = "ncpfs",
1017         .get_sb         = ncp_get_sb,
1018         .kill_sb        = kill_anon_super,
1019         .fs_flags       = FS_BINARY_MOUNTDATA,
1020 };
1021
1022 static int __init init_ncp_fs(void)
1023 {
1024         int err;
1025         DPRINTK("ncpfs: init_ncp_fs called\n");
1026
1027         err = init_inodecache();
1028         if (err)
1029                 goto out1;
1030         err = register_filesystem(&ncp_fs_type);
1031         if (err)
1032                 goto out;
1033         return 0;
1034 out:
1035         destroy_inodecache();
1036 out1:
1037         return err;
1038 }
1039
1040 static void __exit exit_ncp_fs(void)
1041 {
1042         DPRINTK("ncpfs: exit_ncp_fs called\n");
1043         unregister_filesystem(&ncp_fs_type);
1044         destroy_inodecache();
1045 }
1046
1047 module_init(init_ncp_fs)
1048 module_exit(exit_ncp_fs)
1049 MODULE_LICENSE("GPL");