STATIC void free_hash_table(hashtable *ht) { hashelem *hp, *thp; hp = ht->first; while(hp != NULL) { thp = hp; hp = hp->nextelem; free_hash_item(&thp); } free(ht->table); free(ht); }
int filehash_get(const unsigned char *path, unsigned char *val) { unsigned long p_hash; unsigned int idx, i, min_i; struct hash_entry *p, *q; FILE *f = 0; unsigned min_tick; ASSERT(path); p_hash = get_hash(path); idx = p_hash % HASH_SIZE; while (hash_table[idx] && hash_table[idx]->path_hash == p_hash && strcmp(hash_table[idx]->path, path) != 0) { idx = (idx + HASH_STEP) % HASH_SIZE; } if (hash_table[idx] && hash_table[idx]->path_hash == p_hash) { // hit! if (!file_stamp_is_updated(path, hash_table[idx]->stamp)) { info("entry <%s> is in hash table and is not changed", path); memcpy(val, hash_table[idx]->sha1_hash, SHA1_SIZE); hash_table[idx]->tick = cur_tick++; return 0; } // update the hash code, maybe removing an item info("entry <%s> is in hash table and is CHANGED!", path); hash_table[idx]->stamp = file_stamp_update(path, hash_table[idx]->stamp); if (!hash_table[idx]->stamp || !(f = fopen(path, "rb")) || sha_stream(f, hash_table[idx]->sha1_hash)) { // file no longer exists or I/O error if (f) fclose(f); p = remove_hash_item(idx); free_hash_item(p); hash_use--; return -1; } // recalculate the hash fclose(f); memcpy(val, hash_table[idx]->sha1_hash, SHA1_SIZE); hash_table[idx]->tick = cur_tick++; return 0; } // no entry in the hash table XCALLOC(p, 1); if (!(p->stamp = file_stamp_get(path)) || !(f = fopen(path, "rb")) || sha_stream(f, p->sha1_hash)) { if (f) fclose(f); free_hash_item(p); return -1; } fclose(f); p->path_hash = p_hash; p->path = xstrdup(path); p->tick = cur_tick++; memcpy(val, p->sha1_hash, SHA1_SIZE); if (hash_use < HASH_CAP) { info("entry <%s> is not in the hash table - adding", path); add_hash_item(p); hash_use++; return 0; } // find the least recently used entry and remove it info("entry <%s> is not in the hash table - REPLACING", path); min_i = -1; min_tick = cur_tick; for (i = 0; i < HASH_SIZE; i++) if (hash_table[i] && hash_table[i]->tick < min_tick) { min_i = i; min_tick = hash_table[i]->tick; } ASSERT(min_i >= 0); q = remove_hash_item(min_i); free_hash_item(q); add_hash_item(p); return 0; }