summaryrefslogtreecommitdiffstats
path: root/fs/efs/symlink.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-04 07:40:19 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-04 07:40:19 +0000
commit33263fc5f9ac8e8cb2b22d06af3ce5ac1dd815e4 (patch)
tree2d1b86a40bef0958a68cf1a2eafbeb0667a70543 /fs/efs/symlink.c
parent216f5f51aa02f8b113aa620ebc14a9631a217a00 (diff)
Merge with Linux 2.3.32.
Diffstat (limited to 'fs/efs/symlink.c')
-rw-r--r--fs/efs/symlink.c118
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
+};