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>
This commit is contained in:
parent
a17f0cb5b9
commit
ad4d05329d
@ -1547,7 +1547,7 @@ reread:
|
||||
break;
|
||||
case ICBTAG_FILE_TYPE_SYMLINK:
|
||||
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->i_mode = S_IFLNK | S_IRWXUGO;
|
||||
break;
|
||||
|
@ -931,7 +931,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -84,6 +84,7 @@ extern const struct inode_operations udf_dir_inode_operations;
|
||||
extern const struct file_operations udf_dir_operations;
|
||||
extern const struct inode_operations udf_file_inode_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_adinicb_aops;
|
||||
extern const struct address_space_operations udf_symlink_aops;
|
||||
|
Loading…
Reference in New Issue
Block a user