diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
commit | 33263fc5f9ac8e8cb2b22d06af3ce5ac1dd815e4 (patch) | |
tree | 2d1b86a40bef0958a68cf1a2eafbeb0667a70543 /fs/efs/symlink.c | |
parent | 216f5f51aa02f8b113aa620ebc14a9631a217a00 (diff) |
Merge with Linux 2.3.32.
Diffstat (limited to 'fs/efs/symlink.c')
-rw-r--r-- | fs/efs/symlink.c | 118 |
1 files changed, 34 insertions, 84 deletions
diff --git a/fs/efs/symlink.c b/fs/efs/symlink.c index 69ddda45b..6bfc16be7 100644 --- a/fs/efs/symlink.c +++ b/fs/efs/symlink.c @@ -7,99 +7,49 @@ */ #include <linux/string.h> -#include <linux/malloc.h> #include <linux/efs_fs.h> +#include <linux/pagemap.h> -static int efs_readlink(struct dentry *, char *, int); -static struct dentry * efs_follow_link(struct dentry *, struct dentry *, unsigned int); - -struct inode_operations efs_symlink_inode_operations = { - NULL, /* no symlink file-operations */ - NULL, /* create */ - NULL, /* lookup */ - NULL, /* link */ - NULL, /* unlink */ - NULL, /* symlink */ - NULL, /* mkdir */ - NULL, /* rmdir */ - NULL, /* mknod */ - NULL, /* rename */ - efs_readlink, /* readlink */ - efs_follow_link, /* follow_link */ - NULL, /* get_block */ - NULL, /* readpage */ - NULL, /* writepage */ - NULL, /* flushpage */ - NULL, /* truncate */ - NULL, /* permission */ - NULL, /* smap */ - NULL /* revalidate */ -}; - -static char *efs_linktarget(struct inode *in, int *len) { - char *name; +static int efs_symlink_readpage(struct dentry *dentry, struct page *page) +{ + char *link = (char*)kmap(page); struct buffer_head * bh; - efs_block_t size = in->i_size; - - if (size > 2 * EFS_BLOCKSIZE) { - printk(KERN_ERR "EFS: linktarget(): name too long: %lu\n", in->i_size); - return NULL; - } + struct inode * inode = dentry->d_inode; + efs_block_t size = inode->i_size; + int err; - if (!(name = kmalloc(size + 1, GFP_KERNEL))) - return NULL; + err = -ENAMETOOLONG; + if (size > 2 * EFS_BLOCKSIZE) + goto fail; /* read first 512 bytes of link target */ - bh = bread(in->i_dev, efs_bmap(in, 0), EFS_BLOCKSIZE); - if (!bh) { - kfree(name); - printk(KERN_ERR "EFS: linktarget(): couldn't read block %d\n", efs_bmap(in, 0)); - return NULL; - } - - memcpy(name, bh->b_data, (size > EFS_BLOCKSIZE) ? EFS_BLOCKSIZE : size); + err = -EIO; + bh = bread(inode->i_dev, efs_bmap(inode, 0), EFS_BLOCKSIZE); + if (!bh) + goto fail; + memcpy(link, bh->b_data, (size > EFS_BLOCKSIZE) ? EFS_BLOCKSIZE : size); brelse(bh); - if (size > EFS_BLOCKSIZE) { - bh = bread(in->i_dev, efs_bmap(in, 1), EFS_BLOCKSIZE); - if (!bh) { - kfree(name); - printk(KERN_ERR "EFS: linktarget(): couldn't read block %d\n", efs_bmap(in, 1)); - return NULL; - } - memcpy(name + EFS_BLOCKSIZE, bh->b_data, size - EFS_BLOCKSIZE); + bh = bread(inode->i_dev, efs_bmap(inode, 1), EFS_BLOCKSIZE); + if (!bh) + goto fail; + memcpy(link + EFS_BLOCKSIZE, bh->b_data, size - EFS_BLOCKSIZE); brelse(bh); } - - name[size] = (char) 0; - if (len) *len = size; - - return name; -} - -static struct dentry *efs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow) { - char *name; - struct inode *inode = dentry->d_inode; - - if (!(name = efs_linktarget(inode, NULL))) { - dput(base); - return ERR_PTR(-ELOOP); - } - base = lookup_dentry(name, base, follow); - kfree(name); - - return base; -} - -static int efs_readlink(struct dentry * dir, char * buf, int bufsiz) { - int rc; - char *name; - struct inode *inode = dir->d_inode; - - if (!(name = efs_linktarget(inode, &bufsiz))) return 0; - rc = copy_to_user(buf, name, bufsiz) ? -EFAULT : bufsiz; - kfree(name); - - return rc; + link[size] = '\0'; + SetPageUptodate(page); + kunmap(page); + UnlockPage(page); + return 0; +fail: + SetPageError(page); + kunmap(page); + UnlockPage(page); + return err; } +struct inode_operations efs_symlink_inode_operations = { + readlink: page_readlink, + follow_link: page_follow_link, + readpage: efs_symlink_readpage +}; |