unit sys_fd;

{$mode ObjFPC}{$H+}

interface

uses
 windows,
 Classes,
 SysUtils,
 ps4_handles,
 sys_types,
 sys_kernel;

const
 NAME_MAX  =255;  // max bytes in a file name
 PATH_MAX  =1024; // max bytes in pathname
 IOV_MAX   =1024; // max elements in i/o vector
 MAXNAMLEN =255;

 O_RDONLY  =$0000;  // open for reading only
 O_WRONLY  =$0001;  // open for writing only
 O_RDWR    =$0002;  // open for reading and writing
 O_ACCMODE =$0003;  // mask for above modes

 O_NONBLOCK =$0004;  // no delay
 O_APPEND   =$0008;  // set append mode
 O_SYNC     =$0080;  // POSIX synonym for O_FSYNC
 O_CREAT    =$0200;  // create if nonexistent
 O_TRUNC    =$0400;  // truncate to zero length
 O_EXCL     =$0800;  // error if already exists
 O_DSYNC    =$1000;  // synchronous data writes(omit inode writes)

 O_DIRECT   =$00010000;
 O_FSYNC    =$0080;  // synchronous writes

 O_DIRECTORY =$00020000; // Fail if not directory
 O_EXEC      =$00040000; // Open for execute only

 S_IRWXU  =&0000700;   // RWX mask for owner
 S_IRUSR  =&0000400;   // R for owner
 S_IWUSR  =&0000200;   // W for owner
 S_IXUSR  =&0000100;   // X for owner

 S_IRWXG  =&0000070;   // RWX mask for group
 S_IRGRP  =&0000040;   // R for group
 S_IWGRP  =&0000020;   // W for group
 S_IXGRP  =&0000010;   // X for group

 S_IRWXO  =&0000007;   // RWX mask for other
 S_IROTH  =&0000004;   // R for other
 S_IWOTH  =&0000002;   // W for other
 S_IXOTH  =&0000001;   // X for other

 S_IFMT   =&0170000; // type of file mask
 S_IFIFO  =&0010000; // named pipe (fifo)
 S_IFCHR  =&0020000; // character special
 S_IFDIR  =&0040000; // directory
 S_IFBLK  =&0060000; // block special
 S_IFREG  =&0100000; // regular
 S_IFLNK  =&0120000; // symbolic link
 S_IFSOCK =&0140000; // socket
 S_ISVTX  =&0001000; // save swapped text even after use

 F_GETFL  =3;  // get file status flags
 F_SETFL  =4;  // set file status flags

 SEEK_SET =0; // set file offset to offset
 SEEK_CUR =1; // set file offset to current plus offset
 SEEK_END =2; // set file offset to EOF plus offset

 MAP_SHARED  =$0001;  // share changes
 MAP_PRIVATE =$0002;  // changes are private

 MAP_FILE   =$0000; // map from file (default)
 MAP_ANON   =$1000; // allocated from memory, swap space
 MAP_SYSTEM =$2000;

 MAP_NOCORE  =$00020000; // dont include these pages in a coredump
 MAP_NOSYNC  =$0800; // page to but do not sync underlying file
 MAP_PREFAULT_READ =$00040000; // prefault mapping for reading

 DT_UNKNOWN =0;
 DT_DIR     =4;
 DT_REG     =8;

 SCE_KERNEL_NAME_MAX        =NAME_MAX;
 SCE_KERNEL_PATH_MAX        =PATH_MAX;
 SCE_KERNEL_IOV_MAX         =IOV_MAX;
 SCE_KERNEL_MAXNAMLEN       =MAXNAMLEN;

 SCE_KERNEL_O_RDONLY        =O_RDONLY;
 SCE_KERNEL_O_WRONLY        =O_WRONLY;
 SCE_KERNEL_O_RDWR          =O_RDWR ;
 SCE_KERNEL_O_NONBLOCK      =O_NONBLOCK;
 SCE_KERNEL_O_APPEND        =O_APPEND;
 SCE_KERNEL_O_CREAT         =O_CREAT;
 SCE_KERNEL_O_TRUNC         =O_TRUNC;
 SCE_KERNEL_O_EXCL          =O_EXCL;
 SCE_KERNEL_O_DIRECT        =O_DIRECT;
 SCE_KERNEL_O_FSYNC         =O_FSYNC;
 SCE_KERNEL_O_SYNC          =O_SYNC;
 SCE_KERNEL_O_DSYNC         =O_DSYNC;
 SCE_KERNEL_O_DIRECTORY     =O_DIRECTORY;

 SCE_KERNEL_S_IFMT          =S_IFMT;
 SCE_KERNEL_S_IFDIR         =S_IFDIR;
 SCE_KERNEL_S_IFREG         =S_IFREG;

 SCE_KERNEL_S_IRUSR         =(S_IRUSR or S_IRGRP or S_IROTH or S_IXUSR or S_IXGRP or S_IXOTH);
 SCE_KERNEL_S_IWUSR         =(S_IWUSR or S_IWGRP or S_IWOTH or S_IXUSR or S_IXGRP or S_IXOTH);
 SCE_KERNEL_S_IXUSR         =(S_IXUSR or S_IXGRP or S_IXOTH);
 SCE_KERNEL_S_IRWXU         =(SCE_KERNEL_S_IRUSR or SCE_KERNEL_S_IWUSR);

 SCE_KERNEL_S_IRWU          =(SCE_KERNEL_S_IRUSR or SCE_KERNEL_S_IWUSR);
