2018-05-14 14:16:43 +03:00
/*
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
* Copyright ( C ) 2004 - 2011 Red Hat , Inc . All rights reserved .
*
* This file is part of the device - mapper userspace tools .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v .2 .1 .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2018-06-04 15:22:14 +03:00
# include "device_mapper/misc/dmlib.h"
2018-06-08 15:40:53 +03:00
# include "base/memory/zalloc.h"
2018-06-08 15:54:19 +03:00
# include "hash.h"
2018-05-14 14:16:43 +03:00
struct dm_hash_node {
struct dm_hash_node * next ;
void * data ;
unsigned data_len ;
unsigned keylen ;
char key [ 0 ] ;
} ;
struct dm_hash_table {
unsigned num_nodes ;
unsigned num_slots ;
struct dm_hash_node * * slots ;
} ;
/* Permutation of the Integers 0 through 255 */
static unsigned char _nums [ ] = {
1 , 14 , 110 , 25 , 97 , 174 , 132 , 119 , 138 , 170 , 125 , 118 , 27 , 233 , 140 , 51 ,
87 , 197 , 177 , 107 , 234 , 169 , 56 , 68 , 30 , 7 , 173 , 73 , 188 , 40 , 36 , 65 ,
49 , 213 , 104 , 190 , 57 , 211 , 148 , 223 , 48 , 115 , 15 , 2 , 67 , 186 , 210 , 28 ,
12 , 181 , 103 , 70 , 22 , 58 , 75 , 78 , 183 , 167 , 238 , 157 , 124 , 147 , 172 ,
144 ,
176 , 161 , 141 , 86 , 60 , 66 , 128 , 83 , 156 , 241 , 79 , 46 , 168 , 198 , 41 , 254 ,
178 , 85 , 253 , 237 , 250 , 154 , 133 , 88 , 35 , 206 , 95 , 116 , 252 , 192 , 54 ,
221 ,
102 , 218 , 255 , 240 , 82 , 106 , 158 , 201 , 61 , 3 , 89 , 9 , 42 , 155 , 159 , 93 ,
166 , 80 , 50 , 34 , 175 , 195 , 100 , 99 , 26 , 150 , 16 , 145 , 4 , 33 , 8 , 189 ,
121 , 64 , 77 , 72 , 208 , 245 , 130 , 122 , 143 , 55 , 105 , 134 , 29 , 164 , 185 ,
194 ,
193 , 239 , 101 , 242 , 5 , 171 , 126 , 11 , 74 , 59 , 137 , 228 , 108 , 191 , 232 ,
139 ,
6 , 24 , 81 , 20 , 127 , 17 , 91 , 92 , 251 , 151 , 225 , 207 , 21 , 98 , 113 , 112 ,
84 , 226 , 18 , 214 , 199 , 187 , 13 , 32 , 94 , 220 , 224 , 212 , 247 , 204 , 196 ,
43 ,
249 , 236 , 45 , 244 , 111 , 182 , 153 , 136 , 129 , 90 , 217 , 202 , 19 , 165 , 231 ,
71 ,
230 , 142 , 96 , 227 , 62 , 179 , 246 , 114 , 162 , 53 , 160 , 215 , 205 , 180 , 47 ,
109 ,
44 , 38 , 31 , 149 , 135 , 0 , 216 , 52 , 63 , 23 , 37 , 69 , 39 , 117 , 146 , 184 ,
163 , 200 , 222 , 235 , 248 , 243 , 219 , 10 , 152 , 131 , 123 , 229 , 203 , 76 , 120 ,
209
} ;
static struct dm_hash_node * _create_node ( const char * str , unsigned len )
{
2018-06-08 15:40:53 +03:00
struct dm_hash_node * n = malloc ( sizeof ( * n ) + len ) ;
2018-05-14 14:16:43 +03:00
if ( n ) {
memcpy ( n - > key , str , len ) ;
n - > keylen = len ;
}
return n ;
}
static unsigned long _hash ( const char * str , unsigned len )
{
unsigned long h = 0 , g ;
unsigned i ;
for ( i = 0 ; i < len ; i + + ) {
h < < = 4 ;
h + = _nums [ ( unsigned char ) * str + + ] ;
g = h & ( ( unsigned long ) 0xf < < 16u ) ;
if ( g ) {
h ^ = g > > 16u ;
h ^ = g > > 5u ;
}
}
return h ;
}
struct dm_hash_table * dm_hash_create ( unsigned size_hint )
{
size_t len ;
unsigned new_size = 16u ;
2018-06-08 15:40:53 +03:00
struct dm_hash_table * hc = zalloc ( sizeof ( * hc ) ) ;
2018-05-14 14:16:43 +03:00
if ( ! hc )
return_0 ;
/* round size hint up to a power of two */
while ( new_size < size_hint )
new_size = new_size < < 1 ;
hc - > num_slots = new_size ;
len = sizeof ( * ( hc - > slots ) ) * new_size ;
2018-06-08 15:40:53 +03:00
if ( ! ( hc - > slots = zalloc ( len ) ) )
2018-05-14 14:16:43 +03:00
goto_bad ;
return hc ;
bad :
2018-06-08 15:40:53 +03:00
free ( hc - > slots ) ;
free ( hc ) ;
2018-05-14 14:16:43 +03:00
return 0 ;
}
static void _free_nodes ( struct dm_hash_table * t )
{
struct dm_hash_node * c , * n ;
unsigned i ;
for ( i = 0 ; i < t - > num_slots ; i + + )
for ( c = t - > slots [ i ] ; c ; c = n ) {
n = c - > next ;
2018-06-08 15:40:53 +03:00
free ( c ) ;
2018-05-14 14:16:43 +03:00
}
}
void dm_hash_destroy ( struct dm_hash_table * t )
{
_free_nodes ( t ) ;
2018-06-08 15:40:53 +03:00
free ( t - > slots ) ;
free ( t ) ;
2018-05-14 14:16:43 +03:00
}
static struct dm_hash_node * * _find ( struct dm_hash_table * t , const void * key ,
uint32_t len )
{
unsigned h = _hash ( key , len ) & ( t - > num_slots - 1 ) ;
struct dm_hash_node * * c ;
for ( c = & t - > slots [ h ] ; * c ; c = & ( ( * c ) - > next ) ) {
if ( ( * c ) - > keylen ! = len )
continue ;
if ( ! memcmp ( key , ( * c ) - > key , len ) )
break ;
}
return c ;
}
void * dm_hash_lookup_binary ( struct dm_hash_table * t , const void * key ,
uint32_t len )
{
struct dm_hash_node * * c = _find ( t , key , len ) ;
return * c ? ( * c ) - > data : 0 ;
}
int dm_hash_insert_binary ( struct dm_hash_table * t , const void * key ,
uint32_t len , void * data )
{
struct dm_hash_node * * c = _find ( t , key , len ) ;
if ( * c )
( * c ) - > data = data ;
else {
struct dm_hash_node * n = _create_node ( key , len ) ;
if ( ! n )
return 0 ;
n - > data = data ;
n - > next = 0 ;
* c = n ;
t - > num_nodes + + ;
}
return 1 ;
}
void dm_hash_remove_binary ( struct dm_hash_table * t , const void * key ,
uint32_t len )
{
struct dm_hash_node * * c = _find ( t , key , len ) ;
if ( * c ) {
struct dm_hash_node * old = * c ;
* c = ( * c ) - > next ;
2018-06-08 15:40:53 +03:00
free ( old ) ;
2018-05-14 14:16:43 +03:00
t - > num_nodes - - ;
}
}
void * dm_hash_lookup ( struct dm_hash_table * t , const char * key )
{
return dm_hash_lookup_binary ( t , key , strlen ( key ) + 1 ) ;
}
int dm_hash_insert ( struct dm_hash_table * t , const char * key , void * data )
{
return dm_hash_insert_binary ( t , key , strlen ( key ) + 1 , data ) ;
}
void dm_hash_remove ( struct dm_hash_table * t , const char * key )
{
dm_hash_remove_binary ( t , key , strlen ( key ) + 1 ) ;
}
static struct dm_hash_node * * _find_str_with_val ( struct dm_hash_table * t ,
const void * key , const void * val ,
uint32_t len , uint32_t val_len )
{
struct dm_hash_node * * c ;
unsigned h ;
h = _hash ( key , len ) & ( t - > num_slots - 1 ) ;
for ( c = & t - > slots [ h ] ; * c ; c = & ( ( * c ) - > next ) ) {
if ( ( * c ) - > keylen ! = len )
continue ;
if ( ! memcmp ( key , ( * c ) - > key , len ) & & ( * c ) - > data ) {
if ( ( ( * c ) - > data_len = = val_len ) & &
! memcmp ( val , ( * c ) - > data , val_len ) )
return c ;
}
}
return NULL ;
}
int dm_hash_insert_allow_multiple ( struct dm_hash_table * t , const char * key ,
const void * val , uint32_t val_len )
{
struct dm_hash_node * n ;
struct dm_hash_node * first ;
int len = strlen ( key ) + 1 ;
unsigned h ;
n = _create_node ( key , len ) ;
if ( ! n )
return 0 ;
n - > data = ( void * ) val ;
n - > data_len = val_len ;
h = _hash ( key , len ) & ( t - > num_slots - 1 ) ;
first = t - > slots [ h ] ;
if ( first )
n - > next = first ;
else
n - > next = 0 ;
t - > slots [ h ] = n ;
t - > num_nodes + + ;
return 1 ;
}
/*
* Look through multiple entries with the same key for one that has a
* matching val and return that . If none have maching val , return NULL .
*/
void * dm_hash_lookup_with_val ( struct dm_hash_table * t , const char * key ,
const void * val , uint32_t val_len )
{
struct dm_hash_node * * c ;
c = _find_str_with_val ( t , key , val , strlen ( key ) + 1 , val_len ) ;
return ( c & & * c ) ? ( * c ) - > data : 0 ;
}
/*
* Look through multiple entries with the same key for one that has a
* matching val and remove that .
*/
void dm_hash_remove_with_val ( struct dm_hash_table * t , const char * key ,
const void * val , uint32_t val_len )
{
struct dm_hash_node * * c ;
c = _find_str_with_val ( t , key , val , strlen ( key ) + 1 , val_len ) ;
if ( c & & * c ) {
struct dm_hash_node * old = * c ;
* c = ( * c ) - > next ;
2018-06-08 15:40:53 +03:00
free ( old ) ;
2018-05-14 14:16:43 +03:00
t - > num_nodes - - ;
}
}
/*
* Look up the value for a key and count how many
* entries have the same key .
*
* If no entries have key , return NULL and set count to 0.
*
* If one entry has the key , the function returns the val ,
* and sets count to 1.
*
* If N entries have the key , the function returns the val
* from the first entry , and sets count to N .
*/
void * dm_hash_lookup_with_count ( struct dm_hash_table * t , const char * key , int * count )
{
struct dm_hash_node * * c ;
struct dm_hash_node * * c1 = NULL ;
uint32_t len = strlen ( key ) + 1 ;
unsigned h ;
* count = 0 ;
h = _hash ( key , len ) & ( t - > num_slots - 1 ) ;
for ( c = & t - > slots [ h ] ; * c ; c = & ( ( * c ) - > next ) ) {
if ( ( * c ) - > keylen ! = len )
continue ;
if ( ! memcmp ( key , ( * c ) - > key , len ) ) {
( * count ) + + ;
if ( ! c1 )
c1 = c ;
}
}
if ( ! c1 )
return NULL ;
else
return * c1 ? ( * c1 ) - > data : 0 ;
}
unsigned dm_hash_get_num_entries ( struct dm_hash_table * t )
{
return t - > num_nodes ;
}
void dm_hash_iter ( struct dm_hash_table * t , dm_hash_iterate_fn f )
{
struct dm_hash_node * c , * n ;
unsigned i ;
for ( i = 0 ; i < t - > num_slots ; i + + )
for ( c = t - > slots [ i ] ; c ; c = n ) {
n = c - > next ;
f ( c - > data ) ;
}
}
void dm_hash_wipe ( struct dm_hash_table * t )
{
_free_nodes ( t ) ;
memset ( t - > slots , 0 , sizeof ( struct dm_hash_node * ) * t - > num_slots ) ;
t - > num_nodes = 0u ;
}
char * dm_hash_get_key ( struct dm_hash_table * t __attribute__ ( ( unused ) ) ,
struct dm_hash_node * n )
{
return n - > key ;
}
void * dm_hash_get_data ( struct dm_hash_table * t __attribute__ ( ( unused ) ) ,
struct dm_hash_node * n )
{
return n - > data ;
}
static struct dm_hash_node * _next_slot ( struct dm_hash_table * t , unsigned s )
{
struct dm_hash_node * c = NULL ;
unsigned i ;
for ( i = s ; i < t - > num_slots & & ! c ; i + + )
c = t - > slots [ i ] ;
return c ;
}
struct dm_hash_node * dm_hash_get_first ( struct dm_hash_table * t )
{
return _next_slot ( t , 0 ) ;
}
struct dm_hash_node * dm_hash_get_next ( struct dm_hash_table * t , struct dm_hash_node * n )
{
unsigned h = _hash ( n - > key , n - > keylen ) & ( t - > num_slots - 1 ) ;
return n - > next ? n - > next : _next_slot ( t , h + 1 ) ;
}