unit sys_dir; {$mode ObjFPC}{$H+} interface uses Windows, Classes, SysUtils, RWLock, sys_kernel, sys_time, sys_fd, sys_path; 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; 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 lseek (offset:Int64;whence:Integer):Int64; override; function getdirentries(buf:Pointer;nbytes:Int64;basep:PInt64):Int64; override; procedure add_dir(const name:RawByteString); end; 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 TDirFileRoot=class(TDirFile) function fstat(stat:PSceKernelStat):Integer; 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_name(id:DWORD;d_type:Byte;f:RawByteString;buf:Pointer); 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); p^.d_type :=d_type; p^.d_namlen:=BYTE(len-1); Move(PChar(f)^,p^.d_name,len); end; 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; 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_NO_MORE_FILES, ERROR_FILE_NOT_FOUND :; else Exit(-EIO); end; end; f:=TDirFile.Create; f.path:=path; if (h<>INVALID_HANDLE_VALUE) 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); i:=Length(f.dirs); move_dirent(i,@data,@tmp); i:=Length(f.dirs); SetLength(f.dirs,i+1); f.dirs[i]:=tmp; end else begin err:=GetLastError; Case err of ERROR_NO_MORE_FILES, ERROR_FILE_NOT_FOUND: begin Break; end; else begin Windows.FindClose(h); f.Destroy; Exit(-EIO); end; end; end; until false; Windows.FindClose(h); end; Result:=_sys_open_fd(f,flags); if (Result<0) then begin f.Destroy; end else begin f.Release; 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; // function _sys_root_dir_open(const path:RawByteString;flags,mode:Integer):Integer; var f:TDirFileRoot; begin Result:=0; f:=TDirFileRoot.Create; f.path:=path; SetLength(f.dirs,0); ForEachRootDir(@f.add_dir); Result:=_sys_open_fd(f,flags); if (Result<0) then begin f.Destroy; end else begin f.Release; end; end; 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; function _sys_root_dir_stat(Const path:RawByteString;stat:PSceKernelStat):Integer; 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; 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; // 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.preadv(vector:p_iovec;count:Integer;offset:Int64):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.writev(vector:p_iovec;count:Integer):Int64; begin Result:=-EISDIR; end; function TDirFile.ftruncate(size:Int64):Integer; 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 s,e,count:DWORD; begin count:=nbytes div SizeOf(dirent); if (count=0) then Exit(-EINVAL); rwlock_wrlock(lock); s:=pos; e:=s+count; if (e>Length(dirs)) then begin e:=Length(dirs); if (s>e) then begin count:=0; end else begin count:=(e-s); end; end; pos:=e; rwlock_unlock(lock); if (count<>0) then begin Move(dirs[s],buf^,count*SizeOf(dirent)); end; Writeln('getdirentries:',count,' ',e); if (basep<>nil) then begin basep^:=e; end; Result:=count*SizeOf(dirent); end; procedure TDirFile.add_dir(const name:RawByteString); 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; 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; // end.