security/nss/lib/base/hash.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /*
michael@0 6 * hash.c
michael@0 7 *
michael@0 8 * This is merely a couple wrappers around NSPR's PLHashTable, using
michael@0 9 * the identity hash and arena-aware allocators.
michael@0 10 * This is a copy of ckfw/hash.c, with modifications to use NSS types
michael@0 11 * (not Cryptoki types). Would like for this to be a single implementation,
michael@0 12 * but doesn't seem like it will work.
michael@0 13 */
michael@0 14
michael@0 15 #ifndef BASE_H
michael@0 16 #include "base.h"
michael@0 17 #endif /* BASE_H */
michael@0 18
michael@0 19 #include "prbit.h"
michael@0 20
michael@0 21 /*
michael@0 22 * nssHash
michael@0 23 *
michael@0 24 * nssHash_Create
michael@0 25 * nssHash_Destroy
michael@0 26 * nssHash_Add
michael@0 27 * nssHash_Remove
michael@0 28 * nssHash_Count
michael@0 29 * nssHash_Exists
michael@0 30 * nssHash_Lookup
michael@0 31 * nssHash_Iterate
michael@0 32 */
michael@0 33
michael@0 34 struct nssHashStr {
michael@0 35 NSSArena *arena;
michael@0 36 PRBool i_alloced_arena;
michael@0 37 PRLock *mutex;
michael@0 38
michael@0 39 /*
michael@0 40 * The invariant that mutex protects is:
michael@0 41 * The count accurately reflects the hashtable state.
michael@0 42 */
michael@0 43
michael@0 44 PLHashTable *plHashTable;
michael@0 45 PRUint32 count;
michael@0 46 };
michael@0 47
michael@0 48 static PLHashNumber
michael@0 49 nss_identity_hash
michael@0 50 (
michael@0 51 const void *key
michael@0 52 )
michael@0 53 {
michael@0 54 PRUint32 i = (PRUint32)key;
michael@0 55 PR_ASSERT(sizeof(PLHashNumber) == sizeof(PRUint32));
michael@0 56 return (PLHashNumber)i;
michael@0 57 }
michael@0 58
michael@0 59 static PLHashNumber
michael@0 60 nss_item_hash
michael@0 61 (
michael@0 62 const void *key
michael@0 63 )
michael@0 64 {
michael@0 65 unsigned int i;
michael@0 66 PLHashNumber h;
michael@0 67 NSSItem *it = (NSSItem *)key;
michael@0 68 h = 0;
michael@0 69 for (i=0; i<it->size; i++)
michael@0 70 h = PR_ROTATE_LEFT32(h, 4) ^ ((unsigned char *)it->data)[i];
michael@0 71 return h;
michael@0 72 }
michael@0 73
michael@0 74 static int
michael@0 75 nss_compare_items(const void *v1, const void *v2)
michael@0 76 {
michael@0 77 PRStatus ignore;
michael@0 78 return (int)nssItem_Equal((NSSItem *)v1, (NSSItem *)v2, &ignore);
michael@0 79 }
michael@0 80
michael@0 81 /*
michael@0 82 * nssHash_create
michael@0 83 *
michael@0 84 */
michael@0 85 NSS_IMPLEMENT nssHash *
michael@0 86 nssHash_Create
michael@0 87 (
michael@0 88 NSSArena *arenaOpt,
michael@0 89 PRUint32 numBuckets,
michael@0 90 PLHashFunction keyHash,
michael@0 91 PLHashComparator keyCompare,
michael@0 92 PLHashComparator valueCompare
michael@0 93 )
michael@0 94 {
michael@0 95 nssHash *rv;
michael@0 96 NSSArena *arena;
michael@0 97 PRBool i_alloced;
michael@0 98
michael@0 99 #ifdef NSSDEBUG
michael@0 100 if( arenaOpt && PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
michael@0 101 nss_SetError(NSS_ERROR_INVALID_POINTER);
michael@0 102 return (nssHash *)NULL;
michael@0 103 }
michael@0 104 #endif /* NSSDEBUG */
michael@0 105
michael@0 106 if (arenaOpt) {
michael@0 107 arena = arenaOpt;
michael@0 108 i_alloced = PR_FALSE;
michael@0 109 } else {
michael@0 110 arena = nssArena_Create();
michael@0 111 i_alloced = PR_TRUE;
michael@0 112 }
michael@0 113
michael@0 114 rv = nss_ZNEW(arena, nssHash);
michael@0 115 if( (nssHash *)NULL == rv ) {
michael@0 116 goto loser;
michael@0 117 }
michael@0 118
michael@0 119 rv->mutex = PZ_NewLock(nssILockOther);
michael@0 120 if( (PZLock *)NULL == rv->mutex ) {
michael@0 121 goto loser;
michael@0 122 }
michael@0 123
michael@0 124 rv->plHashTable = PL_NewHashTable(numBuckets,
michael@0 125 keyHash, keyCompare, valueCompare,
michael@0 126 &nssArenaHashAllocOps, arena);
michael@0 127 if( (PLHashTable *)NULL == rv->plHashTable ) {
michael@0 128 (void)PZ_DestroyLock(rv->mutex);
michael@0 129 goto loser;
michael@0 130 }
michael@0 131
michael@0 132 rv->count = 0;
michael@0 133 rv->arena = arena;
michael@0 134 rv->i_alloced_arena = i_alloced;
michael@0 135
michael@0 136 return rv;
michael@0 137 loser:
michael@0 138 (void)nss_ZFreeIf(rv);
michael@0 139 return (nssHash *)NULL;
michael@0 140 }
michael@0 141
michael@0 142 /*
michael@0 143 * nssHash_CreatePointer
michael@0 144 *
michael@0 145 */
michael@0 146 NSS_IMPLEMENT nssHash *
michael@0 147 nssHash_CreatePointer
michael@0 148 (
michael@0 149 NSSArena *arenaOpt,
michael@0 150 PRUint32 numBuckets
michael@0 151 )
michael@0 152 {
michael@0 153 return nssHash_Create(arenaOpt, numBuckets,
michael@0 154 nss_identity_hash, PL_CompareValues, PL_CompareValues);
michael@0 155 }
michael@0 156
michael@0 157 /*
michael@0 158 * nssHash_CreateString
michael@0 159 *
michael@0 160 */
michael@0 161 NSS_IMPLEMENT nssHash *
michael@0 162 nssHash_CreateString
michael@0 163 (
michael@0 164 NSSArena *arenaOpt,
michael@0 165 PRUint32 numBuckets
michael@0 166 )
michael@0 167 {
michael@0 168 return nssHash_Create(arenaOpt, numBuckets,
michael@0 169 PL_HashString, PL_CompareStrings, PL_CompareStrings);
michael@0 170 }
michael@0 171
michael@0 172 /*
michael@0 173 * nssHash_CreateItem
michael@0 174 *
michael@0 175 */
michael@0 176 NSS_IMPLEMENT nssHash *
michael@0 177 nssHash_CreateItem
michael@0 178 (
michael@0 179 NSSArena *arenaOpt,
michael@0 180 PRUint32 numBuckets
michael@0 181 )
michael@0 182 {
michael@0 183 return nssHash_Create(arenaOpt, numBuckets,
michael@0 184 nss_item_hash, nss_compare_items, PL_CompareValues);
michael@0 185 }
michael@0 186
michael@0 187 /*
michael@0 188 * nssHash_Destroy
michael@0 189 *
michael@0 190 */
michael@0 191 NSS_IMPLEMENT void
michael@0 192 nssHash_Destroy
michael@0 193 (
michael@0 194 nssHash *hash
michael@0 195 )
michael@0 196 {
michael@0 197 (void)PZ_DestroyLock(hash->mutex);
michael@0 198 PL_HashTableDestroy(hash->plHashTable);
michael@0 199 if (hash->i_alloced_arena) {
michael@0 200 nssArena_Destroy(hash->arena);
michael@0 201 } else {
michael@0 202 nss_ZFreeIf(hash);
michael@0 203 }
michael@0 204 }
michael@0 205
michael@0 206 /*
michael@0 207 * nssHash_Add
michael@0 208 *
michael@0 209 */
michael@0 210 NSS_IMPLEMENT PRStatus
michael@0 211 nssHash_Add
michael@0 212 (
michael@0 213 nssHash *hash,
michael@0 214 const void *key,
michael@0 215 const void *value
michael@0 216 )
michael@0 217 {
michael@0 218 PRStatus error = PR_FAILURE;
michael@0 219 PLHashEntry *he;
michael@0 220
michael@0 221 PZ_Lock(hash->mutex);
michael@0 222
michael@0 223 he = PL_HashTableAdd(hash->plHashTable, key, (void *)value);
michael@0 224 if( (PLHashEntry *)NULL == he ) {
michael@0 225 nss_SetError(NSS_ERROR_NO_MEMORY);
michael@0 226 } else if (he->value != value) {
michael@0 227 nss_SetError(NSS_ERROR_HASH_COLLISION);
michael@0 228 } else {
michael@0 229 hash->count++;
michael@0 230 error = PR_SUCCESS;
michael@0 231 }
michael@0 232
michael@0 233 (void)PZ_Unlock(hash->mutex);
michael@0 234
michael@0 235 return error;
michael@0 236 }
michael@0 237
michael@0 238 /*
michael@0 239 * nssHash_Remove
michael@0 240 *
michael@0 241 */
michael@0 242 NSS_IMPLEMENT void
michael@0 243 nssHash_Remove
michael@0 244 (
michael@0 245 nssHash *hash,
michael@0 246 const void *it
michael@0 247 )
michael@0 248 {
michael@0 249 PRBool found;
michael@0 250
michael@0 251 PZ_Lock(hash->mutex);
michael@0 252
michael@0 253 found = PL_HashTableRemove(hash->plHashTable, it);
michael@0 254 if( found ) {
michael@0 255 hash->count--;
michael@0 256 }
michael@0 257
michael@0 258 (void)PZ_Unlock(hash->mutex);
michael@0 259 return;
michael@0 260 }
michael@0 261
michael@0 262 /*
michael@0 263 * nssHash_Count
michael@0 264 *
michael@0 265 */
michael@0 266 NSS_IMPLEMENT PRUint32
michael@0 267 nssHash_Count
michael@0 268 (
michael@0 269 nssHash *hash
michael@0 270 )
michael@0 271 {
michael@0 272 PRUint32 count;
michael@0 273
michael@0 274 PZ_Lock(hash->mutex);
michael@0 275
michael@0 276 count = hash->count;
michael@0 277
michael@0 278 (void)PZ_Unlock(hash->mutex);
michael@0 279
michael@0 280 return count;
michael@0 281 }
michael@0 282
michael@0 283 /*
michael@0 284 * nssHash_Exists
michael@0 285 *
michael@0 286 */
michael@0 287 NSS_IMPLEMENT PRBool
michael@0 288 nssHash_Exists
michael@0 289 (
michael@0 290 nssHash *hash,
michael@0 291 const void *it
michael@0 292 )
michael@0 293 {
michael@0 294 void *value;
michael@0 295
michael@0 296 PZ_Lock(hash->mutex);
michael@0 297
michael@0 298 value = PL_HashTableLookup(hash->plHashTable, it);
michael@0 299
michael@0 300 (void)PZ_Unlock(hash->mutex);
michael@0 301
michael@0 302 if( (void *)NULL == value ) {
michael@0 303 return PR_FALSE;
michael@0 304 } else {
michael@0 305 return PR_TRUE;
michael@0 306 }
michael@0 307 }
michael@0 308
michael@0 309 /*
michael@0 310 * nssHash_Lookup
michael@0 311 *
michael@0 312 */
michael@0 313 NSS_IMPLEMENT void *
michael@0 314 nssHash_Lookup
michael@0 315 (
michael@0 316 nssHash *hash,
michael@0 317 const void *it
michael@0 318 )
michael@0 319 {
michael@0 320 void *rv;
michael@0 321
michael@0 322 PZ_Lock(hash->mutex);
michael@0 323
michael@0 324 rv = PL_HashTableLookup(hash->plHashTable, it);
michael@0 325
michael@0 326 (void)PZ_Unlock(hash->mutex);
michael@0 327
michael@0 328 return rv;
michael@0 329 }
michael@0 330
michael@0 331 struct arg_str {
michael@0 332 nssHashIterator fcn;
michael@0 333 void *closure;
michael@0 334 };
michael@0 335
michael@0 336 static PRIntn
michael@0 337 nss_hash_enumerator
michael@0 338 (
michael@0 339 PLHashEntry *he,
michael@0 340 PRIntn index,
michael@0 341 void *arg
michael@0 342 )
michael@0 343 {
michael@0 344 struct arg_str *as = (struct arg_str *)arg;
michael@0 345 as->fcn(he->key, he->value, as->closure);
michael@0 346 return HT_ENUMERATE_NEXT;
michael@0 347 }
michael@0 348
michael@0 349 /*
michael@0 350 * nssHash_Iterate
michael@0 351 *
michael@0 352 * NOTE that the iteration function will be called with the hashtable locked.
michael@0 353 */
michael@0 354 NSS_IMPLEMENT void
michael@0 355 nssHash_Iterate
michael@0 356 (
michael@0 357 nssHash *hash,
michael@0 358 nssHashIterator fcn,
michael@0 359 void *closure
michael@0 360 )
michael@0 361 {
michael@0 362 struct arg_str as;
michael@0 363 as.fcn = fcn;
michael@0 364 as.closure = closure;
michael@0 365
michael@0 366 PZ_Lock(hash->mutex);
michael@0 367
michael@0 368 PL_HashTableEnumerateEntries(hash->plHashTable, nss_hash_enumerator, &as);
michael@0 369
michael@0 370 (void)PZ_Unlock(hash->mutex);
michael@0 371
michael@0 372 return;
michael@0 373 }

mercurial