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