diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index 41c487b2b..16dcf2473 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -6,6 +6,7 @@ foreign import libc "system:c" import "base:runtime" import "core:strings" import "core:c" +import "core:sys/freebsd" Handle :: distinct i32 File_Time :: distinct u64 @@ -481,23 +482,27 @@ write :: proc(fd: Handle, data: []byte) -> (int, Error) { } read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) { - curr := seek(fd, offset, SEEK_CUR) or_return - n, err = read(fd, data) - _, err1 := seek(fd, curr, SEEK_SET) - if err1 != nil && err == nil { - err = err1 + if len(data) == 0 { + return 0, nil } - return + + to_read := min(uint(len(data)), MAX_RW) + + bytes_read, errno := freebsd.pread(cast(freebsd.Fd)fd, data[:to_read], cast(freebsd.off_t)offset) + + return bytes_read, cast(_Platform_Error)errno } write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) { - curr := seek(fd, offset, SEEK_CUR) or_return - n, err = write(fd, data) - _, err1 := seek(fd, curr, SEEK_SET) - if err1 != nil && err == nil { - err = err1 + if len(data) == 0 { + return 0, nil } - return + + to_write := min(uint(len(data)), MAX_RW) + + bytes_written, errno := freebsd.pwrite(cast(freebsd.Fd)fd, data[:to_write], cast(freebsd.off_t)offset) + + return bytes_written, cast(_Platform_Error)errno } seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Error) { diff --git a/core/sys/freebsd/syscalls.odin b/core/sys/freebsd/syscalls.odin index 4a79bd56c..d1876a5e2 100644 --- a/core/sys/freebsd/syscalls.odin +++ b/core/sys/freebsd/syscalls.odin @@ -14,6 +14,8 @@ import "core:c" // FreeBSD 15 syscall numbers // See: https://alfonsosiciliano.gitlab.io/posts/2023-08-28-freebsd-15-system-calls.html +SYS_read : uintptr : 3 +SYS_write : uintptr : 4 SYS_open : uintptr : 5 SYS_close : uintptr : 6 SYS_getpid : uintptr : 20 @@ -29,12 +31,46 @@ SYS_shutdown : uintptr : 134 SYS_setsockopt : uintptr : 105 SYS_sysctl : uintptr : 202 SYS__umtx_op : uintptr : 454 +SYS_pread : uintptr : 475 +SYS_pwrite : uintptr : 476 SYS_accept4 : uintptr : 541 // // Odin syscall wrappers // +// Read input. +// +// The read() function appeared in Version 1 AT&T UNIX. +read :: proc "contextless" (fd: Fd, buf: []u8) -> (int, Errno) { + result, ok := intrinsics.syscall_bsd(SYS_read, + cast(uintptr)fd, + cast(uintptr)raw_data(buf), + cast(uintptr)len(buf)) + + if !ok { + return 0, cast(Errno)result + } + + return cast(int)result, nil +} + +// Write output. +// +// The write() function appeared in Version 1 AT&T UNIX. +write :: proc "contextless" (fd: Fd, buf: []u8) -> (int, Errno) { + result, ok := intrinsics.syscall_bsd(SYS_pwrite, + cast(uintptr)fd, + cast(uintptr)raw_data(buf), + cast(uintptr)len(buf)) + + if !ok { + return 0, cast(Errno)result + } + + return cast(int)result, nil +} + // Open or create a file for reading, writing or executing. // // The open() function appeared in Version 1 AT&T UNIX. @@ -469,6 +505,46 @@ _umtx_op :: proc "contextless" (obj: rawptr, op: Userland_Mutex_Operation, val: return cast(Errno)result } +// Read input without modifying the file pointer. +// +// The pread() function appeared in AT&T System V Release 4 UNIX. +pread :: proc "contextless" (fd: Fd, buf: []u8, offset: off_t) -> (int, Errno) { + result, ok := intrinsics.syscall_bsd(SYS_pread, + cast(uintptr)fd, + cast(uintptr)raw_data(buf), + cast(uintptr)len(buf), + cast(uintptr)offset) + + if !ok { + return 0, cast(Errno)result + } + + return cast(int)result, nil +} + +// Write output without modifying the file pointer. +// +// The pwrite() function appeared in AT&T System V Release 4 UNIX. +// +// BUGS +// +// The pwrite() system call appends the file without changing the file +// offset if O_APPEND is set, contrary to IEEE Std 1003.1-2008 (“POSIX.1”) +// where pwrite() writes into offset regardless of whether O_APPEND is set. +pwrite :: proc "contextless" (fd: Fd, buf: []u8, offset: off_t) -> (int, Errno) { + result, ok := intrinsics.syscall_bsd(SYS_pwrite, + cast(uintptr)fd, + cast(uintptr)raw_data(buf), + cast(uintptr)len(buf), + cast(uintptr)offset) + + if !ok { + return 0, cast(Errno)result + } + + return cast(int)result, nil +} + // Accept a connection on a socket. // // The accept4() system call appeared in FreeBSD 10.0.