Compare commits

...

7 Commits

Author SHA1 Message Date
claude[bot]
261826b80f fix: remove unused kFd import in fs.ts
Co-authored-by: Jarred-Sumner <Jarred-Sumner@users.noreply.github.com>
2025-05-19 19:07:01 +00:00
claude[bot]
e29c629eb9 fix: remove duplicate kFd property declaration in FileHandle class
This property is already imported from internal/shared and used throughout the class, but was 
also incorrectly declared as a class property, causing a lint error.

Co-authored-by: Jarred-Sumner <Jarred-Sumner@users.noreply.github.com>"
2025-05-19 18:58:49 +00:00
Jarred Sumner
ec1696f5fa Fix FileHandle kFd sharing (#19764) 2025-05-19 09:30:06 -07:00
Jarred Sumner
4cb2e33e28 Fix 2025-05-19 02:38:27 -07:00
Jarred Sumner
6748419e75 Fix 2025-05-19 02:29:16 -07:00
Jarred Sumner
6ca072c414 Fix 2025-05-19 02:03:08 -07:00
Jarred Sumner
baf975076a refactor(fs): move FileHandle class 2025-05-18 12:22:23 -07:00
9 changed files with 481 additions and 451 deletions

View File

@@ -54,6 +54,7 @@ src/js/internal/fifo.ts
src/js/internal/fixed_queue.ts
src/js/internal/fs/cp-sync.ts
src/js/internal/fs/cp.ts
src/js/internal/fs/FileHandle.ts
src/js/internal/fs/glob.ts
src/js/internal/fs/streams.ts
src/js/internal/html.ts

View File

@@ -159,8 +159,6 @@ export const bindgen = $zig("bindgen_test.zig", "getBindgenTestFunctions") as {
export const noOpForTesting = $cpp("NoOpForTesting.cpp", "createNoOpForTesting");
export const Dequeue = require("internal/fifo");
export const fs = require("node:fs/promises").$data;
export const fsStreamInternals = {
writeStreamFastPath(str) {
return str[require("internal/fs/streams").kWriteStreamFastPath];

View File

@@ -0,0 +1,422 @@
// Moved from src/js/node/fs.promises.ts
const types = require("node:util/types");
const EventEmitter = require("node:events");
const { validateInteger } = require("internal/validators");
const PromisePrototypeFinally = Promise.prototype.finally;
const SymbolAsyncDispose = Symbol.asyncDispose;
const ObjectFreeze = Object.freeze;
const { kFd } = require("internal/shared");
const kRefs = Symbol("kRefs");
const kClosePromise = Symbol("kClosePromise");
const kCloseResolve = Symbol("kCloseResolve");
const kCloseReject = Symbol("kCloseReject");
const kRef = Symbol("kRef");
const kUnref = Symbol("kUnref");
const kTransfer = Symbol("kTransfer");
const kTransferList = Symbol("kTransferList");
const kDeserialize = Symbol("kDeserialize");
const kEmptyObject = ObjectFreeze({ __proto__: null });
const kFlag = Symbol("kFlag");
let writeFile: typeof import("fs/promises").writeFile,
readFile: typeof import("fs/promises").readFile,
fchmod: typeof import("fs").fchmod.__promisify__,
fchown: typeof import("fs").fchown.__promisify__,
fdatasync: typeof import("fs").fdatasync.__promisify__,
fsync: typeof import("fs").fsync.__promisify__,
read: typeof import("fs").read.__promisify__,
readv: typeof import("fs").readv.__promisify__,
fstat: typeof import("fs").fstat.__promisify__,
ftruncate: typeof import("fs").ftruncate.__promisify__,
futimes: typeof import("fs").futimes.__promisify__,
write: typeof import("fs").write.__promisify__,
writev: typeof import("fs").writev.__promisify__,
close: typeof import("fs").close.__promisify__;
// Avoid circular dependency
function setFSExports(exports: any) {
({
writeFile,
readFile,
fchmod,
fchown,
fdatasync,
fsync,
read,
readv,
fstat,
ftruncate,
futimes,
write,
writev,
close,
} = exports);
}
class FileHandle extends EventEmitter {
constructor(fd, flag) {
super();
this[kFd] = fd ? fd : -1;
this[kRefs] = 1;
this[kClosePromise] = null;
this[kFlag] = flag;
}
getAsyncId() {
throw new Error("BUN TODO FileHandle.getAsyncId");
}
get fd() {
return this[kFd];
}
[kCloseResolve];
[kFlag];
[kClosePromise];
[kRefs];
[Symbol("messaging_transfer_symbol")]() {}
async appendFile(data, options) {
const fd = this[kFd];
throwEBADFIfNecessary("writeFile", fd);
let encoding: BufferEncoding | null = "utf8";
let flush = false;
if (options == null || typeof options === "function") {
} else if (typeof options === "string") {
encoding = options as BufferEncoding;
} else {
encoding = options?.encoding ?? encoding;
flush = options?.flush ?? flush;
}
try {
this[kRef]();
return await writeFile(fd, data, { encoding, flush, flag: this[kFlag] });
} finally {
this[kUnref]();
}
}
async chmod(mode) {
const fd = this[kFd];
throwEBADFIfNecessary("fchmod", fd);
try {
this[kRef]();
return await fchmod(fd, mode);
} finally {
this[kUnref]();
}
}
async chown(uid, gid) {
const fd = this[kFd];
throwEBADFIfNecessary("fchown", fd);
try {
this[kRef]();
return await fchown(fd, uid, gid);
} finally {
this[kUnref]();
}
}
async datasync() {
const fd = this[kFd];
throwEBADFIfNecessary("fdatasync", fd);
try {
this[kRef]();
return await fdatasync(fd);
} finally {
this[kUnref]();
}
}
async sync() {
const fd = this[kFd];
throwEBADFIfNecessary("fsync", fd);
try {
this[kRef]();
return await fsync(fd);
} finally {
this[kUnref]();
}
}
async read(bufferOrParams, offset, length, position) {
const fd = this[kFd];
throwEBADFIfNecessary("fsync", fd);
let buffer = bufferOrParams;
if (!types.isArrayBufferView(buffer)) {
if (bufferOrParams !== undefined) {
if (typeof bufferOrParams !== "object" || $isArray(bufferOrParams)) {
throw $ERR_INVALID_ARG_TYPE("options", "object", bufferOrParams);
}
}
({
buffer = Buffer.alloc(16384),
offset = 0,
length = buffer.byteLength - offset,
position = null,
} = bufferOrParams ?? kEmptyObject);
}
if (offset !== null && typeof offset === "object") {
({ offset = 0, length = buffer?.byteLength - offset, position = null } = offset);
}
if (offset == null) {
offset = 0;
} else {
validateInteger(offset, "offset", 0);
}
length ??= buffer?.byteLength - offset;
try {
this[kRef]();
const bytesRead = await read(fd, buffer, offset, length, position);
return { buffer, bytesRead };
} finally {
this[kUnref]();
}
}
async readv(buffers, position) {
const fd = this[kFd];
throwEBADFIfNecessary("readv", fd);
try {
this[kRef]();
return await readv(fd, buffers, position);
} finally {
this[kUnref]();
}
}
async readFile(options) {
const fd = this[kFd];
throwEBADFIfNecessary("readFile", fd);
try {
this[kRef]();
return await readFile(fd, options);
} finally {
this[kUnref]();
}
}
readLines(_options = undefined) {
throw new Error("BUN TODO FileHandle.readLines");
}
async stat(options) {
const fd = this[kFd];
throwEBADFIfNecessary("fstat", fd);
try {
this[kRef]();
return await fstat(fd, options);
} finally {
this[kUnref]();
}
}
async truncate(len = 0) {
const fd = this[kFd];
throwEBADFIfNecessary("ftruncate", fd);
try {
this[kRef]();
return await ftruncate(fd, len);
} finally {
this[kUnref]();
}
}
async utimes(atime, mtime) {
const fd = this[kFd];
throwEBADFIfNecessary("futimes", fd);
try {
this[kRef]();
return await futimes(fd, atime, mtime);
} finally {
this[kUnref]();
}
}
async write(buffer, offset, length, position) {
const fd = this[kFd];
throwEBADFIfNecessary("write", fd);
if (buffer?.byteLength === 0) return { __proto__: null, bytesWritten: 0, buffer };
let isArrayBufferView;
isArrayBufferView ??= require("node:util/types").isArrayBufferView;
if (isArrayBufferView(buffer)) {
if (typeof offset === "object") {
({ offset = 0, length = buffer.byteLength - offset, position = null } = offset ?? kEmptyObject);
}
if (offset == null) {
offset = 0;
}
if (typeof length !== "number") length = buffer.byteLength - offset;
if (typeof position !== "number") position = null;
}
try {
this[kRef]();
return {
buffer,
bytesWritten: await write(fd, buffer, offset, length, position),
};
} finally {
this[kUnref]();
}
}
async writev(buffers, position) {
const fd = this[kFd];
throwEBADFIfNecessary("writev", fd);
try {
this[kRef]();
return await writev(fd, buffers, position);
} finally {
this[kUnref]();
}
}
async writeFile(data: string, options: any = "utf8") {
const fd = this[kFd];
throwEBADFIfNecessary("writeFile", fd);
let encoding: BufferEncoding | null = "utf8";
let signal: AbortSignal | undefined = undefined;
if (options == null || typeof options === "function") {
} else if (typeof options === "string") {
encoding = options as BufferEncoding;
} else {
encoding = options?.encoding ?? encoding;
signal = options?.signal ?? undefined;
}
try {
this[kRef]();
return await writeFile(fd, data, { encoding, flag: this[kFlag], signal });
} finally {
this[kUnref]();
}
}
close = () => {
const fd = this[kFd];
if (fd === -1) {
return Promise.resolve();
}
if (this[kClosePromise]) {
return this[kClosePromise];
}
if (--this[kRefs] === 0) {
this[kFd] = -1;
this[kClosePromise] = PromisePrototypeFinally.$call(close(fd), () => {
this[kClosePromise] = undefined;
});
} else {
this[kClosePromise] = PromisePrototypeFinally.$call(
new Promise((resolve, reject) => {
this[kCloseResolve] = resolve;
this[kCloseReject] = reject;
}),
() => {
this[kClosePromise] = undefined;
this[kCloseReject] = undefined;
this[kCloseResolve] = undefined;
},
);
}
this.emit("close");
return this[kClosePromise];
};
async [SymbolAsyncDispose]() {
return this.close();
}
readableWebStream(_options = kEmptyObject) {
const fd = this[kFd];
throwEBADFIfNecessary("readableWebStream", fd);
return Bun.file(fd).stream();
}
createReadStream(options = kEmptyObject) {
const fd = this[kFd];
throwEBADFIfNecessary("createReadStream", fd);
return new (require("internal/fs/streams").ReadStream)(undefined, {
highWaterMark: 64 * 1024,
...options,
fd: this,
});
}
createWriteStream(options = kEmptyObject) {
const fd = this[kFd];
throwEBADFIfNecessary("createWriteStream", fd);
return new (require("internal/fs/streams").WriteStream)(undefined as any, {
highWaterMark: 64 * 1024,
...options,
fd: this,
});
}
[kTransfer]() {
throw new Error("BUN TODO FileHandle.kTransfer");
}
[kTransferList]() {
throw new Error("BUN TODO FileHandle.kTransferList");
}
[kDeserialize](_) {
throw new Error("BUN TODO FileHandle.kDeserialize");
}
[kRef]() {
this[kRefs]++;
}
[kUnref]() {
if (--this[kRefs] === 0) {
this[kFd] = -1;
this.close().$then(this[kCloseResolve], this[kCloseReject]);
}
}
}
function throwEBADFIfNecessary(fn: string, fd) {
if (fd === -1) {
const err: any = new Error("Bad file descriptor");
err.code = "EBADF";
err.name = "SystemError";
err.syscall = fn;
throw err;
}
}
export default {
FileHandle,
kFd,
kRef,
kUnref,
setFSExports,
};

View File

@@ -0,0 +1,3 @@
const fs = $zig("node_fs_binding.zig", "createBinding") as $ZigGeneratedClasses.NodeJSFS;
export default fs;

View File

@@ -3,13 +3,7 @@ import type { FileSink } from "bun";
const { Readable, Writable, finished } = require("node:stream");
const fs: typeof import("node:fs") = require("node:fs");
const { read, write, fsync, writev } = fs;
const { FileHandle, kRef, kUnref, kFd } = (fs.promises as any).$data as {
FileHandle: { new (): FileHandle };
readonly kRef: unique symbol;
readonly kUnref: unique symbol;
readonly kFd: unique symbol;
fs: typeof fs;
};
const { FileHandle, kRef, kUnref, kFd } = require("internal/fs/FileHandle");
type FileHandle = import("node:fs/promises").FileHandle & {
on(event: any, listener: any): FileHandle;
};

View File

@@ -110,4 +110,5 @@ export default {
kWeakHandler: Symbol("kWeak"),
kGetNativeReadableProto: Symbol("kGetNativeReadableProto"),
kEmptyObject,
};
kFd: Symbol("kFd"),
} as const;

View File

@@ -1,28 +1,8 @@
// Hardcoded module "node:fs/promises"
const types = require("node:util/types");
const EventEmitter = require("node:events");
const fs = $zig("node_fs_binding.zig", "createBinding") as $ZigGeneratedClasses.NodeJSFS;
const fs = require("internal/fs/binding");
const { glob } = require("internal/fs/glob");
const constants = $processBindingConstants.fs;
var PromisePrototypeFinally = Promise.prototype.finally; //TODO
var SymbolAsyncDispose = Symbol.asyncDispose;
var ObjectFreeze = Object.freeze;
const kFd = Symbol("kFd");
const kRefs = Symbol("kRefs");
const kClosePromise = Symbol("kClosePromise");
const kCloseResolve = Symbol("kCloseResolve");
const kCloseReject = Symbol("kCloseReject");
const kRef = Symbol("kRef");
const kUnref = Symbol("kUnref");
const kTransfer = Symbol("kTransfer");
const kTransferList = Symbol("kTransferList");
const kDeserialize = Symbol("kDeserialize");
const kEmptyObject = ObjectFreeze({ __proto__: null });
const kFlag = Symbol("kFlag");
const { validateInteger } = require("internal/validators");
const { kFd } = require("internal/shared");
function watch(
filename: string | Buffer | URL,
@@ -115,13 +95,7 @@ async function opendir(dir: string, options) {
return new (require("node:fs").Dir)(1, dir, options);
}
const private_symbols = {
kRef,
kUnref,
kFd,
FileHandle: null as any,
fs,
};
let FileHandle: typeof import("internal/fs/FileHandle").default.FileHandle;
const _readFile = fs.readFile.bind(fs);
const _writeFile = fs.writeFile.bind(fs);
@@ -161,7 +135,11 @@ const exports = {
mkdtemp: asyncWrap(fs.mkdtemp, "mkdtemp"),
statfs: asyncWrap(fs.statfs, "statfs"),
open: async (path, flags = "r", mode = 0o666) => {
return new private_symbols.FileHandle(await fs.open(path, flags, mode), flags);
if (!FileHandle) {
lazyInitFileHandle();
}
return new FileHandle(await fs.open(path, flags, mode), flags);
},
read: asyncWrap(fs.read, "read"),
write: asyncWrap(fs.write, "write"),
@@ -213,11 +191,8 @@ const exports = {
constants,
watch,
opendir,
// "$data" is reuse of private symbol
// this is used to export the private symbols to 'fs.js' without making it public.
$data: private_symbols,
};
export default exports;
// TODO: remove this in favor of just returning js functions that don't check `this`
@@ -225,392 +200,17 @@ function asyncWrap(fn: any, name: string) {
const wrapped = async function (...args) {
return fn.$apply(fs, args);
};
Object.defineProperty(wrapped, "name", { value: name });
Object.defineProperty(wrapped, "length", { value: fn.length });
const descriptor = { value: name, enumerable: false, configurable: true };
Object.$defineProperty(wrapped, "name", descriptor);
Object.$defineProperty(wrapped, "displayName", descriptor);
Object.$defineProperty(wrapped, "length", { value: fn.length });
return wrapped;
}
{
const {
writeFile,
readFile,
fchmod,
fchown,
fdatasync,
fsync,
read,
readv,
fstat,
ftruncate,
futimes,
write,
writev,
close,
} = exports;
let isArrayBufferView;
// Partially taken from https://github.com/nodejs/node/blob/c25878d370/lib/internal/fs/promises.js#L148
// These functions await the result so that errors propagate correctly with
// async stack traces and so that the ref counting is correct.
class FileHandle extends EventEmitter {
constructor(fd, flag) {
super();
this[kFd] = fd ? fd : -1;
this[kRefs] = 1;
this[kClosePromise] = null;
this[kFlag] = flag;
}
getAsyncId() {
throw new Error("BUN TODO FileHandle.getAsyncId");
}
get fd() {
return this[kFd];
}
[kCloseResolve];
[kFd];
[kFlag];
[kClosePromise];
[kRefs];
// needs to exist for https://github.com/nodejs/node/blob/8641d941893/test/parallel/test-worker-message-port-transfer-fake-js-transferable.js to pass
[Symbol("messaging_transfer_symbol")]() {}
async appendFile(data, options) {
const fd = this[kFd];
throwEBADFIfNecessary("writeFile", fd);
let encoding = "utf8";
let flush = false;
if (options == null || typeof options === "function") {
} else if (typeof options === "string") {
encoding = options;
} else {
encoding = options?.encoding ?? encoding;
flush = options?.flush ?? flush;
}
try {
this[kRef]();
return await writeFile(fd, data, { encoding, flush, flag: this[kFlag] });
} finally {
this[kUnref]();
}
}
async chmod(mode) {
const fd = this[kFd];
throwEBADFIfNecessary("fchmod", fd);
try {
this[kRef]();
return await fchmod(fd, mode);
} finally {
this[kUnref]();
}
}
async chown(uid, gid) {
const fd = this[kFd];
throwEBADFIfNecessary("fchown", fd);
try {
this[kRef]();
return await fchown(fd, uid, gid);
} finally {
this[kUnref]();
}
}
async datasync() {
const fd = this[kFd];
throwEBADFIfNecessary("fdatasync", fd);
try {
this[kRef]();
return await fdatasync(fd);
} finally {
this[kUnref]();
}
}
async sync() {
const fd = this[kFd];
throwEBADFIfNecessary("fsync", fd);
try {
this[kRef]();
return await fsync(fd);
} finally {
this[kUnref]();
}
}
async read(bufferOrParams, offset, length, position) {
const fd = this[kFd];
throwEBADFIfNecessary("fsync", fd);
let buffer = bufferOrParams;
if (!types.isArrayBufferView(buffer)) {
// This is fh.read(params)
if (bufferOrParams !== undefined) {
// validateObject(bufferOrParams, 'options', kValidateObjectAllowNullable);
if (typeof bufferOrParams !== "object" || $isArray(bufferOrParams)) {
throw $ERR_INVALID_ARG_TYPE("options", "object", bufferOrParams);
}
}
({
buffer = Buffer.alloc(16384),
offset = 0,
length = buffer.byteLength - offset,
position = null,
} = bufferOrParams ?? kEmptyObject);
}
if (offset !== null && typeof offset === "object") {
// This is fh.read(buffer, options)
({ offset = 0, length = buffer?.byteLength - offset, position = null } = offset);
}
if (offset == null) {
offset = 0;
} else {
validateInteger(offset, "offset", 0);
}
length ??= buffer?.byteLength - offset;
try {
this[kRef]();
const bytesRead = await read(fd, buffer, offset, length, position);
return { buffer, bytesRead };
} finally {
this[kUnref]();
}
}
async readv(buffers, position) {
const fd = this[kFd];
throwEBADFIfNecessary("readv", fd);
try {
this[kRef]();
return await readv(fd, buffers, position);
} finally {
this[kUnref]();
}
}
async readFile(options) {
const fd = this[kFd];
throwEBADFIfNecessary("readFile", fd);
try {
this[kRef]();
return await readFile(fd, options);
} finally {
this[kUnref]();
}
}
readLines(_options = undefined) {
throw new Error("BUN TODO FileHandle.readLines");
}
async stat(options) {
const fd = this[kFd];
throwEBADFIfNecessary("fstat", fd);
try {
this[kRef]();
return await fstat(fd, options);
} finally {
this[kUnref]();
}
}
async truncate(len = 0) {
const fd = this[kFd];
throwEBADFIfNecessary("ftruncate", fd);
try {
this[kRef]();
return await ftruncate(fd, len);
} finally {
this[kUnref]();
}
}
async utimes(atime, mtime) {
const fd = this[kFd];
throwEBADFIfNecessary("futimes", fd);
try {
this[kRef]();
return await futimes(fd, atime, mtime);
} finally {
this[kUnref]();
}
}
async write(buffer, offset, length, position) {
const fd = this[kFd];
throwEBADFIfNecessary("write", fd);
if (buffer?.byteLength === 0) return { __proto__: null, bytesWritten: 0, buffer };
isArrayBufferView ??= require("node:util/types").isArrayBufferView;
if (isArrayBufferView(buffer)) {
if (typeof offset === "object") {
({ offset = 0, length = buffer.byteLength - offset, position = null } = offset ?? kEmptyObject);
}
if (offset == null) {
offset = 0;
}
if (typeof length !== "number") length = buffer.byteLength - offset;
if (typeof position !== "number") position = null;
}
try {
this[kRef]();
return { buffer, bytesWritten: await write(fd, buffer, offset, length, position) };
} finally {
this[kUnref]();
}
}
async writev(buffers, position) {
const fd = this[kFd];
throwEBADFIfNecessary("writev", fd);
try {
this[kRef]();
return await writev(fd, buffers, position);
} finally {
this[kUnref]();
}
}
async writeFile(data: string, options: any = "utf8") {
const fd = this[kFd];
throwEBADFIfNecessary("writeFile", fd);
let encoding: string = "utf8";
let signal: AbortSignal | undefined = undefined;
if (options == null || typeof options === "function") {
} else if (typeof options === "string") {
encoding = options;
} else {
encoding = options?.encoding ?? encoding;
signal = options?.signal ?? undefined;
}
try {
this[kRef]();
return await writeFile(fd, data, { encoding, flag: this[kFlag], signal });
} finally {
this[kUnref]();
}
}
close = () => {
const fd = this[kFd];
if (fd === -1) {
return Promise.resolve();
}
if (this[kClosePromise]) {
return this[kClosePromise];
}
if (--this[kRefs] === 0) {
this[kFd] = -1;
this[kClosePromise] = PromisePrototypeFinally.$call(close(fd), () => {
this[kClosePromise] = undefined;
});
} else {
this[kClosePromise] = PromisePrototypeFinally.$call(
new Promise((resolve, reject) => {
this[kCloseResolve] = resolve;
this[kCloseReject] = reject;
}),
() => {
this[kClosePromise] = undefined;
this[kCloseReject] = undefined;
this[kCloseResolve] = undefined;
},
);
}
this.emit("close");
return this[kClosePromise];
};
async [SymbolAsyncDispose]() {
return this.close();
}
readableWebStream(_options = kEmptyObject) {
const fd = this[kFd];
throwEBADFIfNecessary("readableWebStream", fd);
return Bun.file(fd).stream();
}
createReadStream(options = kEmptyObject) {
const fd = this[kFd];
throwEBADFIfNecessary("createReadStream", fd);
return new (require("internal/fs/streams").ReadStream)(undefined, {
highWaterMark: 64 * 1024,
...options,
fd: this,
});
}
createWriteStream(options = kEmptyObject) {
const fd = this[kFd];
throwEBADFIfNecessary("createWriteStream", fd);
return new (require("internal/fs/streams").WriteStream)(undefined, {
highWaterMark: 64 * 1024,
...options,
fd: this,
});
}
[kTransfer]() {
throw new Error("BUN TODO FileHandle.kTransfer");
}
[kTransferList]() {
throw new Error("BUN TODO FileHandle.kTransferList");
}
[kDeserialize](_) {
throw new Error("BUN TODO FileHandle.kDeserialize");
}
[kRef]() {
this[kRefs]++;
}
[kUnref]() {
if (--this[kRefs] === 0) {
this[kFd] = -1;
this.close().$then(this[kCloseResolve], this[kCloseReject]);
}
}
}
private_symbols.FileHandle = FileHandle;
}
function throwEBADFIfNecessary(fn: string, fd) {
if (fd === -1) {
const err: any = new Error("Bad file descriptor");
err.code = "EBADF";
err.name = "SystemError";
err.syscall = fn;
throw err;
}
function lazyInitFileHandle() {
const lazyInitFileHandle = require("internal/fs/FileHandle");
FileHandle = lazyInitFileHandle.FileHandle;
lazyInitFileHandle.setFSExports(exports);
}
async function writeFileAsyncIteratorInner(fd, iterable, encoding, signal: AbortSignal | null) {

View File

@@ -1,25 +1,21 @@
// Hardcoded module "node:fs"
import type { Dirent as DirentType, PathLike, Stats as StatsType } from "fs";
const EventEmitter = require("node:events");
const promises = require("node:fs/promises");
const types = require("node:util/types");
const { validateFunction, validateInteger } = require("internal/validators");
const kEmptyObject = Object.freeze(Object.create(null));
const { kEmptyObject } = require("internal/shared");
const fs = require("internal/fs/binding");
const isDate = types.isDate;
// Private exports
// `fs` points to the return value of `node_fs_binding.zig`'s `createBinding` function.
const { fs } = promises.$data;
const constants = $processBindingConstants.fs;
var _lazyGlob;
function lazyGlob() {
return (_lazyGlob ??= require("internal/fs/glob"));
}
function ensureCallback(callback) {
function ensureCallback(callback: unknown): asserts callback is (...args: any[]) => void {
if (!$isCallable(callback)) {
throw $ERR_INVALID_ARG_TYPE("cb", "function", callback);
}
@@ -789,7 +785,7 @@ const realpathSync: typeof import("node:fs").realpathSync =
}
let resolvedLink;
lastStat = fs.lstatSync(base, { throwIfNoEntry: true });
lastStat = fs.lstatSync(base, { throwIfNoEntry: true }) as StatsType;
if (lastStat === undefined) return;
if (!lastStat.isSymbolicLink()) {
@@ -797,7 +793,7 @@ const realpathSync: typeof import("node:fs").realpathSync =
continue;
}
lastStat = fs.statSync(base, { throwIfNoEntry: true });
lastStat = fs.statSync(base, { throwIfNoEntry: true }) as StatsType;
const linkTarget = fs.readlinkSync(base);
resolvedLink = pathModule.resolve(previous, linkTarget);
@@ -810,7 +806,7 @@ const realpathSync: typeof import("node:fs").realpathSync =
// On windows, check that the root exists. On unix there is no need.
if (!knownHard.$has(base)) {
lastStat = fs.lstatSync(base, { throwIfNoEntry: true });
lastStat = fs.lstatSync(base, { throwIfNoEntry: true }) as StatsType;
if (lastStat === undefined) return;
knownHard.$add(base);
}
@@ -1001,7 +997,7 @@ function cp(src, dest, options, callback) {
ensureCallback(callback);
promises.cp(src, dest, options).then(() => callback(), callback);
exports.promises.cp(src, dest, options).then(() => callback(), callback);
}
function _toUnixTimestamp(time: any, name = "time") {
@@ -1054,7 +1050,7 @@ class Dir {
withFileTypes: true,
encoding: this.#options?.encoding,
recursive: this.#options?.recursive,
}));
}) as DirentType[]);
return entries.shift() ?? null;
}
@@ -1075,8 +1071,8 @@ class Dir {
recursive: this.#options?.recursive,
})
.then(entries => {
this.#entries = entries;
return entries.shift() ?? null;
this.#entries = entries as DirentType[];
return (entries as DirentType[]).shift() ?? null;
});
}
@@ -1271,13 +1267,32 @@ var exports = {
configurable: true,
});
},
promises,
get promises() {
const promises = require("node:fs/promises");
Object.defineProperty(exports, "promises", {
value: promises,
writable: true,
configurable: true,
enumerable: true,
});
return promises;
},
set promises(value) {
Object.defineProperty(exports, "promises", {
value,
writable: true,
configurable: true,
enumerable: true,
});
},
};
export default exports;
// Preserve the names
function setName(fn, value) {
Object.$defineProperty(fn, "name", { value, enumerable: false, configurable: true });
const descriptor = { value, enumerable: false, configurable: true };
Object.$defineProperty(fn, "name", descriptor);
Object.$defineProperty(fn, "displayName", descriptor);
}
setName(Dirent, "Dirent");
setName(FSWatcher, "FSWatcher");

