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