mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
649 lines
18 KiB
ObjectPascal
649 lines
18 KiB
ObjectPascal
{
|
|
Double commander
|
|
-------------------------------------------------------------------------
|
|
This unit contains Unix specific functions
|
|
|
|
Copyright (C) 2015-2024 Alexander Koblov (alexx2000@mail.ru)
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
Notes:
|
|
1. TDarwinStat64 is the workaround for the bug of BaseUnix.Stat in FPC.
|
|
on MacOS with x86_64, Stat64 should be used instead of Stat.
|
|
and lstat64() should be called instead of lstat().
|
|
}
|
|
|
|
unit DCUnix;
|
|
|
|
{$mode objfpc}{$H+}
|
|
{$modeswitch advancedrecords}
|
|
{$packrecords c}
|
|
|
|
interface
|
|
|
|
uses
|
|
InitC, BaseUnix, UnixType, DCBasicTypes, SysUtils;
|
|
|
|
const
|
|
{$IF DEFINED(LINUX)}
|
|
FD_CLOEXEC = 1;
|
|
O_CLOEXEC = &02000000;
|
|
O_PATH = &010000000;
|
|
_SC_NPROCESSORS_CONF = 83;
|
|
_SC_NPROCESSORS_ONLN = 84;
|
|
{$ELSEIF DEFINED(FREEBSD)}
|
|
O_CLOEXEC = &04000000;
|
|
_SC_NPROCESSORS_CONF = 57;
|
|
_SC_NPROCESSORS_ONLN = 58;
|
|
CLOSE_RANGE_CLOEXEC = (1 << 2);
|
|
{$ELSEIF DEFINED(NETBSD)}
|
|
O_CLOEXEC = $00400000;
|
|
{$ELSEIF DEFINED(HAIKU)}
|
|
FD_CLOEXEC = 1;
|
|
O_CLOEXEC = $00000040;
|
|
{$ELSEIF DEFINED(DARWIN)}
|
|
F_NOCACHE = 48;
|
|
O_CLOEXEC = $1000000;
|
|
_SC_NPROCESSORS_CONF = 57;
|
|
_SC_NPROCESSORS_ONLN = 58;
|
|
{$ELSE}
|
|
O_CLOEXEC = 0;
|
|
{$ENDIF}
|
|
|
|
{$IF DEFINED(LINUX)}
|
|
{$I dclinuxmagic.inc}
|
|
{$ENDIF}
|
|
|
|
type
|
|
{$IF DEFINED(LINUX)}
|
|
TUnixTime =
|
|
{$IF DEFINED(CPUAARCH64)}
|
|
Int64
|
|
{$ELSEIF DEFINED(CPUMIPS)}
|
|
LongInt
|
|
{$ELSE}UIntPtr{$ENDIF};
|
|
TUnixMode =
|
|
{$IF DEFINED(CPUPOWERPC)}
|
|
LongInt
|
|
{$ELSE}Cardinal{$ENDIF};
|
|
{$ELSE}
|
|
TUnixTime = TTime;
|
|
TUnixMode = TMode;
|
|
{$ENDIF}
|
|
|
|
type
|
|
PTimeStruct = ^TTimeStruct;
|
|
TTimeStruct = record
|
|
tm_sec: cint; //* Seconds. [0-60] (1 leap second)
|
|
tm_min: cint; //* Minutes. [0-59]
|
|
tm_hour: cint; //* Hours. [0-23]
|
|
tm_mday: cint; //* Day. [1-31]
|
|
tm_mon: cint; //* Month. [0-11]
|
|
tm_year: cint; //* Year - 1900.
|
|
tm_wday: cint; //* Day of week. [0-6]
|
|
tm_yday: cint; //* Days in year. [0-365]
|
|
tm_isdst: cint; //* DST. [-1/0/1]
|
|
tm_gmtoff: clong; //* Seconds east of UTC.
|
|
tm_zone: pansichar; //* Timezone abbreviation.
|
|
end;
|
|
|
|
type
|
|
//en Password file entry record
|
|
passwd = record
|
|
pw_name: PChar; //en< user name
|
|
pw_passwd: PChar; //en< user password
|
|
pw_uid: uid_t; //en< user ID
|
|
pw_gid: gid_t; //en< group ID
|
|
{$IF DEFINED(BSD)}
|
|
pw_change: time_t; //en< password change time
|
|
pw_class: PChar; //en< user access class
|
|
{$ENDIF}
|
|
{$IF NOT DEFINED(HAIKU)}
|
|
pw_gecos: PChar; //en< real name
|
|
{$ENDIF}
|
|
pw_dir: PChar; //en< home directory
|
|
pw_shell: PChar; //en< shell program
|
|
{$IF DEFINED(HAIKU)}
|
|
pw_gecos: PChar; //en< real name
|
|
{$ENDIF}
|
|
{$IF DEFINED(BSD)}
|
|
pw_expire: time_t; //en< account expiration
|
|
pw_fields: cint; //en< internal: fields filled in
|
|
{$ENDIF}
|
|
end;
|
|
TPasswordRecord = passwd;
|
|
PPasswordRecord = ^TPasswordRecord;
|
|
//en Group file entry record
|
|
group = record
|
|
gr_name: PChar; //en< group name
|
|
gr_passwd: PChar; //en< group password
|
|
gr_gid: gid_t; //en< group ID
|
|
gr_mem: ^PChar; //en< group members
|
|
end;
|
|
TGroupRecord = group;
|
|
PGroupRecord = ^TGroupRecord;
|
|
|
|
type
|
|
{$IF DEFINED(DARWIN)}
|
|
TDarwinStat64 = record { the types are real}
|
|
st_dev : dev_t; // inode's device
|
|
st_mode : mode_t; // inode protection mode
|
|
st_nlink : nlink_t; // number of hard links
|
|
st_ino : cuint64; // inode's number
|
|
st_uid : uid_t; // user ID of the file's owner
|
|
st_gid : gid_t; // group ID of the file's group
|
|
st_rdev : dev_t; // device type
|
|
st_atime : time_t; // time of last access
|
|
st_atimensec : clong; // nsec of last access
|
|
st_mtime : time_t; // time of last data modification
|
|
st_mtimensec : clong; // nsec of last data modification
|
|
st_ctime : time_t; // time of last file status change
|
|
st_ctimensec : clong; // nsec of last file status change
|
|
st_birthtime : time_t; // File creation time
|
|
st_birthtimensec : clong; // nsec of file creation time
|
|
st_size : off_t; // file size, in bytes
|
|
st_blocks : cint64; // blocks allocated for file
|
|
st_blksize : cuint32; // optimal blocksize for I/O
|
|
st_flags : cuint32; // user defined flags for file
|
|
st_gen : cuint32; // file generation number
|
|
st_lspare : cint32;
|
|
st_qspare : array[0..1] Of cint64;
|
|
end;
|
|
|
|
TDCStat = TDarwinStat64;
|
|
{$ELSE}
|
|
TDCStat = BaseUnix.Stat;
|
|
{$ENDIF}
|
|
PDCStat = ^TDCStat;
|
|
|
|
TDCStatHelper = record Helper for TDCStat
|
|
Public
|
|
function birthtime: TFileTimeEx; inline;
|
|
function mtime: TFileTimeEx; inline;
|
|
function atime: TFileTimeEx; inline;
|
|
function ctime: TFileTimeEx; inline;
|
|
end;
|
|
|
|
Function DC_fpLstat( const path:RawByteString; var Info:TDCStat ): cint; inline;
|
|
|
|
// nanoseconds supported
|
|
function DC_FileSetTime(const FileName: String;
|
|
const mtime : TFileTimeEx;
|
|
const birthtime: TFileTimeEx;
|
|
const atime : TFileTimeEx ): Boolean;
|
|
|
|
// nanoseconds supported, does not follow symbolic links
|
|
function DC_SymLinkSetTime(const FileName: String;
|
|
const mtime : TFileTimeEx;
|
|
const atime : TFileTimeEx ): Boolean;
|
|
|
|
|
|
{en
|
|
Set the close-on-exec flag to all
|
|
}
|
|
procedure FileCloseOnExecAll;
|
|
{en
|
|
Set the close-on-exec (FD_CLOEXEC) flag
|
|
}
|
|
procedure FileCloseOnExec(Handle: System.THandle); inline;
|
|
{en
|
|
Find mount point of file system where file is located
|
|
@param(FileName File name)
|
|
@returns(Mount point of file system)
|
|
}
|
|
function FindMountPointPath(const FileName: String): String;
|
|
{en
|
|
Change owner and group of a file (does not follow symbolic links)
|
|
@param(path Full path to file)
|
|
@param(owner User ID)
|
|
@param(group Group ID)
|
|
@returns(On success, zero is returned. On error, -1 is returned, and errno is set appropriately)
|
|
}
|
|
function fpLChown(path : String; owner : TUid; group : TGid): cInt;
|
|
{en
|
|
Set process group ID for job control
|
|
}
|
|
function setpgid(pid, pgid: pid_t): cint; cdecl; external clib;
|
|
{en
|
|
The getenv() function searches the environment list to find the
|
|
environment variable name, and returns a pointer to the corresponding
|
|
value string.
|
|
}
|
|
function getenv(name: PAnsiChar): PAnsiChar; cdecl; external clib;
|
|
{en
|
|
Change or add an environment variable
|
|
@param(name Environment variable name)
|
|
@param(value Environment variable value)
|
|
@param(overwrite Overwrite environment variable if exist)
|
|
@returns(The function returns zero on success, or -1 if there was
|
|
insufficient space in the environment)
|
|
}
|
|
function setenv(const name, value: PAnsiChar; overwrite: cint): cint; cdecl; external clib;
|
|
{en
|
|
Remove an environment variable
|
|
@param(name Environment variable name)
|
|
@returns(The function returns zero on success, or -1 on error)
|
|
}
|
|
function unsetenv(const name: PAnsiChar): cint; cdecl; external clib;
|
|
{en
|
|
Get password file entry
|
|
@param(uid User ID)
|
|
@returns(The function returns a pointer to a structure containing the broken-out
|
|
fields of the record in the password database that matches the user ID)
|
|
}
|
|
function getpwuid(uid: uid_t): PPasswordRecord; cdecl; external clib;
|
|
{en
|
|
Get password file entry
|
|
@param(name User name)
|
|
@returns(The function returns a pointer to a structure containing the broken-out
|
|
fields of the record in the password database that matches the user name)
|
|
}
|
|
function getpwnam(const name: PChar): PPasswordRecord; cdecl; external clib;
|
|
{en
|
|
Get group file entry
|
|
@param(gid Group ID)
|
|
@returns(The function returns a pointer to a structure containing the broken-out
|
|
fields of the record in the group database that matches the group ID)
|
|
}
|
|
function getgrgid(gid: gid_t): PGroupRecord; cdecl; external clib;
|
|
{en
|
|
Get group file entry
|
|
@param(name Group name)
|
|
@returns(The function returns a pointer to a structure containing the broken-out
|
|
fields of the record in the group database that matches the group name)
|
|
}
|
|
function getgrnam(name: PChar): PGroupRecord; cdecl; external clib;
|
|
{en
|
|
Get configuration information at run time
|
|
}
|
|
function sysconf(name: cint): clong; cdecl; external clib;
|
|
|
|
function FileLock(Handle: System.THandle; Mode: cInt): System.THandle;
|
|
|
|
function fpMkTime(tm: PTimeStruct): TTime;
|
|
function fpLocalTime(timer: PTime; tp: PTimeStruct): PTimeStruct;
|
|
|
|
{$IF DEFINED(LINUX)}
|
|
var
|
|
KernVersion: UInt16;
|
|
|
|
function fpFDataSync(fd: cint): cint;
|
|
function fpCloneFile(src_fd, dst_fd: cint): Boolean;
|
|
function fpFAllocate(fd: cint; mode: cint; offset, len: coff_t): cint;
|
|
{$ENDIF}
|
|
|
|
{$IF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
|
|
function fnmatch(const pattern: PAnsiChar; const str: PAnsiChar; flags: cint): cint; cdecl; external clib;
|
|
{$ENDIF}
|
|
|
|
implementation
|
|
|
|
uses
|
|
Unix, DCConvertEncoding, DCOSUtils, LazUTF8
|
|
{$IF DEFINED(DARWIN)}
|
|
, DCDarwin
|
|
{$ELSEIF DEFINED(LINUX)}
|
|
, Dos, DCLinux
|
|
{$ENDIF}
|
|
;
|
|
|
|
{$IF not DEFINED(LINUX)}
|
|
function TDCStatHelper.birthtime: TFileTimeEx;
|
|
begin
|
|
{$IF DEFINED(HAIKU)}
|
|
Result.sec:= st_crtime;
|
|
Result.nanosec:= st_crtimensec;
|
|
{$ELSE}
|
|
Result.sec:= st_birthtime;
|
|
Result.nanosec:= st_birthtimensec;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TDCStatHelper.mtime: TFileTimeEx;
|
|
begin
|
|
Result.sec:= st_mtime;
|
|
Result.nanosec:= st_mtimensec;
|
|
end;
|
|
|
|
function TDCStatHelper.atime: TFileTimeEx;
|
|
begin
|
|
Result.sec:= st_atime;
|
|
Result.nanosec:= st_atimensec;
|
|
end;
|
|
|
|
function TDCStatHelper.ctime: TFileTimeEx;
|
|
begin
|
|
Result.sec:= st_ctime;
|
|
Result.nanosec:= st_ctimensec;
|
|
end;
|
|
{$ELSE}
|
|
function TDCStatHelper.birthtime: TFileTimeEx;
|
|
begin
|
|
Result:= TFileTimeExNull;
|
|
end;
|
|
|
|
function TDCStatHelper.mtime: TFileTimeEx;
|
|
begin
|
|
Result.sec:= Int64(st_mtime);
|
|
Result.nanosec:= Int64(st_mtime_nsec);
|
|
end;
|
|
|
|
function TDCStatHelper.atime: TFileTimeEx;
|
|
begin
|
|
Result.sec:= Int64(st_atime);
|
|
Result.nanosec:= Int64(st_atime_nsec);
|
|
end;
|
|
|
|
function TDCStatHelper.ctime: TFileTimeEx;
|
|
begin
|
|
Result.sec:= Int64(st_ctime);
|
|
Result.nanosec:= Int64(st_ctime_nsec);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
|
|
{$IF DEFINED(DARWIN)}
|
|
|
|
Function fpLstat64( path:pchar; Info:pstat ): cint; cdecl; external clib name 'lstat64';
|
|
|
|
Function DC_fpLstat( const path:RawByteString; var Info:TDCStat ): cint; inline;
|
|
var
|
|
SystemPath: RawByteString;
|
|
begin
|
|
SystemPath:=ToSingleByteFileSystemEncodedFileName( path );
|
|
Result:= fpLstat64( pchar(SystemPath), @info );
|
|
end;
|
|
|
|
{$ELSE}
|
|
|
|
Function DC_fpLstat( const path:RawByteString; var Info:TDCStat ): cint; inline;
|
|
begin
|
|
Result:= fpLstat( path, info );
|
|
end;
|
|
|
|
{$ENDIF}
|
|
|
|
function fputimes( path:pchar; times:Array of UnixType.timeval ): cint; cdecl; external clib name 'utimes';
|
|
function flutimes( path:pchar; times:Array of UnixType.timeval ): cint; cdecl; external clib name 'lutimes';
|
|
|
|
function DC_FileSetTime(const FileName: String;
|
|
const mtime : TFileTimeEx;
|
|
const birthtime: TFileTimeEx;
|
|
const atime : TFileTimeEx ): Boolean;
|
|
var
|
|
timevals: Array[0..1] of UnixType.timeval;
|
|
begin
|
|
Result:= false;
|
|
|
|
// last access time
|
|
timevals[0].tv_sec:= atime.sec;
|
|
timevals[0].tv_usec:= round( Extended(atime.nanosec) / 1000.0 );
|
|
// last modification time
|
|
timevals[1].tv_sec:= mtime.sec;
|
|
timevals[1].tv_usec:= round( Extended(mtime.nanosec) / 1000.0 );
|
|
if fputimes(pchar(UTF8ToSys(FileName)), timevals) <> 0 then exit;
|
|
|
|
{$IF not DEFINED(DARWIN)}
|
|
Result:= true;
|
|
{$ELSE}
|
|
Result:= MacosFileSetCreationTime( FileName, birthtime );
|
|
{$ENDIF}
|
|
end;
|
|
|
|
// Like DC_FileSetTime but uses lutimes() instead of utimes(), so the
|
|
// timestamp is set on the symlink itself rather than its target.
|
|
function DC_SymLinkSetTime(const FileName: String;
|
|
const mtime : TFileTimeEx;
|
|
const atime : TFileTimeEx ): Boolean;
|
|
var
|
|
timevals: Array[0..1] of UnixType.timeval;
|
|
begin
|
|
// last access time
|
|
timevals[0].tv_sec:= atime.sec;
|
|
timevals[0].tv_usec:= round( Extended(atime.nanosec) / 1000.0 );
|
|
// last modification time
|
|
timevals[1].tv_sec:= mtime.sec;
|
|
timevals[1].tv_usec:= round( Extended(mtime.nanosec) / 1000.0 );
|
|
Result:= flutimes(pchar(UTF8ToSys(FileName)), timevals) = 0;
|
|
end;
|
|
|
|
{$IF DEFINED(BSD)}
|
|
type rlim_t = Int64;
|
|
{$ENDIF}
|
|
|
|
const
|
|
{$IF DEFINED(LINUX)}
|
|
_SC_OPEN_MAX = 4;
|
|
FICLONE = $40049409;
|
|
RLIM_INFINITY = rlim_t(-1);
|
|
{$ELSEIF DEFINED(BSD)}
|
|
_SC_OPEN_MAX = 5;
|
|
RLIM_INFINITY = rlim_t(High(QWord) shr 1);
|
|
{$ELSEIF DEFINED(HAIKU)}
|
|
_SC_OPEN_MAX = 20;
|
|
RLIMIT_NOFILE = 4;
|
|
RLIM_INFINITY = $ffffffff;
|
|
{$ENDIF}
|
|
|
|
procedure tzset(); cdecl; external clib;
|
|
function mktime(tp: PTimeStruct): TTime; cdecl; external clib;
|
|
function localtime_r(timer: PTime; tp: PTimeStruct): PTimeStruct; cdecl; external clib;
|
|
function lchown(path : PChar; owner : TUid; group : TGid): cInt; cdecl; external clib;
|
|
{$IF DEFINED(LINUX)}
|
|
function fdatasync(fd: cint): cint; cdecl; external clib;
|
|
function fallocate(fd: cint; mode: cint; offset, len: coff_t): cint; cdecl; external clib;
|
|
{$ENDIF}
|
|
|
|
{$IF DEFINED(LINUX) OR DEFINED(FREEBSD)}
|
|
var
|
|
hLibC: TLibHandle = NilHandle;
|
|
|
|
procedure LoadCLibrary;
|
|
begin
|
|
hLibC:= mbLoadLibrary(mbGetModuleName(@tzset));
|
|
end;
|
|
{$ENDIF}
|
|
|
|
{$IF DEFINED(LINUX) OR DEFINED(BSD)}
|
|
var
|
|
close_range: function(first: cuint; last: cuint; flags: cint): cint; cdecl = nil;
|
|
{$ENDIF}
|
|
|
|
procedure FileCloseOnExecAll;
|
|
const
|
|
MAX_FD = 1024;
|
|
var
|
|
fd: cint;
|
|
p: TRLimit;
|
|
fd_max: rlim_t = RLIM_INFINITY;
|
|
begin
|
|
{$IF DEFINED(LINUX) OR DEFINED(BSD)}
|
|
if Assigned(close_range) then
|
|
begin
|
|
close_range(3, High(Int32), CLOSE_RANGE_CLOEXEC);
|
|
Exit;
|
|
end;
|
|
{$ENDIF}
|
|
if (FpGetRLimit(RLIMIT_NOFILE, @p) = 0) and (p.rlim_cur <> RLIM_INFINITY) then
|
|
fd_max:= p.rlim_cur
|
|
else begin
|
|
{$IF DECLARED(_SC_OPEN_MAX)}
|
|
fd_max:= sysconf(_SC_OPEN_MAX);
|
|
{$ENDIF}
|
|
end;
|
|
if (fd_max = RLIM_INFINITY) or (fd_max > MAX_FD) then
|
|
fd_max:= MAX_FD;
|
|
for fd:= 3 to cint(fd_max) do
|
|
FileCloseOnExec(fd);
|
|
end;
|
|
|
|
procedure FileCloseOnExec(Handle: System.THandle);
|
|
begin
|
|
{$IF DECLARED(FD_CLOEXEC)}
|
|
FpFcntl(Handle, F_SETFD, FpFcntl(Handle, F_GETFD) or FD_CLOEXEC);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function FindMountPointPath(const FileName: String): String;
|
|
var
|
|
I, J: LongInt;
|
|
sTemp: String;
|
|
recStat: Stat;
|
|
st_dev: QWord;
|
|
begin
|
|
// Set root directory as mount point by default
|
|
Result:= PathDelim;
|
|
// Get stat info for original file
|
|
if (fpLStat(FileName, recStat) < 0) then Exit;
|
|
// Save device ID of original file
|
|
st_dev:= recStat.st_dev;
|
|
J:= Length(FileName);
|
|
for I:= J downto 1 do
|
|
begin
|
|
if FileName[I] = PathDelim then
|
|
begin
|
|
if (I = 1) then
|
|
sTemp:= PathDelim
|
|
else begin
|
|
sTemp:= Copy(FileName, 1, I - 1);
|
|
end;
|
|
// Stat for current directory
|
|
if (fpLStat(sTemp, recStat) < 0) then Continue;
|
|
// If it is a link then checking link destination
|
|
if fpS_ISLNK(recStat.st_mode) then
|
|
begin
|
|
sTemp:= mbReadAllLinks(sTemp);
|
|
Result:= FindMountPointPath(sTemp);
|
|
Exit;
|
|
end;
|
|
// Check device ID
|
|
if (recStat.st_dev <> st_dev) then
|
|
begin
|
|
Result:= IncludeTrailingPathDelimiter(Copy(FileName, 1, J));
|
|
Exit;
|
|
end;
|
|
J:= I;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function fpLChown(path: String; owner: TUid; group: TGid): cInt;
|
|
begin
|
|
Result := lchown(PAnsiChar(CeUtf8ToSys(path)), owner, group);
|
|
if Result = -1 then fpseterrno(fpgetCerrno);
|
|
end;
|
|
|
|
function FileLock(Handle: System.THandle; Mode: cInt): System.THandle;
|
|
var
|
|
lockop: cint;
|
|
lockres: cint;
|
|
lockerr: cint;
|
|
{$IFDEF LINUX}
|
|
Sbfs: TStatFS;
|
|
{$ENDIF}
|
|
begin
|
|
Result:= Handle;
|
|
case (Mode and $F0) of
|
|
fmShareCompat,
|
|
fmShareExclusive:
|
|
lockop:= LOCK_EX or LOCK_NB;
|
|
fmShareDenyWrite:
|
|
lockop:= LOCK_SH or LOCK_NB;
|
|
else
|
|
Exit;
|
|
end;
|
|
{$IFDEF LINUX}
|
|
if (fpFStatFS(Handle, @Sbfs) = 0) then
|
|
begin
|
|
case UInt32(Sbfs.fstype) of
|
|
NFS_SUPER_MAGIC,
|
|
SMB_SUPER_MAGIC,
|
|
SMB2_MAGIC_NUMBER,
|
|
CIFS_MAGIC_NUMBER: Exit;
|
|
end;
|
|
end;
|
|
{$ENDIF}
|
|
repeat
|
|
lockres:= fpFlock(Handle, lockop);
|
|
until (lockres = 0) or (fpgeterrno <> ESysEIntr);
|
|
lockerr:= fpgeterrno;
|
|
{
|
|
Only return an error if locks are working and the file was already
|
|
locked. Not if locks are simply unsupported (e.g., on Angstrom Linux
|
|
you always get ESysNOLCK in the default configuration)
|
|
}
|
|
if (lockres <> 0) and ((lockerr = ESysEAGAIN) or (lockerr = ESysEDEADLK)) then
|
|
begin
|
|
Result:= -1;
|
|
FileClose(Handle);
|
|
end;
|
|
end;
|
|
|
|
function fpMkTime(tm: PTimeStruct): TTime;
|
|
begin
|
|
Result := mktime(tm);
|
|
if (Result = TTime(-1)) then fpseterrno(fpgetCerrno);
|
|
end;
|
|
|
|
function fpLocalTime(timer: PTime; tp: PTimeStruct): PTimeStruct;
|
|
begin
|
|
Result := localtime_r(timer, tp);
|
|
if (Result = nil) then fpseterrno(fpgetCerrno);
|
|
end;
|
|
|
|
{$IF DEFINED(LINUX)}
|
|
function fpFDataSync(fd: cint): cint;
|
|
begin
|
|
Result := fdatasync(fd);
|
|
if Result = -1 then fpseterrno(fpgetCerrno);
|
|
end;
|
|
|
|
function fpCloneFile(src_fd, dst_fd: cint): Boolean;
|
|
var
|
|
ASource: Pointer absolute src_fd;
|
|
begin
|
|
Result:= (FpIOCtl(dst_fd, FICLONE, ASource) = 0);
|
|
end;
|
|
|
|
function fpFAllocate(fd: cint; mode: cint; offset, len: coff_t): cint;
|
|
begin
|
|
Result := fallocate(fd, mode, offset, len);
|
|
if Result = -1 then fpseterrno(fpgetCerrno);
|
|
end;
|
|
{$ENDIF}
|
|
|
|
procedure Initialize;
|
|
begin
|
|
tzset();
|
|
{$IF DEFINED(LINUX) OR DEFINED(FREEBSD)}
|
|
LoadCLibrary;
|
|
{$IF DEFINED(LINUX)}
|
|
KernVersion:= BEtoN(DosVersion);
|
|
// Linux kernel >= 5.11
|
|
if KernVersion >= $50B then
|
|
{$ENDIF}
|
|
begin
|
|
Pointer(close_range):= GetProcAddress(hLibC, 'close_range');
|
|
end;
|
|
{$ELSEIF DEFINED(DARWIN)}
|
|
close_range:= @CloseRange;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
initialization
|
|
Initialize;
|
|
|
|
end.
|
|
|