summaryrefslogtreecommitdiffstats
path: root/fs/ncpfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ncpfs')
-rw-r--r--fs/ncpfs/.cvsignore1
-rw-r--r--fs/ncpfs/Config.in10
-rw-r--r--fs/ncpfs/Makefile6
-rw-r--r--fs/ncpfs/dir.c217
-rw-r--r--fs/ncpfs/file.c15
-rw-r--r--fs/ncpfs/inode.c155
-rw-r--r--fs/ncpfs/ioctl.c367
-rw-r--r--fs/ncpfs/mmap.c6
-rw-r--r--fs/ncpfs/ncplib_kernel.c290
-rw-r--r--fs/ncpfs/ncplib_kernel.h22
-rw-r--r--fs/ncpfs/sock.c27
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(&current->blocked, mask);
+ siginitsetinv(&current->blocked, mask);
recalc_sigpending(current);
spin_unlock_irqrestore(&current->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(&current->sigmask_lock, flags);
- current->blocked = old_mask;
+ current->blocked = old_set;
recalc_sigpending(current);
spin_unlock_irqrestore(&current->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);