diff options
author | Jan Kara <jack@suse.cz> | 2017-01-02 14:30:31 +0100 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2017-01-05 07:52:57 +0100 |
commit | ad4d05329df5e9825cac3132e12453a6c12915b8 (patch) | |
tree | 56e6acd3b189c2fa6654ee13d1418616de19c7e8 /fs/udf/symlink.c | |
parent | a17f0cb5b9eaf8212b396d2381cf7594cd5315c7 (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.c | 30 |
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, +}; |