Add HTREE root node tests.
+2002-06-26 Theodore Ts'o <tytso@mit.edu>
+
+ * htree.c (do_dx_hash): Use new ext2fs_dirhash function signature.
+ Add getopt support so user can specify the hash version.
+
2002-05-11 <tytso@snap.thunk.org>
* debug_cmds.ct, debugfs.c (do_bmap): Add new command "bmap" which
static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode *inode,
+ struct ext2_dx_root_info * root,
blk_t blk, char *buf)
{
errcode_t errcode;
(dirent->name_len & 0xFF) : EXT2_NAME_LEN;
strncpy(name, dirent->name, thislen);
name[thislen] = '\0';
- errcode = ext2fs_dirhash(0, name, thislen, &hash);
+ errcode = ext2fs_dirhash(root->hash_version, name, thislen,
+ fs->super->s_hash_seed,
+ &hash, 0);
if (errcode)
com_err("htree_dump_leaf_node", errcode,
"while calculating hash");
static void htree_dump_int_block(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode *inode,
+ struct ext2_dx_root_info * root,
blk_t blk, char *buf, int level);
static void htree_dump_int_node(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode *inode,
+ struct ext2_dx_root_info * root,
struct ext2_dx_entry *ent,
char *buf, int level)
{
fprintf(pager, "Entry #%d: Hash 0x%08x, block %d\n", i,
i ? ent[i].hash : 0, ent[i].block);
if (level)
- htree_dump_int_block(fs, ino, inode,
+ htree_dump_int_block(fs, ino, inode, root,
ent[i].block, buf, level-1);
else
- htree_dump_leaf_node(fs, ino, inode,
+ htree_dump_leaf_node(fs, ino, inode, root,
ent[i].block, buf);
}
static void htree_dump_int_block(ext2_filsys fs, ext2_ino_t ino,
struct ext2_inode *inode,
+ struct ext2_dx_root_info * root,
blk_t blk, char *buf, int level)
{
char *cbuf;
return;
}
- htree_dump_int_node(fs, ino, inode, (struct ext2_dx_entry *) (buf+8),
+ htree_dump_int_node(fs, ino, inode, root,
+ (struct ext2_dx_entry *) (buf+8),
cbuf, level);
free(cbuf);
}
ent = (struct ext2_dx_entry *) (buf + 24 + root->info_length);
limit = (struct ext2_dx_countlimit *) ent;
- htree_dump_int_node(current_fs, ino, &inode, ent,
+ htree_dump_int_node(current_fs, ino, &inode, root, ent,
buf + current_fs->blocksize,
root->indirect_levels);
*/
void do_dx_hash(int argc, char *argv[])
{
- ext2_dirhash_t hash;
+ ext2_dirhash_t hash, minor_hash;
errcode_t err;
+ int c;
+ int hash_version = 0;
+ __u32 hash_seed[4];
- if (argc != 2) {
+ hash_seed[0] = hash_seed[1] = hash_seed[2] = hash_seed[3] = 0;
+ optind = 0;
+#ifdef HAVE_OPTRESET
+ optreset = 1; /* Makes BSD getopt happy */
+#endif
+ while ((c = getopt (argc, argv, "h:")) != EOF) {
+ switch (c) {
+ case 'h':
+ hash_version = atoi(optarg);
+ break;
+ }
+ }
+ if (optind != argc-1) {
com_err(argv[0], 0, "usage: dx_hash filename");
return;
}
- err = ext2fs_dirhash(0, argv[1], strlen(argv[1]), &hash);
+ err = ext2fs_dirhash(hash_version, argv[optind], strlen(argv[optind]),
+ hash_seed, &hash, &minor_hash);
if (err) {
com_err(argv[0], err, "while caclulating hash");
return;
}
- printf("Hash of %s is 0x%0x\n", argv[1], hash);
+ printf("Hash of %s is 0x%0x (minor 0x%0x)\n", argv[optind],
+ hash, minor_hash);
}
/*
+2002-06-26 Theodore Ts'o <tytso@mit.edu>
+
+ * pass1.c (check_blocks): Move htree handling to handle_htree().
+ Factor out calls to ext2fs_write_inode so that it happens
+ if dirty_inode is non-zero.
+ (handle_htree): Add checks for invalid htree root, invalid
+ hash version, invalid hash version, and htree depth too deep.
+
+ * problem.h, problem.c (PR_1_HTREE_NODIR, PR_1_HTREE_BADROOT,
+ PR_1_HTREE_HASHV, PR_1_HTREE_INCOMPAT, PR_1_HTREE_DEPTH):
+ Add new problem codes.
+
+ * pass2.c (parse_int_node): Fix silly typo.
+ (check_dir_block): Change to use new ext2fs_dirhash()
+ function prototype.
+ (pass2): Fixed two minor bugs discovered by the test case:
+ Don't stop checking dxdir's after clearing a bad inode.
+ If there is a bad max hash, make sure the bad_dir flag
+ is set to make sure we try to clear inode.
+
2002-06-25 Theodore Ts'o <tytso@mit.edu>
* e2fsck.c (e2fsck_reset_context): Free the dx_dirinfo structure.
return 0;
}
+/* Returns 1 if bad htree, 0 if OK */
+static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
+ ext2_ino_t ino, struct ext2_inode *inode,
+ char *block_buf)
+{
+ struct ext2_dx_root_info *root;
+ ext2_filsys fs = ctx->fs;
+ errcode_t retval;
+ blk_t blk;
+
+ if ((!LINUX_S_ISDIR(inode->i_mode) &&
+ fix_problem(ctx, PR_1_HTREE_NODIR, pctx)) ||
+ (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
+ fix_problem(ctx, PR_1_HTREE_SET, pctx)))
+ return 1;
+
+ blk = inode->i_block[0];
+ if (((blk == 0) ||
+ (blk < fs->super->s_first_data_block) ||
+ (blk >= fs->super->s_blocks_count)) &&
+ fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
+ return 1;
+
+ retval = io_channel_read_blk(fs->io, blk, 1, block_buf);
+ if (retval && fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
+ return 1;
+
+ /* XXX should check that beginning matches a directory */
+ root = (struct ext2_dx_root_info *) (block_buf + 24);
+
+ if ((root->reserved_zero || root->info_length < 8) &&
+ fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
+ return 1;
+
+ pctx->num = root->hash_version;
+ if ((root->hash_version != EXT2_HASH_LEGACY) &&
+ (root->hash_version != EXT2_HASH_HALF_MD4) &&
+ fix_problem(ctx, PR_1_HTREE_HASHV, pctx))
+ return 1;
+
+ if ((root->unused_flags & EXT2_HASH_FLAG_INCOMPAT) &&
+ fix_problem(ctx, PR_1_HTREE_INCOMPAT, pctx))
+ return 1;
+
+ pctx->num = root->indirect_levels;
+ if ((root->indirect_levels > 1) &&
+ fix_problem(ctx, PR_1_HTREE_DEPTH, pctx))
+ return 1;
+
+ return 0;
+}
/*
* This subroutine is called on each inode to account for all of the
ext2_ino_t ino = pctx->ino;
struct ext2_inode *inode = pctx->inode;
int bad_size = 0;
+ int dirty_inode = 0;
__u64 size;
if (!ext2fs_inode_has_valid_blocks(inode))
else {
if (fix_problem(ctx, PR_1_COMPR_SET, pctx)) {
inode->i_flags &= ~EXT2_COMPRBLK_FL;
- e2fsck_write_inode(ctx, ino, inode,
- "check_blocks");
+ dirty_inode++;
}
}
}
pb.is_dir ? BLOCK_FLAG_HOLE : 0,
block_buf, process_block, &pb);
if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
- return;
+ goto out;
end_problem_latch(ctx, PR_LATCH_BLOCK);
end_problem_latch(ctx, PR_LATCH_TOOBIG);
if (pctx->errcode)
ctx->fs_fragmented++;
if (pb.clear) {
- e2fsck_read_inode(ctx, ino, inode, "check_blocks");
inode->i_links_count = 0;
ext2fs_icount_store(ctx->inode_link_info, ino, 0);
inode->i_dtime = time(0);
- e2fsck_write_inode(ctx, ino, inode, "check_blocks");
+ dirty_inode++;
ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
* restart the pass 1 scan.
*/
ctx->flags |= E2F_FLAG_RESTART;
- return;
+ goto out;
}
if (inode->i_flags & EXT2_INDEX_FL) {
- if (fs->super->s_feature_compat &
- EXT2_FEATURE_COMPAT_DIR_INDEX) {
+ if (handle_htree(ctx, pctx, ino, inode, block_buf)) {
+ inode->i_flags &= ~EXT2_INDEX_FL;
+ dirty_inode++;
+ } else {
#ifdef ENABLE_HTREE
e2fsck_add_dx_dir(ctx, ino, pb.last_block+1);
#endif
- } else {
- if (fix_problem(ctx, PR_1_HTREE_SET, pctx)) {
- inode->i_flags &= ~EXT2_INDEX_FL;
- e2fsck_write_inode(ctx, ino, inode,
- "check_blocks");
- }
- }
+ }
}
-
+
if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf))
pb.num_blocks++;
inode->i_links_count = 0;
ext2fs_icount_store(ctx->inode_link_info, ino, 0);
inode->i_dtime = time(0);
- e2fsck_write_inode(ctx, ino, inode, "check_blocks");
+ dirty_inode++;
ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
inode->i_size = pctx->num;
if (LINUX_S_ISREG(inode->i_mode))
inode->i_size_high = pctx->num >> 32;
- e2fsck_write_inode(ctx, ino, inode, "check_blocks");
+ dirty_inode++;
}
pctx->num = 0;
}
pctx->num = pb.num_blocks;
if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) {
inode->i_blocks = pb.num_blocks;
- e2fsck_write_inode(ctx, ino, inode, "check_blocks");
+ dirty_inode++;
}
pctx->num = 0;
}
+out:
+ if (dirty_inode)
+ e2fsck_write_inode(ctx, ino, inode, "check_blocks");
}
#if 0
p->fragmented = 1;
}
p->previous_block = blk;
-
- if (p->is_dir && blockcnt > 2*1024*1024/fs->blocksize)
+
+ if (p->is_dir && blockcnt > (1 << (15 - fs->super->s_log_block_size)))
problem = PR_1_TOOBIG_DIR;
if (p->is_reg && p->num_blocks+1 >= p->max_blocks)
problem = PR_1_TOOBIG_REG;
pctx.blk2 = dx_db->node_max_hash;
code = PR_2_HTREE_MAX_HASH;
fix_problem(ctx, code, &pctx);
+ bad_dir++;
}
if (!(dx_db->flags & DX_FLAG_REFERENCED)) {
code = PR_2_HTREE_NOTREF;
if (bad_dir && fix_problem(ctx, PR_2_HTREE_CLEAR, &pctx)) {
clear_htree(ctx, dx_dir->ino);
dx_dir->ino = 0;
- break;
}
#ifdef ENABLE_HTREE_CLEAR
if (dx_dir->ino) {
/* Check to make sure the block is valid */
if (blk > dx_dir->numblocks) {
if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK,
- cd->pctx)) {
+ &cd->pctx)) {
clear_htree(cd->ctx, cd->pctx.ino);
dx_dir->ino = 0;
return;
#ifdef ENABLE_HTREE
if (dx_db) {
ext2fs_dirhash(dx_dir->hashversion, dirent->name,
- (dirent->name_len & 0xFF), &hash);
+ (dirent->name_len & 0xFF),
+ fs->super->s_hash_seed, &hash, 0);
if (hash < dx_db->min_hash)
dx_db->min_hash = hash;
if (hash > dx_db->max_hash)
#define PROMPT_DELETE 15
#define PROMPT_SUPPRESS 16
#define PROMPT_UNLINK 17
-#define PROMPT_NULL 18
+#define PROMPT_CLEAR_HTREE 18
+#define PROMPT_NULL 19
/*
* These are the prompts which are used to ask the user if they want
N_("Delete file"), /* 15 */
N_("Suppress messages"),/* 16 */
N_("Unlink"), /* 17 */
- "", /* 18 */
+ N_("Clear HTree index"),/* 18 */
+ "", /* 19 */
};
/*
N_("FILE DELETED"), /* 15 */
N_("SUPPRESSED"), /* 16 */
N_("UNLINKED"), /* 17 */
- "", /* 18 */
+ N_("HTREE INDEX CLEARED"),/* 18 */
+ "", /* 19 */
};
static const struct e2fsck_problem problem_table[] = {
/* INDEX_FL flag set on a non-HTREE filesystem */
{ PR_1_HTREE_SET,
N_("@i %i has INDEX_FL flag set on @f without htree support.\n"),
- PROMPT_CLEAR, 0 },
-
+ PROMPT_CLEAR_HTREE, 0 },
+
+ /* INDEX_FL flag set on a non-directory */
+ { PR_1_HTREE_NODIR,
+ N_("@i %i has INDEX_FL flag set but is not a @d.\n"),
+ PROMPT_CLEAR_HTREE, 0 },
+
+ /* Invalid root node in HTREE directory */
+ { PR_1_HTREE_BADROOT,
+ N_("@h %i has an invalid root node.\n"),
+ PROMPT_CLEAR_HTREE, 0 },
+
+ /* Unsupported hash version in HTREE directory */
+ { PR_1_HTREE_HASHV,
+ N_("@h %i has an unsupported hash version (%N)\n"),
+ PROMPT_CLEAR_HTREE, 0 },
+
+ /* Incompatible flag in HTREE root node */
+ { PR_1_HTREE_INCOMPAT,
+ N_("@h %i uses an incompatible htree root node flag.\n"),
+ PROMPT_CLEAR_HTREE, 0 },
+
+ /* HTREE too deep */
+ { PR_1_HTREE_DEPTH,
+ N_("@h %i has a tree depth (%N) which is too big\n"),
+ PROMPT_CLEAR_HTREE, 0 },
+
/* Pass 1b errors */
/* Pass 1B: Rescan for duplicate/bad blocks */
/* Bad block in htree interior node */
{ PR_2_HTREE_BADBLK,
N_("@p @h %d (%q): bad @b number %B.\n"),
- PROMPT_CLEAR, 0 },
+ PROMPT_CLEAR_HTREE, 0 },
/* Pass 3 errors */
/* INDEX_FL flag set on a non-HTREE filesystem */
#define PR_1_HTREE_SET 0x010047
+/* INDEX_FL flag set on a non-directory */
+#define PR_1_HTREE_NODIR 0x010048
+
+/* Invalid root node in HTREE directory */
+#define PR_1_HTREE_BADROOT 0x010049
+
+/* Unsupported hash version in HTREE directory */
+#define PR_1_HTREE_HASHV 0x01004A
+
+/* Incompatible flag in HTREE root node */
+#define PR_1_HTREE_INCOMPAT 0x01004B
+
+/* HTREE too deep */
+#define PR_1_HTREE_DEPTH 0x01004C
+
/*
* Pass 1b errors
*/
+2002-06-26 Theodore Ts'o <tytso@mit.edu>
+
+ * dirhash.c (ext2fs_dirhash): Change function signature to support
+ a hash seed, and to return the minor hash (for 64-bit hash
+ support). Add support for the half MD4, half MD4 with
+ seed, and half MD4 with seed and 64 bits.
+
2002-06-15 Theodore Ts'o <tytso@mit.edu>
* ext2_fs.h (EXT2_DIRSYNC_FL): Add new file.
#include "ext2_fs.h"
#include "ext2fs.h"
+/* F, G and H are basic MD4 functions: selection, majority, parity */
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/*
+ * The generic round function. The application is so specific that
+ * we don't bother protecting all the arguments with parens, as is generally
+ * good macro practice, in favor of extra legibility.
+ * Rotation is separate from addition to prevent recomputation
+ */
+#define ROUND(f, a, b, c, d, x, s) \
+ (a += f(b, c, d) + x, a = (a << s) | (a >> (32-s)))
+#define K1 0
+#define K2 013240474631UL
+#define K3 015666365641UL
+
+/*
+ * Basic cut-down MD4 transform. Returns only 32 bits of result.
+ */
+static __u32 halfMD4Transform (__u32 buf[4], __u32 const in[])
+{
+ __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+ /* Round 1 */
+ ROUND(F, a, b, c, d, in[0] + K1, 3);
+ ROUND(F, d, a, b, c, in[1] + K1, 7);
+ ROUND(F, c, d, a, b, in[2] + K1, 11);
+ ROUND(F, b, c, d, a, in[3] + K1, 19);
+ ROUND(F, a, b, c, d, in[4] + K1, 3);
+ ROUND(F, d, a, b, c, in[5] + K1, 7);
+ ROUND(F, c, d, a, b, in[6] + K1, 11);
+ ROUND(F, b, c, d, a, in[7] + K1, 19);
+
+ /* Round 2 */
+ ROUND(G, a, b, c, d, in[1] + K2, 3);
+ ROUND(G, d, a, b, c, in[3] + K2, 5);
+ ROUND(G, c, d, a, b, in[5] + K2, 9);
+ ROUND(G, b, c, d, a, in[7] + K2, 13);
+ ROUND(G, a, b, c, d, in[0] + K2, 3);
+ ROUND(G, d, a, b, c, in[2] + K2, 5);
+ ROUND(G, c, d, a, b, in[4] + K2, 9);
+ ROUND(G, b, c, d, a, in[6] + K2, 13);
+
+ /* Round 3 */
+ ROUND(H, a, b, c, d, in[3] + K3, 3);
+ ROUND(H, d, a, b, c, in[7] + K3, 9);
+ ROUND(H, c, d, a, b, in[2] + K3, 11);
+ ROUND(H, b, c, d, a, in[6] + K3, 15);
+ ROUND(H, a, b, c, d, in[1] + K3, 3);
+ ROUND(H, d, a, b, c, in[5] + K3, 9);
+ ROUND(H, c, d, a, b, in[0] + K3, 11);
+ ROUND(H, b, c, d, a, in[4] + K3, 15);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+
+ return buf[1]; /* "most hashed" word */
+ /* Alternative: return sum of all words? */
+}
+
+#undef ROUND
+#undef F
+#undef G
+#undef H
+#undef K1
+#undef K2
+#undef K3
+
+/* The old legacy hash */
static ext2_dirhash_t dx_hack_hash (const char *name, int len)
{
__u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
* Returns the hash of a filename. If len is 0 and name is NULL, then
* this function can be used to test whether or not a hash version is
* supported.
+ *
+ * The seed is an 4 longword (32 bits) "secret" which can be used to
+ * uniquify a hash. If the seed is all zero's, then some default seed
+ * may be used.
+ *
+ * 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.
*/
errcode_t ext2fs_dirhash(int version, const char *name, int len,
- ext2_dirhash_t *ret_hash)
+ const __u32 seed[4],
+ ext2_dirhash_t *ret_hash,
+ ext2_dirhash_t *ret_minor_hash)
{
__u32 hash;
+ __u32 minor_hash = 0;
+ char *p;
+ int i;
- if (version == 0)
+ /* Check to see if the seed is all zero's */
+ for (i=0; i < 4; i++) {
+ if (seed[i])
+ break;
+ }
+
+ if (version == EXT2_HASH_LEGACY)
hash = dx_hack_hash(name, len);
- else {
+ else if ((version == EXT2_HASH_HALF_MD4) ||
+ (version == EXT2_HASH_HALF_MD4_SEED) ||
+ (version == EXT2_HASH_HALF_MD4_64)) {
+ char in[32];
+ __u32 buf[4];
+
+ if ((i == 4) || (version == EXT2_HASH_HALF_MD4)) {
+ buf[0] = 0x67452301;
+ buf[1] = 0xefcdab89;
+ buf[2] = 0x98badcfe;
+ buf[3] = 0x10325476;
+ } else
+ memcpy(buf, in, sizeof(buf));
+ while (len) {
+ if (len < 32) {
+ memcpy(in, name, len);
+ memset(in+len, 0, 32-len);
+ hash = halfMD4Transform(buf, (__u32 *) in);
+ break;
+ }
+ hash = halfMD4Transform(buf, (__u32 *) p);
+ len -= 32;
+ p += 32;
+ }
+ if (version == EXT2_HASH_HALF_MD4_64)
+ minor_hash = buf[2];
+ } else {
*ret_hash = 0;
return EXT2_ET_DIRHASH_UNSUPP;
}
*ret_hash = hash;
+ if (ret_minor_hash)
+ *ret_minor_hash = minor_hash;
return 0;
}
+
+
+
__u8 unused_flags;
};
+#define EXT2_HASH_LEGACY 0
+#define EXT2_HASH_HALF_MD4 1
+#define EXT2_HASH_HALF_MD4_SEED 2
+#define EXT2_HASH_HALF_MD4_64 3 /* SEED & 64 */
+
+#define EXT2_HASH_FLAG_INCOMPAT 0x1
+
struct ext2_dx_entry {
__u32 hash;
__u32 block;
__u32 s_journal_inum; /* inode number of journal file */
__u32 s_journal_dev; /* device number of journal file */
__u32 s_last_orphan; /* start of list of inodes to delete */
-
- __u32 s_reserved[197]; /* Padding to the end of the block */
+ __u32 s_hash_seed[4]; /* HTREE hash */
+ __u32 s_reserved[193]; /* Padding to the end of the block */
};
/*
/* dirhash.c */
extern errcode_t ext2fs_dirhash(int version, const char *name, int len,
- ext2_dirhash_t *ret_hash);
+ const __u32 seed[4],
+ ext2_dirhash_t *ret_hash,
+ ext2_dirhash_t *ret_minor_hash);
/* dir_iterate.c */
+2002-06-26 Theodore Ts'o <tytso@mit.edu>
+
+ * f_h_badroot: New test cases to test bogus HTREE node values
+
2002-06-25 Theodore Ts'o <tytso@mit.edu>
* Makefile.in (test_script): Add pass in the state of
--- /dev/null
+Pass 1: Checking inodes, blocks, and sizes
+HTREE directory inode 13345 has an invalid root node.
+Clear HTree index? yes
+
+HTREE directory inode 26689 has an unsupported hash version (240)
+Clear HTree index? yes
+
+HTREE directory inode 40033 has an invalid root node.
+Clear HTree index? yes
+
+HTREE directory inode 53377 has a tree depth (8) which is too big
+Clear HTree index? yes
+
+HTREE directory inode 66721 uses an incompatible htree root node flag.
+Clear HTree index? yes
+
+Pass 2: Checking directory structure
+Problem in HTREE directory inode 73393: node (1) has bad min hash
+Problem in HTREE directory inode 73393: node (2) has bad max hash
+Invalid HTREE directory inode 73393 (/test6). Clear? yes
+
+Problem in HTREE directory inode 80065: node (2) has bad max hash
+Problem in HTREE directory inode 80065: node (7) has bad max hash
+Problem in HTREE directory inode 80065: node (21) has bad max hash
+Invalid HTREE directory inode 80065 (/test7). Clear? yes
+
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 1719/100080 files (0.0% non-contiguous), 12611/15361 blocks
+Exit status is 1
--- /dev/null
+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: 1719/100080 files (0.0% non-contiguous), 12611/15361 blocks
+Exit status is 0
--- /dev/null
+bad htree root nodes
--- /dev/null
+if test "$HTREE"x = yx -a "$HTREE_CLR"x = x; then
+. $cmd_dir/run_e2fsck
+else
+ rm -f $test_name.ok $test_name.failed
+ echo "skipped"
+fi
+++ /dev/null
-if test "$HTREE"x = yx ; then
-. $cmd_dir/run_e2fsck
-fi