This commit is contained in:
red-prig 2022-11-12 00:02:45 +03:00
parent 683f552d55
commit 4fbb608639
5 changed files with 461 additions and 18 deletions

View File

@ -11,6 +11,7 @@ uses
sys_fd,
sys_file,
sys_dev,
sys_dir,
Classes,
SysUtils;
@ -1036,7 +1037,7 @@ begin
PT_FILE:;
PT_DEV :Exit(_set_sce_errno(0));
else
Exit(_set_sce_errno(px2sce(EACCES)));
Exit(_set_sce_errno(SCE_KERNEL_ERROR_EACCES));
end;
if FileExists(fn) or DirectoryExists(fn) then

View File

@ -10,7 +10,6 @@ uses
SysUtils,
RWLock,
sys_kernel,
sys_time,
sys_fd;
function _sys_dev_open(const path:RawByteString;flags,mode:Integer):Integer;
@ -33,8 +32,10 @@ type
end;
TDevStd=class(TDevFile)
Text:PText;
cache:TMemoryStream;
var
Text:PText;
lock:TRWLock;
cache:RawByteString;
Constructor Create(t:PText);
Destructor Destroy; override;
function read (data:Pointer;size:Int64):Int64; override;
@ -155,38 +156,101 @@ type
begin
Handle:=PTextRec(t)^.Handle;
Text:=t;
cache:=TMemoryStream.Create
rwlock_init(lock);
cache:='';
end;
Destructor TDevStd.Destroy;
begin
FreeAndNil(cache);
rwlock_destroy(lock);
cache:='';
end;
function TDevStd.read (data:Pointer;size:Int64):Int64;
var
S:RawByteString;
begin
//
rwlock_wrlock(lock);
if (Length(cache)<>0) then
begin
if (size>Length(cache)) then
begin
size:=Length(cache);
end;
Move(PChar(cache)^,data^,size);
Delete(cache,1,size);
rwlock_unlock(lock);
Exit(size);
end;
rwlock_unlock(lock);
S:='';
System.ReadLn(Text^,S);
S:=S+#10;
if (Length(S)>size) then
begin
Move(PChar(S)^,data^,size);
Result:=size;
Delete(S,1,size);
rwlock_wrlock(lock);
cache:=cache+S;
rwlock_unlock(lock);
end else
begin
size:=Length(S);
Move(PChar(S)^,data^,size);
Result:=size;
end;
end;
function TDevStd.pread (data:Pointer;size,offset:Int64):Int64;
begin
//
Result:=read(data,size);
end;
function TDevStd.readv (vector:p_iovec;count:Integer):Int64;
var
i,n:Integer;
begin
//
Result:=0;
For i:=0 to count-1 do
begin
n:=read(vector[i].iov_base,vector[i].iov_len);
if (n>0) then
begin
Result:=Result+n;
if (n<vector[i].iov_len) then Exit;
end else
begin
Exit(-EIO);
Break;
end;
end;
end;
function TDevStd.write (data:Pointer;size:Int64):Int64;
var
S:RawByteString;
begin
//
SetString(S,data,size);
System.Write(Text^,S);
Result:=size;
end;
function TDevStd.pwrite(data:Pointer;size,offset:Int64):Int64;
begin
//
Result:=write(data,size);
end;
//
end.

369
sys/sys_dir.pas Normal file
View File

