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
11 #include <linux/config.h>
12 #include <linux/module.h>
14 #include <asm/system.h>
15 #include <asm/uaccess.h>
16 #include <asm/byteorder.h>
18 #include <linux/sched.h>
19 #include <linux/kernel.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>
31 #include <linux/ncp_fs.h>
33 #include "ncplib_kernel.h"
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 *);
39 static struct super_operations ncp_sops =
41 put_inode: force_delete,
42 delete_inode: ncp_delete_inode,
43 put_super: ncp_put_super,
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*);
54 * Fill in the ncpfs-specific information in the inode.
56 void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
58 NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
59 NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
60 NCP_FINFO(inode)->volNumber = nwinfo->i.volNumber;
62 #ifdef CONFIG_NCPFS_STRONG
63 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
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);
74 void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
76 struct nw_info_struct *nwi = &nwinfo->i;
77 struct ncp_server *server = NCP_SERVER(inode);
79 if (!atomic_read(&NCP_FINFO(inode)->opened)) {
80 #ifdef CONFIG_NCPFS_STRONG
81 NCP_FINFO(inode)->nwattr = nwi->attributes;
83 if (nwi->attributes & aDIR) {
84 inode->i_mode = server->m.dir_mode;
85 inode->i_size = NCP_BLOCK_SIZE;
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)) {
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;
102 if (server->m.flags & NCP_MOUNT_EXTRAS)
103 inode->i_mode |= 0444;
106 if (server->m.flags & NCP_MOUNT_EXTRAS)
107 inode->i_mode |= (inode->i_mode >> 2) & 0111;
109 /* case aSYSTEM|aHIDDEN: */
111 /* reserved combination */
117 if (nwi->attributes & aRONLY) inode->i_mode &= ~0222;
119 inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
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));
127 NCP_FINFO(inode)->DosDirNum = nwi->DosDirNum;
128 NCP_FINFO(inode)->dirEntNum = nwi->dirEntNum;
129 NCP_FINFO(inode)->volNumber = nwi->volNumber;
133 * Fill in the inode based on the ncp_entry_info structure.
135 static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
137 struct nw_info_struct *nwi = &nwinfo->i;
138 struct ncp_server *server = NCP_SERVER(inode);
140 if (nwi->attributes & aDIR) {
141 inode->i_mode = server->m.dir_mode;
142 /* for directories dataStreamSize seems to be some
144 inode->i_size = NCP_BLOCK_SIZE;
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)) {
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;
162 if (server->m.flags & NCP_MOUNT_EXTRAS)
163 inode->i_mode |= 0444;
166 if (server->m.flags & NCP_MOUNT_EXTRAS)
167 inode->i_mode |= (inode->i_mode >> 2) & 0111;
169 /* case aSYSTEM|aHIDDEN: */
171 /* reserved combination */
177 if (nwi->attributes & aRONLY) inode->i_mode &= ~0222;
179 DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
182 inode->i_uid = server->m.uid;
183 inode->i_gid = server->m.gid;
185 inode->i_blksize = NCP_BLOCK_SIZE;
187 inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
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);
198 static struct inode_operations ncp_symlink_inode_operations = {
199 readlink: page_readlink,
200 follow_link: page_follow_link,
201 setattr: ncp_notify_change,
208 ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
213 printk(KERN_ERR "ncp_iget: info is NULL\n");
217 inode = new_inode(sb);
219 init_MUTEX(&NCP_FINFO(inode)->open_sem);
220 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
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;
236 insert_inode_hash(inode);
238 printk(KERN_ERR "ncp_iget: iget failed!\n");
243 ncp_delete_inode(struct inode *inode)
245 if (S_ISDIR(inode->i_mode)) {
246 DDPRINTK("ncp_delete_inode: put directory %ld\n", inode->i_ino);
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");
257 ncp_read_super(struct super_block *sb, void *raw_data, int silent)
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;
267 #ifdef CONFIG_NCPFS_PACKET_SIGNING
270 struct ncp_entry_info finfo;
272 if (raw_data == NULL)
274 switch (*(int*)raw_data) {
275 case NCP_MOUNT_VERSION:
277 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
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;
288 data.file_mode = md->file_mode;
289 data.dir_mode = md->dir_mode;
290 memcpy(data.mounted_vol, md->mounted_vol,
294 case NCP_MOUNT_VERSION_V4:
296 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
298 data.flags = md->flags;
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;
307 data.file_mode = md->file_mode;
308 data.dir_mode = md->dir_mode;
309 data.mounted_vol[0] = 0;
315 ncp_filp = fget(data.ncp_fd);
318 sock_inode = ncp_filp->f_dentry->d_inode;
319 if (!S_ISSOCK(sock_inode->i_mode))
321 sock = &sock_inode->u.socket_i;
325 if (sock->type == SOCK_STREAM)
326 default_bufsize = 61440;
328 default_bufsize = 1024;
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;
335 server = NCP_SBP(sb);
336 memset(server, 0, sizeof(*server));
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; */
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; */
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");
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;
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 */
376 server->dentry_ttl = 0; /* no caching */
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)
385 ncp_lock_server(server);
386 error = ncp_connect(server);
387 ncp_unlock_server(server);
390 DPRINTK("ncp_read_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
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)
396 if (options != NCP_DEFAULT_OPTIONS)
398 if (ncp_negotiate_size_and_options(server,
401 &(server->buffer_size), &options) != 0)
408 server->sign_wanted = 1;
411 #endif /* CONFIG_NCPFS_PACKET_SIGNING */
412 if (ncp_negotiate_buffersize(server, default_bufsize,
413 &(server->buffer_size)) != 0)
415 DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
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;
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);
433 finfo.i.entryName[0] = '\0';
436 finfo.ino = 2; /* tradition */
438 server->name_space[finfo.i.volNumber] = NW_NS_DOS;
439 root_inode = ncp_iget(sb, &finfo);
442 DPRINTK("ncp_read_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
443 sb->s_root = d_alloc_root(root_inode);
446 sb->s_root->d_op = &ncp_root_dentry_operations;
450 printk(KERN_ERR "ncp_read_super: get root inode failed\n");
454 printk(KERN_ERR "ncp_read_super: could not get bufsize\n");
456 ncp_lock_server(server);
457 ncp_disconnect(server);
458 ncp_unlock_server(server);
459 goto out_free_packet;
461 printk(KERN_ERR "ncp_read_super: Failed connection, error=%d\n", error);
463 vfree(server->packet);
464 goto out_free_server;
466 printk(KERN_ERR "ncp_read_super: could not alloc packet\n");
468 #ifdef CONFIG_NCPFS_NLS
469 unload_nls(server->nls_io);
470 unload_nls(server->nls_vol);
472 /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
474 * The previously used put_filp(ncp_filp); was bogous, since
475 * it doesn't proper unlocking.
483 printk(KERN_ERR "ncp_read_super: invalid ncp socket\n");
486 printk(KERN_INFO "ncp_read_super: kernel requires mount version %d\n",
490 printk(KERN_ERR "ncp_read_super: missing data argument\n");
495 static void ncp_put_super(struct super_block *sb)
497 struct ncp_server *server = NCP_SBP(sb);
499 ncp_lock_server(server);
500 ncp_disconnect(server);
501 ncp_unlock_server(server);
503 #ifdef CONFIG_NCPFS_NLS
504 /* unload the NLS charsets */
507 unload_nls(server->nls_vol);
508 server->nls_vol = NULL;
512 unload_nls(server->nls_io);
513 server->nls_io = NULL;
515 #endif /* CONFIG_NCPFS_NLS */
517 fput(server->ncp_filp);
518 kill_proc(server->m.wdog_pid, SIGTERM, 1);
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);
528 static int ncp_statfs(struct super_block *sb, struct statfs *buf)
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. */
536 buf->f_type = NCP_SUPER_MAGIC;
537 buf->f_bsize = NCP_BLOCK_SIZE;
545 int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
547 struct inode *inode = dentry->d_inode;
550 struct nw_modify_dos_info info;
551 struct ncp_server *server;
555 server = NCP_SERVER(inode);
556 if ((!server) || !ncp_conn_valid(server))
559 /* ageing the dentry to force validation */
560 ncp_age_dentry(server, dentry);
562 result = inode_change_ok(inode, attr);
567 if (((attr->ia_valid & ATTR_UID) &&
568 (attr->ia_uid != server->m.uid)))
571 if (((attr->ia_valid & ATTR_GID) &&
572 (attr->ia_gid != server->m.gid)))
575 if (((attr->ia_valid & ATTR_MODE) &&
577 ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
581 memset(&info, 0, sizeof(info));
584 if ((attr->ia_valid & ATTR_MODE) != 0)
586 if (S_ISDIR(inode->i_mode)) {
589 info_mask |= DM_ATTRIBUTES;
590 newmode = attr->ia_mode;
591 newmode &= NCP_SERVER(inode)->m.dir_mode;
594 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
596 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
597 } else if (!S_ISREG(inode->i_mode))
604 #ifdef CONFIG_NCPFS_EXTRAS
607 extras = server->m.flags & NCP_MOUNT_EXTRAS;
609 info_mask |= DM_ATTRIBUTES;
610 newmode=attr->ia_mode;
611 #ifdef CONFIG_NCPFS_EXTRAS
614 newmode &= server->m.file_mode;
616 if (newmode & 0222) /* any write bit set */
618 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
622 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
624 #ifdef CONFIG_NCPFS_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;
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);
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);
651 if ((attr->ia_valid & ATTR_ATIME) != 0) {
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);
658 if (info_mask != 0) {
659 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
660 inode, info_mask, &info);
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. */
673 #ifdef CONFIG_NCPFS_STRONG
674 if ((!result) && (info_mask & DM_ATTRIBUTES))
675 NCP_FINFO(inode)->nwattr = info.attributes;
678 if ((attr->ia_valid & ATTR_SIZE) != 0) {
681 DPRINTK("ncpfs: trying to change size to %ld\n",
684 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
687 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
688 attr->ia_size, 0, "", &written);
690 /* According to ndir, the changes only take effect after
692 ncp_inode_close(inode);
693 result = ncp_make_closed(inode);
695 result = vmtruncate(inode, attr->ia_size);
701 #ifdef DEBUG_NCP_MALLOC
703 int ncp_current_malloced;
706 static DECLARE_FSTYPE(ncp_fs_type, "ncpfs", ncp_read_super, 0);
708 static int __init init_ncp_fs(void)
710 DPRINTK("ncpfs: init_module called\n");
712 #ifdef DEBUG_NCP_MALLOC
714 ncp_current_malloced = 0;
716 return register_filesystem(&ncp_fs_type);
719 static void __exit exit_ncp_fs(void)
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);
731 module_init(init_ncp_fs)
732 module_exit(exit_ncp_fs)
733 MODULE_LICENSE("GPL");