// 00777, R/W
 SCE_KERNEL_S_IRU           =(SCE_KERNEL_S_IRUSR);
// 00555, R

 SCE_KERNEL_S_INONE         =&0000000;

 //SCE_KERNEL_S_ISDIR(m)      =S_ISDIR(m);
 //SCE_KERNEL_S_ISREG(m)      =S_ISREG(m);

// for sceKernelFcntl()
 SCE_KERNEL_F_GETFL         =F_GETFL;
 SCE_KERNEL_F_SETFL         =F_SETFL;

// for sceKernelLseek()
 SCE_KERNEL_SEEK_SET        =SEEK_SET;
 SCE_KERNEL_SEEK_CUR        =SEEK_CUR;
 SCE_KERNEL_SEEK_END        =SEEK_END;

// for sceKernelMmap()
 SCE_KERNEL_MAP_NOCORE      =MAP_NOCORE;
 SCE_KERNEL_MAP_NOSYNC      =MAP_NOSYNC;
 SCE_KERNEL_MAP_PREFAULT_READ=MAP_PREFAULT_READ;
 SCE_KERNEL_MAP_PRIVATE     =MAP_PRIVATE;
 SCE_KERNEL_MAP_SHARED      =MAP_SHARED;

// for SceKernelDirent
 SCE_KERNEL_DT_UNKNOWN      =DT_UNKNOWN;
 SCE_KERNEL_DT_DIR          =DT_DIR;
 SCE_KERNEL_DT_REG          =DT_REG;

// for sceKernelSetCompress
 SCE_KERNEL_COMPRESS_FILE_MAGIC =($43534650);
 SCE_KERNEL_SET_COMPRESS_FILE   =(1);
 SCE_KERNEL_SET_REGULAR_FILE    =(0);

// for sceKernelLwfsSetAttribute
 SCE_KERNEL_LWFS_DISABLE =(0);
 SCE_KERNEL_LWFS_ENABLE  =(1);

 //fcntl
 O_FL_STATUS=O_NONBLOCK or O_APPEND or O_DIRECT {or O_ASYNC} or O_SYNC or O_DSYNC;

