Browse Source

Update error handling for os2 on windows

gingerBill 3 years ago
parent
commit
bb4f108487

+ 6 - 4
core/os/os2/env_windows.odin

@@ -2,8 +2,9 @@
 package os2
 package os2
 
 
 import win32 "core:sys/windows"
 import win32 "core:sys/windows"
+import "core:runtime"
 
 
-_lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
+_lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) {
 	if key == "" {
 	if key == "" {
 		return
 		return
 	}
 	}
@@ -17,7 +18,7 @@ _lookup_env :: proc(key: string, allocator := context.allocator) -> (value: stri
 		}
 		}
 		return "", true
 		return "", true
 	}
 	}
-	b := make([]u16, n+1, context.temp_allocator)
+	b := make([]u16, n+1, _temp_allocator())
 
 
 	n = win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b)))
 	n = win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b)))
 	if n == 0 {
 	if n == 0 {
@@ -25,6 +26,7 @@ _lookup_env :: proc(key: string, allocator := context.allocator) -> (value: stri
 		if err == win32.ERROR_ENVVAR_NOT_FOUND {
 		if err == win32.ERROR_ENVVAR_NOT_FOUND {
 			return "", false
 			return "", false
 		}
 		}
+		return "", false
 	}
 	}
 
 
 	value = win32.utf16_to_utf8(b[:n], allocator)
 	value = win32.utf16_to_utf8(b[:n], allocator)
@@ -45,7 +47,7 @@ _unset_env :: proc(key: string) -> bool {
 }
 }
 
 
 _clear_env :: proc() {
 _clear_env :: proc() {
-	envs := environ(context.temp_allocator)
+	envs := environ(_temp_allocator())
 	for env in envs {
 	for env in envs {
 		for j in 1..<len(env) {
 		for j in 1..<len(env) {
 			if env[j] == '=' {
 			if env[j] == '=' {
@@ -56,7 +58,7 @@ _clear_env :: proc() {
 	}
 	}
 }
 }
 
 
-_environ :: proc(allocator := context.allocator) -> []string {
+_environ :: proc(allocator: runtime.Allocator) -> []string {
 	envs := win32.GetEnvironmentStringsW()
 	envs := win32.GetEnvironmentStringsW()
 	if envs == nil {
 	if envs == nil {
 		return nil
 		return nil

+ 49 - 30
core/os/os2/errors.odin

@@ -1,9 +1,10 @@
 package os2
 package os2
 
 
 import "core:io"
 import "core:io"
+import "core:runtime"
 
 
 General_Error :: enum u32 {
 General_Error :: enum u32 {
-	Invalid_Argument,
+	None,
 
 
 	Permission_Denied,
 	Permission_Denied,
 	Exist,
 	Exist,
@@ -18,13 +19,12 @@ General_Error :: enum u32 {
 	Unsupported,
 	Unsupported,
 }
 }
 
 
-Platform_Error :: struct {
-	err: i32,
-}
+Platform_Error :: enum i32 {None=0}
 
 
-Error :: union {
+Error :: union #shared_nil {
 	General_Error,
 	General_Error,
 	io.Error,
 	io.Error,
+	runtime.Allocator_Error,
 	Platform_Error,
 	Platform_Error,
 }
 }
 #assert(size_of(Error) == size_of(u64))
 #assert(size_of(Error) == size_of(u64))
@@ -33,36 +33,55 @@ Error :: union {
 
 
 is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) {
 is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) {
 	v := ferr.(Platform_Error) or_else {}
 	v := ferr.(Platform_Error) or_else {}
-	return v.err, v.err != 0
+	return i32(v), i32(v) != 0
 }
 }
 
 
 
 
 error_string :: proc(ferr: Error) -> string {
 error_string :: proc(ferr: Error) -> string {
-	switch ferr {
-	case nil:                return ""
-	case .Invalid_Argument:  return "invalid argument"
-	case .Permission_Denied: return "permission denied"
-	case .Exist:             return "file already exists"
-	case .Not_Exist:         return "file does not exist"
-	case .Closed:            return "file already closed"
-	case .Timeout:           return "i/o timeout"
-	case .EOF:               return "eof"
-	case .Unexpected_EOF:    return "unexpected eof"
-	case .Short_Write:       return "short write"
-	case .Invalid_Write:     return "invalid write result"
-	case .Short_Buffer:      return "short buffer"
-	case .No_Progress:       return "multiple read calls return no data or error"
-	case .Invalid_Whence:    return "invalid whence"
-	case .Invalid_Offset:    return "invalid offset"
-	case .Invalid_Unread:    return "invalid unread"
-	case .Negative_Read:     return "negative read"
-	case .Negative_Write:    return "negative write"
-	case .Negative_Count:    return "negative count"
-	case .Buffer_Full:       return "buffer full"
+	if ferr == nil {
+		return ""
 	}
 	}
-
-	if errno, ok := is_platform_error(ferr); ok {
-		return _error_string(errno)
+	switch e in ferr {
+	case General_Error:
+		switch e {
+		case .None: return ""
+		case .Permission_Denied: return "permission denied"
+		case .Exist:             return "file already exists"
+		case .Not_Exist:         return "file does not exist"
+		case .Closed:            return "file already closed"
+		case .Timeout:           return "i/o timeout"
+		case .Invalid_File:      return "invalid file"
+		case .Invalid_Path:      return "invalid path"
+		case .Unsupported:       return "unsupported"
+		}
+	case io.Error:
+		switch e {
+		case .None: return ""
+		case .EOF:               return "eof"
+		case .Unexpected_EOF:    return "unexpected eof"
+		case .Short_Write:       return "short write"
+		case .Invalid_Write:     return "invalid write result"
+		case .Short_Buffer:      return "short buffer"
+		case .No_Progress:       return "multiple read calls return no data or error"
+		case .Invalid_Whence:    return "invalid whence"
+		case .Invalid_Offset:    return "invalid offset"
+		case .Invalid_Unread:    return "invalid unread"
+		case .Negative_Read:     return "negative read"
+		case .Negative_Write:    return "negative write"
+		case .Negative_Count:    return "negative count"
+		case .Buffer_Full:       return "buffer full"
+		case .Unknown, .Empty: //
+		}
+	case runtime.Allocator_Error:
+		switch e {
+		case .None:                 return ""
+		case .Out_Of_Memory:        return "out of memory"
+		case .Invalid_Pointer:      return "invalid allocator pointer"
+		case .Invalid_Argument:     return "invalid allocator argument"
+		case .Mode_Not_Implemented: return "allocator mode not implemented"
+		}
+	case Platform_Error:
+		return _error_string(i32(e))
 	}
 	}
 
 
 	return "unknown error"
 	return "unknown error"

+ 46 - 0
core/os/os2/errors_windows.odin

@@ -12,3 +12,49 @@ _error_string :: proc(errno: i32) -> string {
 	// FormatMessageW
 	// FormatMessageW
 	return ""
 	return ""
 }
 }
+
+_get_platform_error :: proc() -> Error {
+	err := win32.GetLastError()
+	if err == 0 {
+		return nil
+	}
+	switch err {
+	case win32.ERROR_ACCESS_DENIED, win32.ERROR_SHARING_VIOLATION:
+		return .Permission_Denied
+
+	case win32.ERROR_FILE_EXISTS, win32.ERROR_ALREADY_EXISTS:
+		return .Exist
+
+	case win32.ERROR_FILE_NOT_FOUND, win32.ERROR_PATH_NOT_FOUND:
+		return .Not_Exist
+
+	case win32.ERROR_NO_DATA:
+		return .Closed
+
+	case win32.ERROR_TIMEOUT, win32.WAIT_TIMEOUT:
+		return .Timeout
+
+	case win32.ERROR_NOT_SUPPORTED:
+		return .Unsupported
+
+	case
+		win32.ERROR_BAD_ARGUMENTS,
+		win32.ERROR_INVALID_PARAMETER,
+		win32.ERROR_NOT_ENOUGH_MEMORY,
+		win32.ERROR_INVALID_HANDLE,
+		win32.ERROR_NO_MORE_FILES,
+		win32.ERROR_LOCK_VIOLATION,
+		win32.ERROR_HANDLE_EOF,
+		win32.ERROR_BROKEN_PIPE,
+		win32.ERROR_CALL_NOT_IMPLEMENTED,
+		win32.ERROR_INSUFFICIENT_BUFFER,
+		win32.ERROR_INVALID_NAME,
+		win32.ERROR_LOCK_FAILED,
+		win32.ERROR_ENVVAR_NOT_FOUND,
+		win32.ERROR_OPERATION_ABORTED,
+		win32.ERROR_IO_PENDING,
+		win32.ERROR_NO_UNICODE_TRANSLATION:
+		// fallthrough
+	}
+	return Platform_Error(err)
+}

+ 6 - 4
core/os/os2/file_util.odin

@@ -74,7 +74,7 @@ read_ptr :: proc(f: ^File, data: rawptr, len: int) -> (n: int, err: Error) {
 
 
 
 
 
 
-read_entire_file :: proc(name: string, allocator := context.allocator) -> ([]byte, Error) {
+read_entire_file :: proc(name: string, allocator := context.allocator) -> (data: []byte, err: Error) {
 	f, ferr := open(name)
 	f, ferr := open(name)
 	if ferr != nil {
 	if ferr != nil {
 		return nil, ferr
 		return nil, ferr
@@ -91,15 +91,17 @@ read_entire_file :: proc(name: string, allocator := context.allocator) -> ([]byt
 
 
 	// TODO(bill): Is this correct logic?
 	// TODO(bill): Is this correct logic?
 	total: int
 	total: int
-	data := make([]byte, size, allocator)
+	data = make([]byte, size, allocator) or_return
 	for {
 	for {
-		n, err := read(f, data[total:])
+		n: int
+		n, err = read(f, data[total:])
 		total += n
 		total += n
 		if err != nil {
 		if err != nil {
 			if err == .EOF {
 			if err == .EOF {
 				err = nil
 				err = nil
 			}
 			}
-			return data[:total], err
+			data = data[:total]
+			return
 		}
 		}
 	}
 	}
 }
 }

+ 49 - 31
core/os/os2/file_windows.odin

@@ -3,6 +3,7 @@ package os2
 
 
 import "core:io"
 import "core:io"
 import "core:mem"
 import "core:mem"
+import "core:sync"
 import "core:runtime"
 import "core:runtime"
 import "core:strings"
 import "core:strings"
 import "core:time"
 import "core:time"
@@ -19,6 +20,12 @@ _file_allocator :: proc() -> runtime.Allocator {
 	return heap_allocator()
 	return heap_allocator()
 }
 }
 
 
+_temp_allocator :: proc() -> runtime.Allocator {
+	// TODO(bill): make this not depend on the context allocator
+	return context.temp_allocator
+}
+
+
 _File_Kind :: enum u8 {
 _File_Kind :: enum u8 {
 	File,
 	File,
 	Console,
 	Console,
@@ -30,20 +37,17 @@ _File :: struct {
 	name: string,
 	name: string,
 	wname: win32.wstring,
 	wname: win32.wstring,
 	kind: _File_Kind,
 	kind: _File_Kind,
+
+	allocator: runtime.Allocator,
+
+	rw_mutex: sync.RW_Mutex, // read write calls
+	p_mutex:  sync.Mutex, // pread pwrite calls
 }
 }
 
 
 _handle :: proc(f: ^File) -> win32.HANDLE {
 _handle :: proc(f: ^File) -> win32.HANDLE {
 	return win32.HANDLE(_fd(f))
 	return win32.HANDLE(_fd(f))
 }
 }
 
 
-_get_platform_error :: proc() -> Error {
-	err := i32(win32.GetLastError())
-	if err != 0 {
-		return Platform_Error{err}
-	}
-	return nil
-}
-
 _open_internal :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (handle: uintptr, err: Error) {
 _open_internal :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (handle: uintptr, err: Error) {
 	if len(name) == 0 {
 	if len(name) == 0 {
 		err = .Not_Exist
 		err = .Not_Exist
@@ -100,7 +104,7 @@ _open_internal :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (han
 				case 0:
 				case 0:
 					return uintptr(h), nil
 					return uintptr(h), nil
 				case:
 				case:
-					return 0, Platform_Error{i32(e)}
+					return 0, Platform_Error(e)
 				}
 				}
 			}
 			}
 		}
 		}
@@ -123,11 +127,12 @@ _new_file :: proc(handle: uintptr, name: string) -> ^File {
 	if handle == INVALID_HANDLE {
 	if handle == INVALID_HANDLE {
 		return nil
 		return nil
 	}
 	}
-	context.allocator = _file_allocator()
-	f := new(File)
+	f := new(File, _file_allocator())
+
+	f.impl.allocator = _file_allocator()
 	f.impl.fd = rawptr(fd)
 	f.impl.fd = rawptr(fd)
-	f.impl.name = strings.clone(name, context.allocator)
-	f.impl.wname = win32.utf8_to_wstring(name, context.allocator)
+	f.impl.name = strings.clone(name, f.impl.allocator)
+	f.impl.wname = win32.utf8_to_wstring(name, f.impl.allocator)
 
 
 	handle := _handle(f)
 	handle := _handle(f)
 	kind := _File_Kind.File
 	kind := _File_Kind.File
@@ -154,10 +159,10 @@ _destroy :: proc(f: ^File) -> Error {
 		return nil
 		return nil
 	}
 	}
 
 
-	context.allocator = _file_allocator()
-	free(f.impl.wname)
-	delete(f.impl.name)
-	free(f)
+	a := f.impl.allocator
+	free(f.impl.wname, a)
+	delete(f.impl.name, a)
+	free(f, a)
 	return nil
 	return nil
 }
 }
 
 
@@ -185,6 +190,8 @@ _seek :: proc(f: ^File, offset: i64, whence: Seek_From) -> (ret: i64, err: Error
 		return 0, .Invalid_File
 		return 0, .Invalid_File
 	}
 	}
 
 
+	sync.guard(&f.impl.rw_mutex)
+
 	w: u32
 	w: u32
 	switch whence {
 	switch whence {
 	case .Start:   w = win32.FILE_BEGIN
 	case .Start:   w = win32.FILE_BEGIN
@@ -207,6 +214,7 @@ _read :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
 			return 0, nil
 			return 0, nil
 		}
 		}
 
 
+		// TODO(bill): should this be moved to `_File` instead?
 		BUF_SIZE :: 386
 		BUF_SIZE :: 386
 		buf16: [BUF_SIZE]u16
 		buf16: [BUF_SIZE]u16
 		buf8: [4*BUF_SIZE]u8
 		buf8: [4*BUF_SIZE]u8
@@ -257,22 +265,27 @@ _read :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
 	total_read: int
 	total_read: int
 	length := len(p)
 	length := len(p)
 
 
-	to_read := min(win32.DWORD(length), MAX_RW)
+	sync.shared_guard(&f.impl.rw_mutex) // multiple readers
 
 
-	e: win32.BOOL
-	if f.impl.kind == .Console {
-		n, err := read_console(handle, p[total_read:][:to_read])
-		total_read += n
-		if err != nil {
-			return int(total_read), err
+	if sync.guard(&f.impl.p_mutex) {
+		to_read := min(win32.DWORD(length), MAX_RW)
+		ok: win32.BOOL
+		if f.impl.kind == .Console {
+			n, err := read_console(handle, p[total_read:][:to_read])
+			total_read += n
+			if err != nil {
+				return int(total_read), err
+			}
+		} else {
+			ok = win32.ReadFile(handle, &p[total_read], to_read, &single_read_length, nil)
+		}
+
+		if single_read_length > 0 && ok {
+			total_read += int(single_read_length)
+		} else {
+			err = _get_platform_error()
 		}
 		}
-	} else {
-		e = win32.ReadFile(handle, &p[total_read], to_read, &single_read_length, nil)
-	}
-	if single_read_length <= 0 || !e {
-		return int(total_read), _get_platform_error()
 	}
 	}
-	total_read += int(single_read_length)
 
 
 	return int(total_read), nil
 	return int(total_read), nil
 }
 }
@@ -303,6 +316,9 @@ _read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) {
 		n = int(done)
 		n = int(done)
 		return
 		return
 	}
 	}
+
+	sync.guard(&f.impl.p_mutex)
+
 	p, offset := p, offset
 	p, offset := p, offset
 	for len(p) > 0 {
 	for len(p) > 0 {
 		m := pread(f, p, offset) or_return
 		m := pread(f, p, offset) or_return
@@ -329,6 +345,7 @@ _write :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
 
 
 	handle := _handle(f)
 	handle := _handle(f)
 
 
+	sync.guard(&f.impl.rw_mutex)
 	for total_write < length {
 	for total_write < length {
 		remaining := length - total_write
 		remaining := length - total_write
 		to_write := win32.DWORD(min(i32(remaining), MAX_RW))
 		to_write := win32.DWORD(min(i32(remaining), MAX_RW))
@@ -369,6 +386,7 @@ _write_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) {
 		return
 		return
 	}
 	}
 
 
+	sync.guard(&f.impl.p_mutex)
 	p, offset := p, offset
 	p, offset := p, offset
 	for len(p) > 0 {
 	for len(p) > 0 {
 		m := pwrite(f, p, offset) or_return
 		m := pwrite(f, p, offset) or_return
@@ -531,7 +549,7 @@ _normalize_link_path :: proc(p: []u16, allocator: runtime.Allocator) -> (str: st
 	if n == 0 {
 	if n == 0 {
 		return "", _get_platform_error()
 		return "", _get_platform_error()
 	}
 	}
-	buf := make([]u16, n+1, context.temp_allocator)
+	buf := make([]u16, n+1, _temp_allocator())
 	n = win32.GetFinalPathNameByHandleW(handle, raw_data(buf), u32(len(buf)), win32.VOLUME_NAME_DOS)
 	n = win32.GetFinalPathNameByHandleW(handle, raw_data(buf), u32(len(buf)), win32.VOLUME_NAME_DOS)
 	if n == 0 {
 	if n == 0 {
 		return "", _get_platform_error()
 		return "", _get_platform_error()

+ 3 - 1
core/os/os2/path.odin

@@ -1,5 +1,7 @@
 package os2
 package os2
 
 
+import "core:runtime"
+
 Path_Separator      :: _Path_Separator      // OS-Specific
 Path_Separator      :: _Path_Separator      // OS-Specific
 Path_List_Separator :: _Path_List_Separator // OS-Specific
 Path_List_Separator :: _Path_List_Separator // OS-Specific
 
 
@@ -21,7 +23,7 @@ remove_all :: proc(path: string) -> Error {
 
 
 
 
 
 
-getwd :: proc(allocator := context.allocator) -> (dir: string, err: Error) {
+getwd :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
 	return _getwd(allocator)
 	return _getwd(allocator)
 }
 }
 setwd :: proc(dir: string) -> (err: Error) {
 setwd :: proc(dir: string) -> (err: Error) {

+ 54 - 3
core/os/os2/path_windows.odin

@@ -2,6 +2,8 @@
 package os2
 package os2
 
 
 import win32 "core:sys/windows"
 import win32 "core:sys/windows"
+import "core:runtime"
+import "core:strings"
 
 
 _Path_Separator      :: '\\'
 _Path_Separator      :: '\\'
 _Path_List_Separator :: ';'
 _Path_List_Separator :: ';'
@@ -11,11 +13,58 @@ _is_path_separator :: proc(c: byte) -> bool {
 }
 }
 
 
 _mkdir :: proc(name: string, perm: File_Mode) -> Error {
 _mkdir :: proc(name: string, perm: File_Mode) -> Error {
+	if !win32.CreateDirectoryW(_fix_long_path(name), nil) {
+		return _get_platform_error()
+	}
 	return nil
 	return nil
 }
 }
 
 
 _mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
 _mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
-	// TODO(bill): _mkdir_all for windows
+	fix_root_directory :: proc(p: string) -> (s: string, allocated: bool, err: runtime.Allocator_Error) {
+		if len(p) == len(`\\?\c:`) {
+			if is_path_separator(p[0]) && is_path_separator(p[1]) && p[2] == '?' && is_path_separator(p[3]) && p[5] == ':' {
+				s = strings.concatenate_safe({p, `\`}, _file_allocator()) or_return
+				allocated = true
+				return
+			}
+		}
+		return p, false, nil
+	}
+
+	dir, err := stat(path, _temp_allocator())
+	if err == nil {
+		if dir.is_dir {
+			return nil
+		}
+		return .Exist
+	}
+
+	i := len(path)
+	for i > 0 && is_path_separator(path[i-1]) {
+		i -= 1
+	}
+
+	j := i
+	for j > 0 && !is_path_separator(path[j-1]) {
+		j -= 1
+	}
+
+	if j > 1 {
+		new_path, allocated := fix_root_directory(path[:j-1]) or_return
+		defer if allocated {
+			delete(new_path, _file_allocator())
+		}
+		mkdir_all(new_path, perm) or_return
+	}
+
+	err = mkdir(path, perm)
+	if err != nil {
+		dir1, err1 := lstat(path, _temp_allocator())
+		if err1 == nil && dir1.is_dir {
+			return nil
+		}
+		return err
+	}
 	return nil
 	return nil
 }
 }
 
 
@@ -24,11 +73,13 @@ _remove_all :: proc(path: string) -> Error {
 	return nil
 	return nil
 }
 }
 
 
-_getwd :: proc(allocator := context.allocator) -> (dir: string, err: Error) {
+_getwd :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
+	// TODO(bill)
 	return "", nil
 	return "", nil
 }
 }
 
 
 _setwd :: proc(dir: string) -> (err: Error) {
 _setwd :: proc(dir: string) -> (err: Error) {
+	// TODO(bill)
 	return nil
 	return nil
 }
 }
 
 
@@ -75,7 +126,7 @@ _fix_long_path_internal :: proc(path: string) -> string {
 	}
 	}
 
 
 	PREFIX :: `\\?`
 	PREFIX :: `\\?`
-	path_buf := make([]byte, len(PREFIX)+len(path)+1, context.temp_allocator)
+	path_buf := make([]byte, len(PREFIX)+len(path)+1, _temp_allocator())
 	copy(path_buf, PREFIX)
 	copy(path_buf, PREFIX)
 	n := len(path)
 	n := len(path)
 	r, w := 0, len(PREFIX)
 	r, w := 0, len(PREFIX)

+ 1 - 1
core/os/os2/pipe_windows.odin

@@ -6,7 +6,7 @@ import win32 "core:sys/windows"
 _pipe :: proc() -> (r, w: ^File, err: Error) {
 _pipe :: proc() -> (r, w: ^File, err: Error) {
 	p: [2]win32.HANDLE
 	p: [2]win32.HANDLE
 	if !win32.CreatePipe(&p[0], &p[1], nil, 0) {
 	if !win32.CreatePipe(&p[0], &p[1], nil, 0) {
-		return nil, nil, Platform_Error{i32(win32.GetLastError())}
+		return nil, nil, _get_platform_error()
 	}
 	}
 	return new_file(uintptr(p[0]), ""), new_file(uintptr(p[1]), ""), nil
 	return new_file(uintptr(p[0]), ""), new_file(uintptr(p[1]), ""), nil
 }
 }

+ 6 - 5
core/os/os2/stat.odin

@@ -1,6 +1,7 @@
 package os2
 package os2
 
 
 import "core:time"
 import "core:time"
+import "core:runtime"
 
 
 File_Info :: struct {
 File_Info :: struct {
 	fullpath: string,
 	fullpath: string,
@@ -13,26 +14,26 @@ File_Info :: struct {
 	access_time:       time.Time,
 	access_time:       time.Time,
 }
 }
 
 
-file_info_slice_delete :: proc(infos: []File_Info, allocator := context.allocator) {
+file_info_slice_delete :: proc(infos: []File_Info, allocator: runtime.Allocator) {
 	for i := len(infos)-1; i >= 0; i -= 1 {
 	for i := len(infos)-1; i >= 0; i -= 1 {
 		file_info_delete(infos[i], allocator)
 		file_info_delete(infos[i], allocator)
 	}
 	}
 	delete(infos, allocator)
 	delete(infos, allocator)
 }
 }
 
 
-file_info_delete :: proc(fi: File_Info, allocator := context.allocator) {
+file_info_delete :: proc(fi: File_Info, allocator: runtime.Allocator) {
 	delete(fi.fullpath, allocator)
 	delete(fi.fullpath, allocator)
 }
 }
 
 
-fstat :: proc(f: ^File, allocator := context.allocator) -> (File_Info, Error) {
+fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (File_Info, Error) {
 	return _fstat(f, allocator)
 	return _fstat(f, allocator)
 }
 }
 
 
-stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) {
+stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
 	return _stat(name, allocator)
 	return _stat(name, allocator)
 }
 }
 
 
-lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) {
+lstat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
 	return _lstat(name, allocator)
 	return _lstat(name, allocator)
 }
 }
 
 

+ 56 - 84
core/os/os2/stat_windows.odin

@@ -1,22 +1,22 @@
 //+private
 //+private
 package os2
 package os2
 
 
+import "core:runtime"
 import "core:time"
 import "core:time"
 import "core:strings"
 import "core:strings"
 import win32 "core:sys/windows"
 import win32 "core:sys/windows"
 
 
-_fstat :: proc(f: ^File, allocator := context.allocator) -> (File_Info, Error) {
+_fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (File_Info, Error) {
 	if f == nil || f.impl.fd == nil {
 	if f == nil || f.impl.fd == nil {
-		return {}, .Invalid_Argument
+		return {}, nil
 	}
 	}
-	context.allocator = allocator
 
 
-	path, err := _cleanpath_from_handle(f)
+	path, err := _cleanpath_from_handle(f, allocator)
 	if err != nil {
 	if err != nil {
 		return {}, err
 		return {}, err
 	}
 	}
 
 
-	h := win32.HANDLE(f.impl.fd)
+	h := _handle(f)
 	switch win32.GetFileType(h) {
 	switch win32.GetFileType(h) {
 	case win32.FILE_TYPE_PIPE, win32.FILE_TYPE_CHAR:
 	case win32.FILE_TYPE_PIPE, win32.FILE_TYPE_CHAR:
 		fi: File_Info
 		fi: File_Info
@@ -26,13 +26,13 @@ _fstat :: proc(f: ^File, allocator := context.allocator) -> (File_Info, Error) {
 		return fi, nil
 		return fi, nil
 	}
 	}
 
 
-	return _file_info_from_get_file_information_by_handle(path, h)
+	return _file_info_from_get_file_information_by_handle(path, h, allocator)
 }
 }
-_stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) {
-	return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS)
+_stat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
+	return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS, allocator)
 }
 }
-_lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) {
-	return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS|win32.FILE_FLAG_OPEN_REPARSE_POINT)
+_lstat :: proc(name: string, allocator: runtime.Allocator) -> (File_Info, Error) {
+	return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS|win32.FILE_FLAG_OPEN_REPARSE_POINT, allocator)
 }
 }
 _same_file :: proc(fi1, fi2: File_Info) -> bool {
 _same_file :: proc(fi1, fi2: File_Info) -> bool {
 	return fi1.fullpath == fi2.fullpath
 	return fi1.fullpath == fi2.fullpath
@@ -40,50 +40,38 @@ _same_file :: proc(fi1, fi2: File_Info) -> bool {
 
 
 
 
 
 
-_stat_errno :: proc(errno: win32.DWORD) -> Error {
-	return Platform_Error{i32(errno)}
-}
-
 
 
-full_path_from_name :: proc(name: string, allocator := context.allocator) -> (path: string, err: Error) {
-	context.allocator = allocator
-	
+full_path_from_name :: proc(name: string, allocator: runtime.Allocator) -> (path: string, err: Error) {
 	name := name
 	name := name
 	if name == "" {
 	if name == "" {
 		name = "."
 		name = "."
 	}
 	}
-	p := win32.utf8_to_utf16(name, context.temp_allocator)
-	buf := make([dynamic]u16, 100)
-	for {
-		n := win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil)
-		if n == 0 {
-			delete(buf)
-			return "", _stat_errno(win32.GetLastError())
-		}
-		if n <= u32(len(buf)) {
-			return win32.utf16_to_utf8(buf[:n]), nil
-		}
-		resize(&buf, len(buf)*2)
-	}
+	p := win32.utf8_to_utf16(name, _temp_allocator())
 
 
-	return
+	n := win32.GetFullPathNameW(raw_data(p), 0, nil, nil)
+	if n == 0 {
+		return "", _get_platform_error()
+	}
+	buf := make([]u16, n+1, _temp_allocator())
+	n = win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil)
+	if n == 0 {
+		return "", _get_platform_error()
+	}
+	return win32.utf16_to_utf8(buf[:n], allocator), nil
 }
 }
 
 
 
 
-internal_stat :: proc(name: string, create_file_attributes: u32, allocator := context.allocator) -> (fi: File_Info, e: Error) {
+internal_stat :: proc(name: string, create_file_attributes: u32, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) {
 	if len(name) == 0 {
 	if len(name) == 0 {
 		return {}, .Not_Exist
 		return {}, .Not_Exist
 	}
 	}
 
 
-	context.allocator = allocator
-
-
 	wname := _fix_long_path(name)
 	wname := _fix_long_path(name)
 	fa: win32.WIN32_FILE_ATTRIBUTE_DATA
 	fa: win32.WIN32_FILE_ATTRIBUTE_DATA
 	ok := win32.GetFileAttributesExW(wname, win32.GetFileExInfoStandard, &fa)
 	ok := win32.GetFileAttributesExW(wname, win32.GetFileExInfoStandard, &fa)
 	if ok && fa.dwFileAttributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
 	if ok && fa.dwFileAttributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
 		// Not a symlink
 		// Not a symlink
-		return _file_info_from_win32_file_attribute_data(&fa, name)
+		return _file_info_from_win32_file_attribute_data(&fa, name, allocator)
 	}
 	}
 
 
 	err := 0 if ok else win32.GetLastError()
 	err := 0 if ok else win32.GetLastError()
@@ -97,7 +85,7 @@ internal_stat :: proc(name: string, create_file_attributes: u32, allocator := co
 		}
 		}
 		win32.FindClose(sh)
 		win32.FindClose(sh)
 
 
-		return _file_info_from_win32_find_data(&fd, name)
+		return _file_info_from_win32_find_data(&fd, name, allocator)
 	}
 	}
 
 
 	h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil)
 	h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil)
@@ -106,7 +94,7 @@ internal_stat :: proc(name: string, create_file_attributes: u32, allocator := co
 		return
 		return
 	}
 	}
 	defer win32.CloseHandle(h)
 	defer win32.CloseHandle(h)
-	return _file_info_from_get_file_information_by_handle(name, h)
+	return _file_info_from_get_file_information_by_handle(name, h, allocator)
 }
 }
 
 
 
 
@@ -131,56 +119,40 @@ _cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 {
 }
 }
 
 
 
 
-_cleanpath_from_handle :: proc(f: ^File) -> (string, Error) {
+_cleanpath_from_handle :: proc(f: ^File, allocator: runtime.Allocator) -> (string, Error) {
 	if f == nil || f.impl.fd == nil {
 	if f == nil || f.impl.fd == nil {
-		return "", .Invalid_Argument
-	}
-	h := win32.HANDLE(f.impl.fd)
-
-	MAX_PATH := win32.DWORD(260) + 1
-	buf: []u16
-	for {
-		buf = make([]u16, MAX_PATH, context.temp_allocator)
-		err := win32.GetFinalPathNameByHandleW(h, raw_data(buf), MAX_PATH, 0)
-		switch err {
-		case win32.ERROR_PATH_NOT_FOUND, win32.ERROR_INVALID_PARAMETER:
-			return "", _stat_errno(err)
-		case win32.ERROR_NOT_ENOUGH_MEMORY:
-			MAX_PATH = MAX_PATH*2 + 1
-			continue
-		}
-		break
+		return "", nil
+	}
+	h := _handle(f)
+
+	n := win32.GetFinalPathNameByHandleW(h, nil, 0, 0)
+	if n == 0 {
+		return "", _get_platform_error()
 	}
 	}
-	return _cleanpath_from_buf(buf), nil
+	buf := make([]u16, max(n, 260)+1, _temp_allocator())
+	n = win32.GetFinalPathNameByHandleW(h, raw_data(buf), u32(len(buf)), 0)
+	return _cleanpath_from_buf(buf[:n], allocator), nil
 }
 }
 
 
 _cleanpath_from_handle_u16 :: proc(f: ^File) -> ([]u16, Error) {
 _cleanpath_from_handle_u16 :: proc(f: ^File) -> ([]u16, Error) {
 	if f == nil || f.impl.fd == nil {
 	if f == nil || f.impl.fd == nil {
-		return nil, .Invalid_Argument
-	}
-	h := win32.HANDLE(f.impl.fd)
-
-	MAX_PATH := win32.DWORD(260) + 1
-	buf: []u16
-	for {
-		buf = make([]u16, MAX_PATH, context.temp_allocator)
-		err := win32.GetFinalPathNameByHandleW(h, raw_data(buf), MAX_PATH, 0)
-		switch err {
-		case win32.ERROR_PATH_NOT_FOUND, win32.ERROR_INVALID_PARAMETER:
-			return nil, _stat_errno(err)
-		case win32.ERROR_NOT_ENOUGH_MEMORY:
-			MAX_PATH = MAX_PATH*2 + 1
-			continue
-		}
-		break
+		return nil, nil
+	}
+	h := _handle(f)
+
+	n := win32.GetFinalPathNameByHandleW(h, nil, 0, 0)
+	if n == 0 {
+		return nil, _get_platform_error()
 	}
 	}
-	return _cleanpath_strip_prefix(buf), nil
+	buf := make([]u16, max(n, 260)+1, _temp_allocator())
+	n = win32.GetFinalPathNameByHandleW(h, raw_data(buf), u32(len(buf)), 0)
+	return _cleanpath_strip_prefix(buf[:n]), nil
 }
 }
 
 
-_cleanpath_from_buf :: proc(buf: []u16) -> string {
+_cleanpath_from_buf :: proc(buf: []u16, allocator: runtime.Allocator) -> string {
 	buf := buf
 	buf := buf
 	buf = _cleanpath_strip_prefix(buf)
 	buf = _cleanpath_strip_prefix(buf)
-	return win32.utf16_to_utf8(buf, context.allocator)
+	return win32.utf16_to_utf8(buf, allocator)
 }
 }
 
 
 
 
@@ -252,7 +224,7 @@ _file_mode_from_file_attributes :: proc(FileAttributes: win32.DWORD, h: win32.HA
 }
 }
 
 
 
 
-_file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_DATA, name: string) -> (fi: File_Info, e: Error) {
+_file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_DATA, name: string, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) {
 	fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
 	fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
 
 
 	fi.mode |= _file_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
 	fi.mode |= _file_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
@@ -262,14 +234,14 @@ _file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE
 	fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
 	fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
 	fi.access_time       = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
 	fi.access_time       = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
 
 
-	fi.fullpath, e = full_path_from_name(name)
+	fi.fullpath, e = full_path_from_name(name, allocator)
 	fi.name = basename(fi.fullpath)
 	fi.name = basename(fi.fullpath)
 
 
 	return
 	return
 }
 }
 
 
 
 
-_file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string) -> (fi: File_Info, e: Error) {
+_file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string, allocator: runtime.Allocator) -> (fi: File_Info, e: Error) {
 	fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
 	fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
 
 
 	fi.mode |= _file_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
 	fi.mode |= _file_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
@@ -279,17 +251,17 @@ _file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string
 	fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
 	fi.modification_time = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastWriteTime))
 	fi.access_time       = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
 	fi.access_time       = time.unix(0, win32.FILETIME_as_unix_nanoseconds(d.ftLastAccessTime))
 
 
-	fi.fullpath, e = full_path_from_name(name)
+	fi.fullpath, e = full_path_from_name(name, allocator)
 	fi.name = basename(fi.fullpath)
 	fi.name = basename(fi.fullpath)
 
 
 	return
 	return
 }
 }
 
 
 
 
-_file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE) -> (File_Info, Error) {
+_file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE, allocator: runtime.Allocator) -> (File_Info, Error) {
 	d: win32.BY_HANDLE_FILE_INFORMATION
 	d: win32.BY_HANDLE_FILE_INFORMATION
 	if !win32.GetFileInformationByHandle(h, &d) {
 	if !win32.GetFileInformationByHandle(h, &d) {
-		return {}, _stat_errno(win32.GetLastError())
+		return {}, _get_platform_error()
 
 
 	}
 	}
 
 
@@ -297,7 +269,7 @@ _file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HA
 	if !win32.GetFileInformationByHandleEx(h, .FileAttributeTagInfo, &ti, size_of(ti)) {
 	if !win32.GetFileInformationByHandleEx(h, .FileAttributeTagInfo, &ti, size_of(ti)) {
 		err := win32.GetLastError()
 		err := win32.GetLastError()
 		if err != win32.ERROR_INVALID_PARAMETER {
 		if err != win32.ERROR_INVALID_PARAMETER {
-			return {}, _stat_errno(err)
+			return {}, Platform_Error(err)
 		}
 		}
 		// Indicate this is a symlink on FAT file systems
 		// Indicate this is a symlink on FAT file systems
 		ti.ReparseTag = 0
 		ti.ReparseTag = 0

+ 4 - 3
core/os/os2/temp_file.odin

@@ -1,14 +1,15 @@
 package os2
 package os2
 
 
+import "core:runtime"
 
 
 create_temp :: proc(dir, pattern: string) -> (^File, Error) {
 create_temp :: proc(dir, pattern: string) -> (^File, Error) {
 	return _create_temp(dir, pattern)
 	return _create_temp(dir, pattern)
 }
 }
 
 
-mkdir_temp :: proc(dir, pattern: string, allocator := context.allocator) -> (string, Error) {
-	return _mkdir_temp(dir, pattern)
+mkdir_temp :: proc(dir, pattern: string, allocator: runtime.Allocator) -> (string, Error) {
+	return _mkdir_temp(dir, pattern, allocator)
 }
 }
 
 
-temp_dir :: proc(allocator := context.allocator) -> string {
+temp_dir :: proc(allocator: runtime.Allocator) -> string {
 	return _temp_dir(allocator)
 	return _temp_dir(allocator)
 }
 }

+ 14 - 14
core/os/os2/temp_file_windows.odin

@@ -1,29 +1,29 @@
 //+private
 //+private
 package os2
 package os2
 
 
+import "core:runtime"
 import win32 "core:sys/windows"
 import win32 "core:sys/windows"
 
 
 _create_temp :: proc(dir, pattern: string) -> (^File, Error) {
 _create_temp :: proc(dir, pattern: string) -> (^File, Error) {
 	return nil, nil
 	return nil, nil
 }
 }
 
 
-_mkdir_temp :: proc(dir, pattern: string, allocator := context.allocator) -> (string, Error) {
+_mkdir_temp :: proc(dir, pattern: string, allocator: runtime.Allocator) -> (string, Error) {
 	return "", nil
 	return "", nil
 }
 }
 
 
-_temp_dir :: proc(allocator := context.allocator) -> string {
-	b := make([dynamic]u16, u32(win32.MAX_PATH), context.temp_allocator)
-	for {
-		n := win32.GetTempPathW(u32(len(b)), raw_data(b))
-		if n > u32(len(b)) {
-			resize(&b, int(n))
-			continue
-		}
-		if n == 3 && b[1] == ':' && b[2] == '\\' {
+_temp_dir :: proc(allocator: runtime.Allocator) -> string {
+	n := win32.GetTempPathW(0, nil)
+	if n == 0 {
+		return ""
+	}
+	b := make([]u16, max(win32.MAX_PATH, n), _temp_allocator())
+	n = win32.GetTempPathW(u32(len(b)), raw_data(b))
+
+	if n == 3 && b[1] == ':' && b[2] == '\\' {
 
 
-		} else if n > 0 && b[n-1] == '\\' {
-			n -= 1
-		}
-		return win32.utf16_to_utf8(b[:n], allocator)
+	} else if n > 0 && b[n-1] == '\\' {
+		n -= 1
 	}
 	}
+	return win32.utf16_to_utf8(b[:n], allocator)
 }
 }

+ 18 - 13
core/os/os2/user.odin

@@ -1,18 +1,19 @@
 package os2
 package os2
 
 
 import "core:strings"
 import "core:strings"
+import "core:runtime"
 
 
-user_cache_dir :: proc(allocator := context.allocator) -> (dir: string, is_defined: bool) {
+user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
 	#partial switch ODIN_OS {
 	#partial switch ODIN_OS {
 	case .Windows:
 	case .Windows:
 		dir = get_env("LocalAppData")
 		dir = get_env("LocalAppData")
 		if dir != "" {
 		if dir != "" {
-			dir = strings.clone(dir, allocator)
+			dir = strings.clone_safe(dir, allocator) or_return
 		}
 		}
 	case .Darwin:
 	case .Darwin:
 		dir = get_env("HOME")
 		dir = get_env("HOME")
 		if dir != "" {
 		if dir != "" {
-			dir = strings.concatenate({dir, "/Library/Caches"}, allocator)
+			dir = strings.concatenate_safe({dir, "/Library/Caches"}, allocator) or_return
 		}
 		}
 	case: // All other UNIX systems
 	case: // All other UNIX systems
 		dir = get_env("XDG_CACHE_HOME")
 		dir = get_env("XDG_CACHE_HOME")
@@ -21,24 +22,26 @@ user_cache_dir :: proc(allocator := context.allocator) -> (dir: string, is_defin
 			if dir == "" {
 			if dir == "" {
 				return
 				return
 			}
 			}
-			dir = strings.concatenate({dir, "/.cache"}, allocator)
+			dir = strings.concatenate_safe({dir, "/.cache"}, allocator) or_return
 		}
 		}
 	}
 	}
-	is_defined = dir != ""
+	if dir == "" {
+		err = .Invalid_Path
+	}
 	return
 	return
 }
 }
 
 
-user_config_dir :: proc(allocator := context.allocator) -> (dir: string, is_defined: bool) {
+user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
 	#partial switch ODIN_OS {
 	#partial switch ODIN_OS {
 	case .Windows:
 	case .Windows:
 		dir = get_env("AppData")
 		dir = get_env("AppData")
 		if dir != "" {
 		if dir != "" {
-			dir = strings.clone(dir, allocator)
+			dir = strings.clone_safe(dir, allocator) or_return
 		}
 		}
 	case .Darwin:
 	case .Darwin:
 		dir = get_env("HOME")
 		dir = get_env("HOME")
 		if dir != "" {
 		if dir != "" {
-			dir = strings.concatenate({dir, "/Library/Application Support"}, allocator)
+			dir = strings.concatenate_safe({dir, "/Library/Application Support"}, allocator) or_return
 		}
 		}
 	case: // All other UNIX systems
 	case: // All other UNIX systems
 		dir = get_env("XDG_CACHE_HOME")
 		dir = get_env("XDG_CACHE_HOME")
@@ -47,22 +50,24 @@ user_config_dir :: proc(allocator := context.allocator) -> (dir: string, is_defi
 			if dir == "" {
 			if dir == "" {
 				return
 				return
 			}
 			}
-			dir = strings.concatenate({dir, "/.config"}, allocator)
+			dir = strings.concatenate_safe({dir, "/.config"}, allocator) or_return
 		}
 		}
 	}
 	}
-	is_defined = dir != ""
+	if dir == "" {
+		err = .Invalid_Path
+	}
 	return
 	return
 }
 }
 
 
-user_home_dir :: proc() -> (dir: string, is_defined: bool) {
+user_home_dir :: proc() -> (dir: string, err: Error) {
 	env := "HOME"
 	env := "HOME"
 	#partial switch ODIN_OS {
 	#partial switch ODIN_OS {
 	case .Windows:
 	case .Windows:
 		env = "USERPROFILE"
 		env = "USERPROFILE"
 	}
 	}
 	if v := get_env(env); v != "" {
 	if v := get_env(env); v != "" {
-		return v, true
+		return v, nil
 	}
 	}
-	return "", false
+	return "", .Invalid_Path
 }
 }
 
 

+ 0 - 1
core/os/stat_unix.odin

@@ -119,7 +119,6 @@ lstat :: proc(name: string, allocator := context.allocator) -> (fi: File_Info, e
 }
 }
 
 
 stat :: proc(name: string, allocator := context.allocator) -> (fi: File_Info, err: Errno) {
 stat :: proc(name: string, allocator := context.allocator) -> (fi: File_Info, err: Errno) {
-
 	context.allocator = allocator
 	context.allocator = allocator
 
 
 	s: OS_Stat
 	s: OS_Stat

+ 1 - 0
core/sys/windows/types.odin

@@ -1140,6 +1140,7 @@ ERROR_BROKEN_PIPE: DWORD : 109
 ERROR_CALL_NOT_IMPLEMENTED: DWORD : 120
 ERROR_CALL_NOT_IMPLEMENTED: DWORD : 120
 ERROR_INSUFFICIENT_BUFFER: DWORD : 122
 ERROR_INSUFFICIENT_BUFFER: DWORD : 122
 ERROR_INVALID_NAME: DWORD : 123
 ERROR_INVALID_NAME: DWORD : 123
+ERROR_BAD_ARGUMENTS: DWORD: 160
 ERROR_LOCK_FAILED: DWORD : 167
 ERROR_LOCK_FAILED: DWORD : 167
 ERROR_ALREADY_EXISTS: DWORD : 183
 ERROR_ALREADY_EXISTS: DWORD : 183
 ERROR_NO_DATA: DWORD : 232
 ERROR_NO_DATA: DWORD : 232