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  *
9  */
10 
11 #include <linux/config.h>
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/sched.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/locks.h>
25 #include <linux/file.h>
26 #include <linux/fcntl.h>
27 #include <linux/slab.h>
28 #include <linux/vmalloc.h>
29 #include <linux/init.h>
30 
31 #include <linux/ncp_fs.h>
32 
33 #include "ncplib_kernel.h"
34 
35 static void ncp_delete_inode(struct inode *);
36 static void ncp_put_super(struct super_block *);
37 static int  ncp_statfs(struct super_block *, struct statfs *);
38 
39 static struct super_operations ncp_sops =
40 {
41 	put_inode:	force_delete,
42 	delete_inode:	ncp_delete_inode,
43 	put_super:	ncp_put_super,
44 	statfs:		ncp_statfs,
45 };
46 
47 extern struct dentry_operations ncp_root_dentry_operations;
48 #ifdef CONFIG_NCPFS_EXTRAS
49 extern struct address_space_operations ncp_symlink_aops;
50 extern int ncp_symlink(struct inode*, struct dentry*, const char*);
51 #endif
52 
53 /*
54  * Fill in the ncpfs-specific information in the inode.
55  */
ncp_update_inode(struct inode * inode,struct ncp_entry_info * nwinfo)56 void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
57 {
58 	NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
59 	NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
60 	NCP_FINFO(inode)->volNumber = nwinfo->i.volNumber;
61 
62 #ifdef CONFIG_NCPFS_STRONG
63 	NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
64 #endif
65 	NCP_FINFO(inode)->access = nwinfo->access;
66 	NCP_FINFO(inode)->server_file_handle = nwinfo->server_file_handle;
67 	memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
68 			sizeof(nwinfo->file_handle));
69 	DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
70 		nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
71 		NCP_FINFO(inode)->dirEntNum);
72 }
73 
ncp_update_inode2(struct inode * inode,struct ncp_entry_info * nwinfo)74 void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
75 {
76 	struct nw_info_struct *nwi = &nwinfo->i;
77 	struct ncp_server *server = NCP_SERVER(inode);
78 
79 	if (!atomic_read(&NCP_FINFO(inode)->opened)) {
80 #ifdef CONFIG_NCPFS_STRONG
81 		NCP_FINFO(inode)->nwattr = nwi->attributes;
82 #endif
83 		if (nwi->attributes & aDIR) {
84 			inode->i_mode = server->m.dir_mode;
85 			inode->i_size = NCP_BLOCK_SIZE;
86 		} else {
87 			inode->i_mode = server->m.file_mode;
88 			inode->i_size = le32_to_cpu(nwi->dataStreamSize);
89 #ifdef CONFIG_NCPFS_EXTRAS
90 			if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS)) && (nwi->attributes & aSHARED)) {
91 				switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
92 					case aHIDDEN:
93 						if (server->m.flags & NCP_MOUNT_SYMLINKS) {
94 							if ( /* (inode->i_size >= NCP_MIN_SYMLINK_SIZE)
95 							 && */ (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) {
96 								inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
97 								break;
98 							}
99 						}
100 						/* FALLTHROUGH */
101 					case 0:
102 						if (server->m.flags & NCP_MOUNT_EXTRAS)
103 							inode->i_mode |= 0444;
104 						break;
105 					case aSYSTEM:
106 						if (server->m.flags & NCP_MOUNT_EXTRAS)
107 							inode->i_mode |= (inode->i_mode >> 2) & 0111;
108 						break;
109 					/* case aSYSTEM|aHIDDEN: */
110 					default:
111 						/* reserved combination */
112 						break;
113 				}
114 			}
115 #endif
116 		}
117 		if (nwi->attributes & aRONLY) inode->i_mode &= ~0222;
118 	}
119 	inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
120 
121 	inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(nwi->modifyTime),
122 					   le16_to_cpu(nwi->modifyDate));
123 	inode->i_ctime = ncp_date_dos2unix(le16_to_cpu(nwi->creationTime),
124 					   le16_to_cpu(nwi->creationDate));
125 	inode->i_atime = ncp_date_dos2unix(0, le16_to_cpu(nwi->lastAccessDate));
126 
127 	NCP_FINFO(inode)->DosDirNum = nwi->DosDirNum;
128 	NCP_FINFO(inode)->dirEntNum = nwi->dirEntNum;
129 	NCP_FINFO(inode)->volNumber = nwi->volNumber;
130 }
131 
132 /*
133  * Fill in the inode based on the ncp_entry_info structure.
134  */
ncp_set_attr(struct inode * inode,struct ncp_entry_info * nwinfo)135 static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
136 {
137 	struct nw_info_struct *nwi = &nwinfo->i;
138 	struct ncp_server *server = NCP_SERVER(inode);
139 
140 	if (nwi->attributes & aDIR) {
141 		inode->i_mode = server->m.dir_mode;
142 		/* for directories dataStreamSize seems to be some
143 		   Object ID ??? */
144 		inode->i_size = NCP_BLOCK_SIZE;
145 	} else {
146 		inode->i_mode = server->m.file_mode;
147 		inode->i_size = le32_to_cpu(nwi->dataStreamSize);
148 #ifdef CONFIG_NCPFS_EXTRAS
149 		if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS))
150 		 && (nwi->attributes & aSHARED)) {
151 			switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
152 				case aHIDDEN:
153 					if (server->m.flags & NCP_MOUNT_SYMLINKS) {
154 						if (/* (inode->i_size >= NCP_MIN_SYMLINK_SIZE)
155 						 && */ (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) {
156 							inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
157 							break;
158 						}
159 					}
160 					/* FALLTHROUGH */
161 				case 0:
162 					if (server->m.flags & NCP_MOUNT_EXTRAS)
163 						inode->i_mode |= 0444;
164 					break;
165 				case aSYSTEM:
166 					if (server->m.flags & NCP_MOUNT_EXTRAS)
167 						inode->i_mode |= (inode->i_mode >> 2) & 0111;
168 					break;
169 				/* case aSYSTEM|aHIDDEN: */
170 				default:
171 					/* reserved combination */
172 					break;
173 			}
174 		}
175 #endif
176 	}
177 	if (nwi->attributes & aRONLY) inode->i_mode &= ~0222;
178 
179 	DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
180 
181 	inode->i_nlink = 1;
182 	inode->i_uid = server->m.uid;
183 	inode->i_gid = server->m.gid;
184 	inode->i_rdev = 0;
185 	inode->i_blksize = NCP_BLOCK_SIZE;
186 
187 	inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
188 
189 	inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(nwi->modifyTime),
190 			  		   le16_to_cpu(nwi->modifyDate));
191 	inode->i_ctime = ncp_date_dos2unix(le16_to_cpu(nwi->creationTime),
192 			    		   le16_to_cpu(nwi->creationDate));
193 	inode->i_atime = ncp_date_dos2unix(0,
194 					   le16_to_cpu(nwi->lastAccessDate));
195 	ncp_update_inode(inode, nwinfo);
196 }
197 
198 static struct inode_operations ncp_symlink_inode_operations = {
199 	readlink:	page_readlink,
200 	follow_link:	page_follow_link,
201 	setattr:	ncp_notify_change,
202 };
203 
204 /*
205  * Get a new inode.
206  */
207 struct inode *
ncp_iget(struct super_block * sb,struct ncp_entry_info * info)208 ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
209 {
210 	struct inode *inode;
211 
212 	if (info == NULL) {
213 		printk(KERN_ERR "ncp_iget: info is NULL\n");
214 		return NULL;
215 	}
216 
217 	inode = new_inode(sb);
218 	if (inode) {
219 		init_MUTEX(&NCP_FINFO(inode)->open_sem);
220 		atomic_set(&NCP_FINFO(inode)->opened, info->opened);
221 
222 		inode->i_ino = info->ino;
223 		ncp_set_attr(inode, info);
224 		if (S_ISREG(inode->i_mode)) {
225 			inode->i_op = &ncp_file_inode_operations;
226 			inode->i_fop = &ncp_file_operations;
227 		} else if (S_ISDIR(inode->i_mode)) {
228 			inode->i_op = &ncp_dir_inode_operations;
229 			inode->i_fop = &ncp_dir_operations;
230 #ifdef CONFIG_NCPFS_EXTRAS
231 		} else if (S_ISLNK(inode->i_mode)) {
232 			inode->i_op = &ncp_symlink_inode_operations;
233 			inode->i_data.a_ops = &ncp_symlink_aops;
234 #endif
235 		}
236 		insert_inode_hash(inode);
237 	} else
238 		printk(KERN_ERR "ncp_iget: iget failed!\n");
239 	return inode;
240 }
241 
242 static void
ncp_delete_inode(struct inode * inode)243 ncp_delete_inode(struct inode *inode)
244 {
245 	if (S_ISDIR(inode->i_mode)) {
246 		DDPRINTK("ncp_delete_inode: put directory %ld\n", inode->i_ino);
247 	}
248 
249 	if (ncp_make_closed(inode) != 0) {
250 		/* We can't do anything but complain. */
251 		printk(KERN_ERR "ncp_delete_inode: could not close\n");
252 	}
253 	clear_inode(inode);
254 }
255 
256 struct super_block *
ncp_read_super(struct super_block * sb,void * raw_data,int silent)257 ncp_read_super(struct super_block *sb, void *raw_data, int silent)
258 {
259 	struct ncp_mount_data_kernel data;
260 	struct ncp_server *server;
261 	struct file *ncp_filp;
262 	struct inode *root_inode;
263 	struct inode *sock_inode;
264 	struct socket *sock;
265 	int error;
266 	int default_bufsize;
267 #ifdef CONFIG_NCPFS_PACKET_SIGNING
268 	int options;
269 #endif
270 	struct ncp_entry_info finfo;
271 
272 	if (raw_data == NULL)
273 		goto out_no_data;
274 	switch (*(int*)raw_data) {
275 		case NCP_MOUNT_VERSION:
276 			{
277 				struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
278 
279 				data.flags = md->flags;
280 				data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
281 				data.mounted_uid = md->mounted_uid;
282 				data.wdog_pid = md->wdog_pid;
283 				data.ncp_fd = md->ncp_fd;
284 				data.time_out = md->time_out;
285 				data.retry_count = md->retry_count;
286 				data.uid = md->uid;
287 				data.gid = md->gid;
288 				data.file_mode = md->file_mode;
289 				data.dir_mode = md->dir_mode;
290 				memcpy(data.mounted_vol, md->mounted_vol,
291 					NCP_VOLNAME_LEN+1);
292 			}
293 			break;
294 		case NCP_MOUNT_VERSION_V4:
295 			{
296 				struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
297 
298 				data.flags = md->flags;
299 				data.int_flags = 0;
300 				data.mounted_uid = md->mounted_uid;
301 				data.wdog_pid = md->wdog_pid;
302 				data.ncp_fd = md->ncp_fd;
303 				data.time_out = md->time_out;
304 				data.retry_count = md->retry_count;
305 				data.uid = md->uid;
306 				data.gid = md->gid;
307 				data.file_mode = md->file_mode;
308 				data.dir_mode = md->dir_mode;
309 				data.mounted_vol[0] = 0;
310 			}
311 			break;
312 		default:
313 			goto out_bad_mount;
314 	}
315 	ncp_filp = fget(data.ncp_fd);
316 	if (!ncp_filp)
317 		goto out_bad_file;
318 	sock_inode = ncp_filp->f_dentry->d_inode;
319 	if (!S_ISSOCK(sock_inode->i_mode))
320 		goto out_bad_file2;
321 	sock = &sock_inode->u.socket_i;
322 	if (!sock)
323 		goto out_bad_file2;
324 
325 	if (sock->type == SOCK_STREAM)
326 		default_bufsize = 61440;
327 	else
328 		default_bufsize = 1024;
329 
330 	sb->s_blocksize = 1024;	/* Eh...  Is this correct? */
331 	sb->s_blocksize_bits = 10;
332 	sb->s_magic = NCP_SUPER_MAGIC;
333 	sb->s_op = &ncp_sops;
334 
335 	server = NCP_SBP(sb);
336 	memset(server, 0, sizeof(*server));
337 
338 	server->ncp_filp = ncp_filp;
339 /*	server->lock = 0;	*/
340 	init_MUTEX(&server->sem);
341 	server->packet = NULL;
342 /*	server->buffer_size = 0;	*/
343 /*	server->conn_status = 0;	*/
344 /*	server->root_dentry = NULL;	*/
345 /*	server->root_setuped = 0;	*/
346 #ifdef CONFIG_NCPFS_PACKET_SIGNING
347 /*	server->sign_wanted = 0;	*/
348 /*	server->sign_active = 0;	*/
349 #endif
350 	server->auth.auth_type = NCP_AUTH_NONE;
351 /*	server->auth.object_name_len = 0;	*/
352 /*	server->auth.object_name = NULL;	*/
353 /*	server->auth.object_type = 0;		*/
354 /*	server->priv.len = 0;			*/
355 /*	server->priv.data = NULL;		*/
356 
357 	server->m = data;
358 	/* Althought anything producing this is buggy, it happens
359 	   now because of PATH_MAX changes.. */
360 	if (server->m.time_out < 1) {
361 		server->m.time_out = 10;
362 		printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
363 	}
364 	server->m.time_out = server->m.time_out * HZ / 100;
365 	server->m.file_mode = (server->m.file_mode &
366 			       (S_IRWXU | S_IRWXG | S_IRWXO)) | S_IFREG;
367 	server->m.dir_mode = (server->m.dir_mode &
368 			      (S_IRWXU | S_IRWXG | S_IRWXO)) | S_IFDIR;
369 
370 #ifdef CONFIG_NCPFS_NLS
371 	/* load the default NLS charsets */
372 	server->nls_vol = load_nls_default();
373 	server->nls_io = load_nls_default();
374 #endif /* CONFIG_NCPFS_NLS */
375 
376 	server->dentry_ttl = 0;	/* no caching */
377 
378 #undef NCP_PACKET_SIZE
379 #define NCP_PACKET_SIZE 65536
380 	server->packet_size = NCP_PACKET_SIZE;
381 	server->packet = vmalloc(NCP_PACKET_SIZE);
382 	if (server->packet == NULL)
383 		goto out_no_packet;
384 
385 	ncp_lock_server(server);
386 	error = ncp_connect(server);
387 	ncp_unlock_server(server);
388 	if (error < 0)
389 		goto out_no_connect;
390 	DPRINTK("ncp_read_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
391 
392 #ifdef CONFIG_NCPFS_PACKET_SIGNING
393 	if (ncp_negotiate_size_and_options(server, default_bufsize,
394 		NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
395 	{
396 		if (options != NCP_DEFAULT_OPTIONS)
397 		{
398 			if (ncp_negotiate_size_and_options(server,
399 				default_bufsize,
400 				options & 2,
401 				&(server->buffer_size), &options) != 0)
402 
403 			{
404 				goto out_no_bufsize;
405 			}
406 		}
407 		if (options & 2)
408 			server->sign_wanted = 1;
409 	}
410 	else
411 #endif	/* CONFIG_NCPFS_PACKET_SIGNING */
412 	if (ncp_negotiate_buffersize(server, default_bufsize,
413   				     &(server->buffer_size)) != 0)
414 		goto out_no_bufsize;
415 	DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
416 
417 	memset(&finfo, 0, sizeof(finfo));
418 	finfo.i.attributes	= aDIR;
419 	finfo.i.dataStreamSize	= NCP_BLOCK_SIZE;
420 	finfo.i.dirEntNum	= 0;
421 	finfo.i.DosDirNum	= 0;
422 #ifdef CONFIG_NCPFS_SMALLDOS
423 	finfo.i.NSCreator	= NW_NS_DOS;
424 #endif
425 	finfo.i.volNumber	= NCP_NUMBER_OF_VOLUMES + 1;	/* illegal volnum */
426 	/* set dates of mountpoint to Jan 1, 1986; 00:00 */
427 	finfo.i.creationTime	= finfo.i.modifyTime
428 				= cpu_to_le16(0x0000);
429 	finfo.i.creationDate	= finfo.i.modifyDate
430 				= finfo.i.lastAccessDate
431 				= cpu_to_le16(0x0C21);
432 	finfo.i.nameLen		= 0;
433 	finfo.i.entryName[0]	= '\0';
434 
435 	finfo.opened		= 0;
436 	finfo.ino		= 2;	/* tradition */
437 
438 	server->name_space[finfo.i.volNumber] = NW_NS_DOS;
439         root_inode = ncp_iget(sb, &finfo);
440         if (!root_inode)
441 		goto out_no_root;
442 	DPRINTK("ncp_read_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
443 	sb->s_root = d_alloc_root(root_inode);
444         if (!sb->s_root)
445 		goto out_no_root;
446 	sb->s_root->d_op = &ncp_root_dentry_operations;
447 	return sb;
448 
449 out_no_root:
450 	printk(KERN_ERR "ncp_read_super: get root inode failed\n");
451 	iput(root_inode);
452 	goto out_disconnect;
453 out_no_bufsize:
454 	printk(KERN_ERR "ncp_read_super: could not get bufsize\n");
455 out_disconnect:
456 	ncp_lock_server(server);
457 	ncp_disconnect(server);
458 	ncp_unlock_server(server);
459 	goto out_free_packet;
460 out_no_connect:
461 	printk(KERN_ERR "ncp_read_super: Failed connection, error=%d\n", error);
462 out_free_packet:
463 	vfree(server->packet);
464 	goto out_free_server;
465 out_no_packet:
466 	printk(KERN_ERR "ncp_read_super: could not alloc packet\n");
467 out_free_server:
468 #ifdef CONFIG_NCPFS_NLS
469 	unload_nls(server->nls_io);
470 	unload_nls(server->nls_vol);
471 #endif
472 	/* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
473 	 *
474 	 * The previously used put_filp(ncp_filp); was bogous, since
475 	 * it doesn't proper unlocking.
476 	 */
477 	fput(ncp_filp);
478 	goto out;
479 
480 out_bad_file2:
481 	fput(ncp_filp);
482 out_bad_file:
483 	printk(KERN_ERR "ncp_read_super: invalid ncp socket\n");
484 	goto out;
485 out_bad_mount:
486 	printk(KERN_INFO "ncp_read_super: kernel requires mount version %d\n",
487 		NCP_MOUNT_VERSION);
488 	goto out;
489 out_no_data:
490 	printk(KERN_ERR "ncp_read_super: missing data argument\n");
491 out:
492 	return NULL;
493 }
494 
ncp_put_super(struct super_block * sb)495 static void ncp_put_super(struct super_block *sb)
496 {
497 	struct ncp_server *server = NCP_SBP(sb);
498 
499 	ncp_lock_server(server);
500 	ncp_disconnect(server);
501 	ncp_unlock_server(server);
502 
503 #ifdef CONFIG_NCPFS_NLS
504 	/* unload the NLS charsets */
505 	if (server->nls_vol)
506 	{
507 		unload_nls(server->nls_vol);
508 		server->nls_vol = NULL;
509 	}
510 	if (server->nls_io)
511 	{
512 		unload_nls(server->nls_io);
513 		server->nls_io = NULL;
514 	}
515 #endif /* CONFIG_NCPFS_NLS */
516 
517 	fput(server->ncp_filp);
518 	kill_proc(server->m.wdog_pid, SIGTERM, 1);
519 
520 	if (server->priv.data)
521 		ncp_kfree_s(server->priv.data, server->priv.len);
522 	if (server->auth.object_name)
523 		ncp_kfree_s(server->auth.object_name, server->auth.object_name_len);
524 	vfree(server->packet);
525 
526 }
527 
ncp_statfs(struct super_block * sb,struct statfs * buf)528 static int ncp_statfs(struct super_block *sb, struct statfs *buf)
529 {
530 	/* We cannot say how much disk space is left on a mounted
531 	   NetWare Server, because free space is distributed over
532 	   volumes, and the current user might have disk quotas. So
533 	   free space is not that simple to determine. Our decision
534 	   here is to err conservatively. */
535 
536 	buf->f_type = NCP_SUPER_MAGIC;
537 	buf->f_bsize = NCP_BLOCK_SIZE;
538 	buf->f_blocks = 0;
539 	buf->f_bfree = 0;
540 	buf->f_bavail = 0;
541 	buf->f_namelen = 12;
542 	return 0;
543 }
544 
ncp_notify_change(struct dentry * dentry,struct iattr * attr)545 int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
546 {
547 	struct inode *inode = dentry->d_inode;
548 	int result = 0;
549 	int info_mask;
550 	struct nw_modify_dos_info info;
551 	struct ncp_server *server;
552 
553 	result = -EIO;
554 
555 	server = NCP_SERVER(inode);
556 	if ((!server) || !ncp_conn_valid(server))
557 		goto out;
558 
559 	/* ageing the dentry to force validation */
560 	ncp_age_dentry(server, dentry);
561 
562 	result = inode_change_ok(inode, attr);
563 	if (result < 0)
564 		goto out;
565 
566 	result = -EPERM;
567 	if (((attr->ia_valid & ATTR_UID) &&
568 	     (attr->ia_uid != server->m.uid)))
569 		goto out;
570 
571 	if (((attr->ia_valid & ATTR_GID) &&
572 	     (attr->ia_gid != server->m.gid)))
573 		goto out;
574 
575 	if (((attr->ia_valid & ATTR_MODE) &&
576 	     (attr->ia_mode &
577 	      ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
578 		goto out;
579 
580 	info_mask = 0;
581 	memset(&info, 0, sizeof(info));
582 
583 #if 1
584         if ((attr->ia_valid & ATTR_MODE) != 0)
585         {
586                 if (S_ISDIR(inode->i_mode)) {
587                 	umode_t newmode;
588 
589                 	info_mask |= DM_ATTRIBUTES;
590                 	newmode = attr->ia_mode;
591                 	newmode &= NCP_SERVER(inode)->m.dir_mode;
592 
593                 	if (newmode & 0222)
594                 		info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
595                 	else
596 				info.attributes |=  (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
597                 } else if (!S_ISREG(inode->i_mode))
598                 {
599                         return -EPERM;
600                 }
601                 else
602                 {
603 			umode_t newmode;
604 #ifdef CONFIG_NCPFS_EXTRAS
605 			int extras;
606 
607 			extras = server->m.flags & NCP_MOUNT_EXTRAS;
608 #endif
609                         info_mask |= DM_ATTRIBUTES;
610                         newmode=attr->ia_mode;
611 #ifdef CONFIG_NCPFS_EXTRAS
612 			if (!extras)
613 #endif
614 	                        newmode &= server->m.file_mode;
615 
616                         if (newmode & 0222) /* any write bit set */
617                         {
618                                 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
619                         }
620                         else
621                         {
622                                 info.attributes |=  (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
623                         }
624 #ifdef CONFIG_NCPFS_EXTRAS
625 			if (extras) {
626 				if (newmode & 0111) /* any execute bit set */
627 					info.attributes |= aSHARED | aSYSTEM;
628 				/* read for group/world and not in default file_mode */
629 				else if (newmode & ~server->m.file_mode & 0444)
630 					info.attributes |= aSHARED;
631 			}
632 #endif
633                 }
634         }
635 #endif
636 
637 	if ((attr->ia_valid & ATTR_CTIME) != 0) {
638 		info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
639 		ncp_date_unix2dos(attr->ia_ctime,
640 			     &(info.creationTime), &(info.creationDate));
641 		info.creationTime = le16_to_cpu(info.creationTime);
642 		info.creationDate = le16_to_cpu(info.creationDate);
643 	}
644 	if ((attr->ia_valid & ATTR_MTIME) != 0) {
645 		info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
646 		ncp_date_unix2dos(attr->ia_mtime,
647 				  &(info.modifyTime), &(info.modifyDate));
648 		info.modifyTime = le16_to_cpu(info.modifyTime);
649 		info.modifyDate = le16_to_cpu(info.modifyDate);
650 	}
651 	if ((attr->ia_valid & ATTR_ATIME) != 0) {
652 		__u16 dummy;
653 		info_mask |= (DM_LAST_ACCESS_DATE);
654 		ncp_date_unix2dos(attr->ia_atime,
655 				  &(dummy), &(info.lastAccessDate));
656 		info.lastAccessDate = le16_to_cpu(info.lastAccessDate);
657 	}
658 	if (info_mask != 0) {
659 		result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
660 				      inode, info_mask, &info);
661 		if (result != 0) {
662 			result = -EACCES;
663 
664 			if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
665 				/* NetWare seems not to allow this. I
666 				   do not know why. So, just tell the
667 				   user everything went fine. This is
668 				   a terrible hack, but I do not know
669 				   how to do this correctly. */
670 				result = 0;
671 			}
672 		}
673 #ifdef CONFIG_NCPFS_STRONG
674 		if ((!result) && (info_mask & DM_ATTRIBUTES))
675 			NCP_FINFO(inode)->nwattr = info.attributes;
676 #endif
677 	}
678 	if ((attr->ia_valid & ATTR_SIZE) != 0) {
679 		int written;
680 
681 		DPRINTK("ncpfs: trying to change size to %ld\n",
682 			attr->ia_size);
683 
684 		if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
685 			return -EACCES;
686 		}
687 		ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
688 			  attr->ia_size, 0, "", &written);
689 
690 		/* According to ndir, the changes only take effect after
691 		   closing the file */
692 		ncp_inode_close(inode);
693 		result = ncp_make_closed(inode);
694 		if (!result)
695 			result = vmtruncate(inode, attr->ia_size);
696 	}
697 out:
698 	return result;
699 }
700 
701 #ifdef DEBUG_NCP_MALLOC
702 int ncp_malloced;
703 int ncp_current_malloced;
704 #endif
705 
706 static DECLARE_FSTYPE(ncp_fs_type, "ncpfs", ncp_read_super, 0);
707 
init_ncp_fs(void)708 static int __init init_ncp_fs(void)
709 {
710 	DPRINTK("ncpfs: init_module called\n");
711 
712 #ifdef DEBUG_NCP_MALLOC
713 	ncp_malloced = 0;
714 	ncp_current_malloced = 0;
715 #endif
716 	return register_filesystem(&ncp_fs_type);
717 }
718 
exit_ncp_fs(void)719 static void __exit exit_ncp_fs(void)
720 {
721 	DPRINTK("ncpfs: cleanup_module called\n");
722 	unregister_filesystem(&ncp_fs_type);
723 #ifdef DEBUG_NCP_MALLOC
724 	PRINTK("ncp_malloced: %d\n", ncp_malloced);
725 	PRINTK("ncp_current_malloced: %d\n", ncp_current_malloced);
726 #endif
727 }
728 
729 EXPORT_NO_SYMBOLS;
730 
731 module_init(init_ncp_fs)
732 module_exit(exit_ncp_fs)
733 MODULE_LICENSE("GPL");
734