mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 07:08:48 +00:00
os2: better copy_directory, and add native copy_file and copy_directory variants on MacOS
This commit is contained in:
+40
-13
@@ -2,6 +2,7 @@ package os2
|
|||||||
|
|
||||||
import "base:runtime"
|
import "base:runtime"
|
||||||
import "core:slice"
|
import "core:slice"
|
||||||
|
import "core:strings"
|
||||||
|
|
||||||
read_dir :: read_directory
|
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`
|
// Recursively copies a directory to `dst` from `src`
|
||||||
copy_directory :: proc(dst, src: string, dst_perm := 0o755) -> Error {
|
copy_directory_all :: proc(dst, src: string, dst_perm := 0o755) -> Error {
|
||||||
switch err := make_directory_all(dst, dst_perm); err {
|
when #defined(_copy_directory_all_native) {
|
||||||
case nil, .Exist:
|
return _copy_directory_all_native(dst, src, dst_perm)
|
||||||
// okay
|
} else {
|
||||||
case:
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||||
|
|
||||||
file_infos := read_all_directory_by_path(src, temp_allocator) or_return
|
abs_src := get_absolute_path(src, temp_allocator) or_return
|
||||||
for fi in file_infos {
|
abs_dst := get_absolute_path(dst, temp_allocator) or_return
|
||||||
temp_allocator_scope(temp_allocator)
|
|
||||||
|
|
||||||
dst_path := join_path({dst, fi.name}, temp_allocator) or_return
|
dst_buf := make([dynamic]byte, 0, len(abs_dst) + 256, temp_allocator) or_return
|
||||||
src_path := fi.fullpath
|
|
||||||
|
|
||||||
if fi.type == .Directory {
|
w: Walker
|
||||||
copy_directory(dst_path, src_path) or_return
|
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 {
|
} 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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -313,6 +313,15 @@ is_directory :: proc(path: string) -> bool {
|
|||||||
|
|
||||||
|
|
||||||
copy_file :: proc(dst_path, src_path: string) -> Error {
|
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
|
src := open(src_path) or_return
|
||||||
defer close(src)
|
defer close(src)
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package os2
|
|||||||
|
|
||||||
import "base:runtime"
|
import "base:runtime"
|
||||||
|
|
||||||
|
import "core:sys/darwin"
|
||||||
import "core:sys/posix"
|
import "core:sys/posix"
|
||||||
|
|
||||||
_posix_absolute_path :: proc(fd: posix.FD, name: string, allocator: runtime.Allocator) -> (path: cstring, err: Error) {
|
_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)
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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 ---
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package darwin
|
|||||||
|
|
||||||
import "core:c"
|
import "core:c"
|
||||||
|
|
||||||
|
@(export)
|
||||||
foreign import system "system:System.framework"
|
foreign import system "system:System.framework"
|
||||||
|
|
||||||
Bool :: b8
|
Bool :: b8
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package darwin
|
package darwin
|
||||||
|
|
||||||
foreign import system "system:System.framework"
|
|
||||||
|
|
||||||
// #define OS_WAIT_ON_ADDR_AVAILABILITY \
|
// #define OS_WAIT_ON_ADDR_AVAILABILITY \
|
||||||
// __API_AVAILABLE(macos(14.4), ios(17.4), tvos(17.4), watchos(10.4))
|
// __API_AVAILABLE(macos(14.4), ios(17.4), tvos(17.4), watchos(10.4))
|
||||||
when ODIN_OS == .Darwin {
|
when ODIN_OS == .Darwin {
|
||||||
|
|||||||
@@ -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 */
|
W_OK :: c.int((1 << 1)) /* test for write permission */
|
||||||
R_OK :: c.int((1 << 2)) /* test for read 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 */
|
/* syslimits.h */
|
||||||
PATH_MAX :: 1024 /* max bytes in pathname */
|
PATH_MAX :: 1024 /* max bytes in pathname */
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user