From 658a605c75c32746f248dc8e8e367c6b5dae976e Mon Sep 17 00:00:00 2001 From: jasonkercher Date: Fri, 4 Mar 2022 17:11:53 -0500 Subject: [PATCH] compiles --- core/os/os2/env_linux.odin | 28 +++++ core/os/os2/errors_linux.odin | 134 +++++++++++++++++++++++ core/os/os2/file.odin | 4 + core/os/os2/file_linux.odin | 169 ++++++++++++++++++++---------- core/os/os2/file_windows.odin | 5 + core/os/os2/heap_linux.odin | 27 +++++ core/os/os2/path_linux.odin | 85 +++++++++++++++ core/os/os2/pipe_linux.odin | 7 ++ core/os/os2/stat_linux.odin | 22 ++-- core/os/os2/temp_file_linux.odin | 18 ++++ core/sys/unix/syscalls_linux.odin | 146 +++++++++++++++++++++----- 11 files changed, 557 insertions(+), 88 deletions(-) create mode 100644 core/os/os2/env_linux.odin create mode 100644 core/os/os2/errors_linux.odin create mode 100644 core/os/os2/heap_linux.odin create mode 100644 core/os/os2/path_linux.odin create mode 100644 core/os/os2/pipe_linux.odin create mode 100644 core/os/os2/temp_file_linux.odin diff --git a/core/os/os2/env_linux.odin b/core/os/os2/env_linux.odin new file mode 100644 index 000000000..1833ac4dc --- /dev/null +++ b/core/os/os2/env_linux.odin @@ -0,0 +1,28 @@ +//+private +package os2 + +_get_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) { + //TODO + return +} + +_set_env :: proc(key, value: string) -> bool { + //TODO + return false +} + +_unset_env :: proc(key: string) -> bool { + //TODO + return false +} + +_clear_env :: proc() { + //TODO +} + +_environ :: proc(allocator := context.allocator) -> []string { + //TODO + return nil +} + + diff --git a/core/os/os2/errors_linux.odin b/core/os/os2/errors_linux.odin new file mode 100644 index 000000000..f074c7c86 --- /dev/null +++ b/core/os/os2/errors_linux.odin @@ -0,0 +1,134 @@ +//+private +package os2 + +EPERM :: 1 +ENOENT :: 2 +ESRCH :: 3 +EINTR :: 4 +EIO :: 5 +ENXIO :: 6 +EBADF :: 9 +EAGAIN :: 11 +ENOMEM :: 12 +EACCES :: 13 +EFAULT :: 14 +EEXIST :: 17 +ENODEV :: 19 +ENOTDIR :: 20 +EISDIR :: 21 +EINVAL :: 22 +ENFILE :: 23 +EMFILE :: 24 +ETXTBSY :: 26 +EFBIG :: 27 +ENOSPC :: 28 +ESPIPE :: 29 +EROFS :: 30 +EPIPE :: 32 +ERANGE :: 34 /* Result too large */ +EDEADLK :: 35 /* Resource deadlock would occur */ +ENAMETOOLONG :: 36 /* File name too long */ +ENOLCK :: 37 /* No record locks available */ +ENOSYS :: 38 /* Invalid system call number */ +ENOTEMPTY :: 39 /* Directory not empty */ +ELOOP :: 40 /* Too many symbolic links encountered */ +EWOULDBLOCK :: EAGAIN /* Operation would block */ +ENOMSG :: 42 /* No message of desired type */ +EIDRM :: 43 /* Identifier removed */ +ECHRNG :: 44 /* Channel number out of range */ +EL2NSYNC :: 45 /* Level 2 not synchronized */ +EL3HLT :: 46 /* Level 3 halted */ +EL3RST :: 47 /* Level 3 reset */ +ELNRNG :: 48 /* Link number out of range */ +EUNATCH :: 49 /* Protocol driver not attached */ +ENOCSI :: 50 /* No CSI structure available */ +EL2HLT :: 51 /* Level 2 halted */ +EBADE :: 52 /* Invalid exchange */ +EBADR :: 53 /* Invalid request descriptor */ +EXFULL :: 54 /* Exchange full */ +ENOANO :: 55 /* No anode */ +EBADRQC :: 56 /* Invalid request code */ +EBADSLT :: 57 /* Invalid slot */ +EDEADLOCK :: EDEADLK +EBFONT :: 59 /* Bad font file format */ +ENOSTR :: 60 /* Device not a stream */ +ENODATA :: 61 /* No data available */ +ETIME :: 62 /* Timer expired */ +ENOSR :: 63 /* Out of streams resources */ +ENONET :: 64 /* Machine is not on the network */ +ENOPKG :: 65 /* Package not installed */ +EREMOTE :: 66 /* Object is remote */ +ENOLINK :: 67 /* Link has been severed */ +EADV :: 68 /* Advertise error */ +ESRMNT :: 69 /* Srmount error */ +ECOMM :: 70 /* Communication error on send */ +EPROTO :: 71 /* Protocol error */ +EMULTIHOP :: 72 /* Multihop attempted */ +EDOTDOT :: 73 /* RFS specific error */ +EBADMSG :: 74 /* Not a data message */ +EOVERFLOW :: 75 /* Value too large for defined data type */ +ENOTUNIQ :: 76 /* Name not unique on network */ +EBADFD :: 77 /* File descriptor in bad state */ +EREMCHG :: 78 /* Remote address changed */ +ELIBACC :: 79 /* Can not access a needed shared library */ +ELIBBAD :: 80 /* Accessing a corrupted shared library */ +ELIBSCN :: 81 /* .lib section in a.out corrupted */ +ELIBMAX :: 82 /* Attempting to link in too many shared libraries */ +ELIBEXEC :: 83 /* Cannot exec a shared library directly */ +EILSEQ :: 84 /* Illegal byte sequence */ +ERESTART :: 85 /* Interrupted system call should be restarted */ +ESTRPIPE :: 86 /* Streams pipe error */ +EUSERS :: 87 /* Too many users */ +ENOTSOCK :: 88 /* Socket operation on non-socket */ +EDESTADDRREQ :: 89 /* Destination address required */ +EMSGSIZE :: 90 /* Message too long */ +EPROTOTYPE :: 91 /* Protocol wrong type for socket */ +ENOPROTOOPT :: 92 /* Protocol not available */ +EPROTONOSUPPORT:: 93 /* Protocol not supported */ +ESOCKTNOSUPPORT:: 94 /* Socket type not supported */ +EOPNOTSUPP :: 95 /* Operation not supported on transport endpoint */ +EPFNOSUPPORT :: 96 /* Protocol family not supported */ +EAFNOSUPPORT :: 97 /* Address family not supported by protocol */ +EADDRINUSE :: 98 /* Address already in use */ +EADDRNOTAVAIL :: 99 /* Cannot assign requested address */ +ENETDOWN :: 100 /* Network is down */ +ENETUNREACH :: 101 /* Network is unreachable */ +ENETRESET :: 102 /* Network dropped connection because of reset */ +ECONNABORTED :: 103 /* Software caused connection abort */ +ECONNRESET :: 104 /* Connection reset by peer */ +ENOBUFS :: 105 /* No buffer space available */ +EISCONN :: 106 /* Transport endpoint is already connected */ +ENOTCONN :: 107 /* Transport endpoint is not connected */ +ESHUTDOWN :: 108 /* Cannot send after transport endpoint shutdown */ +ETOOMANYREFS :: 109 /* Too many references: cannot splice */ +ETIMEDOUT :: 110 /* Connection timed out */ +ECONNREFUSED :: 111 /* Connection refused */ +EHOSTDOWN :: 112 /* Host is down */ +EHOSTUNREACH :: 113 /* No route to host */ +EALREADY :: 114 /* Operation already in progress */ +EINPROGRESS :: 115 /* Operation now in progress */ +ESTALE :: 116 /* Stale file handle */ +EUCLEAN :: 117 /* Structure needs cleaning */ +ENOTNAM :: 118 /* Not a XENIX named type file */ +ENAVAIL :: 119 /* No XENIX semaphores available */ +EISNAM :: 120 /* Is a named type file */ +EREMOTEIO :: 121 /* Remote I/O error */ +EDQUOT :: 122 /* Quota exceeded */ +ENOMEDIUM :: 123 /* No medium found */ +EMEDIUMTYPE :: 124 /* Wrong medium type */ +ECANCELED :: 125 /* Operation Canceled */ +ENOKEY :: 126 /* Required key not available */ +EKEYEXPIRED :: 127 /* Key has expired */ +EKEYREVOKED :: 128 /* Key has been revoked */ +EKEYREJECTED :: 129 /* Key was rejected by service */ +EOWNERDEAD :: 130 /* Owner died */ +ENOTRECOVERABLE:: 131 /* State not recoverable */ +ERFKILL :: 132 /* Operation not possible due to RF-kill */ +EHWPOISON :: 133 /* Memory page has hardware error */ + +_error_string :: proc(errno: i32) -> string { + if errno == 0 { + return "" + } + return "Error" +} diff --git a/core/os/os2/file.odin b/core/os/os2/file.odin index 707df37a2..09e1e8daf 100644 --- a/core/os/os2/file.odin +++ b/core/os/os2/file.odin @@ -61,6 +61,10 @@ create :: proc(name: string, perm: File_Mode = 0) -> (Handle, Error) { return open(name, {.Read, .Write, .Create}, perm) } +opendir :: proc(name: string) -> (Handle, Error) { + return _opendir(name) +} + open :: proc(name: string, flags := File_Flags{.Read}, perm: File_Mode = 0) -> (Handle, Error) { flags := flags if .Write not_in flags { diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index 75a71b22b..72fbdcb56 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -3,6 +3,7 @@ package os2 import "core:io" import "core:time" +import "core:strings" import "core:sys/unix" @@ -15,13 +16,64 @@ _ok_or_error :: proc(res: int) -> Error { return res >= 0 ? nil : _get_platform_error(res) } -_open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Error) { - cstr := strings.clone_to_cstring(path, context.temp_allocator) - handle := Handle(unix.sys_open(cstr, int(flags), int(perm))) - if handle < 0 { - return Handle(-1), _get_platform_error(int(handle)) +_std_handle :: proc(kind: Std_Handle_Kind) -> Handle { + switch kind { + case .stdin: return Handle(0) + case .stdout: return Handle(1) + case .stderr: return Handle(2) } - return handle, nil + unreachable() +} + +_O_RDONLY :: 0o0 +_O_WRONLY :: 0o1 +_O_RDWR :: 0o2 +_O_CREAT :: 0o100 +_O_EXCL :: 0o200 +_O_TRUNC :: 0o1000 +_O_APPEND :: 0o2000 +_O_NONBLOCK :: 0o4000 +_O_LARGEFILE :: 0o100000 +_O_DIRECTORY :: 0o200000 +_O_SYNC :: 0o4010000 +_O_CLOEXEC :: 0o2000000 + +_opendir :: proc(name: string) -> (Handle, Error) { + cstr := strings.clone_to_cstring(name, context.temp_allocator) + + flags := _O_RDONLY|_O_NONBLOCK|_O_DIRECTORY|_O_LARGEFILE|_O_CLOEXEC + + handle_i := unix.sys_open(cstr, flags) + if handle_i < 0 { + return INVALID_HANDLE, _get_platform_error(handle_i) + } + + return Handle(handle_i), nil +} + +_open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Error) { + cstr := strings.clone_to_cstring(name, context.temp_allocator) + + flags_i: int + switch flags & O_RDONLY|O_WRONLY|O_RDWR { + case O_RDONLY: flags_i = _O_RDONLY + case O_WRONLY: flags_i = _O_WRONLY + case O_RDWR: flags_i = _O_RDWR + } + + flags_i |= (_O_APPEND * int(.Append in flags)) + flags_i |= (_O_CREAT * int(.Create in flags)) + flags_i |= (_O_EXCL * int(.Excl in flags)) + flags_i |= (_O_SYNC * int(.Sync in flags)) + flags_i |= (_O_TRUNC * int(.Trunc in flags)) + flags_i |= (_O_CLOEXEC * int(.Close_On_Exec in flags)) + + handle_i := unix.sys_open(cstr, flags_i, int(perm)) + if handle_i < 0 { + return INVALID_HANDLE, _get_platform_error(handle_i) + } + + return Handle(handle_i), nil } _close :: proc(fd: Handle) -> Error { @@ -46,30 +98,27 @@ _read :: proc(fd: Handle, p: []byte) -> (n: int, err: Error) { if len(p) == 0 { return 0, nil } - n = unix.sys_read(fd, &data[0], c.size_t(len(data))) + n = unix.sys_read(int(fd), &p[0], len(p)) if n < 0 { - return -1, unix.get_errno(n) + return -1, _get_platform_error(int(unix.get_errno(n))) } - return bytes_read, nil + return n, nil } _read_at :: proc(fd: Handle, p: []byte, offset: i64) -> (n: int, err: Error) { if offset < 0 { return 0, .Invalid_Offset } - - curr_offset, err := _seek(fd, 0, .Current) - if err != nil { - return 0, err - } - defer _seek(fd, curr_offset, .Start) - _seek(fd, offset, .Start) - b := p + b, offset := p, offset for len(b) > 0 { - m := _read(fd, b) or_return + m := unix.sys_pread(int(fd), &b[0], len(b), offset) + if m < 0 { + return -1, _get_platform_error(m) + } n += m b = b[m:] + offset += i64(m) } return } @@ -83,7 +132,7 @@ _write :: proc(fd: Handle, p: []byte) -> (n: int, err: Error) { if len(p) == 0 { return 0, nil } - n = unix.sys_write(fd, &p[0], uint(len(p))) + n = unix.sys_write(int(fd), &p[0], uint(len(p))) if n < 0 { return -1, _get_platform_error(n) } @@ -94,19 +143,16 @@ _write_at :: proc(fd: Handle, p: []byte, offset: i64) -> (n: int, err: Error) { if offset < 0 { return 0, .Invalid_Offset } - - curr_offset, err := _seek(fd, 0, .Current) - if err != nil { - return 0, err - } - defer _seek(fd, curr_offset, .Start) - _seek(fd, offset, .Start) - b := p + b, offset := p, offset for len(b) > 0 { - m := _write(fd, b) or_return + m := unix.sys_pwrite(int(fd), &b[0], len(b), offset) + if m < 0 { + return -1, _get_platform_error(m) + } n += m b = b[m:] + offset += i64(m) } return } @@ -117,11 +163,12 @@ _write_to :: proc(fd: Handle, w: io.Writer) -> (n: i64, err: Error) { } _file_size :: proc(fd: Handle) -> (n: i64, err: Error) { - s, err := _fstat(fd) or_return - if err != nil { - return 0, err + s: OS_Stat = --- + res := unix.sys_fstat(int(fd), &s) + if res < 0 { + return -1, _get_platform_error(res) } - return max(s.size, 0), nil + return s.size, nil } _sync :: proc(fd: Handle) -> Error { @@ -137,17 +184,25 @@ _truncate :: proc(fd: Handle, size: i64) -> Error { } _remove :: proc(name: string) -> Error { - path_cstr := strings.clone_to_cstring(path, context.temp_allocator) - if _is_dir(name) { - return _ok_or_error(unix.sys_rmdir(path_cstr)) + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) + + handle_i := unix.sys_open(name_cstr, int(File_Flags.Read)) + if handle_i < 0 { + return _get_platform_error(handle_i) } - return _ok_or_error(unix.sys_unlink(path_cstr)) + defer unix.sys_close(handle_i) + + /* TODO: THIS WILL NOT WORK */ + if _is_dir(Handle(handle_i)) { + return _ok_or_error(unix.sys_rmdir(name_cstr)) + } + return _ok_or_error(unix.sys_unlink(name_cstr)) } -_rename :: proc(old_path, new_path: string) -> Error { - old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator) - new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator) - return _ok_or_error(unix.sys_rename(old_path_cstr, new_path_cstr)) +_rename :: proc(old_name, new_name: string) -> Error { + old_name_cstr := strings.clone_to_cstring(old_name, context.temp_allocator) + new_name_cstr := strings.clone_to_cstring(new_name, context.temp_allocator) + return _ok_or_error(unix.sys_rename(old_name_cstr, new_name_cstr)) } _link :: proc(old_name, new_name: string) -> Error { @@ -163,16 +218,16 @@ _symlink :: proc(old_name, new_name: string) -> Error { } _read_link :: proc(name: string, allocator := context.allocator) -> (string, Error) { - path_cstr := strings.clone_to_cstring(path) - defer delete(path_cstr) + name_cstr := strings.clone_to_cstring(name) + defer delete(name_cstr) bufsz : uint = 256 buf := make([]byte, bufsz, allocator) for { - rc := unix.sys_readlink(path_cstr, &(buf[0]), bufsz) + rc := unix.sys_readlink(name_cstr, &(buf[0]), bufsz) if rc < 0 { delete(buf) - return "", unix.get_errno(rc) + return "", _get_platform_error(int(unix.get_errno(rc))) } else if rc == int(bufsz) { bufsz *= 2 delete(buf) @@ -183,9 +238,9 @@ _read_link :: proc(name: string, allocator := context.allocator) -> (string, Err } } -_unlink :: proc(path: string) -> Error { - path_cstr := strings.clone_to_cstring(path, context.temp_allocator) - return _ok_or_error(unix.sys_unlink(path_cstr)) +_unlink :: proc(name: string) -> Error { + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) + return _ok_or_error(unix.sys_unlink(name_cstr)) } _chdir :: proc(fd: Handle) -> Error { @@ -193,18 +248,16 @@ _chdir :: proc(fd: Handle) -> Error { } _chmod :: proc(fd: Handle, mode: File_Mode) -> Error { - //TODO - return nil + return _ok_or_error(unix.sys_fchmod(int(fd), int(mode))) } _chown :: proc(fd: Handle, uid, gid: int) -> Error { - //TODO - return nil + return _ok_or_error(unix.sys_fchown(int(fd), uid, gid)) } _lchown :: proc(name: string, uid, gid: int) -> Error { - //TODO - return nil + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) + return _ok_or_error(unix.sys_lchown(name_cstr, uid, gid)) } _chtimes :: proc(name: string, atime, mtime: time.Time) -> Error { @@ -212,14 +265,14 @@ _chtimes :: proc(name: string, atime, mtime: time.Time) -> Error { return nil } -_exists :: proc(path: string) -> bool { - path_cstr := strings.clone_to_cstring(path, context.temp_allocator) - return unix.sys_access(path_cstr, F_OK) == 0 +_exists :: proc(name: string) -> bool { + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) + return unix.sys_access(name_cstr, F_OK) == 0 } _is_file :: proc(fd: Handle) -> bool { s: OS_Stat - res := unix.sys_fstat(int(fd), rawptr(&s)) + res := unix.sys_fstat(int(fd), &s) if res < 0 { // error return false } @@ -228,7 +281,7 @@ _is_file :: proc(fd: Handle) -> bool { _is_dir :: proc(fd: Handle) -> bool { s: OS_Stat - res := unix.sys_fstat(int(fd), rawptr(&s)) + res := unix.sys_fstat(int(fd), &s) if res < 0 { // error return false } diff --git a/core/os/os2/file_windows.odin b/core/os/os2/file_windows.odin index 9fdbd9a5a..dd33d8a53 100644 --- a/core/os/os2/file_windows.odin +++ b/core/os/os2/file_windows.odin @@ -36,6 +36,11 @@ _std_handle :: proc(kind: Std_Handle_Kind) -> Handle { unreachable() } +_opendir :: proc(path: string) -> (handle: Handle, err: Error) { + return INVALID_HANDLE, .Invalid_Argument +} + + _open :: proc(path: string, flags: File_Flags, perm: File_Mode) -> (handle: Handle, err: Error) { handle = INVALID_HANDLE if len(path) == 0 { diff --git a/core/os/os2/heap_linux.odin b/core/os/os2/heap_linux.odin new file mode 100644 index 000000000..f617f8cc8 --- /dev/null +++ b/core/os/os2/heap_linux.odin @@ -0,0 +1,27 @@ +//+private +package os2 + +import "core:mem" + +heap_alloc :: proc(size: int) -> rawptr { + // TODO + return nil +} + +heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr { + // TODO + return nil +} +heap_free :: proc(ptr: rawptr) { + if ptr == nil { + return + } + // TODO +} + +_heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, + size, alignment: int, + old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, mem.Allocator_Error) { + // TODO + return nil, nil +} diff --git a/core/os/os2/path_linux.odin b/core/os/os2/path_linux.odin new file mode 100644 index 000000000..b45d6e976 --- /dev/null +++ b/core/os/os2/path_linux.odin @@ -0,0 +1,85 @@ +//+private +package os2 + +import "core:fmt" +import "core:strings" +import "core:sys/unix" +import "core:path/filepath" + +_Path_Separator :: '/' +_Path_List_Separator :: ':' + +_is_path_separator :: proc(c: byte) -> bool { + return c == '/' +} + +_mkdir :: proc(path: string, perm: File_Mode) -> Error { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + //TODO file_mode + return _ok_or_error(unix.sys_mkdir(path_cstr)) +} + +_mkdir_all :: proc(path: string, perm: File_Mode) -> Error { + _mkdir_all_stat :: proc(path: string, s: ^OS_Stat, perm: File_Mode) -> Error { + if len(path) == 0 { + return nil + } + + path := path[len(path)-1] == '/' ? path[:len(path)-1] : path + dir, _ := filepath.split(path) + + if len(dir) == 0 { + return _mkdir(path, perm) + } + + dir_cstr := strings.clone_to_cstring(dir, context.temp_allocator) + errno := int(unix.get_errno(unix.sys_stat(dir_cstr, s))) + switch errno { + case 0: + if !S_ISDIR(s.mode) { + return .Exist + } + return _mkdir(path, perm) + case ENOENT: + _mkdir_all_stat(dir, s, perm) or_return + return _mkdir(path, perm) + case: + return _get_platform_error(errno) + } + unreachable() + } + // OS_Stat is fat. Make one and re-use it. + s: OS_Stat = --- + return _mkdir_all_stat(path, &s, perm) +} + +_remove_all :: proc(path: string) -> Error { + // TODO + return nil +} + +_getwd :: proc(allocator := context.allocator) -> (dir: string, err: Error) { + // NOTE(tetra): I would use PATH_MAX here, but I was not able to find + // an authoritative value for it across all systems. + // The largest value I could find was 4096, so might as well use the page size. + // NOTE(jason): Avoiding libc, so just use 4096 directly + PATH_MAX :: 4096 + buf := make([dynamic]u8, PATH_MAX, allocator) + for { + #no_bounds_check res := unix.sys_getcwd(&buf[0], uint(len(buf))) + + if res >= 0 { + return strings.string_from_nul_terminated_ptr(&buf[0], len(buf)), nil + } + if errno := int(unix.get_errno(res)); errno != ERANGE { + return "", _get_platform_error(errno) + } + resize(&buf, len(buf)+PATH_MAX) + } + unreachable() +} + +_setwd :: proc(dir: string) -> (err: Error) { + dir_cstr := strings.clone_to_cstring(dir, context.temp_allocator) + return _ok_or_error(unix.sys_chdir(dir_cstr)) +} diff --git a/core/os/os2/pipe_linux.odin b/core/os/os2/pipe_linux.odin new file mode 100644 index 000000000..0699c5720 --- /dev/null +++ b/core/os/os2/pipe_linux.odin @@ -0,0 +1,7 @@ +//+private +package os2 + +_pipe :: proc() -> (r, w: Handle, err: Error) { + return INVALID_HANDLE, INVALID_HANDLE, nil +} + diff --git a/core/os/os2/stat_linux.odin b/core/os/os2/stat_linux.odin index 7fce8fb9c..c4cc5fe8d 100644 --- a/core/os/os2/stat_linux.odin +++ b/core/os/os2/stat_linux.odin @@ -2,7 +2,9 @@ package os2 import "core:time" +import "core:strings" import "core:sys/unix" +import "core:path/filepath" // File type S_IFMT :: 0o170000 // Type of file mask @@ -51,6 +53,12 @@ X_OK :: 1 // Test for execute permission W_OK :: 2 // Test for write permission R_OK :: 4 // Test for read permission +@private +Unix_File_Time :: struct { + seconds: i64, + nanoseconds: i64, +} + @private OS_Stat :: struct { device_id: u64, // ID of device containing file @@ -75,19 +83,21 @@ OS_Stat :: struct { } _fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Error) { + return File_Info{}, nil } _stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) { + return File_Info{}, nil } _lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) { - cstr := strings.clone_to_cstring(path) + cstr := strings.clone_to_cstring(name) defer delete(cstr) s: OS_Stat result := unix.sys_lstat(cstr, &s) if result < 0 { - return {}, unix.get_errno(result) + return {}, _get_platform_error(int(unix.get_errno(result))) } fi := File_Info { @@ -96,10 +106,10 @@ _lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Erro size = s.size, mode = 0, is_dir = S_ISDIR(s.mode), - creation_time = nil, // linux does not track this + creation_time = time.Time{0}, // linux does not track this //TODO - modification_time = nil, - access_time = nil, + modification_time = time.Time{0}, + access_time = time.Time{0}, } return fi, nil @@ -110,7 +120,7 @@ _same_file :: proc(fi1, fi2: File_Info) -> bool { } _stat_internal :: proc(name: string) -> (s: OS_Stat, res: int) { - name_cstr = strings.clone_to_cstring(name, context.temp_allocator) + name_cstr := strings.clone_to_cstring(name, context.temp_allocator) res = unix.sys_stat(name_cstr, &s) return } diff --git a/core/os/os2/temp_file_linux.odin b/core/os/os2/temp_file_linux.odin new file mode 100644 index 000000000..d56bc34d3 --- /dev/null +++ b/core/os/os2/temp_file_linux.odin @@ -0,0 +1,18 @@ +//+private +package os2 + + +_create_temp :: proc(dir, pattern: string) -> (Handle, Error) { + //TODO + return 0, nil +} + +_mkdir_temp :: proc(dir, pattern: string, allocator := context.allocator) -> (string, Error) { + //TODO + return "", nil +} + +_temp_dir :: proc(allocator := context.allocator) -> string { + //TODO + return "" +} diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index 243f8accc..ccd8a75e6 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -15,7 +15,7 @@ import "core:intrinsics" // 386: arch/x86/entry/syscalls/sycall_32.tbl // arm: arch/arm/tools/syscall.tbl -when ODIN_ARCH == "amd64" { +when ODIN_ARCH == .amd64 { SYS_read : uintptr : 0 SYS_write : uintptr : 1 SYS_open : uintptr : 2 @@ -33,8 +33,8 @@ when ODIN_ARCH == "amd64" { SYS_rt_sigprocmask : uintptr : 14 SYS_rt_sigreturn : uintptr : 15 SYS_ioctl : uintptr : 16 - SYS_pread : uintptr : 17 - SYS_pwrite : uintptr : 18 + SYS_pread64 : uintptr : 17 + SYS_pwrite64 : uintptr : 18 SYS_readv : uintptr : 19 SYS_writev : uintptr : 20 SYS_access : uintptr : 21 @@ -374,7 +374,7 @@ when ODIN_ARCH == "amd64" { SYS_landlock_add_rule : uintptr : 445 SYS_landlock_restrict_self : uintptr : 446 SYS_memfd_secret : uintptr : 447 -} else when ODIN_ARCH == "arm64" { +} else when ODIN_ARCH == .arm64 { SYS_io_setup : uintptr : 0 SYS_io_destroy : uintptr : 1 SYS_io_submit : uintptr : 2 @@ -675,7 +675,7 @@ when ODIN_ARCH == "amd64" { SYS_landlock_create_ruleset : uintptr : 444 SYS_landlock_add_rule : uintptr : 445 SYS_landlock_restrict_self : uintptr : 446 -} else when ODIN_ARCH == "386" { +} else when ODIN_ARCH == .i386 { SYS_restart_syscall : uintptr : 0 SYS_exit : uintptr : 1 SYS_fork : uintptr : 2 @@ -1112,7 +1112,7 @@ when ODIN_ARCH == "amd64" { SYS_landlock_add_rule : uintptr : 445 SYS_landlock_restrict_self : uintptr : 446 SYS_memfd_secret : uintptr : 447 -} else when ODIN_ARCH == "arm" { +} else when ODIN_ARCH == .arm { SYS_restart_syscall : uintptr : 0 SYS_exit : uintptr : 1 SYS_fork : uintptr : 2 @@ -1518,6 +1518,7 @@ when ODIN_ARCH == "amd64" { AT_FDCWD :: -100 AT_REMOVEDIR :: uintptr(0x200) +AT_SYMLINK_FOLLOW :: uintptr(0x400) AT_SYMLINK_NOFOLLOW :: uintptr(0x100) sys_gettid :: proc "contextless" () -> int { @@ -1529,12 +1530,11 @@ sys_getrandom :: proc "contextless" (buf: ^byte, buflen: int, flags: uint) -> in } sys_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> int { - when ODIN_ARCH != "arm64" { - res := int(intrinsics.syscall(SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) + when ODIN_ARCH != .arm64 { + return int(intrinsics.syscall(SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) } else { // NOTE: arm64 does not have open - res := int(intrinsics.syscall(SYS_openat, uintptr(AT_FDCWD), uintptr(rawptr(path), uintptr(flags), uintptr(mode)))) + return int(intrinsics.syscall(SYS_openat, uintptr(AT_FDCWD), uintptr(rawptr(path), uintptr(flags), uintptr(mode)))) } - return -1 if res < 0 else res } sys_close :: proc(fd: int) -> int { @@ -1545,26 +1545,46 @@ sys_read :: proc(fd: int, buf: rawptr, size: uint) -> int { return int(intrinsics.syscall(SYS_read, uintptr(fd), uintptr(buf), uintptr(size))) } +sys_pread :: proc(fd: int, buf: rawptr, size: uint, offset: i64) -> int { + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { + return int(intrinsics.syscall(SYS_pread64, uintptr(fd), uintptr(buf), uintptr(size), uintptr(offset))) + } else { + low := uintptr(offset & 0xFFFFFFFF) + high := uintptr(offset >> 32) + return int(intrinsics.syscall(SYS_pread64, uintptr(fd), uintptr(buf), uintptr(size), high, low)) + } +} + sys_write :: proc(fd: int, buf: rawptr, size: uint) -> int { return int(intrinsics.syscall(SYS_write, uintptr(fd), uintptr(buf), uintptr(size))) } +sys_pwrite :: proc(fd: int, buf: rawptr, size: uint, offset: i64) -> int { + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { + return int(intrinsics.syscall(SYS_pwrite64, uintptr(fd), uintptr(buf), uintptr(size), uintptr(offset))) + } else { + low := uintptr(offset & 0xFFFFFFFF) + high := uintptr(offset >> 32) + return int(intrinsics.syscall(SYS_pwrite64, uintptr(fd), uintptr(buf), uintptr(size), high, low)) + } +} + sys_lseek :: proc(fd: int, offset: i64, whence: int) -> i64 { - when ODIN_ARCH == "amd64" || ODIN_ARCH == "arm64" { + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { return i64(intrinsics.syscall(SYS_lseek, uintptr(fd), uintptr(offset), uintptr(whence))) } else { low := uintptr(offset & 0xFFFFFFFF) high := uintptr(offset >> 32) result: i64 res := i64(intrinsics.syscall(SYS__llseek, uintptr(fd), high, low, &result, uintptr(whence))) - return -1 if res < 0 else result + return res if res < 0 else result } } sys_stat :: proc(path: cstring, stat: rawptr) -> int { - when ODIN_ARCH == "amd64" { + when ODIN_ARCH == .amd64 { return int(intrinsics.syscall(SYS_stat, uintptr(rawptr(path)), uintptr(stat))) - } else when ODIN_ARCH != "arm64" { + } else when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_stat64, uintptr(rawptr(path)), uintptr(stat))) } else { // NOTE: arm64 does not have stat return int(intrinsics.syscall(SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), 0)) @@ -1572,7 +1592,7 @@ sys_stat :: proc(path: cstring, stat: rawptr) -> int { } sys_fstat :: proc(fd: int, stat: rawptr) -> int { - when ODIN_ARCH == "amd64" || ODIN_ARCH == "arm64" { + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { return int(intrinsics.syscall(SYS_fstat, uintptr(fd), uintptr(stat))) } else { return int(intrinsics.syscall(SYS_fstat64, uintptr(fd), uintptr(stat))) @@ -1580,9 +1600,9 @@ sys_fstat :: proc(fd: int, stat: rawptr) -> int { } sys_lstat :: proc(path: cstring, stat: rawptr) -> int { - when ODIN_ARCH == "amd64" { + when ODIN_ARCH == .amd64 { return int(intrinsics.syscall(SYS_lstat, uintptr(rawptr(path)), uintptr(stat))) - } else when ODIN_ARCH != "arm64" { + } else when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_lstat64, uintptr(rawptr(path)), uintptr(stat))) } else { // NOTE: arm64 does not have any lstat return int(intrinsics.syscall(SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), AT_SYMLINK_NOFOLLOW)) @@ -1590,15 +1610,23 @@ sys_lstat :: proc(path: cstring, stat: rawptr) -> int { } sys_readlink :: proc(path: cstring, buf: rawptr, bufsiz: uint) -> int { - when ODIN_ARCH != "arm64" { + when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_readlink, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) } else { // NOTE: arm64 does not have readlink return int(intrinsics.syscall(SYS_readlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) } } +sys_symlink :: proc(old_name: cstring, new_name: cstring) -> int { + when ODIN_ARCH != .arm64 { + return int(intrinsics.syscall(SYS_symlink, uintptr(rawptr(old_name)), uintptr(rawptr(new_name)))) + } else { // NOTE: arm64 does not have symlink + return int(intrinsics.syscall(SYS_symlinkat, uintptr(rawptr(old_name)), uintptr(AT_FDCWD), uintptr(rawptr(new_name)))) + } +} + sys_access :: proc(path: cstring, mask: int) -> int { - when ODIN_ARCH != "arm64" { + when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_access, uintptr(rawptr(path)), uintptr(mask))) } else { // NOTE: arm64 does not have access return int(intrinsics.syscall(SYS_faccessat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mask))) @@ -1613,16 +1641,60 @@ sys_chdir :: proc(path: cstring) -> int { return int(intrinsics.syscall(SYS_chdir, uintptr(rawptr(path)))) } +sys_fchdir :: proc(fd: int) -> int { + return int(intrinsics.syscall(SYS_fchdir, uintptr(fd))) +} + +sys_chmod :: proc(path: cstring, mode: int) -> int { + when ODIN_ARCH != .arm64 { + return int(intrinsics.syscall(SYS_chmod, uintptr(rawptr(path)), uintptr(mode))) + } else { // NOTE: arm64 does not have chmod + return int(intrinsics.syscall(SYS_fchmodat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mode))) + } +} + +sys_fchmod :: proc(fd: int, mode: int) -> int { + return int(intrinsics.syscall(SYS_fchmod, uintptr(fd), uintptr(mode))) +} + +sys_chown :: proc(path: cstring, user: int, group: int) -> int { + when ODIN_ARCH != .arm64 { + return int(intrinsics.syscall(SYS_chown, uintptr(rawptr(path)), uintptr(user), uintptr(group))) + } else { // NOTE: arm64 does not have chown + return int(intrinsics.syscall(SYS_fchownat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(user), uintptr(group), 0)) + } +} + +sys_fchown :: proc(fd: int, user: int, group: int) -> int { + return int(intrinsics.syscall(SYS_fchown, uintptr(fd), uintptr(user), uintptr(group))) +} + +sys_lchown :: proc(path: cstring, user: int, group: int) -> int { + when ODIN_ARCH != .arm64 { + return int(intrinsics.syscall(SYS_lchown, uintptr(rawptr(path)), uintptr(user), uintptr(group))) + } else { // NOTE: arm64 does not have lchown + return int(intrinsics.syscall(SYS_fchownat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(user), uintptr(group), AT_SYMLINK_NOFOLLOW)) + } +} + sys_rename :: proc(old, new: cstring) -> int { - when ODIN_ARCH != "arm64" { + when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_rename, uintptr(rawptr(old)), uintptr(rawptr(new)))) } else { // NOTE: arm64 does not have rename return int(intrinsics.syscall(SYS_renameat, uintptr(AT_FDCWD), uintptr(rawptr(old)), uintptr(rawptr(new)))) } } +sys_link :: proc(old_name: cstring, new_name: cstring) -> int { + when ODIN_ARCH != .arm64 { + return int(intrinsics.syscall(SYS_link, uintptr(rawptr(old_name)), uintptr(rawptr(new_name)))) + } else { // NOTE: arm64 does not have link + return int(intrinsics.syscall(SYS_linkat, uintptr(AT_FDCWD), uintptr(rawptr(old_name)), uintptr(AT_FDCWD), uintptr(rawptr(new_name)), AT_SYMLINK_FOLLOW)) + } +} + sys_unlink :: proc(path: cstring) -> int { - when ODIN_ARCH != "arm64" { + when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_unlink, uintptr(rawptr(path)))) } else { // NOTE: arm64 does not have unlink return int(intrinsics.syscall(SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path), 0))) @@ -1630,7 +1702,7 @@ sys_unlink :: proc(path: cstring) -> int { } sys_rmdir :: proc(path: cstring) -> int { - when ODIN_ARCH != "arm64" { + when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_rmdir, uintptr(rawptr(path)))) } else { // NOTE: arm64 does not have rmdir return int(intrinsics.syscall(SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), AT_REMOVEDIR)) @@ -1638,14 +1710,40 @@ sys_rmdir :: proc(path: cstring) -> int { } sys_mkdir :: proc(path: cstring, mode: u32 = 0o775) -> int { - when ODIN_ARCH != "arm64" { + when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_mkdir, uintptr(rawptr(path)), uintptr(mode))) } else { // NOTE: arm64 does not have mkdir return int(intrinsics.syscall(SYS_mkdirat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mode))) } } -//TODO: ftruncate, symlink, readlink, fchdir, fchmod, chown, fchown, lchown +sys_truncate :: proc(path: cstring, length: i64) -> int { + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { + return int(intrinsics.syscall(SYS_truncate, uintptr(rawptr(path)), uintptr(length))) + } else { + low := uintptr(length & 0xFFFFFFFF) + high := uintptr(length >> 32) + return int(intrinsics.syscall(SYS_truncate64, uintptr(rawptr(path)), high, low)) + } +} + +sys_ftruncate :: proc(fd: int, length: i64) -> int { + when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { + return int(intrinsics.syscall(SYS_ftruncate, uintptr(fd), uintptr(length))) + } else { + low := uintptr(length & 0xFFFFFFFF) + high := uintptr(length >> 32) + return int(intrinsics.syscall(SYS_ftruncate64, uintptr(fd), high, low)) + } +} + +sys_fsync :: proc(fd: int) -> int { + return int(intrinsics.syscall(SYS_fsync, uintptr(fd))) +} + +sys_getdents64 :: proc(fd: int, dirent: rawptr, count: int) -> int { + return int(intrinsics.syscall(SYS_getdents64, uintptr(fd), uintptr(dirent), uintptr(count))) +} get_errno :: proc(res: int) -> i32 { if res < 0 && res > -4096 {