mirror of
https://github.com/red-prig/fpPS4.git
synced 2024-11-23 06:19:57 +00:00
685 lines
13 KiB
ObjectPascal
685 lines
13 KiB
ObjectPascal
unit sys_file;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows,
|
|
ntapi,
|
|
Classes,
|
|
SysUtils,
|
|
RWLock,
|
|
sys_kernel,
|
|
sys_time,
|
|
sys_fd;
|
|
|
|
function _sys_file_open(const path:RawByteString;flags,mode:Integer):Integer;
|
|
function _sys_file_stat(Const path:RawByteString;stat:PSceKernelStat):Integer;
|
|
function _sys_file_trunc(Const path:RawByteString;length:Int64):Integer;
|
|
|
|
implementation
|
|
|
|
type
|
|
TFile=class(TCustomFile)
|
|
var
|
|
lock:TRWLock;
|
|
Constructor Create;
|
|
Destructor Destroy; override;
|
|
function lseek (offset:Int64;whence:Integer):Int64; override;
|
|
function read (data:Pointer;size:Int64):Int64; override;
|
|
function pread (data:Pointer;size,offset:Int64):Int64; override;
|
|
function readv (vector:p_iovec;count:Integer):Int64; override;
|
|
function preadv (vector:p_iovec;count:Integer;offset:Int64):Int64; override;
|
|
function write (data:Pointer;size:Int64):Int64; override;
|
|
function pwrite (data:Pointer;size,offset:Int64):Int64; override;
|
|
function writev (vector:p_iovec;count:Integer):Int64; override;
|
|
function ftruncate(size:Int64):Integer; override;
|
|
function fstat (stat:PSceKernelStat):Integer; override;
|
|
function fsync ():Integer; override;
|
|
function fcntl (cmd:Integer;param1:ptruint):Integer; override;
|
|
end;
|
|
|
|
Function get_DesiredAccess(flags:Integer):DWORD;
|
|
begin
|
|
Result:=0;
|
|
if (flags and O_RDWR)<>0 then
|
|
begin
|
|
Result:=GENERIC_READ or GENERIC_WRITE;
|
|
end else
|
|
if (flags and O_WRONLY)<>0 then
|
|
begin
|
|
Result:=GENERIC_WRITE;
|
|
end else
|
|
begin
|
|
Result:=GENERIC_READ;
|
|
end;
|
|
|
|
if (flags and O_APPEND)<>0 then
|
|
begin
|
|
Result:=Result and (not GENERIC_WRITE);
|
|
Result:=Result or FILE_APPEND_DATA;
|
|
end;
|
|
end;
|
|
|
|
Function get_CreationDisposition(flags:Integer):DWORD;
|
|
begin
|
|
Result:=0;
|
|
if (flags and O_CREAT)<>0 then
|
|
begin
|
|
if (flags and O_EXCL)<>0 then
|
|
begin
|
|
Result:=CREATE_NEW;
|
|
end else
|
|
if (flags and O_TRUNC)<>0 then
|
|
begin
|
|
Result:=CREATE_ALWAYS;
|
|
end else
|
|
begin
|
|
Result:=OPEN_ALWAYS;
|
|
end;
|
|
end else
|
|
if (flags and O_TRUNC)<>0 then
|
|
begin
|
|
Result:=TRUNCATE_EXISTING;
|
|
end else
|
|
begin
|
|
Result:=OPEN_EXISTING;
|
|
end;
|
|
end;
|
|
|
|
function __sys_file_open(const path:RawByteString;flags,mode:Integer;var f:TFile):Integer;
|
|
var
|
|
h:THandle;
|
|
|
|
err:DWORD;
|
|
dwDesiredAccess:DWORD;
|
|
dwCreationDisposition:DWORD;
|
|
|
|
wp:WideString;
|
|
begin
|
|
Result:=0;
|
|
|
|
wp:=UTF8Decode(path);
|
|
|
|
if ((flags and O_NONBLOCK)<>0) then
|
|
begin
|
|
Writeln(StdErr,'__sys_file_open:O_NONBLOCK:TODO');
|
|
end;
|
|
|
|
dwDesiredAccess:=get_DesiredAccess(flags);
|
|
dwCreationDisposition:=get_CreationDisposition(flags);
|
|
|
|
h:=CreateFileW(
|
|
PWideChar(wp),
|
|
dwDesiredAccess,
|
|
FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
|
|
nil,
|
|
dwCreationDisposition,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
0
|
|
);
|
|
|
|
if (h=INVALID_HANDLE_VALUE) then
|
|
begin
|
|
err:=GetLastError;
|
|
//Writeln('GetLastError:',err{,' ',ps4_pthread_self^.sig._lock});
|
|
Case err of
|
|
ERROR_INVALID_DRIVE,
|
|
ERROR_PATH_NOT_FOUND,
|
|
ERROR_FILE_NOT_FOUND :Exit(-ENOENT);
|
|
ERROR_ACCESS_DENIED :Exit(-EACCES);
|
|
ERROR_BUFFER_OVERFLOW :Exit(-ENAMETOOLONG);
|
|
ERROR_NOT_ENOUGH_MEMORY:Exit(-ENOMEM);
|
|
ERROR_ALREADY_EXISTS :Exit(-EEXIST);
|
|
ERROR_FILE_EXISTS :Exit(-EEXIST);
|
|
ERROR_DISK_FULL :Exit(-ENOSPC);
|
|
else
|
|
Exit(-EIO);
|
|
end;
|
|
end;
|
|
|
|
f:=TFile.Create;
|
|
f.Handle:=h;
|
|
end;
|
|
|
|
function _sys_file_open(const path:RawByteString;flags,mode:Integer):Integer;
|
|
var
|
|
f:TFile;
|
|
begin
|
|
f:=nil;
|
|
Result:=__sys_file_open(path,flags,mode,f);
|
|
if (Result<>0) then Exit;
|
|
|
|
Result:=_sys_open_fd(f,flags);
|
|
|
|
if (Result<0) then
|
|
begin
|
|
f.Destroy;
|
|
end else
|
|
begin
|
|
f.Release;
|
|
end;
|
|
end;
|
|
|
|
//
|
|
|
|
function _sys_file_stat(Const path:RawByteString;stat:PSceKernelStat):Integer;
|
|
var
|
|
f:TFile;
|
|
begin
|
|
f:=nil;
|
|
Result:=__sys_file_open(path,O_RDONLY,0,f);
|
|
if (Result<>0) then Exit;
|
|
|
|
Result:=f.fstat(stat);
|
|
|
|
f.Destroy;
|
|
end;
|
|
|
|
function _sys_file_trunc(Const path:RawByteString;length:Int64):Integer;
|
|
var
|
|
f:TFile;
|
|
begin
|
|
f:=nil;
|
|
Result:=__sys_file_open(path,O_RDWR,0,f);
|
|
if (Result<>0) then Exit;
|
|
|
|
Result:=f.ftruncate(length);
|
|
|
|
f.Destroy;
|
|
end;
|
|
|
|
//
|
|
|
|
Constructor TFile.Create;
|
|
begin
|
|
rwlock_init(lock);
|
|
end;
|
|
|
|
Destructor TFile.Destroy;
|
|
begin
|
|
rwlock_destroy(lock);
|
|
CloseHandle(Handle);
|
|
end;
|
|
|
|
function TFile.lseek(offset:Int64;whence:Integer):Int64;
|
|
label
|
|
_set_pos;
|
|
var
|
|
s:IO_STATUS_BLOCK;
|
|
i:FILE_STANDARD_INFORMATION;
|
|
e:Integer;
|
|
begin
|
|
s:=Default(IO_STATUS_BLOCK);
|
|
|
|
rwlock_wrlock(lock);
|
|
|
|
Case whence of
|
|
0:begin //beg
|
|
_set_pos:
|
|
|
|
e:=NtSetInformationFile(Handle,@s,@offset,SizeOf(Int64),FilePositionInformation);
|
|
end;
|
|
1:begin //cur
|
|
i.EndOfFile.QuadPart:=0;
|
|
e:=NtQueryInformationFile(Handle,@s,@i.EndOfFile,SizeOf(Int64),FilePositionInformation);
|
|
if (e>=0) then
|
|
begin
|
|
offset:=offset+i.EndOfFile.QuadPart;
|
|
goto _set_pos;
|
|
end;
|
|
end;
|
|
2:begin //end
|
|
i.EndOfFile.QuadPart:=0;
|
|
e:=NtQueryInformationFile(Handle,@s,@i,SizeOf(i),FileStandardInformation);
|
|
if (e>=0) then
|
|
begin
|
|
offset:=offset+i.EndOfFile.QuadPart;
|
|
goto _set_pos;
|
|
end;
|
|
end;
|
|
else
|
|
e:=Integer(STATUS_INVALID_PARAMETER);
|
|
end;
|
|
|
|
rwlock_unlock(lock);
|
|
|
|
e:=-ntf2px(e);
|
|
|
|
if (e<>0) then
|
|
begin
|
|
Result:=e;
|
|
end else
|
|
begin
|
|
Result:=offset;
|
|
end;
|
|
end;
|
|
|
|
function TFile.read(data:Pointer;size:Int64):Int64;
|
|
var
|
|
s:IO_STATUS_BLOCK;
|
|
e:Integer;
|
|
begin
|
|
s:=Default(IO_STATUS_BLOCK);
|
|
|
|
rwlock_wrlock(lock);
|
|
|
|
e:=NtReadFile(Handle,0,nil,nil,@s,data,size,nil,nil);
|
|
if (e=STATUS_PENDING) then e:=NtWaitForSingleObject(Handle,False,nil);
|
|
|
|
rwlock_unlock(lock);
|
|
|
|
e:=-ntf2px(e);
|
|
|
|
if (e<>0) then
|
|
begin
|
|
Result:=e;
|
|
end else
|
|
begin
|
|
Result:=Int64(s.Information);
|
|
end;
|
|
end;
|
|
|
|
{
|
|
function _get_pos(h:THandle):Int64;
|
|
const
|
|
zero:LARGE_INTEGER=(QuadPart:0);
|
|
begin
|
|
Result:=-1;
|
|
if not SetFilePointerEx(h,zero,@Result,FILE_CURRENT) then
|
|
begin
|
|
Result:=-1;
|
|
end;
|
|
end;
|
|
|
|
function _set_pos(h:THandle;p:Int64):Boolean;
|
|
begin
|
|
Result:=SetFilePointerEx(h,LARGE_INTEGER(p),nil,FILE_BEGIN);
|
|
end;
|
|
}
|
|
|
|
function TFile.pread(data:Pointer;size,offset:Int64):Int64;
|
|
var
|
|
s:IO_STATUS_BLOCK;
|
|
e:Integer;
|
|
begin
|
|
s:=Default(IO_STATUS_BLOCK);
|
|
|
|
rwlock_wrlock(lock);
|
|
//---------------------
|
|
///p:=_get_pos(Handle);
|
|
//---------------------
|
|
|
|
e:=NtReadFile(Handle,0,nil,nil,@s,data,size,@offset,nil);
|
|
if (e=STATUS_PENDING) then e:=NtWaitForSingleObject(Handle,False,nil);
|
|
|
|
//---------------------------------------------
|
|
//if not _set_pos(Handle,p) then Assert(False);
|
|
//---------------------------------------------
|
|
rwlock_unlock(lock);
|
|
|
|
e:=-ntf2px(e);
|
|
|
|
if (e<>0) then
|
|
begin
|
|
Result:=e;
|
|
end else
|
|
begin
|
|
Result:=Int64(s.Information);
|
|
end;
|
|
end;
|
|
|
|
function TFile.readv(vector:p_iovec;count:Integer):Int64;
|
|
label
|
|
_exit;
|
|
var
|
|
s:IO_STATUS_BLOCK;
|
|
e:Integer;
|
|
i:Integer;
|
|
v:iovec;
|
|
begin
|
|
Result:=0;
|
|
|
|
rwlock_wrlock(lock);
|
|
|
|
For i:=0 to count-1 do
|
|
begin
|
|
v:=vector[i];
|
|
|
|
if (v.iov_base<>nil) and (v.iov_len<>0) then
|
|
begin
|
|
|
|
s:=Default(IO_STATUS_BLOCK);
|
|
e:=NtReadFile(Handle,0,nil,nil,@s,v.iov_base,v.iov_len,nil,nil);
|
|
if (e=STATUS_PENDING) then e:=NtWaitForSingleObject(Handle,False,nil);
|
|
|
|
e:=-ntf2px(e);
|
|
|
|
if (e<>0) then
|
|
begin
|
|
Result:=e;
|
|
Goto _exit;
|
|
end else
|
|
begin
|
|
Result:=Result+Int64(s.Information);
|
|
if (Int64(s.Information)<v.iov_len) then
|
|
begin
|
|
Goto _exit;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
_exit:
|
|
rwlock_unlock(lock);
|
|
end;
|
|
|
|
function TFile.preadv(vector:p_iovec;count:Integer;offset:Int64):Int64;
|
|
label
|
|
_exit;
|
|
var
|
|
s:IO_STATUS_BLOCK;
|
|
e:Integer;
|
|
i:Integer;
|
|
v:iovec;
|
|
poffset:PLARGE_INTEGER;
|
|
begin
|
|
Result:=0;
|
|
|
|
poffset:=@offset; //first move to offset
|
|
|
|
rwlock_wrlock(lock);
|
|
|
|
//--------------------------------------------------
|
|
//p:=_get_pos(Handle);
|
|
//if not _set_pos(Handle,offset) then Assert(False);
|
|
//--------------------------------------------------
|
|
|
|
For i:=0 to count-1 do
|
|
begin
|
|
v:=vector[i];
|
|
|
|
if (v.iov_base<>nil) and (v.iov_len<>0) then
|
|
begin
|
|
|
|
s:=Default(IO_STATUS_BLOCK);
|
|
e:=NtReadFile(Handle,0,nil,nil,@s,v.iov_base,v.iov_len,poffset,nil);
|
|
if (e=STATUS_PENDING) then e:=NtWaitForSingleObject(Handle,False,nil);
|
|
|
|
poffset:=nil; //reset
|
|
|
|
e:=-ntf2px(e);
|
|
|
|
if (e<>0) then
|
|
begin
|
|
Result:=e;
|
|
Goto _exit;
|
|
end else
|
|
begin
|
|
Result:=Result+Int64(s.Information);
|
|
if (Int64(s.Information)<v.iov_len) then
|
|
begin
|
|
Goto _exit;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
_exit:
|
|
//--------------------------------------------------
|
|
//if not _set_pos(Handle,p) then Assert(False);
|
|
//--------------------------------------------------
|
|
rwlock_unlock(lock);
|
|
end;
|
|
|
|
function TFile.write(data:Pointer;size:Int64):Int64;
|
|
var
|
|
s:IO_STATUS_BLOCK;
|
|
e:Integer;
|
|
begin
|
|
s:=Default(IO_STATUS_BLOCK);
|
|
|
|
rwlock_wrlock(lock);
|
|
|
|
e:=NtWriteFile(Handle,0,nil,nil,@s,data,size,nil,nil);
|
|
if (e=STATUS_PENDING) then e:=NtWaitForSingleObject(Handle,False,nil);
|
|
|
|
rwlock_unlock(lock);
|
|
|
|
e:=-ntf2px(e);
|
|
|
|
if (e<>0) then
|
|
begin
|
|
Result:=e;
|
|
end else
|
|
begin
|
|
Result:=Int64(s.Information);
|
|
end;
|
|
end;
|
|
|
|
function TFile.pwrite(data:Pointer;size,offset:Int64):Int64;
|
|
var
|
|
s:IO_STATUS_BLOCK;
|
|
e:Integer;
|
|
begin
|
|
s:=Default(IO_STATUS_BLOCK);
|
|
|
|
rwlock_wrlock(lock);
|
|
//---------------------
|
|
///p:=_get_pos(Handle);
|
|
//---------------------
|
|
|
|
e:=NtWriteFile(Handle,0,nil,nil,@s,data,size,@offset,nil);
|
|
if (e=STATUS_PENDING) then e:=NtWaitForSingleObject(Handle,False,nil);
|
|
|
|
//---------------------------------------------
|
|
//if not _set_pos(Handle,p) then Assert(False);
|
|
//---------------------------------------------
|
|
rwlock_unlock(lock);
|
|
|
|
e:=-ntf2px(e);
|
|
|
|
if (e<>0) then
|
|
begin
|
|
Result:=e;
|
|
end else
|
|
begin
|
|
Result:=Int64(s.Information);
|
|
end;
|
|
end;
|
|
|
|
function TFile.writev(vector:p_iovec;count:Integer):Int64;
|
|
label
|
|
_exit;
|
|
var
|
|
s:IO_STATUS_BLOCK;
|
|
e:Integer;
|
|
i:Integer;
|
|
v:iovec;
|
|
begin
|
|
Result:=0;
|
|
|
|
rwlock_wrlock(lock);
|
|
|
|
For i:=0 to count-1 do
|
|
begin
|
|
v:=vector[i];
|
|
|
|
if (v.iov_base<>nil) and (v.iov_len<>0) then
|
|
begin
|
|
|
|
s:=Default(IO_STATUS_BLOCK);
|
|
e:=NtWriteFile(Handle,0,nil,nil,@s,v.iov_base,v.iov_len,nil,nil);
|
|
if (e=STATUS_PENDING) then e:=NtWaitForSingleObject(Handle,False,nil);
|
|
|
|
e:=-ntf2px(e);
|
|
|
|
if (e<>0) then
|
|
begin
|
|
Result:=e;
|
|
Goto _exit;
|
|
end else
|
|
begin
|
|
Result:=Result+Int64(s.Information);
|
|
if (Int64(s.Information)<v.iov_len) then
|
|
begin
|
|
Goto _exit;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
_exit:
|
|
rwlock_unlock(lock);
|
|
end;
|
|
|
|
function TFile.ftruncate(size:Int64):Integer;
|
|
var
|
|
s:IO_STATUS_BLOCK;
|
|
e:Integer;
|
|
begin
|
|
s:=Default(IO_STATUS_BLOCK);
|
|
|
|
rwlock_wrlock(lock);
|
|
|
|
e:=NtSetInformationFile(Handle,@s,@size,SizeOf(Int64),FileEndOfFileInformation);
|
|
if (e>=0) then
|
|
begin
|
|
e:=NtSetInformationFile(Handle,@s,@size,SizeOf(Int64),FileAllocationInformation);
|
|
end;
|
|
|
|
rwlock_unlock(lock);
|
|
|
|
Result:=ntf2px(e);
|
|
end;
|
|
|
|
function file_attr_to_st_mode(attr:DWORD):Word;
|
|
begin
|
|
Result:=S_IRUSR;
|
|
if ((attr and FILE_ATTRIBUTE_DIRECTORY)<>0) then
|
|
Result:=Result or S_IFDIR
|
|
else
|
|
Result:=Result or S_IFREG;
|
|
|
|
if ((attr and FILE_ATTRIBUTE_READONLY)=0) then
|
|
Result:=Result or S_IWUSR;
|
|
end;
|
|
|
|
function TFile.fstat (stat:PSceKernelStat):Integer;
|
|
var
|
|
hfi:TByHandleFileInformation;
|
|
err:DWORD;
|
|
begin
|
|
stat^:=Default(SceKernelStat);
|
|
|
|
Case SwGetFileType(Handle) of
|
|
FILE_TYPE_PIPE:
|
|
begin
|
|
stat^.st_dev :=fd;
|
|
stat^.st_rdev :=fd;
|
|
stat^.st_mode :=S_IFIFO;
|
|
stat^.st_nlink:=1;
|
|
end;
|
|
FILE_TYPE_CHAR:
|
|
begin
|
|
stat^.st_dev :=fd;
|
|
stat^.st_rdev :=fd;
|
|
stat^.st_mode :=S_IFCHR;
|
|
stat^.st_nlink:=1;
|
|
end;
|
|
FILE_TYPE_DISK:
|
|
begin
|
|
err:=SwGetFileInformationByHandle(Handle,@hfi);
|
|
if (err<>0) then
|
|
begin
|
|
Case err of
|
|
ERROR_ACCESS_DENIED,
|
|
ERROR_SHARING_VIOLATION,
|
|
ERROR_LOCK_VIOLATION,
|
|
ERROR_SHARING_BUFFER_EXCEEDED:
|
|
Exit(EACCES);
|
|
|
|
ERROR_BUFFER_OVERFLOW:
|
|
Exit(ENAMETOOLONG);
|
|
|
|
ERROR_NOT_ENOUGH_MEMORY:
|
|
Exit(ENOMEM);
|
|
|
|
else
|
|
Exit(ENOENT);
|
|
end;
|
|
end;
|
|
|
|
stat^.st_dev :=fd;
|
|
stat^.st_rdev :=fd;
|
|
|
|
stat^.st_mode :=file_attr_to_st_mode(hfi.dwFileAttributes);
|
|
stat^.st_size :=hfi.nFileSizeLow or (QWORD(hfi.nFileSizeHigh) shl 32);
|
|
stat^.st_nlink :=Word(hfi.nNumberOfLinks);
|
|
stat^.st_gen :=hfi.nFileIndexLow;
|
|
|
|
stat^.st_atim :=filetime_to_timespec(hfi.ftLastAccessTime);
|
|
stat^.st_mtim :=filetime_to_timespec(hfi.ftLastWriteTime);
|
|
stat^.st_ctim :=stat^.st_mtim;
|
|
stat^.st_birthtim:=filetime_to_timespec(hfi.ftCreationTime);
|
|
|
|
stat^.st_blocks :=((stat^.st_size+511) div 512);
|
|
stat^.st_blksize :=512;
|
|
end;
|
|
|
|
else
|
|
Exit(EBADF);
|
|
end;
|
|
|
|
Result:=0;
|
|
end;
|
|
|
|
function TFile.fsync:Integer;
|
|
var
|
|
err:DWORD;
|
|
begin
|
|
if FlushFileBuffers(Handle) then
|
|
begin
|
|
Result:=0;
|
|
end else
|
|
begin
|
|
err:=GetLastError;
|
|
Case err of
|
|
ERROR_INVALID_HANDLE:
|
|
Exit(EINVAL);
|
|
else
|
|
Exit(EIO);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TFile.fcntl(cmd:Integer;param1:ptruint):Integer;
|
|
begin
|
|
Case cmd of
|
|
F_SETFL:
|
|
begin
|
|
if (Integer(param1) and O_NONBLOCK)<>(status and O_NONBLOCK) then
|
|
begin
|
|
Writeln(StdErr,'fcntl:O_NONBLOCK:TODO');
|
|
end;
|
|
if (Integer(param1) and O_APPEND)<>(status and O_APPEND) then
|
|
begin
|
|
Writeln(StdErr,'fcntl:O_APPEND:TODO');
|
|
end;
|
|
end;
|
|
else;
|
|
end;
|
|
Result:=inherited;
|
|
end;
|
|
|
|
//
|
|
|
|
end.
|
|
|
|
|
|
|