View File

@@ -4,8 +4,6 @@
* originally developed by Node.js contributors and Joyent, Inc.
*
* Copyright Node.js contributors. All rights reserved.
* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
@@ -27,13 +25,11 @@
* Modifications were made to the original code.
*/
const { isTypedArray } = require("node:util/types");
const { hideFromStack, throwNotImplemented } = require("internal/shared");
const { hideFromStack, kFd } = require("internal/shared");
const { STATUS_CODES } = require("internal/http");
const tls = require("node:tls");
const net = require("node:net");
const fs = require("node:fs");
const { $data } = require("node:fs/promises");
const FileHandle = $data.FileHandle;
const bunTLSConnectOptions = Symbol.for("::buntlsconnectoptions::");
const bunSocketServerOptions = Symbol.for("::bunnetserveroptions::");
const kInfoHeaders = Symbol("sent-info-headers");
@@ -2170,8 +2166,8 @@ class ServerHttp2Stream extends Http2Stream {
if (options.statCheck !== undefined && typeof options.statCheck !== "function") {
throw $ERR_INVALID_ARG_VALUE("options.statCheck", options.statCheck);
}
if (fd instanceof FileHandle) {
fs.fstat(fd.fd, doSendFileFD.bind(this, options, fd, headers));
if (fd?.[kFd]) {
fs.fstat(fd?.[kFd], doSendFileFD.bind(this, options, fd, headers));
} else {
fs.fstat(fd, doSendFileFD.bind(this, options, fd, headers));
}