diff options
| author | Laytan Laats <laytanlaats@hotmail.com> | 2025-05-03 13:29:37 +0200 |
|---|---|---|
| committer | Laytan Laats <laytanlaats@hotmail.com> | 2025-05-08 19:32:30 +0200 |
| commit | cacb9f9f540b7ffa93d7fd0d0e1b4667be42480f (patch) | |
| tree | e408053c01ece60aa08cd48f9ae49a460b680042 | |
| parent | edbe7aa06e5e9afc833ba85a94597f1a0a568747 (diff) | |
os2: better copy_directory, and add native copy_file and copy_directory variants on MacOS
| -rw-r--r-- | core/os/os2/dir.odin | 53 | ||||
| -rw-r--r-- | core/os/os2/dir_posix_darwin.odin | 17 | ||||
| -rw-r--r-- | core/os/os2/file.odin | 9 | ||||
| -rw-r--r-- | core/os/os2/file_posix_darwin.odin | 28 | ||||
| -rw-r--r-- | core/sys/darwin/copyfile.odin | 67 | ||||
| -rw-r--r-- | core/sys/darwin/darwin.odin | 1 | ||||
| -rw-r--r-- | core/sys/darwin/sync.odin | 2 | ||||
| -rw-r--r-- | core/sys/darwin/xnu_system_call_wrappers.odin | 10 |
8 files changed, 162 insertions, 25 deletions
diff --git a/core/os/os2/dir.odin b/core/os/os2/dir.odin index a33e8a8d9..10b06a8ce 100644 --- a/core/os/os2/dir.odin +++ b/core/os/os2/dir.odin @@ -2,6 +2,7 @@ package os2 import "base:runtime" import "core:slice" +import "core:strings" read_dir :: read_directory @@ -194,28 +195,54 @@ read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info, } // Recursively copies a directory to `dst` from `src` -copy_directory :: proc(dst, src: string, dst_perm := 0o755) -> Error { - switch err := make_directory_all(dst, dst_perm); err { - case nil, .Exist: - // okay - case: +copy_directory_all :: proc(dst, src: string, dst_perm := 0o755) -> Error { + when #defined(_copy_directory_all_native) { + return _copy_directory_all_native(dst, src, dst_perm) + } else { + return _copy_directory_all(dst, src, dst_perm) + } +} + +@(private) +_copy_directory_all :: proc(dst, src: string, dst_perm := 0o755) -> Error { + err := make_directory(dst, dst_perm) + if err != nil && err != .Exist { return err } temp_allocator := TEMP_ALLOCATOR_GUARD({}) - file_infos := read_all_directory_by_path(src, temp_allocator) or_return - for fi in file_infos { - temp_allocator_scope(temp_allocator) + abs_src := get_absolute_path(src, temp_allocator) or_return + abs_dst := get_absolute_path(dst, temp_allocator) or_return + + dst_buf := make([dynamic]byte, 0, len(abs_dst) + 256, temp_allocator) or_return + + w: Walker + walker_init_path(&w, src) + defer walker_destroy(&w) - dst_path := join_path({dst, fi.name}, temp_allocator) or_return - src_path := fi.fullpath + for info in walker_walk(&w) { + _ = walker_error(&w) or_break - if fi.type == .Directory { - copy_directory(dst_path, src_path) or_return + rel := strings.trim_prefix(info.fullpath, abs_src) + + non_zero_resize(&dst_buf, 0) + reserve(&dst_buf, len(abs_dst) + len(Path_Separator_String) + len(rel)) or_return + append(&dst_buf, abs_dst) + append(&dst_buf, Path_Separator_String) + append(&dst_buf, rel) + + if info.type == .Directory { + err = make_directory(string(dst_buf[:]), dst_perm) + if err != nil && err != .Exist { + return err + } } else { - copy_file(dst_path, src_path) or_return + copy_file(string(dst_buf[:]), info.fullpath) or_return } } + + _ = walker_error(&w) or_return + return nil } diff --git a/core/os/os2/dir_posix_darwin.odin b/core/os/os2/dir_posix_darwin.odin new file mode 100644 index 000000000..3cae50d25 --- /dev/null +++ b/core/os/os2/dir_posix_darwin.odin @@ -0,0 +1,17 @@ +#+private +package os2 + +import "core:sys/darwin" + +_copy_directory_all_native :: proc(dst, src: string, dst_perm := 0o755) -> (err: Error) { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + + csrc := clone_to_cstring(src, temp_allocator) or_return + cdst := clone_to_cstring(dst, temp_allocator) or_return + + if darwin.copyfile(csrc, cdst, nil, darwin.COPYFILE_ALL + {.RECURSIVE}) < 0 { + err = _get_platform_error() + } + + return +} diff --git a/core/os/os2/file.odin b/core/os/os2/file.odin index ff214182e..a9878a563 100644 --- a/core/os/os2/file.odin +++ b/core/os/os2/file.odin @@ -313,6 +313,15 @@ is_directory :: proc(path: string) -> bool { copy_file :: proc(dst_path, src_path: string) -> Error { + when #defined(_copy_file_native) { + return _copy_file_native(dst_path, src_path) + } else { + return _copy_file(dst_path, src_path) + } +} + +@(private) +_copy_file :: proc(dst_path, src_path: string) -> Error { src := open(src_path) or_return defer close(src) diff --git a/core/os/os2/file_posix_darwin.odin b/core/os/os2/file_posix_darwin.odin index 920a63a71..aed3e56f5 100644 --- a/core/os/os2/file_posix_darwin.odin +++ b/core/os/os2/file_posix_darwin.odin @@ -3,6 +3,7 @@ package os2 import "base:runtime" +import "core:sys/darwin" import "core:sys/posix" _posix_absolute_path :: proc(fd: posix.FD, name: string, allocator: runtime.Allocator) -> (path: cstring, err: Error) { @@ -16,3 +17,30 @@ _posix_absolute_path :: proc(fd: posix.FD, name: string, allocator: runtime.Allo return clone_to_cstring(string(cstring(&buf[0])), allocator) } + +_copy_file_native :: proc(dst_path, src_path: string) -> (err: Error) { + temp_allocator := TEMP_ALLOCATOR_GUARD({}) + + csrc := clone_to_cstring(src_path, temp_allocator) or_return + cdst := clone_to_cstring(dst_path, temp_allocator) or_return + + // Disallow directories, as specified by the generic implementation. + + stat: posix.stat_t + if posix.stat(csrc, &stat) != .OK { + err = _get_platform_error() + return + } + + if posix.S_ISDIR(stat.st_mode) { + err = .Invalid_File + return + } + + ret := darwin.copyfile(csrc, cdst, nil, darwin.COPYFILE_ALL) + if ret < 0 { + err = _get_platform_error() + } + + return +} diff --git a/core/sys/darwin/copyfile.odin b/core/sys/darwin/copyfile.odin new file mode 100644 index 000000000..6c58b8067 --- /dev/null +++ b/core/sys/darwin/copyfile.odin @@ -0,0 +1,67 @@ +package darwin + +import "core:sys/posix" + +copyfile_state_t :: distinct rawptr + +copyfile_flags :: bit_set[enum { + ACL, + STAT, + XATTR, + DATA, + + RECURSIVE = 15, + + CHECK, + EXCL, + NOFOLLOW_SRC, + NOFOLLOW_DST, + MOVE, + UNLINK, + PACK, + UNPACK, + + CLONE, + CLONE_FORCE, + RUN_IN_PLACE, + DATA_SPARSE, + PRESERVE_DST_TRACKED, + VERBOSE = 30, +}; u32] + +COPYFILE_SECURITY :: copyfile_flags{.STAT, .ACL} +COPYFILE_METADATA :: COPYFILE_SECURITY + copyfile_flags{.XATTR} +COPYFILE_ALL :: COPYFILE_METADATA + copyfile_flags{.DATA} + +COPYFILE_NOFOLLOW :: copyfile_flags{.NOFOLLOW_SRC, .NOFOLLOW_DST} + +copyfile_state_flag :: enum u32 { + SRC_FD = 1, + SRC_FILENAME, + DST_FD, + DST_FILENAME, + QUARANTINE, + STATUS_CB, + STATUS_CTX, + COPIED, + XATTRNAME, + WAS_CLONED, + SRC_BSIZE, + DST_BSIZE, + BSIZE, + FORBID_CROSS_MOUNT, + NOCPROTECT, + PRESERVE_SUID, + RECURSIVE_SRC_FTSENT, + FORBID_DST_EXISTING_SYMLINKS, +} + +foreign system { + copyfile :: proc(from, to: cstring, state: copyfile_state_t, flags: copyfile_flags) -> i32 --- + fcopyfile :: proc(from, to: posix.FD, state: copyfile_state_t, flags: copyfile_flags) -> i32 --- + + copyfile_state_alloc :: proc() -> copyfile_state_t --- + copyfile_state_free :: proc(state: copyfile_state_t) -> posix.result --- + copyfile_state_get :: proc(state: copyfile_state_t, flag: copyfile_state_flag, dst: rawptr) -> posix.result --- + copyfile_state_set :: proc(state: copyfile_state_t, flag: copyfile_state_flag, src: rawptr) -> posix.result --- +} diff --git a/core/sys/darwin/darwin.odin b/core/sys/darwin/darwin.odin index d109f5544..96cfc7be6 100644 --- a/core/sys/darwin/darwin.odin +++ b/core/sys/darwin/darwin.odin @@ -3,6 +3,7 @@ package darwin import "core:c" +@(export) foreign import system "system:System.framework" Bool :: b8 diff --git a/core/sys/darwin/sync.odin b/core/sys/darwin/sync.odin index 58fc7c9e4..6d68dc8f8 100644 --- a/core/sys/darwin/sync.odin +++ b/core/sys/darwin/sync.odin @@ -1,7 +1,5 @@ package darwin -foreign import system "system:System.framework" - // #define OS_WAIT_ON_ADDR_AVAILABILITY \ // __API_AVAILABLE(macos(14.4), ios(17.4), tvos(17.4), watchos(10.4)) when ODIN_OS == .Darwin { diff --git a/core/sys/darwin/xnu_system_call_wrappers.odin b/core/sys/darwin/xnu_system_call_wrappers.odin index 1188091a9..6376949f4 100644 --- a/core/sys/darwin/xnu_system_call_wrappers.odin +++ b/core/sys/darwin/xnu_system_call_wrappers.odin @@ -19,16 +19,6 @@ X_OK :: c.int((1 << 0)) /* test for execute or search permission */ W_OK :: c.int((1 << 1)) /* test for write permission */ R_OK :: c.int((1 << 2)) /* test for read permission */ -/* copyfile flags */ -COPYFILE_ACL :: (1 << 0) -COPYFILE_STAT :: (1 << 1) -COPYFILE_XATTR :: (1 << 2) -COPYFILE_DATA :: (1 << 3) - -COPYFILE_SECURITY :: (COPYFILE_STAT | COPYFILE_ACL) -COPYFILE_METADATA :: (COPYFILE_SECURITY | COPYFILE_XATTR) -COPYFILE_ALL :: (COPYFILE_METADATA | COPYFILE_DATA) - /* syslimits.h */ PATH_MAX :: 1024 /* max bytes in pathname */ |