Browse Source

Mock out os2.remove_all for Windows

gingerBill 1 year ago
parent
commit
a28392852a
3 changed files with 103 additions and 12 deletions
  1. 2 2
      core/os/os2/path.odin
  2. 2 2
      core/os/os2/path_linux.odin
  3. 99 8
      core/os/os2/path_windows.odin

+ 2 - 2
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)
 }

+ 2 - 2
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))
 }

+ 99 - 8
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