mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
171 lines
4.5 KiB
ObjectPascal
171 lines
4.5 KiB
ObjectPascal
unit DCDarwin;
|
|
|
|
{$mode delphi}
|
|
{$packrecords c}
|
|
{$pointermath on}
|
|
{$modeswitch objectivec1}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, DCBasicTypes, CocoaAll, BaseUnix;
|
|
|
|
const
|
|
CLOSE_RANGE_CLOEXEC = (1 << 2);
|
|
|
|
function CloseRange(first: cuint; last: cuint; flags: cint): cint; cdecl;
|
|
function mbFileCopyXattr(const Source, Target: String): Boolean;
|
|
|
|
// MacOS File Utils
|
|
function MacosFileSetCreationTime( const path:String; const birthtime:TFileTimeEx ): Boolean;
|
|
|
|
type
|
|
|
|
{ TDarwinFileUtil }
|
|
|
|
TDarwinFileUtil = class
|
|
class function cloneFile( const fromPath: String; const toPath: String; const size: Int64 ): Boolean;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
DCUnix;
|
|
|
|
type
|
|
proc_fdinfo = record
|
|
proc_fd: Int32;
|
|
proc_fdtype: UInt32;
|
|
end;
|
|
Pproc_fdinfo = ^proc_fdinfo;
|
|
|
|
const
|
|
PROC_PIDLISTFDS = 1;
|
|
PROC_PIDLISTFD_SIZE = SizeOf(proc_fdinfo);
|
|
|
|
const
|
|
NSAppKitVersionNumber10_13 = 1561;
|
|
|
|
const
|
|
COPYFILE_ACL = 1 shl 0;
|
|
COPYFILE_STAT = 1 shl 1;
|
|
COPYFILE_XATTR = 1 shl 2;
|
|
COPYFILE_DATA = 1 shl 3;
|
|
|
|
COPYFILE_SECURITY = COPYFILE_STAT or COPYFILE_ACL;
|
|
COPYFILE_METADATA = COPYFILE_SECURITY or COPYFILE_XATTR;
|
|
COPYFILE_ALL = COPYFILE_METADATA or COPYFILE_DATA;
|
|
|
|
COPYFILE_UNLINK = 1 shl 21;
|
|
COPYFILE_CLONE = 1 shl 24;
|
|
COPYFILE_CLONE_FORCE = 1 shl 25;
|
|
|
|
type
|
|
copyfile_state_t_o = record
|
|
end;
|
|
copyfile_state_t = ^copyfile_state_t_o;
|
|
copyfile_flags_t = UInt32;
|
|
|
|
function copyfile( const fromPath: pchar; const toPath: pchar; state: copyfile_state_t; flags: copyfile_flags_t ): Integer;
|
|
cdecl; external name 'copyfile';
|
|
|
|
function proc_pidinfo(pid: cint; flavor: cint; arg: cuint64; buffer: pointer; buffersize: cint): cint; cdecl; external 'proc';
|
|
|
|
function CloseRange(first: cuint; last: cuint; flags: cint): cint; cdecl;
|
|
var
|
|
I: cint;
|
|
Handle: cint;
|
|
ProcessId: TPid;
|
|
bufferSize: cint;
|
|
pidInfo: Pproc_fdinfo;
|
|
begin
|
|
Result:= -1;
|
|
ProcessId:= FpGetpid;
|
|
bufferSize:= proc_pidinfo(ProcessId, PROC_PIDLISTFDS, 0, nil, 0);
|
|
pidInfo:= GetMem(bufferSize);
|
|
if Assigned(pidInfo) then
|
|
begin
|
|
bufferSize:= proc_pidinfo(ProcessId, PROC_PIDLISTFDS, 0, pidInfo, bufferSize);
|
|
for I:= 0 to (bufferSize div PROC_PIDLISTFD_SIZE) - 1 do
|
|
begin
|
|
Handle:= pidInfo[I].proc_fd;
|
|
if (Handle >= first) and (Handle <= last) then
|
|
begin
|
|
if (flags and CLOSE_RANGE_CLOEXEC <> 0) then
|
|
FileCloseOnExec(Handle)
|
|
else begin
|
|
FileClose(Handle);
|
|
end;
|
|
end;
|
|
end;
|
|
Result:= 0;
|
|
FreeMem(pidInfo);
|
|
end;
|
|
end;
|
|
|
|
function mbFileCopyXattr(const Source, Target: String): Boolean;
|
|
var
|
|
ret: Integer;
|
|
begin
|
|
Writeln( '>>3> mbFileCopyXattr' );
|
|
ret:= copyfile( pchar(Source), pchar(Target), nil, COPYFILE_XATTR );
|
|
fpseterrno( ret );
|
|
Result:= (ret=0);
|
|
end;
|
|
|
|
function StringToNSString(const S: String): NSString;
|
|
begin
|
|
Result:= NSString(NSString.stringWithUTF8String(PAnsiChar(S)));
|
|
end;
|
|
|
|
function MacosFileSetCreationTime( const path:String; const birthtime:TFileTimeEx ): Boolean;
|
|
var
|
|
seconds: Double;
|
|
attrs: NSMutableDictionary;
|
|
nsPath: NSString;
|
|
begin
|
|
Result:= true;
|
|
if birthtime = TFileTimeExNull then exit;
|
|
seconds:= birthtime.sec.ToDouble + birthtime.nanosec.ToDouble / (1000.0*1000.0*1000.0);
|
|
attrs:= NSMutableDictionary.dictionaryWithCapacity( 1 );
|
|
attrs.setValue_forKey( NSDate.dateWithTimeIntervalSince1970(seconds), NSFileCreationDate );
|
|
nsPath:= StringToNSString( path );
|
|
Result:= NSFileManager.defaultManager.setAttributes_ofItemAtPath_error( attrs, nsPath, nil );
|
|
end;
|
|
|
|
{ TDarwinFileUtil }
|
|
|
|
// 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
|
|
flags: copyfile_flags_t;
|
|
ret: Integer;
|
|
begin
|
|
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);
|
|
end;
|
|
|
|
end.
|
|
|