diff options
Diffstat (limited to 'fs/f2fs/dir.c')
-rw-r--r-- | fs/f2fs/dir.c | 125 |
1 files changed, 115 insertions, 10 deletions
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 85a1528f319f..dac07d17cdbd 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/fs.h> | 8 | #include <linux/fs.h> |
9 | #include <linux/f2fs_fs.h> | 9 | #include <linux/f2fs_fs.h> |
10 | #include <linux/sched/signal.h> | 10 | #include <linux/sched/signal.h> |
11 | #include <linux/unicode.h> | ||
11 | #include "f2fs.h" | 12 | #include "f2fs.h" |
12 | #include "node.h" | 13 | #include "node.h" |
13 | #include "acl.h" | 14 | #include "acl.h" |
@@ -81,7 +82,8 @@ static unsigned long dir_block_index(unsigned int level, | |||
81 | return bidx; | 82 | return bidx; |
82 | } | 83 | } |
83 | 84 | ||
84 | static struct f2fs_dir_entry *find_in_block(struct page *dentry_page, | 85 | static struct f2fs_dir_entry *find_in_block(struct inode *dir, |
86 | struct page *dentry_page, | ||
85 | struct fscrypt_name *fname, | 87 | struct fscrypt_name *fname, |
86 | f2fs_hash_t namehash, | 88 | f2fs_hash_t namehash, |
87 | int *max_slots, | 89 | int *max_slots, |
@@ -93,7 +95,7 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page, | |||
93 | 95 | ||
94 | dentry_blk = (struct f2fs_dentry_block *)page_address(dentry_page); | 96 | dentry_blk = (struct f2fs_dentry_block *)page_address(dentry_page); |
95 | 97 | ||
96 | make_dentry_ptr_block(NULL, &d, dentry_blk); | 98 | make_dentry_ptr_block(dir, &d, dentry_blk); |
97 | de = f2fs_find_target_dentry(fname, namehash, max_slots, &d); | 99 | de = f2fs_find_target_dentry(fname, namehash, max_slots, &d); |
98 | if (de) | 100 | if (de) |
99 | *res_page = dentry_page; | 101 | *res_page = dentry_page; |
@@ -101,6 +103,39 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page, | |||
101 | return de; | 103 | return de; |
102 | } | 104 | } |
103 | 105 | ||
106 | #ifdef CONFIG_UNICODE | ||
107 | /* | ||
108 | * Test whether a case-insensitive directory entry matches the filename | ||
109 | * being searched for. | ||
110 | * | ||
111 | * Returns: 0 if the directory entry matches, more than 0 if it | ||
112 | * doesn't match or less than zero on error. | ||
113 | */ | ||
114 | int f2fs_ci_compare(const struct inode *parent, const struct qstr *name, | ||
115 | const struct qstr *entry) | ||
116 | { | ||
117 | const struct f2fs_sb_info *sbi = F2FS_SB(parent->i_sb); | ||
118 | const struct unicode_map *um = sbi->s_encoding; | ||
119 | int ret; | ||
120 | |||
121 | ret = utf8_strncasecmp(um, name, entry); | ||
122 | if (ret < 0) { | ||
123 | /* Handle invalid character sequence as either an error | ||
124 | * or as an opaque byte sequence. | ||
125 | */ | ||
126 | if (f2fs_has_strict_mode(sbi)) | ||
127 | return -EINVAL; | ||
128 | |||
129 | if (name->len != entry->len) | ||
130 | return 1; | ||
131 | |||
132 | return !!memcmp(name->name, entry->name, name->len); | ||
133 | } | ||
134 | |||
135 | return ret; | ||
136 | } | ||
137 | #endif | ||
138 | |||
104 | struct f2fs_dir_entry *f2fs_find_target_dentry(struct fscrypt_name *fname, | 139 | struct f2fs_dir_entry *f2fs_find_target_dentry(struct fscrypt_name *fname, |
105 | f2fs_hash_t namehash, int *max_slots, | 140 | f2fs_hash_t namehash, int *max_slots, |
106 | struct f2fs_dentry_ptr *d) | 141 | struct f2fs_dentry_ptr *d) |
@@ -108,6 +143,9 @@ struct f2fs_dir_entry *f2fs_find_target_dentry(struct fscrypt_name *fname, | |||
108 | struct f2fs_dir_entry *de; | 143 | struct f2fs_dir_entry *de; |
109 | unsigned long bit_pos = 0; | 144 | unsigned long bit_pos = 0; |
110 | int max_len = 0; | 145 | int max_len = 0; |
146 | #ifdef CONFIG_UNICODE | ||
147 | struct qstr entry; | ||
148 | #endif | ||
111 | 149 | ||
112 | if (max_slots) | 150 | if (max_slots) |
113 | *max_slots = 0; | 151 | *max_slots = 0; |
@@ -119,16 +157,28 @@ struct f2fs_dir_entry *f2fs_find_target_dentry(struct fscrypt_name *fname, | |||
119 | } | 157 | } |
120 | 158 | ||
121 | de = &d->dentry[bit_pos]; | 159 | de = &d->dentry[bit_pos]; |
160 | #ifdef CONFIG_UNICODE | ||
161 | entry.name = d->filename[bit_pos]; | ||
162 | entry.len = de->name_len; | ||
163 | #endif | ||
122 | 164 | ||
123 | if (unlikely(!de->name_len)) { | 165 | if (unlikely(!de->name_len)) { |
124 | bit_pos++; | 166 | bit_pos++; |
125 | continue; | 167 | continue; |
126 | } | 168 | } |
169 | if (de->hash_code == namehash) { | ||
170 | #ifdef CONFIG_UNICODE | ||
171 | if (F2FS_SB(d->inode->i_sb)->s_encoding && | ||
172 | IS_CASEFOLDED(d->inode) && | ||
173 | !f2fs_ci_compare(d->inode, | ||
174 | fname->usr_fname, &entry)) | ||
175 | goto found; | ||
127 | 176 | ||
128 | if (de->hash_code == namehash && | 177 | #endif |
129 | fscrypt_match_name(fname, d->filename[bit_pos], | 178 | if (fscrypt_match_name(fname, d->filename[bit_pos], |
130 | le16_to_cpu(de->name_len))) | 179 | le16_to_cpu(de->name_len))) |
131 | goto found; | 180 | goto found; |
181 | } | ||
132 | 182 | ||
133 | if (max_slots && max_len > *max_slots) | 183 | if (max_slots && max_len > *max_slots) |
134 | *max_slots = max_len; | 184 | *max_slots = max_len; |
@@ -157,7 +207,7 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir, | |||
157 | struct f2fs_dir_entry *de = NULL; | 207 | struct f2fs_dir_entry *de = NULL; |
158 | bool room = false; | 208 | bool room = false; |
159 | int max_slots; | 209 | int max_slots; |
160 | f2fs_hash_t namehash = f2fs_dentry_hash(&name, fname); | 210 | f2fs_hash_t namehash = f2fs_dentry_hash(dir, &name, fname); |
161 | 211 | ||
162 | nbucket = dir_buckets(level, F2FS_I(dir)->i_dir_level); | 212 | nbucket = dir_buckets(level, F2FS_I(dir)->i_dir_level); |
163 | nblock = bucket_blocks(level); | 213 | nblock = bucket_blocks(level); |
@@ -179,8 +229,8 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir, | |||
179 | } | 229 | } |
180 | } | 230 | } |
181 | 231 | ||
182 | de = find_in_block(dentry_page, fname, namehash, &max_slots, | 232 | de = find_in_block(dir, dentry_page, fname, namehash, |
183 | res_page); | 233 | &max_slots, res_page); |
184 | if (de) | 234 | if (de) |
185 | break; | 235 | break; |
186 | 236 | ||
@@ -250,6 +300,14 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir, | |||
250 | struct fscrypt_name fname; | 300 | struct fscrypt_name fname; |
251 | int err; | 301 | int err; |
252 | 302 | ||
303 | #ifdef CONFIG_UNICODE | ||
304 | if (f2fs_has_strict_mode(F2FS_I_SB(dir)) && IS_CASEFOLDED(dir) && | ||
305 | utf8_validate(F2FS_I_SB(dir)->s_encoding, child)) { | ||
306 | *res_page = ERR_PTR(-EINVAL); | ||
307 | return NULL; | ||
308 | } | ||
309 | #endif | ||
310 | |||
253 | err = fscrypt_setup_filename(dir, child, 1, &fname); | 311 | err = fscrypt_setup_filename(dir, child, 1, &fname); |
254 | if (err) { | 312 | if (err) { |
255 | if (err == -ENOENT) | 313 | if (err == -ENOENT) |
@@ -504,7 +562,7 @@ int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name, | |||
504 | 562 | ||
505 | level = 0; | 563 | level = 0; |
506 | slots = GET_DENTRY_SLOTS(new_name->len); | 564 | slots = GET_DENTRY_SLOTS(new_name->len); |
507 | dentry_hash = f2fs_dentry_hash(new_name, NULL); | 565 | dentry_hash = f2fs_dentry_hash(dir, new_name, NULL); |
508 | 566 | ||
509 | current_depth = F2FS_I(dir)->i_current_depth; | 567 | current_depth = F2FS_I(dir)->i_current_depth; |
510 | if (F2FS_I(dir)->chash == dentry_hash) { | 568 | if (F2FS_I(dir)->chash == dentry_hash) { |
@@ -943,3 +1001,50 @@ const struct file_operations f2fs_dir_operations = { | |||
943 | .compat_ioctl = f2fs_compat_ioctl, | 1001 | .compat_ioctl = f2fs_compat_ioctl, |
944 | #endif | 1002 | #endif |
945 | }; | 1003 | }; |
1004 | |||
1005 | #ifdef CONFIG_UNICODE | ||
1006 | static int f2fs_d_compare(const struct dentry *dentry, unsigned int len, | ||
1007 | const char *str, const struct qstr *name) | ||
1008 | { | ||
1009 | struct qstr qstr = {.name = str, .len = len }; | ||
1010 | |||
1011 | if (!IS_CASEFOLDED(dentry->d_parent->d_inode)) { | ||
1012 | if (len != name->len) | ||
1013 | return -1; | ||
1014 | return memcmp(str, name, len); | ||
1015 | } | ||
1016 | |||
1017 | return f2fs_ci_compare(dentry->d_parent->d_inode, name, &qstr); | ||
1018 | } | ||
1019 | |||
1020 | static int f2fs_d_hash(const struct dentry *dentry, struct qstr *str) | ||
1021 | { | ||
1022 | struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb); | ||
1023 | const struct unicode_map *um = sbi->s_encoding; | ||
1024 | unsigned char *norm; | ||
1025 | int len, ret = 0; | ||
1026 | |||
1027 | if (!IS_CASEFOLDED(dentry->d_inode)) | ||
1028 | return 0; | ||
1029 | |||
1030 | norm = f2fs_kmalloc(sbi, PATH_MAX, GFP_ATOMIC); | ||
1031 | if (!norm) | ||
1032 | return -ENOMEM; | ||
1033 | |||
1034 | len = utf8_casefold(um, str, norm, PATH_MAX); | ||
1035 | if (len < 0) { | ||
1036 | if (f2fs_has_strict_mode(sbi)) | ||
1037 | ret = -EINVAL; | ||
1038 | goto out; | ||
1039 | } | ||
1040 | str->hash = full_name_hash(dentry, norm, len); | ||
1041 | out: | ||
1042 | kvfree(norm); | ||
1043 | return ret; | ||
1044 | } | ||
1045 | |||
1046 | const struct dentry_operations f2fs_dentry_ops = { | ||
1047 | .d_hash = f2fs_d_hash, | ||
1048 | .d_compare = f2fs_d_compare, | ||
1049 | }; | ||
1050 | #endif | ||