// SPDX-License-Identifier: GPL-2.0
/*
* fs/f2fs/dir.c
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*/
#include <linux/unaligned.h>
#include <linux/fs.h>
#include <linux/f2fs_fs.h>
#include <linux/sched/signal.h>
#include <linux/unicode.h>
#include "f2fs.h"
#include "node.h"
#include "acl.h"
#include "xattr.h"
#include <trace/events/f2fs.h>
#if IS_ENABLED(CONFIG_UNICODE)
extern struct kmem_cache *f2fs_cf_name_slab;
#endif
static unsigned long dir_blocks(struct inode *inode)
{
return ((unsigned long long) (i_size_read(inode) + PAGE_SIZE - 1))
>> PAGE_SHIFT;
}
static unsigned int dir_buckets(unsigned int level, int dir_level)
{
if (level + dir_level < MAX_DIR_HASH_DEPTH / 2)
return BIT(level + dir_level);
else
return MAX_DIR_BUCKETS;
}
static unsigned int bucket_blocks(unsigned int level)
{
if (level < MAX_DIR_HASH_DEPTH / 2)
return 2;
else
return 4;
}
#if IS_ENABLED(CONFIG_UNICODE)
/* If @dir is casefolded, initialize @fname->cf_name from @fname->usr_fname. */
int f2fs_init_casefolded_name(const struct inode *dir,
struct f2fs_filename *fname)
{
struct super_block *sb = dir->i_sb;
unsigned char *buf;
int len;
if (IS_CASEFOLDED(dir) &&
!is_dot_dotdot(fname->usr_fname->name, fname->usr_fname->len)) {
buf = f2fs_kmem_cache_alloc(f2fs_cf_name_slab,
GFP_NOFS, false, F2FS_SB(sb));
if (!buf)
return -ENOMEM;
len = utf8_casefold(sb->s_encoding, fname->usr_fname,
buf, F2FS_NAME_LEN);
if (len <= 0) {
kmem_cache_free(f2fs_cf_name_slab, buf);
if (sb_has_strict_encoding(sb))
return -EINVAL;
/* fall back to treating name as opaque byte sequence */
return 0;
}
fname->cf_name.name = buf;
fname->cf_name.len = len;
}
return 0;
}
void f2fs_free_casefolded_name(struct f2fs_filename *fname)
{
unsigned char *buf = (unsigned char *)fname->cf_name.name;
if (buf) {
kmem_cache_free(f2fs_cf_name_slab, buf);
fname->cf_name.name = NULL;
}
}
#endif /* CONFIG_UNICODE */
static int __f2fs_setup_filename(const struct inode *dir,
const struct fscrypt_name *crypt_name,
struct f2fs_filename *fname)
{
int err;
memset(fname, 0, sizeof(*fname));
fname->usr_fname = crypt_name->usr_fname;
fname->disk_name = crypt_name->disk_name;
#ifdef CONFIG_FS_ENCRYPTION
fname->crypto_buf = crypt_name->crypto_buf;
#endif
if (crypt_name->is_nokey_name) {
/* hash was decoded from the no-key name */
fname->hash = cpu_to_le32(crypt_name->hash);
} else {
err = f2fs_init_casefolded_name(dir, fname);
if (err) {
f2fs_free_filename(fname);
return err;
}
f2fs_hash_filename(dir, fname);
}
return 0;
}
/*
* Prepare to search for @iname in @dir. This is similar to
* fscrypt_setup_filename(), but this also handles computing the casefolded name
* and the f2fs dirhash if needed, then packing all the information about this
* filename up into a 'struct f2fs_filename'.
*/
int f2fs_setup_filename(struct inode *dir, const struct qstr *iname,
int lookup, struct f2fs_filename *fname)
{
struct fscrypt_name crypt_name;
int err;
err = fscrypt_setup_filename(dir, iname, lookup, &crypt_name);
if (err)
return err;
return __f2fs_setup_filename(dir, &crypt_name, fname);
}
/*
* Prepare to look up @dentry in @dir. This is similar to
* fscrypt_prepare_lookup(), but this also handles computing the casefolded name
* and the f2fs dirhash if needed, then packing all the information about this
* filename up into a 'struct f2fs_filename'.
*/
int f2fs_prepare_lookup(struct inode *dir, struct dentry *dentry,
struct f2fs_filename *fname)
{
struct fscrypt_name crypt_name;
int err;
err = fscrypt_prepare_lookup(dir, dentry, &crypt_name);
if (err)
return err;
return __f2fs_setup_filename(dir, &crypt_name, fname);
}
void f2fs_free_filename(struct f2fs_filename *fname)
{
#ifdef CONFIG_FS_ENCRYPTION
kfree(fname->crypto_buf.name);
fname->crypto_buf.name = NULL;
#endif
f2fs_free_casefolded_name(fname);
}
static unsigned long dir_block_index(unsigned int level,
int dir_level, unsigned int idx)
{
unsigned long i;
unsigned long bidx = 0;
for (i = 0; i < level; i++)
bidx += mul_u32_u32(dir_buckets(i, dir_level),
bucket_blocks(i));