[PATCH] inode-diet: Eliminate i_blksize from the inode structure
[pandora-kernel.git] / fs / ncpfs / inode.c
1 /*
2  *  inode.c
3  *
4  *  Copyright (C) 1995, 1996 by Volker Lendecke
5  *  Modified for big endian by J.F. Chadima and David S. Miller
6  *  Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
7  *  Modified 1998 Wolfram Pienkoss for NLS
8  *  Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
9  *
10  */
11
12 #include <linux/module.h>
13
14 #include <asm/system.h>
15 #include <asm/uaccess.h>
16 #include <asm/byteorder.h>
17
18 #include <linux/time.h>
19 #include <linux/kernel.h>
20 #include <linux/mm.h>
21 #include <linux/string.h>
22 #include <linux/stat.h>
23 #include <linux/errno.h>
24 #include <linux/file.h>
25 #include <linux/fcntl.h>
26 #include <linux/slab.h>
27 #include <linux/vmalloc.h>
28 #include <linux/init.h>
29 #include <linux/smp_lock.h>
30 #include <linux/vfs.h>
31
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         kmem_cache_destroy(ncp_inode_cachep);
85 }
86
87 static int ncp_remount(struct super_block *sb, int *flags, char* data)
88 {
89         *flags |= MS_NODIRATIME;
90         return 0;
91 }
92
93 static struct super_operations ncp_sops =
94 {
95         .alloc_inode    = ncp_alloc_inode,
96         .destroy_inode  = ncp_destroy_inode,
97         .drop_inode     = generic_delete_inode,
98         .delete_inode   = ncp_delete_inode,
99         .put_super      = ncp_put_super,
100         .statfs         = ncp_statfs,
101         .remount_fs     = ncp_remount,
102 };
103
104 extern struct dentry_operations ncp_root_dentry_operations;
105 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
106 extern const struct address_space_operations ncp_symlink_aops;
107 extern int ncp_symlink(struct inode*, struct dentry*, const char*);
108 #endif
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 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 const struct ncp_option ncp_opts[] = {
311         { "uid",        OPT_INT,        'u' },
312         { "gid",        OPT_INT,        'g' },
313         { "owner",      OPT_INT,        'o' },
314         { "mode",       OPT_INT,        'm' },
315         { "dirmode",    OPT_INT,        'd' },
316         { "timeout",    OPT_INT,        't' },
317         { "retry",      OPT_INT,        'r' },
318         { "flags",      OPT_INT,        'f' },
319         { "wdogpid",    OPT_INT,        'w' },
320         { "ncpfd",      OPT_INT,        'n' },
321         { "infofd",     OPT_INT,        'i' },  /* v5 */
322         { "version",    OPT_INT,        'v' },
323         { NULL,         0,              0 } };
324
325 static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
326         int optval;
327         char *optarg;
328         unsigned long optint;
329         int version = 0;
330
331         data->flags = 0;
332         data->int_flags = 0;
333         data->mounted_uid = 0;
334         data->wdog_pid = -1;
335         data->ncp_fd = ~0;
336         data->time_out = 10;
337         data->retry_count = 20;
338         data->uid = 0;
339         data->gid = 0;
340         data->file_mode = 0600;
341         data->dir_mode = 0700;
342         data->info_fd = -1;
343         data->mounted_vol[0] = 0;
344         
345         while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
346                 if (optval < 0)
347                         return optval;
348                 switch (optval) {
349                         case 'u':
350                                 data->uid = optint;
351                                 break;
352                         case 'g':
353                                 data->gid = optint;
354                                 break;
355                         case 'o':
356                                 data->mounted_uid = optint;
357                                 break;
358                         case 'm':
359                                 data->file_mode = optint;
360                                 break;
361                         case 'd':
362                                 data->dir_mode = optint;
363                                 break;
364                         case 't':
365                                 data->time_out = optint;
366                                 break;
367                         case 'r':
368                                 data->retry_count = optint;
369                                 break;
370                         case 'f':
371                                 data->flags = optint;
372                                 break;
373                         case 'w':
374                                 data->wdog_pid = optint;
375                                 break;
376                         case 'n':
377                                 data->ncp_fd = optint;
378                                 break;
379                         case 'i':
380                                 data->info_fd = optint;
381                                 break;
382                         case 'v':
383                                 if (optint < NCP_MOUNT_VERSION_V4) {
384                                         return -ECHRNG;
385                                 }
386                                 if (optint > NCP_MOUNT_VERSION_V5) {
387                                         return -ECHRNG;
388                                 }
389                                 version = optint;
390                                 break;
391                         
392                 }
393         }
394         return 0;
395 }
396
397 static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
398 {
399         struct ncp_mount_data_kernel data;
400         struct ncp_server *server;
401         struct file *ncp_filp;
402         struct inode *root_inode;
403         struct inode *sock_inode;
404         struct socket *sock;
405         int error;
406         int default_bufsize;
407 #ifdef CONFIG_NCPFS_PACKET_SIGNING
408         int options;
409 #endif
410         struct ncp_entry_info finfo;
411
412         server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
413         if (!server)
414                 return -ENOMEM;
415         sb->s_fs_info = server;
416
417         error = -EFAULT;
418         if (raw_data == NULL)
419                 goto out;
420         switch (*(int*)raw_data) {
421                 case NCP_MOUNT_VERSION:
422                         {
423                                 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
424
425                                 data.flags = md->flags;
426                                 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
427                                 data.mounted_uid = md->mounted_uid;
428                                 data.wdog_pid = md->wdog_pid;
429                                 data.ncp_fd = md->ncp_fd;
430                                 data.time_out = md->time_out;
431                                 data.retry_count = md->retry_count;
432                                 data.uid = md->uid;
433                                 data.gid = md->gid;
434                                 data.file_mode = md->file_mode;
435                                 data.dir_mode = md->dir_mode;
436                                 data.info_fd = -1;
437                                 memcpy(data.mounted_vol, md->mounted_vol,
438                                         NCP_VOLNAME_LEN+1);
439                         }
440                         break;
441                 case NCP_MOUNT_VERSION_V4:
442                         {
443                                 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
444
445                                 data.flags = md->flags;
446                                 data.int_flags = 0;
447                                 data.mounted_uid = md->mounted_uid;
448                                 data.wdog_pid = md->wdog_pid;
449                                 data.ncp_fd = md->ncp_fd;
450                                 data.time_out = md->time_out;
451                                 data.retry_count = md->retry_count;
452                                 data.uid = md->uid;
453                                 data.gid = md->gid;
454                                 data.file_mode = md->file_mode;
455                                 data.dir_mode = md->dir_mode;
456                                 data.info_fd = -1;
457                                 data.mounted_vol[0] = 0;
458                         }
459                         break;
460                 default:
461                         error = -ECHRNG;
462                         if (memcmp(raw_data, "vers", 4) == 0) {
463                                 error = ncp_parse_options(&data, raw_data);
464                         }
465                         if (error)
466                                 goto out;
467                         break;
468         }
469         error = -EBADF;
470         ncp_filp = fget(data.ncp_fd);
471         if (!ncp_filp)
472                 goto out;
473         error = -ENOTSOCK;
474         sock_inode = ncp_filp->f_dentry->d_inode;
475         if (!S_ISSOCK(sock_inode->i_mode))
476                 goto out_fput;
477         sock = SOCKET_I(sock_inode);
478         if (!sock)
479                 goto out_fput;
480                 
481         if (sock->type == SOCK_STREAM)
482                 default_bufsize = 0xF000;
483         else
484                 default_bufsize = 1024;
485
486         sb->s_flags |= MS_NODIRATIME;   /* probably even noatime */
487         sb->s_maxbytes = 0xFFFFFFFFU;
488         sb->s_blocksize = 1024; /* Eh...  Is this correct? */
489         sb->s_blocksize_bits = 10;
490         sb->s_magic = NCP_SUPER_MAGIC;
491         sb->s_op = &ncp_sops;
492
493         server = NCP_SBP(sb);
494         memset(server, 0, sizeof(*server));
495
496         server->ncp_filp = ncp_filp;
497         server->ncp_sock = sock;
498         
499         if (data.info_fd != -1) {
500                 struct socket *info_sock;
501
502                 error = -EBADF;
503                 server->info_filp = fget(data.info_fd);
504                 if (!server->info_filp)
505                         goto out_fput;
506                 error = -ENOTSOCK;
507                 sock_inode = server->info_filp->f_dentry->d_inode;
508                 if (!S_ISSOCK(sock_inode->i_mode))
509                         goto out_fput2;
510                 info_sock = SOCKET_I(sock_inode);
511                 if (!info_sock)
512                         goto out_fput2;
513                 error = -EBADFD;
514                 if (info_sock->type != SOCK_STREAM)
515                         goto out_fput2;
516                 server->info_sock = info_sock;
517         }
518
519 /*      server->lock = 0;       */
520         mutex_init(&server->mutex);
521         server->packet = NULL;
522 /*      server->buffer_size = 0;        */
523 /*      server->conn_status = 0;        */
524 /*      server->root_dentry = NULL;     */
525 /*      server->root_setuped = 0;       */
526 #ifdef CONFIG_NCPFS_PACKET_SIGNING
527 /*      server->sign_wanted = 0;        */
528 /*      server->sign_active = 0;        */
529 #endif
530         server->auth.auth_type = NCP_AUTH_NONE;
531 /*      server->auth.object_name_len = 0;       */
532 /*      server->auth.object_name = NULL;        */
533 /*      server->auth.object_type = 0;           */
534 /*      server->priv.len = 0;                   */
535 /*      server->priv.data = NULL;               */
536
537         server->m = data;
538         /* Althought anything producing this is buggy, it happens
539            now because of PATH_MAX changes.. */
540         if (server->m.time_out < 1) {
541                 server->m.time_out = 10;
542                 printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
543         }
544         server->m.time_out = server->m.time_out * HZ / 100;
545         server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
546         server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
547
548 #ifdef CONFIG_NCPFS_NLS
549         /* load the default NLS charsets */
550         server->nls_vol = load_nls_default();
551         server->nls_io = load_nls_default();
552 #endif /* CONFIG_NCPFS_NLS */
553
554         server->dentry_ttl = 0; /* no caching */
555
556         INIT_LIST_HEAD(&server->tx.requests);
557         mutex_init(&server->rcv.creq_mutex);
558         server->tx.creq         = NULL;
559         server->rcv.creq        = NULL;
560         server->data_ready      = sock->sk->sk_data_ready;
561         server->write_space     = sock->sk->sk_write_space;
562         server->error_report    = sock->sk->sk_error_report;
563         sock->sk->sk_user_data  = server;
564
565         init_timer(&server->timeout_tm);
566 #undef NCP_PACKET_SIZE
567 #define NCP_PACKET_SIZE 131072
568         error = -ENOMEM;
569         server->packet_size = NCP_PACKET_SIZE;
570         server->packet = vmalloc(NCP_PACKET_SIZE);
571         if (server->packet == NULL)
572                 goto out_nls;
573
574         sock->sk->sk_data_ready   = ncp_tcp_data_ready;
575         sock->sk->sk_error_report = ncp_tcp_error_report;
576         if (sock->type == SOCK_STREAM) {
577                 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
578                 server->rcv.len = 10;
579                 server->rcv.state = 0;
580                 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc, server);
581                 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc, server);
582                 sock->sk->sk_write_space = ncp_tcp_write_space;
583         } else {
584                 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc, server);
585                 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc, server);
586                 server->timeout_tm.data = (unsigned long)server;
587                 server->timeout_tm.function = ncpdgram_timeout_call;
588         }
589
590         ncp_lock_server(server);
591         error = ncp_connect(server);
592         ncp_unlock_server(server);
593         if (error < 0)
594                 goto out_packet;
595         DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
596
597         error = -EMSGSIZE;      /* -EREMOTESIDEINCOMPATIBLE */
598 #ifdef CONFIG_NCPFS_PACKET_SIGNING
599         if (ncp_negotiate_size_and_options(server, default_bufsize,
600                 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
601         {
602                 if (options != NCP_DEFAULT_OPTIONS)
603                 {
604                         if (ncp_negotiate_size_and_options(server, 
605                                 default_bufsize,
606                                 options & 2, 
607                                 &(server->buffer_size), &options) != 0)
608                                 
609                         {
610                                 goto out_disconnect;
611                         }
612                 }
613                 if (options & 2)
614                         server->sign_wanted = 1;
615         }
616         else 
617 #endif  /* CONFIG_NCPFS_PACKET_SIGNING */
618         if (ncp_negotiate_buffersize(server, default_bufsize,
619                                      &(server->buffer_size)) != 0)
620                 goto out_disconnect;
621         DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
622
623         memset(&finfo, 0, sizeof(finfo));
624         finfo.i.attributes      = aDIR;
625         finfo.i.dataStreamSize  = 0;    /* ignored */
626         finfo.i.dirEntNum       = 0;
627         finfo.i.DosDirNum       = 0;
628 #ifdef CONFIG_NCPFS_SMALLDOS
629         finfo.i.NSCreator       = NW_NS_DOS;
630 #endif
631         finfo.volume            = NCP_NUMBER_OF_VOLUMES;
632         /* set dates of mountpoint to Jan 1, 1986; 00:00 */
633         finfo.i.creationTime    = finfo.i.modifyTime
634                                 = cpu_to_le16(0x0000);
635         finfo.i.creationDate    = finfo.i.modifyDate
636                                 = finfo.i.lastAccessDate
637                                 = cpu_to_le16(0x0C21);
638         finfo.i.nameLen         = 0;
639         finfo.i.entryName[0]    = '\0';
640
641         finfo.opened            = 0;
642         finfo.ino               = 2;    /* tradition */
643
644         server->name_space[finfo.volume] = NW_NS_DOS;
645
646         error = -ENOMEM;
647         root_inode = ncp_iget(sb, &finfo);
648         if (!root_inode)
649                 goto out_disconnect;
650         DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
651         sb->s_root = d_alloc_root(root_inode);
652         if (!sb->s_root)
653                 goto out_no_root;
654         sb->s_root->d_op = &ncp_root_dentry_operations;
655         return 0;
656
657 out_no_root:
658         iput(root_inode);
659 out_disconnect:
660         ncp_lock_server(server);
661         ncp_disconnect(server);
662         ncp_unlock_server(server);
663 out_packet:
664         ncp_stop_tasks(server);
665         vfree(server->packet);
666 out_nls:
667 #ifdef CONFIG_NCPFS_NLS
668         unload_nls(server->nls_io);
669         unload_nls(server->nls_vol);
670 #endif
671 out_fput2:
672         if (server->info_filp)
673                 fput(server->info_filp);
674 out_fput:
675         /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
676          * 
677          * The previously used put_filp(ncp_filp); was bogous, since
678          * it doesn't proper unlocking.
679          */
680         fput(ncp_filp);
681 out:
682         sb->s_fs_info = NULL;
683         kfree(server);
684         return error;
685 }
686
687 static void ncp_put_super(struct super_block *sb)
688 {
689         struct ncp_server *server = NCP_SBP(sb);
690
691         ncp_lock_server(server);
692         ncp_disconnect(server);
693         ncp_unlock_server(server);
694
695         ncp_stop_tasks(server);
696
697 #ifdef CONFIG_NCPFS_NLS
698         /* unload the NLS charsets */
699         if (server->nls_vol)
700         {
701                 unload_nls(server->nls_vol);
702                 server->nls_vol = NULL;
703         }
704         if (server->nls_io)
705         {
706                 unload_nls(server->nls_io);
707                 server->nls_io = NULL;
708         }
709 #endif /* CONFIG_NCPFS_NLS */
710
711         if (server->info_filp)
712                 fput(server->info_filp);
713         fput(server->ncp_filp);
714         kill_proc(server->m.wdog_pid, SIGTERM, 1);
715
716         kfree(server->priv.data);
717         kfree(server->auth.object_name);
718         vfree(server->packet);
719         sb->s_fs_info = NULL;
720         kfree(server);
721 }
722
723 static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
724 {
725         struct dentry* d;
726         struct inode* i;
727         struct ncp_inode_info* ni;
728         struct ncp_server* s;
729         struct ncp_volume_info vi;
730         struct super_block *sb = dentry->d_sb;
731         int err;
732         __u8 dh;
733         
734         d = sb->s_root;
735         if (!d) {
736                 goto dflt;
737         }
738         i = d->d_inode;
739         if (!i) {
740                 goto dflt;
741         }
742         ni = NCP_FINFO(i);
743         if (!ni) {
744                 goto dflt;
745         }
746         s = NCP_SBP(sb);
747         if (!s) {
748                 goto dflt;
749         }
750         if (!s->m.mounted_vol[0]) {
751                 goto dflt;
752         }
753
754         err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
755         if (err) {
756                 goto dflt;
757         }
758         err = ncp_get_directory_info(s, dh, &vi);
759         ncp_dirhandle_free(s, dh);
760         if (err) {
761                 goto dflt;
762         }
763         buf->f_type = NCP_SUPER_MAGIC;
764         buf->f_bsize = vi.sectors_per_block * 512;
765         buf->f_blocks = vi.total_blocks;
766         buf->f_bfree = vi.free_blocks;
767         buf->f_bavail = vi.free_blocks;
768         buf->f_files = vi.total_dir_entries;
769         buf->f_ffree = vi.available_dir_entries;
770         buf->f_namelen = 12;
771         return 0;
772
773         /* We cannot say how much disk space is left on a mounted
774            NetWare Server, because free space is distributed over
775            volumes, and the current user might have disk quotas. So
776            free space is not that simple to determine. Our decision
777            here is to err conservatively. */
778
779 dflt:;
780         buf->f_type = NCP_SUPER_MAGIC;
781         buf->f_bsize = NCP_BLOCK_SIZE;
782         buf->f_blocks = 0;
783         buf->f_bfree = 0;
784         buf->f_bavail = 0;
785         buf->f_namelen = 12;
786         return 0;
787 }
788
789 int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
790 {
791         struct inode *inode = dentry->d_inode;
792         int result = 0;
793         __le32 info_mask;
794         struct nw_modify_dos_info info;
795         struct ncp_server *server;
796
797         result = -EIO;
798
799         lock_kernel();  
800
801         server = NCP_SERVER(inode);
802         if ((!server) || !ncp_conn_valid(server))
803                 goto out;
804
805         /* ageing the dentry to force validation */
806         ncp_age_dentry(server, dentry);
807
808         result = inode_change_ok(inode, attr);
809         if (result < 0)
810                 goto out;
811
812         result = -EPERM;
813         if (((attr->ia_valid & ATTR_UID) &&
814              (attr->ia_uid != server->m.uid)))
815                 goto out;
816
817         if (((attr->ia_valid & ATTR_GID) &&
818              (attr->ia_gid != server->m.gid)))
819                 goto out;
820
821         if (((attr->ia_valid & ATTR_MODE) &&
822              (attr->ia_mode &
823               ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
824                 goto out;
825
826         info_mask = 0;
827         memset(&info, 0, sizeof(info));
828
829 #if 1 
830         if ((attr->ia_valid & ATTR_MODE) != 0)
831         {
832                 umode_t newmode = attr->ia_mode;
833
834                 info_mask |= DM_ATTRIBUTES;
835
836                 if (S_ISDIR(inode->i_mode)) {
837                         newmode &= server->m.dir_mode;
838                 } else {
839 #ifdef CONFIG_NCPFS_EXTRAS                      
840                         if (server->m.flags & NCP_MOUNT_EXTRAS) {
841                                 /* any non-default execute bit set */
842                                 if (newmode & ~server->m.file_mode & S_IXUGO)
843                                         info.attributes |= aSHARED | aSYSTEM;
844                                 /* read for group/world and not in default file_mode */
845                                 else if (newmode & ~server->m.file_mode & S_IRUGO)
846                                         info.attributes |= aSHARED;
847                         } else
848 #endif
849                                 newmode &= server->m.file_mode;                 
850                 }
851                 if (newmode & S_IWUGO)
852                         info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
853                 else
854                         info.attributes |=  (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
855
856 #ifdef CONFIG_NCPFS_NFS_NS
857                 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
858                         result = ncp_modify_nfs_info(server,
859                                                      NCP_FINFO(inode)->volNumber,
860                                                      NCP_FINFO(inode)->dirEntNum,
861                                                      attr->ia_mode, 0);
862                         if (result != 0)
863                                 goto out;
864                         info.attributes &= ~(aSHARED | aSYSTEM);
865                         {
866                                 /* mark partial success */
867                                 struct iattr tmpattr;
868                                 
869                                 tmpattr.ia_valid = ATTR_MODE;
870                                 tmpattr.ia_mode = attr->ia_mode;
871
872                                 result = inode_setattr(inode, &tmpattr);
873                                 if (result)
874                                         goto out;
875                         }
876                 }
877 #endif
878         }
879 #endif
880
881         /* Do SIZE before attributes, otherwise mtime together with size does not work...
882          */
883         if ((attr->ia_valid & ATTR_SIZE) != 0) {
884                 int written;
885
886                 DPRINTK("ncpfs: trying to change size to %ld\n",
887                         attr->ia_size);
888
889                 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
890                         result = -EACCES;
891                         goto out;
892                 }
893                 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
894                           attr->ia_size, 0, "", &written);
895
896                 /* According to ndir, the changes only take effect after
897                    closing the file */
898                 ncp_inode_close(inode);
899                 result = ncp_make_closed(inode);
900                 if (result)
901                         goto out;
902                 {
903                         struct iattr tmpattr;
904                         
905                         tmpattr.ia_valid = ATTR_SIZE;
906                         tmpattr.ia_size = attr->ia_size;
907                         
908                         result = inode_setattr(inode, &tmpattr);
909                         if (result)
910                                 goto out;
911                 }
912         }
913         if ((attr->ia_valid & ATTR_CTIME) != 0) {
914                 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
915                 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
916                              &info.creationTime, &info.creationDate);
917         }
918         if ((attr->ia_valid & ATTR_MTIME) != 0) {
919                 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
920                 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
921                                   &info.modifyTime, &info.modifyDate);
922         }
923         if ((attr->ia_valid & ATTR_ATIME) != 0) {
924                 __le16 dummy;
925                 info_mask |= (DM_LAST_ACCESS_DATE);
926                 ncp_date_unix2dos(attr->ia_atime.tv_sec,
927                                   &dummy, &info.lastAccessDate);
928         }
929         if (info_mask != 0) {
930                 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
931                                       inode, info_mask, &info);
932                 if (result != 0) {
933                         result = -EACCES;
934
935                         if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
936                                 /* NetWare seems not to allow this. I
937                                    do not know why. So, just tell the
938                                    user everything went fine. This is
939                                    a terrible hack, but I do not know
940                                    how to do this correctly. */
941                                 result = 0;
942                         } else
943                                 goto out;
944                 }
945 #ifdef CONFIG_NCPFS_STRONG              
946                 if ((!result) && (info_mask & DM_ATTRIBUTES))
947                         NCP_FINFO(inode)->nwattr = info.attributes;
948 #endif
949         }
950         if (!result)
951                 result = inode_setattr(inode, attr);
952 out:
953         unlock_kernel();
954         return result;
955 }
956
957 static int ncp_get_sb(struct file_system_type *fs_type,
958         int flags, const char *dev_name, void *data, struct vfsmount *mnt)
959 {
960         return get_sb_nodev(fs_type, flags, data, ncp_fill_super, mnt);
961 }
962
963 static struct file_system_type ncp_fs_type = {
964         .owner          = THIS_MODULE,
965         .name           = "ncpfs",
966         .get_sb         = ncp_get_sb,
967         .kill_sb        = kill_anon_super,
968 };
969
970 static int __init init_ncp_fs(void)
971 {
972         int err;
973         DPRINTK("ncpfs: init_module called\n");
974
975         err = init_inodecache();
976         if (err)
977                 goto out1;
978         err = register_filesystem(&ncp_fs_type);
979         if (err)
980                 goto out;
981         return 0;
982 out:
983         destroy_inodecache();
984 out1:
985         return err;
986 }
987
988 static void __exit exit_ncp_fs(void)
989 {
990         DPRINTK("ncpfs: cleanup_module called\n");
991         unregister_filesystem(&ncp_fs_type);
992         destroy_inodecache();
993 }
994
995 module_init(init_ncp_fs)
996 module_exit(exit_ncp_fs)
997 MODULE_LICENSE("GPL");