@php-wasm/node 1.1.3 → 1.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/asyncify/7_2_34/php_7_2.wasm +0 -0
  2. package/asyncify/7_3_33/php_7_3.wasm +0 -0
  3. package/asyncify/7_4_33/php_7_4.wasm +0 -0
  4. package/asyncify/8_0_30/php_8_0.wasm +0 -0
  5. package/asyncify/8_1_23/php_8_1.wasm +0 -0
  6. package/asyncify/8_2_10/php_8_2.wasm +0 -0
  7. package/asyncify/8_3_0/php_8_3.wasm +0 -0
  8. package/asyncify/8_4_0/php_8_4.wasm +0 -0
  9. package/asyncify/php_7_2.js +178 -138
  10. package/asyncify/php_7_3.js +177 -137
  11. package/asyncify/php_7_4.js +176 -136
  12. package/asyncify/php_8_0.js +180 -140
  13. package/asyncify/php_8_1.js +179 -139
  14. package/asyncify/php_8_2.js +180 -140
  15. package/asyncify/php_8_3.js +180 -140
  16. package/asyncify/php_8_4.js +179 -139
  17. package/fs_ext.node +0 -0
  18. package/index.cjs +9170 -3617
  19. package/index.js +9054 -3617
  20. package/jspi/7_2_34/php_7_2.wasm +0 -0
  21. package/jspi/7_3_33/php_7_3.wasm +0 -0
  22. package/jspi/7_4_33/php_7_4.wasm +0 -0
  23. package/jspi/8_0_30/php_8_0.wasm +0 -0
  24. package/jspi/8_1_23/php_8_1.wasm +0 -0
  25. package/jspi/8_2_10/php_8_2.wasm +0 -0
  26. package/jspi/8_3_0/php_8_3.wasm +0 -0
  27. package/jspi/8_4_0/php_8_4.wasm +0 -0
  28. package/jspi/php_7_2.js +1922 -1286
  29. package/jspi/php_7_3.js +1922 -1286
  30. package/jspi/php_7_4.js +9262 -7705
  31. package/jspi/php_8_0.js +1922 -1286
  32. package/jspi/php_8_1.js +2434 -1798
  33. package/jspi/php_8_2.js +2414 -1778
  34. package/jspi/php_8_3.js +2414 -1778
  35. package/jspi/php_8_4.js +2414 -1778
  36. package/lib/file-lock-manager-for-node.d.ts +149 -0
  37. package/lib/file-lock-manager.d.ts +96 -0
  38. package/lib/index.d.ts +2 -0
  39. package/lib/load-runtime.d.ts +31 -2
  40. package/package.json +10 -9
package/jspi/php_8_1.js CHANGED
@@ -8,7 +8,7 @@ import path from 'path';
8
8
 
9
9
  const dependencyFilename = path.join(__dirname, '8_1_23', 'php_8_1.wasm');
10
10
  export { dependencyFilename };
