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