From 21d843128d02fffcb8126811c16846420d570c32 Mon Sep 17 00:00:00 2001 From: Nikolay Nikolov Date: Fri, 15 Oct 2021 14:33:43 +0300 Subject: [PATCH] + 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. --- rtl/wasi/sysdir.inc | 7 +------ rtl/wasi/system.pp | 27 +++++++++++++++++++++++++++ rtl/wasi/sysutils.pp | 14 +++++++------- 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/rtl/wasi/sysdir.inc b/rtl/wasi/sysdir.inc index cdcb308f1f..64b6366532 100644 --- a/rtl/wasi/sysdir.inc +++ b/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 diff --git a/rtl/wasi/system.pp b/rtl/wasi/system.pp index bc846b406c..bfc9a7b64a 100644 --- a/rtl/wasi/system.pp +++ b/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 (BufUsedMaximumBufLen); + 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] = ':'); diff --git a/rtl/wasi/sysutils.pp b/rtl/wasi/sysutils.pp index 9643b6a312..3cc5942771 100644 --- a/rtl/wasi/sysutils.pp +++ b/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);