Fixed hash table lookups, some error insertions in push_error_no_context
This commit is contained in:
parent
fbcfed79b8
commit
85c0709504
@ -133,7 +133,7 @@ template <typename T> force_inline void maybe_grow (ArenaArray<T>& array) {
|
|||||||
if (array.count >= array.allocated) {
|
if (array.count >= array.allocated) {
|
||||||
s64 reserve = 2 * array.allocated;
|
s64 reserve = 2 * array.allocated;
|
||||||
// if reserve < 8 reserve = 8; // no point doing this because we allocate by page, and we're never realloc'ing
|
// if reserve < 8 reserve = 8; // no point doing this because we allocate by page, and we're never realloc'ing
|
||||||
reserve_internal(array, reserve, sizeof(T));
|
reserve_internal((ArenaArray<u8>&)array, reserve, sizeof(T));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -33,6 +33,7 @@ template <typename T, typename U> bool table_is_valid (ArenaTable<T, U>* table)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// table_release
|
||||||
template <typename T, typename U> void table_init (ArenaTable<T, U>* table, s64 slots_to_allocate=64, Arena_Reserve new_reserve=Arena_Reserve::Size_64M) {
|
template <typename T, typename U> void table_init (ArenaTable<T, U>* table, s64 slots_to_allocate=64, Arena_Reserve new_reserve=Arena_Reserve::Size_64M) {
|
||||||
s64 n = Next_Power_Of_Two(slots_to_allocate);
|
s64 n = Next_Power_Of_Two(slots_to_allocate);
|
||||||
|
|
||||||
|
|||||||
@ -153,6 +153,7 @@ void push_error_no_context (Thread_Context* tctx, Error* new_error) {
|
|||||||
if (new_error == nullptr) return;
|
if (new_error == nullptr) return;
|
||||||
Error* current_error = tctx->current_error;
|
Error* current_error = tctx->current_error;
|
||||||
if (current_error) {
|
if (current_error) {
|
||||||
|
new_error->previous_error = current_error;
|
||||||
current_error->next_error = new_error;
|
current_error->next_error = new_error;
|
||||||
} else {
|
} else {
|
||||||
tctx->first_error = new_error;
|
tctx->first_error = new_error;
|
||||||
|
|||||||
@ -56,6 +56,13 @@ u32 string_hash_function_fnv1a (void* key, s64 size) {
|
|||||||
return (u32)(hash_u64 ^ (hash_u64 >> 32));
|
return (u32)(hash_u64 ^ (hash_u64 >> 32));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool u32_keys_match (void* key1, void* key2) {
|
||||||
|
u32 key1_u32 = *(u32*)key1;
|
||||||
|
u32 key2_u32 = *(u32*)key2;
|
||||||
|
|
||||||
|
return key1_u32 == key2_u32;
|
||||||
|
}
|
||||||
|
|
||||||
bool u64_keys_match (void* key1, void* key2) {
|
bool u64_keys_match (void* key1, void* key2) {
|
||||||
u64 key1_u64 = *(u64*)key1;
|
u64 key1_u64 = *(u64*)key1;
|
||||||
u64 key2_u64 = *(u64*)key2;
|
u64 key2_u64 = *(u64*)key2;
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
// Returns offset
|
// Returns offset
|
||||||
force_inline s32 AddString_NoCount (Serializer* serializer, u8* data, u8 count) { // #TODO: , bool null_terminate=false
|
force_inline u32 AddString_NoCount (Serializer* serializer, u8* data, u8 count) { // #TODO: , bool null_terminate=false
|
||||||
u8* current_point = &serializer->data[serializer->count];
|
u8* current_point = &serializer->data[serializer->count];
|
||||||
s64 final_count = serializer->allocated + (count * sizeof(u8));
|
s64 final_count = serializer->allocated + (count * sizeof(u8));
|
||||||
|
|
||||||
@ -32,6 +32,8 @@ force_inline s32 AddString_NoCount (Serializer* serializer, u8* data, u8 count)
|
|||||||
|
|
||||||
memcpy(current_point, data, count * sizeof(u8));
|
memcpy(current_point, data, count * sizeof(u8));
|
||||||
serializer->count += count * sizeof(u8);
|
serializer->count += count * sizeof(u8);
|
||||||
|
|
||||||
|
return (u32)serializer->count;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr s64 DFS_Preallocation_Count = 4194304; // 2^22
|
constexpr s64 DFS_Preallocation_Count = 4194304; // 2^22
|
||||||
@ -40,15 +42,16 @@ constexpr s64 DFS_Preallocation_Count = 4194304; // 2^22
|
|||||||
struct DFS_Array {
|
struct DFS_Array {
|
||||||
Serializer* strings;
|
Serializer* strings;
|
||||||
|
|
||||||
ArenaArray<u32>* offsets; // offsets into string_arena
|
ArenaArray<u32>* offsets; // offsets into strings->data
|
||||||
ArenaArray<u8>* lengths; // this type may vary <hmmm> Not sure if I should make it a template argument. Seems yucky.
|
ArenaArray<u8>* lengths; // this type may vary <hmmm> Not sure if I should make it a template argument. Seems yucky.
|
||||||
ArenaArray<u64>* modtimes;
|
ArenaArray<u64>* modtimes;
|
||||||
ArenaArray<u64>* sizes;
|
ArenaArray<u64>* sizes;
|
||||||
|
|
||||||
ArenaArray<s32>* parent_indices;
|
ArenaArray<s32>* parent_indices;
|
||||||
|
|
||||||
s64 index; // current index when inserting;
|
// s64 index; // current index when inserting;
|
||||||
|
|
||||||
// #Temporary arrays for linking???
|
// #Temporary arrays for linking files/dirs to their parent directory, if present.
|
||||||
ArenaArray<u32>* record_ids;
|
ArenaArray<u32>* record_ids;
|
||||||
ArenaArray<u32>* parent_ids;
|
ArenaArray<u32>* parent_ids;
|
||||||
|
|
||||||
@ -57,6 +60,10 @@ struct DFS_Array {
|
|||||||
// ArenaArray<s32> indices_sorted_by_size;
|
// ArenaArray<s32> indices_sorted_by_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
s64 item_count (DFS_Array* dfsa) {
|
||||||
|
return dfsa->offsets->count;
|
||||||
|
}
|
||||||
|
|
||||||
void initialize (DFS_Array* dfsa) {
|
void initialize (DFS_Array* dfsa) {
|
||||||
Assert(dfsa != nullptr);
|
Assert(dfsa != nullptr);
|
||||||
dfsa->strings = new_serializer(Arena_Reserve::Size_2G);
|
dfsa->strings = new_serializer(Arena_Reserve::Size_2G);
|
||||||
@ -65,9 +72,12 @@ void initialize (DFS_Array* dfsa) {
|
|||||||
dfsa->lengths = arena_array_new<u8> (DFS_Preallocation_Count, Arena_Reserve::Size_2G);
|
dfsa->lengths = arena_array_new<u8> (DFS_Preallocation_Count, Arena_Reserve::Size_2G);
|
||||||
dfsa->modtimes = arena_array_new<u64>(DFS_Preallocation_Count, Arena_Reserve::Size_2G);
|
dfsa->modtimes = arena_array_new<u64>(DFS_Preallocation_Count, Arena_Reserve::Size_2G);
|
||||||
dfsa->sizes = arena_array_new<u64>(DFS_Preallocation_Count, Arena_Reserve::Size_2G);
|
dfsa->sizes = arena_array_new<u64>(DFS_Preallocation_Count, Arena_Reserve::Size_2G);
|
||||||
dfsa->parent_indices = arena_array_new<s32>(DFS_Preallocation_Count, Arena_Reserve::Size_2G);
|
|
||||||
|
|
||||||
dfsa->index = 0;
|
dfsa->record_ids = arena_array_new<u32>(DFS_Preallocation_Count, Arena_Reserve::Size_2G);
|
||||||
|
dfsa->parent_ids = arena_array_new<u32>(DFS_Preallocation_Count, Arena_Reserve::Size_2G);
|
||||||
|
|
||||||
|
dfsa->parent_indices = arena_array_new<s32>(DFS_Preallocation_Count, Arena_Reserve::Size_2G);
|
||||||
|
// dfsa->index = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Dense_FS { // Link to OS_Drive
|
struct Dense_FS { // Link to OS_Drive
|
||||||
@ -79,9 +89,33 @@ struct Dense_FS { // Link to OS_Drive
|
|||||||
};
|
};
|
||||||
|
|
||||||
void initialize (Dense_FS* dfs, OS_Drive* drive) {
|
void initialize (Dense_FS* dfs, OS_Drive* drive) {
|
||||||
Assert(drive != nullptr);
|
Assert(drive != nullptr); Assert(dfs != nullptr);
|
||||||
|
// Is there a less stupid way of doing this?
|
||||||
dfs->drive = drive;
|
dfs->drive = drive;
|
||||||
|
drive->data = dfs;
|
||||||
initialize(&dfs->paths);
|
initialize(&dfs->paths);
|
||||||
initialize(&dfs->files);
|
initialize(&dfs->files);
|
||||||
table_init(&dfs->path_table, DFS_Preallocation_Count);
|
|
||||||
}
|
table_init(&dfs->path_table, 1048576); // 2^20
|
||||||
|
// dfs->path_table.hash_function = table_hash_function_fnv1a; // default.
|
||||||
|
dfs->path_table.hash_function = sdbm_hash;
|
||||||
|
dfs->path_table.compare_function = u32_keys_match;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 find_previous_index (Dense_FS* dfs, u32 record_id, bool* success) {
|
||||||
|
s32 result = -1;
|
||||||
|
|
||||||
|
(*success) = table_find(&dfs->path_table, record_id, &result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup_after_enumeration(Dense_FS* dfs) {
|
||||||
|
table_release(&dfs->path_table);
|
||||||
|
reset_struct(&dfs->path_table);
|
||||||
|
|
||||||
|
arena_array_free(*dfs->paths.record_ids);
|
||||||
|
arena_array_free(*dfs->paths.parent_ids);
|
||||||
|
arena_array_free(*dfs->files.record_ids);
|
||||||
|
arena_array_free(*dfs->files.parent_ids);
|
||||||
|
}
|
||||||
|
|||||||
@ -97,14 +97,13 @@ struct NTFS_RunHeader {
|
|||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
struct NTFS_File {
|
struct NTFS_File {
|
||||||
u32 parent_id;
|
u32 parent_id;
|
||||||
u32 record_id;
|
u32 record_id;
|
||||||
bool is_directory;
|
|
||||||
u8 name_count;
|
|
||||||
u16* name_data;
|
u16* name_data;
|
||||||
u64 file_modtime; // FILETIME?
|
u64 file_modtime; // FILETIME
|
||||||
u64 file_size;
|
u64 file_size;
|
||||||
string name_utf8;
|
u8 name_count;
|
||||||
|
bool is_directory;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr s64 NTFS_MFT_File_Record_Size = 1024; // File Entry Block
|
constexpr s64 NTFS_MFT_File_Record_Size = 1024; // File Entry Block
|
||||||
@ -121,6 +120,26 @@ struct NTFS_MFT_Internal {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void add_record (Dense_FS* dfs, NTFS_File* file) {
|
||||||
|
DFS_Array* array;
|
||||||
|
if (file->is_directory) {
|
||||||
|
array = &dfs->paths;
|
||||||
|
} else {
|
||||||
|
array = &dfs->files;
|
||||||
|
}
|
||||||
|
|
||||||
|
string s = wide_to_utf8(file->name_data, file->name_count);
|
||||||
|
|
||||||
|
u32 offset = AddString_NoCount(array->strings, s.data, file->name_count);
|
||||||
|
// #TODO: Add other items to arrays:
|
||||||
|
array_add(*array->parent_ids, file->parent_id);
|
||||||
|
array_add(*array->record_ids, file->record_id);
|
||||||
|
array_add(*array->lengths, file->name_count);
|
||||||
|
array_add(*array->offsets, (u32)offset);
|
||||||
|
array_add(*array->modtimes, file->file_modtime);
|
||||||
|
array_add(*array->sizes, file->file_size);
|
||||||
|
}
|
||||||
|
|
||||||
NTFS_MFT_Internal* new_ntfs_mft_internal () { // call with temp
|
NTFS_MFT_Internal* new_ntfs_mft_internal () { // call with temp
|
||||||
NTFS_MFT_Internal* mft = New<NTFS_MFT_Internal>(true);
|
NTFS_MFT_Internal* mft = New<NTFS_MFT_Internal>(true);
|
||||||
mft->mft_file = ArrayView<u8>(NTFS_MFT_File_Record_Size);
|
mft->mft_file = ArrayView<u8>(NTFS_MFT_File_Record_Size);
|
||||||
@ -152,7 +171,7 @@ Error* NTFS_MFT_read_raw (OS_Drive* drive) {
|
|||||||
string drive_path = drive->label;
|
string drive_path = drive->label;
|
||||||
|
|
||||||
Assert(context_allocator() != temp()); // pointless as we're releasing temp end-of-scope
|
Assert(context_allocator() != temp()); // pointless as we're releasing temp end-of-scope
|
||||||
Allocator primary_allocator = context_allocator();
|
// Allocator primary_allocator = context_allocator();
|
||||||
|
|
||||||
auto_release_temp();
|
auto_release_temp();
|
||||||
push_allocator(temp());
|
push_allocator(temp());
|
||||||
@ -170,7 +189,7 @@ Error* NTFS_MFT_read_raw (OS_Drive* drive) {
|
|||||||
|
|
||||||
NTFS_MFT_Internal* mft = new_ntfs_mft_internal();
|
NTFS_MFT_Internal* mft = new_ntfs_mft_internal();
|
||||||
mft->handle = file_handle;
|
mft->handle = file_handle;
|
||||||
push_allocator(primary_allocator);
|
// push_allocator(primary_allocator);
|
||||||
|
|
||||||
bool success;
|
bool success;
|
||||||
NTFS_BootSector boot_sector;
|
NTFS_BootSector boot_sector;
|
||||||
@ -206,8 +225,8 @@ Error* NTFS_MFT_read_raw (OS_Drive* drive) {
|
|||||||
Assert(data_attribute != nullptr);
|
Assert(data_attribute != nullptr);
|
||||||
|
|
||||||
// #dense_fs_alloc
|
// #dense_fs_alloc
|
||||||
Dense_FS* dfs = New<Dense_FS>();
|
drive->data = New<Dense_FS>(GPAllocator());
|
||||||
initialize(dfs, drive);
|
initialize(drive->data, drive);
|
||||||
|
|
||||||
NTFS_RunHeader* dataRun = (NTFS_RunHeader*)((u8*)data_attribute + data_attribute->dataRunsOffset);
|
NTFS_RunHeader* dataRun = (NTFS_RunHeader*)((u8*)data_attribute + data_attribute->dataRunsOffset);
|
||||||
u64 cluster_number = 0, records_processed = 0;
|
u64 cluster_number = 0, records_processed = 0;
|
||||||
@ -269,14 +288,13 @@ Error* NTFS_MFT_read_raw (OS_Drive* drive) {
|
|||||||
if (fileNameAttribute->namespaceType != 2 && !fileNameAttribute->nonResident) {
|
if (fileNameAttribute->namespaceType != 2 && !fileNameAttribute->nonResident) {
|
||||||
file.parent_id = (u32)fileNameAttribute->parentRecordNumber; // truncate
|
file.parent_id = (u32)fileNameAttribute->parentRecordNumber; // truncate
|
||||||
file.record_id = fileRecord->recordNumber;
|
file.record_id = fileRecord->recordNumber;
|
||||||
|
file.is_directory = fileRecord->isDirectory;
|
||||||
file.name_count = fileNameAttribute->fileNameLength;
|
file.name_count = fileNameAttribute->fileNameLength;
|
||||||
file.name_data = (u16*)fileNameAttribute->fileName;
|
file.name_data = (u16*)fileNameAttribute->fileName;
|
||||||
// file.name_utf8 = wide_to_utf8(file.name_data, file.name_count); // @Allocates
|
|
||||||
file.file_modtime = (u64)fileNameAttribute->modificationTime;
|
file.file_modtime = (u64)fileNameAttribute->modificationTime;
|
||||||
file.is_directory = fileRecord->isDirectory;
|
|
||||||
// We need to get size from the data attribute
|
// We need to get size from the data attribute
|
||||||
|
|
||||||
// #TODO: #continue from here!
|
add_record(drive->data, &file);
|
||||||
// See Dense_FS drive->data
|
// See Dense_FS drive->data
|
||||||
mft->file_count += 1;
|
mft->file_count += 1;
|
||||||
}
|
}
|
||||||
@ -297,12 +315,48 @@ Error* NTFS_MFT_read_raw (OS_Drive* drive) {
|
|||||||
|
|
||||||
CloseHandle(file_handle);
|
CloseHandle(file_handle);
|
||||||
|
|
||||||
log_none("Found %lld files (bytes_accessed: %s)", mft->file_count, format_bytes(mft->bytes_accessed).data);
|
log_none("Found %lld files on drive %s (bytes_accessed: %s)", mft->file_count, drive_path.data, format_bytes(mft->bytes_accessed).data);
|
||||||
|
|
||||||
drive->file_count = mft->file_count;
|
drive->file_count = mft->file_count;
|
||||||
drive->bytes_accessed = mft->bytes_accessed;
|
drive->bytes_accessed = mft->bytes_accessed;
|
||||||
drive->time_to_enumerate = (f32)(GetUnixTimestamp() - start_time);
|
drive->time_to_enumerate = (f32)(GetUnixTimestamp() - start_time);
|
||||||
|
|
||||||
|
// #TODO: Generate parent_indices from record_id and parent_id
|
||||||
|
Timed_Block_Print("NTFS_MFT_read_raw: generate parent_indices");
|
||||||
|
// 1. Setup hash table:
|
||||||
|
s64 path_count = item_count(&drive->data->paths);
|
||||||
|
for (s64 i = 0; i < path_count; i += 1) {
|
||||||
|
table_set(&drive->data->path_table, (*drive->data->paths.record_ids)[i], (s32)i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link directories:
|
||||||
|
array_resize(*drive->data->paths.parent_indices, path_count, /*init*/false);
|
||||||
|
s64 fail_count = 0;
|
||||||
|
for (s64 i = 0; i < path_count; i += 1) {
|
||||||
|
u32 parent_id = (*drive->data->paths.parent_ids)[i];
|
||||||
|
bool parent_exists = 0;
|
||||||
|
s32 previous_index = find_previous_index(drive->data, parent_id, &parent_exists);
|
||||||
|
(*drive->data->paths.parent_indices)[i] = previous_index; // -1 if failed.
|
||||||
|
fail_count += (s64)(!parent_exists);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link files:
|
||||||
|
s64 file_count = item_count(&drive->data->files);
|
||||||
|
array_resize(*drive->data->files.parent_indices, file_count, false);
|
||||||
|
for (s64 i = 0; i < file_count; i += 1) {
|
||||||
|
u32 parent_id = (*drive->data->files.parent_ids)[i];
|
||||||
|
bool parent_exists = 0;
|
||||||
|
s32 previous_index = find_previous_index(drive->data, parent_id, &parent_exists);
|
||||||
|
(*drive->data->files.parent_indices)[i] = previous_index; // -1 if failed.
|
||||||
|
fail_count += (s64)(!parent_exists);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fail_count) {
|
||||||
|
log_warning("[%s] Failed to find parent for %lld items", drive_path.data, fail_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_after_enumeration(drive->data);
|
||||||
|
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
21
src/Ex1.cpp
21
src/Ex1.cpp
@ -166,16 +166,6 @@ void Ex1_Control_Panel () { using namespace ImGui;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ex1_ntfs.threads_started && !ex1_ntfs.threads_in_flight.count) {
|
|
||||||
// All threads are complete, we're free to clean up remaining memory
|
|
||||||
push_allocator(GPAllocator());
|
|
||||||
array_free(ex1_ntfs.threads);
|
|
||||||
array_free(ex1_ntfs.threads_in_flight);
|
|
||||||
|
|
||||||
// Instead maybe we should just memset this to zero.
|
|
||||||
reset_struct(&ex1_ntfs);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ex1_ntfs.threads_in_flight.count) {
|
if (ex1_ntfs.threads_in_flight.count) {
|
||||||
Text("Threads in flight: %d", ex1_ntfs.threads_in_flight.count);
|
Text("Threads in flight: %d", ex1_ntfs.threads_in_flight.count);
|
||||||
|
|
||||||
@ -196,6 +186,17 @@ void Ex1_Control_Panel () { using namespace ImGui;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ex1_ntfs.threads_started && !ex1_ntfs.threads_in_flight.count) {
|
||||||
|
// All threads are complete, we're free to clean up remaining memory
|
||||||
|
push_allocator(GPAllocator());
|
||||||
|
array_free(ex1_ntfs.threads);
|
||||||
|
array_free(ex1_ntfs.threads_in_flight);
|
||||||
|
|
||||||
|
// Instead maybe we should just memset this to zero.
|
||||||
|
reset_struct(&ex1_ntfs);
|
||||||
|
}
|
||||||
|
|
||||||
End();
|
End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user