diff options
author | Theodore Ts'o <tytso@mit.edu> | 2002-06-26 16:52:10 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2002-06-26 16:52:10 -0400 |
commit | 503f9e7f6eb331c5b75d7f1ad126f71bcdcfb4e3 (patch) | |
tree | c1eb5dd60299228866ce95a7e1b46ed29944b059 /lib | |
parent | 8fdc9985c1e2a4467630b33719b7feb281b7b33b (diff) | |
download | e2fsprogs-503f9e7f6eb331c5b75d7f1ad126f71bcdcfb4e3.tar.gz |
Add support for the half-MD4 HTREE hash.
Add HTREE root node tests.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/ext2fs/ChangeLog | 7 | ||||
-rw-r--r-- | lib/ext2fs/dirhash.c | 128 | ||||
-rw-r--r-- | lib/ext2fs/ext2_fs.h | 11 | ||||
-rw-r--r-- | lib/ext2fs/ext2fs.h | 4 |
4 files changed, 144 insertions, 6 deletions
diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog index b84275a5..afe6f95b 100644 --- a/lib/ext2fs/ChangeLog +++ b/lib/ext2fs/ChangeLog @@ -1,3 +1,10 @@ +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. diff --git a/lib/ext2fs/dirhash.c b/lib/ext2fs/dirhash.c index 87e86d94..113d182e 100644 --- a/lib/ext2fs/dirhash.c +++ b/lib/ext2fs/dirhash.c @@ -16,6 +16,78 @@ #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; @@ -33,19 +105,69 @@ static ext2_dirhash_t dx_hack_hash (const char *name, int len) * 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; } + + + diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h index c47b59b4..9e6a9753 100644 --- a/lib/ext2fs/ext2_fs.h +++ b/lib/ext2fs/ext2_fs.h @@ -167,6 +167,13 @@ struct ext2_dx_root_info { __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; @@ -428,8 +435,8 @@ struct ext2_super_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 */ }; /* diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index d6e91947..2763e682 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -612,7 +612,9 @@ extern errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t 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 */ |