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