Browse Source

+ added a wrapper function around __wasi_path_readlink that calls it iteratively
with doubling buffer sizes, starting with 64 bytes, until it reaches 16384
bytes, and reads the link into a rawbytestring. Use that function in all
places in the WASI rtl that need to read a symlink.

Nikolay Nikolov 3 years ago
parent
commit
21d843128d
3 changed files with 35 additions and 13 deletions
  1. 1 6
      rtl/wasi/sysdir.inc
  2. 27 0
      rtl/wasi/system.pp
  3. 7 7
      rtl/wasi/sysutils.pp

+ 1 - 6
rtl/wasi/sysdir.inc

@@ -73,8 +73,6 @@ procedure do_ChDir_internal(s: rawbytestring; SymLinkFollowCount: longint);
         delete(s,1,1);
     end;
 
-const
-  MaxSymLinkSize = 4096;
 var
   new_drive_nr: longint;
   new_dir,new_dir_save,next_dir_part: RawByteString;
@@ -83,7 +81,6 @@ var
   st: __wasi_filestat_t;
   res: __wasi_errno_t;
   symlink: RawByteString;
-  symlink_len: __wasi_size_t;
 begin
   if SymLinkFollowCount<0 then
   begin
@@ -151,14 +148,12 @@ begin
         end;
         if st.filetype=__WASI_FILETYPE_SYMBOLIC_LINK then
         begin
-          SetLength(symlink,MaxSymLinkSize);
-          res:=__wasi_path_readlink(fd,PChar(pr),Length(pr),@symlink[1],Length(symlink),@symlink_len);
+          res:=fpc_wasi_path_readlink_ansistring(fd,PChar(pr),Length(pr),symlink);
           if res<>__WASI_ERRNO_SUCCESS then
           begin
             InOutRes:=Errno2InoutRes(res);
             exit;
           end;
-          SetLength(symlink,symlink_len);
           if (symlink<>'') and (symlink[1] in AllowDirectorySeparators) then
             do_ChDir_internal(symlink,SymLinkFollowCount-1)
           else if (new_dir_save<>'') and (new_dir_save[length(new_dir_save)] in AllowDirectorySeparators) then

+ 27 - 0
rtl/wasi/system.pp

@@ -60,6 +60,33 @@ implementation
 {$I wasitypes.inc}
 {$I wasiprocs.inc}
 
+function fpc_wasi_path_readlink_ansistring(
+                 fd: __wasi_fd_t;
+                 const path: PChar;
+                 path_len: size_t;
+                 out link: rawbytestring): __wasi_errno_t;[Public, Alias : 'FPC_WASI_PATH_READLINK_ANSISTRING'];
+const
+  InitialBufLen=64;
+  MaximumBufLen=16384;
+var
+  CurrentBufLen: __wasi_size_t;
+  BufUsed: __wasi_size_t;
+begin
+  CurrentBufLen:=InitialBufLen div 2;
+  repeat
+    CurrentBufLen:=CurrentBufLen*2;
+    SetLength(link,CurrentBufLen);
+    result:=__wasi_path_readlink(fd,path,path_len,@(link[1]),CurrentBufLen,@BufUsed);
+  until (result<>__WASI_ERRNO_SUCCESS) or ((result=__WASI_ERRNO_SUCCESS) and (BufUsed<CurrentBufLen)) or (CurrentBufLen>MaximumBufLen);
+  if result=__WASI_ERRNO_SUCCESS then
+  begin
+    SetLength(link,BufUsed);
+    setcodepage(link,DefaultRTLFileSystemCodePage,true);
+  end
+  else
+    link:='';
+end;
+
 function HasDriveLetter(const path: rawbytestring): Boolean;
 begin
   HasDriveLetter:=(Length(path)>=2) and (UpCase(path[1]) in ['A'..'Z']) and (path[2] = ':');

+ 7 - 7
rtl/wasi/sysutils.pp

@@ -52,6 +52,12 @@ implementation
 
 {$DEFINE executeprocuni} (* Only 1 byte version of ExecuteProcess is provided by the OS *)
 
+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 UniversalToEpoch(year,month,day,hour,minute,second:Word):int64;
 const
   days_in_month: array [boolean, 1..12] of Byte =
@@ -453,14 +459,11 @@ end;
 
 
 function FileGetSymLinkTarget(const FileName: RawByteString; out SymLinkRec: TRawbyteSymLinkRec): Boolean;
-const
-  MaxSymLinkSize=4096;
 var
   pr: RawByteString;
   fd: __wasi_fd_t;
   Info: __wasi_filestat_t;
   symlink: RawByteString;
-  symlink_len: __wasi_size_t;
   res: __wasi_errno_t;
 begin
   FillChar(SymLinkRec, SizeOf(SymLinkRec), 0);
@@ -471,11 +474,8 @@ begin
     exit;
   if Info.filetype<>__WASI_FILETYPE_SYMBOLIC_LINK then
     exit;
-  SetLength(symlink,MaxSymLinkSize);
-  if __wasi_path_readlink(fd,PChar(pr),Length(pr),@symlink[1],Length(symlink),@symlink_len)<>__WASI_ERRNO_SUCCESS then
+  if fpc_wasi_path_readlink_ansistring(fd,PChar(pr),Length(pr),symlink)<>__WASI_ERRNO_SUCCESS then
     exit;
-  SetLength(symlink,symlink_len);
-  setcodepage(symlink,DefaultRTLFileSystemCodePage,true);
   SymLinkRec.TargetName:=symlink;
 
   res:=__wasi_path_filestat_get(fd,__WASI_LOOKUPFLAGS_SYMLINK_FOLLOW,PChar(pr),length(pr),@Info);