mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-04 06:38:47 +00:00
Begin mocking os2 for windows out more
This commit is contained in:
+2
-30
@@ -11,6 +11,8 @@ General_Error :: enum u32 {
|
|||||||
Closed,
|
Closed,
|
||||||
|
|
||||||
Timeout,
|
Timeout,
|
||||||
|
|
||||||
|
Invalid_File,
|
||||||
}
|
}
|
||||||
|
|
||||||
Platform_Error :: struct {
|
Platform_Error :: struct {
|
||||||
@@ -24,36 +26,6 @@ Error :: union {
|
|||||||
}
|
}
|
||||||
#assert(size_of(Error) == size_of(u64))
|
#assert(size_of(Error) == size_of(u64))
|
||||||
|
|
||||||
Path_Error :: struct {
|
|
||||||
op: string,
|
|
||||||
path: string,
|
|
||||||
err: Error,
|
|
||||||
}
|
|
||||||
|
|
||||||
Link_Error :: struct {
|
|
||||||
op: string,
|
|
||||||
old: string,
|
|
||||||
new: string,
|
|
||||||
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()
|
|
||||||
delete(err.op)
|
|
||||||
delete(err.old)
|
|
||||||
delete(err.new)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) {
|
is_platform_error :: proc(ferr: Error) -> (err: i32, ok: bool) {
|
||||||
|
|||||||
+36
-23
@@ -21,14 +21,27 @@ File_Mode_Char_Device :: File_Mode(1<<19)
|
|||||||
File_Mode_Sym_Link :: File_Mode(1<<20)
|
File_Mode_Sym_Link :: File_Mode(1<<20)
|
||||||
|
|
||||||
|
|
||||||
O_RDONLY :: int( 0)
|
File_Flags :: distinct bit_set[File_Flag; uint]
|
||||||
O_WRONLY :: int( 1)
|
File_Flag :: enum {
|
||||||
O_RDWR :: int( 2)
|
Read,
|
||||||
O_APPEND :: int( 4)
|
Write,
|
||||||
O_CREATE :: int( 8)
|
Append,
|
||||||
O_EXCL :: int(16)
|
Create,
|
||||||
O_SYNC :: int(32)
|
Excl,
|
||||||
O_TRUNC :: int(64)
|
Sync,
|
||||||
|
Trunc,
|
||||||
|
Sparse,
|
||||||
|
}
|
||||||
|
|
||||||
|
O_RDONLY :: File_Flags{.Read}
|
||||||
|
O_WRONLY :: File_Flags{.Write}
|
||||||
|
O_RDWR :: File_Flags{.Read, .Write}
|
||||||
|
O_APPEND :: File_Flags{.Append}
|
||||||
|
O_CREATE :: File_Flags{.Create}
|
||||||
|
O_EXCL :: File_Flags{.Excl}
|
||||||
|
O_SYNC :: File_Flags{.Sync}
|
||||||
|
O_TRUNC :: File_Flags{.Trunc}
|
||||||
|
O_SPARSE :: File_Flags{.Sparse}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -38,27 +51,27 @@ stderr: ^File = nil // OS-Specific
|
|||||||
|
|
||||||
|
|
||||||
create :: proc(name: string) -> (^File, Error) {
|
create :: proc(name: string) -> (^File, Error) {
|
||||||
return _create(name)
|
return open(name, {.Read, .Write, .Create}, File_Mode(0o777))
|
||||||
}
|
}
|
||||||
|
|
||||||
open :: proc(name: string) -> (^File, Error) {
|
open :: proc(name: string, flags := File_Flags{.Read}, perm := File_Mode(0o777)) -> (^File, Error) {
|
||||||
return _open(name)
|
return _open(name, flags, perm)
|
||||||
}
|
|
||||||
|
|
||||||
open_file :: proc(name: string, flag: int, perm: File_Mode) -> (^File, Error) {
|
|
||||||
return _open_file(name, flag, perm)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
new_file :: proc(handle: uintptr, name: string) -> ^File {
|
new_file :: proc(handle: uintptr, name: string) -> ^File {
|
||||||
return _new_file(handle, name)
|
return _new_file(handle, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fd :: proc(f: ^File) -> uintptr {
|
||||||
|
return _fd(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
close :: proc(f: ^File) -> Error {
|
close :: proc(f: ^File) -> Error {
|
||||||
return _close(f)
|
return _close(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
name :: proc(f: ^File, allocator := context.allocator) -> string {
|
name :: proc(f: ^File) -> string {
|
||||||
return _name(f)
|
return _name(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,28 +116,28 @@ flush :: proc(f: ^File) -> Error {
|
|||||||
return _flush(f)
|
return _flush(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
truncate :: proc(f: ^File, size: i64) -> Maybe(Path_Error) {
|
truncate :: proc(f: ^File, size: i64) -> Error {
|
||||||
return _truncate(f, size)
|
return _truncate(f, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
remove :: proc(name: string) -> Maybe(Path_Error) {
|
remove :: proc(name: string) -> Error {
|
||||||
return _remove(name)
|
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)
|
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)
|
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)
|
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)
|
return _read_link(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +160,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)
|
return _chtimes(name, atime, mtime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ write_entire_file :: proc(name: string, data: []byte, perm: File_Mode, truncate
|
|||||||
if truncate {
|
if truncate {
|
||||||
flags |= O_TRUNC
|
flags |= O_TRUNC
|
||||||
}
|
}
|
||||||
f, err := open_file(name, flags, perm)
|
f, err := open(name, flags, perm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+185
-34
@@ -3,38 +3,119 @@ package os2
|
|||||||
|
|
||||||
import "core:io"
|
import "core:io"
|
||||||
import "core:time"
|
import "core:time"
|
||||||
|
import "core:runtime"
|
||||||
|
import "core:strings"
|
||||||
|
import win32 "core:sys/windows"
|
||||||
|
|
||||||
|
INVALID_HANDLE :: ~uintptr(0)
|
||||||
|
|
||||||
|
_file_allocator :: proc() -> runtime.Allocator {
|
||||||
|
return heap_allocator()
|
||||||
|
}
|
||||||
|
|
||||||
|
_File_Kind :: enum u8 {
|
||||||
|
File,
|
||||||
|
Console,
|
||||||
|
Pipe,
|
||||||
|
}
|
||||||
|
|
||||||
_File :: struct {
|
_File :: struct {
|
||||||
fd: rawptr,
|
fd: rawptr,
|
||||||
name: string,
|
name: string,
|
||||||
|
wname: win32.wstring,
|
||||||
|
kind: _File_Kind,
|
||||||
}
|
}
|
||||||
|
|
||||||
_create :: proc(name: string) -> (^File, Error) {
|
_get_platform_error :: proc() -> Error {
|
||||||
return nil, nil
|
err := i32(win32.GetLastError())
|
||||||
|
if err != 0 {
|
||||||
|
return Platform_Error{err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_open :: proc(name: string) -> (^File, Error) {
|
_open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (^File, Error) {
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_open_file :: proc(name: string, flag: int, perm: File_Mode) -> (^File, Error) {
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_new_file :: proc(handle: uintptr, name: string) -> ^File {
|
_new_file :: proc(handle: uintptr, name: string) -> ^File {
|
||||||
|
if handle == INVALID_HANDLE {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
context.allocator = _file_allocator()
|
||||||
|
f := new(File)
|
||||||
|
f.impl.fd = rawptr(fd)
|
||||||
|
f.impl.name = strings.clone(name, context.allocator)
|
||||||
|
f.impl.wname = win32.utf8_to_wstring(name, context.allocator)
|
||||||
|
|
||||||
|
kind := _File_Kind.File
|
||||||
|
if m: u32; win32.GetConsoleMode(win32.HANDLE(fd), &m) {
|
||||||
|
kind = .Console
|
||||||
|
}
|
||||||
|
if win32.GetFileType(win32.HANDLE(fd)) == win32.FILE_TYPE_PIPE {
|
||||||
|
kind = .Pipe
|
||||||
|
}
|
||||||
|
f.impl.kind = kind
|
||||||
|
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
_fd :: proc(f: ^File) -> uintptr {
|
||||||
|
if f == nil {
|
||||||
|
return INVALID_HANDLE
|
||||||
|
}
|
||||||
|
return uintptr(f.impl.fd)
|
||||||
|
}
|
||||||
|
|
||||||
|
_destroy :: proc(f: ^File) -> Error {
|
||||||
|
if f == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
context.allocator = _file_allocator()
|
||||||
|
free(f.impl.wname)
|
||||||
|
delete(f.impl.name)
|
||||||
|
free(f)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_close :: proc(f: ^File) -> Error {
|
_close :: proc(f: ^File) -> Error {
|
||||||
return nil
|
if f == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if !win32.CloseHandle(win32.HANDLE(f.impl.fd)) {
|
||||||
|
return .Closed
|
||||||
|
}
|
||||||
|
return _destroy(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
_name :: proc(f: ^File, allocator := context.allocator) -> string {
|
_name :: proc(f: ^File) -> string {
|
||||||
return ""
|
return f.impl.name if f != nil else ""
|
||||||
}
|
}
|
||||||
|
|
||||||
_seek :: proc(f: ^File, offset: i64, whence: Seek_From) -> (ret: i64, err: Error) {
|
_seek :: proc(f: ^File, offset: i64, whence: Seek_From) -> (ret: i64, err: Error) {
|
||||||
return
|
if f == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w: u32
|
||||||
|
switch whence {
|
||||||
|
case .Start: w = win32.FILE_BEGIN
|
||||||
|
case .Current: w = win32.FILE_CURRENT
|
||||||
|
case .End: w = win32.FILE_END
|
||||||
|
}
|
||||||
|
hi := i32(offset>>32)
|
||||||
|
lo := i32(offset)
|
||||||
|
ft := win32.GetFileType(win32.HANDLE(fd))
|
||||||
|
if ft == win32.FILE_TYPE_PIPE {
|
||||||
|
return 0, .Invalid_File
|
||||||
|
}
|
||||||
|
|
||||||
|
dw_ptr := win32.SetFilePointer(win32.HANDLE(fd), lo, &hi, w)
|
||||||
|
if dw_ptr == win32.INVALID_SET_FILE_POINTER {
|
||||||
|
return 0, _get_platform_error()
|
||||||
|
}
|
||||||
|
return i64(hi)<<32 + i64(dw_ptr), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_read :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
|
_read :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
|
||||||
@@ -62,6 +143,14 @@ _write_to :: proc(f: ^File, w: io.Writer) -> (n: i64, err: Error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_file_size :: proc(f: ^File) -> (n: i64, err: Error) {
|
_file_size :: proc(f: ^File) -> (n: i64, err: Error) {
|
||||||
|
if f == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
length: win32.LARGE_INTEGER
|
||||||
|
if !win32.GetFileSizeEx(win32.HANDLE(fd), &length) {
|
||||||
|
err = _get_platform_error()
|
||||||
|
}
|
||||||
|
n = i64(length)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,34 +163,93 @@ _flush :: proc(f: ^File) -> Error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_truncate :: proc(f: ^File, size: i64) -> Maybe(Path_Error) {
|
_truncate :: proc(f: ^File, size: i64) -> Error {
|
||||||
|
if f == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
curr_off := seek(f, 0, .Current) or_return
|
||||||
|
defer seek(f, curr_off, .Start)
|
||||||
|
seek(f, size, .Start) or_return
|
||||||
|
if !win32.SetEndOfFile(win32.HANDLE(fd)) {
|
||||||
|
return _get_platform_error()
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_remove :: proc(name: string) -> Maybe(Path_Error) {
|
_remove :: proc(name: string) -> Error {
|
||||||
return nil
|
p := _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 {
|
||||||
return nil
|
from := _fix_long_path(old_path)
|
||||||
|
to := _fix_long_path(new_path)
|
||||||
|
if win32.MoveFileExW(from, to, win32.MOVEFILE_REPLACE_EXISTING) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return _get_platform_error()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_link :: proc(old_name, new_name: string) -> Maybe(Link_Error) {
|
_link :: proc(old_name, new_name: string) -> Error {
|
||||||
|
o := _fix_long_path(old_name)
|
||||||
|
n := _fix_long_path(new_name)
|
||||||
|
if win32.CreateHardLinkW(n, o, nil) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return _get_platform_error()
|
||||||
|
}
|
||||||
|
|
||||||
|
_symlink :: proc(old_name, new_name: string) -> Error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_symlink :: proc(old_name, new_name: string) -> Maybe(Link_Error) {
|
_read_link :: proc(name: string) -> (string, Error) {
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_read_link :: proc(name: string) -> (string, Maybe(Path_Error)) {
|
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_chdir :: proc(f: ^File) -> Error {
|
_chdir :: proc(f: ^File) -> Error {
|
||||||
return nil
|
if f == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if win32.SetCurrentDirectoryW(f.impl.wname) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return _get_platform_error()
|
||||||
}
|
}
|
||||||
|
|
||||||
_chmod :: proc(f: ^File, mode: File_Mode) -> Error {
|
_chmod :: proc(f: ^File, mode: File_Mode) -> Error {
|
||||||
@@ -118,28 +266,31 @@ _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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_exists :: proc(path: string) -> bool {
|
_exists :: proc(path: string) -> bool {
|
||||||
return false
|
wpath := _fix_long_path(path)
|
||||||
|
attribs := win32.GetFileAttributesW(wpath)
|
||||||
|
return i32(attribs) != win32.INVALID_FILE_ATTRIBUTES
|
||||||
}
|
}
|
||||||
|
|
||||||
_is_file :: proc(path: string) -> bool {
|
_is_file :: proc(path: string) -> bool {
|
||||||
|
wpath := _fix_long_path(path)
|
||||||
|
attribs := win32.GetFileAttributesW(wpath)
|
||||||
|
if i32(attribs) != win32.INVALID_FILE_ATTRIBUTES {
|
||||||
|
return attribs & win32.FILE_ATTRIBUTE_DIRECTORY == 0
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
_is_dir :: proc(path: string) -> bool {
|
_is_dir :: proc(path: string) -> bool {
|
||||||
|
wpath := _fix_long_path(path)
|
||||||
|
attribs := win32.GetFileAttributesW(wpath)
|
||||||
|
if i32(attribs) != win32.INVALID_FILE_ATTRIBUTES {
|
||||||
|
return attribs & win32.FILE_ATTRIBUTE_DIRECTORY != 0
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_path_error_delete :: proc(perr: Maybe(Path_Error)) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
_link_error_delete :: proc(lerr: Maybe(Link_Error)) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -7,15 +7,15 @@ is_path_separator :: proc(c: byte) -> bool {
|
|||||||
return _is_path_separator(c)
|
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)
|
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)
|
return _mkdir_all(path, perm)
|
||||||
}
|
}
|
||||||
|
|
||||||
remove_all :: proc(path: string) -> Maybe(Path_Error) {
|
remove_all :: proc(path: string) -> Error {
|
||||||
return _remove_all(path)
|
return _remove_all(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
//+private
|
//+private
|
||||||
package os2
|
package os2
|
||||||
|
|
||||||
|
import win32 "core:sys/windows"
|
||||||
|
|
||||||
_Path_Separator :: '\\'
|
_Path_Separator :: '\\'
|
||||||
_Path_List_Separator :: ';'
|
_Path_List_Separator :: ';'
|
||||||
|
|
||||||
@@ -8,16 +10,16 @@ _is_path_separator :: proc(c: byte) -> bool {
|
|||||||
return c == '\\' || c == '/'
|
return c == '\\' || c == '/'
|
||||||
}
|
}
|
||||||
|
|
||||||
_mkdir :: proc(name: string, perm: File_Mode) -> Maybe(Path_Error) {
|
_mkdir :: proc(name: string, perm: File_Mode) -> Error {
|
||||||
return nil
|
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
|
// TODO(bill): _mkdir_all for windows
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_remove_all :: proc(path: string) -> Maybe(Path_Error) {
|
_remove_all :: proc(path: string) -> Error {
|
||||||
// TODO(bill): _remove_all for windows
|
// TODO(bill): _remove_all for windows
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -29,3 +31,81 @@ _getwd :: proc(allocator := context.allocator) -> (dir: string, err: Error) {
|
|||||||
_setwd :: proc(dir: string) -> (err: Error) {
|
_setwd :: proc(dir: string) -> (err: Error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
can_use_long_paths: bool
|
||||||
|
|
||||||
|
@(init)
|
||||||
|
init_long_path_support :: proc() {
|
||||||
|
// TODO(bill): init_long_path_support
|
||||||
|
// ADD THIS SHIT
|
||||||
|
// registry_path := win32.L(`Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem\LongPathsEnabled`)
|
||||||
|
can_use_long_paths = false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_fix_long_path_slice :: proc(path: string) -> []u16 {
|
||||||
|
return win32.utf8_to_utf16(_fix_long_path_internal(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
_fix_long_path :: proc(path: string) -> win32.wstring {
|
||||||
|
return win32.utf8_to_wstring(_fix_long_path_internal(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_fix_long_path_internal :: proc(path: string) -> string {
|
||||||
|
if can_use_long_paths {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
// When using win32 to create a directory, the path
|
||||||
|
// cannot be too long that you cannot append an 8.3
|
||||||
|
// file name, because MAX_PATH is 260, 260-12 = 248
|
||||||
|
if len(path) < 248 {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
// UNC paths do not need to be modified
|
||||||
|
if len(path) >= 2 && path[:2] == `\\` {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
if !_is_abs(path) { // relative path
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
PREFIX :: `\\?`
|
||||||
|
path_buf := make([]byte, len(PREFIX)+len(path)+1, context.temp_allocator)
|
||||||
|
copy(path_buf, PREFIX)
|
||||||
|
n := len(path)
|
||||||
|
r, w := 0, len(PREFIX)
|
||||||
|
for r < n {
|
||||||
|
switch {
|
||||||
|
case is_path_separator(path[r]):
|
||||||
|
r += 1
|
||||||
|
case path[r] == '.' && (r+1 == n || is_path_separator(path[r+1])):
|
||||||
|
// \.\
|
||||||
|
r += 1
|
||||||
|
case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || is_path_separator(path[r+2])):
|
||||||
|
// Skip \..\ paths
|
||||||
|
return path
|
||||||
|
case:
|
||||||
|
path_buf[w] = '\\'
|
||||||
|
w += 1
|
||||||
|
for r < n && !is_path_separator(path[r]) {
|
||||||
|
path_buf[w] = path[r]
|
||||||
|
r += 1
|
||||||
|
w += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Root directories require a trailing \
|
||||||
|
if w == len(`\\?\c:`) {
|
||||||
|
path_buf[w] = '\\'
|
||||||
|
w += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(path_buf[:w])
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,15 +24,15 @@ file_info_delete :: proc(fi: File_Info, allocator := context.allocator) {
|
|||||||
delete(fi.fullpath, allocator)
|
delete(fi.fullpath, allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
fstat :: proc(f: ^File, allocator := context.allocator) -> (File_Info, Maybe(Path_Error)) {
|
fstat :: proc(f: ^File, allocator := context.allocator) -> (File_Info, Error) {
|
||||||
return _fstat(f, allocator)
|
return _fstat(f, 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)
|
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)
|
return _lstat(name, allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,12 @@
|
|||||||
package os2
|
package os2
|
||||||
|
|
||||||
import "core:time"
|
import "core:time"
|
||||||
|
import "core:strings"
|
||||||
import win32 "core:sys/windows"
|
import win32 "core:sys/windows"
|
||||||
|
|
||||||
_fstat :: proc(f: ^File, allocator := context.allocator) -> (File_Info, Maybe(Path_Error)) {
|
_fstat :: proc(f: ^File, allocator := context.allocator) -> (File_Info, Error) {
|
||||||
if f == nil || f.impl.fd == nil {
|
if f == nil || f.impl.fd == nil {
|
||||||
return {}, Path_Error{err = .Invalid_Argument}
|
return {}, .Invalid_Argument
|
||||||
}
|
}
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
|
|
||||||
@@ -27,10 +28,10 @@ _fstat :: proc(f: ^File, allocator := context.allocator) -> (File_Info, Maybe(Pa
|
|||||||
|
|
||||||
return _file_info_from_get_file_information_by_handle(path, h)
|
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)
|
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)
|
return internal_stat(name, win32.FILE_FLAG_BACKUP_SEMANTICS|win32.FILE_FLAG_OPEN_REPARSE_POINT)
|
||||||
}
|
}
|
||||||
_same_file :: proc(fi1, fi2: File_Info) -> bool {
|
_same_file :: proc(fi1, fi2: File_Info) -> bool {
|
||||||
@@ -39,12 +40,12 @@ _same_file :: proc(fi1, fi2: File_Info) -> bool {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
_stat_errno :: proc(errno: win32.DWORD) -> Path_Error {
|
_stat_errno :: proc(errno: win32.DWORD) -> Error {
|
||||||
return Path_Error{err = Platform_Error{i32(errno)}}
|
return 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
|
context.allocator = allocator
|
||||||
|
|
||||||
name := name
|
name := name
|
||||||
@@ -69,15 +70,15 @@ 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 {
|
if len(name) == 0 {
|
||||||
return {}, Path_Error{err = .Not_Exist}
|
return {}, .Not_Exist
|
||||||
}
|
}
|
||||||
|
|
||||||
context.allocator = allocator
|
context.allocator = allocator
|
||||||
|
|
||||||
|
|
||||||
wname := win32.utf8_to_wstring(_fix_long_path(name), context.temp_allocator)
|
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 {
|
||||||
@@ -91,7 +92,7 @@ internal_stat :: proc(name: string, create_file_attributes: u32, allocator := co
|
|||||||
fd: win32.WIN32_FIND_DATAW
|
fd: win32.WIN32_FIND_DATAW
|
||||||
sh := win32.FindFirstFileW(wname, &fd)
|
sh := win32.FindFirstFileW(wname, &fd)
|
||||||
if sh == win32.INVALID_HANDLE_VALUE {
|
if sh == win32.INVALID_HANDLE_VALUE {
|
||||||
e = Path_Error{err = Platform_Error{i32(win32.GetLastError())}}
|
e = _get_platform_error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
win32.FindClose(sh)
|
win32.FindClose(sh)
|
||||||
@@ -101,7 +102,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)
|
h := win32.CreateFileW(wname, 0, 0, nil, win32.OPEN_EXISTING, create_file_attributes, nil)
|
||||||
if h == win32.INVALID_HANDLE_VALUE {
|
if h == win32.INVALID_HANDLE_VALUE {
|
||||||
e = Path_Error{err = Platform_Error{i32(win32.GetLastError())}}
|
e = _get_platform_error()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer win32.CloseHandle(h)
|
defer win32.CloseHandle(h)
|
||||||
@@ -130,9 +131,9 @@ _cleanpath_strip_prefix :: proc(buf: []u16) -> []u16 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_cleanpath_from_handle :: proc(f: ^File) -> (string, Maybe(Path_Error)) {
|
_cleanpath_from_handle :: proc(f: ^File) -> (string, Error) {
|
||||||
if f == nil || f.impl.fd == nil {
|
if f == nil || f.impl.fd == nil {
|
||||||
return "", Path_Error{err = .Invalid_Argument}
|
return "", .Invalid_Argument
|
||||||
}
|
}
|
||||||
h := win32.HANDLE(f.impl.fd)
|
h := win32.HANDLE(f.impl.fd)
|
||||||
|
|
||||||
@@ -153,9 +154,9 @@ _cleanpath_from_handle :: proc(f: ^File) -> (string, Maybe(Path_Error)) {
|
|||||||
return _cleanpath_from_buf(buf), nil
|
return _cleanpath_from_buf(buf), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_cleanpath_from_handle_u16 :: proc(f: ^File) -> ([]u16, Maybe(Path_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, Path_Error{err = .Invalid_Argument}
|
return nil, .Invalid_Argument
|
||||||
}
|
}
|
||||||
h := win32.HANDLE(f.impl.fd)
|
h := win32.HANDLE(f.impl.fd)
|
||||||
|
|
||||||
@@ -251,7 +252,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.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)
|
||||||
@@ -268,7 +269,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.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)
|
||||||
@@ -285,7 +286,7 @@ _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
|
d: win32.BY_HANDLE_FILE_INFORMATION
|
||||||
if !win32.GetFileInformationByHandle(h, &d) {
|
if !win32.GetFileInformationByHandle(h, &d) {
|
||||||
return {}, _stat_errno(win32.GetLastError())
|
return {}, _stat_errno(win32.GetLastError())
|
||||||
@@ -318,58 +319,83 @@ _file_info_from_get_file_information_by_handle :: proc(path: string, h: win32.HA
|
|||||||
return fi, nil
|
return fi, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
_is_abs :: proc(path: string) -> bool {
|
|
||||||
if len(path) > 0 && path[0] == '/' {
|
|
||||||
return true
|
reserved_names := [?]string{
|
||||||
|
"CON", "PRN", "AUX", "NUL",
|
||||||
|
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
|
||||||
|
"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
|
||||||
|
}
|
||||||
|
|
||||||
|
_is_reserved_name :: proc(path: string) -> bool {
|
||||||
|
if len(path) == 0 {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
if len(path) > 2 {
|
for reserved in reserved_names {
|
||||||
switch path[0] {
|
if strings.equal_fold(path, reserved) {
|
||||||
case 'A'..='Z', 'a'..='z':
|
return true
|
||||||
return path[1] == ':' && is_path_separator(path[2])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
_fix_long_path :: proc(path: string) -> string {
|
_is_UNC :: proc(path: string) -> bool {
|
||||||
if len(path) < 248 {
|
return _volume_name_len(path) > 2
|
||||||
return path
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if len(path) >= 2 && path[:2] == `\\` {
|
_volume_name_len :: proc(path: string) -> int {
|
||||||
return path
|
if ODIN_OS == .Windows {
|
||||||
}
|
if len(path) < 2 {
|
||||||
if !_is_abs(path) {
|
return 0
|
||||||
return path
|
}
|
||||||
}
|
c := path[0]
|
||||||
|
if path[1] == ':' {
|
||||||
|
switch c {
|
||||||
|
case 'a'..='z', 'A'..='Z':
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
prefix :: `\\?`
|
// URL: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
|
||||||
|
if l := len(path); l >= 5 && _is_path_separator(path[0]) && _is_path_separator(path[1]) &&
|
||||||
path_buf := make([]byte, len(prefix)+len(path)+len(`\`), context.temp_allocator)
|
!_is_path_separator(path[2]) && path[2] != '.' {
|
||||||
copy(path_buf, prefix)
|
for n := 3; n < l-1; n += 1 {
|
||||||
n := len(path)
|
if _is_path_separator(path[n]) {
|
||||||
r, w := 0, len(prefix)
|
n += 1
|
||||||
for r < n {
|
if !_is_path_separator(path[n]) {
|
||||||
switch {
|
if path[n] == '.' {
|
||||||
case is_path_separator(path[r]):
|
break
|
||||||
r += 1
|
}
|
||||||
case path[r] == '.' && (r+1 == n || is_path_separator(path[r+1])):
|
}
|
||||||
r += 1
|
for ; n < l; n += 1 {
|
||||||
case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || is_path_separator(path[r+2])):
|
if _is_path_separator(path[n]) {
|
||||||
return path
|
break
|
||||||
case:
|
}
|
||||||
path_buf[w] = '\\'
|
}
|
||||||
w += 1
|
return n
|
||||||
for ; r < n && !is_path_separator(path[r]); r += 1 {
|
}
|
||||||
path_buf[w] = path[r]
|
break
|
||||||
w += 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0
|
||||||
if w == len(`\\?\c:`) {
|
|
||||||
path_buf[w] = '\\'
|
|
||||||
w += 1
|
|
||||||
}
|
|
||||||
return string(path_buf[:w])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_is_abs :: proc(path: string) -> bool {
|
||||||
|
if _is_reserved_name(path) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
l := _volume_name_len(path)
|
||||||
|
if l == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
path := path
|
||||||
|
path = path[l:]
|
||||||
|
if path == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return is_path_separator(path[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ Monitor_Enum_Proc :: distinct #type proc "std" (Hmonitor, Hdc, ^Rect, Lparam) ->
|
|||||||
|
|
||||||
Bool :: distinct b32
|
Bool :: distinct b32
|
||||||
|
|
||||||
Wstring :: distinct ^u16
|
Wstring :: distinct [^]u16
|
||||||
|
|
||||||
Point :: struct {
|
Point :: struct {
|
||||||
x, y: i32,
|
x, y: i32,
|
||||||
|
|||||||
Reference in New Issue
Block a user