소스 검색

* moved the FindFirst/FindNext/FindClose code from unit DOS to WasiUtil, using
RawByteString. This will allow to reuse the same implementation in SysUtils.

Nikolay Nikolov 3 년 전
부모
커밋
090cc8fa8f
2개의 변경된 파일345개의 추가작업 그리고 251개의 파일을 삭제
  1. 51 251
      rtl/wasi/dos.pp
  2. 294 0
      rtl/wasi/wasiutil.pp

+ 51 - 251
rtl/wasi/dos.pp

@@ -375,275 +375,75 @@ end;
 ******************************************************************************}
 
 
-Const
-  RtlFindSize = 15;
-Type
-  RtlFindRecType = Record
-    DirFD    : LongInt;
-    SearchNum,
-    LastUsed : LongInt;
-  End;
-Var
-  RtlFindRecs   : Array[1..RtlFindSize] of RtlFindRecType;
-  CurrSearchNum : LongInt;
-
-
-Procedure FindClose(Var f: SearchRec);
-{
-  Closes dirfd if it is open
-}
-Var
-  res: __wasi_errno_t;
-  i : longint;
-Begin
-  if f.SearchType=0 then
-   begin
-     i:=1;
-     repeat
-       if (RtlFindRecs[i].SearchNum=f.SearchNum) then
-        break;
-       inc(i);
-     until (i>RtlFindSize);
-     If i<=RtlFindSize Then
-      Begin
-        RtlFindRecs[i].SearchNum:=0;
-        if f.dirfd<>-1 then
-          repeat
-            res:=__wasi_fd_close(f.dirfd);
-          until (res=__WASI_ERRNO_SUCCESS) or (res<>__WASI_ERRNO_INTR);
-      End;
-   end;
-  f.dirfd:=-1;
-End;
+procedure SearchRec2WasiSearchRec(const i: SearchRec; var o: TWasiSearchRec);
+var
+  DT: DateTime;
+begin
+  FillChar(o,SizeOf(o),0);
+  o.SearchPos:=i.SearchPos;
+  o.SearchNum:=i.SearchNum;
+  o.DirFD:=i.DirFD;
+  o.SearchType:=i.SearchType;
+  o.SearchAttr:=i.SearchAttr;
+  o.Mode:=i.Mode;
+  o.Attr:=i.Attr;
+  UnpackTime(i.Time,DT);
+  o.Time:=DTToWasiDate(DT);
+  o.Size:=i.Size;
+  o.Name:=i.Name;
+  o.SearchSpec:=i.SearchSpec;
+  o.NamePos:=i.NamePos;
+end;
 
 
-Function FindGetFileInfo(const s:string;var f:SearchRec):boolean;
+procedure WasiSearchRec2SearchRec(const i: TWasiSearchRec; var o: SearchRec);
 var
-  DT   : DateTime;
-  st   : __wasi_filestat_t;
-  fd   : __wasi_fd_t;
-  pr   : RawByteString;
-  Info : record
-    FMode: LongInt;
-    FSize: __wasi_filesize_t;
-    FMTime: __wasi_timestamp_t;
-  end;
+  DT: DateTime;
 begin
