addToLibrary({
#if WASMFS
$NODEFS__deps: ['$stringToUTF8OnStack', 'wasmfs_create_node_backend'],
$NODEFS: {
createBackend(opts) {
return _wasmfs_create_node_backend(stringToUTF8OnStack(opts.root));
}
}
#else
$NODEFS__deps: ['$FS', '$PATH', '$ERRNO_CODES', '$mmapAlloc'],
$NODEFS__postset: 'if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); }',
$NODEFS: {
isWindows: false,
staticInit() {
NODEFS.isWindows = !!process.platform.match(/^win/);
var flags = process.binding("constants")["fs"];
NODEFS.flagsForNodeMap = {
"{{{ cDefs.O_APPEND }}}": flags["O_APPEND"],
"{{{ cDefs.O_CREAT }}}": flags["O_CREAT"],
"{{{ cDefs.O_EXCL }}}": flags["O_EXCL"],
"{{{ cDefs.O_NOCTTY }}}": flags["O_NOCTTY"],
"{{{ cDefs.O_RDONLY }}}": flags["O_RDONLY"],
"{{{ cDefs.O_RDWR }}}": flags["O_RDWR"],
"{{{ cDefs.O_DSYNC }}}": flags["O_SYNC"],
"{{{ cDefs.O_TRUNC }}}": flags["O_TRUNC"],
"{{{ cDefs.O_WRONLY }}}": flags["O_WRONLY"],
"{{{ cDefs.O_NOFOLLOW }}}": flags["O_NOFOLLOW"],
};
#if ASSERTIONS
assert(NODEFS.flagsForNodeMap["0"] === 0);
#endif
},
convertNodeCode(e) {
var code = e.code;
#if ASSERTIONS
assert(code in ERRNO_CODES, `unexpected node error code: ${code} (${e})`);
#endif
return ERRNO_CODES[code];
},
tryFSOperation(f) {
try {
return f();
} catch (e) {
if (!e.code) throw e;
if (e.code === 'UNKNOWN') throw new FS.ErrnoError({{{ cDefs.EINVAL }}});
throw new FS.ErrnoError(NODEFS.convertNodeCode(e));
}
},
mount(mount) {
#if ASSERTIONS
assert(ENVIRONMENT_IS_NODE);
#endif
return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
},
createNode(parent, name, mode, dev) {
if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
throw new FS.ErrnoError({{{ cDefs.EINVAL }}});
}
var node = FS.createNode(parent, name, mode);
node.node_ops = NODEFS.node_ops;
node.stream_ops = NODEFS.stream_ops;
return node;
},
getMode(path) {
return NODEFS.tryFSOperation(() => {
var mode = fs.lstatSync(path).mode;
if (NODEFS.isWindows) {
mode |= (mode & {{{ cDefs.S_IRUGO }}}) >> 2;
}
return mode;
});
},
realPath(node) {
var parts = [];
while (node.parent !== node) {
parts.push(node.name);
node = node.parent;
}
parts.push(node.mount.opts.root);
parts.reverse();
return PATH.join(...parts);
},
flagsForNode(flags) {
flags &= ~{{{ cDefs.O_PATH }}};
flags &= ~{{{ cDefs.O_NONBLOCK }}};
flags &= ~{{{ cDefs.O_LARGEFILE }}};
flags &= ~{{{ cDefs.O_CLOEXEC }}};
flags &= ~{{{ cDefs.O_DIRECTORY }}};
var newFlags = 0;
for (var k in NODEFS.flagsForNodeMap) {
if (flags & k) {
newFlags |= NODEFS.flagsForNodeMap[k];
flags ^= k;
}
}
if (flags) {
throw new FS.ErrnoError({{{ cDefs.EINVAL }}});
}
return newFlags;
},
getattr(func, node) {
var stat = NODEFS.tryFSOperation(func);
if (NODEFS.isWindows) {
if (!stat.blksize) {
stat.blksize = 4096;
}
if (!stat.blocks) {
stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
}
stat.mode |= (stat.mode & {{{ cDefs.S_IRUGO }}}) >> 2;
}
return {
dev: stat.dev,
ino: node.id,
mode: stat.mode,
nlink: stat.nlink,
uid: stat.uid,
gid: stat.gid,
rdev: stat.rdev,
size: stat.size,
atime: stat.atime,
mtime: stat.mtime,
ctime: stat.ctime,
blksize: stat.blksize,
blocks: stat.blocks
};
},
setattr(arg, node, attr, chmod, utimes, truncate, stat) {
NODEFS.tryFSOperation(() => {
if (attr.mode !== undefined) {
var mode = attr.mode;
if (NODEFS.isWindows) {
mode &= {{{ cDefs.S_IRUSR | cDefs.S_IWUSR }}};
}
chmod(arg, mode);
node.mode = attr.mode;
}
if (typeof (attr.atime ?? attr.mtime) === "number") {
var atime = new Date(attr.atime ?? stat(arg).atime);
var mtime = new Date(attr.mtime ?? stat(arg).mtime);
utimes(arg, atime, mtime);
}
if (attr.size !== undefined) {
truncate(arg, attr.size);
}
});
},
node_ops: {
getattr(node) {
var path = NODEFS.realPath(node);
return NODEFS.getattr(() => fs.lstatSync(path), node);
},
setattr(node, attr) {
var path = NODEFS.realPath(node);
if (attr.mode != null && attr.dontFollow) {
throw new FS.ErrnoError({{{ cDefs.ENOSYS }}});
}
NODEFS.setattr(path, node, attr, fs.chmodSync, fs.utimesSync, fs.truncateSync, fs.lstatSync);
},
lookup(parent, name) {
var path = PATH.join2(NODEFS.realPath(parent), name);
var mode = NODEFS.getMode(path);
return NODEFS.createNode(parent, name, mode);
},
mknod(parent, name, mode, dev) {
var node = NODEFS.createNode(parent, name, mode, dev);
var path = NODEFS.realPath(node);
NODEFS.tryFSOperation(() => {
if (FS.isDir(node.mode)) {
fs.mkdirSync(path, node.mode);
} else {
fs.writeFileSync(path, '', { mode: node.mode });
}
});
return node;
},
rename(oldNode, newDir, newName) {
var oldPath = NODEFS.realPath(oldNode);
var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
try {
FS.unlink(newPath);
} catch(e) {}
NODEFS.tryFSOperation(() => fs.renameSync(oldPath, newPath));
oldNode.name = newName;
},
unlink(parent, name) {
var path = PATH.join2(NODEFS.realPath(parent), name);
NODEFS.tryFSOperation(() => fs.unlinkSync(path));
},
rmdir(parent, name) {
var path = PATH.join2(NODEFS.realPath(parent), name);
NODEFS.tryFSOperation(() => fs.rmdirSync(path));
},
readdir(node) {
var path = NODEFS.realPath(node);
return NODEFS.tryFSOperation(() => fs.readdirSync(path));
},
symlink(parent, newName, oldPath) {
var newPath = PATH.join2(NODEFS.realPath(parent), newName);
NODEFS.tryFSOperation(() => fs.symlinkSync(oldPath, newPath));
},
readlink(node) {
var path = NODEFS.realPath(node);
return NODEFS.tryFSOperation(() => fs.readlinkSync(path));
},
statfs(path) {
var stats = NODEFS.tryFSOperation(() => fs.statfsSync(path));
stats.frsize = stats.bsize;
return stats;
}
},
stream_ops: {
getattr(stream) {
return NODEFS.getattr(() => fs.fstatSync(stream.nfd), stream.node);
},
setattr(stream, attr) {
NODEFS.setattr(stream.nfd, stream.node, attr, fs.fchmodSync, fs.futimesSync, fs.ftruncateSync, fs.fstatSync);
},
open(stream) {
var path = NODEFS.realPath(stream.node);
NODEFS.tryFSOperation(() => {
stream.shared.refcount = 1;
stream.nfd = fs.openSync(path, NODEFS.flagsForNode(stream.flags));
});
},
close(stream) {
NODEFS.tryFSOperation(() => {
if (stream.nfd && --stream.shared.refcount === 0) {
fs.closeSync(stream.nfd);
}
});
},
dup(stream) {
stream.shared.refcount++;
},
read(stream, buffer, offset, length, position) {
return NODEFS.tryFSOperation(() =>
fs.readSync(stream.nfd, new Int8Array(buffer.buffer, offset, length), 0, length, position)
);
},
write(stream, buffer, offset, length, position) {
return NODEFS.tryFSOperation(() =>
fs.writeSync(stream.nfd, new Int8Array(buffer.buffer, offset, length), 0, length, position)
);
},
llseek(stream, offset, whence) {
var position = offset;
if (whence === {{{ cDefs.SEEK_CUR }}}) {
position += stream.position;
} else if (whence === {{{ cDefs.SEEK_END }}}) {
if (FS.isFile(stream.node.mode)) {
NODEFS.tryFSOperation(() => {
var stat = fs.fstatSync(stream.nfd);
position += stat.size;
});
}
}
if (position < 0) {
throw new FS.ErrnoError({{{ cDefs.EINVAL }}});
}
return position;
},
mmap(stream, length, position, prot, flags) {
if (!FS.isFile(stream.node.mode)) {
throw new FS.ErrnoError({{{ cDefs.ENODEV }}});
}
var ptr = mmapAlloc(length);
NODEFS.stream_ops.read(stream, HEAP8, ptr, length, position);
return { ptr, allocated: true };
},
msync(stream, buffer, offset, length, mmapFlags) {
NODEFS.stream_ops.write(stream, buffer, 0, length, offset, false);
return 0;
}
}
}
#endif
});