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
+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
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) {
"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);
(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)
{ "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 }
};
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):
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) &&
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 */
/* 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
*/
struct ext2_dir_entry *dirent;
char *dir;
unsigned int offset, dir_offset;
+ int hash_alg;
if (blockcnt < 0)
return 0;
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) {
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);
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;
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);
}
+/*
+ * 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;
*/
e2fsck_fix_ext3_journal_hint(ctx);
+ /*
+ * Add dirhash hint if necessary
+ */
+ e2fsck_fix_dirhash_hint(ctx);
+
return;
}
+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
#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)
} 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);
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
#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;
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;
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;
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;
}
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;
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;
__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
#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */
#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
*/
__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 */
};
/*
int rsv_gdt;
int io_flags;
char *buf;
+ char c;
if (!param || !param->s_blocks_count)
return EXT2_ET_INVALID_ARGUMENT;
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);
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++)
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
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
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
-Normal HTREE directory
+Normal (signed) HTREE directory
--- /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: 47730/100192 files (0.0% non-contiguous), 13378/31745 blocks
+Exit status is 0
--- /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: 47730/100192 files (0.0% non-contiguous), 13378/31745 blocks
+Exit status is 0
--- /dev/null
+Unsigned HTREE directory
--- /dev/null
+if test "$HTREE"x = yx ; then
+. $cmd_dir/run_e2fsck
+else
+ rm -f $test_name.ok $test_name.failed
+ echo "skipped"
+fi
1s/^.*$//
/^Filesystem UUID:/d
/^Filesystem created:/d
+/^Filesystem flags:/d
/^Last write time:/d
/^Last mount time:/d
/^Last checked:/d