Commit 59ece965 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://vana.vc.cvut.cz/ncpfs

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 6eebabfa 41783de4
......@@ -5,7 +5,13 @@
obj-$(CONFIG_NCP_FS) += ncpfs.o
ncpfs-objs := dir.o file.o inode.o ioctl.o mmap.o ncplib_kernel.o sock.o \
symlink.o ncpsign_kernel.o
ncpsign_kernel.o
ifeq ($(CONFIG_NCPFS_EXTRAS),y)
ncpfs-objs += symlink.o
endif
ifeq ($(CONFIG_NCPFS_NFS_NS),y)
ncpfs-objs += symlink.o
endif
# If you want debugging output, please uncomment the following line
# EXTRA_CFLAGS += -DDEBUG_NCP=1
......
......@@ -6,6 +6,7 @@
* Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
* Modified 1998, 1999 Wolfram Pienkoss for NLS
* Modified 1999 Wolfram Pienkoss for directory caching
* Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
*
*/
......@@ -40,8 +41,12 @@ static int ncp_mkdir(struct inode *, struct dentry *, int);
static int ncp_rmdir(struct inode *, struct dentry *);
static int ncp_rename(struct inode *, struct dentry *,
struct inode *, struct dentry *);
#ifdef CONFIG_NCPFS_EXTRAS
static int ncp_mknod(struct inode * dir, struct dentry *dentry,
int mode, int rdev);
#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
extern int ncp_symlink(struct inode *, struct dentry *, const char *);
#else
#define ncp_symlink NULL
#endif
struct file_operations ncp_dir_operations =
......@@ -56,11 +61,10 @@ struct inode_operations ncp_dir_inode_operations =
create: ncp_create,
lookup: ncp_lookup,
unlink: ncp_unlink,
#ifdef CONFIG_NCPFS_EXTRAS
symlink: ncp_symlink,
#endif
mkdir: ncp_mkdir,
rmdir: ncp_rmdir,
mknod: ncp_mknod,
rename: ncp_rename,
setattr: ncp_notify_change,
};
......@@ -73,7 +77,7 @@ static int ncp_hash_dentry(struct dentry *, struct qstr *);
static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *);
static int ncp_delete_dentry(struct dentry *);
struct dentry_operations ncp_dentry_operations =
static struct dentry_operations ncp_dentry_operations =
{
d_revalidate: ncp_lookup_validate,
d_hash: ncp_hash_dentry,
......@@ -81,6 +85,13 @@ struct dentry_operations ncp_dentry_operations =
d_delete: ncp_delete_dentry,
};
struct dentry_operations ncp_root_dentry_operations =
{
d_hash: ncp_hash_dentry,
d_compare: ncp_compare_dentry,
d_delete: ncp_delete_dentry,
};
/*
* Note: leave the hash unchanged if the directory
......@@ -300,6 +311,7 @@ __ncp_lookup_validate(struct dentry * dentry, int flags)
if (!res)
res = ncp_obtain_info(server, dir, __name, &(finfo.i));
}
finfo.volume = finfo.i.volNumber;
DDPRINTK("ncp_lookup_validate: looked for %s/%s, res=%d\n",
dentry->d_parent->d_name.name, __name, res);
/*
......@@ -663,6 +675,7 @@ ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir,
info.volume_name);
continue;
}
entry.volume = entry.i.volNumber;
if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry))
return;
}
......@@ -678,6 +691,9 @@ ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir,
struct nw_search_sequence seq;
struct ncp_entry_info entry;
int err;
void* buf;
int more;
size_t bufsize;
DPRINTK("ncp_do_readdir: %s/%s, fpos=%ld\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
......@@ -691,15 +707,57 @@ ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir,
DPRINTK("ncp_do_readdir: init failed, err=%d\n", err);
return;
}
#ifdef USE_OLD_SLOW_DIRECTORY_LISTING
for (;;) {
err = ncp_search_for_file_or_subdir(server, &seq, &entry.i);
if (err) {
DPRINTK("ncp_do_readdir: search failed, err=%d\n", err);
return;
break;
}
entry.volume = entry.i.volNumber;
if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry))
break;
}
#else
/* We MUST NOT use server->buffer_size handshaked with server if we are
using UDP, as for UDP server uses max. buffer size determined by
MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes).
So we use 128KB, just to be sure, as there is no way how to know
this value in advance. */
bufsize = 131072;
buf = vmalloc(bufsize);
if (!buf)
return;
do {
int cnt;
char* rpl;
size_t rpls;
err = ncp_search_for_fileset(server, &seq, &more, &cnt, buf, bufsize, &rpl, &rpls);
if (err) /* Error */
break;
if (!cnt) /* prevent endless loop */
break;
while (cnt--) {
size_t onerpl;
if (rpls < offsetof(struct nw_info_struct, entryName))
break; /* short packet */
ncp_extract_file_info(rpl, &entry.i);
onerpl = offsetof(struct nw_info_struct, entryName) + entry.i.nameLen;
if (rpls < onerpl)
break; /* short packet */
(void)ncp_obtain_nfs_info(server, &entry.i);
rpl += onerpl;
rpls -= onerpl;
entry.volume = entry.i.volNumber;
if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry))
break;
}
} while (more);
vfree(buf);
#endif
return;
}
int ncp_conn_logged_in(struct super_block *sb)
......@@ -781,6 +839,7 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry)
*/
finfo.opened = 0;
finfo.ino = iunique(dir->i_sb, 2);
finfo.volume = finfo.i.volNumber;
error = -EACCES;
inode = ncp_iget(dir->i_sb, &finfo);
......@@ -824,7 +883,7 @@ static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
}
int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
int attributes)
int rdev, int attributes)
{
struct ncp_server *server = NCP_SERVER(dir);
struct ncp_entry_info finfo;
......@@ -870,6 +929,15 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
opmode = O_WRONLY;
}
finfo.access = opmode;
if (ncp_is_nfs_extras(server, finfo.volume)) {
finfo.i.nfs.mode = mode;
finfo.i.nfs.rdev = rdev;
if (ncp_modify_nfs_info(server, finfo.volume,
finfo.i.dirEntNum,
mode, rdev) != 0)
goto out;
}
error = ncp_instantiate(dir, dentry, &finfo);
out:
unlock_kernel();
......@@ -878,7 +946,7 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
static int ncp_create(struct inode *dir, struct dentry *dentry, int mode)
{
return ncp_create_new(dir, dentry, mode, 0);
return ncp_create_new(dir, dentry, mode, 0, 0);
}
static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
......@@ -906,6 +974,15 @@ static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
OC_MODE_CREATE, aDIR, 0xffff,
&finfo) == 0)
{
if (ncp_is_nfs_extras(server, finfo.volume)) {
mode |= S_IFDIR;
finfo.i.nfs.mode = mode;
if (ncp_modify_nfs_info(server,
finfo.volume,
finfo.i.dirEntNum,
mode, 0) != 0)
goto out;
}
error = ncp_instantiate(dir, dentry, &finfo);
}
out:
......@@ -1091,6 +1168,16 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
return error;
}
static int ncp_mknod(struct inode * dir, struct dentry *dentry,
int mode, int rdev)
{
if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) {
DPRINTK(KERN_DEBUG "ncp_mknod: mode = 0%o\n", mode);
return ncp_create_new(dir, dentry, mode, rdev, 0);
}
return -EPERM; /* Strange, but true */
}
/* The following routines are taken directly from msdos-fs */
/* Linear day numbers of the respective 1sts in non-leap years. */
......
......@@ -51,12 +51,10 @@ int ncp_make_open(struct inode *inode, int right)
struct ncp_entry_info finfo;
int result;
finfo.i.dirEntNum = NCP_FINFO(inode)->dirEntNum;
finfo.i.volNumber = NCP_FINFO(inode)->volNumber;
/* tries max. rights */
finfo.access = O_RDWR;
result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
NULL, NULL, OC_MODE_OPEN,
inode, NULL, OC_MODE_OPEN,
0, AR_READ | AR_WRITE, &finfo);
if (!result)
goto update;
......@@ -65,13 +63,13 @@ int ncp_make_open(struct inode *inode, int right)
case O_RDONLY:
finfo.access = O_RDONLY;
result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
NULL, NULL, OC_MODE_OPEN,
inode, NULL, OC_MODE_OPEN,
0, AR_READ, &finfo);
break;
case O_WRONLY:
finfo.access = O_WRONLY;
result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
NULL, NULL, OC_MODE_OPEN,
inode, NULL, OC_MODE_OPEN,
0, AR_WRITE, &finfo);
break;
}
......@@ -115,30 +113,31 @@ ncp_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
DPRINTK("ncp_file_read: enter %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
error = -EIO;
if (!ncp_conn_valid(NCP_SERVER(inode)))
goto out;
error = -EINVAL;
return -EIO;
if (!S_ISREG(inode->i_mode)) {
DPRINTK("ncp_file_read: read from non-file, mode %07o\n",
inode->i_mode);
goto out;
return -EINVAL;
}
pos = *ppos;
/* leave it out on server ...
if (pos + count > inode->i_size) {
count = inode->i_size - pos;
if ((ssize_t) count < 0) {
return -EINVAL;
}
if (!count)
return 0;
if (pos > inode->i_sb->s_maxbytes)
return 0;
if (pos + count > inode->i_sb->s_maxbytes) {
count = inode->i_sb->s_maxbytes - pos;
}
*/
error = 0;
if (!count) /* size_t is never < 0 */
goto out;
error = ncp_make_open(inode, O_RDONLY);
if (error) {
DPRINTK(KERN_ERR "ncp_file_read: open failed, error=%d\n", error);
goto out;
return error;
}
bufsize = NCP_SERVER(inode)->buffer_size;
......@@ -184,7 +183,6 @@ ncp_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
dentry->d_parent->d_name.name, dentry->d_name.name);
outrel:
ncp_inode_close(inode);
out:
return already_read ? already_read : error;
}
......@@ -201,28 +199,46 @@ ncp_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
DPRINTK("ncp_file_write: enter %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
errno = -EIO;
if (!ncp_conn_valid(NCP_SERVER(inode)))
goto out;
return -EIO;
if (!S_ISREG(inode->i_mode)) {
DPRINTK("ncp_file_write: write to non-file, mode %07o\n",
inode->i_mode);
return -EINVAL;
}
if ((ssize_t) count < 0)
return -EINVAL;
pos = *ppos;
if (file->f_flags & O_APPEND) {
pos = inode->i_size;
}
if (pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) {
if (pos >= MAX_NON_LFS) {
send_sig(SIGXFSZ, current, 0);
return -EFBIG;
}
if (count > MAX_NON_LFS - (u32)pos) {
count = MAX_NON_LFS - (u32)pos;
}
}
if (pos >= inode->i_sb->s_maxbytes) {
if (count || pos > inode->i_sb->s_maxbytes) {
send_sig(SIGXFSZ, current, 0);
return -EFBIG;
}
}
if (pos + count > inode->i_sb->s_maxbytes) {
count = inode->i_sb->s_maxbytes - pos;
}
errno = 0;
if (!count)
goto out;
return 0;
errno = ncp_make_open(inode, O_WRONLY);
if (errno) {
DPRINTK(KERN_ERR "ncp_file_write: open failed, error=%d\n", errno);
return errno;
}
pos = *ppos;
if (file->f_flags & O_APPEND) {
pos = inode->i_size;
}
bufsize = NCP_SERVER(inode)->buffer_size;
already_written = 0;
......@@ -268,7 +284,6 @@ ncp_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
dentry->d_parent->d_name.name, dentry->d_name.name);
outrel:
ncp_inode_close(inode);
out:
return already_written ? already_written : errno;
}
......
......@@ -5,6 +5,7 @@
* Modified for big endian by J.F. Chadima and David S. Miller
* Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
* Modified 1998 Wolfram Pienkoss for NLS
* Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
*
*/
......@@ -90,8 +91,8 @@ static struct super_operations ncp_sops =
statfs: ncp_statfs,
};
extern struct dentry_operations ncp_dentry_operations;
#ifdef CONFIG_NCPFS_EXTRAS
extern struct dentry_operations ncp_root_dentry_operations;
#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
extern struct address_space_operations ncp_symlink_aops;
extern int ncp_symlink(struct inode*, struct dentry*, const char*);
#endif
......@@ -99,19 +100,18 @@ extern int ncp_symlink(struct inode*, struct dentry*, const char*);
/*
* Fill in the ncpfs-specific information in the inode.
*/
void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
{
NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
NCP_FINFO(inode)->volNumber = nwinfo->i.volNumber;
NCP_FINFO(inode)->volNumber = nwinfo->volume;
}
#ifdef CONFIG_NCPFS_STRONG
NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
#else
void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
{
ncp_update_dirent(inode, nwinfo);
NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
#endif
NCP_FINFO(inode)->access = nwinfo->access;
NCP_FINFO(inode)->server_file_handle = nwinfo->server_file_handle;
memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
sizeof(nwinfo->file_handle));
DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
......@@ -119,68 +119,27 @@ void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
NCP_FINFO(inode)->dirEntNum);
}
void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
{
struct nw_info_struct *nwi = &nwinfo->i;
struct ncp_server *server = NCP_SERVER(inode);
if (!atomic_read(&NCP_FINFO(inode)->opened)) {
#ifdef CONFIG_NCPFS_STRONG
NCP_FINFO(inode)->nwattr = nwi->attributes;
#endif
if (nwi->attributes & aDIR) {
inode->i_mode = server->m.dir_mode;
inode->i_size = NCP_BLOCK_SIZE;
} else {
inode->i_mode = server->m.file_mode;
inode->i_size = le32_to_cpu(nwi->dataStreamSize);
#ifdef CONFIG_NCPFS_EXTRAS
if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS)) && (nwi->attributes & aSHARED)) {
switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
case aHIDDEN:
if (server->m.flags & NCP_MOUNT_SYMLINKS) {
if ( /* (inode->i_size >= NCP_MIN_SYMLINK_SIZE)
&& */ (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) {
inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
break;
}
}
/* FALLTHROUGH */
case 0:
if (server->m.flags & NCP_MOUNT_EXTRAS)
inode->i_mode |= 0444;
break;
case aSYSTEM:
if (server->m.flags & NCP_MOUNT_EXTRAS)
inode->i_mode |= (inode->i_mode >> 2) & 0111;
break;
/* case aSYSTEM|aHIDDEN: */
default:
/* reserved combination */
break;
}
}
#endif
}
if (nwi->attributes & aRONLY) inode->i_mode &= ~0222;
/* NFS namespace mode overrides others if it's set. */
DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n",
nwi->entryName, nwi->nfs.mode);
if (nwi->nfs.mode) {
/* XXX Security? */
inode->i_mode = nwi->nfs.mode;
}
inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(nwi->modifyTime),
le16_to_cpu(nwi->modifyDate));
inode->i_ctime = ncp_date_dos2unix(le16_to_cpu(nwi->creationTime),
le16_to_cpu(nwi->creationDate));
inode->i_atime = ncp_date_dos2unix(0, le16_to_cpu(nwi->lastAccessDate));
NCP_FINFO(inode)->DosDirNum = nwi->DosDirNum;
NCP_FINFO(inode)->dirEntNum = nwi->dirEntNum;
NCP_FINFO(inode)->volNumber = nwi->volNumber;
inode->i_atime = ncp_date_dos2unix(0,
le16_to_cpu(nwi->lastAccessDate));
}
/*
* Fill in the inode based on the ncp_entry_info structure.
*/
static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
{
struct nw_info_struct *nwi = &nwinfo->i;
struct ncp_server *server = NCP_SERVER(inode);
......@@ -202,17 +161,18 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
if (/* (inode->i_size >= NCP_MIN_SYMLINK_SIZE)
&& */ (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) {
inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
break;
}
}
/* FALLTHROUGH */
case 0:
if (server->m.flags & NCP_MOUNT_EXTRAS)
inode->i_mode |= 0444;
inode->i_mode |= S_IRUGO;
break;
case aSYSTEM:
if (server->m.flags & NCP_MOUNT_EXTRAS)
inode->i_mode |= (inode->i_mode >> 2) & 0111;
inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO;
break;
/* case aSYSTEM|aHIDDEN: */
default:
......@@ -222,7 +182,31 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
}
#endif
}
if (nwi->attributes & aRONLY) inode->i_mode &= ~0222;
if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
}
void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
{
NCP_FINFO(inode)->flags = 0;
if (!atomic_read(&NCP_FINFO(inode)->opened)) {
NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
ncp_update_attrs(inode, nwinfo);
}
ncp_update_dates(inode, &nwinfo->i);
ncp_update_dirent(inode, nwinfo);
}
/*
* Fill in the inode based on the ncp_entry_info structure.
*/
static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
{
struct ncp_server *server = NCP_SERVER(inode);
NCP_FINFO(inode)->flags = 0;
ncp_update_attrs(inode, nwinfo);
DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
......@@ -232,14 +216,7 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
inode->i_rdev = NODEV;
inode->i_blksize = NCP_BLOCK_SIZE;
inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(nwi->modifyTime),
le16_to_cpu(nwi->modifyDate));
inode->i_ctime = ncp_date_dos2unix(le16_to_cpu(nwi->creationTime),
le16_to_cpu(nwi->creationDate));
inode->i_atime = ncp_date_dos2unix(0,
le16_to_cpu(nwi->lastAccessDate));
ncp_update_dates(inode, &nwinfo->i);
ncp_update_inode(inode, nwinfo);
}
......@@ -274,11 +251,17 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &ncp_dir_inode_operations;
inode->i_fop = &ncp_dir_operations;
#ifdef CONFIG_NCPFS_EXTRAS
#ifdef CONFIG_NCPFS_NFS_NS
} else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
init_special_inode(inode, inode->i_mode, info->i.nfs.rdev);
#endif
#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
} else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &ncp_symlink_inode_operations;
inode->i_data.a_ops = &ncp_symlink_aops;
#endif
} else {
make_bad_inode(inode);
}
insert_inode_hash(inode);
} else
......@@ -479,7 +462,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
#ifdef CONFIG_NCPFS_SMALLDOS
finfo.i.NSCreator = NW_NS_DOS;
#endif
finfo.i.volNumber = NCP_NUMBER_OF_VOLUMES + 1; /* illegal volnum */
finfo.volume = NCP_NUMBER_OF_VOLUMES;
/* set dates of mountpoint to Jan 1, 1986; 00:00 */
finfo.i.creationTime = finfo.i.modifyTime
= cpu_to_le16(0x0000);
......@@ -492,7 +475,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
finfo.opened = 0;
finfo.ino = 2; /* tradition */
server->name_space[finfo.i.volNumber] = NW_NS_DOS;
server->name_space[finfo.volume] = NW_NS_DOS;
error = -ENOMEM;
root_inode = ncp_iget(sb, &finfo);
......@@ -502,7 +485,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
sb->s_root = d_alloc_root(root_inode);
if (!sb->s_root)
goto out_no_root;
sb->s_root->d_op = &ncp_dentry_operations;
sb->s_root->d_op = &ncp_root_dentry_operations;
return 0;
out_no_root:
......@@ -567,12 +550,60 @@ static void ncp_put_super(struct super_block *sb)
static int ncp_statfs(struct super_block *sb, struct statfs *buf)
{
struct dentry* d;
struct inode* i;
struct ncp_inode_info* ni;
struct ncp_server* s;
struct ncp_volume_info vi;
int err;
__u8 dh;
d = sb->s_root;
if (!d) {
goto dflt;
}
i = d->d_inode;
if (!i) {
goto dflt;
}
ni = NCP_FINFO(i);
if (!ni) {
goto dflt;
}
s = NCP_SBP(sb);
if (!s) {
goto dflt;
}
if (!s->m.mounted_vol[0]) {
goto dflt;
}
err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
if (err) {
goto dflt;
}
err = ncp_get_directory_info(s, dh, &vi);
ncp_dirhandle_free(s, dh);
if (err) {
goto dflt;
}
buf->f_type = NCP_SUPER_MAGIC;
buf->f_bsize = vi.sectors_per_block * 512;
buf->f_blocks = vi.total_blocks;
buf->f_bfree = vi.free_blocks;
buf->f_bavail = vi.free_blocks;
buf->f_files = vi.total_dir_entries;
buf->f_ffree = vi.available_dir_entries;
buf->f_namelen = 12;
return 0;
/* We cannot say how much disk space is left on a mounted
NetWare Server, because free space is distributed over
volumes, and the current user might have disk quotas. So
free space is not that simple to determine. Our decision
here is to err conservatively. */
dflt:;
buf->f_type = NCP_SUPER_MAGIC;
buf->f_bsize = NCP_BLOCK_SIZE;
buf->f_blocks = 0;
......@@ -616,7 +647,7 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
if (((attr->ia_valid & ATTR_MODE) &&
(attr->ia_mode &
~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
~(S_IFREG | S_IFDIR | S_IRWXUGO))))
goto out;
info_mask = 0;
......@@ -625,58 +656,81 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
#if 1
if ((attr->ia_valid & ATTR_MODE) != 0)
{
if (S_ISDIR(inode->i_mode)) {
umode_t newmode;
umode_t newmode = attr->ia_mode;
info_mask |= DM_ATTRIBUTES;
newmode = attr->ia_mode;
newmode &= NCP_SERVER(inode)->m.dir_mode;
if (newmode & 0222)
if (S_ISDIR(inode->i_mode)) {
newmode &= server->m.dir_mode;
} else {
#ifdef CONFIG_NCPFS_EXTRAS
if (server->m.flags & NCP_MOUNT_EXTRAS) {
/* any non-default execute bit set */
if (newmode & ~server->m.file_mode & S_IXUGO)
info.attributes |= aSHARED | aSYSTEM;
/* read for group/world and not in default file_mode */
else if (newmode & ~server->m.file_mode & S_IRUGO)
info.attributes |= aSHARED;
} else
#endif
newmode &= server->m.file_mode;
}
if (newmode & S_IWUGO)
info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
else
info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
} else if (!S_ISREG(inode->i_mode))
{
result = -EPERM;
#ifdef CONFIG_NCPFS_NFS_NS
if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
result = ncp_modify_nfs_info(server,
NCP_FINFO(inode)->volNumber,
NCP_FINFO(inode)->dirEntNum,
attr->ia_mode, 0);
if (result != 0)
goto out;
}
else
info.attributes &= ~(aSHARED | aSYSTEM);
{
umode_t newmode;
#ifdef CONFIG_NCPFS_EXTRAS
int extras;
/* mark partial success */
struct iattr tmpattr;
extras = server->m.flags & NCP_MOUNT_EXTRAS;
#endif
info_mask |= DM_ATTRIBUTES;
newmode=attr->ia_mode;
#ifdef CONFIG_NCPFS_EXTRAS
if (!extras)
#endif
newmode &= server->m.file_mode;
tmpattr.ia_valid = ATTR_MODE;
tmpattr.ia_mode = attr->ia_mode;
if (newmode & 0222) /* any write bit set */
{
info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
inode_setattr(inode, &tmpattr);
}
else
{
info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
}
#ifdef CONFIG_NCPFS_EXTRAS
if (extras) {
if (newmode & 0111) /* any execute bit set */
info.attributes |= aSHARED | aSYSTEM;
/* read for group/world and not in default file_mode */
else if (newmode & ~server->m.file_mode & 0444)
info.attributes |= aSHARED;
}
#endif
}
}
#endif
/* Do SIZE before attributes, otherwise mtime together with size does not work...
*/
if ((attr->ia_valid & ATTR_SIZE) != 0) {
int written;
DPRINTK("ncpfs: trying to change size to %ld\n",
attr->ia_size);
if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
result = -EACCES;
goto out;
}
ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
attr->ia_size, 0, "", &written);
/* According to ndir, the changes only take effect after
closing the file */
ncp_inode_close(inode);
result = ncp_make_closed(inode);
{
struct iattr tmpattr;
tmpattr.ia_valid = ATTR_SIZE;
tmpattr.ia_size = attr->ia_size;
inode_setattr(inode, &tmpattr);
}
}
if ((attr->ia_valid & ATTR_CTIME) != 0) {
info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
ncp_date_unix2dos(attr->ia_ctime,
......@@ -711,33 +765,16 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
a terrible hack, but I do not know
how to do this correctly. */
result = 0;
}
} else
goto out;
}
#ifdef CONFIG_NCPFS_STRONG
if ((!result) && (info_mask & DM_ATTRIBUTES))
NCP_FINFO(inode)->nwattr = info.attributes;
#endif
}
if ((attr->ia_valid & ATTR_SIZE) != 0) {
int written;
DPRINTK("ncpfs: trying to change size to %ld\n",
attr->ia_size);
if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
result = -EACCES;
goto out;
}
ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
attr->ia_size, 0, "", &written);
/* According to ndir, the changes only take effect after
closing the file */
ncp_inode_close(inode);
result = ncp_make_closed(inode);
if (!result)
result = vmtruncate(inode, attr->ia_size);
}
inode_setattr(inode, attr);
out:
unlock_kernel();
return result;
......
......@@ -201,7 +201,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
case NCP_IOC_SETROOT:
{
struct ncp_setroot_ioctl sr;
struct nw_info_struct i;
unsigned int vnum, de, dosde;
struct dentry* dentry;
if (!capable(CAP_SYS_ADMIN))
......@@ -214,15 +214,21 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
sizeof(sr))) return -EFAULT;
if (sr.volNumber < 0) {
server->m.mounted_vol[0] = 0;
i.volNumber = NCP_NUMBER_OF_VOLUMES + 1;
i.dirEntNum = 0;
i.DosDirNum = 0;
vnum = NCP_NUMBER_OF_VOLUMES;
de = 0;
dosde = 0;
} else if (sr.volNumber >= NCP_NUMBER_OF_VOLUMES) {
return -EINVAL;
} else
if (ncp_mount_subdir(server, &i, sr.volNumber,
} else {
struct nw_info_struct ni;
if (ncp_mount_subdir(server, &ni, sr.volNumber,
sr.namespace, sr.dirEntNum))
return -ENOENT;
vnum = ni.volNumber;
de = ni.dirEntNum;
dosde = ni.DosDirNum;
}
dentry = inode->i_sb->s_root;
server->root_setuped = 1;
......@@ -230,9 +236,9 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
struct inode* inode = dentry->d_inode;
if (inode) {
NCP_FINFO(inode)->volNumber = i.volNumber;
NCP_FINFO(inode)->dirEntNum = i.dirEntNum;
NCP_FINFO(inode)->DosDirNum = i.DosDirNum;
NCP_FINFO(inode)->volNumber = vnum;
NCP_FINFO(inode)->dirEntNum = de;
NCP_FINFO(inode)->DosDirNum = dosde;
} else
DPRINTK("ncpfs: s_root->d_inode==NULL\n");
} else
......
......@@ -5,6 +5,7 @@
* Modified for big endian by J.F. Chadima and David S. Miller
* Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
* Modified 1999 Wolfram Pienkoss for NLS
* Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
*
*/
......@@ -44,6 +45,10 @@ static void ncp_add_dword(struct ncp_server *server, __u32 x)
return;
}
static inline void ncp_add_dword_lh(struct ncp_server *server, __u32 x) {
ncp_add_dword(server, cpu_to_le32(x));
}
static void ncp_add_mem(struct ncp_server *server, const void *source, int size)
{
assert_server_locked(server);
......@@ -89,24 +94,43 @@ static inline char *
return &(server->packet[sizeof(struct ncp_reply_header) + offset]);
}
static inline __u8 BVAL(void* data)
{
return get_unaligned((__u8*)data);
}
static __u8
ncp_reply_byte(struct ncp_server *server, int offset)
{
return get_unaligned((__u8 *) ncp_reply_data(server, offset));
}
static inline __u16 WVAL_LH(void* data)
{
return le16_to_cpu(get_unaligned((__u16*)data));
}
static __u16
ncp_reply_word(struct ncp_server *server, int offset)
{
return get_unaligned((__u16 *) ncp_reply_data(server, offset));
}
static inline __u32 DVAL_LH(void* data)
{
return le32_to_cpu(get_unaligned((__u32*)data));
}
static __u32
ncp_reply_dword(struct ncp_server *server, int offset)
{
return get_unaligned((__u32 *) ncp_reply_data(server, offset));
}
static inline __u32 ncp_reply_dword_lh(struct ncp_server* server, int offset) {
return le32_to_cpu(ncp_reply_dword(server, offset));
}
int
ncp_negotiate_buffersize(struct ncp_server *server, int size, int *target)
{
......@@ -159,10 +183,8 @@ ncp_negotiate_size_and_options(struct ncp_server *server,
return 0;
}
int
ncp_get_volume_info_with_number(struct ncp_server *server, int n,
struct ncp_volume_info *target)
{
int ncp_get_volume_info_with_number(struct ncp_server* server,
int n, struct ncp_volume_info* target) {
int result;
int len;
......@@ -172,12 +194,12 @@ ncp_get_volume_info_with_number(struct ncp_server *server, int n,
if ((result = ncp_request(server, 22)) != 0) {
goto out;
}
target->total_blocks = ncp_reply_dword(server, 0);
target->free_blocks = ncp_reply_dword(server, 4);
target->purgeable_blocks = ncp_reply_dword(server, 8);
target->not_yet_purgeable_blocks = ncp_reply_dword(server, 12);
target->total_dir_entries = ncp_reply_dword(server, 16);
target->available_dir_entries = ncp_reply_dword(server, 20);
target->total_blocks = ncp_reply_dword_lh(server, 0);
target->free_blocks = ncp_reply_dword_lh(server, 4);
target->purgeable_blocks = ncp_reply_dword_lh(server, 8);
target->not_yet_purgeable_blocks = ncp_reply_dword_lh(server, 12);
target->total_dir_entries = ncp_reply_dword_lh(server, 16);
target->available_dir_entries = ncp_reply_dword_lh(server, 20);
target->sectors_per_block = ncp_reply_byte(server, 28);
memset(&(target->volume_name), 0, sizeof(target->volume_name));
......@@ -195,6 +217,40 @@ ncp_get_volume_info_with_number(struct ncp_server *server, int n,
return result;
}
int ncp_get_directory_info(struct ncp_server* server, __u8 n,
struct ncp_volume_info* target) {
int result;
int len;
ncp_init_request_s(server, 45);
ncp_add_byte(server, n);
if ((result = ncp_request(server, 22)) != 0) {
goto out;
}
target->total_blocks = ncp_reply_dword_lh(server, 0);
target->free_blocks = ncp_reply_dword_lh(server, 4);
target->purgeable_blocks = 0;
target->not_yet_purgeable_blocks = 0;
target->total_dir_entries = ncp_reply_dword_lh(server, 8);
target->available_dir_entries = ncp_reply_dword_lh(server, 12);
target->sectors_per_block = ncp_reply_byte(server, 20);
memset(&(target->volume_name), 0, sizeof(target->volume_name));
result = -EIO;
len = ncp_reply_byte(server, 21);
if (len > NCP_VOLNAME_LEN) {
DPRINTK("ncpfs: volume name too long: %d\n", len);
goto out;
}
memcpy(&(target->volume_name), ncp_reply_data(server, 22), len);
result = 0;
out:
ncp_unlock_server(server);
return result;
}
int
ncp_close_file(struct ncp_server *server, const char *file_id)
{
......@@ -248,10 +304,37 @@ static void ncp_add_handle_path(struct ncp_server *server, __u8 vol_num,
}
}
static void ncp_extract_file_info(void *structure, struct nw_info_struct *target)
int ncp_dirhandle_alloc(struct ncp_server* server, __u8 volnum, __u32 dirent,
__u8* dirhandle) {
int result;
ncp_init_request(server);
ncp_add_byte(server, 12); /* subfunction */
ncp_add_byte(server, NW_NS_DOS);
ncp_add_byte(server, 0);
ncp_add_word(server, 0);
ncp_add_handle_path(server, volnum, dirent, 1, NULL);
if ((result = ncp_request(server, 87)) == 0) {
*dirhandle = ncp_reply_byte(server, 0);
}
ncp_unlock_server(server);
return result;
}
int ncp_dirhandle_free(struct ncp_server* server, __u8 dirhandle) {
int result;
ncp_init_request_s(server, 20);
ncp_add_byte(server, dirhandle);
result = ncp_request(server, 22);
ncp_unlock_server(server);
return result;
}
void ncp_extract_file_info(void *structure, struct nw_info_struct *target)
{
__u8 *name_len;
const int info_struct_size = sizeof(struct nw_info_struct) - 257;
const int info_struct_size = offsetof(struct nw_info_struct, nameLen);
memcpy(target, structure, info_struct_size);
name_len = structure + info_struct_size;
......@@ -261,6 +344,56 @@ static void ncp_extract_file_info(void *structure, struct nw_info_struct *target
return;
}
#ifdef CONFIG_NCPFS_NFS_NS
static inline void ncp_extract_nfs_info(unsigned char *structure,
struct nw_nfs_info *target)
{
target->mode = DVAL_LH(structure);
target->rdev = DVAL_LH(structure + 8);
}
#endif
int ncp_obtain_nfs_info(struct ncp_server *server,
struct nw_info_struct *target)
{
int result = 0;
#ifdef CONFIG_NCPFS_NFS_NS
__u32 volnum = target->volNumber;
if (ncp_is_nfs_extras(server, volnum)) {
ncp_init_request(server);
ncp_add_byte(server, 19); /* subfunction */
ncp_add_byte(server, server->name_space[volnum]);
ncp_add_byte(server, NW_NS_NFS);
ncp_add_byte(server, 0);
ncp_add_byte(server, volnum);
ncp_add_dword(server, target->dirEntNum);
/* We must retrieve both nlinks and rdev, otherwise some server versions
report zeroes instead of valid data */
ncp_add_dword_lh(server, NSIBM_NFS_MODE | NSIBM_NFS_NLINKS | NSIBM_NFS_RDEV);
if ((result = ncp_request(server, 87)) == 0) {
ncp_extract_nfs_info(ncp_reply_data(server, 0), &target->nfs);
DPRINTK(KERN_DEBUG
"ncp_obtain_nfs_info: (%s) mode=0%o, rdev=0x%x\n",
target->entryName, target->nfs.mode,
target->nfs.rdev);
} else {
target->nfs.mode = 0;
target->nfs.rdev = 0;
}
ncp_unlock_server(server);
} else
#endif
{
target->nfs.mode = 0;
target->nfs.rdev = 0;
}
return result;
}
/*
* Returns information for a (one-component) name relative to
* the specified directory.
......@@ -287,6 +420,10 @@ int ncp_obtain_info(struct ncp_server *server, struct inode *dir, char *path,
if ((result = ncp_request(server, 87)) != 0)
goto out;
ncp_extract_file_info(ncp_reply_data(server, 0), target);
ncp_unlock_server(server);
result = ncp_obtain_nfs_info(server, target);
return result;
out:
ncp_unlock_server(server);
......@@ -463,6 +600,7 @@ ncp_lookup_volume(struct ncp_server *server, char *volname,
/* set dates to Jan 1, 1986 00:00 */
target->creationTime = target->modifyTime = cpu_to_le16(0x0000);
target->creationDate = target->modifyDate = target->lastAccessDate = cpu_to_le16(0x0C21);
target->nfs.mode = 0;
return 0;
}
......@@ -500,6 +638,34 @@ int ncp_modify_file_or_subdir_dos_info(struct ncp_server *server,
info_mask, info);
}
#ifdef CONFIG_NCPFS_NFS_NS
int ncp_modify_nfs_info(struct ncp_server *server, __u8 volnum, __u32 dirent,
__u32 mode, __u32 rdev)
{
int result = 0;
if (server->name_space[volnum] == NW_NS_NFS) {
ncp_init_request(server);
ncp_add_byte(server, 25); /* subfunction */
ncp_add_byte(server, server->name_space[volnum]);
ncp_add_byte(server, NW_NS_NFS);
ncp_add_byte(server, volnum);
ncp_add_dword(server, dirent);
/* we must always operate on both nlinks and rdev, otherwise
rdev is not set */
ncp_add_dword_lh(server, NSIBM_NFS_MODE | NSIBM_NFS_NLINKS | NSIBM_NFS_RDEV);
ncp_add_dword_lh(server, mode);
ncp_add_dword_lh(server, 1); /* nlinks */
ncp_add_dword_lh(server, rdev);
result = ncp_request(server, 87);
ncp_unlock_server(server);
}
return result;
}
#endif
static int
ncp_DeleteNSEntry(struct ncp_server *server,
__u8 have_dir_base, __u8 volnum, __u32 dirent,
......@@ -577,15 +743,12 @@ int ncp_open_create_file_or_subdir(struct ncp_server *server,
struct ncp_entry_info *target)
{
__u16 search_attribs = ntohs(0x0600);
__u8 volnum = target->i.volNumber;
__u32 dirent = target->i.dirEntNum;
__u8 volnum;
__u32 dirent;
int result;
if (dir)
{
volnum = NCP_FINFO(dir)->volNumber;
dirent = NCP_FINFO(dir)->dirEntNum;
}
if ((create_attributes & aDIR) != 0) {
search_attribs |= ntohs(0x0080);
......@@ -606,12 +769,16 @@ int ncp_open_create_file_or_subdir(struct ncp_server *server,
goto out;
if (!(create_attributes & aDIR))
target->opened = 1;
target->server_file_handle = ncp_reply_dword(server, 0);
target->open_create_action = ncp_reply_byte(server, 4);
/* in target there's a new finfo to fill */
ncp_extract_file_info(ncp_reply_data(server, 6), &(target->i));
ConvertToNWfromDWORD(target->server_file_handle, target->file_handle);
target->volume = target->i.volNumber;
ConvertToNWfromDWORD(ncp_reply_dword(server, 0), target->file_handle);
ncp_unlock_server(server);
(void)ncp_obtain_nfs_info(server, &(target->i));
return 0;
out:
ncp_unlock_server(server);
......@@ -672,11 +839,64 @@ int ncp_search_for_file_or_subdir(struct ncp_server *server,
memcpy(seq, ncp_reply_data(server, 0), sizeof(*seq));
ncp_extract_file_info(ncp_reply_data(server, 10), target);
ncp_unlock_server(server);
result = ncp_obtain_nfs_info(server, target);
return result;
out:
ncp_unlock_server(server);
return result;
}
int ncp_search_for_fileset(struct ncp_server *server,
struct nw_search_sequence *seq,
int* more,
int* cnt,
char* buffer,
size_t bufsize,
char** rbuf,
size_t* rsize)
{
int result;
ncp_init_request(server);
ncp_add_byte(server, 20);
ncp_add_byte(server, server->name_space[seq->volNumber]);
ncp_add_byte(server, 0); /* datastream */
ncp_add_word(server, htons(0x0680));
ncp_add_dword(server, RIM_ALL);
ncp_add_word(server, 32767); /* max returned items */
ncp_add_mem(server, seq, 9);
#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, '*');
}
result = ncp_request2(server, 87, buffer, bufsize);
if (result) {
ncp_unlock_server(server);
return result;
}
if (server->ncp_reply_size < 12) {
ncp_unlock_server(server);
return 0xFF;
}
*rsize = server->ncp_reply_size - 12;
ncp_unlock_server(server);
buffer = buffer + sizeof(struct ncp_reply_header);
*rbuf = buffer + 12;
*cnt = WVAL_LH(buffer + 10);
*more = BVAL(buffer + 9);
memcpy(seq, buffer, 9);
return 0;
}
int
ncp_RenameNSEntry(struct ncp_server *server,
struct inode *old_dir, char *old_name, int old_type,
......
......@@ -44,8 +44,13 @@
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_get_volume_info_with_number(struct ncp_server* server, int n,
struct ncp_volume_info *target);
int ncp_get_directory_info(struct ncp_server* server, __u8 dirhandle,
struct ncp_volume_info* target);
int ncp_close_file(struct ncp_server *, const char *);
static inline int ncp_read_bounce_size(__u32 size) {
return sizeof(struct ncp_reply_header) + 2 + 2 + size + 8;
......@@ -61,13 +66,17 @@ static inline void ncp_inode_close(struct inode *inode) {
atomic_dec(&NCP_FINFO(inode)->opened);
}
void ncp_extract_file_info(void* src, struct nw_info_struct* target);
int ncp_obtain_info(struct ncp_server *server, struct inode *, char *,
struct nw_info_struct *target);
int ncp_obtain_nfs_info(struct ncp_server *server, struct nw_info_struct *target);
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, const struct nw_modify_dos_info *info);
int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server *, struct inode *,
const char* path, __u32, const struct nw_modify_dos_info *info);
int ncp_modify_nfs_info(struct ncp_server *, __u8 volnum, __u32 dirent,
__u32 mode, __u32 rdev);
int ncp_del_file_or_subdir2(struct ncp_server *, struct dentry*);
int ncp_del_file_or_subdir(struct ncp_server *, struct inode *, char *);
......@@ -79,6 +88,11 @@ int ncp_initialize_search(struct ncp_server *, struct inode *,
int ncp_search_for_file_or_subdir(struct ncp_server *server,
struct nw_search_sequence *seq,
struct nw_info_struct *target);
int ncp_search_for_fileset(struct ncp_server *server,
struct nw_search_sequence *seq,
int* more, int* cnt,
char* buffer, size_t bufsize,
char** rbuf, size_t* rsize);
int ncp_ren_or_mov_file_or_subdir(struct ncp_server *server,
struct inode *, char *, struct inode *, char *);
......@@ -99,6 +113,20 @@ ncp_ClearPhysicalRecord(struct ncp_server *server,
int
ncp_mount_subdir(struct ncp_server *, struct nw_info_struct *,
__u8, __u8, __u32);
int ncp_dirhandle_alloc(struct ncp_server *, __u8 vol, __u32 dirent, __u8 *dirhandle);
int ncp_dirhandle_free(struct ncp_server *, __u8 dirhandle);
int ncp_create_new(struct inode *dir, struct dentry *dentry,
int mode, int rdev, int attributes);
static inline int ncp_is_nfs_extras(struct ncp_server* server, unsigned int volnum) {
#ifdef CONFIG_NCPFS_NFS_NS
return (server->m.flags & NCP_MOUNT_NFS_EXTRAS) &&
(server->name_space[volnum] == NW_NS_NFS);
#else
return 0;
#endif
}
#ifdef CONFIG_NCPFS_NLS
......
......@@ -7,19 +7,21 @@
* the file to make sure we don't accidentally use a non-link file
* as a link.
*
* When using the NFS namespace, we set the mode to indicate a symlink and
* don't bother with the magic numbers.
*
* from linux/fs/ext2/symlink.c
*
* Copyright (C) 1998-99, Frank A. Vorstenbosch
*
* ncpfs symlink handling code
* NLS support (c) 1999 Petr Vandrovec
* Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
*
*/
#include <linux/config.h>
#ifdef CONFIG_NCPFS_EXTRAS
#include <asm/uaccess.h>
#include <linux/errno.h>
......@@ -28,7 +30,6 @@
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/stat.h>
#include <linux/smp_lock.h>
#include "ncplib_kernel.h"
......@@ -38,30 +39,25 @@
#define NCP_SYMLINK_MAGIC0 le32_to_cpu(0x6c6d7973) /* "symlnk->" */
#define NCP_SYMLINK_MAGIC1 le32_to_cpu(0x3e2d6b6e)
int ncp_create_new(struct inode *dir, struct dentry *dentry,
int mode,int attributes);
/* ----- read a symbolic link ------------------------------------------ */
static int ncp_symlink_readpage(struct file *file, struct page *page)
{
struct inode *inode = page->mapping->host;
int error, length, len, cnt;
char *link;
int error, length, len;
char *link, *rawlink;
char *buf = kmap(page);
error = -ENOMEM;
for (cnt = 0; (link=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_NFS))==NULL; cnt++) {
if (cnt > 10)
rawlink=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_NFS);
if (!rawlink)
goto fail;
schedule();
}
if (ncp_make_open(inode,O_RDONLY))
goto failEIO;
error=ncp_read_kernel(NCP_SERVER(inode),NCP_FINFO(inode)->file_handle,
0,NCP_MAX_SYMLINK_SIZE,link,&length);
0,NCP_MAX_SYMLINK_SIZE,rawlink,&length);
ncp_inode_close(inode);
/* Close file handle if no other users... */
......@@ -69,14 +65,20 @@ static int ncp_symlink_readpage(struct file *file, struct page *page)
if (error)
goto failEIO;
if (NCP_FINFO(inode)->flags & NCPI_KLUDGE_SYMLINK) {
if (length<NCP_MIN_SYMLINK_SIZE ||
((__u32 *)link)[0]!=NCP_SYMLINK_MAGIC0 ||
((__u32 *)link)[1]!=NCP_SYMLINK_MAGIC1)
((__u32 *)rawlink)[0]!=NCP_SYMLINK_MAGIC0 ||
((__u32 *)rawlink)[1]!=NCP_SYMLINK_MAGIC1)
goto failEIO;
link = rawlink + 8;
length -= 8;
} else {
link = rawlink;
}
len = NCP_MAX_SYMLINK_SIZE;
error = ncp_vol2io(NCP_SERVER(inode), buf, &len, link+8, length-8, 0);
kfree(link);
error = ncp_vol2io(NCP_SERVER(inode), buf, &len, link, length, 0);
kfree(rawlink);
if (error)
goto fail;
SetPageUptodate(page);
......@@ -86,7 +88,7 @@ static int ncp_symlink_readpage(struct file *file, struct page *page)
failEIO:
error = -EIO;
kfree(link);
kfree(rawlink);
fail:
SetPageError(page);
kunmap(page);
......@@ -105,62 +107,76 @@ struct address_space_operations ncp_symlink_aops = {
int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) {
struct inode *inode;
char *link;
int length, err, i;
char *rawlink;
int length, err, i, outlen;
int kludge;
int mode, attr;
unsigned int hdr;
DPRINTK("ncp_symlink(dir=%p,dentry=%p,symname=%s)\n",dir,dentry,symname);
#ifdef DEBUG
PRINTK("ncp_symlink(dir=%p,dentry=%p,symname=%s)\n",dir,dentry,symname);
if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber))
kludge = 0;
else
#ifdef CONFIG_NCPFS_EXTRAS
if (NCP_SERVER(dir)->m.flags & NCP_MOUNT_SYMLINKS)
kludge = 1;
else
#endif
/* EPERM is returned by VFS if symlink procedure does not exist */
return -EPERM;
if (!(NCP_SERVER(dir)->m.flags & NCP_MOUNT_SYMLINKS))
return -EPERM; /* EPERM is returned by VFS if symlink procedure does not exist */
rawlink=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_NFS);
if (!rawlink)
return -ENOMEM;
if ((length=strlen(symname))>NCP_MAX_SYMLINK_SIZE-8)
return -EINVAL;
if (kludge) {
mode = 0;
attr = aSHARED | aHIDDEN;
((__u32 *)rawlink)[0]=NCP_SYMLINK_MAGIC0;
((__u32 *)rawlink)[1]=NCP_SYMLINK_MAGIC1;
hdr = 8;
} else {
mode = S_IFLNK | S_IRWXUGO;
attr = 0;
hdr = 0;
}
if ((link=(char *)kmalloc(length+9,GFP_NFS))==NULL)
return -ENOMEM;
length = strlen(symname);
/* map to/from server charset, do not touch upper/lower case as
symlink can point out of ncp filesystem */
outlen = NCP_MAX_SYMLINK_SIZE - hdr;
err = ncp_io2vol(NCP_SERVER(dir), rawlink + hdr, &outlen, symname, length, 0);
if (err)
goto failfree;
outlen += hdr;
err = -EIO;
lock_kernel();
if (ncp_create_new(dir,dentry,0,aSHARED|aHIDDEN))
if (ncp_create_new(dir,dentry,mode,0,attr)) {
goto failfree;
}
inode=dentry->d_inode;
if (ncp_make_open(inode, O_WRONLY))
goto failfree;
((__u32 *)link)[0]=NCP_SYMLINK_MAGIC0;
((__u32 *)link)[1]=NCP_SYMLINK_MAGIC1;
/* map to/from server charset, do not touch upper/lower case as
symlink can point out of ncp filesystem */
length += 1;
err = ncp_io2vol(NCP_SERVER(inode),link+8,&length,symname,length-1,0);
if (err)
goto fail;
if(ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
0, length+8, link, &i) || i!=length+8) {
err = -EIO;
if (ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
0, outlen, rawlink, &i) || i!=outlen) {
goto fail;
}
ncp_inode_close(inode);
ncp_make_closed(inode);
unlock_kernel();
kfree(link);
kfree(rawlink);
return 0;
fail:
fail:;
ncp_inode_close(inode);
ncp_make_closed(inode);
failfree:
unlock_kernel();
kfree(link);
failfree:;
kfree(rawlink);
return err;
}
#endif
/* ----- EOF ----- */
......@@ -44,7 +44,7 @@ struct ncp_reply_header {
};
#define NCP_VOLNAME_LEN (16)
#define NCP_NUMBER_OF_VOLUMES (64)
#define NCP_NUMBER_OF_VOLUMES (256)
struct ncp_volume_info {
__u32 total_blocks;
__u32 free_blocks;
......@@ -85,6 +85,18 @@ struct ncp_volume_info {
#define RIM_ALL (ntohl(0xFF0F0000L))
#define RIM_COMPRESSED_INFO (ntohl(0x00000080L))
/* Defines for NSInfoBitMask */
#define NSIBM_NFS_NAME 0x0001
#define NSIBM_NFS_MODE 0x0002
#define NSIBM_NFS_GID 0x0004
#define NSIBM_NFS_NLINKS 0x0008
#define NSIBM_NFS_RDEV 0x0010
#define NSIBM_NFS_LINK 0x0020
#define NSIBM_NFS_CREATED 0x0040
#define NSIBM_NFS_UID 0x0080
#define NSIBM_NFS_ACSFLAG 0x0100
#define NSIBM_NFS_MYFLAG 0x0200
/* open/create modes */
#define OC_MODE_OPEN 0x01
#define OC_MODE_TRUNCATE 0x02
......@@ -109,6 +121,11 @@ struct ncp_volume_info {
#define AR_OPEN_COMPRESSED 0x0100
#endif
struct nw_nfs_info {
__u32 mode;
__u32 rdev;
};
struct nw_info_struct {
__u32 spaceAlloc __attribute__((packed));
__u32 attributes __attribute__((packed));
......@@ -136,6 +153,10 @@ struct nw_info_struct {
__u32 NSCreator __attribute__((packed));
__u8 nameLen __attribute__((packed));
__u8 entryName[256] __attribute__((packed));
/* libncp may depend on there being nothing after entryName */
#ifdef __KERNEL__
struct nw_nfs_info nfs;
#endif
};
/* modify mask - use with MODIFY_DOS_INFO structure */
......
......@@ -182,9 +182,8 @@ struct ncp_entry_info {
ino_t ino;
int opened;
int access;
__u32 server_file_handle __attribute__((packed));
__u8 open_create_action __attribute__((packed));
__u8 file_handle[6] __attribute__((packed));
unsigned int volume;
__u8 file_handle[6];
};
/* Guess, what 0x564c is :-) */
......
......@@ -22,7 +22,8 @@ struct ncp_inode_info {
struct semaphore open_sem;
atomic_t opened;
int access;
__u32 server_file_handle;
int flags;
#define NCPI_KLUDGE_SYMLINK 0x0001
__u8 file_handle[6];
struct inode vfs_inode;
};
......
......@@ -21,6 +21,7 @@
#define NCP_MOUNT_NO_NFS 0x0010 /* do not use NFS namespace */
#define NCP_MOUNT_EXTRAS 0x0020
#define NCP_MOUNT_SYMLINKS 0x0040 /* enable symlinks */
#define NCP_MOUNT_NFS_EXTRAS 0x0080 /* Enable use of NFS NS meta-info */
struct ncp_mount_data {
int version;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment