diff --git a/core/os/os2/path_linux.odin b/core/os/os2/path_linux.odin index b474ae207..e47bd36b0 100644 --- a/core/os/os2/path_linux.odin +++ b/core/os/os2/path_linux.odin @@ -24,18 +24,73 @@ _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) - perm_i: int if perm & (File_Mode_Named_Pipe | File_Mode_Device | File_Mode_Char_Device | File_Mode_Sym_Link) != 0 { return .Invalid_Argument } + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) return _ok_or_error(unix.sys_mkdir(path_cstr, int(perm & 0o777))) } -// TODO _mkdir_all :: proc(path: string, perm: File_Mode) -> Error { - return nil + _mkdirat :: proc(dfd: Handle, path: []u8, perm: int, has_created: ^bool) -> Error { + if len(path) == 0 { + return nil + } + i: int + for /**/; i < len(path) - 1 && path[i] != '/'; i += 1 {} + path[i] = 0 + new_dfd := unix.sys_openat(int(dfd), cstring(&path[0]), _OPENDIR_FLAGS) + switch new_dfd { + case -ENOENT: + res := unix.sys_mkdirat(int(dfd), cstring(&path[0]), perm) + if res < 0 { + return _get_platform_error(res) + } + has_created^ = true + new_dfd = unix.sys_openat(int(dfd), cstring(&path[0]), _OPENDIR_FLAGS) + if new_dfd < 0 { + return _get_platform_error(new_dfd) + } + fallthrough + case 0: + unix.sys_close(int(dfd)) + // skip consecutive '/' + for i += 1; i < len(path) && path[i] == '/'; i += 1 {} + return _mkdirat(Handle(new_dfd), path[i:], perm, has_created) + case: + return _get_platform_error(new_dfd) + } + unreachable() + } + + if perm & (File_Mode_Named_Pipe | File_Mode_Device | File_Mode_Char_Device | File_Mode_Sym_Link) != 0 { + return .Invalid_Argument + } + + // need something we can edit, and use to generate cstrings + path_bytes := make([]u8, len(path) + 1, context.temp_allocator) + copy(path_bytes, path) + path_bytes[len(path)] = 0 + + dfd: int + if path_bytes[0] == '/' { + dfd = unix.sys_open("/", _OPENDIR_FLAGS) + path_bytes = path_bytes[1:] + } else { + dfd = unix.sys_open(".", _OPENDIR_FLAGS) + } + if dfd < 0 { + return _get_platform_error(dfd) + } + + has_created: bool + _mkdirat(Handle(dfd), path_bytes, int(perm & 0o777), &has_created) or_return + if has_created { + return nil + } + return .Exist + //return has_created ? nil : .Exist } dirent64 :: struct { diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index 8cfb97076..8a1aadb9c 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -1518,7 +1518,7 @@ when ODIN_ARCH == .amd64 { #panic("Unsupported architecture") } -AT_FDCWD :: -100 +AT_FDCWD :: ~uintptr(99) AT_REMOVEDIR :: uintptr(0x200) AT_SYMLINK_FOLLOW :: uintptr(0x400) AT_SYMLINK_NOFOLLOW :: uintptr(0x100) @@ -1535,7 +1535,7 @@ sys_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) } else { // NOTE: arm64 does not have open - return int(intrinsics.syscall(SYS_openat, uintptr(AT_FDCWD), uintptr(rawptr(path), uintptr(flags), uintptr(mode)))) + return int(intrinsics.syscall(SYS_openat, AT_FDCWD, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) } } @@ -1593,7 +1593,7 @@ sys_stat :: proc(path: cstring, stat: rawptr) -> int { } 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)) + return int(intrinsics.syscall(SYS_fstatat, AT_FDCWD, uintptr(rawptr(path)), uintptr(stat), 0)) } } @@ -1611,7 +1611,7 @@ sys_lstat :: proc(path: cstring, stat: rawptr) -> int { } 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)) + return int(intrinsics.syscall(SYS_fstatat, AT_FDCWD, uintptr(rawptr(path)), uintptr(stat), AT_SYMLINK_NOFOLLOW)) } } @@ -1619,7 +1619,7 @@ 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))) + return int(intrinsics.syscall(SYS_readlinkat, AT_FDCWD, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) } } @@ -1627,7 +1627,7 @@ sys_symlink :: proc(old_name: cstring, new_name: cstring) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_symlink, uintptr(rawptr(old_name)), uintptr(rawptr(new_name)))) } else { // NOTE: arm64 does not have symlink - return int(intrinsics.syscall(SYS_symlinkat, uintptr(rawptr(old_name)), uintptr(AT_FDCWD), uintptr(rawptr(new_name)))) + return int(intrinsics.syscall(SYS_symlinkat, uintptr(rawptr(old_name)), AT_FDCWD, uintptr(rawptr(new_name)))) } } @@ -1635,7 +1635,7 @@ 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))) + return int(intrinsics.syscall(SYS_faccessat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mask))) } } @@ -1655,7 +1655,7 @@ sys_chmod :: proc(path: cstring, mode: int) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_chmod, uintptr(rawptr(path)), uintptr(mode))) } else { // NOTE: arm64 does not have chmod - return int(intrinsics.syscall(SYS_fchmodat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mode))) + return int(intrinsics.syscall(SYS_fchmodat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mode))) } } @@ -1667,7 +1667,7 @@ sys_chown :: proc(path: cstring, user: int, group: int) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_chown, uintptr(rawptr(path)), uintptr(user), uintptr(group))) } else { // NOTE: arm64 does not have chown - return int(intrinsics.syscall(SYS_fchownat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(user), uintptr(group), 0)) + return int(intrinsics.syscall(SYS_fchownat, AT_FDCWD, uintptr(rawptr(path)), uintptr(user), uintptr(group), 0)) } } @@ -1679,7 +1679,7 @@ sys_lchown :: proc(path: cstring, user: int, group: int) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_lchown, uintptr(rawptr(path)), uintptr(user), uintptr(group))) } else { // NOTE: arm64 does not have lchown - return int(intrinsics.syscall(SYS_fchownat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(user), uintptr(group), AT_SYMLINK_NOFOLLOW)) + return int(intrinsics.syscall(SYS_fchownat, AT_FDCWD, uintptr(rawptr(path)), uintptr(user), uintptr(group), AT_SYMLINK_NOFOLLOW)) } } @@ -1687,7 +1687,7 @@ 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)))) + return int(intrinsics.syscall(SYS_renameat, AT_FDCWD, uintptr(rawptr(old)), uintptr(rawptr(new)))) } } @@ -1695,7 +1695,7 @@ sys_link :: proc(old_name: cstring, new_name: cstring) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_link, uintptr(rawptr(old_name)), uintptr(rawptr(new_name)))) } else { // NOTE: arm64 does not have link - return int(intrinsics.syscall(SYS_linkat, uintptr(AT_FDCWD), uintptr(rawptr(old_name)), uintptr(AT_FDCWD), uintptr(rawptr(new_name)), AT_SYMLINK_FOLLOW)) + return int(intrinsics.syscall(SYS_linkat, AT_FDCWD, uintptr(rawptr(old_name)), AT_FDCWD, uintptr(rawptr(new_name)), AT_SYMLINK_FOLLOW)) } } @@ -1703,7 +1703,7 @@ 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))) + return int(intrinsics.syscall(SYS_unlinkat, AT_FDCWD, uintptr(rawptr(path)), 0)) } } @@ -1715,7 +1715,7 @@ 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)) + return int(intrinsics.syscall(SYS_unlinkat, AT_FDCWD, uintptr(rawptr(path)), AT_REMOVEDIR)) } } @@ -1723,18 +1723,26 @@ 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 - return int(intrinsics.syscall(SYS_mkdirat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mode))) + return int(intrinsics.syscall(SYS_mkdirat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mode))) } } +sys_mkdirat :: proc(dfd: int, path: cstring, mode: int) -> int { + return int(intrinsics.syscall(SYS_mkdirat, uintptr(dfd), uintptr(rawptr(path)), uintptr(mode))) +} + 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))) + return int(intrinsics.syscall(SYS_mknodat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mode), uintptr(dev))) } } +sys_mknodat :: proc(dfd: int, path: cstring, mode: int, dev: int) -> int { + return int(intrinsics.syscall(SYS_mknodat, uintptr(dfd), 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))) @@ -1763,6 +1771,14 @@ sys_getdents64 :: proc(fd: int, dirent: rawptr, count: int) -> int { return int(intrinsics.syscall(SYS_getdents64, uintptr(fd), uintptr(dirent), uintptr(count))) } +sys_fork :: proc() -> int { + when ODIN_ARCH != .arm64 { + return int(intrinsics.syscall(SYS_fork)) + } else { + return int(intrinsics.syscall(SYS_clone, SIGCHLD)) + } +} + get_errno :: proc(res: int) -> i32 { if res < 0 && res > -4096 { return i32(-res) diff --git a/tests/core/Makefile b/tests/core/Makefile index 449efbb25..90b0df449 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -1,12 +1,8 @@ ODIN=../../odin PYTHON=$(shell which python3) -<<<<<<< HEAD -all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test os2_test -======= all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \ - math_test linalg_glsl_math_test ->>>>>>> upstream/master + math_test linalg_glsl_math_test os2_test download_test_assets: $(PYTHON) download_assets.py @@ -29,18 +25,16 @@ crypto_test: noise_test: $(ODIN) run math/noise -out=test_noise -os2_test: - $(ODIN) run os2/test_os2.odin -out=test_os2 - encoding_test: $(ODIN) run encoding/json -out=test_json $(ODIN) run encoding/varint -out=test_varint -<<<<<<< HEAD -======= math_test: $(ODIN) run math/test_core_math.odin -out=test_core_math -collection:tests=.. linalg_glsl_math_test: $(ODIN) run math/linalg/glsl/test_linalg_glsl_math.odin -out=test_linalg_glsl_math -collection:tests=.. ->>>>>>> upstream/master + +os2_test: + $(ODIN) run os2/test_os2.odin -out=test_os2 + diff --git a/tests/core/os2/test_os2.odin b/tests/core/os2/test_os2.odin index a629063bd..0e0d3dcb5 100644 --- a/tests/core/os2/test_os2.odin +++ b/tests/core/os2/test_os2.odin @@ -15,8 +15,9 @@ TEST_count := 0 TEST_fail := 0 when ODIN_TEST { - expect :: testing.expect - log :: testing.log + expect_value :: testing.expect_value + expect :: testing.expect + log :: testing.log } else { expect_value :: proc(t: ^testing.T, value, expected: $T, loc := #caller_location) where intrinsics.type_is_comparable(T) { fmt.printf("[%v] ", loc) @@ -170,7 +171,7 @@ file_test :: proc(t: ^testing.T) { _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.mkdir("empty dir", 0o755)) _expect_no_error(t, os2.remove("empty dir")) } @@ -182,7 +183,7 @@ path_test :: proc(t: ^testing.T) { _expect_no_error(t, err) } - err = os2.mkdir_all("a/b/c/d", 0) + err = os2.mkdir_all("a/b/c/d", 0o755) _expect_no_error(t, err) expect(t, os2.exists("a"), "directory does not exist")