Browse Source

rewrite mkdir_all

CiD- 3 năm trước cách đây
mục cha
commit
b21e7e4518

+ 59 - 4
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 {

+ 32 - 16
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)

+ 5 - 11
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
+

+ 5 - 4
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")