-  FindGetFileInfo:=false;
-  if ConvertToFdRelativePath(s,fd,pr)<>0 then
-    exit;
-  { todo: __WASI_LOOKUPFLAGS_SYMLINK_FOLLOW??? }
-  if __wasi_path_filestat_get(fd,0,PChar(pr),Length(pr),@st)<>__WASI_ERRNO_SUCCESS then
-    exit;
-  info.FSize:=st.size;
-  info.FMTime:=st.mtim;
-  if st.filetype=__WASI_FILETYPE_DIRECTORY then
-   info.fmode:=$10
-  else
-   info.fmode:=$0;
-  {if (st.st_mode and STAT_IWUSR)=0 then
-   info.fmode:=info.fmode or 1;}
-  if s[f.NamePos+1]='.' then
-   info.fmode:=info.fmode or $2;
-
-  If ((Info.FMode and Not(f.searchattr))=0) Then
-   Begin
-     f.Name:=Copy(s,f.NamePos+1,255);
-     f.Attr:=Info.FMode;
-     f.Size:=Info.FSize;
-     {f.mode:=st.st_mode;}
-     WasiDateToDT(Info.FMTime, DT);
-     PackTime(DT,f.Time);
-     FindGetFileInfo:=true;
-   End;
+  FillChar(o,SizeOf(o),0);
+  o.SearchPos:=i.SearchPos;
+  o.SearchNum:=i.SearchNum;
+  o.DirFD:=i.DirFD;
+  o.SearchType:=i.SearchType;
+  o.SearchAttr:=i.SearchAttr;
+  o.Mode:=i.Mode;
+  o.Attr:=i.Attr;
+  WasiDateToDt(i.Time,DT);
+  PackTime(DT,o.Time);
+  o.Size:=i.Size;
+  o.Name:=i.Name;
+  o.SearchSpec:=i.SearchSpec;
+  o.NamePos:=i.NamePos;
 end;
 
 
-Function  FindLastUsed: Longint;
-{
-  Find unused or least recently used dirpointer slot in findrecs array
-}
-Var
-  BestMatch,i : Longint;
-  Found       : Boolean;
+Procedure FindClose(Var f: SearchRec);
+var
+  wf: TWasiSearchRec;
 Begin
-  BestMatch:=1;
-  i:=1;
-  Found:=False;
-  While (i <= RtlFindSize) And (Not Found) Do
-   Begin
-     If (RtlFindRecs[i].SearchNum = 0) Then
-      Begin
-        BestMatch := i;
-        Found := True;
-      End
-     Else
-      Begin
-        If RtlFindRecs[i].LastUsed > RtlFindRecs[BestMatch].LastUsed Then
-         BestMatch := i;
-      End;
-     Inc(i);
-   End;
-  FindLastUsed := BestMatch;
+  SearchRec2WasiSearchRec(f,wf);
+  WasiFindClose(wf);
+  WasiSearchRec2SearchRec(wf,f);
 End;
 
 
-
 Procedure FindNext(Var f: SearchRec);
-{
-  re-opens dir if not already in array and calls FindWorkProc
-}
-Var
-  fd,ourfd: __wasi_fd_t;
-  pr: RawByteString;
-  res: __wasi_errno_t;
-  DirName  : RawByteString;
-  i,
-  ArrayPos : Longint;
-  FName,
-  SName    : string;
-  Found,
-  Finished : boolean;
-  Buf: array [0..SizeOf(__wasi_dirent_t)+256-1] of Byte;
-  BufUsed: __wasi_size_t;
+var
+  wf: TWasiSearchRec;
 Begin
