diff --git a/core/os/os2/file.odin b/core/os/os2/file.odin index 454bc50b9..f1c5b1fad 100644 --- a/core/os/os2/file.odin +++ b/core/os/os2/file.odin @@ -115,7 +115,11 @@ open :: proc(name: string, flags := File_Flags{.Read}, perm := 0o777) -> (^File, @(require_results) new_file :: proc(handle: uintptr, name: string) -> ^File { - return _new_file(handle, name) or_else panic("Out of memory") + file, err := _new_file(handle, name) + if err != nil { + panic(error_string(err)) + } + return file } @(require_results) diff --git a/core/os/os2/file_posix.odin b/core/os/os2/file_posix.odin index efecf6e49..06526d2e8 100644 --- a/core/os/os2/file_posix.odin +++ b/core/os/os2/file_posix.odin @@ -26,9 +26,18 @@ File_Impl :: struct { @(init) init_std_files :: proc() { // NOTE: is this (paths) also the case on non darwin? - stdin = new_file(posix.STDIN_FILENO, "/dev/stdin") - stdout = new_file(posix.STDOUT_FILENO, "/dev/stdout") - stderr = new_file(posix.STDERR_FILENO, "/dev/stdout") + + stdin = __new_file(posix.STDIN_FILENO) + (^File_Impl)(stdin.impl).name = "/dev/stdin" + (^File_Impl)(stdin.impl).cname = "/dev/stdin" + + stdout = __new_file(posix.STDIN_FILENO) + (^File_Impl)(stdout.impl).name = "/dev/stdout" + (^File_Impl)(stdout.impl).cname = "/dev/stdout" + + stderr = __new_file(posix.STDIN_FILENO) + (^File_Impl)(stderr.impl).name = "/dev/stderr" + (^File_Impl)(stderr.impl).cname = "/dev/stderr" } _open :: proc(name: string, flags: File_Flags, perm: int) -> (f: ^File, err: Error) { @@ -75,19 +84,12 @@ _new_file :: proc(handle: uintptr, name: string) -> (f: ^File, err: Error) { return } - TEMP_ALLOCATOR_GUARD() - cname := temp_cstring(name) + crname := _posix_absolute_path(posix.FD(handle), name, file_allocator()) or_return + rname := string(crname) - crname := posix.realpath(cname, nil) - if crname == nil { - err = _get_platform_error() - return - } - rname := string(crname) - - f = __new_file(posix.FD(handle)) + f = __new_file(posix.FD(handle)) impl := (^File_Impl)(f.impl) - impl.name = rname + impl.name = rname impl.cname = crname return f, nil diff --git a/core/os/os2/file_posix_darwin.odin b/core/os/os2/file_posix_darwin.odin new file mode 100644 index 000000000..056d775e6 --- /dev/null +++ b/core/os/os2/file_posix_darwin.odin @@ -0,0 +1,18 @@ +//+private +package os2 + +import "base:runtime" + +import "core:sys/posix" + +_posix_absolute_path :: proc(fd: posix.FD, name: string, allocator: runtime.Allocator) -> (path: cstring, err: Error) { + F_GETPATH :: 50 + + buf: [posix.PATH_MAX]byte + if posix.fcntl(fd, posix.FCNTL_Cmd(F_GETPATH), &buf) != 0 { + err = _get_platform_error() + return + } + + return clone_to_cstring(string(cstring(&buf[0])), allocator) +} diff --git a/core/os/os2/file_posix_freebsd.odin b/core/os/os2/file_posix_freebsd.odin new file mode 100644 index 000000000..e5007f8fe --- /dev/null +++ b/core/os/os2/file_posix_freebsd.odin @@ -0,0 +1,47 @@ +//+private +package os2 + +import "base:runtime" + +import "core:c" +import "core:sys/posix" + +_posix_absolute_path :: proc(fd: posix.FD, name: string, allocator: runtime.Allocator) -> (path: cstring, err: Error) { + // NOTE(Feoramund): The situation isn't ideal, but this was the best way I + // could find to implement this. There are a couple outstanding bug reports + // regarding the desire to retrieve an absolute path from a handle, but to + // my knowledge, there hasn't been any work done on it. + // + // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=198570 + // + // This may be unreliable, according to a comment from 2023. + + KInfo_File :: struct { + structsize: c.int, + type: c.int, + fd: c.int, + ref_count: c.int, + flags: c.int, + pad0: c.int, + offset: i64, + + // NOTE(Feoramund): This field represents a complicated union that I am + // avoiding implementing for now. I only need the path data below. + _union: [336]byte, + + path: [posix.PATH_MAX]c.char, + } + + F_KINFO :: 22 + + kinfo: KInfo_File + kinfo.structsize = size_of(KInfo_File) + + res := posix.fcntl(fd, posix.FCNTL_Cmd(F_KINFO), &kinfo) + if res == -1 { + err = _get_platform_error() + return + } + + return clone_to_cstring(string(cstring(&kinfo.path[0])), allocator) +} diff --git a/core/os/os2/file_posix_netbsd.odin b/core/os/os2/file_posix_netbsd.odin new file mode 100644 index 000000000..a9cc77a41 --- /dev/null +++ b/core/os/os2/file_posix_netbsd.odin @@ -0,0 +1,18 @@ +//+private +package os2 + +import "base:runtime" + +import "core:sys/posix" + +_posix_absolute_path :: proc(fd: posix.FD, name: string, allocator: runtime.Allocator) -> (path: cstring, err: Error) { + F_GETPATH :: 15 + + buf: [posix.PATH_MAX]byte + if posix.fcntl(fd, posix.FCNTL_Cmd(F_GETPATH), &buf) != 0 { + err = _get_platform_error() + return + } + + return clone_to_cstring(string(cstring(&buf[0])), allocator) +} diff --git a/core/os/os2/file_posix_other.odin b/core/os/os2/file_posix_other.odin new file mode 100644 index 000000000..8a76f4cd7 --- /dev/null +++ b/core/os/os2/file_posix_other.odin @@ -0,0 +1,21 @@ +//+private +//+build openbsd +package os2 + +import "base:runtime" + +import "core:sys/posix" + +_posix_absolute_path :: proc(fd: posix.FD, name: string, allocator: runtime.Allocator) -> (path: cstring, err: Error) { + TEMP_ALLOCATOR_GUARD(ignore=is_temp(allocator)) + cname := temp_cstring(name) + + buf: [posix.PATH_MAX]byte + path = posix.realpath(cname, raw_data(buf[:])) + if path == nil { + err = _get_platform_error() + return + } + + return clone_to_cstring(string(path), allocator) +} diff --git a/core/os/os2/stat_posix.odin b/core/os/os2/stat_posix.odin index eb63febe7..f670dd394 100644 --- a/core/os/os2/stat_posix.odin +++ b/core/os/os2/stat_posix.odin @@ -73,21 +73,22 @@ _stat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err TEMP_ALLOCATOR_GUARD(ignore=is_temp(allocator)) cname := temp_cstring(name) or_return - rcname := posix.realpath(cname) - if rcname == nil { - err = .Invalid_Path + fd := posix.open(cname, {}) + if fd == -1 { + err = _get_platform_error() return } - defer posix.free(rcname) + defer posix.close(fd) + + fullpath := _posix_absolute_path(fd, name, allocator) or_return stat: posix.stat_t - if posix.stat(rcname, &stat) != .OK { + if posix.stat(fullpath, &stat) != .OK { err = _get_platform_error() return } - fullpath := clone_string(string(rcname), allocator) or_return - return internal_stat(stat, fullpath), nil + return internal_stat(stat, string(fullpath)), nil } _lstat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) { @@ -98,7 +99,7 @@ _lstat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, er TEMP_ALLOCATOR_GUARD(ignore=is_temp(allocator)) - // NOTE: can't use realpath here because it tries to resolve symlinks. + // NOTE: can't use realpath or open (+ fcntl F_GETPATH) here because it tries to resolve symlinks. // NOTE: This might not be correct when given "/symlink/foo.txt", // you would want that to resolve "/symlink", but not resolve "foo.txt". diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index ba7e7ccf3..c2d747a60 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -388,7 +388,7 @@ foreign libc { @(link_name="unlink") _unix_unlink :: proc(path: cstring) -> c.int --- @(link_name="rmdir") _unix_rmdir :: proc(path: cstring) -> c.int --- @(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int --- - @(link_name="fcntl") _unix_fcntl :: proc(fd: Handle, cmd: c.int, arg: uintptr) -> c.int --- + @(link_name="fcntl") _unix_fcntl :: proc(fd: Handle, cmd: c.int, #c_vararg args: ..any) -> c.int --- @(link_name="dup") _unix_dup :: proc(fd: Handle) -> Handle --- @(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir --- diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin index fac1bc311..931b38f12 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/os_netbsd.odin @@ -440,7 +440,7 @@ foreign libc { @(link_name="unlink") _unix_unlink :: proc(path: cstring) -> c.int --- @(link_name="rmdir") _unix_rmdir :: proc(path: cstring) -> c.int --- @(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int --- - @(link_name="fcntl") _unix_fcntl :: proc(fd: Handle, cmd: c.int, arg: uintptr) -> c.int --- + @(link_name="fcntl") _unix_fcntl :: proc(fd: Handle, cmd: c.int, #c_vararg args: ..any) -> c.int --- @(link_name="dup") _unix_dup :: proc(fd: Handle) -> Handle --- @(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir --- diff --git a/core/sys/posix/fcntl.odin b/core/sys/posix/fcntl.odin index e98086eb3..8f1b1a511 100644 --- a/core/sys/posix/fcntl.odin +++ b/core/sys/posix/fcntl.odin @@ -23,7 +23,7 @@ foreign lib { [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html ]] */ - fcntl :: proc(fd: FD, cmd: FCNTL_Cmd, arg: rawptr = nil) -> c.int --- + fcntl :: proc(fd: FD, cmd: FCNTL_Cmd, #c_vararg args: ..any) -> c.int --- /* Establish the connection between a file and a file descriptor.