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