Browse Source

Start filling in the file_windows.odin procedures

gingerBill 3 years ago
parent
commit
9c3cdc4620

+ 0 - 14
core/os/os2/errors.odin

@@ -24,12 +24,6 @@ Error :: union {
 }
 #assert(size_of(Error) == size_of(u64))
 
-Path_Error :: struct {
-	op:   string,
-	path: string,
-	err:  Error,
-}
-
 Link_Error :: struct {
 	op:  string,
 	old: string,
@@ -37,14 +31,6 @@ Link_Error :: struct {
 	err: Error,
 }
 
-path_error_delete :: proc(perr: Maybe(Path_Error)) {
-	if err, ok := perr.?; ok {
-		context.allocator = error_allocator()
-		delete(err.op)
-		delete(err.path)
-	}
-}
-
 link_error_delete :: proc(lerr: Maybe(Link_Error)) {
 	if err, ok := lerr.?; ok {
 		context.allocator = error_allocator()

+ 38 - 22
core/os/os2/file.odin

@@ -5,6 +5,8 @@ import "core:time"
 
 Handle :: distinct uintptr
 
+INVALID_HANDLE :: ~Handle(0)
+
 Seek_From :: enum {
 	Start   = 0, // seek relative to the origin of the file
 	Current = 1, // seek relative to the current offset
@@ -27,6 +29,7 @@ File_Flag :: enum u32 {
 	Excl   = 4,
 	Sync   = 5,
 	Trunc  = 6,
+	Close_On_Exec = 7,
 }
 File_Flags :: distinct bit_set[File_Flag; u32]
 
@@ -38,24 +41,32 @@ O_CREATE :: File_Flags{.Create}
 O_EXCL   :: File_Flags{.Excl}
 O_SYNC   :: File_Flags{.Sync}
 O_TRUNC  :: File_Flags{.Trunc}
+O_CLOEXEC :: File_Flags{.Close_On_Exec}
 
+Std_Handle_Kind :: enum u8 {
+	stdin  = 0,
+	stdout = 1,
+	stderr = 2,
+}
 
+stdin:  Handle = std_handle(.stdin)
+stdout: Handle = std_handle(.stdout)
+stderr: Handle = std_handle(.stderr)
 
-stdin:  Handle = 0 // OS-Specific
-stdout: Handle = 1 // OS-Specific
-stderr: Handle = 2 // OS-Specific
-
-
-create :: proc(name: string) -> (Handle, Error) {
-	return _create(name)
+std_handle :: proc(kind: Std_Handle_Kind) -> Handle {
+	return _std_handle(kind)
 }
 
-open :: proc(name: string) -> (Handle, Error) {
-	return _open(name)
+create :: proc(name: string, perm: File_Mode = 0) -> (Handle, Error) {
+	return open(name, {.Read, .Write, .Create}, perm)
 }
 
-open_file :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Error) {
-	return _open_file(name, flags, perm)
+open :: proc(name: string, flags := File_Flags{.Read}, perm: File_Mode = 0) -> (Handle, Error) {
+	flags := flags
+	if .Write not_in flags {
+		flags += {.Read}
+	}
+	return _open(name, flags, perm)
 }
 
 close :: proc(fd: Handle) -> Error {
@@ -107,31 +118,36 @@ flush :: proc(fd: Handle) -> Error {
 	return _flush(fd)
 }
 
-truncate :: proc(fd: Handle, size: i64) -> Maybe(Path_Error) {
+truncate :: proc(fd: Handle, size: i64) -> Error {
 	return _truncate(fd, size)
 }
 
-remove :: proc(name: string) -> Maybe(Path_Error) {
+remove :: proc(name: string) -> Error {
 	return _remove(name)
 }
 
-rename :: proc(old_path, new_path: string) -> Maybe(Path_Error) {
+rename :: proc(old_path, new_path: string) -> Error {
 	return _rename(old_path, new_path)
 }
 
 
-link :: proc(old_name, new_name: string) -> Maybe(Link_Error) {
+link :: proc(old_name, new_name: string) -> Error {
 	return _link(old_name, new_name)
 }
 
-symlink :: proc(old_name, new_name: string) -> Maybe(Link_Error) {
+symlink :: proc(old_name, new_name: string) -> Error {
 	return _symlink(old_name, new_name)
 }
 
-read_link :: proc(name: string) -> (string, Maybe(Path_Error)) {
+read_link :: proc(name: string) -> (string, Error) {
 	return _read_link(name)
 }
 
+unlink :: proc(path: string) -> Error {
+	return _unlink(path)
+}
+
+
 
 chdir :: proc(fd: Handle) -> Error {
 	return _chdir(fd)
@@ -151,7 +167,7 @@ lchown :: proc(name: string, uid, gid: int) -> Error {
 }
 
 
-chtimes :: proc(name: string, atime, mtime: time.Time) -> Maybe(Path_Error) {
+chtimes :: proc(name: string, atime, mtime: time.Time) -> Error {
 	return _chtimes(name, atime, mtime)
 }
 
@@ -159,11 +175,11 @@ exists :: proc(path: string) -> bool {
 	return _exists(path)
 }
 
-is_file :: proc(path: string) -> bool {
-	return _is_file(path)
+is_file :: proc(fd: Handle) -> bool {
+	return _is_file(fd)
 }
 
-is_dir :: proc(path: string) -> bool {
-	return _is_dir(path)
+is_dir :: proc(fd: Handle) -> bool {
+	return _is_dir(fd)
 }
 

+ 54 - 30
core/os/os2/file_util.odin

@@ -61,7 +61,6 @@ write_encoded_rune :: proc(fd: Handle, r: rune) -> (n: int, err: Error) {
 	return
 }
 
-
 write_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (n: int, err: Error) {
 	s := transmute([]byte)mem.Raw_Slice{data, len}
 	return write(fd, s)
@@ -73,35 +72,62 @@ read_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (n: int, err: Error) {
 }
 
 
+read_at_least :: proc(fd: Handle, buf: []byte, min: int) -> (n: int, err: Error) {
+	if len(buf) < min {
+		return 0, .Short_Buffer
+	}
+	for n < min && err == nil {
+		nn: int
+		nn, err = read(fd, buf[n:])
+		n += nn
+	}
+	if n >= min {
+		err = nil
+	}
+	return
+}
+
+read_full :: proc(fd: Handle, buf: []byte) -> (n: int, err: Error) {
+	return read_at_least(fd, buf, len(buf))
+}
+
+file_size_from_path :: proc(path: string) -> (length: i64, err: Error) {
+	fd := open(path, O_RDONLY, 0) or_return
+	defer close(fd)
+	return file_size(fd)
+}
+
+read_entire_file :: proc{
+	read_entire_file_from_path,
+	read_entire_file_from_handle,
+}
+
+read_entire_file_from_path :: proc(name: string, allocator := context.allocator) -> (data: []byte, err: Error) {
+	fd := open(name, {.Read}) or_return
+	defer close(fd)
+	return read_entire_file_from_handle(fd, allocator)
+}
 
-read_entire_file :: proc(name: string, allocator := context.allocator) -> ([]byte, Error) {
-	f, ferr := open(name)
-	if ferr != nil {
-		return nil, ferr
+read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator) -> (data: []byte, err: Error) {
+	length := file_size(fd) or_return
+	if length <= 0 {
+		return nil, nil
 	}
-	defer close(f)
 
-	size: int
-	if size64, err := file_size(f); err == nil {
-		if i64(int(size64)) != size64 {
-			size = int(size64)
-		}
+	if i64(int(length)) != length {
+		return nil, .Short_Buffer
 	}
-	size += 1 // for EOF
-
-	// TODO(bill): Is this correct logic?
-	total: int
-	data := make([]byte, size, allocator)
-	for {
-		n, err := read(f, data[total:])
-		total += n
-		if err != nil {
-			if err == .EOF {
-				err = nil
-			}
-			return data[:total], err
-		}
+
+	data = make([]byte, int(length), allocator)
+	if data == nil {
+		return nil, .Short_Buffer
+	}
+	defer if err != nil {
+		delete(data, allocator)
 	}
+
+	bytes_read := read_full(fd, data) or_return
+	return data[:bytes_read], nil
 }
 
 write_entire_file :: proc(name: string, data: []byte, perm: File_Mode, truncate := true) -> Error {
@@ -109,11 +135,9 @@ write_entire_file :: proc(name: string, data: []byte, perm: File_Mode, truncate
 	if truncate {
 		flags |= O_TRUNC
 	}
-	f, err := open_file(name, flags, perm)
-	if err != nil {
-		return err
-	}
-	_, err = write(f, data)
+	f := open(name, flags, perm) or_return
+
+	_, err := write(f, data)
 	if cerr := close(f); cerr != nil && err == nil {
 		err = cerr
 	}

+ 344 - 28
core/os/os2/file_windows.odin

@@ -3,36 +3,221 @@ package os2
 
 import "core:io"
 import "core:time"
-
-_create :: proc(name: string) -> (Handle, Error) {
-	return 0, nil
+import "core:unicode/utf16"
+import win32 "core:sys/windows"
+
+_get_platform_error :: proc() -> Error {
+	// TODO(bill): map some of these errors correctly
+	err := win32.GetLastError()
+	if err == 0 {
+		return nil
+	}
+	return Platform_Error{i32(err)}
 }
 
-_open :: proc(name: string) -> (Handle, Error) {
-	return 0, nil
+_std_handle :: proc(kind: Std_Handle_Kind) -> Handle {
+	get_handle :: proc(h: win32.DWORD) -> Handle {
+		fd := win32.GetStdHandle(h)
+		when size_of(uintptr) == 8 {
+			win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0)
+		}
+		return Handle(fd)
+	}
+
+	switch kind {
+	case .stdin:  return get_handle(win32.STD_INPUT_HANDLE)
+	case .stdout: return get_handle(win32.STD_OUTPUT_HANDLE)
+	case .stderr: return get_handle(win32.STD_ERROR_HANDLE)
+	}
+	unreachable()
 }
 
-_open_file :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Error) {
-	return 0, nil
+_open :: proc(path: string, flags: File_Flags, perm: File_Mode) -> (handle: Handle, err: Error) {
+	handle = INVALID_HANDLE
+	if len(path) == 0 {
+		err = .Not_Exist
+		return
+	}
+	access: u32
+	switch flags & O_RDONLY|O_WRONLY|O_RDWR {
+	case O_RDONLY: access = win32.FILE_GENERIC_READ
+	case O_WRONLY: access = win32.FILE_GENERIC_WRITE
+	case O_RDWR:   access = win32.FILE_GENERIC_READ | win32.FILE_GENERIC_WRITE
+	}
+
+	if .Append in flags {
+		access &~= win32.FILE_GENERIC_WRITE
+		access |=  win32.FILE_APPEND_DATA
+	}
+	if .Create in flags {
+		access |= win32.FILE_GENERIC_WRITE
+	}
+
+	share_mode := win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE
+	sa: ^win32.SECURITY_ATTRIBUTES = nil
+	sa_inherit := win32.SECURITY_ATTRIBUTES{nLength = size_of(win32.SECURITY_ATTRIBUTES), bInheritHandle = true}
+	if .Close_On_Exec in flags {
+		sa = &sa_inherit
+	}
+
+	create_mode: u32
+	switch {
+	case flags&(O_CREATE|O_EXCL) == (O_CREATE | O_EXCL):
+		create_mode = win32.CREATE_NEW
+	case flags&(O_CREATE|O_TRUNC) == (O_CREATE | O_TRUNC):
+		create_mode = win32.CREATE_ALWAYS
+	case flags&O_CREATE == O_CREATE:
+		create_mode = win32.OPEN_ALWAYS
+	case flags&O_TRUNC == O_TRUNC:
+		create_mode = win32.TRUNCATE_EXISTING
+	case:
+		create_mode = win32.OPEN_EXISTING
+	}
+	wide_path := win32.utf8_to_wstring(path)
+	handle = Handle(win32.CreateFileW(wide_path, access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL|win32.FILE_FLAG_BACKUP_SEMANTICS, nil))
+	if handle == INVALID_HANDLE {
+		err = _get_platform_error()
+	}
+	return
 }
 
 _close :: proc(fd: Handle) -> Error {
+	if fd == 0 {
+		return .Invalid_Argument
+	}
+	hnd := win32.HANDLE(fd)
+
+	file_info: win32.BY_HANDLE_FILE_INFORMATION
+	if ok := win32.GetFileInformationByHandle(hnd, &file_info); !ok {
+		return _get_platform_error()
+	}
+	if file_info.dwFileAttributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
+		return nil
+	}
+
+	if ok := win32.CloseHandle(hnd); !ok {
+		return _get_platform_error()
+	}
 	return nil
 }
 
 _name :: proc(fd: Handle, allocator := context.allocator) -> string {
-	return ""
+	FILE_NAME_NORMALIZED :: 0x0
+	handle := win32.HANDLE(fd)
+	buf_len := win32.GetFinalPathNameByHandleW(handle, nil, 0, FILE_NAME_NORMALIZED)
+	if buf_len == 0 {
+		return ""
+	}
+	buf := make([]u16, buf_len, context.temp_allocator)
+	n := win32.GetFinalPathNameByHandleW(handle, raw_data(buf), buf_len, FILE_NAME_NORMALIZED)
+	return win32.utf16_to_utf8(buf[:n], allocator)
 }
 
 _seek :: proc(fd: Handle, offset: i64, whence: Seek_From) -> (ret: i64, err: Error) {
+	new_offset: win32.LARGE_INTEGER
+	move_method: win32.DWORD
+	switch whence {
+	case .Start:   move_method = win32.FILE_BEGIN
+	case .Current: move_method = win32.FILE_CURRENT
+	case .End:     move_method = win32.FILE_END
+	}
+	ok := win32.SetFilePointerEx(win32.HANDLE(fd), win32.LARGE_INTEGER(offset), &new_offset, move_method)
+	ret = i64(new_offset)
+	if !ok {
+		err = .Invalid_Whence
+	}
 	return
 }
 
-_read :: proc(fd: Handle, p: []byte) -> (n: int, err: Error) {
+MAX_RW :: 1<<30
+
+@(private="file")
+_read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Error) {
+	if len(b) == 0 {
+		return 0, nil
+	}
+
+	BUF_SIZE :: 386
+	buf16: [BUF_SIZE]u16
+	buf8: [4*BUF_SIZE]u8
+
+	for n < len(b) && err == nil {
+		max_read := u32(min(BUF_SIZE, len(b)/4))
+
+		single_read_length: u32
+		ok := win32.ReadConsoleW(handle, &buf16[0], max_read, &single_read_length, nil)
+		if !ok {
+			err = _get_platform_error()
+		}
+
+		buf8_len := utf16.decode_to_utf8(buf8[:], buf16[:single_read_length])
+		src := buf8[:buf8_len]
+
+		ctrl_z := false
+		for i := 0; i < len(src) && n+i < len(b); i += 1 {
+			x := src[i]
+			if x == 0x1a { // ctrl-z
+				ctrl_z = true
+				break
+			}
+			b[n] = x
+			n += 1
+		}
+		if ctrl_z || single_read_length < len(buf16) {
+			break
+		}
+	}
+
 	return
 }
 
+_read :: proc(fd: Handle, p: []byte) -> (n: int, err: Error) {
+	if len(p) == 0 {
+		return 0, nil
+	}
+
+	handle := win32.HANDLE(fd)
+
+	m: u32
+	is_console := win32.GetConsoleMode(handle, &m)
+
+	single_read_length: win32.DWORD
+	total_read: int
+	length := len(p)
+
+	to_read := min(win32.DWORD(length), MAX_RW)
+
+	e: win32.BOOL
+	if is_console {
+		n, err := _read_console(handle, p[total_read:][:to_read])
+		total_read += n
+		if err != nil {
+			return int(total_read), err
+		}
+	} 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
+}
+
+
 _read_at :: proc(fd: Handle, p: []byte, offset: i64) -> (n: int, err: Error) {
+	if offset < 0 {
+		return 0, .Invalid_Offset
+	}
+
+	b, offset := p, offset
+	for len(b) > 0 {
+		m := _pread(fd, b, offset) or_return
+		n += m
+		b = b[m:]
+		offset += i64(m)
+	}
 	return
 }
 
@@ -40,11 +225,70 @@ _read_from :: proc(fd: Handle, r: io.Reader) -> (n: i64, err: Error) {
 	return
 }
 
+
+
+_pread :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
+	buf := data
+	if len(buf) > MAX_RW {
+		buf = buf[:MAX_RW]
+
+	}
+	curr_offset := seek(fd, offset, .Current) or_return
+	defer seek(fd, curr_offset, .Start)
+
+	o := win32.OVERLAPPED{
+		OffsetHigh = u32(offset>>32),
+		Offset = u32(offset),
+	}
+
+	// TODO(bill): Determine the correct behaviour for consoles
+
+	h := win32.HANDLE(fd)
+	done: win32.DWORD
+	if !win32.ReadFile(h, raw_data(buf), u32(len(buf)), &done, &o) {
+		_get_platform_error() or_return
+	}
+	return int(done), nil
+}
+
+_pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
+	buf := data
+	if len(buf) > MAX_RW {
+		buf = buf[:MAX_RW]
+
+	}
+	curr_offset := seek(fd, offset, .Current) or_return
+	defer seek(fd, curr_offset, .Start)
+
+	o := win32.OVERLAPPED{
+		OffsetHigh = u32(offset>>32),
+		Offset = u32(offset),
+	}
+
+	h := win32.HANDLE(fd)
+	done: win32.DWORD
+	if !win32.WriteFile(h, raw_data(buf), u32(len(buf)), &done, &o) {
+		_get_platform_error() or_return
+	}
+	return int(done), nil
+}
+
 _write :: proc(fd: Handle, p: []byte) -> (n: int, err: Error) {
 	return
 }
 
 _write_at :: proc(fd: Handle, p: []byte, offset: i64) -> (n: int, err: Error) {
+	if offset < 0 {
+		return 0, .Invalid_Offset
+	}
+
+	b, offset := p, offset
+	for len(b) > 0 {
+		m := _pwrite(fd, b, offset) or_return
+		n += m
+		b = b[m:]
+		offset += i64(m)
+	}
 	return
 }
 
@@ -53,7 +297,11 @@ _write_to :: proc(fd: Handle, w: io.Writer) -> (n: i64, err: Error) {
 }
 
 _file_size :: proc(fd: Handle) -> (n: i64, err: Error) {
-	return
+	length: win32.LARGE_INTEGER
+	if !win32.GetFileSizeEx(win32.HANDLE(fd), &length) {
+		err = _get_platform_error()
+	}
+	return i64(length), err
 }
 
 
@@ -62,34 +310,94 @@ _sync :: proc(fd: Handle) -> Error {
 }
 
 _flush :: proc(fd: Handle) -> Error {
+	if !win32.FlushFileBuffers(win32.HANDLE(fd)) {
+		return _get_platform_error()
+	}
 	return nil
 }
 
-_truncate :: proc(fd: Handle, size: i64) -> Maybe(Path_Error) {
+_truncate :: proc(fd: Handle, size: i64) -> Error {
+	offset := seek(fd, size, .Start) or_return
+	defer seek(fd, offset, .Start)
+
+	if !win32.SetEndOfFile(win32.HANDLE(fd)) {
+		return _get_platform_error()
+	}
 	return nil
 }
 
-_remove :: proc(name: string) -> Maybe(Path_Error) {
-	return nil
+_remove :: proc(name: string) -> Error {
+	p := win32.utf8_to_wstring(_fix_long_path(name))
+	err, err1: Error
+	if !win32.DeleteFileW(p) {
+		err = _get_platform_error()
+	}
+	if err == nil {
+		return nil
+	}
+	if !win32.RemoveDirectoryW(p) {
+		err1 = _get_platform_error()
+	}
+	if err1 == nil {
+		return nil
+	}
+
+	if err != err1 {
+		a := win32.GetFileAttributesW(p)
+		if a == ~u32(0) {
+			err = _get_platform_error()
+		} else {
+			if a & win32.FILE_ATTRIBUTE_DIRECTORY != 0 {
+				err = err1
+			} else if a & win32.FILE_ATTRIBUTE_READONLY != 0 {
+				if win32.SetFileAttributesW(p, a &~ win32.FILE_ATTRIBUTE_READONLY) {
+					err = nil
+					if !win32.DeleteFileW(p) {
+						err = _get_platform_error()
+					}
+				}
+			}
+		}
+	}
+
+	return err
 }
 
-_rename :: proc(old_path, new_path: string) -> Maybe(Path_Error) {
+_rename :: proc(old_path, new_path: string) -> Error {
+	from := win32.utf8_to_wstring(old_path, context.temp_allocator)
+	to := win32.utf8_to_wstring(new_path, context.temp_allocator)
+	if !win32.MoveFileExW(from, to, win32.MOVEFILE_REPLACE_EXISTING) {
+		return _get_platform_error()
+	}
 	return nil
 }
 
 
-_link :: proc(old_name, new_name: string) -> Maybe(Link_Error) {
+_link :: proc(old_name, new_name: string) -> Error {
+	n := win32.utf8_to_wstring(_fix_long_path(new_name))
+	o := win32.utf8_to_wstring(_fix_long_path(old_name))
+	if !win32.CreateHardLinkW(n, o, nil) {
+		return _get_platform_error()
+	}
 	return nil
 }
 
-_symlink :: proc(old_name, new_name: string) -> Maybe(Link_Error) {
+_symlink :: proc(old_name, new_name: string) -> Error {
 	return nil
 }
 
-_read_link :: proc(name: string) -> (string, Maybe(Path_Error)) {
+_read_link :: proc(name: string) -> (string, Error) {
 	return "", nil
 }
 
+_unlink :: proc(path: string) -> Error {
+	wpath := win32.utf8_to_wstring(path, context.temp_allocator)
+	if !win32.DeleteFileW(wpath) {
+		return _get_platform_error()
+	}
+	return nil
+}
+
 
 _chdir :: proc(fd: Handle) -> Error {
 	return nil
@@ -109,28 +417,36 @@ _lchown :: proc(name: string, uid, gid: int) -> Error {
 }
 
 
-_chtimes :: proc(name: string, atime, mtime: time.Time) -> Maybe(Path_Error) {
+_chtimes :: proc(name: string, atime, mtime: time.Time) -> Error {
 	return nil
 }
 
 
 _exists :: proc(path: string) -> bool {
-	return false
+	wpath := win32.utf8_to_wstring(path, context.temp_allocator)
+	return bool(win32.PathFileExistsW(wpath))
 }
 
-_is_file :: proc(path: string) -> bool {
-	return false
-}
+_is_file :: proc(fd: Handle) -> bool {
+	hnd := win32.HANDLE(fd)
 
-_is_dir :: proc(path: string) -> bool {
-	return false
+	file_info: win32.BY_HANDLE_FILE_INFORMATION
+	if ok := win32.GetFileInformationByHandle(hnd, &file_info); !ok {
+		return false
+	}
+	no_flags :: win32.FILE_ATTRIBUTE_DIRECTORY | win32.FILE_ATTRIBUTE_DEVICE
+	yes_flags :: win32.FILE_ATTRIBUTE_NORMAL
+	return (file_info.dwFileAttributes & no_flags == 0) && (file_info.dwFileAttributes & yes_flags != 0)
 }
 
+_is_dir :: proc(fd: Handle) -> bool {
+	hnd := win32.HANDLE(fd)
 
-_path_error_delete :: proc(perr: Maybe(Path_Error)) {
-
+	file_info: win32.BY_HANDLE_FILE_INFORMATION
+	if ok := win32.GetFileInformationByHandle(hnd, &file_info); !ok {
+		return false
+	}
+	return file_info.dwFileAttributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0
 }
 
-_link_error_delete :: proc(lerr: Maybe(Link_Error)) {
 
-}

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

@@ -7,15 +7,15 @@ is_path_separator :: proc(c: byte) -> bool {
 	return _is_path_separator(c)
 }
 
-mkdir :: proc(name: string, perm: File_Mode) -> Maybe(Path_Error) {
+mkdir :: proc(name: string, perm: File_Mode) -> Error {
 	return _mkdir(name, perm)
 }
 
-mkdir_all :: proc(path: string, perm: File_Mode) -> Maybe(Path_Error) {
+mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
 	return _mkdir_all(path, perm)
 }
 
-remove_all :: proc(path: string) -> Maybe(Path_Error) {
+remove_all :: proc(path: string) -> Error {
 	return _remove_all(path)
 }
 

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

@@ -8,16 +8,16 @@ _is_path_separator :: proc(c: byte) -> bool {
 	return c == '\\' || c == '/'
 }
 
-_mkdir :: proc(name: string, perm: File_Mode) -> Maybe(Path_Error) {
+_mkdir :: proc(name: string, perm: File_Mode) -> Error {
 	return nil
 }
 
-_mkdir_all :: proc(path: string, perm: File_Mode) -> Maybe(Path_Error) {
+_mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
 	// TODO(bill): _mkdir_all for windows
 	return nil
 }
 
-_remove_all :: proc(path: string) -> Maybe(Path_Error) {
+_remove_all :: proc(path: string) -> Error {
 	// TODO(bill): _remove_all for windows
 	return nil
 }

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

@@ -4,8 +4,12 @@ package os2
 import win32 "core:sys/windows"
 
 _pipe :: proc() -> (r, w: Handle, err: Error) {
+	sa: win32.SECURITY_ATTRIBUTES
+	sa.nLength = size_of(win32.SECURITY_ATTRIBUTES)
+	sa.bInheritHandle = true
+
 	p: [2]win32.HANDLE
-	if !win32.CreatePipe(&p[0], &p[1], nil, 0) {
+	if !win32.CreatePipe(&p[0], &p[1], &sa, 0) {
 		return 0, 0, Platform_Error{i32(win32.GetLastError())}
 	}
 	return Handle(p[0]), Handle(p[1]), nil

+ 3 - 3
core/os/os2/stat.odin

@@ -24,15 +24,15 @@ file_info_delete :: proc(fi: File_Info, allocator := context.allocator) {
 	delete(fi.fullpath, allocator)
 }
 
-fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Maybe(Path_Error)) {
+fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Error) {
 	return _fstat(fd, allocator)
 }
 
-stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Maybe(Path_Error)) {
+stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) {
 	return _stat(name, allocator)
 }
 
-lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Maybe(Path_Error)) {
+lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) {
 	return _lstat(name, allocator)
 }
 

+ 21 - 27
core/os/os2/stat_windows.odin

@@ -4,9 +4,9 @@ package os2
 import "core:time"
 import win32 "core:sys/windows"
 
-_fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Maybe(Path_Error)) {
+_fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Error) {
 	if fd == 0 {
-		return {}, Path_Error{err = .Invalid_Argument}
+		return {}, .Invalid_Argument
 	}
 	context.allocator = allocator
 
@@ -27,10 +27,10 @@ _fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Maybe(
 
 	return _file_info_from_get_file_information_by_handle(path, h)
 }
-_stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Maybe(Path_Error)) {
+_stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) {
 	return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS)
 }
-_lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Maybe(Path_Error)) {
+_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)
 }
 _same_file :: proc(fi1, fi2: File_Info) -> bool {
@@ -38,13 +38,7 @@ _same_file :: proc(fi1, fi2: File_Info) -> bool {
 }
 
 
-
-_stat_errno :: proc(errno: win32.DWORD) -> Path_Error {
-	return Path_Error{err = Platform_Error{i32(errno)}}
-}
-
-
-full_path_from_name :: proc(name: string, allocator := context.allocator) -> (path: string, err: Maybe(Path_Error)) {
+full_path_from_name :: proc(name: string, allocator := context.allocator) -> (path: string, err: Error) {
 	context.allocator = allocator
 	
 	name := name
@@ -57,7 +51,7 @@ full_path_from_name :: proc(name: string, allocator := context.allocator) -> (pa
 		n := win32.GetFullPathNameW(raw_data(p), u32(len(buf)), raw_data(buf), nil)
 		if n == 0 {
 			delete(buf)
-			return "", _stat_errno(win32.GetLastError())
+			return "", _get_platform_error()
 		}
 		if n <= u32(len(buf)) {
 			return win32.utf16_to_utf8(buf[:n]), nil
@@ -69,9 +63,9 @@ full_path_from_name :: proc(name: string, allocator := context.allocator) -> (pa
 }
 
 
-internal_stat :: proc(name: string, create_file_attributes: u32, allocator := context.allocator) -> (fi: File_Info, e: Maybe(Path_Error)) {
+internal_stat :: proc(name: string, create_file_attributes: u32, allocator := context.allocator) -> (fi: File_Info, e: Error) {
 	if len(name) == 0 {
-		return {}, Path_Error{err = .Not_Exist}
+		return {}, .Not_Exist
 	}
 
 	context.allocator = allocator
@@ -91,7 +85,7 @@ internal_stat :: proc(name: string, create_file_attributes: u32, allocator := co
 		fd: win32.WIN32_FIND_DATAW
 		sh := win32.FindFirstFileW(wname, &fd)
 		if sh == win32.INVALID_HANDLE_VALUE {
-			e = Path_Error{err = Platform_Error{i32(win32.GetLastError())}}
+			e = _get_platform_error()
 			return
 		}
 		win32.FindClose(sh)
@@ -101,7 +95,7 @@ internal_stat :: proc(name: string, create_file_attributes: u32, allocator := co
 
 	h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil)
 	if h == win32.INVALID_HANDLE_VALUE {
-		e = Path_Error{err = Platform_Error{i32(win32.GetLastError())}}
+		e = _get_platform_error()
 		return
 	}
 	defer win32.CloseHandle(h)
@@ -130,9 +124,9 @@ _cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 {
 }
 
 
-_cleanpath_from_handle :: proc(fd: Handle) -> (string, Maybe(Path_Error)) {
+_cleanpath_from_handle :: proc(fd: Handle) -> (string, Error) {
 	if fd == 0 {
-		return "", Path_Error{err = .Invalid_Argument}
+		return "", .Invalid_Argument
 	}
 	h := win32.HANDLE(fd)
 
@@ -143,7 +137,7 @@ _cleanpath_from_handle :: proc(fd: Handle) -> (string, Maybe(Path_Error)) {
 		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)
+			return "", Platform_Error{i32(err)}
 		case win32.ERROR_NOT_ENOUGH_MEMORY:
 			MAX_PATH = MAX_PATH*2 + 1
 			continue
@@ -153,9 +147,9 @@ _cleanpath_from_handle :: proc(fd: Handle) -> (string, Maybe(Path_Error)) {
 	return _cleanpath_from_buf(buf), nil
 }
 
-_cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Maybe(Path_Error)) {
+_cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Error) {
 	if fd == 0 {
-		return nil, Path_Error{err = .Invalid_Argument}
+		return nil, .Invalid_Argument
 	}
 	h := win32.HANDLE(fd)
 
@@ -166,7 +160,7 @@ _cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Maybe(Path_Error)) {
 		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)
+			return nil, Platform_Error{i32(err)}
 		case win32.ERROR_NOT_ENOUGH_MEMORY:
 			MAX_PATH = MAX_PATH*2 + 1
 			continue
@@ -251,7 +245,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: Maybe(Path_Error)) {
+_file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE_DATA, name: string) -> (fi: File_Info, e: Error) {
 	fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
 
 	fi.mode |= _file_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
@@ -268,7 +262,7 @@ _file_info_from_win32_file_attribute_data :: proc(d: ^win32.WIN32_FILE_ATTRIBUTE
 }
 
 
-_file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string) -> (fi: File_Info, e: Maybe(Path_Error)) {
+_file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string) -> (fi: File_Info, e: Error) {
 	fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow)
 
 	fi.mode |= _file_mode_from_file_attributes(d.dwFileAttributes, nil, 0)
@@ -285,10 +279,10 @@ _file_info_from_win32_find_data :: proc(d: ^win32.WIN32_FIND_DATAW, name: string
 }
 
 
-_file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE) -> (File_Info, Maybe(Path_Error)) {
+_file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HANDLE) -> (File_Info, Error) {
 	d: win32.BY_HANDLE_FILE_INFORMATION
 	if !win32.GetFileInformationByHandle(h, &d) {
-		return {}, _stat_errno(win32.GetLastError())
+		return {}, _get_platform_error()
 
 	}
 
@@ -296,7 +290,7 @@ _file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HA
 	if !win32.GetFileInformationByHandleEx(h, .FileAttributeTagInfo, &ti, size_of(ti)) {
 		err := win32.GetLastError()
 		if err != win32.ERROR_INVALID_PARAMETER {
-			return {}, _stat_errno(err)
+			return {}, Platform_Error{i32(err)}
 		}
 		// Indicate this is a symlink on FAT file systems
 		ti.ReparseTag = 0

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

@@ -53,6 +53,7 @@ foreign kernel32 {
 	LeaveCriticalSection :: proc(CriticalSection: ^CRITICAL_SECTION) ---
 	DeleteCriticalSection :: proc(CriticalSection: ^CRITICAL_SECTION) ---
 
+	PathFileExistsW :: proc(lpPathName: LPCWSTR) -> BOOL ---
 	RemoveDirectoryW :: proc(lpPathName: LPCWSTR) -> BOOL ---
 	SetFileAttributesW :: proc(lpFileName: LPCWSTR, dwFileAttributes: DWORD) -> BOOL ---
 	SetLastError :: proc(dwErrCode: DWORD) ---