summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2002-06-26 16:52:10 -0400
committerTheodore Ts'o <tytso@mit.edu>2002-06-26 16:52:10 -0400
commit503f9e7f6eb331c5b75d7f1ad126f71bcdcfb4e3 (patch)
treec1eb5dd60299228866ce95a7e1b46ed29944b059 /lib
parent8fdc9985c1e2a4467630b33719b7feb281b7b33b (diff)
downloade2fsprogs-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/ChangeLog7
-rw-r--r--lib/ext2fs/dirhash.c128
-rw-r--r--lib/ext2fs/ext2_fs.h11
-rw-r--r--lib/ext2fs/ext2fs.h4
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 */