summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xdebian/rules2
-rw-r--r--debugfs/ChangeLog9
-rw-r--r--debugfs/htree.c7
-rw-r--r--debugfs/set_fields.c1
-rw-r--r--e2fsck/ChangeLog11
-rw-r--r--e2fsck/pass2.c5
-rw-r--r--e2fsck/problem.c5
-rw-r--r--e2fsck/problem.h3
-rw-r--r--e2fsck/rehash.c17
-rw-r--r--e2fsck/super.c35
-rw-r--r--lib/e2p/ChangeLog5
-rw-r--r--lib/e2p/ls.c23
-rw-r--r--lib/ext2fs/ChangeLog14
-rw-r--r--lib/ext2fs/dirhash.c42
-rw-r--r--lib/ext2fs/ext2_fs.h18
-rw-r--r--lib/ext2fs/initialize.c8
-rw-r--r--lib/ext2fs/swapfs.c1
-rw-r--r--tests/ChangeLog15
-rw-r--r--tests/f_dup_de/image.gzbin8961 -> 8970 bytes
-rw-r--r--tests/f_h_badnode/image.gzbin467065 -> 467331 bytes
-rw-r--r--tests/f_h_badroot/image.gzbin43120 -> 43165 bytes
-rw-r--r--tests/f_h_normal/expect.12
-rw-r--r--tests/f_h_normal/expect.22
-rw-r--r--tests/f_h_normal/image.gzbin466817 -> 454847 bytes
-rw-r--r--tests/f_h_normal/name2
-rw-r--r--tests/f_h_reindex/image.gzbin621257 -> 621257 bytes
-rw-r--r--tests/f_h_unsigned/expect.17
-rw-r--r--tests/f_h_unsigned/expect.27
-rw-r--r--tests/f_h_unsigned/image.gzbin0 -> 454913 bytes
-rw-r--r--tests/f_h_unsigned/name1
-rw-r--r--tests/f_h_unsigned/script6
-rw-r--r--tests/filter_dumpe2fs1
32 files changed, 226 insertions, 23 deletions
diff --git a/debian/rules b/debian/rules
index dbf8077a..4448418f 100755
--- a/debian/rules
+++ b/debian/rules
@@ -64,7 +64,7 @@ CFGBFSTAMP=${STAMPSDIR}/configure-bf-stamp
BUILDSTDSTAMP=${STAMPSDIR}/build-std-stamp
BUILDBFSTAMP=${STAMPSDIR}/build-bf-stamp
-CCOPTS = -g -fsigned-char
+CCOPTS = -g
INSTALL = install
INSTALL_PROGRAM = $(INSTALL) -p -o root -g root -m 0755
diff --git a/debugfs/ChangeLog b/debugfs/ChangeLog
index 1f8465d7..8ed8cfb7 100644
--- a/debugfs/ChangeLog
+++ b/debugfs/ChangeLog
@@ -1,3 +1,12 @@
+2006-11-11 Theodore Tso <tytso@mit.edu>
+
+ * set_fields.c: Add the ability to use set_super_value to set the
+ superblock flags field.
+
+ * htree.c (htree_dump_leaf_node): Check the superblock flags to
+ determine whether to use the signed or unsigned version of
+ the hash should be used.
+
2006-10-01 Theodore Tso <tytso@mit.edu>
* Makefile.in (DEPLIBBLKID): Use DEPLIBBLKID not LIBBLKID to
diff --git a/debugfs/htree.c b/debugfs/htree.c
index 4e5286f0..7abdfc02 100644
--- a/debugfs/htree.c
+++ b/debugfs/htree.c
@@ -39,6 +39,7 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
char tmp[EXT2_NAME_LEN + 16];
blk_t pblk;
ext2_dirhash_t hash;
+ int hash_alg;
errcode = ext2fs_bmap(fs, ino, inode, buf, 0, blk, &pblk);
if (errcode) {
@@ -53,6 +54,10 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
"while reading block %u\n", blk);
return;
}
+ hash_alg = rootnode->hash_version;
+ if ((hash_alg <= EXT2_HASH_TEA) &&
+ (fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH))
+ hash_alg += 3;
while (offset < fs->blocksize) {
dirent = (struct ext2_dir_entry *) (buf + offset);
@@ -67,7 +72,7 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
(dirent->name_len & 0xFF) : EXT2_NAME_LEN;
strncpy(name, dirent->name, thislen);
name[thislen] = '\0';
- errcode = ext2fs_dirhash(rootnode->hash_version, name,
+ errcode = ext2fs_dirhash(hash_alg, name,
thislen, fs->super->s_hash_seed,
&hash, 0);
if (errcode)
diff --git a/debugfs/set_fields.c b/debugfs/set_fields.c
index 5bbddfb4..c3de1cfa 100644
--- a/debugfs/set_fields.c
+++ b/debugfs/set_fields.c
@@ -110,6 +110,7 @@ static struct field_set_info super_fields[] = {
{ "mkfs_time", &set_sb.s_mkfs_time, 4, parse_time },
{ "jnl_blocks", &set_sb.s_jnl_blocks[0], 4, parse_uint, FLAG_ARRAY,
17 },
+ { "flags", &set_sb.s_flags, 4, parse_uint },
{ 0, 0, 0, 0 }
};
diff --git a/e2fsck/ChangeLog b/e2fsck/ChangeLog
index 2f11bd75..24288fee 100644
--- a/e2fsck/ChangeLog
+++ b/e2fsck/ChangeLog
@@ -1,5 +1,16 @@
2006-11-11 Theodore Tso <tytso@mit.edu>
+ * super.c (e2fsck_fix_dirhash_hint, check_super_block): If neither
+ the signed or unsigned dirhash hint, set it based on
+ default signed vs. unsigned character type in use by the
+ platform.
+
+ * problem.c, problem.h (PR_0_DIRHASH_HINT): Add new problem code.
+
+ * pass2.c (check_dir_block), rehash.c (fill_dir_block): Check the
+ superblock flags to determine whether to use the signed or
+ unsigned version of the hash should be used.
+
* problem.c, problem.h (PR_2_BLOCKS_HI_ZERO): Add new problem code.
* pass1.c (e2fsck_pass1), pass2.c (e2fsck_process_bad_inode):
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 8bcb3d18..6dc5e5ff 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -801,8 +801,11 @@ static int check_dir_block(ext2_filsys fs,
clear_htree(ctx, ino);
dx_dir->numblocks = 0;
dx_db = 0;
- }
+ }
dx_dir->hashversion = root->hash_version;
+ if ((dx_dir->hashversion <= EXT2_HASH_TEA) &&
+ (fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH))
+ dx_dir->hashversion += 3;
dx_dir->depth = root->indirect_levels + 1;
} else if ((dirent->inode == 0) &&
(dirent->rec_len == fs->blocksize) &&
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index 7f6add40..cb535ad0 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -346,6 +346,11 @@ static struct e2fsck_problem problem_table[] = {
N_("@S hint for external superblock @s %X. "),
PROMPT_FIX, PR_PREEN_OK },
+ /* Adding dirhash hint */
+ { PR_0_DIRHASH_HINT,
+ N_("Adding dirhash hint to @f.\n\n"),
+ PROMPT_NONE, 0 },
+
/* Pass 1 errors */
/* Pass 1: Checking inodes, blocks, and sizes */
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index 4561c618..e5070b05 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -193,6 +193,9 @@ struct problem_context {
/* Superblock hint for external journal incorrect */
#define PR_0_EXTERNAL_JOURNAL_HINT 0x000033
+/* Superblock hint for external journal incorrect */
+#define PR_0_DIRHASH_HINT 0x000034
+
/*
* Pass 1 errors
*/
diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
index 727e08c2..4a73ddf5 100644
--- a/e2fsck/rehash.c
+++ b/e2fsck/rehash.c
@@ -88,6 +88,7 @@ static int fill_dir_block(ext2_filsys fs,
struct ext2_dir_entry *dirent;
char *dir;
unsigned int offset, dir_offset;
+ int hash_alg;
if (blockcnt < 0)
return 0;
@@ -107,6 +108,10 @@ static int fill_dir_block(ext2_filsys fs,
if (fd->err)
return BLOCK_ABORT;
}
+ hash_alg = fs->super->s_def_hash_version;
+ if ((hash_alg <= EXT2_HASH_TEA) &&
+ (fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH))
+ hash_alg += 3;
/* While the directory block is "hot", index it. */
dir_offset = 0;
while (dir_offset < fs->blocksize) {
@@ -145,8 +150,7 @@ static int fill_dir_block(ext2_filsys fs,
if (fd->compress)
ent->hash = ent->minor_hash = 0;
else {
- fd->err = ext2fs_dirhash(fs->super->s_def_hash_version,
- dirent->name,
+ fd->err = ext2fs_dirhash(hash_alg, dirent->name,
dirent->name_len & 0xFF,
fs->super->s_hash_seed,
&ent->hash, &ent->minor_hash);
@@ -323,10 +327,16 @@ static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
int fixed = 0;
char new_name[256];
__u16 new_len;
+ int hash_alg;
clear_problem_context(&pctx);
pctx.ino = ino;
+ hash_alg = fs->super->s_def_hash_version;
+ if ((hash_alg <= EXT2_HASH_TEA) &&
+ (fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH))
+ hash_alg += 3;
+
for (i=1; i < fd->num_array; i++) {
ent = fd->harray + i;
prev = ent - 1;
@@ -363,8 +373,7 @@ 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 & 0xFF);
ent->dir->name_len = new_len;
- ext2fs_dirhash(fs->super->s_def_hash_version,
- ent->dir->name,
+ ext2fs_dirhash(hash_alg, ent->dir->name,
ent->dir->name_len & 0xFF,
fs->super->s_hash_seed,
&ent->hash, &ent->minor_hash);
diff --git a/e2fsck/super.c b/e2fsck/super.c
index ae40531c..62e03a5b 100644
--- a/e2fsck/super.c
+++ b/e2fsck/super.c
@@ -436,6 +436,36 @@ cleanup:
}
+/*
+ * This function checks the dirhash signed/unsigned hint if necessary.
+ */
+void e2fsck_fix_dirhash_hint(e2fsck_t ctx)
+{
+ struct ext2_super_block *sb = ctx->fs->super;
+ struct problem_context pctx;
+ problem_t problem;
+ int retval;
+ char c;
+
+ if ((ctx->options & E2F_OPT_READONLY) ||
+ !(sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
+ (sb->s_flags & (EXT2_FLAGS_SIGNED_HASH|EXT2_FLAGS_UNSIGNED_HASH)))
+ return;
+
+ c = (char) 255;
+
+ clear_problem_context(&pctx);
+ if (fix_problem(ctx, PR_0_DIRHASH_HINT, &pctx)) {
+ if (((int) c) == -1) {
+ sb->s_flags |= EXT2_FLAGS_SIGNED_HASH;
+ } else {
+ sb->s_flags |= EXT2_FLAGS_UNSIGNED_HASH;
+ }
+ ext2fs_mark_super_dirty(ctx->fs);
+ }
+}
+
+
void check_super_block(e2fsck_t ctx)
{
ext2_filsys fs = ctx->fs;
@@ -732,5 +762,10 @@ void check_super_block(e2fsck_t ctx)
*/
e2fsck_fix_ext3_journal_hint(ctx);
+ /*
+ * Add dirhash hint if necessary
+ */
+ e2fsck_fix_dirhash_hint(ctx);
+
return;
}
diff --git a/lib/e2p/ChangeLog b/lib/e2p/ChangeLog
index 75e2cd3b..a3df5571 100644
--- a/lib/e2p/ChangeLog
+++ b/lib/e2p/ChangeLog
@@ -1,3 +1,8 @@
+2006-11-11 Theodore Tso <tytso@mit.edu>
+
+ * ls.c (print_super_flags, list_super2): Print the signed/unsigned
+ dirhash information from the superblock flags field.
+
2006-09-29 Theodore Tso <tytso@mit.edu>
* percent.c (e2p_percent): Fix bug which caused e2p_percent to
diff --git a/lib/e2p/ls.c b/lib/e2p/ls.c
index 14368db7..b9ae14ad 100644
--- a/lib/e2p/ls.c
+++ b/lib/e2p/ls.c
@@ -138,6 +138,28 @@ static void print_mntopts(struct ext2_super_block * s, FILE *f)
#endif
}
+static void print_super_flags(struct ext2_super_block * s, FILE *f)
+{
+ int flags_found = 0;
+
+ if (s->s_flags == 0)
+ return;
+
+ fputs("Filesystem flags: ", f);
+ if (s->s_flags & EXT2_FLAGS_SIGNED_HASH) {
+ fputs("signed directory hash ", f);
+ flags_found++;
+ }
+ if (s->s_flags & EXT2_FLAGS_UNSIGNED_HASH) {
+ fputs("unsigned directory hash ", f);
+ flags_found++;
+ }
+ if (flags_found)
+ fputs("\n", f);
+ else
+ fputs("(none)\n", f);
+}
+
#ifndef EXT2_INODE_SIZE
#define EXT2_INODE_SIZE(s) sizeof(struct ext2_inode)
@@ -181,6 +203,7 @@ void list_super2(struct ext2_super_block * sb, FILE *f)
} else
fprintf(f, " (unknown)\n");
print_features(sb, f);
+ print_super_flags(sb, f);
print_mntopts(sb, f);
fprintf(f, "Filesystem state: ");
print_fs_state (f, sb->s_state);
diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog
index 3453d686..51a2f3ae 100644
--- a/lib/ext2fs/ChangeLog
+++ b/lib/ext2fs/ChangeLog
@@ -1,5 +1,19 @@
2006-11-11 Theodore Tso <tytso@mit.edu>
+ * dirhash.c (str2hashbuf, ext2fs_dirhash): Add support for
+ calculating the unsigned version of the directory hash.
+
+ * initialize.c (ext2fs_initialize): Set the dirhash
+ signed/unsigned hint in s_flags.
+
+ * swapfs.c (ext2fs_swap_super): Byte swap the s_flags superblock
+ field.
+
+ * ext2_fs.h: Define a new superblock field, s_flags, which is used
+ to store a signed vs. unsigned dirhash hint. Define new
+ HTREE hash algorithm numbers to pass to userspace if the
+ unsigned algorithm are required.
+
* swapfs.c (ext2fs_swap_super):
ext2_fs.h: Add definition of EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE,
which adds s_min_extra_isize and s_want_extra_isize fields
diff --git a/lib/ext2fs/dirhash.c b/lib/ext2fs/dirhash.c
index 4d18593f..9fd20160 100644
--- a/lib/ext2fs/dirhash.c
+++ b/lib/ext2fs/dirhash.c
@@ -116,11 +116,20 @@ static void halfMD4Transform (__u32 buf[4], __u32 const in[])
#undef K3
/* The old legacy hash */
-static ext2_dirhash_t dx_hack_hash (const char *name, int len)
+static ext2_dirhash_t dx_hack_hash (const char *name, int len,
+ int unsigned_flag)
{
- __u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
+ __u32 hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
+ const unsigned char *ucp = (const unsigned char *) name;
+ const signed char *scp = (const signed char *) name;
+ int c;
+
while (len--) {
- __u32 hash = hash1 + (hash0 ^ (*name++ * 7152373));
+ if (unsigned_flag)
+ c = (int) *ucp++;
+ else
+ c = (int) *scp++;
+ hash = hash1 + (hash0 ^ (c * 7152373));
if (hash & 0x80000000) hash -= 0x7fffffff;
hash1 = hash0;
@@ -129,10 +138,13 @@ static ext2_dirhash_t dx_hack_hash (const char *name, int len)
return (hash0 << 1);
}
-static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
+static void str2hashbuf(const char *msg, int len, __u32 *buf, int num,
+ int unsigned_flag)
{
__u32 pad, val;
- int i;
+ int i, c;
+ const unsigned char *ucp = (const unsigned char *) msg;
+ const signed char *scp = (const signed char *) msg;
pad = (__u32)len | ((__u32)len << 8);
pad |= pad << 16;
@@ -143,7 +155,12 @@ static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
for (i=0; i < len; i++) {
if ((i % 4) == 0)
val = pad;
- val = msg[i] + (val << 8);
+ if (unsigned_flag)
+ c = (int) ucp[i];
+ else
+ c = (int) scp[i];
+
+ val = c + (val << 8);
if ((i % 4) == 3) {
*buf++ = val;
val = pad;
@@ -179,6 +196,7 @@ errcode_t ext2fs_dirhash(int version, const char *name, int len,
const char *p;
int i;
__u32 in[8], buf[4];
+ int unsigned_flag = 0;
/* Initialize the default seed for the hash checksum functions */
buf[0] = 0x67452301;
@@ -197,13 +215,17 @@ errcode_t ext2fs_dirhash(int version, const char *name, int len,
}
switch (version) {
+ case EXT2_HASH_LEGACY_UNSIGNED:
+ unsigned_flag++;
case EXT2_HASH_LEGACY:
- hash = dx_hack_hash(name, len);
+ hash = dx_hack_hash(name, len, unsigned_flag);
break;
+ case EXT2_HASH_HALF_MD4_UNSIGNED:
+ unsigned_flag++;
case EXT2_HASH_HALF_MD4:
p = name;
while (len > 0) {
- str2hashbuf(p, len, in, 8);
+ str2hashbuf(p, len, in, 8, unsigned_flag);
halfMD4Transform(buf, in);
len -= 32;
p += 32;
@@ -211,10 +233,12 @@ errcode_t ext2fs_dirhash(int version, const char *name, int len,
minor_hash = buf[2];
hash = buf[1];
break;
+ case EXT2_HASH_TEA_UNSIGNED:
+ unsigned_flag++;
case EXT2_HASH_TEA:
p = name;
while (len > 0) {
- str2hashbuf(p, len, in, 4);
+ str2hashbuf(p, len, in, 4, unsigned_flag);
TEA_transform(buf, in);
len -= 16;
p += 16;
diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index 61958d90..0203636c 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -193,9 +193,12 @@ struct ext2_dx_root_info {
__u8 unused_flags;
};
-#define EXT2_HASH_LEGACY 0
-#define EXT2_HASH_HALF_MD4 1
-#define EXT2_HASH_TEA 2
+#define EXT2_HASH_LEGACY 0
+#define EXT2_HASH_HALF_MD4 1
+#define EXT2_HASH_TEA 2
+#define EXT2_HASH_LEGACY_UNSIGNED 3 /* reserved for userspace lib */
+#define EXT2_HASH_HALF_MD4_UNSIGNED 4 /* reserved for userspace lib */
+#define EXT2_HASH_TEA_UNSIGNED 5 /* reserved for userspace lib */
#define EXT2_HASH_FLAG_INCOMPAT 0x1
@@ -449,6 +452,12 @@ struct ext2_inode_large {
#define EXT2_ERROR_FS 0x0002 /* Errors detected */
/*
+ * Misc. filesystem flags
+ */
+#define EXT2_FLAGS_SIGNED_HASH 0x0001 /* Signed dirhash in use */
+#define EXT2_FLAGS_UNSIGNED_HASH 0x0002 /* Unsigned dirhash in use */
+
+/*
* Mount flags
*/
#define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */
@@ -557,7 +566,8 @@ struct ext2_super_block {
__u32 s_free_blocks_hi; /* Free blocks count */
__u16 s_min_extra_isize; /* All inodes have at least # bytes */
__u16 s_want_extra_isize; /* New inodes should reserve # bytes */
- __u32 s_reserved[168]; /* Padding to the end of the block */
+ __u32 s_flags; /* Miscellaneous flags */
+ __u32 s_reserved[167]; /* Padding to the end of the block */
};
/*
diff --git a/lib/ext2fs/initialize.c b/lib/ext2fs/initialize.c
index 98351f8c..9cc3d121 100644
--- a/lib/ext2fs/initialize.c
+++ b/lib/ext2fs/initialize.c
@@ -105,6 +105,7 @@ errcode_t ext2fs_initialize(const char *name, int flags,
int rsv_gdt;
int io_flags;
char *buf;
+ char c;
if (!param || !param->s_blocks_count)
return EXT2_ET_INVALID_ARGUMENT;
@@ -373,6 +374,13 @@ ipg_retry:
fs->group_desc[i].bg_used_dirs_count = 0;
}
+ c = (char) 255;
+ if (((int) c) == -1) {
+ super->s_flags |= EXT2_FLAGS_SIGNED_HASH;
+ } else {
+ super->s_flags |= EXT2_FLAGS_UNSIGNED_HASH;
+ }
+
ext2fs_mark_super_dirty(fs);
ext2fs_mark_bb_dirty(fs);
ext2fs_mark_ib_dirty(fs);
diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
index 54a79252..90ba6f1a 100644
--- a/lib/ext2fs/swapfs.c
+++ b/lib/ext2fs/swapfs.c
@@ -69,6 +69,7 @@ void ext2fs_swap_super(struct ext2_super_block * sb)
sb->s_free_blocks_hi = ext2fs_swab32(sb->s_free_blocks_hi);
sb->s_min_extra_isize = ext2fs_swab16(sb->s_min_extra_isize);
sb->s_want_extra_isize = ext2fs_swab16(sb->s_want_extra_isize);
+ sb->s_flags = ext2fs_swab32(sb->s_flags);
for (i=0; i < 4; i++)
sb->s_hash_seed[i] = ext2fs_swab32(sb->s_hash_seed[i]);
for (i=0; i < 17; i++)
diff --git a/tests/ChangeLog b/tests/ChangeLog
index b21ea95a..a38ded50 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,5 +1,20 @@
2006-11-11 Theodore Tso <tytso@mit.edu>
+ * filter_dumpe2fs: Filter out the filesystem flags field since it
+ will be different for filesystems created with unsigned
+ char types.
+
+ * f_dup_de, f_h_badnode, f_h_badroot, f_h_reindex: Set the
+ directory hash bits so that these images are known to be
+ using the standard signed dirhash algorithm.
+
+ * f_h_normal: Add an 8-bit filename so we can test to make sure the
+ directory hash is working correctly when using the signed
+ dirhash algorithm.
+
+ * f_h_unsigned: New test to test calculating an unsigned directory
+ hash algorithm.
+
* Makefile.in (check-failed): New target which automatically
re-runs any failed tests
diff --git a/tests/f_dup_de/image.gz b/tests/f_dup_de/image.gz
index 152c5911..8bdb12f4 100644
--- a/tests/f_dup_de/image.gz
+++ b/tests/f_dup_de/image.gz
Binary files differ
diff --git a/tests/f_h_badnode/image.gz b/tests/f_h_badnode/image.gz
index a3cf21d2..0ac41db0 100644
--- a/tests/f_h_badnode/image.gz
+++ b/tests/f_h_badnode/image.gz
Binary files differ
diff --git a/tests/f_h_badroot/image.gz b/tests/f_h_badroot/image.gz
index fb8ce001..7160cd57 100644
--- a/tests/f_h_badroot/image.gz
+++ b/tests/f_h_badroot/image.gz
Binary files differ
diff --git a/tests/f_h_normal/expect.1 b/tests/f_h_normal/expect.1
index 96ed2b02..ff7579d6 100644
--- a/tests/f_h_normal/expect.1
+++ b/tests/f_h_normal/expect.1
@@ -3,5 +3,5 @@ Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
-test_filesys: 47729/100192 files (0.0% non-contiguous), 13687/31745 blocks
+test_filesys: 47730/100192 files (0.0% non-contiguous), 13378/31745 blocks
Exit status is 0
diff --git a/tests/f_h_normal/expect.2 b/tests/f_h_normal/expect.2
index 96ed2b02..ff7579d6 100644
--- a/tests/f_h_normal/expect.2
+++ b/tests/f_h_normal/expect.2
@@ -3,5 +3,5 @@ Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
-test_filesys: 47729/100192 files (0.0% non-contiguous), 13687/31745 blocks
+test_filesys: 47730/100192 files (0.0% non-contiguous), 13378/31745 blocks
Exit status is 0
diff --git a/tests/f_h_normal/image.gz b/tests/f_h_normal/image.gz
index c8eb163b..8b4daeee 100644
--- a/tests/f_h_normal/image.gz
+++ b/tests/f_h_normal/image.gz
Binary files differ
diff --git a/tests/f_h_normal/name b/tests/f_h_normal/name
index 900493ff..5190f353 100644
--- a/tests/f_h_normal/name
+++ b/tests/f_h_normal/name
@@ -1 +1 @@
-Normal HTREE directory
+Normal (signed) HTREE directory
diff --git a/tests/f_h_reindex/image.gz b/tests/f_h_reindex/image.gz
index 4a71602b..4aae72f4 100644
--- a/tests/f_h_reindex/image.gz
+++ b/tests/f_h_reindex/image.gz
Binary files differ
diff --git a/tests/f_h_unsigned/expect.1 b/tests/f_h_unsigned/expect.1
new file mode 100644
index 00000000..ff7579d6
--- /dev/null
+++ b/tests/f_h_unsigned/expect.1
@@ -0,0 +1,7 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 47730/100192 files (0.0% non-contiguous), 13378/31745 blocks
+Exit status is 0
diff --git a/tests/f_h_unsigned/expect.2 b/tests/f_h_unsigned/expect.2
new file mode 100644
index 00000000..ff7579d6
--- /dev/null
+++ b/tests/f_h_unsigned/expect.2
@@ -0,0 +1,7 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 47730/100192 files (0.0% non-contiguous), 13378/31745 blocks
+Exit status is 0
diff --git a/tests/f_h_unsigned/image.gz b/tests/f_h_unsigned/image.gz
new file mode 100644
index 00000000..3af9c840
--- /dev/null
+++ b/tests/f_h_unsigned/image.gz
Binary files differ
diff --git a/tests/f_h_unsigned/name b/tests/f_h_unsigned/name
new file mode 100644
index 00000000..16069580
--- /dev/null
+++ b/tests/f_h_unsigned/name
@@ -0,0 +1 @@
+Unsigned HTREE directory
diff --git a/tests/f_h_unsigned/script b/tests/f_h_unsigned/script
new file mode 100644
index 00000000..9eec0840
--- /dev/null
+++ b/tests/f_h_unsigned/script
@@ -0,0 +1,6 @@
+if test "$HTREE"x = yx ; then
+. $cmd_dir/run_e2fsck
+else
+ rm -f $test_name.ok $test_name.failed
+ echo "skipped"
+fi
diff --git a/tests/filter_dumpe2fs b/tests/filter_dumpe2fs
index 0a6e0655..51211f36 100644
--- a/tests/filter_dumpe2fs
+++ b/tests/filter_dumpe2fs
@@ -1,6 +1,7 @@
1s/^.*$//
/^Filesystem UUID:/d
/^Filesystem created:/d
+/^Filesystem flags:/d
/^Last write time:/d
/^Last mount time:/d
/^Last checked:/d