mirror of
https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git
synced 2024-11-24 02:25:03 +08:00
libext2fs: support encoding when calculating dx hashes
fsck must be aware of the superblock encoding and the casefold directory setting, such that it is able to correctly calculate the dentry hashes. [ Changed to use a stack-allocated buffer instead of a calling calloc() with a fixed size -- TYT ] Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
parent
ab93e18318
commit
28b44ef08a
@ -293,7 +293,8 @@ pass1.o: $(srcdir)/pass1.c $(top_builddir)/lib/config.h \
|
||||
$(top_srcdir)/lib/ext2fs/bitops.h $(top_srcdir)/lib/support/profile.h \
|
||||
$(top_builddir)/lib/support/prof_err.h $(top_srcdir)/lib/support/quotaio.h \
|
||||
$(top_srcdir)/lib/support/dqblk_v2.h \
|
||||
$(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h
|
||||
$(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h \
|
||||
$(top_srcdir)/lib/ext2fs/nls.h
|
||||
pass1b.o: $(srcdir)/pass1b.c $(top_builddir)/lib/config.h \
|
||||
$(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \
|
||||
$(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
|
||||
@ -317,7 +318,7 @@ pass2.o: $(srcdir)/pass2.c $(top_builddir)/lib/config.h \
|
||||
$(top_builddir)/lib/support/prof_err.h $(top_srcdir)/lib/support/quotaio.h \
|
||||
$(top_srcdir)/lib/support/dqblk_v2.h \
|
||||
$(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h \
|
||||
$(top_srcdir)/lib/support/dict.h
|
||||
$(top_srcdir)/lib/support/dict.h $(top_srcdir)/lib/ext2fs/nls.h
|
||||
pass3.o: $(srcdir)/pass3.c $(top_builddir)/lib/config.h \
|
||||
$(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
|
||||
$(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
|
||||
@ -416,7 +417,7 @@ unix.o: $(srcdir)/unix.c $(top_builddir)/lib/config.h \
|
||||
$(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/support/plausible.h \
|
||||
$(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
|
||||
$(top_srcdir)/lib/ext2fs/ext3_extents.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
|
||||
$(top_builddir)/lib/ext2fs/ext2_err.h \
|
||||
$(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/nls.h \
|
||||
$(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/hashmap.h \
|
||||
$(top_srcdir)/lib/ext2fs/bitops.h $(top_srcdir)/lib/support/profile.h \
|
||||
$(top_builddir)/lib/support/prof_err.h $(top_srcdir)/lib/support/quotaio.h \
|
||||
|
@ -13,7 +13,8 @@
|
||||
* entry. During pass1, the passed-in parent is 0; it will get filled
|
||||
* in during pass2.
|
||||
*/
|
||||
void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, int num_blocks)
|
||||
void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, struct ext2_inode *inode,
|
||||
int num_blocks)
|
||||
{
|
||||
struct dx_dir_info *dir;
|
||||
int i, j;
|
||||
@ -72,6 +73,7 @@ void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, int num_blocks)
|
||||
dir->ino = ino;
|
||||
dir->numblocks = num_blocks;
|
||||
dir->hashversion = 0;
|
||||
dir->casefolded_hash = inode->i_flags & EXT4_CASEFOLD_FL;
|
||||
dir->dx_block = e2fsck_allocate_memory(ctx, num_blocks
|
||||
* sizeof (struct dx_dirblock_info),
|
||||
"dx_block info array");
|
||||
|
@ -109,6 +109,7 @@ struct dx_dir_info {
|
||||
int hashversion;
|
||||
short depth; /* depth of tree */
|
||||
struct dx_dirblock_info *dx_block; /* Array of size numblocks */
|
||||
int casefolded_hash;
|
||||
};
|
||||
|
||||
#define DX_DIRBLOCK_ROOT 1
|
||||
@ -471,7 +472,8 @@ extern int e2fsck_dir_info_get_dotdot(e2fsck_t ctx, ext2_ino_t ino,
|
||||
ext2_ino_t *dotdot);
|
||||
|
||||
/* dx_dirinfo.c */
|
||||
extern void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, int num_blocks);
|
||||
extern void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino,
|
||||
struct ext2_inode *inode, int num_blocks);
|
||||
extern struct dx_dir_info *e2fsck_get_dx_dir_info(e2fsck_t ctx, ext2_ino_t ino);
|
||||
extern void e2fsck_free_dx_dir_info(e2fsck_t ctx);
|
||||
extern int e2fsck_get_num_dx_dirinfo(e2fsck_t ctx);
|
||||
|
@ -48,6 +48,7 @@
|
||||
|
||||
#include "e2fsck.h"
|
||||
#include <ext2fs/ext2_ext_attr.h>
|
||||
#include <e2p/e2p.h>
|
||||
|
||||
#include "problem.h"
|
||||
|
||||
@ -3381,7 +3382,7 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
|
||||
inode->i_flags &= ~EXT2_INDEX_FL;
|
||||
dirty_inode++;
|
||||
} else {
|
||||
e2fsck_add_dx_dir(ctx, ino, pb.last_block+1);
|
||||
e2fsck_add_dx_dir(ctx, ino, inode, pb.last_block+1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -933,6 +933,7 @@ static int check_dir_block(ext2_filsys fs,
|
||||
int filetype = 0;
|
||||
int encrypted = 0;
|
||||
size_t max_block_size;
|
||||
int hash_flags = 0;
|
||||
|
||||
cd = (struct check_dir_struct *) priv_data;
|
||||
ibuf = buf = cd->buf;
|
||||
@ -1426,9 +1427,13 @@ skip_checksum:
|
||||
dir_modified++;
|
||||
|
||||
if (dx_db) {
|
||||
ext2fs_dirhash(dx_dir->hashversion, dirent->name,
|
||||
ext2fs_dirent_name_len(dirent),
|
||||
fs->super->s_hash_seed, &hash, 0);
|
||||
if (dx_dir->casefolded_hash)
|
||||
hash_flags = EXT4_CASEFOLD_FL;
|
||||
|
||||
ext2fs_dirhash2(dx_dir->hashversion, dirent->name,
|
||||
ext2fs_dirent_name_len(dirent),
|
||||
fs->encoding, hash_flags,
|
||||
fs->super->s_hash_seed, &hash, 0);
|
||||
if (hash < dx_db->min_hash)
|
||||
dx_db->min_hash = hash;
|
||||
if (hash > dx_db->max_hash)
|
||||
|
@ -113,7 +113,7 @@ static int fill_dir_block(ext2_filsys fs,
|
||||
struct ext2_dir_entry *dirent;
|
||||
char *dir;
|
||||
unsigned int offset, dir_offset, rec_len, name_len;
|
||||
int hash_alg;
|
||||
int hash_alg, hash_flags;
|
||||
|
||||
if (blockcnt < 0)
|
||||
return 0;
|
||||
@ -139,6 +139,7 @@ static int fill_dir_block(ext2_filsys fs,
|
||||
if (fd->err)
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
hash_flags = fd->inode->i_flags & EXT4_CASEFOLD_FL;
|
||||
hash_alg = fs->super->s_def_hash_version;
|
||||
if ((hash_alg <= EXT2_HASH_TEA) &&
|
||||
(fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH))
|
||||
@ -184,10 +185,11 @@ static int fill_dir_block(ext2_filsys fs,
|
||||
if (fd->compress)
|
||||
ent->hash = ent->minor_hash = 0;
|
||||
else {
|
||||
fd->err = ext2fs_dirhash(hash_alg, dirent->name,
|
||||
name_len,
|
||||
fs->super->s_hash_seed,
|
||||
&ent->hash, &ent->minor_hash);
|
||||
fd->err = ext2fs_dirhash2(hash_alg,
|
||||
dirent->name, name_len,
|
||||
fs->encoding, hash_flags,
|
||||
fs->super->s_hash_seed,
|
||||
&ent->hash, &ent->minor_hash);
|
||||
if (fd->err)
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
@ -371,6 +373,7 @@ static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
|
||||
char new_name[256];
|
||||
unsigned int new_len;
|
||||
int hash_alg;
|
||||
int hash_flags = fd->inode->i_flags & EXT4_CASEFOLD_FL;
|
||||
|
||||
clear_problem_context(&pctx);
|
||||
pctx.ino = ino;
|
||||
@ -415,9 +418,10 @@ static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
|
||||
if (fix_problem(ctx, PR_2_NON_UNIQUE_FILE, &pctx)) {
|
||||
memcpy(ent->dir->name, new_name, new_len);
|
||||
ext2fs_dirent_set_name_len(ent->dir, new_len);
|
||||
ext2fs_dirhash(hash_alg, new_name, new_len,
|
||||
fs->super->s_hash_seed,
|
||||
&ent->hash, &ent->minor_hash);
|
||||
ext2fs_dirhash2(hash_alg, new_name, new_len,
|
||||
fs->encoding, hash_flags,
|
||||
fs->super->s_hash_seed,
|
||||
&ent->hash, &ent->minor_hash);
|
||||
fixed++;
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ extern int optind;
|
||||
#include "problem.h"
|
||||
#include "jfs_user.h"
|
||||
#include "../version.h"
|
||||
#include <ext2fs/nls.h>
|
||||
|
||||
/* Command line options */
|
||||
static int cflag; /* check disk */
|
||||
@ -1784,6 +1785,15 @@ print_unsupp_features:
|
||||
goto get_newer;
|
||||
}
|
||||
|
||||
if (ext2fs_has_feature_fname_encoding(sb)) {
|
||||
fs->encoding = nls_load_table(sb->s_encoding);
|
||||
if (!fs->encoding) {
|
||||
log_err(ctx, _("%s has unsupported encoding: %0x\n"),
|
||||
ctx->filesystem_name, sb->s_encoding);
|
||||
goto get_newer;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If the user specified a specific superblock, presumably the
|
||||
* master superblock has been trashed. So we mark the
|
||||
|
@ -779,7 +779,8 @@ dirhash.o: $(srcdir)/dirhash.c $(top_builddir)/lib/config.h \
|
||||
$(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
|
||||
$(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h $(top_srcdir)/lib/et/com_err.h \
|
||||
$(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
|
||||
$(srcdir)/ext2_ext_attr.h $(srcdir)/hashmap.h $(srcdir)/bitops.h
|
||||
$(srcdir)/ext2_ext_attr.h $(srcdir)/hashmap.h $(srcdir)/bitops.h \
|
||||
$(srcdir)/nls.h
|
||||
dir_iterate.o: $(srcdir)/dir_iterate.c $(top_builddir)/lib/config.h \
|
||||
$(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
|
||||
$(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fsP.h \
|
||||
|
@ -14,9 +14,11 @@
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
#include "nls.h"
|
||||
|
||||
/*
|
||||
* Keyed 32-bit hash function using TEA in a Davis-Meyer function
|
||||
@ -184,6 +186,11 @@ static void str2hashbuf(const char *msg, int len, __u32 *buf, int num,
|
||||
* A particular hash version specifies whether or not the seed is
|
||||
* represented, and whether or not the returned hash is 32 bits or 64
|
||||
* bits. 32 bit hashes will return 0 for the minor hash.
|
||||
*
|
||||
* This function doesn't do any normalization or casefolding of the
|
||||
* input string. To take charset encoding into account, use
|
||||
* ext2fs_dirhash2.
|
||||
*
|
||||
*/
|
||||
errcode_t ext2fs_dirhash(int version, const char *name, int len,
|
||||
const __u32 *seed,
|
||||
@ -257,3 +264,44 @@ errcode_t ext2fs_dirhash(int version, const char *name, int len,
|
||||
*ret_minor_hash = minor_hash;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the hash of a filename considering normalization and
|
||||
* casefolding. This is a wrapper around ext2fs_dirhash with string
|
||||
* encoding support based on the nls_table and the flags. Check
|
||||
* ext2fs_dirhash for documentation on the input and output parameters.
|
||||
*/
|
||||
errcode_t ext2fs_dirhash2(int version, const char *name, int len,
|
||||
const struct nls_table *charset, int hash_flags,
|
||||
const __u32 *seed,
|
||||
ext2_dirhash_t *ret_hash,
|
||||
ext2_dirhash_t *ret_minor_hash)
|
||||
{
|
||||
errcode_t r;
|
||||
int dlen;
|
||||
unsigned char *buff;
|
||||
|
||||
if (len && charset) {
|
||||
char buff[PATH_MAX];
|
||||
|
||||
if (hash_flags & EXT4_CASEFOLD_FL)
|
||||
dlen = charset->ops->casefold(charset, name, len, buff,
|
||||
sizeof(buff));
|
||||
else
|
||||
dlen = charset->ops->normalize(charset, name, len, buff,
|
||||
sizeof(buff));
|
||||
if (dlen < 0) {
|
||||
if (dlen == -EINVAL)
|
||||
goto opaque_seq;
|
||||
|
||||
return dlen;
|
||||
}
|
||||
r = ext2fs_dirhash(version, buff, dlen, seed, ret_hash,
|
||||
ret_minor_hash);
|
||||
return r;
|
||||
}
|
||||
|
||||
opaque_seq:
|
||||
return ext2fs_dirhash(version, name, len, seed, ret_hash,
|
||||
ret_minor_hash);
|
||||
}
|
||||
|
@ -307,6 +307,8 @@ struct struct_ext2_filsys {
|
||||
|
||||
/* hashmap for SHA of data blocks */
|
||||
struct ext2fs_hashmap* block_sha_map;
|
||||
|
||||
const struct nls_table *encoding;
|
||||
};
|
||||
|
||||
#if EXT2_FLAT_INCLUDES
|
||||
@ -1174,6 +1176,12 @@ extern errcode_t ext2fs_dirhash(int version, const char *name, int len,
|
||||
ext2_dirhash_t *ret_hash,
|
||||
ext2_dirhash_t *ret_minor_hash);
|
||||
|
||||
extern errcode_t ext2fs_dirhash2(int version, const char *name, int len,
|
||||
const struct nls_table *charset,
|
||||
int hash_flags,
|
||||
const __u32 *seed,
|
||||
ext2_dirhash_t *ret_hash,
|
||||
ext2_dirhash_t *ret_minor_hash);
|
||||
|
||||
/* dir_iterate.c */
|
||||
extern errcode_t ext2fs_get_rec_len(ext2_filsys fs,
|
||||
|
Loading…
Reference in New Issue
Block a user