diff options
Diffstat (limited to 'fs/btrfs/hash.c')
| -rw-r--r-- | fs/btrfs/hash.c | 86 | 
1 files changed, 86 insertions, 0 deletions
diff --git a/fs/btrfs/hash.c b/fs/btrfs/hash.c new file mode 100644 index 00000000000..92c37eece1f --- /dev/null +++ b/fs/btrfs/hash.c @@ -0,0 +1,86 @@ +/* + *  Original copy from: + *  linux/fs/ext3/hash.c + * + * Copyright (C) 2002 by Theodore Ts'o + * + * This file is released under the GPL v2. + * + * This file may be redistributed under the terms of the GNU Public + * License. + */ + +#include "kerncompat.h" +#define DELTA 0x9E3779B9 + +static void TEA_transform(__u32 buf[2], __u32 const in[]) +{ +	__u32	sum = 0; +	__u32	b0 = buf[0], b1 = buf[1]; +	__u32	a = in[0], b = in[1], c = in[2], d = in[3]; +	int	n = 16; + +	do { +		sum += DELTA; +		b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); +		b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); +	} while(--n); + +	buf[0] += b0; +	buf[1] += b1; +} + +static void str2hashbuf(const char *msg, int len, __u32 *buf, int num) +{ +	__u32	pad, val; +	int	i; + +	pad = (__u32)len | ((__u32)len << 8); +	pad |= pad << 16; + +	val = pad; +	if (len > num*4) +		len = num * 4; +	for (i=0; i < len; i++) { +		if ((i % 4) == 0) +			val = pad; +		val = msg[i] + (val << 8); +		if ((i % 4) == 3) { +			*buf++ = val; +			val = pad; +			num--; +		} +	} +	if (--num >= 0) +		*buf++ = val; +	while (--num >= 0) +		*buf++ = pad; +} + +int btrfs_name_hash(const char *name, int len, u64 *hash_result) +{ +	__u32	hash; +	__u32	minor_hash = 0; +	const char	*p; +	__u32		in[8], buf[2]; + +	/* Initialize the default seed for the hash checksum functions */ +	buf[0] = 0x67452301; +	buf[1] = 0xefcdab89; +	buf[2] = 0x98badcfe; +	buf[3] = 0x10325476; + +	p = name; +	while (len > 0) { +		str2hashbuf(p, len, in, 4); +		TEA_transform(buf, in); +		len -= 16; +		p += 16; +	} +	hash = buf[0]; +	minor_hash = buf[1]; +	*hash_result = buf[0]; +	*hash_result <<= 32; +	*hash_result |= buf[1]; +	return 0; +}  |