type
 p_iovec=^iovec;
 iovec=packed record
  iov_base:Pointer; //Base address.
  iov_len :Int64;   //Length.
 end;

 PSceKernelStat=^SceKernelStat;
 SceKernelStat=packed object
  type
   __dev_t  =DWORD;
   ino_t    =DWORD;
   mode_t   =Word;
   nlink_t  =Word;
   uid_t    =DWORD;
   gid_t    =DWORD;
   off_t    =Int64;
   blkcnt_t =Int64;
   blksize_t=DWORD;
   fflags_t =DWORD;
  var
   st_dev     :__dev_t   ;      // inode's device
   st_ino     :ino_t     ;      // inode's number
   st_mode    :mode_t    ;      // inode protection mode         S_IFMT.....
   st_nlink   :nlink_t   ;      // number of hard links
   st_uid     :uid_t     ;      // user ID of the file's owner   S_IRWXU....
   st_gid     :gid_t     ;      // group ID of the file's group  S_IRWXG....
   st_rdev    :__dev_t   ;      // device type
   st_atim    :timespec  ;      // time of last access
   st_mtim    :timespec  ;      // time of last data modification
   st_ctim    :timespec  ;      // time of last file status change
   st_size    :off_t     ;      // file size, in bytes
   st_blocks  :blkcnt_t  ;      // blocks allocated for file
   st_blksize :blksize_t ;      // optimal blocksize for I/O
   st_flags   :fflags_t  ;      // user defined flags for file
   st_gen     :DWORD     ;      // file generation number
   st_lspare  :DWORD     ;
   st_birthtim:timespec  ;      // time of file creation
 end;

 TCustomFile=class(TClassHandle)
  var
   fd:Integer;
   status: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 preadv       (vector:p_iovec;count:Integer;offset:Int64):Int64; virtual;
  function write        (data:Pointer;size:Int64):Int64;                   virtual;
  function pwrite       (data:Pointer;size,offset:Int64):Int64;            virtual;
  function writev       (vector:p_iovec;count:Integer):Int64;              virtual;
  function ftruncate    (size:Int64):Integer;                              virtual;
  function fstat        (stat:PSceKernelStat):Integer;                     virtual;
  function fsync        ():Integer;                                        virtual;
  function fcntl        (cmd:Integer;param1:ptruint):Integer;              virtual;
  function ioctl        (cmd:Integer;param1:ptruint):Integer;              virtual;
  function getdirentries(buf:Pointer;nbytes:Int64;basep:PInt64):Int64;     virtual;
 end;

function _sys_get_osfhandle(fd:Integer):THandle;
function _sys_open_fd(f:TCustomFile;flags:Integer):Integer;
function _sys_acqure_fd(fd:Integer):TCustomFile;
function _sys_close(fd:Integer):Integer;
function _sys_lseek(fd:Integer;offset:Int64;whence:Integer):Int64;
function _sys_read(fd:Integer;data:Pointer;size:Int64):Int64;
function _sys_pread(fd:Integer;data:Pointer;size,offset:Int64):Int64;
function _sys_readv(fd:Integer;vector:p_iovec;count:Integer):Int64;
function _sys_preadv(fd:Integer;vector:p_iovec;count:Integer;offset:Int64):Int64;
function _sys_write(fd:Integer;data:Pointer;size:Int64):Int64;
function _sys_writev(fd:Integer;vector:p_iovec;count:Integer):Int64;
function _sys_pwrite(fd:Integer;data:Pointer;size,offset:Int64):Int64;
function _sys_ftruncate(fd:Integer;size:Int64):Integer;
function _sys_fstat(fd:Integer;stat:PSceKernelStat):Integer;
function _sys_getdirentries(fd:Integer;buf:Pointer;nbytes:Int64;basep:PInt64):Int64;
function _sys_fsync(fd:Integer):Integer;
function _sys_fcntl(fd,cmd:Integer;param1:ptruint):Integer;
function _sys_ioctl(fd,cmd:Integer;param1:ptruint):Integer;

implementation

var
 FileHandles:TIntegerHandles;

//

function TCustomFile.lseek (offset:Int64;whence:Integer):Int64;
begin
 Result:=-ENOTSUP;
end;

function TCustomFile.read  (data:Pointer;size:Int64):Int64;
begin
 Result:=-ENOTSUP;
end;

function TCustomFile.pread (data:Pointer;size,offset:Int64):Int64;
begin
 Result:=-ENOTSUP;
end;

function TCustomFile.readv (vector:p_iovec;count:Integer):Int64;
begin
 Result:=-ENOTSUP;
end;

function TCustomFile.preadv(vector:p_iovec;count:Integer;offset:Int64):Int64;
begin
 Result:=-ENOTSUP;
end;

function TCustomFile.write (data:Pointer;size:Int64):Int64;
begin
 Result:=-ENOTSUP;
end;

function TCustomFile.pwrite(data:Pointer;size,offset:Int64):Int64;
begin
 Result:=-ENOTSUP;
end;

function TCustomFile.writev(vector:p_iovec;count:Integer):Int64;
begin
 Result:=-ENOTSUP;
end;

function TCustomFile.ftruncate(size:Int64):Integer;
begin
 Result:=ENOTSUP;
end;

function TCustomFile.fstat (stat:PSceKernelStat):Integer;
begin
 Result:=ENOTSUP;
end;

function TCustomFile.fsync:Integer;
begin
 Result:=EINVAL;
end;

