Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ad4d0532 authored by Jan Kara's avatar Jan Kara
Browse files

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: default avatarJan Kara <jack@suse.cz>
parent a17f0cb5
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1547,7 +1547,7 @@ static int udf_read_inode(struct inode *inode, bool hidden_inode)
		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;
+1 −1
Original line number Diff line number Diff line
@@ -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) {
+30 −0
Original line number Diff line number Diff line
@@ -152,9 +152,39 @@ static int udf_symlink_filler(struct file *file, struct page *page)
	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,
};
+1 −0
Original line number Diff line number Diff line
@@ -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;