diff options
Diffstat (limited to 'fs/ncpfs')
-rw-r--r-- | fs/ncpfs/.cvsignore | 1 | ||||
-rw-r--r-- | fs/ncpfs/Config.in | 10 | ||||
-rw-r--r-- | fs/ncpfs/Makefile | 6 | ||||
-rw-r--r-- | fs/ncpfs/dir.c | 217 | ||||
-rw-r--r-- | fs/ncpfs/file.c | 15 | ||||
-rw-r--r-- | fs/ncpfs/inode.c | 155 | ||||
-rw-r--r-- | fs/ncpfs/ioctl.c | 367 | ||||
-rw-r--r-- | fs/ncpfs/mmap.c | 6 | ||||
-rw-r--r-- | fs/ncpfs/ncplib_kernel.c | 290 | ||||
-rw-r--r-- | fs/ncpfs/ncplib_kernel.h | 22 | ||||
-rw-r--r-- | fs/ncpfs/sock.c | 27 |
11 files changed, 979 insertions, 137 deletions
diff --git a/fs/ncpfs/.cvsignore b/fs/ncpfs/.cvsignore index 4671378ae..857dd22e9 100644 --- a/fs/ncpfs/.cvsignore +++ b/fs/ncpfs/.cvsignore @@ -1 +1,2 @@ .depend +.*.flags diff --git a/fs/ncpfs/Config.in b/fs/ncpfs/Config.in new file mode 100644 index 000000000..48cf4aa86 --- /dev/null +++ b/fs/ncpfs/Config.in @@ -0,0 +1,10 @@ +# +# NCP Filesystem configuration +# +# bool ' Packet singatures' CONFIG_NCPFS_PACKET_SIGNING +bool ' Proprietary file locking' CONFIG_NCPFS_IOCTL_LOCKING +bool ' Clear remove/delete inhibit when needed' CONFIG_NCPFS_STRONG +bool ' Use NFS namespace if available' CONFIG_NCPFS_NFS_NS +bool ' Use LONG (OS/2) namespace if available' CONFIG_NCPFS_OS2_NS +bool ' Allow mounting of volume subdirectories' CONFIG_NCPFS_MOUNT_SUBDIR +# bool ' NDS interserver authentication support' CONFIG_NCPFS_NDS_DOMAINS diff --git a/fs/ncpfs/Makefile b/fs/ncpfs/Makefile index be43c491b..5c83ada11 100644 --- a/fs/ncpfs/Makefile +++ b/fs/ncpfs/Makefile @@ -12,10 +12,8 @@ O_OBJS := dir.o file.o inode.o ioctl.o mmap.o ncplib_kernel.o sock.o M_OBJS := $(O_TARGET) # If you want debugging output, please uncomment the following line - # EXTRA_CFLAGS += -DDEBUG_NCP=1 -include $(TOPDIR)/Rules.make +CFLAGS_ncplib_kernel.o := -finline-functions -ncplib_kernel.o: ncplib_kernel.c ncplib_kernel.h - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -finline-functions -c -o $@ $< +include $(TOPDIR)/Rules.make diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 005431485..8424b2ec7 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -7,6 +7,8 @@ * */ +#include <linux/config.h> + #include <linux/sched.h> #include <linux/errno.h> #include <linux/stat.h> @@ -105,10 +107,10 @@ ncp_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos) /* * Dentry operations routines */ -static int ncp_lookup_validate(struct dentry *); -static void ncp_delete_dentry(struct dentry *); +static int ncp_lookup_validate(struct dentry *); static int ncp_hash_dentry(struct dentry *, struct qstr *); static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *); +static void ncp_delete_dentry(struct dentry *); static struct dentry_operations ncp_dentry_operations = { @@ -125,19 +127,23 @@ static struct dentry_operations ncp_dentry_operations = */ #define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)-('A'-'a') : (c)) - +/* + * Note: leave the hash unchanged if the directory + * is case-sensitive. + */ static int ncp_hash_dentry(struct dentry *dentry, struct qstr *this) { - unsigned long hash; - int i; - - hash = init_name_hash(); - for (i=0; i<this->len ; i++) - hash = partial_name_hash(tolower(this->name[i]),hash); - this->hash = end_name_hash(hash); - - return 0; + unsigned long hash; + int i; + + if (!ncp_case_sensitive(dentry->d_inode)) { + hash = init_name_hash(); + for (i=0; i<this->len ; i++) + hash = partial_name_hash(tolower(this->name[i]),hash); + this->hash = end_name_hash(hash); + } + return 0; } static int @@ -202,45 +208,17 @@ dentry->d_parent->d_name.name, dentry->d_name.name); */ ino_t ncp_invent_inos(unsigned long n) { - static ino_t ino = 1; + static ino_t ino = 2; if (ino + 2*n < ino) { /* wrap around */ - ino += n; + ino = 2; } ino += n; return ino; } -/* - * Check whether a dentry already exists for the given name, - * and return the inode number if it has an inode. This is - * needed to keep getcwd() working. - */ -static ino_t -find_inode_number(struct dentry *dir, struct qstr *name) -{ - unsigned long hash; - int i; - struct dentry * dentry; - ino_t ino = 0; - - hash = init_name_hash(); - for (i=0; i<name->len ; i++) - hash = partial_name_hash(tolower(name->name[i]),hash); - name->hash = end_name_hash(hash); - - dentry = d_lookup(dir, name); - if (dentry) - { - if (dentry->d_inode) - ino = dentry->d_inode->i_ino; - dput(dentry); - } - return ino; -} - static inline int ncp_single_volume(struct ncp_server *server) { @@ -271,6 +249,98 @@ static inline void ncp_unlock_dircache(void) * This is the callback when the dcache has a lookup hit. */ + +#ifdef CONFIG_NCPFS_STRONG +/* try to delete a readonly file (NW R bit set) */ + +static int +ncp_force_unlink(struct inode *dir, struct dentry* dentry) +{ + int res=0x9c,res2; + struct iattr ia; + + /* remove the Read-Only flag on the NW server */ + + memset(&ia,0,sizeof(struct iattr)); + ia.ia_mode = dentry->d_inode->i_mode; + ia.ia_mode |= NCP_SERVER(dir)->m.file_mode & 0222; /* set write bits */ + ia.ia_valid = ATTR_MODE; + + res2=ncp_notify_change(dentry, &ia); + if (res2) + { + goto leave_me; + } + + /* now try again the delete operation */ + + res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry); + + if (res) /* delete failed, set R bit again */ + { + memset(&ia,0,sizeof(struct iattr)); + ia.ia_mode = dentry->d_inode->i_mode; + ia.ia_mode &= ~(NCP_SERVER(dir)->m.file_mode & 0222); /* clear write bits */ + ia.ia_valid = ATTR_MODE; + + res2=ncp_notify_change(dentry, &ia); + if (res2) + { + goto leave_me; + } + } +leave_me: + return(res); +} +#endif /* CONFIG_NCPFS_STRONG */ + +#ifdef CONFIG_NCPFS_STRONG +static int +ncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name, + struct inode *new_dir, struct dentry* new_dentry, char *_new_name) +{ + int res=0x90,res2; + struct iattr ia; + + /* remove the Read-Only flag on the NW server */ + + memset(&ia,0,sizeof(struct iattr)); + ia.ia_mode = old_dentry->d_inode->i_mode; + ia.ia_mode |= NCP_SERVER(old_dir)->m.file_mode & 0222; /* set write bits */ + ia.ia_valid = ATTR_MODE; + + res2=ncp_notify_change(old_dentry, &ia); + if (res2) + { + goto leave_me; + } + + /* now try again the rename operation */ + res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir), + old_dir, _old_name, + new_dir, _new_name); + + memset(&ia,0,sizeof(struct iattr)); + ia.ia_mode = old_dentry->d_inode->i_mode; + ia.ia_mode &= ~(NCP_SERVER(old_dentry->d_inode)->m.file_mode & 0222); /* clear write bits */ + ia.ia_valid = ATTR_MODE; + + /* FIXME: uses only inode info, no dentry info... so it is safe to call */ + /* it now with old dentry. If we use name (in future), we have to move */ + /* it after dentry_move in caller */ + res2=ncp_notify_change(old_dentry, &ia); + if (res2) + { + printk(KERN_INFO "ncpfs: ncp_notify_change (2) failed: %08x\n",res2); + goto leave_me; + } + + leave_me: + return(res); +} +#endif /* CONFIG_NCPFS_STRONG */ + + static int ncp_lookup_validate(struct dentry * dentry) { @@ -338,13 +408,15 @@ dentry->d_parent->d_name.name, __name, res); * If we didn't find it, or if it has a different dirEntNum to * what we remember, it's not valid any more. */ - if (!res) + if (!res) { if (finfo.nw_info.i.dirEntNum == NCP_FINFO(dentry->d_inode)->dirEntNum) val=1; #ifdef NCPFS_PARANOIA else printk(KERN_DEBUG "ncp_lookup_validate: found, but dirEntNum changed\n"); #endif + ncp_update_inode2(dentry->d_inode, &finfo.nw_info); + } if (!val) ncp_invalid_dir_cache(dir); finished: @@ -641,6 +713,8 @@ int ncp_conn_logged_in(struct ncp_server *server) int result; if (ncp_single_volume(server)) { + struct dentry* dent; + result = -ENOENT; str_upper(server->m.mounted_vol); if (ncp_lookup_volume(server, server->m.mounted_vol, @@ -651,6 +725,19 @@ printk(KERN_DEBUG "ncp_conn_logged_in: %s not found\n", server->m.mounted_vol); goto out; } str_lower(server->root.finfo.i.entryName); + dent = server->root_dentry; + if (dent) { + struct inode* ino = dent->d_inode; + if (ino) { + NCP_FINFO(ino)->volNumber = server->root.finfo.i.volNumber; + NCP_FINFO(ino)->dirEntNum = server->root.finfo.i.dirEntNum; + NCP_FINFO(ino)->DosDirNum = server->root.finfo.i.DosDirNum; + } else { + DPRINTK(KERN_DEBUG "ncpfs: sb->root_dentry->d_inode == NULL!\n"); + } + } else { + DPRINTK(KERN_DEBUG "ncpfs: sb->root_dentry == NULL!\n"); + } } result = 0; @@ -838,6 +925,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, mode); finfo.nw_info.access = O_RDWR; error = ncp_instantiate(dir, dentry, &finfo); } else { + if (result == 0x87) error = -ENAMETOOLONG; DPRINTK(KERN_DEBUG "ncp_create: %s/%s failed\n", dentry->d_parent->d_name.name, dentry->d_name.name); } @@ -928,8 +1016,7 @@ out: static int ncp_unlink(struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; - int error, result; - __u8 _name[dentry->d_name.len + 1]; + int error; DPRINTK(KERN_DEBUG "ncp_unlink: unlinking %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name); @@ -953,21 +1040,23 @@ printk(KERN_DEBUG "ncp_unlink: closing file\n"); ncp_make_closed(inode); } - strncpy(_name, dentry->d_name.name, dentry->d_name.len); - _name[dentry->d_name.len] = '\0'; - if (!ncp_preserve_case(dir)) - { - str_upper(_name); + error = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry); +#ifdef CONFIG_NCPFS_STRONG + if (error == 0x9C && NCP_SERVER(dir)->m.flags & NCP_MOUNT_STRONG) { /* R/O */ + error = ncp_force_unlink(dir, dentry); } - error = -EACCES; - result = ncp_del_file_or_subdir(NCP_SERVER(dir), dir, _name); - if (!result) { +#endif + if (!error) { DPRINTK(KERN_DEBUG "ncp: removed %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name); ncp_invalid_dir_cache(dir); d_delete(dentry); - error = 0; + } else if (error == 0xFF) { + error = -ENOENT; + } else { + error = -EACCES; } + out: return error; } @@ -977,7 +1066,7 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry, { int old_len = old_dentry->d_name.len; int new_len = new_dentry->d_name.len; - int error, result; + int error; char _old_name[old_dentry->d_name.len + 1]; char _new_name[new_dentry->d_name.len + 1]; @@ -1010,18 +1099,28 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry, str_upper(_new_name); } - error = -EACCES; - result = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir), + error = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir), old_dir, _old_name, new_dir, _new_name); - if (result == 0) +#ifdef CONFIG_NCPFS_STRONG + if (error == 0x90 && NCP_SERVER(old_dir)->m.flags & NCP_MOUNT_STRONG) { /* RO */ + error = ncp_force_rename(old_dir, old_dentry, _old_name, new_dir, new_dentry, _new_name); + } +#endif + if (error == 0) { DPRINTK(KERN_DEBUG "ncp renamed %s -> %s.\n", old_dentry->d_name.name,new_dentry->d_name.name); ncp_invalid_dir_cache(old_dir); ncp_invalid_dir_cache(new_dir); d_move(old_dentry,new_dentry); - error = 0; + } else { + if (error == 0x9E) + error = -ENAMETOOLONG; + else if (error == 0xFF) + error = -ENOENT; + else + error = -EACCES; } out: return error; diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c index 2f22f25d1..d26fee881 100644 --- a/fs/ncpfs/file.c +++ b/fs/ncpfs/file.c @@ -15,11 +15,12 @@ #include <linux/fcntl.h> #include <linux/stat.h> #include <linux/mm.h> -#include <linux/ncp_fs.h> #include <linux/locks.h> -#include "ncplib_kernel.h" #include <linux/malloc.h> +#include <linux/ncp_fs.h> +#include "ncplib_kernel.h" + static inline int min(int a, int b) { return a < b ? a : b; @@ -65,7 +66,7 @@ int ncp_make_open(struct inode *inode, int right) result = ncp_open_create_file_or_subdir(NCP_SERVER(inode), NULL, NULL, OC_MODE_OPEN, 0, AR_READ, &finfo); - if (!result) { + if (result) { #ifdef NCPFS_PARANOIA printk(KERN_DEBUG "ncp_make_open: failed, result=%d\n", result); #endif @@ -82,11 +83,7 @@ printk(KERN_DEBUG "ncp_make_open: failed, result=%d\n", result); #ifdef NCPFS_PARANOIA printk(KERN_DEBUG "ncp_make_open: file open, access=%x\n", access); #endif - if (((right == O_RDONLY) && ((access == O_RDONLY) - || (access == O_RDWR))) - || ((right == O_WRONLY) && ((access == O_WRONLY) - || (access == O_RDWR))) - || ((right == O_RDWR) && (access == O_RDWR))) + if (access == right || access == O_RDWR) error = 0; out_unlock: @@ -231,7 +228,7 @@ ncp_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) } } - inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_mtime = inode->i_atime = CURRENT_TIME; file->f_pos = pos; diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 61cdd0319..f11f4640c 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -32,12 +32,9 @@ #include <linux/ncp_fs.h> #include "ncplib_kernel.h" -extern int close_fp(struct file *filp); - static void ncp_read_inode(struct inode *); static void ncp_put_inode(struct inode *); static void ncp_delete_inode(struct inode *); -static int ncp_notify_change(struct inode *, struct iattr *); static void ncp_put_super(struct super_block *); static int ncp_statfs(struct super_block *, struct statfs *, int); @@ -54,6 +51,8 @@ static struct super_operations ncp_sops = NULL /* remount */ }; +extern struct dentry_operations ncp_dentry_operations; + static struct nw_file_info *read_nwinfo = NULL; static struct semaphore read_sem = MUTEX; @@ -77,6 +76,31 @@ nwinfo->i.entryName, NCP_FINFO(inode)->volNumber, NCP_FINFO(inode)->dirEntNum); #endif } +void ncp_update_inode2(struct inode* inode, struct nw_file_info *nwinfo) +{ + struct nw_info_struct *nwi = &nwinfo->i; + struct ncp_server *server = NCP_SERVER(inode); + + if (!NCP_FINFO(inode)->opened) { + if (nwi->attributes & aDIR) { + inode->i_mode = server->m.dir_mode; + inode->i_size = 512; + } else { + inode->i_mode = server->m.file_mode; + inode->i_size = le32_to_cpu(nwi->dataStreamSize); + } + if (nwi->attributes & aRONLY) inode->i_mode &= ~0222; + } + inode->i_blocks = 0; + if ((inode->i_size)&&(inode->i_blksize)) { + inode->i_blocks = (inode->i_size-1)/(inode->i_blksize)+1; + } + /* TODO: times? I'm not sure... */ + NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum; + NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum; + NCP_FINFO(inode)->volNumber = nwinfo->i.volNumber; +} + /* * Fill in the inode based on the nw_file_info structure. */ @@ -94,6 +118,7 @@ static void ncp_set_attr(struct inode *inode, struct nw_file_info *nwinfo) inode->i_mode = server->m.file_mode; inode->i_size = le32_to_cpu(nwi->dataStreamSize); } + if (nwi->attributes & aRONLY) inode->i_mode &= ~0222; DDPRINTK(KERN_DEBUG "ncp_read_inode: inode->i_mode = %u\n", inode->i_mode); @@ -210,8 +235,9 @@ static void ncp_init_root(struct ncp_server *server, i->entryName[0] = '\0'; root->finfo.opened= 0; - info->ino = 1; + info->ino = 2; /* tradition */ info->nw_info = root->finfo; + return; } struct super_block * @@ -223,6 +249,9 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent) struct inode *root_inode; kdev_t dev = sb->s_dev; int error; +#ifdef CONFIG_NCPFS_PACKET_SIGNING + int options; +#endif struct ncpfs_inode_info finfo; MOD_INC_USE_COUNT; @@ -230,13 +259,13 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent) goto out_no_data; if (data->version != NCP_MOUNT_VERSION) goto out_bad_mount; - if ((data->ncp_fd >= NR_OPEN) || - ((ncp_filp = current->files->fd[data->ncp_fd]) == NULL) || - !S_ISSOCK(ncp_filp->f_dentry->d_inode->i_mode)) + ncp_filp = fget(data->ncp_fd); + if (!ncp_filp) goto out_bad_file; + if (!S_ISSOCK(ncp_filp->f_dentry->d_inode->i_mode)) + goto out_bad_file2; lock_super(sb); - ncp_filp->f_count++; sb->s_blocksize = 1024; /* Eh... Is this correct? */ sb->s_blocksize_bits = 10; @@ -257,6 +286,17 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent) server->packet = NULL; server->buffer_size = 0; server->conn_status = 0; + server->root_dentry = NULL; +#ifdef CONFIG_NCPFS_PACKET_SIGNING + server->sign_wanted = 0; + server->sign_active = 0; +#endif + server->auth.auth_type = NCP_AUTH_NONE; + server->auth.object_name_len = 0; + server->auth.object_name = NULL; + server->auth.object_type = 0; + server->priv.len = 0; + server->priv.data = NULL; server->m = *data; /* Althought anything producing this is buggy, it happens @@ -282,21 +322,41 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent) goto out_no_connect; DPRINTK(KERN_DEBUG "ncp_read_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb)); - error = ncp_negotiate_buffersize(server, NCP_DEFAULT_BUFSIZE, - &(server->buffer_size)); - if (error) +#ifdef CONFIG_NCPFS_PACKET_SIGNING + if (ncp_negotiate_size_and_options(server, NCP_DEFAULT_BUFSIZE, + NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0) + { + if (options != NCP_DEFAULT_OPTIONS) + { + if (ncp_negotiate_size_and_options(server, + NCP_DEFAULT_BUFSIZE, + options & 2, + &(server->buffer_size), &options) != 0) + + { + goto out_no_bufsize; + } + } + if (options & 2) + server->sign_wanted = 1; + } + else +#endif /* CONFIG_NCPFS_PACKET_SIGNING */ + if (ncp_negotiate_buffersize(server, NCP_DEFAULT_BUFSIZE, + &(server->buffer_size)) != 0) goto out_no_bufsize; DPRINTK(KERN_DEBUG "ncpfs: bufsize = %d\n", server->buffer_size); ncp_init_root(server, &finfo); + server->name_space[finfo.nw_info.i.volNumber] = NW_NS_DOS; root_inode = ncp_iget(sb, &finfo); if (!root_inode) goto out_no_root; DPRINTK(KERN_DEBUG "ncp_read_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber); - sb->s_root = d_alloc_root(root_inode, NULL); + server->root_dentry = sb->s_root = d_alloc_root(root_inode, NULL); if (!sb->s_root) goto out_no_root; - + server->root_dentry->d_op = &ncp_dentry_operations; unlock_super(sb); return sb; @@ -328,6 +388,8 @@ out_unlock: unlock_super(sb); goto out; +out_bad_file2: + fput(ncp_filp); out_bad_file: printk(KERN_ERR "ncp_read_super: invalid ncp socket\n"); goto out; @@ -353,9 +415,13 @@ static void ncp_put_super(struct super_block *sb) ncp_disconnect(server); ncp_unlock_server(server); - close_fp(server->ncp_filp); - kill_proc(server->m.wdog_pid, SIGTERM, 0); + fput(server->ncp_filp); + kill_proc(server->m.wdog_pid, SIGTERM, 1); + if (server->priv.data) + ncp_kfree_s(server->priv.data, server->priv.len); + if (server->auth.object_name) + ncp_kfree_s(server->auth.object_name, server->auth.object_name_len); ncp_kfree_s(server->packet, server->packet_size); ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server)); @@ -387,34 +453,65 @@ static int ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0; } -static int ncp_notify_change(struct inode *inode, struct iattr *attr) +int ncp_notify_change(struct dentry *dentry, struct iattr *attr) { + struct inode *inode = dentry->d_inode; int result = 0; int info_mask; struct nw_modify_dos_info info; - if (!ncp_conn_valid(NCP_SERVER(inode))) { - return -EIO; - } - if ((result = inode_change_ok(inode, attr)) < 0) - return result; + result = -EIO; + if (!ncp_conn_valid(NCP_SERVER(inode))) + goto out; + + result = inode_change_ok(inode, attr); + if (result < 0) + goto out; + result = -EPERM; if (((attr->ia_valid & ATTR_UID) && (attr->ia_uid != NCP_SERVER(inode)->m.uid))) - return -EPERM; + goto out; if (((attr->ia_valid & ATTR_GID) && (attr->ia_uid != NCP_SERVER(inode)->m.gid))) - return -EPERM; + goto out; if (((attr->ia_valid & ATTR_MODE) && (attr->ia_mode & ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO)))) - return -EPERM; + goto out; info_mask = 0; memset(&info, 0, sizeof(info)); +#if 1 + if ((attr->ia_valid & ATTR_MODE) != 0) + { + if (!S_ISREG(inode->i_mode)) + { + return -EPERM; + } + else + { + umode_t newmode; + + info_mask |= DM_ATTRIBUTES; + newmode=attr->ia_mode; + newmode &= NCP_SERVER(inode)->m.file_mode; + + if (newmode & 0222) /* any write bit set */ + { + info.attributes &= ~0x60001; + } + else + { + info.attributes |= 0x60001; + } + } + } +#endif + if ((attr->ia_valid & ATTR_CTIME) != 0) { info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE); ncp_date_unix2dos(attr->ia_ctime, @@ -455,7 +552,8 @@ static int ncp_notify_change(struct inode *inode, struct iattr *attr) if ((attr->ia_valid & ATTR_SIZE) != 0) { int written; - DPRINTK(KERN_DEBUG "ncpfs: trying to change size to %ld\n", attr->ia_size); + DPRINTK(KERN_DEBUG "ncpfs: trying to change size to %ld\n", + attr->ia_size); if ((result = ncp_make_open(inode, O_RDWR)) < 0) { return -EACCES; @@ -467,11 +565,8 @@ static int ncp_notify_change(struct inode *inode, struct iattr *attr) closing the file */ result = ncp_make_closed(inode); } - /* - * We need a dentry here ... - */ - /* ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode); */ - + ncp_invalid_dir_cache(dentry->d_parent->d_inode); +out: return result; } diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index e9f0ca86c..078d26596 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c @@ -6,6 +6,8 @@ * */ +#include <linux/config.h> + #include <asm/uaccess.h> #include <linux/errno.h> #include <linux/fs.h> @@ -15,6 +17,12 @@ #include <linux/ncp.h> #include <linux/ncp_fs.h> +#include "ncplib_kernel.h" + +/* maximum limit for ncp_objectname_ioctl */ +#define NCP_OBJECT_NAME_MAX_LEN 4096 +/* maximum limit for ncp_privatedata_ioctl */ +#define NCP_PRIVATE_DATA_MAX_LEN 8192 int ncp_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) @@ -113,9 +121,364 @@ int ncp_ioctl(struct inode *inode, struct file *filp, put_user(server->m.mounted_uid, (uid_t *) arg); return 0; + case NCP_IOC_GETMOUNTUID_INT: + if ( (permission(inode, MAY_READ) != 0) + && (current->uid != server->m.mounted_uid)) + { + return -EACCES; + } + + { + unsigned int tmp=server->m.mounted_uid; + if (put_user(tmp, (unsigned long*) arg)) return -EFAULT; + } + return 0; + +#ifdef CONFIG_NCPFS_MOUNT_SUBDIR + case NCP_IOC_GETROOT: + { + struct ncp_setroot_ioctl sr; + + if ( (permission(inode, MAY_READ) != 0) + && (current->uid != server->m.mounted_uid)) + { + return -EACCES; + } + if (server->m.mounted_vol[0]) { + sr.volNumber = server->root.finfo.i.volNumber; + sr.dirEntNum = server->root.finfo.i.dirEntNum; + sr.namespace = server->name_space[sr.volNumber]; + } else { + sr.volNumber = -1; + sr.namespace = 0; + sr.dirEntNum = 0; + } + if (copy_to_user((struct ncp_setroot_ioctl*)arg, + &sr, + sizeof(sr))) return -EFAULT; + return 0; + } + case NCP_IOC_SETROOT: + { + struct ncp_setroot_ioctl sr; + struct dentry* dentry; + + if ( (permission(inode, MAY_WRITE) != 0) + && (current->uid != server->m.mounted_uid)) + { + return -EACCES; + } + if (copy_from_user(&sr, + (struct ncp_setroot_ioctl*)arg, + sizeof(sr))) return -EFAULT; + if (sr.volNumber < 0) { + server->m.mounted_vol[0] = 0; + server->root.finfo.i.volNumber = NCP_NUMBER_OF_VOLUMES + 1; + server->root.finfo.i.dirEntNum = 0; + server->root.finfo.i.DosDirNum = 0; + } else if (sr.volNumber >= NCP_NUMBER_OF_VOLUMES) { + return -EINVAL; + } else { + if (ncp_mount_subdir(server, sr.volNumber, sr.namespace, sr.dirEntNum)) { + return -ENOENT; + } + } + dentry = server->root_dentry; + if (dentry) { + struct inode* inode = dentry->d_inode; + + if (inode) { + NCP_FINFO(inode)->volNumber = server->root.finfo.i.volNumber; + NCP_FINFO(inode)->dirEntNum = server->root.finfo.i.dirEntNum; + NCP_FINFO(inode)->DosDirNum = server->root.finfo.i.DosDirNum; + } else { + DPRINTK(KERN_DEBUG "ncpfs: root_dentry->d_inode==NULL\n"); + } + } else { + DPRINTK(KERN_DEBUG "ncpfs: root_dentry==NULL\n"); + } + return 0; + } +#endif /* CONFIG_NCPFS_MOUNT_SUBDIR */ + +#ifdef CONFIG_NCPFS_PACKET_SIGNING + case NCP_IOC_SIGN_INIT: + if ((permission(inode, MAY_WRITE) != 0) + && (current->uid != server->m.mounted_uid)) + { + return -EACCES; + } + if (server->sign_active) + { + return -EINVAL; + } + if (server->sign_wanted) + { + struct ncp_sign_init sign; + + if (copy_from_user(&sign, (struct ncp_sign_init *) arg, + sizeof(sign))) return -EFAULT; + memcpy(server->sign_root,sign.sign_root,8); + memcpy(server->sign_last,sign.sign_last,16); + server->sign_active = 1; + } + /* ignore when signatures not wanted */ + return 0; + + case NCP_IOC_SIGN_WANTED: + if ( (permission(inode, MAY_READ) != 0) + && (current->uid != server->m.mounted_uid)) + { + return -EACCES; + } + + if (put_user(server->sign_wanted, (int*) arg)) + return -EFAULT; + return 0; + case NCP_IOC_SET_SIGN_WANTED: + { + int newstate; + + if ( (permission(inode, MAY_WRITE) != 0) + && (current->uid != server->m.mounted_uid)) + { + return -EACCES; + } + /* get only low 8 bits... */ + get_user_ret(newstate, (unsigned char*)arg, -EFAULT); + if (server->sign_active) { + /* cannot turn signatures OFF when active */ + if (!newstate) return -EINVAL; + } else { + server->sign_wanted = newstate != 0; + } + return 0; + } + +#endif /* CONFIG_NCPFS_PACKET_SIGNING */ + +#ifdef CONFIG_NCPFS_IOCTL_LOCKING + case NCP_IOC_LOCKUNLOCK: + if ( (permission(inode, MAY_WRITE) != 0) + && (current->uid != server->m.mounted_uid)) + { + return -EACCES; + } + { + struct ncp_lock_ioctl rqdata; + int result; + + if (copy_from_user(&rqdata, (struct ncp_lock_ioctl*)arg, + sizeof(rqdata))) return -EFAULT; + if (rqdata.origin != 0) + return -EINVAL; + /* check for cmd */ + switch (rqdata.cmd) { + case NCP_LOCK_EX: + case NCP_LOCK_SH: + if (rqdata.timeout == 0) + rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT; + else if (rqdata.timeout > NCP_LOCK_MAX_TIMEOUT) + rqdata.timeout = NCP_LOCK_MAX_TIMEOUT; + break; + case NCP_LOCK_LOG: + rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT; /* has no effect */ + case NCP_LOCK_CLEAR: + break; + default: + return -EINVAL; + } + if ((result = ncp_make_open(inode, O_RDWR)) != 0) + { + return result; + } + if (!ncp_conn_valid(server)) + { + return -EIO; + } + if (!S_ISREG(inode->i_mode)) + { + return -EISDIR; + } + if (!NCP_FINFO(inode)->opened) + { + return -EBADFD; + } + if (rqdata.cmd == NCP_LOCK_CLEAR) + { + result = ncp_ClearPhysicalRecord(NCP_SERVER(inode), + NCP_FINFO(inode)->file_handle, + rqdata.offset, + rqdata.length); + if (result > 0) result = 0; /* no such lock */ + } + else + { + int lockcmd; + + switch (rqdata.cmd) + { + case NCP_LOCK_EX: lockcmd=1; break; + case NCP_LOCK_SH: lockcmd=3; break; + default: lockcmd=0; break; + } + result = ncp_LogPhysicalRecord(NCP_SERVER(inode), + NCP_FINFO(inode)->file_handle, + lockcmd, + rqdata.offset, + rqdata.length, + rqdata.timeout); + if (result > 0) result = -EAGAIN; + } + return result; + } +#endif /* CONFIG_NCPFS_IOCTL_LOCKING */ + +#ifdef CONFIG_NCPFS_NDS_DOMAINS + case NCP_IOC_GETOBJECTNAME: + if ( (permission(inode, MAY_READ) != 0) + && (current->uid != server->m.mounted_uid)) { + return -EACCES; + } + { + struct ncp_objectname_ioctl user; + int outl; + + if ((result = verify_area(VERIFY_WRITE, + (struct ncp_objectname_ioctl*)arg, + sizeof(user))) != 0) { + return result; + } + if (copy_from_user(&user, + (struct ncp_objectname_ioctl*)arg, + sizeof(user))) return -EFAULT; + user.auth_type = server->auth.auth_type; + outl = user.object_name_len; + user.object_name_len = server->auth.object_name_len; + if (outl > user.object_name_len) + outl = user.object_name_len; + if (outl) { + if (copy_to_user(user.object_name, + server->auth.object_name, + outl)) return -EFAULT; + } + if (copy_to_user((struct ncp_objectname_ioctl*)arg, + &user, + sizeof(user))) return -EFAULT; + return 0; + } + case NCP_IOC_SETOBJECTNAME: + if ( (permission(inode, MAY_WRITE) != 0) + && (current->uid != server->m.mounted_uid)) { + return -EACCES; + } + { + struct ncp_objectname_ioctl user; + void* newname; + void* oldname; + size_t oldnamelen; + void* oldprivate; + size_t oldprivatelen; + + if (copy_from_user(&user, + (struct ncp_objectname_ioctl*)arg, + sizeof(user))) return -EFAULT; + if (user.object_name_len > NCP_OBJECT_NAME_MAX_LEN) + return -ENOMEM; + if (user.object_name_len) { + newname = ncp_kmalloc(user.object_name_len, GFP_USER); + if (!newname) return -ENOMEM; + if (copy_from_user(newname, user.object_name, sizeof(user))) { + ncp_kfree_s(newname, user.object_name_len); + return -EFAULT; + } + } else { + newname = NULL; + } + /* enter critical section */ + /* maybe that kfree can sleep so do that this way */ + /* it is at least more SMP friendly (in future...) */ + oldname = server->auth.object_name; + oldnamelen = server->auth.object_name_len; + oldprivate = server->priv.data; + oldprivatelen = server->priv.len; + server->auth.auth_type = user.auth_type; + server->auth.object_name_len = user.object_name_len; + server->auth.object_name = user.object_name; + server->priv.len = 0; + server->priv.data = NULL; + /* leave critical section */ + if (oldprivate) ncp_kfree_s(oldprivate, oldprivatelen); + if (oldname) ncp_kfree_s(oldname, oldnamelen); + return 0; + } + case NCP_IOC_GETPRIVATEDATA: + if ( (permission(inode, MAY_READ) != 0) + && (current->uid != server->m.mounted_uid)) { + return -EACCES; + } + { + struct ncp_privatedata_ioctl user; + int outl; + + if ((result = verify_area(VERIFY_WRITE, + (struct ncp_privatedata_ioctl*)arg, + sizeof(user))) != 0) { + return result; + } + if (copy_from_user(&user, + (struct ncp_privatedata_ioctl*)arg, + sizeof(user))) return -EFAULT; + outl = user.len; + user.len = server->priv.len; + if (outl > user.len) outl = user.len; + if (outl) { + if (copy_to_user(user.data, + server->priv.data, + outl)) return -EFAULT; + } + if (copy_to_user((struct ncp_privatedata_ioctl*)arg, + &user, + sizeof(user))) return -EFAULT; + return 0; + } + case NCP_IOC_SETPRIVATEDATA: + if ( (permission(inode, MAY_WRITE) != 0) + && (current->uid != server->m.mounted_uid)) { + return -EACCES; + } + { + struct ncp_privatedata_ioctl user; + void* new; + void* old; + size_t oldlen; + + if (copy_from_user(&user, + (struct ncp_privatedata_ioctl*)arg, + sizeof(user))) return -EFAULT; + if (user.len > NCP_PRIVATE_DATA_MAX_LEN) + return -ENOMEM; + if (user.len) { + new = ncp_kmalloc(user.len, GFP_USER); + if (!new) return -ENOMEM; + if (copy_from_user(new, user.data, user.len)) { + ncp_kfree_s(new, user.len); + return -EFAULT; + } + } else { + new = NULL; + } + /* enter critical section */ + old = server->priv.data; + oldlen = server->priv.len; + server->priv.len = user.len; + server->priv.data = new; + /* leave critical section */ + if (old) ncp_kfree_s(old, oldlen); + return 0; + } +#endif /* CONFIG_NCPFS_NDS_DOMAINS */ default: return -EINVAL; } - - return -EINVAL; } diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c index 2a140ea55..2c7610d0b 100644 --- a/fs/ncpfs/mmap.c +++ b/fs/ncpfs/mmap.c @@ -33,7 +33,8 @@ static inline int min(int a, int b) static unsigned long ncp_file_mmap_nopage(struct vm_area_struct *area, unsigned long address, int no_share) { - struct dentry *dentry = area->vm_dentry; + struct file *file = area->vm_file; + struct dentry *dentry = file->f_dentry; struct inode *inode = dentry->d_inode; unsigned long page; unsigned int clear; @@ -136,7 +137,8 @@ int ncp_mmap(struct file *file, struct vm_area_struct *vma) inode->i_atime = CURRENT_TIME; } - vma->vm_dentry = dget(file->f_dentry); + vma->vm_file = file; + file->f_count++; vma->vm_ops = &ncp_file_mmap; return 0; } diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c index 8d60732ef..5de6767e4 100644 --- a/fs/ncpfs/ncplib_kernel.c +++ b/fs/ncpfs/ncplib_kernel.c @@ -8,6 +8,8 @@ */ +#include <linux/config.h> + #include "ncplib_kernel.h" static inline int min(int a, int b) @@ -135,6 +137,33 @@ ncp_negotiate_buffersize(struct ncp_server *server, int size, int *target) return 0; } + +/* options: + * bit 0 ipx checksum + * bit 1 packet signing + */ +int +ncp_negotiate_size_and_options(struct ncp_server *server, + int size, int options, int *ret_size, int *ret_options) { + int result; + + ncp_init_request(server); + ncp_add_word(server, htons(size)); + ncp_add_byte(server, options); + + if ((result = ncp_request(server, 0x61)) != 0) + { + ncp_unlock_server(server); + return result; + } + + *ret_size = min(ntohs(ncp_reply_word(server, 0)), size); + *ret_options = ncp_reply_byte(server, 4); + + ncp_unlock_server(server); + return 0; +} + int ncp_get_volume_info_with_number(struct ncp_server *server, int n, struct ncp_volume_info *target) @@ -252,7 +281,7 @@ int ncp_obtain_info(struct ncp_server *server, struct inode *dir, char *path, ncp_add_byte(server, 6); /* subfunction */ ncp_add_byte(server, server->name_space[volnum]); ncp_add_byte(server, server->name_space[volnum]); /* N.B. twice ?? */ - ncp_add_word(server, htons(0xff00)); /* get all */ + ncp_add_word(server, htons(0x0680)); /* get all */ ncp_add_dword(server, RIM_ALL); ncp_add_handle_path(server, volnum, dirent, 1, path); @@ -265,9 +294,34 @@ out: return result; } +static int +ncp_obtain_DOS_dir_base(struct ncp_server *server, + __u8 volnum, __u32 dirent, + char *path, /* At most 1 component */ + __u32 *DOS_dir_base) +{ + int result; + + ncp_init_request(server); + ncp_add_byte(server, 6); /* subfunction */ + ncp_add_byte(server, server->name_space[volnum]); + ncp_add_byte(server, server->name_space[volnum]); + ncp_add_word(server, htons(0x0680)); /* get all */ + ncp_add_dword(server, RIM_DIRECTORY); + ncp_add_handle_path(server, volnum, dirent, 1, path); + + if ((result = ncp_request(server, 87)) == 0) + { + if (DOS_dir_base) *DOS_dir_base=ncp_reply_dword(server, 0x34); + } + ncp_unlock_server(server); + return result; +} + static inline int -ncp_has_os2_namespace(struct ncp_server *server, __u8 volume) +ncp_get_known_namespace(struct ncp_server *server, __u8 volume) { +#if defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS) int result; __u8 *namespace; __u16 no_namespaces; @@ -279,26 +333,92 @@ ncp_has_os2_namespace(struct ncp_server *server, __u8 volume) if ((result = ncp_request(server, 87)) != 0) { ncp_unlock_server(server); - return 0; /* not result ?? */ + return NW_NS_DOS; /* not result ?? */ } + + result = NW_NS_DOS; no_namespaces = ncp_reply_word(server, 0); namespace = ncp_reply_data(server, 2); - result = 1; while (no_namespaces > 0) { DPRINTK(KERN_DEBUG "get_namespaces: found %d on %d\n", *namespace, volume); - if (*namespace == 4) { - DPRINTK(KERN_DEBUG "get_namespaces: found OS2\n"); - goto out; +#ifdef CONFIG_NCPFS_NFS_NS + if ((*namespace == NW_NS_NFS) && !(server->m.flags&NCP_MOUNT_NO_NFS)) + { + result = NW_NS_NFS; + break; } +#endif /* CONFIG_NCPFS_NFS_NS */ +#ifdef CONFIG_NCPFS_OS2_NS + if ((*namespace == NW_NS_OS2) && !(server->m.flags&NCP_MOUNT_NO_OS2)) + { + result = NW_NS_OS2; + } +#endif /* CONFIG_NCPFS_OS2_NS */ namespace += 1; no_namespaces -= 1; } - result = 0; -out: ncp_unlock_server(server); return result; +#else /* neither OS2 nor NFS - only DOS */ + return NW_NS_DOS; +#endif /* defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS) */ +} + +static int +ncp_ObtainSpecificDirBase(struct ncp_server *server, + __u8 nsSrc, __u8 nsDst, __u8 vol_num, __u32 dir_base, + char *path, /* At most 1 component */ + __u32 *dirEntNum, __u32 *DosDirNum) +{ + int result; + + ncp_init_request(server); + ncp_add_byte(server, 6); /* subfunction */ + ncp_add_byte(server, nsSrc); + ncp_add_byte(server, nsDst); + ncp_add_word(server, 0x8006); /* get all */ + ncp_add_dword(server, RIM_ALL); + ncp_add_handle_path(server, vol_num, dir_base, 1, path); + + if ((result = ncp_request(server, 87)) != 0) + { + ncp_unlock_server(server); + return result; + } + + if (dirEntNum) + *dirEntNum = ncp_reply_dword(server, 0x30); + if (DosDirNum) + *DosDirNum = ncp_reply_dword(server, 0x34); + ncp_unlock_server(server); + return 0; +} + +int +ncp_mount_subdir(struct ncp_server *server, + __u8 volNumber, + __u8 srcNS, __u32 dirEntNum) +{ + int dstNS; + int result; + __u32 newDirEnt; + __u32 newDosEnt; + + dstNS = ncp_get_known_namespace(server, volNumber); + if ((result = ncp_ObtainSpecificDirBase(server, srcNS, dstNS, volNumber, + dirEntNum, NULL, &newDirEnt, &newDosEnt)) != 0) + { + return result; + } + server->name_space[volNumber] = dstNS; + server->root.finfo.i.volNumber = volNumber; + server->root.finfo.i.dirEntNum = newDirEnt; + server->root.finfo.i.DosDirNum = newDosEnt; + server->m.mounted_vol[1] = 0; + server->m.mounted_vol[0] = 'X'; + return 0; } int @@ -332,7 +452,7 @@ ncp_lookup_volume(struct ncp_server *server, char *volname, target->volNumber = volnum = ncp_reply_byte(server, 8); ncp_unlock_server(server); - server->name_space[volnum] = ncp_has_os2_namespace(server, volnum) ? 4 : 0; + server->name_space[volnum] = ncp_get_known_namespace(server, volnum); DPRINTK(KERN_DEBUG "lookup_vol: namespace[%d] = %d\n", volnum, server->name_space[volnum]); @@ -366,25 +486,65 @@ int ncp_modify_file_or_subdir_dos_info(struct ncp_server *server, return result; } -int ncp_del_file_or_subdir(struct ncp_server *server, - struct inode *dir, char *name) +static int +ncp_DeleteNSEntry(struct ncp_server *server, + __u8 have_dir_base, __u8 volnum, __u32 dirent, + char* name, __u8 ns, int attr) { - __u8 volnum = NCP_FINFO(dir)->volNumber; - __u32 dirent = NCP_FINFO(dir)->dirEntNum; int result; ncp_init_request(server); ncp_add_byte(server, 8); /* subfunction */ - ncp_add_byte(server, server->name_space[volnum]); + ncp_add_byte(server, ns); ncp_add_byte(server, 0); /* reserved */ - ncp_add_word(server, ntohs(0x0680)); /* search attribs: all */ - ncp_add_handle_path(server, volnum, dirent, 1, name); + ncp_add_word(server, attr); /* search attribs: all */ + ncp_add_handle_path(server, volnum, dirent, have_dir_base, name); result = ncp_request(server, 87); ncp_unlock_server(server); return result; } +int +ncp_del_file_or_subdir2(struct ncp_server *server, + struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + __u8 volnum; + __u32 dirent; + + if (!inode) { +#if CONFIG_NCPFS_DEBUGDENTRY + printk(KERN_DEBUG "ncpfs: ncpdel2: dentry->d_inode == NULL\n"); +#endif + return 0xFF; /* Any error */ + } + volnum = NCP_FINFO(inode)->volNumber; + dirent = NCP_FINFO(inode)->DosDirNum; + return ncp_DeleteNSEntry(server, 1, volnum, dirent, NULL, NW_NS_DOS, htons(0x0680)); +} + +int +ncp_del_file_or_subdir(struct ncp_server *server, + struct inode *dir, char *name) +{ + __u8 volnum = NCP_FINFO(dir)->volNumber; + __u32 dirent = NCP_FINFO(dir)->dirEntNum; + +#ifdef CONFIG_NCPFS_NFS_NS + if (server->name_space[volnum]==NW_NS_NFS) + { + int result; + + result=ncp_obtain_DOS_dir_base(server, volnum, dirent, name, &dirent); + if (result) return result; + return ncp_DeleteNSEntry(server, 1, volnum, dirent, NULL, NW_NS_DOS, htons(0x0680)); + } + else +#endif /* CONFIG_NCPFS_NFS_NS */ + return ncp_DeleteNSEntry(server, 1, volnum, dirent, name, server->name_space[volnum], htons(0x0680)); +} + static inline void ConvertToNWfromDWORD(__u32 sfd, __u8 ret[6]) { __u16 *dest = (__u16 *) ret; @@ -480,13 +640,20 @@ int ncp_search_for_file_or_subdir(struct ncp_server *server, ncp_add_byte(server, 3); /* subfunction */ ncp_add_byte(server, server->name_space[seq->volNumber]); ncp_add_byte(server, 0); /* data stream (???) */ - ncp_add_word(server, 0xffff); /* Search attribs */ + ncp_add_word(server, htons(0x0680)); /* Search attribs */ ncp_add_dword(server, RIM_ALL); /* return info mask */ ncp_add_mem(server, seq, 9); - ncp_add_byte(server, 2); /* 2 byte pattern */ - ncp_add_byte(server, 0xff); /* following is a wildcard */ - ncp_add_byte(server, '*'); - +#ifdef CONFIG_NCPFS_NFS_NS + if (server->name_space[seq->volNumber] == NW_NS_NFS) { + ncp_add_byte(server, 0); /* 0 byte pattern */ + } else +#endif + { + ncp_add_byte(server, 2); /* 2 byte pattern */ + ncp_add_byte(server, 0xff); /* following is a wildcard */ + ncp_add_byte(server, '*'); + } + if ((result = ncp_request(server, 87)) != 0) goto out; memcpy(seq, ncp_reply_data(server, 0), sizeof(*seq)); @@ -497,9 +664,10 @@ out: return result; } -int ncp_ren_or_mov_file_or_subdir(struct ncp_server *server, - struct inode *old_dir, char *old_name, - struct inode *new_dir, char *new_name) +int +ncp_RenameNSEntry(struct ncp_server *server, + struct inode *old_dir, char *old_name, int old_type, + struct inode *new_dir, char *new_name) { int result = -EINVAL; @@ -511,7 +679,7 @@ int ncp_ren_or_mov_file_or_subdir(struct ncp_server *server, ncp_add_byte(server, 4); /* subfunction */ ncp_add_byte(server, server->name_space[NCP_FINFO(old_dir)->volNumber]); ncp_add_byte(server, 1); /* rename flag */ - ncp_add_word(server, ntohs(0x0680)); /* search attributes */ + ncp_add_word(server, old_type); /* search attributes */ /* source Handle Path */ ncp_add_byte(server, NCP_FINFO(old_dir)->volNumber); @@ -536,6 +704,30 @@ out: return result; } +int ncp_ren_or_mov_file_or_subdir(struct ncp_server *server, + struct inode *old_dir, char *old_name, + struct inode *new_dir, char *new_name) +{ + int result; + int old_type = htons(0x0600); + +/* If somebody can do it atomic, call me... vandrove@vc.cvut.cz */ + result = ncp_RenameNSEntry(server, old_dir, old_name, old_type, + new_dir, new_name); + if (result == 0xFF) /* File Not Found, try directory */ + { + old_type = htons(0x1600); + result = ncp_RenameNSEntry(server, old_dir, old_name, old_type, + new_dir, new_name); + } + if (result != 0x92) return result; /* All except NO_FILES_RENAMED */ + result = ncp_del_file_or_subdir(server, new_dir, new_name); + if (result != 0) return -EACCES; + result = ncp_RenameNSEntry(server, old_dir, old_name, old_type, + new_dir, new_name); + return result; +} + /* We have to transfer to/from user space */ int @@ -587,3 +779,49 @@ out: ncp_unlock_server(server); return result; } + +#ifdef CONFIG_NCPFS_IOCTL_LOCKING +int +ncp_LogPhysicalRecord(struct ncp_server *server, const char *file_id, + __u8 locktype, __u32 offset, __u32 length, __u16 timeout) +{ + int result; + + ncp_init_request(server); + ncp_add_byte(server, locktype); + ncp_add_mem(server, file_id, 6); + ncp_add_dword(server, htonl(offset)); + ncp_add_dword(server, htonl(length)); + ncp_add_word(server, htons(timeout)); + + if ((result = ncp_request(server, 0x1A)) != 0) + { + ncp_unlock_server(server); + return result; + } + ncp_unlock_server(server); + return 0; +} + +int +ncp_ClearPhysicalRecord(struct ncp_server *server, const char *file_id, + __u32 offset, __u32 length) +{ + int result; + + ncp_init_request(server); + ncp_add_byte(server, 0); /* who knows... lanalyzer says that */ + ncp_add_mem(server, file_id, 6); + ncp_add_dword(server, htonl(offset)); + ncp_add_dword(server, htonl(length)); + + if ((result = ncp_request(server, 0x1E)) != 0) + { + ncp_unlock_server(server); + return result; + } + ncp_unlock_server(server); + return 0; +} +#endif /* CONFIG_NCPFS_IOCTL_LOCKING */ + diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h index 69388576b..7834c6c4f 100644 --- a/fs/ncpfs/ncplib_kernel.h +++ b/fs/ncpfs/ncplib_kernel.h @@ -10,6 +10,8 @@ #ifndef _NCPLIB_H #define _NCPLIB_H +#include <linux/config.h> + #include <linux/fs.h> #include <linux/types.h> #include <linux/errno.h> @@ -26,6 +28,8 @@ #include <linux/ncp_fs_sb.h> int ncp_negotiate_buffersize(struct ncp_server *, int, int *); +int ncp_negotiate_size_and_options(struct ncp_server *server, int size, + int options, int *ret_size, int *ret_options); int ncp_get_volume_info_with_number(struct ncp_server *, int, struct ncp_volume_info *); int ncp_close_file(struct ncp_server *, const char *); @@ -39,6 +43,7 @@ int ncp_lookup_volume(struct ncp_server *, char *, struct nw_info_struct *); int ncp_modify_file_or_subdir_dos_info(struct ncp_server *, struct inode *, __u32, struct nw_modify_dos_info *info); +int ncp_del_file_or_subdir2(struct ncp_server *, struct dentry*); int ncp_del_file_or_subdir(struct ncp_server *, struct inode *, char *); int ncp_open_create_file_or_subdir(struct ncp_server *, struct inode *, char *, int, __u32, int, struct nw_file_info *); @@ -53,4 +58,21 @@ int ncp_ren_or_mov_file_or_subdir(struct ncp_server *server, struct inode *, char *, struct inode *, char *); +int +ncp_LogPhysicalRecord(struct ncp_server *server, + const char *file_id, __u8 locktype, + __u32 offset, __u32 length, __u16 timeout); + +#ifdef CONFIG_NCPFS_IOCTL_LOCKING +int +ncp_ClearPhysicalRecord(struct ncp_server *server, + const char *file_id, + __u32 offset, __u32 length); +#endif /* CONFIG_NCPFS_IOCTL_LOCKING */ + +#ifdef CONFIG_NCPFS_MOUNT_SUBDIR +int +ncp_mount_subdir(struct ncp_server* server, __u8 volNumber, + __u8 srcNS, __u32 srcDirEntNum); +#endif /* CONFIG_NCPFS_MOUNT_SUBDIR */ #endif /* _NCPLIB_H */ diff --git a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c index cc8326c05..ea15ae968 100644 --- a/fs/ncpfs/sock.c +++ b/fs/ncpfs/sock.c @@ -8,6 +8,8 @@ * */ +#include <linux/config.h> + #include <linux/sched.h> #include <linux/errno.h> #include <linux/socket.h> @@ -18,15 +20,21 @@ #include <linux/net.h> #include <linux/mm.h> #include <linux/netdevice.h> +#include <linux/signal.h> #include <net/scm.h> #include <net/sock.h> #include <linux/ipx.h> #include <linux/poll.h> +#include <linux/file.h> #include <linux/ncp.h> #include <linux/ncp_fs.h> #include <linux/ncp_fs_sb.h> +#ifdef CONFIG_NCPFS_PACKET_SIGNING +#include "ncpsign_kernel.h" +#endif + static int _recv(struct socket *sock, unsigned char *ubuf, int size, unsigned flags) { @@ -124,12 +132,12 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size) What if we've blocked it ourselves? What about alarms? Why, in fact, are we mucking with the sigmask at all? -- r~ */ - if (current->sig->action[SIGINT - 1].sa_handler == SIG_DFL) + if (current->sig->action[SIGINT - 1].sa.sa_handler == SIG_DFL) mask |= sigmask(SIGINT); - if (current->sig->action[SIGQUIT - 1].sa_handler == SIG_DFL) + if (current->sig->action[SIGQUIT - 1].sa.sa_handler == SIG_DFL) mask |= sigmask(SIGQUIT); } - siginitmaskinv(¤t->blocked, mask); + siginitsetinv(¤t->blocked, mask); recalc_sigpending(current); spin_unlock_irqrestore(¤t->sigmask_lock, flags); @@ -177,6 +185,7 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size) current->timeout = jiffies + timeout; schedule(); remove_wait_queue(entry.wait_address, &entry.wait); + fput(file); current->state = TASK_RUNNING; if (signal_pending(current)) { current->timeout = 0; @@ -201,8 +210,10 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size) continue; } else current->timeout = 0; - } else if (wait_table.nr) + } else if (wait_table.nr) { remove_wait_queue(entry.wait_address, &entry.wait); + fput(file); + } current->state = TASK_RUNNING; /* Get the header from the next packet using a peek, so keep it @@ -278,7 +289,7 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size) } spin_lock_irqsave(¤t->sigmask_lock, flags); - current->blocked = old_mask; + current->blocked = old_set; recalc_sigpending(current); spin_unlock_irqrestore(¤t->sigmask_lock, flags); @@ -301,6 +312,12 @@ static int ncp_do_request(struct ncp_server *server, int size) if (!ncp_conn_valid(server)) { return -EIO; } +#ifdef CONFIG_NCPFS_PACKET_SIGNING + if (server->sign_active) + { + sign_packet(server, &size); + } +#endif /* CONFIG_NCPFS_PACKET_SIGNING */ result = do_ncp_rpc_call(server, size); DDPRINTK(KERN_DEBUG "do_ncp_rpc_call returned %d\n", result); |