11
- export const dependenciesTotalSize = 17183362;
11
+ export const dependenciesTotalSize = 17185468;
12
12
  export function init(RuntimeName, PHPLoader) {
13
13
  // The rest of the code comes from the built php.js file and esm-suffix.js
14
14
  // include: shell.js
@@ -5227,734 +5227,850 @@ export function init(RuntimeName, PHPLoader) {
5227
5227
 
5228
5228
  var syscallGetVarargP = syscallGetVarargI;
5229
5229
 
5230
- function ___syscall_fcntl64(fd, cmd, varargs) {
5231
- SYSCALLS.varargs = varargs;
5232
- try {
5233
- var stream = SYSCALLS.getStreamFromFD(fd);
5234
- switch (cmd) {
5235
- case 0: {
5236
- var arg = syscallGetVarargI();
5237
- if (arg < 0) {
5238
- return -28;
5239
- }
5240
- while (FS.streams[arg]) {
5241
- arg++;
5242
- }
5243
- var newStream;
5244
- newStream = FS.dupStream(stream, arg);
5245
- return newStream.fd;
5246
- }
5247
-
5248
- case 1:
5249
- case 2:
5250
- return 0;
5251
-
5252
- // FD_CLOEXEC makes no sense for a single process.
5253
- case 3:
5254
- return stream.flags;
5255
-
5256
- case 4: {
5257
- var arg = syscallGetVarargI();
5258
- stream.flags |= arg;
5259
- return 0;
5260
- }
5261
-
5262
- case 12: {
5263
- var arg = syscallGetVarargP();
5264
- var offset = 0;
5265
- // We're always unlocked.
5266
- HEAP16[(arg + offset) >> 1] = 2;
5267
- return 0;
5268
- }
5269
-
5270
- case 13:
5271
- case 14:
5272
- // Pretend that the locking is successful. These are process-level locks,
5273
- // and Emscripten programs are a single process. If we supported linking a
5274
- // filesystem between programs, we'd need to do more here.
5275
- // See https://github.com/emscripten-core/emscripten/issues/23697
5276
- return 0;
5277
- }
5278
- return -28;
5279
- } catch (e) {
5280
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5281
- return -e.errno;
5282
- }
5283
- }
5284
-
5285
- function ___syscall_fdatasync(fd) {
5286
- try {
5287
- var stream = SYSCALLS.getStreamFromFD(fd);
5288
- return 0;
5289
- } catch (e) {
5290
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5291
- return -e.errno;
5292
- }
5293
- }
5294
-
5295
- function ___syscall_fstat64(fd, buf) {
5296
- try {
5297
- return SYSCALLS.writeStat(buf, FS.fstat(fd));
5298
- } catch (e) {
5299
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5300
- return -e.errno;
5301
- }
5302
- }
5303
-
5304
- function ___syscall_ftruncate64(fd, length) {
5305
- length = bigintToI53Checked(length);
5306
- try {
5307
- if (isNaN(length)) return 61;
5308
- FS.ftruncate(fd, length);
5309
- return 0;
5310
- } catch (e) {
5311
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5312
- return -e.errno;
5313
- }
5314
- }
5315
-
5316
5230
  var stringToUTF8 = (str, outPtr, maxBytesToWrite) =>
5317
5231
  stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite);
5318
5232
 
5319
5233
  Module['stringToUTF8'] = stringToUTF8;
5320
5234
 
5321
- function ___syscall_getcwd(buf, size) {
5322
- try {
5323
- if (size === 0) return -28;
5324
- var cwd = FS.cwd();
5325
- var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1;
5326
- if (size < cwdLengthInBytes) return -68;
5327
- stringToUTF8(cwd, buf, size);
5328
- return cwdLengthInBytes;
5329
- } catch (e) {
5330
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5331
- return -e.errno;
5332
- }
5333
- }
5334
-
5335
- function ___syscall_getdents64(fd, dirp, count) {
5336
- try {
5337
- var stream = SYSCALLS.getStreamFromFD(fd);
5338
- stream.getdents ||= FS.readdir(stream.path);
5339
- var struct_size = 280;
5340
- var pos = 0;
5341
- var off = FS.llseek(stream, 0, 1);
5342
- var startIdx = Math.floor(off / struct_size);
5343
- var endIdx = Math.min(
5344
- stream.getdents.length,
5345
- startIdx + Math.floor(count / struct_size)
5346
- );
5347
- for (var idx = startIdx; idx < endIdx; idx++) {
5348
- var id;
5349
- var type;
5350
- var name = stream.getdents[idx];
5351
- if (name === '.') {
5352
- id = stream.node.id;
5353
- type = 4;
5354
- } else if (name === '..') {
5355
- var lookup = FS.lookupPath(stream.path, {
5356
- parent: true,
5357
- });
5358
- id = lookup.node.id;
5359
- type = 4;
5360
- } else {
5361
- var child;
5362
- try {
5363
- child = FS.lookupNode(stream.node, name);
5364
- } catch (e) {
5365
- // If the entry is not a directory, file, or symlink, nodefs
5366
- // lookupNode will raise EINVAL. Skip these and continue.
5367
- if (e?.errno === 28) {
5368
- continue;
5369
- }
5370
- throw e;
5371
- }
5372
- id = child.id;
5373
- type = FS.isChrdev(child.mode)
5374
- ? 2 // DT_CHR, character device.
5375
- : FS.isDir(child.mode)
5376
- ? 4 // DT_DIR, directory.
5377
- : FS.isLink(child.mode)
5378
- ? 10 // DT_LNK, symbolic link.
5379
- : 8;
5380
- }
5381
- HEAP64[(dirp + pos) >> 3] = BigInt(id);
5382
- HEAP64[(dirp + pos + 8) >> 3] = BigInt((idx + 1) * struct_size);
5383
- HEAP16[(dirp + pos + 16) >> 1] = 280;
5384
- HEAP8[dirp + pos + 18] = type;
5385
- stringToUTF8(name, dirp + pos + 19, 256);
5386
- pos += struct_size;
5387
- }
5388
- FS.llseek(stream, idx * struct_size, 0);
5389
- return pos;
5390
- } catch (e) {
5391
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5392
- return -e.errno;
5393
- }
5394
- }
5395
-
5396
- function ___syscall_getpeername(fd, addr, addrlen, d1, d2, d3) {
5397
- try {
5398
- var sock = getSocketFromFD(fd);
5399
- if (!sock.daddr) {
5400
- return -53;
5401
- }
5402
- var errno = writeSockaddr(
5403
- addr,
5404
- sock.family,
5405
- DNS.lookup_name(sock.daddr),
5406
- sock.dport,
5407
- addrlen
5408
- );
5409
- return 0;
5410
- } catch (e) {
5411
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5412
- return -e.errno;
5413
- }
5414
- }
5415
-
5416
- function ___syscall_getsockname(fd, addr, addrlen, d1, d2, d3) {
5417
- try {
5418
- var sock = getSocketFromFD(fd);
5419
- // TODO: sock.saddr should never be undefined, see TODO in websocket_sock_ops.getname
5420
- var errno = writeSockaddr(
5421
- addr,
5422
- sock.family,
5423
- DNS.lookup_name(sock.saddr || '0.0.0.0'),
5424
- sock.sport,
5425
- addrlen
5426
- );
5427
- return 0;
5428
- } catch (e) {
5429
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5430
- return -e.errno;
5431
- }
5432
- }
5433
-
5434
- function ___syscall_getsockopt(fd, level, optname, optval, optlen, d1) {
5435
- try {
5436
- var sock = getSocketFromFD(fd);
5437
- // Minimal getsockopt aimed at resolving https://github.com/emscripten-core/emscripten/issues/2211
5438
- // so only supports SOL_SOCKET with SO_ERROR.
5439
- if (level === 1) {
5440
- if (optname === 4) {
5441
- HEAP32[optval >> 2] = sock.error;
5442
- HEAP32[optlen >> 2] = 4;
5443
- sock.error = null;
5444
- // Clear the error (The SO_ERROR option obtains and then clears this field).
5445
- return 0;
5446
- }
5447
- }
5448
- return -50;
5449
- } catch (e) {
5450
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5451
- return -e.errno;
5452
- }
5453
- }
5235
+ var stackAlloc = (sz) => __emscripten_stack_alloc(sz);
5454
5236
 
5455
- function ___syscall_ioctl(fd, op, varargs) {
5456
- SYSCALLS.varargs = varargs;
5457
- try {
5458
- var stream = SYSCALLS.getStreamFromFD(fd);
5459
- switch (op) {
5460
- case 21509: {
5461
- if (!stream.tty) return -59;
5462
- return 0;
5463
- }
5237
+ /** @suppress {duplicate } */ var stringToUTF8OnStack = (str) => {
5238
+ var size = lengthBytesUTF8(str) + 1;
5239
+ var ret = stackAlloc(size);
5240
+ stringToUTF8(str, ret, size);
5241
+ return ret;
5242
+ };
5464
5243
 
5465
- case 21505: {
5466
- if (!stream.tty) return -59;
5467
- if (stream.tty.ops.ioctl_tcgets) {
5468
- var termios = stream.tty.ops.ioctl_tcgets(stream);
5469
- var argp = syscallGetVarargP();
5470
- HEAP32[argp >> 2] = termios.c_iflag || 0;
5471
- HEAP32[(argp + 4) >> 2] = termios.c_oflag || 0;
5472
- HEAP32[(argp + 8) >> 2] = termios.c_cflag || 0;
5473
- HEAP32[(argp + 12) >> 2] = termios.c_lflag || 0;
5474
- for (var i = 0; i < 32; i++) {
5475
- HEAP8[argp + i + 17] = termios.c_cc[i] || 0;
5476
- }
5477
- return 0;
5478
- }
5479
- return 0;
5480
- }
5244
+ var allocateUTF8OnStack = stringToUTF8OnStack;
5481
5245
 
5482
- case 21510:
5483
- case 21511:
5484
- case 21512: {
5485
- if (!stream.tty) return -59;
5486
- return 0;
5487
- }
5488
-
5489
- case 21506:
5490
- case 21507:
5491
- case 21508: {
5492
- if (!stream.tty) return -59;
5493
- if (stream.tty.ops.ioctl_tcsets) {
5494
- var argp = syscallGetVarargP();
5495
- var c_iflag = HEAP32[argp >> 2];
5496
- var c_oflag = HEAP32[(argp + 4) >> 2];
5497
- var c_cflag = HEAP32[(argp + 8) >> 2];
5498
- var c_lflag = HEAP32[(argp + 12) >> 2];
5499
- var c_cc = [];
5500
- for (var i = 0; i < 32; i++) {
5501
- c_cc.push(HEAP8[argp + i + 17]);
5246
+ var PHPWASM = {
5247
+ init: function () {
5248
+ // The /internal directory is required by the C module. It's where the
5249
+ // stdout, stderr, and headers information are written for the JavaScript
5250
+ // code to read later on.
5251
+ FS.mkdir('/internal');
5252
+ // The files from the shared directory are shared between all the
5253
+ // PHP processes managed by PHPProcessManager.
5254
+ FS.mkdir('/internal/shared');
5255
+ // The files from the preload directory are preloaded using the
5256
+ // auto_prepend_file php.ini directive.
5257
+ FS.mkdir('/internal/shared/preload');
5258
+ // Create stdout and stderr devices. We can't just use Emscripten's
5259
+ // default stdout and stderr devices because they stop processing data
5260
+ // on the first null byte. However, when dealing with binary data,
5261
+ // null bytes are valid and common.
5262
+ FS.registerDevice(FS.makedev(64, 0), {
5263
+ open: () => {},
5264
+ close: () => {},
5265
+ read: () => 0,
5266
+ write: (stream, buffer, offset, length, pos) => {
5267
+ const chunk = buffer.subarray(offset, offset + length);
5268
+ PHPWASM.onStdout(chunk);
5269
+ return length;
5270
+ },
5271
+ });
5272
+ FS.mkdev('/internal/stdout', FS.makedev(64, 0));
5273
+ FS.registerDevice(FS.makedev(63, 0), {
5274
+ open: () => {},
5275
+ close: () => {},
5276
+ read: () => 0,
5277
+ write: (stream, buffer, offset, length, pos) => {
5278
+ const chunk = buffer.subarray(offset, offset + length);
5279
+ PHPWASM.onStderr(chunk);
5280
+ return length;
5281
+ },
5282
+ });
5283
+ FS.mkdev('/internal/stderr', FS.makedev(63, 0));
5284
+ FS.registerDevice(FS.makedev(62, 0), {
5285
+ open: () => {},
5286
+ close: () => {},
5287
+ read: () => 0,
5288
+ write: (stream, buffer, offset, length, pos) => {
5289
+ const chunk = buffer.subarray(offset, offset + length);
5290
+ PHPWASM.onHeaders(chunk);
5291
+ return length;
5292
+ },
5293
+ });
5294
+ FS.mkdev('/internal/headers', FS.makedev(62, 0));
5295
+ // Handle events.
5296
+ PHPWASM.EventEmitter = ENVIRONMENT_IS_NODE
5297
+ ? require('events').EventEmitter
5298
+ : class EventEmitter {
5299
+ constructor() {
5300
+ this.listeners = {};
5502
5301
  }
5503
- return stream.tty.ops.ioctl_tcsets(stream.tty, op, {
5504
- c_iflag,
5505
- c_oflag,
5506
- c_cflag,
5507
- c_lflag,
5508
- c_cc,
5509
- });
5510
- }
5511
- return 0;
5512
- }
5513
-
5514
- case 21519: {
5515
- if (!stream.tty) return -59;
5516
- var argp = syscallGetVarargP();
5517
- HEAP32[argp >> 2] = 0;
5518
- return 0;
5519
- }
5520
-
5521
- case 21520: {
5522
- if (!stream.tty) return -59;
5523
- return -28;
5524
- }
5525
-
5526
- case 21531: {
5527
- var argp = syscallGetVarargP();
5528
- return FS.ioctl(stream, op, argp);
5529
- }
5530
-
5531
- case 21523: {
5532
- // TODO: in theory we should write to the winsize struct that gets
5533
- // passed in, but for now musl doesn't read anything on it
5534
- if (!stream.tty) return -59;
5535
- if (stream.tty.ops.ioctl_tiocgwinsz) {
5536
- var winsize = stream.tty.ops.ioctl_tiocgwinsz(
5537
- stream.tty
5538
- );
5539
- var argp = syscallGetVarargP();
5540
- HEAP16[argp >> 1] = winsize[0];
5541
- HEAP16[(argp + 2) >> 1] = winsize[1];
5542
- }
5543
- return 0;
5544
- }
5545
-
5546
- case 21524: {
5547
- // TODO: technically, this ioctl call should change the window size.
5548
- // but, since emscripten doesn't have any concept of a terminal window
5549
- // yet, we'll just silently throw it away as we do TIOCGWINSZ
5550
- if (!stream.tty) return -59;
5551
- return 0;
5552
- }
5553
-
5554
- case 21515: {
5555
- if (!stream.tty) return -59;
5556
- return 0;
5302
+ emit(eventName, data) {
5303
+ if (this.listeners[eventName]) {
5304
+ this.listeners[eventName].forEach(
5305
+ (callback) => {
5306
+ callback(data);
5307
+ }
5308
+ );
5309
+ }
5310
+ }
5311
+ once(eventName, callback) {
5312
+ const self = this;
5313
+ function removedCallback() {
5314
+ callback(...arguments);
5315
+ self.removeListener(eventName, removedCallback);
5316
+ }
5317
+ this.on(eventName, removedCallback);
5318
+ }
5319
+ removeAllListeners(eventName) {
5320
+ if (eventName) {
5321
+ delete this.listeners[eventName];
5322
+ } else {
5323
+ this.listeners = {};
5324
+ }
5325
+ }
5326
+ removeListener(eventName, callback) {
5327
+ if (this.listeners[eventName]) {
5328
+ const idx =
5329
+ this.listeners[eventName].indexOf(callback);
5330
+ if (idx !== -1) {
5331
+ this.listeners[eventName].splice(idx, 1);
5332
+ }
5333
+ }
5334
+ }
5335
+ };
5336
+ // Clean up the fd -> childProcess mapping when the fd is closed:
5337
+ const originalClose = FS.close;
5338
+ FS.close = function (stream) {
5339
+ originalClose(stream);
5340
+ delete PHPWASM.child_proc_by_fd[stream.fd];
5341
+ };
5342
+ PHPWASM.child_proc_by_fd = {};
5343
+ PHPWASM.child_proc_by_pid = {};
5344
+ PHPWASM.input_devices = {};
5345
+ const originalWrite = TTY.stream_ops.write;
5346
+ TTY.stream_ops.write = function (stream, ...rest) {
5347
+ const retval = originalWrite(stream, ...rest);
5348
+ // Implicit flush since PHP's fflush() doesn't seem to trigger the fsync event
5349
+ // @TODO: Fix this at the wasm level
5350
+ stream.tty.ops.fsync(stream.tty);
5351
+ return retval;
5352
+ };
5353
+ const originalPutChar = TTY.stream_ops.put_char;
5354
+ TTY.stream_ops.put_char = function (tty, val) {
5355
+ /**
5356
+ * Buffer newlines that Emscripten normally ignores.
5357
+ *
5358
+ * Emscripten doesn't do it by default because its default
5359
+ * print function is console.log that implicitly adds a newline. We are overwriting
5360
+ * it with an environment-specific function that outputs exaclty what it was given,
5361
+ * e.g. in Node.js it's process.stdout.write(). Therefore, we need to mak sure
5362
+ * all the newlines make it to the output buffer.
5363
+ */ if (val === 10) tty.output.push(val);
5364
+ return originalPutChar(tty, val);
5365
+ };
5366
+ },
5367
+ onHeaders: function (chunk) {
5368
+ if (Module['onHeaders']) {
5369
+ Module['onHeaders'](chunk);
5370
+ return;
5371
+ }
5372
+ console.log('headers', {
5373
+ chunk,
5374
+ });
5375
+ },
5376
+ onStdout: function (chunk) {
5377
+ if (Module['onStdout']) {
5378
+ Module['onStdout'](chunk);
5379
+ return;
5380
+ }
5381
+ if (ENVIRONMENT_IS_NODE) {
5382
+ process.stdout.write(chunk);
5383
+ } else {
5384
+ console.log('stdout', {
5385
+ chunk,
5386
+ });
5387
+ }
5388
+ },
5389
+ onStderr: function (chunk) {
5390
+ if (Module['onStderr']) {
5391
+ Module['onStderr'](chunk);
5392
+ return;
5393
+ }
5394
+ if (ENVIRONMENT_IS_NODE) {
5395
+ process.stderr.write(chunk);
5396
+ } else {
5397
+ console.warn('stderr', {
5398
+ chunk,
5399
+ });
5400
+ }
5401
+ },
5402
+ getAllWebSockets: function (sock) {
5403
+ const webSockets = new Set();
5404
+ if (sock.server) {
5405
+ sock.server.clients.forEach((ws) => {
5406
+ webSockets.add(ws);
5407
+ });
5408
+ }
5409
+ for (const peer of PHPWASM.getAllPeers(sock)) {
5410
+ webSockets.add(peer.socket);
5411
+ }
5412
+ return Array.from(webSockets);
5413
+ },
5414
+ getAllPeers: function (sock) {
5415
+ const peers = new Set();
5416
+ if (sock.server) {
5417
+ sock.pending
5418
+ .filter((pending) => pending.peers)
5419
+ .forEach((pending) => {
5420
+ for (const peer of Object.values(pending.peers)) {
5421
+ peers.add(peer);
5422
+ }
5423
+ });
5424
+ }
5425
+ if (sock.peers) {
5426
+ for (const peer of Object.values(sock.peers)) {
5427
+ peers.add(peer);
5557
5428
  }
5558
-
5559
- default:
5560
- return -28;
5561
5429
  }
5562
- } catch (e) {
5563
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5564
- return -e.errno;
5565
- }
5566
- }
5567
-
5568
- function ___syscall_listen(fd, backlog) {
5569
- try {
5570
- var sock = getSocketFromFD(fd);
5571
- sock.sock_ops.listen(sock, backlog);
5572
- return 0;
5573
- } catch (e) {
5574
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5575
- return -e.errno;
5576
- }
5577
- }
5578
-
5579
- function ___syscall_lstat64(path, buf) {
5580
- try {
5581
- path = SYSCALLS.getStr(path);
5582
- return SYSCALLS.writeStat(buf, FS.lstat(path));
5583
- } catch (e) {
5584
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5585
- return -e.errno;
5586
- }
5587
- }
5588
-
5589
- function ___syscall_mkdirat(dirfd, path, mode) {
5590
- try {
5591
- path = SYSCALLS.getStr(path);
5592
- path = SYSCALLS.calculateAt(dirfd, path);
5593
- FS.mkdir(path, mode, 0);
5594
- return 0;
5595
- } catch (e) {
5596
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5597
- return -e.errno;
5598
- }
5599
- }
5600
-
5601
- function ___syscall_newfstatat(dirfd, path, buf, flags) {
5602
- try {
5603
- path = SYSCALLS.getStr(path);
5604
- var nofollow = flags & 256;
5605
- var allowEmpty = flags & 4096;
5606
- flags = flags & ~6400;
5607
- path = SYSCALLS.calculateAt(dirfd, path, allowEmpty);
5608
- return SYSCALLS.writeStat(
5609
- buf,
5610
- nofollow ? FS.lstat(path) : FS.stat(path)
5611
- );
5612
- } catch (e) {
5613
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5614
- return -e.errno;
5615
- }
5616
- }
5617
-
5618
- function ___syscall_openat(dirfd, path, flags, varargs) {
5619
- SYSCALLS.varargs = varargs;
5620
- try {
5621
- path = SYSCALLS.getStr(path);
5622
- path = SYSCALLS.calculateAt(dirfd, path);
5623
- var mode = varargs ? syscallGetVarargI() : 0;
5624
- return FS.open(path, flags, mode).fd;
5625
- } catch (e) {
5626
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5627
- return -e.errno;
5628
- }
5629
- }
5630
-
5631
- var PIPEFS = {
5632
- BUCKET_BUFFER_SIZE: 8192,
5633
- mount(mount) {
5634
- // Do not pollute the real root directory or its child nodes with pipes
5635
- // Looks like it is OK to create another pseudo-root node not linked to the FS.root hierarchy this way
5636
- return FS.createNode(null, '/', 16384 | 511, 0);
5430
+ return Array.from(peers);
5637
5431
  },
5638
- createPipe() {
5639
- var pipe = {
5640
- buckets: [],
5641
- // refcnt 2 because pipe has a read end and a write end. We need to be
5642
- // able to read from the read end after write end is closed.
5643
- refcnt: 2,
5644
- timestamp: new Date(),
5432
+ awaitData: function (ws) {
5433
+ return PHPWASM.awaitEvent(ws, 'message');
5434
+ },
5435
+ awaitConnection: function (ws) {
5436
+ if (ws.OPEN === ws.readyState) {
5437
+ return [Promise.resolve(), PHPWASM.noop];
5438
+ }
5439
+ return PHPWASM.awaitEvent(ws, 'open');
5440
+ },
5441
+ awaitClose: function (ws) {
5442
+ if ([ws.CLOSING, ws.CLOSED].includes(ws.readyState)) {
5443
+ return [Promise.resolve(), PHPWASM.noop];
5444
+ }
5445
+ return PHPWASM.awaitEvent(ws, 'close');
5446
+ },
5447
+ awaitError: function (ws) {
5448
+ if ([ws.CLOSING, ws.CLOSED].includes(ws.readyState)) {
5449
+ return [Promise.resolve(), PHPWASM.noop];
5450
+ }
5451
+ return PHPWASM.awaitEvent(ws, 'error');
5452
+ },
5453
+ awaitEvent: function (ws, event) {
5454
+ let resolve;
5455
+ const listener = () => {
5456
+ resolve();
5645
5457
  };
5646
- pipe.buckets.push({
5647
- buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),
5648
- offset: 0,
5649
- roffset: 0,
5650
- });
5651
- var rName = PIPEFS.nextname();
5652
- var wName = PIPEFS.nextname();
5653
- var rNode = FS.createNode(PIPEFS.root, rName, 4096, 0);
5654
- var wNode = FS.createNode(PIPEFS.root, wName, 4096, 0);
5655
- rNode.pipe = pipe;
5656
- wNode.pipe = pipe;
5657
- var readableStream = FS.createStream({
5658
- path: rName,
5659
- node: rNode,
5660
- flags: 0,
5661
- seekable: false,
5662
- stream_ops: PIPEFS.stream_ops,
5663
- });
5664
- rNode.stream = readableStream;
5665
- var writableStream = FS.createStream({
5666
- path: wName,
5667
- node: wNode,
5668
- flags: 1,
5669
- seekable: false,
5670
- stream_ops: PIPEFS.stream_ops,
5671
- });
5672
- wNode.stream = writableStream;
5673
- return {
5674
- readable_fd: readableStream.fd,
5675
- writable_fd: writableStream.fd,
5458
+ const promise = new Promise(function (_resolve) {
5459
+ resolve = _resolve;
5460
+ ws.once(event, listener);
5461
+ });
5462
+ const cancel = () => {
5463
+ ws.removeListener(event, listener);
5464
+ // Rejecting the promises bubbles up and kills the entire
5465
+ // node process. Let's resolve them on the next tick instead
5466
+ // to give the caller some space to unbind any handlers.
5467
+ setTimeout(resolve);
5676
5468
  };
5469
+ return [promise, cancel];
5677
5470
  },
5678
- stream_ops: {
5679
- getattr(stream) {
5680
- var node = stream.node;
5681
- var timestamp = node.pipe.timestamp;
5682
- return {
5683
- dev: 14,
5684
- ino: node.id,
5685
- mode: 4480,
5686
- nlink: 1,
5687
- uid: 0,
5688
- gid: 0,
5689
- rdev: 0,
5690
- size: 0,
5691
- atime: timestamp,
5692
- mtime: timestamp,
5693
- ctime: timestamp,
5694
- blksize: 4096,
5695
- blocks: 0,
5696
- };
5697
- },
5698
- poll(stream) {
5699
- var pipe = stream.node.pipe;
5700
- if ((stream.flags & 2097155) === 1) {
5701
- return 256 | 4;
5702
- }
5703
- for (var bucket of pipe.buckets) {
5704
- if (bucket.offset - bucket.roffset > 0) {
5705
- return 64 | 1;
5706
- }
5707
- }
5708
- return 0;
5709
- },
5710
- dup(stream) {
5711
- stream.node.pipe.refcnt++;
5712
- },
5713
- ioctl(stream, request, varargs) {
5714
- return 28;
5715
- },
5716
- fsync(stream) {
5717
- return 28;
5718
- },
5719
- read(stream, buffer, offset, length, position) {
5720
- var pipe = stream.node.pipe;
5721
- var currentLength = 0;
5722
- for (var bucket of pipe.buckets) {
5723
- currentLength += bucket.offset - bucket.roffset;
5724
- }
5725
- var data = buffer.subarray(offset, offset + length);
5726
- if (length <= 0) {
5727
- return 0;
5728
- }
5729
- if (currentLength == 0) {
5730
- // Behave as if the read end is always non-blocking
5731
- throw new FS.ErrnoError(6);
5732
- }
5733
- var toRead = Math.min(currentLength, length);
5734
- var totalRead = toRead;
5735
- var toRemove = 0;
5736
- for (var bucket of pipe.buckets) {
5737
- var bucketSize = bucket.offset - bucket.roffset;
5738
- if (toRead <= bucketSize) {
5739
- var tmpSlice = bucket.buffer.subarray(
5740
- bucket.roffset,
5741
- bucket.offset
5742
- );
5743
- if (toRead < bucketSize) {
5744
- tmpSlice = tmpSlice.subarray(0, toRead);
5745
- bucket.roffset += toRead;
5746
- } else {
5747
- toRemove++;
5748
- }
5749
- data.set(tmpSlice);
5750
- break;
5751
- } else {
5752
- var tmpSlice = bucket.buffer.subarray(
5753
- bucket.roffset,
5754
- bucket.offset
5471
+ noop: function () {},
5472
+ spawnProcess: function (command, args, options) {
5473
+ if (Module['spawnProcess']) {
5474
+ const spawnedPromise = Module['spawnProcess'](
5475
+ command,
5476
+ args,
5477
+ options
5478
+ );
5479
+ return Promise.resolve(spawnedPromise).then(function (spawned) {
5480
+ if (!spawned || !spawned.on) {
5481
+ throw new Error(
5482
+ 'spawnProcess() must return an EventEmitter but returned a different type.'
5755
5483
  );
5756
- data.set(tmpSlice);
5757
- data = data.subarray(tmpSlice.byteLength);
5758
- toRead -= tmpSlice.byteLength;
5759
- toRemove++;
5760
5484
  }
5761
- }
5762
- if (toRemove && toRemove == pipe.buckets.length) {
5763
- // Do not generate excessive garbage in use cases such as
5764
- // write several bytes, read everything, write several bytes, read everything...
5765
- toRemove--;
5766
- pipe.buckets[toRemove].offset = 0;
5767
- pipe.buckets[toRemove].roffset = 0;
5768
- }
5769
- pipe.buckets.splice(0, toRemove);
5770
- return totalRead;
5771
- },
5772
- write(stream, buffer, offset, length, position) {
5773
- var pipe = stream.node.pipe;
5774
- var data = buffer.subarray(offset, offset + length);
5775
- var dataLen = data.byteLength;
5776
- if (dataLen <= 0) {
5777
- return 0;
5778
- }
5779
- var currBucket = null;
5780
- if (pipe.buckets.length == 0) {
5781
- currBucket = {
5782
- buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),
5783
- offset: 0,
5784
- roffset: 0,
5785
- };
5786
- pipe.buckets.push(currBucket);
5787
- } else {
5788
- currBucket = pipe.buckets[pipe.buckets.length - 1];
5789
- }
5790
- assert(currBucket.offset <= PIPEFS.BUCKET_BUFFER_SIZE);
5791
- var freeBytesInCurrBuffer =
5792
- PIPEFS.BUCKET_BUFFER_SIZE - currBucket.offset;
5793
- if (freeBytesInCurrBuffer >= dataLen) {
5794
- currBucket.buffer.set(data, currBucket.offset);
5795
- currBucket.offset += dataLen;
5796
- return dataLen;
5797
- } else if (freeBytesInCurrBuffer > 0) {
5798
- currBucket.buffer.set(
5799
- data.subarray(0, freeBytesInCurrBuffer),
5800
- currBucket.offset
5801
- );
5802
- currBucket.offset += freeBytesInCurrBuffer;
5803
- data = data.subarray(
5804
- freeBytesInCurrBuffer,
5805
- data.byteLength
5806
- );
5807
- }
5808
- var numBuckets =
5809
- (data.byteLength / PIPEFS.BUCKET_BUFFER_SIZE) | 0;
5810
- var remElements = data.byteLength % PIPEFS.BUCKET_BUFFER_SIZE;
5811
- for (var i = 0; i < numBuckets; i++) {
5812
- var newBucket = {
5813
- buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),
5814
- offset: PIPEFS.BUCKET_BUFFER_SIZE,
5815
- roffset: 0,
5816
- };
5817
- pipe.buckets.push(newBucket);
5818
- newBucket.buffer.set(
5819
- data.subarray(0, PIPEFS.BUCKET_BUFFER_SIZE)
5820
- );
5821
- data = data.subarray(
5822
- PIPEFS.BUCKET_BUFFER_SIZE,
5823
- data.byteLength
5824
- );
5825
- }
5826
- if (remElements > 0) {
5827
- var newBucket = {
5828
- buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),
5829
- offset: data.byteLength,
5830
- roffset: 0,
5831
- };
5832
- pipe.buckets.push(newBucket);
5833
- newBucket.buffer.set(data);
5834
- }
5835
- return dataLen;
5836
- },
5837
- close(stream) {
5838
- var pipe = stream.node.pipe;
5839
- pipe.refcnt--;
5840
- if (pipe.refcnt === 0) {
5841
- pipe.buckets = null;
5842
- }
5843
- },
5485
+ return spawned;
5486
+ });
5487
+ }
5488
+ if (ENVIRONMENT_IS_NODE) {
5489
+ return require('child_process').spawn(command, args, {
5490
+ ...options,
5491
+ shell: true,
5492
+ stdio: ['pipe', 'pipe', 'pipe'],
5493
+ timeout: 100,
5494
+ });
5495
+ }
5496
+ const e = new Error(
5497
+ 'popen(), proc_open() etc. are unsupported in the browser. Call php.setSpawnHandler() ' +
5498
+ 'and provide a callback to handle spawning processes, or disable a popen(), proc_open() ' +
5499
+ 'and similar functions via php.ini.'
5500
+ );
5501
+ e.code = 'SPAWN_UNSUPPORTED';
5502
+ throw e;
5844
5503
  },
5845
- nextname() {
5846
- if (!PIPEFS.nextname.current) {
5847
- PIPEFS.nextname.current = 0;
5504
+ shutdownSocket: function (socketd, how) {
5505
+ // This implementation only supports websockets at the moment
5506
+ const sock = getSocketFromFD(socketd);
5507
+ const peer = Object.values(sock.peers)[0];
5508
+ if (!peer) {
5509
+ return -1;
5510
+ }
5511
+ try {
5512
+ peer.socket.close();
5513
+ SOCKFS.websocket_sock_ops.removePeer(sock, peer);
5514
+ return 0;
5515
+ } catch (e) {
5516
+ console.log('Socket shutdown error', e);
5517
+ return -1;
5848
5518
  }
5849
- return 'pipe[' + PIPEFS.nextname.current++ + ']';
5850
5519
  },
5851
5520
  };
5852
5521
 
5853
- function ___syscall_pipe(fdPtr) {
5854
- try {
5855
- if (fdPtr == 0) {
5856
- throw new FS.ErrnoError(21);
5857
- }
5858
- var res = PIPEFS.createPipe();
5859
- HEAP32[fdPtr >> 2] = res.readable_fd;
5860
- HEAP32[(fdPtr + 4) >> 2] = res.writable_fd;
5861
- return 0;
5862
- } catch (e) {
5863
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5864
- return -e.errno;
5865
- }
5522
+ function _js_getpid() {
5523
+ return PHPLoader.processId ?? 42;
5866
5524
  }
5867
5525
 
5868
- function ___syscall_poll(fds, nfds, timeout) {
5869
- try {
5870
- var nonzero = 0;
5871
- for (var i = 0; i < nfds; i++) {
5872
- var pollfd = fds + 8 * i;
5873
- var fd = HEAP32[pollfd >> 2];
5874
- var events = HEAP16[(pollfd + 4) >> 1];
5875
- var mask = 32;
5876
- var stream = FS.getStream(fd);
5877
- if (stream) {
5878
- mask = SYSCALLS.DEFAULT_POLLMASK;
5879
- if (stream.stream_ops?.poll) {
5880
- mask = stream.stream_ops.poll(stream, -1);
5881
- }
5882
- }
5883
- mask &= events | 8 | 16;
5884
- if (mask) nonzero++;
5885
- HEAP16[(pollfd + 6) >> 1] = mask;
5886
- }
5887
- return nonzero;
5888
- } catch (e) {
5889
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5890
- return -e.errno;
5526
+ function _js_wasm_trace(format, ...args) {
5527
+ if (PHPLoader.trace instanceof Function) {
5528
+ PHPLoader.trace(_js_getpid(), format, ...args);
5891
5529
  }
5892
5530
  }
5893
5531
 
5894
- function ___syscall_readlinkat(dirfd, path, buf, bufsize) {
5532
+ function _fd_close(fd) {
5533
+ _js_wasm_trace('fd_close(%d)', fd);
5534
+ const [vfsPath, pathResolutionErrno] = locking.get_vfs_path_from_fd(fd);
5535
+ if (pathResolutionErrno !== 0) {
5536
+ _js_wasm_trace(
5537
+ 'fd_close(%d) get_vfs_path_from_fd error %d',
5538
+ fd,
5539
+ pathResolutionErrno
5540
+ );
5541
+ return -ERRNO_CODES.EBADF;
5542
+ }
5543
+ const result = _builtin_fd_close(fd);
5544
+ if (result === 0 && locking.maybeLockedFds.has(fd)) {
5545
+ const nativeFilePath =
5546
+ locking.get_native_path_from_vfs_path(vfsPath);
5547
+ return PHPLoader.fileLockManager
5548
+ .releaseLocksForProcessFd(
5549
+ PHPLoader.processId,
5550
+ fd,
5551
+ nativeFilePath
5552
+ )
5553
+ .then(() => {
5554
+ _js_wasm_trace('fd_close(%d) release locks success', fd);
5555
+ })
5556
+ .catch((e) => {
5557
+ _js_wasm_trace("fd_close(%d) error '%s'", fd, e);
5558
+ })
5559
+ .then(() => {
5560
+ _js_wasm_trace('fd_close(%d) result %d', fd, result);
5561
+ return result;
5562
+ })
5563
+ .finally(() => {
5564
+ locking.maybeLockedFds.delete(fd);
5565
+ });
5566
+ } else {
5567
+ _js_wasm_trace('fd_close(%d) result %d', fd, result);
5568
+ return result;
5569
+ }
5570
+ }
5571
+
5572
+ function _builtin_fd_close(fd) {
5895
5573
  try {
5896
- path = SYSCALLS.getStr(path);
5897
- path = SYSCALLS.calculateAt(dirfd, path);
5898
- if (bufsize <= 0) return -28;
5899
- var ret = FS.readlink(path);
5900
- var len = Math.min(bufsize, lengthBytesUTF8(ret));
5901
- var endChar = HEAP8[buf + len];
5902
- stringToUTF8(ret, buf, bufsize + 1);
5903
- // readlink is one of the rare functions that write out a C string, but does never append a null to the output buffer(!)
5904
- // stringToUTF8() always appends a null byte, so restore the character under the null byte after the write.
5905
- HEAP8[buf + len] = endChar;
5906
- return len;
5574
+ var stream = SYSCALLS.getStreamFromFD(fd);
5575
+ FS.close(stream);
5576
+ return 0;
5907
5577
  } catch (e) {
5908
5578
  if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5909
- return -e.errno;
5579
+ return e.errno;
5910
5580
  }
5911
5581
  }
5912
5582
 
5913
- function ___syscall_recvfrom(fd, buf, len, flags, addr, addrlen) {
5583
+ function _builtin_fcntl64(fd, cmd, varargs) {
5584
+ SYSCALLS.varargs = varargs;
5914
5585
  try {
5915
- var sock = getSocketFromFD(fd);
5916
- var msg = sock.sock_ops.recvmsg(
5917
- sock,
5918
- len,
5919
- typeof flags !== 'undefined' ? flags : 0
5920
- );
5921
- if (!msg) return 0;
5922
- // socket is closed
5923
- if (addr) {
5924
- var errno = writeSockaddr(
5925
- addr,
5926
- sock.family,
5927
- DNS.lookup_name(msg.addr),
5928
- msg.port,
5929
- addrlen
5930
- );
5586
+ var stream = SYSCALLS.getStreamFromFD(fd);
5587
+ switch (cmd) {
5588
+ case 0: {
5589
+ var arg = syscallGetVarargI();
5590
+ if (arg < 0) {
5591
+ return -28;
5592
+ }
5593
+ while (FS.streams[arg]) {
5594
+ arg++;
5595
+ }
5596
+ var newStream;
5597
+ newStream = FS.dupStream(stream, arg);
5598
+ return newStream.fd;
5599
+ }
5600
+
5601
+ case 1:
5602
+ case 2:
5603
+ return 0;
5604
+
5605
+ // FD_CLOEXEC makes no sense for a single process.
5606
+ case 3:
5607
+ return stream.flags;
5608
+
5609
+ case 4: {
5610
+ var arg = syscallGetVarargI();
5611
+ stream.flags |= arg;
5612
+ return 0;
5613
+ }
5614
+
5615
+ case 12: {
5616
+ var arg = syscallGetVarargP();
5617
+ var offset = 0;
5618
+ // We're always unlocked.
5619
+ HEAP16[(arg + offset) >> 1] = 2;
5620
+ return 0;
5621
+ }
5622
+
5623
+ case 13:
5624
+ case 14:
5625
+ // Pretend that the locking is successful. These are process-level locks,
5626
+ // and Emscripten programs are a single process. If we supported linking a
5627
+ // filesystem between programs, we'd need to do more here.
5628
+ // See https://github.com/emscripten-core/emscripten/issues/23697
5629
+ return 0;
5931
5630
  }
5932
- HEAPU8.set(msg.buffer, buf);
5933
- return msg.buffer.byteLength;
5631
+ return -28;
5934
5632
  } catch (e) {
5935
5633
  if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5936
5634
  return -e.errno;
5937
5635
  }
5938
5636
  }
5939
5637
 
5940
- function ___syscall_renameat(olddirfd, oldpath, newdirfd, newpath) {
5941
- try {
5942
- oldpath = SYSCALLS.getStr(oldpath);
5943
- newpath = SYSCALLS.getStr(newpath);
5944
- oldpath = SYSCALLS.calculateAt(olddirfd, oldpath);
5945
- newpath = SYSCALLS.calculateAt(newdirfd, newpath);
5946
- FS.rename(oldpath, newpath);
5638
+ var locking = {
5639
+ maybeLockedFds: new Set(),
5640
+ F_RDLCK: 0,
5641
+ F_WRLCK: 1,
5642
+ F_UNLCK: 2,
5643
+ lockStateToFcntl: {
5644
+ shared: 0,
5645
+ exclusive: 1,
5646
+ unlocked: 2,
5647
+ },
5648
+ fcntlToLockState: {
5649
+ 0: 'shared',
5650
+ 1: 'exclusive',
5651
+ 2: 'unlocked',
5652
+ },
5653
+ is_shared_fs_node(node) {
5654
+ if (node?.isSharedFS) {
5655
+ return true;
5656
+ }
5657
+ // Handle PROXYFS nodes which wrap other nodes.
5658
+ if (!node?.mount?.opts?.fs?.lookupPath) {
5659
+ return false;
5660
+ }
5661
+ const vfsPath = NODEFS.realPath(node);
5662
+ const underlyingNode = node.mount.opts.fs.lookupPath(vfsPath)?.node;
5663
+ return !!underlyingNode?.isSharedFS;
5664
+ },
5665
+ is_path_to_shared_fs(path) {
5666
+ const { node } = FS.lookupPath(path);
5667
+ return locking.is_shared_fs_node(node);
5668
+ },
5669
+ get_fd_access_mode(fd) {
5670
+ const emscripten_F_GETFL = Number('3');
5671
+ const emscripten_O_ACCMODE = Number('2097155');
5672
+ return (
5673
+ _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE
5674
+ );
5675
+ },
5676
+ get_vfs_path_from_fd(fd) {
5677
+ try {
5678
+ return [FS.readlink(`/proc/self/fd/${fd}`), 0];
5679
+ } catch (error) {
5680
+ return [null, ERRNO_CODES.EBADF];
5681
+ }
5682
+ },
5683
+ get_native_path_from_vfs_path(vfsPath) {
5684
+ const { node } = FS.lookupPath(vfsPath);
5685
+ return NODEFS.realPath(node);
5686
+ },
5687
+ check_lock_params(fd, l_type) {
5688
+ const emscripten_O_RDONLY = Number('0');
5689
+ const emscripten_O_WRONLY = Number('1');
5690
+ const accessMode = locking.get_fd_access_mode(fd);
5691
+ if (
5692
+ (l_type === locking.F_WRLCK &&
5693
+ accessMode === emscripten_O_RDONLY) ||
5694
+ (l_type === locking.F_RDLCK &&
5695
+ accessMode === emscripten_O_WRONLY)
5696
+ ) {
5697
+ return ERRNO_CODES.EBADF;
5698
+ }
5947
5699
  return 0;
5948
- } catch (e) {
5949
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5950
- return -e.errno;
5700
+ },
5701
+ };
5702
+
5703
+ async function ___syscall_fcntl64(fd, cmd, varargs) {
5704
+ // Necessary to use varargs accessor
5705
+ SYSCALLS.varargs = varargs;
5706
+ // These constants are replaced by Emscripten during the build process
5707
+ const emscripten_F_GETLK = Number('12');
5708
+ const emscripten_F_SETLK = Number('13');
5709
+ const emscripten_F_SETLKW = Number('14');
5710
+ const emscripten_SEEK_SET = Number('0');
5711
+ // NOTE: With the exception of l_type, these offsets are not exposed to
5712
+ // JS by Emscripten, so we hardcode them here.
5713
+ const emscripten_flock_l_type_offset = 0;
5714
+ const emscripten_flock_l_whence_offset = 2;
5715
+ const emscripten_flock_l_start_offset = 8;
5716
+ const emscripten_flock_l_len_offset = 16;
5717
+ const emscripten_flock_l_pid_offset = 24;
5718
+ /**
5719
+ * Read the flock struct at the given address.
5720
+ *
5721
+ * @param {bigint} flockStructAddress - the address of the flock struct
5722
+ * @returns the flock struct
5723
+ */ function read_flock_struct(flockStructAddress) {
5724
+ /*
5725
+ * NOTE: Since we are using HEAP<WORD_SIZE> vars like HEAP16 and HEAP64,
5726
+ * we need to adjust offsets to address the word size of each HEAP.
5727
+ *
5728
+ * For example, an offset of 64 bytes is the following for each HEAP:
5729
+ * - HEAP8: 64 (the 64th byte)
5730
+ * - HEAP16: 32 (the 32nd 16-bit word)
5731
+ * - HEAP32: 16 (the 16th 32-bit word)
5732
+ * - HEAP64: 8 (the 8th 64-bit word)
5733
+ *
5734
+ * We get a word offset by dividing the byte offset by the word size.
5735
+ */ return {
5736
+ l_type: HEAP16[ // Shift right by 1 to divide by 2^1.
5737
+ (flockStructAddress + emscripten_flock_l_type_offset) >> 1
5738
+ ],
5739
+ l_whence:
5740
+ HEAP16[ // Shift right by 1 to divide by 2^1.
5741
+ (flockStructAddress +
5742
+ emscripten_flock_l_whence_offset) >>
5743
+ 1
5744
+ ],
5745
+ l_start:
5746
+ HEAP64[ // Shift right by 3 to divide by 2^3.
5747
+ (flockStructAddress +
5748
+ emscripten_flock_l_start_offset) >>
5749
+ 3
5750
+ ],
5751
+ l_len: HEAP64[ // Shift right by 3 to divide by 2^3.
5752
+ (flockStructAddress + emscripten_flock_l_len_offset) >> 3
5753
+ ],
5754
+ l_pid: HEAP32[ // Shift right by 2 to divide by 2^2.
5755
+ (flockStructAddress + emscripten_flock_l_pid_offset) >> 2
5756
+ ],
5757
+ };
5758
+ }
5759
+ /**
5760
+ * Update the flock struct at the given address with the given fields.
5761
+ *
5762
+ * @param {bigint} flockStructAddress - the address of the flock struct
5763
+ * @param {object} fields - the fields to update
5764
+ */ function update_flock_struct(flockStructAddress, fields) {
5765
+ /*
5766
+ * NOTE: Since we are using HEAP<WORD_SIZE> vars like HEAP16 and HEAP64,
5767
+ * we need to adjust offsets to address the word size of each HEAP.
5768
+ *
5769
+ * For example, an offset of 64 bytes is the following for each HEAP:
5770
+ * - HEAP8: 64 (the 64th byte)
5771
+ * - HEAP16: 32 (the 32nd 16-bit word)
5772
+ * - HEAP32: 16 (the 16th 32-bit word)
5773
+ * - HEAP64: 8 (the 8th 64-bit word)
5774
+ *
5775
+ * We get a word offset by dividing the byte offset by the word size.
5776
+ */ if (fields.l_type !== undefined) {
5777
+ HEAP16[ // Shift right by 1 to divide by 2^1.
5778
+ (flockStructAddress + emscripten_flock_l_type_offset) >> 1
5779
+ ] = fields.l_type;
5780
+ }
5781
+ if (fields.l_whence !== undefined) {
5782
+ HEAP16[ // Shift right by 1 to divide by 2^1.
5783
+ (flockStructAddress + emscripten_flock_l_whence_offset) >> 1
5784
+ ] = fields.l_whence;
5785
+ }
5786
+ if (fields.l_start !== undefined) {
5787
+ HEAP64[ // Shift right by 3 to divide by 2^3.
5788
+ (flockStructAddress + emscripten_flock_l_start_offset) >> 3
5789
+ ] = fields.l_start;
5790
+ }
5791
+ if (fields.l_len !== undefined) {
5792
+ HEAP64[ // Shift right by 3 to divide by 2^3.
5793
+ (flockStructAddress + emscripten_flock_l_len_offset) >> 3
5794
+ ] = fields.l_len;
5795
+ }
5796
+ if (fields.l_pid !== undefined) {
5797
+ HEAP32[ // Shift right by 2 to divide by 2^2.
5798
+ (flockStructAddress + emscripten_flock_l_pid_offset) >> 2
5799
+ ] = fields.l_pid;
5800
+ }
5801
+ }
5802
+ /**
5803
+ * Resolve the base address of the range depending on the whence and start offset.
5804
+ *
5805
+ * @param {number} fd - the file descriptor
5806
+ * @param {number} whence - what the start offset is relative to
5807
+ * @param {bigint} startOffset - the offset from the whence
5808
+ * @returns The resolved offset and the errno. If there is an error,
5809
+ * the resolved offset is null, and the errno is non-zero.
5810
+ */ function get_base_address(fd, whence, startOffset) {
5811
+ let baseAddress;
5812
+ switch (whence) {
5813
+ case emscripten_SEEK_SET:
5814
+ baseAddress = 0n;
5815
+ break;
5816
+
5817
+ case emscripten_SEEK_CUR:
5818
+ baseAddress = FS.lseek(fd, 0, whence);
5819
+ break;
5820
+
5821
+ case emscripten_SEEK_END:
5822
+ baseAddress = _wasm_get_end_offset(fd);
5823
+ break;
5824
+
5825
+ default:
5826
+ return [null, ERRNO_CODES.EINVAL];
5827
+ }
5828
+ if (baseAddress == -1) {
5829
+ // We cannot resolve the offset within the file.
5830
+ // Let's treat this as a problem with the file descriptor.
5831
+ return [null, ERRNO_CODES.EBADF];
5832
+ }
5833
+ const resolvedOffset = baseAddress + startOffset;
5834
+ if (resolvedOffset < 0) {
5835
+ // This is not a valid offset. Report args as invalid.
5836
+ return [null, ERRNO_CODES.EINVAL];
5837
+ }
5838
+ return [resolvedOffset, 0];
5839
+ }
5840
+ const pid = PHPLoader.processId;
5841
+ switch (cmd) {
5842
+ case emscripten_F_GETLK: {
5843
+ _js_wasm_trace('fcntl(%d, F_GETLK)', fd);
5844
+ let vfsPath;
5845
+ let errno;
5846
+ [vfsPath, errno] = locking.get_vfs_path_from_fd(fd);
5847
+ if (errno !== 0) {
5848
+ _js_wasm_trace(
5849
+ 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d',
5850
+ fd,
5851
+ vfsPath,
5852
+ errno
5853
+ );
5854
+ return -ERRNO_CODES.EBADF;
5855
+ }
5856
+ if (!locking.is_path_to_shared_fs(vfsPath)) {
5857
+ _js_wasm_trace(
5858
+ "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'",
5859
+ fd,
5860
+ vfsPath
5861
+ );
5862
+ // If not a NodeFS path, we can't lock it.
5863
+ // Default to succeeding as Emscripten does.
5864
+ update_flock_struct(flockStructAddr, {
5865
+ l_type: F_UNLCK,
5866
+ });
5867
+ return 0;
5868
+ }
5869
+ const flockStructAddr = syscallGetVarargP();
5870
+ const flockStruct = read_flock_struct(flockStructAddr);
5871
+ if (!(flockStruct.l_type in locking.fcntlToLockState)) {
5872
+ return -ERRNO_CODES.EINVAL;
5873
+ }
5874
+ errno = locking.check_lock_params(fd, flockStruct.l_type);
5875
+ if (errno !== 0) {
5876
+ _js_wasm_trace(
5877
+ 'fcntl(%d, F_GETLK) %s check_lock_params errno %d',
5878
+ fd,
5879
+ vfsPath,
5880
+ errno
5881
+ );
5882
+ return -ERRNO_CODES.EINVAL;
5883
+ }
5884
+ const requestedLockType =
5885
+ locking.fcntlToLockState[flockStruct.l_type];
5886
+ let absoluteStartOffset;
5887
+ [absoluteStartOffset, errno] = get_base_address(
5888
+ fd,
5889
+ flockStruct.l_whence,
5890
+ flockStruct.l_start
5891
+ );
5892
+ if (errno !== 0) {
5893
+ _js_wasm_trace(
5894
+ 'fcntl(%d, F_GETLK) %s get_base_address errno %d',
5895
+ fd,
5896
+ vfsPath,
5897
+ errno
5898
+ );
5899
+ return -ERRNO_CODES.EINVAL;
5900
+ }
5901
+ const nativeFilePath =
5902
+ locking.get_native_path_from_vfs_path(vfsPath);
5903
+ return PHPLoader.fileLockManager
5904
+ .findFirstConflictingByteRangeLock(nativeFilePath, {
5905
+ type: requestedLockType,
5906
+ start: absoluteStartOffset,
5907
+ end: absoluteStartOffset + flockStruct.l_len,
5908
+ pid,
5909
+ })
5910
+ .then((conflictingLock) => {
5911
+ if (conflictingLock === undefined) {
5912
+ _js_wasm_trace(
5913
+ 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x',
5914
+ fd,
5915
+ vfsPath,
5916
+ absoluteStartOffset,
5917
+ absoluteStartOffset + flockStruct.l_len
5918
+ );
5919
+ update_flock_struct(flockStructAddr, {
5920
+ l_type: F_UNLCK,
5921
+ });
5922
+ return 0;
5923
+ }
5924
+ _js_wasm_trace(
5925
+ 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d',
5926
+ fd,
5927
+ vfsPath,
5928
+ conflictingLock.type,
5929
+ conflictingLock.start,
5930
+ conflictingLock.end,
5931
+ conflictingLock.pid
5932
+ );
5933
+ const fcntlLockState =
5934
+ locking.lockStateToFcntl[conflictingLock.type];
5935
+ update_flock_struct(flockStructAddr, {
5936
+ l_type: fcntlLockState,
5937
+ l_whence: emscripten_SEEK_SET,
5938
+ l_start: conflictingLock.start,
5939
+ l_len: conflictingLock.end - conflictingLock.start,
5940
+ l_pid: conflictingLock.pid,
5941
+ });
5942
+ return 0;
5943
+ })
5944
+ .catch((e) => {
5945
+ _js_wasm_trace(
5946
+ 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s',
5947
+ fd,
5948
+ vfsPath,
5949
+ e
5950
+ );
5951
+ return -ERRNO_CODES.EINVAL;
5952
+ });
5953
+ }
5954
+
5955
+ case emscripten_F_SETLK: {
5956
+ _js_wasm_trace('fcntl(%d, F_SETLK)', fd);
5957
+ let vfsPath;
5958
+ let errno;
5959
+ [vfsPath, errno] = locking.get_vfs_path_from_fd(fd);
5960
+ if (errno !== 0) {
5961
+ _js_wasm_trace(
5962
+ 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d',
5963
+ fd,
5964
+ vfsPath,
5965
+ errno
5966
+ );
5967
+ return -errno;
5968
+ }
5969
+ if (!locking.is_path_to_shared_fs(vfsPath)) {
5970
+ _js_wasm_trace(
5971
+ 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s',
5972
+ fd,
5973
+ vfsPath
5974
+ );
5975
+ // If not a NodeFS path, we can't lock it.
5976
+ // Default to succeeding as Emscripten does.
5977
+ return 0;
5978
+ }
5979
+ var flockStructAddr = syscallGetVarargP();
5980
+ const flockStruct = read_flock_struct(flockStructAddr);
5981
+ let absoluteStartOffset;
5982
+ [absoluteStartOffset, errno] = get_base_address(
5983
+ fd,
5984
+ flockStruct.l_whence,
5985
+ flockStruct.l_start
5986
+ );
5987
+ if (errno !== 0) {
5988
+ _js_wasm_trace(
5989
+ 'fcntl(%d, F_SETLK) %s get_base_address errno %d',
5990
+ fd,
5991
+ vfsPath,
5992
+ errno
5993
+ );
5994
+ return -errno;
5995
+ }
5996
+ if (!(flockStruct.l_type in locking.fcntlToLockState)) {
5997
+ _js_wasm_trace(
5998
+ 'fcntl(%d, F_SETLK) %s invalid lock type %d',
5999
+ fd,
6000
+ vfsPath,
6001
+ flockStruct.l_type
6002
+ );
6003
+ return -ERRNO_CODES.EINVAL;
6004
+ }
6005
+ errno = locking.check_lock_params(fd, flockStruct.l_type);
6006
+ if (errno !== 0) {
6007
+ _js_wasm_trace(
6008
+ 'fcntl(%d, F_SETLK) %s check_lock_params errno %d',
6009
+ fd,
6010
+ vfsPath,
6011
+ errno
6012
+ );
6013
+ return -errno;
6014
+ }
6015
+ locking.maybeLockedFds.add(fd);
6016
+ const requestedLockType =
6017
+ locking.fcntlToLockState[flockStruct.l_type];
6018
+ const rangeLock = {
6019
+ type: requestedLockType,
6020
+ start: absoluteStartOffset,
6021
+ end: absoluteStartOffset + flockStruct.l_len,
6022
+ pid,
6023
+ };
6024
+ const nativeFilePath =
6025
+ locking.get_native_path_from_vfs_path(vfsPath);
6026
+ _js_wasm_trace(
6027
+ 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s',
6028
+ fd,
6029
+ vfsPath,
6030
+ rangeLock
6031
+ );
6032
+ return PHPLoader.fileLockManager
6033
+ .lockFileByteRange(nativeFilePath, rangeLock)
6034
+ .then((succeeded) => {
6035
+ _js_wasm_trace(
6036
+ 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s',
6037
+ fd,
6038
+ vfsPath,
6039
+ succeeded,
6040
+ rangeLock
6041
+ );
6042
+ return succeeded ? 0 : -ERRNO_CODES.EAGAIN;
6043
+ })
6044
+ .catch((e) => {
6045
+ _js_wasm_trace(
6046
+ 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s',
6047
+ fd,
6048
+ vfsPath,
6049
+ e,
6050
+ rangeLock
6051
+ );
6052
+ return -ERRNO_CODES.EINVAL;
6053
+ });
6054
+ }
6055
+
6056
+ // @TODO: Implement waiting for lock
6057
+ case emscripten_F_SETLKW: {
6058
+ // We do not yet support the blocking form of flock().
6059
+ // We respond with EDEADLK to indicate failure
6060
+ // because it is a known errno for a failed F_SETLKW command.
6061
+ return -ERRNO_CODES.EDEADLK;
6062
+ }
6063
+
6064
+ default:
6065
+ return _builtin_fcntl64(fd, cmd, varargs);
5951
6066
  }
5952
6067
  }
5953
6068
 
5954
- function ___syscall_rmdir(path) {
6069
+ ___syscall_fcntl64.isAsync = true;
6070
+
6071
+ function ___syscall_fdatasync(fd) {
5955
6072
  try {
5956
- path = SYSCALLS.getStr(path);
5957
- FS.rmdir(path);
6073
+ var stream = SYSCALLS.getStreamFromFD(fd);
5958
6074
  return 0;
5959
6075
  } catch (e) {
5960
6076
  if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
@@ -5962,65 +6078,115 @@ export function init(RuntimeName, PHPLoader) {
5962
6078
  }
5963
6079
  }
5964
6080
 
5965
- function ___syscall_sendto(fd, message, length, flags, addr, addr_len) {
6081
+ function ___syscall_fstat64(fd, buf) {
5966
6082
  try {
5967
- var sock = getSocketFromFD(fd);
5968
- if (!addr) {
5969
- // send, no address provided
5970
- return FS.write(sock.stream, HEAP8, message, length);
5971
- }
5972
- var dest = getSocketAddress(addr, addr_len);
5973
- // sendto an address
5974
- return sock.sock_ops.sendmsg(
5975
- sock,
5976
- HEAP8,
5977
- message,
5978
- length,
5979
- dest.addr,
5980
- dest.port
5981
- );
6083
+ return SYSCALLS.writeStat(buf, FS.fstat(fd));
5982
6084
  } catch (e) {
5983
6085
  if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5984
6086
  return -e.errno;
5985
6087
  }
5986
6088
  }
5987
6089
 
5988
- function ___syscall_socket(domain, type, protocol) {
6090
+ function ___syscall_ftruncate64(fd, length) {
6091
+ length = bigintToI53Checked(length);
5989
6092
  try {
5990
- var sock = SOCKFS.createSocket(domain, type, protocol);
5991
- return sock.stream.fd;
6093
+ if (isNaN(length)) return 61;
6094
+ FS.ftruncate(fd, length);
6095
+ return 0;
5992
6096
  } catch (e) {
5993
6097
  if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
5994
6098
  return -e.errno;
5995
6099
  }
5996
6100
  }
5997
6101
 
5998
- function ___syscall_stat64(path, buf) {
6102
+ function ___syscall_getcwd(buf, size) {
5999
6103
  try {
6000
- path = SYSCALLS.getStr(path);
6001
- return SYSCALLS.writeStat(buf, FS.stat(path));
6104
+ if (size === 0) return -28;
6105
+ var cwd = FS.cwd();
6106
+ var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1;
6107
+ if (size < cwdLengthInBytes) return -68;
6108
+ stringToUTF8(cwd, buf, size);
6109
+ return cwdLengthInBytes;
6002
6110
  } catch (e) {
6003
6111
  if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6004
6112
  return -e.errno;
6005
6113
  }
6006
6114
  }
6007
6115
 
6008
- function ___syscall_statfs64(path, size, buf) {
6116
+ function ___syscall_getdents64(fd, dirp, count) {
6009
6117
  try {
6010
- SYSCALLS.writeStatFs(buf, FS.statfs(SYSCALLS.getStr(path)));
6011
- return 0;
6118
+ var stream = SYSCALLS.getStreamFromFD(fd);
6119
+ stream.getdents ||= FS.readdir(stream.path);
6120
+ var struct_size = 280;
6121
+ var pos = 0;
6122
+ var off = FS.llseek(stream, 0, 1);
6123
+ var startIdx = Math.floor(off / struct_size);
6124
+ var endIdx = Math.min(
6125
+ stream.getdents.length,
6126
+ startIdx + Math.floor(count / struct_size)
6127
+ );
6128
+ for (var idx = startIdx; idx < endIdx; idx++) {
6129
+ var id;
6130
+ var type;
6131
+ var name = stream.getdents[idx];
6132
+ if (name === '.') {
6133
+ id = stream.node.id;
6134
+ type = 4;
6135
+ } else if (name === '..') {
6136
+ var lookup = FS.lookupPath(stream.path, {
6137
+ parent: true,
6138
+ });
6139
+ id = lookup.node.id;
6140
+ type = 4;
6141
+ } else {
6142
+ var child;
6143
+ try {
6144
+ child = FS.lookupNode(stream.node, name);
6145
+ } catch (e) {
6146
+ // If the entry is not a directory, file, or symlink, nodefs
6147
+ // lookupNode will raise EINVAL. Skip these and continue.
6148
+ if (e?.errno === 28) {
6149
+ continue;
6150
+ }
6151
+ throw e;
6152
+ }
6153
+ id = child.id;
6154
+ type = FS.isChrdev(child.mode)
6155
+ ? 2 // DT_CHR, character device.
6156
+ : FS.isDir(child.mode)
6157
+ ? 4 // DT_DIR, directory.
6158
+ : FS.isLink(child.mode)
6159
+ ? 10 // DT_LNK, symbolic link.
6160
+ : 8;
6161
+ }
6162
+ HEAP64[(dirp + pos) >> 3] = BigInt(id);
6163
+ HEAP64[(dirp + pos + 8) >> 3] = BigInt((idx + 1) * struct_size);
6164
+ HEAP16[(dirp + pos + 16) >> 1] = 280;
6165
+ HEAP8[dirp + pos + 18] = type;
6166
+ stringToUTF8(name, dirp + pos + 19, 256);
6167
+ pos += struct_size;
6168
+ }
6169
+ FS.llseek(stream, idx * struct_size, 0);
6170
+ return pos;
6012
6171
  } catch (e) {
6013
6172
  if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6014
6173
  return -e.errno;
6015
6174
  }
6016
6175
  }
6017
6176
 
6018
- function ___syscall_symlinkat(target, dirfd, linkpath) {
6177
+ function ___syscall_getpeername(fd, addr, addrlen, d1, d2, d3) {
6019
6178
  try {
6020
- target = SYSCALLS.getStr(target);
6021
- linkpath = SYSCALLS.getStr(linkpath);
6022
- linkpath = SYSCALLS.calculateAt(dirfd, linkpath);
6023
- FS.symlink(target, linkpath);
6179
+ var sock = getSocketFromFD(fd);
6180
+ if (!sock.daddr) {
6181
+ return -53;
6182
+ }
6183
+ var errno = writeSockaddr(
6184
+ addr,
6185
+ sock.family,
6186
+ DNS.lookup_name(sock.daddr),
6187
+ sock.dport,
6188
+ addrlen
6189
+ );
6024
6190
  return 0;
6025
6191
  } catch (e) {
6026
6192
  if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
@@ -6028,17 +6194,17 @@ export function init(RuntimeName, PHPLoader) {
6028
6194
  }
6029
6195
  }
6030
6196
 
6031
- function ___syscall_unlinkat(dirfd, path, flags) {
6197
+ function ___syscall_getsockname(fd, addr, addrlen, d1, d2, d3) {
6032
6198
  try {
6033
- path = SYSCALLS.getStr(path);
6034
- path = SYSCALLS.calculateAt(dirfd, path);
6035
- if (flags === 0) {
6036
- FS.unlink(path);
6037
- } else if (flags === 512) {
6038
- FS.rmdir(path);
6039
- } else {
6040
- abort('Invalid flags passed to unlinkat');
6041
- }
6199
+ var sock = getSocketFromFD(fd);
6200
+ // TODO: sock.saddr should never be undefined, see TODO in websocket_sock_ops.getname
6201
+ var errno = writeSockaddr(
6202
+ addr,
6203
+ sock.family,
6204
+ DNS.lookup_name(sock.saddr || '0.0.0.0'),
6205
+ sock.sport,
6206
+ addrlen
6207
+ );
6042
6208
  return 0;
6043
6209
  } catch (e) {
6044
6210
  if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
@@ -6046,1218 +6212,1535 @@ export function init(RuntimeName, PHPLoader) {
6046
6212
  }
6047
6213
  }
6048
6214
 
6049
- var readI53FromI64 = (ptr) =>
6050
- HEAPU32[ptr >> 2] + HEAP32[(ptr + 4) >> 2] * 4294967296;
6051
-
6052
- function ___syscall_utimensat(dirfd, path, times, flags) {
6215
+ function ___syscall_getsockopt(fd, level, optname, optval, optlen, d1) {
6053
6216
  try {
6054
- path = SYSCALLS.getStr(path);
6055
- path = SYSCALLS.calculateAt(dirfd, path, true);
6056
- var now = Date.now(),
6057
- atime,
6058
- mtime;
6059
- if (!times) {
6060
- atime = now;
6061
- mtime = now;
6062
- } else {
6063
- var seconds = readI53FromI64(times);
6064
- var nanoseconds = HEAP32[(times + 8) >> 2];
6065
- if (nanoseconds == 1073741823) {
6066
- atime = now;
6067
- } else if (nanoseconds == 1073741822) {
6068
- atime = null;
6069
- } else {
6070
- atime = seconds * 1e3 + nanoseconds / (1e3 * 1e3);
6071
- }
6072
- times += 16;
6073
- seconds = readI53FromI64(times);
6074
- nanoseconds = HEAP32[(times + 8) >> 2];
6075
- if (nanoseconds == 1073741823) {
6076
- mtime = now;
6077
- } else if (nanoseconds == 1073741822) {
6078
- mtime = null;
6079
- } else {
6080
- mtime = seconds * 1e3 + nanoseconds / (1e3 * 1e3);
6217
+ var sock = getSocketFromFD(fd);
6218
+ // Minimal getsockopt aimed at resolving https://github.com/emscripten-core/emscripten/issues/2211
6219
+ // so only supports SOL_SOCKET with SO_ERROR.
6220
+ if (level === 1) {
6221
+ if (optname === 4) {
6222
+ HEAP32[optval >> 2] = sock.error;
6223
+ HEAP32[optlen >> 2] = 4;
6224
+ sock.error = null;
6225
+ // Clear the error (The SO_ERROR option obtains and then clears this field).
6226
+ return 0;
6081
6227
  }
6082
6228
  }
6083
- // null here means UTIME_OMIT was passed. If both were set to UTIME_OMIT then
6084
- // we can skip the call completely.
6085
- if ((mtime ?? atime) !== null) {
6086
- FS.utime(path, atime, mtime);
6087
- }
6088
- return 0;
6089
- } catch (e) {
6090
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6091
- return -e.errno;
6092
- }
6093
- }
6094
-
6095
- var __abort_js = () => abort('');
6096
-
6097
- var __emscripten_lookup_name = (name) => {
6098
- // uint32_t _emscripten_lookup_name(const char *name);
6099
- var nameString = UTF8ToString(name);
6100
- return inetPton4(DNS.lookup_name(nameString));
6101
- };
6102
-
6103
- var runtimeKeepaliveCounter = 0;
6104
-
6105
- var __emscripten_runtime_keepalive_clear = () => {
6106
- noExitRuntime = false;
6107
- runtimeKeepaliveCounter = 0;
6108
- };
6109
-
6110
- function __gmtime_js(time, tmPtr) {
6111
- time = bigintToI53Checked(time);
6112
- var date = new Date(time * 1e3);
6113
- HEAP32[tmPtr >> 2] = date.getUTCSeconds();
6114
- HEAP32[(tmPtr + 4) >> 2] = date.getUTCMinutes();
6115
- HEAP32[(tmPtr + 8) >> 2] = date.getUTCHours();
6116
- HEAP32[(tmPtr + 12) >> 2] = date.getUTCDate();
6117
- HEAP32[(tmPtr + 16) >> 2] = date.getUTCMonth();
6118
- HEAP32[(tmPtr + 20) >> 2] = date.getUTCFullYear() - 1900;
6119
- HEAP32[(tmPtr + 24) >> 2] = date.getUTCDay();
6120
- var start = Date.UTC(date.getUTCFullYear(), 0, 1, 0, 0, 0, 0);
6121
- var yday = ((date.getTime() - start) / (1e3 * 60 * 60 * 24)) | 0;
6122
- HEAP32[(tmPtr + 28) >> 2] = yday;
6123
- }
6124
-
6125
- var isLeapYear = (year) =>
6126
- year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
6127
-
6128
- var MONTH_DAYS_LEAP_CUMULATIVE = [
6129
- 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335,
6130
- ];
6131
-
6132
- var MONTH_DAYS_REGULAR_CUMULATIVE = [
6133
- 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
6134
- ];
6135
-
6136
- var ydayFromDate = (date) => {
6137
- var leap = isLeapYear(date.getFullYear());
6138
- var monthDaysCumulative = leap
6139
- ? MONTH_DAYS_LEAP_CUMULATIVE
6140
- : MONTH_DAYS_REGULAR_CUMULATIVE;
6141
- var yday = monthDaysCumulative[date.getMonth()] + date.getDate() - 1;
6142
- // -1 since it's days since Jan 1
6143
- return yday;
6144
- };
6145
-
6146
- function __localtime_js(time, tmPtr) {
6147
- time = bigintToI53Checked(time);
6148
- var date = new Date(time * 1e3);
6149
- HEAP32[tmPtr >> 2] = date.getSeconds();
6150
- HEAP32[(tmPtr + 4) >> 2] = date.getMinutes();
6151
- HEAP32[(tmPtr + 8) >> 2] = date.getHours();
6152
- HEAP32[(tmPtr + 12) >> 2] = date.getDate();
6153
- HEAP32[(tmPtr + 16) >> 2] = date.getMonth();
6154
- HEAP32[(tmPtr + 20) >> 2] = date.getFullYear() - 1900;
6155
- HEAP32[(tmPtr + 24) >> 2] = date.getDay();
6156
- var yday = ydayFromDate(date) | 0;
6157
- HEAP32[(tmPtr + 28) >> 2] = yday;
6158
- HEAP32[(tmPtr + 36) >> 2] = -(date.getTimezoneOffset() * 60);
6159
- // Attention: DST is in December in South, and some regions don't have DST at all.
6160
- var start = new Date(date.getFullYear(), 0, 1);
6161
- var summerOffset = new Date(
6162
- date.getFullYear(),
6163
- 6,
6164
- 1
6165
- ).getTimezoneOffset();
6166
- var winterOffset = start.getTimezoneOffset();
6167
- var dst =
6168
- (summerOffset != winterOffset &&
6169
- date.getTimezoneOffset() ==
6170
- Math.min(winterOffset, summerOffset)) | 0;
6171
- HEAP32[(tmPtr + 32) >> 2] = dst;
6172
- }
6173
-
6174
- var __mktime_js = function (tmPtr) {
6175
- var ret = (() => {
6176
- var date = new Date(
6177
- HEAP32[(tmPtr + 20) >> 2] + 1900,
6178
- HEAP32[(tmPtr + 16) >> 2],
6179
- HEAP32[(tmPtr + 12) >> 2],
6180
- HEAP32[(tmPtr + 8) >> 2],
6181
- HEAP32[(tmPtr + 4) >> 2],
6182
- HEAP32[tmPtr >> 2],
6183
- 0
6184
- );
6185
- // There's an ambiguous hour when the time goes back; the tm_isdst field is
6186
- // used to disambiguate it. Date() basically guesses, so we fix it up if it
6187
- // guessed wrong, or fill in tm_isdst with the guess if it's -1.
6188
- var dst = HEAP32[(tmPtr + 32) >> 2];
6189
- var guessedOffset = date.getTimezoneOffset();
6190
- var start = new Date(date.getFullYear(), 0, 1);
6191
- var summerOffset = new Date(
6192
- date.getFullYear(),
6193
- 6,
6194
- 1
6195
- ).getTimezoneOffset();
6196
- var winterOffset = start.getTimezoneOffset();
6197
- var dstOffset = Math.min(winterOffset, summerOffset);
6198
- // DST is in December in South
6199
- if (dst < 0) {
6200
- // Attention: some regions don't have DST at all.
6201
- HEAP32[(tmPtr + 32) >> 2] = Number(
6202
- summerOffset != winterOffset && dstOffset == guessedOffset
6203
- );
6204
- } else if (dst > 0 != (dstOffset == guessedOffset)) {
6205
- var nonDstOffset = Math.max(winterOffset, summerOffset);
6206
- var trueOffset = dst > 0 ? dstOffset : nonDstOffset;
6207
- // Don't try setMinutes(date.getMinutes() + ...) -- it's messed up.
6208
- date.setTime(
6209
- date.getTime() + (trueOffset - guessedOffset) * 6e4
6210
- );
6211
- }
6212
- HEAP32[(tmPtr + 24) >> 2] = date.getDay();
6213
- var yday = ydayFromDate(date) | 0;
6214
- HEAP32[(tmPtr + 28) >> 2] = yday;
6215
- // To match expected behavior, update fields from date
6216
- HEAP32[tmPtr >> 2] = date.getSeconds();
6217
- HEAP32[(tmPtr + 4) >> 2] = date.getMinutes();
6218
- HEAP32[(tmPtr + 8) >> 2] = date.getHours();
6219
- HEAP32[(tmPtr + 12) >> 2] = date.getDate();
6220
- HEAP32[(tmPtr + 16) >> 2] = date.getMonth();
6221
- HEAP32[(tmPtr + 20) >> 2] = date.getYear();
6222
- var timeMs = date.getTime();
6223
- if (isNaN(timeMs)) {
6224
- return -1;
6225
- }
6226
- // Return time in microseconds
6227
- return timeMs / 1e3;
6228
- })();
6229
- return BigInt(ret);
6230
- };
6231
-
6232
- function __mmap_js(len, prot, flags, fd, offset, allocated, addr) {
6233
- offset = bigintToI53Checked(offset);
6234
- try {
6235
- if (isNaN(offset)) return 61;
6236
- var stream = SYSCALLS.getStreamFromFD(fd);
6237
- var res = FS.mmap(stream, len, offset, prot, flags);
6238
- var ptr = res.ptr;
6239
- HEAP32[allocated >> 2] = res.allocated;
6240
- HEAPU32[addr >> 2] = ptr;
6241
- return 0;
6229
+ return -50;
6242
6230
  } catch (e) {
6243
6231
  if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6244
6232
  return -e.errno;
6245
6233
  }
6246
6234
  }
6247
6235
 
6248
- function __munmap_js(addr, len, prot, flags, fd, offset) {
6249
- offset = bigintToI53Checked(offset);
6236
+ function ___syscall_ioctl(fd, op, varargs) {
6237
+ SYSCALLS.varargs = varargs;
6250
6238
  try {
6251
6239
  var stream = SYSCALLS.getStreamFromFD(fd);
6252
- if (prot & 2) {
6253
- SYSCALLS.doMsync(addr, stream, len, flags, offset);
6254
- }
6255
- } catch (e) {
6256
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6257
- return -e.errno;
6258
- }
6259
- }
6240
+ switch (op) {
6241
+ case 21509: {
6242
+ if (!stream.tty) return -59;
6243
+ return 0;
6244
+ }
6260
6245
 
6261
- var timers = {};
6246
+ case 21505: {
6247
+ if (!stream.tty) return -59;
6248
+ if (stream.tty.ops.ioctl_tcgets) {
6249
+ var termios = stream.tty.ops.ioctl_tcgets(stream);
6250
+ var argp = syscallGetVarargP();
6251
+ HEAP32[argp >> 2] = termios.c_iflag || 0;
6252
+ HEAP32[(argp + 4) >> 2] = termios.c_oflag || 0;
6253
+ HEAP32[(argp + 8) >> 2] = termios.c_cflag || 0;
6254
+ HEAP32[(argp + 12) >> 2] = termios.c_lflag || 0;
6255
+ for (var i = 0; i < 32; i++) {
6256
+ HEAP8[argp + i + 17] = termios.c_cc[i] || 0;
6257
+ }
6258
+ return 0;
6259
+ }
6260
+ return 0;
6261
+ }
6262
6262
 
6263
- var handleException = (e) => {
6264
- // Certain exception types we do not treat as errors since they are used for
6265
- // internal control flow.
6266
- // 1. ExitStatus, which is thrown by exit()
6267
- // 2. "unwind", which is thrown by emscripten_unwind_to_js_event_loop() and others
6268
- // that wish to return to JS event loop.
6269
- if (e instanceof ExitStatus || e == 'unwind') {
6270
- return EXITSTATUS;
6271
- }
6272
- quit_(1, e);
6273
- };
6263
+ case 21510:
6264
+ case 21511:
6265
+ case 21512: {
6266
+ if (!stream.tty) return -59;
6267
+ return 0;
6268
+ }
6274
6269
 
6275
- var keepRuntimeAlive = () => noExitRuntime || runtimeKeepaliveCounter > 0;
6270
+ case 21506:
6271
+ case 21507:
6272
+ case 21508: {
6273
+ if (!stream.tty) return -59;
6274
+ if (stream.tty.ops.ioctl_tcsets) {
6275
+ var argp = syscallGetVarargP();
6276
+ var c_iflag = HEAP32[argp >> 2];
6277
+ var c_oflag = HEAP32[(argp + 4) >> 2];
6278
+ var c_cflag = HEAP32[(argp + 8) >> 2];
6279
+ var c_lflag = HEAP32[(argp + 12) >> 2];
6280
+ var c_cc = [];
6281
+ for (var i = 0; i < 32; i++) {
6282
+ c_cc.push(HEAP8[argp + i + 17]);
6283
+ }
6284
+ return stream.tty.ops.ioctl_tcsets(stream.tty, op, {
6285
+ c_iflag,
6286
+ c_oflag,
6287
+ c_cflag,
6288
+ c_lflag,
6289
+ c_cc,
6290
+ });
6291
+ }
6292
+ return 0;
6293
+ }
6276
6294
 
6277
- var _proc_exit = (code) => {
6278
- EXITSTATUS = code;
6279
- if (!keepRuntimeAlive()) {
6280
- Module['onExit']?.(code);
6281
- ABORT = true;
6282
- }
6283
- quit_(code, new ExitStatus(code));
6284
- };
6295
+ case 21519: {
6296
+ if (!stream.tty) return -59;
6297
+ var argp = syscallGetVarargP();
6298
+ HEAP32[argp >> 2] = 0;
6299
+ return 0;
6300
+ }
6285
6301
 
6286
- /** @suppress {duplicate } */ /** @param {boolean|number=} implicit */ var exitJS =
6287
- (status, implicit) => {
6288
- EXITSTATUS = status;
6289
- if (!keepRuntimeAlive()) {
6290
- exitRuntime();
6291
- }
6292
- _proc_exit(status);
6293
- };
6302
+ case 21520: {
6303
+ if (!stream.tty) return -59;
6304
+ return -28;
6305
+ }
6294
6306
 
6295
- var _exit = exitJS;
6307
+ case 21531: {
6308
+ var argp = syscallGetVarargP();
6309
+ return FS.ioctl(stream, op, argp);
6310
+ }
6296
6311
 
6297
- Module['_exit'] = _exit;
6312
+ case 21523: {
6313
+ // TODO: in theory we should write to the winsize struct that gets
6314
+ // passed in, but for now musl doesn't read anything on it
6315
+ if (!stream.tty) return -59;
6316
+ if (stream.tty.ops.ioctl_tiocgwinsz) {
6317
+ var winsize = stream.tty.ops.ioctl_tiocgwinsz(
6318
+ stream.tty
6319
+ );
6320
+ var argp = syscallGetVarargP();
6321
+ HEAP16[argp >> 1] = winsize[0];
6322
+ HEAP16[(argp + 2) >> 1] = winsize[1];
6323
+ }
6324
+ return 0;
6325
+ }
6298
6326
 
6299
- var maybeExit = () => {
6300
- if (runtimeExited) {
6301
- return;
6302
- }
6303
- if (!keepRuntimeAlive()) {
6304
- try {
6305
- _exit(EXITSTATUS);
6306
- } catch (e) {
6307
- handleException(e);
6327
+ case 21524: {
6328
+ // TODO: technically, this ioctl call should change the window size.
6329
+ // but, since emscripten doesn't have any concept of a terminal window
6330
+ // yet, we'll just silently throw it away as we do TIOCGWINSZ
6331
+ if (!stream.tty) return -59;
6332
+ return 0;
6333
+ }
6334
+
6335
+ case 21515: {
6336
+ if (!stream.tty) return -59;
6337
+ return 0;
6338
+ }
6339
+
6340
+ default:
6341
+ return -28;
6308
6342
  }
6343
+ } catch (e) {
6344
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6345
+ return -e.errno;
6309
6346
  }
6310
- };
6347
+ }
6311
6348
 
6312
- var callUserCallback = (func) => {
6313
- if (runtimeExited || ABORT) {
6314
- return;
6315
- }
6349
+ function ___syscall_listen(fd, backlog) {
6316
6350
  try {
6317
- func();
6318
- maybeExit();
6351
+ var sock = getSocketFromFD(fd);
6352
+ sock.sock_ops.listen(sock, backlog);
6353
+ return 0;
6319
6354
  } catch (e) {
6320
- handleException(e);
6355
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6356
+ return -e.errno;
6321
6357
  }
6322
- };
6358
+ }
6323
6359
 
6324
- var _emscripten_get_now = () => performance.now();
6360
+ function ___syscall_lstat64(path, buf) {
6361
+ try {
6362
+ path = SYSCALLS.getStr(path);
6363
+ return SYSCALLS.writeStat(buf, FS.lstat(path));
6364
+ } catch (e) {
6365
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6366
+ return -e.errno;
6367
+ }
6368
+ }
6325
6369
 
6326
- var __setitimer_js = (which, timeout_ms) => {
6327
- // First, clear any existing timer.
6328
- if (timers[which]) {
6329
- clearTimeout(timers[which].id);
6330
- delete timers[which];
6370
+ function ___syscall_mkdirat(dirfd, path, mode) {
6371
+ try {
6372
+ path = SYSCALLS.getStr(path);
6373
+ path = SYSCALLS.calculateAt(dirfd, path);
6374
+ FS.mkdir(path, mode, 0);
6375
+ return 0;
6376
+ } catch (e) {
6377
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6378
+ return -e.errno;
6331
6379
  }
6332
- // A timeout of zero simply cancels the current timeout so we have nothing
6333
- // more to do.
6334
- if (!timeout_ms) return 0;
6335
- var id = setTimeout(() => {
6336
- delete timers[which];
6337
- callUserCallback(() =>
6338
- __emscripten_timeout(which, _emscripten_get_now())
6339
- );
6340
- }, timeout_ms);
6341
- timers[which] = {
6342
- id,
6343
- timeout_ms,
6344
- };
6345
- return 0;
6346
- };
6380
+ }
6347
6381
 
6348
- var __tzset_js = (timezone, daylight, std_name, dst_name) => {
6349
- // TODO: Use (malleable) environment variables instead of system settings.
6350
- var currentYear = new Date().getFullYear();
6351
- var winter = new Date(currentYear, 0, 1);
6352
- var summer = new Date(currentYear, 6, 1);
6353
- var winterOffset = winter.getTimezoneOffset();
6354
- var summerOffset = summer.getTimezoneOffset();
6355
- // Local standard timezone offset. Local standard time is not adjusted for
6356
- // daylight savings. This code uses the fact that getTimezoneOffset returns
6357
- // a greater value during Standard Time versus Daylight Saving Time (DST).
6358
- // Thus it determines the expected output during Standard Time, and it
6359
- // compares whether the output of the given date the same (Standard) or less
6360
- // (DST).
6361
- var stdTimezoneOffset = Math.max(winterOffset, summerOffset);
6362
- // timezone is specified as seconds west of UTC ("The external variable
6363
- // `timezone` shall be set to the difference, in seconds, between
6364
- // Coordinated Universal Time (UTC) and local standard time."), the same
6365
- // as returned by stdTimezoneOffset.
6366
- // See http://pubs.opengroup.org/onlinepubs/009695399/functions/tzset.html
6367
- HEAPU32[timezone >> 2] = stdTimezoneOffset * 60;
6368
- HEAP32[daylight >> 2] = Number(winterOffset != summerOffset);
6369
- var extractZone = (timezoneOffset) => {
6370
- // Why inverse sign?
6371
- // Read here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset
6372
- var sign = timezoneOffset >= 0 ? '-' : '+';
6373
- var absOffset = Math.abs(timezoneOffset);
6374
- var hours = String(Math.floor(absOffset / 60)).padStart(2, '0');
6375
- var minutes = String(absOffset % 60).padStart(2, '0');
6376
- return `UTC${sign}${hours}${minutes}`;
6377
- };
6378
- var winterName = extractZone(winterOffset);
6379
- var summerName = extractZone(summerOffset);
6380
- if (summerOffset < winterOffset) {
6381
- // Northern hemisphere
6382
- stringToUTF8(winterName, std_name, 17);
6383
- stringToUTF8(summerName, dst_name, 17);
6384
- } else {
6385
- stringToUTF8(winterName, dst_name, 17);
6386
- stringToUTF8(summerName, std_name, 17);
6382
+ function ___syscall_newfstatat(dirfd, path, buf, flags) {
6383
+ try {
6384
+ path = SYSCALLS.getStr(path);
6385
+ var nofollow = flags & 256;
6386
+ var allowEmpty = flags & 4096;
6387
+ flags = flags & ~6400;
6388
+ path = SYSCALLS.calculateAt(dirfd, path, allowEmpty);
6389
+ return SYSCALLS.writeStat(
6390
+ buf,
6391
+ nofollow ? FS.lstat(path) : FS.stat(path)
6392
+ );
6393
+ } catch (e) {
6394
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6395
+ return -e.errno;
6387
6396
  }
6388
- };
6389
-
6390
- var _emscripten_date_now = () => Date.now();
6391
-
6392
- var nowIsMonotonic = 1;
6393
-
6394
- var checkWasiClock = (clock_id) => clock_id >= 0 && clock_id <= 3;
6397
+ }
6395
6398
 
6396
- function _clock_time_get(clk_id, ignored_precision, ptime) {
6397
- ignored_precision = bigintToI53Checked(ignored_precision);
6398
- if (!checkWasiClock(clk_id)) {
6399
- return 28;
6399
+ function ___syscall_openat(dirfd, path, flags, varargs) {
6400
+ SYSCALLS.varargs = varargs;
6401
+ try {
6402
+ path = SYSCALLS.getStr(path);
6403
+ path = SYSCALLS.calculateAt(dirfd, path);
6404
+ var mode = varargs ? syscallGetVarargI() : 0;
6405
+ return FS.open(path, flags, mode).fd;
6406
+ } catch (e) {
6407
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6408
+ return -e.errno;
6400
6409
  }
6401
- var now;
6402
- // all wasi clocks but realtime are monotonic
6403
- if (clk_id === 0) {
6404
- now = _emscripten_date_now();
6405
- } else if (nowIsMonotonic) {
6406
- now = _emscripten_get_now();
6407
- } else {
6408
- return 52;
6410
+ }
6411
+
6412
+ var PIPEFS = {
6413
+ BUCKET_BUFFER_SIZE: 8192,
6414
+ mount(mount) {
6415
+ // Do not pollute the real root directory or its child nodes with pipes
6416
+ // Looks like it is OK to create another pseudo-root node not linked to the FS.root hierarchy this way
6417
+ return FS.createNode(null, '/', 16384 | 511, 0);
6418
+ },
6419
+ createPipe() {
6420
+ var pipe = {
6421
+ buckets: [],
6422
+ // refcnt 2 because pipe has a read end and a write end. We need to be
6423
+ // able to read from the read end after write end is closed.
6424
+ refcnt: 2,
6425
+ timestamp: new Date(),
6426
+ };
6427
+ pipe.buckets.push({
6428
+ buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),
6429
+ offset: 0,
6430
+ roffset: 0,
6431
+ });
6432
+ var rName = PIPEFS.nextname();
6433
+ var wName = PIPEFS.nextname();
6434
+ var rNode = FS.createNode(PIPEFS.root, rName, 4096, 0);
6435
+ var wNode = FS.createNode(PIPEFS.root, wName, 4096, 0);
6436
+ rNode.pipe = pipe;
6437
+ wNode.pipe = pipe;
6438
+ var readableStream = FS.createStream({
6439
+ path: rName,
6440
+ node: rNode,
6441
+ flags: 0,
6442
+ seekable: false,
6443
+ stream_ops: PIPEFS.stream_ops,
6444
+ });
6445
+ rNode.stream = readableStream;
6446
+ var writableStream = FS.createStream({
6447
+ path: wName,
6448
+ node: wNode,
6449
+ flags: 1,
6450
+ seekable: false,
6451
+ stream_ops: PIPEFS.stream_ops,
6452
+ });
6453
+ wNode.stream = writableStream;
6454
+ return {
6455
+ readable_fd: readableStream.fd,
6456
+ writable_fd: writableStream.fd,
6457
+ };
6458
+ },
6459
+ stream_ops: {
6460
+ getattr(stream) {
6461
+ var node = stream.node;
6462
+ var timestamp = node.pipe.timestamp;
6463
+ return {
6464
+ dev: 14,
6465
+ ino: node.id,
6466
+ mode: 4480,
6467
+ nlink: 1,
6468
+ uid: 0,
6469
+ gid: 0,
6470
+ rdev: 0,
6471
+ size: 0,
6472
+ atime: timestamp,
6473
+ mtime: timestamp,
6474
+ ctime: timestamp,
6475
+ blksize: 4096,
6476
+ blocks: 0,
6477
+ };
6478
+ },
6479
+ poll(stream) {
6480
+ var pipe = stream.node.pipe;
6481
+ if ((stream.flags & 2097155) === 1) {
6482
+ return 256 | 4;
6483
+ }
6484
+ for (var bucket of pipe.buckets) {
6485
+ if (bucket.offset - bucket.roffset > 0) {
6486
+ return 64 | 1;
6487
+ }
6488
+ }
6489
+ return 0;
6490
+ },
6491
+ dup(stream) {
6492
+ stream.node.pipe.refcnt++;
6493
+ },
6494
+ ioctl(stream, request, varargs) {
6495
+ return 28;
6496
+ },
6497
+ fsync(stream) {
6498
+ return 28;
6499
+ },
6500
+ read(stream, buffer, offset, length, position) {
6501
+ var pipe = stream.node.pipe;
6502
+ var currentLength = 0;
6503
+ for (var bucket of pipe.buckets) {
6504
+ currentLength += bucket.offset - bucket.roffset;
6505
+ }
6506
+ var data = buffer.subarray(offset, offset + length);
6507
+ if (length <= 0) {
6508
+ return 0;
6509
+ }
6510
+ if (currentLength == 0) {
6511
+ // Behave as if the read end is always non-blocking
6512
+ throw new FS.ErrnoError(6);
6513
+ }
6514
+ var toRead = Math.min(currentLength, length);
6515
+ var totalRead = toRead;
6516
+ var toRemove = 0;
6517
+ for (var bucket of pipe.buckets) {
6518
+ var bucketSize = bucket.offset - bucket.roffset;
6519
+ if (toRead <= bucketSize) {
6520
+ var tmpSlice = bucket.buffer.subarray(
6521
+ bucket.roffset,
6522
+ bucket.offset
6523
+ );
6524
+ if (toRead < bucketSize) {
6525
+ tmpSlice = tmpSlice.subarray(0, toRead);
6526
+ bucket.roffset += toRead;
6527
+ } else {
6528
+ toRemove++;
6529
+ }
6530
+ data.set(tmpSlice);
6531
+ break;
6532
+ } else {
6533
+ var tmpSlice = bucket.buffer.subarray(
6534
+ bucket.roffset,
6535
+ bucket.offset
6536
+ );
6537
+ data.set(tmpSlice);
6538
+ data = data.subarray(tmpSlice.byteLength);
6539
+ toRead -= tmpSlice.byteLength;
6540
+ toRemove++;
6541
+ }
6542
+ }
6543
+ if (toRemove && toRemove == pipe.buckets.length) {
6544
+ // Do not generate excessive garbage in use cases such as
6545
+ // write several bytes, read everything, write several bytes, read everything...
6546
+ toRemove--;
6547
+ pipe.buckets[toRemove].offset = 0;
6548
+ pipe.buckets[toRemove].roffset = 0;
6549
+ }
6550
+ pipe.buckets.splice(0, toRemove);
6551
+ return totalRead;
6552
+ },
6553
+ write(stream, buffer, offset, length, position) {
6554
+ var pipe = stream.node.pipe;
6555
+ var data = buffer.subarray(offset, offset + length);
6556
+ var dataLen = data.byteLength;
6557
+ if (dataLen <= 0) {
6558
+ return 0;
6559
+ }
6560
+ var currBucket = null;
6561
+ if (pipe.buckets.length == 0) {
6562
+ currBucket = {
6563
+ buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),
6564
+ offset: 0,
6565
+ roffset: 0,
6566
+ };
6567
+ pipe.buckets.push(currBucket);
6568
+ } else {
6569
+ currBucket = pipe.buckets[pipe.buckets.length - 1];
6570
+ }
6571
+ assert(currBucket.offset <= PIPEFS.BUCKET_BUFFER_SIZE);
6572
+ var freeBytesInCurrBuffer =
6573
+ PIPEFS.BUCKET_BUFFER_SIZE - currBucket.offset;
6574
+ if (freeBytesInCurrBuffer >= dataLen) {
6575
+ currBucket.buffer.set(data, currBucket.offset);
6576
+ currBucket.offset += dataLen;
6577
+ return dataLen;
6578
+ } else if (freeBytesInCurrBuffer > 0) {
6579
+ currBucket.buffer.set(
6580
+ data.subarray(0, freeBytesInCurrBuffer),
6581
+ currBucket.offset
6582
+ );
6583
+ currBucket.offset += freeBytesInCurrBuffer;
6584
+ data = data.subarray(
6585
+ freeBytesInCurrBuffer,
6586
+ data.byteLength
6587
+ );
6588
+ }
6589
+ var numBuckets =
6590
+ (data.byteLength / PIPEFS.BUCKET_BUFFER_SIZE) | 0;
6591
+ var remElements = data.byteLength % PIPEFS.BUCKET_BUFFER_SIZE;
6592
+ for (var i = 0; i < numBuckets; i++) {
6593
+ var newBucket = {
6594
+ buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),
6595
+ offset: PIPEFS.BUCKET_BUFFER_SIZE,
6596
+ roffset: 0,
6597
+ };
6598
+ pipe.buckets.push(newBucket);
6599
+ newBucket.buffer.set(
6600
+ data.subarray(0, PIPEFS.BUCKET_BUFFER_SIZE)
6601
+ );
6602
+ data = data.subarray(
6603
+ PIPEFS.BUCKET_BUFFER_SIZE,
6604
+ data.byteLength
6605
+ );
6606
+ }
6607
+ if (remElements > 0) {
6608
+ var newBucket = {
6609
+ buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),
6610
+ offset: data.byteLength,
6611
+ roffset: 0,
6612
+ };
6613
+ pipe.buckets.push(newBucket);
6614
+ newBucket.buffer.set(data);
6615
+ }
6616
+ return dataLen;
6617
+ },
6618
+ close(stream) {
6619
+ var pipe = stream.node.pipe;
6620
+ pipe.refcnt--;
6621
+ if (pipe.refcnt === 0) {
6622
+ pipe.buckets = null;
6623
+ }
6624
+ },
6625
+ },
6626
+ nextname() {
6627
+ if (!PIPEFS.nextname.current) {
6628
+ PIPEFS.nextname.current = 0;
6629
+ }
6630
+ return 'pipe[' + PIPEFS.nextname.current++ + ']';
6631
+ },
6632
+ };
6633
+
6634
+ function ___syscall_pipe(fdPtr) {
6635
+ try {
6636
+ if (fdPtr == 0) {
6637
+ throw new FS.ErrnoError(21);
6638
+ }
6639
+ var res = PIPEFS.createPipe();
6640
+ HEAP32[fdPtr >> 2] = res.readable_fd;
6641
+ HEAP32[(fdPtr + 4) >> 2] = res.writable_fd;
6642
+ return 0;
6643
+ } catch (e) {
6644
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6645
+ return -e.errno;
6409
6646
  }
6410
- // "now" is in ms, and wasi times are in ns.
6411
- var nsec = Math.round(now * 1e3 * 1e3);
6412
- HEAP64[ptime >> 3] = BigInt(nsec);
6413
- return 0;
6414
6647
  }
6415
6648
 
6416
- var getHeapMax = () =>
6417
- // Stay one Wasm page short of 4GB: while e.g. Chrome is able to allocate
6418
- // full 4GB Wasm memories, the size will wrap back to 0 bytes in Wasm side
6419
- // for any code that deals with heap sizes, which would require special
6420
- // casing all heap size related code to treat 0 specially.
6421
- 2147483648;
6422
-
6423
- var _emscripten_get_heap_max = () => getHeapMax();
6424
-
6425
- var growMemory = (size) => {
6426
- var b = wasmMemory.buffer;
6427
- var pages = ((size - b.byteLength + 65535) / 65536) | 0;
6649
+ function ___syscall_poll(fds, nfds, timeout) {
6428
6650
  try {
6429
- // round size grow request up to wasm page size (fixed 64KB per spec)
6430
- wasmMemory.grow(pages);
6431
- // .grow() takes a delta compared to the previous size
6432
- updateMemoryViews();
6433
- return 1;
6434
- } catch (e) {}
6435
- };
6651
+ var nonzero = 0;
6652
+ for (var i = 0; i < nfds; i++) {
6653
+ var pollfd = fds + 8 * i;
6654
+ var fd = HEAP32[pollfd >> 2];
6655
+ var events = HEAP16[(pollfd + 4) >> 1];
6656
+ var mask = 32;
6657
+ var stream = FS.getStream(fd);
6658
+ if (stream) {
6659
+ mask = SYSCALLS.DEFAULT_POLLMASK;
6660
+ if (stream.stream_ops?.poll) {
6661
+ mask = stream.stream_ops.poll(stream, -1);
6662
+ }
6663
+ }
6664
+ mask &= events | 8 | 16;
6665
+ if (mask) nonzero++;
6666
+ HEAP16[(pollfd + 6) >> 1] = mask;
6667
+ }
6668
+ return nonzero;
6669
+ } catch (e) {
6670
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6671
+ return -e.errno;
6672
+ }
6673
+ }
6436
6674
 
6437
- var _emscripten_resize_heap = (requestedSize) => {
6438
- var oldSize = HEAPU8.length;
6439
- // With CAN_ADDRESS_2GB or MEMORY64, pointers are already unsigned.
6440
- requestedSize >>>= 0;
6441
- // With multithreaded builds, races can happen (another thread might increase the size
6442
- // in between), so return a failure, and let the caller retry.
6443
- // Memory resize rules:
6444
- // 1. Always increase heap size to at least the requested size, rounded up
6445
- // to next page multiple.
6446
- // 2a. If MEMORY_GROWTH_LINEAR_STEP == -1, excessively resize the heap
6447
- // geometrically: increase the heap size according to
6448
- // MEMORY_GROWTH_GEOMETRIC_STEP factor (default +20%), At most
6449
- // overreserve by MEMORY_GROWTH_GEOMETRIC_CAP bytes (default 96MB).
6450
- // 2b. If MEMORY_GROWTH_LINEAR_STEP != -1, excessively resize the heap
6451
- // linearly: increase the heap size by at least
6452
- // MEMORY_GROWTH_LINEAR_STEP bytes.
6453
- // 3. Max size for the heap is capped at 2048MB-WASM_PAGE_SIZE, or by
6454
- // MAXIMUM_MEMORY, or by ASAN limit, depending on which is smallest
6455
- // 4. If we were unable to allocate as much memory, it may be due to
6456
- // over-eager decision to excessively reserve due to (3) above.
6457
- // Hence if an allocation fails, cut down on the amount of excess
6458
- // growth, in an attempt to succeed to perform a smaller allocation.
6459
- // A limit is set for how much we can grow. We should not exceed that
6460
- // (the wasm binary specifies it, so if we tried, we'd fail anyhow).
6461
- var maxHeapSize = getHeapMax();
6462
- if (requestedSize > maxHeapSize) {
6463
- return false;
6675
+ function ___syscall_readlinkat(dirfd, path, buf, bufsize) {
6676
+ try {
6677
+ path = SYSCALLS.getStr(path);
6678
+ path = SYSCALLS.calculateAt(dirfd, path);
6679
+ if (bufsize <= 0) return -28;
6680
+ var ret = FS.readlink(path);
6681
+ var len = Math.min(bufsize, lengthBytesUTF8(ret));
6682
+ var endChar = HEAP8[buf + len];
6683
+ stringToUTF8(ret, buf, bufsize + 1);
6684
+ // readlink is one of the rare functions that write out a C string, but does never append a null to the output buffer(!)
6685
+ // stringToUTF8() always appends a null byte, so restore the character under the null byte after the write.
6686
+ HEAP8[buf + len] = endChar;
6687
+ return len;
6688
+ } catch (e) {
6689
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6690
+ return -e.errno;
6464
6691
  }
6465
- // Loop through potential heap size increases. If we attempt a too eager
6466
- // reservation that fails, cut down on the attempted size and reserve a
6467
- // smaller bump instead. (max 3 times, chosen somewhat arbitrarily)
6468
- for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {
6469
- var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown);
6470
- // ensure geometric growth
6471
- // but limit overreserving (default to capping at +96MB overgrowth at most)
6472
- overGrownHeapSize = Math.min(
6473
- overGrownHeapSize,
6474
- requestedSize + 100663296
6475
- );
6476
- var newSize = Math.min(
6477
- maxHeapSize,
6478
- alignMemory(Math.max(requestedSize, overGrownHeapSize), 65536)
6692
+ }
6693
+
6694
+ function ___syscall_recvfrom(fd, buf, len, flags, addr, addrlen) {
6695
+ try {
6696
+ var sock = getSocketFromFD(fd);
6697
+ var msg = sock.sock_ops.recvmsg(
6698
+ sock,
6699
+ len,
6700
+ typeof flags !== 'undefined' ? flags : 0
6479
6701
  );
6480
- var replacement = growMemory(newSize);
6481
- if (replacement) {
6482
- return true;
6702
+ if (!msg) return 0;
6703
+ // socket is closed
6704
+ if (addr) {
6705
+ var errno = writeSockaddr(
6706
+ addr,
6707
+ sock.family,
6708
+ DNS.lookup_name(msg.addr),
6709
+ msg.port,
6710
+ addrlen
6711
+ );
6483
6712
  }
6713
+ HEAPU8.set(msg.buffer, buf);
6714
+ return msg.buffer.byteLength;
6715
+ } catch (e) {
6716
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6717
+ return -e.errno;
6484
6718
  }
6485
- return false;
6486
- };
6487
-
6488
- var runtimeKeepalivePush = () => {
6489
- runtimeKeepaliveCounter += 1;
6490
- };
6491
-
6492
- var runtimeKeepalivePop = () => {
6493
- runtimeKeepaliveCounter -= 1;
6494
- };
6495
-
6496
- /** @param {number=} timeout */ var safeSetTimeout = (func, timeout) => {
6497
- runtimeKeepalivePush();
6498
- return setTimeout(() => {
6499
- runtimeKeepalivePop();
6500
- callUserCallback(func);
6501
- }, timeout);
6502
- };
6503
-
6504
- var _emscripten_sleep = (ms) =>
6505
- Asyncify.handleSleep((wakeUp) => safeSetTimeout(wakeUp, ms));
6506
-
6507
- Module['_emscripten_sleep'] = _emscripten_sleep;
6508
-
6509
- _emscripten_sleep.isAsync = true;
6719
+ }
6510
6720
 
6511
- var ENV = PHPLoader.ENV || {};
6721
+ function ___syscall_renameat(olddirfd, oldpath, newdirfd, newpath) {
6722
+ try {
6723
+ oldpath = SYSCALLS.getStr(oldpath);
6724
+ newpath = SYSCALLS.getStr(newpath);
6725
+ oldpath = SYSCALLS.calculateAt(olddirfd, oldpath);
6726
+ newpath = SYSCALLS.calculateAt(newdirfd, newpath);
6727
+ FS.rename(oldpath, newpath);
6728
+ return 0;
6729
+ } catch (e) {
6730
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6731
+ return -e.errno;
6732
+ }
6733
+ }
6512
6734
 
6513
- var getExecutableName = () => thisProgram || './this.program';
6735
+ function ___syscall_rmdir(path) {
6736
+ try {
6737
+ path = SYSCALLS.getStr(path);
6738
+ FS.rmdir(path);
6739
+ return 0;
6740
+ } catch (e) {
6741
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6742
+ return -e.errno;
6743
+ }
6744
+ }
6514
6745
 
6515
- var getEnvStrings = () => {
6516
- if (!getEnvStrings.strings) {
6517
- // Default values.
6518
- // Browser language detection #8751
6519
- var lang =
6520
- (
6521
- (typeof navigator == 'object' &&
6522
- navigator.languages &&
6523
- navigator.languages[0]) ||
6524
- 'C'
6525
- ).replace('-', '_') + '.UTF-8';
6526
- var env = {
6527
- USER: 'web_user',
6528
- LOGNAME: 'web_user',
6529
- PATH: '/',
6530
- PWD: '/',
6531
- HOME: '/home/web_user',
6532
- LANG: lang,
6533
- _: getExecutableName(),
6534
- };
6535
- // Apply the user-provided values, if any.
6536
- for (var x in ENV) {
6537
- // x is a key in ENV; if ENV[x] is undefined, that means it was
6538
- // explicitly set to be so. We allow user code to do that to
6539
- // force variables with default values to remain unset.
6540
- if (ENV[x] === undefined) delete env[x];
6541
- else env[x] = ENV[x];
6542
- }
6543
- var strings = [];
6544
- for (var x in env) {
6545
- strings.push(`${x}=${env[x]}`);
6746
+ function ___syscall_sendto(fd, message, length, flags, addr, addr_len) {
6747
+ try {
6748
+ var sock = getSocketFromFD(fd);
6749
+ if (!addr) {
6750
+ // send, no address provided
6751
+ return FS.write(sock.stream, HEAP8, message, length);
6546
6752
  }
6547
- getEnvStrings.strings = strings;
6753
+ var dest = getSocketAddress(addr, addr_len);
6754
+ // sendto an address
6755
+ return sock.sock_ops.sendmsg(
6756
+ sock,
6757
+ HEAP8,
6758
+ message,
6759
+ length,
6760
+ dest.addr,
6761
+ dest.port
6762
+ );
6763
+ } catch (e) {
6764
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6765
+ return -e.errno;
6766
+ }
6767
+ }
6768
+
6769
+ function ___syscall_socket(domain, type, protocol) {
6770
+ try {
6771
+ var sock = SOCKFS.createSocket(domain, type, protocol);
6772
+ return sock.stream.fd;
6773
+ } catch (e) {
6774
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6775
+ return -e.errno;
6548
6776
  }
6549
- return getEnvStrings.strings;
6550
- };
6777
+ }
6551
6778
 
6552
- var stringToAscii = (str, buffer) => {
6553
- for (var i = 0; i < str.length; ++i) {
6554
- HEAP8[buffer++] = str.charCodeAt(i);
6779
+ function ___syscall_stat64(path, buf) {
6780
+ try {
6781
+ path = SYSCALLS.getStr(path);
6782
+ return SYSCALLS.writeStat(buf, FS.stat(path));
6783
+ } catch (e) {
6784
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6785
+ return -e.errno;
6555
6786
  }
6556
- // Null-terminate the string
6557
- HEAP8[buffer] = 0;
6558
- };
6787
+ }
6559
6788
 
6560
- var _environ_get = (__environ, environ_buf) => {
6561
- var bufSize = 0;
6562
- getEnvStrings().forEach((string, i) => {
6563
- var ptr = environ_buf + bufSize;
6564
- HEAPU32[(__environ + i * 4) >> 2] = ptr;
6565
- stringToAscii(string, ptr);
6566
- bufSize += string.length + 1;
6567
- });
6568
- return 0;
6569
- };
6789
+ function ___syscall_statfs64(path, size, buf) {
6790
+ try {
6791
+ SYSCALLS.writeStatFs(buf, FS.statfs(SYSCALLS.getStr(path)));
6792
+ return 0;
6793
+ } catch (e) {
6794
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6795
+ return -e.errno;
6796
+ }
6797
+ }
6570
6798
 
6571
- var _environ_sizes_get = (penviron_count, penviron_buf_size) => {
6572
- var strings = getEnvStrings();
6573
- HEAPU32[penviron_count >> 2] = strings.length;
6574
- var bufSize = 0;
6575
- strings.forEach((string) => (bufSize += string.length + 1));
6576
- HEAPU32[penviron_buf_size >> 2] = bufSize;
6577
- return 0;
6578
- };
6799
+ function ___syscall_symlinkat(target, dirfd, linkpath) {
6800
+ try {
6801
+ target = SYSCALLS.getStr(target);
6802
+ linkpath = SYSCALLS.getStr(linkpath);
6803
+ linkpath = SYSCALLS.calculateAt(dirfd, linkpath);
6804
+ FS.symlink(target, linkpath);
6805
+ return 0;
6806
+ } catch (e) {
6807
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6808
+ return -e.errno;
6809
+ }
6810
+ }
6579
6811
 
6580
- function _fd_close(fd) {
6812
+ function ___syscall_unlinkat(dirfd, path, flags) {
6581
6813
  try {
6582
- var stream = SYSCALLS.getStreamFromFD(fd);
6583
- FS.close(stream);
6814
+ path = SYSCALLS.getStr(path);
6815
+ path = SYSCALLS.calculateAt(dirfd, path);
6816
+ if (flags === 0) {
6817
+ FS.unlink(path);
6818
+ } else if (flags === 512) {
6819
+ FS.rmdir(path);
6820
+ } else {
6821
+ abort('Invalid flags passed to unlinkat');
6822
+ }
6584
6823
  return 0;
6585
6824
  } catch (e) {
6586
6825
  if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6587
- return e.errno;
6826
+ return -e.errno;
6588
6827
  }
6589
6828
  }
6590
6829
 
6591
- function _fd_fdstat_get(fd, pbuf) {
6830
+ var readI53FromI64 = (ptr) =>
6831
+ HEAPU32[ptr >> 2] + HEAP32[(ptr + 4) >> 2] * 4294967296;
6832
+
6833
+ function ___syscall_utimensat(dirfd, path, times, flags) {
6592
6834
  try {
6593
- var rightsBase = 0;
6594
- var rightsInheriting = 0;
6595
- var flags = 0;
6596
- {
6597
- var stream = SYSCALLS.getStreamFromFD(fd);
6598
- // All character devices are terminals (other things a Linux system would
6599
- // assume is a character device, like the mouse, we have special APIs for).
6600
- var type = stream.tty
6601
- ? 2
6602
- : FS.isDir(stream.mode)
6603
- ? 3
6604
- : FS.isLink(stream.mode)
6605
- ? 7
6606
- : 4;
6835
+ path = SYSCALLS.getStr(path);
6836
+ path = SYSCALLS.calculateAt(dirfd, path, true);
6837
+ var now = Date.now(),
6838
+ atime,
6839
+ mtime;
6840
+ if (!times) {
6841
+ atime = now;
6842
+ mtime = now;
6843
+ } else {
6844
+ var seconds = readI53FromI64(times);
6845
+ var nanoseconds = HEAP32[(times + 8) >> 2];
6846
+ if (nanoseconds == 1073741823) {
6847
+ atime = now;
6848
+ } else if (nanoseconds == 1073741822) {
6849
+ atime = null;
6850
+ } else {
6851
+ atime = seconds * 1e3 + nanoseconds / (1e3 * 1e3);
6852
+ }
6853
+ times += 16;
6854
+ seconds = readI53FromI64(times);
6855
+ nanoseconds = HEAP32[(times + 8) >> 2];
6856
+ if (nanoseconds == 1073741823) {
6857
+ mtime = now;
6858
+ } else if (nanoseconds == 1073741822) {
6859
+ mtime = null;
6860
+ } else {
6861
+ mtime = seconds * 1e3 + nanoseconds / (1e3 * 1e3);
6862
+ }
6863
+ }
6864
+ // null here means UTIME_OMIT was passed. If both were set to UTIME_OMIT then
6865
+ // we can skip the call completely.
6866
+ if ((mtime ?? atime) !== null) {
6867
+ FS.utime(path, atime, mtime);
6607
6868
  }
6608
- HEAP8[pbuf] = type;
6609
- HEAP16[(pbuf + 2) >> 1] = flags;
6610
- HEAP64[(pbuf + 8) >> 3] = BigInt(rightsBase);
6611
- HEAP64[(pbuf + 16) >> 3] = BigInt(rightsInheriting);
6612
6869
  return 0;
6613
6870
  } catch (e) {
6614
6871
  if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6615
- return e.errno;
6872
+ return -e.errno;
6616
6873
  }
6617
6874
  }
6618
6875
 
6619
- /** @param {number=} offset */ var doReadv = (
6620
- stream,
6621
- iov,
6622
- iovcnt,
6623
- offset
6624
- ) => {
6625
- var ret = 0;
6626
- for (var i = 0; i < iovcnt; i++) {
6627
- var ptr = HEAPU32[iov >> 2];
6628
- var len = HEAPU32[(iov + 4) >> 2];
6629
- iov += 8;
6630
- var curr = FS.read(stream, HEAP8, ptr, len, offset);
6631
- if (curr < 0) return -1;
6632
- ret += curr;
6633
- if (curr < len) break;
6634
- // nothing more to read
6635
- if (typeof offset != 'undefined') {
6636
- offset += curr;
6876
+ var __abort_js = () => abort('');
6877
+
6878
+ var __emscripten_lookup_name = (name) => {
6879
+ // uint32_t _emscripten_lookup_name(const char *name);
6880
+ var nameString = UTF8ToString(name);
6881
+ return inetPton4(DNS.lookup_name(nameString));
6882
+ };
6883
+
6884
+ var runtimeKeepaliveCounter = 0;
6885
+
6886
+ var __emscripten_runtime_keepalive_clear = () => {
6887
+ noExitRuntime = false;
6888
+ runtimeKeepaliveCounter = 0;
6889
+ };
6890
+
6891
+ function __gmtime_js(time, tmPtr) {
6892
+ time = bigintToI53Checked(time);
6893
+ var date = new Date(time * 1e3);
6894
+ HEAP32[tmPtr >> 2] = date.getUTCSeconds();
6895
+ HEAP32[(tmPtr + 4) >> 2] = date.getUTCMinutes();
6896
+ HEAP32[(tmPtr + 8) >> 2] = date.getUTCHours();
6897
+ HEAP32[(tmPtr + 12) >> 2] = date.getUTCDate();
6898
+ HEAP32[(tmPtr + 16) >> 2] = date.getUTCMonth();
6899
+ HEAP32[(tmPtr + 20) >> 2] = date.getUTCFullYear() - 1900;
6900
+ HEAP32[(tmPtr + 24) >> 2] = date.getUTCDay();
6901
+ var start = Date.UTC(date.getUTCFullYear(), 0, 1, 0, 0, 0, 0);
6902
+ var yday = ((date.getTime() - start) / (1e3 * 60 * 60 * 24)) | 0;
6903
+ HEAP32[(tmPtr + 28) >> 2] = yday;
6904
+ }
6905
+
6906
+ var isLeapYear = (year) =>
6907
+ year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
6908
+
6909
+ var MONTH_DAYS_LEAP_CUMULATIVE = [
6910
+ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335,
6911
+ ];
6912
+
6913
+ var MONTH_DAYS_REGULAR_CUMULATIVE = [
6914
+ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
6915
+ ];
6916
+
6917
+ var ydayFromDate = (date) => {
6918
+ var leap = isLeapYear(date.getFullYear());
6919
+ var monthDaysCumulative = leap
6920
+ ? MONTH_DAYS_LEAP_CUMULATIVE
6921
+ : MONTH_DAYS_REGULAR_CUMULATIVE;
6922
+ var yday = monthDaysCumulative[date.getMonth()] + date.getDate() - 1;
6923
+ // -1 since it's days since Jan 1
6924
+ return yday;
6925
+ };
6926
+
6927
+ function __localtime_js(time, tmPtr) {
6928
+ time = bigintToI53Checked(time);
6929
+ var date = new Date(time * 1e3);
6930
+ HEAP32[tmPtr >> 2] = date.getSeconds();
6931
+ HEAP32[(tmPtr + 4) >> 2] = date.getMinutes();
6932
+ HEAP32[(tmPtr + 8) >> 2] = date.getHours();
6933
+ HEAP32[(tmPtr + 12) >> 2] = date.getDate();
6934
+ HEAP32[(tmPtr + 16) >> 2] = date.getMonth();
6935
+ HEAP32[(tmPtr + 20) >> 2] = date.getFullYear() - 1900;
6936
+ HEAP32[(tmPtr + 24) >> 2] = date.getDay();
6937
+ var yday = ydayFromDate(date) | 0;
6938
+ HEAP32[(tmPtr + 28) >> 2] = yday;
6939
+ HEAP32[(tmPtr + 36) >> 2] = -(date.getTimezoneOffset() * 60);
6940
+ // Attention: DST is in December in South, and some regions don't have DST at all.
6941
+ var start = new Date(date.getFullYear(), 0, 1);
6942
+ var summerOffset = new Date(
6943
+ date.getFullYear(),
6944
+ 6,
6945
+ 1
6946
+ ).getTimezoneOffset();
6947
+ var winterOffset = start.getTimezoneOffset();
6948
+ var dst =
6949
+ (summerOffset != winterOffset &&
6950
+ date.getTimezoneOffset() ==
6951
+ Math.min(winterOffset, summerOffset)) | 0;
6952
+ HEAP32[(tmPtr + 32) >> 2] = dst;
6953
+ }
6954
+
6955
+ var __mktime_js = function (tmPtr) {
6956
+ var ret = (() => {
6957
+ var date = new Date(
6958
+ HEAP32[(tmPtr + 20) >> 2] + 1900,
6959
+ HEAP32[(tmPtr + 16) >> 2],
6960
+ HEAP32[(tmPtr + 12) >> 2],
6961
+ HEAP32[(tmPtr + 8) >> 2],
6962
+ HEAP32[(tmPtr + 4) >> 2],
6963
+ HEAP32[tmPtr >> 2],
6964
+ 0
6965
+ );
6966
+ // There's an ambiguous hour when the time goes back; the tm_isdst field is
6967
+ // used to disambiguate it. Date() basically guesses, so we fix it up if it
6968
+ // guessed wrong, or fill in tm_isdst with the guess if it's -1.
6969
+ var dst = HEAP32[(tmPtr + 32) >> 2];
6970
+ var guessedOffset = date.getTimezoneOffset();
6971
+ var start = new Date(date.getFullYear(), 0, 1);
6972
+ var summerOffset = new Date(
6973
+ date.getFullYear(),
6974
+ 6,
6975
+ 1
6976
+ ).getTimezoneOffset();
6977
+ var winterOffset = start.getTimezoneOffset();
6978
+ var dstOffset = Math.min(winterOffset, summerOffset);
6979
+ // DST is in December in South
6980
+ if (dst < 0) {
6981
+ // Attention: some regions don't have DST at all.
6982
+ HEAP32[(tmPtr + 32) >> 2] = Number(
6983
+ summerOffset != winterOffset && dstOffset == guessedOffset
6984
+ );
6985
+ } else if (dst > 0 != (dstOffset == guessedOffset)) {
6986
+ var nonDstOffset = Math.max(winterOffset, summerOffset);
6987
+ var trueOffset = dst > 0 ? dstOffset : nonDstOffset;
6988
+ // Don't try setMinutes(date.getMinutes() + ...) -- it's messed up.
6989
+ date.setTime(
6990
+ date.getTime() + (trueOffset - guessedOffset) * 6e4
6991
+ );
6637
6992
  }
6638
- }
6639
- return ret;
6993
+ HEAP32[(tmPtr + 24) >> 2] = date.getDay();
6994
+ var yday = ydayFromDate(date) | 0;
6995
+ HEAP32[(tmPtr + 28) >> 2] = yday;
6996
+ // To match expected behavior, update fields from date
6997
+ HEAP32[tmPtr >> 2] = date.getSeconds();
6998
+ HEAP32[(tmPtr + 4) >> 2] = date.getMinutes();
6999
+ HEAP32[(tmPtr + 8) >> 2] = date.getHours();
7000
+ HEAP32[(tmPtr + 12) >> 2] = date.getDate();
7001
+ HEAP32[(tmPtr + 16) >> 2] = date.getMonth();
7002
+ HEAP32[(tmPtr + 20) >> 2] = date.getYear();
7003
+ var timeMs = date.getTime();
7004
+ if (isNaN(timeMs)) {
7005
+ return -1;
7006
+ }
7007
+ // Return time in microseconds
7008
+ return timeMs / 1e3;
7009
+ })();
7010
+ return BigInt(ret);
6640
7011
  };
6641
7012
 
6642
- function _fd_read(fd, iov, iovcnt, pnum) {
7013
+ function __mmap_js(len, prot, flags, fd, offset, allocated, addr) {
7014
+ offset = bigintToI53Checked(offset);
6643
7015
  try {
7016
+ if (isNaN(offset)) return 61;
6644
7017
  var stream = SYSCALLS.getStreamFromFD(fd);
6645
- var num = doReadv(stream, iov, iovcnt);
6646
- HEAPU32[pnum >> 2] = num;
7018
+ var res = FS.mmap(stream, len, offset, prot, flags);
7019
+ var ptr = res.ptr;
7020
+ HEAP32[allocated >> 2] = res.allocated;
7021
+ HEAPU32[addr >> 2] = ptr;
6647
7022
  return 0;
6648
7023
  } catch (e) {
6649
7024
  if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6650
- return e.errno;
7025
+ return -e.errno;
6651
7026
  }
6652
7027
  }
6653
7028
 
6654
- function _fd_seek(fd, offset, whence, newOffset) {
7029
+ function __munmap_js(addr, len, prot, flags, fd, offset) {
6655
7030
  offset = bigintToI53Checked(offset);
6656
7031
  try {
6657
- if (isNaN(offset)) return 61;
6658
7032
  var stream = SYSCALLS.getStreamFromFD(fd);
6659
- FS.llseek(stream, offset, whence);
6660
- HEAP64[newOffset >> 3] = BigInt(stream.position);
6661
- if (stream.getdents && offset === 0 && whence === 0)
6662
- stream.getdents = null;
6663
- // reset readdir state
6664
- return 0;
7033
+ if (prot & 2) {
7034
+ SYSCALLS.doMsync(addr, stream, len, flags, offset);
7035
+ }
6665
7036
  } catch (e) {
6666
7037
  if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6667
- return e.errno;
7038
+ return -e.errno;
6668
7039
  }
6669
7040
  }
6670
7041
 
6671
- var _fd_sync = function (fd) {
6672
- try {
6673
- var stream = SYSCALLS.getStreamFromFD(fd);
6674
- return Asyncify.handleSleep((wakeUp) => {
6675
- var mount = stream.node.mount;
6676
- if (!mount.type.syncfs) {
6677
- // We write directly to the file system, so there's nothing to do here.
6678
- wakeUp(0);
6679
- return;
6680
- }
6681
- mount.type.syncfs(mount, false, (err) => {
6682
- if (err) {
6683
- wakeUp(29);
6684
- return;
6685
- }
6686
- wakeUp(0);
6687
- });
6688
- });
6689
- } catch (e) {
6690
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6691
- return e.errno;
7042
+ var timers = {};
7043
+
7044
+ var handleException = (e) => {
7045
+ // Certain exception types we do not treat as errors since they are used for
7046
+ // internal control flow.
7047
+ // 1. ExitStatus, which is thrown by exit()
7048
+ // 2. "unwind", which is thrown by emscripten_unwind_to_js_event_loop() and others
7049
+ // that wish to return to JS event loop.
7050
+ if (e instanceof ExitStatus || e == 'unwind') {
7051
+ return EXITSTATUS;
6692
7052
  }
7053
+ quit_(1, e);
6693
7054
  };
6694
7055
 
6695
- _fd_sync.isAsync = true;
7056
+ var keepRuntimeAlive = () => noExitRuntime || runtimeKeepaliveCounter > 0;
6696
7057
 
6697
- /** @param {number=} offset */ var doWritev = (
6698
- stream,
6699
- iov,
6700
- iovcnt,
6701
- offset
6702
- ) => {
6703
- var ret = 0;
6704
- for (var i = 0; i < iovcnt; i++) {
6705
- var ptr = HEAPU32[iov >> 2];
6706
- var len = HEAPU32[(iov + 4) >> 2];
6707
- iov += 8;
6708
- var curr = FS.write(stream, HEAP8, ptr, len, offset);
6709
- if (curr < 0) return -1;
6710
- ret += curr;
6711
- if (curr < len) {
6712
- // No more space to write.
6713
- break;
6714
- }
6715
- if (typeof offset != 'undefined') {
6716
- offset += curr;
6717
- }
7058
+ var _proc_exit = (code) => {
7059
+ EXITSTATUS = code;
7060
+ if (!keepRuntimeAlive()) {
7061
+ Module['onExit']?.(code);
7062
+ ABORT = true;
6718
7063
  }
6719
- return ret;
7064
+ quit_(code, new ExitStatus(code));
6720
7065
  };
6721
7066
 
6722
- function _fd_write(fd, iov, iovcnt, pnum) {
6723
- try {
6724
- var stream = SYSCALLS.getStreamFromFD(fd);
6725
- var num = doWritev(stream, iov, iovcnt);
6726
- HEAPU32[pnum >> 2] = num;
6727
- return 0;
6728
- } catch (e) {
6729
- if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
6730
- return e.errno;
6731
- }
6732
- }
6733
-
6734
- var _getaddrinfo = (node, service, hint, out) => {
6735
- var addr = 0;
6736
- var port = 0;
6737
- var flags = 0;
6738
- var family = 0;
6739
- var type = 0;
6740
- var proto = 0;
6741
- var ai;
6742
- function allocaddrinfo(family, type, proto, canon, addr, port) {
6743
- var sa, salen, ai;
6744
- var errno;
6745
- salen = family === 10 ? 28 : 16;
6746
- addr = family === 10 ? inetNtop6(addr) : inetNtop4(addr);
6747
- sa = _malloc(salen);
6748
- errno = writeSockaddr(sa, family, addr, port);
6749
- assert(!errno);
6750
- ai = _malloc(32);
6751
- HEAP32[(ai + 4) >> 2] = family;
6752
- HEAP32[(ai + 8) >> 2] = type;
6753
- HEAP32[(ai + 12) >> 2] = proto;
6754
- HEAPU32[(ai + 24) >> 2] = canon;
6755
- HEAPU32[(ai + 20) >> 2] = sa;
6756
- if (family === 10) {
6757
- HEAP32[(ai + 16) >> 2] = 28;
6758
- } else {
6759
- HEAP32[(ai + 16) >> 2] = 16;
6760
- }
6761
- HEAP32[(ai + 28) >> 2] = 0;
6762
- return ai;
6763
- }
6764
- if (hint) {
6765
- flags = HEAP32[hint >> 2];
6766
- family = HEAP32[(hint + 4) >> 2];
6767
- type = HEAP32[(hint + 8) >> 2];
6768
- proto = HEAP32[(hint + 12) >> 2];
6769
- }
6770
- if (type && !proto) {
6771
- proto = type === 2 ? 17 : 6;
6772
- }
6773
- if (!type && proto) {
6774
- type = proto === 17 ? 2 : 1;
6775
- }
6776
- // If type or proto are set to zero in hints we should really be returning multiple addrinfo values, but for
6777
- // now default to a TCP STREAM socket so we can at least return a sensible addrinfo given NULL hints.
6778
- if (proto === 0) {
6779
- proto = 6;
6780
- }
6781
- if (type === 0) {
6782
- type = 1;
6783
- }
6784
- if (!node && !service) {
6785
- return -2;
6786
- }
6787
- if (flags & ~(1 | 2 | 4 | 1024 | 8 | 16 | 32)) {
6788
- return -1;
6789
- }
6790
- if (hint !== 0 && HEAP32[hint >> 2] & 2 && !node) {
6791
- return -1;
6792
- }
6793
- if (flags & 32) {
6794
- // TODO
6795
- return -2;
6796
- }
6797
- if (type !== 0 && type !== 1 && type !== 2) {
6798
- return -7;
6799
- }
6800
- if (family !== 0 && family !== 2 && family !== 10) {
6801
- return -6;
6802
- }
6803
- if (service) {
6804
- service = UTF8ToString(service);
6805
- port = parseInt(service, 10);
6806
- if (isNaN(port)) {
6807
- if (flags & 1024) {
6808
- return -2;
6809
- }
6810
- // TODO support resolving well-known service names from:
6811
- // http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt
6812
- return -8;
6813
- }
6814
- }
6815
- if (!node) {
6816
- if (family === 0) {
6817
- family = 2;
6818
- }
6819
- if ((flags & 1) === 0) {
6820
- if (family === 2) {
6821
- addr = _htonl(2130706433);
6822
- } else {
6823
- addr = [0, 0, 0, _htonl(1)];
6824
- }
6825
- }
6826
- ai = allocaddrinfo(family, type, proto, null, addr, port);
6827
- HEAPU32[out >> 2] = ai;
6828
- return 0;
6829
- }
6830
- // try as a numeric address
6831
- node = UTF8ToString(node);
6832
- addr = inetPton4(node);
6833
- if (addr !== null) {
6834
- // incoming node is a valid ipv4 address
6835
- if (family === 0 || family === 2) {
6836
- family = 2;
6837
- } else if (family === 10 && flags & 8) {
6838
- addr = [0, 0, _htonl(65535), addr];
6839
- family = 10;
6840
- } else {
6841
- return -2;
6842
- }
6843
- } else {
6844
- addr = inetPton6(node);
6845
- if (addr !== null) {
6846
- // incoming node is a valid ipv6 address
6847
- if (family === 0 || family === 10) {
6848
- family = 10;
6849
- } else {
6850
- return -2;
6851
- }
7067
+ /** @suppress {duplicate } */ /** @param {boolean|number=} implicit */ var exitJS =
7068
+ (status, implicit) => {
7069
+ EXITSTATUS = status;
7070
+ if (!keepRuntimeAlive()) {
7071
+ exitRuntime();
6852
7072
  }
7073
+ _proc_exit(status);
7074
+ };
7075
+
7076
+ var _exit = exitJS;
7077
+
7078
+ Module['_exit'] = _exit;
7079
+
7080
+ var maybeExit = () => {
7081
+ if (runtimeExited) {
7082
+ return;
6853
7083
  }
6854
- if (addr != null) {
6855
- ai = allocaddrinfo(family, type, proto, node, addr, port);
6856
- HEAPU32[out >> 2] = ai;
6857
- return 0;
7084
+ if (!keepRuntimeAlive()) {
7085
+ try {
7086
+ _exit(EXITSTATUS);
7087
+ } catch (e) {
7088
+ handleException(e);
7089
+ }
6858
7090
  }
6859
- if (flags & 4) {
6860
- return -2;
7091
+ };
7092
+
7093
+ var callUserCallback = (func) => {
7094
+ if (runtimeExited || ABORT) {
7095
+ return;
6861
7096
  }
6862
- // try as a hostname
6863
- // resolve the hostname to a temporary fake address
6864
- node = DNS.lookup_name(node);
6865
- addr = inetPton4(node);
6866
- if (family === 0) {
6867
- family = 2;
6868
- } else if (family === 10) {
6869
- addr = [0, 0, _htonl(65535), addr];
7097
+ try {
7098
+ func();
7099
+ maybeExit();
7100
+ } catch (e) {
7101
+ handleException(e);
6870
7102
  }
6871
- ai = allocaddrinfo(family, type, proto, null, addr, port);
6872
- HEAPU32[out >> 2] = ai;
6873
- return 0;
6874
7103
  };
6875
7104
 
6876
- var _getcontext = () => abort('missing function: ${name}');
7105
+ var _emscripten_get_now = () => performance.now();
6877
7106
 
6878
- var _getnameinfo = (sa, salen, node, nodelen, serv, servlen, flags) => {
6879
- var info = readSockaddr(sa, salen);
6880
- if (info.errno) {
6881
- return -6;
7107
+ var __setitimer_js = (which, timeout_ms) => {
7108
+ // First, clear any existing timer.
7109
+ if (timers[which]) {
7110
+ clearTimeout(timers[which].id);
7111
+ delete timers[which];
6882
7112
  }
6883
- var port = info.port;
6884
- var addr = info.addr;
6885
- var overflowed = false;
6886
- if (node && nodelen) {
6887
- var lookup;
6888
- if (flags & 1 || !(lookup = DNS.lookup_addr(addr))) {
6889
- if (flags & 8) {
6890
- return -2;
6891
- }
6892
- } else {
6893
- addr = lookup;
6894
- }
6895
- var numBytesWrittenExclNull = stringToUTF8(addr, node, nodelen);
6896
- if (numBytesWrittenExclNull + 1 >= nodelen) {
6897
- overflowed = true;
6898
- }
7113
+ // A timeout of zero simply cancels the current timeout so we have nothing
7114
+ // more to do.
7115
+ if (!timeout_ms) return 0;
7116
+ var id = setTimeout(() => {
7117
+ delete timers[which];
7118
+ callUserCallback(() =>
7119
+ __emscripten_timeout(which, _emscripten_get_now())
7120
+ );
7121
+ }, timeout_ms);
7122
+ timers[which] = {
7123
+ id,
7124
+ timeout_ms,
7125
+ };
7126
+ return 0;
7127
+ };
7128
+
7129
+ var __tzset_js = (timezone, daylight, std_name, dst_name) => {
7130
+ // TODO: Use (malleable) environment variables instead of system settings.
7131
+ var currentYear = new Date().getFullYear();
7132
+ var winter = new Date(currentYear, 0, 1);
7133
+ var summer = new Date(currentYear, 6, 1);
7134
+ var winterOffset = winter.getTimezoneOffset();
7135
+ var summerOffset = summer.getTimezoneOffset();
7136
+ // Local standard timezone offset. Local standard time is not adjusted for
7137
+ // daylight savings. This code uses the fact that getTimezoneOffset returns
7138
+ // a greater value during Standard Time versus Daylight Saving Time (DST).
7139
+ // Thus it determines the expected output during Standard Time, and it
7140
+ // compares whether the output of the given date the same (Standard) or less
7141
+ // (DST).
7142
+ var stdTimezoneOffset = Math.max(winterOffset, summerOffset);
7143
+ // timezone is specified as seconds west of UTC ("The external variable
7144
+ // `timezone` shall be set to the difference, in seconds, between
7145
+ // Coordinated Universal Time (UTC) and local standard time."), the same
7146
+ // as returned by stdTimezoneOffset.
7147
+ // See http://pubs.opengroup.org/onlinepubs/009695399/functions/tzset.html
7148
+ HEAPU32[timezone >> 2] = stdTimezoneOffset * 60;
7149
+ HEAP32[daylight >> 2] = Number(winterOffset != summerOffset);
7150
+ var extractZone = (timezoneOffset) => {
7151
+ // Why inverse sign?
7152
+ // Read here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset
7153
+ var sign = timezoneOffset >= 0 ? '-' : '+';
7154
+ var absOffset = Math.abs(timezoneOffset);
7155
+ var hours = String(Math.floor(absOffset / 60)).padStart(2, '0');
7156
+ var minutes = String(absOffset % 60).padStart(2, '0');
7157
+ return `UTC${sign}${hours}${minutes}`;
7158
+ };
7159
+ var winterName = extractZone(winterOffset);
7160
+ var summerName = extractZone(summerOffset);
7161
+ if (summerOffset < winterOffset) {
7162
+ // Northern hemisphere
7163
+ stringToUTF8(winterName, std_name, 17);
7164
+ stringToUTF8(summerName, dst_name, 17);
7165
+ } else {
7166
+ stringToUTF8(winterName, dst_name, 17);
7167
+ stringToUTF8(summerName, std_name, 17);
6899
7168
  }
6900
- if (serv && servlen) {
6901
- port = '' + port;
6902
- var numBytesWrittenExclNull = stringToUTF8(port, serv, servlen);
6903
- if (numBytesWrittenExclNull + 1 >= servlen) {
6904
- overflowed = true;
6905
- }
7169
+ };
7170
+
7171
+ var _emscripten_date_now = () => Date.now();
7172
+
7173
+ var nowIsMonotonic = 1;
7174
+
7175
+ var checkWasiClock = (clock_id) => clock_id >= 0 && clock_id <= 3;
7176
+
7177
+ function _clock_time_get(clk_id, ignored_precision, ptime) {
7178
+ ignored_precision = bigintToI53Checked(ignored_precision);
7179
+ if (!checkWasiClock(clk_id)) {
7180
+ return 28;
6906
7181
  }
6907
- if (overflowed) {
6908
- // Note: even when we overflow, getnameinfo() is specced to write out the truncated results.
6909
- return -12;
7182
+ var now;
7183
+ // all wasi clocks but realtime are monotonic
7184
+ if (clk_id === 0) {
7185
+ now = _emscripten_date_now();
7186
+ } else if (nowIsMonotonic) {
7187
+ now = _emscripten_get_now();
7188
+ } else {
7189
+ return 52;
6910
7190
  }
7191
+ // "now" is in ms, and wasi times are in ns.
7192
+ var nsec = Math.round(now * 1e3 * 1e3);
7193
+ HEAP64[ptime >> 3] = BigInt(nsec);
6911
7194
  return 0;
6912
- };
7195
+ }
6913
7196
 
6914
- var Protocols = {
6915
- list: [],
6916
- map: {},
7197
+ var getHeapMax = () =>
7198
+ // Stay one Wasm page short of 4GB: while e.g. Chrome is able to allocate
7199
+ // full 4GB Wasm memories, the size will wrap back to 0 bytes in Wasm side
7200
+ // for any code that deals with heap sizes, which would require special
7201
+ // casing all heap size related code to treat 0 specially.
7202
+ 2147483648;
7203
+
7204
+ var _emscripten_get_heap_max = () => getHeapMax();
7205
+
7206
+ var growMemory = (size) => {
7207
+ var b = wasmMemory.buffer;
7208
+ var pages = ((size - b.byteLength + 65535) / 65536) | 0;
7209
+ try {
7210
+ // round size grow request up to wasm page size (fixed 64KB per spec)
7211
+ wasmMemory.grow(pages);
7212
+ // .grow() takes a delta compared to the previous size
7213
+ updateMemoryViews();
7214
+ return 1;
7215
+ } catch (e) {}
6917
7216
  };
6918
7217
 
6919
- var _setprotoent = (stayopen) => {
6920
- // void setprotoent(int stayopen);
6921
- // Allocate and populate a protoent structure given a name, protocol number and array of aliases
6922
- function allocprotoent(name, proto, aliases) {
6923
- // write name into buffer
6924
- var nameBuf = _malloc(name.length + 1);
6925
- stringToAscii(name, nameBuf);
6926
- // write aliases into buffer
6927
- var j = 0;
6928
- var length = aliases.length;
6929
- var aliasListBuf = _malloc((length + 1) * 4);
6930
- // Use length + 1 so we have space for the terminating NULL ptr.
6931
- for (var i = 0; i < length; i++, j += 4) {
6932
- var alias = aliases[i];
6933
- var aliasBuf = _malloc(alias.length + 1);
6934
- stringToAscii(alias, aliasBuf);
6935
- HEAPU32[(aliasListBuf + j) >> 2] = aliasBuf;
6936
- }
6937
- HEAPU32[(aliasListBuf + j) >> 2] = 0;
6938
- // Terminating NULL pointer.
6939
- // generate protoent
6940
- var pe = _malloc(12);
6941
- HEAPU32[pe >> 2] = nameBuf;
6942
- HEAPU32[(pe + 4) >> 2] = aliasListBuf;
6943
- HEAP32[(pe + 8) >> 2] = proto;
6944
- return pe;
7218
+ var _emscripten_resize_heap = (requestedSize) => {
7219
+ var oldSize = HEAPU8.length;
7220
+ // With CAN_ADDRESS_2GB or MEMORY64, pointers are already unsigned.
7221
+ requestedSize >>>= 0;
7222
+ // With multithreaded builds, races can happen (another thread might increase the size
7223
+ // in between), so return a failure, and let the caller retry.
7224
+ // Memory resize rules:
7225
+ // 1. Always increase heap size to at least the requested size, rounded up
7226
+ // to next page multiple.
7227
+ // 2a. If MEMORY_GROWTH_LINEAR_STEP == -1, excessively resize the heap
7228
+ // geometrically: increase the heap size according to
7229
+ // MEMORY_GROWTH_GEOMETRIC_STEP factor (default +20%), At most
7230
+ // overreserve by MEMORY_GROWTH_GEOMETRIC_CAP bytes (default 96MB).
7231
+ // 2b. If MEMORY_GROWTH_LINEAR_STEP != -1, excessively resize the heap
7232
+ // linearly: increase the heap size by at least
7233
+ // MEMORY_GROWTH_LINEAR_STEP bytes.
7234
+ // 3. Max size for the heap is capped at 2048MB-WASM_PAGE_SIZE, or by
7235
+ // MAXIMUM_MEMORY, or by ASAN limit, depending on which is smallest
7236
+ // 4. If we were unable to allocate as much memory, it may be due to
7237
+ // over-eager decision to excessively reserve due to (3) above.
7238
+ // Hence if an allocation fails, cut down on the amount of excess
7239
+ // growth, in an attempt to succeed to perform a smaller allocation.
7240
+ // A limit is set for how much we can grow. We should not exceed that
7241
+ // (the wasm binary specifies it, so if we tried, we'd fail anyhow).
7242
+ var maxHeapSize = getHeapMax();
7243
+ if (requestedSize > maxHeapSize) {
7244
+ return false;
6945
7245
  }
6946
- // Populate the protocol 'database'. The entries are limited to tcp and udp, though it is fairly trivial
6947
- // to add extra entries from /etc/protocols if desired - though not sure if that'd actually be useful.
6948
- var list = Protocols.list;
6949
- var map = Protocols.map;
6950
- if (list.length === 0) {
6951
- var entry = allocprotoent('tcp', 6, ['TCP']);
6952
- list.push(entry);
6953
- map['tcp'] = map['6'] = entry;
6954
- entry = allocprotoent('udp', 17, ['UDP']);
6955
- list.push(entry);
6956
- map['udp'] = map['17'] = entry;
7246
+ // Loop through potential heap size increases. If we attempt a too eager
7247
+ // reservation that fails, cut down on the attempted size and reserve a
7248
+ // smaller bump instead. (max 3 times, chosen somewhat arbitrarily)
7249
+ for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {
7250
+ var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown);
7251
+ // ensure geometric growth
7252
+ // but limit overreserving (default to capping at +96MB overgrowth at most)
7253
+ overGrownHeapSize = Math.min(
7254
+ overGrownHeapSize,
7255
+ requestedSize + 100663296
7256
+ );
7257
+ var newSize = Math.min(
7258
+ maxHeapSize,
7259
+ alignMemory(Math.max(requestedSize, overGrownHeapSize), 65536)
7260
+ );
7261
+ var replacement = growMemory(newSize);
7262
+ if (replacement) {
7263
+ return true;
7264
+ }
6957
7265
  }
6958
- _setprotoent.index = 0;
7266
+ return false;
6959
7267
  };
6960
7268
 
6961
- var _getprotobyname = (name) => {
6962
- // struct protoent *getprotobyname(const char *);
6963
- name = UTF8ToString(name);
6964
- _setprotoent(true);
6965
- var result = Protocols.map[name];
6966
- return result;
7269
+ var runtimeKeepalivePush = () => {
7270
+ runtimeKeepaliveCounter += 1;
6967
7271
  };
6968
7272
 
6969
- var _getprotobynumber = (number) => {
6970
- // struct protoent *getprotobynumber(int proto);
6971
- _setprotoent(true);
6972
- var result = Protocols.map[number];
6973
- return result;
7273
+ var runtimeKeepalivePop = () => {
7274
+ runtimeKeepaliveCounter -= 1;
6974
7275
  };
6975
7276
 
6976
- var stackAlloc = (sz) => __emscripten_stack_alloc(sz);
6977
-
6978
- /** @suppress {duplicate } */ var stringToUTF8OnStack = (str) => {
6979
- var size = lengthBytesUTF8(str) + 1;
6980
- var ret = stackAlloc(size);
6981
- stringToUTF8(str, ret, size);
6982
- return ret;
7277
+ /** @param {number=} timeout */ var safeSetTimeout = (func, timeout) => {
7278
+ runtimeKeepalivePush();
7279
+ return setTimeout(() => {
7280
+ runtimeKeepalivePop();
7281
+ callUserCallback(func);
7282
+ }, timeout);
6983
7283
  };
6984
7284
 
6985
- var allocateUTF8OnStack = stringToUTF8OnStack;
7285
+ var _emscripten_sleep = (ms) =>
7286
+ Asyncify.handleSleep((wakeUp) => safeSetTimeout(wakeUp, ms));
6986
7287
 
6987
- var PHPWASM = {
6988
- init: function () {
6989
- // The /internal directory is required by the C module. It's where the
6990
- // stdout, stderr, and headers information are written for the JavaScript
6991
- // code to read later on.
6992
- FS.mkdir('/internal');
6993
- // The files from the shared directory are shared between all the
6994
- // PHP processes managed by PHPProcessManager.
6995
- FS.mkdir('/internal/shared');
6996
- // The files from the preload directory are preloaded using the
6997
- // auto_prepend_file php.ini directive.
6998
- FS.mkdir('/internal/shared/preload');
6999
- // Create stdout and stderr devices. We can't just use Emscripten's
7000
- // default stdout and stderr devices because they stop processing data
7001
- // on the first null byte. However, when dealing with binary data,
7002
- // null bytes are valid and common.
7003
- FS.registerDevice(FS.makedev(64, 0), {
7004
- open: () => {},
7005
- close: () => {},
7006
- read: () => 0,
7007
- write: (stream, buffer, offset, length, pos) => {
7008
- const chunk = buffer.subarray(offset, offset + length);
7009
- PHPWASM.onStdout(chunk);
7010
- return length;
7011
- },
7012
- });
7013
- FS.mkdev('/internal/stdout', FS.makedev(64, 0));
7014
- FS.registerDevice(FS.makedev(63, 0), {
7015
- open: () => {},
7016
- close: () => {},
7017
- read: () => 0,
7018
- write: (stream, buffer, offset, length, pos) => {
7019
- const chunk = buffer.subarray(offset, offset + length);
7020
- PHPWASM.onStderr(chunk);
7021
- return length;
7022
- },
7023
- });
7024
- FS.mkdev('/internal/stderr', FS.makedev(63, 0));
7025
- FS.registerDevice(FS.makedev(62, 0), {
7026
- open: () => {},
7027
- close: () => {},
7028
- read: () => 0,
7029
- write: (stream, buffer, offset, length, pos) => {
7030
- const chunk = buffer.subarray(offset, offset + length);
7031
- PHPWASM.onHeaders(chunk);
7032
- return length;
7033
- },
7034
- });
7035
- FS.mkdev('/internal/headers', FS.makedev(62, 0));
7036
- // Handle events.
7037
- PHPWASM.EventEmitter = ENVIRONMENT_IS_NODE
7038
- ? require('events').EventEmitter
7039
- : class EventEmitter {
7040
- constructor() {
7041
- this.listeners = {};
7042
- }
7043
- emit(eventName, data) {
7044
- if (this.listeners[eventName]) {
7045
- this.listeners[eventName].forEach(
7046
- (callback) => {
7047
- callback(data);
7048
- }
7049
- );
7050
- }
7051
- }
7052
- once(eventName, callback) {
7053
- const self = this;
7054
- function removedCallback() {
7055
- callback(...arguments);
7056
- self.removeListener(eventName, removedCallback);
7057
- }
7058
- this.on(eventName, removedCallback);
7059
- }
7060
- removeAllListeners(eventName) {
7061
- if (eventName) {
7062
- delete this.listeners[eventName];
7063
- } else {
7064
- this.listeners = {};
7065
- }
7066
- }
7067
- removeListener(eventName, callback) {
7068
- if (this.listeners[eventName]) {
7069
- const idx =
7070
- this.listeners[eventName].indexOf(callback);
7071
- if (idx !== -1) {
7072
- this.listeners[eventName].splice(idx, 1);
7073
- }
7074
- }
7075
- }
7076
- };
7077
- // Clean up the fd -> childProcess mapping when the fd is closed:
7078
- const originalClose = FS.close;
7079
- FS.close = function (stream) {
7080
- originalClose(stream);
7081
- delete PHPWASM.child_proc_by_fd[stream.fd];
7082
- };
7083
- PHPWASM.child_proc_by_fd = {};
7084
- PHPWASM.child_proc_by_pid = {};
7085
- PHPWASM.input_devices = {};
7086
- const originalWrite = TTY.stream_ops.write;
7087
- TTY.stream_ops.write = function (stream, ...rest) {
7088
- const retval = originalWrite(stream, ...rest);
7089
- // Implicit flush since PHP's fflush() doesn't seem to trigger the fsync event
7090
- // @TODO: Fix this at the wasm level
7091
- stream.tty.ops.fsync(stream.tty);
7092
- return retval;
7093
- };
7094
- const originalPutChar = TTY.stream_ops.put_char;
7095
- TTY.stream_ops.put_char = function (tty, val) {
7096
- /**
7097
- * Buffer newlines that Emscripten normally ignores.
7098
- *
7099
- * Emscripten doesn't do it by default because its default
7100
- * print function is console.log that implicitly adds a newline. We are overwriting
7101
- * it with an environment-specific function that outputs exaclty what it was given,
7102
- * e.g. in Node.js it's process.stdout.write(). Therefore, we need to mak sure
7103
- * all the newlines make it to the output buffer.
7104
- */ if (val === 10) tty.output.push(val);
7105
- return originalPutChar(tty, val);
7288
+ Module['_emscripten_sleep'] = _emscripten_sleep;
7289
+
7290
+ _emscripten_sleep.isAsync = true;
7291
+
7292
+ var ENV = PHPLoader.ENV || {};
7293
+
7294
+ var getExecutableName = () => thisProgram || './this.program';
7295
+
7296
+ var getEnvStrings = () => {
7297
+ if (!getEnvStrings.strings) {
7298
+ // Default values.
7299
+ // Browser language detection #8751
7300
+ var lang =
7301
+ (
7302
+ (typeof navigator == 'object' &&
7303
+ navigator.languages &&
7304
+ navigator.languages[0]) ||
7305
+ 'C'
7306
+ ).replace('-', '_') + '.UTF-8';
7307
+ var env = {
7308
+ USER: 'web_user',
7309
+ LOGNAME: 'web_user',
7310
+ PATH: '/',
7311
+ PWD: '/',
7312
+ HOME: '/home/web_user',
7313
+ LANG: lang,
7314
+ _: getExecutableName(),
7106
7315
  };
7107
- },
7108
- onHeaders: function (chunk) {
7109
- if (Module['onHeaders']) {
7110
- Module['onHeaders'](chunk);
7111
- return;
7112
- }
7113
- console.log('headers', {
7114
- chunk,
7115
- });
7116
- },
7117
- onStdout: function (chunk) {
7118
- if (Module['onStdout']) {
7119
- Module['onStdout'](chunk);
7120
- return;
7316
+ // Apply the user-provided values, if any.
7317
+ for (var x in ENV) {
7318
+ // x is a key in ENV; if ENV[x] is undefined, that means it was
7319
+ // explicitly set to be so. We allow user code to do that to
7320
+ // force variables with default values to remain unset.
7321
+ if (ENV[x] === undefined) delete env[x];
7322
+ else env[x] = ENV[x];
7121
7323
  }
7122
- if (ENVIRONMENT_IS_NODE) {
7123
- process.stdout.write(chunk);
7124
- } else {
7125
- console.log('stdout', {
7126
- chunk,
7127
- });
7324
+ var strings = [];
7325
+ for (var x in env) {
7326
+ strings.push(`${x}=${env[x]}`);
7128
7327
  }
7129
- },
7130
- onStderr: function (chunk) {
7131
- if (Module['onStderr']) {
7132
- Module['onStderr'](chunk);
7133
- return;
7328
+ getEnvStrings.strings = strings;
7329
+ }
7330
+ return getEnvStrings.strings;
7331
+ };
7332
+
7333
+ var stringToAscii = (str, buffer) => {
7334
+ for (var i = 0; i < str.length; ++i) {
7335
+ HEAP8[buffer++] = str.charCodeAt(i);
7336
+ }
7337
+ // Null-terminate the string
7338
+ HEAP8[buffer] = 0;
7339
+ };
7340
+
7341
+ var _environ_get = (__environ, environ_buf) => {
7342
+ var bufSize = 0;
7343
+ getEnvStrings().forEach((string, i) => {
7344
+ var ptr = environ_buf + bufSize;
7345
+ HEAPU32[(__environ + i * 4) >> 2] = ptr;
7346
+ stringToAscii(string, ptr);
7347
+ bufSize += string.length + 1;
7348
+ });
7349
+ return 0;
7350
+ };
7351
+
7352
+ var _environ_sizes_get = (penviron_count, penviron_buf_size) => {
7353
+ var strings = getEnvStrings();
7354
+ HEAPU32[penviron_count >> 2] = strings.length;
7355
+ var bufSize = 0;
7356
+ strings.forEach((string) => (bufSize += string.length + 1));
7357
+ HEAPU32[penviron_buf_size >> 2] = bufSize;
7358
+ return 0;
7359
+ };
7360
+
7361
+ function _fd_fdstat_get(fd, pbuf) {
7362
+ try {
7363
+ var rightsBase = 0;
7364
+ var rightsInheriting = 0;
7365
+ var flags = 0;
7366
+ {
7367
+ var stream = SYSCALLS.getStreamFromFD(fd);
7368
+ // All character devices are terminals (other things a Linux system would
7369
+ // assume is a character device, like the mouse, we have special APIs for).
7370
+ var type = stream.tty
7371
+ ? 2
7372
+ : FS.isDir(stream.mode)
7373
+ ? 3
7374
+ : FS.isLink(stream.mode)
7375
+ ? 7
7376
+ : 4;
7134
7377
  }
7135
- if (ENVIRONMENT_IS_NODE) {
7136
- process.stderr.write(chunk);
7137
- } else {
7138
- console.warn('stderr', {
7139
- chunk,
7140
- });
7378
+ HEAP8[pbuf] = type;
7379
+ HEAP16[(pbuf + 2) >> 1] = flags;
7380
+ HEAP64[(pbuf + 8) >> 3] = BigInt(rightsBase);
7381
+ HEAP64[(pbuf + 16) >> 3] = BigInt(rightsInheriting);
7382
+ return 0;
7383
+ } catch (e) {
7384
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
7385
+ return e.errno;
7386
+ }
7387
+ }
7388
+
7389
+ /** @param {number=} offset */ var doReadv = (
7390
+ stream,
7391
+ iov,
7392
+ iovcnt,
7393
+ offset
7394
+ ) => {
7395
+ var ret = 0;
7396
+ for (var i = 0; i < iovcnt; i++) {
7397
+ var ptr = HEAPU32[iov >> 2];
7398
+ var len = HEAPU32[(iov + 4) >> 2];
7399
+ iov += 8;
7400
+ var curr = FS.read(stream, HEAP8, ptr, len, offset);
7401
+ if (curr < 0) return -1;
7402
+ ret += curr;
7403
+ if (curr < len) break;
7404
+ // nothing more to read
7405
+ if (typeof offset != 'undefined') {
7406
+ offset += curr;
7141
7407
  }
7142
- },
7143
- getAllWebSockets: function (sock) {
7144
- const webSockets = new Set();
7145
- if (sock.server) {
7146
- sock.server.clients.forEach((ws) => {
7147
- webSockets.add(ws);
7408
+ }
7409
+ return ret;
7410
+ };
7411
+
7412
+ function _fd_read(fd, iov, iovcnt, pnum) {
7413
+ try {
7414
+ var stream = SYSCALLS.getStreamFromFD(fd);
7415
+ var num = doReadv(stream, iov, iovcnt);
7416
+ HEAPU32[pnum >> 2] = num;
7417
+ return 0;
7418
+ } catch (e) {
7419
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
7420
+ return e.errno;
7421
+ }
7422
+ }
7423
+
7424
+ function _fd_seek(fd, offset, whence, newOffset) {
7425
+ offset = bigintToI53Checked(offset);
7426
+ try {
7427
+ if (isNaN(offset)) return 61;
7428
+ var stream = SYSCALLS.getStreamFromFD(fd);
7429
+ FS.llseek(stream, offset, whence);
7430
+ HEAP64[newOffset >> 3] = BigInt(stream.position);
7431
+ if (stream.getdents && offset === 0 && whence === 0)
7432
+ stream.getdents = null;
7433
+ // reset readdir state
7434
+ return 0;
7435
+ } catch (e) {
7436
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
7437
+ return e.errno;
7438
+ }
7439
+ }
7440
+
7441
+ var _fd_sync = function (fd) {
7442
+ try {
7443
+ var stream = SYSCALLS.getStreamFromFD(fd);
7444
+ return Asyncify.handleSleep((wakeUp) => {
7445
+ var mount = stream.node.mount;
7446
+ if (!mount.type.syncfs) {
7447
+ // We write directly to the file system, so there's nothing to do here.
7448
+ wakeUp(0);
7449
+ return;
7450
+ }
7451
+ mount.type.syncfs(mount, false, (err) => {
7452
+ if (err) {
7453
+ wakeUp(29);
7454
+ return;
7455
+ }
7456
+ wakeUp(0);
7148
7457
  });
7458
+ });
7459
+ } catch (e) {
7460
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
7461
+ return e.errno;
7462
+ }
7463
+ };
7464
+
7465
+ _fd_sync.isAsync = true;
7466
+
7467
+ /** @param {number=} offset */ var doWritev = (
7468
+ stream,
7469
+ iov,
7470
+ iovcnt,
7471
+ offset
7472
+ ) => {
7473
+ var ret = 0;
7474
+ for (var i = 0; i < iovcnt; i++) {
7475
+ var ptr = HEAPU32[iov >> 2];
7476
+ var len = HEAPU32[(iov + 4) >> 2];
7477
+ iov += 8;
7478
+ var curr = FS.write(stream, HEAP8, ptr, len, offset);
7479
+ if (curr < 0) return -1;
7480
+ ret += curr;
7481
+ if (curr < len) {
7482
+ // No more space to write.
7483
+ break;
7149
7484
  }
7150
- for (const peer of PHPWASM.getAllPeers(sock)) {
7151
- webSockets.add(peer.socket);
7485
+ if (typeof offset != 'undefined') {
7486
+ offset += curr;
7152
7487
  }
7153
- return Array.from(webSockets);
7154
- },
7155
- getAllPeers: function (sock) {
7156
- const peers = new Set();
7157
- if (sock.server) {
7158
- sock.pending
7159
- .filter((pending) => pending.peers)
7160
- .forEach((pending) => {
7161
- for (const peer of Object.values(pending.peers)) {
7162
- peers.add(peer);
7163
- }
7164
- });
7488
+ }
7489
+ return ret;
7490
+ };
7491
+
7492
+ function _fd_write(fd, iov, iovcnt, pnum) {
7493
+ try {
7494
+ var stream = SYSCALLS.getStreamFromFD(fd);
7495
+ var num = doWritev(stream, iov, iovcnt);
7496
+ HEAPU32[pnum >> 2] = num;
7497
+ return 0;
7498
+ } catch (e) {
7499
+ if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;
7500
+ return e.errno;
7501
+ }
7502
+ }
7503
+
7504
+ var _getaddrinfo = (node, service, hint, out) => {
7505
+ var addr = 0;
7506
+ var port = 0;
7507
+ var flags = 0;
7508
+ var family = 0;
7509
+ var type = 0;
7510
+ var proto = 0;
7511
+ var ai;
7512
+ function allocaddrinfo(family, type, proto, canon, addr, port) {
7513
+ var sa, salen, ai;
7514
+ var errno;
7515
+ salen = family === 10 ? 28 : 16;
7516
+ addr = family === 10 ? inetNtop6(addr) : inetNtop4(addr);
7517
+ sa = _malloc(salen);
7518
+ errno = writeSockaddr(sa, family, addr, port);
7519
+ assert(!errno);
7520
+ ai = _malloc(32);
7521
+ HEAP32[(ai + 4) >> 2] = family;
7522
+ HEAP32[(ai + 8) >> 2] = type;
7523
+ HEAP32[(ai + 12) >> 2] = proto;
7524
+ HEAPU32[(ai + 24) >> 2] = canon;
7525
+ HEAPU32[(ai + 20) >> 2] = sa;
7526
+ if (family === 10) {
7527
+ HEAP32[(ai + 16) >> 2] = 28;
7528
+ } else {
7529
+ HEAP32[(ai + 16) >> 2] = 16;
7165
7530
  }
7166
- if (sock.peers) {
7167
- for (const peer of Object.values(sock.peers)) {
7168
- peers.add(peer);
7531
+ HEAP32[(ai + 28) >> 2] = 0;
7532
+ return ai;
7533
+ }
7534
+ if (hint) {
7535
+ flags = HEAP32[hint >> 2];
7536
+ family = HEAP32[(hint + 4) >> 2];
7537
+ type = HEAP32[(hint + 8) >> 2];
7538
+ proto = HEAP32[(hint + 12) >> 2];
7539
+ }
7540
+ if (type && !proto) {
7541
+ proto = type === 2 ? 17 : 6;
7542
+ }
7543
+ if (!type && proto) {
7544
+ type = proto === 17 ? 2 : 1;
7545
+ }
7546
+ // If type or proto are set to zero in hints we should really be returning multiple addrinfo values, but for
7547
+ // now default to a TCP STREAM socket so we can at least return a sensible addrinfo given NULL hints.
7548
+ if (proto === 0) {
7549
+ proto = 6;
7550
+ }
7551
+ if (type === 0) {
7552
+ type = 1;
7553
+ }
7554
+ if (!node && !service) {
7555
+ return -2;
7556
+ }
7557
+ if (flags & ~(1 | 2 | 4 | 1024 | 8 | 16 | 32)) {
7558
+ return -1;
7559
+ }
7560
+ if (hint !== 0 && HEAP32[hint >> 2] & 2 && !node) {
7561
+ return -1;
7562
+ }
7563
+ if (flags & 32) {
7564
+ // TODO
7565
+ return -2;
7566
+ }
7567
+ if (type !== 0 && type !== 1 && type !== 2) {
7568
+ return -7;
7569
+ }
7570
+ if (family !== 0 && family !== 2 && family !== 10) {
7571
+ return -6;
7572
+ }
7573
+ if (service) {
7574
+ service = UTF8ToString(service);
7575
+ port = parseInt(service, 10);
7576
+ if (isNaN(port)) {
7577
+ if (flags & 1024) {
7578
+ return -2;
7169
7579
  }
7580
+ // TODO support resolving well-known service names from:
7581
+ // http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt
7582
+ return -8;
7170
7583
  }
7171
- return Array.from(peers);
7172
- },
7173
- awaitData: function (ws) {
7174
- return PHPWASM.awaitEvent(ws, 'message');
7175
- },
7176
- awaitConnection: function (ws) {
7177
- if (ws.OPEN === ws.readyState) {
7178
- return [Promise.resolve(), PHPWASM.noop];
7584
+ }
7585
+ if (!node) {
7586
+ if (family === 0) {
7587
+ family = 2;
7588
+ }
7589
+ if ((flags & 1) === 0) {
7590
+ if (family === 2) {
7591
+ addr = _htonl(2130706433);
7592
+ } else {
7593
+ addr = [0, 0, 0, _htonl(1)];
7594
+ }
7179
7595
  }
7180
- return PHPWASM.awaitEvent(ws, 'open');
7181
- },
7182
- awaitClose: function (ws) {
7183
- if ([ws.CLOSING, ws.CLOSED].includes(ws.readyState)) {
7184
- return [Promise.resolve(), PHPWASM.noop];
7596
+ ai = allocaddrinfo(family, type, proto, null, addr, port);
7597
+ HEAPU32[out >> 2] = ai;
7598
+ return 0;
7599
+ }
7600
+ // try as a numeric address
7601
+ node = UTF8ToString(node);
7602
+ addr = inetPton4(node);
7603
+ if (addr !== null) {
7604
+ // incoming node is a valid ipv4 address
7605
+ if (family === 0 || family === 2) {
7606
+ family = 2;
7607
+ } else if (family === 10 && flags & 8) {
7608
+ addr = [0, 0, _htonl(65535), addr];
7609
+ family = 10;
7610
+ } else {
7611
+ return -2;
7185
7612
  }
7186
- return PHPWASM.awaitEvent(ws, 'close');
7187
- },
7188
- awaitError: function (ws) {
7189
- if ([ws.CLOSING, ws.CLOSED].includes(ws.readyState)) {
7190
- return [Promise.resolve(), PHPWASM.noop];
7613
+ } else {
7614
+ addr = inetPton6(node);
7615
+ if (addr !== null) {
7616
+ // incoming node is a valid ipv6 address
7617
+ if (family === 0 || family === 10) {
7618
+ family = 10;
7619
+ } else {
7620
+ return -2;
7621
+ }
7191
7622
  }
7192
- return PHPWASM.awaitEvent(ws, 'error');
7193
- },
7194
- awaitEvent: function (ws, event) {
7195
- let resolve;
7196
- const listener = () => {
7197
- resolve();
7198
- };
7199
- const promise = new Promise(function (_resolve) {
7200
- resolve = _resolve;
7201
- ws.once(event, listener);
7202
- });
7203
- const cancel = () => {
7204
- ws.removeListener(event, listener);
7205
- // Rejecting the promises bubbles up and kills the entire
7206
- // node process. Let's resolve them on the next tick instead
7207
- // to give the caller some space to unbind any handlers.
7208
- setTimeout(resolve);
7209
- };
7210
- return [promise, cancel];
7211
- },
7212
- noop: function () {},
7213
- spawnProcess: function (command, args, options) {
7214
- if (Module['spawnProcess']) {
7215
- const spawnedPromise = Module['spawnProcess'](
7216
- command,
7217
- args,
7218
- options
7219
- );
7220
- return Promise.resolve(spawnedPromise).then(function (spawned) {
7221
- if (!spawned || !spawned.on) {
7222
- throw new Error(
7223
- 'spawnProcess() must return an EventEmitter but returned a different type.'
7224
- );
7225
- }
7226
- return spawned;
7227
- });
7623
+ }
7624
+ if (addr != null) {
7625
+ ai = allocaddrinfo(family, type, proto, node, addr, port);
7626
+ HEAPU32[out >> 2] = ai;
7627
+ return 0;
7628
+ }
7629
+ if (flags & 4) {
7630
+ return -2;
7631
+ }
7632
+ // try as a hostname
7633
+ // resolve the hostname to a temporary fake address
7634
+ node = DNS.lookup_name(node);
7635
+ addr = inetPton4(node);
7636
+ if (family === 0) {
7637
+ family = 2;
7638
+ } else if (family === 10) {
7639
+ addr = [0, 0, _htonl(65535), addr];
7640
+ }
7641
+ ai = allocaddrinfo(family, type, proto, null, addr, port);
7642
+ HEAPU32[out >> 2] = ai;
7643
+ return 0;
7644
+ };
7645
+
7646
+ var _getcontext = () => abort('missing function: ${name}');
7647
+
7648
+ var _getnameinfo = (sa, salen, node, nodelen, serv, servlen, flags) => {
7649
+ var info = readSockaddr(sa, salen);
7650
+ if (info.errno) {
7651
+ return -6;
7652
+ }
7653
+ var port = info.port;
7654
+ var addr = info.addr;
7655
+ var overflowed = false;
7656
+ if (node && nodelen) {
7657
+ var lookup;
7658
+ if (flags & 1 || !(lookup = DNS.lookup_addr(addr))) {
7659
+ if (flags & 8) {
7660
+ return -2;
7661
+ }
7662
+ } else {
7663
+ addr = lookup;
7228
7664
  }
7229
- if (ENVIRONMENT_IS_NODE) {
7230
- return require('child_process').spawn(command, args, {
7231
- ...options,
7232
- shell: true,
7233
- stdio: ['pipe', 'pipe', 'pipe'],
7234
- timeout: 100,
7235
- });
7665
+ var numBytesWrittenExclNull = stringToUTF8(addr, node, nodelen);
7666
+ if (numBytesWrittenExclNull + 1 >= nodelen) {
7667
+ overflowed = true;
7236
7668
  }
7237
- const e = new Error(
7238
- 'popen(), proc_open() etc. are unsupported in the browser. Call php.setSpawnHandler() ' +
7239
- 'and provide a callback to handle spawning processes, or disable a popen(), proc_open() ' +
7240
- 'and similar functions via php.ini.'
7241
- );
7242
- e.code = 'SPAWN_UNSUPPORTED';
7243
- throw e;
7244
- },
7245
- shutdownSocket: function (socketd, how) {
7246
- // This implementation only supports websockets at the moment
7247
- const sock = getSocketFromFD(socketd);
7248
- const peer = Object.values(sock.peers)[0];
7249
- if (!peer) {
7250
- return -1;
7669
+ }
7670
+ if (serv && servlen) {
7671
+ port = '' + port;
7672
+ var numBytesWrittenExclNull = stringToUTF8(port, serv, servlen);
7673
+ if (numBytesWrittenExclNull + 1 >= servlen) {
7674
+ overflowed = true;
7251
7675
  }
7252
- try {
7253
- peer.socket.close();
7254
- SOCKFS.websocket_sock_ops.removePeer(sock, peer);
7255
- return 0;
7256
- } catch (e) {
7257
- console.log('Socket shutdown error', e);
7258
- return -1;
7676
+ }
7677
+ if (overflowed) {
7678
+ // Note: even when we overflow, getnameinfo() is specced to write out the truncated results.
7679
+ return -12;
7680
+ }
7681
+ return 0;
7682
+ };
7683
+
7684
+ var Protocols = {
7685
+ list: [],
7686
+ map: {},
7687
+ };
7688
+
7689
+ var _setprotoent = (stayopen) => {
7690
+ // void setprotoent(int stayopen);
7691
+ // Allocate and populate a protoent structure given a name, protocol number and array of aliases
7692
+ function allocprotoent(name, proto, aliases) {
7693
+ // write name into buffer
7694
+ var nameBuf = _malloc(name.length + 1);
7695
+ stringToAscii(name, nameBuf);
7696
+ // write aliases into buffer
7697
+ var j = 0;
7698
+ var length = aliases.length;
7699
+ var aliasListBuf = _malloc((length + 1) * 4);
7700
+ // Use length + 1 so we have space for the terminating NULL ptr.
7701
+ for (var i = 0; i < length; i++, j += 4) {
7702
+ var alias = aliases[i];
7703
+ var aliasBuf = _malloc(alias.length + 1);
7704
+ stringToAscii(alias, aliasBuf);
7705
+ HEAPU32[(aliasListBuf + j) >> 2] = aliasBuf;
7259
7706
  }
7260
- },
7707
+ HEAPU32[(aliasListBuf + j) >> 2] = 0;
7708
+ // Terminating NULL pointer.
7709
+ // generate protoent
7710
+ var pe = _malloc(12);
7711
+ HEAPU32[pe >> 2] = nameBuf;
7712
+ HEAPU32[(pe + 4) >> 2] = aliasListBuf;
7713
+ HEAP32[(pe + 8) >> 2] = proto;
7714
+ return pe;
7715
+ }
7716
+ // Populate the protocol 'database'. The entries are limited to tcp and udp, though it is fairly trivial
7717
+ // to add extra entries from /etc/protocols if desired - though not sure if that'd actually be useful.
7718
+ var list = Protocols.list;
7719
+ var map = Protocols.map;
7720
+ if (list.length === 0) {
7721
+ var entry = allocprotoent('tcp', 6, ['TCP']);
7722
+ list.push(entry);
7723
+ map['tcp'] = map['6'] = entry;
7724
+ entry = allocprotoent('udp', 17, ['UDP']);
7725
+ list.push(entry);
7726
+ map['udp'] = map['17'] = entry;
7727
+ }
7728
+ _setprotoent.index = 0;
7729
+ };
7730
+
7731
+ var _getprotobyname = (name) => {
7732
+ // struct protoent *getprotobyname(const char *);
7733
+ name = UTF8ToString(name);
7734
+ _setprotoent(true);
7735
+ var result = Protocols.map[name];
7736
+ return result;
7737
+ };
7738
+
7739
+ var _getprotobynumber = (number) => {
7740
+ // struct protoent *getprotobynumber(int proto);
7741
+ _setprotoent(true);
7742
+ var result = Protocols.map[number];
7743
+ return result;
7261
7744
  };
7262
7745
 
7263
7746
  function _js_create_input_device(deviceId) {
@@ -7295,6 +7778,98 @@ export function init(RuntimeName, PHPLoader) {
7295
7778
  return allocateUTF8OnStack(devicePath);
7296
7779
  }
7297
7780
 
7781
+ async function _js_flock(fd, op) {
7782
+ _js_wasm_trace('js_flock(%d, %d)', fd, op);
7783
+ // Emscripten does not expose these constants to JS, so we hardcode them here.
7784
+ // Based on
7785
+ // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10
7786
+ const emscripten_LOCK_SH = 1;
7787
+ const emscripten_LOCK_EX = 2;
7788
+ const emscripten_LOCK_NB = 4;
7789
+ const emscripten_LOCK_UN = 8;
7790
+ const flockToLockOpType = {
7791
+ [emscripten_LOCK_SH]: 'shared',
7792
+ [emscripten_LOCK_EX]: 'exclusive',
7793
+ [emscripten_LOCK_UN]: 'unlocked',
7794
+ };
7795
+ let vfsPath;
7796
+ let errno;
7797
+ [vfsPath, errno] = locking.get_vfs_path_from_fd(fd);
7798
+ if (errno !== 0) {
7799
+ _js_wasm_trace(
7800
+ 'js_flock(%d, %d) get_vfs_path_from_fd errno %d',
7801
+ fd,
7802
+ op,
7803
+ vfsPath,
7804
+ errno
7805
+ );
7806
+ return -errno;
7807
+ }
7808
+ if (!locking.is_path_to_shared_fs(vfsPath)) {
7809
+ _js_wasm_trace(
7810
+ 'flock(%d, %d) locking is not implemented for non-NodeFS path %s',
7811
+ fd,
7812
+ op,
7813
+ vfsPath
7814
+ );
7815
+ // If not a NodeFS path, we can't lock it.
7816
+ // Default to succeeding as Emscripten does.
7817
+ return 0;
7818
+ }
7819
+ errno = locking.check_lock_params(fd, op);
7820
+ if (errno !== 0) {
7821
+ _js_wasm_trace(
7822
+ 'js_flock(%d, %d) check_lock_params errno %d',
7823
+ fd,
7824
+ op,
7825
+ errno
7826
+ );
7827
+ return -errno;
7828
+ }
7829
+ // @TODO: Consider supporting blocking mode of flock()
7830
+ if (op & (emscripten_LOCK_NB === 0)) {
7831
+ _js_wasm_trace(
7832
+ 'js_flock(%d, %d) blocking mode of flock() is not implemented',
7833
+ fd,
7834
+ op
7835
+ );
7836
+ // We do not yet support the blocking form of flock().
7837
+ // We respond with EINVAL to indicate failure
7838
+ // because it is a known errno for a failed blocking flock().
7839
+ return -ERRNO_CODES.EINVAL;
7840
+ }
7841
+ const maskedOp =
7842
+ op & (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN);
7843
+ const lockOpType = flockToLockOpType[maskedOp];
7844
+ if (lockOpType === undefined) {
7845
+ _js_wasm_trace(
7846
+ 'js_flock(%d, %d) invalid flock() operation',
7847
+ fd,
7848
+ op
7849
+ );
7850
+ return -ERRNO_CODES.EINVAL;
7851
+ }
7852
+ const nativeFilePath = locking.get_native_path_from_vfs_path(vfsPath);
7853
+ const obtainedLock = await PHPLoader.fileLockManager.lockWholeFile(
7854
+ nativeFilePath,
7855
+ {
7856
+ type: lockOpType,
7857
+ pid: PHPLoader.processId,
7858
+ fd,
7859
+ }
7860
+ );
7861
+ _js_wasm_trace(
7862
+ 'js_flock(%d, %d) lockWholeFile %s returned %d',
7863
+ fd,
7864
+ op,
7865
+ vfsPath,
7866
+ obtainedLock
7867
+ );
7868
+ return obtainedLock ? 0 : -ERRNO_CODES.EWOULDBLOCK;
7869
+ }
7870
+
7871
+ _js_flock.isAsync = true;
7872
+
7298
7873
  function _js_open_process(
7299
7874
  command,
7300
7875
  argsPtr,
@@ -7567,6 +8142,21 @@ export function init(RuntimeName, PHPLoader) {
7567
8142
  return 0;
7568
8143
  }
7569
8144
 
8145
+ var _js_release_file_locks = async function js_release_file_locks() {
8146
+ _js_wasm_trace('js_release_file_locks()');
8147
+ const pid = PHPLoader.processId;
8148
+ return await PHPLoader.fileLockManager
8149
+ .releaseLocksForProcess(pid)
8150
+ .then(() => {
8151
+ _js_wasm_trace('js_release_file_locks succeeded');
8152
+ })
8153
+ .catch((e) => {
8154
+ _js_wasm_trace('js_release_file_locks error %s', e);
8155
+ });
8156
+ };
8157
+
8158
+ _js_release_file_locks.isAsync = true;
8159
+
7570
8160
  function _js_waitpid(pid, exitCodePtr) {
7571
8161
  if (!PHPWASM.child_proc_by_pid[pid]) {
7572
8162
  return -1;
@@ -8499,9 +9089,13 @@ export function init(RuntimeName, PHPLoader) {
8499
9089
  /** @export */ getprotobyname: _getprotobyname,
8500
9090
  /** @export */ getprotobynumber: _getprotobynumber,
8501
9091
  /** @export */ js_create_input_device: _js_create_input_device,
9092
+ /** @export */ js_flock: _js_flock,
9093
+ /** @export */ js_getpid: _js_getpid,
8502
9094
  /** @export */ js_open_process: _js_open_process,
8503
9095
  /** @export */ js_process_status: _js_process_status,
9096
+ /** @export */ js_release_file_locks: _js_release_file_locks,
8504
9097
  /** @export */ js_waitpid: _js_waitpid,
9098
+ /** @export */ js_wasm_trace: _js_wasm_trace,
8505
9099
  /** @export */ makecontext: _makecontext,
8506
9100
  /** @export */ proc_exit: _proc_exit,
8507
9101
  /** @export */ strptime: _strptime,
@@ -8529,6 +9123,12 @@ export function init(RuntimeName, PHPLoader) {
8529
9123
 
8530
9124
  var _fflush = (a0) => (_fflush = wasmExports['fflush'])(a0);
8531
9125
 
9126
+ var _flock = (Module['_flock'] = (a0, a1) =>
9127
+ (_flock = Module['_flock'] = wasmExports['flock'])(a0, a1));
9128
+
9129
+ var _getpid = (Module['_getpid'] = () =>
9130
+ (_getpid = Module['_getpid'] = wasmExports['getpid'])());
9131
+
8532
9132
  var _wasm_popen = (Module['_wasm_popen'] = (a0, a1) =>
8533
9133
  (_wasm_popen = Module['_wasm_popen'] = wasmExports['wasm_popen'])(
8534
9134
  a0,
@@ -8643,6 +9243,16 @@ export function init(RuntimeName, PHPLoader) {
8643
9243
  var _wasm_free = (Module['_wasm_free'] = (a0) =>
8644
9244
  (_wasm_free = Module['_wasm_free'] = wasmExports['wasm_free'])(a0));
8645
9245
 
9246
+ var _wasm_get_end_offset = (Module['_wasm_get_end_offset'] = (a0) =>
9247
+ (_wasm_get_end_offset = Module['_wasm_get_end_offset'] =
9248
+ wasmExports['wasm_get_end_offset'])(a0));
9249
+
9250
+ var _wasm_trace = (Module['_wasm_trace'] = (a0, a1) =>
9251
+ (_wasm_trace = Module['_wasm_trace'] = wasmExports['wasm_trace'])(
9252
+ a0,
9253
+ a1
9254
+ ));
9255
+
8646
9256
  var ___funcs_on_exit = () =>
8647
9257
  (___funcs_on_exit = wasmExports['__funcs_on_exit'])();
8648
9258
 
@@ -8790,6 +9400,32 @@ export function init(RuntimeName, PHPLoader) {
8790
9400
  PHPLoader['free'] =
8791
9401
  typeof _free === 'function' ? _free : PHPLoader['_wasm_free'];
8792
9402
 
9403
+ if (typeof NODEFS === 'object') {
9404
+ // We override NODEFS.createNode() to add an `isSharedFS` flag to all NODEFS
9405
+ // nodes. This way we can tell whether file-locking is needed and possible
9406
+ // for an FS node, even if wrapped with PROXYFS.
9407
+ const originalCreateNode = NODEFS.createNode;
9408
+ NODEFS.createNode = function createNodeWithSharedFlag() {
9409
+ const node = originalCreateNode.apply(NODEFS, arguments);
9410
+ node.isSharedFS = true;
9411
+ return node;
9412
+ };
9413
+
9414
+ var originalHashAddNode = FS.hashAddNode;
9415
+ FS.hashAddNode = function hashAddNodeIfNotSharedFS(node) {
9416
+ if (
9417
+ typeof locking === 'object' &&
9418
+ locking?.is_shared_fs_node(node)
9419
+ ) {
9420
+ // Avoid caching shared VFS nodes so multiple instances
9421
+ // can access the same underlying filesystem without
9422
+ // conflicting caches.
9423
+ return;
9424
+ }
9425
+ return originalHashAddNode.apply(FS, arguments);
9426
+ };
9427
+ }
9428
+
8793
9429
  return PHPLoader;
8794
9430
 
8795
9431
  // Close the opening bracket from esm-prefix.js: