summaryrefslogtreecommitdiffstats
path: root/fs/ncpfs/symlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ncpfs/symlink.c')
-rw-r--r--fs/ncpfs/symlink.c159
1 files changed, 50 insertions, 109 deletions
diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c
index 81151959a..5e5bf2fbd 100644
--- a/fs/ncpfs/symlink.c
+++ b/fs/ncpfs/symlink.c
@@ -38,139 +38,76 @@
#define NCP_SYMLINK_MAGIC0 le32_to_cpu(0x6c6d7973) /* "symlnk->" */
#define NCP_SYMLINK_MAGIC1 le32_to_cpu(0x3e2d6b6e)
-static int ncp_readlink(struct dentry *, char *, int);
-static struct dentry *ncp_follow_link(struct dentry *, struct dentry *, unsigned int);
int ncp_create_new(struct inode *dir, struct dentry *dentry,
int mode,int attributes);
-/*
- * symlinks can't do much...
- */
-struct inode_operations ncp_symlink_inode_operations={
- NULL, /* no file-operations */
- NULL, /* create */
- NULL, /* lookup */
- NULL, /* link */
- NULL, /* unlink */
- NULL, /* symlink */
- NULL, /* mkdir */
- NULL, /* rmdir */
- NULL, /* mknod */
- NULL, /* rename */
- ncp_readlink, /* readlink */
- ncp_follow_link, /* follow_link */
- NULL, /* get_block */
- NULL, /* readpage */
- NULL, /* writepage */
- NULL, /* flushpage */
- NULL, /* truncate */
- NULL, /* permission */
- NULL, /* smap */
- NULL /* revalidate */
-};
-
-/* ----- follow a symbolic link ------------------------------------------ */
+/* ----- read a symbolic link ------------------------------------------ */
-static struct dentry *ncp_follow_link(struct dentry *dentry,
- struct dentry *base,
- unsigned int follow)
+static int ncp_symlink_readpage(struct dentry *dentry, struct page *page)
{
struct inode *inode=dentry->d_inode;
- int error, length, cnt;
+ int error, length, len, cnt;
char *link;
+ char *buf = (char*)kmap(page);
-#ifdef DEBUG
- PRINTK("ncp_follow_link(dentry=%p,base=%p,follow=%u)\n",dentry,base,follow);
-#endif
-
- if(!S_ISLNK(inode->i_mode)) {
- dput(base);
- return ERR_PTR(-EINVAL);
- }
+ error = -EIO;
+ if (ncp_make_open(inode,O_RDONLY))
+ goto fail;
- if(ncp_make_open(inode,O_RDONLY)) {
- dput(base);
- return ERR_PTR(-EIO);
- }
-
- for (cnt = 0; (link=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE+1, GFP_NFS))==NULL; cnt++) {
- if (cnt > 10) {
- dput(base);
- return ERR_PTR(-EAGAIN); /* -ENOMEM? */
- }
+ error = -ENOMEM;
+ for (cnt = 0; (link=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_NFS))==NULL; cnt++) {
+ if (cnt > 10)
+ goto fail;
schedule();
}
error=ncp_read_kernel(NCP_SERVER(inode),NCP_FINFO(inode)->file_handle,
0,NCP_MAX_SYMLINK_SIZE,link,&length);
- if (error!=0 || length<NCP_MIN_SYMLINK_SIZE ||
- ((__u32 *)link)[0]!=NCP_SYMLINK_MAGIC0 || ((__u32 *)link)[1]!=NCP_SYMLINK_MAGIC1) {
- dput(base);
+ if (error) {
kfree(link);
- return ERR_PTR(-EIO);
+ goto fail;
}
-
- link[length]=0;
-
- vol2io(NCP_SERVER(inode), link+8, 0);
-
- /* UPDATE_ATIME(inode); */
- base=lookup_dentry(link+8, base, follow);
- kfree(link);
-
- return base;
-}
-
-/* ----- read symbolic link ---------------------------------------------- */
-
-static int ncp_readlink(struct dentry * dentry, char * buffer, int buflen)
-{
- struct inode *inode=dentry->d_inode;
- char *link;
- int length,error;
-
-#ifdef DEBUG
- PRINTK("ncp_readlink(dentry=%p,buffer=%p,buflen=%d)\n",dentry,buffer,buflen);
-#endif
-
- if(!S_ISLNK(inode->i_mode))
- return -EINVAL;
-
- if(ncp_make_open(inode,O_RDONLY))
- return -EIO;
-
- if((link=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE+1,GFP_NFS))==NULL)
- return -ENOMEM;
-
- error = ncp_read_kernel(NCP_SERVER(inode),NCP_FINFO(inode)->file_handle,
- 0,NCP_MAX_SYMLINK_SIZE,link,&length);
-
- if (error!=0 || length < NCP_MIN_SYMLINK_SIZE || buflen < (length-8) ||
- ((__u32 *)link)[0]!=NCP_SYMLINK_MAGIC0 ||((__u32 *)link)[1]!=NCP_SYMLINK_MAGIC1) {
- error = -EIO;
- goto out;
+ if (length<NCP_MIN_SYMLINK_SIZE ||
+ ((__u32 *)link)[0]!=NCP_SYMLINK_MAGIC0 ||
+ ((__u32 *)link)[1]!=NCP_SYMLINK_MAGIC1) {
+ error = -EIO;
+ kfree(link);
+ goto fail;
}
- link[length] = 0;
-
- vol2io(NCP_SERVER(inode), link+8, 0);
-
- error = length - 8;
- if(copy_to_user(buffer, link+8, error))
- error = -EFAULT;
-
-out:;
+ len = NCP_MAX_SYMLINK_SIZE;
+ error = ncp_vol2io(NCP_SERVER(inode), buf, &len, link+8, length-8, 0);
kfree(link);
+ if (error)
+ goto fail;
+ SetPageUptodate(page);
+ kunmap(page);
+ UnlockPage(page);
+ return 0;
+
+fail:
+ SetPageError(page);
+ kunmap(page);
+ UnlockPage(page);
return error;
}
+/*
+ * symlinks can't do much...
+ */
+struct inode_operations ncp_symlink_inode_operations={
+ readlink: page_readlink,
+ follow_link: page_follow_link,
+ readpage: ncp_symlink_readpage,
+};
+
/* ----- create a new symbolic link -------------------------------------- */
int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) {
- int i,length;
struct inode *inode;
char *link;
+ int length, err, i;
#ifdef DEBUG
PRINTK("ncp_symlink(dir=%p,dentry=%p,symname=%s)\n",dir,dentry,symname);
@@ -179,7 +116,7 @@ int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) {
if (!(NCP_SERVER(dir)->m.flags & NCP_MOUNT_SYMLINKS))
return -EPERM; /* EPERM is returned by VFS if symlink procedure does not exist */
- if ((length=strlen(symname))>NCP_MAX_SYMLINK_SIZE)
+ if ((length=strlen(symname))>NCP_MAX_SYMLINK_SIZE-8)
return -EINVAL;
if ((link=(char *)kmalloc(length+9,GFP_NFS))==NULL)
@@ -194,12 +131,16 @@ int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) {
((__u32 *)link)[0]=NCP_SYMLINK_MAGIC0;
((__u32 *)link)[1]=NCP_SYMLINK_MAGIC1;
- memcpy(link+8, symname, length+1); /* including last zero for io2vol */
/* map to/from server charset, do not touch upper/lower case as
symlink can point out of ncp filesystem */
- io2vol(NCP_SERVER(inode), link+8, 0);
-
+ length += 1;
+ err = ncp_io2vol(NCP_SERVER(inode),link+8,&length,symname,length-1,0);
+ if (err) {
+ kfree(link);
+ return err;
+ }
+
if(ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
0, length+8, link, &i) || i!=length+8) {
kfree(link);