diff --git a/src/linker/lnk_io.c b/src/linker/lnk_io.c index 792c28e7..6b9aee8d 100644 --- a/src/linker/lnk_io.c +++ b/src/linker/lnk_io.c @@ -10,15 +10,6 @@ lnk_open_file_read(char *path, uint64_t path_size, void *handle_buffer, uint64_t return !os_handle_match(handle, os_handle_zero()); } -shared_function int -lnk_open_file_write_rename(char *path, uint64_t path_size, void *handle_buffer, uint64_t handle_buffer_max) -{ - OS_Handle handle = os_file_open(OS_AccessFlag_Write|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite|OS_AccessFlag_ShareDelete, str8((U8*)path, path_size)); - Assert(sizeof(handle) <= handle_buffer_max); - MemoryCopy(handle_buffer, &handle, sizeof(handle)); - return !os_handle_match(handle, os_handle_zero()); -} - shared_function int lnk_open_file_write(char *path, uint64_t path_size, void *handle_buffer, uint64_t handle_buffer_max) { @@ -35,14 +26,6 @@ lnk_close_file(void *raw_handle) os_file_close(handle); } -shared_function int -lnk_rename_file(void *raw_handle, char *new_file_path, uint64_t new_file_path_size) -{ - OS_Handle handle = *(OS_Handle *)raw_handle; - B32 is_renamed = os_rename_file_by_handle(handle, str8((U8*)new_file_path, new_file_path_size)); - return (int)is_renamed; -} - shared_function uint64_t lnk_size_from_file(void *raw_handle) { @@ -70,6 +53,118 @@ lnk_write_file(void *raw_handle, uint64_t offset, void *buffer, uint64_t buffer_ //////////////////////////////// +internal String8List +lnk_file_search(Arena *arena, String8List dir_list, String8 file_path) +{ + ProfBeginFunction(); + Temp scratch = scratch_begin(&arena, 1); + String8List match_list; MemoryZeroStruct(&match_list); + + if (os_file_path_exists(file_path)) { + String8 str = push_str8_copy(arena, file_path); + str8_list_push(arena, &match_list, str); + } + + PathStyle file_path_style = path_style_from_str8(file_path); + B32 is_relative = file_path_style != PathStyle_WindowsAbsolute && + file_path_style != PathStyle_UnixAbsolute; + + if (is_relative) { + for (String8Node *i = dir_list.first; i != 0; i = i->next) { + String8List path_list = {0}; + str8_list_push(scratch.arena, &path_list, i->string); + str8_list_push(scratch.arena, &path_list, file_path); + String8 path = str8_path_list_join_by_style(scratch.arena, &path_list, PathStyle_SystemAbsolute); + B32 file_exists = os_file_path_exists(path); + if (file_exists) { + B32 is_unique = 1; + OS_FileID file_id = os_id_from_file_path(path); + for (String8Node *k = match_list.first; k != 0; k = k->next) { + OS_FileID test_id = os_id_from_file_path(k->string); + int cmp = os_file_id_compare(test_id, file_id) != 0; + if (cmp == 0) { + is_unique = 0; + break; + } + } + if (is_unique) { + String8 str = push_str8_copy(arena, path); + str8_list_push(arena, &match_list, str); + } + } + } + } + + scratch_end(scratch); + ProfEnd(); + return match_list; +} + +internal OS_Handle +lnk_file_open_with_rename_permissions(String8 path) +{ + OS_Handle file_handle = os_handle_zero(); +#if _WIN32 + Temp scratch = scratch_begin(0,0); + + // open file with permissions to rename + String16 path16 = str16_from_8(scratch.arena, path); + SECURITY_ATTRIBUTES security_attributes = { sizeof(security_attributes) }; + HANDLE native_handle = CreateFileW((WCHAR*)path16.str, + GENERIC_WRITE|DELETE, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + &security_attributes, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + 0); + if (native_handle != INVALID_HANDLE_VALUE) { + file_handle.u64[0] = (U64)native_handle; + } + + scratch_end(scratch); +#else +#error "TODO: file rename" +#endif + return file_handle; +} + +internal B32 +lnk_file_set_delete_on_close(OS_Handle handle, B32 delete_file) +{ +#if _WIN32 + FILE_DISPOSITION_INFO file_disposition = {0}; + file_disposition.DeleteFile = (BOOL)delete_file; + B32 is_set = SetFileInformationByHandle((HANDLE)handle.u64[0], FileDispositionInfo, &file_disposition, sizeof(file_disposition)); +#else +#error "TODO: file rename" +#endif + return is_set; +} + +internal B32 +lnk_file_rename(OS_Handle handle, String8 new_name) +{ + Temp scratch = scratch_begin(0,0); +#if _WIN32 + String16 new_name16 = str16_from_8(scratch.arena, new_name); + + U64 file_rename_info_size = sizeof(FILE_RENAME_INFO); + U64 buffer_size = file_rename_info_size + sizeof(new_name16.str)*new_name16.size; + U8 *buffer = push_array(scratch.arena, U8, buffer_size); + + FILE_RENAME_INFO *rename_info = (FILE_RENAME_INFO *)buffer; + rename_info->ReplaceIfExists = 1; + rename_info->FileNameLength = new_name16.size * sizeof(new_name16.str[0]); + MemoryCopy(rename_info->FileName, new_name16.str, new_name16.size * sizeof(new_name16.str[0])); + + B32 is_renamed = SetFileInformationByHandle((HANDLE)handle.u64[0], FileRenameInfo, buffer, buffer_size); +#else +#error "TODO: file rename" +#endif + scratch_end(scratch); + return is_renamed; +} + internal void lnk_log_read(String8 path, U64 size) { @@ -184,38 +279,48 @@ lnk_write_data_list_to_file_path(String8 path, String8 temp_path, String8List da { ProfBeginV("Write %M to %S", data.total_size, path); - U64 bytes_written = 0; - B32 open_with_rename = (temp_path.size > 0); OS_Handle file_handle = {0}; + String8 open_file_path = {0}; if (open_with_rename) { - lnk_open_file_write_rename((char*)temp_path.str, temp_path.size, &file_handle, sizeof(file_handle)); + file_handle = lnk_file_open_with_rename_permissions(temp_path); + open_file_path = temp_path; + + // mark file to be deleted on exit, so we don't leave corrupted files on disk + if (!lnk_file_set_delete_on_close(file_handle, 1)) { + lnk_error(LNK_Error_IO, "failed to update file disposition on %S", open_file_path); + } } else { lnk_open_file_write((char*)path.str, path.size, &file_handle, sizeof(file_handle)); + open_file_path = path; } if (!os_handle_match(file_handle, os_handle_zero())) { + // try to reserve up front file size if (!os_file_reserve_size(file_handle, data.total_size)) { - lnk_log(LNK_Log_IO_Write, "Failed to pre-allocate file %S with size %M", path, data.total_size); + lnk_log(LNK_Log_IO_Write, "Failed to pre-allocate file %S with size %M", open_file_path, data.total_size); } // write data nodes - { - for (String8Node *data_n = data.first; data_n != 0; data_n = data_n->next) { - U64 write_size = lnk_write_file(&file_handle, bytes_written, data_n->string.str, data_n->string.size); - if (write_size != data_n->string.size) { - break; - } - bytes_written += data_n->string.size; + U64 bytes_written = 0; + for (String8Node *data_n = data.first; data_n != 0; data_n = data_n->next) { + U64 write_size = lnk_write_file(&file_handle, bytes_written, data_n->string.str, data_n->string.size); + if (write_size != data_n->string.size) { + break; } + bytes_written += data_n->string.size; } - B32 is_write_complete = (bytes_written == data.total_size); if (is_write_complete) { - // rename file to original name + // rename temp file if (open_with_rename) { - if (lnk_rename_file(&file_handle, (char*)path.str, path.size)) { + // all writes succeeded, remove delete on exit flag + if (!lnk_file_set_delete_on_close(file_handle, 0)) { + lnk_error(LNK_Error_IO, "failed to update file disposition on %S", open_file_path); + } + + if (lnk_file_rename(file_handle, path)) { lnk_log(LNK_Log_IO_Write, "Renamed %S -> %S", temp_path, path); } else { lnk_error(LNK_Error_IO, "failed to rename %S -> %S", temp_path, path); @@ -223,6 +328,9 @@ lnk_write_data_list_to_file_path(String8 path, String8 temp_path, String8List da } } + // clean up file handle + lnk_close_file(&file_handle); + // log write if (is_write_complete) { if (lnk_get_log_status(LNK_Log_IO_Write)) { @@ -231,9 +339,6 @@ lnk_write_data_list_to_file_path(String8 path, String8 temp_path, String8List da } else { lnk_error(LNK_Error_IO, "incomplete write, %M written, expected %M, file %S", bytes_written, data.total_size, path); } - - // clean up handle - lnk_close_file(&file_handle); } else { lnk_error(LNK_Error_NoAccess, "don't have access to write to %S", path); } @@ -251,50 +356,4 @@ lnk_write_data_to_file_path(String8 path, String8 temp_path, String8 data) scratch_end(scratch); } -internal String8List -lnk_file_search(Arena *arena, String8List dir_list, String8 file_path) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(&arena, 1); - String8List match_list; MemoryZeroStruct(&match_list); - - if (os_file_path_exists(file_path)) { - String8 str = push_str8_copy(arena, file_path); - str8_list_push(arena, &match_list, str); - } - - PathStyle file_path_style = path_style_from_str8(file_path); - B32 is_relative = file_path_style != PathStyle_WindowsAbsolute && - file_path_style != PathStyle_UnixAbsolute; - - if (is_relative) { - for (String8Node *i = dir_list.first; i != 0; i = i->next) { - String8List path_list = {0}; - str8_list_push(scratch.arena, &path_list, i->string); - str8_list_push(scratch.arena, &path_list, file_path); - String8 path = str8_path_list_join_by_style(scratch.arena, &path_list, PathStyle_SystemAbsolute); - B32 file_exists = os_file_path_exists(path); - if (file_exists) { - B32 is_unique = 1; - OS_FileID file_id = os_id_from_file_path(path); - for (String8Node *k = match_list.first; k != 0; k = k->next) { - OS_FileID test_id = os_id_from_file_path(k->string); - int cmp = os_file_id_compare(test_id, file_id) != 0; - if (cmp == 0) { - is_unique = 0; - break; - } - } - if (is_unique) { - String8 str = push_str8_copy(arena, path); - str8_list_push(arena, &match_list, str); - } - } - } - } - - scratch_end(scratch); - ProfEnd(); - return match_list; -} diff --git a/src/linker/lnk_io.h b/src/linker/lnk_io.h index 7771caf0..13b0d777 100644 --- a/src/linker/lnk_io.h +++ b/src/linker/lnk_io.h @@ -17,20 +17,23 @@ typedef struct shared_function int lnk_open_file_read(char *path, uint64_t path_size, void *handle_buffer, uint64_t handle_buffer_max); shared_function int lnk_open_file_write(char *path, uint64_t path_size, void *handle_buffer, uint64_t handle_buffer_max); -shared_function int lnk_open_file_write_rename(char *path, uint64_t path_size, void *handle_buffer, uint64_t handle_buffer_max); shared_function void lnk_close_file(void *raw_handle); -shared_function int lnk_rename_file(void *raw_handle, char *new_file_path, uint64_t new_file_path_size); shared_function uint64_t lnk_size_from_file(void *raw_handle); shared_function uint64_t lnk_read_file(void *raw_handle, void *buffer, uint64_t buffer_max); shared_function uint64_t lnk_write_file(void *raw_handle, uint64_t offset, void *buffer, uint64_t buffer_size); //////////////////////////////// +internal String8List lnk_file_search(Arena *arena, String8List dir_list, String8 file_path); + +internal OS_Handle lnk_file_open_with_rename_permissions(String8 path); +internal B32 lnk_file_set_delete_on_close(OS_Handle handle, B32 delete_file); +internal B32 lnk_file_rename(OS_Handle handle, String8 new_name); + internal String8 lnk_read_data_from_file_path(Arena *arena, String8 path); internal String8Array lnk_read_data_from_file_path_parallel(TP_Context *tp, Arena *arena, String8Array path_arr); internal void lnk_write_data_list_to_file_path(String8 path, String8 temp_path, String8List list); internal void lnk_write_data_to_file_path(String8 path, String8 temp_path, String8 data); -internal String8List lnk_file_search(Arena *arena, String8List dir_list, String8 file_path); diff --git a/src/os/core/os_core.c b/src/os/core/os_core.c index f44d5cb8..21a0a413 100644 --- a/src/os/core/os_core.c +++ b/src/os/core/os_core.c @@ -151,16 +151,6 @@ os_string_from_file_range(Arena *arena, OS_Handle file, Rng1U64 range) return result; } -internal B32 -os_rename_file(String8 orig_name, String8 new_name) -{ - Temp scratch = scratch_begin(0,0); - OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareWrite|OS_AccessFlag_ShareDelete, orig_name); - B32 is_renamed = os_rename_file_by_handle(file, new_name); - os_file_close(file); - return is_renamed; -} - //////////////////////////////// //~ rjf: Process Launcher Helpers diff --git a/src/os/core/os_core.h b/src/os/core/os_core.h index 30b7c142..2c07e759 100644 --- a/src/os/core/os_core.h +++ b/src/os/core/os_core.h @@ -44,8 +44,7 @@ enum OS_AccessFlag_Append = (1<<3), OS_AccessFlag_ShareRead = (1<<4), OS_AccessFlag_ShareWrite = (1<<5), - OS_AccessFlag_ShareDelete = (1<<6), - OS_AccessFlag_Inherited = (1<<7), + OS_AccessFlag_Inherited = (1<<6), }; //////////////////////////////// @@ -207,7 +206,6 @@ internal U64 os_file_write(OS_Handle file, Rng1U64 rng, void *data); internal B32 os_file_set_times(OS_Handle file, DateTime time); internal FileProperties os_properties_from_file(OS_Handle file); internal OS_FileID os_id_from_file(OS_Handle file); -internal B32 os_rename_file_by_handle(OS_Handle file, String8 new_name); internal B32 os_rename_file(String8 orig_name, String8 new_name); internal B32 os_file_reserve_size(OS_Handle file, U64 size); internal B32 os_delete_file_at_path(String8 path); diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index fc615797..90b1277c 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -326,7 +326,6 @@ os_file_open(OS_AccessFlags flags, String8 path) if(flags & OS_AccessFlag_Execute) {access_flags |= GENERIC_EXECUTE;} if(flags & OS_AccessFlag_ShareRead) {share_mode |= FILE_SHARE_READ;} if(flags & OS_AccessFlag_ShareWrite) {share_mode |= FILE_SHARE_WRITE|FILE_SHARE_DELETE;} - if(flags & OS_AccessFlag_ShareDelete) {share_mode |= FILE_SHARE_DELETE; access_flags |= DELETE;} if(flags & OS_AccessFlag_Write) {creation_disposition = CREATE_ALWAYS;} if(flags & OS_AccessFlag_Append) {creation_disposition = OPEN_ALWAYS; access_flags |= FILE_APPEND_DATA; } if(flags & OS_AccessFlag_Inherited) @@ -470,30 +469,6 @@ os_id_from_file(OS_Handle file) return result; } -internal B32 -os_rename_file_by_handle(OS_Handle file, String8 new_name) -{ - Temp scratch = scratch_begin(0,0); - - HANDLE handle = (HANDLE)file.u64[0]; - - String16 new_name16 = str16_from_8(scratch.arena, new_name); - - U64 file_rename_info_size = sizeof(FILE_RENAME_INFO); - U64 buffer_size = file_rename_info_size + sizeof(WCHAR)*new_name16.size; - U8 *buffer = push_array(scratch.arena, U8, buffer_size); - - FILE_RENAME_INFO *rename_info = (FILE_RENAME_INFO *)buffer; - rename_info->ReplaceIfExists = 1; - rename_info->FileNameLength = new_name16.size * sizeof(new_name16.str[0]); - MemoryCopy(rename_info->FileName, new_name16.str, new_name16.size * sizeof(new_name16.str[0])); - - BOOL is_renamed = SetFileInformationByHandle(handle, FileRenameInfo, buffer, buffer_size); - - scratch_end(scratch); - return is_renamed; -} - internal B32 os_file_reserve_size(OS_Handle file, U64 size) {