+ 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.
This commit is contained in:
Nikolay Nikolov 2021-10-15 14:33:43 +03:00
parent 0da5d57c1e
commit 21d843128d
3 changed files with 35 additions and 13 deletions

View File

@ -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

View File

@ -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] = ':');

View File

@ -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);