commit to merge upstream/master

This commit is contained in:
CiD-
2022-03-14 13:34:06 -04:00
parent e008b5a160
commit c293e88f2e
5 changed files with 129 additions and 92 deletions

View File

@@ -11,35 +11,35 @@ _std_handle :: proc(kind: Std_Handle_Kind) -> Handle {
return Handle(kind)
}
__O_RDONLY :: 0o0
__O_WRONLY :: 0o1
__O_RDWR :: 0o2
__O_CREAT :: 0o100
__O_EXCL :: 0o200
__O_TRUNC :: 0o1000
__O_APPEND :: 0o2000
__O_NONBLOCK :: 0o4000
__O_LARGEFILE :: 0o100000
__O_DIRECTORY :: 0o200000
__O_SYNC :: 0o4010000
__O_CLOEXEC :: 0o2000000
_O_RDONLY :: 0o0
_O_WRONLY :: 0o1
_O_RDWR :: 0o2
_O_CREAT :: 0o100
_O_EXCL :: 0o200
_O_TRUNC :: 0o1000
_O_APPEND :: 0o2000
_O_NONBLOCK :: 0o4000
_O_LARGEFILE :: 0o100000
_O_DIRECTORY :: 0o200000
_O_SYNC :: 0o4010000
_O_CLOEXEC :: 0o2000000
_open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Error) {
cstr := strings.clone_to_cstring(name, context.temp_allocator)
flags_i: int
switch flags & O_RDONLY|O_WRONLY|O_RDWR {
case O_RDONLY: flags_i = __O_RDONLY
case O_WRONLY: flags_i = __O_WRONLY
case O_RDWR: flags_i = __O_RDWR
case O_RDONLY: flags_i = _O_RDONLY
case O_WRONLY: flags_i = _O_WRONLY
case O_RDWR: flags_i = _O_RDWR
}
flags_i |= (__O_APPEND * int(.Append in flags))
flags_i |= (__O_CREAT * int(.Create in flags))
flags_i |= (__O_EXCL * int(.Excl in flags))
flags_i |= (__O_SYNC * int(.Sync in flags))
flags_i |= (__O_TRUNC * int(.Trunc in flags))
flags_i |= (__O_CLOEXEC * int(.Close_On_Exec in flags))
flags_i |= (_O_APPEND * int(.Append in flags))
flags_i |= (_O_CREAT * int(.Create in flags))
flags_i |= (_O_EXCL * int(.Excl in flags))
flags_i |= (_O_SYNC * int(.Sync in flags))
flags_i |= (_O_TRUNC * int(.Trunc in flags))
flags_i |= (_O_CLOEXEC * int(.Close_On_Exec in flags))
handle_i := unix.sys_open(cstr, flags_i, int(perm))
if handle_i < 0 {
@@ -165,7 +165,6 @@ _remove :: proc(name: string) -> Error {
}
defer unix.sys_close(handle_i)
/* TODO: THIS WILL NOT WORK */
if _is_dir(Handle(handle_i)) {
return _ok_or_error(unix.sys_rmdir(name_cstr))
}

View File

@@ -8,7 +8,16 @@ import "core:path/filepath"
_Path_Separator :: '/'
_Path_List_Separator :: ':'
DIRECTORY_FLAGS :: __O_RDONLY|__O_NONBLOCK|__O_DIRECTORY|__O_LARGEFILE|__O_CLOEXEC
_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
_OPENDIR_FLAGS :: _O_RDONLY|_O_NONBLOCK|_O_DIRECTORY|_O_LARGEFILE|_O_CLOEXEC
_is_path_separator :: proc(c: byte) -> bool {
return c == '/'
@@ -16,42 +25,17 @@ _is_path_separator :: proc(c: byte) -> bool {
_mkdir :: proc(path: string, perm: File_Mode) -> Error {
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
//TODO file_mode
return _ok_or_error(unix.sys_mkdir(path_cstr))
perm_i: int
if perm & (File_Mode_Named_Pipe | File_Mode_Device | File_Mode_Char_Device | File_Mode_Sym_Link) != 0 {
return .Invalid_Argument
}
return _ok_or_error(unix.sys_mkdir(path_cstr, int(perm & 0o777)))
}
// TODO
_mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
_mkdir_all_stat :: proc(path: string, s: ^OS_Stat, perm: File_Mode) -> Error {
if len(path) == 0 {
return nil
}
path := path[len(path)-1] == '/' ? path[:len(path)-1] : path
dir, _ := filepath.split(path)
if len(dir) == 0 {
return _mkdir(path, perm)
}
dir_cstr := strings.clone_to_cstring(dir, context.temp_allocator)
errno := int(unix.get_errno(unix.sys_stat(dir_cstr, s)))
switch errno {
case 0:
if !S_ISDIR(s.mode) {
return .Exist
}
return _mkdir(path, perm)
case ENOENT:
_mkdir_all_stat(dir, s, perm) or_return
return _mkdir(path, perm)
case:
return _get_platform_error(errno)
}
unreachable()
}
// OS_Stat is fat. Make one and re-use it.
s: OS_Stat = ---
return _mkdir_all_stat(path, &s, perm)
return nil
}
dirent64 :: struct {
@@ -62,17 +46,9 @@ dirent64 :: struct {
d_name: [1]u8,
}
DT_UNKNOWN :: 0
DT_FIFO :: 1
DT_CHR :: 2
DT_DIR :: 4
DT_BLK :: 6
DT_REG :: 8
DT_LNK :: 10
DT_SOCK :: 12
DT_WHT :: 14
_remove_all :: proc(path: string) -> Error {
DT_DIR :: 4
_remove_all_dir :: proc(dfd: Handle) -> Error {
n := 64
buf := make([]u8, n)
@@ -114,7 +90,7 @@ _remove_all :: proc(path: string) -> Error {
switch d.d_type {
case DT_DIR:
handle_i := unix.sys_openat(int(dfd), d_name_cstr, DIRECTORY_FLAGS)
handle_i := unix.sys_openat(int(dfd), d_name_cstr, _OPENDIR_FLAGS)
if handle_i < 0 {
return _get_platform_error(handle_i)
}
@@ -135,7 +111,7 @@ _remove_all :: proc(path: string) -> Error {
cstr := strings.clone_to_cstring(path, context.temp_allocator)
handle_i := unix.sys_open(cstr, DIRECTORY_FLAGS)
handle_i := unix.sys_open(cstr, _OPENDIR_FLAGS)
switch handle_i {
case -ENOTDIR:
return _ok_or_error(unix.sys_unlink(cstr))
@@ -149,7 +125,7 @@ _remove_all :: proc(path: string) -> Error {
return _ok_or_error(unix.sys_rmdir(cstr))
}
_getwd :: proc(allocator := context.allocator) -> (dir: string, err: Error) {
_getwd :: proc(allocator := context.allocator) -> (string, Error) {
// NOTE(tetra): I would use PATH_MAX here, but I was not able to find
// an authoritative value for it across all systems.
// The largest value I could find was 4096, so might as well use the page size.
@@ -170,7 +146,7 @@ _getwd :: proc(allocator := context.allocator) -> (dir: string, err: Error) {
unreachable()
}
_setwd :: proc(dir: string) -> (err: Error) {
_setwd :: proc(dir: string) -> Error {
dir_cstr := strings.clone_to_cstring(dir, context.temp_allocator)
return _ok_or_error(unix.sys_chdir(dir_cstr))
}

View File

@@ -1717,7 +1717,7 @@ sys_rmdir :: proc(path: cstring) -> int {
}
}
sys_mkdir :: proc(path: cstring, mode: u32 = 0o775) -> int {
sys_mkdir :: proc(path: cstring, mode: int) -> int {
when ODIN_ARCH != .arm64 {
return int(intrinsics.syscall(SYS_mkdir, uintptr(rawptr(path)), uintptr(mode)))
} else { // NOTE: arm64 does not have mkdir
@@ -1725,6 +1725,14 @@ sys_mkdir :: proc(path: cstring, mode: u32 = 0o775) -> int {
}
}
sys_mknod :: proc(path: cstring, mode: int, dev: int) -> int {
when ODIN_ARCH != .arm64 {
return int(intrinsics.syscall(SYS_mknod, uintptr(rawptr(path)), uintptr(mode), uintptr(dev)))
} else { // NOTE: arm64 does not have mknod
return int(intrinsics.syscall(SYS_mknodat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mode), uintptr(dev)))
}
}
sys_truncate :: proc(path: cstring, length: i64) -> int {
when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 {
return int(intrinsics.syscall(SYS_truncate, uintptr(rawptr(path)), uintptr(length)))

Binary file not shown.

View File

@@ -1,5 +1,6 @@
package test_os2
import "core:os"
import "core:fmt"
import "core:os/os2"
import "core:testing"
@@ -22,7 +23,7 @@ when ODIN_TEST {
TEST_count += 1
ok := value == expected
if !ok {
fmt.printf("expected %v, got %v", expected, value)
fmt.printf("expected %v, got %v\n", expected, value)
TEST_fail += 1
return
}
@@ -45,12 +46,13 @@ when ODIN_TEST {
}
}
main :: proc()
main :: proc()
{
t: testing.T
file_test(&t)
path_test(&t)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
os.exit(TEST_fail > 0 ? 1 : 0)
}
@private
@@ -59,7 +61,7 @@ _expect_no_error :: proc(t: ^testing.T, e: os2.Error, loc := #caller_location) {
}
F_OK :: 0 // Test for file existance
F_OK :: 0 // Test for file existence
X_OK :: 1 // Test for execute permission
W_OK :: 2 // Test for write permission
R_OK :: 4 // Test for read permission
@@ -84,44 +86,92 @@ file_test :: proc(t: ^testing.T) {
expect(t, err != nil, "missing error")
expect_value(t, fd, os2.INVALID_HANDLE)
fd, err = os2.open("write.txt", {.Write, .Create, .Trunc}, 0o664)
// NOTE: no executable permissions here
fd, err = os2.open("file.txt", {.Write, .Create, .Trunc}, 0o664)
_expect_no_error(t, err)
expect(t, fd != os2.INVALID_HANDLE, "unexpected handle")
s1 := "hello"
b1 := transmute([]u8)s1
s := "hello"
n: int
n, err = os2.write_at(fd, b1, 10)
n, err = os2.write_at(fd, transmute([]u8)s, 10)
_expect_no_error(t, err)
expect_value(t, n, 5)
s2 := "abcdefghij"
b2 := transmute([]u8)s2
n, err = os2.write(fd, b2)
s = "abcdefghij"
n, err = os2.write(fd, transmute([]u8)s)
_expect_no_error(t, err)
expect_value(t, n, 10)
// seek to the "ll" in "hello"
n64: i64
n64, err = os2.seek(fd, 12, .Start)
_expect_no_error(t, err)
expect_value(t, n64, 12)
s = "11"
n, err = os2.write(fd, transmute([]u8)s)
_expect_no_error(t, err)
expect_value(t, n, 2)
// seek to the "e" in "he11o"
n64, err = os2.seek(fd, -3, .Current)
_expect_no_error(t, err)
expect_value(t, n64, 11)
s = "3"
n, err = os2.write(fd, transmute([]u8)s)
_expect_no_error(t, err)
expect_value(t, n, 1)
// seek to the "o" in "h311o"
n64, err = os2.seek(fd, -1, .End)
_expect_no_error(t, err)
expect_value(t, n64, 14)
s = "0"
n, err = os2.write(fd, transmute([]u8)s)
_expect_no_error(t, err)
expect_value(t, n, 1)
_expect_no_error(t, os2.sync(fd))
// Add executable permissions to current file (as well as read/write to all)
err = os2.chmod(fd, 0o766)
_expect_no_error(t, err)
when ODIN_OS == .Linux {
expect(t, unix.sys_access("file.txt", X_OK) == 0, "expected exec permission")
}
// NOTE: chown not possible without root user
//_expect_no_error(t, os2.chown(fd, 0, 0))
_expect_no_error(t, os2.close(fd))
fd, err = os2.open("write.txt")
fd, err = os2.open("file.txt")
_expect_no_error(t, err)
buf: [32]u8
n, err = os2.read(fd, buf[:])
_expect_no_error(t, err)
expect_value(t, n, 15)
expect_value(t, string(buf[:n]), "abcdefghijhello")
expect_value(t, string(buf[:n]), "abcdefghijh3110")
n, err = os2.read_at(fd, buf[0:2], 1)
_expect_no_error(t, err)
expect_value(t, n, 2)
expect_value(t, string(buf[0:2]), "bc")
n64, err = os2.file_size(fd)
_expect_no_error(t, err)
expect_value(t, n64, 15)
_expect_no_error(t, os2.close(fd))
_expect_no_error(t, os2.remove("file.txt"))
_expect_no_error(t, os2.mkdir("empty dir", 0))
_expect_no_error(t, os2.remove("empty dir"))
}
@test
@@ -131,7 +181,7 @@ path_test :: proc(t: ^testing.T) {
err = os2.remove_all("a")
_expect_no_error(t, err)
}
err = os2.mkdir_all("a/b/c/d", 0)
_expect_no_error(t, err)
@@ -141,23 +191,25 @@ path_test :: proc(t: ^testing.T) {
fd, err = os2.create("a/b/c/file.txt", 0o644)
_expect_no_error(t, err)
err = os2.close(fd)
_expect_no_error(t, err)
when ODIN_OS == .Linux {
expect(t, unix.sys_access("a/b/c/file.txt", X_OK) < 0, "unexpected exec permission")
} else {
expect(t, os2.exists("a/b/c/file.txt"), "file does not exist")
}
err = os2.rename("a/b/c/file.txt", "a/b/file.txt")
_expect_no_error(t, err)
when ODIN_OS == .Linux {
expect(t, unix.sys_access("a/b/c/file.txt", F_OK) < 0, "unexpected exec permission")
expect(t, unix.sys_access("a/b/c/file.txt", F_OK) < 0, "unexpected file existence")
} else {
expect(t, !os2.exists("a/b/c/file.txt"), "unexpected file existence")
}
err = os2.symlink("b/c/d", "a/symlink_to_d")
_expect_no_error(t, err)
symlink: string
symlink, err = os2.read_link("a/symlink_to_d")
_expect_no_error(t, err)
@@ -171,8 +223,10 @@ path_test :: proc(t: ^testing.T) {
when ODIN_OS == .Linux {
expect_value(t, unix.sys_access("a/b/c/d/shnt.txt", X_OK | R_OK | W_OK), 0)
} else {
expect(t, os2.exists("a/b/c/d/shnt.txt"), "file does not exist")
}
err = os2.remove_all("a")
_expect_no_error(t, err)