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