os2: improve absolute/full path handling for posix

This commit is contained in:
Laytan Laats
2024-08-04 16:58:18 +02:00
parent a73677d21a
commit b07d0b38b1
10 changed files with 137 additions and 26 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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".

View File

@@ -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 ---

View File

@@ -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 ---

View File

@@ -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.