Blame view

fs/ext3/hash.c 4.35 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
  /*
   *  linux/fs/ext3/hash.c
   *
   * Copyright (C) 2002 by Theodore Ts'o
   *
   * This file is released under the GPL v2.
ae6ddcc5f   Mingming Cao   [PATCH] ext3 and ...
7
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
11
12
13
   * This file may be redistributed under the terms of the GNU Public
   * License.
   */
  
  #include <linux/fs.h>
  #include <linux/jbd.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  #include <linux/ext3_fs.h>
  #include <linux/cryptohash.h>
  
  #define DELTA 0x9E3779B9
  
  static void TEA_transform(__u32 buf[4], __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;
  }
  
  
  /* The old legacy hash */
5e1f8c9e2   Theodore Ts'o   ext3: Add support...
38
  static __u32 dx_hack_hash_unsigned(const char *name, int len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
  {
5e1f8c9e2   Theodore Ts'o   ext3: Add support...
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
  	__u32 hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
  	const unsigned char *ucp = (const unsigned char *) name;
  
  	while (len--) {
  		hash = hash1 + (hash0 ^ (((int) *ucp++) * 7152373));
  
  		if (hash & 0x80000000)
  			hash -= 0x7fffffff;
  		hash1 = hash0;
  		hash0 = hash;
  	}
  	return hash0 << 1;
  }
  
  static __u32 dx_hack_hash_signed(const char *name, int len)
  {
  	__u32 hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
  	const signed char *scp = (const signed char *) name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  	while (len--) {
5e1f8c9e2   Theodore Ts'o   ext3: Add support...
59
  		hash = hash1 + (hash0 ^ (((int) *scp++) * 7152373));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60

5e1f8c9e2   Theodore Ts'o   ext3: Add support...
61
62
  		if (hash & 0x80000000)
  			hash -= 0x7fffffff;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
65
  		hash1 = hash0;
  		hash0 = hash;
  	}
5e1f8c9e2   Theodore Ts'o   ext3: Add support...
66
  	return hash0 << 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
  }
5e1f8c9e2   Theodore Ts'o   ext3: Add support...
68
  static void str2hashbuf_signed(const char *msg, int len, __u32 *buf, int num)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
  {
  	__u32	pad, val;
  	int	i;
5e1f8c9e2   Theodore Ts'o   ext3: Add support...
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  	const signed char *scp = (const signed char *) msg;
  
  	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 = ((int) scp[i]) + (val << 8);
  		if ((i % 4) == 3) {
  			*buf++ = val;
  			val = pad;
  			num--;
  		}
  	}
  	if (--num >= 0)
  		*buf++ = val;
  	while (--num >= 0)
  		*buf++ = pad;
  }
  
  static void str2hashbuf_unsigned(const char *msg, int len, __u32 *buf, int num)
  {
  	__u32	pad, val;
  	int	i;
  	const unsigned char *ucp = (const unsigned char *) msg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
103
104
105
106
107
108
109
110
  
  	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;
5e1f8c9e2   Theodore Ts'o   ext3: Add support...
111
  		val = ((int) ucp[i]) + (val << 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
  		if ((i % 4) == 3) {
  			*buf++ = val;
  			val = pad;
  			num--;
  		}
  	}
  	if (--num >= 0)
  		*buf++ = val;
  	while (--num >= 0)
  		*buf++ = pad;
  }
  
  /*
   * 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.
ae6ddcc5f   Mingming Cao   [PATCH] ext3 and ...
128
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
131
   * 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.
ae6ddcc5f   Mingming Cao   [PATCH] ext3 and ...
132
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
134
135
136
137
138
139
140
141
142
   * 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.
   */
  int ext3fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo)
  {
  	__u32	hash;
  	__u32	minor_hash = 0;
  	const char	*p;
  	int		i;
e9ad5620b   Dave Kleikamp   [PATCH] ext3: Mor...
143
  	__u32		in[8], buf[4];
5e1f8c9e2   Theodore Ts'o   ext3: Add support...
144
145
  	void		(*str2hashbuf)(const char *, int, __u32 *, int) =
  				str2hashbuf_signed;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
  
  	/* Initialize the default seed for the hash checksum functions */
  	buf[0] = 0x67452301;
  	buf[1] = 0xefcdab89;
  	buf[2] = 0x98badcfe;
  	buf[3] = 0x10325476;
  
  	/* Check to see if the seed is all zero's */
  	if (hinfo->seed) {
  		for (i=0; i < 4; i++) {
  			if (hinfo->seed[i])
  				break;
  		}
  		if (i < 4)
  			memcpy(buf, hinfo->seed, sizeof(buf));
  	}
  
  	switch (hinfo->hash_version) {
5e1f8c9e2   Theodore Ts'o   ext3: Add support...
164
165
166
  	case DX_HASH_LEGACY_UNSIGNED:
  		hash = dx_hack_hash_unsigned(name, len);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  	case DX_HASH_LEGACY:
5e1f8c9e2   Theodore Ts'o   ext3: Add support...
168
  		hash = dx_hack_hash_signed(name, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
  		break;
5e1f8c9e2   Theodore Ts'o   ext3: Add support...
170
171
  	case DX_HASH_HALF_MD4_UNSIGNED:
  		str2hashbuf = str2hashbuf_unsigned;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
173
174
  	case DX_HASH_HALF_MD4:
  		p = name;
  		while (len > 0) {
5e1f8c9e2   Theodore Ts'o   ext3: Add support...
175
  			(*str2hashbuf)(p, len, in, 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
178
179
180
181
182
  			half_md4_transform(buf, in);
  			len -= 32;
  			p += 32;
  		}
  		minor_hash = buf[2];
  		hash = buf[1];
  		break;
5e1f8c9e2   Theodore Ts'o   ext3: Add support...
183
184
  	case DX_HASH_TEA_UNSIGNED:
  		str2hashbuf = str2hashbuf_unsigned;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
187
  	case DX_HASH_TEA:
  		p = name;
  		while (len > 0) {
5e1f8c9e2   Theodore Ts'o   ext3: Add support...
188
  			(*str2hashbuf)(p, len, in, 4);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  			TEA_transform(buf, in);
  			len -= 16;
  			p += 16;
  		}
  		hash = buf[0];
  		minor_hash = buf[1];
  		break;
  	default:
  		hinfo->hash = 0;
  		return -1;
  	}
  	hash = hash & ~1;
  	if (hash == (EXT3_HTREE_EOF << 1))
  		hash = (EXT3_HTREE_EOF-1) << 1;
  	hinfo->hash = hash;
  	hinfo->minor_hash = minor_hash;
  	return 0;
  }