os2: better copy_directory, and add native copy_file and copy_directory variants on MacOS

This commit is contained in:
Laytan Laats
2025-05-08 19:32:30 +02:00
parent edbe7aa06e
commit cacb9f9f54
8 changed files with 162 additions and 25 deletions
+40 -13
View File
@@ -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_path := join_path({dst, fi.name}, temp_allocator) or_return
src_path := fi.fullpath
dst_buf := make([dynamic]byte, 0, len(abs_dst) + 256, temp_allocator) or_return
if fi.type == .Directory {
copy_directory(dst_path, src_path) or_return
w: Walker
walker_init_path(&w, src)
defer walker_destroy(&w)
for info in walker_walk(&w) {
_ = walker_error(&w) or_break
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
}
+17
View File
@@ -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
}
+9
View File
@@ -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)
+28
View File
@@ -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
}