diff options
| author | Petr Vandrovec <vandrove@vc.cvut.cz> | 2002-07-25 00:48:08 +0200 |
|---|---|---|
| committer | Petr Vandrovec <vandrove@vc.cvut.cz> | 2002-07-25 00:48:08 +0200 |
| commit | 41783de41528808b064bf5bc617c2ddcd7d7061a (patch) | |
| tree | a83a4b3e91b09912bc27c38e1ca15247c017d2d9 | |
| parent | 3b89dbbd78bb638c2691c5752ed0d54fd1a73fa1 (diff) | |
| parent | 275d178366f4df0dc12fe79f72c732d6a369a07d (diff) | |
Merge bk://linux.bkbits.net/linux-2.5 into vc.cvut.cz:/bk/repo/ncpfs
| -rw-r--r-- | fs/ncpfs/Makefile | 8 | ||||
| -rw-r--r-- | fs/ncpfs/dir.c | 103 | ||||
| -rw-r--r-- | fs/ncpfs/file.c | 71 | ||||
| -rw-r--r-- | fs/ncpfs/inode.c | 317 | ||||
| -rw-r--r-- | fs/ncpfs/ioctl.c | 26 | ||||
| -rw-r--r-- | fs/ncpfs/ncplib_kernel.c | 264 | ||||
| -rw-r--r-- | fs/ncpfs/ncplib_kernel.h | 32 | ||||
| -rw-r--r-- | fs/ncpfs/symlink.c | 128 | ||||
| -rw-r--r-- | include/linux/ncp.h | 23 | ||||
| -rw-r--r-- | include/linux/ncp_fs.h | 5 | ||||
| -rw-r--r-- | include/linux/ncp_fs_i.h | 3 | ||||
| -rw-r--r-- | include/linux/ncp_mount.h | 1 |
12 files changed, 709 insertions, 272 deletions
diff --git a/fs/ncpfs/Makefile b/fs/ncpfs/Makefile index 26cd285c7dfd..f28ef2850982 100644 --- a/fs/ncpfs/Makefile +++ b/fs/ncpfs/Makefile @@ -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 diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index fd44657ee616..6e4f4d4c9bcf 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -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)) - return; + 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 @@ out_close: } 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 @@ out: 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 @@ out: 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. */ diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c index 81c224f1558f..2386f5ab120e 100644 --- a/fs/ncpfs/file.c +++ b/fs/ncpfs/file.c @@ -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; + } - errno = 0; + 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; + } + 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; } diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 5bccc9fb649d..bf4d9af2b92a 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -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) { + umode_t newmode = attr->ia_mode; + + info_mask |= DM_ATTRIBUTES; + if (S_ISDIR(inode->i_mode)) { - umode_t newmode; - - info_mask |= DM_ATTRIBUTES; - newmode = attr->ia_mode; - newmode &= NCP_SERVER(inode)->m.dir_mode; - - if (newmode & 0222) - info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); - else - info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); - } else if (!S_ISREG(inode->i_mode)) - { - result = -EPERM; - goto out; - } - else - { - umode_t newmode; + newmode &= server->m.dir_mode; + } else { #ifdef CONFIG_NCPFS_EXTRAS - int extras; - - 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; - - if (newmode & 0222) /* any write bit set */ - { - info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); - } - else - { - info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); - } -#ifdef CONFIG_NCPFS_EXTRAS - if (extras) { - if (newmode & 0111) /* any execute bit set */ + 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 & 0444) + 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); + +#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; + info.attributes &= ~(aSHARED | aSYSTEM); + { + /* mark partial success */ + struct iattr tmpattr; + + tmpattr.ia_valid = ATTR_MODE; + tmpattr.ia_mode = attr->ia_mode; + + inode_setattr(inode, &tmpattr); + } + } +#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); - } + if (!result) + inode_setattr(inode, attr); out: unlock_kernel(); return result; diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index d923de41ec13..8a0369da6893 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c @@ -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,25 +214,31 @@ 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; if (dentry) { 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 diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c index b72f9100c855..c32e5c653af2 100644 --- a/fs/ncpfs/ncplib_kernel.c +++ b/fs/ncpfs/ncplib_kernel.c @@ -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 @@ out: 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; - } + 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, diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h index 43c1306ac903..b25803e23272 100644 --- a/fs/ncpfs/ncplib_kernel.h +++ b/fs/ncpfs/ncplib_kernel.h @@ -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 diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c index fe3f9bef2691..f07f5669c61f 100644 --- a/fs/ncpfs/symlink.c +++ b/fs/ncpfs/symlink.c @@ -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) - goto fail; - schedule(); - } + rawlink=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_NFS); + if (!rawlink) + goto fail; 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 (length<NCP_MIN_SYMLINK_SIZE || - ((__u32 *)link)[0]!=NCP_SYMLINK_MAGIC0 || - ((__u32 *)link)[1]!=NCP_SYMLINK_MAGIC1) - goto failEIO; + if (NCP_FINFO(inode)->flags & NCPI_KLUDGE_SYMLINK) { + if (length<NCP_MIN_SYMLINK_SIZE || + ((__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; -#ifdef DEBUG - PRINTK("ncp_symlink(dir=%p,dentry=%p,symname=%s)\n",dir,dentry,symname); -#endif + DPRINTK("ncp_symlink(dir=%p,dentry=%p,symname=%s)\n",dir,dentry,symname); - if (!(NCP_SERVER(dir)->m.flags & NCP_MOUNT_SYMLINKS)) - return -EPERM; /* EPERM is returned by VFS if symlink procedure does not exist */ + 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; + + 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; + } + + 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; - if ((link=(char *)kmalloc(length+9,GFP_NFS))==NULL) - return -ENOMEM; + 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); - return err; +failfree:; + kfree(rawlink); + return err; } -#endif /* ----- EOF ----- */ diff --git a/include/linux/ncp.h b/include/linux/ncp.h index e6cdfe1b0748..fa20708267b9 100644 --- a/include/linux/ncp.h +++ b/include/linux/ncp.h @@ -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 */ diff --git a/include/linux/ncp_fs.h b/include/linux/ncp_fs.h index 74206155eb42..4a060ff0c868 100644 --- a/include/linux/ncp_fs.h +++ b/include/linux/ncp_fs.h @@ -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 :-) */ diff --git a/include/linux/ncp_fs_i.h b/include/linux/ncp_fs_i.h index 528fc633a27b..009dd388cf85 100644 --- a/include/linux/ncp_fs_i.h +++ b/include/linux/ncp_fs_i.h @@ -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; }; diff --git a/include/linux/ncp_mount.h b/include/linux/ncp_mount.h index d74092d08dac..4bdcfff1f79e 100644 --- a/include/linux/ncp_mount.h +++ b/include/linux/ncp_mount.h @@ -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; |
