Lots of refactoring, overhaul logging system to use context (see log_error macro)

This commit is contained in:
Musa Mahmood 2025-12-05 21:24:50 -05:00
parent 849b8210e0
commit 6970a59c35
22 changed files with 325 additions and 116 deletions

View File

@ -12,7 +12,7 @@ constexpr u16 ARENA_DEFAULT_ALIGNMENT = CPU_REGISTER_WIDTH_BYTES;
#define ARENA_DEBUG BUILD_DEBUG
enum class Arena_Reserve: u8 {
Size_64K = 0, // these are used as indices in Arena_Table!
Size_64K = 0, // these are used as indices in Arena_Free_List!
Size_2M = 1,
Size_64M = 2,
Size_2G = 3,
@ -60,8 +60,8 @@ typedef void* (*Memory_Wipe_Function)(void* memory, u64 byte_count);
void* arena_allocator_proc (Allocator_Mode mode, s64 requested_size, s64 old_size, void* old_memory, void* allocator_data);
// Interface API for normal use (idk how to explain - see Arena_Table.cpp)
struct Arena_Table {
// Interface API for normal use (idk how to explain - see Arena_Free_List.cpp)
struct Arena_Free_List {
Mutex mutex;
s32 in_flight_count[6];
Array<Arena*> free_table[6];

View File

@ -1,71 +1,71 @@
// #TODO: #Arena_Table #garbage_collection in `release_arena`
// #TODO: #Arena_Free_List #garbage_collection in `release_arena`
// [ ] Garbage collection if we have >> 64 in a particular table for a while.
// There should be some parameters regarding what the upper limit for idle
// committed pages should be and a heuristic for maximum number of arenas waiting
global Arena_Table* arena_table;
global Arena_Free_List* arena_free_list;
// Only call once from main thread!
void initialize_arena_table (Allocator allocator) {
mutex_init(&arena_table->mutex);
Assert(arena_table != nullptr);
if (arena_table->initialized)
void initialize_arena_free_list (Allocator allocator) {
mutex_init(&arena_free_list->mutex);
Assert(arena_free_list != nullptr);
if (arena_free_list->initialized)
return;
for (s32 i = 0; i < 6; i += 1) {
arena_table->in_flight_count[i] = 0;
arena_table->free_table[i].allocator = allocator;
array_reserve(arena_table->free_table[i], 64);
arena_free_list->in_flight_count[i] = 0;
arena_free_list->free_table[i].allocator = allocator;
array_reserve(arena_free_list->free_table[i], 64);
#if ARENA_DEBUG
arena_table->in_flight[i].allocator = allocator;
array_reserve(arena_table->in_flight[i], 64);
arena_free_list->in_flight[i].allocator = allocator;
array_reserve(arena_free_list->in_flight[i], 64);
#endif
}
arena_table->initialized = true;
arena_free_list->initialized = true;
}
Arena* next_arena (Arena_Reserve reserve_size) {
Assert(arena_table != nullptr);
Assert(arena_free_list != nullptr);
Arena* arena;
lock_guard(&arena_table->mutex);
lock_guard(&arena_free_list->mutex);
s64 reserve_index = (s64)reserve_size;
if (!arena_table->free_table[reserve_index].count) {
if (!arena_free_list->free_table[reserve_index].count) {
arena = bootstrap_arena(reserve_size, ARENA_DEFAULT_COMMIT_PAGE_COUNT);
} else {
arena = pop(arena_table->free_table[reserve_index]);
arena = pop(arena_free_list->free_table[reserve_index]);
}
#if ARENA_DEBUG
array_add(arena_table->in_flight[reserve_index], arena);
array_add(arena_free_list->in_flight[reserve_index], arena);
#endif
arena_table->in_flight_count[reserve_index] += 1;
arena_free_list->in_flight_count[reserve_index] += 1;
unlock(&arena_table->mutex);
unlock(&arena_free_list->mutex);
Assert(arena != nullptr);
return arena;
}
void release_arena (Arena* arena, bool delete_extra_pages) {
Assert(arena_table != nullptr);
Assert(arena_free_list != nullptr);
Assert(arena != nullptr);
Assert(arena_is_bootstrapped(arena));
// Only put into free table if arena is bootstrapped?
lock_guard(&arena_table->mutex);
lock_guard(&arena_free_list->mutex);
s64 reserve_index = (s64)arena->reserve_size;
#if ARENA_DEBUG
array_unordered_remove_by_value(arena_table->in_flight[reserve_index], arena, 1); // BUILD_DEBUG!
array_unordered_remove_by_value(arena_free_list->in_flight[reserve_index], arena, 1); // BUILD_DEBUG!
#endif
arena_reset_keeping_memory(arena);
if (delete_extra_pages) {
free_pages_down_to(arena, arena->initial_commit_page_count);
}
array_add(arena_table->free_table[reserve_index], arena);
array_add(arena_free_list->free_table[reserve_index], arena);
arena_table->in_flight_count[reserve_index] -= 1;
arena_free_list->in_flight_count[reserve_index] -= 1;
// #TODO #garbage_collection
// if (arena_free_table[reserve_index].count > 64) {
// s64 arenas_to_delete_count = arena_free_table[reserve_index].count - 64;

View File

@ -1,3 +1,6 @@
// #ArenaTableConfusion I just realized ArenaTable (a hash-table backed by an Arena allocator) may be confused with Arena_Table (which is a table tracking free Arenas)
// Solution: rename Arena_Table, to Arena_Free_List.
// Should ArenaTable be bootstrapped like String_Builder?
// see: new_string_builder
template <typename T, typename U>

View File

@ -6,12 +6,11 @@ internal void Bootstrap_Main_Thread_Context () {
GPAllocator_Initialize_Allocation_Tracker();
// 1. Setup arena table
arena_table = (Arena_Table*)GPAllocator_New(sizeof(Arena_Table), 64, true); // permanent allocation.
memset(arena_table, 0, sizeof(Arena_Table));
initialize_arena_table(GPAllocator());
arena_free_list = (Arena_Free_List*)GPAllocator_New(sizeof(Arena_Free_List), 64, true); // permanent allocation.
memset(arena_free_list, 0, sizeof(Arena_Free_List));
initialize_arena_free_list(GPAllocator());
// 2. Setup thread local context
// #NewContext
// 2. #NewContext Setup thread local context
ExpandableArena* arena_ex = expandable_arena_new(Arena_Reserve::Size_64M, 16);
thread_local_context = New<Thread_Context>(allocator(arena_ex));
@ -21,6 +20,7 @@ internal void Bootstrap_Main_Thread_Context () {
thread_local_context->thread_idx = 0;
thread_local_context->thread_name = "Main Thread";
thread_local_context->log_builder = new_string_builder(Arena_Reserve::Size_64M);
thread_local_context->error_arena = next_arena(Arena_Reserve::Size_64M);
default_logger_initialize();
thread_local_context->logger = {default_logger_proc, &default_logger};

View File

@ -1,4 +1,6 @@
struct Thread; // hacky fwd declare
// #hacky fwd declares
struct Thread;
struct Error;
struct Graphics;
struct Thread_Context {
@ -21,6 +23,7 @@ struct Thread_Context {
Allocator error_allocator = GPAllocator();
Error* first_error = nullptr;
Error* current_error = nullptr;
Arena* error_arena;
// Graphics stuff:
Graphics* graphics;
@ -30,6 +33,7 @@ struct Thread_Context {
thread_static Thread_Context* thread_local_context;
// #TODO #NewContext void create_thread_context (Thread_Context** context, string thread_name, bool is_main_thread);
// Thread-context #Errors:
internal void Bootstrap_Main_Thread_Context ();

View File

@ -15,26 +15,154 @@ struct Error {
ErrorClass severity = ErrorClass::NONE;
s32 thread_id;
s32 source_line;
s32 path_length;
char* path;
string file_path;
string function_name;
// Linked list to errors
Error* previous_error; // if we're passing errors up the callstack.
Error* next_error;
// Arena* arena;
// Error () { memset(this, 0, sizeof(*this)); }
};
// string create_error(ErrorClass severity, string fmt, ...) {
// }
string to_string (Error error) {
return { error.count, error.data };
char* error_severity (ErrorClass severity) {
switch (severity) {
case ErrorClass::NONE: {
} break;
case ErrorClass::WARNING: {
return "[WARNING]";
} break;
case ErrorClass::ERROR: {
return "[ERROR]";
} break;
case ErrorClass::FATAL: {
return "[FATAL ERROR]";
} break;
}
return "";
}
void push_error (Error* new_error);
string to_string (Error* error) {
return { error->count, error->data };
}
#define log_fatal_error(fmt, ...) \
Log_Error_2(__FILE__, __FUNCTION__, __LINE__, ErrorClass::FATAL, fmt, ##__VA_ARGS__)
#define log_error(fmt, ...) \
Log_Error_2(__FILE__, __FUNCTION__, __LINE__, ErrorClass::ERROR, fmt, ##__VA_ARGS__)
#define log_warning(fmt, ...) \
Log_Error_2(__FILE__, __FUNCTION__, __LINE__, ErrorClass::WARNING, fmt, ##__VA_ARGS__)
Error* new_error (ErrorClass severity, string error_string) {
Error* error = New<Error>();
error->count = error_string.count;
error->data = error_string.data;
error->severity = severity;
return error;
}
// #TODO: // void OS_Log_Error_With_Code // OS-SPECIFIC CALLING GetLastError, etc.
// Then remove all instances of log_error_code_and_string()
//
void Log_Error_2 (string file_path, string function_name, s32 line_number, ErrorClass severity, string fmt, ...) {
Assert(thread_context() != nullptr);
push_arena(thread_context()->error_arena);
String_Builder* sb = new_string_builder(Arena_Reserve::Size_64K);
// #TODO: prepend severity, other information
print_to_builder(sb, "%s ", error_severity(severity));
va_list args;
va_start(args, fmt);
print_to_builder_internal(sb, fmt, args);
va_end(args);
append(sb, "\n");
string error_string = builder_to_string(sb);
Error* error = new_error(severity, error_string);
// Additional information
error->thread_id = thread_context()->thread_idx;
error->source_line = line_number;
error->file_path = copy_string(file_path);
error->function_name = copy_string(function_name);
// Note: we don't need to assign previous_error or next_error, as that is done by the thread_context when we #push_error
error->previous_error = nullptr;
error->next_error = nullptr;
push_error(error);
}
void push_error (Error* new_error) {
Assert(new_error != nullptr);
if (new_error == nullptr) return;
Error* current_error = thread_context()->current_error;
if (current_error) {
current_error->next_error = new_error;
new_error->previous_error = current_error;
} else {
thread_context()->first_error = new_error;
new_error->previous_error = nullptr;
}
thread_context()->current_error = new_error;
switch (new_error->severity) {
case ErrorClass::NONE:
case ErrorClass::WARNING: {
print(to_string(new_error));
} break;
case ErrorClass::ERROR:
case ErrorClass::FATAL: {
print_error(to_string(new_error));
} break;
}
}
void clear_errors () { // Reset pointers and reset error_arena
arena_reset(thread_context()->error_arena); // maybe overwrite memory?
thread_context()->first_error = nullptr;
thread_context()->current_error = nullptr;
}
void clear_error (Error* error) {
// If we want to clear a specific error (simply remove from the list)
Assert(error != nullptr);
bool is_current_error = (thread_context()->current_error == error);
bool is_first_error = (thread_context()->first_error == error);
Error* current_error = thread_context()->first_error;
if (current_error == nullptr) return; // no errors in linked list.
while (current_error != error && current_error != nullptr) {
current_error = current_error->next_error;
}
Assert(current_error != nullptr);
if (current_error == nullptr) return; // shouldn't happen
Error* the_previous_error = current_error->previous_error;
Error* the_next_error = current_error->next_error;
// Remove current_node from linked list:
the_previous_error->next_error = the_next_error;
the_next_error->previous_error = the_previous_error;
if (is_first_error && is_current_error) { // It matches the only item in the list, just empty the list:
clear_errors();
return;
}
if (is_first_error) {
// the_next_error becomes new first error.
thread_context()->first_error = the_next_error;
}
if (is_current_error) {
// the current_error becomes the previous error
thread_context()->current_error = the_previous_error;
}
}
// Will need to use __FILE__ and __LINE__ macros
// Error* new_error (string error_message, ErrorClass severity, Error* previous_error=nullptr);

View File

@ -46,7 +46,7 @@ void* expandable_arena_alloc (ExpandableArena* arena_ex, s64 byte_count) {
Assert(arena_ex != nullptr);
Assert(arena_ex->memory_base != nullptr); // must be initialized before calling.
Assert(is_valid(arena_ex));
Assert(arena_table->initialized);
Assert(arena_free_list->initialized);
Arena* arena = (Arena*)arena_ex->current;

View File

@ -1,32 +1,9 @@
void log_error (string fmt, ...) {
String_Builder* sb = thread_context()->log_builder;
va_list args;
va_start(args, fmt);
print_to_builder(sb, fmt, args);
va_end(args);
// Append newline if needed
string result = string_view(sb);
bool ends_with_newline = (result.data[result.count-1] == '\n');
if (!ends_with_newline) {
append(sb, "\n");
}
string message = string_view(sb);
Logger* logger = context_logger();
logger->proc(message, Log_Level::Error, logger->data);
reset_string_builder(sb, true);
}
void log (string fmt, ...) {
String_Builder* sb = thread_context()->log_builder;
va_list args;
va_start(args, fmt);
print_to_builder(sb, fmt, args);
print_to_builder_internal(sb, fmt, args);
va_end(args);
// Append newline if needed
@ -48,3 +25,8 @@ void print (string message) {
Logger* logger = context_logger();
logger->proc(message, Log_Level::None, logger->data);
}
void print_error (string error_message) {
Logger* logger = context_logger();
logger->proc(error_message, Log_Level::Error, logger->data);
}

View File

@ -65,7 +65,6 @@ void default_logger_initialize() {
#endif
}
void log_error (string fmt, ...);
void log (string fmt, ...);
void print (string message);
void print_error (string error_message);

View File

@ -37,18 +37,18 @@ template <typename T> force_inline void AddArray (Serializer* serializer, ArrayV
AddArray_NoSize(serializer, view);
}
template <typename T> force_inline void AddString (Serializer* serializer, string s) {
force_inline void AddString (Serializer* serializer, string s) {
Add(serializer, s.count);
AddArray_NoSize(serializer, to_view(s));
}
template <typename T> force_inline void AddString32 (Serializer* serializer, string s) {
force_inline void AddString32 (Serializer* serializer, string s) {
u32 string_length = (u32)s.count;
Add(serializer, string_length);
AddArray_NoSize(serializer, to_view(s));
}
template <typename T> force_inline void AddString16 (Serializer* serializer, string s) {
force_inline void AddString16 (Serializer* serializer, string s) {
u16 string_length = (u16)s.count;
Add(serializer, string_length);
AddArray_NoSize(serializer, to_view(s));

View File

@ -199,7 +199,7 @@ force_inline void append_no_add (String_Builder* sb, string s) {
// Unfortunately this follows the printf format, which is annoying.
// I'd rather have something like fmt::
void print_to_builder (String_Builder* sb, string format, va_list args) {
void print_to_builder_internal (String_Builder* sb, string format, va_list args) {
s64 expected_final_count = max_array_size(*sb);// amount to reserve
if (sb->allocated < expected_final_count) {

View File

@ -117,9 +117,10 @@ void append (String_Builder* sb, ArrayView<string> strings);
// This should probably be called append_but_do_not_increment_count
internal force_inline void append_no_add (String_Builder* sb, string s); // for appending null terminators, does not increment count.
void print_to_builder (String_Builder* sb, string format, ...);
void print_to_builder (String_Builder* sb, string format, va_list args);
void print_to_builder_internal (String_Builder* sb, string format, va_list args);
string string_view (String_Builder* sb);
internal force_inline void reset_string_builder (String_Builder* sb, bool keep_memory=false);
force_inline string builder_to_string (String_Builder* sb); // returns string view
// #rename copy_string_and_free_builder
force_inline string builder_to_string (String_Builder* sb); // returns copy and frees string_builder
internal force_inline void free_string_builder (String_Builder* sb);

View File

@ -53,7 +53,7 @@ struct Worker_Info {
u8 padding1[48];
};
static_assert(sizeof(Worker_Info) % 64 == 0); // This MUST be padded to cache line!
enum class Thread_Continue_Status : s32 {
enum class Thread_Continue_Status: s32 {
THREAD_STOP = 0,
THREAD_CONTINUE = 1
};

View File

@ -6,6 +6,10 @@ void run_pre_setup_tests() {
string string_literal_example = "Hello, I am a string literal.";
void run_post_setup_tests() {
debug_break();
log_warning("Hello, I am a warning :), and I am a big number: %lld", (s64)293509357);
log_error("Hello, I am an error - %s", "I'm another string");
log_error("This is an error");
printf("Running post-setup tests...\n");
// See: main_thread_base_entry_point
{ Timed_Block_Print("string_builder_testing");

87
lib/OS/OS_Filesystem.cpp Normal file
View File

@ -0,0 +1,87 @@
// So NTFS (and most systems) sort the tree by default in lexicographical descending order.
// For lookups, this often isn't that useful if you only know substrings of the path.
// struct BTNode {
// u16 key_count;
// BTNode* keys;
// u16 allocated;
// };
// struct B_Tree {
// BTNode* root;
// Allocator allocator;
// };
// A compact collection of data with sorting indices
// Maybe we can make B+ trees for sorting according to
// size and modtime.
// It really doesn't make sense to store data in memory as a B-tree except
// if we need ordered insertions and deletes.
//
// Returns offset
force_inline s32 AddString_NoCount (Serializer* serializer, u8* data, u8 count) { // #TODO: , bool null_terminate=false
u8* current_point = &serializer->data[serializer->count];
s64 final_count = serializer->allocated + (count * sizeof(u8));
if (serializer->allocated < final_count) {
array_reserve(*serializer, final_count);
}
memcpy(current_point, data, count * sizeof(u8));
serializer->count += count * sizeof(u8);
}
constexpr s64 DFS_Preallocation_Count = 4194304; // 2^22
// template <typename Length_Type>
struct DFS_Array {
Serializer* strings;
ArenaArray<u32>* offsets; // offsets into string_arena
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>* sizes;
ArenaArray<s32>* parent_indices;
s64 index; // current index when inserting;
// #Temporary arrays for linking???
ArenaArray<u32>* record_ids;
ArenaArray<u32>* parent_ids;
// #TODO: Sort indices (should these be trees?)
// ArenaArray<s32> indices_sorted_by_modtime;
// ArenaArray<s32> indices_sorted_by_size;
};
void initialize (DFS_Array* dfsa) {
Assert(dfsa != nullptr);
dfsa->strings = new_serializer(Arena_Reserve::Size_2G);
dfsa->offsets = arena_array_new<u32>(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->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;
}
struct Dense_FS { // Link to OS_Drive
OS_Drive* drive; // backlink for reference.
DFS_Array paths;
DFS_Array files;
ArenaTable<u32, s32> path_table; // <entry_id, array_offset>.
};
void initialize (Dense_FS* dfs, OS_Drive* drive) {
Assert(drive != nullptr);
dfs->drive = drive;
initialize(&dfs->paths);
initialize(&dfs->files);
table_init(&dfs->path_table, DFS_Preallocation_Count);
}

View File

@ -222,9 +222,10 @@ internal bool thread_init (Thread* thread, Thread_Proc proc, string thread_name=
}
s64 this_thread_index = InterlockedIncrement(&next_thread_index);
// #NewContext
// 2. #NewContext Setup NEW thread local context
ExpandableArena* arena_ex = expandable_arena_new(Arena_Reserve::Size_64M, 16);
// #NOTE: we don't assign thread_local_context until we hit the #thread_entry_point
thread->context = New<Thread_Context>(allocator(arena_ex));
thread->context->temp = expandable_arena_new(Arena_Reserve::Size_2M, 16);
thread->context->arena = arena_ex;
@ -232,6 +233,7 @@ internal bool thread_init (Thread* thread, Thread_Proc proc, string thread_name=
thread->context->thread_idx = (s32)this_thread_index;
thread->context->thread_name = copy_string(thread_name);
thread->context->log_builder = new_string_builder(Arena_Reserve::Size_64M);
thread->context->error_arena = next_arena(Arena_Reserve::Size_64M);
thread->os_thread.windows_thread = windows_thread;
thread->os_thread.windows_thread_id = windows_thread_id;
@ -338,7 +340,7 @@ internal string get_error_string (OS_Error_Code error_code) {
return result; // trim_right(result, "\r\n");
}
internal void log_error_code_and_string () {
internal void log_error_code_and_string () { // #TODO: replace with call to log_error_with_code
OS_Error_Code error_code = GetLastError();
log_error(" > GetLastError code: %d, %s\n", error_code, get_error_string(error_code).data);
}
@ -372,8 +374,9 @@ internal File file_open (string file_path, bool for_writing, bool keep_existing_
}
if (handle == INVALID_HANDLE_VALUE && log_errors) {
OS_Error_Code error_code = GetLastError();
log_error("Could not open file `%s`, code: %d, %s", file_path, error_code, get_error_string(error_code).data);
// OS_Error_Code error_code = GetLastError();
log_error("Could not open file `%s`", file_path);
log_error_code_and_string();
}
File file;
@ -390,6 +393,7 @@ internal bool file_read (File file, u8* data, s64 bytes_to_read_count, s64* byte
// ignore bytes_read_count if null.
if (data == nullptr) {
log_error("file_read called with null destination pointer.\n");
log_error_code_and_string();
if (bytes_read_count) (*bytes_read_count) = 0;
return false;
}
@ -574,7 +578,7 @@ internal void os_enumerate_monitors () {
if (!global_win32_state.system_info.monitors_enumerated) {
// should reset array?
if (!EnumDisplayMonitors(nullptr, nullptr, monitor_enum_proc, 0)) {
log_error("Failed to enumerate monitors\n");
log_fatal_error("Failed to enumerate monitors\n");
Assert(false); // Failed to enumerate monitors
ExitProcess(1);
}

View File

@ -5,7 +5,7 @@
f64 GetUnixTimestamp ();
s64 GetUnixTimestampNanoseconds ();
enum class Wait_For_Result : s32 {
enum class Wait_For_Result: s32 {
SUCCESS = 0,
TIMEOUT = 1,
ERROR = 2 // can't use ERROR because of Windows.h *sigh*
@ -165,7 +165,7 @@ File_System Win32_filesystem_from_string (string s) {
Assert(false);
return File_System::Unknown;
}
struct Dense_FS; // #Temp forward declare!
struct Win32_Drive {
string label;
string volume_name;
@ -180,8 +180,11 @@ struct Win32_Drive {
// Not sure if this should be here...
// f32 enumeration_time;
// f64 last_seen_alive_timestamp;
Dense_FS* data;
};
typedef Win32_Drive OS_Drive;
bool os_window_is_minimized (Window_Type window);
bool os_main_window_is_minimized ();

View File

@ -141,38 +141,31 @@ bool NTFS_read_internal (NTFS_MFT_Internal* mft, void* buffer, u64 from, u64 cou
return bytes_accessed_internal == count;
}
enum class NTFS_Block_Flag : s32 {
idk = 0,
idk2 = 1,
};
struct NTFS_MFT_Copy {
u32 error_code;
// Array<ArrayView<u8>> mft_blocks; // idk if this is correct!
// Array<NTFS_Block_Flag> mft_flags;
};
// #TODO: make a version where we just reconstruct the MFT as a deque in memory.
NTFS_MFT_Copy* NTFS_MFT_read_raw (string drive_path) {
// #TODO: Release resources if we face an early return!
Dense_FS* NTFS_MFT_read_raw (string drive_path) {
Table<string, Win32_Drive>* drive_table = &global_win32_state.system_info.drives;
// We should be able to fetch from the table using table_find_pointer
bool just_added = false;
Win32_Drive* drive = table_find_or_add(drive_table, drive_path, &just_added);
Assert(just_added == false && drive != nullptr);
if (drive == nullptr) {
return nullptr;
}
Assert(context_allocator() != temp()); // pointless as we're releasing temp end-of-scope
Allocator primary_allocator = context_allocator();
auto_release_temp();
push_allocator(temp());
NTFS_MFT_Copy* mft_copy = New<NTFS_MFT_Copy>(primary_allocator); //use context allocator.
string drive_letter = Win32_drive_letter(drive_path);
string create_file_target = format_string("\\\\.\\%s:", drive_letter.data);
HANDLE file_handle = CreateFileA((LPCSTR)create_file_target.data, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
if (file_handle == INVALID_HANDLE_VALUE) {
log_error("CreateFileA failed on target %s", create_file_target.data);
log_error_code_and_string();
mft_copy->error_code = GetLastError();
return mft_copy;
return nullptr;
}
push_allocator(primary_allocator);
@ -271,11 +264,11 @@ NTFS_MFT_Copy* NTFS_MFT_read_raw (string drive_path) {
NTFS_FileNameAttributeHeader* fileNameAttribute = (NTFS_FileNameAttributeHeader*)attribute;
if (fileNameAttribute->namespaceType != 2 && !fileNameAttribute->nonResident) {
file.parent_id = (u32)fileNameAttribute->parentRecordNumber; // truncate
file.record_id = fileRecord->recordNumber;
file.name_count = fileNameAttribute->fileNameLength;
file.name_data = (u16*)fileNameAttribute->fileName;
file.name_utf8 = wide_to_utf8(file.name_data, file.name_count);
file.parent_id = (u32)fileNameAttribute->parentRecordNumber; // truncate
file.record_id = fileRecord->recordNumber;
file.name_count = fileNameAttribute->fileNameLength;
file.name_data = (u16*)fileNameAttribute->fileName;
file.name_utf8 = wide_to_utf8(file.name_data, file.name_count);
file.file_modtime = (u64)fileNameAttribute->modificationTime;
file.is_directory = fileRecord->isDirectory;
// We need to get size from the data attribute

View File

@ -31,15 +31,15 @@
#include "lib/Base/Serializer.h"
#include "lib/Base/Serializer.cpp"
#include "lib/Base/ErrorType.cpp"
#include "lib/Base/Base_Thread_Context.h"
#include "lib/Base/Expandable_Arena.h"
#include "lib/Base/Timing.h"
#include "lib/Base/Arena_Table.cpp"
#include "lib/Base/Arena_Free_List.cpp"
#include "lib/Base/Arena.cpp"
#include "lib/Base/Base_Thread_Context.cpp"
#include "lib/Base/ErrorType.cpp"
#include "lib/Base/Logger.cpp"
#include "lib/Base/Expandable_Arena.cpp"
#include "lib/Base/Allocator.cpp"
@ -47,6 +47,7 @@
// OS-Abstraction Layer
#include "lib/Base/Threads.cpp"
#include "lib/OS/OS_Filesystem.cpp"
#if OS_WINDOWS
# include "lib/OS/OS_Win32.cpp"

View File

@ -26,7 +26,7 @@ void Ex1_Unregister_Global_Hotkeys () {
bool Ex1_Register_Global_Hotkeys () {
if (!RegisterHotKey(nullptr, HOTKEY_ID_BRING_TO_FOREGROUND, MOD_CONTROL|MOD_SHIFT|MOD_ALT, VK_SPACE_KEY_CODE)) {
Assert(false);
log_error("Failed to register global hotkey Ctrl-Alt-Space");
log_error("Failed to register global hotkey Ctrl-Shift-Alt-Space");
return false;
}
return true;

View File

@ -371,8 +371,8 @@ void ImGui_Debug_Panel () {
if (ImGui::Button(button_label)) {
push_arena(thread_context()->arena);
// auto_release(thread_context()->arena);
auto result = NTFS_MFT_read_raw(entry->value.label);
if (result->error_code != 0) {
auto dfs = NTFS_MFT_read_raw(entry->value.label);
if (dfs == nullptr) {
log("[NTFS_MFT_read_raw] operation failed");
}
}

View File

@ -20,9 +20,9 @@ void Explorer_ImGui_Application_Win32 () {
HWND hwnd = get_main_window().window;
success = Win32_Load_Main_Window_Icon("tmp.ico");
if (!success) { log_error("Failed to load tmp.ico"); }
if (!success) { log_warning("Failed to load tmp.ico"); }
success = Win32_Load_Main_Window_Icon_Minimized("tmp_min.ico");
if (!success) { log_error("Failed to load tmp_min.ico"); }
if (!success) { log_warning("Failed to load tmp_min.ico"); }
// :Win32_Initialize_Extended
Win32_Set_Main_Icon();