diff options
Diffstat (limited to 'src/js/node/fs.js')
-rw-r--r-- | src/js/node/fs.js | 489 |
1 files changed, 240 insertions, 249 deletions
diff --git a/src/js/node/fs.js b/src/js/node/fs.js index e3630c461..b4165311f 100644 --- a/src/js/node/fs.js +++ b/src/js/node/fs.js @@ -6,6 +6,9 @@ const promises = require("node:fs/promises"); const Stream = require("node:stream"); const { isArrayBufferView } = require("node:util/types"); +var _writeStreamPathFastPathSymbol = Symbol.for("Bun.NodeWriteStreamFastPath"); +var _fs = Symbol.for("#fs"); + const constants = $processBindingConstants.fs; var fs = Bun.fs(); @@ -820,302 +823,290 @@ var defaultWriteStreamOptions = { }, }; -var WriteStreamClass; -WriteStream = (function (InternalWriteStream) { - WriteStreamClass = InternalWriteStream; - Object.defineProperty(WriteStreamClass.prototype, Symbol.toStringTag, { - value: "WriteStream", - enumerable: false, - }); - - function WriteStream(path, options) { - return new InternalWriteStream(path, options); +var WriteStreamClass = (WriteStream = function WriteStream(path, options = defaultWriteStreamOptions) { + if (!(this instanceof WriteStream)) { + return new WriteStream(path, options); } - WriteStream.prototype = InternalWriteStream.prototype; - return Object.defineProperty(WriteStream, Symbol.hasInstance, { - value(instance) { - return instance instanceof InternalWriteStream; - }, - }); -})( - class WriteStream extends Stream.NativeWritable { - constructor(path, options = defaultWriteStreamOptions) { - if (!options) { - throw new TypeError("Expected options to be an object"); - } - var { - fs = defaultWriteStreamOptions.fs, - start = defaultWriteStreamOptions.start, - flags = defaultWriteStreamOptions.flags, - mode = defaultWriteStreamOptions.mode, - autoClose = true, - emitClose = false, - autoDestroy = autoClose, - encoding = defaultWriteStreamOptions.encoding, - fd = defaultWriteStreamOptions.fd, - pos = defaultWriteStreamOptions.pos, - } = options; - - var tempThis = {}; - if (fd != null) { - if (typeof fd !== "number") { - throw new Error("Expected options.fd to be a number"); - } - tempThis.fd = fd; - tempThis[writeStreamPathFastPathSymbol] = false; - } else if (typeof path === "string") { - if (path.length === 0) { - throw new TypeError("Expected a non-empty path"); - } + if (!options) { + throw new TypeError("Expected options to be an object"); + } - if (path.startsWith("file:")) { - path = Bun.fileURLToPath(path); - } + var { + fs = defaultWriteStreamOptions.fs, + start = defaultWriteStreamOptions.start, + flags = defaultWriteStreamOptions.flags, + mode = defaultWriteStreamOptions.mode, + autoClose = true, + emitClose = false, + autoDestroy = autoClose, + encoding = defaultWriteStreamOptions.encoding, + fd = defaultWriteStreamOptions.fd, + pos = defaultWriteStreamOptions.pos, + } = options; + + var tempThis = {}; + if (fd != null) { + if (typeof fd !== "number") { + throw new Error("Expected options.fd to be a number"); + } + tempThis.fd = fd; + tempThis[_writeStreamPathFastPathSymbol] = false; + } else if (typeof path === "string") { + if (path.length === 0) { + throw new TypeError("Expected a non-empty path"); + } - tempThis.path = path; - tempThis.fd = null; - tempThis[writeStreamPathFastPathSymbol] = - autoClose && - (start === undefined || start === 0) && - fs.write === defaultWriteStreamOptions.fs.write && - fs.close === defaultWriteStreamOptions.fs.close; - } + if (path.startsWith("file:")) { + path = Bun.fileURLToPath(path); + } - if (tempThis.fd == null) { - tempThis.fd = fs.openSync(path, flags, mode); - } + tempThis.path = path; + tempThis.fd = null; + tempThis[_writeStreamPathFastPathSymbol] = + autoClose && + (start === undefined || start === 0) && + fs.write === defaultWriteStreamOptions.fs.write && + fs.close === defaultWriteStreamOptions.fs.close; + } - super(tempThis.fd, { - ...options, - decodeStrings: false, - autoDestroy, - emitClose, - fd: tempThis, - }); - Object.assign(this, tempThis); + if (tempThis.fd == null) { + tempThis.fd = fs.openSync(path, flags, mode); + } - if (typeof fs?.write !== "function") { - throw new TypeError("Expected fs.write to be a function"); - } + NativeWritable.call(this, tempThis.fd, { + ...options, + decodeStrings: false, + autoDestroy, + emitClose, + fd: tempThis, + }); + Object.assign(this, tempThis); - if (typeof fs?.close !== "function") { - throw new TypeError("Expected fs.close to be a function"); - } + if (typeof fs?.write !== "function") { + throw new TypeError("Expected fs.write to be a function"); + } - if (typeof fs?.open !== "function") { - throw new TypeError("Expected fs.open to be a function"); - } + if (typeof fs?.close !== "function") { + throw new TypeError("Expected fs.close to be a function"); + } - if (typeof path === "object" && path) { - if (path instanceof URL) { - path = Bun.fileURLToPath(path); - } - } + if (typeof fs?.open !== "function") { + throw new TypeError("Expected fs.open to be a function"); + } - if (typeof path !== "string" && typeof fd !== "number") { - throw new TypeError("Expected a path or file descriptor"); - } + if (typeof path === "object" && path) { + if (path instanceof URL) { + path = Bun.fileURLToPath(path); + } + } - this.start = start; - this.#fs = fs; - this.flags = flags; - this.mode = mode; + if (typeof path !== "string" && typeof fd !== "number") { + throw new TypeError("Expected a path or file descriptor"); + } - if (this.start !== undefined) { - this.pos = this.start; - } + this.start = start; + this[_fs] = fs; + this.flags = flags; + this.mode = mode; + this.bytesWritten = 0; + this[writeStreamSymbol] = true; + this[kIoDone] = false; + // _write = undefined; + // _writev = undefined; + + if (this.start !== undefined) { + this.pos = this.start; + } - if (encoding !== defaultWriteStreamOptions.encoding) { - this.setDefaultEncoding(encoding); - if (encoding !== "buffer" && encoding !== "utf8" && encoding !== "utf-8" && encoding !== "binary") { - this[writeStreamPathFastPathSymbol] = false; - } - } + if (encoding !== defaultWriteStreamOptions.encoding) { + this.setDefaultEncoding(encoding); + if (encoding !== "buffer" && encoding !== "utf8" && encoding !== "utf-8" && encoding !== "binary") { + this[_writeStreamPathFastPathSymbol] = false; } + } - get autoClose() { - return this._writableState.autoDestroy; - } + return this; +}); +const NativeWritable = Stream.NativeWritable; +const WriteStreamPrototype = (WriteStream.prototype = Object.create(NativeWritable.prototype)); - set autoClose(val) { +Object.defineProperties(WriteStreamPrototype, { + autoClose: { + get() { + return this._writableState.autoDestroy; + }, + set(val) { this._writableState.autoDestroy = val; - } + }, + }, + pending: { + get() { + return this.fd === null; + }, + }, +}); - destroySoon = this.end; // TODO: what is this for? +// TODO: what is this for? +WriteStreamPrototype.destroySoon = WriteStreamPrototype.end; - // noop, node has deprecated this - open() {} +// noop, node has deprecated this +WriteStreamPrototype.open = function open() {}; - path; - fd; - flags; - mode; - #fs; - bytesWritten = 0; - pos; - [writeStreamPathFastPathSymbol]; - [writeStreamSymbol] = true; - start; +WriteStreamPrototype[writeStreamPathFastPathCallSymbol] = function WriteStreamPathFastPathCallSymbol( + readStream, + pipeOpts, +) { + if (!this[_writeStreamPathFastPathSymbol]) { + return false; + } - [writeStreamPathFastPathCallSymbol](readStream, pipeOpts) { - if (!this[writeStreamPathFastPathSymbol]) { - return false; - } + if (this.fd !== null) { + this[_writeStreamPathFastPathSymbol] = false; + return false; + } - if (this.fd !== null) { - this[writeStreamPathFastPathSymbol] = false; - return false; - } + this[kIoDone] = false; + readStream[kIoDone] = false; + return Bun.write(this[_writeStreamPathFastPathSymbol], readStream[readStreamPathOrFdSymbol]).then( + bytesWritten => { + readStream[kIoDone] = this[kIoDone] = true; + this.bytesWritten += bytesWritten; + readStream.bytesRead += bytesWritten; + this.end(); + readStream.close(); + }, + err => { + readStream[kIoDone] = this[kIoDone] = true; + WriteStream_errorOrDestroy.call(this, err); + readStream.emit("error", err); + }, + ); +}; - this[kIoDone] = false; - readStream[kIoDone] = false; - return Bun.write(this[writeStreamPathFastPathSymbol], readStream[readStreamPathOrFdSymbol]).then( - bytesWritten => { - readStream[kIoDone] = this[kIoDone] = true; - this.bytesWritten += bytesWritten; - readStream.bytesRead += bytesWritten; - this.end(); - readStream.close(); - }, - err => { - readStream[kIoDone] = this[kIoDone] = true; - this.#errorOrDestroy(err); - readStream.emit("error", err); - }, - ); - } +WriteStreamPrototype.isBunFastPathEnabled = function isBunFastPathEnabled() { + return this[_writeStreamPathFastPathSymbol]; +}; - isBunFastPathEnabled() { - return this[writeStreamPathFastPathSymbol]; - } +WriteStreamPrototype.disableBunFastPath = function disableBunFastPath() { + this[_writeStreamPathFastPathSymbol] = false; +}; - disableBunFastPath() { - this[writeStreamPathFastPathSymbol] = false; - } +function WriteStream_handleWrite(er, bytes) { + if (er) { + return WriteStream_errorOrDestroy.call(this, er); + } - #handleWrite(er, bytes) { - if (er) { - return this.#errorOrDestroy(er); - } + this.bytesWritten += bytes; +} - this.bytesWritten += bytes; - } +function WriteStream_internalClose(err, cb) { + this[_writeStreamPathFastPathSymbol] = false; + var fd = this.fd; + this[_fs].close(fd, er => { + this.fd = null; + cb(err || er); + }); +} - #internalClose(err, cb) { - this[writeStreamPathFastPathSymbol] = false; - var fd = this.fd; - this.#fs.close(fd, er => { - this.fd = null; - cb(err || er); - }); - } +WriteStreamPrototype._construct = function _construct(callback) { + if (typeof this.fd === "number") { + callback(); + return; + } - _construct(callback) { - if (typeof this.fd === "number") { - callback(); - return; - } + callback(); + this.emit("open", this.fd); + this.emit("ready"); +}; - callback(); - this.emit("open", this.fd); - this.emit("ready"); - } +WriteStreamPrototype._destroy = function _destroy(err, cb) { + if (this.fd === null) { + return cb(err); + } - _destroy(err, cb) { - if (this.fd === null) { - return cb(err); - } + if (this[kIoDone]) { + this.once(kIoDone, () => WriteStream_internalClose.call(this, err, cb)); + return; + } - if (this[kIoDone]) { - this.once(kIoDone, () => this.#internalClose(err, cb)); - return; - } + WriteStream_internalClose.call(this, err, cb); +}; - this.#internalClose(err, cb); +WriteStreamPrototype.close = function close(cb) { + if (cb) { + if (this.closed) { + process.nextTick(cb); + return; } + this.on("close", cb); + } - [kIoDone] = false; - - close(cb) { - if (cb) { - if (this.closed) { - process.nextTick(cb); - return; - } - this.on("close", cb); - } - - // If we are not autoClosing, we should call - // destroy on 'finish'. - if (!this.autoClose) { - this.on("finish", this.destroy); - } + // If we are not autoClosing, we should call + // destroy on 'finish'. + if (!this.autoClose) { + this.on("finish", this.destroy); + } - // We use end() instead of destroy() because of - // https://github.com/nodejs/node/issues/2006 - this.end(); - } + // We use end() instead of destroy() because of + // https://github.com/nodejs/node/issues/2006 + this.end(); +}; - write(chunk, encoding = this._writableState.defaultEncoding, cb) { - this[writeStreamPathFastPathSymbol] = false; - if (typeof chunk === "string") { - chunk = Buffer.from(chunk, encoding); - } +WriteStreamPrototype.write = function write(chunk, encoding, cb) { + encoding ??= this._writableState?.defaultEncoding; + this[_writeStreamPathFastPathSymbol] = false; + if (typeof chunk === "string") { + chunk = Buffer.from(chunk, encoding); + } - // TODO: Replace this when something like lseek is available - var native = this.pos === undefined; - const callback = native - ? (err, bytes) => { - this[kIoDone] = false; - this.#handleWrite(err, bytes); - this.emit(kIoDone); - if (cb) !err ? cb() : cb(err); - } - : () => {}; - this[kIoDone] = true; - if (this._write) { - return this._write(chunk, encoding, callback); - } else { - return super.write(chunk, encoding, callback, native); + // TODO: Replace this when something like lseek is available + var native = this.pos === undefined; + const callback = native + ? (err, bytes) => { + this[kIoDone] = false; + WriteStream_handleWrite.call(this, err, bytes); + this.emit(kIoDone); + if (cb) !err ? cb() : cb(err); } - } - - end(chunk, encoding, cb) { - var native = this.pos === undefined; - return super.end(chunk, encoding, cb, native); - } + : () => {}; + this[kIoDone] = true; + if (this._write) { + return this._write(chunk, encoding, callback); + } else { + return NativeWritable.prototype.write.call(this, chunk, encoding, callback, native); + } +}; - _write = undefined; - _writev = undefined; +// Do not inherit +WriteStreamPrototype._write = undefined; +WriteStreamPrototype._writev = undefined; - get pending() { - return this.fd === null; - } +WriteStreamPrototype.end = function end(chunk, encoding, cb) { + var native = this.pos === undefined; + return NativeWritable.prototype.end.call(this, chunk, encoding, cb, native); +}; - _destroy(err, cb) { - this.close(err, cb); - } +WriteStreamPrototype._destroy = function _destroy(err, cb) { + this.close(err, cb); +}; - #errorOrDestroy(err) { - var { - _readableState: r = { destroyed: false, autoDestroy: false }, - _writableState: w = { destroyed: false, autoDestroy: false }, - } = this; +function WriteStream_errorOrDestroy(err) { + var { + _readableState: r = { destroyed: false, autoDestroy: false }, + _writableState: w = { destroyed: false, autoDestroy: false }, + } = this; - if (w?.destroyed || r?.destroyed) { - return this; - } - if (r?.autoDestroy || w?.autoDestroy) this.destroy(err); - else if (err) { - this.emit("error", err); - } - } - }, -); + if (w?.destroyed || r?.destroyed) { + return this; + } + if (r?.autoDestroy || w?.autoDestroy) this.destroy(err); + else if (err) { + this.emit("error", err); + } +} function createWriteStream(path, options) { - // const WriteStream = getLazyWriteStream(); return new WriteStream(path, options); } |