From a28392852a791c107185653997008621bd479dd5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 23 Jul 2024 17:05:41 +0100 Subject: [PATCH] Mock out os2.remove_all for Windows --- core/os/os2/path.odin | 4 +- core/os/os2/path_linux.odin | 4 +- core/os/os2/path_windows.odin | 107 +++++++++++++++++++++++++++++++--- 3 files changed, 103 insertions(+), 12 deletions(-) diff --git a/core/os/os2/path.odin b/core/os/os2/path.odin index f3c662a70..3bf422ccb 100644 --- a/core/os/os2/path.odin +++ b/core/os/os2/path.odin @@ -31,11 +31,11 @@ getwd :: get_working_directory @(require_results) get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { - return _getwd(allocator) + return _get_working_directory(allocator) } setwd :: set_working_directory set_working_directory :: proc(dir: string) -> (err: Error) { - return _setwd(dir) + return _set_working_directory(dir) } diff --git a/core/os/os2/path_linux.odin b/core/os/os2/path_linux.odin index b388322b5..1634c79c8 100644 --- a/core/os/os2/path_linux.odin +++ b/core/os/os2/path_linux.odin @@ -163,7 +163,7 @@ _remove_all :: proc(path: string) -> Error { return _get_platform_error(linux.rmdir(path_cstr)) } -_getwd :: proc(allocator: runtime.Allocator) -> (string, Error) { +_get_working_directory :: proc(allocator: runtime.Allocator) -> (string, Error) { // NOTE(tetra): I would use PATH_MAX here, but I was not able to find // an authoritative value for it across all systems. // The largest value I could find was 4096, so might as well use the page size. @@ -183,7 +183,7 @@ _getwd :: proc(allocator: runtime.Allocator) -> (string, Error) { unreachable() } -_setwd :: proc(dir: string) -> Error { +_set_working_directory :: proc(dir: string) -> Error { dir_cstr := temp_cstring(dir) or_return return _get_platform_error(linux.chdir(dir_cstr)) } diff --git a/core/os/os2/path_windows.odin b/core/os/os2/path_windows.odin index a5eb8f13c..8fc4ef721 100644 --- a/core/os/os2/path_windows.odin +++ b/core/os/os2/path_windows.odin @@ -71,18 +71,109 @@ _mkdir_all :: proc(path: string, perm: int) -> Error { } _remove_all :: proc(path: string) -> Error { - // TODO(bill): _remove_all for windows - return nil + if path == "" { + return nil + } + + + err := remove(path) + if err == nil || err == .Not_Exist { + return nil + } + + TEMP_ALLOCATOR_GUARD() + dir, serr := stat_do_not_follow_links(path, temp_allocator()) + if serr != nil { + if serr == .Not_Exist || serr == .Invalid_Dir { + return nil + } + return serr + } + if dir.type != .Directory { + return err + } + + err = nil + remove_contents: { + f: ^File + f, err = open(path) + if err != nil { + if err == .Not_Exist { + return nil + } + return err + } + + files, read_err := read_all_directory(f, temp_allocator()) + for file in files { + err1 := remove_all(file.fullpath) + if err == nil { + err = err1 + } + } + close(f) + + if read_err == .EOF { + break remove_contents + } + + if err == nil { + err = read_err + } + if len(files) == 0 { + break remove_contents + } + } + + err1 := remove(path) + if err1 == nil || err1 == .Not_Exist { + return nil + } + + if ODIN_OS == .Windows && err1 == .Permission_Denied { + if fi, err2 := stat(path, temp_allocator()); err2 == nil { + if err2 = chmod(path, 0o200|fi.mode); err2 == nil { + err1 = remove(path) + } + } + } + if err == nil { + err = err1 + } + return err } -_getwd :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { - // TODO(bill) - return "", nil +@private cwd_lock: win32.SRWLOCK // zero is initialized + +_get_working_directory :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { + win32.AcquireSRWLockExclusive(&cwd_lock) + + TEMP_ALLOCATOR_GUARD() + + sz_utf16 := win32.GetCurrentDirectoryW(0, nil) + dir_buf_wstr := make([]u16, sz_utf16, temp_allocator()) or_return + + sz_utf16 = win32.GetCurrentDirectoryW(win32.DWORD(len(dir_buf_wstr)), raw_data(dir_buf_wstr)) + assert(int(sz_utf16)+1 == len(dir_buf_wstr)) // the second time, it _excludes_ the NUL. + + win32.ReleaseSRWLockExclusive(&cwd_lock) + + return win32_utf16_to_utf8(dir_buf_wstr, allocator) } -_setwd :: proc(dir: string) -> (err: Error) { - // TODO(bill) - return nil +_set_working_directory :: proc(dir: string) -> (err: Error) { + TEMP_ALLOCATOR_GUARD() + wstr := win32_utf8_to_wstring(dir, temp_allocator()) or_return + + win32.AcquireSRWLockExclusive(&cwd_lock) + + if !win32.SetCurrentDirectoryW(wstr) { + err = _get_platform_error() + } + + win32.ReleaseSRWLockExclusive(&cwd_lock) + + return } can_use_long_paths: bool