2006-10-11 12:20:50 +04:00
/*
2006-10-11 12:20:53 +04:00
* linux / fs / ext4 / hash . c
2006-10-11 12:20:50 +04:00
*
* 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 <linux/fs.h>
2006-10-11 12:21:01 +04:00
# include <linux/jbd2.h>
2006-10-11 12:20:50 +04:00
# include <linux/cryptohash.h>
2008-04-30 02:13:32 +04:00
# include "ext4.h"
2006-10-11 12:20:50 +04:00
# 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 ) ;
2008-09-09 06:25:24 +04:00
} while ( - - n ) ;
2006-10-11 12:20:50 +04:00
buf [ 0 ] + = b0 ;
buf [ 1 ] + = b1 ;
}
/* The old legacy hash */
2008-10-28 20:21:44 +03:00
static __u32 dx_hack_hash_unsigned ( const char * name , int len )
2006-10-11 12:20:50 +04:00
{
2008-10-28 20:21:44 +03:00
__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 ;
2006-10-11 12:20:50 +04:00
while ( len - - ) {
2008-10-28 20:21:44 +03:00
hash = hash1 + ( hash0 ^ ( ( ( int ) * scp + + ) * 7152373 ) ) ;
2006-10-11 12:20:50 +04:00
2008-10-28 20:21:44 +03:00
if ( hash & 0x80000000 )
hash - = 0x7fffffff ;
2006-10-11 12:20:50 +04:00
hash1 = hash0 ;
hash0 = hash ;
}
2008-10-28 20:21:44 +03:00
return hash0 < < 1 ;
}
static void str2hashbuf_signed ( const char * msg , int len , __u32 * buf , int num )
{
__u32 pad , val ;
int i ;
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 ;
2006-10-11 12:20:50 +04:00
}
2008-10-28 20:21:44 +03:00
static void str2hashbuf_unsigned ( const char * msg , int len , __u32 * buf , int num )
2006-10-11 12:20:50 +04:00
{
__u32 pad , val ;
int i ;
2008-10-28 20:21:44 +03:00
const unsigned char * ucp = ( const unsigned char * ) msg ;
2006-10-11 12:20:50 +04:00
pad = ( __u32 ) len | ( ( __u32 ) len < < 8 ) ;
pad | = pad < < 16 ;
val = pad ;
if ( len > num * 4 )
len = num * 4 ;
2008-09-09 06:25:24 +04:00
for ( i = 0 ; i < len ; i + + ) {
2006-10-11 12:20:50 +04:00
if ( ( i % 4 ) = = 0 )
val = pad ;
2008-10-28 20:21:44 +03:00
val = ( ( int ) ucp [ i ] ) + ( val < < 8 ) ;
2006-10-11 12:20:50 +04:00
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 .
*
* 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 .
*/
2006-10-11 12:20:53 +04:00
int ext4fs_dirhash ( const char * name , int len , struct dx_hash_info * hinfo )
2006-10-11 12:20:50 +04:00
{
__u32 hash ;
__u32 minor_hash = 0 ;
const char * p ;
int i ;
__u32 in [ 8 ] , buf [ 4 ] ;
2008-10-28 20:21:44 +03:00
void ( * str2hashbuf ) ( const char * , int , __u32 * , int ) =
str2hashbuf_signed ;
2006-10-11 12:20:50 +04:00
/* 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 ) {
2008-09-09 06:25:24 +04:00
for ( i = 0 ; i < 4 ; i + + ) {
2006-10-11 12:20:50 +04:00
if ( hinfo - > seed [ i ] )
break ;
}
if ( i < 4 )
memcpy ( buf , hinfo - > seed , sizeof ( buf ) ) ;
}
switch ( hinfo - > hash_version ) {
2008-10-28 20:21:44 +03:00
case DX_HASH_LEGACY_UNSIGNED :
hash = dx_hack_hash_unsigned ( name , len ) ;
break ;
2006-10-11 12:20:50 +04:00
case DX_HASH_LEGACY :
2008-10-28 20:21:44 +03:00
hash = dx_hack_hash_signed ( name , len ) ;
2006-10-11 12:20:50 +04:00
break ;
2008-10-28 20:21:44 +03:00
case DX_HASH_HALF_MD4_UNSIGNED :
str2hashbuf = str2hashbuf_unsigned ;
2006-10-11 12:20:50 +04:00
case DX_HASH_HALF_MD4 :
p = name ;
while ( len > 0 ) {
2008-10-28 20:21:44 +03:00
( * str2hashbuf ) ( p , len , in , 8 ) ;
2006-10-11 12:20:50 +04:00
half_md4_transform ( buf , in ) ;
len - = 32 ;
p + = 32 ;
}
minor_hash = buf [ 2 ] ;
hash = buf [ 1 ] ;
break ;
2008-10-28 20:21:44 +03:00
case DX_HASH_TEA_UNSIGNED :
str2hashbuf = str2hashbuf_unsigned ;
2006-10-11 12:20:50 +04:00
case DX_HASH_TEA :
p = name ;
while ( len > 0 ) {
2008-10-28 20:21:44 +03:00
( * str2hashbuf ) ( p , len , in , 4 ) ;
2006-10-11 12:20:50 +04:00
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 ;
2006-10-11 12:20:53 +04:00
if ( hash = = ( EXT4_HTREE_EOF < < 1 ) )
hash = ( EXT4_HTREE_EOF - 1 ) < < 1 ;
2006-10-11 12:20:50 +04:00
hinfo - > hash = hash ;
hinfo - > minor_hash = minor_hash ;
return 0 ;
}