aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorLaytan Laats <laytanlaats@hotmail.com>2025-05-03 13:29:37 +0200
committerLaytan Laats <laytanlaats@hotmail.com>2025-05-08 19:32:30 +0200
commitcacb9f9f540b7ffa93d7fd0d0e1b4667be42480f (patch)
treee408053c01ece60aa08cd48f9ae49a460b680042 /core
parentedbe7aa06e5e9afc833ba85a94597f1a0a568747 (diff)
os2: better copy_directory, and add native copy_file and copy_directory variants on MacOS
Diffstat (limited to 'core')
-rw-r--r--core/os/os2/dir.odin53
-rw-r--r--core/os/os2/dir_posix_darwin.odin17
-rw-r--r--core/os/os2/file.odin9
-rw-r--r--core/os/os2/file_posix_darwin.odin28
-rw-r--r--core/sys/darwin/copyfile.odin67
-rw-r--r--core/sys/darwin/darwin.odin1
-rw-r--r--core/sys/darwin/sync.odin2
-rw-r--r--core/sys/darwin/xnu_system_call_wrappers.odin10
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 */