os2 linux begin

This commit is contained in:
CiD-
2022-03-03 10:16:36 -05:00
parent 6630d703f8
commit e51bb4ef12
3 changed files with 486 additions and 4 deletions

236
core/os/os2/file_linux.odin Normal file
View File

@@ -0,0 +1,236 @@
//+private
package os2
import "core:io"
import "core:time"
import "core:sys/unix"
_get_platform_error :: proc(res: int) -> Error {
errno := unix.get_errno(res)
return Platform_Error{i32(errno)}
}
_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))
}
return handle, nil
}
_close :: proc(fd: Handle) -> Error {
res := unix.sys_close(int(fd))
return _ok_or_error(res)
}
_name :: proc(fd: Handle, allocator := context.allocator) -> string {
//TODO
return ""
}
_seek :: proc(fd: Handle, offset: i64, whence: Seek_From) -> (ret: i64, err: Error) {
res := unix.sys_lseek(int(fd), offset, int(whence))
if res < 0 {
return -1, _get_platform_error(int(res))
}
return res, nil
}
_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)))
if n < 0 {
return -1, unix.get_errno(n)
}
return bytes_read, 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
for len(b) > 0 {
m := _read(fd, b) or_return
n += m
b = b[m:]
}
return
}
_read_from :: proc(fd: Handle, r: io.Reader) -> (n: i64, err: Error) {
//TODO
return
}
_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)))
if n < 0 {
return -1, _get_platform_error(n)
}
return int(n), nil
}
_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
for len(b) > 0 {
m := _write(fd, b) or_return
n += m
b = b[m:]
}
return
}
_write_to :: proc(fd: Handle, w: io.Writer) -> (n: i64, err: Error) {
//TODO
return
}
_file_size :: proc(fd: Handle) -> (n: i64, err: Error) {
s, err := _fstat(fd) or_return
if err != nil {
return 0, err
}
return max(s.size, 0), nil
}
_sync :: proc(fd: Handle) -> Error {
return _ok_or_error(unix.sys_fsync(int(fd)))
}
_flush :: proc(fd: Handle) -> Error {
return _ok_or_error(unix.sys_fsync(int(fd)))
}
_truncate :: proc(fd: Handle, size: i64) -> Error {
return _ok_or_error(unix.sys_ftruncate(int(fd), size))
}
_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))
}
return _ok_or_error(unix.sys_unlink(path_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))
}
_link :: 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_link(old_name_cstr, new_name_cstr))
}
_symlink :: 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_symlink(old_name_cstr, new_name_cstr))
}
_read_link :: proc(name: string, allocator := context.allocator) -> (string, Error) {
path_cstr := strings.clone_to_cstring(path)
defer delete(path_cstr)
bufsz : uint = 256
buf := make([]byte, bufsz, allocator)
for {
rc := unix.sys_readlink(path_cstr, &(buf[0]), bufsz)
if rc < 0 {
delete(buf)
return "", unix.get_errno(rc)
} else if rc == int(bufsz) {
bufsz *= 2
delete(buf)
buf = make([]byte, bufsz, allocator)
} else {
return strings.string_from_ptr(&buf[0], rc), nil
}
}
}
_unlink :: proc(path: string) -> Error {
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
return _ok_or_error(unix.sys_unlink(path_cstr))
}
_chdir :: proc(fd: Handle) -> Error {
return _ok_or_error(unix.sys_fchdir(int(fd)))
}
_chmod :: proc(fd: Handle, mode: File_Mode) -> Error {
//TODO
return nil
}
_chown :: proc(fd: Handle, uid, gid: int) -> Error {
//TODO
return nil
}
_lchown :: proc(name: string, uid, gid: int) -> Error {
//TODO
return nil
}
_chtimes :: proc(name: string, atime, mtime: time.Time) -> Error {
//TODO
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
}
_is_file :: proc(fd: Handle) -> bool {
s: OS_Stat
res := unix.sys_fstat(int(fd), rawptr(&s))
if res < 0 { // error
return false
}
return S_ISREG(s.mode)
}
_is_dir :: proc(fd: Handle) -> bool {
s: OS_Stat
res := unix.sys_fstat(int(fd), rawptr(&s))
if res < 0 { // error
return false
}
return S_ISDIR(s.mode)
}

116
core/os/os2/stat_linux.odin Normal file
View File