-  If f.SearchType=0 Then
-   Begin
-     ArrayPos:=0;
-     For i:=1 to RtlFindSize Do
-      Begin
-        If RtlFindRecs[i].SearchNum = f.SearchNum Then
-         ArrayPos:=i;
-        Inc(RtlFindRecs[i].LastUsed);
-      End;
-     If ArrayPos=0 Then
-      Begin
-        If f.NamePos = 0 Then
-         DirName:='./'
-        Else
-         DirName:=Copy(f.SearchSpec,1,f.NamePos);
-        if ConvertToFdRelativePath(DirName,fd,pr)=0 then
-         begin
-           repeat
-             res:=__wasi_path_open(fd,
-                                   0,
-                                   PChar(pr),
-                                   length(pr),
-                                   __WASI_OFLAGS_DIRECTORY,
-                                   __WASI_RIGHTS_FD_READDIR,
-                                   __WASI_RIGHTS_FD_READDIR,
-                                   0,
-                                   @ourfd);
-           until (res=__WASI_ERRNO_SUCCESS) or (res<>__WASI_ERRNO_INTR);
-           If res=__WASI_ERRNO_SUCCESS Then
-            begin
-              f.DirFD := ourfd;
-              ArrayPos:=FindLastUsed;
-              If RtlFindRecs[ArrayPos].SearchNum > 0 Then
-                repeat
-                  res:=__wasi_fd_close(RtlFindRecs[arraypos].DirFD);
-                until (res=__WASI_ERRNO_SUCCESS) or (res<>__WASI_ERRNO_INTR);
-              RtlFindRecs[ArrayPos].SearchNum := f.SearchNum;
-              RtlFindRecs[ArrayPos].DirFD := f.DirFD;
-            end
-           else
-            f.DirFD:=-1;
-         end
-        else
-         f.DirFD:=-1;
-      End;
-     if ArrayPos>0 then
-       RtlFindRecs[ArrayPos].LastUsed:=0;
-   end;
-{Main loop}
-  SName:=Copy(f.SearchSpec,f.NamePos+1,255);
-  Found:=False;
-  Finished:=(f.DirFD=-1);
-  While Not Finished Do
-   Begin
-     res:=__wasi_fd_readdir(f.DirFD,
-                            @buf,
-                            SizeOf(buf),
-                            f.searchpos,
-                            @bufused);
-     if (res<>__WASI_ERRNO_SUCCESS) or (bufused<=SizeOf(__wasi_dirent_t)) then
-      FName:=''
-     else
-      begin
-        if P__wasi_dirent_t(@buf)^.d_namlen<=255 then
-          SetLength(FName,P__wasi_dirent_t(@buf)^.d_namlen)
-        else
-          SetLength(FName,255);
-        Move(buf[SizeOf(__wasi_dirent_t)],FName[1],Length(FName));
-        f.searchpos:=P__wasi_dirent_t(@buf)^.d_next;
-      end;
-     If FName='' Then
-      Finished:=True
-     Else
-      Begin
-        If FNMatch(SName,FName) Then
-         Begin
-           Found:=FindGetFileInfo(Copy(f.SearchSpec,1,f.NamePos)+FName,f);
-           if Found then
-            Finished:=true;
-         End;
-      End;
-   End;
-{Shutdown}
-  If Found Then
-   DosError:=0
-  Else
-   Begin
-     FindClose(f);
-     DosError:=18;
-   End;
+  SearchRec2WasiSearchRec(f,wf);
+  doserror:=WasiFindNext(wf);
+  WasiSearchRec2SearchRec(wf,f);
 End;
 
 
 Procedure FindFirst(Const Path: PathStr; Attr: Word; Var f: SearchRec);
-{
-  opens dir and calls FindWorkProc
-}
+var
+  wf: TWasiSearchRec;
 Begin
-  fillchar(f,sizeof(f),0);
-  if Path='' then
-   begin
-     DosError:=3;
-     exit;
-   end;
-{Create Info}
-  f.SearchSpec := Path;
-  {We always also search for readonly and archive, regardless of Attr:}
-  f.SearchAttr := Attr or archive or readonly;
-  f.SearchPos  := 0;
-  f.NamePos := Length(f.SearchSpec);
-  while (f.NamePos>0) and not (f.SearchSpec[f.NamePos] in AllowDirectorySeparators) do
-   dec(f.NamePos);
-{Wildcards?}
-  if (Pos('?',Path)=0)  and (Pos('*',Path)=0) then
-   begin
-     if FindGetFileInfo(Path,f) then
-      DosError:=0
-     else
-      begin
-        { According to tdos2 test it should return 18
-        if ErrNo=Sys_ENOENT then
-         DosError:=3
-        else }
-         DosError:=18;
-      end;
-     f.DirFD:=-1;
-     f.SearchType:=1;
-     f.searchnum:=-1;
-   end
-  else
-{Find Entry}
-   begin
-     Inc(CurrSearchNum);
-     f.SearchNum:=CurrSearchNum;
-     f.SearchType:=0;
-     FindNext(f);
-   end;
+  SearchRec2WasiSearchRec(f,wf);
+  doserror:=WasiFindFirst(Path,Attr,wf);
+  WasiSearchRec2SearchRec(wf,f);
 End;
 
 