function TCustomFile.fcntl(cmd:Integer;param1:ptruint):Integer;
begin
 Case cmd of
  F_GETFL:
   begin
    Result:=status;
   end;
  F_SETFL:
   begin
    status:=Integer(param1) and O_FL_STATUS;
   end;
  else
   begin
    Assert(false,'fcntl:'+IntToStr(cmd));
    Exit(EINVAL);
   end;
 end;
end;

function TCustomFile.ioctl(cmd:Integer;param1:ptruint):Integer;
begin
 Result:=ENOTTY;
end;

function TCustomFile.getdirentries(buf:Pointer;nbytes:Int64;basep:PInt64):Int64;
begin
 Result:=-EINVAL;
end;

//

function _sys_get_osfhandle(fd:Integer):THandle;
var
 f:TCustomFile;
begin
 Result:=INVALID_HANDLE_VALUE;
 f:=TCustomFile(FileHandles.Acqure(fd));
 if (f<>nil) then
 begin
  Result:=f.Handle;
  f.Release;
 end;
end;

function _sys_open_fd(f:TCustomFile;flags:Integer):Integer;
begin
 if (f=nil) then Exit(-EINVAL);
 if FileHandles.New(f,Result) then
 begin
  f.fd:=Result;
  f.status:=flags and O_FL_STATUS;
 end else
 begin
  Result:=-EMFILE;
 end;
end;

function _sys_acqure_fd(fd:Integer):TCustomFile;
begin
 Result:=TCustomFile(FileHandles.Acqure(fd));
end;

function _sys_close(fd:Integer):Integer;
begin
 Result:=0;
 if (fd<0) then Exit(EINVAL);
 if not FileHandles.Delete(fd) then Exit(EBADF);
end;

function _sys_lseek(fd:Integer;offset:Int64;whence:Integer):Int64;
var
 f:TCustomFile;
begin
 Result:=0;
 if (fd<0) then Exit(-EINVAL);

 case whence of
  SEEK_SET,
  SEEK_CUR,
  SEEK_END:;
  else
   Exit(-EINVAL);
 end;

 f:=_sys_acqure_fd(fd);
 if (f=nil) then Exit(-EBADF);

 Result:=f.lseek(offset,whence);

 f.Release;
end;

function _sys_read(fd:Integer;data:Pointer;size:Int64):Int64;
var
 f:TCustomFile;
begin
 if (fd<0) then Exit(-EINVAL);

 if (data=nil) or (size=0) then //zero check
 begin
  f:=_sys_acqure_fd(fd);
  if (f=nil) then Exit(-EBADF);
  f.Release;
  Exit(0);
 end;

 if (size<=0) then Exit(-EINVAL);

 f:=_sys_acqure_fd(fd);
 if (f=nil) then Exit(-EBADF);

 Result:=f.read(data,size);

 f.Release;
end;

function _sys_pread(fd:Integer;data:Pointer;size,offset:Int64):Int64;
var
 f:TCustomFile;
begin
 if (fd<0) then Exit(-EINVAL);

 if (data=nil) or (size=0) then //zero check
 begin
  f:=_sys_acqure_fd(fd);
  if (f=nil) then Exit(-EBADF);
  f.Release;
  Exit(0);
 end;

 if (size<=0) then Exit(-EINVAL);
 if (offset<0) then Exit(-EINVAL);

 f:=_sys_acqure_fd(fd);
 if (f=nil) then Exit(-EBADF);

 Result:=f.pread(data,size,offset);

 f.Release;
end;

function _sys_readv(fd:Integer;vector:p_iovec;count:Integer):Int64;
var
 f:TCustomFile;
begin
 if (fd<0) then Exit(-EINVAL);

 if (vector=nil) or (count=0) then //zero check
 begin
  f:=_sys_acqure_fd(fd);
  if (f=nil) then Exit(-EBADF);
  f.Release;
  Exit(0);
 end;

 if (count<=0) or (count>IOV_MAX) then Exit(-EINVAL);

 f:=_sys_acqure_fd(fd);
 if (f=nil) then Exit(-EBADF);

 Result:=f.readv(vector,count);

 f.Release;
end;

function _sys_preadv(fd:Integer;vector:p_iovec;count:Integer;offset:Int64):Int64;
var
 f:TCustomFile;
begin
 if (fd<0) then Exit(-EINVAL);

 if (vector=nil) or (count=0) then //zero check
 begin
  f:=_sys_acqure_fd(fd);
  if (f=nil) then Exit(-EBADF);
  f.Release;
  Exit(0);
 end;

 if (count<=0) or (count>IOV_MAX) then Exit(-EINVAL);

 f:=_sys_acqure_fd(fd);
 if (f=nil) then Exit(-EBADF);

 Result:=f.preadv(vector,count,offset);

 f.Release;
