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
12 #include <linux/config.h>
13 #include <linux/module.h>
15 #include <asm/system.h>
16 #include <asm/uaccess.h>
17 #include <asm/byteorder.h>
19 #include <linux/time.h>
20 #include <linux/kernel.h>
22 #include <linux/string.h>
23 #include <linux/stat.h>
24 #include <linux/errno.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 #include <linux/smp_lock.h>
31 #include <linux/vfs.h>
33 #include <linux/ncp_fs.h>
37 #include "ncplib_kernel.h"
40 static void ncp_delete_inode(struct inode *);
41 static void ncp_put_super(struct super_block *);
42 static int ncp_statfs(struct super_block *, struct kstatfs *);
44 static kmem_cache_t * ncp_inode_cachep;
46 static struct inode *ncp_alloc_inode(struct super_block *sb)
48 struct ncp_inode_info *ei;
49 ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, SLAB_KERNEL);
52 return &ei->vfs_inode;
55 static void ncp_destroy_inode(struct inode *inode)
57 kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
60 static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
62 struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
64 if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
65 SLAB_CTOR_CONSTRUCTOR) {
66 init_MUTEX(&ei->open_sem);
67 inode_init_once(&ei->vfs_inode);
71 static int init_inodecache(void)
73 ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
74 sizeof(struct ncp_inode_info),
75 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
77 if (ncp_inode_cachep == NULL)
82 static void destroy_inodecache(void)
84 if (kmem_cache_destroy(ncp_inode_cachep))
85 printk(KERN_INFO "ncp_inode_cache: not all structures were freed\n");
88 static int ncp_remount(struct super_block *sb, int *flags, char* data)
90 *flags |= MS_NODIRATIME;
94 static struct super_operations ncp_sops =
96 .alloc_inode = ncp_alloc_inode,
97 .destroy_inode = ncp_destroy_inode,
98 .drop_inode = generic_delete_inode,
99 .delete_inode = ncp_delete_inode,
100 .put_super = ncp_put_super,
101 .statfs = ncp_statfs,
102 .remount_fs = ncp_remount,
105 extern struct dentry_operations ncp_root_dentry_operations;
106 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
107 extern struct address_space_operations ncp_symlink_aops;
108 extern int ncp_symlink(struct inode*, struct dentry*, const char*);
112 * Fill in the ncpfs-specific information in the inode.
114 static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
116 NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
117 NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
118 NCP_FINFO(inode)->volNumber = nwinfo->volume;
121 void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
123 ncp_update_dirent(inode, nwinfo);
124 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
125 NCP_FINFO(inode)->access = nwinfo->access;
126 memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
127 sizeof(nwinfo->file_handle));
128 DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
129 nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
130 NCP_FINFO(inode)->dirEntNum);
133 static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
135 /* NFS namespace mode overrides others if it's set. */
136 DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n",
137 nwi->entryName, nwi->nfs.mode);
140 inode->i_mode = nwi->nfs.mode;
143 inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
145 inode->i_mtime.tv_sec = ncp_date_dos2unix(le16_to_cpu(nwi->modifyTime),
146 le16_to_cpu(nwi->modifyDate));
147 inode->i_ctime.tv_sec = ncp_date_dos2unix(le16_to_cpu(nwi->creationTime),
148 le16_to_cpu(nwi->creationDate));
149 inode->i_atime.tv_sec = ncp_date_dos2unix(0,
150 le16_to_cpu(nwi->lastAccessDate));
151 inode->i_atime.tv_nsec = 0;
152 inode->i_mtime.tv_nsec = 0;
153 inode->i_ctime.tv_nsec = 0;
156 static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
158 struct nw_info_struct *nwi = &nwinfo->i;
159 struct ncp_server *server = NCP_SERVER(inode);
161 if (nwi->attributes & aDIR) {
162 inode->i_mode = server->m.dir_mode;
163 /* for directories dataStreamSize seems to be some
165 inode->i_size = NCP_BLOCK_SIZE;
167 inode->i_mode = server->m.file_mode;
168 inode->i_size = le32_to_cpu(nwi->dataStreamSize);
169 #ifdef CONFIG_NCPFS_EXTRAS
170 if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS))
171 && (nwi->attributes & aSHARED)) {
172 switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
174 if (server->m.flags & NCP_MOUNT_SYMLINKS) {
175 if (/* (inode->i_size >= NCP_MIN_SYMLINK_SIZE)
176 && */ (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) {
177 inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
178 NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
184 if (server->m.flags & NCP_MOUNT_EXTRAS)
185 inode->i_mode |= S_IRUGO;
188 if (server->m.flags & NCP_MOUNT_EXTRAS)
189 inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO;
191 /* case aSYSTEM|aHIDDEN: */
193 /* reserved combination */
199 if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
202 void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
204 NCP_FINFO(inode)->flags = 0;
205 if (!atomic_read(&NCP_FINFO(inode)->opened)) {
206 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
207 ncp_update_attrs(inode, nwinfo);
210 ncp_update_dates(inode, &nwinfo->i);
211 ncp_update_dirent(inode, nwinfo);
215 * Fill in the inode based on the ncp_entry_info structure.
217 static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
219 struct ncp_server *server = NCP_SERVER(inode);
221 NCP_FINFO(inode)->flags = 0;
223 ncp_update_attrs(inode, nwinfo);
225 DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
228 inode->i_uid = server->m.uid;
229 inode->i_gid = server->m.gid;
230 inode->i_blksize = NCP_BLOCK_SIZE;
232 ncp_update_dates(inode, &nwinfo->i);
233 ncp_update_inode(inode, nwinfo);
236 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
237 static struct inode_operations ncp_symlink_inode_operations = {
238 .readlink = generic_readlink,
239 .follow_link = page_follow_link_light,
240 .put_link = page_put_link,
241 .setattr = ncp_notify_change,
249 ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
254 printk(KERN_ERR "ncp_iget: info is NULL\n");
258 inode = new_inode(sb);
260 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
262 inode->i_ino = info->ino;
263 ncp_set_attr(inode, info);
264 if (S_ISREG(inode->i_mode)) {
265 inode->i_op = &ncp_file_inode_operations;
266 inode->i_fop = &ncp_file_operations;
267 } else if (S_ISDIR(inode->i_mode)) {
268 inode->i_op = &ncp_dir_inode_operations;
269 inode->i_fop = &ncp_dir_operations;
270 #ifdef CONFIG_NCPFS_NFS_NS
271 } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
272 init_special_inode(inode, inode->i_mode,
273 new_decode_dev(info->i.nfs.rdev));
275 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
276 } else if (S_ISLNK(inode->i_mode)) {
277 inode->i_op = &ncp_symlink_inode_operations;
278 inode->i_data.a_ops = &ncp_symlink_aops;
281 make_bad_inode(inode);
283 insert_inode_hash(inode);
285 printk(KERN_ERR "ncp_iget: iget failed!\n");
290 ncp_delete_inode(struct inode *inode)
292 if (S_ISDIR(inode->i_mode)) {
293 DDPRINTK("ncp_delete_inode: put directory %ld\n", inode->i_ino);
296 if (ncp_make_closed(inode) != 0) {
297 /* We can't do anything but complain. */
298 printk(KERN_ERR "ncp_delete_inode: could not close\n");
303 static void ncp_stop_tasks(struct ncp_server *server) {
304 struct sock* sk = server->ncp_sock->sk;
306 sk->sk_error_report = server->error_report;
307 sk->sk_data_ready = server->data_ready;
308 sk->sk_write_space = server->write_space;
309 del_timer_sync(&server->timeout_tm);
310 flush_scheduled_work();
313 static const struct ncp_option ncp_opts[] = {
314 { "uid", OPT_INT, 'u' },
315 { "gid", OPT_INT, 'g' },
316 { "owner", OPT_INT, 'o' },
317 { "mode", OPT_INT, 'm' },
318 { "dirmode", OPT_INT, 'd' },
319 { "timeout", OPT_INT, 't' },
320 { "retry", OPT_INT, 'r' },
321 { "flags", OPT_INT, 'f' },
322 { "wdogpid", OPT_INT, 'w' },
323 { "ncpfd", OPT_INT, 'n' },
324 { "infofd", OPT_INT, 'i' }, /* v5 */
325 { "version", OPT_INT, 'v' },
328 static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
331 unsigned long optint;
336 data->mounted_uid = 0;
340 data->retry_count = 20;
343 data->file_mode = 0600;
344 data->dir_mode = 0700;
346 data->mounted_vol[0] = 0;
348 while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
359 data->mounted_uid = optint;
362 data->file_mode = optint;
365 data->dir_mode = optint;
368 data->time_out = optint;
371 data->retry_count = optint;
374 data->flags = optint;
377 data->wdog_pid = optint;
380 data->ncp_fd = optint;
383 data->info_fd = optint;
386 if (optint < NCP_MOUNT_VERSION_V4) {
389 if (optint > NCP_MOUNT_VERSION_V5) {
400 static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
402 struct ncp_mount_data_kernel data;
403 struct ncp_server *server;
404 struct file *ncp_filp;
405 struct inode *root_inode;
406 struct inode *sock_inode;
410 #ifdef CONFIG_NCPFS_PACKET_SIGNING
413 struct ncp_entry_info finfo;
415 server = kmalloc(sizeof(struct ncp_server), GFP_KERNEL);
418 sb->s_fs_info = server;
419 memset(server, 0, sizeof(struct ncp_server));
422 if (raw_data == NULL)
424 switch (*(int*)raw_data) {
425 case NCP_MOUNT_VERSION:
427 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
429 data.flags = md->flags;
430 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
431 data.mounted_uid = md->mounted_uid;
432 data.wdog_pid = md->wdog_pid;
433 data.ncp_fd = md->ncp_fd;
434 data.time_out = md->time_out;
435 data.retry_count = md->retry_count;
438 data.file_mode = md->file_mode;
439 data.dir_mode = md->dir_mode;
441 memcpy(data.mounted_vol, md->mounted_vol,
445 case NCP_MOUNT_VERSION_V4:
447 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
449 data.flags = md->flags;
451 data.mounted_uid = md->mounted_uid;
452 data.wdog_pid = md->wdog_pid;
453 data.ncp_fd = md->ncp_fd;
454 data.time_out = md->time_out;
455 data.retry_count = md->retry_count;
458 data.file_mode = md->file_mode;
459 data.dir_mode = md->dir_mode;
461 data.mounted_vol[0] = 0;
466 if (*(__u32*)raw_data == cpu_to_be32(0x76657273)) {
467 error = ncp_parse_options(&data, raw_data);
474 ncp_filp = fget(data.ncp_fd);
478 sock_inode = ncp_filp->f_dentry->d_inode;
479 if (!S_ISSOCK(sock_inode->i_mode))
481 sock = SOCKET_I(sock_inode);
485 if (sock->type == SOCK_STREAM)
486 default_bufsize = 0xF000;
488 default_bufsize = 1024;
490 sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
491 sb->s_maxbytes = 0xFFFFFFFFU;
492 sb->s_blocksize = 1024; /* Eh... Is this correct? */
493 sb->s_blocksize_bits = 10;
494 sb->s_magic = NCP_SUPER_MAGIC;
495 sb->s_op = &ncp_sops;
497 server = NCP_SBP(sb);
498 memset(server, 0, sizeof(*server));
500 server->ncp_filp = ncp_filp;
501 server->ncp_sock = sock;
503 if (data.info_fd != -1) {
504 struct socket *info_sock;
507 server->info_filp = fget(data.info_fd);
508 if (!server->info_filp)
511 sock_inode = server->info_filp->f_dentry->d_inode;
512 if (!S_ISSOCK(sock_inode->i_mode))
514 info_sock = SOCKET_I(sock_inode);
518 if (info_sock->type != SOCK_STREAM)
520 server->info_sock = info_sock;
523 /* server->lock = 0; */
524 init_MUTEX(&server->sem);
525 server->packet = NULL;
526 /* server->buffer_size = 0; */
527 /* server->conn_status = 0; */
528 /* server->root_dentry = NULL; */
529 /* server->root_setuped = 0; */
530 #ifdef CONFIG_NCPFS_PACKET_SIGNING
531 /* server->sign_wanted = 0; */
532 /* server->sign_active = 0; */
534 server->auth.auth_type = NCP_AUTH_NONE;
535 /* server->auth.object_name_len = 0; */
536 /* server->auth.object_name = NULL; */
537 /* server->auth.object_type = 0; */
538 /* server->priv.len = 0; */
539 /* server->priv.data = NULL; */
542 /* Althought anything producing this is buggy, it happens
543 now because of PATH_MAX changes.. */
544 if (server->m.time_out < 1) {
545 server->m.time_out = 10;
546 printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
548 server->m.time_out = server->m.time_out * HZ / 100;
549 server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
550 server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
552 #ifdef CONFIG_NCPFS_NLS
553 /* load the default NLS charsets */
554 server->nls_vol = load_nls_default();
555 server->nls_io = load_nls_default();
556 #endif /* CONFIG_NCPFS_NLS */
558 server->dentry_ttl = 0; /* no caching */
560 INIT_LIST_HEAD(&server->tx.requests);
561 init_MUTEX(&server->rcv.creq_sem);
562 server->tx.creq = NULL;
563 server->rcv.creq = NULL;
564 server->data_ready = sock->sk->sk_data_ready;
565 server->write_space = sock->sk->sk_write_space;
566 server->error_report = sock->sk->sk_error_report;
567 sock->sk->sk_user_data = server;
569 init_timer(&server->timeout_tm);
570 #undef NCP_PACKET_SIZE
571 #define NCP_PACKET_SIZE 131072
573 server->packet_size = NCP_PACKET_SIZE;
574 server->packet = vmalloc(NCP_PACKET_SIZE);
575 if (server->packet == NULL)
578 sock->sk->sk_data_ready = ncp_tcp_data_ready;
579 sock->sk->sk_error_report = ncp_tcp_error_report;
580 if (sock->type == SOCK_STREAM) {
581 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
582 server->rcv.len = 10;
583 server->rcv.state = 0;
584 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc, server);
585 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc, server);
586 sock->sk->sk_write_space = ncp_tcp_write_space;
588 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc, server);
589 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc, server);
590 server->timeout_tm.data = (unsigned long)server;
591 server->timeout_tm.function = ncpdgram_timeout_call;
594 ncp_lock_server(server);
595 error = ncp_connect(server);
596 ncp_unlock_server(server);
599 DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
601 error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */
602 #ifdef CONFIG_NCPFS_PACKET_SIGNING
603 if (ncp_negotiate_size_and_options(server, default_bufsize,
604 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
606 if (options != NCP_DEFAULT_OPTIONS)
608 if (ncp_negotiate_size_and_options(server,
611 &(server->buffer_size), &options) != 0)
618 server->sign_wanted = 1;
621 #endif /* CONFIG_NCPFS_PACKET_SIGNING */
622 if (ncp_negotiate_buffersize(server, default_bufsize,
623 &(server->buffer_size)) != 0)
625 DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
627 memset(&finfo, 0, sizeof(finfo));
628 finfo.i.attributes = aDIR;
629 finfo.i.dataStreamSize = NCP_BLOCK_SIZE;
630 finfo.i.dirEntNum = 0;
631 finfo.i.DosDirNum = 0;
632 #ifdef CONFIG_NCPFS_SMALLDOS
633 finfo.i.NSCreator = NW_NS_DOS;
635 finfo.volume = NCP_NUMBER_OF_VOLUMES;
636 /* set dates of mountpoint to Jan 1, 1986; 00:00 */
637 finfo.i.creationTime = finfo.i.modifyTime
638 = cpu_to_le16(0x0000);
639 finfo.i.creationDate = finfo.i.modifyDate
640 = finfo.i.lastAccessDate
641 = cpu_to_le16(0x0C21);
643 finfo.i.entryName[0] = '\0';
646 finfo.ino = 2; /* tradition */
648 server->name_space[finfo.volume] = NW_NS_DOS;
651 root_inode = ncp_iget(sb, &finfo);
654 DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
655 sb->s_root = d_alloc_root(root_inode);
658 sb->s_root->d_op = &ncp_root_dentry_operations;
664 ncp_lock_server(server);
665 ncp_disconnect(server);
666 ncp_unlock_server(server);
668 ncp_stop_tasks(server);
669 vfree(server->packet);
671 #ifdef CONFIG_NCPFS_NLS
672 unload_nls(server->nls_io);
673 unload_nls(server->nls_vol);
676 if (server->info_filp)
677 fput(server->info_filp);
679 /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
681 * The previously used put_filp(ncp_filp); was bogous, since
682 * it doesn't proper unlocking.
686 sb->s_fs_info = NULL;
691 static void ncp_put_super(struct super_block *sb)
693 struct ncp_server *server = NCP_SBP(sb);
695 ncp_lock_server(server);
696 ncp_disconnect(server);
697 ncp_unlock_server(server);
699 ncp_stop_tasks(server);
701 #ifdef CONFIG_NCPFS_NLS
702 /* unload the NLS charsets */
705 unload_nls(server->nls_vol);
706 server->nls_vol = NULL;
710 unload_nls(server->nls_io);
711 server->nls_io = NULL;
713 #endif /* CONFIG_NCPFS_NLS */
715 if (server->info_filp)
716 fput(server->info_filp);
717 fput(server->ncp_filp);
718 kill_proc(server->m.wdog_pid, SIGTERM, 1);
720 if (server->priv.data)
721 ncp_kfree_s(server->priv.data, server->priv.len);
722 if (server->auth.object_name)
723 ncp_kfree_s(server->auth.object_name, server->auth.object_name_len);
724 vfree(server->packet);
725 sb->s_fs_info = NULL;
729 static int ncp_statfs(struct super_block *sb, struct kstatfs *buf)
733 struct ncp_inode_info* ni;
734 struct ncp_server* s;
735 struct ncp_volume_info vi;
755 if (!s->m.mounted_vol[0]) {
759 err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
763 err = ncp_get_directory_info(s, dh, &vi);
764 ncp_dirhandle_free(s, dh);
768 buf->f_type = NCP_SUPER_MAGIC;
769 buf->f_bsize = vi.sectors_per_block * 512;
770 buf->f_blocks = vi.total_blocks;
771 buf->f_bfree = vi.free_blocks;
772 buf->f_bavail = vi.free_blocks;
773 buf->f_files = vi.total_dir_entries;
774 buf->f_ffree = vi.available_dir_entries;
778 /* We cannot say how much disk space is left on a mounted
779 NetWare Server, because free space is distributed over
780 volumes, and the current user might have disk quotas. So
781 free space is not that simple to determine. Our decision
782 here is to err conservatively. */
785 buf->f_type = NCP_SUPER_MAGIC;
786 buf->f_bsize = NCP_BLOCK_SIZE;
794 int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
796 struct inode *inode = dentry->d_inode;
799 struct nw_modify_dos_info info;
800 struct ncp_server *server;
806 server = NCP_SERVER(inode);
807 if ((!server) || !ncp_conn_valid(server))
810 /* ageing the dentry to force validation */
811 ncp_age_dentry(server, dentry);
813 result = inode_change_ok(inode, attr);
818 if (((attr->ia_valid & ATTR_UID) &&
819 (attr->ia_uid != server->m.uid)))
822 if (((attr->ia_valid & ATTR_GID) &&
823 (attr->ia_gid != server->m.gid)))
826 if (((attr->ia_valid & ATTR_MODE) &&
828 ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
832 memset(&info, 0, sizeof(info));
835 if ((attr->ia_valid & ATTR_MODE) != 0)
837 umode_t newmode = attr->ia_mode;
839 info_mask |= DM_ATTRIBUTES;
841 if (S_ISDIR(inode->i_mode)) {
842 newmode &= server->m.dir_mode;
844 #ifdef CONFIG_NCPFS_EXTRAS
845 if (server->m.flags & NCP_MOUNT_EXTRAS) {
846 /* any non-default execute bit set */
847 if (newmode & ~server->m.file_mode & S_IXUGO)
848 info.attributes |= aSHARED | aSYSTEM;
849 /* read for group/world and not in default file_mode */
850 else if (newmode & ~server->m.file_mode & S_IRUGO)
851 info.attributes |= aSHARED;
854 newmode &= server->m.file_mode;
856 if (newmode & S_IWUGO)
857 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
859 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
861 #ifdef CONFIG_NCPFS_NFS_NS
862 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
863 result = ncp_modify_nfs_info(server,
864 NCP_FINFO(inode)->volNumber,
865 NCP_FINFO(inode)->dirEntNum,
869 info.attributes &= ~(aSHARED | aSYSTEM);
871 /* mark partial success */
872 struct iattr tmpattr;
874 tmpattr.ia_valid = ATTR_MODE;
875 tmpattr.ia_mode = attr->ia_mode;
877 result = inode_setattr(inode, &tmpattr);
886 /* Do SIZE before attributes, otherwise mtime together with size does not work...
888 if ((attr->ia_valid & ATTR_SIZE) != 0) {
891 DPRINTK("ncpfs: trying to change size to %ld\n",
894 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
898 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
899 attr->ia_size, 0, "", &written);
901 /* According to ndir, the changes only take effect after
903 ncp_inode_close(inode);
904 result = ncp_make_closed(inode);
908 struct iattr tmpattr;
910 tmpattr.ia_valid = ATTR_SIZE;
911 tmpattr.ia_size = attr->ia_size;
913 result = inode_setattr(inode, &tmpattr);
918 if ((attr->ia_valid & ATTR_CTIME) != 0) {
919 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
920 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
921 &(info.creationTime), &(info.creationDate));
922 info.creationTime = le16_to_cpu(info.creationTime);
923 info.creationDate = le16_to_cpu(info.creationDate);
925 if ((attr->ia_valid & ATTR_MTIME) != 0) {
926 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
927 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
928 &(info.modifyTime), &(info.modifyDate));
929 info.modifyTime = le16_to_cpu(info.modifyTime);
930 info.modifyDate = le16_to_cpu(info.modifyDate);
932 if ((attr->ia_valid & ATTR_ATIME) != 0) {
934 info_mask |= (DM_LAST_ACCESS_DATE);
935 ncp_date_unix2dos(attr->ia_atime.tv_sec,
936 &(dummy), &(info.lastAccessDate));
937 info.lastAccessDate = le16_to_cpu(info.lastAccessDate);
939 if (info_mask != 0) {
940 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
941 inode, info_mask, &info);
945 if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
946 /* NetWare seems not to allow this. I
947 do not know why. So, just tell the
948 user everything went fine. This is
949 a terrible hack, but I do not know
950 how to do this correctly. */
955 #ifdef CONFIG_NCPFS_STRONG
956 if ((!result) && (info_mask & DM_ATTRIBUTES))
957 NCP_FINFO(inode)->nwattr = info.attributes;
961 result = inode_setattr(inode, attr);
967 #ifdef DEBUG_NCP_MALLOC
969 int ncp_current_malloced;
972 static struct super_block *ncp_get_sb(struct file_system_type *fs_type,
973 int flags, const char *dev_name, void *data)
975 return get_sb_nodev(fs_type, flags, data, ncp_fill_super);
978 static struct file_system_type ncp_fs_type = {
979 .owner = THIS_MODULE,
981 .get_sb = ncp_get_sb,
982 .kill_sb = kill_anon_super,
985 static int __init init_ncp_fs(void)
988 DPRINTK("ncpfs: init_module called\n");
990 #ifdef DEBUG_NCP_MALLOC
992 ncp_current_malloced = 0;
994 err = init_inodecache();
997 err = register_filesystem(&ncp_fs_type);
1002 destroy_inodecache();
1007 static void __exit exit_ncp_fs(void)
1009 DPRINTK("ncpfs: cleanup_module called\n");
1010 unregister_filesystem(&ncp_fs_type);
1011 destroy_inodecache();
1012 #ifdef DEBUG_NCP_MALLOC
1013 PRINTK("ncp_malloced: %d\n", ncp_malloced);
1014 PRINTK("ncp_current_malloced: %d\n", ncp_current_malloced);
1018 module_init(init_ncp_fs)
1019 module_exit(exit_ncp_fs)
1020 MODULE_LICENSE("GPL");