Browse Source

added _remove_all

jasonkercher 3 years ago
parent
commit
1f19610fd6
3 changed files with 126 additions and 27 deletions
  1. 22 22
      core/os/os2/file_linux.odin
  2. 96 5
      core/os/os2/path_linux.odin
  3. 8 0
      core/sys/unix/syscalls_linux.odin

+ 22 - 22
core/os/os2/file_linux.odin

@@ -25,23 +25,23 @@ _std_handle :: proc(kind: Std_Handle_Kind) -> Handle {
 	unreachable()
 	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) {
 _opendir :: proc(name: string) -> (Handle, Error) {
 	cstr := strings.clone_to_cstring(name, context.temp_allocator)
 	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)
 	handle_i := unix.sys_open(cstr, flags)
 	if handle_i < 0 {
 	if handle_i < 0 {
@@ -56,17 +56,17 @@ _open :: proc(name: string, flags: File_Flags, perm: File_Mode) -> (Handle, Erro
 
 
 	flags_i: int
 	flags_i: int
 	switch flags & O_RDONLY|O_WRONLY|O_RDWR {
 	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))
 	handle_i := unix.sys_open(cstr, flags_i, int(perm))
 	if handle_i < 0 {
 	if handle_i < 0 {

+ 96 - 5
core/os/os2/path_linux.odin

@@ -1,7 +1,6 @@
 //+private
 //+private
 package os2
 package os2
 
 
-import "core:fmt"
 import "core:strings"
 import "core:strings"
 import "core:sys/unix"
 import "core:sys/unix"
 import "core:path/filepath"
 import "core:path/filepath"
@@ -9,6 +8,8 @@ import "core:path/filepath"
 _Path_Separator      :: '/'
 _Path_Separator      :: '/'
 _Path_List_Separator :: ':'
 _Path_List_Separator :: ':'
 
 
+DIRECTORY_FLAGS :: __O_RDONLY|__O_NONBLOCK|__O_DIRECTORY|__O_LARGEFILE|__O_CLOEXEC
+
 _is_path_separator :: proc(c: byte) -> bool {
 _is_path_separator :: proc(c: byte) -> bool {
 	return c == '/'
 	return c == '/'
 }
 }
@@ -53,9 +54,99 @@ _mkdir_all :: proc(path: string, perm: File_Mode) -> Error {
 	return _mkdir_all_stat(path, &s, perm)
 	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 {
 _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) {
 _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 {
 		if res >= 0 {
 			return strings.string_from_nul_terminated_ptr(&buf[0], len(buf)), nil
 			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)
 		resize(&buf, len(buf)+PATH_MAX)
 	}
 	}

+ 8 - 0
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 {
 sys_close :: proc(fd: int) -> int {
 	return int(intrinsics.syscall(SYS_close, uintptr(fd)))
 	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 {
 sys_rmdir :: proc(path: cstring) -> int {
 	when ODIN_ARCH != .arm64 {
 	when ODIN_ARCH != .arm64 {
 		return int(intrinsics.syscall(SYS_rmdir, uintptr(rawptr(path))))
 		return int(intrinsics.syscall(SYS_rmdir, uintptr(rawptr(path))))