ANDROID: sync generic casefolding code with patches going upstream
Get the generic casefolding code in sync with the patches that are queued in f2fs.git#dev for 5.10. Equivalently, this reverts the patch "ANDROID-fs-adjust-casefolding-support-to-match-android-mainline.patch" from the android-mainline quilt series, with the following conflicts: Conflicts: fs/ext4/hash.c # due to "ANDROID: ext4: Handle casefolding with encryption" fs/ext4/namei.c # due to "ANDROID: ext4: Handle casefolding with encryption" fs/f2fs/dir.c # due to "ANDROID: f2fs: Handle casefolding with Encryption" Bug: 161184936 Cc: Daniel Rosenberg <drosen@google.com> Cc: Paul Lawrence <paullawrence@google.com> Cc: Jaegeuk Kim <jaegeuk@google.com> Change-Id: I0ae169f0f5f413fb21e4be7a163213aef3fa6756 Signed-off-by: Eric Biggers <ebiggers@google.com>
This commit is contained in:
parent
fb3b36d52f
commit
76bfcb2dc2
@ -296,7 +296,7 @@ int ext4fs_dirhash(const struct inode *dir, const char *name, int len,
|
||||
unsigned char *buff;
|
||||
struct qstr qstr = {.name = name, .len = len };
|
||||
|
||||
if (len && needs_casefold(dir) && um) {
|
||||
if (len && IS_CASEFOLDED(dir) && um) {
|
||||
buff = kzalloc(sizeof(char) * PATH_MAX, GFP_KERNEL);
|
||||
if (!buff)
|
||||
return -ENOMEM;
|
||||
|
@ -1359,7 +1359,7 @@ static int ext4_ci_compare(const struct inode *parent, const struct qstr *name,
|
||||
/* Handle invalid character sequence as either an error
|
||||
* or as an opaque byte sequence.
|
||||
*/
|
||||
if (sb_has_enc_strict_mode(sb))
|
||||
if (sb_has_strict_encoding(sb))
|
||||
ret = -EINVAL;
|
||||
else if (name->len != entry.len)
|
||||
ret = 1;
|
||||
@ -1378,7 +1378,7 @@ int ext4_fname_setup_ci_filename(struct inode *dir, const struct qstr *iname,
|
||||
struct dx_hash_info *hinfo = &name->hinfo;
|
||||
int len;
|
||||
|
||||
if (!needs_casefold(dir)) {
|
||||
if (!IS_CASEFOLDED(dir) || !dir->i_sb->s_encoding) {
|
||||
cf_name->name = NULL;
|
||||
return 0;
|
||||
}
|
||||
@ -1429,7 +1429,7 @@ static bool ext4_match(struct inode *parent,
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_UNICODE
|
||||
if (needs_casefold(parent)) {
|
||||
if (parent->i_sb->s_encoding && IS_CASEFOLDED(parent)) {
|
||||
if (fname->cf_name.name) {
|
||||
struct qstr cf = {.name = fname->cf_name.name,
|
||||
.len = fname->cf_name.len};
|
||||
@ -2302,7 +2302,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
|
||||
return -EINVAL;
|
||||
|
||||
#ifdef CONFIG_UNICODE
|
||||
if (sb_has_enc_strict_mode(sb) && IS_CASEFOLDED(dir) &&
|
||||
if (sb_has_strict_encoding(sb) && IS_CASEFOLDED(dir) &&
|
||||
sb->s_encoding && utf8_validate(sb->s_encoding, &dentry->d_name))
|
||||
return -EINVAL;
|
||||
#endif
|
||||
|
@ -76,21 +76,22 @@ int f2fs_init_casefolded_name(const struct inode *dir,
|
||||
struct f2fs_filename *fname)
|
||||
{
|
||||
#ifdef CONFIG_UNICODE
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(sb);
|
||||
|
||||
if (IS_CASEFOLDED(dir)) {
|
||||
fname->cf_name.name = f2fs_kmalloc(sbi, F2FS_NAME_LEN,
|
||||
GFP_NOFS);
|
||||
if (!fname->cf_name.name)
|
||||
return -ENOMEM;
|
||||
fname->cf_name.len = utf8_casefold(sbi->sb->s_encoding,
|
||||
fname->cf_name.len = utf8_casefold(sb->s_encoding,
|
||||
fname->usr_fname,
|
||||
fname->cf_name.name,
|
||||
F2FS_NAME_LEN);
|
||||
if ((int)fname->cf_name.len <= 0) {
|
||||
kfree(fname->cf_name.name);
|
||||
fname->cf_name.name = NULL;
|
||||
if (sb_has_enc_strict_mode(dir->i_sb))
|
||||
if (sb_has_strict_encoding(sb))
|
||||
return -EINVAL;
|
||||
/* fall back to treating name as opaque byte sequence */
|
||||
}
|
||||
@ -246,7 +247,7 @@ static bool f2fs_match_ci_name(const struct inode *dir, const struct qstr *name,
|
||||
* In strict mode, ignore invalid names. In non-strict mode,
|
||||
* fall back to treating them as opaque byte sequences.
|
||||
*/
|
||||
if (sb_has_enc_strict_mode(sb) || name->len != entry.len)
|
||||
if (sb_has_strict_encoding(sb) || name->len != entry.len)
|
||||
res = 1;
|
||||
else
|
||||
res = memcmp(name->name, entry.name, name->len);
|
||||
|
56
fs/libfs.c
56
fs/libfs.c
@ -1367,27 +1367,38 @@ bool is_empty_dir_inode(struct inode *inode)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UNICODE
|
||||
bool needs_casefold(const struct inode *dir)
|
||||
/*
|
||||
* Determine if the name of a dentry should be casefolded.
|
||||
*
|
||||
* Return: if names will need casefolding
|
||||
*/
|
||||
static bool needs_casefold(const struct inode *dir)
|
||||
{
|
||||
return IS_CASEFOLDED(dir) && dir->i_sb->s_encoding &&
|
||||
(!IS_ENCRYPTED(dir) || fscrypt_has_encryption_key(dir));
|
||||
return IS_CASEFOLDED(dir) && dir->i_sb->s_encoding;
|
||||
}
|
||||
EXPORT_SYMBOL(needs_casefold);
|
||||
|
||||
/**
|
||||
* generic_ci_d_compare - generic d_compare implementation for casefolding filesystems
|
||||
* @dentry: dentry whose name we are checking against
|
||||
* @len: len of name of dentry
|
||||
* @str: str pointer to name of dentry
|
||||
* @name: Name to compare against
|
||||
*
|
||||
* Return: 0 if names match, 1 if mismatch, or -ERRNO
|
||||
*/
|
||||
int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
|
||||
const char *str, const struct qstr *name)
|
||||
{
|
||||
const struct dentry *parent = READ_ONCE(dentry->d_parent);
|
||||
const struct inode *inode = READ_ONCE(parent->d_inode);
|
||||
const struct inode *dir = READ_ONCE(parent->d_inode);
|
||||
const struct super_block *sb = dentry->d_sb;
|
||||
const struct unicode_map *um = sb->s_encoding;
|
||||
struct qstr entry = QSTR_INIT(str, len);
|
||||
struct qstr qstr = QSTR_INIT(str, len);
|
||||
char strbuf[DNAME_INLINE_LEN];
|
||||
int ret;
|
||||
|
||||
if (!inode || !needs_casefold(inode))
|
||||
if (!dir || !needs_casefold(dir))
|
||||
goto fallback;
|
||||
|
||||
/*
|
||||
* If the dentry name is stored in-line, then it may be concurrently
|
||||
* modified by a rename. If this happens, the VFS will eventually retry
|
||||
@ -1398,16 +1409,15 @@ int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
|
||||
if (len <= DNAME_INLINE_LEN - 1) {
|
||||
memcpy(strbuf, str, len);
|
||||
strbuf[len] = 0;
|
||||
entry.name = strbuf;
|
||||
qstr.name = strbuf;
|
||||
/* prevent compiler from optimizing out the temporary buffer */
|
||||
barrier();
|
||||
}
|
||||
|
||||
ret = utf8_strncasecmp(um, name, &entry);
|
||||
ret = utf8_strncasecmp(um, name, &qstr);
|
||||
if (ret >= 0)
|
||||
return ret;
|
||||
|
||||
if (sb_has_enc_strict_mode(sb))
|
||||
if (sb_has_strict_encoding(sb))
|
||||
return -EINVAL;
|
||||
fallback:
|
||||
if (len != name->len)
|
||||
@ -1416,27 +1426,27 @@ int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
|
||||
}
|
||||
EXPORT_SYMBOL(generic_ci_d_compare);
|
||||
|
||||
/**
|
||||
* generic_ci_d_hash - generic d_hash implementation for casefolding filesystems
|
||||
* @dentry: dentry of the parent directory
|
||||
* @str: qstr of name whose hash we should fill in
|
||||
*
|
||||
* Return: 0 if hash was successful or unchanged, and -EINVAL on error
|
||||
*/
|
||||
int generic_ci_d_hash(const struct dentry *dentry, struct qstr *str)
|
||||
{
|
||||
const struct inode *inode = READ_ONCE(dentry->d_inode);
|
||||
const struct inode *dir = READ_ONCE(dentry->d_inode);
|
||||
struct super_block *sb = dentry->d_sb;
|
||||
const struct unicode_map *um = sb->s_encoding;
|
||||
int ret = 0;
|
||||
|
||||
if (!inode || !needs_casefold(inode))
|
||||
if (!dir || !needs_casefold(dir))
|
||||
return 0;
|
||||
|
||||
ret = utf8_casefold_hash(um, dentry, str);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
if (ret < 0 && sb_has_strict_encoding(sb))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
err:
|
||||
if (sb_has_enc_strict_mode(sb))
|
||||
ret = -EINVAL;
|
||||
else
|
||||
ret = 0;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(generic_ci_d_hash);
|
||||
|
||||
|
@ -138,7 +138,7 @@ int utf8_casefold_hash(const struct unicode_map *um, const void *salt,
|
||||
|
||||
while ((c = utf8byte(&cur))) {
|
||||
if (c < 0)
|
||||
return c;
|
||||
return -EINVAL;
|
||||
hash = partial_name_hash((unsigned char)c, hash);
|
||||
}
|
||||
str->hash = end_name_hash(hash);
|
||||
|
@ -1374,7 +1374,7 @@ extern int send_sigurg(struct fown_struct *fown);
|
||||
/* These flags relate to encoding and casefolding */
|
||||
#define SB_ENC_STRICT_MODE_FL (1 << 0)
|
||||
|
||||
#define sb_has_enc_strict_mode(sb) \
|
||||
#define sb_has_strict_encoding(sb) \
|
||||
(sb->s_encoding_flags & SB_ENC_STRICT_MODE_FL)
|
||||
|
||||
/*
|
||||
@ -3276,12 +3276,6 @@ extern int generic_check_addressable(unsigned, u64);
|
||||
extern int generic_ci_d_hash(const struct dentry *dentry, struct qstr *str);
|
||||
extern int generic_ci_d_compare(const struct dentry *dentry, unsigned int len,
|
||||
const char *str, const struct qstr *name);
|
||||
extern bool needs_casefold(const struct inode *dir);
|
||||
#else
|
||||
static inline bool needs_casefold(const struct inode *dir)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
extern void generic_set_encrypted_ci_d_ops(struct inode *dir,
|
||||
struct dentry *dentry);
|
||||
|
Loading…
Reference in New Issue
Block a user