@ezdevlol/memfs
Version:
In-memory file-system with Node's fs API.
806 lines (805 loc) • 33.1 kB
JavaScript
import * as optHelpers from '../node/options';
import * as util from '../node/util';
import { Buffer } from '../internal/buffer';
import { FsPromises } from '../node/FsPromises';
import { pathToLocation, testDirectoryIsWritable } from './util';
import { ERRSTR } from '../node/constants';
import { strToEncoding } from '../encoding';
import { FsaNodeDirent } from './FsaNodeDirent';
import { constants } from '../constants';
import { FsaNodeStats } from './FsaNodeStats';
import queueMicrotask from '../queueMicrotask';
import { FsaNodeWriteStream } from './FsaNodeWriteStream';
import { FsaNodeReadStream } from './FsaNodeReadStream';
import { FsaNodeCore } from './FsaNodeCore';
import { FileHandle } from '../node/FileHandle';
const notSupported = () => {
throw new Error('Method not supported by the File System Access API.');
};
const notImplemented = () => {
throw new Error('Not implemented');
};
const noop = () => { };
/**
* Constructs a Node.js `fs` API from a File System Access API
* [`FileSystemDirectoryHandle` object](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemDirectoryHandle).
*/
export class FsaNodeFs extends FsaNodeCore {
// ------------------------------------------------------------ FsPromisesApi
promises = new FsPromises(this, FileHandle);
// ------------------------------------------------------------ FsCallbackApi
open = (path, flags, a, b) => {
let mode = a;
let callback = b;
if (typeof a === 'function') {
mode = 438 /* MODE.DEFAULT */;
callback = a;
}
mode = mode || 438 /* MODE.DEFAULT */;
const modeNum = util.modeToNumber(mode);
const filename = util.pathToFilename(path);
const flagsNum = util.flagsToNumber(flags);
this.__open(filename, flagsNum, modeNum).then(openFile => callback(null, openFile.fd), error => callback(error));
};
close = (fd, callback) => {
util.validateFd(fd);
this.__close(fd).then(() => callback(null), error => callback(error));
};
read = (fd, buffer, offset, length, position, callback) => {
util.validateCallback(callback);
// This `if` branch is from Node.js
if (length === 0) {
return queueMicrotask(() => {
if (callback)
callback(null, 0, buffer);
});
}
(async () => {
const openFile = await this.getFileByFd(fd, 'read');
const file = await openFile.file.getFile();
const src = await file.arrayBuffer();
const slice = new Uint8Array(src, Number(position), Number(length));
const dest = new Uint8Array(buffer.buffer, buffer.byteOffset + offset, slice.length);
dest.set(slice, 0);
return slice.length;
})().then(bytesWritten => callback(null, bytesWritten, buffer), error => callback(error));
};
readFile = (id, a, b) => {
const [opts, callback] = optHelpers.optsAndCbGenerator(optHelpers.getReadFileOptions)(a, b);
const flagsNum = util.flagsToNumber(opts.flag);
(async () => {
let fd = typeof id === 'number' ? id : -1;
const originalFd = fd;
try {
if (fd === -1) {
const filename = util.pathToFilename(id);
fd = (await this.__open(filename, flagsNum, 0)).fd;
}
const handle = await this.__getFileById(fd, 'readFile');
const file = await handle.getFile();
const buffer = Buffer.from(await file.arrayBuffer());
return util.bufferToEncoding(buffer, opts.encoding);
}
finally {
try {
const idWasFd = typeof originalFd === 'number' && originalFd >= 0;
if (idWasFd)
await this.__close(originalFd);
}
catch { }
}
})()
.then(data => callback(null, data))
.catch(error => callback(error));
};
write = (fd, a, b, c, d, e) => {
const [, asStr, buf, offset, length, position, cb] = util.getWriteArgs(fd, a, b, c, d, e);
(async () => {
const openFile = await this.getFileByFd(fd, 'write');
const data = buf.subarray(offset, offset + length);
await openFile.write(data, position);
return length;
})().then(bytesWritten => cb(null, bytesWritten, asStr ? a : buf), error => cb(error));
};
writev = (fd, buffers, a, b) => {
util.validateFd(fd);
let position = null;
let callback;
if (typeof a === 'function') {
callback = a;
}
else {
position = Number(a);
callback = b;
}
util.validateCallback(callback);
(async () => {
const openFile = await this.getFileByFd(fd, 'writev');
const length = buffers.length;
let bytesWritten = 0;
for (let i = 0; i < length; i++) {
const data = buffers[i];
await openFile.write(data, position);
bytesWritten += data.byteLength;
position = null;
}
return bytesWritten;
})().then(bytesWritten => callback(null, bytesWritten, buffers), error => callback(error));
};
writeFile = (id, data, a, b) => {
let options = a;
let callback = b;
if (typeof a === 'function') {
options = optHelpers.writeFileDefaults;
callback = a;
}
const cb = util.validateCallback(callback);
const opts = optHelpers.getWriteFileOptions(options);
const flagsNum = util.flagsToNumber(opts.flag);
const modeNum = util.modeToNumber(opts.mode);
const buf = util.dataToBuffer(data, opts.encoding);
(async () => {
let fd = typeof id === 'number' ? id : -1;
const originalFd = fd;
try {
if (fd === -1) {
const filename = util.pathToFilename(id);
fd = (await this.__open(filename, flagsNum, modeNum)).fd;
}
const file = await this.__getFileById(fd, 'writeFile');
const writable = await file.createWritable({ keepExistingData: false });
await writable.write(buf);
await writable.close();
}
finally {
try {
const idWasFd = typeof originalFd === 'number' && originalFd >= 0;
if (idWasFd)
await this.__close(originalFd);
}
catch { }
}
})().then(() => cb(null), error => cb(error));
};
copyFile = (src, dest, a, b) => {
const srcFilename = util.pathToFilename(src);
const destFilename = util.pathToFilename(dest);
let flags;
let callback;
if (typeof a === 'function') {
flags = 0;
callback = a;
}
else {
flags = a;
callback = b;
}
util.validateCallback(callback);
const [oldFolder, oldName] = pathToLocation(srcFilename);
const [newFolder, newName] = pathToLocation(destFilename);
(async () => {
const oldFile = await this.getFile(oldFolder, oldName, 'copyFile');
const newDir = await this.getDir(newFolder, false, 'copyFile');
const newFile = await newDir.getFileHandle(newName, { create: true });
const writable = await newFile.createWritable({ keepExistingData: false });
const oldData = await oldFile.getFile();
await writable.write(await oldData.arrayBuffer());
await writable.close();
})().then(() => callback(null), error => callback(error));
};
/**
* @todo There is a proposal for native "self remove" operation.
* @see https://github.com/whatwg/fs/blob/main/proposals/Remove.md
*/
unlink = (path, callback) => {
const filename = util.pathToFilename(path);
const [folder, name] = pathToLocation(filename);
this.getDir(folder, false, 'unlink')
.then(dir => dir.removeEntry(name))
.then(() => callback(null), error => {
if (error && typeof error === 'object') {
switch (error.name) {
case 'NotFoundError': {
callback(util.createError('ENOENT', 'unlink', filename));
return;
}
case 'InvalidModificationError': {
callback(util.createError('EISDIR', 'unlink', filename));
return;
}
}
}
callback(error);
});
};
realpath = (path, a, b) => {
const [opts, callback] = optHelpers.getRealpathOptsAndCb(a, b);
let pathFilename = util.pathToFilename(path);
if (pathFilename[0] !== "/" /* FsaToNodeConstants.Separator */)
pathFilename = "/" /* FsaToNodeConstants.Separator */ + pathFilename;
callback(null, strToEncoding(pathFilename, opts.encoding));
};
stat = (path, a, b) => {
const [{ bigint = false, throwIfNoEntry = true }, callback] = optHelpers.getStatOptsAndCb(a, b);
const filename = util.pathToFilename(path);
const [folder, name] = pathToLocation(filename);
(async () => {
const handle = await this.getFileOrDir(folder, name, 'stat');
return await this.getHandleStats(bigint, handle);
})().then(stats => callback(null, stats), error => callback(error));
};
lstat = this.stat;
fstat = (fd, a, b) => {
const [{ bigint = false, throwIfNoEntry = true }, callback] = optHelpers.getStatOptsAndCb(a, b);
(async () => {
const openFile = await this.getFileByFd(fd, 'fstat');
return await this.getHandleStats(bigint, openFile.file);
})().then(stats => callback(null, stats), error => callback(error));
};
async getHandleStats(bigint, handle) {
let size = 0;
if (handle.kind === 'file') {
const file = handle;
const fileData = await file.getFile();
size = fileData.size;
}
const stats = new FsaNodeStats(bigint, bigint ? BigInt(size) : size, handle.kind);
return stats;
}
/**
* @todo There is a proposal for native move support.
* @see https://github.com/whatwg/fs/blob/main/proposals/MovingNonOpfsFiles.md
*/
rename = (oldPath, newPath, callback) => {
const oldPathFilename = util.pathToFilename(oldPath);
const newPathFilename = util.pathToFilename(newPath);
const [oldFolder, oldName] = pathToLocation(oldPathFilename);
const [newFolder, newName] = pathToLocation(newPathFilename);
(async () => {
const oldFile = await this.getFile(oldFolder, oldName, 'rename');
const newDir = await this.getDir(newFolder, false, 'rename');
const newFile = await newDir.getFileHandle(newName, { create: true });
const writable = await newFile.createWritable({ keepExistingData: false });
const oldData = await oldFile.getFile();
await writable.write(await oldData.arrayBuffer());
await writable.close();
const oldDir = await this.getDir(oldFolder, false, 'rename');
await oldDir.removeEntry(oldName);
})().then(() => callback(null), error => callback(error));
};
exists = (path, callback) => {
const filename = util.pathToFilename(path);
if (typeof callback !== 'function')
throw Error(ERRSTR.CB);
this.access(path, 0 /* AMODE.F_OK */, error => callback(!error));
};
access = (path, a, b) => {
let mode = 0 /* AMODE.F_OK */;
let callback;
if (typeof a !== 'function') {
mode = a | 0; // cast to number
callback = util.validateCallback(b);
}
else {
callback = a;
}
const filename = util.pathToFilename(path);
const [folder, name] = pathToLocation(filename);
(async () => {
const node = folder.length || name ? await this.getFileOrDir(folder, name, 'access') : await this.root;
const checkIfCanExecute = mode & 1 /* AMODE.X_OK */;
if (checkIfCanExecute)
throw util.createError('EACCESS', 'access', filename);
const checkIfCanWrite = mode & 2 /* AMODE.W_OK */;
switch (node.kind) {
case 'file': {
if (checkIfCanWrite) {
try {
const file = node;
const writable = await file.createWritable();
await writable.close();
}
catch {
throw util.createError('EACCESS', 'access', filename);
}
}
break;
}
case 'directory': {
if (checkIfCanWrite) {
const dir = node;
const canWrite = await testDirectoryIsWritable(dir);
if (!canWrite)
throw util.createError('EACCESS', 'access', filename);
}
break;
}
default: {
throw util.createError('EACCESS', 'access', filename);
}
}
})().then(() => callback(null), error => callback(error));
};
appendFile = (id, data, a, b) => {
const [opts, callback] = optHelpers.getAppendFileOptsAndCb(a, b);
const buffer = util.dataToBuffer(data, opts.encoding);
this.getFileByIdOrCreate(id, 'appendFile')
.then(file => (async () => {
const blob = await file.getFile();
const writable = await file.createWritable({ keepExistingData: true });
await writable.write({
type: 'write',
data: buffer,
position: blob.size,
});
await writable.close();
})())
.then(() => callback(null), error => callback(error));
};
readdir = (path, a, b) => {
const [options, callback] = optHelpers.getReaddirOptsAndCb(a, b);
const filename = util.pathToFilename(path);
const [folder, name] = pathToLocation(filename);
if (name)
folder.push(name);
this.getDir(folder, false, 'readdir')
.then(dir => (async () => {
if (options.withFileTypes) {
const list = [];
for await (const [name, handle] of dir.entries()) {
const dirent = new FsaNodeDirent(name, handle.kind);
list.push(dirent);
}
if (!util.isWin && options.encoding !== 'buffer')
list.sort((a, b) => {
if (a.name < b.name)
return -1;
if (a.name > b.name)
return 1;
return 0;
});
return list;
}
else {
const list = [];
for await (const key of dir.keys())
list.push(key);
if (!util.isWin && options.encoding !== 'buffer')
list.sort();
return list;
}
})())
.then(res => callback(null, res), err => callback(err));
};
readlink = (path, a, b) => {
const [opts, callback] = optHelpers.getDefaultOptsAndCb(a, b);
const filename = util.pathToFilename(path);
const buffer = Buffer.from(filename);
callback(null, util.bufferToEncoding(buffer, opts.encoding));
};
/** @todo Could this use `FileSystemSyncAccessHandle.flush` through a Worker thread? */
fsync = (fd, callback) => {
callback(null);
};
fdatasync = (fd, callback) => {
callback(null);
};
ftruncate = (fd, a, b) => {
const len = typeof a === 'number' ? a : 0;
const callback = util.validateCallback(typeof a === 'number' ? b : a);
this.getFileByFdAsync(fd)
.then(file => file.file.createWritable({ keepExistingData: true }))
.then(writable => writable.truncate(len).then(() => writable.close()))
.then(() => callback(null), error => callback(error));
};
truncate = (path, a, b) => {
const len = typeof a === 'number' ? a : 0;
const callback = util.validateCallback(typeof a === 'number' ? b : a);
this.open(path, 'r+', (error, fd) => {
if (error)
callback(error);
else {
this.ftruncate(fd, len, error => {
if (error)
this.close(fd, () => callback(error));
else
this.close(fd, callback);
});
}
});
};
futimes = (fd, atime, mtime, callback) => {
callback(null);
};
utimes = (path, atime, mtime, callback) => {
callback(null);
};
mkdir = (path, a, b) => {
const opts = optHelpers.getMkdirOptions(a);
const callback = util.validateCallback(typeof a === 'function' ? a : b);
// const modeNum = modeToNumber(opts.mode, 0o777);
const filename = util.pathToFilename(path);
const [folder, name] = pathToLocation(filename);
// TODO: need to throw if directory already exists
this.getDir(folder, opts.recursive ?? false)
.then(dir => dir.getDirectoryHandle(name, { create: true }))
.then(() => callback(null), error => {
if (error && typeof error === 'object') {
switch (error.name) {
case 'NotFoundError': {
const err = util.createError('ENOENT', 'mkdir', folder.join('/'));
callback(err);
return;
}
}
}
callback(error);
});
};
mkdtemp = (prefix, a, b) => {
const [{ encoding }, callback] = optHelpers.getDefaultOptsAndCb(a, b);
if (!prefix || typeof prefix !== 'string')
throw new TypeError('filename prefix is required');
if (!util.nullCheck(prefix))
return;
const filename = prefix + util.genRndStr6();
this.mkdir(filename, 511 /* MODE.DIR */, err => {
if (err)
callback(err);
else
callback(null, strToEncoding(filename, encoding));
});
};
rmAll(callback) {
(async () => {
const root = await this.root;
for await (const name of root.keys()) {
await root.removeEntry(name, { recursive: true });
}
})().then(() => callback(null), error => callback(error));
}
rmdir = (path, a, b) => {
const options = optHelpers.getRmdirOptions(a);
const callback = util.validateCallback(typeof a === 'function' ? a : b);
const [folder, name] = pathToLocation(util.pathToFilename(path));
if (!name && options.recursive)
return this.rmAll(callback);
this.getDir(folder, false, 'rmdir')
.then(dir => dir.getDirectoryHandle(name).then(() => dir))
.then(dir => dir.removeEntry(name, { recursive: options.recursive ?? false }))
.then(() => callback(null), error => {
if (error && typeof error === 'object') {
switch (error.name) {
case 'NotFoundError': {
const err = util.createError('ENOENT', 'rmdir', folder.join('/'));
callback(err);
return;
}
case 'InvalidModificationError': {
const err = util.createError('ENOTEMPTY', 'rmdir', folder.join('/'));
callback(err);
return;
}
}
}
callback(error);
});
};
rm = (path, a, b) => {
const [options, callback] = optHelpers.getRmOptsAndCb(a, b);
const [folder, name] = pathToLocation(util.pathToFilename(path));
if (!name && options.recursive)
return this.rmAll(callback);
this.getDir(folder, false, 'rmdir')
.then(dir => dir.removeEntry(name, { recursive: options.recursive ?? false }))
.then(() => callback(null), error => {
if (options.force) {
callback(null);
return;
}
if (error && typeof error === 'object') {
switch (error.name) {
case 'NotFoundError': {
const err = util.createError('ENOENT', 'rmdir', folder.join('/'));
callback(err);
return;
}
case 'InvalidModificationError': {
const err = util.createError('ENOTEMPTY', 'rmdir', folder.join('/'));
callback(err);
return;
}
}
}
callback(error);
});
};
fchmod = (fd, mode, callback) => {
callback(null);
};
chmod = (path, mode, callback) => {
callback(null);
};
lchmod = (path, mode, callback) => {
callback(null);
};
fchown = (fd, uid, gid, callback) => {
callback(null);
};
chown = (path, uid, gid, callback) => {
callback(null);
};
lchown = (path, uid, gid, callback) => {
callback(null);
};
createWriteStream = (path, options) => {
const defaults = {
encoding: 'utf8',
flags: 'w',
autoClose: true,
emitClose: true,
};
const optionsObj = optHelpers.getOptions(defaults, options);
const filename = util.pathToFilename(path);
const flags = util.flagsToNumber(optionsObj.flags ?? 'w');
const fd = optionsObj.fd ? (typeof optionsObj.fd === 'number' ? optionsObj.fd : optionsObj.fd.fd) : 0;
const handle = fd ? this.getFileByFdAsync(fd) : this.__open(filename, flags, 0);
const stream = new FsaNodeWriteStream(handle, filename, optionsObj);
if (optionsObj.autoClose) {
stream.once('finish', () => {
handle.then(file => this.close(file.fd, () => { }));
});
stream.once('error', () => {
handle.then(file => this.close(file.fd, () => { }));
});
}
return stream;
};
createReadStream = (path, options) => {
const defaults = {
flags: 'r',
fd: null,
mode: 0o666,
autoClose: true,
emitClose: true,
start: 0,
end: Infinity,
highWaterMark: 64 * 1024,
fs: null,
signal: null,
};
const optionsObj = optHelpers.getOptions(defaults, options);
const filename = util.pathToFilename(path);
const flags = util.flagsToNumber(optionsObj.flags);
const fd = optionsObj.fd ? (typeof optionsObj.fd === 'number' ? optionsObj.fd : optionsObj.fd.fd) : 0;
const handle = fd ? this.getFileByFdAsync(fd) : this.__open(filename, flags, 0);
const stream = new FsaNodeReadStream(this, handle, filename, optionsObj);
return stream;
};
cp = notImplemented;
lutimes = notImplemented;
openAsBlob = notImplemented;
opendir = notImplemented;
readv = notImplemented;
statfs = notImplemented;
/**
* @todo Watchers could be implemented in the future on top of `FileSystemObserver`,
* which is currently a proposal.
* @see https://github.com/whatwg/fs/blob/main/proposals/FileSystemObserver.md
*/
watchFile = notSupported;
unwatchFile = notSupported;
watch = notSupported;
symlink = notSupported;
link = notSupported;
// --------------------------------------------------------- FsSynchronousApi
statSync = (path, options) => {
const { bigint = true, throwIfNoEntry = true } = optHelpers.getStatOptions(options);
const filename = util.pathToFilename(path);
const location = pathToLocation(filename);
const adapter = this.getSyncAdapter();
const res = adapter.call('stat', location);
const stats = new FsaNodeStats(bigint, res.size ?? 0, res.kind);
return stats;
};
lstatSync = this.statSync;
fstatSync = (fd, options) => {
const filename = this.getFileName(fd);
return this.statSync(filename, options);
};
accessSync = (path, mode = 0 /* AMODE.F_OK */) => {
const filename = util.pathToFilename(path);
mode = mode | 0;
const adapter = this.getSyncAdapter();
adapter.call('access', [filename, mode]);
};
readFileSync = (id, options) => {
const opts = optHelpers.getReadFileOptions(options);
const flagsNum = util.flagsToNumber(opts.flag);
const filename = this.getFileName(id);
const adapter = this.getSyncAdapter();
const uint8 = adapter.call('readFile', [filename, opts]);
const buffer = Buffer.from(uint8.buffer, uint8.byteOffset, uint8.byteLength);
return util.bufferToEncoding(buffer, opts.encoding);
};
writeFileSync = (id, data, options) => {
const opts = optHelpers.getWriteFileOptions(options);
const flagsNum = util.flagsToNumber(opts.flag);
const modeNum = util.modeToNumber(opts.mode);
const buf = util.dataToBuffer(data, opts.encoding);
const filename = this.getFileName(id);
const adapter = this.getSyncAdapter();
adapter.call('writeFile', [filename, util.bufToUint8(buf), opts]);
};
appendFileSync = (id, data, options) => {
const opts = optHelpers.getAppendFileOpts(options);
if (!opts.flag || util.isFd(id))
opts.flag = 'a';
const filename = this.getFileName(id);
const buf = util.dataToBuffer(data, opts.encoding);
const adapter = this.getSyncAdapter();
adapter.call('appendFile', [filename, util.bufToUint8(buf), opts]);
};
closeSync = (fd) => {
util.validateFd(fd);
const file = this.getFileByFd(fd, 'close');
file.close().catch(() => { });
this.fds.delete(fd);
this.releasedFds.push(fd);
};
existsSync = (path) => {
try {
this.statSync(path);
return true;
}
catch {
return false;
}
};
copyFileSync = (src, dest, flags) => {
const srcFilename = util.pathToFilename(src);
const destFilename = util.pathToFilename(dest);
const adapter = this.getSyncAdapter();
adapter.call('copy', [srcFilename, destFilename, flags]);
};
renameSync = (oldPath, newPath) => {
const srcFilename = util.pathToFilename(oldPath);
const destFilename = util.pathToFilename(newPath);
const adapter = this.getSyncAdapter();
adapter.call('move', [srcFilename, destFilename]);
};
rmdirSync = (path, opts) => {
const filename = util.pathToFilename(path);
const adapter = this.getSyncAdapter();
adapter.call('rmdir', [filename, opts]);
};
rmSync = (path, options) => {
const filename = util.pathToFilename(path);
const adapter = this.getSyncAdapter();
adapter.call('rm', [filename, options]);
};
mkdirSync = (path, options) => {
const opts = optHelpers.getMkdirOptions(options);
const modeNum = util.modeToNumber(opts.mode, 0o777);
const filename = util.pathToFilename(path);
return this.getSyncAdapter().call('mkdir', [filename, options]);
};
mkdtempSync = (prefix, options) => {
const { encoding } = optHelpers.getDefaultOpts(options);
if (!prefix || typeof prefix !== 'string')
throw new TypeError('filename prefix is required');
util.nullCheck(prefix);
const result = this.getSyncAdapter().call('mkdtemp', [prefix, options]);
return strToEncoding(result, encoding);
};
readlinkSync = (path, options) => {
const opts = optHelpers.getDefaultOpts(options);
const filename = util.pathToFilename(path);
const buffer = Buffer.from(filename);
return util.bufferToEncoding(buffer, opts.encoding);
};
truncateSync = (id, len) => {
if (util.isFd(id))
return this.ftruncateSync(id, len);
const filename = util.pathToFilename(id);
this.getSyncAdapter().call('trunc', [filename, Number(len) || 0]);
};
ftruncateSync = (fd, len) => {
const filename = this.getFileName(fd);
this.truncateSync(filename, len);
};
unlinkSync = (path) => {
const filename = util.pathToFilename(path);
this.getSyncAdapter().call('unlink', [filename]);
};
readdirSync = (path, options) => {
const opts = optHelpers.getReaddirOptions(options);
const filename = util.pathToFilename(path);
const adapter = this.getSyncAdapter();
const list = adapter.call('readdir', [filename]);
if (opts.withFileTypes) {
const res = [];
for (const entry of list)
res.push(new FsaNodeDirent(entry.name, entry.kind));
return res;
}
else {
const res = [];
for (const entry of list) {
const buffer = Buffer.from(entry.name);
res.push(util.bufferToEncoding(buffer, opts.encoding));
}
return res;
}
};
realpathSync = (path, options) => {
let filename = util.pathToFilename(path);
const { encoding } = optHelpers.getRealpathOptions(options);
if (filename[0] !== "/" /* FsaToNodeConstants.Separator */)
filename = "/" /* FsaToNodeConstants.Separator */ + filename;
return strToEncoding(filename, encoding);
};
readSync = (fd, buffer, offset, length, position) => {
util.validateFd(fd);
const filename = this.getFileName(fd);
const adapter = this.getSyncAdapter();
const uint8 = adapter.call('read', [filename, position, length]);
const dest = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
dest.set(uint8, offset);
return uint8.length;
};
writeSync = (fd, a, b, c, d) => {
const [, buf, offset, length, position] = util.getWriteSyncArgs(fd, a, b, c, d);
const filename = this.getFileName(fd);
const data = new Uint8Array(buf.buffer, buf.byteOffset + offset, length);
return this.getSyncAdapter().call('write', [filename, data, position || null]);
};
openSync = (path, flags, mode = 438 /* MODE.DEFAULT */) => {
const modeNum = util.modeToNumber(mode);
const filename = util.pathToFilename(path);
const flagsNum = util.flagsToNumber(flags);
const adapter = this.getSyncAdapter();
const handle = adapter.call('open', [filename, flagsNum, modeNum]);
const openFile = this.__open2(handle, filename, flagsNum, modeNum);
return openFile.fd;
};
writevSync = (fd, buffers, position) => {
if (buffers.length === 0)
return;
this.writeSync(fd, buffers[0], 0, buffers[0].byteLength, position);
for (let i = 1; i < buffers.length; i++) {
this.writeSync(fd, buffers[i], 0, buffers[i].byteLength, null);
}
};
fdatasyncSync = noop;
fsyncSync = noop;
chmodSync = noop;
chownSync = noop;
fchmodSync = noop;
fchownSync = noop;
futimesSync = noop;
lchmodSync = noop;
lchownSync = noop;
utimesSync = noop;
lutimesSync = noop;
cpSync = notImplemented;
opendirSync = notImplemented;
statfsSync = notImplemented;
readvSync = notImplemented;
symlinkSync = notSupported;
linkSync = notSupported;
// ---------------------------------------------------------- FsCommonObjects
F_OK = constants.F_OK;
R_OK = constants.R_OK;
W_OK = constants.W_OK;
X_OK = constants.X_OK;
constants = constants;
Dirent = FsaNodeDirent;
Stats = (FsaNodeStats);
WriteStream = FsaNodeWriteStream;
ReadStream = FsaNodeReadStream;
StatFs = 0;
Dir = 0;
StatsWatcher = 0;
FSWatcher = 0;
}