+ 294 - 0
rtl/wasi/wasiutil.pp

@@ -22,12 +22,54 @@ interface
 uses
   wasiapi;
 
+type
+  PWasiSearchRec = ^TWasiSearchRec;
+  TWasiSearchRec = record
+    SearchPos  : UInt64;             {directory position}
+    SearchNum  : LongInt;            {to track which search this is}
+    DirFD      : __wasi_fd_t;        {directory fd handle for reading directory}
+    SearchType : Byte;               {0=normal, 1=open will close, 2=only 1 file}
+    SearchAttr : Byte;               {attribute we are searching for}
+    Mode       : Word;
+    Attr       : Byte;               {attribute of found file}
+    Time       : __wasi_timestamp_t; {last modify date of found file}
+    Size       : __wasi_filesize_t;  {file size of found file}
+    Name       : RawByteString;      {name of found file}
+    SearchSpec : RawByteString;      {search pattern}
+    NamePos    : Word;               {end of path, start of name position}
+  End;
+
 function ConvertToFdRelativePath(path: RawByteString; out fd: LongInt; out relfd_path: RawByteString): Word; external name 'FPC_WASI_CONVERTTOFDRELATIVEPATH';
 function fpc_wasi_path_readlink_ansistring(fd: __wasi_fd_t; const path: PChar; path_len: size_t; out link: rawbytestring): __wasi_errno_t; external name 'FPC_WASI_PATH_READLINK_ANSISTRING';
 function FNMatch(const Pattern,Name:rawbytestring):Boolean;
+function WasiFindFirst(const Path: RawByteString; Attr: Word; var f: TWasiSearchRec): longint;
+function WasiFindNext(var f: TWasiSearchRec): longint;
+procedure WasiFindClose(var f: TWasiSearchRec);
 
 implementation
 
+const
+  {Bitmasks for file attribute}
+  readonly  = $01;
+  hidden    = $02;
+  sysfile   = $04;
+  volumeid  = $08;
+  directory = $10;
+  archive   = $20;
+  anyfile   = $3F;
+
+Const
+  RtlFindSize = 15;
+Type
+  RtlFindRecType = Record
+    DirFD    : LongInt;
+    SearchNum,
+    LastUsed : LongInt;
+  End;
+Var
+  RtlFindRecs   : Array[1..RtlFindSize] of RtlFindRecType;
+  CurrSearchNum : LongInt;
+
 Function FNMatch(const Pattern,Name:rawbytestring):Boolean;
 Var
   LenPat,LenName : longint;
@@ -109,4 +151,256 @@ Begin {start FNMatch}
   FNMatch:=DoFNMatch(1,1);
 End;
 
