mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-19 21:10:30 +00:00
os2: improve absolute/full path handling for posix
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
18
core/os/os2/file_posix_darwin.odin
Normal file
18
core/os/os2/file_posix_darwin.odin
Normal 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)
|
||||
}
|
||||
47
core/os/os2/file_posix_freebsd.odin
Normal file
47
core/os/os2/file_posix_freebsd.odin
Normal 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)
|
||||
}
|
||||
18
core/os/os2/file_posix_netbsd.odin
Normal file
18
core/os/os2/file_posix_netbsd.odin
Normal 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)
|
||||
}
|
||||
21
core/os/os2/file_posix_other.odin
Normal file
21
core/os/os2/file_posix_other.odin
Normal 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)
|
||||
}
|
||||
@@ -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".
|
||||
|
||||
@@ -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 ---
|
||||
|
||||
@@ -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 ---
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user