summaryrefslogtreecommitdiffstats
path: root/fs/ext2/symlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext2/symlink.c')
-rw-r--r--fs/ext2/symlink.c37
1 files changed, 28 insertions, 9 deletions
diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c
index 4d5a5cada..781f9165d 100644
--- a/fs/ext2/symlink.c
+++ b/fs/ext2/symlink.c
@@ -25,6 +25,7 @@
#include <linux/stat.h>
static int ext2_readlink (struct inode *, char *, int);
+static struct dentry *ext2_follow_link(struct inode *, struct dentry *);
/*
* symlinks can't do much...
@@ -41,6 +42,7 @@ struct inode_operations ext2_symlink_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
ext2_readlink, /* readlink */
+ ext2_follow_link, /* follow_link */
NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
@@ -49,37 +51,54 @@ struct inode_operations ext2_symlink_inode_operations = {
NULL /* smap */
};
+static struct dentry * ext2_follow_link(struct inode * inode, struct dentry *base)
+{
+ int error;
+ struct buffer_head * bh = NULL;
+ char * link;
+
+ link = (char *) inode->u.ext2_i.i_data;
+ if (inode->i_blocks) {
+ if (!(bh = ext2_bread (inode, 0, 0, &error))) {
+ dput(base);
+ return ERR_PTR(-EIO);
+ }
+ link = bh->b_data;
+ }
+ UPDATE_ATIME(inode);
+ base = lookup_dentry(link, base, 1);
+ if (bh)
+ brelse(bh);
+ return base;
+}
+
static int ext2_readlink (struct inode * inode, char * buffer, int buflen)
{
struct buffer_head * bh = NULL;
char * link;
- int i, err;
+ int i;
if (buflen > inode->i_sb->s_blocksize - 1)
buflen = inode->i_sb->s_blocksize - 1;
+
+ link = (char *) inode->u.ext2_i.i_data;
if (inode->i_blocks) {
+ int err;
bh = ext2_bread (inode, 0, 0, &err);
if (!bh) {
- iput (inode);
if(err < 0) /* indicate type of error */
return err;
return 0;
}
link = bh->b_data;
}
- else
- link = (char *) inode->u.ext2_i.i_data;
i = 0;
while (i < buflen && link[i])
i++;
if (copy_to_user(buffer, link, i))
i = -EFAULT;
- if (DO_UPDATE_ATIME(inode)) {
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
- }
- iput (inode);
+ UPDATE_ATIME(inode);
if (bh)
brelse (bh);
return i;