+Procedure WasiFindClose(Var f: TWasiSearchRec);
+{
+  Closes dirfd if it is open
+}
+Var
+  res: __wasi_errno_t;
+  i : longint;
+Begin
+  if f.SearchType=0 then
+   begin
+     i:=1;
+     repeat
+       if (RtlFindRecs[i].SearchNum=f.SearchNum) then
+        break;
+       inc(i);
+     until (i>RtlFindSize);
+     If i<=RtlFindSize Then
+      Begin
+        RtlFindRecs[i].SearchNum:=0;
+        if f.dirfd<>-1 then
+          repeat
+            res:=__wasi_fd_close(f.dirfd);
+          until (res=__WASI_ERRNO_SUCCESS) or (res<>__WASI_ERRNO_INTR);
+      End;
+   end;
+  f.dirfd:=-1;
+End;
+
+
+Function FindGetFileInfo(const s:rawbytestring;var f:TWasiSearchRec):boolean;
+var
+  st   : __wasi_filestat_t;
+  fd   : __wasi_fd_t;
+  pr   : RawByteString;
+  Info : record
+    FMode: LongInt;
+    FSize: __wasi_filesize_t;
+    FMTime: __wasi_timestamp_t;
+  end;
+begin
+  FindGetFileInfo:=false;
+  if ConvertToFdRelativePath(s,fd,pr)<>0 then
+    exit;
+  { todo: __WASI_LOOKUPFLAGS_SYMLINK_FOLLOW??? }
+  if __wasi_path_filestat_get(fd,0,PChar(pr),Length(pr),@st)<>__WASI_ERRNO_SUCCESS then
+    exit;
+  info.FSize:=st.size;
+  info.FMTime:=st.mtim;
+  if st.filetype=__WASI_FILETYPE_DIRECTORY then
+   info.fmode:=$10
+  else
+   info.fmode:=$0;
+  {if (st.st_mode and STAT_IWUSR)=0 then
+   info.fmode:=info.fmode or 1;}
+  if s[f.NamePos+1]='.' then
+   info.fmode:=info.fmode or $2;
+
+  If ((Info.FMode and Not(f.searchattr))=0) Then
+   Begin
+     f.Name:=Copy(s,f.NamePos+1);
+     f.Attr:=Info.FMode;
+     f.Size:=Info.FSize;
+     f.Time:=Info.FMTime;
+     FindGetFileInfo:=true;
+   End;
+end;
+
+
+Function  FindLastUsed: Longint;
+{
+  Find unused or least recently used dirpointer slot in findrecs array
+}
+Var
+  BestMatch,i : Longint;
+  Found       : Boolean;
+Begin
+  BestMatch:=1;
+  i:=1;
+  Found:=False;
+  While (i <= RtlFindSize) And (Not Found) Do
+   Begin
+     If (RtlFindRecs[i].SearchNum = 0) Then
+      Begin
+        BestMatch := i;
+        Found := True;
+      End
+     Else
+      Begin
+        If RtlFindRecs[i].LastUsed > RtlFindRecs[BestMatch].LastUsed Then
+         BestMatch := i;
+      End;
+     Inc(i);
+   End;
+  FindLastUsed := BestMatch;
+End;
+
+
+
+function WasiFindNext(var f: TWasiSearchRec): longint;
+{
+  re-opens dir if not already in array and calls FindWorkProc
+}
+Var
+  fd,ourfd: __wasi_fd_t;
+  pr: RawByteString;
+  res: __wasi_errno_t;
+  DirName  : RawByteString;
+  i,
+  ArrayPos : Longint;
+  FName,
+  SName    : RawByteString;
+  Found,
+  Finished : boolean;
+  Buf: array [0..SizeOf(__wasi_dirent_t)+256-1] of Byte;
+  BufUsed: __wasi_size_t;
+Begin
+  If f.SearchType=0 Then
+   Begin
+     ArrayPos:=0;
+     For i:=1 to RtlFindSize Do
+      Begin
+        If RtlFindRecs[i].SearchNum = f.SearchNum Then
+         ArrayPos:=i;
+        Inc(RtlFindRecs[i].LastUsed);
+      End;
+     If ArrayPos=0 Then
+      Begin
+        If f.NamePos = 0 Then
+         DirName:='./'
+        Else
+         DirName:=Copy(f.SearchSpec,1,f.NamePos);
+        if ConvertToFdRelativePath(DirName,fd,pr)=0 then
+         begin
+           repeat
+             res:=__wasi_path_open(fd,
+                                   0,
+                                   PChar(pr),
+                                   length(pr),
+                                   __WASI_OFLAGS_DIRECTORY,
+                                   __WASI_RIGHTS_FD_READDIR,
+                                   __WASI_RIGHTS_FD_READDIR,
+                                   0,
+                                   @ourfd);
+           until (res=__WASI_ERRNO_SUCCESS) or (res<>__WASI_ERRNO_INTR);
+           If res=__WASI_ERRNO_SUCCESS Then
+            begin
+              f.DirFD := ourfd;
+              ArrayPos:=FindLastUsed;
+              If RtlFindRecs[ArrayPos].SearchNum > 0 Then
+                repeat
+                  res:=__wasi_fd_close(RtlFindRecs[arraypos].DirFD);
+                until (res=__WASI_ERRNO_SUCCESS) or (res<>__WASI_ERRNO_INTR);
+              RtlFindRecs[ArrayPos].SearchNum := f.SearchNum;
+              RtlFindRecs[ArrayPos].DirFD := f.DirFD;
+            end
+           else
+            f.DirFD:=-1;
+         end
+        else
+         f.DirFD:=-1;
+      End;
+     if ArrayPos>0 then
+       RtlFindRecs[ArrayPos].LastUsed:=0;
+   end;
+{Main loop}
+  SName:=Copy(f.SearchSpec,f.NamePos+1);
+  Found:=False;
+  Finished:=(f.DirFD=-1);
+  While Not Finished Do
+   Begin
+     res:=__wasi_fd_readdir(f.DirFD,
+                            @buf,
+                            SizeOf(buf),
+                            f.searchpos,
+                            @bufused);
+     if (res<>__WASI_ERRNO_SUCCESS) or (bufused<=SizeOf(__wasi_dirent_t)) then
+      FName:=''
+     else
+      begin
+        SetLength(FName,P__wasi_dirent_t(@buf)^.d_namlen);
+        Move(buf[SizeOf(__wasi_dirent_t)],FName[1],Length(FName));
+        f.searchpos:=P__wasi_dirent_t(@buf)^.d_next;
+      end;
+     If FName='' Then
+      Finished:=True
+     Else
+      Begin
+        If FNMatch(SName,FName) Then
+         Begin
+           Found:=FindGetFileInfo(Copy(f.SearchSpec,1,f.NamePos)+FName,f);
+           if Found then
+            Finished:=true;
+         End;
+      End;
+   End;
+{Shutdown}
+  If Found Then
+   result:=0
+  Else
+   Begin
+     WasiFindClose(f);
+     result:=18;
+   End;
+End;
+
+
+function WasiFindFirst(const Path: RawByteString; Attr: Word; var f: TWasiSearchRec): longint;
+{
+  opens dir and calls FindWorkProc
+}
+Begin
+  fillchar(f,sizeof(f),0);
+  if Path='' then
+   begin
+     result:=3;
+     exit;
+   end;
+{Create Info}
+  f.SearchSpec := Path;
+  {We always also search for readonly and archive, regardless of Attr:}
+  f.SearchAttr := Attr or archive or readonly;
+  f.SearchPos  := 0;
+  f.NamePos := Length(f.SearchSpec);
+  while (f.NamePos>0) and not (f.SearchSpec[f.NamePos] in AllowDirectorySeparators) do
+   dec(f.NamePos);
+{Wildcards?}
+  if (Pos('?',Path)=0)  and (Pos('*',Path)=0) then
+   begin
+     if FindGetFileInfo(Path,f) then
+      result:=0
+     else
+      begin
+        { According to tdos2 test it should return 18
+        if ErrNo=Sys_ENOENT then
+         result:=3
+        else }
+         result:=18;
+      end;
+     f.DirFD:=-1;
+     f.SearchType:=1;
+     f.searchnum:=-1;
+   end
+  else
+{Find Entry}
+   begin
+     Inc(CurrSearchNum);
+     f.SearchNum:=CurrSearchNum;
+     f.SearchType:=0;
+     result:=WasiFindNext(f);
+   end;
+End;
+
 end.