fpPS4/sys/sys_dir.pas

510 lines
9.7 KiB
ObjectPascal
Raw Normal View History

2022-11-11 21:02:45 +00:00
unit sys_dir;
{$mode ObjFPC}{$H+}
interface
uses
Windows,
Classes,
SysUtils,
RWLock,
sys_kernel,
sys_time,
2023-01-24 08:19:27 +00:00
sys_fd,
sys_path;
2022-11-11 21:02:45 +00:00
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;
a_dirent=array of dirent;
TDirFile=class(TCustomFile)
var
lock:TRWLock;
path:RawByteString;
dirs:a_dirent;
pos:DWORD;
Constructor Create;
Destructor Destroy; override;
2023-01-09 19:06:26 +00:00
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;
2023-01-09 19:06:26 +00:00
function ftruncate (size:Int64):Integer; 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;
2023-01-30 17:40:04 +00:00
procedure add_dir(const name:RawByteString);
2023-01-25 18:04:28 +00:00
end;
2023-01-30 17:40:04 +00:00
function _sys_dir_open(const path:RawByteString;flags,mode:Integer):Integer;
function _sys_dir_stat(Const path:RawByteString;stat:PSceKernelStat):Integer;
function _sys_root_open(const path:RawByteString;flags,mode:Integer):Integer;
function _sys_root_stat(Const path:RawByteString;stat:PSceKernelStat):Integer;
implementation
type
2023-01-25 18:04:28 +00:00
TDirFileRoot=class(TDirFile)
function fstat(stat:PSceKernelStat):Integer; override;
2022-11-11 21:02:45 +00:00
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;
2022-12-31 13:57:43 +00:00
procedure move_name(id:DWORD;d_type:Byte;f:RawByteString;buf:Pointer);
2022-11-11 21:02:45 +00:00
var
p:p_dirent;
len:ptruint;
begin
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);
2022-12-31 13:57:43 +00:00
p^.d_type :=d_type;
2022-11-11 21:02:45 +00:00
p^.d_namlen:=BYTE(len-1);
Move(PChar(f)^,p^.d_name,len);
end;
2022-12-31 13:57:43 +00:00
procedure move_dirent(id:DWORD;src:PWIN32FindDataW;buf:Pointer);
var
p:p_dirent;
f:RawByteString;
len:ptruint;
begin
f:=UTF8Encode(WideString(src^.cFileName));
move_name(id,get_d_type(src^.dwFileAttributes),f,buf);
end;
2022-11-11 21:02:45 +00:00
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);
2022-11-12 21:59:35 +00:00
ERROR_NO_MORE_FILES,
2022-11-11 21:02:45 +00:00
ERROR_FILE_NOT_FOUND :;
else
Exit(-EIO);
end;
end;
f:=TDirFile.Create;
f.path:=path;
2022-11-12 21:59:35 +00:00
if (h<>INVALID_HANDLE_VALUE) then
2022-11-11 21:02:45 +00:00
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);
2022-11-13 14:43:00 +00:00
i:=Length(f.dirs);
move_dirent(i,@data,@tmp);
2022-11-11 21:02:45 +00:00
i:=Length(f.dirs);
SetLength(f.dirs,i+1);
f.dirs[i]:=tmp;
end else
begin
err:=GetLastError;
Case err of
2022-11-12 21:59:35 +00:00
ERROR_NO_MORE_FILES,
2022-11-11 21:02:45 +00:00
ERROR_FILE_NOT_FOUND:
begin
Break;
end;
else
begin
Windows.FindClose(h);
f.Destroy;
Exit(-EIO);
end;
end;
end;
until false;
2022-11-12 21:59:35 +00:00
Windows.FindClose(h);
2022-11-11 21:02:45 +00:00
end;
2022-12-16 11:06:02 +00:00
Result:=_sys_open_fd(f,flags);
2022-11-11 21:02:45 +00:00
if (Result<0) then
begin
2022-11-12 21:59:35 +00:00
f.Destroy;
2022-11-11 21:02:45 +00:00
end else
begin
2022-11-12 21:59:35 +00:00
f.Release;
2022-11-11 21:02:45 +00:00
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;
//
2023-01-24 08:41:19 +00:00
function _sys_root_dir_open(const path:RawByteString;flags,mode:Integer):Integer;
2022-12-31 13:57:43 +00:00
var
2023-01-25 18:04:28 +00:00
f:TDirFileRoot;
2022-12-31 13:57:43 +00:00
begin
Result:=0;
2023-01-25 18:04:28 +00:00
f:=TDirFileRoot.Create;
2022-12-31 13:57:43 +00:00
f.path:=path;
SetLength(f.dirs,0);
2023-01-24 08:19:27 +00:00
ForEachRootDir(@f.add_dir);
2022-12-31 13:57:43 +00:00
Result:=_sys_open_fd(f,flags);
if (Result<0) then
begin
f.Destroy;
end else
begin
f.Release;
end;
end;
2023-01-30 17:40:04 +00:00
function _sys_root_open(const path:RawByteString;flags,mode:Integer):Integer;
begin
if (path='') then
begin
//root dir
Result:=_sys_root_dir_open(path,flags,mode);
end else
begin
//root file
Result:=-ENOENT;
end;
end;
2023-01-24 08:41:19 +00:00
function _sys_root_dir_stat(Const path:RawByteString;stat:PSceKernelStat):Integer;
2022-12-31 13:57:43 +00:00
begin
stat^:=Default(SceKernelStat);
stat^.st_mode :=S_IFDIR;
stat^.st_size :=1;
stat^.st_nlink :=1;
stat^.st_atim.tv_sec :=1;
stat^.st_mtim.tv_sec :=1;
stat^.st_ctim.tv_sec :=1;
stat^.st_birthtim.tv_sec:=1;
stat^.st_blocks :=0;
stat^.st_blksize :=SizeOf(dirent);
Result:=0;
end;
2023-01-30 17:40:04 +00:00
function _sys_root_stat(Const path:RawByteString;stat:PSceKernelStat):Integer;
begin
if (path='') then
begin
//root dir
Result:=_sys_root_dir_stat(path,stat);
end else
begin
//root file
Result:=ENOENT;
end;
end;
2022-12-31 13:57:43 +00:00
//
2022-11-11 21:02:45 +00:00
Constructor TDirFile.Create;
begin
pos:=0;
Handle:=INVALID_HANDLE_VALUE;
rwlock_init(lock);
dirs:=Default(a_dirent);
end;
2022-12-31 13:57:43 +00:00
Destructor TDirFile.Destroy;
2022-11-11 21:02:45 +00:00
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;
2023-01-09 19:06:26 +00:00
function TDirFile.preadv(vector:p_iovec;count:Integer;offset:Int64):Int64;
begin
Result:=-EISDIR;
end;
2022-11-11 21:02:45 +00:00
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.writev(vector:p_iovec;count:Integer):Int64;
begin
Result:=-EISDIR;
end;
2022-11-29 07:42:53 +00:00
function TDirFile.ftruncate(size:Int64):Integer;
begin
Result:=EISDIR;
end;
2022-11-11 21:02:45 +00:00
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
2022-11-16 08:22:22 +00:00
s,e,count:DWORD;
2022-11-11 21:02:45 +00:00
begin
count:=nbytes div SizeOf(dirent);
2022-11-16 08:22:22 +00:00
if (count=0) then Exit(-EINVAL);
2022-11-11 21:02:45 +00:00
rwlock_wrlock(lock);
2022-11-16 08:22:22 +00:00
s:=pos;
e:=s+count;
if (e>Length(dirs)) then
2022-11-11 21:02:45 +00:00
begin
2022-11-16 08:22:22 +00:00
e:=Length(dirs);
if (s>e) then
2022-11-11 21:02:45 +00:00
begin
count:=0;
end else
begin
2022-11-16 08:22:22 +00:00
count:=(e-s);
2022-11-11 21:02:45 +00:00
end;
end;
2022-11-16 08:22:22 +00:00
pos:=e;
2022-11-11 21:02:45 +00:00
rwlock_unlock(lock);
2022-11-16 08:22:22 +00:00
if (count<>0) then
begin
Move(dirs[s],buf^,count*SizeOf(dirent));
end;
Writeln('getdirentries:',count,' ',e);
2022-11-13 14:43:00 +00:00
2022-11-11 21:02:45 +00:00
if (basep<>nil) then
begin
2022-11-16 08:22:22 +00:00
basep^:=e;
2022-11-11 21:02:45 +00:00
end;
Result:=count*SizeOf(dirent);
end;
2023-01-30 17:40:04 +00:00
procedure TDirFile.add_dir(const name:RawByteString);
2023-01-24 08:19:27 +00:00
var
tmp:dirent;
i:Integer;
begin
tmp:=Default(dirent);
i:=Length(dirs);
move_name(i,DT_DIR,name,@tmp);
i:=Length(dirs);
SetLength(dirs,i+1);
dirs[i]:=tmp;
end;
2023-01-30 17:40:04 +00:00
function TDirFileRoot.fstat(stat:PSceKernelStat):Integer;
begin
Result:=_sys_root_dir_stat(path,stat);
if (Result=0) then
begin
stat^.st_dev :=fd;
stat^.st_rdev:=fd;
end;
end;
2022-11-11 21:02:45 +00:00
//
end.