提交 ad4d0532 编写于 作者: J Jan Kara

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: NJan Kara <jack@suse.cz>
上级 a17f0cb5
...@@ -1547,7 +1547,7 @@ static int udf_read_inode(struct inode *inode, bool hidden_inode) ...@@ -1547,7 +1547,7 @@ static int udf_read_inode(struct inode *inode, bool hidden_inode)
break; break;
case ICBTAG_FILE_TYPE_SYMLINK: case ICBTAG_FILE_TYPE_SYMLINK:
inode->i_data.a_ops = &udf_symlink_aops; inode->i_data.a_ops = &udf_symlink_aops;
inode->i_op = &page_symlink_inode_operations; inode->i_op = &udf_symlink_inode_operations;
inode_nohighmem(inode); inode_nohighmem(inode);
inode->i_mode = S_IFLNK | S_IRWXUGO; inode->i_mode = S_IFLNK | S_IRWXUGO;
break; break;
......
...@@ -931,7 +931,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, ...@@ -931,7 +931,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
} }
inode->i_data.a_ops = &udf_symlink_aops; inode->i_data.a_ops = &udf_symlink_aops;
inode->i_op = &page_symlink_inode_operations; inode->i_op = &udf_symlink_inode_operations;
inode_nohighmem(inode); inode_nohighmem(inode);
if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
......
...@@ -152,9 +152,39 @@ static int udf_symlink_filler(struct file *file, struct page *page) ...@@ -152,9 +152,39 @@ static int udf_symlink_filler(struct file *file, struct page *page)
return err; 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... * symlinks can't do much...
*/ */
const struct address_space_operations udf_symlink_aops = { const struct address_space_operations udf_symlink_aops = {
.readpage = udf_symlink_filler, .readpage = udf_symlink_filler,
}; };
const struct inode_operations udf_symlink_inode_operations = {
.get_link = page_get_link,
.getattr = udf_symlink_getattr,
};
...@@ -84,6 +84,7 @@ extern const struct inode_operations udf_dir_inode_operations; ...@@ -84,6 +84,7 @@ extern const struct inode_operations udf_dir_inode_operations;
extern const struct file_operations udf_dir_operations; extern const struct file_operations udf_dir_operations;
extern const struct inode_operations udf_file_inode_operations; extern const struct inode_operations udf_file_inode_operations;
extern const struct file_operations udf_file_operations; extern const struct file_operations udf_file_operations;
extern const struct inode_operations udf_symlink_inode_operations;
extern const struct address_space_operations udf_aops; extern const struct address_space_operations udf_aops;
extern const struct address_space_operations udf_adinicb_aops; extern const struct address_space_operations udf_adinicb_aops;
extern const struct address_space_operations udf_symlink_aops; extern const struct address_space_operations udf_symlink_aops;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册