|
@@ -6,14 +6,15 @@ unit uDarwinFileUtil;
|
|
interface
|
|
interface
|
|
|
|
|
|
uses
|
|
uses
|
|
- Classes, SysUtils;
|
|
|
|
|
|
+ Classes, SysUtils,
|
|
|
|
+ CocoaAll, Cocoa_Extra;
|
|
|
|
|
|
type
|
|
type
|
|
|
|
|
|
{ TDarwinFileUtil }
|
|
{ TDarwinFileUtil }
|
|
|
|
|
|
TDarwinFileUtil = class
|
|
TDarwinFileUtil = class
|
|
- class function cloneFile( const fromPath: String; const toPath: String ): Boolean;
|
|
|
|
|
|
+ class function cloneFile( const fromPath: String; const toPath: String; const size: Int64 ): Boolean;
|
|
end;
|
|
end;
|
|
|
|
|
|
implementation
|
|
implementation
|
|
@@ -43,11 +44,35 @@ const
|
|
|
|
|
|
{ TDarwinFileUtil }
|
|
{ TDarwinFileUtil }
|
|
|
|
|
|
-class function TDarwinFileUtil.cloneFile( const fromPath: String; const toPath: String ): Boolean;
|
|
|
|
|
|
+// the copyfile() api has two advantages:
|
|
|
|
+// 1. dramatically improve file copy speed on APFS
|
|
|
|
+// 2. supports copying macOS specific attributes
|
|
|
|
+// therefore, we should try copyfile() as much as possible on macOS
|
|
|
|
+class function TDarwinFileUtil.cloneFile( const fromPath: String; const toPath: String; const size: Int64 ): Boolean;
|
|
|
|
+const
|
|
|
|
+ NO_CALLBACK_MAXSIZE = 20*1024*1024; // 20MB
|
|
var
|
|
var
|
|
|
|
+ flags: copyfile_flags_t;
|
|
ret: Integer;
|
|
ret: Integer;
|
|
begin
|
|
begin
|
|
- ret:= copyfile( pchar(fromPath), pchar(toPath), nil, COPYFILE_ALL or COPYFILE_UNLINK or COPYFILE_CLONE_FORCE );
|
|
|
|
|
|
+ Result:= False;
|
|
|
|
+ flags:= COPYFILE_ALL;
|
|
|
|
+
|
|
|
|
+ // call copyfile() when:
|
|
|
|
+ // 1. macOS < 10.13 and filesize <= MAX_SIZE (copy only)
|
|
|
|
+ // 2. macOS >= 10.13 and filesize > MAX_SIZE (clone only, fail fast)
|
|
|
|
+ // 3. macOS >= 10.13 and filesize <= MAX_SIZE (try clone, then copy)
|
|
|
|
+ if NSAppKitVersionNumber < NSAppKitVersionNumber10_13 then begin
|
|
|
|
+ if size > NO_CALLBACK_MAXSIZE then
|
|
|
|
+ Exit;
|
|
|
|
+ end else begin
|
|
|
|
+ if size > NO_CALLBACK_MAXSIZE then
|
|
|
|
+ flags:= flags or COPYFILE_CLONE_FORCE or COPYFILE_UNLINK
|
|
|
|
+ else
|
|
|
|
+ flags:= flags or COPYFILE_CLONE;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ ret:= copyfile( pchar(fromPath), pchar(toPath), nil, flags );
|
|
Result:= (ret=0);
|
|
Result:= (ret=0);
|
|
end;
|
|
end;
|
|
|
|
|