@ -0,0 +1,369 @@
unit sys_dir;
{$mode ObjFPC}{$H+}
interface
uses
Windows,
Classes,
SysUtils,
RWLock,
sys_kernel,
sys_time,
sys_fd;
const
// File types
DT_UNKNOWN= 0; //The type is unknown.
DT_FIFO = 1; //A named pipe, or FIFO.
DT_CHR = 2; //A character device.
DT_DIR = 4; //A directory.
DT_BLK = 6; //A block device.
DT_REG = 8; //A regular file.
DT_LNK =10; //A symbolic link.
DT_SOCK =12; //A local-domain socket.
DT_WHT =14; //
type
p_dirent=^dirent;
dirent=packed object
Const
MAXNAMLEN=255;
Var
d_fileno:DWORD; // file number of entry
d_reclen:WORD; // length of this record
d_type :BYTE; // file type, see below
d_namlen:BYTE; // length of string in d_name
d_name :array[0..MAXNAMLEN] of AnsiChar; //name must be no longer than this
end;
function _sys_dir_open(const path:RawByteString;flags,mode:Integer):Integer;
function _sys_dir_stat(Const path:RawByteString;stat:PSceKernelStat):Integer;
implementation
type
a_dirent=array of dirent;
TDirFile=class(TCustomFile)
var
lock:TRWLock;
path:RawByteString;
dirs:a_dirent;
pos:DWORD;
Constructor Create;
Destructor Destroy; 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 write (data:Pointer;size:Int64):Int64; override;
function pwrite(data:Pointer;size,offset:Int64):Int64; override;
function fstat (stat:PSceKernelStat):Integer; override;
function lseek (offset:Int64;whence:Integer):Int64; override;
function getdirentries(buf:Pointer;nbytes:Int64;basep:PInt64):Int64; override;
end;
function get_d_type(dwFileAttributes:DWORD):BYTE;
begin
if (dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY)<>0 then
begin
Result:=DT_DIR;
end else
begin
Result:=DT_REG;
end;
end;
procedure move_dirent(id:DWORD;src:PWIN32FindDataW;buf:Pointer);
var
p:p_dirent;
f:RawByteString;
len:ptruint;
begin
f:=UTF8Encode(WideString(src^.cFileName));
len:=Length(f);
if (len>dirent.MAXNAMLEN) then len:=dirent.MAXNAMLEN;
Inc(len);
SetLength(f,len);
f[len]:=#0;
p:=buf;
p^.d_fileno:=id;
p^.d_reclen:=SizeOf(dirent);
p^.d_type :=get_d_type(src^.dwFileAttributes);
p^.d_namlen:=BYTE(len-1);
Move(PChar(f)^,p^.d_name,len);
end;
function get_dir_wp(const path:RawByteString):WideString;
begin
Result:=UTF8Decode(IncludeTrailingPathDelimiter(path)+'*');
end;
function _sys_dir_open(const path:RawByteString;flags,mode:Integer):Integer;
var
f:TDirFile;
h:THandle;
err:DWORD;
wp:WideString;
data:TWIN32FindDataW;
tmp:dirent;
i:Integer;
begin
Result:=0;
wp:=get_dir_wp(path);
data:=Default(TWIN32FindDataW);
h:=FindFirstFileW(PWideChar(wp),data);
err:=0;
if (h=INVALID_HANDLE_VALUE) then
begin
err:=GetLastError;
Case err of
ERROR_INVALID_DRIVE,
ERROR_PATH_NOT_FOUND :Exit(-ENOENT);
ERROR_ACCESS_DENIED :Exit(-EACCES);
ERROR_BUFFER_OVERFLOW :Exit(-ENAMETOOLONG);
ERROR_NOT_ENOUGH_MEMORY:Exit(-ENOMEM);
ERROR_DISK_FULL :Exit(-ENOSPC);
ERROR_FILE_NOT_FOUND :;
else
Exit(-EIO);
end;
end;
f:=TDirFile.Create;
f.path:=path;
if (err<>ERROR_FILE_NOT_FOUND) then
begin
tmp:=Default(dirent);
move_dirent(0,@data,@tmp);
SetLength(f.dirs,1);
f.dirs[0]:=tmp;
repeat
if FindNextFileW(h,data) then
begin
tmp:=Default(dirent);
move_dirent(0,@data,@tmp);
i:=Length(f.dirs);
SetLength(f.dirs,i+1);
f.dirs[i]:=tmp;
end else
begin
err:=GetLastError;
Case err of
ERROR_FILE_NOT_FOUND:
begin
Break;
end;
else
begin
Windows.FindClose(h);
f.Destroy;
Exit(-EIO);
end;
end;
end;
until false;
end;
Result:=_sys_open_fd(f);
if (Result<0) then
begin
f.Release;
end else
begin
f.Destroy;
end;
end;
function _sys_dir_stat(Const path:RawByteString;stat:PSceKernelStat):Integer;
var
hfi:WIN32_FILE_ATTRIBUTE_DATA;
err:DWORD;
begin
stat^:=Default(SceKernelStat);
hfi:=Default(WIN32_FILE_ATTRIBUTE_DATA);
err:=SwGetFileAttributes(path,@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_mode :=S_IFDIR;
stat^.st_size :=hfi.nFileSizeLow or (QWORD(hfi.nFileSizeHigh) shl 32);
stat^.st_nlink :=1;
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 :=0;
stat^.st_blksize :=SizeOf(dirent);
Result:=0;
end;
//
Constructor TDirFile.Create;
begin
pos:=0;
Handle:=INVALID_HANDLE_VALUE;
rwlock_init(lock);
dirs:=Default(a_dirent);
end;
Destructor TDirFile.Destroy;
begin
dirs:=Default(a_dirent);
rwlock_destroy(lock);
end;
function TDirFile.read (data:Pointer;size:Int64):Int64;
begin
Result:=-EISDIR;
end;
function TDirFile.pread (data:Pointer;size,offset:Int64):Int64;
begin
Result:=-EISDIR;
end;
function TDirFile.readv (vector:p_iovec;count:Integer):Int64;
begin
Result:=-EISDIR;
end;
function TDirFile.write (data:Pointer;size:Int64):Int64;
begin
Result:=-EISDIR;
end;
function TDirFile.pwrite(data:Pointer;size,offset:Int64):Int64;
begin
Result:=-EISDIR;
end;
function TDirFile.fstat (stat:PSceKernelStat):Integer;
begin
Result:=_sys_dir_stat(path,stat);
if (Result=0) then
begin
stat^.st_dev :=fd;
stat^.st_rdev:=fd;
end;
end;
function TDirFile.lseek (offset:Int64;whence:Integer):Int64;
begin
rwlock_wrlock(lock);
case whence of
SEEK_SET:
begin
if (offset>=0) then
begin
pos:=offset;
Result:=offset;
end else
begin
Result:=-EINVAL;
end;
end;
SEEK_CUR:
begin
offset:=offset+pos;
if (offset>=0) then
begin
pos:=offset;
Result:=offset;
end else
begin
Result:=-EINVAL;
end;
end;
SEEK_END:
begin
offset:=offset+Length(dirs);
if (offset>=0) then
begin
pos:=offset;
Result:=offset;
end else
begin
Result:=-EINVAL;
end;
end;
else
Result:=-EINVAL;
end;
rwlock_unlock(lock);
end;
function TDirFile.getdirentries(buf:Pointer;nbytes:Int64;basep:PInt64):Int64;
var
i,count:DWORD;
begin
count:=nbytes div SizeOf(dirent);
rwlock_wrlock(lock);
i:=pos+count;
if (i>Length(dirs)) then
begin
i:=Length(dirs);
if (pos>i) then
begin
count:=0;
end else
begin
count:=(i-pos);
end;
end;
if (count<>0) then
begin
Move(dirs[pos],buf^,count);
end;
pos:=i;
rwlock_unlock(lock);
if (basep<>nil) then
begin
basep^:=i;
end;
Result:=count*SizeOf(dirent);
end;
//
end.

View File

@ -196,13 +196,14 @@ type
var
fd:Integer;
Handle:THandle;
function lseek (offset:Int64;whence:Integer):Int64; virtual;
function read (data:Pointer;size:Int64):Int64; virtual;
function pread (data:Pointer;size,offset:Int64):Int64; virtual;
function readv (vector:p_iovec;count:Integer):Int64; virtual;
function write (data:Pointer;size:Int64):Int64; virtual;
function pwrite(data:Pointer;size,offset:Int64):Int64; virtual;
function fstat (stat:PSceKernelStat):Integer; virtual;
function lseek (offset:Int64;whence:Integer):Int64; virtual;
function read (data:Pointer;size:Int64):Int64; virtual;
function pread (data:Pointer;size,offset:Int64):Int64; virtual;
function readv (vector:p_iovec;count:Integer):Int64; virtual;
function write (data:Pointer;size:Int64):Int64; virtual;
function pwrite(data:Pointer;size,offset:Int64):Int64; virtual;
function fstat (stat:PSceKernelStat):Integer; virtual;
function getdirentries(buf:Pointer;nbytes:Int64;basep:PInt64):Int64; virtual;
end;
function _sys_get_osfhandle(fd:Integer):THandle;
@ -251,6 +252,11 @@ begin
Result:=-ENOTSUP;
end;
function TCustomFile.getdirentries(buf:Pointer;nbytes:Int64;basep:PInt64):Int64;
begin
Result:=-EINVAL;
end;
//
function _sys_get_osfhandle(fd:Integer):THandle;

View File

@ -379,6 +379,9 @@ begin
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);