summaryrefslogtreecommitdiff
path: root/fs/udf/symlink.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2017-01-02 14:30:31 +0100
committerJan Kara <jack@suse.cz>2017-01-05 07:52:57 +0100
commitad4d05329df5e9825cac3132e12453a6c12915b8 (patch)
tree56e6acd3b189c2fa6654ee13d1418616de19c7e8 /fs/udf/symlink.c
parenta17f0cb5b9eaf8212b396d2381cf7594cd5315c7 (diff)
udf: Make stat on symlink report symlink length as st_size
UDF encodes symlinks in a more complex fashion and thus i_size of a symlink does not match the lenght of a string returned by readlink(2). This confuses some applications (see bug 191241) and may be considered a violation of POSIX. Fix the problem by reading the link into page cache in response to stat(2) call and report the length of the decoded path. Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/udf/symlink.c')
-rw-r--r--fs/udf/symlink.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c
index 8d619773056b..f7dfef53f739 100644
--- a/fs/udf/symlink.c
+++ b/fs/udf/symlink.c
@@ -152,9 +152,39 @@ out_unmap:
return err;
}
+static int udf_symlink_getattr(struct vfsmount *mnt, struct dentry *dentry,
+ struct kstat *stat)
+{
+ struct inode *inode = d_backing_inode(dentry);
+ struct page *page;
+
+ generic_fillattr(inode, stat);
+ page = read_mapping_page(inode->i_mapping, 0, NULL);
+ if (IS_ERR(page))
+ return PTR_ERR(page);
+ /*
+ * UDF uses non-trivial encoding of symlinks so i_size does not match
+ * number of characters reported by readlink(2) which apparently some
+ * applications expect. Also POSIX says that "The value returned in the
+ * st_size field shall be the length of the contents of the symbolic
+ * link, and shall not count a trailing null if one is present." So
+ * let's report the length of string returned by readlink(2) for
+ * st_size.
+ */
+ stat->size = strlen(page_address(page));
+ put_page(page);
+
+ return 0;
+}
+
/*
* symlinks can't do much...
*/
const struct address_space_operations udf_symlink_aops = {
.readpage = udf_symlink_filler,
};
+
+const struct inode_operations udf_symlink_inode_operations = {
+ .get_link = page_get_link,
+ .getattr = udf_symlink_getattr,
+};