From 1f19610fd67b00b49cc9d726af2e8d9ac5f4807b Mon Sep 17 00:00:00 2001 From: jasonkercher Date: Mon, 7 Mar 2022 17:16:03 -0500 Subject: [PATCH] added _remove_all --- core/os/os2/file_linux.odin | 44 ++++++------- core/os/os2/path_linux.odin | 101 ++++++++++++++++++++++++++++-- core/sys/unix/syscalls_linux.odin | 8 +++ 3 files changed, 126 insertions(+), 27 deletions(-) diff --git a/core/os/os2/file_linux.odin b/core/os/os2/file_linux.odin index 72fbdcb56..a88515b0e 100644 --- a/core/os/os2/file_linux.odin +++ b/core/os/os2/file_linux.odin @@ -25,23 +25,23 @@ _std_handle :: proc(kind: Std_Handle_Kind) -> Handle { unreachable() } -_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 _opendir :: proc(name: string) -> (Handle, Error) { cstr := strings.clone_to_cstring(name, context.temp_allocator) - flags := _O_RDONLY|_O_NONBLOCK|_O_DIRECTORY|_O_LARGEFILE|_O_CLOEXEC + flags := __O_RDONLY|__O_NONBLOCK|__O_DIRECTORY|__O_LARGEFILE|__O_CLOEXEC handle_i := unix.sys_open(cstr, flags) if handle_i < 0 { @@ -56,17 +56,17 @@ _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Erro 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 { diff --git a/core/os/os2/path_linux.odin b/core/os/os2/path_linux.odin index b45d6e976..31abf5bf8 100644 --- a/core/os/os2/path_linux.odin +++ b/core/os/os2/path_linux.odin @@ -1,7 +1,6 @@ //+private package os2 -import "core:fmt" import "core:strings" import "core:sys/unix" import "core:path/filepath" @@ -9,6 +8,8 @@ import "core:path/filepath" _Path_Separator :: '/' _Path_List_Separator :: ':' +DIRECTORY_FLAGS :: __O_RDONLY|__O_NONBLOCK|__O_DIRECTORY|__O_LARGEFILE|__O_CLOEXEC + _is_path_separator :: proc(c: byte) -> bool { return c == '/' } @@ -53,9 +54,99 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error { return _mkdir_all_stat(path, &s, perm) } +dirent64 :: struct { + d_ino: u64, + d_off: u64, + d_reclen: u16, + d_type: u8, + 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 { - // TODO - return nil + _remove_all_dir :: proc(dfd: Handle) -> Error { + n := 64 + buf := make([]u8, n) + defer delete(buf) + + loop: for { + res := unix.sys_getdents64(int(dfd), &buf[0], n) + switch res { + case -22: //-EINVAL + n *= 2 + buf = make([]u8, n) + continue loop + case -4096..<0: + return _get_platform_error(res) + case 0: + break loop + } + + d: ^dirent64 + + for i := 0; i < res; i += int(d.d_reclen) { + description: string + d = (^dirent64)(rawptr(&buf[i])) + d_name_cstr := cstring(&d.d_name[0]) + + buf_len := uintptr(d.d_reclen) - offset_of(d.d_name) + + /* check for current directory (.) */ + #no_bounds_check if buf_len > 1 && d.d_name[0] == '.' && d.d_name[1] == 0 { + continue + } + + /* check for parent directory (..) */ + #no_bounds_check if buf_len > 2 && d.d_name[0] == '.' && d.d_name[1] == '.' && d.d_name[2] == 0 { + continue + } + + res: int + + switch d.d_type { + case DT_DIR: + handle_i := unix.sys_openat(int(dfd), d_name_cstr, DIRECTORY_FLAGS) + if handle_i < 0 { + return _get_platform_error(handle_i) + } + defer unix.sys_close(handle_i) + _remove_all_dir(Handle(handle_i)) or_return + res = unix.sys_unlinkat(int(dfd), d_name_cstr, int(unix.AT_REMOVEDIR)) + case: + res = unix.sys_unlinkat(int(dfd), d_name_cstr) + } + + if res < 0 { + return _get_platform_error(res) + } + } + } + return nil + } + + cstr := strings.clone_to_cstring(path, context.temp_allocator) + + handle_i := unix.sys_open(cstr, DIRECTORY_FLAGS) + switch handle_i { + case -ENOTDIR: + return _ok_or_error(unix.sys_unlink(cstr)) + case -4096..<0: + return _get_platform_error(handle_i) + } + + fd := Handle(handle_i) + defer close(fd) + _remove_all_dir(fd) or_return + return _ok_or_error(unix.sys_rmdir(cstr)) } _getwd :: proc(allocator := context.allocator) -> (dir: string, err: Error) { @@ -71,8 +162,8 @@ _getwd :: proc(allocator := context.allocator) -> (dir: string, err: Error) { if res >= 0 { return strings.string_from_nul_terminated_ptr(&buf[0], len(buf)), nil } - if errno := int(unix.get_errno(res)); errno != ERANGE { - return "", _get_platform_error(errno) + if res != -ERANGE { + return "", _get_platform_error(res) } resize(&buf, len(buf)+PATH_MAX) } diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index ccd8a75e6..889dd3b90 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -1537,6 +1537,10 @@ sys_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> int { } } +sys_openat :: proc(dfd: int, path: cstring, flags: int, mode: int = 0o000) -> int { + return int(intrinsics.syscall(SYS_openat, uintptr(dfd), uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) +} + sys_close :: proc(fd: int) -> int { return int(intrinsics.syscall(SYS_close, uintptr(fd))) } @@ -1701,6 +1705,10 @@ sys_unlink :: proc(path: cstring) -> int { } } +sys_unlinkat :: proc(dfd: int, path: cstring, flag: int = 0) -> int { + return int(intrinsics.syscall(SYS_unlinkat, uintptr(dfd), uintptr(rawptr(path)), flag)) +} + sys_rmdir :: proc(path: cstring) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_rmdir, uintptr(rawptr(path))))