@@ -0,0 +1,116 @@
//+private
package os2
import "core:time"
import "core:sys/unix"
// File type
S_IFMT :: 0o170000 // Type of file mask
S_IFIFO :: 0o010000 // Named pipe (fifo)
S_IFCHR :: 0o020000 // Character special
S_IFDIR :: 0o040000 // Directory
S_IFBLK :: 0o060000 // Block special
S_IFREG :: 0o100000 // Regular
S_IFLNK :: 0o120000 // Symbolic link
S_IFSOCK :: 0o140000 // Socket
// File mode
// Read, write, execute/search by owner
S_IRWXU :: 0o0700 // RWX mask for owner
S_IRUSR :: 0o0400 // R for owner
S_IWUSR :: 0o0200 // W for owner
S_IXUSR :: 0o0100 // X for owner
// Read, write, execute/search by group
S_IRWXG :: 0o0070 // RWX mask for group
S_IRGRP :: 0o0040 // R for group
S_IWGRP :: 0o0020 // W for group
S_IXGRP :: 0o0010 // X for group
// Read, write, execute/search by others
S_IRWXO :: 0o0007 // RWX mask for other
S_IROTH :: 0o0004 // R for other
S_IWOTH :: 0o0002 // W for other
S_IXOTH :: 0o0001 // X for other
S_ISUID :: 0o4000 // Set user id on execution
S_ISGID :: 0o2000 // Set group id on execution
S_ISVTX :: 0o1000 // Directory restrcted delete
S_ISLNK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFLNK }
S_ISREG :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFREG }
S_ISDIR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFDIR }
S_ISCHR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFCHR }
S_ISBLK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFBLK }
S_ISFIFO :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFIFO }
S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK }
F_OK :: 0 // Test for file existance
X_OK :: 1 // Test for execute permission
W_OK :: 2 // Test for write permission
R_OK :: 4 // Test for read permission
@private
OS_Stat :: struct {
device_id: u64, // ID of device containing file
serial: u64, // File serial number
nlink: u64, // Number of hard links
mode: u32, // Mode of the file
uid: u32, // User ID of the file's owner
gid: u32, // Group ID of the file's group
_padding: i32, // 32 bits of padding
rdev: u64, // Device ID, if device
size: i64, // Size of the file, in bytes
block_size: i64, // Optimal bllocksize for I/O
blocks: i64, // Number of 512-byte blocks allocated
last_access: Unix_File_Time, // Time of last access
modified: Unix_File_Time, // Time of last modification
status_change: Unix_File_Time, // Time of last status change
_reserve1,
_reserve2,
_reserve3: i64,
}
_fstat :: proc(fd: Handle, allocator := context.allocator) -> (File_Info, Error) {
}
_stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) {
}
_lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) {
cstr := strings.clone_to_cstring(path)
defer delete(cstr)
s: OS_Stat
result := unix.sys_lstat(cstr, &s)
if result < 0 {
return {}, unix.get_errno(result)
}
fi := File_Info {
fullpath = "",
name = "",
size = s.size,
mode = 0,
is_dir = S_ISDIR(s.mode),
creation_time = nil, // linux does not track this
//TODO
modification_time = nil,
access_time = nil,
}
return fi, nil
}
_same_file :: proc(fi1, fi2: File_Info) -> bool {
return fi1.fullpath == fi2.fullpath
}
_stat_internal :: proc(name: string) -> (s: OS_Stat, res: int) {
name_cstr = strings.clone_to_cstring(name, context.temp_allocator)
res = unix.sys_stat(name_cstr, &s)
return
}

View File

@@ -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
@@ -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 == .i386 {
} else when ODIN_ARCH == "386" {
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 false /*ODIN_ARCH == .arm*/ { // TODO
} else when ODIN_ARCH == "arm" {
SYS_restart_syscall : uintptr : 0
SYS_exit : uintptr : 1
SYS_fork : uintptr : 2
@@ -1516,6 +1516,10 @@ when ODIN_ARCH == .amd64 {
#panic("Unsupported architecture")
}
AT_FDCWD :: -100
AT_REMOVEDIR :: uintptr(0x200)
AT_SYMLINK_NOFOLLOW :: uintptr(0x100)
sys_gettid :: proc "contextless" () -> int {
return cast(int)intrinsics.syscall(SYS_gettid)
}
@@ -1523,3 +1527,129 @@ sys_gettid :: proc "contextless" () -> int {
sys_getrandom :: proc "contextless" (buf: ^byte, buflen: int, flags: uint) -> int {
return cast(int)intrinsics.syscall(SYS_getrandom, buf, cast(uintptr)(buflen), cast(uintptr)(flags))
}
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)))
} else { // NOTE: arm64 does not have open
res := 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 {
return int(intrinsics.syscall(SYS_close, uintptr(fd)))
}
sys_read :: proc(fd: int, buf: rawptr, size: uint) -> int {
return int(intrinsics.syscall(SYS_read, uintptr(fd), uintptr(buf), uintptr(size)))
}
sys_write :: proc(fd: int, buf: rawptr, size: uint) -> int {
return int(intrinsics.syscall(SYS_write, uintptr(fd), uintptr(buf), uintptr(size)))
}
sys_lseek :: proc(fd: int, offset: i64, whence: int) -> i64 {
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
}
}
sys_stat :: proc(path: cstring, stat: rawptr) -> int {
when ODIN_ARCH == "amd64" {
return int(intrinsics.syscall(SYS_stat, uintptr(rawptr(path)), uintptr(stat)))
} 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))
}
}
sys_fstat :: proc(fd: int, stat: rawptr) -> int {
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)))
}
}
sys_lstat :: proc(path: cstring, stat: rawptr) -> int {
when ODIN_ARCH == "amd64" {
return int(intrinsics.syscall(SYS_lstat, uintptr(rawptr(path)), uintptr(stat)))
} 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))
}
}
sys_readlink :: proc(path: cstring, buf: rawptr, bufsiz: uint) -> int {
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_access :: proc(path: cstring, mask: int) -> int {
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)))
}
}
sys_getcwd :: proc(buf: rawptr, size: uint) -> int {
return int(intrinsics.syscall(SYS_getcwd, uintptr(buf), uintptr(size)))
}
sys_chdir :: proc(path: cstring) -> int {
return int(intrinsics.syscall(SYS_chdir, uintptr(rawptr(path))))
}
sys_rename :: proc(old, new: cstring) -> int {
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_unlink :: proc(path: cstring) -> int {
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)))
}
}
sys_rmdir :: proc(path: cstring) -> int {
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))
}
}
sys_mkdir :: proc(path: cstring, mode: u32 = 0o775) -> int {
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
get_errno :: proc(res: int) -> i32 {
if res < 0 && res > -4096 {
return i32(-res)
}
return 0
}