diff --git a/packages/php-wasm/universal/src/lib/php-worker.ts b/packages/php-wasm/universal/src/lib/php-worker.ts index b35020c216..5bf050db90 100644 --- a/packages/php-wasm/universal/src/lib/php-worker.ts +++ b/packages/php-wasm/universal/src/lib/php-worker.ts @@ -158,13 +158,14 @@ export class PHPWorker implements LimitedPHPApi { /** @inheritDoc @php-wasm/universal!/PHP.run */ async run(request: PHPRunOptions): Promise { - const { php, reap } = await _private - .get(this)! - .requestHandler!.processManager.acquirePHPInstance(); + const php = _private.get(this)!.php!; + // const { php, reap } = await _private + // .get(this)! + // .requestHandler!.processManager.acquirePHPInstance(); try { return await php.run(request); } finally { - reap(); + // reap(); } } diff --git a/packages/php-wasm/universal/src/lib/php.ts b/packages/php-wasm/universal/src/lib/php.ts index fe0508d011..ff888860c7 100644 --- a/packages/php-wasm/universal/src/lib/php.ts +++ b/packages/php-wasm/universal/src/lib/php.ts @@ -900,6 +900,20 @@ export class PHP implements Disposable { return FSHelpers.mv(this[__private__dont__use].FS, fromPath, toPath); } + /** + * Discuss: should we keep this? Or are the argument semantics too confusing? But it's + * the same as for mv, isn't it? + * + * Also, should it be copy(fromPath, toPath, { recursive: true }) like rmdir? + */ + copyRecursive(fromPath: string, toPath: string) { + return FSHelpers.copyRecursive( + this[__private__dont__use].FS, + fromPath, + toPath + ); + } + /** * Removes a directory from the PHP filesystem. * diff --git a/packages/php-wasm/web-service-worker/src/utils.ts b/packages/php-wasm/web-service-worker/src/utils.ts index 3c7925985c..b0b52ac31b 100644 --- a/packages/php-wasm/web-service-worker/src/utils.ts +++ b/packages/php-wasm/web-service-worker/src/utils.ts @@ -58,6 +58,11 @@ export async function convertFetchEventToPHPRequest(event: FetchEvent) { // X-frame-options gets in a way when PHP is // being displayed in an iframe. delete phpResponse.headers['x-frame-options']; + + // When using SharedArrayBuffers, every response needs to have + // these headers. + phpResponse.headers['Cross-Origin-Opener-Policy'] = 'same-origin'; + phpResponse.headers['Cross-Origin-Embedder-Policy'] = 'credentialless'; } catch (e) { console.error(e, { url: url.toString() }); throw e; diff --git a/packages/php-wasm/web/public/php/jspi/php_8_0.js b/packages/php-wasm/web/public/php/jspi/php_8_0.js index 1ce73abc69..f988043940 100644 --- a/packages/php-wasm/web/public/php/jspi/php_8_0.js +++ b/packages/php-wasm/web/public/php/jspi/php_8_0.js @@ -1,79 +1,6927 @@ -import dependencyFilename from './8_0_30/php_8_0.wasm'; -export { dependencyFilename }; -export const dependenciesTotalSize = 12655915; +import dependencyFilename from './8_0_30/php_8_0.wasm'; +export { dependencyFilename }; +export const dependenciesTotalSize = 12655915; export function init(RuntimeName, PHPLoader) { - // The rest of the code comes from the built php.js file and esm-suffix.js -var Module=typeof PHPLoader!="undefined"?PHPLoader:{};var ENVIRONMENT_IS_WEB=RuntimeName==="WEB";var ENVIRONMENT_IS_WORKER=RuntimeName==="WORKER";var ENVIRONMENT_IS_NODE=RuntimeName==="NODE";var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(scriptDirectory.startsWith("blob:")){scriptDirectory=""}else{scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}{readAsync=async url=>{var response=await fetch(url,{credentials:"same-origin"});if(response.ok){return response.arrayBuffer()}throw new Error(response.status+" : "+response.url)}}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"]; -if (Module["quit"]) quit_=Module["quit"];var wasmBinary=Module["wasmBinary"];var wasmMemory;var ABORT=false;var EXITSTATUS;function assert(condition,text){if(!condition){abort(text)}}var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAP64,HEAPU64,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b);Module["HEAP64"]=HEAP64=new BigInt64Array(b);Module["HEAPU64"]=HEAPU64=new BigUint64Array(b)}var __ATPRERUN__=[];var __ATINIT__=[];var __ATEXIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;SOCKFS.root=FS.mount(SOCKFS,{},null);if(!Module["noFSInit"]&&!FS.initialized)FS.init();FS.ignorePermissions=false;TTY.init();PIPEFS.root=FS.mount(PIPEFS,{},null);callRuntimeCallbacks(__ATINIT__)}function exitRuntime(){___funcs_on_exit();callRuntimeCallbacks(__ATEXIT__);FS.quit();TTY.shutdown();runtimeExited=true}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;Module["monitorRunDependencies"]?.(runDependencies)}function removeRunDependency(id){runDependencies--;Module["monitorRunDependencies"]?.(runDependencies);if(runDependencies==0){if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";if(runtimeInitialized){___trap()}var e=new WebAssembly.RuntimeError(what);throw e}var dataURIPrefix="data:application/octet-stream;base64,";var isDataURI=filename=>filename.startsWith(dataURIPrefix);function findWasmBinary(){var f=dependencyFilename;if(!isDataURI(f)){return locateFile(f)}return f}var wasmBinaryFile;function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}async function getWasmBinary(binaryFile){if(!wasmBinary){try{var response=await readAsync(binaryFile);return new Uint8Array(response)}catch{}}return getBinarySync(binaryFile)}async function instantiateArrayBuffer(binaryFile,imports){try{var binary=await getWasmBinary(binaryFile);var instance=await WebAssembly.instantiate(binary,imports);return instance}catch(reason){err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)}}async function instantiateAsync(binary,binaryFile,imports){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&typeof fetch=="function"){try{var response=fetch(binaryFile,{credentials:"same-origin"});var instantiationResult=await WebAssembly.instantiateStreaming(response,imports);return instantiationResult}catch(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation")}}return instantiateArrayBuffer(binaryFile,imports)}function getWasmImports(){Asyncify.instrumentWasmImports(wasmImports);return{env:wasmImports,wasi_snapshot_preview1:wasmImports}}async function createWasm(){function receiveInstance(instance,module){wasmExports=instance.exports;wasmExports=Asyncify.instrumentWasmExports(wasmExports);Module["wasmExports"]=wasmExports;wasmMemory=wasmExports["memory"];updateMemoryViews();wasmTable=wasmExports["__indirect_function_table"];addOnInit(wasmExports["__wasm_call_ctors"]);removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}var info=getWasmImports();if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);return false}}wasmBinaryFile??=findWasmBinary();var result=await instantiateAsync(wasmBinary,wasmBinaryFile,info);receiveInstantiationResult(result);return result}function __asyncjs__js_popen_to_file(command,mode,exitCodePtr){return Asyncify.handleAsync(async()=>{const returnCallback=resolver=>new Promise(resolver);if(!command)return 1;const cmdstr=UTF8ToString(command);if(!cmdstr.length)return 0;const modestr=UTF8ToString(mode);if(!modestr.length)return 0;if(modestr==="w"){console.error('popen($cmd, "w") is not implemented yet')}return returnCallback(async wakeUp=>{let cp;try{cp=PHPWASM.spawnProcess(cmdstr,[]);if(cp instanceof Promise){cp=await cp}}catch(e){console.error(e);if(e.code==="SPAWN_UNSUPPORTED"){return 1}throw e}const outByteArrays=[];cp.stdout.on("data",function(data){outByteArrays.push(data)});const outputPath="/tmp/popen_output";cp.on("exit",function(exitCode){const outBytes=new Uint8Array(outByteArrays.reduce((acc,curr)=>acc+curr.length,0));let offset=0;for(const byteArray of outByteArrays){outBytes.set(byteArray,offset);offset+=byteArray.length}FS.writeFile(outputPath,outBytes);HEAPU8[exitCodePtr]=exitCode;wakeUp(allocateUTF8OnStack(outputPath))})})})}__asyncjs__js_popen_to_file.sig="iiii";function __asyncjs__wasm_poll_socket(socketd,events,timeout){return Asyncify.handleAsync(async()=>{const returnCallback=resolver=>new Promise(resolver);const POLLIN=1;const POLLPRI=2;const POLLOUT=4;const POLLERR=8;const POLLHUP=16;const POLLNVAL=32;return returnCallback(wakeUp=>{const polls=[];if(socketd in PHPWASM.child_proc_by_fd){const procInfo=PHPWASM.child_proc_by_fd[socketd];if(procInfo.exited){wakeUp(0);return}polls.push(PHPWASM.awaitEvent(procInfo.stdout,"data"))}else if(FS.isSocket(FS.getStream(socketd)?.node.mode)){const sock=getSocketFromFD(socketd);if(!sock){wakeUp(0);return}const lookingFor=new Set;if(events&POLLIN||events&POLLPRI){if(sock.server){for(const client of sock.pending){if((client.recv_queue||[]).length>0){wakeUp(1);return}}}else if((sock.recv_queue||[]).length>0){wakeUp(1);return}}const webSockets=PHPWASM.getAllWebSockets(sock);if(!webSockets.length){wakeUp(0);return}for(const ws of webSockets){if(events&POLLIN||events&POLLPRI){polls.push(PHPWASM.awaitData(ws));lookingFor.add("POLLIN")}if(events&POLLOUT){polls.push(PHPWASM.awaitConnection(ws));lookingFor.add("POLLOUT")}if(events&POLLHUP){polls.push(PHPWASM.awaitClose(ws));lookingFor.add("POLLHUP")}if(events&POLLERR||events&POLLNVAL){polls.push(PHPWASM.awaitError(ws));lookingFor.add("POLLERR")}}}else{setTimeout(function(){wakeUp(1)},timeout);return}if(polls.length===0){console.warn("Unsupported poll event "+events+", defaulting to setTimeout().");setTimeout(function(){wakeUp(0)},timeout);return}const promises=polls.map(([promise])=>promise);const clearPolling=()=>polls.forEach(([,clear])=>clear());let awaken=false;let timeoutId;Promise.race(promises).then(function(results){if(!awaken){awaken=true;wakeUp(1);if(timeoutId){clearTimeout(timeoutId)}clearPolling()}});if(timeout!==-1){timeoutId=setTimeout(function(){if(!awaken){awaken=true;wakeUp(0);clearPolling()}},timeout)}})})}__asyncjs__wasm_poll_socket.sig="iiii";function __asyncjs__js_fd_read(fd,iov,iovcnt,pnum){return Asyncify.handleAsync(async()=>{const returnCallback=resolver=>new Promise(resolver);if(Asyncify?.State?.Normal===undefined||Asyncify?.state===Asyncify?.State?.Normal){var returnCode;var stream;let num=0;try{stream=SYSCALLS.getStreamFromFD(fd);const num=doReadv(stream,iov,iovcnt);HEAPU32[pnum>>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError")){throw e}if(e.errno!==6||!(stream?.fd in PHPWASM.child_proc_by_fd)){HEAPU32[pnum>>2]=0;return returnCode}}}return returnCallback(wakeUp=>{var retries=0;var interval=50;var timeout=5e3;var maxRetries=timeout/interval;function poll(){var returnCode;var stream;let num;try{stream=SYSCALLS.getStreamFromFD(fd);num=doReadv(stream,iov,iovcnt);returnCode=0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError")){console.error(e);throw e}returnCode=e.errno}const success=returnCode===0;const failure=++retries>maxRetries||!(fd in PHPWASM.child_proc_by_fd)||PHPWASM.child_proc_by_fd[fd]?.exited||FS.isClosed(stream);if(success){HEAPU32[pnum>>2]=num;wakeUp(0)}else if(failure){HEAPU32[pnum>>2]=0;wakeUp(returnCode===6?0:returnCode)}else{setTimeout(poll,interval)}}poll()})})}__asyncjs__js_fd_read.sig="iiiii";function __asyncjs__js_module_onMessage(data,response_buffer){return Asyncify.handleAsync(async()=>{if(Module["onMessage"]){const dataStr=UTF8ToString(data);return Module["onMessage"](dataStr).then(response=>{const responseBytes=typeof response==="string"?(new TextEncoder).encode(response):response;const responseSize=responseBytes.byteLength;const responsePtr=_malloc(responseSize+1);HEAPU8.set(responseBytes,responsePtr);HEAPU8[responsePtr+responseSize]=0;HEAPU8[response_buffer]=responsePtr;HEAPU8[response_buffer+1]=responsePtr>>8;HEAPU8[response_buffer+2]=responsePtr>>16;HEAPU8[response_buffer+3]=responsePtr>>24;return responseSize}).catch(e=>{console.error(e);return-1})}})}__asyncjs__js_module_onMessage.sig="iii";class ExitStatus{name="ExitStatus";constructor(status){this.message=`Program terminated with exit(${status})`;this.status=status}} -ExitStatus = class PHPExitStatus extends Error { - constructor(status) { - super(status); - this.name = 'ExitStatus'; - this.message = 'Program terminated with exit(' + status + ')'; - this.status = status; - } -};var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var noExitRuntime=Module["noExitRuntime"]||false;function _SharpYuvConvert(){abort("missing function: SharpYuvConvert")}_SharpYuvConvert.stub=true;function _SharpYuvGetConversionMatrix(){abort("missing function: SharpYuvGetConversionMatrix")}_SharpYuvGetConversionMatrix.stub=true;function _SharpYuvInit(){abort("missing function: SharpYuvInit")}_SharpYuvInit.stub=true;var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder:undefined;var UTF8ArrayToString=(heapOrArray,idx=0,maxBytesToRead=NaN)=>{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):"";Module["UTF8ToString"]=UTF8ToString;var ___assert_fail=(condition,filename,line,func)=>abort(`Assertion failed: ${UTF8ToString(condition)}, at: `+[filename?UTF8ToString(filename):"unknown filename",line,func?UTF8ToString(func):"unknown function"]);var wasmTableMirror=[];var wasmTable;var getWasmTableEntry=funcPtr=>{var func=wasmTableMirror[funcPtr];if(!func){if(funcPtr>=wasmTableMirror.length)wasmTableMirror.length=funcPtr+1;wasmTableMirror[funcPtr]=func=wasmTable.get(funcPtr);if(Asyncify.isAsyncExport(func)){wasmTableMirror[funcPtr]=func=Asyncify.makeAsyncFunction(func)}}return func};var ___call_sighandler=(fp,sig)=>getWasmTableEntry(fp)(sig);var initRandomFill=()=>{if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>crypto.getRandomValues(view)}else abort("initRandomDevice")};var randomFill=view=>(randomFill=initRandomFill())(view);var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:path=>{if(path==="/")return"/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:(...paths)=>PATH.normalize(paths.join("/")),join2:(l,r)=>PATH.normalize(l+"/"+r)};var PATH_FS={resolve:(...args)=>{var resolvedPath="",resolvedAbsolute=false;for(var i=args.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?args[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};Module["lengthBytesUTF8"]=lengthBytesUTF8;var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx};function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else{}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true)}return FS_stdin_getChar_buffer.shift()};var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close(stream){stream.tty.ops.fsync(stream.tty)},fsync(stream){stream.tty.ops.fsync(stream.tty)},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output));tty.output=[]}},ioctl_tcgets(tty){return{c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return[24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output));tty.output=[]}}}};var zeroMemory=(address,size)=>{HEAPU8.fill(0,address,address+size)};var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var mmapAlloc=size=>{size=alignMemory(size,65536);var ptr=_emscripten_builtin_memalign(65536,size);if(ptr)zeroMemory(ptr,size);return ptr};var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16895,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}MEMFS.ops_table||={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}};var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.atime=node.mtime=node.ctime=Date.now();if(parent){parent.contents[name]=node;parent.atime=parent.mtime=parent.ctime=node.atime}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.atime);attr.mtime=new Date(node.mtime);attr.ctime=new Date(node.ctime);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){for(const key of["mode","atime","mtime","ctime"]){if(attr[key]){node[key]=attr[key]}}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup(parent,name){throw MEMFS.doesNotExistError},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){if(FS.isDir(old_node.mode)){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}FS.hashRemoveNode(new_node)}delete old_node.parent.contents[old_node.name];new_dir.contents[new_name]=old_node;old_node.name=new_name;new_dir.ctime=new_dir.mtime=old_node.parent.ctime=old_node.parent.mtime=Date.now()},unlink(parent,name){delete parent.contents[name];parent.ctime=parent.mtime=Date.now()},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.ctime=parent.mtime=Date.now()},readdir(node){return[".","..",...Object.keys(node.contents)]},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length{var arrayBuffer=await readAsync(url);return new Uint8Array(arrayBuffer)};asyncLoad.isAsync=true;var FS_createDataFile=(parent,name,fileData,canRead,canWrite,canOwn)=>{FS.createDataFile(parent,name,fileData,canRead,canWrite,canOwn)};var preloadPlugins=Module["preloadPlugins"]||[];var FS_handledByPreloadPlugin=(byteArray,fullname,finish,onerror)=>{if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true}});return handled};var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);function processData(byteArray){function finish(byteArray){preFinish?.();if(!dontCreateFile){FS_createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}onload?.();removeRunDependency(dep)}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{onerror?.();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url).then(processData,onerror)}else{processData(url)}};var FS_modeStringToFlags=str=>{var flagModes={r:0,"r+":2,w:512|64|1,"w+":512|64|2,a:1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};var ERRNO_CODES={EPERM:63,ENOENT:44,ESRCH:71,EINTR:27,EIO:29,ENXIO:60,E2BIG:1,ENOEXEC:45,EBADF:8,ECHILD:12,EAGAIN:6,EWOULDBLOCK:6,ENOMEM:48,EACCES:2,EFAULT:21,ENOTBLK:105,EBUSY:10,EEXIST:20,EXDEV:75,ENODEV:43,ENOTDIR:54,EISDIR:31,EINVAL:28,ENFILE:41,EMFILE:33,ENOTTY:59,ETXTBSY:74,EFBIG:22,ENOSPC:51,ESPIPE:70,EROFS:69,EMLINK:34,EPIPE:64,EDOM:18,ERANGE:68,ENOMSG:49,EIDRM:24,ECHRNG:106,EL2NSYNC:156,EL3HLT:107,EL3RST:108,ELNRNG:109,EUNATCH:110,ENOCSI:111,EL2HLT:112,EDEADLK:16,ENOLCK:46,EBADE:113,EBADR:114,EXFULL:115,ENOANO:104,EBADRQC:103,EBADSLT:102,EDEADLOCK:16,EBFONT:101,ENOSTR:100,ENODATA:116,ETIME:117,ENOSR:118,ENONET:119,ENOPKG:120,EREMOTE:121,ENOLINK:47,EADV:122,ESRMNT:123,ECOMM:124,EPROTO:65,EMULTIHOP:36,EDOTDOT:125,EBADMSG:9,ENOTUNIQ:126,EBADFD:127,EREMCHG:128,ELIBACC:129,ELIBBAD:130,ELIBSCN:131,ELIBMAX:132,ELIBEXEC:133,ENOSYS:52,ENOTEMPTY:55,ENAMETOOLONG:37,ELOOP:32,EOPNOTSUPP:138,EPFNOSUPPORT:139,ECONNRESET:15,ENOBUFS:42,EAFNOSUPPORT:5,EPROTOTYPE:67,ENOTSOCK:57,ENOPROTOOPT:50,ESHUTDOWN:140,ECONNREFUSED:14,EADDRINUSE:3,ECONNABORTED:13,ENETUNREACH:40,ENETDOWN:38,ETIMEDOUT:73,EHOSTDOWN:142,EHOSTUNREACH:23,EINPROGRESS:26,EALREADY:7,EDESTADDRREQ:17,EMSGSIZE:35,EPROTONOSUPPORT:66,ESOCKTNOSUPPORT:137,EADDRNOTAVAIL:4,ENETRESET:39,EISCONN:30,ENOTCONN:53,ETOOMANYREFS:141,EUSERS:136,EDQUOT:19,ESTALE:72,ENOTSUP:138,ENOMEDIUM:148,EILSEQ:25,EOVERFLOW:61,ECANCELED:11,ENOTRECOVERABLE:56,EOWNERDEAD:62,ESTRPIPE:135};var PROXYFS={mount(mount){return PROXYFS.createNode(null,"/",mount.opts.fs.lstat(mount.opts.root).mode,0)},createNode(parent,name,mode,dev){if(!FS.isDir(mode)&&!FS.isFile(mode)&&!FS.isLink(mode)){throw new FS.ErrnoError(ERRNO_CODES.EINVAL)}var node=FS.createNode(parent,name,mode);node.node_ops=PROXYFS.node_ops;node.stream_ops=PROXYFS.stream_ops;return node},realPath(node){var parts=[];while(node.parent!==node){parts.push(node.name);node=node.parent}parts.push(node.mount.opts.root);parts.reverse();return PATH.join(...parts)},node_ops:{getattr(node){var path=PROXYFS.realPath(node);var stat;try{stat=node.mount.opts.fs.lstat(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}return{dev:stat.dev,ino:stat.ino,mode:stat.mode,nlink:stat.nlink,uid:stat.uid,gid:stat.gid,rdev:stat.rdev,size:stat.size,atime:stat.atime,mtime:stat.mtime,ctime:stat.ctime,blksize:stat.blksize,blocks:stat.blocks}},setattr(node,attr){var path=PROXYFS.realPath(node);try{if(attr.mode!==undefined){node.mount.opts.fs.chmod(path,attr.mode);node.mode=attr.mode}if(attr.atime||attr.mtime){var atime=new Date(attr.atime||attr.mtime);var mtime=new Date(attr.mtime||attr.atime);node.mount.opts.fs.utime(path,atime,mtime)}if(attr.size!==undefined){node.mount.opts.fs.truncate(path,attr.size)}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},lookup(parent,name){try{var path=PATH.join2(PROXYFS.realPath(parent),name);var mode=parent.mount.opts.fs.lstat(path).mode;var node=PROXYFS.createNode(parent,name,mode);return node}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},mknod(parent,name,mode,dev){var node=PROXYFS.createNode(parent,name,mode,dev);var path=PROXYFS.realPath(node);try{if(FS.isDir(node.mode)){node.mount.opts.fs.mkdir(path,node.mode)}else{node.mount.opts.fs.writeFile(path,"",{mode:node.mode})}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}return node},rename(oldNode,newDir,newName){var oldPath=PROXYFS.realPath(oldNode);var newPath=PATH.join2(PROXYFS.realPath(newDir),newName);try{oldNode.mount.opts.fs.rename(oldPath,newPath);oldNode.name=newName}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},unlink(parent,name){var path=PATH.join2(PROXYFS.realPath(parent),name);try{parent.mount.opts.fs.unlink(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},rmdir(parent,name){var path=PATH.join2(PROXYFS.realPath(parent),name);try{parent.mount.opts.fs.rmdir(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},readdir(node){var path=PROXYFS.realPath(node);try{return node.mount.opts.fs.readdir(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},symlink(parent,newName,oldPath){var newPath=PATH.join2(PROXYFS.realPath(parent),newName);try{parent.mount.opts.fs.symlink(oldPath,newPath)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},readlink(node){var path=PROXYFS.realPath(node);try{return node.mount.opts.fs.readlink(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}}},stream_ops:{open(stream){var path=PROXYFS.realPath(stream.node);try{stream.nfd=stream.node.mount.opts.fs.open(path,stream.flags)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},close(stream){try{stream.node.mount.opts.fs.close(stream.nfd)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},read(stream,buffer,offset,length,position){try{return stream.node.mount.opts.fs.read(stream.nfd,buffer,offset,length,position)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},write(stream,buffer,offset,length,position){try{return stream.node.mount.opts.fs.write(stream.nfd,buffer,offset,length,position)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},llseek(stream,offset,whence){var position=offset;if(whence===1){position+=stream.position}else if(whence===2){if(FS.isFile(stream.node.mode)){try{var stat=stream.node.node_ops.getattr(stream.node);position+=stat.size}catch(e){throw new FS.ErrnoError(ERRNO_CODES[e.code])}}}if(position<0){throw new FS.ErrnoError(ERRNO_CODES.EINVAL)}return position}}};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:class{name="ErrnoError";constructor(errno){this.errno=errno}},filesystems:null,syncFSRequests:0,readFiles:{},FSStream:class{shared={};get object(){return this.node}set object(val){this.node=val}get isRead(){return(this.flags&2097155)!==1}get isWrite(){return(this.flags&2097155)!==0}get isAppend(){return this.flags&1024}get flags(){return this.shared.flags}set flags(val){this.shared.flags=val}get position(){return this.shared.position}set position(val){this.shared.position=val}},FSNode:class{node_ops={};stream_ops={};readMode=292|73;writeMode=146;mounted=null;constructor(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.rdev=rdev;this.atime=this.mtime=this.ctime=Date.now()}get read(){return(this.mode&this.readMode)===this.readMode}set read(val){val?this.mode|=this.readMode:this.mode&=~this.readMode}get write(){return(this.mode&this.writeMode)===this.writeMode}set write(val){val?this.mode|=this.writeMode:this.mode&=~this.writeMode}get isFolder(){return FS.isDir(this.mode)}get isDevice(){return FS.isChrdev(this.mode)}},lookupPath(path,opts={}){if(!path)return{path:"",node:null};opts.follow_mount??=true;if(!PATH.isAbs(path)){path=FS.cwd()+"/"+path}linkloop:for(var nlinks=0;nlinks<40;nlinks++){var parts=path.split("/").filter(p=>!!p&&p!==".");var current=FS.root;var current_path="/";for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node)},isRoot(node){return node===node.parent},isMountpoint(node){return!!node.mounted},isFile(mode){return(mode&61440)===32768},isDir(mode){return(mode&61440)===16384},isLink(mode){return(mode&61440)===40960},isChrdev(mode){return(mode&61440)===8192},isBlkdev(mode){return(mode&61440)===24576},isFIFO(mode){return(mode&61440)===4096},isSocket(mode){return(mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){if(!FS.isDir(dir.mode))return 54;var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){if(!FS.isDir(dir.mode)){return 54}try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd()}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null},dupStream(origStream,fd=-1){var stream=FS.createStream(origStream,fd);stream.stream_ops?.dup?.(stream);return stream},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;stream.stream_ops.open?.(stream)},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push(...m.mounts)}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type,opts,mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},statfs(path){var rtn={bsize:4096,frsize:4096,blocks:1e6,bfree:5e5,bavail:5e5,files:FS.nextInode,ffree:FS.nextInode-1,fsid:42,flags:2,namelen:255};var parent=FS.lookupPath(path,{follow:true}).node;if(parent?.node_ops.statfs){Object.assign(rtn,parent.node_ops.statfs(parent.mount.opts.root))}return rtn},create(path,mode=438){mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode=511){mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var i=0;iFS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length,llseek:()=>0});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomLeft=randomFill(randomBuffer).byteLength}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16895,73);node.stream_ops={llseek:MEMFS.stream_ops.llseek};node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path},id:fd+1};ret.parent=ret;return ret},readdir(){return Array.from(FS.streams.entries()).filter(([k,v])=>v).map(([k,v])=>k.toString())}};return node}},{},"/proc/self/fd")},createStandardStreams(input,output,error){if(input){FS.createDevice("/dev","stdin",input)}else{FS.symlink("/dev/tty","/dev/stdin")}if(output){FS.createDevice("/dev","stdout",null,output)}else{FS.symlink("/dev/tty","/dev/stdout")}if(error){FS.createDevice("/dev","stderr",null,error)}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},staticInit(){FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={MEMFS,PROXYFS}},init(input,output,error){FS.initialized=true;input??=Module["stdin"];output??=Module["stdout"];error??=Module["stderr"];FS.createStandardStreams(input,output,error)},quit(){FS.initialized=false;_fflush(0);for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]}setDataGetter(getter){this.getter=getter}cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true}get length(){if(!this.lengthKnown){this.cacheLength()}return this._length}get chunkSize(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=(...args)=>{FS.forceLoadFile(node);return fn(...args)}});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr,allocated:true}};node.stream_ops=stream_ops;return node}};Module["FS"]=FS;var SOCKFS={websocketArgs:{},callbacks:{},on(event,callback){SOCKFS.callbacks[event]=callback},emit(event,param){SOCKFS.callbacks[event]?.(param)},mount(mount){SOCKFS.websocketArgs=Module["websocket"]||{};(Module["websocket"]??={})["on"]=SOCKFS.on;return FS.createNode(null,"/",16895,0)},createSocket(family,type,protocol){type&=~526336;var streaming=type==1;if(streaming&&protocol&&protocol!=6){throw new FS.ErrnoError(66)}var sock={family,type,protocol,server:null,error:null,peers:{},pending:[],recv_queue:[],sock_ops:SOCKFS.websocket_sock_ops};var name=SOCKFS.nextname();var node=FS.createNode(SOCKFS.root,name,49152,0);node.sock=sock;var stream=FS.createStream({path:name,node,flags:2,seekable:false,stream_ops:SOCKFS.stream_ops});sock.stream=stream;return sock},getSocket(fd){var stream=FS.getStream(fd);if(!stream||!FS.isSocket(stream.node.mode)){return null}return stream.node.sock},stream_ops:{poll(stream){var sock=stream.node.sock;return sock.sock_ops.poll(sock)},ioctl(stream,request,varargs){var sock=stream.node.sock;return sock.sock_ops.ioctl(sock,request,varargs)},read(stream,buffer,offset,length,position){var sock=stream.node.sock;var msg=sock.sock_ops.recvmsg(sock,length);if(!msg){return 0}buffer.set(msg.buffer,offset);return msg.buffer.length},write(stream,buffer,offset,length,position){var sock=stream.node.sock;return sock.sock_ops.sendmsg(sock,buffer,offset,length)},close(stream){var sock=stream.node.sock;sock.sock_ops.close(sock)}},nextname(){if(!SOCKFS.nextname.current){SOCKFS.nextname.current=0}return`socket[${SOCKFS.nextname.current++}]`},websocket_sock_ops:{createPeer(sock,addr,port){var ws;if(typeof addr=="object"){ws=addr;addr=null;port=null}if(ws){if(ws._socket){addr=ws._socket.remoteAddress;port=ws._socket.remotePort}else{var result=/ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);if(!result){throw new Error("WebSocket URL must be in the format ws(s)://address:port")}addr=result[1];port=parseInt(result[2],10)}}else{try{var url="ws:#".replace("#","//");var subProtocols="binary";var opts=undefined;if("function"===typeof SOCKFS.websocketArgs["url"]) { -url = SOCKFS.websocketArgs["url"](...arguments); -}else if ("string" === typeof SOCKFS.websocketArgs["url"]){url=SOCKFS.websocketArgs["url"]}if(SOCKFS.websocketArgs["subprotocol"]){subProtocols=SOCKFS.websocketArgs["subprotocol"]}else if(SOCKFS.websocketArgs["subprotocol"]===null){subProtocols="null"}if(url==="ws://"||url==="wss://"){var parts=addr.split("/");url=url+parts[0]+":"+port+"/"+parts.slice(1).join("/")}if(subProtocols!=="null"){subProtocols=subProtocols.replace(/^ +| +$/g,"").split(/ *, */);opts=subProtocols}var WebSocketConstructor;{WebSocketConstructor=WebSocket}if (Module['websocket']['decorator']) {WebSocketConstructor = Module['websocket']['decorator'](WebSocketConstructor);}ws = new WebSocketConstructor(url,opts);ws.binaryType="arraybuffer"}catch(e){throw new FS.ErrnoError(23)}}var peer={addr,port,socket:ws,msg_send_queue:[]};SOCKFS.websocket_sock_ops.addPeer(sock,peer);SOCKFS.websocket_sock_ops.handlePeerEvents(sock,peer);if(sock.type===2&&typeof sock.sport!="undefined"){peer.msg_send_queue.push(new Uint8Array([255,255,255,255,"p".charCodeAt(0),"o".charCodeAt(0),"r".charCodeAt(0),"t".charCodeAt(0),(sock.sport&65280)>>8,sock.sport&255]))}return peer},getPeer(sock,addr,port){return sock.peers[addr+":"+port]},addPeer(sock,peer){sock.peers[peer.addr+":"+peer.port]=peer},removePeer(sock,peer){delete sock.peers[peer.addr+":"+peer.port]},handlePeerEvents(sock,peer){var first=true;var handleOpen=function(){sock.connecting=false;SOCKFS.emit("open",sock.stream.fd);try{var queued=peer.msg_send_queue.shift();while(queued){peer.socket.send(queued);queued=peer.msg_send_queue.shift()}}catch(e){peer.socket.close()}};function handleMessage(data){if(typeof data=="string"){var encoder=new TextEncoder;data=encoder.encode(data)}else{assert(data.byteLength!==undefined);if(data.byteLength==0){return}data=new Uint8Array(data)}var wasfirst=first;first=false;if(wasfirst&&data.length===10&&data[0]===255&&data[1]===255&&data[2]===255&&data[3]===255&&data[4]==="p".charCodeAt(0)&&data[5]==="o".charCodeAt(0)&&data[6]==="r".charCodeAt(0)&&data[7]==="t".charCodeAt(0)){var newport=data[8]<<8|data[9];SOCKFS.websocket_sock_ops.removePeer(sock,peer);peer.port=newport;SOCKFS.websocket_sock_ops.addPeer(sock,peer);return}sock.recv_queue.push({addr:peer.addr,port:peer.port,data});SOCKFS.emit("message",sock.stream.fd)}if(ENVIRONMENT_IS_NODE){peer.socket.on("open",handleOpen);peer.socket.on("message",function(data,isBinary){if(!isBinary){return}handleMessage(new Uint8Array(data).buffer)});peer.socket.on("close",function(){SOCKFS.emit("close",sock.stream.fd)});peer.socket.on("error",function(error){sock.error=14;SOCKFS.emit("error",[sock.stream.fd,sock.error,"ECONNREFUSED: Connection refused"])})}else{peer.socket.onopen=handleOpen;peer.socket.onclose=function(){SOCKFS.emit("close",sock.stream.fd)};peer.socket.onmessage=function peer_socket_onmessage(event){handleMessage(event.data)};peer.socket.onerror=function(error){sock.error=14;SOCKFS.emit("error",[sock.stream.fd,sock.error,"ECONNREFUSED: Connection refused"])}}},poll(sock){if(sock.type===1&&sock.server){return sock.pending.length?64|1:0}var mask=0;var dest=sock.type===1?SOCKFS.websocket_sock_ops.getPeer(sock,sock.daddr,sock.dport):null;if(sock.recv_queue.length||!dest||dest&&dest.socket.readyState===dest.socket.CLOSING||dest&&dest.socket.readyState===dest.socket.CLOSED){mask|=64|1}if(!dest||dest&&dest.socket.readyState===dest.socket.OPEN){mask|=4}if(dest&&dest.socket.readyState===dest.socket.CLOSING||dest&&dest.socket.readyState===dest.socket.CLOSED){if(sock.connecting){mask|=4}else{mask|=16}}return mask},ioctl(sock,request,arg){switch(request){case 21531:var bytes=0;if(sock.recv_queue.length){bytes=sock.recv_queue[0].data.length}HEAP32[arg>>2]=bytes;return 0;default:return 28}},close(sock){if(sock.server){try{sock.server.close()}catch(e){}sock.server=null}var peers=Object.keys(sock.peers);for(var i=0;i{var socket=SOCKFS.getSocket(fd);if(!socket)throw new FS.ErrnoError(8);return socket};var inetPton4=str=>{var b=str.split(".");for(var i=0;i<4;i++){var tmp=Number(b[i]);if(isNaN(tmp))return null;b[i]=tmp}return(b[0]|b[1]<<8|b[2]<<16|b[3]<<24)>>>0};var jstoi_q=str=>parseInt(str);var inetPton6=str=>{var words;var w,offset,z;var valid6regx=/^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i;var parts=[];if(!valid6regx.test(str)){return null}if(str==="::"){return[0,0,0,0,0,0,0,0]}if(str.startsWith("::")){str=str.replace("::","Z:")}else{str=str.replace("::",":Z:")}if(str.indexOf(".")>0){str=str.replace(new RegExp("[.]","g"),":");words=str.split(":");words[words.length-4]=jstoi_q(words[words.length-4])+jstoi_q(words[words.length-3])*256;words[words.length-3]=jstoi_q(words[words.length-2])+jstoi_q(words[words.length-1])*256;words=words.slice(0,words.length-2)}else{words=str.split(":")}offset=0;z=0;for(w=0;w{switch(family){case 2:addr=inetPton4(addr);zeroMemory(sa,16);if(addrlen){HEAP32[addrlen>>2]=16}HEAP16[sa>>1]=family;HEAP32[sa+4>>2]=addr;HEAP16[sa+2>>1]=_htons(port);break;case 10:addr=inetPton6(addr);zeroMemory(sa,28);if(addrlen){HEAP32[addrlen>>2]=28}HEAP32[sa>>2]=family;HEAP32[sa+8>>2]=addr[0];HEAP32[sa+12>>2]=addr[1];HEAP32[sa+16>>2]=addr[2];HEAP32[sa+20>>2]=addr[3];HEAP16[sa+2>>1]=_htons(port);break;default:return 5}return 0};var DNS={address_map:{id:1,addrs:{},names:{}},lookup_name(name){var res=inetPton4(name);if(res!==null){return name}res=inetPton6(name);if(res!==null){return name}var addr;if(DNS.address_map.addrs[name]){addr=DNS.address_map.addrs[name]}else{var id=DNS.address_map.id++;assert(id<65535,"exceeded max address mappings of 65535");addr="172.29."+(id&255)+"."+(id&65280);DNS.address_map.names[addr]=name;DNS.address_map.addrs[name]=addr}return addr},lookup_addr(addr){if(DNS.address_map.names[addr]){return DNS.address_map.names[addr]}return null}};function ___syscall_accept4(fd,addr,addrlen,flags,d1,d2){try{var sock=getSocketFromFD(fd);var newsock=sock.sock_ops.accept(sock);if(addr){var errno=writeSockaddr(addr,newsock.family,DNS.lookup_name(newsock.daddr),newsock.dport,addrlen)}return newsock.stream.fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var inetNtop4=addr=>(addr&255)+"."+(addr>>8&255)+"."+(addr>>16&255)+"."+(addr>>24&255);var inetNtop6=ints=>{var str="";var word=0;var longest=0;var lastzero=0;var zstart=0;var len=0;var i=0;var parts=[ints[0]&65535,ints[0]>>16,ints[1]&65535,ints[1]>>16,ints[2]&65535,ints[2]>>16,ints[3]&65535,ints[3]>>16];var hasipv4=true;var v4part="";for(i=0;i<5;i++){if(parts[i]!==0){hasipv4=false;break}}if(hasipv4){v4part=inetNtop4(parts[6]|parts[7]<<16);if(parts[5]===-1){str="::ffff:";str+=v4part;return str}if(parts[5]===0){str="::";if(v4part==="0.0.0.0")v4part="";if(v4part==="0.0.0.1")v4part="1";str+=v4part;return str}}for(word=0;word<8;word++){if(parts[word]===0){if(word-lastzero>1){len=0}lastzero=word;len++}if(len>longest){longest=len;zstart=word-longest+1}}for(word=0;word<8;word++){if(longest>1){if(parts[word]===0&&word>=zstart&&word{var family=HEAP16[sa>>1];var port=_ntohs(HEAPU16[sa+2>>1]);var addr;switch(family){case 2:if(salen!==16){return{errno:28}}addr=HEAP32[sa+4>>2];addr=inetNtop4(addr);break;case 10:if(salen!==28){return{errno:28}}addr=[HEAP32[sa+8>>2],HEAP32[sa+12>>2],HEAP32[sa+16>>2],HEAP32[sa+20>>2]];addr=inetNtop6(addr);break;default:return{errno:5}}return{family,addr,port}};var getSocketAddress=(addrp,addrlen)=>{var info=readSockaddr(addrp,addrlen);if(info.errno)throw new FS.ErrnoError(info.errno);info.addr=DNS.lookup_addr(info.addr)||info.addr;return info};function ___syscall_bind(fd,addr,addrlen,d1,d2,d3){try{var sock=getSocketFromFD(fd);var info=getSocketAddress(addr,addrlen);sock.sock_ops.bind(sock,info.addr,info.port);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return dir+"/"+path},doStat(func,path,buf){var stat=func(path);HEAP32[buf>>2]=stat.dev;HEAP32[buf+4>>2]=stat.mode;HEAPU32[buf+8>>2]=stat.nlink;HEAP32[buf+12>>2]=stat.uid;HEAP32[buf+16>>2]=stat.gid;HEAP32[buf+20>>2]=stat.rdev;HEAP64[buf+24>>3]=BigInt(stat.size);HEAP32[buf+32>>2]=4096;HEAP32[buf+36>>2]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();HEAP64[buf+40>>3]=BigInt(Math.floor(atime/1e3));HEAPU32[buf+48>>2]=atime%1e3*1e3*1e3;HEAP64[buf+56>>3]=BigInt(Math.floor(mtime/1e3));HEAPU32[buf+64>>2]=mtime%1e3*1e3*1e3;HEAP64[buf+72>>3]=BigInt(Math.floor(ctime/1e3));HEAPU32[buf+80>>2]=ctime%1e3*1e3*1e3;HEAP64[buf+88>>3]=BigInt(stat.ino);return 0},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream},varargs:undefined,getStr(ptr){var ret=UTF8ToString(ptr);return ret}};function ___syscall_chdir(path){try{path=SYSCALLS.getStr(path);FS.chdir(path);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_chmod(path,mode){try{path=SYSCALLS.getStr(path);FS.chmod(path,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_connect(fd,addr,addrlen,d1,d2,d3){try{var sock=getSocketFromFD(fd);var info=getSocketAddress(addr,addrlen);sock.sock_ops.connect(sock,info.addr,info.port);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_dup(fd){try{var old=SYSCALLS.getStreamFromFD(fd);return FS.dupStream(old).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_dup3(fd,newfd,flags){try{var old=SYSCALLS.getStreamFromFD(fd);if(old.fd===newfd)return-28;if(newfd<0||newfd>=FS.MAX_OPEN_FDS)return-8;var existing=FS.getStream(newfd);if(existing)FS.close(existing);return FS.dupStream(old,newfd).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_faccessat(dirfd,path,amode,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(amode&~7){return-28}var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node){return-44}var perms="";if(amode&4)perms+="r";if(amode&2)perms+="w";if(amode&1)perms+="x";if(perms&&FS.nodePermissions(node,perms)){return-2}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var INT53_MAX=9007199254740992;var INT53_MIN=-9007199254740992;var bigintToI53Checked=num=>numINT53_MAX?NaN:Number(num);function ___syscall_fallocate(fd,mode,offset,len){offset=bigintToI53Checked(offset);len=bigintToI53Checked(len);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.allocate(stream,offset,len);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_fchmod(fd,mode){try{FS.fchmod(fd,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_fchown32(fd,owner,group){try{FS.fchown(fd,owner,group);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_fchownat(dirfd,path,owner,group,flags){try{path=SYSCALLS.getStr(path);var nofollow=flags&256;flags=flags&~256;path=SYSCALLS.calculateAt(dirfd,path);(nofollow?FS.lchown:FS.chown)(path,owner,group);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var syscallGetVarargI=()=>{var ret=HEAP32[+SYSCALLS.varargs>>2];SYSCALLS.varargs+=4;return ret};var syscallGetVarargP=syscallGetVarargI;function ___syscall_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=syscallGetVarargI();if(arg<0){return-28}while(FS.streams[arg]){arg++}var newStream;newStream=FS.dupStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=syscallGetVarargI();stream.flags|=arg;return 0}case 12:{var arg=syscallGetVarargP();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 13:case 14:return 0}return-28}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_fdatasync(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_fstat64(fd,buf){try{var stream=SYSCALLS.getStreamFromFD(fd);return SYSCALLS.doStat(FS.stat,stream.path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_ftruncate64(fd,length){length=bigintToI53Checked(length);try{if(isNaN(length))return 61;FS.ftruncate(fd,length);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);Module["stringToUTF8"]=stringToUTF8;function ___syscall_getcwd(buf,size){try{if(size===0)return-28;var cwd=FS.cwd();var cwdLengthInBytes=lengthBytesUTF8(cwd)+1;if(size>3]=BigInt(id);HEAP64[dirp+pos+8>>3]=BigInt((idx+1)*struct_size);HEAP16[dirp+pos+16>>1]=280;HEAP8[dirp+pos+18]=type;stringToUTF8(name,dirp+pos+19,256);pos+=struct_size}FS.llseek(stream,idx*struct_size,0);return pos}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_getpeername(fd,addr,addrlen,d1,d2,d3){try{var sock=getSocketFromFD(fd);if(!sock.daddr){return-53}var errno=writeSockaddr(addr,sock.family,DNS.lookup_name(sock.daddr),sock.dport,addrlen);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_getsockname(fd,addr,addrlen,d1,d2,d3){try{var sock=getSocketFromFD(fd);var errno=writeSockaddr(addr,sock.family,DNS.lookup_name(sock.saddr||"0.0.0.0"),sock.sport,addrlen);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_getsockopt(fd,level,optname,optval,optlen,d1){try{var sock=getSocketFromFD(fd);if(level===1){if(optname===4){HEAP32[optval>>2]=sock.error;HEAP32[optlen>>2]=4;sock.error=null;return 0}}return-50}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_ioctl(fd,op,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:{if(!stream.tty)return-59;return 0}case 21505:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcgets){var termios=stream.tty.ops.ioctl_tcgets(stream);var argp=syscallGetVarargP();HEAP32[argp>>2]=termios.c_iflag||0;HEAP32[argp+4>>2]=termios.c_oflag||0;HEAP32[argp+8>>2]=termios.c_cflag||0;HEAP32[argp+12>>2]=termios.c_lflag||0;for(var i=0;i<32;i++){HEAP8[argp+i+17]=termios.c_cc[i]||0}return 0}return 0}case 21510:case 21511:case 21512:{if(!stream.tty)return-59;return 0}case 21506:case 21507:case 21508:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcsets){var argp=syscallGetVarargP();var c_iflag=HEAP32[argp>>2];var c_oflag=HEAP32[argp+4>>2];var c_cflag=HEAP32[argp+8>>2];var c_lflag=HEAP32[argp+12>>2];var c_cc=[];for(var i=0;i<32;i++){c_cc.push(HEAP8[argp+i+17])}return stream.tty.ops.ioctl_tcsets(stream.tty,op,{c_iflag,c_oflag,c_cflag,c_lflag,c_cc})}return 0}case 21519:{if(!stream.tty)return-59;var argp=syscallGetVarargP();HEAP32[argp>>2]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=syscallGetVarargP();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tiocgwinsz){var winsize=stream.tty.ops.ioctl_tiocgwinsz(stream.tty);var argp=syscallGetVarargP();HEAP16[argp>>1]=winsize[0];HEAP16[argp+2>>1]=winsize[1]}return 0}case 21524:{if(!stream.tty)return-59;return 0}case 21515:{if(!stream.tty)return-59;return 0}default:return-28}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_listen(fd,backlog){try{var sock=getSocketFromFD(fd);sock.sock_ops.listen(sock,backlog);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_lstat64(path,buf){try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.lstat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_mkdirat(dirfd,path,mode){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);FS.mkdir(path,mode,0);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_newfstatat(dirfd,path,buf,flags){try{path=SYSCALLS.getStr(path);var nofollow=flags&256;var allowEmpty=flags&4096;flags=flags&~6400;path=SYSCALLS.calculateAt(dirfd,path,allowEmpty);return SYSCALLS.doStat(nofollow?FS.lstat:FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_openat(dirfd,path,flags,varargs){SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?syscallGetVarargI():0;return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var PIPEFS={BUCKET_BUFFER_SIZE:8192,mount(mount){return FS.createNode(null,"/",16384|511,0)},createPipe(){var pipe={buckets:[],refcnt:2};pipe.buckets.push({buffer:new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),offset:0,roffset:0});var rName=PIPEFS.nextname();var wName=PIPEFS.nextname();var rNode=FS.createNode(PIPEFS.root,rName,4096,0);var wNode=FS.createNode(PIPEFS.root,wName,4096,0);rNode.pipe=pipe;wNode.pipe=pipe;var readableStream=FS.createStream({path:rName,node:rNode,flags:0,seekable:false,stream_ops:PIPEFS.stream_ops});rNode.stream=readableStream;var writableStream=FS.createStream({path:wName,node:wNode,flags:1,seekable:false,stream_ops:PIPEFS.stream_ops});wNode.stream=writableStream;return{readable_fd:readableStream.fd,writable_fd:writableStream.fd}},stream_ops:{poll(stream){var pipe=stream.node.pipe;if((stream.flags&2097155)===1){return 256|4}if(pipe.buckets.length>0){for(var i=0;i0){return 64|1}}}return 0},ioctl(stream,request,varargs){return 28},fsync(stream){return 28},read(stream,buffer,offset,length,position){var pipe=stream.node.pipe;var currentLength=0;for(var i=0;i=dataLen){currBucket.buffer.set(data,currBucket.offset);currBucket.offset+=dataLen;return dataLen}else if(freeBytesInCurrBuffer>0){currBucket.buffer.set(data.subarray(0,freeBytesInCurrBuffer),currBucket.offset);currBucket.offset+=freeBytesInCurrBuffer;data=data.subarray(freeBytesInCurrBuffer,data.byteLength)}var numBuckets=data.byteLength/PIPEFS.BUCKET_BUFFER_SIZE|0;var remElements=data.byteLength%PIPEFS.BUCKET_BUFFER_SIZE;for(var i=0;i0){var newBucket={buffer:new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),offset:data.byteLength,roffset:0};pipe.buckets.push(newBucket);newBucket.buffer.set(data)}return dataLen},close(stream){var pipe=stream.node.pipe;pipe.refcnt--;if(pipe.refcnt===0){pipe.buckets=null}}},nextname(){if(!PIPEFS.nextname.current){PIPEFS.nextname.current=0}return"pipe["+PIPEFS.nextname.current+++"]"}};function ___syscall_pipe(fdPtr){try{if(fdPtr==0){throw new FS.ErrnoError(21)}var res=PIPEFS.createPipe();HEAP32[fdPtr>>2]=res.readable_fd;HEAP32[fdPtr+4>>2]=res.writable_fd;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_poll(fds,nfds,timeout){try{var nonzero=0;for(var i=0;i>2];var events=HEAP16[pollfd+4>>1];var mask=32;var stream=FS.getStream(fd);if(stream){mask=SYSCALLS.DEFAULT_POLLMASK;if (stream.stream_ops?.poll){mask=stream.stream_ops.poll(stream,-1)}}mask&=events|8|16;if(mask)nonzero++;HEAP16[pollfd+6>>1]=mask}return nonzero}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_readlinkat(dirfd,path,buf,bufsize){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(bufsize<=0)return-28;var ret=FS.readlink(path);var len=Math.min(bufsize,lengthBytesUTF8(ret));var endChar=HEAP8[buf+len];stringToUTF8(ret,buf,bufsize+1);HEAP8[buf+len]=endChar;return len}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_recvfrom(fd,buf,len,flags,addr,addrlen){try{var sock=getSocketFromFD(fd);var msg=sock.sock_ops.recvmsg(sock, len, typeof flags !== "undefined" ? flags : 0);if(!msg)return 0;if(addr){var errno=writeSockaddr(addr,sock.family,DNS.lookup_name(msg.addr),msg.port,addrlen)}HEAPU8.set(msg.buffer,buf);return msg.buffer.byteLength}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_renameat(olddirfd,oldpath,newdirfd,newpath){try{oldpath=SYSCALLS.getStr(oldpath);newpath=SYSCALLS.getStr(newpath);oldpath=SYSCALLS.calculateAt(olddirfd,oldpath);newpath=SYSCALLS.calculateAt(newdirfd,newpath);FS.rename(oldpath,newpath);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_rmdir(path){try{path=SYSCALLS.getStr(path);FS.rmdir(path);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_sendto(fd,message,length,flags,addr,addr_len){try{var sock=getSocketFromFD(fd);if(!addr){return FS.write(sock.stream,HEAP8,message,length)}var dest=getSocketAddress(addr,addr_len);return sock.sock_ops.sendmsg(sock,HEAP8,message,length,dest.addr,dest.port)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_socket(domain,type,protocol){try{var sock=SOCKFS.createSocket(domain,type,protocol);return sock.stream.fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_stat64(path,buf){try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_statfs64(path,size,buf){try{var stats=FS.statfs(SYSCALLS.getStr(path));HEAP32[buf+4>>2]=stats.bsize;HEAP32[buf+40>>2]=stats.bsize;HEAP32[buf+8>>2]=stats.blocks;HEAP32[buf+12>>2]=stats.bfree;HEAP32[buf+16>>2]=stats.bavail;HEAP32[buf+20>>2]=stats.files;HEAP32[buf+24>>2]=stats.ffree;HEAP32[buf+28>>2]=stats.fsid;HEAP32[buf+44>>2]=stats.flags;HEAP32[buf+36>>2]=stats.namelen;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_symlinkat(target,dirfd,linkpath){try{target=SYSCALLS.getStr(target);linkpath=SYSCALLS.getStr(linkpath);linkpath=SYSCALLS.calculateAt(dirfd,linkpath);FS.symlink(target,linkpath);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_unlinkat(dirfd,path,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(flags===0){FS.unlink(path)}else if(flags===512){FS.rmdir(path)}else{abort("Invalid flags passed to unlinkat")}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var readI53FromI64=ptr=>HEAPU32[ptr>>2]+HEAP32[ptr+4>>2]*4294967296;function ___syscall_utimensat(dirfd,path,times,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path,true);var now=Date.now(),atime,mtime;if(!times){atime=now;mtime=now}else{var seconds=readI53FromI64(times);var nanoseconds=HEAP32[times+8>>2];if(nanoseconds==1073741823){atime=now}else if(nanoseconds==1073741822){atime=null}else{atime=seconds*1e3+nanoseconds/(1e3*1e3)}times+=16;seconds=readI53FromI64(times);nanoseconds=HEAP32[times+8>>2];if(nanoseconds==1073741823){mtime=now}else if(nanoseconds==1073741822){mtime=null}else{mtime=seconds*1e3+nanoseconds/(1e3*1e3)}}if((mtime??atime)!==null){FS.utime(path,atime,mtime)}return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var __abort_js=()=>abort("");var __emscripten_lookup_name=name=>{var nameString=UTF8ToString(name);return inetPton4(DNS.lookup_name(nameString))};var runtimeKeepaliveCounter=0;var __emscripten_runtime_keepalive_clear=()=>{noExitRuntime=false;runtimeKeepaliveCounter=0};function __gmtime_js(time,tmPtr){time=bigintToI53Checked(time);var date=new Date(time*1e3);HEAP32[tmPtr>>2]=date.getUTCSeconds();HEAP32[tmPtr+4>>2]=date.getUTCMinutes();HEAP32[tmPtr+8>>2]=date.getUTCHours();HEAP32[tmPtr+12>>2]=date.getUTCDate();HEAP32[tmPtr+16>>2]=date.getUTCMonth();HEAP32[tmPtr+20>>2]=date.getUTCFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getUTCDay();var start=Date.UTC(date.getUTCFullYear(),0,1,0,0,0,0);var yday=(date.getTime()-start)/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>2]=yday}var isLeapYear=year=>year%4===0&&(year%100!==0||year%400===0);var MONTH_DAYS_LEAP_CUMULATIVE=[0,31,60,91,121,152,182,213,244,274,305,335];var MONTH_DAYS_REGULAR_CUMULATIVE=[0,31,59,90,120,151,181,212,243,273,304,334];var ydayFromDate=date=>{var leap=isLeapYear(date.getFullYear());var monthDaysCumulative=leap?MONTH_DAYS_LEAP_CUMULATIVE:MONTH_DAYS_REGULAR_CUMULATIVE;var yday=monthDaysCumulative[date.getMonth()]+date.getDate()-1;return yday};function __localtime_js(time,tmPtr){time=bigintToI53Checked(time);var date=new Date(time*1e3);HEAP32[tmPtr>>2]=date.getSeconds();HEAP32[tmPtr+4>>2]=date.getMinutes();HEAP32[tmPtr+8>>2]=date.getHours();HEAP32[tmPtr+12>>2]=date.getDate();HEAP32[tmPtr+16>>2]=date.getMonth();HEAP32[tmPtr+20>>2]=date.getFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr+36>>2]=-(date.getTimezoneOffset()*60);var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dst=(summerOffset!=winterOffset&&date.getTimezoneOffset()==Math.min(winterOffset,summerOffset))|0;HEAP32[tmPtr+32>>2]=dst}var __mktime_js=function(tmPtr){var ret=(()=>{var date=new Date(HEAP32[tmPtr+20>>2]+1900,HEAP32[tmPtr+16>>2],HEAP32[tmPtr+12>>2],HEAP32[tmPtr+8>>2],HEAP32[tmPtr+4>>2],HEAP32[tmPtr>>2],0);var dst=HEAP32[tmPtr+32>>2];var guessedOffset=date.getTimezoneOffset();var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dstOffset=Math.min(winterOffset,summerOffset);if(dst<0){HEAP32[tmPtr+32>>2]=Number(summerOffset!=winterOffset&&dstOffset==guessedOffset)}else if(dst>0!=(dstOffset==guessedOffset)){var nonDstOffset=Math.max(winterOffset,summerOffset);var trueOffset=dst>0?dstOffset:nonDstOffset;date.setTime(date.getTime()+(trueOffset-guessedOffset)*6e4)}HEAP32[tmPtr+24>>2]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr>>2]=date.getSeconds();HEAP32[tmPtr+4>>2]=date.getMinutes();HEAP32[tmPtr+8>>2]=date.getHours();HEAP32[tmPtr+12>>2]=date.getDate();HEAP32[tmPtr+16>>2]=date.getMonth();HEAP32[tmPtr+20>>2]=date.getYear();var timeMs=date.getTime();if(isNaN(timeMs)){return-1}return timeMs/1e3})();return BigInt(ret)};function __mmap_js(len,prot,flags,fd,offset,allocated,addr){offset=bigintToI53Checked(offset);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);var res=FS.mmap(stream,len,offset,prot,flags);var ptr=res.ptr;HEAP32[allocated>>2]=res.allocated;HEAPU32[addr>>2]=ptr;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function __munmap_js(addr,len,prot,flags,fd,offset){offset=bigintToI53Checked(offset);try{var stream=SYSCALLS.getStreamFromFD(fd);if(prot&2){SYSCALLS.doMsync(addr,stream,len,flags,offset)}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var timers={};var handleException=e=>{if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e)};var keepRuntimeAlive=()=>noExitRuntime||runtimeKeepaliveCounter>0;var _proc_exit=code=>{EXITSTATUS=code;if(!keepRuntimeAlive()){Module["onExit"]?.(code);ABORT=true}quit_(code,new ExitStatus(code))};var exitJS=(status,implicit)=>{EXITSTATUS=status;if(!keepRuntimeAlive()){exitRuntime()}_proc_exit(status)};var _exit=exitJS;Module["_exit"]=_exit;var maybeExit=()=>{if(runtimeExited){return}if(!keepRuntimeAlive()){try{_exit(EXITSTATUS)}catch(e){handleException(e)}}};var callUserCallback=func=>{if(runtimeExited||ABORT){return}try{func();maybeExit()}catch(e){handleException(e)}};var _emscripten_get_now=()=>performance.now();var __setitimer_js=(which,timeout_ms)=>{if(timers[which]){clearTimeout(timers[which].id);delete timers[which]}if(!timeout_ms)return 0;var id=setTimeout(()=>{delete timers[which];callUserCallback(()=>__emscripten_timeout(which,_emscripten_get_now()))},timeout_ms);timers[which]={id,timeout_ms};return 0};var __tzset_js=(timezone,daylight,std_name,dst_name)=>{var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);var winterOffset=winter.getTimezoneOffset();var summerOffset=summer.getTimezoneOffset();var stdTimezoneOffset=Math.max(winterOffset,summerOffset);HEAPU32[timezone>>2]=stdTimezoneOffset*60;HEAP32[daylight>>2]=Number(winterOffset!=summerOffset);var extractZone=timezoneOffset=>{var sign=timezoneOffset>=0?"-":"+";var absOffset=Math.abs(timezoneOffset);var hours=String(Math.floor(absOffset/60)).padStart(2,"0");var minutes=String(absOffset%60).padStart(2,"0");return`UTC${sign}${hours}${minutes}`};var winterName=extractZone(winterOffset);var summerName=extractZone(summerOffset);if(summerOffsetDate.now();var nowIsMonotonic=1;var checkWasiClock=clock_id=>clock_id>=0&&clock_id<=3;function _clock_time_get(clk_id,ignored_precision,ptime){ignored_precision=bigintToI53Checked(ignored_precision);if(!checkWasiClock(clk_id)){return 28}var now;if(clk_id===0){now=_emscripten_date_now()}else if(nowIsMonotonic){now=_emscripten_get_now()}else{return 52}var nsec=Math.round(now*1e3*1e3);HEAP64[ptime>>3]=BigInt(nsec);return 0}var getHeapMax=()=>2147483648;var _emscripten_get_heap_max=()=>getHeapMax();var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=HEAPU8.length;requestedSize>>>=0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var runtimeKeepalivePush=()=>{runtimeKeepaliveCounter+=1};var runtimeKeepalivePop=()=>{runtimeKeepaliveCounter-=1};var safeSetTimeout=(func,timeout)=>{runtimeKeepalivePush();return setTimeout(()=>{runtimeKeepalivePop();callUserCallback(func)},timeout)};var _emscripten_sleep=ms=>Asyncify.handleSleep(wakeUp=>safeSetTimeout(wakeUp,ms));Module["_emscripten_sleep"]=_emscripten_sleep;_emscripten_sleep.isAsync=true;var ENV = PHPLoader.ENV || {};var getExecutableName=()=>thisProgram||"./this.program";var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:lang,_:getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`)}getEnvStrings.strings=strings}return getEnvStrings.strings};var stringToAscii=(str,buffer)=>{for(var i=0;i{var bufSize=0;getEnvStrings().forEach((string,i)=>{var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>2]=ptr;stringToAscii(string,ptr);bufSize+=string.length+1});return 0};var _environ_sizes_get=(penviron_count,penviron_buf_size)=>{var strings=getEnvStrings();HEAPU32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(string=>bufSize+=string.length+1);HEAPU32[penviron_buf_size>>2]=bufSize;return 0};function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_fdstat_get(fd,pbuf){try{var rightsBase=0;var rightsInheriting=0;var flags=0;{var stream=SYSCALLS.getStreamFromFD(fd);var type=stream.tty?2:FS.isDir(stream.mode)?3:FS.isLink(stream.mode)?7:4}HEAP8[pbuf]=type;HEAP16[pbuf+2>>1]=flags;HEAP64[pbuf+8>>3]=BigInt(rightsBase);HEAP64[pbuf+16>>3]=BigInt(rightsInheriting);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_seek(fd,offset,whence,newOffset){offset=bigintToI53Checked(offset);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);HEAP64[newOffset>>3]=BigInt(stream.position);if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var _getaddrinfo=(node,service,hint,out)=>{var addr=0;var port=0;var flags=0;var family=0;var type=0;var proto=0;var ai;function allocaddrinfo(family,type,proto,canon,addr,port){var sa,salen,ai;var errno;salen=family===10?28:16;addr=family===10?inetNtop6(addr):inetNtop4(addr);sa=_malloc(salen);errno=writeSockaddr(sa,family,addr,port);assert(!errno);ai=_malloc(32);HEAP32[ai+4>>2]=family;HEAP32[ai+8>>2]=type;HEAP32[ai+12>>2]=proto;HEAPU32[ai+24>>2]=canon;HEAPU32[ai+20>>2]=sa;if(family===10){HEAP32[ai+16>>2]=28}else{HEAP32[ai+16>>2]=16}HEAP32[ai+28>>2]=0;return ai}if(hint){flags=HEAP32[hint>>2];family=HEAP32[hint+4>>2];type=HEAP32[hint+8>>2];proto=HEAP32[hint+12>>2]}if(type&&!proto){proto=type===2?17:6}if(!type&&proto){type=proto===17?2:1}if(proto===0){proto=6}if(type===0){type=1}if(!node&&!service){return-2}if(flags&~(1|2|4|1024|8|16|32)){return-1}if(hint!==0&&HEAP32[hint>>2]&2&&!node){return-1}if(flags&32){return-2}if(type!==0&&type!==1&&type!==2){return-7}if(family!==0&&family!==2&&family!==10){return-6}if(service){service=UTF8ToString(service);port=parseInt(service,10);if(isNaN(port)){if(flags&1024){return-2}return-8}}if(!node){if(family===0){family=2}if((flags&1)===0){if(family===2){addr=_htonl(2130706433)}else{addr=[0,0,0,_htonl(1)]}}ai=allocaddrinfo(family,type,proto,null,addr,port);HEAPU32[out>>2]=ai;return 0}node=UTF8ToString(node);addr=inetPton4(node);if(addr!==null){if(family===0||family===2){family=2}else if(family===10&&flags&8){addr=[0,0,_htonl(65535),addr];family=10}else{return-2}}else{addr=inetPton6(node);if(addr!==null){if(family===0||family===10){family=10}else{return-2}}}if(addr!=null){ai=allocaddrinfo(family,type,proto,node,addr,port);HEAPU32[out>>2]=ai;return 0}if(flags&4){return-2}node=DNS.lookup_name(node);addr=inetPton4(node);if(family===0){family=2}else if(family===10){addr=[0,0,_htonl(65535),addr]}ai=allocaddrinfo(family,type,proto,null,addr,port);HEAPU32[out>>2]=ai;return 0};var _getnameinfo=(sa,salen,node,nodelen,serv,servlen,flags)=>{var info=readSockaddr(sa,salen);if(info.errno){return-6}var port=info.port;var addr=info.addr;var overflowed=false;if(node&&nodelen){var lookup;if(flags&1||!(lookup=DNS.lookup_addr(addr))){if(flags&8){return-2}}else{addr=lookup}var numBytesWrittenExclNull=stringToUTF8(addr,node,nodelen);if(numBytesWrittenExclNull+1>=nodelen){overflowed=true}}if(serv&&servlen){port=""+port;var numBytesWrittenExclNull=stringToUTF8(port,serv,servlen);if(numBytesWrittenExclNull+1>=servlen){overflowed=true}}if(overflowed){return-12}return 0};var Protocols={list:[],map:{}};var _setprotoent=stayopen=>{function allocprotoent(name,proto,aliases){var nameBuf=_malloc(name.length+1);stringToAscii(name,nameBuf);var j=0;var length=aliases.length;var aliasListBuf=_malloc((length+1)*4);for(var i=0;i>2]=aliasBuf}HEAPU32[aliasListBuf+j>>2]=0;var pe=_malloc(12);HEAPU32[pe>>2]=nameBuf;HEAPU32[pe+4>>2]=aliasListBuf;HEAP32[pe+8>>2]=proto;return pe}var list=Protocols.list;var map=Protocols.map;if(list.length===0){var entry=allocprotoent("tcp",6,["TCP"]);list.push(entry);map["tcp"]=map["6"]=entry;entry=allocprotoent("udp",17,["UDP"]);list.push(entry);map["udp"]=map["17"]=entry}_setprotoent.index=0};var _getprotobyname=name=>{name=UTF8ToString(name);_setprotoent(true);var result=Protocols.map[name];return result};var _getprotobynumber=number=>{_setprotoent(true);var result=Protocols.map[number];return result};var stackAlloc=sz=>__emscripten_stack_alloc(sz);var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var allocateUTF8OnStack=stringToUTF8OnStack;var PHPWASM={init:function(){FS.mkdir("/internal");FS.mkdir("/internal/shared");FS.mkdir("/internal/shared/preload");PHPWASM.EventEmitter=ENVIRONMENT_IS_NODE?require("events").EventEmitter:class EventEmitter{constructor(){this.listeners={}}emit(eventName,data){if(this.listeners[eventName]){this.listeners[eventName].forEach(callback=>{callback(data)})}}once(eventName,callback){const self=this;function removedCallback(){callback(...arguments);self.removeListener(eventName,removedCallback)}this.on(eventName,removedCallback)}removeAllListeners(eventName){if(eventName){delete this.listeners[eventName]}else{this.listeners={}}}removeListener(eventName,callback){if(this.listeners[eventName]){const idx=this.listeners[eventName].indexOf(callback);if(idx!==-1){this.listeners[eventName].splice(idx,1)}}}};PHPWASM.child_proc_by_fd={};PHPWASM.child_proc_by_pid={};PHPWASM.input_devices={}},getAllWebSockets:function(sock){const webSockets=new Set;if(sock.server){sock.server.clients.forEach(ws=>{webSockets.add(ws)})}for(const peer of PHPWASM.getAllPeers(sock)){webSockets.add(peer.socket)}return Array.from(webSockets)},getAllPeers:function(sock){const peers=new Set;if(sock.server){sock.pending.filter(pending=>pending.peers).forEach(pending=>{for(const peer of Object.values(pending.peers)){peers.add(peer)}})}if(sock.peers){for(const peer of Object.values(sock.peers)){peers.add(peer)}}return Array.from(peers)},awaitData:function(ws){return PHPWASM.awaitEvent(ws,"message")},awaitConnection:function(ws){if(ws.OPEN===ws.readyState){return[Promise.resolve(),PHPWASM.noop]}return PHPWASM.awaitEvent(ws,"open")},awaitClose:function(ws){if([ws.CLOSING,ws.CLOSED].includes(ws.readyState)){return[Promise.resolve(),PHPWASM.noop]}return PHPWASM.awaitEvent(ws,"close")},awaitError:function(ws){if([ws.CLOSING,ws.CLOSED].includes(ws.readyState)){return[Promise.resolve(),PHPWASM.noop]}return PHPWASM.awaitEvent(ws,"error")},awaitEvent:function(ws,event){let resolve;const listener=()=>{resolve()};const promise=new Promise(function(_resolve){resolve=_resolve;ws.once(event,listener)});const cancel=()=>{ws.removeListener(event,listener);setTimeout(resolve)};return[promise,cancel]},noop:function(){},spawnProcess:function(command,args,options){if(Module["spawnProcess"]){const spawnedPromise=Module["spawnProcess"](command,args,options);return Promise.resolve(spawnedPromise).then(function(spawned){if(!spawned||!spawned.on){throw new Error("spawnProcess() must return an EventEmitter but returned a different type.")}return spawned})}if(ENVIRONMENT_IS_NODE){return require("child_process").spawn(command,args,{...options,shell:true,stdio:["pipe","pipe","pipe"],timeout:100})}const e=new Error("popen(), proc_open() etc. are unsupported in the browser. Call php.setSpawnHandler() "+"and provide a callback to handle spawning processes, or disable a popen(), proc_open() "+"and similar functions via php.ini.");e.code="SPAWN_UNSUPPORTED";throw e},shutdownSocket:function(socketd,how){const sock=getSocketFromFD(socketd);const peer=Object.values(sock.peers)[0];if(!peer){return-1}try{peer.socket.close();SOCKFS.websocket_sock_ops.removePeer(sock,peer);return 0}catch(e){console.log("Socket shutdown error",e);return-1}}};function _js_create_input_device(deviceId){let dataBuffer=[];let dataCallback;const filename="proc_id_"+deviceId;const device=FS.createDevice("/dev",filename,function(){},function(byte){try{dataBuffer.push(byte);if(dataCallback){dataCallback(new Uint8Array(dataBuffer));dataBuffer=[]}}catch(e){console.error(e);throw e}});const devicePath="/dev/"+filename;PHPWASM.input_devices[deviceId]={devicePath,onData:function(cb){dataCallback=cb;dataBuffer.forEach(function(data){cb(data)});dataBuffer.length=0}};return allocateUTF8OnStack(devicePath)}function _js_open_process(command,argsPtr,argsLength,descriptorsPtr,descriptorsLength,cwdPtr,cwdLength,envPtr,envLength){if(!command){return 1}const cmdstr=UTF8ToString(command);if(!cmdstr.length){return 0}let argsArray=[];if(argsLength){for(var i=0;i>2]))}}const cwdstr=cwdPtr?UTF8ToString(cwdPtr):null;let envObject=null;if(envLength){envObject={};for(var i=0;i>2]);const splitAt=envEntry.indexOf("=");if(splitAt===-1){continue}const key=envEntry.substring(0,splitAt);const value=envEntry.substring(splitAt+1);envObject[key]=value}}var std={};for(var i=0;i>2];std[HEAPU32[descriptorPtr>>2]]={child:HEAPU32[descriptorPtr+4>>2],parent:HEAPU32[descriptorPtr+8>>2]}}return Asyncify.handleSleep(async wakeUp=>{let cp;try{const options={};if(cwdstr!==null){options.cwd=cwdstr}if(envObject!==null){options.env=envObject}cp=PHPWASM.spawnProcess(cmdstr,argsArray,options);if(cp instanceof Promise){cp=await cp}}catch(e){if(e.code==="SPAWN_UNSUPPORTED"){wakeUp(1);return}console.error(e);wakeUp(1);throw e}const ProcInfo={pid:cp.pid,exited:false,stdinFd:std[0]?.child,stdinIsDevice:std[0]?.child in PHPWASM.input_devices,stdoutChildFd:std[1]?.child,stdoutParentFd:std[1]?.parent,stderrChildFd:std[2]?.child,stderrParentFd:std[2]?.parent,stdout:new PHPWASM.EventEmitter,stderr:new PHPWASM.EventEmitter};if(ProcInfo.stdoutChildFd)PHPWASM.child_proc_by_fd[ProcInfo.stdoutChildFd]=ProcInfo;if(ProcInfo.stderrChildFd)PHPWASM.child_proc_by_fd[ProcInfo.stderrChildFd]=ProcInfo;if(ProcInfo.stdoutParentFd)PHPWASM.child_proc_by_fd[ProcInfo.stdoutParentFd]=ProcInfo;if(ProcInfo.stderrParentFd)PHPWASM.child_proc_by_fd[ProcInfo.stderrParentFd]=ProcInfo;PHPWASM.child_proc_by_pid[ProcInfo.pid]=ProcInfo;cp.on("exit",function(code){ProcInfo.exitCode=code;ProcInfo.exited=true;ProcInfo.stdout.emit("data");ProcInfo.stderr.emit("data")});if(ProcInfo.stdoutChildFd){const stdoutStream=SYSCALLS.getStreamFromFD(ProcInfo.stdoutChildFd);let stdoutAt=0;cp.stdout.on("data",function(data){ProcInfo.stdout.emit("data",data);stdoutStream.stream_ops.write(stdoutStream,data,0,data.length,stdoutAt);stdoutAt+=data.length})}if(ProcInfo.stderrChildFd){const stderrStream=SYSCALLS.getStreamFromFD(ProcInfo.stderrChildFd);let stderrAt=0;cp.stderr.on("data",function(data){ProcInfo.stderr.emit("data",data);stderrStream.stream_ops.write(stderrStream,data,0,data.length,stderrAt);stderrAt+=data.length})}try{await new Promise((resolve,reject)=>{cp.on("spawn",resolve);cp.on("error",reject)})}catch(e){console.error(e);wakeUp(1);return}if(ProcInfo.stdinIsDevice){PHPWASM.input_devices[ProcInfo.stdinFd].onData(function(data){if(!data)return;if(typeof data==="number"){data=new Uint8Array([data])}const dataStr=new TextDecoder("utf-8").decode(data);cp.stdin.write(dataStr)});wakeUp(ProcInfo.pid);return}if(ProcInfo.stdinFd){const stdinStream=SYSCALLS.getStreamFromFD(ProcInfo.stdinFd);if(stdinStream.node){const CHUNK_SIZE=1024;const buffer=new Uint8Array(CHUNK_SIZE);let offset=0;while(true){const bytesRead=stdinStream.stream_ops.read(stdinStream,buffer,0,CHUNK_SIZE,offset);if(bytesRead===null||bytesRead===0){break}try{cp.stdin.write(buffer.subarray(0,bytesRead))}catch(e){console.error(e);return 1}if(bytesRead>2]=PHPWASM.child_proc_by_pid[pid].exitCode;return 1}return 0}function _js_waitpid(pid,exitCodePtr){if(!PHPWASM.child_proc_by_pid[pid]){return-1}return Asyncify.handleSleep(wakeUp=>{const poll=function(){if(PHPWASM.child_proc_by_pid[pid]?.exited){HEAPU32[exitCodePtr>>2]=PHPWASM.child_proc_by_pid[pid].exitCode;wakeUp(pid)}else{setTimeout(poll,50)}};poll()})}var arraySum=(array,index)=>{var sum=0;for(var i=0;i<=index;sum+=array[i++]){}return sum};var MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];var MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];var addDays=(date,days)=>{var newDate=new Date(date.getTime());while(days>0){var leap=isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate};var _strptime=(buf,format,tm)=>{var pattern=UTF8ToString(format);var SPECIAL_CHARS="\\!@#$^&*()+=-[]/{}|:<>?,.";for(var i=0,ii=SPECIAL_CHARS.length;iEQUIVALENT_MATCHERS[c]||m).replace(/%(.)/g,(_,c)=>{let pat=DATE_PATTERNS[c];if(pat){capture.push(c);return`(${pat})`}else{return c}}).replace(/\s+/g,"\\s*");var matches=new RegExp("^"+pattern_out,"i").exec(UTF8ToString(buf));function initDate(){function fixup(value,min,max){return typeof value!="number"||isNaN(value)?min:value>=min?value<=max?value:max:min}return{year:fixup(HEAP32[tm+20>>2]+1900,1970,9999),month:fixup(HEAP32[tm+16>>2],0,11),day:fixup(HEAP32[tm+12>>2],1,31),hour:fixup(HEAP32[tm+8>>2],0,23),min:fixup(HEAP32[tm+4>>2],0,59),sec:fixup(HEAP32[tm>>2],0,59),gmtoff:0}}if(matches){var date=initDate();var value;var getMatch=symbol=>{var pos=capture.indexOf(symbol);if(pos>=0){return matches[pos+1]}return};if(value=getMatch("S")){date.sec=jstoi_q(value)}if(value=getMatch("M")){date.min=jstoi_q(value)}if(value=getMatch("H")){date.hour=jstoi_q(value)}else if(value=getMatch("I")){var hour=jstoi_q(value);if(value=getMatch("p")){hour+=value.toUpperCase()[0]==="P"?12:0}date.hour=hour}if(value=getMatch("Y")){date.year=jstoi_q(value)}else if(value=getMatch("y")){var year=jstoi_q(value);if(value=getMatch("C")){year+=jstoi_q(value)*100}else{year+=year<69?2e3:1900}date.year=year}if(value=getMatch("m")){date.month=jstoi_q(value)-1}else if(value=getMatch("b")){date.month=MONTH_NUMBERS[value.substring(0,3).toUpperCase()]||0}if(value=getMatch("d")){date.day=jstoi_q(value)}else if(value=getMatch("j")){var day=jstoi_q(value);var leapYear=isLeapYear(date.year);for(var month=0;month<12;++month){var daysUntilMonth=arraySum(leapYear?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR,month-1);if(day<=daysUntilMonth+(leapYear?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR)[month]){date.day=day-daysUntilMonth}}}else if(value=getMatch("a")){var weekDay=value.substring(0,3).toUpperCase();if(value=getMatch("U")){var weekDayNumber=DAY_NUMBERS_SUN_FIRST[weekDay];var weekNumber=jstoi_q(value);var janFirst=new Date(date.year,0,1);var endDate;if(janFirst.getDay()===0){endDate=addDays(janFirst,weekDayNumber+7*(weekNumber-1))}else{endDate=addDays(janFirst,7-janFirst.getDay()+weekDayNumber+7*(weekNumber-1))}date.day=endDate.getDate();date.month=endDate.getMonth()}else if(value=getMatch("W")){var weekDayNumber=DAY_NUMBERS_MON_FIRST[weekDay];var weekNumber=jstoi_q(value);var janFirst=new Date(date.year,0,1);var endDate;if(janFirst.getDay()===1){endDate=addDays(janFirst,weekDayNumber+7*(weekNumber-1))}else{endDate=addDays(janFirst,7-janFirst.getDay()+1+weekDayNumber+7*(weekNumber-1))}date.day=endDate.getDate();date.month=endDate.getMonth()}}if(value=getMatch("z")){if(value.toLowerCase()==="z"){date.gmtoff=0}else{var match=value.match(/^((?:\-|\+)\d\d):?(\d\d)?/);date.gmtoff=match[1]*3600;if(match[2]){date.gmtoff+=date.gmtoff>0?match[2]*60:-match[2]*60}}}var fullDate=new Date(date.year,date.month,date.day,date.hour,date.min,date.sec,0);HEAP32[tm>>2]=fullDate.getSeconds();HEAP32[tm+4>>2]=fullDate.getMinutes();HEAP32[tm+8>>2]=fullDate.getHours();HEAP32[tm+12>>2]=fullDate.getDate();HEAP32[tm+16>>2]=fullDate.getMonth();HEAP32[tm+20>>2]=fullDate.getFullYear()-1900;HEAP32[tm+24>>2]=fullDate.getDay();HEAP32[tm+28>>2]=arraySum(isLeapYear(fullDate.getFullYear())?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR,fullDate.getMonth()-1)+fullDate.getDate()-1;HEAP32[tm+32>>2]=0;HEAP32[tm+36>>2]=date.gmtoff;return buf+intArrayFromString(matches[0]).length-1}return 0};function _wasm_setsockopt(socketd,level,optionName,optionValuePtr,optionLen){const optionValue=HEAPU8[optionValuePtr];const SOL_SOCKET=1;const SO_KEEPALIVE=9;const IPPROTO_TCP=6;const TCP_NODELAY=1;const isSupported=level===SOL_SOCKET&&optionName===SO_KEEPALIVE||level===IPPROTO_TCP&&optionName===TCP_NODELAY;if(!isSupported){console.warn(`Unsupported socket option: ${level}, ${optionName}, ${optionValue}`);return-1}const ws=PHPWASM.getAllWebSockets(socketd)[0];if(!ws){return-1}ws.setSocketOpt(level,optionName,optionValuePtr);return 0}var Asyncify={instrumentWasmImports(imports){var importPattern=/^(js_open_process|js_waitpid|js_process_status|js_create_input_device|wasm_setsockopt|wasm_shutdown|wasm_close|invoke_.*|__asyncjs__.*)$/;for(let[x,original]of Object.entries(imports)){if(typeof original=="function"){let isAsyncifyImport=original.isAsync||importPattern.test(x);if(isAsyncifyImport){imports[x]=original=new WebAssembly.Suspending(original)}}}},instrumentWasmExports(exports){var exportPattern=/^(wasm_sleep|wasm_read|emscripten_sleep|wasm_sapi_handle_request|wasm_sapi_request_shutdown|wasm_poll_socket|wrap_select|__wrap_select|select|php_pollfd_for|fflush|wasm_popen|wasm_read|wasm_php_exec|run_cli|main|__main_argc_argv)$/;Asyncify.asyncExports=new Set;var ret={};for(let[x,original]of Object.entries(exports)){if(typeof original=="function"){let isAsyncifyExport=exportPattern.test(x);if(isAsyncifyExport){Asyncify.asyncExports.add(original);original=Asyncify.makeAsyncFunction(original)}ret[x]=(...args)=>original(...args)}else{ret[x]=original}}return ret},asyncExports:null,isAsyncExport(func){return Asyncify.asyncExports?.has(func)},handleAsync:async startAsync=>{runtimeKeepalivePush();try{return await startAsync()}finally{runtimeKeepalivePop()}},handleSleep(startAsync){return Asyncify.handleAsync(()=>new Promise(startAsync))},makeAsyncFunction(original){return WebAssembly.promising(original)}};var getCFunc=ident=>{var func=Module["_"+ident];return func};var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer)};var stackSave=()=>_emscripten_stack_get_current();var stackRestore=val=>__emscripten_stack_restore(val);var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={string:str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},array:arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;iFS.unlink(path);var FS_createLazyFile=FS.createLazyFile;var FS_createDevice=FS.createDevice;FS.createPreloadedFile=FS_createPreloadedFile;FS.staticInit();Module["FS_createPath"]=FS.createPath;Module["FS_createDataFile"]=FS.createDataFile;Module["FS_createPreloadedFile"]=FS.createPreloadedFile;Module["FS_unlink"]=FS.unlink;Module["FS_createLazyFile"]=FS.createLazyFile;Module["FS_createDevice"]=FS.createDevice;MEMFS.doesNotExistError=new FS.ErrnoError(44);MEMFS.doesNotExistError.stack="";PHPWASM.init();var wasmImports={SharpYuvConvert:_SharpYuvConvert,SharpYuvGetConversionMatrix:_SharpYuvGetConversionMatrix,SharpYuvInit:_SharpYuvInit,__assert_fail:___assert_fail,__asyncjs__js_fd_read,__asyncjs__js_module_onMessage,__asyncjs__js_popen_to_file,__asyncjs__wasm_poll_socket,__call_sighandler:___call_sighandler,__syscall_accept4:___syscall_accept4,__syscall_bind:___syscall_bind,__syscall_chdir:___syscall_chdir,__syscall_chmod:___syscall_chmod,__syscall_connect:___syscall_connect,__syscall_dup:___syscall_dup,__syscall_dup3:___syscall_dup3,__syscall_faccessat:___syscall_faccessat,__syscall_fallocate:___syscall_fallocate,__syscall_fchmod:___syscall_fchmod,__syscall_fchown32:___syscall_fchown32,__syscall_fchownat:___syscall_fchownat,__syscall_fcntl64:___syscall_fcntl64,__syscall_fdatasync:___syscall_fdatasync,__syscall_fstat64:___syscall_fstat64,__syscall_ftruncate64:___syscall_ftruncate64,__syscall_getcwd:___syscall_getcwd,__syscall_getdents64:___syscall_getdents64,__syscall_getpeername:___syscall_getpeername,__syscall_getsockname:___syscall_getsockname,__syscall_getsockopt:___syscall_getsockopt,__syscall_ioctl:___syscall_ioctl,__syscall_listen:___syscall_listen,__syscall_lstat64:___syscall_lstat64,__syscall_mkdirat:___syscall_mkdirat,__syscall_newfstatat:___syscall_newfstatat,__syscall_openat:___syscall_openat,__syscall_pipe:___syscall_pipe,__syscall_poll:___syscall_poll,__syscall_readlinkat:___syscall_readlinkat,__syscall_recvfrom:___syscall_recvfrom,__syscall_renameat:___syscall_renameat,__syscall_rmdir:___syscall_rmdir,__syscall_sendto:___syscall_sendto,__syscall_socket:___syscall_socket,__syscall_stat64:___syscall_stat64,__syscall_statfs64:___syscall_statfs64,__syscall_symlinkat:___syscall_symlinkat,__syscall_unlinkat:___syscall_unlinkat,__syscall_utimensat:___syscall_utimensat,_abort_js:__abort_js,_emscripten_lookup_name:__emscripten_lookup_name,_emscripten_runtime_keepalive_clear:__emscripten_runtime_keepalive_clear,_gmtime_js:__gmtime_js,_localtime_js:__localtime_js,_mktime_js:__mktime_js,_mmap_js:__mmap_js,_munmap_js:__munmap_js,_setitimer_js:__setitimer_js,_tzset_js:__tzset_js,clock_time_get:_clock_time_get,emscripten_date_now:_emscripten_date_now,emscripten_get_heap_max:_emscripten_get_heap_max,emscripten_get_now:_emscripten_get_now,emscripten_resize_heap:_emscripten_resize_heap,emscripten_sleep:_emscripten_sleep,environ_get:_environ_get,environ_sizes_get:_environ_sizes_get,exit:_exit,fd_close:_fd_close,fd_fdstat_get:_fd_fdstat_get,fd_read:_fd_read,fd_seek:_fd_seek,fd_write:_fd_write,getaddrinfo:_getaddrinfo,getnameinfo:_getnameinfo,getprotobyname:_getprotobyname,getprotobynumber:_getprotobynumber,js_create_input_device:_js_create_input_device,js_open_process:_js_open_process,js_process_status:_js_process_status,js_waitpid:_js_waitpid,proc_exit:_proc_exit,strptime:_strptime,wasm_setsockopt:_wasm_setsockopt};var wasmExports;createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports["__wasm_call_ctors"])();var _malloc=a0=>(_malloc=wasmExports["malloc"])(a0);var _wasm_read=Module["_wasm_read"]=(a0,a1,a2)=>(_wasm_read=Module["_wasm_read"]=wasmExports["wasm_read"])(a0,a1,a2);var _fflush=a0=>(_fflush=wasmExports["fflush"])(a0);var _wasm_popen=Module["_wasm_popen"]=(a0,a1)=>(_wasm_popen=Module["_wasm_popen"]=wasmExports["wasm_popen"])(a0,a1);var _wasm_php_exec=Module["_wasm_php_exec"]=(a0,a1,a2,a3)=>(_wasm_php_exec=Module["_wasm_php_exec"]=wasmExports["wasm_php_exec"])(a0,a1,a2,a3);var _php_pollfd_for=Module["_php_pollfd_for"]=(a0,a1,a2)=>(_php_pollfd_for=Module["_php_pollfd_for"]=wasmExports["php_pollfd_for"])(a0,a1,a2);var _htons=a0=>(_htons=wasmExports["htons"])(a0);var _ntohs=a0=>(_ntohs=wasmExports["ntohs"])(a0);var _htonl=a0=>(_htonl=wasmExports["htonl"])(a0);var _wasm_sleep=Module["_wasm_sleep"]=a0=>(_wasm_sleep=Module["_wasm_sleep"]=wasmExports["wasm_sleep"])(a0);var ___wrap_select=Module["___wrap_select"]=(a0,a1,a2,a3,a4)=>(___wrap_select=Module["___wrap_select"]=wasmExports["__wrap_select"])(a0,a1,a2,a3,a4);var _wasm_set_sapi_name=Module["_wasm_set_sapi_name"]=a0=>(_wasm_set_sapi_name=Module["_wasm_set_sapi_name"]=wasmExports["wasm_set_sapi_name"])(a0);var _wasm_set_phpini_path=Module["_wasm_set_phpini_path"]=a0=>(_wasm_set_phpini_path=Module["_wasm_set_phpini_path"]=wasmExports["wasm_set_phpini_path"])(a0);var _wasm_add_SERVER_entry=Module["_wasm_add_SERVER_entry"]=(a0,a1)=>(_wasm_add_SERVER_entry=Module["_wasm_add_SERVER_entry"]=wasmExports["wasm_add_SERVER_entry"])(a0,a1);var _wasm_add_ENV_entry=Module["_wasm_add_ENV_entry"]=(a0,a1)=>(_wasm_add_ENV_entry=Module["_wasm_add_ENV_entry"]=wasmExports["wasm_add_ENV_entry"])(a0,a1);var _wasm_set_query_string=Module["_wasm_set_query_string"]=a0=>(_wasm_set_query_string=Module["_wasm_set_query_string"]=wasmExports["wasm_set_query_string"])(a0);var _wasm_set_path_translated=Module["_wasm_set_path_translated"]=a0=>(_wasm_set_path_translated=Module["_wasm_set_path_translated"]=wasmExports["wasm_set_path_translated"])(a0);var _wasm_set_skip_shebang=Module["_wasm_set_skip_shebang"]=a0=>(_wasm_set_skip_shebang=Module["_wasm_set_skip_shebang"]=wasmExports["wasm_set_skip_shebang"])(a0);var _wasm_set_request_uri=Module["_wasm_set_request_uri"]=a0=>(_wasm_set_request_uri=Module["_wasm_set_request_uri"]=wasmExports["wasm_set_request_uri"])(a0);var _wasm_set_request_method=Module["_wasm_set_request_method"]=a0=>(_wasm_set_request_method=Module["_wasm_set_request_method"]=wasmExports["wasm_set_request_method"])(a0);var _wasm_set_request_host=Module["_wasm_set_request_host"]=a0=>(_wasm_set_request_host=Module["_wasm_set_request_host"]=wasmExports["wasm_set_request_host"])(a0);var _wasm_set_content_type=Module["_wasm_set_content_type"]=a0=>(_wasm_set_content_type=Module["_wasm_set_content_type"]=wasmExports["wasm_set_content_type"])(a0);var _wasm_set_request_body=Module["_wasm_set_request_body"]=a0=>(_wasm_set_request_body=Module["_wasm_set_request_body"]=wasmExports["wasm_set_request_body"])(a0);var _wasm_set_content_length=Module["_wasm_set_content_length"]=a0=>(_wasm_set_content_length=Module["_wasm_set_content_length"]=wasmExports["wasm_set_content_length"])(a0);var _wasm_set_cookies=Module["_wasm_set_cookies"]=a0=>(_wasm_set_cookies=Module["_wasm_set_cookies"]=wasmExports["wasm_set_cookies"])(a0);var _wasm_set_request_port=Module["_wasm_set_request_port"]=a0=>(_wasm_set_request_port=Module["_wasm_set_request_port"]=wasmExports["wasm_set_request_port"])(a0);var _wasm_sapi_request_shutdown=Module["_wasm_sapi_request_shutdown"]=()=>(_wasm_sapi_request_shutdown=Module["_wasm_sapi_request_shutdown"]=wasmExports["wasm_sapi_request_shutdown"])();var _wasm_sapi_handle_request=Module["_wasm_sapi_handle_request"]=()=>(_wasm_sapi_handle_request=Module["_wasm_sapi_handle_request"]=wasmExports["wasm_sapi_handle_request"])();var _php_wasm_init=Module["_php_wasm_init"]=()=>(_php_wasm_init=Module["_php_wasm_init"]=wasmExports["php_wasm_init"])();var _wasm_free=Module["_wasm_free"]=a0=>(_wasm_free=Module["_wasm_free"]=wasmExports["wasm_free"])(a0);var ___funcs_on_exit=()=>(___funcs_on_exit=wasmExports["__funcs_on_exit"])();var _emscripten_builtin_memalign=(a0,a1)=>(_emscripten_builtin_memalign=wasmExports["emscripten_builtin_memalign"])(a0,a1);var __emscripten_timeout=(a0,a1)=>(__emscripten_timeout=wasmExports["_emscripten_timeout"])(a0,a1);var ___trap=()=>(___trap=wasmExports["__trap"])();var __emscripten_stack_restore=a0=>(__emscripten_stack_restore=wasmExports["_emscripten_stack_restore"])(a0);var __emscripten_stack_alloc=a0=>(__emscripten_stack_alloc=wasmExports["_emscripten_stack_alloc"])(a0);var _emscripten_stack_get_current=()=>(_emscripten_stack_get_current=wasmExports["emscripten_stack_get_current"])();Module["addRunDependency"]=addRunDependency;Module["removeRunDependency"]=removeRunDependency;Module["wasmExports"]=wasmExports;Module["ccall"]=ccall;Module["FS_createPreloadedFile"]=FS_createPreloadedFile;Module["FS_unlink"]=FS_unlink;Module["FS_createPath"]=FS_createPath;Module["FS_createDevice"]=FS_createDevice;Module["FS_createDataFile"]=FS_createDataFile;Module["FS_createLazyFile"]=FS_createLazyFile;Module["PROXYFS"]=PROXYFS;var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function run(){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();Module["onRuntimeInitialized"]?.();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(()=>{setTimeout(()=>Module["setStatus"](""),1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}run(); -/** - * Emscripten resolves `localhost` to a random IP address. Let's - * make it always resolve to 127.0.0.1. - */ -DNS.address_map.addrs.localhost = '127.0.0.1'; + // The rest of the code comes from the built php.js file and esm-suffix.js + var Module = typeof PHPLoader != 'undefined' ? PHPLoader : {}; + var ENVIRONMENT_IS_WEB = RuntimeName === 'WEB'; + var ENVIRONMENT_IS_WORKER = RuntimeName === 'WORKER'; + var ENVIRONMENT_IS_NODE = RuntimeName === 'NODE'; + var moduleOverrides = Object.assign({}, Module); + var arguments_ = []; + var thisProgram = './this.program'; + var quit_ = (status, toThrow) => { + throw toThrow; + }; + var scriptDirectory = ''; + function locateFile(path) { + if (Module['locateFile']) { + return Module['locateFile'](path, scriptDirectory); + } + return scriptDirectory + path; + } + var readAsync, readBinary; + if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { + if (ENVIRONMENT_IS_WORKER) { + scriptDirectory = self.location.href; + } else if (typeof document != 'undefined' && document.currentScript) { + scriptDirectory = document.currentScript.src; + } + if (scriptDirectory.startsWith('blob:')) { + scriptDirectory = ''; + } else { + scriptDirectory = scriptDirectory.substr( + 0, + scriptDirectory.replace(/[?#].*/, '').lastIndexOf('/') + 1 + ); + } + { + readAsync = async (url) => { + var response = await fetch(url, { credentials: 'same-origin' }); + if (response.ok) { + return response.arrayBuffer(); + } + throw new Error(response.status + ' : ' + response.url); + }; + } + } else { + } + var out = Module['print'] || console.log.bind(console); + var err = Module['printErr'] || console.error.bind(console); + Object.assign(Module, moduleOverrides); + moduleOverrides = null; + if (Module['arguments']) arguments_ = Module['arguments']; + if (Module['thisProgram']) thisProgram = Module['thisProgram']; + if (Module['quit']) quit_ = Module['quit']; + var wasmBinary = Module['wasmBinary']; + var wasmMemory; + var ABORT = false; + var EXITSTATUS; + function assert(condition, text) { + if (!condition) { + abort(text); + } + } + var HEAP8, + HEAPU8, + HEAP16, + HEAPU16, + HEAP32, + HEAPU32, + HEAPF32, + HEAP64, + HEAPU64, + HEAPF64; + function updateMemoryViews() { + var b = wasmMemory.buffer; + Module['HEAP8'] = HEAP8 = new Int8Array(b); + Module['HEAP16'] = HEAP16 = new Int16Array(b); + Module['HEAPU8'] = HEAPU8 = new Uint8Array(b); + Module['HEAPU16'] = HEAPU16 = new Uint16Array(b); + Module['HEAP32'] = HEAP32 = new Int32Array(b); + Module['HEAPU32'] = HEAPU32 = new Uint32Array(b); + Module['HEAPF32'] = HEAPF32 = new Float32Array(b); + Module['HEAPF64'] = HEAPF64 = new Float64Array(b); + Module['HEAP64'] = HEAP64 = new BigInt64Array(b); + Module['HEAPU64'] = HEAPU64 = new BigUint64Array(b); + } + var __ATPRERUN__ = []; + var __ATINIT__ = []; + var __ATEXIT__ = []; + var __ATPOSTRUN__ = []; + var runtimeInitialized = false; + var runtimeExited = false; + function preRun() { + if (Module['preRun']) { + if (typeof Module['preRun'] == 'function') + Module['preRun'] = [Module['preRun']]; + while (Module['preRun'].length) { + addOnPreRun(Module['preRun'].shift()); + } + } + callRuntimeCallbacks(__ATPRERUN__); + } + function initRuntime() { + runtimeInitialized = true; + SOCKFS.root = FS.mount(SOCKFS, {}, null); + if (!Module['noFSInit'] && !FS.initialized) FS.init(); + FS.ignorePermissions = false; + TTY.init(); + PIPEFS.root = FS.mount(PIPEFS, {}, null); + callRuntimeCallbacks(__ATINIT__); + } + function exitRuntime() { + ___funcs_on_exit(); + callRuntimeCallbacks(__ATEXIT__); + FS.quit(); + TTY.shutdown(); + runtimeExited = true; + } + function postRun() { + if (Module['postRun']) { + if (typeof Module['postRun'] == 'function') + Module['postRun'] = [Module['postRun']]; + while (Module['postRun'].length) { + addOnPostRun(Module['postRun'].shift()); + } + } + callRuntimeCallbacks(__ATPOSTRUN__); + } + function addOnPreRun(cb) { + __ATPRERUN__.unshift(cb); + } + function addOnInit(cb) { + __ATINIT__.unshift(cb); + } + function addOnPostRun(cb) { + __ATPOSTRUN__.unshift(cb); + } + var runDependencies = 0; + var dependenciesFulfilled = null; + function getUniqueRunDependency(id) { + return id; + } + function addRunDependency(id) { + runDependencies++; + Module['monitorRunDependencies']?.(runDependencies); + } + function removeRunDependency(id) { + runDependencies--; + Module['monitorRunDependencies']?.(runDependencies); + if (runDependencies == 0) { + if (dependenciesFulfilled) { + var callback = dependenciesFulfilled; + dependenciesFulfilled = null; + callback(); + } + } + } + function abort(what) { + Module['onAbort']?.(what); + what = 'Aborted(' + what + ')'; + err(what); + ABORT = true; + what += '. Build with -sASSERTIONS for more info.'; + if (runtimeInitialized) { + ___trap(); + } + var e = new WebAssembly.RuntimeError(what); + throw e; + } + var dataURIPrefix = 'data:application/octet-stream;base64,'; + var isDataURI = (filename) => filename.startsWith(dataURIPrefix); + function findWasmBinary() { + var f = dependencyFilename; + if (!isDataURI(f)) { + return locateFile(f); + } + return f; + } + var wasmBinaryFile; + function getBinarySync(file) { + if (file == wasmBinaryFile && wasmBinary) { + return new Uint8Array(wasmBinary); + } + if (readBinary) { + return readBinary(file); + } + throw 'both async and sync fetching of the wasm failed'; + } + async function getWasmBinary(binaryFile) { + if (!wasmBinary) { + try { + var response = await readAsync(binaryFile); + return new Uint8Array(response); + } catch {} + } + return getBinarySync(binaryFile); + } + async function instantiateArrayBuffer(binaryFile, imports) { + try { + var binary = await getWasmBinary(binaryFile); + var instance = await WebAssembly.instantiate(binary, imports); + return instance; + } catch (reason) { + err(`failed to asynchronously prepare wasm: ${reason}`); + abort(reason); + } + } + async function instantiateAsync(binary, binaryFile, imports) { + if ( + !binary && + typeof WebAssembly.instantiateStreaming == 'function' && + !isDataURI(binaryFile) && + typeof fetch == 'function' + ) { + try { + var response = fetch(binaryFile, { + credentials: 'same-origin', + }); + var instantiationResult = + await WebAssembly.instantiateStreaming(response, imports); + return instantiationResult; + } catch (reason) { + err(`wasm streaming compile failed: ${reason}`); + err('falling back to ArrayBuffer instantiation'); + } + } + return instantiateArrayBuffer(binaryFile, imports); + } + function getWasmImports() { + Asyncify.instrumentWasmImports(wasmImports); + return { env: wasmImports, wasi_snapshot_preview1: wasmImports }; + } + async function createWasm() { + function receiveInstance(instance, module) { + wasmExports = instance.exports; + wasmExports = Asyncify.instrumentWasmExports(wasmExports); + Module['wasmExports'] = wasmExports; + wasmMemory = wasmExports['memory']; + updateMemoryViews(); + wasmTable = wasmExports['__indirect_function_table']; + addOnInit(wasmExports['__wasm_call_ctors']); + removeRunDependency('wasm-instantiate'); + return wasmExports; + } + addRunDependency('wasm-instantiate'); + function receiveInstantiationResult(result) { + receiveInstance(result['instance']); + } + var info = getWasmImports(); + if (Module['instantiateWasm']) { + try { + return Module['instantiateWasm'](info, receiveInstance); + } catch (e) { + err(`Module.instantiateWasm callback failed with error: ${e}`); + return false; + } + } + wasmBinaryFile ??= findWasmBinary(); + var result = await instantiateAsync(wasmBinary, wasmBinaryFile, info); + receiveInstantiationResult(result); + return result; + } + function __asyncjs__js_popen_to_file(command, mode, exitCodePtr) { + return Asyncify.handleAsync(async () => { + const returnCallback = (resolver) => new Promise(resolver); + if (!command) return 1; + const cmdstr = UTF8ToString(command); + if (!cmdstr.length) return 0; + const modestr = UTF8ToString(mode); + if (!modestr.length) return 0; + if (modestr === 'w') { + console.error('popen($cmd, "w") is not implemented yet'); + } + return returnCallback(async (wakeUp) => { + let cp; + try { + cp = PHPWASM.spawnProcess(cmdstr, []); + if (cp instanceof Promise) { + cp = await cp; + } + } catch (e) { + console.error(e); + if (e.code === 'SPAWN_UNSUPPORTED') { + return 1; + } + throw e; + } + const outByteArrays = []; + cp.stdout.on('data', function (data) { + outByteArrays.push(data); + }); + const outputPath = '/tmp/popen_output'; + cp.on('exit', function (exitCode) { + const outBytes = new Uint8Array( + outByteArrays.reduce( + (acc, curr) => acc + curr.length, + 0 + ) + ); + let offset = 0; + for (const byteArray of outByteArrays) { + outBytes.set(byteArray, offset); + offset += byteArray.length; + } + FS.writeFile(outputPath, outBytes); + HEAPU8[exitCodePtr] = exitCode; + wakeUp(allocateUTF8OnStack(outputPath)); + }); + }); + }); + } + __asyncjs__js_popen_to_file.sig = 'iiii'; + function __asyncjs__wasm_poll_socket(socketd, events, timeout) { + return Asyncify.handleAsync(async () => { + const returnCallback = (resolver) => new Promise(resolver); + const POLLIN = 1; + const POLLPRI = 2; + const POLLOUT = 4; + const POLLERR = 8; + const POLLHUP = 16; + const POLLNVAL = 32; + return returnCallback((wakeUp) => { + const polls = []; + if (socketd in PHPWASM.child_proc_by_fd) { + const procInfo = PHPWASM.child_proc_by_fd[socketd]; + if (procInfo.exited) { + wakeUp(0); + return; + } + polls.push(PHPWASM.awaitEvent(procInfo.stdout, 'data')); + } else if (FS.isSocket(FS.getStream(socketd)?.node.mode)) { + const sock = getSocketFromFD(socketd); + if (!sock) { + wakeUp(0); + return; + } + const lookingFor = new Set(); + if (events & POLLIN || events & POLLPRI) { + if (sock.server) { + for (const client of sock.pending) { + if ((client.recv_queue || []).length > 0) { + wakeUp(1); + return; + } + } + } else if ((sock.recv_queue || []).length > 0) { + wakeUp(1); + return; + } + } + const webSockets = PHPWASM.getAllWebSockets(sock); + if (!webSockets.length) { + wakeUp(0); + return; + } + for (const ws of webSockets) { + if (events & POLLIN || events & POLLPRI) { + polls.push(PHPWASM.awaitData(ws)); + lookingFor.add('POLLIN'); + } + if (events & POLLOUT) { + polls.push(PHPWASM.awaitConnection(ws)); + lookingFor.add('POLLOUT'); + } + if (events & POLLHUP) { + polls.push(PHPWASM.awaitClose(ws)); + lookingFor.add('POLLHUP'); + } + if (events & POLLERR || events & POLLNVAL) { + polls.push(PHPWASM.awaitError(ws)); + lookingFor.add('POLLERR'); + } + } + } else { + setTimeout(function () { + wakeUp(1); + }, timeout); + return; + } + if (polls.length === 0) { + console.warn( + 'Unsupported poll event ' + + events + + ', defaulting to setTimeout().' + ); + setTimeout(function () { + wakeUp(0); + }, timeout); + return; + } + const promises = polls.map(([promise]) => promise); + const clearPolling = () => + polls.forEach(([, clear]) => clear()); + let awaken = false; + let timeoutId; + Promise.race(promises).then(function (results) { + if (!awaken) { + awaken = true; + wakeUp(1); + if (timeoutId) { + clearTimeout(timeoutId); + } + clearPolling(); + } + }); + if (timeout !== -1) { + timeoutId = setTimeout(function () { + if (!awaken) { + awaken = true; + wakeUp(0); + clearPolling(); + } + }, timeout); + } + }); + }); + } + __asyncjs__wasm_poll_socket.sig = 'iiii'; + function __asyncjs__js_fd_read(fd, iov, iovcnt, pnum) { + return Asyncify.handleAsync(async () => { + const returnCallback = (resolver) => new Promise(resolver); + if ( + Asyncify?.State?.Normal === undefined || + Asyncify?.state === Asyncify?.State?.Normal + ) { + var returnCode; + var stream; + let num = 0; + try { + stream = SYSCALLS.getStreamFromFD(fd); + const num = doReadv(stream, iov, iovcnt); + HEAPU32[pnum >> 2] = num; + return 0; + } catch (e) { + if ( + typeof FS == 'undefined' || + !(e.name === 'ErrnoError') + ) { + throw e; + } + if ( + e.errno !== 6 || + !(stream?.fd in PHPWASM.child_proc_by_fd) + ) { + HEAPU32[pnum >> 2] = 0; + return returnCode; + } + } + } + return returnCallback((wakeUp) => { + var retries = 0; + var interval = 50; + var timeout = 5e3; + var maxRetries = timeout / interval; + function poll() { + var returnCode; + var stream; + let num; + try { + stream = SYSCALLS.getStreamFromFD(fd); + num = doReadv(stream, iov, iovcnt); + returnCode = 0; + } catch (e) { + if ( + typeof FS == 'undefined' || + !(e.name === 'ErrnoError') + ) { + console.error(e); + throw e; + } + returnCode = e.errno; + } + const success = returnCode === 0; + const failure = + ++retries > maxRetries || + !(fd in PHPWASM.child_proc_by_fd) || + PHPWASM.child_proc_by_fd[fd]?.exited || + FS.isClosed(stream); + if (success) { + HEAPU32[pnum >> 2] = num; + wakeUp(0); + } else if (failure) { + HEAPU32[pnum >> 2] = 0; + wakeUp(returnCode === 6 ? 0 : returnCode); + } else { + setTimeout(poll, interval); + } + } + poll(); + }); + }); + } + __asyncjs__js_fd_read.sig = 'iiiii'; + function __asyncjs__js_module_onMessage(data, response_buffer) { + return Asyncify.handleAsync(async () => { + if (Module['onMessage']) { + const dataStr = UTF8ToString(data); + return Module['onMessage'](dataStr) + .then((response) => { + const responseBytes = + typeof response === 'string' + ? new TextEncoder().encode(response) + : response; + const responseSize = responseBytes.byteLength; + const responsePtr = _malloc(responseSize + 1); + HEAPU8.set(responseBytes, responsePtr); + HEAPU8[responsePtr + responseSize] = 0; + HEAPU8[response_buffer] = responsePtr; + HEAPU8[response_buffer + 1] = responsePtr >> 8; + HEAPU8[response_buffer + 2] = responsePtr >> 16; + HEAPU8[response_buffer + 3] = responsePtr >> 24; + return responseSize; + }) + .catch((e) => { + console.error(e); + return -1; + }); + } + }); + } + __asyncjs__js_module_onMessage.sig = 'iii'; + class ExitStatus { + name = 'ExitStatus'; + constructor(status) { + this.message = `Program terminated with exit(${status})`; + this.status = status; + } + } + ExitStatus = class PHPExitStatus extends Error { + constructor(status) { + super(status); + this.name = 'ExitStatus'; + this.message = 'Program terminated with exit(' + status + ')'; + this.status = status; + } + }; + var callRuntimeCallbacks = (callbacks) => { + while (callbacks.length > 0) { + callbacks.shift()(Module); + } + }; + var noExitRuntime = Module['noExitRuntime'] || false; + function _SharpYuvConvert() { + abort('missing function: SharpYuvConvert'); + } + _SharpYuvConvert.stub = true; + function _SharpYuvGetConversionMatrix() { + abort('missing function: SharpYuvGetConversionMatrix'); + } + _SharpYuvGetConversionMatrix.stub = true; + function _SharpYuvInit() { + abort('missing function: SharpYuvInit'); + } + _SharpYuvInit.stub = true; + var UTF8Decoder = + typeof TextDecoder != 'undefined' ? new TextDecoder() : undefined; + var UTF8ArrayToString = (heapOrArray, idx = 0, maxBytesToRead = NaN) => { + var endIdx = idx + maxBytesToRead; + var endPtr = idx; + while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr; + if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) { + return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr)); + } + var str = ''; + while (idx < endPtr) { + var u0 = heapOrArray[idx++]; + if (!(u0 & 128)) { + str += String.fromCharCode(u0); + continue; + } + var u1 = heapOrArray[idx++] & 63; + if ((u0 & 224) == 192) { + str += String.fromCharCode(((u0 & 31) << 6) | u1); + continue; + } + var u2 = heapOrArray[idx++] & 63; + if ((u0 & 240) == 224) { + u0 = ((u0 & 15) << 12) | (u1 << 6) | u2; + } else { + u0 = + ((u0 & 7) << 18) | + (u1 << 12) | + (u2 << 6) | + (heapOrArray[idx++] & 63); + } + if (u0 < 65536) { + str += String.fromCharCode(u0); + } else { + var ch = u0 - 65536; + str += String.fromCharCode( + 55296 | (ch >> 10), + 56320 | (ch & 1023) + ); + } + } + return str; + }; + var UTF8ToString = (ptr, maxBytesToRead) => + ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''; + Module['UTF8ToString'] = UTF8ToString; + var ___assert_fail = (condition, filename, line, func) => + abort( + `Assertion failed: ${UTF8ToString(condition)}, at: ` + + [ + filename ? UTF8ToString(filename) : 'unknown filename', + line, + func ? UTF8ToString(func) : 'unknown function', + ] + ); + var wasmTableMirror = []; + var wasmTable; + var getWasmTableEntry = (funcPtr) => { + var func = wasmTableMirror[funcPtr]; + if (!func) { + if (funcPtr >= wasmTableMirror.length) + wasmTableMirror.length = funcPtr + 1; + wasmTableMirror[funcPtr] = func = wasmTable.get(funcPtr); + if (Asyncify.isAsyncExport(func)) { + wasmTableMirror[funcPtr] = func = + Asyncify.makeAsyncFunction(func); + } + } + return func; + }; + var ___call_sighandler = (fp, sig) => getWasmTableEntry(fp)(sig); + var initRandomFill = () => { + if ( + typeof crypto == 'object' && + typeof crypto['getRandomValues'] == 'function' + ) { + return (view) => crypto.getRandomValues(view); + } else abort('initRandomDevice'); + }; + var randomFill = (view) => (randomFill = initRandomFill())(view); + var PATH = { + isAbs: (path) => path.charAt(0) === '/', + splitPath: (filename) => { + var splitPathRe = + /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; + return splitPathRe.exec(filename).slice(1); + }, + normalizeArray: (parts, allowAboveRoot) => { + var up = 0; + for (var i = parts.length - 1; i >= 0; i--) { + var last = parts[i]; + if (last === '.') { + parts.splice(i, 1); + } else if (last === '..') { + parts.splice(i, 1); + up++; + } else if (up) { + parts.splice(i, 1); + up--; + } + } + if (allowAboveRoot) { + for (; up; up--) { + parts.unshift('..'); + } + } + return parts; + }, + normalize: (path) => { + var isAbsolute = PATH.isAbs(path), + trailingSlash = path.substr(-1) === '/'; + path = PATH.normalizeArray( + path.split('/').filter((p) => !!p), + !isAbsolute + ).join('/'); + if (!path && !isAbsolute) { + path = '.'; + } + if (path && trailingSlash) { + path += '/'; + } + return (isAbsolute ? '/' : '') + path; + }, + dirname: (path) => { + var result = PATH.splitPath(path), + root = result[0], + dir = result[1]; + if (!root && !dir) { + return '.'; + } + if (dir) { + dir = dir.substr(0, dir.length - 1); + } + return root + dir; + }, + basename: (path) => { + if (path === '/') return '/'; + path = PATH.normalize(path); + path = path.replace(/\/$/, ''); + var lastSlash = path.lastIndexOf('/'); + if (lastSlash === -1) return path; + return path.substr(lastSlash + 1); + }, + join: (...paths) => PATH.normalize(paths.join('/')), + join2: (l, r) => PATH.normalize(l + '/' + r), + }; + var PATH_FS = { + resolve: (...args) => { + var resolvedPath = '', + resolvedAbsolute = false; + for (var i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path = i >= 0 ? args[i] : FS.cwd(); + if (typeof path != 'string') { + throw new TypeError( + 'Arguments to path.resolve must be strings' + ); + } else if (!path) { + return ''; + } + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = PATH.isAbs(path); + } + resolvedPath = PATH.normalizeArray( + resolvedPath.split('/').filter((p) => !!p), + !resolvedAbsolute + ).join('/'); + return (resolvedAbsolute ? '/' : '') + resolvedPath || '.'; + }, + relative: (from, to) => { + from = PATH_FS.resolve(from).substr(1); + to = PATH_FS.resolve(to).substr(1); + function trim(arr) { + var start = 0; + for (; start < arr.length; start++) { + if (arr[start] !== '') break; + } + var end = arr.length - 1; + for (; end >= 0; end--) { + if (arr[end] !== '') break; + } + if (start > end) return []; + return arr.slice(start, end - start + 1); + } + var fromParts = trim(from.split('/')); + var toParts = trim(to.split('/')); + var length = Math.min(fromParts.length, toParts.length); + var samePartsLength = length; + for (var i = 0; i < length; i++) { + if (fromParts[i] !== toParts[i]) { + samePartsLength = i; + break; + } + } + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push('..'); + } + outputParts = outputParts.concat(toParts.slice(samePartsLength)); + return outputParts.join('/'); + }, + }; + var FS_stdin_getChar_buffer = []; + var lengthBytesUTF8 = (str) => { + var len = 0; + for (var i = 0; i < str.length; ++i) { + var c = str.charCodeAt(i); + if (c <= 127) { + len++; + } else if (c <= 2047) { + len += 2; + } else if (c >= 55296 && c <= 57343) { + len += 4; + ++i; + } else { + len += 3; + } + } + return len; + }; + Module['lengthBytesUTF8'] = lengthBytesUTF8; + var stringToUTF8Array = (str, heap, outIdx, maxBytesToWrite) => { + if (!(maxBytesToWrite > 0)) return 0; + var startIdx = outIdx; + var endIdx = outIdx + maxBytesToWrite - 1; + for (var i = 0; i < str.length; ++i) { + var u = str.charCodeAt(i); + if (u >= 55296 && u <= 57343) { + var u1 = str.charCodeAt(++i); + u = (65536 + ((u & 1023) << 10)) | (u1 & 1023); + } + if (u <= 127) { + if (outIdx >= endIdx) break; + heap[outIdx++] = u; + } else if (u <= 2047) { + if (outIdx + 1 >= endIdx) break; + heap[outIdx++] = 192 | (u >> 6); + heap[outIdx++] = 128 | (u & 63); + } else if (u <= 65535) { + if (outIdx + 2 >= endIdx) break; + heap[outIdx++] = 224 | (u >> 12); + heap[outIdx++] = 128 | ((u >> 6) & 63); + heap[outIdx++] = 128 | (u & 63); + } else { + if (outIdx + 3 >= endIdx) break; + heap[outIdx++] = 240 | (u >> 18); + heap[outIdx++] = 128 | ((u >> 12) & 63); + heap[outIdx++] = 128 | ((u >> 6) & 63); + heap[outIdx++] = 128 | (u & 63); + } + } + heap[outIdx] = 0; + return outIdx - startIdx; + }; + function intArrayFromString(stringy, dontAddNull, length) { + var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1; + var u8array = new Array(len); + var numBytesWritten = stringToUTF8Array( + stringy, + u8array, + 0, + u8array.length + ); + if (dontAddNull) u8array.length = numBytesWritten; + return u8array; + } + var FS_stdin_getChar = () => { + if (!FS_stdin_getChar_buffer.length) { + var result = null; + if ( + typeof window != 'undefined' && + typeof window.prompt == 'function' + ) { + result = window.prompt('Input: '); + if (result !== null) { + result += '\n'; + } + } else { + } + if (!result) { + return null; + } + FS_stdin_getChar_buffer = intArrayFromString(result, true); + } + return FS_stdin_getChar_buffer.shift(); + }; + var TTY = { + ttys: [], + init() {}, + shutdown() {}, + register(dev, ops) { + TTY.ttys[dev] = { input: [], output: [], ops }; + FS.registerDevice(dev, TTY.stream_ops); + }, + stream_ops: { + open(stream) { + var tty = TTY.ttys[stream.node.rdev]; + if (!tty) { + throw new FS.ErrnoError(43); + } + stream.tty = tty; + stream.seekable = false; + }, + close(stream) { + stream.tty.ops.fsync(stream.tty); + }, + fsync(stream) { + stream.tty.ops.fsync(stream.tty); + }, + read(stream, buffer, offset, length, pos) { + if (!stream.tty || !stream.tty.ops.get_char) { + throw new FS.ErrnoError(60); + } + var bytesRead = 0; + for (var i = 0; i < length; i++) { + var result; + try { + result = stream.tty.ops.get_char(stream.tty); + } catch (e) { + throw new FS.ErrnoError(29); + } + if (result === undefined && bytesRead === 0) { + throw new FS.ErrnoError(6); + } + if (result === null || result === undefined) break; + bytesRead++; + buffer[offset + i] = result; + } + if (bytesRead) { + stream.node.atime = Date.now(); + } + return bytesRead; + }, + write(stream, buffer, offset, length, pos) { + if (!stream.tty || !stream.tty.ops.put_char) { + throw new FS.ErrnoError(60); + } + try { + for (var i = 0; i < length; i++) { + stream.tty.ops.put_char(stream.tty, buffer[offset + i]); + } + } catch (e) { + throw new FS.ErrnoError(29); + } + if (length) { + stream.node.mtime = stream.node.ctime = Date.now(); + } + return i; + }, + }, + default_tty_ops: { + get_char(tty) { + return FS_stdin_getChar(); + }, + put_char(tty, val) { + if (val === null || val === 10) { + out(UTF8ArrayToString(tty.output)); + tty.output = []; + } else { + if (val != 0) tty.output.push(val); + } + }, + fsync(tty) { + if (tty.output && tty.output.length > 0) { + out(UTF8ArrayToString(tty.output)); + tty.output = []; + } + }, + ioctl_tcgets(tty) { + return { + c_iflag: 25856, + c_oflag: 5, + c_cflag: 191, + c_lflag: 35387, + c_cc: [ + 3, 28, 127, 21, 4, 0, 1, 0, 17, 19, 26, 0, 18, 15, 23, + 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }; + }, + ioctl_tcsets(tty, optional_actions, data) { + return 0; + }, + ioctl_tiocgwinsz(tty) { + return [24, 80]; + }, + }, + default_tty1_ops: { + put_char(tty, val) { + if (val === null || val === 10) { + err(UTF8ArrayToString(tty.output)); + tty.output = []; + } else { + if (val != 0) tty.output.push(val); + } + }, + fsync(tty) { + if (tty.output && tty.output.length > 0) { + err(UTF8ArrayToString(tty.output)); + tty.output = []; + } + }, + }, + }; + var zeroMemory = (address, size) => { + HEAPU8.fill(0, address, address + size); + }; + var alignMemory = (size, alignment) => + Math.ceil(size / alignment) * alignment; + var mmapAlloc = (size) => { + size = alignMemory(size, 65536); + var ptr = _emscripten_builtin_memalign(65536, size); + if (ptr) zeroMemory(ptr, size); + return ptr; + }; + var MEMFS = { + ops_table: null, + mount(mount) { + return MEMFS.createNode(null, '/', 16895, 0); + }, + createNode(parent, name, mode, dev) { + if (FS.isBlkdev(mode) || FS.isFIFO(mode)) { + throw new FS.ErrnoError(63); + } + MEMFS.ops_table ||= { + dir: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr, + lookup: MEMFS.node_ops.lookup, + mknod: MEMFS.node_ops.mknod, + rename: MEMFS.node_ops.rename, + unlink: MEMFS.node_ops.unlink, + rmdir: MEMFS.node_ops.rmdir, + readdir: MEMFS.node_ops.readdir, + symlink: MEMFS.node_ops.symlink, + }, + stream: { llseek: MEMFS.stream_ops.llseek }, + }, + file: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr, + }, + stream: { + llseek: MEMFS.stream_ops.llseek, + read: MEMFS.stream_ops.read, + write: MEMFS.stream_ops.write, + allocate: MEMFS.stream_ops.allocate, + mmap: MEMFS.stream_ops.mmap, + msync: MEMFS.stream_ops.msync, + }, + }, + link: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr, + readlink: MEMFS.node_ops.readlink, + }, + stream: {}, + }, + chrdev: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr, + }, + stream: FS.chrdev_stream_ops, + }, + }; + var node = FS.createNode(parent, name, mode, dev); + if (FS.isDir(node.mode)) { + node.node_ops = MEMFS.ops_table.dir.node; + node.stream_ops = MEMFS.ops_table.dir.stream; + node.contents = {}; + } else if (FS.isFile(node.mode)) { + node.node_ops = MEMFS.ops_table.file.node; + node.stream_ops = MEMFS.ops_table.file.stream; + node.usedBytes = 0; + node.contents = null; + } else if (FS.isLink(node.mode)) { + node.node_ops = MEMFS.ops_table.link.node; + node.stream_ops = MEMFS.ops_table.link.stream; + } else if (FS.isChrdev(node.mode)) { + node.node_ops = MEMFS.ops_table.chrdev.node; + node.stream_ops = MEMFS.ops_table.chrdev.stream; + } + node.atime = node.mtime = node.ctime = Date.now(); + if (parent) { + parent.contents[name] = node; + parent.atime = parent.mtime = parent.ctime = node.atime; + } + return node; + }, + getFileDataAsTypedArray(node) { + if (!node.contents) return new Uint8Array(0); + if (node.contents.subarray) + return node.contents.subarray(0, node.usedBytes); + return new Uint8Array(node.contents); + }, + expandFileStorage(node, newCapacity) { + var prevCapacity = node.contents ? node.contents.length : 0; + if (prevCapacity >= newCapacity) return; + var CAPACITY_DOUBLING_MAX = 1024 * 1024; + newCapacity = Math.max( + newCapacity, + (prevCapacity * + (prevCapacity < CAPACITY_DOUBLING_MAX ? 2 : 1.125)) >>> + 0 + ); + if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256); + var oldContents = node.contents; + node.contents = new Uint8Array(newCapacity); + if (node.usedBytes > 0) + node.contents.set(oldContents.subarray(0, node.usedBytes), 0); + }, + resizeFileStorage(node, newSize) { + if (node.usedBytes == newSize) return; + if (newSize == 0) { + node.contents = null; + node.usedBytes = 0; + } else { + var oldContents = node.contents; + node.contents = new Uint8Array(newSize); + if (oldContents) { + node.contents.set( + oldContents.subarray( + 0, + Math.min(newSize, node.usedBytes) + ) + ); + } + node.usedBytes = newSize; + } + }, + node_ops: { + getattr(node) { + var attr = {}; + attr.dev = FS.isChrdev(node.mode) ? node.id : 1; + attr.ino = node.id; + attr.mode = node.mode; + attr.nlink = 1; + attr.uid = 0; + attr.gid = 0; + attr.rdev = node.rdev; + if (FS.isDir(node.mode)) { + attr.size = 4096; + } else if (FS.isFile(node.mode)) { + attr.size = node.usedBytes; + } else if (FS.isLink(node.mode)) { + attr.size = node.link.length; + } else { + attr.size = 0; + } + attr.atime = new Date(node.atime); + attr.mtime = new Date(node.mtime); + attr.ctime = new Date(node.ctime); + attr.blksize = 4096; + attr.blocks = Math.ceil(attr.size / attr.blksize); + return attr; + }, + setattr(node, attr) { + for (const key of ['mode', 'atime', 'mtime', 'ctime']) { + if (attr[key]) { + node[key] = attr[key]; + } + } + if (attr.size !== undefined) { + MEMFS.resizeFileStorage(node, attr.size); + } + }, + lookup(parent, name) { + throw MEMFS.doesNotExistError; + }, + mknod(parent, name, mode, dev) { + return MEMFS.createNode(parent, name, mode, dev); + }, + rename(old_node, new_dir, new_name) { + var new_node; + try { + new_node = FS.lookupNode(new_dir, new_name); + } catch (e) {} + if (new_node) { + if (FS.isDir(old_node.mode)) { + for (var i in new_node.contents) { + throw new FS.ErrnoError(55); + } + } + FS.hashRemoveNode(new_node); + } + delete old_node.parent.contents[old_node.name]; + new_dir.contents[new_name] = old_node; + old_node.name = new_name; + new_dir.ctime = + new_dir.mtime = + old_node.parent.ctime = + old_node.parent.mtime = + Date.now(); + }, + unlink(parent, name) { + delete parent.contents[name]; + parent.ctime = parent.mtime = Date.now(); + }, + rmdir(parent, name) { + var node = FS.lookupNode(parent, name); + for (var i in node.contents) { + throw new FS.ErrnoError(55); + } + delete parent.contents[name]; + parent.ctime = parent.mtime = Date.now(); + }, + readdir(node) { + return ['.', '..', ...Object.keys(node.contents)]; + }, + symlink(parent, newname, oldpath) { + var node = MEMFS.createNode(parent, newname, 511 | 40960, 0); + node.link = oldpath; + return node; + }, + readlink(node) { + if (!FS.isLink(node.mode)) { + throw new FS.ErrnoError(28); + } + return node.link; + }, + }, + stream_ops: { + read(stream, buffer, offset, length, position) { + var contents = stream.node.contents; + if (position >= stream.node.usedBytes) return 0; + var size = Math.min(stream.node.usedBytes - position, length); + if (size > 8 && contents.subarray) { + buffer.set( + contents.subarray(position, position + size), + offset + ); + } else { + for (var i = 0; i < size; i++) + buffer[offset + i] = contents[position + i]; + } + return size; + }, + write(stream, buffer, offset, length, position, canOwn) { + if (buffer.buffer === HEAP8.buffer) { + canOwn = false; + } + if (!length) return 0; + var node = stream.node; + node.mtime = node.ctime = Date.now(); + if ( + buffer.subarray && + (!node.contents || node.contents.subarray) + ) { + if (canOwn) { + node.contents = buffer.subarray( + offset, + offset + length + ); + node.usedBytes = length; + return length; + } else if (node.usedBytes === 0 && position === 0) { + node.contents = buffer.slice(offset, offset + length); + node.usedBytes = length; + return length; + } else if (position + length <= node.usedBytes) { + node.contents.set( + buffer.subarray(offset, offset + length), + position + ); + return length; + } + } + MEMFS.expandFileStorage(node, position + length); + if (node.contents.subarray && buffer.subarray) { + node.contents.set( + buffer.subarray(offset, offset + length), + position + ); + } else { + for (var i = 0; i < length; i++) { + node.contents[position + i] = buffer[offset + i]; + } + } + node.usedBytes = Math.max(node.usedBytes, position + length); + return length; + }, + llseek(stream, offset, whence) { + var position = offset; + if (whence === 1) { + position += stream.position; + } else if (whence === 2) { + if (FS.isFile(stream.node.mode)) { + position += stream.node.usedBytes; + } + } + if (position < 0) { + throw new FS.ErrnoError(28); + } + return position; + }, + allocate(stream, offset, length) { + MEMFS.expandFileStorage(stream.node, offset + length); + stream.node.usedBytes = Math.max( + stream.node.usedBytes, + offset + length + ); + }, + mmap(stream, length, position, prot, flags) { + if (!FS.isFile(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + var ptr; + var allocated; + var contents = stream.node.contents; + if ( + !(flags & 2) && + contents && + contents.buffer === HEAP8.buffer + ) { + allocated = false; + ptr = contents.byteOffset; + } else { + allocated = true; + ptr = mmapAlloc(length); + if (!ptr) { + throw new FS.ErrnoError(48); + } + if (contents) { + if ( + position > 0 || + position + length < contents.length + ) { + if (contents.subarray) { + contents = contents.subarray( + position, + position + length + ); + } else { + contents = Array.prototype.slice.call( + contents, + position, + position + length + ); + } + } + HEAP8.set(contents, ptr); + } + } + return { ptr, allocated }; + }, + msync(stream, buffer, offset, length, mmapFlags) { + MEMFS.stream_ops.write( + stream, + buffer, + 0, + length, + offset, + false + ); + return 0; + }, + }, + }; + var asyncLoad = async (url) => { + var arrayBuffer = await readAsync(url); + return new Uint8Array(arrayBuffer); + }; + asyncLoad.isAsync = true; + var FS_createDataFile = ( + parent, + name, + fileData, + canRead, + canWrite, + canOwn + ) => { + FS.createDataFile(parent, name, fileData, canRead, canWrite, canOwn); + }; + var preloadPlugins = Module['preloadPlugins'] || []; + var FS_handledByPreloadPlugin = (byteArray, fullname, finish, onerror) => { + if (typeof Browser != 'undefined') Browser.init(); + var handled = false; + preloadPlugins.forEach((plugin) => { + if (handled) return; + if (plugin['canHandle'](fullname)) { + plugin['handle'](byteArray, fullname, finish, onerror); + handled = true; + } + }); + return handled; + }; + var FS_createPreloadedFile = ( + parent, + name, + url, + canRead, + canWrite, + onload, + onerror, + dontCreateFile, + canOwn, + preFinish + ) => { + var fullname = name + ? PATH_FS.resolve(PATH.join2(parent, name)) + : parent; + var dep = getUniqueRunDependency(`cp ${fullname}`); + function processData(byteArray) { + function finish(byteArray) { + preFinish?.(); + if (!dontCreateFile) { + FS_createDataFile( + parent, + name, + byteArray, + canRead, + canWrite, + canOwn + ); + } + onload?.(); + removeRunDependency(dep); + } + if ( + FS_handledByPreloadPlugin(byteArray, fullname, finish, () => { + onerror?.(); + removeRunDependency(dep); + }) + ) { + return; + } + finish(byteArray); + } + addRunDependency(dep); + if (typeof url == 'string') { + asyncLoad(url).then(processData, onerror); + } else { + processData(url); + } + }; + var FS_modeStringToFlags = (str) => { + var flagModes = { + r: 0, + 'r+': 2, + w: 512 | 64 | 1, + 'w+': 512 | 64 | 2, + a: 1024 | 64 | 1, + 'a+': 1024 | 64 | 2, + }; + var flags = flagModes[str]; + if (typeof flags == 'undefined') { + throw new Error(`Unknown file open mode: ${str}`); + } + return flags; + }; + var FS_getMode = (canRead, canWrite) => { + var mode = 0; + if (canRead) mode |= 292 | 73; + if (canWrite) mode |= 146; + return mode; + }; + var ERRNO_CODES = { + EPERM: 63, + ENOENT: 44, + ESRCH: 71, + EINTR: 27, + EIO: 29, + ENXIO: 60, + E2BIG: 1, + ENOEXEC: 45, + EBADF: 8, + ECHILD: 12, + EAGAIN: 6, + EWOULDBLOCK: 6, + ENOMEM: 48, + EACCES: 2, + EFAULT: 21, + ENOTBLK: 105, + EBUSY: 10, + EEXIST: 20, + EXDEV: 75, + ENODEV: 43, + ENOTDIR: 54, + EISDIR: 31, + EINVAL: 28, + ENFILE: 41, + EMFILE: 33, + ENOTTY: 59, + ETXTBSY: 74, + EFBIG: 22, + ENOSPC: 51, + ESPIPE: 70, + EROFS: 69, + EMLINK: 34, + EPIPE: 64, + EDOM: 18, + ERANGE: 68, + ENOMSG: 49, + EIDRM: 24, + ECHRNG: 106, + EL2NSYNC: 156, + EL3HLT: 107, + EL3RST: 108, + ELNRNG: 109, + EUNATCH: 110, + ENOCSI: 111, + EL2HLT: 112, + EDEADLK: 16, + ENOLCK: 46, + EBADE: 113, + EBADR: 114, + EXFULL: 115, + ENOANO: 104, + EBADRQC: 103, + EBADSLT: 102, + EDEADLOCK: 16, + EBFONT: 101, + ENOSTR: 100, + ENODATA: 116, + ETIME: 117, + ENOSR: 118, + ENONET: 119, + ENOPKG: 120, + EREMOTE: 121, + ENOLINK: 47, + EADV: 122, + ESRMNT: 123, + ECOMM: 124, + EPROTO: 65, + EMULTIHOP: 36, + EDOTDOT: 125, + EBADMSG: 9, + ENOTUNIQ: 126, + EBADFD: 127, + EREMCHG: 128, + ELIBACC: 129, + ELIBBAD: 130, + ELIBSCN: 131, + ELIBMAX: 132, + ELIBEXEC: 133, + ENOSYS: 52, + ENOTEMPTY: 55, + ENAMETOOLONG: 37, + ELOOP: 32, + EOPNOTSUPP: 138, + EPFNOSUPPORT: 139, + ECONNRESET: 15, + ENOBUFS: 42, + EAFNOSUPPORT: 5, + EPROTOTYPE: 67, + ENOTSOCK: 57, + ENOPROTOOPT: 50, + ESHUTDOWN: 140, + ECONNREFUSED: 14, + EADDRINUSE: 3, + ECONNABORTED: 13, + ENETUNREACH: 40, + ENETDOWN: 38, + ETIMEDOUT: 73, + EHOSTDOWN: 142, + EHOSTUNREACH: 23, + EINPROGRESS: 26, + EALREADY: 7, + EDESTADDRREQ: 17, + EMSGSIZE: 35, + EPROTONOSUPPORT: 66, + ESOCKTNOSUPPORT: 137, + EADDRNOTAVAIL: 4, + ENETRESET: 39, + EISCONN: 30, + ENOTCONN: 53, + ETOOMANYREFS: 141, + EUSERS: 136, + EDQUOT: 19, + ESTALE: 72, + ENOTSUP: 138, + ENOMEDIUM: 148, + EILSEQ: 25, + EOVERFLOW: 61, + ECANCELED: 11, + ENOTRECOVERABLE: 56, + EOWNERDEAD: 62, + ESTRPIPE: 135, + }; + var PROXYFS = { + mount(mount) { + return PROXYFS.createNode( + null, + '/', + mount.opts.fs.lstat(mount.opts.root).mode, + 0 + ); + }, + createNode(parent, name, mode, dev) { + if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) { + throw new FS.ErrnoError(ERRNO_CODES.EINVAL); + } + var node = FS.createNode(parent, name, mode); + node.node_ops = PROXYFS.node_ops; + node.stream_ops = PROXYFS.stream_ops; + return node; + }, + realPath(node) { + var parts = []; + while (node.parent !== node) { + parts.push(node.name); + node = node.parent; + } + parts.push(node.mount.opts.root); + parts.reverse(); + return PATH.join(...parts); + }, + node_ops: { + getattr(node) { + var path = PROXYFS.realPath(node); + var stat; + try { + stat = node.mount.opts.fs.lstat(path); + } catch (e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + return { + dev: stat.dev, + ino: stat.ino, + mode: stat.mode, + nlink: stat.nlink, + uid: stat.uid, + gid: stat.gid, + rdev: stat.rdev, + size: stat.size, + atime: stat.atime, + mtime: stat.mtime, + ctime: stat.ctime, + blksize: stat.blksize, + blocks: stat.blocks, + }; + }, + setattr(node, attr) { + var path = PROXYFS.realPath(node); + try { + if (attr.mode !== undefined) { + node.mount.opts.fs.chmod(path, attr.mode); + node.mode = attr.mode; + } + if (attr.atime || attr.mtime) { + var atime = new Date(attr.atime || attr.mtime); + var mtime = new Date(attr.mtime || attr.atime); + node.mount.opts.fs.utime(path, atime, mtime); + } + if (attr.size !== undefined) { + node.mount.opts.fs.truncate(path, attr.size); + } + } catch (e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + lookup(parent, name) { + try { + var path = PATH.join2(PROXYFS.realPath(parent), name); + var mode = parent.mount.opts.fs.lstat(path).mode; + var node = PROXYFS.createNode(parent, name, mode); + return node; + } catch (e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + mknod(parent, name, mode, dev) { + var node = PROXYFS.createNode(parent, name, mode, dev); + var path = PROXYFS.realPath(node); + try { + if (FS.isDir(node.mode)) { + node.mount.opts.fs.mkdir(path, node.mode); + } else { + node.mount.opts.fs.writeFile(path, '', { + mode: node.mode, + }); + } + } catch (e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + return node; + }, + rename(oldNode, newDir, newName) { + var oldPath = PROXYFS.realPath(oldNode); + var newPath = PATH.join2(PROXYFS.realPath(newDir), newName); + try { + oldNode.mount.opts.fs.rename(oldPath, newPath); + oldNode.name = newName; + } catch (e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + unlink(parent, name) { + var path = PATH.join2(PROXYFS.realPath(parent), name); + try { + parent.mount.opts.fs.unlink(path); + } catch (e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + rmdir(parent, name) { + var path = PATH.join2(PROXYFS.realPath(parent), name); + try { + parent.mount.opts.fs.rmdir(path); + } catch (e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + readdir(node) { + var path = PROXYFS.realPath(node); + try { + return node.mount.opts.fs.readdir(path); + } catch (e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + symlink(parent, newName, oldPath) { + var newPath = PATH.join2(PROXYFS.realPath(parent), newName); + try { + parent.mount.opts.fs.symlink(oldPath, newPath); + } catch (e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + readlink(node) { + var path = PROXYFS.realPath(node); + try { + return node.mount.opts.fs.readlink(path); + } catch (e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + }, + stream_ops: { + open(stream) { + var path = PROXYFS.realPath(stream.node); + try { + stream.nfd = stream.node.mount.opts.fs.open( + path, + stream.flags + ); + } catch (e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + close(stream) { + try { + stream.node.mount.opts.fs.close(stream.nfd); + } catch (e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + read(stream, buffer, offset, length, position) { + try { + return stream.node.mount.opts.fs.read( + stream.nfd, + buffer, + offset, + length, + position + ); + } catch (e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + write(stream, buffer, offset, length, position) { + try { + return stream.node.mount.opts.fs.write( + stream.nfd, + buffer, + offset, + length, + position + ); + } catch (e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + llseek(stream, offset, whence) { + var position = offset; + if (whence === 1) { + position += stream.position; + } else if (whence === 2) { + if (FS.isFile(stream.node.mode)) { + try { + var stat = stream.node.node_ops.getattr( + stream.node + ); + position += stat.size; + } catch (e) { + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + } + } + if (position < 0) { + throw new FS.ErrnoError(ERRNO_CODES.EINVAL); + } + return position; + }, + }, + }; + var FS = { + root: null, + mounts: [], + devices: {}, + streams: [], + nextInode: 1, + nameTable: null, + currentPath: '/', + initialized: false, + ignorePermissions: true, + ErrnoError: class { + name = 'ErrnoError'; + constructor(errno) { + this.errno = errno; + } + }, + filesystems: null, + syncFSRequests: 0, + readFiles: {}, + FSStream: class { + shared = {}; + get object() { + return this.node; + } + set object(val) { + this.node = val; + } + get isRead() { + return (this.flags & 2097155) !== 1; + } + get isWrite() { + return (this.flags & 2097155) !== 0; + } + get isAppend() { + return this.flags & 1024; + } + get flags() { + return this.shared.flags; + } + set flags(val) { + this.shared.flags = val; + } + get position() { + return this.shared.position; + } + set position(val) { + this.shared.position = val; + } + }, + FSNode: class { + node_ops = {}; + stream_ops = {}; + readMode = 292 | 73; + writeMode = 146; + mounted = null; + constructor(parent, name, mode, rdev) { + if (!parent) { + parent = this; + } + this.parent = parent; + this.mount = parent.mount; + this.id = FS.nextInode++; + this.name = name; + this.mode = mode; + this.rdev = rdev; + this.atime = this.mtime = this.ctime = Date.now(); + } + get read() { + return (this.mode & this.readMode) === this.readMode; + } + set read(val) { + val + ? (this.mode |= this.readMode) + : (this.mode &= ~this.readMode); + } + get write() { + return (this.mode & this.writeMode) === this.writeMode; + } + set write(val) { + val + ? (this.mode |= this.writeMode) + : (this.mode &= ~this.writeMode); + } + get isFolder() { + return FS.isDir(this.mode); + } + get isDevice() { + return FS.isChrdev(this.mode); + } + }, + lookupPath(path, opts = {}) { + if (!path) return { path: '', node: null }; + opts.follow_mount ??= true; + if (!PATH.isAbs(path)) { + path = FS.cwd() + '/' + path; + } + linkloop: for (var nlinks = 0; nlinks < 40; nlinks++) { + var parts = path.split('/').filter((p) => !!p && p !== '.'); + var current = FS.root; + var current_path = '/'; + for (var i = 0; i < parts.length; i++) { + var islast = i === parts.length - 1; + if (islast && opts.parent) { + break; + } + if (parts[i] === '..') { + current_path = PATH.dirname(current_path); + current = current.parent; + continue; + } + current_path = PATH.join2(current_path, parts[i]); + try { + current = FS.lookupNode(current, parts[i]); + } catch (e) { + if (e?.errno === 44 && islast && opts.noent_okay) { + return { path: current_path }; + } + throw e; + } + if ( + FS.isMountpoint(current) && + (!islast || opts.follow_mount) + ) { + current = current.mounted.root; + } + if (FS.isLink(current.mode) && (!islast || opts.follow)) { + if (!current.node_ops.readlink) { + throw new FS.ErrnoError(52); + } + var link = current.node_ops.readlink(current); + if (!PATH.isAbs(link)) { + link = PATH.dirname(current_path) + '/' + link; + } + path = link + '/' + parts.slice(i + 1).join('/'); + continue linkloop; + } + } + return { path: current_path, node: current }; + } + throw new FS.ErrnoError(32); + }, + getPath(node) { + var path; + while (true) { + if (FS.isRoot(node)) { + var mount = node.mount.mountpoint; + if (!path) return mount; + return mount[mount.length - 1] !== '/' + ? `${mount}/${path}` + : mount + path; + } + path = path ? `${node.name}/${path}` : node.name; + node = node.parent; + } + }, + hashName(parentid, name) { + var hash = 0; + for (var i = 0; i < name.length; i++) { + hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0; + } + return ((parentid + hash) >>> 0) % FS.nameTable.length; + }, + hashAddNode(node) { + var hash = FS.hashName(node.parent.id, node.name); + node.name_next = FS.nameTable[hash]; + FS.nameTable[hash] = node; + }, + hashRemoveNode(node) { + var hash = FS.hashName(node.parent.id, node.name); + if (FS.nameTable[hash] === node) { + FS.nameTable[hash] = node.name_next; + } else { + var current = FS.nameTable[hash]; + while (current) { + if (current.name_next === node) { + current.name_next = node.name_next; + break; + } + current = current.name_next; + } + } + }, + lookupNode(parent, name) { + var errCode = FS.mayLookup(parent); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + var hash = FS.hashName(parent.id, name); + for (var node = FS.nameTable[hash]; node; node = node.name_next) { + var nodeName = node.name; + if (node.parent.id === parent.id && nodeName === name) { + return node; + } + } + return FS.lookup(parent, name); + }, + createNode(parent, name, mode, rdev) { + var node = new FS.FSNode(parent, name, mode, rdev); + FS.hashAddNode(node); + return node; + }, + destroyNode(node) { + FS.hashRemoveNode(node); + }, + isRoot(node) { + return node === node.parent; + }, + isMountpoint(node) { + return !!node.mounted; + }, + isFile(mode) { + return (mode & 61440) === 32768; + }, + isDir(mode) { + return (mode & 61440) === 16384; + }, + isLink(mode) { + return (mode & 61440) === 40960; + }, + isChrdev(mode) { + return (mode & 61440) === 8192; + }, + isBlkdev(mode) { + return (mode & 61440) === 24576; + }, + isFIFO(mode) { + return (mode & 61440) === 4096; + }, + isSocket(mode) { + return (mode & 49152) === 49152; + }, + flagsToPermissionString(flag) { + var perms = ['r', 'w', 'rw'][flag & 3]; + if (flag & 512) { + perms += 'w'; + } + return perms; + }, + nodePermissions(node, perms) { + if (FS.ignorePermissions) { + return 0; + } + if (perms.includes('r') && !(node.mode & 292)) { + return 2; + } else if (perms.includes('w') && !(node.mode & 146)) { + return 2; + } else if (perms.includes('x') && !(node.mode & 73)) { + return 2; + } + return 0; + }, + mayLookup(dir) { + if (!FS.isDir(dir.mode)) return 54; + var errCode = FS.nodePermissions(dir, 'x'); + if (errCode) return errCode; + if (!dir.node_ops.lookup) return 2; + return 0; + }, + mayCreate(dir, name) { + if (!FS.isDir(dir.mode)) { + return 54; + } + try { + var node = FS.lookupNode(dir, name); + return 20; + } catch (e) {} + return FS.nodePermissions(dir, 'wx'); + }, + mayDelete(dir, name, isdir) { + var node; + try { + node = FS.lookupNode(dir, name); + } catch (e) { + return e.errno; + } + var errCode = FS.nodePermissions(dir, 'wx'); + if (errCode) { + return errCode; + } + if (isdir) { + if (!FS.isDir(node.mode)) { + return 54; + } + if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) { + return 10; + } + } else { + if (FS.isDir(node.mode)) { + return 31; + } + } + return 0; + }, + mayOpen(node, flags) { + if (!node) { + return 44; + } + if (FS.isLink(node.mode)) { + return 32; + } else if (FS.isDir(node.mode)) { + if (FS.flagsToPermissionString(flags) !== 'r' || flags & 512) { + return 31; + } + } + return FS.nodePermissions(node, FS.flagsToPermissionString(flags)); + }, + MAX_OPEN_FDS: 4096, + nextfd() { + for (var fd = 0; fd <= FS.MAX_OPEN_FDS; fd++) { + if (!FS.streams[fd]) { + return fd; + } + } + throw new FS.ErrnoError(33); + }, + getStreamChecked(fd) { + var stream = FS.getStream(fd); + if (!stream) { + throw new FS.ErrnoError(8); + } + return stream; + }, + getStream: (fd) => FS.streams[fd], + createStream(stream, fd = -1) { + stream = Object.assign(new FS.FSStream(), stream); + if (fd == -1) { + fd = FS.nextfd(); + } + stream.fd = fd; + FS.streams[fd] = stream; + return stream; + }, + closeStream(fd) { + FS.streams[fd] = null; + }, + dupStream(origStream, fd = -1) { + var stream = FS.createStream(origStream, fd); + stream.stream_ops?.dup?.(stream); + return stream; + }, + chrdev_stream_ops: { + open(stream) { + var device = FS.getDevice(stream.node.rdev); + stream.stream_ops = device.stream_ops; + stream.stream_ops.open?.(stream); + }, + llseek() { + throw new FS.ErrnoError(70); + }, + }, + major: (dev) => dev >> 8, + minor: (dev) => dev & 255, + makedev: (ma, mi) => (ma << 8) | mi, + registerDevice(dev, ops) { + FS.devices[dev] = { stream_ops: ops }; + }, + getDevice: (dev) => FS.devices[dev], + getMounts(mount) { + var mounts = []; + var check = [mount]; + while (check.length) { + var m = check.pop(); + mounts.push(m); + check.push(...m.mounts); + } + return mounts; + }, + syncfs(populate, callback) { + if (typeof populate == 'function') { + callback = populate; + populate = false; + } + FS.syncFSRequests++; + if (FS.syncFSRequests > 1) { + err( + `warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work` + ); + } + var mounts = FS.getMounts(FS.root.mount); + var completed = 0; + function doCallback(errCode) { + FS.syncFSRequests--; + return callback(errCode); + } + function done(errCode) { + if (errCode) { + if (!done.errored) { + done.errored = true; + return doCallback(errCode); + } + return; + } + if (++completed >= mounts.length) { + doCallback(null); + } + } + mounts.forEach((mount) => { + if (!mount.type.syncfs) { + return done(null); + } + mount.type.syncfs(mount, populate, done); + }); + }, + mount(type, opts, mountpoint) { + var root = mountpoint === '/'; + var pseudo = !mountpoint; + var node; + if (root && FS.root) { + throw new FS.ErrnoError(10); + } else if (!root && !pseudo) { + var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); + mountpoint = lookup.path; + node = lookup.node; + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); + } + if (!FS.isDir(node.mode)) { + throw new FS.ErrnoError(54); + } + } + var mount = { type, opts, mountpoint, mounts: [] }; + var mountRoot = type.mount(mount); + mountRoot.mount = mount; + mount.root = mountRoot; + if (root) { + FS.root = mountRoot; + } else if (node) { + node.mounted = mount; + if (node.mount) { + node.mount.mounts.push(mount); + } + } + return mountRoot; + }, + unmount(mountpoint) { + var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); + if (!FS.isMountpoint(lookup.node)) { + throw new FS.ErrnoError(28); + } + var node = lookup.node; + var mount = node.mounted; + var mounts = FS.getMounts(mount); + Object.keys(FS.nameTable).forEach((hash) => { + var current = FS.nameTable[hash]; + while (current) { + var next = current.name_next; + if (mounts.includes(current.mount)) { + FS.destroyNode(current); + } + current = next; + } + }); + node.mounted = null; + var idx = node.mount.mounts.indexOf(mount); + node.mount.mounts.splice(idx, 1); + }, + lookup(parent, name) { + return parent.node_ops.lookup(parent, name); + }, + mknod(path, mode, dev) { + var lookup = FS.lookupPath(path, { parent: true }); + var parent = lookup.node; + var name = PATH.basename(path); + if (!name || name === '.' || name === '..') { + throw new FS.ErrnoError(28); + } + var errCode = FS.mayCreate(parent, name); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.mknod) { + throw new FS.ErrnoError(63); + } + return parent.node_ops.mknod(parent, name, mode, dev); + }, + statfs(path) { + var rtn = { + bsize: 4096, + frsize: 4096, + blocks: 1e6, + bfree: 5e5, + bavail: 5e5, + files: FS.nextInode, + ffree: FS.nextInode - 1, + fsid: 42, + flags: 2, + namelen: 255, + }; + var parent = FS.lookupPath(path, { follow: true }).node; + if (parent?.node_ops.statfs) { + Object.assign( + rtn, + parent.node_ops.statfs(parent.mount.opts.root) + ); + } + return rtn; + }, + create(path, mode = 438) { + mode &= 4095; + mode |= 32768; + return FS.mknod(path, mode, 0); + }, + mkdir(path, mode = 511) { + mode &= 511 | 512; + mode |= 16384; + return FS.mknod(path, mode, 0); + }, + mkdirTree(path, mode) { + var dirs = path.split('/'); + var d = ''; + for (var i = 0; i < dirs.length; ++i) { + if (!dirs[i]) continue; + d += '/' + dirs[i]; + try { + FS.mkdir(d, mode); + } catch (e) { + if (e.errno != 20) throw e; + } + } + }, + mkdev(path, mode, dev) { + if (typeof dev == 'undefined') { + dev = mode; + mode = 438; + } + mode |= 8192; + return FS.mknod(path, mode, dev); + }, + symlink(oldpath, newpath) { + if (!PATH_FS.resolve(oldpath)) { + throw new FS.ErrnoError(44); + } + var lookup = FS.lookupPath(newpath, { parent: true }); + var parent = lookup.node; + if (!parent) { + throw new FS.ErrnoError(44); + } + var newname = PATH.basename(newpath); + var errCode = FS.mayCreate(parent, newname); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.symlink) { + throw new FS.ErrnoError(63); + } + return parent.node_ops.symlink(parent, newname, oldpath); + }, + rename(old_path, new_path) { + var old_dirname = PATH.dirname(old_path); + var new_dirname = PATH.dirname(new_path); + var old_name = PATH.basename(old_path); + var new_name = PATH.basename(new_path); + var lookup, old_dir, new_dir; + lookup = FS.lookupPath(old_path, { parent: true }); + old_dir = lookup.node; + lookup = FS.lookupPath(new_path, { parent: true }); + new_dir = lookup.node; + if (!old_dir || !new_dir) throw new FS.ErrnoError(44); + if (old_dir.mount !== new_dir.mount) { + throw new FS.ErrnoError(75); + } + var old_node = FS.lookupNode(old_dir, old_name); + var relative = PATH_FS.relative(old_path, new_dirname); + if (relative.charAt(0) !== '.') { + throw new FS.ErrnoError(28); + } + relative = PATH_FS.relative(new_path, old_dirname); + if (relative.charAt(0) !== '.') { + throw new FS.ErrnoError(55); + } + var new_node; + try { + new_node = FS.lookupNode(new_dir, new_name); + } catch (e) {} + if (old_node === new_node) { + return; + } + var isdir = FS.isDir(old_node.mode); + var errCode = FS.mayDelete(old_dir, old_name, isdir); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + errCode = new_node + ? FS.mayDelete(new_dir, new_name, isdir) + : FS.mayCreate(new_dir, new_name); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!old_dir.node_ops.rename) { + throw new FS.ErrnoError(63); + } + if ( + FS.isMountpoint(old_node) || + (new_node && FS.isMountpoint(new_node)) + ) { + throw new FS.ErrnoError(10); + } + if (new_dir !== old_dir) { + errCode = FS.nodePermissions(old_dir, 'w'); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + } + FS.hashRemoveNode(old_node); + try { + old_dir.node_ops.rename(old_node, new_dir, new_name); + old_node.parent = new_dir; + } catch (e) { + throw e; + } finally { + FS.hashAddNode(old_node); + } + }, + rmdir(path) { + var lookup = FS.lookupPath(path, { parent: true }); + var parent = lookup.node; + var name = PATH.basename(path); + var node = FS.lookupNode(parent, name); + var errCode = FS.mayDelete(parent, name, true); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.rmdir) { + throw new FS.ErrnoError(63); + } + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); + } + parent.node_ops.rmdir(parent, name); + FS.destroyNode(node); + }, + readdir(path) { + var lookup = FS.lookupPath(path, { follow: true }); + var node = lookup.node; + if (!node.node_ops.readdir) { + throw new FS.ErrnoError(54); + } + return node.node_ops.readdir(node); + }, + unlink(path) { + var lookup = FS.lookupPath(path, { parent: true }); + var parent = lookup.node; + if (!parent) { + throw new FS.ErrnoError(44); + } + var name = PATH.basename(path); + var node = FS.lookupNode(parent, name); + var errCode = FS.mayDelete(parent, name, false); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.unlink) { + throw new FS.ErrnoError(63); + } + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); + } + parent.node_ops.unlink(parent, name); + FS.destroyNode(node); + }, + readlink(path) { + var lookup = FS.lookupPath(path); + var link = lookup.node; + if (!link) { + throw new FS.ErrnoError(44); + } + if (!link.node_ops.readlink) { + throw new FS.ErrnoError(28); + } + return link.node_ops.readlink(link); + }, + stat(path, dontFollow) { + var lookup = FS.lookupPath(path, { follow: !dontFollow }); + var node = lookup.node; + if (!node) { + throw new FS.ErrnoError(44); + } + if (!node.node_ops.getattr) { + throw new FS.ErrnoError(63); + } + return node.node_ops.getattr(node); + }, + lstat(path) { + return FS.stat(path, true); + }, + chmod(path, mode, dontFollow) { + var node; + if (typeof path == 'string') { + var lookup = FS.lookupPath(path, { follow: !dontFollow }); + node = lookup.node; + } else { + node = path; + } + if (!node.node_ops.setattr) { + throw new FS.ErrnoError(63); + } + node.node_ops.setattr(node, { + mode: (mode & 4095) | (node.mode & ~4095), + ctime: Date.now(), + }); + }, + lchmod(path, mode) { + FS.chmod(path, mode, true); + }, + fchmod(fd, mode) { + var stream = FS.getStreamChecked(fd); + FS.chmod(stream.node, mode); + }, + chown(path, uid, gid, dontFollow) { + var node; + if (typeof path == 'string') { + var lookup = FS.lookupPath(path, { follow: !dontFollow }); + node = lookup.node; + } else { + node = path; + } + if (!node.node_ops.setattr) { + throw new FS.ErrnoError(63); + } + node.node_ops.setattr(node, { timestamp: Date.now() }); + }, + lchown(path, uid, gid) { + FS.chown(path, uid, gid, true); + }, + fchown(fd, uid, gid) { + var stream = FS.getStreamChecked(fd); + FS.chown(stream.node, uid, gid); + }, + truncate(path, len) { + if (len < 0) { + throw new FS.ErrnoError(28); + } + var node; + if (typeof path == 'string') { + var lookup = FS.lookupPath(path, { follow: true }); + node = lookup.node; + } else { + node = path; + } + if (!node.node_ops.setattr) { + throw new FS.ErrnoError(63); + } + if (FS.isDir(node.mode)) { + throw new FS.ErrnoError(31); + } + if (!FS.isFile(node.mode)) { + throw new FS.ErrnoError(28); + } + var errCode = FS.nodePermissions(node, 'w'); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + node.node_ops.setattr(node, { size: len, timestamp: Date.now() }); + }, + ftruncate(fd, len) { + var stream = FS.getStreamChecked(fd); + if ((stream.flags & 2097155) === 0) { + throw new FS.ErrnoError(28); + } + FS.truncate(stream.node, len); + }, + utime(path, atime, mtime) { + var lookup = FS.lookupPath(path, { follow: true }); + var node = lookup.node; + node.node_ops.setattr(node, { atime, mtime }); + }, + open(path, flags, mode = 438) { + if (path === '') { + throw new FS.ErrnoError(44); + } + flags = + typeof flags == 'string' ? FS_modeStringToFlags(flags) : flags; + if (flags & 64) { + mode = (mode & 4095) | 32768; + } else { + mode = 0; + } + var node; + if (typeof path == 'object') { + node = path; + } else { + var lookup = FS.lookupPath(path, { + follow: !(flags & 131072), + noent_okay: true, + }); + node = lookup.node; + path = lookup.path; + } + var created = false; + if (flags & 64) { + if (node) { + if (flags & 128) { + throw new FS.ErrnoError(20); + } + } else { + node = FS.mknod(path, mode, 0); + created = true; + } + } + if (!node) { + throw new FS.ErrnoError(44); + } + if (FS.isChrdev(node.mode)) { + flags &= ~512; + } + if (flags & 65536 && !FS.isDir(node.mode)) { + throw new FS.ErrnoError(54); + } + if (!created) { + var errCode = FS.mayOpen(node, flags); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + } + if (flags & 512 && !created) { + FS.truncate(node, 0); + } + flags &= ~(128 | 512 | 131072); + var stream = FS.createStream({ + node, + path: FS.getPath(node), + flags, + seekable: true, + position: 0, + stream_ops: node.stream_ops, + ungotten: [], + error: false, + }); + if (stream.stream_ops.open) { + stream.stream_ops.open(stream); + } + if (Module['logReadFiles'] && !(flags & 1)) { + if (!(path in FS.readFiles)) { + FS.readFiles[path] = 1; + } + } + return stream; + }, + close(stream) { + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if (stream.getdents) stream.getdents = null; + try { + if (stream.stream_ops.close) { + stream.stream_ops.close(stream); + } + } catch (e) { + throw e; + } finally { + FS.closeStream(stream.fd); + } + stream.fd = null; + }, + isClosed(stream) { + return stream.fd === null; + }, + llseek(stream, offset, whence) { + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if (!stream.seekable || !stream.stream_ops.llseek) { + throw new FS.ErrnoError(70); + } + if (whence != 0 && whence != 1 && whence != 2) { + throw new FS.ErrnoError(28); + } + stream.position = stream.stream_ops.llseek(stream, offset, whence); + stream.ungotten = []; + return stream.position; + }, + read(stream, buffer, offset, length, position) { + if (length < 0 || position < 0) { + throw new FS.ErrnoError(28); + } + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if ((stream.flags & 2097155) === 1) { + throw new FS.ErrnoError(8); + } + if (FS.isDir(stream.node.mode)) { + throw new FS.ErrnoError(31); + } + if (!stream.stream_ops.read) { + throw new FS.ErrnoError(28); + } + var seeking = typeof position != 'undefined'; + if (!seeking) { + position = stream.position; + } else if (!stream.seekable) { + throw new FS.ErrnoError(70); + } + var bytesRead = stream.stream_ops.read( + stream, + buffer, + offset, + length, + position + ); + if (!seeking) stream.position += bytesRead; + return bytesRead; + }, + write(stream, buffer, offset, length, position, canOwn) { + if (length < 0 || position < 0) { + throw new FS.ErrnoError(28); + } + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if ((stream.flags & 2097155) === 0) { + throw new FS.ErrnoError(8); + } + if (FS.isDir(stream.node.mode)) { + throw new FS.ErrnoError(31); + } + if (!stream.stream_ops.write) { + throw new FS.ErrnoError(28); + } + if (stream.seekable && stream.flags & 1024) { + FS.llseek(stream, 0, 2); + } + var seeking = typeof position != 'undefined'; + if (!seeking) { + position = stream.position; + } else if (!stream.seekable) { + throw new FS.ErrnoError(70); + } + var bytesWritten = stream.stream_ops.write( + stream, + buffer, + offset, + length, + position, + canOwn + ); + if (!seeking) stream.position += bytesWritten; + return bytesWritten; + }, + allocate(stream, offset, length) { + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if (offset < 0 || length <= 0) { + throw new FS.ErrnoError(28); + } + if ((stream.flags & 2097155) === 0) { + throw new FS.ErrnoError(8); + } + if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + if (!stream.stream_ops.allocate) { + throw new FS.ErrnoError(138); + } + stream.stream_ops.allocate(stream, offset, length); + }, + mmap(stream, length, position, prot, flags) { + if ( + (prot & 2) !== 0 && + (flags & 2) === 0 && + (stream.flags & 2097155) !== 2 + ) { + throw new FS.ErrnoError(2); + } + if ((stream.flags & 2097155) === 1) { + throw new FS.ErrnoError(2); + } + if (!stream.stream_ops.mmap) { + throw new FS.ErrnoError(43); + } + if (!length) { + throw new FS.ErrnoError(28); + } + return stream.stream_ops.mmap( + stream, + length, + position, + prot, + flags + ); + }, + msync(stream, buffer, offset, length, mmapFlags) { + if (!stream.stream_ops.msync) { + return 0; + } + return stream.stream_ops.msync( + stream, + buffer, + offset, + length, + mmapFlags + ); + }, + ioctl(stream, cmd, arg) { + if (!stream.stream_ops.ioctl) { + throw new FS.ErrnoError(59); + } + return stream.stream_ops.ioctl(stream, cmd, arg); + }, + readFile(path, opts = {}) { + opts.flags = opts.flags || 0; + opts.encoding = opts.encoding || 'binary'; + if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') { + throw new Error(`Invalid encoding type "${opts.encoding}"`); + } + var ret; + var stream = FS.open(path, opts.flags); + var stat = FS.stat(path); + var length = stat.size; + var buf = new Uint8Array(length); + FS.read(stream, buf, 0, length, 0); + if (opts.encoding === 'utf8') { + ret = UTF8ArrayToString(buf); + } else if (opts.encoding === 'binary') { + ret = buf; + } + FS.close(stream); + return ret; + }, + writeFile(path, data, opts = {}) { + opts.flags = opts.flags || 577; + var stream = FS.open(path, opts.flags, opts.mode); + if (typeof data == 'string') { + var buf = new Uint8Array(lengthBytesUTF8(data) + 1); + var actualNumBytes = stringToUTF8Array( + data, + buf, + 0, + buf.length + ); + FS.write( + stream, + buf, + 0, + actualNumBytes, + undefined, + opts.canOwn + ); + } else if (ArrayBuffer.isView(data)) { + FS.write( + stream, + data, + 0, + data.byteLength, + undefined, + opts.canOwn + ); + } else { + throw new Error('Unsupported data type'); + } + FS.close(stream); + }, + cwd: () => FS.currentPath, + chdir(path) { + var lookup = FS.lookupPath(path, { follow: true }); + if (lookup.node === null) { + throw new FS.ErrnoError(44); + } + if (!FS.isDir(lookup.node.mode)) { + throw new FS.ErrnoError(54); + } + var errCode = FS.nodePermissions(lookup.node, 'x'); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + FS.currentPath = lookup.path; + }, + createDefaultDirectories() { + FS.mkdir('/tmp'); + FS.mkdir('/home'); + FS.mkdir('/home/web_user'); + }, + createDefaultDevices() { + FS.mkdir('/dev'); + FS.registerDevice(FS.makedev(1, 3), { + read: () => 0, + write: (stream, buffer, offset, length, pos) => length, + llseek: () => 0, + }); + FS.mkdev('/dev/null', FS.makedev(1, 3)); + TTY.register(FS.makedev(5, 0), TTY.default_tty_ops); + TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops); + FS.mkdev('/dev/tty', FS.makedev(5, 0)); + FS.mkdev('/dev/tty1', FS.makedev(6, 0)); + var randomBuffer = new Uint8Array(1024), + randomLeft = 0; + var randomByte = () => { + if (randomLeft === 0) { + randomLeft = randomFill(randomBuffer).byteLength; + } + return randomBuffer[--randomLeft]; + }; + FS.createDevice('/dev', 'random', randomByte); + FS.createDevice('/dev', 'urandom', randomByte); + FS.mkdir('/dev/shm'); + FS.mkdir('/dev/shm/tmp'); + }, + createSpecialDirectories() { + FS.mkdir('/proc'); + var proc_self = FS.mkdir('/proc/self'); + FS.mkdir('/proc/self/fd'); + FS.mount( + { + mount() { + var node = FS.createNode(proc_self, 'fd', 16895, 73); + node.stream_ops = { llseek: MEMFS.stream_ops.llseek }; + node.node_ops = { + lookup(parent, name) { + var fd = +name; + var stream = FS.getStreamChecked(fd); + var ret = { + parent: null, + mount: { mountpoint: 'fake' }, + node_ops: { readlink: () => stream.path }, + id: fd + 1, + }; + ret.parent = ret; + return ret; + }, + readdir() { + return Array.from(FS.streams.entries()) + .filter(([k, v]) => v) + .map(([k, v]) => k.toString()); + }, + }; + return node; + }, + }, + {}, + '/proc/self/fd' + ); + }, + createStandardStreams(input, output, error) { + if (input) { + FS.createDevice('/dev', 'stdin', input); + } else { + FS.symlink('/dev/tty', '/dev/stdin'); + } + if (output) { + FS.createDevice('/dev', 'stdout', null, output); + } else { + FS.symlink('/dev/tty', '/dev/stdout'); + } + if (error) { + FS.createDevice('/dev', 'stderr', null, error); + } else { + FS.symlink('/dev/tty1', '/dev/stderr'); + } + var stdin = FS.open('/dev/stdin', 0); + var stdout = FS.open('/dev/stdout', 1); + var stderr = FS.open('/dev/stderr', 1); + }, + staticInit() { + FS.nameTable = new Array(4096); + FS.mount(MEMFS, {}, '/'); + FS.createDefaultDirectories(); + FS.createDefaultDevices(); + FS.createSpecialDirectories(); + FS.filesystems = { MEMFS, PROXYFS }; + }, + init(input, output, error) { + FS.initialized = true; + input ??= Module['stdin']; + output ??= Module['stdout']; + error ??= Module['stderr']; + FS.createStandardStreams(input, output, error); + }, + quit() { + FS.initialized = false; + _fflush(0); + for (var i = 0; i < FS.streams.length; i++) { + var stream = FS.streams[i]; + if (!stream) { + continue; + } + FS.close(stream); + } + }, + findObject(path, dontResolveLastLink) { + var ret = FS.analyzePath(path, dontResolveLastLink); + if (!ret.exists) { + return null; + } + return ret.object; + }, + analyzePath(path, dontResolveLastLink) { + try { + var lookup = FS.lookupPath(path, { + follow: !dontResolveLastLink, + }); + path = lookup.path; + } catch (e) {} + var ret = { + isRoot: false, + exists: false, + error: 0, + name: null, + path: null, + object: null, + parentExists: false, + parentPath: null, + parentObject: null, + }; + try { + var lookup = FS.lookupPath(path, { parent: true }); + ret.parentExists = true; + ret.parentPath = lookup.path; + ret.parentObject = lookup.node; + ret.name = PATH.basename(path); + lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); + ret.exists = true; + ret.path = lookup.path; + ret.object = lookup.node; + ret.name = lookup.node.name; + ret.isRoot = lookup.path === '/'; + } catch (e) { + ret.error = e.errno; + } + return ret; + }, + createPath(parent, path, canRead, canWrite) { + parent = typeof parent == 'string' ? parent : FS.getPath(parent); + var parts = path.split('/').reverse(); + while (parts.length) { + var part = parts.pop(); + if (!part) continue; + var current = PATH.join2(parent, part); + try { + FS.mkdir(current); + } catch (e) {} + parent = current; + } + return current; + }, + createFile(parent, name, properties, canRead, canWrite) { + var path = PATH.join2( + typeof parent == 'string' ? parent : FS.getPath(parent), + name + ); + var mode = FS_getMode(canRead, canWrite); + return FS.create(path, mode); + }, + createDataFile(parent, name, data, canRead, canWrite, canOwn) { + var path = name; + if (parent) { + parent = + typeof parent == 'string' ? parent : FS.getPath(parent); + path = name ? PATH.join2(parent, name) : parent; + } + var mode = FS_getMode(canRead, canWrite); + var node = FS.create(path, mode); + if (data) { + if (typeof data == 'string') { + var arr = new Array(data.length); + for (var i = 0, len = data.length; i < len; ++i) + arr[i] = data.charCodeAt(i); + data = arr; + } + FS.chmod(node, mode | 146); + var stream = FS.open(node, 577); + FS.write(stream, data, 0, data.length, 0, canOwn); + FS.close(stream); + FS.chmod(node, mode); + } + }, + createDevice(parent, name, input, output) { + var path = PATH.join2( + typeof parent == 'string' ? parent : FS.getPath(parent), + name + ); + var mode = FS_getMode(!!input, !!output); + FS.createDevice.major ??= 64; + var dev = FS.makedev(FS.createDevice.major++, 0); + FS.registerDevice(dev, { + open(stream) { + stream.seekable = false; + }, + close(stream) { + if (output?.buffer?.length) { + output(10); + } + }, + read(stream, buffer, offset, length, pos) { + var bytesRead = 0; + for (var i = 0; i < length; i++) { + var result; + try { + result = input(); + } catch (e) { + throw new FS.ErrnoError(29); + } + if (result === undefined && bytesRead === 0) { + throw new FS.ErrnoError(6); + } + if (result === null || result === undefined) break; + bytesRead++; + buffer[offset + i] = result; + } + if (bytesRead) { + stream.node.atime = Date.now(); + } + return bytesRead; + }, + write(stream, buffer, offset, length, pos) { + for (var i = 0; i < length; i++) { + try { + output(buffer[offset + i]); + } catch (e) { + throw new FS.ErrnoError(29); + } + } + if (length) { + stream.node.mtime = stream.node.ctime = Date.now(); + } + return i; + }, + }); + return FS.mkdev(path, mode, dev); + }, + forceLoadFile(obj) { + if (obj.isDevice || obj.isFolder || obj.link || obj.contents) + return true; + if (typeof XMLHttpRequest != 'undefined') { + throw new Error( + 'Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.' + ); + } else { + try { + obj.contents = readBinary(obj.url); + obj.usedBytes = obj.contents.length; + } catch (e) { + throw new FS.ErrnoError(29); + } + } + }, + createLazyFile(parent, name, url, canRead, canWrite) { + class LazyUint8Array { + lengthKnown = false; + chunks = []; + get(idx) { + if (idx > this.length - 1 || idx < 0) { + return undefined; + } + var chunkOffset = idx % this.chunkSize; + var chunkNum = (idx / this.chunkSize) | 0; + return this.getter(chunkNum)[chunkOffset]; + } + setDataGetter(getter) { + this.getter = getter; + } + cacheLength() { + var xhr = new XMLHttpRequest(); + xhr.open('HEAD', url, false); + xhr.send(null); + if ( + !( + (xhr.status >= 200 && xhr.status < 300) || + xhr.status === 304 + ) + ) + throw new Error( + "Couldn't load " + url + '. Status: ' + xhr.status + ); + var datalength = Number( + xhr.getResponseHeader('Content-length') + ); + var header; + var hasByteServing = + (header = xhr.getResponseHeader('Accept-Ranges')) && + header === 'bytes'; + var usesGzip = + (header = xhr.getResponseHeader('Content-Encoding')) && + header === 'gzip'; + var chunkSize = 1024 * 1024; + if (!hasByteServing) chunkSize = datalength; + var doXHR = (from, to) => { + if (from > to) + throw new Error( + 'invalid range (' + + from + + ', ' + + to + + ') or no bytes requested!' + ); + if (to > datalength - 1) + throw new Error( + 'only ' + + datalength + + ' bytes available! programmer error!' + ); + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, false); + if (datalength !== chunkSize) + xhr.setRequestHeader( + 'Range', + 'bytes=' + from + '-' + to + ); + xhr.responseType = 'arraybuffer'; + if (xhr.overrideMimeType) { + xhr.overrideMimeType( + 'text/plain; charset=x-user-defined' + ); + } + xhr.send(null); + if ( + !( + (xhr.status >= 200 && xhr.status < 300) || + xhr.status === 304 + ) + ) + throw new Error( + "Couldn't load " + + url + + '. Status: ' + + xhr.status + ); + if (xhr.response !== undefined) { + return new Uint8Array(xhr.response || []); + } + return intArrayFromString(xhr.responseText || '', true); + }; + var lazyArray = this; + lazyArray.setDataGetter((chunkNum) => { + var start = chunkNum * chunkSize; + var end = (chunkNum + 1) * chunkSize - 1; + end = Math.min(end, datalength - 1); + if (typeof lazyArray.chunks[chunkNum] == 'undefined') { + lazyArray.chunks[chunkNum] = doXHR(start, end); + } + if (typeof lazyArray.chunks[chunkNum] == 'undefined') + throw new Error('doXHR failed!'); + return lazyArray.chunks[chunkNum]; + }); + if (usesGzip || !datalength) { + chunkSize = datalength = 1; + datalength = this.getter(0).length; + chunkSize = datalength; + out( + 'LazyFiles on gzip forces download of the whole file when length is accessed' + ); + } + this._length = datalength; + this._chunkSize = chunkSize; + this.lengthKnown = true; + } + get length() { + if (!this.lengthKnown) { + this.cacheLength(); + } + return this._length; + } + get chunkSize() { + if (!this.lengthKnown) { + this.cacheLength(); + } + return this._chunkSize; + } + } + if (typeof XMLHttpRequest != 'undefined') { + if (!ENVIRONMENT_IS_WORKER) + throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'; + var lazyArray = new LazyUint8Array(); + var properties = { isDevice: false, contents: lazyArray }; + } else { + var properties = { isDevice: false, url }; + } + var node = FS.createFile( + parent, + name, + properties, + canRead, + canWrite + ); + if (properties.contents) { + node.contents = properties.contents; + } else if (properties.url) { + node.contents = null; + node.url = properties.url; + } + Object.defineProperties(node, { + usedBytes: { + get: function () { + return this.contents.length; + }, + }, + }); + var stream_ops = {}; + var keys = Object.keys(node.stream_ops); + keys.forEach((key) => { + var fn = node.stream_ops[key]; + stream_ops[key] = (...args) => { + FS.forceLoadFile(node); + return fn(...args); + }; + }); + function writeChunks(stream, buffer, offset, length, position) { + var contents = stream.node.contents; + if (position >= contents.length) return 0; + var size = Math.min(contents.length - position, length); + if (contents.slice) { + for (var i = 0; i < size; i++) { + buffer[offset + i] = contents[position + i]; + } + } else { + for (var i = 0; i < size; i++) { + buffer[offset + i] = contents.get(position + i); + } + } + return size; + } + stream_ops.read = (stream, buffer, offset, length, position) => { + FS.forceLoadFile(node); + return writeChunks(stream, buffer, offset, length, position); + }; + stream_ops.mmap = (stream, length, position, prot, flags) => { + FS.forceLoadFile(node); + var ptr = mmapAlloc(length); + if (!ptr) { + throw new FS.ErrnoError(48); + } + writeChunks(stream, HEAP8, ptr, length, position); + return { ptr, allocated: true }; + }; + node.stream_ops = stream_ops; + return node; + }, + }; + Module['FS'] = FS; + var SOCKFS = { + websocketArgs: {}, + callbacks: {}, + on(event, callback) { + SOCKFS.callbacks[event] = callback; + }, + emit(event, param) { + SOCKFS.callbacks[event]?.(param); + }, + mount(mount) { + SOCKFS.websocketArgs = Module['websocket'] || {}; + (Module['websocket'] ??= {})['on'] = SOCKFS.on; + return FS.createNode(null, '/', 16895, 0); + }, + createSocket(family, type, protocol) { + type &= ~526336; + var streaming = type == 1; + if (streaming && protocol && protocol != 6) { + throw new FS.ErrnoError(66); + } + var sock = { + family, + type, + protocol, + server: null, + error: null, + peers: {}, + pending: [], + recv_queue: [], + sock_ops: SOCKFS.websocket_sock_ops, + }; + var name = SOCKFS.nextname(); + var node = FS.createNode(SOCKFS.root, name, 49152, 0); + node.sock = sock; + var stream = FS.createStream({ + path: name, + node, + flags: 2, + seekable: false, + stream_ops: SOCKFS.stream_ops, + }); + sock.stream = stream; + return sock; + }, + getSocket(fd) { + var stream = FS.getStream(fd); + if (!stream || !FS.isSocket(stream.node.mode)) { + return null; + } + return stream.node.sock; + }, + stream_ops: { + poll(stream) { + var sock = stream.node.sock; + return sock.sock_ops.poll(sock); + }, + ioctl(stream, request, varargs) { + var sock = stream.node.sock; + return sock.sock_ops.ioctl(sock, request, varargs); + }, + read(stream, buffer, offset, length, position) { + var sock = stream.node.sock; + var msg = sock.sock_ops.recvmsg(sock, length); + if (!msg) { + return 0; + } + buffer.set(msg.buffer, offset); + return msg.buffer.length; + }, + write(stream, buffer, offset, length, position) { + var sock = stream.node.sock; + return sock.sock_ops.sendmsg(sock, buffer, offset, length); + }, + close(stream) { + var sock = stream.node.sock; + sock.sock_ops.close(sock); + }, + }, + nextname() { + if (!SOCKFS.nextname.current) { + SOCKFS.nextname.current = 0; + } + return `socket[${SOCKFS.nextname.current++}]`; + }, + websocket_sock_ops: { + createPeer(sock, addr, port) { + var ws; + if (typeof addr == 'object') { + ws = addr; + addr = null; + port = null; + } + if (ws) { + if (ws._socket) { + addr = ws._socket.remoteAddress; + port = ws._socket.remotePort; + } else { + var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url); + if (!result) { + throw new Error( + 'WebSocket URL must be in the format ws(s)://address:port' + ); + } + addr = result[1]; + port = parseInt(result[2], 10); + } + } else { + try { + var url = 'ws:#'.replace('#', '//'); + var subProtocols = 'binary'; + var opts = undefined; + if ('function' === typeof SOCKFS.websocketArgs['url']) { + url = SOCKFS.websocketArgs['url'](...arguments); + } else if ( + 'string' === typeof SOCKFS.websocketArgs['url'] + ) { + url = SOCKFS.websocketArgs['url']; + } + if (SOCKFS.websocketArgs['subprotocol']) { + subProtocols = SOCKFS.websocketArgs['subprotocol']; + } else if ( + SOCKFS.websocketArgs['subprotocol'] === null + ) { + subProtocols = 'null'; + } + if (url === 'ws://' || url === 'wss://') { + var parts = addr.split('/'); + url = + url + + parts[0] + + ':' + + port + + '/' + + parts.slice(1).join('/'); + } + if (subProtocols !== 'null') { + subProtocols = subProtocols + .replace(/^ +| +$/g, '') + .split(/ *, */); + opts = subProtocols; + } + var WebSocketConstructor; + { + WebSocketConstructor = WebSocket; + } + if (Module['websocket']['decorator']) { + WebSocketConstructor = + Module['websocket']['decorator']( + WebSocketConstructor + ); + } + ws = new WebSocketConstructor(url, opts); + ws.binaryType = 'arraybuffer'; + } catch (e) { + throw new FS.ErrnoError(23); + } + } + var peer = { addr, port, socket: ws, msg_send_queue: [] }; + SOCKFS.websocket_sock_ops.addPeer(sock, peer); + SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer); + if (sock.type === 2 && typeof sock.sport != 'undefined') { + peer.msg_send_queue.push( + new Uint8Array([ + 255, + 255, + 255, + 255, + 'p'.charCodeAt(0), + 'o'.charCodeAt(0), + 'r'.charCodeAt(0), + 't'.charCodeAt(0), + (sock.sport & 65280) >> 8, + sock.sport & 255, + ]) + ); + } + return peer; + }, + getPeer(sock, addr, port) { + return sock.peers[addr + ':' + port]; + }, + addPeer(sock, peer) { + sock.peers[peer.addr + ':' + peer.port] = peer; + }, + removePeer(sock, peer) { + delete sock.peers[peer.addr + ':' + peer.port]; + }, + handlePeerEvents(sock, peer) { + var first = true; + var handleOpen = function () { + sock.connecting = false; + SOCKFS.emit('open', sock.stream.fd); + try { + var queued = peer.msg_send_queue.shift(); + while (queued) { + peer.socket.send(queued); + queued = peer.msg_send_queue.shift(); + } + } catch (e) { + peer.socket.close(); + } + }; + function handleMessage(data) { + if (typeof data == 'string') { + var encoder = new TextEncoder(); + data = encoder.encode(data); + } else { + assert(data.byteLength !== undefined); + if (data.byteLength == 0) { + return; + } + data = new Uint8Array(data); + } + var wasfirst = first; + first = false; + if ( + wasfirst && + data.length === 10 && + data[0] === 255 && + data[1] === 255 && + data[2] === 255 && + data[3] === 255 && + data[4] === 'p'.charCodeAt(0) && + data[5] === 'o'.charCodeAt(0) && + data[6] === 'r'.charCodeAt(0) && + data[7] === 't'.charCodeAt(0) + ) { + var newport = (data[8] << 8) | data[9]; + SOCKFS.websocket_sock_ops.removePeer(sock, peer); + peer.port = newport; + SOCKFS.websocket_sock_ops.addPeer(sock, peer); + return; + } + sock.recv_queue.push({ + addr: peer.addr, + port: peer.port, + data, + }); + SOCKFS.emit('message', sock.stream.fd); + } + if (ENVIRONMENT_IS_NODE) { + peer.socket.on('open', handleOpen); + peer.socket.on('message', function (data, isBinary) { + if (!isBinary) { + return; + } + handleMessage(new Uint8Array(data).buffer); + }); + peer.socket.on('close', function () { + SOCKFS.emit('close', sock.stream.fd); + }); + peer.socket.on('error', function (error) { + sock.error = 14; + SOCKFS.emit('error', [ + sock.stream.fd, + sock.error, + 'ECONNREFUSED: Connection refused', + ]); + }); + } else { + peer.socket.onopen = handleOpen; + peer.socket.onclose = function () { + SOCKFS.emit('close', sock.stream.fd); + }; + peer.socket.onmessage = function peer_socket_onmessage( + event + ) { + handleMessage(event.data); + }; + peer.socket.onerror = function (error) { + sock.error = 14; + SOCKFS.emit('error', [ + sock.stream.fd, + sock.error, + 'ECONNREFUSED: Connection refused', + ]); + }; + } + }, + poll(sock) { + if (sock.type === 1 && sock.server) { + return sock.pending.length ? 64 | 1 : 0; + } + var mask = 0; + var dest = + sock.type === 1 + ? SOCKFS.websocket_sock_ops.getPeer( + sock, + sock.daddr, + sock.dport + ) + : null; + if ( + sock.recv_queue.length || + !dest || + (dest && dest.socket.readyState === dest.socket.CLOSING) || + (dest && dest.socket.readyState === dest.socket.CLOSED) + ) { + mask |= 64 | 1; + } + if ( + !dest || + (dest && dest.socket.readyState === dest.socket.OPEN) + ) { + mask |= 4; + } + if ( + (dest && dest.socket.readyState === dest.socket.CLOSING) || + (dest && dest.socket.readyState === dest.socket.CLOSED) + ) { + if (sock.connecting) { + mask |= 4; + } else { + mask |= 16; + } + } + return mask; + }, + ioctl(sock, request, arg) { + switch (request) { + case 21531: + var bytes = 0; + if (sock.recv_queue.length) { + bytes = sock.recv_queue[0].data.length; + } + HEAP32[arg >> 2] = bytes; + return 0; + default: + return 28; + } + }, + close(sock) { + if (sock.server) { + try { + sock.server.close(); + } catch (e) {} + sock.server = null; + } + var peers = Object.keys(sock.peers); + for (var i = 0; i < peers.length; i++) { + var peer = sock.peers[peers[i]]; + try { + peer.socket.close(); + } catch (e) {} + SOCKFS.websocket_sock_ops.removePeer(sock, peer); + } + return 0; + }, + bind(sock, addr, port) { + if ( + typeof sock.saddr != 'undefined' || + typeof sock.sport != 'undefined' + ) { + throw new FS.ErrnoError(28); + } + sock.saddr = addr; + sock.sport = port; + if (sock.type === 2) { + if (sock.server) { + sock.server.close(); + sock.server = null; + } + try { + sock.sock_ops.listen(sock, 0); + } catch (e) { + if (!(e.name === 'ErrnoError')) throw e; + if (e.errno !== 138) throw e; + } + } + }, + connect(sock, addr, port) { + if (sock.server) { + throw new FS.ErrnoError(138); + } + if ( + typeof sock.daddr != 'undefined' && + typeof sock.dport != 'undefined' + ) { + var dest = SOCKFS.websocket_sock_ops.getPeer( + sock, + sock.daddr, + sock.dport + ); + if (dest) { + if (dest.socket.readyState === dest.socket.CONNECTING) { + throw new FS.ErrnoError(7); + } else { + throw new FS.ErrnoError(30); + } + } + } + var peer = SOCKFS.websocket_sock_ops.createPeer( + sock, + addr, + port + ); + sock.daddr = peer.addr; + sock.dport = peer.port; + sock.connecting = true; + }, + listen(sock, backlog) { + if (!ENVIRONMENT_IS_NODE) { + throw new FS.ErrnoError(138); + } + }, + accept(listensock) { + if (!listensock.server || !listensock.pending.length) { + throw new FS.ErrnoError(28); + } + var newsock = listensock.pending.shift(); + newsock.stream.flags = listensock.stream.flags; + return newsock; + }, + getname(sock, peer) { + var addr, port; + if (peer) { + if (sock.daddr === undefined || sock.dport === undefined) { + throw new FS.ErrnoError(53); + } + addr = sock.daddr; + port = sock.dport; + } else { + addr = sock.saddr || 0; + port = sock.sport || 0; + } + return { addr, port }; + }, + sendmsg(sock, buffer, offset, length, addr, port) { + if (sock.type === 2) { + if (addr === undefined || port === undefined) { + addr = sock.daddr; + port = sock.dport; + } + if (addr === undefined || port === undefined) { + throw new FS.ErrnoError(17); + } + } else { + addr = sock.daddr; + port = sock.dport; + } + var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port); + if (sock.type === 1) { + if ( + !dest || + dest.socket.readyState === dest.socket.CLOSING || + dest.socket.readyState === dest.socket.CLOSED + ) { + throw new FS.ErrnoError(53); + } + } + if (ArrayBuffer.isView(buffer)) { + offset += buffer.byteOffset; + buffer = buffer.buffer; + } + var data = buffer.slice(offset, offset + length); + if (!dest || dest.socket.readyState !== dest.socket.OPEN) { + if (sock.type === 2) { + if ( + !dest || + dest.socket.readyState === dest.socket.CLOSING || + dest.socket.readyState === dest.socket.CLOSED + ) { + dest = SOCKFS.websocket_sock_ops.createPeer( + sock, + addr, + port + ); + } + } + dest.msg_send_queue.push(data); + return length; + } + try { + dest.socket.send(data); + return length; + } catch (e) { + throw new FS.ErrnoError(28); + } + }, + recvmsg(sock, length, flags) { + if (sock.type === 1 && sock.server) { + throw new FS.ErrnoError(53); + } + var queued = sock.recv_queue.shift(); + if (!queued) { + if (sock.type === 1) { + var dest = SOCKFS.websocket_sock_ops.getPeer( + sock, + sock.daddr, + sock.dport + ); + if (!dest) { + throw new FS.ErrnoError(53); + } + if ( + dest.socket.readyState === dest.socket.CLOSING || + dest.socket.readyState === dest.socket.CLOSED + ) { + return null; + } + throw new FS.ErrnoError(6); + } + throw new FS.ErrnoError(6); + } + var queuedLength = queued.data.byteLength || queued.data.length; + var queuedOffset = queued.data.byteOffset || 0; + var queuedBuffer = queued.data.buffer || queued.data; + var bytesRead = Math.min(length, queuedLength); + var res = { + buffer: new Uint8Array( + queuedBuffer, + queuedOffset, + bytesRead + ), + addr: queued.addr, + port: queued.port, + }; + if (flags & 2) { + bytesRead = 0; + } + if (sock.type === 1 && bytesRead < queuedLength) { + var bytesRemaining = queuedLength - bytesRead; + queued.data = new Uint8Array( + queuedBuffer, + queuedOffset + bytesRead, + bytesRemaining + ); + sock.recv_queue.unshift(queued); + } + return res; + }, + }, + }; + var getSocketFromFD = (fd) => { + var socket = SOCKFS.getSocket(fd); + if (!socket) throw new FS.ErrnoError(8); + return socket; + }; + var inetPton4 = (str) => { + var b = str.split('.'); + for (var i = 0; i < 4; i++) { + var tmp = Number(b[i]); + if (isNaN(tmp)) return null; + b[i] = tmp; + } + return (b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24)) >>> 0; + }; + var jstoi_q = (str) => parseInt(str); + var inetPton6 = (str) => { + var words; + var w, offset, z; + var valid6regx = + /^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i; + var parts = []; + if (!valid6regx.test(str)) { + return null; + } + if (str === '::') { + return [0, 0, 0, 0, 0, 0, 0, 0]; + } + if (str.startsWith('::')) { + str = str.replace('::', 'Z:'); + } else { + str = str.replace('::', ':Z:'); + } + if (str.indexOf('.') > 0) { + str = str.replace(new RegExp('[.]', 'g'), ':'); + words = str.split(':'); + words[words.length - 4] = + jstoi_q(words[words.length - 4]) + + jstoi_q(words[words.length - 3]) * 256; + words[words.length - 3] = + jstoi_q(words[words.length - 2]) + + jstoi_q(words[words.length - 1]) * 256; + words = words.slice(0, words.length - 2); + } else { + words = str.split(':'); + } + offset = 0; + z = 0; + for (w = 0; w < words.length; w++) { + if (typeof words[w] == 'string') { + if (words[w] === 'Z') { + for (z = 0; z < 8 - words.length + 1; z++) { + parts[w + z] = 0; + } + offset = z - 1; + } else { + parts[w + offset] = _htons(parseInt(words[w], 16)); + } + } else { + parts[w + offset] = words[w]; + } + } + return [ + (parts[1] << 16) | parts[0], + (parts[3] << 16) | parts[2], + (parts[5] << 16) | parts[4], + (parts[7] << 16) | parts[6], + ]; + }; + var writeSockaddr = (sa, family, addr, port, addrlen) => { + switch (family) { + case 2: + addr = inetPton4(addr); + zeroMemory(sa, 16); + if (addrlen) { + HEAP32[addrlen >> 2] = 16; + } + HEAP16[sa >> 1] = family; + HEAP32[(sa + 4) >> 2] = addr; + HEAP16[(sa + 2) >> 1] = _htons(port); + break; + case 10: + addr = inetPton6(addr); + zeroMemory(sa, 28); + if (addrlen) { + HEAP32[addrlen >> 2] = 28; + } + HEAP32[sa >> 2] = family; + HEAP32[(sa + 8) >> 2] = addr[0]; + HEAP32[(sa + 12) >> 2] = addr[1]; + HEAP32[(sa + 16) >> 2] = addr[2]; + HEAP32[(sa + 20) >> 2] = addr[3]; + HEAP16[(sa + 2) >> 1] = _htons(port); + break; + default: + return 5; + } + return 0; + }; + var DNS = { + address_map: { id: 1, addrs: {}, names: {} }, + lookup_name(name) { + var res = inetPton4(name); + if (res !== null) { + return name; + } + res = inetPton6(name); + if (res !== null) { + return name; + } + var addr; + if (DNS.address_map.addrs[name]) { + addr = DNS.address_map.addrs[name]; + } else { + var id = DNS.address_map.id++; + assert(id < 65535, 'exceeded max address mappings of 65535'); + addr = '172.29.' + (id & 255) + '.' + (id & 65280); + DNS.address_map.names[addr] = name; + DNS.address_map.addrs[name] = addr; + } + return addr; + }, + lookup_addr(addr) { + if (DNS.address_map.names[addr]) { + return DNS.address_map.names[addr]; + } + return null; + }, + }; + function ___syscall_accept4(fd, addr, addrlen, flags, d1, d2) { + try { + var sock = getSocketFromFD(fd); + var newsock = sock.sock_ops.accept(sock); + if (addr) { + var errno = writeSockaddr( + addr, + newsock.family, + DNS.lookup_name(newsock.daddr), + newsock.dport, + addrlen + ); + } + return newsock.stream.fd; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + var inetNtop4 = (addr) => + (addr & 255) + + '.' + + ((addr >> 8) & 255) + + '.' + + ((addr >> 16) & 255) + + '.' + + ((addr >> 24) & 255); + var inetNtop6 = (ints) => { + var str = ''; + var word = 0; + var longest = 0; + var lastzero = 0; + var zstart = 0; + var len = 0; + var i = 0; + var parts = [ + ints[0] & 65535, + ints[0] >> 16, + ints[1] & 65535, + ints[1] >> 16, + ints[2] & 65535, + ints[2] >> 16, + ints[3] & 65535, + ints[3] >> 16, + ]; + var hasipv4 = true; + var v4part = ''; + for (i = 0; i < 5; i++) { + if (parts[i] !== 0) { + hasipv4 = false; + break; + } + } + if (hasipv4) { + v4part = inetNtop4(parts[6] | (parts[7] << 16)); + if (parts[5] === -1) { + str = '::ffff:'; + str += v4part; + return str; + } + if (parts[5] === 0) { + str = '::'; + if (v4part === '0.0.0.0') v4part = ''; + if (v4part === '0.0.0.1') v4part = '1'; + str += v4part; + return str; + } + } + for (word = 0; word < 8; word++) { + if (parts[word] === 0) { + if (word - lastzero > 1) { + len = 0; + } + lastzero = word; + len++; + } + if (len > longest) { + longest = len; + zstart = word - longest + 1; + } + } + for (word = 0; word < 8; word++) { + if (longest > 1) { + if ( + parts[word] === 0 && + word >= zstart && + word < zstart + longest + ) { + if (word === zstart) { + str += ':'; + if (zstart === 0) str += ':'; + } + continue; + } + } + str += Number(_ntohs(parts[word] & 65535)).toString(16); + str += word < 7 ? ':' : ''; + } + return str; + }; + var readSockaddr = (sa, salen) => { + var family = HEAP16[sa >> 1]; + var port = _ntohs(HEAPU16[(sa + 2) >> 1]); + var addr; + switch (family) { + case 2: + if (salen !== 16) { + return { errno: 28 }; + } + addr = HEAP32[(sa + 4) >> 2]; + addr = inetNtop4(addr); + break; + case 10: + if (salen !== 28) { + return { errno: 28 }; + } + addr = [ + HEAP32[(sa + 8) >> 2], + HEAP32[(sa + 12) >> 2], + HEAP32[(sa + 16) >> 2], + HEAP32[(sa + 20) >> 2], + ]; + addr = inetNtop6(addr); + break; + default: + return { errno: 5 }; + } + return { family, addr, port }; + }; + var getSocketAddress = (addrp, addrlen) => { + var info = readSockaddr(addrp, addrlen); + if (info.errno) throw new FS.ErrnoError(info.errno); + info.addr = DNS.lookup_addr(info.addr) || info.addr; + return info; + }; + function ___syscall_bind(fd, addr, addrlen, d1, d2, d3) { + try { + var sock = getSocketFromFD(fd); + var info = getSocketAddress(addr, addrlen); + sock.sock_ops.bind(sock, info.addr, info.port); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + var SYSCALLS = { + DEFAULT_POLLMASK: 5, + calculateAt(dirfd, path, allowEmpty) { + if (PATH.isAbs(path)) { + return path; + } + var dir; + if (dirfd === -100) { + dir = FS.cwd(); + } else { + var dirstream = SYSCALLS.getStreamFromFD(dirfd); + dir = dirstream.path; + } + if (path.length == 0) { + if (!allowEmpty) { + throw new FS.ErrnoError(44); + } + return dir; + } + return dir + '/' + path; + }, + doStat(func, path, buf) { + var stat = func(path); + HEAP32[buf >> 2] = stat.dev; + HEAP32[(buf + 4) >> 2] = stat.mode; + HEAPU32[(buf + 8) >> 2] = stat.nlink; + HEAP32[(buf + 12) >> 2] = stat.uid; + HEAP32[(buf + 16) >> 2] = stat.gid; + HEAP32[(buf + 20) >> 2] = stat.rdev; + HEAP64[(buf + 24) >> 3] = BigInt(stat.size); + HEAP32[(buf + 32) >> 2] = 4096; + HEAP32[(buf + 36) >> 2] = stat.blocks; + var atime = stat.atime.getTime(); + var mtime = stat.mtime.getTime(); + var ctime = stat.ctime.getTime(); + HEAP64[(buf + 40) >> 3] = BigInt(Math.floor(atime / 1e3)); + HEAPU32[(buf + 48) >> 2] = (atime % 1e3) * 1e3 * 1e3; + HEAP64[(buf + 56) >> 3] = BigInt(Math.floor(mtime / 1e3)); + HEAPU32[(buf + 64) >> 2] = (mtime % 1e3) * 1e3 * 1e3; + HEAP64[(buf + 72) >> 3] = BigInt(Math.floor(ctime / 1e3)); + HEAPU32[(buf + 80) >> 2] = (ctime % 1e3) * 1e3 * 1e3; + HEAP64[(buf + 88) >> 3] = BigInt(stat.ino); + return 0; + }, + doMsync(addr, stream, len, flags, offset) { + if (!FS.isFile(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + if (flags & 2) { + return 0; + } + var buffer = HEAPU8.slice(addr, addr + len); + FS.msync(stream, buffer, offset, len, flags); + }, + getStreamFromFD(fd) { + var stream = FS.getStreamChecked(fd); + return stream; + }, + varargs: undefined, + getStr(ptr) { + var ret = UTF8ToString(ptr); + return ret; + }, + }; + function ___syscall_chdir(path) { + try { + path = SYSCALLS.getStr(path); + FS.chdir(path); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_chmod(path, mode) { + try { + path = SYSCALLS.getStr(path); + FS.chmod(path, mode); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_connect(fd, addr, addrlen, d1, d2, d3) { + try { + var sock = getSocketFromFD(fd); + var info = getSocketAddress(addr, addrlen); + sock.sock_ops.connect(sock, info.addr, info.port); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_dup(fd) { + try { + var old = SYSCALLS.getStreamFromFD(fd); + return FS.dupStream(old).fd; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_dup3(fd, newfd, flags) { + try { + var old = SYSCALLS.getStreamFromFD(fd); + if (old.fd === newfd) return -28; + if (newfd < 0 || newfd >= FS.MAX_OPEN_FDS) return -8; + var existing = FS.getStream(newfd); + if (existing) FS.close(existing); + return FS.dupStream(old, newfd).fd; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_faccessat(dirfd, path, amode, flags) { + try { + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + if (amode & ~7) { + return -28; + } + var lookup = FS.lookupPath(path, { follow: true }); + var node = lookup.node; + if (!node) { + return -44; + } + var perms = ''; + if (amode & 4) perms += 'r'; + if (amode & 2) perms += 'w'; + if (amode & 1) perms += 'x'; + if (perms && FS.nodePermissions(node, perms)) { + return -2; + } + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + var INT53_MAX = 9007199254740992; + var INT53_MIN = -9007199254740992; + var bigintToI53Checked = (num) => + num < INT53_MIN || num > INT53_MAX ? NaN : Number(num); + function ___syscall_fallocate(fd, mode, offset, len) { + offset = bigintToI53Checked(offset); + len = bigintToI53Checked(len); + try { + if (isNaN(offset)) return 61; + var stream = SYSCALLS.getStreamFromFD(fd); + FS.allocate(stream, offset, len); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_fchmod(fd, mode) { + try { + FS.fchmod(fd, mode); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_fchown32(fd, owner, group) { + try { + FS.fchown(fd, owner, group); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_fchownat(dirfd, path, owner, group, flags) { + try { + path = SYSCALLS.getStr(path); + var nofollow = flags & 256; + flags = flags & ~256; + path = SYSCALLS.calculateAt(dirfd, path); + (nofollow ? FS.lchown : FS.chown)(path, owner, group); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + var syscallGetVarargI = () => { + var ret = HEAP32[+SYSCALLS.varargs >> 2]; + SYSCALLS.varargs += 4; + return ret; + }; + var syscallGetVarargP = syscallGetVarargI; + function ___syscall_fcntl64(fd, cmd, varargs) { + SYSCALLS.varargs = varargs; + try { + var stream = SYSCALLS.getStreamFromFD(fd); + switch (cmd) { + case 0: { + var arg = syscallGetVarargI(); + if (arg < 0) { + return -28; + } + while (FS.streams[arg]) { + arg++; + } + var newStream; + newStream = FS.dupStream(stream, arg); + return newStream.fd; + } + case 1: + case 2: + return 0; + case 3: + return stream.flags; + case 4: { + var arg = syscallGetVarargI(); + stream.flags |= arg; + return 0; + } + case 12: { + var arg = syscallGetVarargP(); + var offset = 0; + HEAP16[(arg + offset) >> 1] = 2; + return 0; + } + case 13: + case 14: + return 0; + } + return -28; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_fdatasync(fd) { + try { + var stream = SYSCALLS.getStreamFromFD(fd); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_fstat64(fd, buf) { + try { + var stream = SYSCALLS.getStreamFromFD(fd); + return SYSCALLS.doStat(FS.stat, stream.path, buf); + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_ftruncate64(fd, length) { + length = bigintToI53Checked(length); + try { + if (isNaN(length)) return 61; + FS.ftruncate(fd, length); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + var stringToUTF8 = (str, outPtr, maxBytesToWrite) => + stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite); + Module['stringToUTF8'] = stringToUTF8; + function ___syscall_getcwd(buf, size) { + try { + if (size === 0) return -28; + var cwd = FS.cwd(); + var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1; + if (size < cwdLengthInBytes) return -68; + stringToUTF8(cwd, buf, size); + return cwdLengthInBytes; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_getdents64(fd, dirp, count) { + try { + var stream = SYSCALLS.getStreamFromFD(fd); + stream.getdents ||= FS.readdir(stream.path); + var struct_size = 280; + var pos = 0; + var off = FS.llseek(stream, 0, 1); + var startIdx = Math.floor(off / struct_size); + var endIdx = Math.min( + stream.getdents.length, + startIdx + Math.floor(count / struct_size) + ); + for (var idx = startIdx; idx < endIdx; idx++) { + var id; + var type; + var name = stream.getdents[idx]; + if (name === '.') { + id = stream.node.id; + type = 4; + } else if (name === '..') { + var lookup = FS.lookupPath(stream.path, { parent: true }); + id = lookup.node.id; + type = 4; + } else { + var child; + try { + child = FS.lookupNode(stream.node, name); + } catch (e) { + if (e?.errno === 28) { + continue; + } + throw e; + } + id = child.id; + type = FS.isChrdev(child.mode) + ? 2 + : FS.isDir(child.mode) + ? 4 + : FS.isLink(child.mode) + ? 10 + : 8; + } + HEAP64[(dirp + pos) >> 3] = BigInt(id); + HEAP64[(dirp + pos + 8) >> 3] = BigInt((idx + 1) * struct_size); + HEAP16[(dirp + pos + 16) >> 1] = 280; + HEAP8[dirp + pos + 18] = type; + stringToUTF8(name, dirp + pos + 19, 256); + pos += struct_size; + } + FS.llseek(stream, idx * struct_size, 0); + return pos; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_getpeername(fd, addr, addrlen, d1, d2, d3) { + try { + var sock = getSocketFromFD(fd); + if (!sock.daddr) { + return -53; + } + var errno = writeSockaddr( + addr, + sock.family, + DNS.lookup_name(sock.daddr), + sock.dport, + addrlen + ); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_getsockname(fd, addr, addrlen, d1, d2, d3) { + try { + var sock = getSocketFromFD(fd); + var errno = writeSockaddr( + addr, + sock.family, + DNS.lookup_name(sock.saddr || '0.0.0.0'), + sock.sport, + addrlen + ); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_getsockopt(fd, level, optname, optval, optlen, d1) { + try { + var sock = getSocketFromFD(fd); + if (level === 1) { + if (optname === 4) { + HEAP32[optval >> 2] = sock.error; + HEAP32[optlen >> 2] = 4; + sock.error = null; + return 0; + } + } + return -50; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_ioctl(fd, op, varargs) { + SYSCALLS.varargs = varargs; + try { + var stream = SYSCALLS.getStreamFromFD(fd); + switch (op) { + case 21509: { + if (!stream.tty) return -59; + return 0; + } + case 21505: { + if (!stream.tty) return -59; + if (stream.tty.ops.ioctl_tcgets) { + var termios = stream.tty.ops.ioctl_tcgets(stream); + var argp = syscallGetVarargP(); + HEAP32[argp >> 2] = termios.c_iflag || 0; + HEAP32[(argp + 4) >> 2] = termios.c_oflag || 0; + HEAP32[(argp + 8) >> 2] = termios.c_cflag || 0; + HEAP32[(argp + 12) >> 2] = termios.c_lflag || 0; + for (var i = 0; i < 32; i++) { + HEAP8[argp + i + 17] = termios.c_cc[i] || 0; + } + return 0; + } + return 0; + } + case 21510: + case 21511: + case 21512: { + if (!stream.tty) return -59; + return 0; + } + case 21506: + case 21507: + case 21508: { + if (!stream.tty) return -59; + if (stream.tty.ops.ioctl_tcsets) { + var argp = syscallGetVarargP(); + var c_iflag = HEAP32[argp >> 2]; + var c_oflag = HEAP32[(argp + 4) >> 2]; + var c_cflag = HEAP32[(argp + 8) >> 2]; + var c_lflag = HEAP32[(argp + 12) >> 2]; + var c_cc = []; + for (var i = 0; i < 32; i++) { + c_cc.push(HEAP8[argp + i + 17]); + } + return stream.tty.ops.ioctl_tcsets(stream.tty, op, { + c_iflag, + c_oflag, + c_cflag, + c_lflag, + c_cc, + }); + } + return 0; + } + case 21519: { + if (!stream.tty) return -59; + var argp = syscallGetVarargP(); + HEAP32[argp >> 2] = 0; + return 0; + } + case 21520: { + if (!stream.tty) return -59; + return -28; + } + case 21531: { + var argp = syscallGetVarargP(); + return FS.ioctl(stream, op, argp); + } + case 21523: { + if (!stream.tty) return -59; + if (stream.tty.ops.ioctl_tiocgwinsz) { + var winsize = stream.tty.ops.ioctl_tiocgwinsz( + stream.tty + ); + var argp = syscallGetVarargP(); + HEAP16[argp >> 1] = winsize[0]; + HEAP16[(argp + 2) >> 1] = winsize[1]; + } + return 0; + } + case 21524: { + if (!stream.tty) return -59; + return 0; + } + case 21515: { + if (!stream.tty) return -59; + return 0; + } + default: + return -28; + } + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_listen(fd, backlog) { + try { + var sock = getSocketFromFD(fd); + sock.sock_ops.listen(sock, backlog); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_lstat64(path, buf) { + try { + path = SYSCALLS.getStr(path); + return SYSCALLS.doStat(FS.lstat, path, buf); + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_mkdirat(dirfd, path, mode) { + try { + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + FS.mkdir(path, mode, 0); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_newfstatat(dirfd, path, buf, flags) { + try { + path = SYSCALLS.getStr(path); + var nofollow = flags & 256; + var allowEmpty = flags & 4096; + flags = flags & ~6400; + path = SYSCALLS.calculateAt(dirfd, path, allowEmpty); + return SYSCALLS.doStat(nofollow ? FS.lstat : FS.stat, path, buf); + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_openat(dirfd, path, flags, varargs) { + SYSCALLS.varargs = varargs; + try { + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + var mode = varargs ? syscallGetVarargI() : 0; + return FS.open(path, flags, mode).fd; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + var PIPEFS = { + BUCKET_BUFFER_SIZE: 8192, + mount(mount) { + return FS.createNode(null, '/', 16384 | 511, 0); + }, + createPipe() { + var pipe = { buckets: [], refcnt: 2 }; + pipe.buckets.push({ + buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE), + offset: 0, + roffset: 0, + }); + var rName = PIPEFS.nextname(); + var wName = PIPEFS.nextname(); + var rNode = FS.createNode(PIPEFS.root, rName, 4096, 0); + var wNode = FS.createNode(PIPEFS.root, wName, 4096, 0); + rNode.pipe = pipe; + wNode.pipe = pipe; + var readableStream = FS.createStream({ + path: rName, + node: rNode, + flags: 0, + seekable: false, + stream_ops: PIPEFS.stream_ops, + }); + rNode.stream = readableStream; + var writableStream = FS.createStream({ + path: wName, + node: wNode, + flags: 1, + seekable: false, + stream_ops: PIPEFS.stream_ops, + }); + wNode.stream = writableStream; + return { + readable_fd: readableStream.fd, + writable_fd: writableStream.fd, + }; + }, + stream_ops: { + poll(stream) { + var pipe = stream.node.pipe; + if ((stream.flags & 2097155) === 1) { + return 256 | 4; + } + if (pipe.buckets.length > 0) { + for (var i = 0; i < pipe.buckets.length; i++) { + var bucket = pipe.buckets[i]; + if (bucket.offset - bucket.roffset > 0) { + return 64 | 1; + } + } + } + return 0; + }, + ioctl(stream, request, varargs) { + return 28; + }, + fsync(stream) { + return 28; + }, + read(stream, buffer, offset, length, position) { + var pipe = stream.node.pipe; + var currentLength = 0; + for (var i = 0; i < pipe.buckets.length; i++) { + var bucket = pipe.buckets[i]; + currentLength += bucket.offset - bucket.roffset; + } + var data = buffer.subarray(offset, offset + length); + if (length <= 0) { + return 0; + } + if (currentLength == 0) { + throw new FS.ErrnoError(6); + } + var toRead = Math.min(currentLength, length); + var totalRead = toRead; + var toRemove = 0; + for (var i = 0; i < pipe.buckets.length; i++) { + var currBucket = pipe.buckets[i]; + var bucketSize = currBucket.offset - currBucket.roffset; + if (toRead <= bucketSize) { + var tmpSlice = currBucket.buffer.subarray( + currBucket.roffset, + currBucket.offset + ); + if (toRead < bucketSize) { + tmpSlice = tmpSlice.subarray(0, toRead); + currBucket.roffset += toRead; + } else { + toRemove++; + } + data.set(tmpSlice); + break; + } else { + var tmpSlice = currBucket.buffer.subarray( + currBucket.roffset, + currBucket.offset + ); + data.set(tmpSlice); + data = data.subarray(tmpSlice.byteLength); + toRead -= tmpSlice.byteLength; + toRemove++; + } + } + if (toRemove && toRemove == pipe.buckets.length) { + toRemove--; + pipe.buckets[toRemove].offset = 0; + pipe.buckets[toRemove].roffset = 0; + } + pipe.buckets.splice(0, toRemove); + return totalRead; + }, + write(stream, buffer, offset, length, position) { + var pipe = stream.node.pipe; + var data = buffer.subarray(offset, offset + length); + var dataLen = data.byteLength; + if (dataLen <= 0) { + return 0; + } + var currBucket = null; + if (pipe.buckets.length == 0) { + currBucket = { + buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE), + offset: 0, + roffset: 0, + }; + pipe.buckets.push(currBucket); + } else { + currBucket = pipe.buckets[pipe.buckets.length - 1]; + } + assert(currBucket.offset <= PIPEFS.BUCKET_BUFFER_SIZE); + var freeBytesInCurrBuffer = + PIPEFS.BUCKET_BUFFER_SIZE - currBucket.offset; + if (freeBytesInCurrBuffer >= dataLen) { + currBucket.buffer.set(data, currBucket.offset); + currBucket.offset += dataLen; + return dataLen; + } else if (freeBytesInCurrBuffer > 0) { + currBucket.buffer.set( + data.subarray(0, freeBytesInCurrBuffer), + currBucket.offset + ); + currBucket.offset += freeBytesInCurrBuffer; + data = data.subarray( + freeBytesInCurrBuffer, + data.byteLength + ); + } + var numBuckets = + (data.byteLength / PIPEFS.BUCKET_BUFFER_SIZE) | 0; + var remElements = data.byteLength % PIPEFS.BUCKET_BUFFER_SIZE; + for (var i = 0; i < numBuckets; i++) { + var newBucket = { + buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE), + offset: PIPEFS.BUCKET_BUFFER_SIZE, + roffset: 0, + }; + pipe.buckets.push(newBucket); + newBucket.buffer.set( + data.subarray(0, PIPEFS.BUCKET_BUFFER_SIZE) + ); + data = data.subarray( + PIPEFS.BUCKET_BUFFER_SIZE, + data.byteLength + ); + } + if (remElements > 0) { + var newBucket = { + buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE), + offset: data.byteLength, + roffset: 0, + }; + pipe.buckets.push(newBucket); + newBucket.buffer.set(data); + } + return dataLen; + }, + close(stream) { + var pipe = stream.node.pipe; + pipe.refcnt--; + if (pipe.refcnt === 0) { + pipe.buckets = null; + } + }, + }, + nextname() { + if (!PIPEFS.nextname.current) { + PIPEFS.nextname.current = 0; + } + return 'pipe[' + PIPEFS.nextname.current++ + ']'; + }, + }; + function ___syscall_pipe(fdPtr) { + try { + if (fdPtr == 0) { + throw new FS.ErrnoError(21); + } + var res = PIPEFS.createPipe(); + HEAP32[fdPtr >> 2] = res.readable_fd; + HEAP32[(fdPtr + 4) >> 2] = res.writable_fd; + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_poll(fds, nfds, timeout) { + try { + var nonzero = 0; + for (var i = 0; i < nfds; i++) { + var pollfd = fds + 8 * i; + var fd = HEAP32[pollfd >> 2]; + var events = HEAP16[(pollfd + 4) >> 1]; + var mask = 32; + var stream = FS.getStream(fd); + if (stream) { + mask = SYSCALLS.DEFAULT_POLLMASK; + if (stream.stream_ops?.poll) { + mask = stream.stream_ops.poll(stream, -1); + } + } + mask &= events | 8 | 16; + if (mask) nonzero++; + HEAP16[(pollfd + 6) >> 1] = mask; + } + return nonzero; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_readlinkat(dirfd, path, buf, bufsize) { + try { + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + if (bufsize <= 0) return -28; + var ret = FS.readlink(path); + var len = Math.min(bufsize, lengthBytesUTF8(ret)); + var endChar = HEAP8[buf + len]; + stringToUTF8(ret, buf, bufsize + 1); + HEAP8[buf + len] = endChar; + return len; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_recvfrom(fd, buf, len, flags, addr, addrlen) { + try { + var sock = getSocketFromFD(fd); + var msg = sock.sock_ops.recvmsg( + sock, + len, + typeof flags !== 'undefined' ? flags : 0 + ); + if (!msg) return 0; + if (addr) { + var errno = writeSockaddr( + addr, + sock.family, + DNS.lookup_name(msg.addr), + msg.port, + addrlen + ); + } + HEAPU8.set(msg.buffer, buf); + return msg.buffer.byteLength; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_renameat(olddirfd, oldpath, newdirfd, newpath) { + try { + oldpath = SYSCALLS.getStr(oldpath); + newpath = SYSCALLS.getStr(newpath); + oldpath = SYSCALLS.calculateAt(olddirfd, oldpath); + newpath = SYSCALLS.calculateAt(newdirfd, newpath); + FS.rename(oldpath, newpath); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_rmdir(path) { + try { + path = SYSCALLS.getStr(path); + FS.rmdir(path); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_sendto(fd, message, length, flags, addr, addr_len) { + try { + var sock = getSocketFromFD(fd); + if (!addr) { + return FS.write(sock.stream, HEAP8, message, length); + } + var dest = getSocketAddress(addr, addr_len); + return sock.sock_ops.sendmsg( + sock, + HEAP8, + message, + length, + dest.addr, + dest.port + ); + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_socket(domain, type, protocol) { + try { + var sock = SOCKFS.createSocket(domain, type, protocol); + return sock.stream.fd; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_stat64(path, buf) { + try { + path = SYSCALLS.getStr(path); + return SYSCALLS.doStat(FS.stat, path, buf); + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_statfs64(path, size, buf) { + try { + var stats = FS.statfs(SYSCALLS.getStr(path)); + HEAP32[(buf + 4) >> 2] = stats.bsize; + HEAP32[(buf + 40) >> 2] = stats.bsize; + HEAP32[(buf + 8) >> 2] = stats.blocks; + HEAP32[(buf + 12) >> 2] = stats.bfree; + HEAP32[(buf + 16) >> 2] = stats.bavail; + HEAP32[(buf + 20) >> 2] = stats.files; + HEAP32[(buf + 24) >> 2] = stats.ffree; + HEAP32[(buf + 28) >> 2] = stats.fsid; + HEAP32[(buf + 44) >> 2] = stats.flags; + HEAP32[(buf + 36) >> 2] = stats.namelen; + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_symlinkat(target, dirfd, linkpath) { + try { + target = SYSCALLS.getStr(target); + linkpath = SYSCALLS.getStr(linkpath); + linkpath = SYSCALLS.calculateAt(dirfd, linkpath); + FS.symlink(target, linkpath); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function ___syscall_unlinkat(dirfd, path, flags) { + try { + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + if (flags === 0) { + FS.unlink(path); + } else if (flags === 512) { + FS.rmdir(path); + } else { + abort('Invalid flags passed to unlinkat'); + } + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + var readI53FromI64 = (ptr) => + HEAPU32[ptr >> 2] + HEAP32[(ptr + 4) >> 2] * 4294967296; + function ___syscall_utimensat(dirfd, path, times, flags) { + try { + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path, true); + var now = Date.now(), + atime, + mtime; + if (!times) { + atime = now; + mtime = now; + } else { + var seconds = readI53FromI64(times); + var nanoseconds = HEAP32[(times + 8) >> 2]; + if (nanoseconds == 1073741823) { + atime = now; + } else if (nanoseconds == 1073741822) { + atime = null; + } else { + atime = seconds * 1e3 + nanoseconds / (1e3 * 1e3); + } + times += 16; + seconds = readI53FromI64(times); + nanoseconds = HEAP32[(times + 8) >> 2]; + if (nanoseconds == 1073741823) { + mtime = now; + } else if (nanoseconds == 1073741822) { + mtime = null; + } else { + mtime = seconds * 1e3 + nanoseconds / (1e3 * 1e3); + } + } + if ((mtime ?? atime) !== null) { + FS.utime(path, atime, mtime); + } + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + var __abort_js = () => abort(''); + var __emscripten_lookup_name = (name) => { + var nameString = UTF8ToString(name); + return inetPton4(DNS.lookup_name(nameString)); + }; + var runtimeKeepaliveCounter = 0; + var __emscripten_runtime_keepalive_clear = () => { + noExitRuntime = false; + runtimeKeepaliveCounter = 0; + }; + function __gmtime_js(time, tmPtr) { + time = bigintToI53Checked(time); + var date = new Date(time * 1e3); + HEAP32[tmPtr >> 2] = date.getUTCSeconds(); + HEAP32[(tmPtr + 4) >> 2] = date.getUTCMinutes(); + HEAP32[(tmPtr + 8) >> 2] = date.getUTCHours(); + HEAP32[(tmPtr + 12) >> 2] = date.getUTCDate(); + HEAP32[(tmPtr + 16) >> 2] = date.getUTCMonth(); + HEAP32[(tmPtr + 20) >> 2] = date.getUTCFullYear() - 1900; + HEAP32[(tmPtr + 24) >> 2] = date.getUTCDay(); + var start = Date.UTC(date.getUTCFullYear(), 0, 1, 0, 0, 0, 0); + var yday = ((date.getTime() - start) / (1e3 * 60 * 60 * 24)) | 0; + HEAP32[(tmPtr + 28) >> 2] = yday; + } + var isLeapYear = (year) => + year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); + var MONTH_DAYS_LEAP_CUMULATIVE = [ + 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, + ]; + var MONTH_DAYS_REGULAR_CUMULATIVE = [ + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, + ]; + var ydayFromDate = (date) => { + var leap = isLeapYear(date.getFullYear()); + var monthDaysCumulative = leap + ? MONTH_DAYS_LEAP_CUMULATIVE + : MONTH_DAYS_REGULAR_CUMULATIVE; + var yday = monthDaysCumulative[date.getMonth()] + date.getDate() - 1; + return yday; + }; + function __localtime_js(time, tmPtr) { + time = bigintToI53Checked(time); + var date = new Date(time * 1e3); + HEAP32[tmPtr >> 2] = date.getSeconds(); + HEAP32[(tmPtr + 4) >> 2] = date.getMinutes(); + HEAP32[(tmPtr + 8) >> 2] = date.getHours(); + HEAP32[(tmPtr + 12) >> 2] = date.getDate(); + HEAP32[(tmPtr + 16) >> 2] = date.getMonth(); + HEAP32[(tmPtr + 20) >> 2] = date.getFullYear() - 1900; + HEAP32[(tmPtr + 24) >> 2] = date.getDay(); + var yday = ydayFromDate(date) | 0; + HEAP32[(tmPtr + 28) >> 2] = yday; + HEAP32[(tmPtr + 36) >> 2] = -(date.getTimezoneOffset() * 60); + var start = new Date(date.getFullYear(), 0, 1); + var summerOffset = new Date( + date.getFullYear(), + 6, + 1 + ).getTimezoneOffset(); + var winterOffset = start.getTimezoneOffset(); + var dst = + (summerOffset != winterOffset && + date.getTimezoneOffset() == + Math.min(winterOffset, summerOffset)) | 0; + HEAP32[(tmPtr + 32) >> 2] = dst; + } + var __mktime_js = function (tmPtr) { + var ret = (() => { + var date = new Date( + HEAP32[(tmPtr + 20) >> 2] + 1900, + HEAP32[(tmPtr + 16) >> 2], + HEAP32[(tmPtr + 12) >> 2], + HEAP32[(tmPtr + 8) >> 2], + HEAP32[(tmPtr + 4) >> 2], + HEAP32[tmPtr >> 2], + 0 + ); + var dst = HEAP32[(tmPtr + 32) >> 2]; + var guessedOffset = date.getTimezoneOffset(); + var start = new Date(date.getFullYear(), 0, 1); + var summerOffset = new Date( + date.getFullYear(), + 6, + 1 + ).getTimezoneOffset(); + var winterOffset = start.getTimezoneOffset(); + var dstOffset = Math.min(winterOffset, summerOffset); + if (dst < 0) { + HEAP32[(tmPtr + 32) >> 2] = Number( + summerOffset != winterOffset && dstOffset == guessedOffset + ); + } else if (dst > 0 != (dstOffset == guessedOffset)) { + var nonDstOffset = Math.max(winterOffset, summerOffset); + var trueOffset = dst > 0 ? dstOffset : nonDstOffset; + date.setTime( + date.getTime() + (trueOffset - guessedOffset) * 6e4 + ); + } + HEAP32[(tmPtr + 24) >> 2] = date.getDay(); + var yday = ydayFromDate(date) | 0; + HEAP32[(tmPtr + 28) >> 2] = yday; + HEAP32[tmPtr >> 2] = date.getSeconds(); + HEAP32[(tmPtr + 4) >> 2] = date.getMinutes(); + HEAP32[(tmPtr + 8) >> 2] = date.getHours(); + HEAP32[(tmPtr + 12) >> 2] = date.getDate(); + HEAP32[(tmPtr + 16) >> 2] = date.getMonth(); + HEAP32[(tmPtr + 20) >> 2] = date.getYear(); + var timeMs = date.getTime(); + if (isNaN(timeMs)) { + return -1; + } + return timeMs / 1e3; + })(); + return BigInt(ret); + }; + function __mmap_js(len, prot, flags, fd, offset, allocated, addr) { + offset = bigintToI53Checked(offset); + try { + if (isNaN(offset)) return 61; + var stream = SYSCALLS.getStreamFromFD(fd); + var res = FS.mmap(stream, len, offset, prot, flags); + var ptr = res.ptr; + HEAP32[allocated >> 2] = res.allocated; + HEAPU32[addr >> 2] = ptr; + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + function __munmap_js(addr, len, prot, flags, fd, offset) { + offset = bigintToI53Checked(offset); + try { + var stream = SYSCALLS.getStreamFromFD(fd); + if (prot & 2) { + SYSCALLS.doMsync(addr, stream, len, flags, offset); + } + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + var timers = {}; + var handleException = (e) => { + if (e instanceof ExitStatus || e == 'unwind') { + return EXITSTATUS; + } + quit_(1, e); + }; + var keepRuntimeAlive = () => noExitRuntime || runtimeKeepaliveCounter > 0; + var _proc_exit = (code) => { + EXITSTATUS = code; + if (!keepRuntimeAlive()) { + Module['onExit']?.(code); + ABORT = true; + } + quit_(code, new ExitStatus(code)); + }; + var exitJS = (status, implicit) => { + EXITSTATUS = status; + if (!keepRuntimeAlive()) { + exitRuntime(); + } + _proc_exit(status); + }; + var _exit = exitJS; + Module['_exit'] = _exit; + var maybeExit = () => { + if (runtimeExited) { + return; + } + if (!keepRuntimeAlive()) { + try { + _exit(EXITSTATUS); + } catch (e) { + handleException(e); + } + } + }; + var callUserCallback = (func) => { + if (runtimeExited || ABORT) { + return; + } + try { + func(); + maybeExit(); + } catch (e) { + handleException(e); + } + }; + var _emscripten_get_now = () => performance.now(); + var __setitimer_js = (which, timeout_ms) => { + if (timers[which]) { + clearTimeout(timers[which].id); + delete timers[which]; + } + if (!timeout_ms) return 0; + var id = setTimeout(() => { + delete timers[which]; + callUserCallback(() => + __emscripten_timeout(which, _emscripten_get_now()) + ); + }, timeout_ms); + timers[which] = { id, timeout_ms }; + return 0; + }; + var __tzset_js = (timezone, daylight, std_name, dst_name) => { + var currentYear = new Date().getFullYear(); + var winter = new Date(currentYear, 0, 1); + var summer = new Date(currentYear, 6, 1); + var winterOffset = winter.getTimezoneOffset(); + var summerOffset = summer.getTimezoneOffset(); + var stdTimezoneOffset = Math.max(winterOffset, summerOffset); + HEAPU32[timezone >> 2] = stdTimezoneOffset * 60; + HEAP32[daylight >> 2] = Number(winterOffset != summerOffset); + var extractZone = (timezoneOffset) => { + var sign = timezoneOffset >= 0 ? '-' : '+'; + var absOffset = Math.abs(timezoneOffset); + var hours = String(Math.floor(absOffset / 60)).padStart(2, '0'); + var minutes = String(absOffset % 60).padStart(2, '0'); + return `UTC${sign}${hours}${minutes}`; + }; + var winterName = extractZone(winterOffset); + var summerName = extractZone(summerOffset); + if (summerOffset < winterOffset) { + stringToUTF8(winterName, std_name, 17); + stringToUTF8(summerName, dst_name, 17); + } else { + stringToUTF8(winterName, dst_name, 17); + stringToUTF8(summerName, std_name, 17); + } + }; + var _emscripten_date_now = () => Date.now(); + var nowIsMonotonic = 1; + var checkWasiClock = (clock_id) => clock_id >= 0 && clock_id <= 3; + function _clock_time_get(clk_id, ignored_precision, ptime) { + ignored_precision = bigintToI53Checked(ignored_precision); + if (!checkWasiClock(clk_id)) { + return 28; + } + var now; + if (clk_id === 0) { + now = _emscripten_date_now(); + } else if (nowIsMonotonic) { + now = _emscripten_get_now(); + } else { + return 52; + } + var nsec = Math.round(now * 1e3 * 1e3); + HEAP64[ptime >> 3] = BigInt(nsec); + return 0; + } + var getHeapMax = () => 2147483648; + var _emscripten_get_heap_max = () => getHeapMax(); + var growMemory = (size) => { + var b = wasmMemory.buffer; + var pages = ((size - b.byteLength + 65535) / 65536) | 0; + try { + wasmMemory.grow(pages); + updateMemoryViews(); + return 1; + } catch (e) {} + }; + var _emscripten_resize_heap = (requestedSize) => { + var oldSize = HEAPU8.length; + requestedSize >>>= 0; + var maxHeapSize = getHeapMax(); + if (requestedSize > maxHeapSize) { + return false; + } + for (var cutDown = 1; cutDown <= 4; cutDown *= 2) { + var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown); + overGrownHeapSize = Math.min( + overGrownHeapSize, + requestedSize + 100663296 + ); + var newSize = Math.min( + maxHeapSize, + alignMemory(Math.max(requestedSize, overGrownHeapSize), 65536) + ); + var replacement = growMemory(newSize); + if (replacement) { + return true; + } + } + return false; + }; + var runtimeKeepalivePush = () => { + runtimeKeepaliveCounter += 1; + }; + var runtimeKeepalivePop = () => { + runtimeKeepaliveCounter -= 1; + }; + var safeSetTimeout = (func, timeout) => { + runtimeKeepalivePush(); + return setTimeout(() => { + runtimeKeepalivePop(); + callUserCallback(func); + }, timeout); + }; + var _emscripten_sleep = (ms) => + Asyncify.handleSleep((wakeUp) => safeSetTimeout(wakeUp, ms)); + Module['_emscripten_sleep'] = _emscripten_sleep; + _emscripten_sleep.isAsync = true; + var ENV = PHPLoader.ENV || {}; + var getExecutableName = () => thisProgram || './this.program'; + var getEnvStrings = () => { + if (!getEnvStrings.strings) { + var lang = + ( + (typeof navigator == 'object' && + navigator.languages && + navigator.languages[0]) || + 'C' + ).replace('-', '_') + '.UTF-8'; + var env = { + USER: 'web_user', + LOGNAME: 'web_user', + PATH: '/', + PWD: '/', + HOME: '/home/web_user', + LANG: lang, + _: getExecutableName(), + }; + for (var x in ENV) { + if (ENV[x] === undefined) delete env[x]; + else env[x] = ENV[x]; + } + var strings = []; + for (var x in env) { + strings.push(`${x}=${env[x]}`); + } + getEnvStrings.strings = strings; + } + return getEnvStrings.strings; + }; + var stringToAscii = (str, buffer) => { + for (var i = 0; i < str.length; ++i) { + HEAP8[buffer++] = str.charCodeAt(i); + } + HEAP8[buffer] = 0; + }; + var _environ_get = (__environ, environ_buf) => { + var bufSize = 0; + getEnvStrings().forEach((string, i) => { + var ptr = environ_buf + bufSize; + HEAPU32[(__environ + i * 4) >> 2] = ptr; + stringToAscii(string, ptr); + bufSize += string.length + 1; + }); + return 0; + }; + var _environ_sizes_get = (penviron_count, penviron_buf_size) => { + var strings = getEnvStrings(); + HEAPU32[penviron_count >> 2] = strings.length; + var bufSize = 0; + strings.forEach((string) => (bufSize += string.length + 1)); + HEAPU32[penviron_buf_size >> 2] = bufSize; + return 0; + }; + function _fd_close(fd) { + try { + var stream = SYSCALLS.getStreamFromFD(fd); + FS.close(stream); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return e.errno; + } + } + function _fd_fdstat_get(fd, pbuf) { + try { + var rightsBase = 0; + var rightsInheriting = 0; + var flags = 0; + { + var stream = SYSCALLS.getStreamFromFD(fd); + var type = stream.tty + ? 2 + : FS.isDir(stream.mode) + ? 3 + : FS.isLink(stream.mode) + ? 7 + : 4; + } + HEAP8[pbuf] = type; + HEAP16[(pbuf + 2) >> 1] = flags; + HEAP64[(pbuf + 8) >> 3] = BigInt(rightsBase); + HEAP64[(pbuf + 16) >> 3] = BigInt(rightsInheriting); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return e.errno; + } + } + var doReadv = (stream, iov, iovcnt, offset) => { + var ret = 0; + for (var i = 0; i < iovcnt; i++) { + var ptr = HEAPU32[iov >> 2]; + var len = HEAPU32[(iov + 4) >> 2]; + iov += 8; + var curr = FS.read(stream, HEAP8, ptr, len, offset); + if (curr < 0) return -1; + ret += curr; + if (curr < len) break; + if (typeof offset != 'undefined') { + offset += curr; + } + } + return ret; + }; + function _fd_read(fd, iov, iovcnt, pnum) { + try { + var stream = SYSCALLS.getStreamFromFD(fd); + var num = doReadv(stream, iov, iovcnt); + HEAPU32[pnum >> 2] = num; + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return e.errno; + } + } + function _fd_seek(fd, offset, whence, newOffset) { + offset = bigintToI53Checked(offset); + try { + if (isNaN(offset)) return 61; + var stream = SYSCALLS.getStreamFromFD(fd); + FS.llseek(stream, offset, whence); + HEAP64[newOffset >> 3] = BigInt(stream.position); + if (stream.getdents && offset === 0 && whence === 0) + stream.getdents = null; + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return e.errno; + } + } + var doWritev = (stream, iov, iovcnt, offset) => { + var ret = 0; + for (var i = 0; i < iovcnt; i++) { + var ptr = HEAPU32[iov >> 2]; + var len = HEAPU32[(iov + 4) >> 2]; + iov += 8; + var curr = FS.write(stream, HEAP8, ptr, len, offset); + if (curr < 0) return -1; + ret += curr; + if (curr < len) { + break; + } + if (typeof offset != 'undefined') { + offset += curr; + } + } + return ret; + }; + function _fd_write(fd, iov, iovcnt, pnum) { + try { + var stream = SYSCALLS.getStreamFromFD(fd); + var num = doWritev(stream, iov, iovcnt); + HEAPU32[pnum >> 2] = num; + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return e.errno; + } + } + var _getaddrinfo = (node, service, hint, out) => { + var addr = 0; + var port = 0; + var flags = 0; + var family = 0; + var type = 0; + var proto = 0; + var ai; + function allocaddrinfo(family, type, proto, canon, addr, port) { + var sa, salen, ai; + var errno; + salen = family === 10 ? 28 : 16; + addr = family === 10 ? inetNtop6(addr) : inetNtop4(addr); + sa = _malloc(salen); + errno = writeSockaddr(sa, family, addr, port); + assert(!errno); + ai = _malloc(32); + HEAP32[(ai + 4) >> 2] = family; + HEAP32[(ai + 8) >> 2] = type; + HEAP32[(ai + 12) >> 2] = proto; + HEAPU32[(ai + 24) >> 2] = canon; + HEAPU32[(ai + 20) >> 2] = sa; + if (family === 10) { + HEAP32[(ai + 16) >> 2] = 28; + } else { + HEAP32[(ai + 16) >> 2] = 16; + } + HEAP32[(ai + 28) >> 2] = 0; + return ai; + } + if (hint) { + flags = HEAP32[hint >> 2]; + family = HEAP32[(hint + 4) >> 2]; + type = HEAP32[(hint + 8) >> 2]; + proto = HEAP32[(hint + 12) >> 2]; + } + if (type && !proto) { + proto = type === 2 ? 17 : 6; + } + if (!type && proto) { + type = proto === 17 ? 2 : 1; + } + if (proto === 0) { + proto = 6; + } + if (type === 0) { + type = 1; + } + if (!node && !service) { + return -2; + } + if (flags & ~(1 | 2 | 4 | 1024 | 8 | 16 | 32)) { + return -1; + } + if (hint !== 0 && HEAP32[hint >> 2] & 2 && !node) { + return -1; + } + if (flags & 32) { + return -2; + } + if (type !== 0 && type !== 1 && type !== 2) { + return -7; + } + if (family !== 0 && family !== 2 && family !== 10) { + return -6; + } + if (service) { + service = UTF8ToString(service); + port = parseInt(service, 10); + if (isNaN(port)) { + if (flags & 1024) { + return -2; + } + return -8; + } + } + if (!node) { + if (family === 0) { + family = 2; + } + if ((flags & 1) === 0) { + if (family === 2) { + addr = _htonl(2130706433); + } else { + addr = [0, 0, 0, _htonl(1)]; + } + } + ai = allocaddrinfo(family, type, proto, null, addr, port); + HEAPU32[out >> 2] = ai; + return 0; + } + node = UTF8ToString(node); + addr = inetPton4(node); + if (addr !== null) { + if (family === 0 || family === 2) { + family = 2; + } else if (family === 10 && flags & 8) { + addr = [0, 0, _htonl(65535), addr]; + family = 10; + } else { + return -2; + } + } else { + addr = inetPton6(node); + if (addr !== null) { + if (family === 0 || family === 10) { + family = 10; + } else { + return -2; + } + } + } + if (addr != null) { + ai = allocaddrinfo(family, type, proto, node, addr, port); + HEAPU32[out >> 2] = ai; + return 0; + } + if (flags & 4) { + return -2; + } + node = DNS.lookup_name(node); + addr = inetPton4(node); + if (family === 0) { + family = 2; + } else if (family === 10) { + addr = [0, 0, _htonl(65535), addr]; + } + ai = allocaddrinfo(family, type, proto, null, addr, port); + HEAPU32[out >> 2] = ai; + return 0; + }; + var _getnameinfo = (sa, salen, node, nodelen, serv, servlen, flags) => { + var info = readSockaddr(sa, salen); + if (info.errno) { + return -6; + } + var port = info.port; + var addr = info.addr; + var overflowed = false; + if (node && nodelen) { + var lookup; + if (flags & 1 || !(lookup = DNS.lookup_addr(addr))) { + if (flags & 8) { + return -2; + } + } else { + addr = lookup; + } + var numBytesWrittenExclNull = stringToUTF8(addr, node, nodelen); + if (numBytesWrittenExclNull + 1 >= nodelen) { + overflowed = true; + } + } + if (serv && servlen) { + port = '' + port; + var numBytesWrittenExclNull = stringToUTF8(port, serv, servlen); + if (numBytesWrittenExclNull + 1 >= servlen) { + overflowed = true; + } + } + if (overflowed) { + return -12; + } + return 0; + }; + var Protocols = { list: [], map: {} }; + var _setprotoent = (stayopen) => { + function allocprotoent(name, proto, aliases) { + var nameBuf = _malloc(name.length + 1); + stringToAscii(name, nameBuf); + var j = 0; + var length = aliases.length; + var aliasListBuf = _malloc((length + 1) * 4); + for (var i = 0; i < length; i++, j += 4) { + var alias = aliases[i]; + var aliasBuf = _malloc(alias.length + 1); + stringToAscii(alias, aliasBuf); + HEAPU32[(aliasListBuf + j) >> 2] = aliasBuf; + } + HEAPU32[(aliasListBuf + j) >> 2] = 0; + var pe = _malloc(12); + HEAPU32[pe >> 2] = nameBuf; + HEAPU32[(pe + 4) >> 2] = aliasListBuf; + HEAP32[(pe + 8) >> 2] = proto; + return pe; + } + var list = Protocols.list; + var map = Protocols.map; + if (list.length === 0) { + var entry = allocprotoent('tcp', 6, ['TCP']); + list.push(entry); + map['tcp'] = map['6'] = entry; + entry = allocprotoent('udp', 17, ['UDP']); + list.push(entry); + map['udp'] = map['17'] = entry; + } + _setprotoent.index = 0; + }; + var _getprotobyname = (name) => { + name = UTF8ToString(name); + _setprotoent(true); + var result = Protocols.map[name]; + return result; + }; + var _getprotobynumber = (number) => { + _setprotoent(true); + var result = Protocols.map[number]; + return result; + }; + var stackAlloc = (sz) => __emscripten_stack_alloc(sz); + var stringToUTF8OnStack = (str) => { + var size = lengthBytesUTF8(str) + 1; + var ret = stackAlloc(size); + stringToUTF8(str, ret, size); + return ret; + }; + var allocateUTF8OnStack = stringToUTF8OnStack; + var PHPWASM = { + init: function () { + FS.mkdir('/internal'); + FS.mkdir('/internal/shared'); + FS.mkdir('/internal/shared/preload'); + PHPWASM.EventEmitter = ENVIRONMENT_IS_NODE + ? require('events').EventEmitter + : class EventEmitter { + constructor() { + this.listeners = {}; + } + emit(eventName, data) { + if (this.listeners[eventName]) { + this.listeners[eventName].forEach( + (callback) => { + callback(data); + } + ); + } + } + once(eventName, callback) { + const self = this; + function removedCallback() { + callback(...arguments); + self.removeListener(eventName, removedCallback); + } + this.on(eventName, removedCallback); + } + removeAllListeners(eventName) { + if (eventName) { + delete this.listeners[eventName]; + } else { + this.listeners = {}; + } + } + removeListener(eventName, callback) { + if (this.listeners[eventName]) { + const idx = + this.listeners[eventName].indexOf(callback); + if (idx !== -1) { + this.listeners[eventName].splice(idx, 1); + } + } + } + }; + PHPWASM.child_proc_by_fd = {}; + PHPWASM.child_proc_by_pid = {}; + PHPWASM.input_devices = {}; + }, + getAllWebSockets: function (sock) { + const webSockets = new Set(); + if (sock.server) { + sock.server.clients.forEach((ws) => { + webSockets.add(ws); + }); + } + for (const peer of PHPWASM.getAllPeers(sock)) { + webSockets.add(peer.socket); + } + return Array.from(webSockets); + }, + getAllPeers: function (sock) { + const peers = new Set(); + if (sock.server) { + sock.pending + .filter((pending) => pending.peers) + .forEach((pending) => { + for (const peer of Object.values(pending.peers)) { + peers.add(peer); + } + }); + } + if (sock.peers) { + for (const peer of Object.values(sock.peers)) { + peers.add(peer); + } + } + return Array.from(peers); + }, + awaitData: function (ws) { + return PHPWASM.awaitEvent(ws, 'message'); + }, + awaitConnection: function (ws) { + if (ws.OPEN === ws.readyState) { + return [Promise.resolve(), PHPWASM.noop]; + } + return PHPWASM.awaitEvent(ws, 'open'); + }, + awaitClose: function (ws) { + if ([ws.CLOSING, ws.CLOSED].includes(ws.readyState)) { + return [Promise.resolve(), PHPWASM.noop]; + } + return PHPWASM.awaitEvent(ws, 'close'); + }, + awaitError: function (ws) { + if ([ws.CLOSING, ws.CLOSED].includes(ws.readyState)) { + return [Promise.resolve(), PHPWASM.noop]; + } + return PHPWASM.awaitEvent(ws, 'error'); + }, + awaitEvent: function (ws, event) { + let resolve; + const listener = () => { + resolve(); + }; + const promise = new Promise(function (_resolve) { + resolve = _resolve; + ws.once(event, listener); + }); + const cancel = () => { + ws.removeListener(event, listener); + setTimeout(resolve); + }; + return [promise, cancel]; + }, + noop: function () {}, + spawnProcess: function (command, args, options) { + if (Module['spawnProcess']) { + const spawnedPromise = Module['spawnProcess']( + command, + args, + options + ); + return Promise.resolve(spawnedPromise).then(function (spawned) { + if (!spawned || !spawned.on) { + throw new Error( + 'spawnProcess() must return an EventEmitter but returned a different type.' + ); + } + return spawned; + }); + } + if (ENVIRONMENT_IS_NODE) { + return require('child_process').spawn(command, args, { + ...options, + shell: true, + stdio: ['pipe', 'pipe', 'pipe'], + timeout: 100, + }); + } + const e = new Error( + 'popen(), proc_open() etc. are unsupported in the browser. Call php.setSpawnHandler() ' + + 'and provide a callback to handle spawning processes, or disable a popen(), proc_open() ' + + 'and similar functions via php.ini.' + ); + e.code = 'SPAWN_UNSUPPORTED'; + throw e; + }, + shutdownSocket: function (socketd, how) { + const sock = getSocketFromFD(socketd); + const peer = Object.values(sock.peers)[0]; + if (!peer) { + return -1; + } + try { + peer.socket.close(); + SOCKFS.websocket_sock_ops.removePeer(sock, peer); + return 0; + } catch (e) { + console.log('Socket shutdown error', e); + return -1; + } + }, + }; + function _js_create_input_device(deviceId) { + let dataBuffer = []; + let dataCallback; + const filename = 'proc_id_' + deviceId; + const device = FS.createDevice( + '/dev', + filename, + function () {}, + function (byte) { + try { + dataBuffer.push(byte); + if (dataCallback) { + dataCallback(new Uint8Array(dataBuffer)); + dataBuffer = []; + } + } catch (e) { + console.error(e); + throw e; + } + } + ); + const devicePath = '/dev/' + filename; + PHPWASM.input_devices[deviceId] = { + devicePath, + onData: function (cb) { + dataCallback = cb; + dataBuffer.forEach(function (data) { + cb(data); + }); + dataBuffer.length = 0; + }, + }; + return allocateUTF8OnStack(devicePath); + } + function _js_open_process( + command, + argsPtr, + argsLength, + descriptorsPtr, + descriptorsLength, + cwdPtr, + cwdLength, + envPtr, + envLength + ) { + if (!command) { + return 1; + } + const cmdstr = UTF8ToString(command); + if (!cmdstr.length) { + return 0; + } + let argsArray = []; + if (argsLength) { + for (var i = 0; i < argsLength; i++) { + const charPointer = argsPtr + i * 4; + argsArray.push(UTF8ToString(HEAPU32[charPointer >> 2])); + } + } + const cwdstr = cwdPtr ? UTF8ToString(cwdPtr) : null; + let envObject = null; + if (envLength) { + envObject = {}; + for (var i = 0; i < envLength; i++) { + const envPointer = envPtr + i * 4; + const envEntry = UTF8ToString(HEAPU32[envPointer >> 2]); + const splitAt = envEntry.indexOf('='); + if (splitAt === -1) { + continue; + } + const key = envEntry.substring(0, splitAt); + const value = envEntry.substring(splitAt + 1); + envObject[key] = value; + } + } + var std = {}; + for (var i = 0; i < descriptorsLength; i++) { + const descriptorPtr = HEAPU32[(descriptorsPtr + i * 4) >> 2]; + std[HEAPU32[descriptorPtr >> 2]] = { + child: HEAPU32[(descriptorPtr + 4) >> 2], + parent: HEAPU32[(descriptorPtr + 8) >> 2], + }; + } + return Asyncify.handleSleep(async (wakeUp) => { + let cp; + try { + const options = {}; + if (cwdstr !== null) { + options.cwd = cwdstr; + } + if (envObject !== null) { + options.env = envObject; + } + cp = PHPWASM.spawnProcess(cmdstr, argsArray, options); + if (cp instanceof Promise) { + cp = await cp; + } + } catch (e) { + if (e.code === 'SPAWN_UNSUPPORTED') { + wakeUp(1); + return; + } + console.error(e); + wakeUp(1); + throw e; + } + const ProcInfo = { + pid: cp.pid, + exited: false, + stdinFd: std[0]?.child, + stdinIsDevice: std[0]?.child in PHPWASM.input_devices, + stdoutChildFd: std[1]?.child, + stdoutParentFd: std[1]?.parent, + stderrChildFd: std[2]?.child, + stderrParentFd: std[2]?.parent, + stdout: new PHPWASM.EventEmitter(), + stderr: new PHPWASM.EventEmitter(), + }; + if (ProcInfo.stdoutChildFd) + PHPWASM.child_proc_by_fd[ProcInfo.stdoutChildFd] = ProcInfo; + if (ProcInfo.stderrChildFd) + PHPWASM.child_proc_by_fd[ProcInfo.stderrChildFd] = ProcInfo; + if (ProcInfo.stdoutParentFd) + PHPWASM.child_proc_by_fd[ProcInfo.stdoutParentFd] = ProcInfo; + if (ProcInfo.stderrParentFd) + PHPWASM.child_proc_by_fd[ProcInfo.stderrParentFd] = ProcInfo; + PHPWASM.child_proc_by_pid[ProcInfo.pid] = ProcInfo; + cp.on('exit', function (code) { + ProcInfo.exitCode = code; + ProcInfo.exited = true; + ProcInfo.stdout.emit('data'); + ProcInfo.stderr.emit('data'); + }); + if (ProcInfo.stdoutChildFd) { + const stdoutStream = SYSCALLS.getStreamFromFD( + ProcInfo.stdoutChildFd + ); + let stdoutAt = 0; + cp.stdout.on('data', function (data) { + ProcInfo.stdout.emit('data', data); + stdoutStream.stream_ops.write( + stdoutStream, + data, + 0, + data.length, + stdoutAt + ); + stdoutAt += data.length; + }); + } + if (ProcInfo.stderrChildFd) { + const stderrStream = SYSCALLS.getStreamFromFD( + ProcInfo.stderrChildFd + ); + let stderrAt = 0; + cp.stderr.on('data', function (data) { + ProcInfo.stderr.emit('data', data); + stderrStream.stream_ops.write( + stderrStream, + data, + 0, + data.length, + stderrAt + ); + stderrAt += data.length; + }); + } + try { + await new Promise((resolve, reject) => { + cp.on('spawn', resolve); + cp.on('error', reject); + }); + } catch (e) { + console.error(e); + wakeUp(1); + return; + } + if (ProcInfo.stdinIsDevice) { + PHPWASM.input_devices[ProcInfo.stdinFd].onData(function (data) { + if (!data) return; + if (typeof data === 'number') { + data = new Uint8Array([data]); + } + const dataStr = new TextDecoder('utf-8').decode(data); + cp.stdin.write(dataStr); + }); + wakeUp(ProcInfo.pid); + return; + } + if (ProcInfo.stdinFd) { + const stdinStream = SYSCALLS.getStreamFromFD(ProcInfo.stdinFd); + if (stdinStream.node) { + const CHUNK_SIZE = 1024; + const buffer = new Uint8Array(CHUNK_SIZE); + let offset = 0; + while (true) { + const bytesRead = stdinStream.stream_ops.read( + stdinStream, + buffer, + 0, + CHUNK_SIZE, + offset + ); + if (bytesRead === null || bytesRead === 0) { + break; + } + try { + cp.stdin.write(buffer.subarray(0, bytesRead)); + } catch (e) { + console.error(e); + return 1; + } + if (bytesRead < CHUNK_SIZE) { + break; + } + offset += bytesRead; + } + wakeUp(ProcInfo.pid); + return; + } + } + wakeUp(ProcInfo.pid); + }); + } + function _js_process_status(pid, exitCodePtr) { + if (!PHPWASM.child_proc_by_pid[pid]) { + return -1; + } + if (PHPWASM.child_proc_by_pid[pid].exited) { + HEAPU32[exitCodePtr >> 2] = PHPWASM.child_proc_by_pid[pid].exitCode; + return 1; + } + return 0; + } + function _js_waitpid(pid, exitCodePtr) { + if (!PHPWASM.child_proc_by_pid[pid]) { + return -1; + } + return Asyncify.handleSleep((wakeUp) => { + const poll = function () { + if (PHPWASM.child_proc_by_pid[pid]?.exited) { + HEAPU32[exitCodePtr >> 2] = + PHPWASM.child_proc_by_pid[pid].exitCode; + wakeUp(pid); + } else { + setTimeout(poll, 50); + } + }; + poll(); + }); + } + var arraySum = (array, index) => { + var sum = 0; + for (var i = 0; i <= index; sum += array[i++]) {} + return sum; + }; + var MONTH_DAYS_LEAP = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; + var MONTH_DAYS_REGULAR = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; + var addDays = (date, days) => { + var newDate = new Date(date.getTime()); + while (days > 0) { + var leap = isLeapYear(newDate.getFullYear()); + var currentMonth = newDate.getMonth(); + var daysInCurrentMonth = ( + leap ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR + )[currentMonth]; + if (days > daysInCurrentMonth - newDate.getDate()) { + days -= daysInCurrentMonth - newDate.getDate() + 1; + newDate.setDate(1); + if (currentMonth < 11) { + newDate.setMonth(currentMonth + 1); + } else { + newDate.setMonth(0); + newDate.setFullYear(newDate.getFullYear() + 1); + } + } else { + newDate.setDate(newDate.getDate() + days); + return newDate; + } + } + return newDate; + }; + var _strptime = (buf, format, tm) => { + var pattern = UTF8ToString(format); + var SPECIAL_CHARS = '\\!@#$^&*()+=-[]/{}|:<>?,.'; + for (var i = 0, ii = SPECIAL_CHARS.length; i < ii; ++i) { + pattern = pattern.replace( + new RegExp('\\' + SPECIAL_CHARS[i], 'g'), + '\\' + SPECIAL_CHARS[i] + ); + } + var EQUIVALENT_MATCHERS = { + A: '%a', + B: '%b', + c: '%a %b %d %H:%M:%S %Y', + D: '%m\\/%d\\/%y', + e: '%d', + F: '%Y-%m-%d', + h: '%b', + R: '%H\\:%M', + r: '%I\\:%M\\:%S\\s%p', + T: '%H\\:%M\\:%S', + x: '%m\\/%d\\/(?:%y|%Y)', + X: '%H\\:%M\\:%S', + }; + var DATE_PATTERNS = { + a: '(?:Sun(?:day)?)|(?:Mon(?:day)?)|(?:Tue(?:sday)?)|(?:Wed(?:nesday)?)|(?:Thu(?:rsday)?)|(?:Fri(?:day)?)|(?:Sat(?:urday)?)', + b: '(?:Jan(?:uary)?)|(?:Feb(?:ruary)?)|(?:Mar(?:ch)?)|(?:Apr(?:il)?)|May|(?:Jun(?:e)?)|(?:Jul(?:y)?)|(?:Aug(?:ust)?)|(?:Sep(?:tember)?)|(?:Oct(?:ober)?)|(?:Nov(?:ember)?)|(?:Dec(?:ember)?)', + C: '\\d\\d', + d: '0[1-9]|[1-9](?!\\d)|1\\d|2\\d|30|31', + H: '\\d(?!\\d)|[0,1]\\d|20|21|22|23', + I: '\\d(?!\\d)|0\\d|10|11|12', + j: '00[1-9]|0?[1-9](?!\\d)|0?[1-9]\\d(?!\\d)|[1,2]\\d\\d|3[0-6]\\d', + m: '0[1-9]|[1-9](?!\\d)|10|11|12', + M: '0\\d|\\d(?!\\d)|[1-5]\\d', + n: ' ', + p: 'AM|am|PM|pm|A\\.M\\.|a\\.m\\.|P\\.M\\.|p\\.m\\.', + S: '0\\d|\\d(?!\\d)|[1-5]\\d|60', + U: '0\\d|\\d(?!\\d)|[1-4]\\d|50|51|52|53', + W: '0\\d|\\d(?!\\d)|[1-4]\\d|50|51|52|53', + w: '[0-6]', + y: '\\d\\d', + Y: '\\d\\d\\d\\d', + t: ' ', + z: 'Z|(?:[\\+\\-]\\d\\d:?(?:\\d\\d)?)', + }; + var MONTH_NUMBERS = { + JAN: 0, + FEB: 1, + MAR: 2, + APR: 3, + MAY: 4, + JUN: 5, + JUL: 6, + AUG: 7, + SEP: 8, + OCT: 9, + NOV: 10, + DEC: 11, + }; + var DAY_NUMBERS_SUN_FIRST = { + SUN: 0, + MON: 1, + TUE: 2, + WED: 3, + THU: 4, + FRI: 5, + SAT: 6, + }; + var DAY_NUMBERS_MON_FIRST = { + MON: 0, + TUE: 1, + WED: 2, + THU: 3, + FRI: 4, + SAT: 5, + SUN: 6, + }; + var capture = []; + var pattern_out = pattern + .replace(/%(.)/g, (m, c) => EQUIVALENT_MATCHERS[c] || m) + .replace(/%(.)/g, (_, c) => { + let pat = DATE_PATTERNS[c]; + if (pat) { + capture.push(c); + return `(${pat})`; + } else { + return c; + } + }) + .replace(/\s+/g, '\\s*'); + var matches = new RegExp('^' + pattern_out, 'i').exec( + UTF8ToString(buf) + ); + function initDate() { + function fixup(value, min, max) { + return typeof value != 'number' || isNaN(value) + ? min + : value >= min + ? value <= max + ? value + : max + : min; + } + return { + year: fixup(HEAP32[(tm + 20) >> 2] + 1900, 1970, 9999), + month: fixup(HEAP32[(tm + 16) >> 2], 0, 11), + day: fixup(HEAP32[(tm + 12) >> 2], 1, 31), + hour: fixup(HEAP32[(tm + 8) >> 2], 0, 23), + min: fixup(HEAP32[(tm + 4) >> 2], 0, 59), + sec: fixup(HEAP32[tm >> 2], 0, 59), + gmtoff: 0, + }; + } + if (matches) { + var date = initDate(); + var value; + var getMatch = (symbol) => { + var pos = capture.indexOf(symbol); + if (pos >= 0) { + return matches[pos + 1]; + } + return; + }; + if ((value = getMatch('S'))) { + date.sec = jstoi_q(value); + } + if ((value = getMatch('M'))) { + date.min = jstoi_q(value); + } + if ((value = getMatch('H'))) { + date.hour = jstoi_q(value); + } else if ((value = getMatch('I'))) { + var hour = jstoi_q(value); + if ((value = getMatch('p'))) { + hour += value.toUpperCase()[0] === 'P' ? 12 : 0; + } + date.hour = hour; + } + if ((value = getMatch('Y'))) { + date.year = jstoi_q(value); + } else if ((value = getMatch('y'))) { + var year = jstoi_q(value); + if ((value = getMatch('C'))) { + year += jstoi_q(value) * 100; + } else { + year += year < 69 ? 2e3 : 1900; + } + date.year = year; + } + if ((value = getMatch('m'))) { + date.month = jstoi_q(value) - 1; + } else if ((value = getMatch('b'))) { + date.month = + MONTH_NUMBERS[value.substring(0, 3).toUpperCase()] || 0; + } + if ((value = getMatch('d'))) { + date.day = jstoi_q(value); + } else if ((value = getMatch('j'))) { + var day = jstoi_q(value); + var leapYear = isLeapYear(date.year); + for (var month = 0; month < 12; ++month) { + var daysUntilMonth = arraySum( + leapYear ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR, + month - 1 + ); + if ( + day <= + daysUntilMonth + + (leapYear ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR)[ + month + ] + ) { + date.day = day - daysUntilMonth; + } + } + } else if ((value = getMatch('a'))) { + var weekDay = value.substring(0, 3).toUpperCase(); + if ((value = getMatch('U'))) { + var weekDayNumber = DAY_NUMBERS_SUN_FIRST[weekDay]; + var weekNumber = jstoi_q(value); + var janFirst = new Date(date.year, 0, 1); + var endDate; + if (janFirst.getDay() === 0) { + endDate = addDays( + janFirst, + weekDayNumber + 7 * (weekNumber - 1) + ); + } else { + endDate = addDays( + janFirst, + 7 - + janFirst.getDay() + + weekDayNumber + + 7 * (weekNumber - 1) + ); + } + date.day = endDate.getDate(); + date.month = endDate.getMonth(); + } else if ((value = getMatch('W'))) { + var weekDayNumber = DAY_NUMBERS_MON_FIRST[weekDay]; + var weekNumber = jstoi_q(value); + var janFirst = new Date(date.year, 0, 1); + var endDate; + if (janFirst.getDay() === 1) { + endDate = addDays( + janFirst, + weekDayNumber + 7 * (weekNumber - 1) + ); + } else { + endDate = addDays( + janFirst, + 7 - + janFirst.getDay() + + 1 + + weekDayNumber + + 7 * (weekNumber - 1) + ); + } + date.day = endDate.getDate(); + date.month = endDate.getMonth(); + } + } + if ((value = getMatch('z'))) { + if (value.toLowerCase() === 'z') { + date.gmtoff = 0; + } else { + var match = value.match(/^((?:\-|\+)\d\d):?(\d\d)?/); + date.gmtoff = match[1] * 3600; + if (match[2]) { + date.gmtoff += + date.gmtoff > 0 ? match[2] * 60 : -match[2] * 60; + } + } + } + var fullDate = new Date( + date.year, + date.month, + date.day, + date.hour, + date.min, + date.sec, + 0 + ); + HEAP32[tm >> 2] = fullDate.getSeconds(); + HEAP32[(tm + 4) >> 2] = fullDate.getMinutes(); + HEAP32[(tm + 8) >> 2] = fullDate.getHours(); + HEAP32[(tm + 12) >> 2] = fullDate.getDate(); + HEAP32[(tm + 16) >> 2] = fullDate.getMonth(); + HEAP32[(tm + 20) >> 2] = fullDate.getFullYear() - 1900; + HEAP32[(tm + 24) >> 2] = fullDate.getDay(); + HEAP32[(tm + 28) >> 2] = + arraySum( + isLeapYear(fullDate.getFullYear()) + ? MONTH_DAYS_LEAP + : MONTH_DAYS_REGULAR, + fullDate.getMonth() - 1 + ) + + fullDate.getDate() - + 1; + HEAP32[(tm + 32) >> 2] = 0; + HEAP32[(tm + 36) >> 2] = date.gmtoff; + return buf + intArrayFromString(matches[0]).length - 1; + } + return 0; + }; + function _wasm_setsockopt( + socketd, + level, + optionName, + optionValuePtr, + optionLen + ) { + const optionValue = HEAPU8[optionValuePtr]; + const SOL_SOCKET = 1; + const SO_KEEPALIVE = 9; + const IPPROTO_TCP = 6; + const TCP_NODELAY = 1; + const isSupported = + (level === SOL_SOCKET && optionName === SO_KEEPALIVE) || + (level === IPPROTO_TCP && optionName === TCP_NODELAY); + if (!isSupported) { + console.warn( + `Unsupported socket option: ${level}, ${optionName}, ${optionValue}` + ); + return -1; + } + const ws = PHPWASM.getAllWebSockets(socketd)[0]; + if (!ws) { + return -1; + } + ws.setSocketOpt(level, optionName, optionValuePtr); + return 0; + } + var Asyncify = { + instrumentWasmImports(imports) { + var importPattern = + /^(js_open_process|js_waitpid|js_process_status|js_create_input_device|wasm_setsockopt|wasm_shutdown|wasm_close|invoke_.*|__asyncjs__.*)$/; + for (let [x, original] of Object.entries(imports)) { + if (typeof original == 'function') { + let isAsyncifyImport = + original.isAsync || importPattern.test(x); + if (isAsyncifyImport) { + imports[x] = original = new WebAssembly.Suspending( + original + ); + } + } + } + }, + instrumentWasmExports(exports) { + var exportPattern = + /^(wasm_sleep|wasm_read|emscripten_sleep|wasm_sapi_handle_request|wasm_sapi_request_shutdown|wasm_poll_socket|wrap_select|__wrap_select|select|php_pollfd_for|fflush|wasm_popen|wasm_read|wasm_php_exec|run_cli|main|__main_argc_argv)$/; + Asyncify.asyncExports = new Set(); + var ret = {}; + for (let [x, original] of Object.entries(exports)) { + if (typeof original == 'function') { + let isAsyncifyExport = exportPattern.test(x); + if (isAsyncifyExport) { + Asyncify.asyncExports.add(original); + original = Asyncify.makeAsyncFunction(original); + } + ret[x] = (...args) => original(...args); + } else { + ret[x] = original; + } + } + return ret; + }, + asyncExports: null, + isAsyncExport(func) { + return Asyncify.asyncExports?.has(func); + }, + handleAsync: async (startAsync) => { + runtimeKeepalivePush(); + try { + return await startAsync(); + } finally { + runtimeKeepalivePop(); + } + }, + handleSleep(startAsync) { + return Asyncify.handleAsync(() => new Promise(startAsync)); + }, + makeAsyncFunction(original) { + return WebAssembly.promising(original); + }, + }; + var getCFunc = (ident) => { + var func = Module['_' + ident]; + return func; + }; + var writeArrayToMemory = (array, buffer) => { + HEAP8.set(array, buffer); + }; + var stackSave = () => _emscripten_stack_get_current(); + var stackRestore = (val) => __emscripten_stack_restore(val); + var ccall = (ident, returnType, argTypes, args, opts) => { + var toC = { + string: (str) => { + var ret = 0; + if (str !== null && str !== undefined && str !== 0) { + ret = stringToUTF8OnStack(str); + } + return ret; + }, + array: (arr) => { + var ret = stackAlloc(arr.length); + writeArrayToMemory(arr, ret); + return ret; + }, + }; + function convertReturnValue(ret) { + if (returnType === 'string') { + return UTF8ToString(ret); + } + if (returnType === 'boolean') return Boolean(ret); + return ret; + } + var func = getCFunc(ident); + var cArgs = []; + var stack = 0; + if (args) { + for (var i = 0; i < args.length; i++) { + var converter = toC[argTypes[i]]; + if (converter) { + if (stack === 0) stack = stackSave(); + cArgs[i] = converter(args[i]); + } else { + cArgs[i] = args[i]; + } + } + } + var ret = func(...cArgs); + function onDone(ret) { + if (stack !== 0) stackRestore(stack); + return convertReturnValue(ret); + } + var asyncMode = opts?.async; + if (asyncMode) return ret.then(onDone); + ret = onDone(ret); + return ret; + }; + var FS_createPath = FS.createPath; + var FS_unlink = (path) => FS.unlink(path); + var FS_createLazyFile = FS.createLazyFile; + var FS_createDevice = FS.createDevice; + FS.createPreloadedFile = FS_createPreloadedFile; + FS.staticInit(); + Module['FS_createPath'] = FS.createPath; + Module['FS_createDataFile'] = FS.createDataFile; + Module['FS_createPreloadedFile'] = FS.createPreloadedFile; + Module['FS_unlink'] = FS.unlink; + Module['FS_createLazyFile'] = FS.createLazyFile; + Module['FS_createDevice'] = FS.createDevice; + MEMFS.doesNotExistError = new FS.ErrnoError(44); + MEMFS.doesNotExistError.stack = ''; + PHPWASM.init(); + var wasmImports = { + SharpYuvConvert: _SharpYuvConvert, + SharpYuvGetConversionMatrix: _SharpYuvGetConversionMatrix, + SharpYuvInit: _SharpYuvInit, + __assert_fail: ___assert_fail, + __asyncjs__js_fd_read, + __asyncjs__js_module_onMessage, + __asyncjs__js_popen_to_file, + __asyncjs__wasm_poll_socket, + __call_sighandler: ___call_sighandler, + __syscall_accept4: ___syscall_accept4, + __syscall_bind: ___syscall_bind, + __syscall_chdir: ___syscall_chdir, + __syscall_chmod: ___syscall_chmod, + __syscall_connect: ___syscall_connect, + __syscall_dup: ___syscall_dup, + __syscall_dup3: ___syscall_dup3, + __syscall_faccessat: ___syscall_faccessat, + __syscall_fallocate: ___syscall_fallocate, + __syscall_fchmod: ___syscall_fchmod, + __syscall_fchown32: ___syscall_fchown32, + __syscall_fchownat: ___syscall_fchownat, + __syscall_fcntl64: ___syscall_fcntl64, + __syscall_fdatasync: ___syscall_fdatasync, + __syscall_fstat64: ___syscall_fstat64, + __syscall_ftruncate64: ___syscall_ftruncate64, + __syscall_getcwd: ___syscall_getcwd, + __syscall_getdents64: ___syscall_getdents64, + __syscall_getpeername: ___syscall_getpeername, + __syscall_getsockname: ___syscall_getsockname, + __syscall_getsockopt: ___syscall_getsockopt, + __syscall_ioctl: ___syscall_ioctl, + __syscall_listen: ___syscall_listen, + __syscall_lstat64: ___syscall_lstat64, + __syscall_mkdirat: ___syscall_mkdirat, + __syscall_newfstatat: ___syscall_newfstatat, + __syscall_openat: ___syscall_openat, + __syscall_pipe: ___syscall_pipe, + __syscall_poll: ___syscall_poll, + __syscall_readlinkat: ___syscall_readlinkat, + __syscall_recvfrom: ___syscall_recvfrom, + __syscall_renameat: ___syscall_renameat, + __syscall_rmdir: ___syscall_rmdir, + __syscall_sendto: ___syscall_sendto, + __syscall_socket: ___syscall_socket, + __syscall_stat64: ___syscall_stat64, + __syscall_statfs64: ___syscall_statfs64, + __syscall_symlinkat: ___syscall_symlinkat, + __syscall_unlinkat: ___syscall_unlinkat, + __syscall_utimensat: ___syscall_utimensat, + _abort_js: __abort_js, + _emscripten_lookup_name: __emscripten_lookup_name, + _emscripten_runtime_keepalive_clear: + __emscripten_runtime_keepalive_clear, + _gmtime_js: __gmtime_js, + _localtime_js: __localtime_js, + _mktime_js: __mktime_js, + _mmap_js: __mmap_js, + _munmap_js: __munmap_js, + _setitimer_js: __setitimer_js, + _tzset_js: __tzset_js, + clock_time_get: _clock_time_get, + emscripten_date_now: _emscripten_date_now, + emscripten_get_heap_max: _emscripten_get_heap_max, + emscripten_get_now: _emscripten_get_now, + emscripten_resize_heap: _emscripten_resize_heap, + emscripten_sleep: _emscripten_sleep, + environ_get: _environ_get, + environ_sizes_get: _environ_sizes_get, + exit: _exit, + fd_close: _fd_close, + fd_fdstat_get: _fd_fdstat_get, + fd_read: _fd_read, + fd_seek: _fd_seek, + fd_write: _fd_write, + getaddrinfo: _getaddrinfo, + getnameinfo: _getnameinfo, + getprotobyname: _getprotobyname, + getprotobynumber: _getprotobynumber, + js_create_input_device: _js_create_input_device, + js_open_process: _js_open_process, + js_process_status: _js_process_status, + js_waitpid: _js_waitpid, + proc_exit: _proc_exit, + strptime: _strptime, + wasm_setsockopt: _wasm_setsockopt, + }; + var wasmExports; + createWasm(); + var ___wasm_call_ctors = () => + (___wasm_call_ctors = wasmExports['__wasm_call_ctors'])(); + var _malloc = (a0) => (_malloc = wasmExports['malloc'])(a0); + var _wasm_read = (Module['_wasm_read'] = (a0, a1, a2) => + (_wasm_read = Module['_wasm_read'] = wasmExports['wasm_read'])( + a0, + a1, + a2 + )); + var _fflush = (a0) => (_fflush = wasmExports['fflush'])(a0); + var _wasm_popen = (Module['_wasm_popen'] = (a0, a1) => + (_wasm_popen = Module['_wasm_popen'] = wasmExports['wasm_popen'])( + a0, + a1 + )); + var _wasm_php_exec = (Module['_wasm_php_exec'] = (a0, a1, a2, a3) => + (_wasm_php_exec = Module['_wasm_php_exec'] = + wasmExports['wasm_php_exec'])(a0, a1, a2, a3)); + var _php_pollfd_for = (Module['_php_pollfd_for'] = (a0, a1, a2) => + (_php_pollfd_for = Module['_php_pollfd_for'] = + wasmExports['php_pollfd_for'])(a0, a1, a2)); + var _htons = (a0) => (_htons = wasmExports['htons'])(a0); + var _ntohs = (a0) => (_ntohs = wasmExports['ntohs'])(a0); + var _htonl = (a0) => (_htonl = wasmExports['htonl'])(a0); + var _wasm_sleep = (Module['_wasm_sleep'] = (a0) => + (_wasm_sleep = Module['_wasm_sleep'] = wasmExports['wasm_sleep'])(a0)); + var ___wrap_select = (Module['___wrap_select'] = (a0, a1, a2, a3, a4) => + (___wrap_select = Module['___wrap_select'] = + wasmExports['__wrap_select'])(a0, a1, a2, a3, a4)); + var _wasm_set_sapi_name = (Module['_wasm_set_sapi_name'] = (a0) => + (_wasm_set_sapi_name = Module['_wasm_set_sapi_name'] = + wasmExports['wasm_set_sapi_name'])(a0)); + var _wasm_set_phpini_path = (Module['_wasm_set_phpini_path'] = (a0) => + (_wasm_set_phpini_path = Module['_wasm_set_phpini_path'] = + wasmExports['wasm_set_phpini_path'])(a0)); + var _wasm_add_SERVER_entry = (Module['_wasm_add_SERVER_entry'] = (a0, a1) => + (_wasm_add_SERVER_entry = Module['_wasm_add_SERVER_entry'] = + wasmExports['wasm_add_SERVER_entry'])(a0, a1)); + var _wasm_add_ENV_entry = (Module['_wasm_add_ENV_entry'] = (a0, a1) => + (_wasm_add_ENV_entry = Module['_wasm_add_ENV_entry'] = + wasmExports['wasm_add_ENV_entry'])(a0, a1)); + var _wasm_set_query_string = (Module['_wasm_set_query_string'] = (a0) => + (_wasm_set_query_string = Module['_wasm_set_query_string'] = + wasmExports['wasm_set_query_string'])(a0)); + var _wasm_set_path_translated = (Module['_wasm_set_path_translated'] = ( + a0 + ) => + (_wasm_set_path_translated = Module['_wasm_set_path_translated'] = + wasmExports['wasm_set_path_translated'])(a0)); + var _wasm_set_skip_shebang = (Module['_wasm_set_skip_shebang'] = (a0) => + (_wasm_set_skip_shebang = Module['_wasm_set_skip_shebang'] = + wasmExports['wasm_set_skip_shebang'])(a0)); + var _wasm_set_request_uri = (Module['_wasm_set_request_uri'] = (a0) => + (_wasm_set_request_uri = Module['_wasm_set_request_uri'] = + wasmExports['wasm_set_request_uri'])(a0)); + var _wasm_set_request_method = (Module['_wasm_set_request_method'] = (a0) => + (_wasm_set_request_method = Module['_wasm_set_request_method'] = + wasmExports['wasm_set_request_method'])(a0)); + var _wasm_set_request_host = (Module['_wasm_set_request_host'] = (a0) => + (_wasm_set_request_host = Module['_wasm_set_request_host'] = + wasmExports['wasm_set_request_host'])(a0)); + var _wasm_set_content_type = (Module['_wasm_set_content_type'] = (a0) => + (_wasm_set_content_type = Module['_wasm_set_content_type'] = + wasmExports['wasm_set_content_type'])(a0)); + var _wasm_set_request_body = (Module['_wasm_set_request_body'] = (a0) => + (_wasm_set_request_body = Module['_wasm_set_request_body'] = + wasmExports['wasm_set_request_body'])(a0)); + var _wasm_set_content_length = (Module['_wasm_set_content_length'] = (a0) => + (_wasm_set_content_length = Module['_wasm_set_content_length'] = + wasmExports['wasm_set_content_length'])(a0)); + var _wasm_set_cookies = (Module['_wasm_set_cookies'] = (a0) => + (_wasm_set_cookies = Module['_wasm_set_cookies'] = + wasmExports['wasm_set_cookies'])(a0)); + var _wasm_set_request_port = (Module['_wasm_set_request_port'] = (a0) => + (_wasm_set_request_port = Module['_wasm_set_request_port'] = + wasmExports['wasm_set_request_port'])(a0)); + var _wasm_sapi_request_shutdown = (Module['_wasm_sapi_request_shutdown'] = + () => + (_wasm_sapi_request_shutdown = Module[ + '_wasm_sapi_request_shutdown' + ] = + wasmExports['wasm_sapi_request_shutdown'])()); + var _wasm_sapi_handle_request = (Module['_wasm_sapi_handle_request'] = () => + (_wasm_sapi_handle_request = Module['_wasm_sapi_handle_request'] = + wasmExports['wasm_sapi_handle_request'])()); + var _php_wasm_init = (Module['_php_wasm_init'] = () => + (_php_wasm_init = Module['_php_wasm_init'] = + wasmExports['php_wasm_init'])()); + var _wasm_free = (Module['_wasm_free'] = (a0) => + (_wasm_free = Module['_wasm_free'] = wasmExports['wasm_free'])(a0)); + var ___funcs_on_exit = () => + (___funcs_on_exit = wasmExports['__funcs_on_exit'])(); + var _emscripten_builtin_memalign = (a0, a1) => + (_emscripten_builtin_memalign = + wasmExports['emscripten_builtin_memalign'])(a0, a1); + var __emscripten_timeout = (a0, a1) => + (__emscripten_timeout = wasmExports['_emscripten_timeout'])(a0, a1); + var ___trap = () => (___trap = wasmExports['__trap'])(); + var __emscripten_stack_restore = (a0) => + (__emscripten_stack_restore = wasmExports['_emscripten_stack_restore'])( + a0 + ); + var __emscripten_stack_alloc = (a0) => + (__emscripten_stack_alloc = wasmExports['_emscripten_stack_alloc'])(a0); + var _emscripten_stack_get_current = () => + (_emscripten_stack_get_current = + wasmExports['emscripten_stack_get_current'])(); + Module['addRunDependency'] = addRunDependency; + Module['removeRunDependency'] = removeRunDependency; + Module['wasmExports'] = wasmExports; + Module['ccall'] = ccall; + Module['FS_createPreloadedFile'] = FS_createPreloadedFile; + Module['FS_unlink'] = FS_unlink; + Module['FS_createPath'] = FS_createPath; + Module['FS_createDevice'] = FS_createDevice; + Module['FS_createDataFile'] = FS_createDataFile; + Module['FS_createLazyFile'] = FS_createLazyFile; + Module['PROXYFS'] = PROXYFS; + var calledRun; + dependenciesFulfilled = function runCaller() { + if (!calledRun) run(); + if (!calledRun) dependenciesFulfilled = runCaller; + }; + function run() { + if (runDependencies > 0) { + return; + } + preRun(); + if (runDependencies > 0) { + return; + } + function doRun() { + if (calledRun) return; + calledRun = true; + Module['calledRun'] = true; + if (ABORT) return; + initRuntime(); + Module['onRuntimeInitialized']?.(); + postRun(); + } + if (Module['setStatus']) { + Module['setStatus']('Running...'); + setTimeout(() => { + setTimeout(() => Module['setStatus'](''), 1); + doRun(); + }, 1); + } else { + doRun(); + } + } + if (Module['preInit']) { + if (typeof Module['preInit'] == 'function') + Module['preInit'] = [Module['preInit']]; + while (Module['preInit'].length > 0) { + Module['preInit'].pop()(); + } + } + run(); + /** + * Emscripten resolves `localhost` to a random IP address. Let's + * make it always resolve to 127.0.0.1. + */ + DNS.address_map.addrs.localhost = '127.0.0.1'; -/** - * Debugging Asyncify errors is tricky because the stack trace is lost when the - * error is thrown. This code saves the stack trace in a global variable - * so that it can be inspected later. - */ -PHPLoader.debug = 'debug' in PHPLoader ? PHPLoader.debug : true; -if (PHPLoader.debug && typeof Asyncify !== "undefined") { - const originalHandleSleep = Asyncify.handleSleep; - Asyncify.handleSleep = function (startAsync) { - if (!ABORT) { - Module["lastAsyncifyStackSource"] = new Error(); - } - return originalHandleSleep(startAsync); - } -} + /** + * Debugging Asyncify errors is tricky because the stack trace is lost when the + * error is thrown. This code saves the stack trace in a global variable + * so that it can be inspected later. + */ + PHPLoader.debug = 'debug' in PHPLoader ? PHPLoader.debug : true; + if (PHPLoader.debug && typeof Asyncify !== 'undefined') { + const originalHandleSleep = Asyncify.handleSleep; + Asyncify.handleSleep = function (startAsync) { + if (!ABORT) { + Module['lastAsyncifyStackSource'] = new Error(); + } + return originalHandleSleep(startAsync); + }; + } -/** - * Data dependencies call removeRunDependency() when they are loaded. - * The synchronous call stack then continues to run. If an error occurs - * in PHP initialization, e.g. Out Of Memory error, it will not be - * caught by any try/catch. This override propagates the failure to - * PHPLoader.onAbort() so that it can be handled. - */ -const originalRemoveRunDependency = PHPLoader['removeRunDependency']; -PHPLoader['removeRunDependency'] = function (...args) { - try { - originalRemoveRunDependency(...args); - } catch (e) { - PHPLoader['onAbort'](e); - } -} + /** + * Data dependencies call removeRunDependency() when they are loaded. + * The synchronous call stack then continues to run. If an error occurs + * in PHP initialization, e.g. Out Of Memory error, it will not be + * caught by any try/catch. This override propagates the failure to + * PHPLoader.onAbort() so that it can be handled. + */ + const originalRemoveRunDependency = PHPLoader['removeRunDependency']; + PHPLoader['removeRunDependency'] = function (...args) { + try { + originalRemoveRunDependency(...args); + } catch (e) { + PHPLoader['onAbort'](e); + } + }; -/** - * Other exports live in the Dockerfile in: - * - * * EXPORTED_RUNTIME_METHODS - * * EXPORTED_FUNCTIONS - * - * These exports, however, live in here because: - * - * * Listing them in EXPORTED_RUNTIME_METHODS doesn't actually - * export them. This could be a bug in Emscripten or a consequence of - * that option being deprecated. - * * Listing them in EXPORTED_FUNCTIONS works, but they are overridden - * on every `BasePHP.run()` call. This is a problem because we want to - * spy on these calls in some unit tests. - * - * Therefore, we export them here. - */ -PHPLoader['malloc'] = _malloc; -PHPLoader['free'] = typeof _free === 'function' ? _free : PHPLoader['_wasm_free']; + /** + * Other exports live in the Dockerfile in: + * + * * EXPORTED_RUNTIME_METHODS + * * EXPORTED_FUNCTIONS + * + * These exports, however, live in here because: + * + * * Listing them in EXPORTED_RUNTIME_METHODS doesn't actually + * export them. This could be a bug in Emscripten or a consequence of + * that option being deprecated. + * * Listing them in EXPORTED_FUNCTIONS works, but they are overridden + * on every `BasePHP.run()` call. This is a problem because we want to + * spy on these calls in some unit tests. + * + * Therefore, we export them here. + */ + PHPLoader['malloc'] = _malloc; + PHPLoader['free'] = + typeof _free === 'function' ? _free : PHPLoader['_wasm_free']; -return PHPLoader; + return PHPLoader; -// Close the opening bracket from esm-prefix.js: + // Close the opening bracket from esm-prefix.js: } diff --git a/packages/playground/remote/service-worker.ts b/packages/playground/remote/service-worker.ts index a4b3089045..deee35e8bc 100644 --- a/packages/playground/remote/service-worker.ts +++ b/packages/playground/remote/service-worker.ts @@ -199,7 +199,6 @@ self.addEventListener('fetch', (event) => { } const url = new URL(event.request.url); - // Don't handle requests to the service worker script itself. if (url.pathname.startsWith(self.location.pathname)) { return; diff --git a/packages/playground/remote/src/lib/boot-playground-remote.ts b/packages/playground/remote/src/lib/boot-playground-remote.ts index 424dcdadf5..b58ae40151 100644 --- a/packages/playground/remote/src/lib/boot-playground-remote.ts +++ b/packages/playground/remote/src/lib/boot-playground-remote.ts @@ -26,6 +26,11 @@ import moduleWorkerUrl from './worker-thread?worker&url'; export const workerUrl: string = new URL(moduleWorkerUrl, origin) + ''; +// @ts-ignore +import experimentalSABFSModuleWorkerUrl from './worker-thread-shared?worker&url'; +export const experimentalSABFSWorkerUrl: string = + new URL(experimentalSABFSModuleWorkerUrl, origin) + ''; + // @ts-ignore import serviceWorkerPath from '../../service-worker.ts?worker&url'; import { FilesystemOperation } from '@php-wasm/fs-journal'; @@ -33,6 +38,11 @@ import { setupFetchNetworkTransport } from './setup-fetch-network-transport'; import { logger } from '@php-wasm/logger'; import { PhpWasmError } from '@php-wasm/util'; import { responseTo } from '@php-wasm/web-service-worker'; +import { + SharedFSBuffers, + createSharedFSBuffers, +} from './shared-array-buffer-fs'; +import type { ExperimentalWorkerEndpoint } from './worker-thread-shared'; export const serviceWorkerUrl = new URL(serviceWorkerPath, origin); // Prevent Vite from hot-reloading this file – it would @@ -422,3 +432,38 @@ function assertNotInfiniteLoadingLoop() { } (window as any).IS_WASM_WORDPRESS = true; } + +async function spawnSharedFSPhpWorker(sharedBuffers: SharedFSBuffers) { + const experimentalPhpWorkerApi = await spawnPHPWorkerThread( + experimentalSABFSWorkerUrl + ); + const phpWorkerApi = consumeAPI( + experimentalPhpWorkerApi + ); + await phpWorkerApi.isConnected(); + await phpWorkerApi.boot({ + sharedBuffers, + }); + await phpWorkerApi.isReady(); + return phpWorkerApi; +} + +const buffers = createSharedFSBuffers(); +const worker1 = await spawnSharedFSPhpWorker(buffers); +const worker2 = await spawnSharedFSPhpWorker(buffers); + +// We can actually write and read files! +console.log('writing file'); +await worker1.writeFile('/experimental-sabfs/test.txt', 'Hello, world!'); +console.log('reading file worker 1'); +console.log(await worker1.readFileAsText('/experimental-sabfs/test.txt')); +await worker1.logHeader('worker1'); +await worker1.logDirState('worker1'); +await worker1.dumpDir('worker1'); +await worker2.logHeader('worker2'); +await worker2.logDirState('worker2'); +await worker2.dumpDir('worker2'); + +console.log('reading file worker 2'); +console.log(await worker2.readFileAsText('/experimental-sabfs/test.txt')); +// @TODO solution: We need to use a SharedArrayBuffer to store the top-level FS metadata diff --git a/packages/playground/remote/src/lib/sab.ts b/packages/playground/remote/src/lib/sab.ts new file mode 100644 index 0000000000..6c742f8941 --- /dev/null +++ b/packages/playground/remote/src/lib/sab.ts @@ -0,0 +1,1114 @@ +// SharedSABFS — SharedArrayBuffer‑backed MEMFS replacement +// Complete, self‑contained and debug‑instrumented. Plug‑and‑play: +// import { createBuffers, SharedSABFS } from './shared-sabfs.ts'; +// const { metaBuf, dataBuf } = createBuffers(); +// FS.mount(SharedSABFS(FS, metaBuf, dataBuf), {}, '/'); +// worker.postMessage({ metaBuf, dataBuf }, [metaBuf, dataBuf]); + +/* Enable or disable verbose console output */ +const DEBUG = false; +const log = (...a: any[]) => DEBUG && console.log('[SABFS]', ...a); + +/* ─── POSIX mode and type bits ───────────────────────────────────────────── */ +const S_IFMT = 0o170000, + // S_IFCHR = 0o020000, // Character device - unused for now + S_IFDIR = 0o040000, + S_IFLNK = 0o120000; +const MODE_DIR = S_IFDIR | 0o777, + MODE_SYMLINK = S_IFLNK | 0o777; + +/* ─── shared‑memory layout ───────────────────────────────────────────────── */ +const IDX_LOCK = 0, // global mutex (int32) + IDX_MAGIC = 1, // magic word "SAFS" + IDX_NEXT_INODE = 2, // next inode id + IDX_NEXT_DATA = 3; // next free byte in data buffer +const HEADER_WORDS = 256; // leave ample header space (1kB) + +// inode fields (Int32 offsets relative to inode start) +const I_MODE = 0, + I_UID = 1, + I_GID = 2, + I_NLINK = 3, + I_SIZEL = 4, + I_SIZEH = 5, + I_PARENT = 6, + I_DATA_OFF = 7, + I_CAP = 8, + I_RDEV = 9, + I_ATIME_L = 10, + I_ATIME_H = 11, + I_MTIME_L = 12, + I_MTIME_H = 13, + I_CTIME_L = 14, + I_CTIME_H = 15, + I_NAME = 16, // 16..47 (128 bytes) for UTF-8 name + I_OPENREFS = 48, + I_PERSIST = 49; // Flag to indicate journal file for truncate-on-close +const INODE_WORDS = 16 + 32 + 2; // Re-add I_PERSIST to size +const NAME_BYTES = 128; +const MAGIC = 0x53414653; // "SAFS" + +const TD = new TextDecoder(); +const TE = new TextEncoder(); +const now64 = () => BigInt(Date.now()); + +/* SQLite specific constants */ +// SQLite database header structure - first 100 bytes + +/* ─── exported factory ───────────────────────────────────────────────────── */ +export function SharedSABFS( + FS: any, + metaBuf: SharedArrayBuffer, + dataBuf: SharedArrayBuffer, + maxInodes = 4096 +) { + /* typed views on metadata buffer */ + const meta = new Int32Array(metaBuf); + const meta8 = new Uint8Array(metaBuf); + const data8 = new Uint8Array(dataBuf); + + /* atomics helpers (short names) */ + const L = Atomics.load, + S = Atomics.store; + + /* mutex helpers */ + const lock = () => { + while (Atomics.compareExchange(meta, IDX_LOCK, 0, 1) !== 0) + Atomics.wait(meta, IDX_LOCK, 1); + }; + const unlock = () => { + S(meta, IDX_LOCK, 0); + Atomics.notify(meta, IDX_LOCK, 1); + }; + + /* inode helpers */ + const ioff = (id: number) => HEADER_WORDS + (id - 1) * INODE_WORDS; + const sz = (off: number) => + L(meta, off + I_SIZEL) + L(meta, off + I_SIZEH) * 0x100000000; + const setSize = (off: number, bytes: number) => { + S(meta, off + I_SIZEL, bytes >>> 0); + S(meta, off + I_SIZEH, (bytes / 0x100000000) >>> 0); + }; + const setTimes = (off: number, a = false, m = false, c = false) => { + const t = now64(); + const lo = Number(t & 0xffffffffn), + hi = Number(t >> 32n); + if (a) { + S(meta, off + I_ATIME_L, lo); + S(meta, off + I_ATIME_H, hi); + } + if (m) { + S(meta, off + I_MTIME_L, lo); + S(meta, off + I_MTIME_H, hi); + } + if (c) { + S(meta, off + I_CTIME_L, lo); + S(meta, off + I_CTIME_H, hi); + } + }; + const putName = (off: number, name: string) => { + const enc = TE.encode(name); + if (enc.length >= NAME_BYTES) throw new FS.ErrnoError(63); + meta8.fill(0, (off + I_NAME) * 4, (off + I_NAME) * 4 + NAME_BYTES); + meta8.set(enc, (off + I_NAME) * 4); + }; + const getName = (off: number) => { + const slice = meta8.subarray( + (off + I_NAME) * 4, + (off + I_NAME) * 4 + NAME_BYTES + ); + const end = slice.indexOf(0); + return TD.decode( + new Uint8Array(slice.slice(0, end < 0 ? NAME_BYTES : end)) + ); + }; + + /* root init (only once) */ + if (L(meta, IDX_MAGIC) !== MAGIC) { + lock(); + if (L(meta, IDX_MAGIC) !== MAGIC) { + S(meta, IDX_MAGIC, MAGIC); + S(meta, IDX_NEXT_INODE, 2); + S(meta, IDX_NEXT_DATA, 0); + const off = ioff(1); + meta.fill(0, off, off + INODE_WORDS); + S(meta, off + I_MODE, MODE_DIR); + S(meta, off + I_PARENT, 1); + S(meta, off + I_NLINK, 1); + S(meta, off + I_RDEV, 0); + S(meta, off + I_OPENREFS, 0); + S(meta, off + I_PERSIST, 0); + setSize(off, 0); + putName(off, '/'); + setTimes(off, true, true, true); + S(meta, off + I_CAP, 0); + log('root initialized'); + } + unlock(); + } + + /* directory helpers */ + const dCount = (off: number) => L(meta, off + I_SIZEL); + const dVec = (off: number) => + new Int32Array(dataBuf, L(meta, off + I_DATA_OFF), dCount(off)); + const pushChild = (off: number, id: number) => { + const cnt = dCount(off); + let cap = L(meta, off + I_CAP); + let start = L(meta, off + I_DATA_OFF); + if (cnt >= cap) { + const ncap = Math.max(4, cap ? cap * 2 : 4); + const nOff = allocData(ncap * 4); + const m32 = new Int32Array(dataBuf); // Get view on the whole data buffer + if (cnt) { + // Copy old ids from old location (start) to new location (nOff) + m32.set( + m32.subarray(start >> 2, (start >> 2) + cnt), + nOff >> 2 + ); + } + // Update start and cap to new values *before* using them + start = nOff; + cap = ncap; + S(meta, off + I_DATA_OFF, start); + S(meta, off + I_CAP, cap); + // Store new id at the correct offset in the *new* buffer location + Atomics.store(m32, (start >> 2) + cnt, id); + } else { + // If not reallocating, just store the new id at the end + const vec = new Int32Array(dataBuf, start, cap); + Atomics.store(vec, cnt, id); + } + S(meta, off + I_SIZEL, cnt + 1); // Increment count + Atomics.notify(meta, (off + I_SIZEL) >> 2, 1); // Use meta index, not offset + log('dir+', (off - HEADER_WORDS) / INODE_WORDS + 1, 'add', id); + }; + const removeChild = (off: number, id: number) => { + const cnt = dCount(off), + vec = dVec(off); + for (let i = 0; i < cnt; i++) { + if (Atomics.load(vec, i) !== id) continue; + + const last = cnt - 1; + // Swap down the last entry (if not the same slot) + if (i !== last) { + Atomics.store(vec, i, Atomics.load(vec, last)); + } + // Really clear the old slot + Atomics.store(vec, last, 0); + + // Decrement count + S(meta, off + I_SIZEL, last); + Atomics.notify(meta, (off + I_SIZEL) >> 2, 1); + log('dir-', (off - HEADER_WORDS) / INODE_WORDS + 1, 'del', id); + return; + } + throw new FS.ErrnoError(44); + }; + + /* data allocation */ + const align4 = (x: number) => (x + 3) & ~3; + + const allocData = (bytes: number) => { + let cur, next; + do { + cur = align4(Atomics.load(meta, IDX_NEXT_DATA)); // <-- new + next = cur + align4(bytes); // | + if (next > data8.length) throw new FS.ErrnoError(28); + } while ( + Atomics.compareExchange(meta, IDX_NEXT_DATA, cur, next) !== cur + ); + return cur; // always multiple of 4 + }; + + /* Helper to check if a filename is a SQLite journal or WAL file */ + const isSQLiteJournalFile = (name: string): boolean => { + return name.endsWith('-journal') || name.endsWith('-wal'); + }; + + /* ─── Helper to check if a filename is a SQLite shared memory file ─── */ + const isSQLiteShmFile = (name: string): boolean => { + return name.endsWith('-shm'); + }; + + /* ─── Helper to check if a filename is a SQLite database file ─── */ + const isSQLiteDbFile = (name: string): boolean => { + return name.endsWith('.sqlite') || name.endsWith('.db'); + }; + + /* Helper to flush a database to ensure data is persisted */ + const flushDatabase = (id: number) => { + const off = ioff(id); + const name = getName(off); + + if (isSQLiteDbFile(name)) { + // No need to acquire a lock here as we'll be called with a lock already held + // Mark the database as fully persisted + log( + ` -> FLUSH: Ensuring durability for SQLite database ${name} (id=${id})` + ); + S(meta, off + I_PERSIST, 1); + + // Get the current size for logging + const size = sz(off); + log( + ` -> FLUSH: Database ${name} marked as persistent, size=${size}` + ); + } + }; + + /* ─── Helper to check if a filename is ANY SQLite-related file ─── */ + const checkSQLiteFile = (name: string): boolean => { + return ( + isSQLiteJournalFile(name) || + isSQLiteShmFile(name) || + isSQLiteDbFile(name) + ); + }; + + /* ─── Create necessary filesystem resources for SQLite consistency ─── */ + const ensureSQLiteConsistency = (path: string) => { + // If this is a SQLite database file, make sure all related files are ready + if (checkSQLiteFile(path)) { + log(`Ensuring consistency for SQLite database: ${path}`); + + // Perform any additional setup needed for SQLite to work correctly + // without requiring EXCLUSIVE locking mode + + // Create a special lock file metadata to coordinate database access + if (isSQLiteDbFile(path)) { + // This metadata helps us track active transactions for this database + // A real implementation would do more here + return { + locked: false, + pendingWriters: 0, + activeReaders: 0, + version: 1, + }; + } + } + return null; + }; + + /* inode allocation */ + // Internal implementation, assumes lock is held + const newInodeInternal = ( + parent: number, + mode: number, + name: string, + rdev = 0 + ) => { + let id = -1; + let success = false; + // Loop to find a suitable inode ID + for (let attempts = 0; attempts < maxInodes * 2; attempts++) { + id = Atomics.add(meta, IDX_NEXT_INODE, 1); + if (id > maxInodes) { + Atomics.sub(meta, IDX_NEXT_INODE, 1); + log(`newInode error: exceeded maxInodes (${maxInodes})`); + throw new FS.ErrnoError(28); + } + success = true; + break; + } + if (!success) { + log( + `newInode error: failed to find unused inode ID after ${ + maxInodes * 2 + } attempts` + ); + throw new FS.ErrnoError(28); + } + + // --- Initialize the chosen inode ID --- + const off = ioff(id); + meta.fill(0, off, off + INODE_WORDS); + S(meta, off + I_MODE, mode); + S(meta, off + I_PARENT, parent); + S(meta, off + I_NLINK, 1); + S(meta, off + I_RDEV, rdev); + S(meta, off + I_OPENREFS, 0); + S(meta, off + I_PERSIST, 0); + setSize(off, 0); + putName(off, name); + setTimes(off, true, true, true); + if ((mode & S_IFMT) === S_IFDIR) S(meta, off + I_CAP, 0); + pushChild(ioff(parent), id); + setTimes(ioff(parent), false, true, true); + log('inode', id, '"' + name + '"'); + return id; + }; + + // Public wrapper that handles locking + const newInode = ( + parent: number, + mode: number, + name: string, + rdev = 0, + alreadyLocked = false + ) => { + if (!alreadyLocked) lock(); + try { + return newInodeInternal(parent, mode, name, rdev); + } finally { + if (!alreadyLocked) unlock(); + } + }; + + const readBytes = ( + id: number, + pos: number, + len: number, + out: Uint8Array + ) => { + const off = ioff(id); + + // Check if this inode is valid (mode != 0) + if (L(meta, off + I_MODE) === 0) { + log( + ` -> ERROR: Attempted to read from an inaccessible inode ${id} (mode=0)` + ); + throw new FS.ErrnoError(9); // EBADF - Bad file descriptor + } + + lock(); + try { + const size = sz(off); + if (pos >= size) return 0; + const to = Math.min(len, size - pos), + src = L(meta, off + I_DATA_OFF) + pos; + out.set(data8.subarray(src, src + to)); + setTimes(off, true, false, false); + return to; + } finally { + unlock(); + } + }; + + const writeBytes = (id: number, pos: number, src: Uint8Array) => { + log(`writeBytes id=${id} pos=${pos} len=${src.length}`); + const off = ioff(id); + + // Check if this inode is valid (mode != 0) + if (L(meta, off + I_MODE) === 0) { + log( + ` -> ERROR: Attempted to write to an inaccessible inode ${id} (mode=0)` + ); + throw new FS.ErrnoError(9); // EBADF - Bad file descriptor + } + + let cap = L(meta, off + I_CAP), + start = L(meta, off + I_DATA_OFF); + const end = pos + src.length, + size = sz(off); + const name = getName(off); + + log( + ` -> initial size=${size} cap=${cap} start=${start} end=${end} name=${name}` + ); + lock(); + try { + // Additional check after acquiring lock - check mode again + if (L(meta, off + I_MODE) === 0) { + log( + ` -> ERROR: Inode ${id} became inaccessible while waiting for lock (mode=0)` + ); + throw new FS.ErrnoError(2); // ENOENT + } + + if (end > cap) { + log(` -> reallocating: end(${end}) > cap(${cap})`); + const ncap = Math.max( + end, + cap ? (cap < 1 << 20 ? cap * 2 : (cap * 9) >> 3) : 256 + ); + log(` -> new capacity ncap=${ncap}`); + const nOff = allocData(ncap); + log(` -> allocated new block at nOff=${nOff}`); + if (size > 0) { + // Only copy if there was previous data + log(` -> slicing ${size} bytes from old offset ${start}`); + const oldData = data8.slice(start, start + size); + log( + ` -> writing ${oldData.length} sliced bytes to new offset ${nOff}` + ); + data8.set(oldData, nOff); + } + start = nOff; + cap = ncap; + S(meta, off + I_DATA_OFF, start); + S(meta, off + I_CAP, cap); + log(` -> updated DATA_OFF=${start}, CAP=${cap}`); + } + + // If the write position is beyond the current size, fill the gap with zeros + if (pos > size) { + log( + ` -> filling gap: pos(${pos}) > size(${size}), filling ${ + pos - size + } bytes from ${start + size}` + ); + data8.fill(0, start + size, start + pos); + } + + log( + ` -> writing ${src.length} bytes to data buffer at offset ${ + start + pos + }` + ); + data8.set(src, start + pos); + + // Update size *after* writing the data if the file grew. + if (end > size) { + log(` -> updating size from ${size} to ${end} *after* write`); + setSize(off, end); + } + + // Write operation finished, now ensure the data is flushed and protected + setTimes(off, false, true, true); + + // Special handling for SQLite database files + // Force an fsync-like behavior to ensure durability + if (isSQLiteDbFile(name)) { + log( + ` -> writeBytes: special handling for SQLite database file ${name}` + ); + // Make sure any pending writes are guaranteed to be visible to all threads + S(meta, off + I_PERSIST, 1); // Mark SQLite database as persistent + } + } finally { + unlock(); + } + }; + + /* JS node constructor */ + const mkNode = (id: number, mount: any, parent: any) => { + const off = ioff(id), + mode = L(meta, off + I_MODE); + const node = FS.createNode( + parent, + getName(off), + mode, + L(meta, off + I_RDEV) + ); + node.sabId = id; + node.node_ops = node_ops; + node.stream_ops = FS.isChrdev(mode) + ? FS.getDevice(node.rdev).stream_ops + : stream_ops; + + // Check if this is a SQLite file and needs special handling + if (checkSQLiteFile(getName(off))) { + // Add a property to track SQLite-specific metadata + node.sqliteInfo = ensureSQLiteConsistency(getName(off)); + } + + return node; + }; + + /* node_ops with robust lookup (retry + wait) */ + const node_ops: any = { + getattr(n: any) { + lock(); + try { + const o = ioff(n.sabId); + const mode = L(meta, o + I_MODE); + + // Read all attributes while holding the lock + const attrs = { + dev: 1, + ino: n.sabId, + mode, + nlink: L(meta, o + I_NLINK), + uid: L(meta, o + I_UID), + gid: L(meta, o + I_GID), + rdev: L(meta, o + I_RDEV), + size: mode & S_IFDIR ? 4096 : sz(o), // sz() also uses Atomics.load + // Faking times for now, reading them atomically would be needed otherwise + atime: new Date(), + mtime: new Date(), + ctime: new Date(), + }; + return attrs; + } finally { + unlock(); + } + }, + setattr(n: any, a: any) { + const o = ioff(n.sabId); + lock(); + if (a.mode !== undefined) + S( + meta, + o + I_MODE, + (L(meta, o + I_MODE) & S_IFMT) | (a.mode & 0o777) + ); + if (a.size !== undefined) { + const cur = sz(o); + if (a.size < cur) setSize(o, a.size); + else if (a.size > cur) + writeBytes(n.sabId, cur, new Uint8Array(a.size - cur)); + } + setTimes(o, false, false, true); + unlock(); + }, + lookup(p: any, name: string) { + const poff = ioff(p.sabId); + const parentId = p.sabId; + const cnt = L(meta, poff + I_SIZEL); + const start = L(meta, poff + I_DATA_OFF); + log( + `lookup("${name}") dir ${parentId} cnt=${cnt} dataStart=${start}` + ); + + // Normal lookup: Iterate through directory entries + if (cnt > 0 && start >= 0) { + const baseArr = new Int32Array(dataBuf); + for (let i = 0; i < cnt; i++) { + const id = L(baseArr, (start >> 2) + i); + if (id <= 0) { + continue; + } + const childOff = ioff(id); + // Check if mode is non-zero AND link count is non-zero + if ( + L(meta, childOff + I_MODE) === 0 || + L(meta, childOff + I_NLINK) === 0 + ) { + log( + ` lookup skipping inactive/unlinked child id=${id}` + ); + continue; + } + const childName = getName(childOff); + if (childName === name) { + log( + ` lookup dir ${parentId}: found "${name}" as id ${id}` + ); + return mkNode(id, p.mount, p); + } + } + } + + log(`lookup failed for "${name}" in dir ${parentId}`); + throw new FS.ErrnoError(44); // ENOENT + }, + mknod(p: any, n: string, m: number, d: number, alreadyLocked = false) { + const parentId = p.sabId; + log(`mknod: creating "${n}" in parent ${parentId}`); + + // Create the new inode, passing the lock status + const id = newInode(parentId, m, n, d, alreadyLocked); + + // Check for SQLite files to ensure filesystem consistency + if (checkSQLiteFile(n)) { + ensureSQLiteConsistency(n); + } + + // Mark ONLY journal files as persistent (for truncate-on-close behavior) + if (isSQLiteJournalFile(n)) { + const off = ioff(id); + log( + `mknod: marking journal file ${n} (id=${id}) for truncate-on-close` + ); + if (!alreadyLocked) lock(); + try { + S(meta, off + I_PERSIST, 1); + } finally { + if (!alreadyLocked) unlock(); + } + } + + return mkNode(id, p.mount, p); + }, + rename(o: any, nd: any, nn: string) { + lock(); + removeChild(ioff(L(meta, ioff(o.sabId) + I_PARENT)), o.sabId); + S(meta, ioff(o.sabId) + I_PARENT, nd.sabId); + putName(ioff(o.sabId), nn); + pushChild(ioff(nd.sabId), o.sabId); + unlock(); + }, + unlink(p: any, nm: string) { + let c; + try { + c = node_ops.lookup(p, nm); + } catch (e: any) { + if (e.errno === 44) { + // ENOENT + log('unlink: file not found, ignore', nm); + return; + } + throw e; + } + const off = ioff(c.sabId); + const name = getName(off); + + log(`[SABFS] unlink: ${name} (id=${c.sabId})`); + lock(); + try { + // Remove from parent directory + try { + removeChild(ioff(p.sabId), c.sabId); + } catch (e: any) { + if (e.errno !== 44) throw e; + } + + // Set link count to 0. + // The file will be fully deleted (mode=0) by the 'close' operation + // when the last open reference is closed. + log( + `[SABFS] unlink: setting nlink=0 for inode ${c.sabId} ("${name}")` + ); + S(meta, off + I_NLINK, 0); + } finally { + unlock(); + } + }, + rmdir(p: any, nm: string) { + const c = node_ops.lookup(p, nm); + // Prevent removing directories named like journal files, just in case + if (nm.endsWith('-journal') || nm.endsWith('-wal')) { + log( + `rmdir: refusing to remove directory resembling journal file ${nm}` + ); + throw new FS.ErrnoError(1); // EPERM - Operation not permitted + } + + if (dCount(ioff(c.sabId)) > 0) throw new FS.ErrnoError(55); // ENOTEMPTY + lock(); + removeChild(ioff(p.sabId), c.sabId); + const off = ioff(c.sabId); + S(meta, off + I_NLINK, 0); + + // Only fully delete the directory if there are no open references + const openRefs = L(meta, off + I_OPENREFS); + if (openRefs === 0) { + S(meta, off + I_MODE, 0); + log(`rmdir: removed directory "${nm}" (id=${c.sabId})`); + } else { + log( + `rmdir: marked directory "${nm}" (id=${c.sabId}) for deletion, but keeping accessible for ${openRefs} open refs` + ); + } + unlock(); + }, + readdir(n: any) { + const out = ['.', '..']; + const parentId = n.sabId; + const off = ioff(parentId); + const cnt = dCount(off); + const start = L(meta, off + I_DATA_OFF); + log(`readdir dir ${parentId} cnt=${cnt} dataStart=${start}`); + if (cnt > 0 && start >= 0) { + const vec = dVec(off); // Uses dCount internally + for (let i = 0; i < vec.length; i++) { + const id = vec[i]; // Use view directly + log(` readdir dir ${parentId}: index ${i} id=${id}`); + if (id > 0 && L(meta, ioff(id) + I_MODE) !== 0) { + out.push(getName(ioff(id))); + } else { + log( + ` readdir dir ${parentId}: skipping invalid id ${id} at index ${i}` + ); + } + } + } + return out; + }, + symlink(p: any, nm: string, tgt: string) { + const id = newInode(p.sabId, MODE_SYMLINK, nm); + writeBytes(id, 0, TE.encode(tgt)); + return mkNode(id, p.mount, p); + }, + readlink(n: any) { + lock(); + try { + const off = ioff(n.sabId); + const len = sz(off); // Read size under lock + const dataOffset = L(meta, off + I_DATA_OFF); // Read offset under lock + // Slice data under lock + const linkData = data8.slice(dataOffset, dataOffset + len); + return TD.decode(linkData); + } finally { + unlock(); + } + }, + chmod(n: any, mode: number) { + node_ops.setattr(n, { mode }); + }, + chown() {}, + fsync(s: any) { + const id = s.node.sabId; + const off = ioff(id); + const name = getName(off); + + log(`fsync called for node id ${id} (${name})`); + + // Use a single lock to avoid recursive locking issues + lock(); + try { + // Update timestamp first + setTimes(off, false, true, false); + + if (isSQLiteDbFile(name)) { + log(` -> fsync: calling flushDatabase for ${name}`); + flushDatabase(id); // Still calls this (currently just sets time again) + + // Speculative fix: Attempt to read entire file content to force sync? + try { + const currentSize = sz(off); + if (currentSize > 0) { + log( + ` -> fsync: performing full read (${currentSize} bytes) on db id ${id}` + ); + const dummyBuffer = new Uint8Array(currentSize); + const bytesRead = readBytes( + id, + 0, + currentSize, + dummyBuffer + ); + log( + ` -> fsync: dummy full read complete, bytesRead=${bytesRead}` + ); + } else { + log( + ` -> fsync: skipping full read on empty db file id ${id}` + ); + } + } catch (readErr: any) { + log( + ` -> fsync: dummy full read failed for db id ${id}: ${readErr}` + ); + // Ignore dummy read errors + } + } else { + // Optional: Keep dummy single byte read for non-DB files? + // For simplicity, let's remove it for now. + /* + try { + if (sz(off) > 0) { + log(` -> fsync: performing dummy read on id ${id}`); + const dummyByte = new Uint8Array(1); + readBytes(id, 0, 1, dummyByte); + } else { + log(` -> fsync: skipping dummy read on empty file id ${id}`); + } + } catch (readErr: any) { + log(` -> fsync: dummy read failed for id ${id}: ${readErr}`); + // Ignore dummy read errors, fsync should still succeed + } + */ + } + } finally { + unlock(); + } + + return 0; + }, + flush() { + return 0; + }, + }; + + /* stream_ops */ + const stream_ops: any = { + open(s: any) { + // --- Initial setup before lock --- + const id = s.node.sabId; + const off = ioff(id); + const name = getName(off); // Read name early, might be slightly racy but ok for logic below + const isWriteIntent = s.flags & 0x302; // O_WRONLY, O_RDWR, O_TRUNC, etc + + log( + ` -> open: ${name} (id=${id}) with flags=${s.flags}, writeIntent=${isWriteIntent}` + ); + + // Check if inode is already deleted BEFORE locking + // If mode is 0, the file is gone. open should probably fail. + if (L(meta, off + I_MODE) === 0) { + log( + ` -> ERROR: open called on deleted inode ${id} ("${name}") mode=0` + ); + throw new FS.ErrnoError(9); // EBADF - Bad file descriptor + } + + // --- Main lock section --- + lock(); + try { + // Re-check mode after acquiring lock, in case of race condition + if (L(meta, off + I_MODE) === 0) { + log( + ` -> ERROR: inode ${id} ("${name}") deleted while waiting for lock in open` + ); + throw new FS.ErrnoError(9); // EBADF - Bad file descriptor + } + + // Handle O_TRUNC *after* acquiring lock + if (s.flags & 0x400 && FS.isFile(s.node.mode)) { + log(` -> open: truncating ${name} (id=${id})`); + node_ops.setattr( + s.node, + { size: 0 }, + true /* alreadyLocked */ + ); // Assuming setattr is adapted or safe + // TODO: Adapt setattr if needed, or simplify truncate logic here + // Quick fix for truncate: + setSize(off, 0); + setTimes(off, false, true, true); + } + s.position = s.flags & 0x800 ? sz(off) : 0; + + // Handle -shm file lookup/creation *inside* the lock + if (isSQLiteDbFile(name) && isWriteIntent) { + log( + ` -> open: SQLite database being opened for writing: ${name}` + ); + const shmName = name + '-shm'; + let shmNode = null; + const parentNode = s.node.parent; + + if (parentNode) { + // Ensure parentNode exists + log( + ` -> open: Looking for ${shmName} in parent directory ${parentNode.name}` + ); + try { + // Call lookup WITHOUT alreadyLocked flag now + shmNode = parentNode.node_ops.lookup( + parentNode, + shmName + ); + log(` -> open: Found existing ${shmName}`); + } catch (e: any) { + // ENOENT is expected if it doesn't exist + if ((e as any).errno !== 44 /* ENOENT */) { + log( + ` -> open: Error looking up ${shmName}: ${e}` + ); + } else { + log( + ` -> open: ${shmName} not found, attempting creation.` + ); + // Create the -shm file if lookup failed + try { + // Call mknod with alreadyLocked = true + shmNode = parentNode.node_ops.mknod( + parentNode, + shmName, + 0o100666, + 0, + true + ); + log( + ` -> open: Successfully created ${shmName}` + ); + + // Initialize it - does this need FS.open/write? + // FS.open calls stream_ops.open again -> deadlock risk if not careful + // Direct write is safer if possible. + // We have the node (shmNode), let's write directly using writeBytes + if (shmNode) { + log( + ` -> open: Initializing ${shmName} with header` + ); + } + } catch (createError: any) { + log( + ` -> open: Error creating ${shmName}: ${createError}` + ); + } + } + } + } else { + log( + ` -> open: Cannot handle SHM file for root node or node without parent.` + ); + } + + // Record SHM node if found/created + if (s.node.sqliteInfo && shmNode) { + s.node.sqliteInfo.shmNode = shmNode; + log( + ` -> open: Associated shmNode (id=${shmNode.sabId}) with dbNode (id=${id})` + ); + } + if (s.node.sqliteInfo) { + log( + ` -> open: Tracking write access to database ${name}` + ); + s.node.sqliteInfo.pendingWriters++; + } + } // End SHM handling + + // Increment open reference count + Atomics.add(meta, off + I_OPENREFS, 1); + log( + ` -> Incremented open refs for inode ${id} to ${L( + meta, + off + I_OPENREFS + )}` + ); + } finally { + unlock(); + } + }, + close(s: any) { + // Decrement the open reference count + lock(); + try { + const off = ioff(s.node.sabId); + // Check if inode still exists before proceeding + if (L(meta, off + I_MODE) === 0) { + log( + ` -> WARNING: close called on already deleted inode ${s.node.sabId}, ignoring ref count.` + ); + // Do nothing if mode is already 0 + return; + } + + const openRefs = Atomics.sub(meta, off + I_OPENREFS, 1); + const newRefs = openRefs - 1; + const nlink = L(meta, off + I_NLINK); + const name = getName(off); + + // Track SQLite database statistics (optional, keep for now) + if (s.node.sqliteInfo) { + if (isSQLiteDbFile(name)) { + log( + ` -> close: Cleaning up database tracking for ${name}` + ); + s.node.sqliteInfo.pendingWriters = Math.max( + 0, + s.node.sqliteInfo.pendingWriters - 1 + ); + s.node.sqliteInfo.version++; + } + } + + log( + ` -> Decremented open refs for inode ${s.node.sabId} to ${newRefs}, nlink=${nlink}` + ); + + // If the link count is 0 and this is the last open reference, + // decide whether to TRUNCATE (journal) or DELETE (normal). + if (newRefs === 0 && nlink === 0) { + const persist = L(meta, off + I_PERSIST); + if (persist === 1) { + // Journal file: Truncate instead of deleting mode + log( + ` -> Journal inode ${s.node.sabId} ("${name}") closed and unlinked. Truncating and clearing persist flag.` + ); + setSize(off, 0); // Truncate to zero bytes + setTimes(off, false, true, true); // Update times + S(meta, off + I_PERSIST, 0); // Clear flag so it deletes next time + } else { + // Normal file or already-truncated journal: Delete inode + log( + ` -> No more open refs and nlink=0, marking inode ${s.node.sabId} ("${name}") as fully deleted (mode=0)` + ); + S(meta, off + I_MODE, 0); // Set mode to 0 + S(meta, off + I_PERSIST, 0); // Ensure persist is 0 + } + } + } finally { + unlock(); + } + }, + read(s: any, buf: Uint8Array, off: number, len: number, pos: number) { + const p = pos ?? s.position, + tmp = new Uint8Array(len); + const r = readBytes(s.node.sabId, p, len, tmp); + buf.set(tmp.subarray(0, r), off); + if (pos === undefined) s.position += r; + return r; + }, + write(s: any, buf: Uint8Array, off: number, len: number, pos: number) { + const p = pos ?? s.position; + writeBytes(s.node.sabId, p, buf.subarray(off, off + len)); + if (pos === undefined) s.position += len; + + return len; + }, + llseek(s: any, ofs: number, wh: number) { + lock(); + try { + const size = sz(ioff(s.node.sabId)); // Read size under lock + let p: number; + if (wh === 0) { + // SEEK_SET + p = ofs; + } else if (wh === 1) { + // SEEK_CUR + p = s.position + ofs; + } else if (wh === 2) { + // SEEK_END + p = size + ofs; + } else { + throw new FS.ErrnoError(28); // EINVAL + } + + if (p < 0) throw new FS.ErrnoError(22); // EINVAL + s.position = p; + return p; + } finally { + unlock(); + } + }, + flush(s: any) { + log(`flush called for node id ${s.node.sabId}`); + const id = s.node.sabId; + const off = ioff(id); + + // Lock the metadata to ensure atomic updates + lock(); + try { + // Check if the node is valid + if (L(meta, off + I_MODE) === 0) { + // For flush, if the inode is invalid, we'll just log and succeed + // This is because SQLite may call flush on already-closed files + log( + ` -> WARNING: flush called on invalid inode ${id}, ignoring` + ); + return 0; + } + + // Update mtime to indicate data was modified + setTimes(off, false, true, false); + log(` -> flush completed for inode ${id}`); + return 0; + } finally { + unlock(); + } + }, + ioctl() { + throw new FS.ErrnoError(59); + }, + // Add dummy locking operations to potentially satisfy SQLite + fcntl(s: any, cmd: any, arg: any) { + log( + `[SABFS] fcntl called for node ${s.node.sabId}, cmd=${cmd}, arg=${arg} - returning 0 (success)` + ); + // Return 0 for success, assuming commands are related to locking (e.g., F_SETLK) + // A real implementation would need to inspect cmd/arg and simulate locks. + return 0; + }, + lock(s: any) { + log(`[SABFS] lock called for node ${s.node.sabId} - NO-OP`); + // No-op + }, + unlock(s: any) { + log(`[SABFS] unlock called for node ${s.node.sabId} - NO-OP`); + // No-op + }, + }; + + /* backend object for FS.mount */ + return { mount: (m: any) => mkNode(1, m, null) }; +} + +/* ─── helper to allocate buffers ─────────────────────────────────────────── */ +export const createBuffers = (metaBytes = 16 << 20, dataBytes = 128 << 20) => ({ + metaBuf: new SharedArrayBuffer(metaBytes), + dataBuf: new SharedArrayBuffer(dataBytes), +}); diff --git a/packages/playground/remote/src/lib/sab_node.ts b/packages/playground/remote/src/lib/sab_node.ts new file mode 100644 index 0000000000..78d84f6cca --- /dev/null +++ b/packages/playground/remote/src/lib/sab_node.ts @@ -0,0 +1,192 @@ +import { createSharedFSBuffers } from './shared-array-buffer-fs'; +import { consumeAPI, spawnPHPWorkerThread } from '@php-wasm/web'; +import { SharedFSBuffers } from './shared-array-buffer-fs'; +import { ExperimentalWorkerEndpoint } from './worker-thread-shared'; + +// @ts-ignore +export const experimentalSABFSWorkerUrl: string = + new URL('./worker-thread-shared-node.ts', import.meta.url) + ''; + +async function spawnSharedFSPhpWorker(sharedBuffers: SharedFSBuffers) { + console.log('[Node] Spawning PHP worker thread...'); + const experimentalPhpWorkerApi = await spawnPHPWorkerThread( + experimentalSABFSWorkerUrl + ); + console.log('[Node] Worker thread spawned, consuming API...'); + const phpWorkerApi = consumeAPI( + experimentalPhpWorkerApi + ); + console.log('[Node] Waiting for worker connection...'); + await phpWorkerApi.isConnected(); + console.log('[Node] Worker connected, booting worker...'); + await phpWorkerApi.boot({ + sharedBuffers, + }); + console.log('[Node] Worker booted, waiting for worker ready...'); + await phpWorkerApi.isReady(); + console.log('[Node] Worker ready.'); + return phpWorkerApi; +} + +async function main() { + const buffers = createSharedFSBuffers(); + console.log('[Node] Spawning worker 1...'); + const worker1 = await spawnSharedFSPhpWorker(buffers); + console.log('[Node] Worker 1 spawned and ready.'); + + console.log( + '[Node] Running Worker 1 Task (Create DB, Create Table, Insert Row)...' + ); + try { + const result = await worker1.run({ + code: `setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + echo "[PHP] Setting SQLite pragmas to MEMORY mode to fix journal issues\\n"; + // We can NEVER set 'PRAGMA journal_mode = MEMORY' or else + // the company will go bankrupt. NEVER EVER EVER! We MUST fix the ROOT CAUSE + // of the filesystem corruption. + // The problem IS NOT a race condition. The problem IS NOT related to + // threads or concurrency. The problem IS related to the filesystem and + // is happening the very first time we try to write to the database. + + + echo "[PHP] Beginning transaction...\\n"; + $pdo->beginTransaction(); + + echo "[PHP] Creating table users (if not exists)...\\n"; + $pdo->exec('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)'); + + // Verify the table was created + $tableCheck = $pdo->query("SELECT name FROM sqlite_master WHERE type='table' AND name='users'"); + $tableExists = $tableCheck->fetchColumn(); + if (!$tableExists) { + echo "[PHP] ERROR: Failed to create table: 'users'\\n"; + $pdo->exec('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)'); + echo "[PHP] Retrying table creation with direct SQL...\\n"; + } + + echo "[PHP] Committing transaction...\\n"; + $pdo->commit(); + + // Force database to flush changes by closing and reopening + echo "[PHP] Flushing database changes by closing and reopening connection...\\n"; + $pdo = null; // Close connection completely + + // Wait a bit to ensure filesystem operations are complete + usleep(50000); // 50ms + + // Reopen connection to verify table exists + $pdo = new PDO('sqlite:' . $dbPath); + $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + // Double check if table exists + $tableCheck = $pdo->query("SELECT name FROM sqlite_master WHERE type='table' AND name='users'"); + $tableExists = $tableCheck->fetchColumn(); + if (!$tableExists) { + echo "[PHP] ERROR: Table 'users' still missing after reopen!\\n"; + echo "[PHP] Creating table one more time...\\n"; + $pdo->exec('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)'); + } + $pdo->exec("INSERT INTO users (id, name) VALUES (1, 'John Doe')"); + + echo "[PHP] Table users created.\\n"; + // Show all tables in the database + echo "[PHP] Listing all tables in the database – EXPECTED TO SEE the 'users' table...\\n"; + $stmt = $pdo->query("SELECT name FROM sqlite_master WHERE type='table'"); + echo "[PHP] Tables in the database:\\n"; + $tables = []; + while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { + $tables[] = $row['name']; + } + if(in_array('users', $tables)) { + echo "[PHP] - " . implode(", ", $tables) . "\\n"; + } else { + echo "[PHP] - no tables found in the database.\\n"; + } + + echo "[PHP] Inserting user (id=1)...\\n"; + echo "[PHP] >>> PRE INSERT <<<<<<<<<<<<<<\\n"; + + // Run the insert in a transaction + $pdo->beginTransaction(); + $pdo->exec("INSERT INTO users (id, name) VALUES (2, 'John Doe')"); + $pdo->commit(); + + echo "[PHP] >>> POST INSERT (SUCCESS) <<<<<<<<<<<<<<\\n"; // This won't be reached on error + echo "[PHP] User (id=1) inserted successfully.\\n"; // This likely won't be reached on error + + // Verify the insert worked + echo "[PHP] Verifying user was inserted:\\n"; + $stmt = $pdo->query("SELECT * FROM users"); + while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { + echo "[PHP] User ID: " . $row['id'] . ", Name: " . $row['name'] . "\\n"; + } + } catch (PDOException $e) { + echo "[PHP] >>> POST INSERT (PDOException) <<<<<<<<<<<<<<\\n"; + echo "[PHP] ***** PDOException *****\\n"; + echo "[PHP] Message: " . $e->getMessage() . "\\n"; + echo "[PHP] Code: " . $e->getCode() . "\\n"; + echo "[PHP] File: " . $e->getFile() . ":" . $e->getLine() . "\\n"; + // echo "[PHP] Trace:\\n" . $e->getTraceAsString() . "\\n"; + echo "[PHP] **************************\\n"; + } + echo "[PHP] Worker 1 End\\n"; + ?>`, + }); + console.log('[Node] Worker 1 Raw Result:\n---\n' + result.text + '---'); + } catch (e) { + console.error('[Node] Worker 1 Execution Failed:', e); + } + + console.log('\n[Node] Spawning worker 2...'); + const worker2 = await spawnSharedFSPhpWorker(buffers); + console.log('[Node] Worker 2 spawned and ready.'); + console.log('\n[Node] Running Worker 2 Task (Read DB)...'); + try { + const result2 = await worker2.run({ + code: `setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + echo "[PHP] Querying users table...\\n"; + $stmt = $pdo->query("SELECT * FROM users"); + while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { + echo "[PHP] User ID: " . $row['id'] . ", Name: " . $row['name'] . "\\n"; + } + } catch (PDOException $e) { + echo "[PHP] >>> POST QUERY (PDOException) <<<<<<<<<<<<<<\\n"; + echo "[PHP] ***** PDOException *****\\n"; + echo "[PHP] Message: " . $e->getMessage() . "\\n"; + echo "[PHP] Code: " . $e->getCode() . "\\n"; + echo "[PHP] File: " . $e->getFile() . ":" . $e->getLine() . "\\n"; + echo "[PHP] **************************\\n"; + } + echo "[PHP] Worker 2 End\\n"; + ?>`, + }); + console.log( + '[Node] Worker 2 Raw Result:\n---\n' + result2.text + '---' + ); + } catch (e) { + console.error('[Node] Worker 2 failed:', e); + } + + console.log('\n[Node] Test finished.'); + process.exit(0); // Explicitly exit the process +} + +main().catch(console.error); diff --git a/packages/playground/remote/src/lib/sab_node_wp.ts b/packages/playground/remote/src/lib/sab_node_wp.ts new file mode 100644 index 0000000000..a2155c0102 --- /dev/null +++ b/packages/playground/remote/src/lib/sab_node_wp.ts @@ -0,0 +1,212 @@ +import { + createSharedFSBuffers, + sharedArrayBufferMount, +} from './shared-array-buffer-fs'; +import { consumeAPI, spawnPHPWorkerThread } from '@php-wasm/web'; +import type { ExperimentalWorkerEndpoint } from './worker-thread-shared-node'; +import { getWordPressModule } from '@wp-playground/wordpress-builds'; +import { bootWordPress } from '@wp-playground/wordpress'; +import { RecommendedPHPVersion } from '@wp-playground/common'; +import { loadNodeRuntime } from '@php-wasm/node'; +import { getSqliteDatabaseModule } from '@wp-playground/wordpress-builds'; + +const DEBUG = true; +const log = (...a: any[]) => DEBUG && console.log('[SABFS]', ...a); + +/** + * Boot WordPress once in this worker thread so child + * workers can reuse it. It's simple and should speed up + * the boot process of each child worker. + */ +const wpBuffers = createSharedFSBuffers(); +const internalSharedBuffers = createSharedFSBuffers(); + +log('[MAIN] Booting WordPress'); + +let firstTime = true; + +/** + * We don't store the result in a variable because we don't need it. + * All we want are SharedArrayBuffers populated with WordPress files. + */ +const requestHandler = await bootWordPress({ + createPhpRuntime: async () => await loadNodeRuntime(RecommendedPHPVersion), + siteUrl: 'http://playground-domain/', + + wordPressZip: await getWordPressModule(), + sqliteIntegrationPluginZip: await getSqliteDatabaseModule(), + hooks: { + /** + * A hook I added temporarily for the sake of explorations. + * I'm not sure if I want to keep it yet. Let's discuss. + */ + afterPhpInstanceCreated: async (php, { isPrimary }) => { + if (!isPrimary) { + return; + } + if (!firstTime) { + return; + } + // This hook will be called every time a new PHP instance is created. + // We only want to the mount once. + firstTime = false; + log('[MAIN] Mounting shared array buffers'); + php.mv('/internal/shared', '/internal/shared-old'); + php.mkdir('/internal/shared'); + + await php.mount( + '/internal/shared', + sharedArrayBufferMount(internalSharedBuffers) + ); + php.copyRecursive('/internal/shared-old', '/internal/shared'); + php.rmdir('/internal/shared-old', { recursive: true }); + + php.mkdir('/wordpress'); + await php.mount('/wordpress', sharedArrayBufferMount(wpBuffers)); + log('[MAIN] Mounted shared array buffers'); + }, + }, +}); + +log('[MAIN] Booted WordPress'); +const response = await requestHandler.request({ + url: '/', + method: 'GET', + body: '', + headers: {}, +}); +const titleMatch = response.text.match(/(.*?)<\/title>/i); +if (titleMatch && titleMatch[1]) { + console.log('Extracted Title:', titleMatch[1]); +} else { + console.log('Could not extract title from response.'); + // Optionally log the full text if title extraction fails + // console.log(response.text); +} + +// @ts-ignore +export const experimentalSABFSWorkerUrl: string = + new URL('./worker-thread-shared-node.ts', import.meta.url) + ''; + +let workerNb = 1; +async function spawnSharedFSPhpWorker() { + log(`[MAIN] Spawning worker ${workerNb}...`); + const experimentalPhpWorkerApi = await spawnPHPWorkerThread( + experimentalSABFSWorkerUrl + ); + const phpWorkerApi = consumeAPI<ExperimentalWorkerEndpoint>( + experimentalPhpWorkerApi + ); + await phpWorkerApi.isConnected(); + await phpWorkerApi.bootWordPress({ + sharedMounts: { + '/wordpress': wpBuffers, + '/internal/shared': internalSharedBuffers, + }, + }); + await phpWorkerApi.isReady(); + log(`[MAIN] Worker ${workerNb} booted`); + workerNb++; + return phpWorkerApi; +} + +async function main() { + const worker1 = await spawnSharedFSPhpWorker(); + const worker2 = await spawnSharedFSPhpWorker(); + + // Print all the posts in the database + const result = await worker1.run({ + code: `<?php +require_once '/wordpress/wp-load.php'; + +error_reporting(E_ALL); +ini_set('display_errors', 1); + +echo "[PHP] Getting post titles...\\n"; + +$all_posts = $wpdb->get_results( "SELECT ID, post_title FROM {$wpdb->posts} ORDER BY ID ASC" ); + +if ( ! empty( $all_posts ) ) { + echo "[PHP] Found " . count($all_posts) . " posts:\\n"; + foreach ( $all_posts as $single_post ) { + // Use htmlspecialchars to prevent potential XSS if titles contain HTML/JS + echo "[PHP] - ID: " . $single_post->ID . ", Title: " . htmlspecialchars($single_post->post_title) . "\\n"; + } +} else { + echo "[PHP] No posts found.\\n"; +} + +echo "[PHP] Finished getting post titles.\\n"; +?>`, + }); + console.log(result.text); + + console.log('\n[MAIN] Worker 1: Inserting a new post...'); + const insertResult = await worker1.run({ + code: `<?php +require_once '/wordpress/wp-load.php'; + +error_reporting(E_ALL); +ini_set('display_errors', 1); + +echo "[PHP] Inserting a new post...\\n"; + +$post_id = wp_insert_post(array( + 'post_title' => 'My New Post from Worker 1', + 'post_content' => 'This is the content of the new post created via PHP.', + 'post_status' => 'publish', + 'post_author' => 1, + 'post_type' => 'post' +)); + +if ( is_wp_error( $post_id ) ) { + echo "[PHP] Error inserting post: " . $post_id->get_error_message() . "\\n"; +} else { + echo "[PHP] Successfully inserted post with ID: " . $post_id . "\\n"; +} +`, + }); + console.log(insertResult.text); + + // Verify the post was inserted by listing posts again in worker 2 + console.log( + '\n[MAIN] Worker 2: Listing posts again to verify insertion...' + ); + const verifyResult = await worker2.run({ + code: `<?php +require_once '/wordpress/wp-load.php'; + +error_reporting(E_ALL); +ini_set('display_errors', 1); + +echo "[PHP] Getting post titles again...\\n"; +global $wpdb; + +$all_posts = $wpdb->get_results( "SELECT ID, post_title FROM {$wpdb->posts} ORDER BY ID ASC" ); + +if ( ! empty( $all_posts ) ) { + echo "[PHP] Found " . count($all_posts) . " posts:\\n"; + foreach ( $all_posts as $single_post ) { + // Use htmlspecialchars to prevent potential XSS if titles contain HTML/JS + echo "[PHP] - ID: " . $single_post->ID . ", Title: " . htmlspecialchars($single_post->post_title) . "\\n"; + } +} else { + echo "[PHP] No posts found.\\n"; +} + +echo "[PHP] Finished getting post titles again.\\n"; +?>`, + }); + console.log(verifyResult.text); + + // console.log('[Node] Worker 2 spawned and ready.'); + + // console.log( + // '[Node] Running Worker 1 Task (Create DB, Create Table, Insert Row)...' + // ); + + // console.log('\n[Node] Test finished.'); + process.exit(0); // Explicitly exit the process +} + +main().catch(console.trace); diff --git a/packages/playground/remote/src/lib/shared-array-buffer-fs.ts b/packages/playground/remote/src/lib/shared-array-buffer-fs.ts new file mode 100644 index 0000000000..d5868e9095 --- /dev/null +++ b/packages/playground/remote/src/lib/shared-array-buffer-fs.ts @@ -0,0 +1,26 @@ +import { PHP } from '@php-wasm/universal'; +import { SharedSABFS } from './sab'; + +// ───────────────── convenience helper ───────────────── +export type SharedFSBuffers = { + metaBuf: SharedArrayBuffer; + dataBuf: SharedArrayBuffer; +}; +export const createSharedFSBuffers = ( + metaBytes = 16 << 20, + dataBytes = 128 << 20 +): SharedFSBuffers => ({ + metaBuf: new SharedArrayBuffer(metaBytes), + dataBuf: new SharedArrayBuffer(dataBytes), +}); + +export function sharedArrayBufferMount(buffers: SharedFSBuffers) { + return async function (php: PHP, FS: any, vfsMountPoint: string) { + const sabfs = SharedSABFS(FS, buffers.metaBuf, buffers.dataBuf); + FS.mount(sabfs, {}, vfsMountPoint); + + return () => { + FS!.unmount(vfsMountPoint); + }; + }; +} diff --git a/packages/playground/remote/src/lib/worker-thread-shared-node.ts b/packages/playground/remote/src/lib/worker-thread-shared-node.ts new file mode 100644 index 0000000000..00b34e289a --- /dev/null +++ b/packages/playground/remote/src/lib/worker-thread-shared-node.ts @@ -0,0 +1,124 @@ +import { PHP, PHPWorker, loadPHPRuntime } from '@php-wasm/universal'; +import { getPHPLoaderModule, loadNodeRuntime } from '@php-wasm/node'; +import { exposeAPI } from '@php-wasm/web'; +import { + sharedArrayBufferMount, + SharedFSBuffers, +} from './shared-array-buffer-fs'; +import { + getSqliteDatabaseModule, + getWordPressModule, +} from '@wp-playground/wordpress-builds'; +import { bootWordPress } from '@wp-playground/wordpress'; +import { RecommendedPHPVersion } from '@wp-playground/common'; + +interface BootOptions { + sharedBuffers: SharedFSBuffers; +} + +let bufs: SharedFSBuffers | null = null; + +export class ExperimentalWorkerEndpoint extends PHPWorker { + booted = false; + + async boot(options: BootOptions) { + const php = new PHP( + await loadPHPRuntime(await getPHPLoaderModule('8.0')) + ); + php.mkdir('/experimental-sabfs'); + php.mount( + '/experimental-sabfs', + sharedArrayBufferMount(options.sharedBuffers) + ); + bufs = options.sharedBuffers; + this.setPrimaryPHP(php); + setApiReady(); + } + + async bootWordPress(options: { + sharedMounts: Record<string, SharedFSBuffers>; + }) { + const php = new PHP( + await loadPHPRuntime(await getPHPLoaderModule('8.0')) + ); + for (const [mountPoint, sharedBuffers] of Object.entries( + options.sharedMounts + )) { + php.mkdir(mountPoint); + php.mount(mountPoint, sharedArrayBufferMount(sharedBuffers)); + } + this.setPrimaryPHP(php); + setApiReady(); + } + + async logHeader(tag: string) { + const hdr = new Int32Array(bufs!.metaBuf, 0, 8); // first 8 words are enough + /* fields we care about: + 0: lock (should be 0 most of the time) + 1: MAGIC (0x53414653 = “SAFS”) + 2: NEXT_INODE (== 2 before any file is created, == 3 after your test.txt) + 3: NEXT_DATA (advances as you write file contents) */ + console.log( + `[SABFS‑DEBUG] ${tag}`, + 'MAGIC=', + hdr[1].toString(16), + 'NEXT_INODE=', + hdr[2], + 'NEXT_DATA=', + hdr[3] + ); + } + + async logDirState(tag: string) { + const meta32 = new Int32Array(bufs!.metaBuf); + const I_SIZEL = 4, + I_DATA_OFF = 7; // offsets inside every inode + const HEADER_WORDS = 256; // inode‑table starts here + + // inode 1 starts at HEADER_WORDS + const base = HEADER_WORDS + 1 * (16 + 32); // 16+32 = 48 words per inode + const count = meta32[base + I_SIZEL]; + const dataOff = meta32[base + I_DATA_OFF]; + + console.log( + `[SABFS‑DEBUG] ${tag}`, + 'dirCount=', + count, + 'dataOff=', + dataOff + ); + } + dumpDir(tag: string) { + const meta32 = new Int32Array(bufs!.metaBuf); + const HEADER_WORDS = 256; + const INODE_WORDS = 48; // as defined + const I_SIZEL = 4, + I_DATA_OFF = 7; + + const base = HEADER_WORDS + 1 * INODE_WORDS; // inode 1 + const cnt = meta32[base + I_SIZEL]; + const data = meta32[base + I_DATA_OFF]; + + console.log(`[SABFS‑DEBUG] ${tag} dirCount=${cnt}`); + const vec = new Int32Array(bufs!.metaBuf, data, cnt); + for (let i = 0; i < cnt; i++) { + const id = vec[i]; + const off = HEADER_WORDS + (id - 1) * INODE_WORDS; + const nameBytes = new Uint8Array( + bufs!.metaBuf, + (off + 16) * 4, + 128 + ); // I_NAME field + const nul = nameBytes.indexOf(0); + const name = new TextDecoder().decode( + new Uint8Array(nameBytes.slice(0, nul < 0 ? 128 : nul)) + ); + console.log(' child', i, 'id', id, 'name', JSON.stringify(name)); + } + } +} + +// post message to parent +self.postMessage('worker-script-started'); + +const [setApiReady, setAPIError] = exposeAPI(new ExperimentalWorkerEndpoint()); diff --git a/packages/playground/remote/src/lib/worker-thread-shared.ts b/packages/playground/remote/src/lib/worker-thread-shared.ts new file mode 100644 index 0000000000..5a970d6c9a --- /dev/null +++ b/packages/playground/remote/src/lib/worker-thread-shared.ts @@ -0,0 +1,101 @@ +import { PHP, PHPWorker, loadPHPRuntime } from '@php-wasm/universal'; +import { exposeAPI, getPHPLoaderModule } from '@php-wasm/web'; +import { + sharedArrayBufferMount, + SharedFSBuffers, +} from './shared-array-buffer-fs'; + +interface BootOptions { + sharedBuffers: SharedFSBuffers; +} + +let bufs: SharedFSBuffers | null = null; + +export class ExperimentalWorkerEndpoint extends PHPWorker { + booted = false; + + async boot(options: BootOptions) { + const php = new PHP( + await loadPHPRuntime(await getPHPLoaderModule('8.0')) + ); + php.mkdir('/experimental-sabfs'); + php.mount( + '/experimental-sabfs', + sharedArrayBufferMount(options.sharedBuffers) + ); + bufs = options.sharedBuffers; + this.setPrimaryPHP(php); + setApiReady(); + } + + async logHeader(tag: string) { + const hdr = new Int32Array(bufs!.metaBuf, 0, 8); // first 8 words are enough + /* fields we care about: + 0: lock (should be 0 most of the time) + 1: MAGIC (0x53414653 = “SAFS”) + 2: NEXT_INODE (== 2 before any file is created, == 3 after your test.txt) + 3: NEXT_DATA (advances as you write file contents) */ + console.log( + `[SABFS‑DEBUG] ${tag}`, + 'MAGIC=', + hdr[1].toString(16), + 'NEXT_INODE=', + hdr[2], + 'NEXT_DATA=', + hdr[3] + ); + } + + async logDirState(tag: string) { + const meta32 = new Int32Array(bufs!.metaBuf); + const I_SIZEL = 4, + I_DATA_OFF = 7; // offsets inside every inode + const HEADER_WORDS = 256; // inode‑table starts here + + // inode 1 starts at HEADER_WORDS + const base = HEADER_WORDS + 1 * (16 + 32); // 16+32 = 48 words per inode + const count = meta32[base + I_SIZEL]; + const dataOff = meta32[base + I_DATA_OFF]; + + console.log( + `[SABFS‑DEBUG] ${tag}`, + 'dirCount=', + count, + 'dataOff=', + dataOff + ); + } + dumpDir(tag: string) { + const meta32 = new Int32Array(bufs!.metaBuf); + const HEADER_WORDS = 256; + const INODE_WORDS = 48; // as defined + const I_SIZEL = 4, + I_DATA_OFF = 7; + + const base = HEADER_WORDS + 1 * INODE_WORDS; // inode 1 + const cnt = meta32[base + I_SIZEL]; + const data = meta32[base + I_DATA_OFF]; + + console.log(`[SABFS‑DEBUG] ${tag} dirCount=${cnt}`); + const vec = new Int32Array(bufs!.metaBuf, data, cnt); + for (let i = 0; i < cnt; i++) { + const id = vec[i]; + const off = HEADER_WORDS + (id - 1) * INODE_WORDS; + const nameBytes = new Uint8Array( + bufs!.metaBuf, + (off + 16) * 4, + 128 + ); // I_NAME field + const nul = nameBytes.indexOf(0); + const name = new TextDecoder().decode( + new Uint8Array(nameBytes.slice(0, nul < 0 ? 128 : nul)) + ); + console.log(' child', i, 'id', id, 'name', JSON.stringify(name)); + } + } +} + +// post message to parent +self.postMessage('worker-script-started'); + +const [setApiReady, setAPIError] = exposeAPI(new ExperimentalWorkerEndpoint()); diff --git a/packages/playground/remote/vite.config.ts b/packages/playground/remote/vite.config.ts index 815181e7ae..9ddf999465 100644 --- a/packages/playground/remote/vite.config.ts +++ b/packages/playground/remote/vite.config.ts @@ -65,6 +65,10 @@ export default defineConfig({ // Allow serving files from the 'packages' directory allow: ['../../'], }, + headers: { + 'Cross-Origin-Opener-Policy': 'same-origin', + 'Cross-Origin-Embedder-Policy': 'credentialless', + }, }, plugins, diff --git a/packages/playground/website/vite.config.ts b/packages/playground/website/vite.config.ts index 253f1fbb39..44ef4ee60a 100644 --- a/packages/playground/website/vite.config.ts +++ b/packages/playground/website/vite.config.ts @@ -74,6 +74,10 @@ export default defineConfig(({ command, mode }) => { fs: { strict: false, // Serve files from the other project directories. }, + headers: { + 'Cross-Origin-Opener-Policy': 'same-origin', + 'Cross-Origin-Embedder-Policy': 'credentialless', + }, }, plugins: [ react({ diff --git a/packages/playground/wordpress/src/boot.ts b/packages/playground/wordpress/src/boot.ts index 84da4ac372..be639be6f9 100644 --- a/packages/playground/wordpress/src/boot.ts +++ b/packages/playground/wordpress/src/boot.ts @@ -26,6 +26,18 @@ import { logger } from '@php-wasm/logger'; export type PhpIniOptions = Record<string, string>; export type Hook = (php: PHP) => void | Promise<void>; export interface Hooks { + /** + * Runs immediately after the PHP instance is created. + * + * This hook is called: + * + * * For every PHP instance, including the primary one. + * * Every time a PHP instance is rotated. + */ + afterPhpInstanceCreated?: ( + php: PHP, + { isPrimary }: { isPrimary: boolean } + ) => void | Promise<void>; beforeWordPressFiles?: Hook; beforeDatabaseSetup?: Hook; } @@ -79,7 +91,7 @@ export interface BootOptions { * { * createFiles: { * '/tmp/hello.txt': 'Hello, World!', - * '/internal/preload': { + * '/internal/shared/preload': { * '1-custom-mu-plugin.php': '<?php echo "Hello, World!";', * } * } @@ -133,6 +145,9 @@ export async function bootWordPress(options: BootOptions) { isPrimary: boolean ) { const php = new PHP(await options.createPhpRuntime()); + if (options.hooks?.afterPhpInstanceCreated) { + await options.hooks.afterPhpInstanceCreated(php, { isPrimary }); + } if (options.sapiName) { php.setSapiName(options.sapiName); } @@ -204,7 +219,6 @@ export async function bootWordPress(options: BootOptions) { if (options.hooks?.beforeWordPressFiles) { await options.hooks.beforeWordPressFiles(php); } - if (options.wordPressZip) { await unzipWordPress(php, await options.wordPressZip); }