Skip to content

Instantly share code, notes, and snippets.

@RealNeGate
Created May 14, 2021 14:01
Show Gist options
  • Save RealNeGate/6560ebb46e48bbc7405f0ee72347469b to your computer and use it in GitHub Desktop.
Save RealNeGate/6560ebb46e48bbc7405f0ee72347469b to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
enum {
FS_MAGIC_NUMBER = 0x666f6f64,
FS_LATEST_VERSION = 1,
};
#define HAS_HASH_IN_ENTRY 1
typedef struct fsIndexingFile {
FILE* indexing;
FILE* data_blob;
// Header info
struct fsIndexingFileHeader {
uint32_t magic_number;
uint32_t version;
uint32_t num_files;
// string table
uint32_t st_offset;
uint32_t st_length;
// hash table
uint32_t ht_offset;
uint32_t ht_buckets;
uint32_t ht_max_items_per_bucket;
} header;
} fsIndexingFile;
typedef struct fsEntry {
struct {
uint64_t tag, tag_len; // In the string table
uint64_t data_offset, data_length; // In the data blob
#if HAS_HASH_IN_ENTRY
uint64_t hash;
#endif
} file;
const uint8_t* file_cached; // NULL if the entry isn't being cached at the moment
} fsEntry;
static const uint64_t fnv64_prime = 1099511628211L;
static const uint64_t fnv64_offset_basis = 14695981039346656037UL;
uint64_t fsFNV1A(const char* tag) {
uint64_t h = fnv64_offset_basis;
while (*tag) {
h = (h ^ ((uint8_t)*tag)) * fnv64_prime;
tag++;
}
return h;
}
fsEntry fsLookupEntry(const fsIndexingFile* indexing, const char* tag) {
uint64_t hash = fsFNV1A(tag);
uint32_t index = (hash % indexing->header.ht_buckets) * indexing->header.ht_max_items_per_bucket;
#if 0
fsEntry e;
fseek(indexing->indexing, indexing->header.ht_offset + (index * sizeof(e.file)), SEEK_SET);
for (int i = 0; i < indexing->header.ht_max_items_per_bucket; i++) {
fread(&e, sizeof(e[0].file), 1, indexing->indexing);
#if HAS_HASH_IN_ENTRY
// Verify hash
if (e.hash != hash) continue;
#endif
// Verify tag
char* e_tag = alloca(e.file.tag_len+1);
fseek(indexing->indexing, indexing->header.st_offset + e.file.tag, SEEK_SET);
fread(e_tag, e.file.tag_len+1, 1, indexing->indexing);
if (strcmp(e_tag, tag) != 0) continue;
return e;
}
#else
fsEntry e[4];
fseek(indexing->indexing, indexing->header.ht_offset + (index * sizeof(e[0].file)), SEEK_SET);
fread(&e[0], sizeof(e[0].file), indexing->header.ht_max_items_per_bucket, indexing->indexing);
for (int i = 0; i < indexing->header.ht_max_items_per_bucket; i++) {
#if HAS_HASH_IN_ENTRY
// Verify hash
if (e[i].file.hash != hash) continue;
#endif
// Verify tag
char* e_tag = alloca(e[i].file.tag_len+1);
fseek(indexing->indexing, indexing->header.st_offset + e[i].file.tag, SEEK_SET);
fread(e_tag, e[i].file.tag_len+1, 1, indexing->indexing);
if (strcmp(e_tag, tag) != 0) continue;
return e[i];
}
#endif
exit(1);
}
fsIndexingFile fsLoadIndexingFile(FILE* index_file, FILE* data_file) {
fsIndexingFile index;
index.indexing = index_file;
index.data_blob = data_file;
fread(&index.header, sizeof(index.header), 1, index_file);
if (index.header.magic_number != FS_MAGIC_NUMBER) exit(1);
if (index.header.version != FS_LATEST_VERSION) exit(1);
return index;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment