system.pp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2020,2021 by the Free Pascal development team.
  4. System unit for The WebAssembly System Interface (WASI).
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit system;
  12. interface
  13. {$define FPC_IS_SYSTEM}
  14. {$I systemh.inc}
  15. const
  16. LineEnding = #10;
  17. LFNSupport = true;
  18. DirectorySeparator = '/';
  19. DriveSeparator = '';
  20. ExtensionSeparator = '.';
  21. PathSeparator = ':';
  22. AllowDirectorySeparators : set of char = ['\','/'];
  23. AllowDriveSeparators : set of char = [];
  24. { FileNameCaseSensitive and FileNameCasePreserving are defined below! }
  25. maxExitCode = 65535;
  26. MaxPathLen = 4096;
  27. AllFilesMask = '*';
  28. const
  29. UnusedHandle = -1;
  30. StdInputHandle = 0;
  31. StdOutputHandle = 1;
  32. StdErrorHandle = 2;
  33. FileNameCaseSensitive : boolean = true;
  34. FileNameCasePreserving: boolean = true;
  35. CtrlZMarksEOF: boolean = false; (* #26 not considered as end of file *)
  36. sLineBreak = LineEnding;
  37. DefaultTextLineBreakStyle : TTextLineBreakStyle = tlbsLF;
  38. var
  39. argc: longint;
  40. argv: PPChar;
  41. envp: PPChar;
  42. implementation
  43. {$I wasitypes.inc}
  44. {$I wasiprocs.inc}
  45. function ConvertToFdRelativePath(path: RawByteString; out fd: LongInt; out relfd_path: RawByteString): Word; forward;
  46. function fpc_wasi_path_readlink_ansistring(
  47. fd: __wasi_fd_t;
  48. const path: PChar;
  49. path_len: size_t;
  50. out link: rawbytestring): __wasi_errno_t;[Public, Alias : 'FPC_WASI_PATH_READLINK_ANSISTRING'];
  51. const
  52. InitialBufLen=64;
  53. MaximumBufLen=16384;
  54. var
  55. CurrentBufLen: __wasi_size_t;
  56. BufUsed: __wasi_size_t;
  57. begin
  58. CurrentBufLen:=InitialBufLen div 2;
  59. repeat
  60. CurrentBufLen:=CurrentBufLen*2;
  61. SetLength(link,CurrentBufLen);
  62. result:=__wasi_path_readlink(fd,path,path_len,@(link[1]),CurrentBufLen,@BufUsed);
  63. until (result<>__WASI_ERRNO_SUCCESS) or ((result=__WASI_ERRNO_SUCCESS) and (BufUsed<CurrentBufLen)) or (CurrentBufLen>MaximumBufLen);
  64. if result=__WASI_ERRNO_SUCCESS then
  65. begin
  66. SetLength(link,BufUsed);
  67. setcodepage(link,DefaultRTLFileSystemCodePage,true);
  68. end
  69. else
  70. link:='';
  71. end;
  72. function HasDriveLetter(const path: rawbytestring): Boolean;
  73. begin
  74. HasDriveLetter:=(Length(path)>=2) and (UpCase(path[1]) in ['A'..'Z']) and (path[2] = ':');
  75. end;
  76. type
  77. PPreopenedDir = ^TPreopenedDir;
  78. TPreopenedDir = record
  79. dir_name: RawByteString;
  80. drive_str: RawByteString;
  81. fd: longint;
  82. end;
  83. PCurrentDir = ^TCurrentDir;
  84. TCurrentDir = record
  85. dir_name: RawByteString;
  86. drive_str: RawByteString;
  87. end;
  88. var
  89. preopened_dirs_count: longint;
  90. preopened_dirs: PPreopenedDir;
  91. drives_count: longint;
  92. current_dirs: PCurrentDir;
  93. current_drive: longint;
  94. {$I system.inc}
  95. var
  96. argv_size,
  97. argv_buf_size: __wasi_size_t;
  98. argv_buf: Pointer;
  99. environc,environ_buf_size,envp_size: __wasi_size_t;
  100. environ_buf: Pointer;
  101. function GetProcessID: SizeUInt;
  102. begin
  103. end;
  104. Procedure Randomize;
  105. Begin
  106. __wasi_random_get(@RandSeed,SizeOf(RandSeed));
  107. End;
  108. procedure System_exit;
  109. begin
  110. __wasi_proc_exit(ExitCode);
  111. End;
  112. function Do_ConvertToFdRelativePath(path: RawByteString; out fd: LongInt; out relfd_path: RawByteString): Word;
  113. var
  114. drive_nr,I,pdir_drive,longest_match,chridx: longint;
  115. IsAbsolutePath: Boolean;
  116. pdir: RawByteString;
  117. begin
  118. fd:=0;
  119. relfd_path:='';
  120. if HasDriveLetter(path) then
  121. begin
  122. drive_nr:=Ord(UpCase(path[1]))-(Ord('A')-1);
  123. delete(path,1,2);
  124. end
  125. else
  126. drive_nr:=current_drive;
  127. { path is relative to a current directory? }
  128. if (path='') or not (path[1] in AllowDirectorySeparators) then
  129. begin
  130. { if so, convert to absolute }
  131. if (drive_nr>=drives_count) or (current_dirs[drive_nr].dir_name='') then
  132. begin
  133. Do_ConvertToFdRelativePath:=15;
  134. exit;
  135. end;
  136. if current_dirs[drive_nr].dir_name[Length(current_dirs[drive_nr].dir_name)] in AllowDirectorySeparators then
  137. path:=current_dirs[drive_nr].dir_name+path
  138. else
  139. path:=current_dirs[drive_nr].dir_name+DirectorySeparator+path;
  140. end;
  141. { path is now absolute. Try to find it in the preopened dirs array }
  142. longest_match:=0;
  143. for I:=0 to preopened_dirs_count-1 do
  144. begin
  145. pdir:=preopened_dirs[I].dir_name;
  146. if preopened_dirs[I].drive_str<>'' then
  147. pdir_drive:=Ord(UpCase(preopened_dirs[I].drive_str[1]))-(Ord('A')-1)
  148. else
  149. pdir_drive:=0;
  150. if pdir_drive<>drive_nr then
  151. continue;
  152. if Length(pdir)>Length(path) then
  153. continue;
  154. if Copy(path,1,Length(pdir))<>pdir then
  155. continue;
  156. chridx:=Length(pdir)+1;
  157. if ((Length(pdir)<>1) or ((Length(pdir)=1) and not (pdir[1] in AllowDirectorySeparators))) and
  158. ((chridx>Length(path)) or not (path[chridx] in AllowDirectorySeparators)) then
  159. continue;
  160. if Length(pdir)>longest_match then
  161. begin
  162. longest_match:=Length(pdir);
  163. while (chridx<=Length(path)) and (path[chridx] in AllowDirectorySeparators) do
  164. Inc(chridx);
  165. fd:=preopened_dirs[I].fd;
  166. relfd_path:=Copy(path,chridx,Length(path)-chridx+1);
  167. end;
  168. end;
  169. if longest_match>0 then
  170. Do_ConvertToFdRelativePath:=0
  171. else
  172. Do_ConvertToFdRelativePath:=3;
  173. end;
  174. function ConvertToFdRelativePath(path: RawByteString; out fd: LongInt; out relfd_path: RawByteString): Word;[Public, Alias : 'FPC_WASI_CONVERTTOFDRELATIVEPATH'];
  175. begin
  176. ConvertToFdRelativePath:=Do_ConvertToFdRelativePath(ToSingleByteFileSystemEncodedFileName(path),fd,relfd_path);
  177. setcodepage(relfd_path,DefaultRTLFileSystemCodePage,true);
  178. end;
  179. procedure Setup_PreopenedDirs;
  180. var
  181. fd: __wasi_fd_t;
  182. prestat: __wasi_prestat_t;
  183. res: __wasi_errno_t;
  184. prestat_dir_name: RawByteString;
  185. drive_nr: longint;
  186. begin
  187. preopened_dirs_count:=0;
  188. preopened_dirs:=nil;
  189. drives_count:=0;
  190. current_dirs:=nil;
  191. current_drive:=0;
  192. fd:=3;
  193. repeat
  194. res:=__wasi_fd_prestat_get(fd, @prestat);
  195. if res=__WASI_ERRNO_SUCCESS then
  196. begin
  197. if (prestat.tag=__WASI_PREOPENTYPE_DIR) and (prestat.u.dir.pr_name_len>0) then
  198. begin
  199. SetLength(prestat_dir_name,prestat.u.dir.pr_name_len);
  200. if __wasi_fd_prestat_dir_name(fd,PByte(prestat_dir_name),prestat.u.dir.pr_name_len)=__WASI_ERRNO_SUCCESS then
  201. begin
  202. setcodepage(prestat_dir_name,DefaultRTLFileSystemCodePage,true);
  203. Inc(preopened_dirs_count);
  204. if preopened_dirs=nil then
  205. preopened_dirs:=AllocMem(preopened_dirs_count*SizeOf(TPreopenedDir))
  206. else
  207. ReAllocMem(preopened_dirs, preopened_dirs_count*SizeOf(TPreopenedDir));
  208. preopened_dirs[preopened_dirs_count-1].fd:=fd;
  209. if HasDriveLetter(prestat_dir_name) then
  210. begin
  211. drive_nr:=Ord(UpCase(prestat_dir_name[1]))-(Ord('A')-1);
  212. preopened_dirs[preopened_dirs_count-1].drive_str:=Copy(prestat_dir_name,1,2);
  213. preopened_dirs[preopened_dirs_count-1].dir_name:=Copy(prestat_dir_name,2,Length(prestat_dir_name)-2);
  214. end
  215. else
  216. begin
  217. drive_nr:=0;
  218. preopened_dirs[preopened_dirs_count-1].drive_str:='';
  219. preopened_dirs[preopened_dirs_count-1].dir_name:=prestat_dir_name;
  220. end;
  221. if (drive_nr+1)>drives_count then
  222. begin
  223. drives_count:=drive_nr+1;
  224. if current_dirs=nil then
  225. current_dirs:=AllocMem(drives_count*SizeOf(TCurrentDir))
  226. else
  227. ReAllocMem(current_dirs,drives_count*SizeOf(TCurrentDir));
  228. end;
  229. if current_dirs[drive_nr].dir_name='' then
  230. current_dirs[drive_nr].dir_name:=prestat_dir_name;
  231. end;
  232. end;
  233. end;
  234. Inc(fd);
  235. until res<>__WASI_ERRNO_SUCCESS;
  236. while (current_drive<(drives_count-1)) and (current_dirs[current_drive].dir_name='') do
  237. Inc(current_drive);
  238. for drive_nr:=0 to drives_count-1 do
  239. begin
  240. if drive_nr>0 then
  241. current_dirs[drive_nr].drive_str:=Chr(Ord('A')+drive_nr-1)+':';
  242. if current_dirs[drive_nr].dir_name='' then
  243. current_dirs[drive_nr].dir_name:=DirectorySeparator;
  244. end;
  245. end;
  246. procedure Setup_Environment;
  247. begin
  248. if envp<>nil then
  249. exit;
  250. if __wasi_environ_sizes_get(@environc, @environ_buf_size)<>__WASI_ERRNO_SUCCESS then
  251. begin
  252. envp:=nil;
  253. exit;
  254. end;
  255. envp_size:=(environc+1)*SizeOf(PChar);
  256. GetMem(envp, envp_size);
  257. GetMem(environ_buf, environ_buf_size);
  258. envp[environc]:=nil;
  259. if __wasi_environ_get(Pointer(envp), environ_buf)<>__WASI_ERRNO_SUCCESS then
  260. begin
  261. FreeMem(envp, envp_size);
  262. FreeMem(environ_buf, environ_buf_size);
  263. envp:=nil;
  264. end;
  265. end;
  266. procedure setup_arguments;
  267. begin
  268. if argv<>nil then
  269. exit;
  270. if __wasi_args_sizes_get(@argc, @argv_buf_size)<>__WASI_ERRNO_SUCCESS then
  271. begin
  272. argc:=0;
  273. argv:=nil;
  274. exit;
  275. end;
  276. argv_size:=(argc+1)*SizeOf(PChar);
  277. GetMem(argv, argv_size);
  278. GetMem(argv_buf, argv_buf_size);
  279. if __wasi_args_get(Pointer(argv), argv_buf)<>__WASI_ERRNO_SUCCESS then
  280. begin
  281. FreeMem(argv, argv_size);
  282. FreeMem(argv_buf, argv_buf_size);
  283. argc:=0;
  284. argv:=nil;
  285. end;
  286. end;
  287. Function ParamCount: Longint;
  288. Begin
  289. if argv=nil then
  290. setup_arguments;
  291. paramcount := argc - 1;
  292. End;
  293. function paramstr(l: longint) : string;
  294. begin
  295. if argv=nil then
  296. setup_arguments;
  297. if (l>=0) and (l+1<=argc) then
  298. paramstr:=strpas(argv[l])
  299. else
  300. paramstr:='';
  301. end;
  302. procedure SysInitStdIO;
  303. begin
  304. OpenStdIO(Input,fmInput,StdInputHandle);
  305. OpenStdIO(Output,fmOutput,StdOutputHandle);
  306. OpenStdIO(ErrOutput,fmOutput,StdErrorHandle);
  307. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  308. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  309. end;
  310. function CheckInitialStkLen(stklen : SizeUInt) : SizeUInt;
  311. begin
  312. end;
  313. begin
  314. { To be set if this is a GUI or console application }
  315. IsConsole := TRUE;
  316. {$ifdef FPC_HAS_FEATURE_DYNLIBS}
  317. { If dynlibs feature is disabled,
  318. IsLibrary is a constant, which can thus not be set to a value }
  319. { To be set if this is a library and not a program }
  320. IsLibrary := FALSE;
  321. {$endif def FPC_HAS_FEATURE_DYNLIBS}
  322. { Setup heap }
  323. InitHeap;
  324. SysInitExceptions;
  325. initunicodestringmanager;
  326. { Setup stdin, stdout and stderr }
  327. SysInitStdIO;
  328. { Reset IO Error }
  329. InOutRes:=0;
  330. {$ifdef FPC_HAS_FEATURE_THREADING}
  331. InitSystemThreads;
  332. {$endif}
  333. Setup_Environment;
  334. Setup_PreopenedDirs;
  335. end.