end;

function _sys_write(fd:Integer;data:Pointer;size:Int64):Int64;
var
 f:TCustomFile;
begin
 if (fd<0) then Exit(-EINVAL);

 if (data=nil) or (size=0) then //zero check
 begin
  f:=_sys_acqure_fd(fd);
  if (f=nil) then Exit(-EBADF);
  f.Release;
  Exit(0);
 end;

 if (size<=0) then Exit(-EINVAL);

 f:=_sys_acqure_fd(fd);
 if (f=nil) then Exit(-EBADF);

 Result:=f.write(data,size);

 f.Release;
end;

function _sys_pwrite(fd:Integer;data:Pointer;size,offset:Int64):Int64;
var
 f:TCustomFile;
begin
 if (fd<0) then Exit(-EINVAL);

 if (data=nil) or (size=0) then //zero check
 begin
  f:=_sys_acqure_fd(fd);
  if (f=nil) then Exit(-EBADF);
  f.Release;
  Exit(0);
 end;

 if (size<=0) then Exit(-EINVAL);
 if (offset<0) then Exit(-EINVAL);

 f:=_sys_acqure_fd(fd);
 if (f=nil) then Exit(-EBADF);

 Result:=f.pwrite(data,size,offset);

 f.Release;
end;

function _sys_writev(fd:Integer;vector:p_iovec;count:Integer):Int64;
var
 f:TCustomFile;
begin
 if (fd<0) then Exit(-EINVAL);

 if (vector=nil) or (count=0) then //zero check
 begin
  f:=_sys_acqure_fd(fd);
  if (f=nil) then Exit(-EBADF);
  f.Release;
  Exit(0);
 end;

 if (count<=0) or (count>IOV_MAX) then Exit(-EINVAL);

 f:=_sys_acqure_fd(fd);
 if (f=nil) then Exit(-EBADF);

 Result:=f.writev(vector,count);

 f.Release;
end;

function _sys_ftruncate(fd:Integer;size:Int64):Integer;
var
 f:TCustomFile;
begin
 if (fd<0) then Exit(EINVAL);
 if (size<=0) then Exit(EINVAL);

 f:=_sys_acqure_fd(fd);
 if (f=nil) then Exit(EBADF);

 Result:=f.ftruncate(size);

 f.Release;
end;

function _sys_fstat(fd:Integer;stat:PSceKernelStat):Integer;
var
 f:TCustomFile;
begin
 if (fd<0) then Exit(EINVAL);
 if (stat=nil) then Exit(EINVAL);

 f:=_sys_acqure_fd(fd);
 if (f=nil) then Exit(EBADF);

 Result:=f.fstat(stat);

 f.Release;
end;

function _sys_getdirentries(fd:Integer;buf:Pointer;nbytes:Int64;basep:PInt64):Int64;
var
 f:TCustomFile;
begin
 if (fd<0) then Exit(-EINVAL);
 if (buf=nil) then Exit(-EFAULT);
 if (nbytes<=0) then Exit(-EINVAL);

 f:=_sys_acqure_fd(fd);
 if (f=nil) then Exit(-EBADF);

 Result:=f.getdirentries(buf,nbytes,basep);

 f.Release;
end;

function _sys_fsync(fd:Integer):Integer;
var
 f:TCustomFile;
begin
 if (fd<0) then Exit(EINVAL);

 f:=_sys_acqure_fd(fd);
 if (f=nil) then Exit(EBADF);

 Result:=f.fsync;

 f.Release;
end;

function _sys_fcntl(fd,cmd:Integer;param1:ptruint):Integer;
var
 f:TCustomFile;
begin
 if (fd<0) then Exit(EINVAL);

 f:=_sys_acqure_fd(fd);
 if (f=nil) then Exit(EBADF);

 Result:=f.fcntl(cmd,param1);

 f.Release;
end;

function _sys_ioctl(fd,cmd:Integer;param1:ptruint):Integer;
var
 f:TCustomFile;
begin
 if (fd<0) then Exit(EINVAL);

 f:=_sys_acqure_fd(fd);
 if (f=nil) then Exit(EBADF);

 Result:=f.ioctl(cmd,param1);

 f.Release;
end;

//

initialization
 FileHandles:=TIntegerHandles.Create(0);

end.

