diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/f2fs/dir.c | 57 | ||||
-rw-r--r-- | fs/f2fs/f2fs.h | 3 |
2 files changed, 53 insertions, 7 deletions
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 501999af581d..7afbf8f5ab08 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -112,13 +112,17 @@ static struct f2fs_dir_entry *find_in_block(struct inode *dir, * doesn't match or less than zero on error. */ int f2fs_ci_compare(const struct inode *parent, const struct qstr *name, - const struct qstr *entry) + const struct qstr *entry, bool quick) { const struct f2fs_sb_info *sbi = F2FS_SB(parent->i_sb); const struct unicode_map *um = sbi->s_encoding; int ret; - ret = utf8_strncasecmp(um, name, entry); + if (quick) + ret = utf8_strncasecmp_folded(um, name, entry); + else + ret = utf8_strncasecmp(um, name, entry); + if (ret < 0) { /* Handle invalid character sequence as either an error * or as an opaque byte sequence. @@ -134,11 +138,36 @@ int f2fs_ci_compare(const struct inode *parent, const struct qstr *name, return ret; } + +static void f2fs_fname_setup_ci_filename(struct inode *dir, + const struct qstr *iname, + struct fscrypt_str *cf_name) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); + + if (!IS_CASEFOLDED(dir)) { + cf_name->name = NULL; + return; + } + + cf_name->name = f2fs_kmalloc(sbi, F2FS_NAME_LEN, GFP_NOFS); + if (!cf_name->name) + return; + + cf_name->len = utf8_casefold(sbi->s_encoding, + iname, cf_name->name, + F2FS_NAME_LEN); + if ((int)cf_name->len <= 0) { + kvfree(cf_name->name); + cf_name->name = NULL; + } +} #endif static inline bool f2fs_match_name(struct f2fs_dentry_ptr *d, struct f2fs_dir_entry *de, struct fscrypt_name *fname, + struct fscrypt_str *cf_str, unsigned long bit_pos, f2fs_hash_t namehash) { @@ -155,8 +184,15 @@ static inline bool f2fs_match_name(struct f2fs_dentry_ptr *d, entry.name = d->filename[bit_pos]; entry.len = de->name_len; - if (sbi->s_encoding && IS_CASEFOLDED(parent)) - return !f2fs_ci_compare(parent, fname->usr_fname, &entry); + if (sbi->s_encoding && IS_CASEFOLDED(parent)) { + if (cf_str->name) { + struct qstr cf = {.name = cf_str->name, + .len = cf_str->len}; + return !f2fs_ci_compare(parent, &cf, &entry, true); + } + return !f2fs_ci_compare(parent, fname->usr_fname, &entry, + false); + } #endif if (fscrypt_match_name(fname, d->filename[bit_pos], le16_to_cpu(de->name_len))) @@ -169,9 +205,14 @@ struct f2fs_dir_entry *f2fs_find_target_dentry(struct fscrypt_name *fname, struct f2fs_dentry_ptr *d) { struct f2fs_dir_entry *de; + struct fscrypt_str cf_str = { .name = NULL, .len = 0 }; unsigned long bit_pos = 0; int max_len = 0; +#ifdef CONFIG_UNICODE + f2fs_fname_setup_ci_filename(d->inode, fname->usr_fname, &cf_str); +#endif + if (max_slots) *max_slots = 0; while (bit_pos < d->max) { @@ -188,7 +229,7 @@ struct f2fs_dir_entry *f2fs_find_target_dentry(struct fscrypt_name *fname, continue; } - if (f2fs_match_name(d, de, fname, bit_pos, namehash)) + if (f2fs_match_name(d, de, fname, &cf_str, bit_pos, namehash)) goto found; if (max_slots && max_len > *max_slots) @@ -202,6 +243,10 @@ struct f2fs_dir_entry *f2fs_find_target_dentry(struct fscrypt_name *fname, found: if (max_slots && max_len > *max_slots) *max_slots = max_len; + +#ifdef CONFIG_UNICODE + kvfree(cf_str.name); +#endif return de; } @@ -1025,7 +1070,7 @@ static int f2fs_d_compare(const struct dentry *dentry, unsigned int len, return memcmp(str, name, len); } - return f2fs_ci_compare(dentry->d_parent->d_inode, name, &qstr); + return f2fs_ci_compare(dentry->d_parent->d_inode, name, &qstr, false); } static int f2fs_d_hash(const struct dentry *dentry, struct qstr *str) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index d2b718e33f88..260c6b2dca97 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -2941,7 +2941,8 @@ struct dentry *f2fs_get_parent(struct dentry *child); extern int f2fs_ci_compare(const struct inode *parent, const struct qstr *name, - const struct qstr *entry); + const struct qstr *entry, + bool quick); /* * dir.c |