| const FIFO = require('fast-fifo') |
| const EventEmitter = require('bare-events') |
| const path = require('bare-path') |
| const { isURL, fileURLToPath } = require('bare-url') |
| const { Readable, Writable } = require('bare-stream') |
| const binding = require('./binding') |
| const constants = require('./lib/constants') |
| const FileError = require('./lib/errors') |
| |
| const isWindows = Bare.platform === 'win32' |
| |
| exports.constants = constants |
| |
| class FileRequest { |
| static borrow() { |
| if (this._free.length > 0) return this._free.pop() |
| return new FileRequest() |
| } |
| |
| static return(req) { |
| if (this._free.length < 32) this._free.push(req.reset()) |
| else req.destroy() |
| } |
| |
| constructor() { |
| this._reset() |
| this._handle = binding.requestInit(this, this._onresult) |
| } |
| |
| get handle() { |
| return this._handle |
| } |
| |
| retain(value) { |
| this._retain = value // Tie the lifetime of `value` to the lifetime of `this` |
| } |
| |
| reset() { |
| if (this._handle === null) return this |
| |
| binding.requestReset(this._handle) |
| |
| this._reset() |
| |
| return this |
| } |
| |
| destroy() { |
| if (this._handle === null) return this |
| |
| binding.requestDestroy(this._handle) |
| |
| this._reset() |
| this._handle = null |
| |
| return this |
| } |
| |
| then(resolve, reject) { |
| return this._promise.then(resolve, reject) |
| } |
| |
| return() { |
| if (this._handle === null) return this |
| |
| FileRequest.return(this) |
| |
| return this |
| } |
| |
| _reset() { |
| this._promise = new Promise((resolve, reject) => { |
| this._resolve = resolve |
| this._reject = reject |
| }) |
| this._retain = null |
| } |
| |
| _onresult(err, status) { |
| if (err) this._reject(err) |
| else this._resolve(status) |
| } |
| } |
| |
| FileRequest._free = [] |
| |
| function ok(result, cb) { |
| if (typeof result === 'function') { |
| cb = result |
| result = undefined |
| } |
| |
| if (cb) cb(null, result) |
| else return result |
| } |
| |
| function fail(err, cb) { |
| if (cb) cb(err) |
| else throw err |
| } |
| |
| function done(err, result, cb) { |
| if (typeof result === 'function') { |
| cb = result |
| result = undefined |
| } |
| |
| if (err) fail(err, cb) |
| else return ok(result, cb) |
| } |
| |
| async function open(filepath, flags = 'r', mode = 0o666, cb) { |
| if (typeof flags === 'function') { |
| cb = flags |
| flags = 'r' |
| mode = 0o666 |
| } else if (typeof mode === 'function') { |
| cb = mode |
| mode = 0o666 |
| } |
| |
| if (typeof flags === 'string') flags = toFlags(flags) |
| if (typeof mode === 'string') mode = toMode(mode) |
| |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| let fd |
| let err = null |
| try { |
| binding.open(req.handle, filepath, flags, mode) |
| |
| fd = await req |
| } catch (e) { |
| err = new FileError(e.message, { |
| operation: 'open', |
| code: e.code, |
| path: filepath |
| }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, fd, cb) |
| } |
| |
| function openSync(filepath, flags = 'r', mode = 0o666) { |
| if (typeof flags === 'string') flags = toFlags(flags) |
| if (typeof mode === 'string') mode = toMode(mode) |
| |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| return binding.openSync(req.handle, filepath, flags, mode) |
| } catch (e) { |
| throw new FileError(e.message, { |
| operation: 'open', |
| code: e.code, |
| path: filepath |
| }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function close(fd, cb) { |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.close(req.handle, fd) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'close', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, cb) |
| } |
| |
| function closeSync(fd) { |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.closeSync(req.handle, fd) |
| } catch (e) { |
| throw new FileError(e.message, { operation: 'close', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function access(filepath, mode = constants.F_OK, cb) { |
| if (typeof mode === 'function') { |
| cb = mode |
| mode = constants.F_OK |
| } |
| |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.access(req.handle, filepath, mode) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { |
| operation: 'access', |
| code: e.code, |
| path: filepath |
| }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, cb) |
| } |
| |
| function accessSync(filepath, mode = constants.F_OK) { |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.accessSync(req.handle, filepath, mode) |
| } catch (e) { |
| throw new FileError(e.message, { |
| operation: 'access', |
| code: e.code, |
| path: filepath |
| }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function exists(filepath, cb) { |
| let ok = true |
| try { |
| await access(filepath) |
| } catch { |
| ok = false |
| } |
| |
| return done(null, ok, cb) |
| } |
| |
| function existsSync(filepath) { |
| try { |
| accessSync(filepath) |
| } catch { |
| return false |
| } |
| |
| return true |
| } |
| |
| async function read(fd, buffer, offset = 0, len = buffer.byteLength - offset, pos = -1, cb) { |
| if (typeof offset === 'function') { |
| cb = offset |
| offset = 0 |
| len = buffer.byteLength |
| pos = -1 |
| } else if (typeof len === 'function') { |
| cb = len |
| len = buffer.byteLength - offset |
| pos = -1 |
| } else if (typeof pos === 'function') { |
| cb = pos |
| pos = -1 |
| } |
| |
| if (typeof pos !== 'number') pos = -1 |
| |
| const req = FileRequest.borrow() |
| |
| let bytes |
| let err = null |
| try { |
| binding.read(req.handle, fd, buffer, offset, len, pos) |
| |
| req.retain(buffer) |
| |
| bytes = await req |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'read', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, bytes, cb) |
| } |
| |
| function readSync(fd, buffer, offset = 0, len = buffer.byteLength - offset, pos = -1) { |
| const req = FileRequest.borrow() |
| |
| try { |
| return binding.readSync(req.handle, fd, buffer, offset, len, pos) |
| } catch (e) { |
| throw new FileError(e.message, { operation: 'read', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function readv(fd, buffers, pos = -1, cb) { |
| if (typeof pos === 'function') { |
| cb = pos |
| pos = -1 |
| } |
| |
| if (typeof pos !== 'number') pos = -1 |
| |
| const req = FileRequest.borrow() |
| |
| let bytes |
| let err = null |
| try { |
| binding.readv(req.handle, fd, buffers, pos) |
| |
| req.retain(buffers) |
| |
| bytes = await req |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'readv', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, bytes, cb) |
| } |
| |
| function readvSync(fd, buffers, pos = -1) { |
| if (typeof pos !== 'number') pos = -1 |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| return binding.readvSync(req.handle, fd, buffers, pos) |
| } catch (e) { |
| throw new FileError(e.message, { operation: 'readv', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function write(fd, data, offset, len, pos = -1, cb) { |
| if (typeof data === 'string') { |
| let encoding = len |
| cb = pos |
| pos = offset |
| |
| if (typeof pos === 'function') { |
| cb = pos |
| pos = -1 |
| encoding = 'utf8' |
| } else if (typeof encoding === 'function') { |
| cb = encoding |
| encoding = 'utf8' |
| } |
| |
| if (typeof pos === 'string') { |
| encoding = pos |
| pos = -1 |
| } |
| |
| data = Buffer.from(data, encoding) |
| offset = 0 |
| len = data.byteLength |
| } else if (typeof offset === 'function') { |
| cb = offset |
| offset = 0 |
| len = data.byteLength |
| pos = -1 |
| } else if (typeof len === 'function') { |
| cb = len |
| len = data.byteLength - offset |
| pos = -1 |
| } else if (typeof pos === 'function') { |
| cb = pos |
| pos = -1 |
| } |
| |
| if (typeof offset !== 'number') offset = 0 |
| if (typeof len !== 'number') len = data.byteLength - offset |
| if (typeof pos !== 'number') pos = -1 |
| |
| const req = FileRequest.borrow() |
| |
| let bytes |
| let err = null |
| try { |
| binding.write(req.handle, fd, data, offset, len, pos) |
| |
| req.retain(data) |
| |
| bytes = await req |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'write', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, bytes, cb) |
| } |
| |
| function writeSync(fd, data, offset, len, pos = -1) { |
| if (typeof data === 'string') { |
| let encoding = len |
| pos = offset |
| |
| if (typeof pos === 'string') { |
| encoding = pos |
| pos = -1 |
| } |
| |
| data = Buffer.from(data, encoding) |
| offset = 0 |
| len = data.byteLength |
| } |
| |
| if (typeof offset !== 'number') offset = 0 |
| if (typeof len !== 'number') len = data.byteLength - offset |
| if (typeof pos !== 'number') pos = -1 |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| return binding.writeSync(req.handle, fd, data, offset, len, pos) |
| } catch (e) { |
| throw new FileError(e.message, { operation: 'write', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function writev(fd, buffers, pos = -1, cb) { |
| if (typeof pos === 'function') { |
| cb = pos |
| pos = -1 |
| } |
| |
| if (typeof pos !== 'number') pos = -1 |
| |
| const req = FileRequest.borrow() |
| |
| let bytes |
| let err = null |
| try { |
| binding.writev(req.handle, fd, buffers, pos) |
| |
| req.retain(buffers) |
| |
| bytes = await req |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'writev', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, bytes, cb) |
| } |
| |
| function writevSync(fd, buffers, pos = -1) { |
| if (typeof pos !== 'number') pos = -1 |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| return binding.writevSync(req.handle, fd, buffers, pos) |
| } catch (e) { |
| throw new FileError(e.message, { operation: 'writev', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function stat(filepath, cb) { |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| let st |
| let err = null |
| try { |
| binding.stat(req.handle, filepath) |
| |
| await req |
| |
| st = new Stats(...binding.requestResultStat(req.handle)) |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'stat', code: e.code, path: filepath }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, st, cb) |
| } |
| |
| function statSync(filepath) { |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.statSync(req.handle, filepath) |
| |
| return new Stats(...binding.requestResultStat(req.handle)) |
| } catch (e) { |
| throw new FileError(e.message, { operation: 'stat', code: e.code, path: filepath }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function lstat(filepath, cb) { |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| let st |
| let err = null |
| try { |
| binding.lstat(req.handle, filepath) |
| |
| await req |
| |
| st = new Stats(...binding.requestResultStat(req.handle)) |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'lstat', code: e.code, path: filepath }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, st, cb) |
| } |
| |
| function lstatSync(filepath) { |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.lstatSync(req.handle, filepath) |
| |
| return new Stats(...binding.requestResultStat(req.handle)) |
| } catch (e) { |
| throw new FileError(e.message, { operation: 'lstat', code: e.code, path: filepath }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function fstat(fd, cb) { |
| const req = FileRequest.borrow() |
| |
| let st |
| let err = null |
| try { |
| binding.fstat(req.handle, fd) |
| |
| await req |
| |
| st = new Stats(...binding.requestResultStat(req.handle)) |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'fstat', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, st, cb) |
| } |
| |
| function fstatSync(fd) { |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.fstatSync(req.handle, fd) |
| |
| return new Stats(...binding.requestResultStat(req.handle)) |
| } catch (e) { |
| throw new FileError(e.message, { operation: 'fstat', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function statfs(filepath, cb) { |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| let st |
| let err = null |
| try { |
| binding.statfs(req.handle, filepath) |
| |
| await req |
| |
| st = new StatFs(...binding.requestResultStatfs(req.handle)) |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'statfs', code: e.code, path: filepath }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, st, cb) |
| } |
| |
| function statfsSync(filepath) { |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.statfsSync(req.handle, filepath) |
| |
| return new StatFs(...binding.requestResultStatfs(req.handle)) |
| } catch (e) { |
| throw new FileError(e.message, { operation: 'statfs', code: e.code, path: filepath }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function ftruncate(fd, len = 0, cb) { |
| if (typeof len === 'function') { |
| cb = len |
| len = 0 |
| } |
| |
| if (typeof len !== 'number') len = 0 |
| |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.ftruncate(req.handle, fd, len) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'ftruncate', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, cb) |
| } |
| |
| function ftruncateSync(fd, len = 0) { |
| if (typeof len !== 'number') len = 0 |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.ftruncateSync(req.handle, fd, len) |
| } catch (e) { |
| throw new FileError(e.message, { operation: 'ftruncate', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function truncate(filepath, len, cb) { |
| let fd = -1 |
| let err |
| |
| try { |
| fd = await open(filepath, 'r+') |
| |
| await ftruncate(fd, len) |
| } catch (e) { |
| err = e |
| } finally { |
| if (fd !== -1) await close(fd) |
| } |
| |
| return done(err, cb) |
| } |
| |
| function truncateSync(filepath, len) { |
| let fd = -1 |
| let err |
| |
| try { |
| fd = openSync(filepath, 'r+') |
| |
| ftruncateSync(fd, len) |
| } catch (e) { |
| err = e |
| } finally { |
| if (fd !== -1) closeSync(fd) |
| } |
| } |
| |
| async function chmod(filepath, mode, cb) { |
| if (typeof mode === 'string') mode = toMode(mode) |
| |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.chmod(req.handle, filepath, mode) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { |
| operation: 'chmod', |
| code: e.code, |
| path: filepath |
| }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, cb) |
| } |
| |
| function chmodSync(filepath, mode) { |
| if (typeof mode === 'string') mode = toMode(mode) |
| |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.chmodSync(req.handle, filepath, mode) |
| } catch (e) { |
| throw new FileError(e.message, { |
| operation: 'chmod', |
| code: e.code, |
| path: filepath |
| }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function fchmod(fd, mode, cb) { |
| if (typeof mode === 'string') mode = toMode(mode) |
| |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.fchmod(req.handle, fd, mode) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'fchmod', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, cb) |
| } |
| |
| function fchmodSync(fd, mode) { |
| if (typeof mode === 'string') mode = toMode(mode) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.fchmodSync(req.handle, fd, mode) |
| } catch (e) { |
| throw new FileError(e.message, { operation: 'fchmod', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function chown(filepath, uid, gid, cb) { |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.chown(req.handle, filepath, uid, gid) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'chown', code: e.code, path: filepath }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, cb) |
| } |
| |
| function chownSync(filepath, uid, gid) { |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.chownSync(req.handle, filepath, uid, gid) |
| } catch (e) { |
| throw new FileError(e.message, { operation: 'chownSync', code: e.code, path: filepath }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function lchown(filepath, uid, gid, cb) { |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.lchown(req.handle, filepath, uid, gid) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'lchown', code: e.code, path: filepath }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, cb) |
| } |
| |
| function lchownSync(filepath, uid, gid) { |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.lchownSync(req.handle, filepath, uid, gid) |
| } catch (e) { |
| throw new FileError(e.message, { operation: 'lchownSync', code: e.code, path: filepath }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function fchown(fd, uid, gid, cb) { |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.fchown(req.handle, fd, uid, gid) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'fchown', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, cb) |
| } |
| |
| function fchownSync(fd, uid, gid) { |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.fchownSync(req.handle, fd, uid, gid) |
| } catch (e) { |
| throw new FileError(e.message, { operation: 'fchownSync', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function utimes(filepath, atime, mtime, cb) { |
| if (typeof atime !== 'number') atime = atime.getTime() / 1000 |
| if (typeof mtime !== 'number') mtime = mtime.getTime() / 1000 |
| |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.utimes(req.handle, filepath, atime, mtime) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'utimes', code: e.code, path: filepath }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, cb) |
| } |
| |
| function utimesSync(filepath, atime, mtime) { |
| if (typeof atime !== 'number') atime = atime.getTime() / 1000 |
| if (typeof mtime !== 'number') mtime = mtime.getTime() / 1000 |
| |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.utimesSync(req.handle, filepath, atime, mtime) |
| } catch (e) { |
| throw new FileError(e.message, { operation: 'utimes', code: e.code, path: filepath }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function lutimes(filepath, atime, mtime, cb) { |
| if (typeof atime !== 'number') atime = atime.getTime() / 1000 |
| if (typeof mtime !== 'number') mtime = mtime.getTime() / 1000 |
| |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.lutimes(req.handle, filepath, atime, mtime) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'lutimes', code: e.code, path: filepath }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, cb) |
| } |
| |
| function lutimesSync(filepath, atime, mtime) { |
| if (typeof atime !== 'number') atime = atime.getTime() / 1000 |
| if (typeof mtime !== 'number') mtime = mtime.getTime() / 1000 |
| |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.lutimesSync(req.handle, filepath, atime, mtime) |
| } catch (e) { |
| throw new FileError(e.message, { operation: 'lutimes', code: e.code, path: filepath }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function futimes(fd, atime, mtime, cb) { |
| if (typeof atime !== 'number') atime = atime.getTime() / 1000 |
| if (typeof mtime !== 'number') mtime = mtime.getTime() / 1000 |
| |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.futimes(req.handle, fd, atime, mtime) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'futimes', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, cb) |
| } |
| |
| function futimesSync(fd, atime, mtime) { |
| if (typeof atime !== 'number') atime = atime.getTime() / 1000 |
| if (typeof mtime !== 'number') mtime = mtime.getTime() / 1000 |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.futimesSync(req.handle, fd, atime, mtime) |
| } catch (e) { |
| throw new FileError(e.message, { operation: 'futimesSync', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function link(src, dst, cb) { |
| src = toNamespacedPath(src) |
| dst = toNamespacedPath(dst) |
| |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.link(req.handle, src, dst) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'link', code: e.code, path: src, destination: dst }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, cb) |
| } |
| |
| function linkSync(src, dst) { |
| src = toNamespacedPath(src) |
| dst = toNamespacedPath(dst) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.linkSync(req.handle, src, dst) |
| } catch (e) { |
| throw new FileError(e.message, { |
| operation: 'linkSync', |
| code: e.code, |
| path: src, |
| destination: dst |
| }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function mkdir(filepath, opts, cb) { |
| if (typeof opts === 'function') { |
| cb = opts |
| opts = { mode: 0o777 } |
| } |
| |
| if (typeof opts === 'number') opts = { mode: opts } |
| else if (!opts) opts = {} |
| |
| const mode = typeof opts.mode === 'number' ? opts.mode : 0o777 |
| |
| filepath = toNamespacedPath(filepath) |
| |
| if (opts.recursive) { |
| let err = null |
| try { |
| try { |
| await mkdir(filepath, { mode }) |
| } catch (err) { |
| if (err.code !== 'ENOENT') { |
| if (!(await stat(filepath)).isDirectory()) throw err |
| } else { |
| while (filepath.endsWith(path.sep)) filepath = filepath.slice(0, -1) |
| const i = filepath.lastIndexOf(path.sep) |
| if (i <= 0) throw err |
| |
| await mkdir(filepath.slice(0, i), { mode, recursive: true }) |
| |
| try { |
| await mkdir(filepath, { mode }) |
| } catch (err) { |
| if (!(await stat(filepath)).isDirectory()) throw err |
| } |
| } |
| } |
| } catch (e) { |
| err = e |
| } |
| |
| return done(err, cb) |
| } |
| |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.mkdir(req.handle, filepath, mode) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { |
| operation: 'mkdir', |
| code: e.code, |
| path: filepath |
| }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, cb) |
| } |
| |
| function mkdirSync(filepath, opts) { |
| if (typeof opts === 'number') opts = { mode: opts } |
| else if (!opts) opts = {} |
| |
| const mode = typeof opts.mode === 'number' ? opts.mode : 0o777 |
| |
| filepath = toNamespacedPath(filepath) |
| |
| if (opts.recursive) { |
| try { |
| mkdirSync(filepath, { mode }) |
| } catch (err) { |
| if (err.code !== 'ENOENT') { |
| if (!statSync(filepath).isDirectory()) throw err |
| } else { |
| while (filepath.endsWith(path.sep)) filepath = filepath.slice(0, -1) |
| const i = filepath.lastIndexOf(path.sep) |
| if (i <= 0) throw err |
| |
| mkdirSync(filepath.slice(0, i), { mode, recursive: true }) |
| |
| try { |
| mkdirSync(filepath, { mode }) |
| } catch (err) { |
| if (!statSync(filepath).isDirectory()) throw err |
| } |
| } |
| } |
| |
| return |
| } |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.mkdirSync(req.handle, filepath, mode) |
| } catch (e) { |
| throw new FileError(e.message, { |
| operation: 'mkdir', |
| code: e.code, |
| path: filepath |
| }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function mkdtemp(prefix, cb) { |
| prefix = toNamespacedPath(prefix) |
| |
| const req = FileRequest.borrow() |
| |
| let res |
| let err = null |
| try { |
| binding.mkdtemp(req.handle, prefix + 'XXXXXX') |
| |
| await req |
| |
| res = binding.requestResultPath(req.handle) |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'mkdtemp', code: e.code, path: prefix }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, res, cb) |
| } |
| |
| function mkdtempSync(prefix) { |
| prefix = toNamespacedPath(prefix) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.mkdtempSync(req.handle, prefix + 'XXXXXX') |
| |
| return binding.requestResultPath(req.handle) |
| } catch (e) { |
| throw new FileError(e.message, { operation: 'mkdtempSync', code: e.code, path: prefix }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function rmdir(filepath, cb) { |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.rmdir(req.handle, filepath) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { |
| operation: 'rmdir', |
| code: e.code, |
| path: filepath |
| }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, cb) |
| } |
| |
| function rmdirSync(filepath) { |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.rmdirSync(req.handle, filepath) |
| } catch (e) { |
| throw new FileError(e.message, { |
| operation: 'rmdir', |
| code: e.code, |
| path: filepath |
| }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function rm(filepath, opts, cb) { |
| if (typeof opts === 'function') { |
| cb = opts |
| opts = {} |
| } |
| |
| if (!opts) opts = {} |
| |
| filepath = toNamespacedPath(filepath) |
| |
| let err = null |
| try { |
| const st = await lstat(filepath) |
| |
| if (st.isDirectory()) { |
| if (opts.recursive) { |
| try { |
| await rmdir(filepath) |
| } catch (err) { |
| if (err.code !== 'ENOTEMPTY') throw err |
| |
| const files = await readdir(filepath) |
| |
| for (const file of files) { |
| await rm(filepath + path.sep + file, opts) |
| } |
| |
| await rmdir(filepath) |
| } |
| } else { |
| throw new FileError('is a directory', { |
| operation: 'rm', |
| code: 'EISDIR', |
| path: filepath |
| }) |
| } |
| } else { |
| await unlink(filepath) |
| } |
| } catch (e) { |
| if (e.code !== 'ENOENT' || !opts.force) err = e |
| } |
| |
| return done(err, cb) |
| } |
| |
| function rmSync(filepath, opts) { |
| if (!opts) opts = {} |
| |
| filepath = toNamespacedPath(filepath) |
| |
| try { |
| const st = lstatSync(filepath) |
| |
| if (st.isDirectory()) { |
| if (opts.recursive) { |
| try { |
| rmdirSync(filepath) |
| } catch (err) { |
| if (err.code !== 'ENOTEMPTY') throw err |
| |
| const files = readdirSync(filepath) |
| |
| for (const file of files) { |
| rmSync(filepath + path.sep + file, opts) |
| } |
| |
| rmdirSync(filepath) |
| } |
| } else { |
| throw new FileError('is a directory', { |
| operation: 'rm', |
| code: 'EISDIR', |
| path: filepath |
| }) |
| } |
| } else { |
| unlinkSync(filepath) |
| } |
| } catch (err) { |
| if (err.code !== 'ENOENT' || !opts.force) throw err |
| } |
| } |
| |
| async function unlink(filepath, cb) { |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.unlink(req.handle, filepath) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { |
| operation: 'unlink', |
| code: e.code, |
| path: filepath |
| }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, cb) |
| } |
| |
| function unlinkSync(filepath) { |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.unlinkSync(req.handle, filepath) |
| } catch (e) { |
| throw new FileError(e.message, { |
| operation: 'unlink', |
| code: e.code, |
| path: filepath |
| }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function rename(src, dst, cb) { |
| src = toNamespacedPath(src) |
| dst = toNamespacedPath(dst) |
| |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.rename(req.handle, src, dst) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { |
| operation: 'rename', |
| code: e.code, |
| path: src, |
| destination: dst |
| }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, cb) |
| } |
| |
| function renameSync(src, dst) { |
| src = toNamespacedPath(src) |
| dst = toNamespacedPath(dst) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.renameSync(req.handle, src, dst) |
| } catch (e) { |
| throw new FileError(e.message, { |
| operation: 'rename', |
| code: e.code, |
| path: src, |
| destination: dst |
| }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function copyFile(src, dst, mode = 0, cb) { |
| if (typeof mode === 'function') { |
| cb = mode |
| mode = 0 |
| } |
| |
| src = toNamespacedPath(src) |
| dst = toNamespacedPath(dst) |
| |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.copyfile(req.handle, src, dst, mode) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { |
| operation: 'copyfile', |
| code: e.code, |
| path: src, |
| destination: dst |
| }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, cb) |
| } |
| |
| function copyFileSync(src, dst, mode = 0) { |
| src = toNamespacedPath(src) |
| dst = toNamespacedPath(dst) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.copyfileSync(req.handle, src, dst, mode) |
| } catch (e) { |
| throw new FileError(e.message, { |
| operation: 'copyfile', |
| code: e.code, |
| path: src, |
| destination: dst |
| }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function cp(src, dst, opts, cb) { |
| if (typeof opts === 'function') { |
| cb = opts |
| opts = {} |
| } |
| |
| if (!opts) opts = {} |
| |
| src = toNamespacedPath(src) |
| dst = toNamespacedPath(dst) |
| |
| let err = null |
| try { |
| const st = await lstat(src) |
| |
| if (st.isDirectory()) { |
| if (opts.recursive !== true) { |
| throw new FileError('is a directory', { operation: 'cp', code: 'EISDIR', path: src }) |
| } |
| |
| try { |
| await lstat(dst) |
| } catch (e) { |
| if (e.code !== 'ENOENT') throw e |
| |
| await mkdir(dst, { mode: st.mode, recursive: true }) |
| } |
| |
| const dir = await opendir(src) |
| for await (const { name } of dir) { |
| await cp(path.join(src, name), path.join(dst, name), opts) |
| } |
| } else if (st.isFile()) { |
| await copyFile(src, dst) |
| await chmod(dst, st.mode) |
| } |
| } catch (e) { |
| err = e |
| } |
| |
| return done(err, cb) |
| } |
| |
| function cpSync(src, dst, opts = {}) { |
| src = toNamespacedPath(src) |
| dst = toNamespacedPath(dst) |
| |
| const st = lstatSync(src) |
| |
| if (st.isDirectory()) { |
| if (opts.recursive !== true) { |
| throw new FileError('is a directory', { operation: 'cp', code: 'EISDIR', path: src }) |
| } |
| |
| try { |
| lstatSync(dst) |
| } catch (e) { |
| if (e.code !== 'ENOENT') throw e |
| |
| mkdirSync(dst, { mode: st.mode, recursive: true }) |
| } |
| |
| const dir = opendirSync(src) |
| for (const { name } of dir) { |
| cpSync(path.join(src, name), path.join(dst, name), opts) |
| } |
| } else if (st.isFile()) { |
| copyFileSync(src, dst) |
| chmodSync(dst, st.mode) |
| } |
| } |
| |
| async function realpath(filepath, opts, cb) { |
| if (typeof opts === 'function') { |
| cb = opts |
| opts = {} |
| } |
| |
| if (typeof opts === 'string') opts = { encoding: opts } |
| else if (!opts) opts = {} |
| |
| const { encoding = 'utf8' } = opts |
| |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| let res |
| let err = null |
| try { |
| binding.realpath(req.handle, filepath) |
| |
| await req |
| |
| res = Buffer.from(binding.requestResultString(req.handle)) |
| |
| if (encoding !== 'buffer') res = res.toString(encoding) |
| } catch (e) { |
| err = new FileError(e.message, { |
| operation: 'realpath', |
| code: e.code, |
| path: filepath |
| }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, res, cb) |
| } |
| |
| function realpathSync(filepath, opts) { |
| if (typeof opts === 'string') opts = { encoding: opts } |
| else if (!opts) opts = {} |
| |
| const { encoding = 'utf8' } = opts |
| |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.realpathSync(req.handle, filepath) |
| |
| let res = Buffer.from(binding.requestResultString(req.handle)) |
| |
| if (encoding !== 'buffer') res = res.toString(encoding) |
| |
| return res |
| } catch (e) { |
| throw new FileError(e.message, { |
| operation: 'realpath', |
| code: e.code, |
| path: filepath |
| }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function readlink(filepath, opts, cb) { |
| if (typeof opts === 'function') { |
| cb = opts |
| opts = {} |
| } |
| |
| if (typeof opts === 'string') opts = { encoding: opts } |
| else if (!opts) opts = {} |
| |
| const { encoding = 'utf8' } = opts |
| |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| let res |
| let err = null |
| try { |
| binding.readlink(req.handle, filepath) |
| |
| await req |
| |
| res = Buffer.from(binding.requestResultString(req.handle)) |
| |
| if (encoding !== 'buffer') res = res.toString(encoding) |
| } catch (e) { |
| err = new FileError(e.message, { |
| operation: 'readlink', |
| code: e.code, |
| path: filepath |
| }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, res, cb) |
| } |
| |
| function readlinkSync(filepath, opts) { |
| if (typeof opts === 'string') opts = { encoding: opts } |
| else if (!opts) opts = {} |
| |
| const { encoding = 'utf8' } = opts |
| |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.readlinkSync(req.handle, filepath) |
| |
| let res = Buffer.from(binding.requestResultString(req.handle)) |
| |
| if (encoding !== 'buffer') res = res.toString(encoding) |
| |
| return res |
| } catch (e) { |
| throw new FileError(e.message, { |
| operation: 'readlink', |
| code: e.code, |
| path: filepath |
| }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function fsync(fd, cb) { |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.fsync(req.handle, fd) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'fsync', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, cb) |
| } |
| |
| function fsyncSync(fd) { |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.fsyncSync(req.handle, fd) |
| } catch (e) { |
| throw new FileError(e.message, { operation: 'fsyncSync', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function fdatasync(fd, cb) { |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.fdatasync(req.handle, fd) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { operation: 'fdatasync', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, cb) |
| } |
| |
| function fdatasyncSync(fd) { |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.fdatasyncSync(req.handle, fd) |
| } catch (e) { |
| throw new FileError(e.message, { operation: 'fdatasyncSync', code: e.code, fd }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| function normalizeSymlinkTarget(target, type, filepath) { |
| if (isWindows) { |
| if (type === constants.UV_FS_SYMLINK_JUNCTION) target = path.resolve(filepath, '..', target) |
| |
| if (path.isAbsolute(target)) return path.toNamespacedPath(target) |
| |
| return target.replace(/\//g, path.sep) |
| } |
| |
| return target |
| } |
| |
| async function symlink(target, filepath, type, cb) { |
| if (typeof type === 'function') { |
| cb = type |
| type = null |
| } |
| |
| filepath = toNamespacedPath(filepath) |
| |
| if (typeof type === 'string') { |
| switch (type) { |
| case 'dir': |
| type = constants.UV_FS_SYMLINK_DIR |
| break |
| case 'junction': |
| type = constants.UV_FS_SYMLINK_JUNCTION |
| break |
| case 'file': |
| default: |
| type = 0 |
| break |
| } |
| } else if (typeof type !== 'number') { |
| if (isWindows) { |
| target = path.resolve(filepath, '..', target) |
| |
| try { |
| type = (await stat(target)).isDirectory() |
| ? constants.UV_FS_SYMLINK_DIR |
| : constants.UV_FS_SYMLINK_JUNCTION |
| } catch { |
| type = 0 |
| } |
| } else { |
| type = 0 |
| } |
| } |
| |
| target = normalizeSymlinkTarget(target, type, filepath) |
| |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.symlink(req.handle, target, filepath, type) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { |
| operation: 'symlink', |
| code: e.code, |
| path: target, |
| destination: filepath |
| }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, cb) |
| } |
| |
| function symlinkSync(target, filepath, type) { |
| filepath = toNamespacedPath(filepath) |
| |
| if (typeof type === 'string') { |
| switch (type) { |
| case 'dir': |
| type = constants.UV_FS_SYMLINK_DIR |
| break |
| case 'junction': |
| type = constants.UV_FS_SYMLINK_JUNCTION |
| break |
| case 'file': |
| default: |
| type = 0 |
| break |
| } |
| } else if (typeof type !== 'number') { |
| if (isWindows) { |
| target = path.resolve(filepath, '..', target) |
| |
| try { |
| type = statSync(target).isDirectory() |
| ? constants.UV_FS_SYMLINK_DIR |
| : constants.UV_FS_SYMLINK_JUNCTION |
| } catch { |
| type = 0 |
| } |
| } else { |
| type = 0 |
| } |
| } |
| |
| target = normalizeSymlinkTarget(target, type, filepath) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.symlinkSync(req.handle, target, filepath, type) |
| } catch (e) { |
| throw new FileError(e.message, { |
| operation: 'symlink', |
| code: e.code, |
| path: target, |
| destination: filepath |
| }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function opendir(filepath, opts, cb) { |
| if (typeof opts === 'function') { |
| cb = opts |
| opts = {} |
| } |
| |
| if (typeof opts === 'string') opts = { encoding: opts } |
| else if (!opts) opts = {} |
| |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| let dir |
| let err = null |
| try { |
| binding.opendir(req.handle, filepath) |
| |
| await req |
| |
| dir = new Dir(filepath, binding.requestResultDir(req.handle), opts) |
| } catch (e) { |
| err = new FileError(e.message, { |
| operation: 'opendir', |
| code: e.code, |
| path: filepath |
| }) |
| } finally { |
| req.return() |
| } |
| |
| return done(err, dir, cb) |
| } |
| |
| function opendirSync(filepath, opts) { |
| if (typeof opts === 'string') opts = { encoding: opts } |
| else if (!opts) opts = {} |
| |
| filepath = toNamespacedPath(filepath) |
| |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.opendirSync(req.handle, filepath) |
| |
| return new Dir(filepath, binding.requestResultDir(req.handle), opts) |
| } catch (e) { |
| throw new FileError(e.message, { |
| operation: 'opendir', |
| code: e.code, |
| path: filepath |
| }) |
| } finally { |
| req.return() |
| } |
| } |
| |
| async function readdir(filepath, opts, cb) { |
| if (typeof opts === 'function') { |
| cb = opts |
| opts = {} |
| } |
| |
| if (typeof opts === 'string') opts = { encoding: opts } |
| else if (!opts) opts = {} |
| |
| const { withFileTypes = false, recursive = false } = opts |
| |
| filepath = toNamespacedPath(filepath) |
| |
| const queue = [filepath] |
| let result = [] |
| let err = null |
| try { |
| while (queue.length !== 0) { |
| const dir = await opendir(queue.pop()) |
| |
| for await (const entry of dir) { |
| const entryPath = path.join(entry.parentPath, entry.name) |
| |
| if (withFileTypes) { |
| result.push(entry) |
| } else { |
| result.push(path.relative(filepath, entryPath)) |
| } |
| |
| if (recursive && entry.isDirectory()) queue.push(entryPath) |
| } |
| } |
| } catch (e) { |
| result = [] |
| err = e |
| } |
| |
| return done(err, result, cb) |
| } |
| |
| function readdirSync(filepath, opts) { |
| if (typeof opts === 'string') opts = { encoding: opts } |
| else if (!opts) opts = {} |
| |
| const { withFileTypes = false, recursive = false } = opts |
| |
| filepath = toNamespacedPath(filepath) |
| |
| const queue = [filepath] |
| const result = [] |
| |
| while (queue.length !== 0) { |
| const dir = opendirSync(queue.pop(), opts) |
| |
| for (const entry of dir) { |
| const entryPath = path.join(entry.parentPath, entry.name) |
| |
| if (withFileTypes) { |
| result.push(entry) |
| } else { |
| result.push(path.relative(filepath, entryPath)) |
| } |
| |
| if (recursive && entry.isDirectory()) queue.push(entryPath) |
| } |
| } |
| |
| return result |
| } |
| |
| async function readFile(filepath, opts, cb) { |
| if (typeof opts === 'function') { |
| cb = opts |
| opts = {} |
| } |
| |
| if (typeof opts === 'string') opts = { encoding: opts } |
| else if (!opts) opts = {} |
| |
| const { encoding = 'buffer' } = opts |
| |
| let fd = -1 |
| let buffer = null |
| let err = null |
| try { |
| fd = await open(filepath, opts.flag || 'r') |
| |
| const st = await fstat(fd) |
| |
| let len = 0 |
| |
| if (st.size === 0) { |
| const buffers = [] |
| |
| while (true) { |
| buffer = Buffer.allocUnsafe(8192) |
| const r = await read(fd, buffer) |
| len += r |
| if (r === 0) break |
| buffers.push(buffer.subarray(0, r)) |
| } |
| |
| buffer = Buffer.concat(buffers) |
| } else { |
| buffer = Buffer.allocUnsafe(st.size) |
| |
| while (true) { |
| const r = await read(fd, len ? buffer.subarray(len) : buffer) |
| len += r |
| if (r === 0 || len === buffer.byteLength) break |
| } |
| |
| if (len !== buffer.byteLength) buffer = buffer.subarray(0, len) |
| } |
| |
| if (encoding !== 'buffer') buffer = buffer.toString(encoding) |
| } catch (e) { |
| err = e |
| } finally { |
| if (fd !== -1) await close(fd) |
| } |
| |
| return done(err, buffer, cb) |
| } |
| |
| function readFileSync(filepath, opts) { |
| if (typeof opts === 'string') opts = { encoding: opts } |
| else if (!opts) opts = {} |
| |
| const { encoding = 'buffer' } = opts |
| |
| let fd = -1 |
| try { |
| fd = openSync(filepath, opts.flag || 'r') |
| |
| const st = fstatSync(fd) |
| |
| let buffer |
| let len = 0 |
| |
| if (st.size === 0) { |
| const buffers = [] |
| |
| while (true) { |
| buffer = Buffer.allocUnsafe(8192) |
| const r = readSync(fd, buffer) |
| len += r |
| if (r === 0) break |
| buffers.push(buffer.subarray(0, r)) |
| } |
| |
| buffer = Buffer.concat(buffers) |
| } else { |
| buffer = Buffer.allocUnsafe(st.size) |
| |
| while (true) { |
| const r = readSync(fd, len ? buffer.subarray(len) : buffer) |
| len += r |
| if (r === 0 || len === buffer.byteLength) break |
| } |
| |
| if (len !== buffer.byteLength) buffer = buffer.subarray(0, len) |
| } |
| |
| if (encoding !== 'buffer') buffer = buffer.toString(encoding) |
| |
| return buffer |
| } finally { |
| if (fd !== -1) closeSync(fd) |
| } |
| } |
| |
| async function writeFile(filepath, data, opts, cb) { |
| if (typeof opts === 'function') { |
| cb = opts |
| opts = {} |
| } |
| |
| if (typeof opts === 'string') opts = { encoding: opts } |
| else if (!opts) opts = {} |
| |
| if (typeof data === 'string') data = Buffer.from(data, opts.encoding) |
| |
| let fd = -1 |
| let len = 0 |
| let err = null |
| try { |
| fd = await open(filepath, opts.flag || 'w', opts.mode || 0o666) |
| |
| while (true) { |
| len += await write(fd, len ? data.subarray(len) : data) |
| if (len === data.byteLength) break |
| } |
| } catch (e) { |
| err = e |
| } finally { |
| if (fd !== -1) await close(fd) |
| } |
| |
| return done(err, len, cb) |
| } |
| |
| function writeFileSync(filepath, data, opts) { |
| if (typeof opts === 'string') opts = { encoding: opts } |
| else if (!opts) opts = {} |
| |
| if (typeof data === 'string') data = Buffer.from(data, opts.encoding) |
| |
| let fd = -1 |
| try { |
| fd = openSync(filepath, opts.flag || 'w', opts.mode || 0o666) |
| |
| let len = 0 |
| |
| while (true) { |
| len += writeSync(fd, len ? data.subarray(len) : data) |
| if (len === data.byteLength) break |
| } |
| } finally { |
| if (fd !== -1) closeSync(fd) |
| } |
| } |
| |
| function appendFile(filepath, data, opts, cb) { |
| if (typeof opts === 'function') { |
| cb = opts |
| opts = {} |
| } |
| |
| if (typeof opts === 'string') opts = { encoding: opts } |
| else if (!opts) opts = {} |
| |
| if (!opts.flag) opts = { ...opts, flag: 'a' } |
| |
| return writeFile(filepath, data, opts, cb) |
| } |
| |
| function appendFileSync(filepath, data, opts) { |
| if (typeof opts === 'string') opts = { encoding: opts } |
| else if (!opts) opts = {} |
| |
| if (!opts.flag) opts = { ...opts, flag: 'a' } |
| |
| return writeFileSync(filepath, data, opts) |
| } |
| |
| function watch(filepath, opts, cb) { |
| if (typeof opts === 'function') { |
| cb = opts |
| opts = {} |
| } |
| |
| if (typeof opts === 'string') opts = { encoding: opts } |
| else if (!opts) opts = {} |
| |
| filepath = toNamespacedPath(filepath) |
| |
| return new Watcher(filepath, opts, cb) |
| } |
| |
| class Stats { |
| constructor( |
| dev, |
| mode, |
| nlink, |
| uid, |
| gid, |
| rdev, |
| blksize, |
| ino, |
| size, |
| blocks, |
| atimeMs, |
| mtimeMs, |
| ctimeMs, |
| birthtimeMs |
| ) { |
| this.dev = dev |
| this.mode = mode |
| this.nlink = nlink |
| this.uid = uid |
| this.gid = gid |
| this.rdev = rdev |
| this.blksize = blksize |
| this.ino = ino |
| this.size = size |
| this.blocks = blocks |
| this.atimeMs = atimeMs |
| this.mtimeMs = mtimeMs |
| this.ctimeMs = ctimeMs |
| this.birthtimeMs = birthtimeMs |
| this.atime = new Date(atimeMs) |
| this.mtime = new Date(mtimeMs) |
| this.ctime = new Date(ctimeMs) |
| this.birthtime = new Date(birthtimeMs) |
| } |
| |
| isDirectory() { |
| return (this.mode & constants.S_IFMT) === constants.S_IFDIR |
| } |
| |
| isFile() { |
| return (this.mode & constants.S_IFMT) === constants.S_IFREG |
| } |
| |
| isBlockDevice() { |
| return (this.mode & constants.S_IFMT) === constants.S_IFBLK |
| } |
| |
| isCharacterDevice() { |
| return (this.mode & constants.S_IFMT) === constants.S_IFCHR |
| } |
| |
| isFIFO() { |
| return (this.mode & constants.S_IFMT) === constants.S_IFIFO |
| } |
| |
| isSymbolicLink() { |
| return (this.mode & constants.S_IFMT) === constants.S_IFLNK |
| } |
| |
| isSocket() { |
| return (this.mode & constants.S_IFMT) === constants.S_IFSOCK |
| } |
| } |
| |
| class StatFs { |
| constructor(type, bsize, blocks, bfree, bavail, files, ffree) { |
| this.type = type |
| this.bsize = bsize |
| this.blocks = blocks |
| this.bfree = bfree |
| this.bavail = bavail |
| this.files = files |
| this.ffree = ffree |
| } |
| } |
| |
| class Dir { |
| constructor(path, handle, opts = {}) { |
| const { encoding = 'utf8', bufferSize = 32 } = opts |
| |
| this.path = path |
| |
| this._encoding = encoding |
| this._capacity = bufferSize |
| this._buffer = new FIFO() |
| this._ended = false |
| this._handle = handle |
| } |
| |
| async read(cb) { |
| if (this._buffer.length) return ok(this._buffer.shift(), cb) |
| if (this._ended) return ok(null, cb) |
| |
| const req = FileRequest.borrow() |
| |
| let entries |
| let err = null |
| try { |
| req.retain(binding.readdir(req.handle, this._handle, this._capacity)) |
| |
| await req |
| |
| entries = binding.requestResultDirents(req.handle) |
| } catch (e) { |
| err = new FileError(e.message, { |
| operation: 'readdir', |
| code: e.code, |
| path: this.path |
| }) |
| } finally { |
| req.return() |
| } |
| |
| if (err) return fail(err, cb) |
| |
| if (entries.length === 0) { |
| this._ended = true |
| |
| return ok(null, cb) |
| } |
| |
| for (const entry of entries) { |
| let name = Buffer.from(entry.name) |
| |
| if (this._encoding !== 'buffer') name = name.toString(this._encoding) |
| |
| this._buffer.push(new Dirent(this.path, name, entry.type)) |
| } |
| |
| return ok(this._buffer.shift(), cb) |
| } |
| |
| readSync() { |
| if (this._buffer.length) return this._buffer.shift() |
| if (this._ended) return null |
| |
| const req = FileRequest.borrow() |
| |
| let entries |
| try { |
| req.retain(binding.readdirSync(req.handle, this._handle, this._capacity)) |
| |
| entries = binding.requestResultDirents(req.handle) |
| } catch (e) { |
| throw new FileError(e.message, { |
| operation: 'readdir', |
| code: e.code, |
| path: this.path |
| }) |
| } finally { |
| req.return() |
| } |
| |
| if (entries.length === 0) { |
| this._ended = true |
| |
| return null |
| } |
| |
| for (const entry of entries) { |
| let name = Buffer.from(entry.name) |
| |
| if (this._encoding !== 'buffer') name = name.toString(this._encoding) |
| |
| this._buffer.push(new Dirent(this.path, name, entry.type)) |
| } |
| |
| return this._buffer.shift() |
| } |
| |
| async close(cb) { |
| const req = FileRequest.borrow() |
| |
| let err = null |
| try { |
| binding.closedir(req.handle, this._handle) |
| |
| await req |
| } catch (e) { |
| err = new FileError(e.message, { |
| operation: 'closedir', |
| code: e.code, |
| path: this.path |
| }) |
| } finally { |
| req.return() |
| } |
| |
| this._handle = null |
| |
| return done(err, cb) |
| } |
| |
| closeSync() { |
| const req = FileRequest.borrow() |
| |
| try { |
| binding.closedirSync(req.handle, this._handle) |
| } catch (e) { |
| throw new FileError(e.message, { |
| operation: 'closedir', |
| code: e.code, |
| path: this.path |
| }) |
| } finally { |
| req.return() |
| } |
| |
| this._handle = null |
| } |
| |
| [Symbol.dispose]() { |
| this.closeSync() |
| } |
| |
| async [Symbol.asyncDispose]() { |
| await this.close() |
| } |
| |
| *[Symbol.iterator]() { |
| while (true) { |
| const entry = this.readSync() |
| if (entry === null) break |
| yield entry |
| } |
| |
| this.closeSync() |
| } |
| |
| async *[Symbol.asyncIterator]() { |
| while (true) { |
| const entry = await this.read() |
| if (entry === null) break |
| yield entry |
| } |
| |
| await this.close() |
| } |
| } |
| |
| class Dirent { |
| constructor(parentPath, name, type) { |
| this.parentPath = parentPath |
| this.name = name |
| this.type = type |
| } |
| |
| isFile() { |
| return this.type === constants.UV_DIRENT_FILE |
| } |
| |
| isDirectory() { |
| return this.type === constants.UV_DIRENT_DIR |
| } |
| |
| isSymbolicLink() { |
| return this.type === constants.UV_DIRENT_LINK |
| } |
| |
| isFIFO() { |
| return this.type === constants.UV_DIRENT_FIFO |
| } |
| |
| isSocket() { |
| return this.type === constants.UV_DIRENT_SOCKET |
| } |
| |
| isCharacterDevice() { |
| return this.type === constants.UV_DIRENT_CHAR |
| } |
| |
| isBlockDevice() { |
| return this.type === constants.UV_DIRENT_BLOCK |
| } |
| } |
| |
| class FileReadStream extends Readable { |
| constructor(path, opts = {}) { |
| const { eagerOpen = true } = opts |
| |
| super({ eagerOpen, ...opts }) |
| |
| this.path = path |
| this.fd = typeof opts.fd === 'number' ? opts.fd : -1 |
| this.flags = opts.flags || 'r' |
| this.mode = opts.mode || 0o666 |
| |
| this._offset = opts.start || 0 |
| this._missing = 0 |
| |
| if (opts.length) { |
| this._missing = opts.length |
| } else if (typeof opts.end === 'number') { |
| this._missing = opts.end - this._offset + 1 |
| } else { |
| this._missing = -1 |
| } |
| } |
| |
| async _open(cb) { |
| let err |
| |
| if (this.fd === -1) { |
| err = null |
| try { |
| this.fd = await open(this.path, this.flags, this.mode) |
| } catch (e) { |
| err = e |
| } |
| |
| if (err) return cb(err) |
| } |
| |
| let st |
| err = null |
| try { |
| st = await fstat(this.fd) |
| } catch (e) { |
| err = e |
| } |
| |
| if (err) return cb(err) |
| |
| if (this._missing === -1) this._missing = st.size |
| |
| if (st.size < this._offset) { |
| this._offset = st.size |
| this._missing = 0 |
| } else if (st.size < this._offset + this._missing) { |
| this._missing = st.size - this._offset |
| } |
| |
| cb(null) |
| } |
| |
| async _read(size) { |
| if (this._missing <= 0) return this.push(null) |
| |
| const data = Buffer.allocUnsafe(Math.min(this._missing, size)) |
| |
| let len |
| let err = null |
| try { |
| len = await read(this.fd, data, 0, data.byteLength, this._offset) |
| } catch (e) { |
| err = e |
| } |
| |
| if (err) return this.destroy(err) |
| |
| if (len === 0) return this.push(null) |
| |
| if (this._missing < len) len = this._missing |
| |
| this._missing -= len |
| this._offset += len |
| |
| this.push(data.subarray(0, len)) |
| } |
| |
| async _destroy(err, cb) { |
| if (this.fd === -1) return cb(err) |
| |
| try { |
| await close(this.fd) |
| } catch (e) { |
| err = err || e |
| } |
| |
| cb(err) |
| } |
| } |
| |
| class FileWriteStream extends Writable { |
| constructor(path, opts = {}) { |
| const { eagerOpen = true } = opts |
| |
| super({ eagerOpen, ...opts }) |
| |
| this.path = path |
| this.fd = typeof opts.fd === 'number' ? opts.fd : -1 |
| this.flags = opts.flags || 'w' |
| this.mode = opts.mode || 0o666 |
| } |
| |
| async _open(cb) { |
| if (this.fd !== -1) return cb(null) |
| |
| let err = null |
| try { |
| this.fd = await open(this.path, this.flags, this.mode) |
| } catch (e) { |
| err = e |
| } |
| |
| cb(err) |
| } |
| |
| async _writev(batch, cb) { |
| let err = null |
| try { |
| await writev( |
| this.fd, |
| batch.map(({ chunk }) => chunk) |
| ) |
| } catch (e) { |
| err = e |
| } |
| |
| cb(err) |
| } |
| |
| async _destroy(err, cb) { |
| if (this.fd === -1) return cb(err) |
| |
| try { |
| await close(this.fd) |
| } catch (e) { |
| err = err || e |
| } |
| |
| cb(err) |
| } |
| } |
| |
| class Watcher extends EventEmitter { |
| constructor(path, opts, onchange) { |
| if (typeof opts === 'function') { |
| onchange = opts |
| opts = {} |
| } |
| |
| if (!opts) opts = {} |
| |
| const { persistent = true, recursive = false, encoding = 'utf8' } = opts |
| |
| super() |
| |
| this._closed = false |
| this._encoding = encoding |
| this._handle = binding.watcherInit(path, recursive, this, this._onevent, this._onclose) |
| |
| if (!persistent) this.unref() |
| |
| if (onchange) this.on('change', onchange) |
| } |
| |
| close() { |
| if (this._closed) return |
| this._closed = true |
| |
| binding.watcherClose(this._handle) |
| } |
| |
| ref() { |
| if (this._handle) binding.watcherRef(this._handle) |
| return this |
| } |
| |
| unref() { |
| if (this._handle) binding.watcherUnref(this._handle) |
| return this |
| } |
| |
| [Symbol.asyncIterator]() { |
| const buffer = [] |
| let done = false |
| let error = null |
| let next = null |
| |
| this.on('change', (eventType, filename) => { |
| if (next) { |
| next.resolve({ done: false, value: { eventType, filename } }) |
| next = null |
| } else { |
| buffer.push({ eventType, filename }) |
| } |
| }) |
| .on('error', (err) => { |
| done = true |
| error = err |
| |
| if (next) { |
| next.reject(error) |
| next = null |
| } |
| }) |
| .on('close', () => { |
| done = true |
| |
| if (next) { |
| next.resolve({ done }) |
| next = null |
| } |
| }) |
| |
| return { |
| next: () => |
| new Promise((resolve, reject) => { |
| if (error) return reject(error) |
| |
| if (buffer.length) return resolve({ done: false, value: buffer.shift() }) |
| |
| if (done) return resolve({ done }) |
| |
| next = { resolve, reject } |
| }) |
| } |
| } |
| |
| _onevent(err, events, filename) { |
| if (err) { |
| this.close() |
| this.emit('error', err) |
| } else { |
| const path = |
| this._encoding === 'buffer' |
| ? Buffer.from(filename) |
| : Buffer.from(filename).toString(this._encoding) |
| |
| if (events & binding.UV_RENAME) { |
| this.emit('change', 'rename', path) |
| } |
| |
| if (events & binding.UV_CHANGE) { |
| this.emit('change', 'change', path) |
| } |
| } |
| } |
| |
| _onclose() { |
| this._handle = null |
| |
| this.emit('close') |
| } |
| } |
| |
| exports.access = access |
| exports.appendFile = appendFile |
| exports.chmod = chmod |
| exports.chown = chown |
| exports.close = close |
| exports.copyFile = copyFile |
| exports.cp = cp |
| exports.exists = exists |
| exports.fchmod = fchmod |
| exports.fchown = fchown |
| exports.fdatasync = fdatasync |
| exports.fstat = fstat |
| exports.fsync = fsync |
| exports.ftruncate = ftruncate |
| exports.futimes = futimes |
| exports.lchown = lchown |
| exports.lutimes = lutimes |
| exports.link = link |
| exports.lstat = lstat |
| exports.mkdir = mkdir |
| exports.mkdtemp = mkdtemp |
| exports.open = open |
| exports.opendir = opendir |
| exports.read = read |
| exports.readFile = readFile |
| exports.readdir = readdir |
| exports.readlink = readlink |
| exports.readv = readv |
| exports.realpath = realpath |
| exports.rename = rename |
| exports.rm = rm |
| exports.rmdir = rmdir |
| exports.stat = stat |
| exports.statfs = statfs |
| exports.symlink = symlink |
| exports.truncate = truncate |
| exports.unlink = unlink |
| exports.utimes = utimes |
| exports.watch = watch |
| exports.write = write |
| exports.writeFile = writeFile |
| exports.writev = writev |
| |
| exports.accessSync = accessSync |
| exports.appendFileSync = appendFileSync |
| exports.chmodSync = chmodSync |
| exports.chownSync = chownSync |
| exports.closeSync = closeSync |
| exports.copyFileSync = copyFileSync |
| exports.cpSync = cpSync |
| exports.existsSync = existsSync |
| exports.fchmodSync = fchmodSync |
| exports.fchownSync = fchownSync |
| exports.fdatasyncSync = fdatasyncSync |
| exports.fstatSync = fstatSync |
| exports.fsyncSync = fsyncSync |
| exports.ftruncateSync = ftruncateSync |
| exports.futimesSync = futimesSync |
| exports.lchownSync = lchownSync |
| exports.lutimesSync = lutimesSync |
| exports.linkSync = linkSync |
| exports.lstatSync = lstatSync |
| exports.mkdirSync = mkdirSync |
| exports.mkdtempSync = mkdtempSync |
| exports.openSync = openSync |
| exports.opendirSync = opendirSync |
| exports.readFileSync = readFileSync |
| exports.readSync = readSync |
| exports.readdirSync = readdirSync |
| exports.readlinkSync = readlinkSync |
| exports.readvSync = readvSync |
| exports.realpathSync = realpathSync |
| exports.renameSync = renameSync |
| exports.rmSync = rmSync |
| exports.rmdirSync = rmdirSync |
| exports.statSync = statSync |
| exports.statfsSync = statfsSync |
| exports.symlinkSync = symlinkSync |
| exports.truncateSync = truncateSync |
| exports.unlinkSync = unlinkSync |
| exports.utimesSync = utimesSync |
| exports.writeFileSync = writeFileSync |
| exports.writeSync = writeSync |
| exports.writevSync = writevSync |
| |
| exports.promises = require('./promises') |
| |
| exports.Stats = Stats |
| exports.StatFs = StatFs |
| exports.Dir = Dir |
| exports.Dirent = Dirent |
| exports.Watcher = Watcher |
| |
| exports.ReadStream = FileReadStream |
| |
| exports.createReadStream = function createReadStream(path, opts) { |
| return new FileReadStream(path, opts) |
| } |
| |
| exports.WriteStream = FileWriteStream |
| |
| exports.createWriteStream = function createWriteStream(path, opts) { |
| return new FileWriteStream(path, opts) |
| } |
| |
| function toNamespacedPath(filepath) { |
| if (typeof filepath !== 'string') { |
| if (isURL(filepath)) filepath = fileURLToPath(filepath) |
| else filepath = filepath.toString() |
| } |
| |
| return path.toNamespacedPath(filepath) |
| } |
| |
| function toFlags(flags) { |
| switch (flags) { |
| case 'r': |
| return constants.O_RDONLY |
| case 'rs': // Fall through. |
| case 'sr': |
| return constants.O_RDONLY | constants.O_SYNC |
| case 'r+': |
| return constants.O_RDWR |
| case 'rs+': // Fall through. |
| case 'sr+': |
| return constants.O_RDWR | constants.O_SYNC |
| |
| case 'w': |
| return constants.O_TRUNC | constants.O_CREAT | constants.O_WRONLY |
| case 'wx': // Fall through. |
| case 'xw': |
| return constants.O_TRUNC | constants.O_CREAT | constants.O_WRONLY | constants.O_EXCL |
| |
| case 'w+': |
| return constants.O_TRUNC | constants.O_CREAT | constants.O_RDWR |
| case 'wx+': // Fall through. |
| case 'xw+': |
| return constants.O_TRUNC | constants.O_CREAT | constants.O_RDWR | constants.O_EXCL |
| |
| case 'a': |
| return constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY |
| case 'ax': // Fall through. |
| case 'xa': |
| return constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY | constants.O_EXCL |
| case 'as': // Fall through. |
| case 'sa': |
| return constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY | constants.O_SYNC |
| |
| case 'a+': |
| return constants.O_APPEND | constants.O_CREAT | constants.O_RDWR |
| case 'ax+': // Fall through. |
| case 'xa+': |
| return constants.O_APPEND | constants.O_CREAT | constants.O_RDWR | constants.O_EXCL |
| case 'as+': // Fall through. |
| case 'sa+': |
| return constants.O_APPEND | constants.O_CREAT | constants.O_RDWR | constants.O_SYNC |
| default: |
| return 0 |
| } |
| } |
| |
| function toMode(mode) { |
| return parseInt(mode, 8) |
| } |