aboutsummaryrefslogtreecommitdiffstats
path: root/fs/udf
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2017-01-02 08:30:31 -0500
committerJan Kara <jack@suse.cz>2017-01-05 01:52:57 -0500
commitad4d05329df5e9825cac3132e12453a6c12915b8 (patch)
tree56e6acd3b189c2fa6654ee13d1418616de19c7e8 /fs/udf
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')
-rw-r--r--fs/udf/inode.c2
-rw-r--r--fs/udf/namei.c2
-rw-r--r--fs/udf/symlink.c30
-rw-r--r--fs/udf/udfdecl.h1
4 files changed, 33 insertions, 2 deletions
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 3a5ac2221a88..5f643c93f564 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -1547,7 +1547,7 @@ reread:
1547 break; 1547 break;
1548 case ICBTAG_FILE_TYPE_SYMLINK: 1548 case ICBTAG_FILE_TYPE_SYMLINK:
1549 inode->i_data.a_ops = &udf_symlink_aops; 1549 inode->i_data.a_ops = &udf_symlink_aops;
1550 inode->i_op = &page_symlink_inode_operations; 1550 inode->i_op = &udf_symlink_inode_operations;
1551 inode_nohighmem(inode); 1551 inode_nohighmem(inode);
1552 inode->i_mode = S_IFLNK | S_IRWXUGO; 1552 inode->i_mode = S_IFLNK | S_IRWXUGO;
1553 break; 1553 break;
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index 2d65e280748b..babf48d0e553 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -931,7 +931,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
931 } 931 }
932 932
933 inode->i_data.a_ops = &udf_symlink_aops; 933 inode->i_data.a_ops = &udf_symlink_aops;
934 inode->i_op = &page_symlink_inode_operations; 934 inode->i_op = &udf_symlink_inode_operations;
935 inode_nohighmem(inode); 935 inode_nohighmem(inode);
936 936
937 if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { 937 if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
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:
152 return err; 152 return err;
153} 153}
154 154
155static int udf_symlink_getattr(struct vfsmount *mnt, struct dentry *dentry,
156 struct kstat *stat)
157{
158 struct inode *inode = d_backing_inode(dentry);
159 struct page *page;
160
161 generic_fillattr(inode, stat);
162 page = read_mapping_page(inode->i_mapping, 0, NULL);
163 if (IS_ERR(page))
164 return PTR_ERR(page);
165 /*
166 * UDF uses non-trivial encoding of symlinks so i_size does not match
167 * number of characters reported by readlink(2) which apparently some
168 * applications expect. Also POSIX says that "The value returned in the
169 * st_size field shall be the length of the contents of the symbolic
170 * link, and shall not count a trailing null if one is present." So
171 * let's report the length of string returned by readlink(2) for
172 * st_size.
173 */
174 stat->size = strlen(page_address(page));
175 put_page(page);
176
177 return 0;
178}
179
155/* 180/*
156 * symlinks can't do much... 181 * symlinks can't do much...
157 */ 182 */
158const struct address_space_operations udf_symlink_aops = { 183const struct address_space_operations udf_symlink_aops = {
159 .readpage = udf_symlink_filler, 184 .readpage = udf_symlink_filler,
160}; 185};
186
187const struct inode_operations udf_symlink_inode_operations = {
188 .get_link = page_get_link,
189 .getattr = udf_symlink_getattr,
190};
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index b608624e7089..63b034984378 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -84,6 +84,7 @@ extern const struct inode_operations udf_dir_inode_operations;
84extern const struct file_operations udf_dir_operations; 84extern const struct file_operations udf_dir_operations;
85extern const struct inode_operations udf_file_inode_operations; 85extern const struct inode_operations udf_file_inode_operations;
86extern const struct file_operations udf_file_operations; 86extern const struct file_operations udf_file_operations;
87extern const struct inode_operations udf_symlink_inode_operations;
87extern const struct address_space_operations udf_aops; 88extern const struct address_space_operations udf_aops;
88extern const struct address_space_operations udf_adinicb_aops; 89extern const struct address_space_operations udf_adinicb_aops;
89extern const struct address_space_operations udf_symlink_aops; 90extern const struct address_space_operations udf_symlink_aops;