diff options
Diffstat (limited to 'src/bun.js')
-rw-r--r-- | src/bun.js/node/node_fs.zig | 182 | ||||
-rw-r--r-- | src/bun.js/node/node_fs_binding.zig | 6 |
2 files changed, 139 insertions, 49 deletions
diff --git a/src/bun.js/node/node_fs.zig b/src/bun.js/node/node_fs.zig index 826fde635..fbd58b3a1 100644 --- a/src/bun.js/node/node_fs.zig +++ b/src/bun.js/node/node_fs.zig @@ -123,10 +123,10 @@ pub const AsyncReaddirTask = struct { } pub fn deinit(this: *AsyncReaddirTask) void { - this.arena.deinit(); this.ref.unref(this.globalObject.bunVM()); this.args.deinitAndUnprotect(); this.promise.strong.deinit(); + this.arena.deinit(); bun.default_allocator.destroy(this); } }; @@ -210,10 +210,99 @@ pub const AsyncStatTask = struct { } pub fn deinit(this: *AsyncStatTask) void { + this.ref.unref(this.globalObject.bunVM()); + this.args.deinitAndUnprotect(); + this.promise.strong.deinit(); this.arena.deinit(); + bun.default_allocator.destroy(this); + } +}; + +pub const AsyncRealpathTask = struct { + promise: JSC.JSPromise.Strong, + args: Arguments.Realpath, + globalObject: *JSC.JSGlobalObject, + task: JSC.WorkPoolTask = .{ .callback = &workPoolCallback }, + result: JSC.Maybe(Return.Realpath), + ref: JSC.PollRef = .{}, + arena: bun.ArenaAllocator, + + pub fn create( + globalObject: *JSC.JSGlobalObject, + args: Arguments.Realpath, + vm: *JSC.VirtualMachine, + arena: bun.ArenaAllocator, + ) JSC.JSValue { + var task = bun.default_allocator.create(AsyncRealpathTask) catch @panic("out of memory"); + task.* = AsyncRealpathTask{ + .promise = JSC.JSPromise.Strong.init(globalObject), + .args = args, + .result = undefined, + .globalObject = globalObject, + .arena = arena, + }; + task.ref.ref(vm); + task.args.path.toThreadSafe(); + + JSC.WorkPool.schedule(&task.task); + + return task.promise.value(); + } + + fn workPoolCallback(task: *JSC.WorkPoolTask) void { + var this: *AsyncRealpathTask = @fieldParentPtr(AsyncRealpathTask, "task", task); + + var node_fs = NodeFS{}; + this.result = node_fs.realpath(this.args, .promise); + + if (this.result == .err) { + this.result.err.path = bun.default_allocator.dupe(u8, this.result.err.path) catch ""; + } + + this.globalObject.bunVMConcurrently().eventLoop().enqueueTaskConcurrent(JSC.ConcurrentTask.fromCallback(this, runFromJSThread)); + } + + fn runFromJSThread(this: *AsyncRealpathTask) void { + var globalObject = this.globalObject; + var success = @as(JSC.Maybe(Return.Realpath).Tag, this.result) == .result; + const result = switch (this.result) { + .err => |err| err.toJSC(globalObject), + .result => |res| brk: { + var exceptionref: JSC.C.JSValueRef = null; + const out = JSC.JSValue.c(JSC.To.JS.withType(Return.Realpath, res, globalObject, &exceptionref)); + const exception = JSC.JSValue.c(exceptionref); + if (exception != .zero) { + success = false; + break :brk exception; + } + + break :brk out; + }, + }; + var promise_value = this.promise.value(); + var promise = this.promise.get(); + promise_value.ensureStillAlive(); + + this.deinit(); + switch (success) { + false => { + promise.reject(globalObject, result); + }, + true => { + promise.resolve(globalObject, result); + }, + } + } + + pub fn deinit(this: *AsyncRealpathTask) void { + if (this.result == .err) { + bun.default_allocator.free(this.result.err.path); + } + this.ref.unref(this.globalObject.bunVM()); this.args.deinitAndUnprotect(); this.promise.strong.deinit(); + this.arena.deinit(); bun.default_allocator.destroy(this); } }; @@ -1157,6 +1246,10 @@ pub const Arguments = struct { this.path.deinit(); } + pub fn deinitAndUnprotect(this: *Realpath) void { + this.path.deinitAndUnprotect(); + } + pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Realpath { const path = PathLike.fromJS(ctx, arguments, exception) orelse { if (exception.* == null) { @@ -4269,65 +4362,58 @@ pub const NodeFS = struct { return Maybe(Return.Readlink).todo; } - pub fn realpath(this: *NodeFS, args: Arguments.Realpath, comptime flavor: Flavor) Maybe(Return.Realpath) { + pub fn realpath(this: *NodeFS, args: Arguments.Realpath, comptime _: Flavor) Maybe(Return.Realpath) { var outbuf: [bun.MAX_PATH_BYTES]u8 = undefined; var inbuf = &this.sync_error_buf; if (comptime Environment.allow_assert) std.debug.assert(FileSystem.instance_loaded); - switch (comptime flavor) { - .sync => { - var path_slice = args.path.slice(); + var path_slice = args.path.slice(); - var parts = [_]string{ FileSystem.instance.top_level_dir, path_slice }; - var path_ = FileSystem.instance.absBuf(&parts, inbuf); - inbuf[path_.len] = 0; - var path: [:0]u8 = inbuf[0..path_.len :0]; + var parts = [_]string{ FileSystem.instance.top_level_dir, path_slice }; + var path_ = FileSystem.instance.absBuf(&parts, inbuf); + inbuf[path_.len] = 0; + var path: [:0]u8 = inbuf[0..path_.len :0]; - const flags = if (comptime Environment.isLinux) - // O_PATH is faster - std.os.O.PATH - else - std.os.O.RDONLY; + const flags = if (comptime Environment.isLinux) + // O_PATH is faster + std.os.O.PATH + else + std.os.O.RDONLY; - const fd = switch (Syscall.open(path, flags, 0)) { - .err => |err| return .{ - .err = err.withPath(path), - }, - .result => |fd_| fd_, - }; + const fd = switch (Syscall.open(path, flags, 0)) { + .err => |err| return .{ + .err = err.withPath(path), + }, + .result => |fd_| fd_, + }; - defer { - _ = Syscall.close(fd); - } + defer { + _ = Syscall.close(fd); + } - const buf = switch (Syscall.getFdPath(fd, &outbuf)) { - .err => |err| return .{ - .err = err.withPath(path), - }, - .result => |buf_| buf_, - }; + const buf = switch (Syscall.getFdPath(fd, &outbuf)) { + .err => |err| return .{ + .err = err.withPath(path), + }, + .result => |buf_| buf_, + }; - return .{ - .result = switch (args.encoding) { - .buffer => .{ - .buffer = Buffer.fromString(buf, bun.default_allocator) catch unreachable, - }, - else => if (args.path == .slice_with_underlying_string and - strings.eqlLong(args.path.slice_with_underlying_string.slice(), buf, true)) - .{ - .BunString = args.path.slice_with_underlying_string.underlying.dupeRef(), - } - else - .{ - .BunString = bun.String.create(buf), - }, + return .{ + .result = switch (args.encoding) { + .buffer => .{ + .buffer = Buffer.fromString(buf, bun.default_allocator) catch unreachable, + }, + else => if (args.path == .slice_with_underlying_string and + strings.eqlLong(args.path.slice_with_underlying_string.slice(), buf, true)) + .{ + .BunString = args.path.slice_with_underlying_string.underlying.dupeRef(), + } + else + .{ + .BunString = bun.String.create(buf), }, - }; }, - else => {}, - } - - return Maybe(Return.Realpath).todo; + }; } pub const realpathNative = realpath; // pub fn realpathNative(this: *NodeFS, args: Arguments.Realpath, comptime flavor: Flavor) Maybe(Return.Realpath) { diff --git a/src/bun.js/node/node_fs_binding.zig b/src/bun.js/node/node_fs_binding.zig index b7ce9996c..845f6936e 100644 --- a/src/bun.js/node/node_fs_binding.zig +++ b/src/bun.js/node/node_fs_binding.zig @@ -108,7 +108,7 @@ fn call(comptime FunctionEnum: NodeFSFunctionEnum) NodeFSFunction { globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame, ) callconv(.C) JSC.JSValue { - if (comptime FunctionEnum != .readdir and FunctionEnum != .lstat and FunctionEnum != .stat and FunctionEnum != .readFile) { + if (comptime FunctionEnum != .readdir and FunctionEnum != .lstat and FunctionEnum != .stat and FunctionEnum != .readFile and FunctionEnum != .realpath) { globalObject.throw("Not implemented yet", .{}); return .zero; } @@ -147,6 +147,10 @@ fn call(comptime FunctionEnum: NodeFSFunctionEnum) NodeFSFunction { return JSC.Node.AsyncReadFileTask.create(globalObject, args, slice.vm, slice.arena); } + if (comptime FunctionEnum == .realpath) { + return JSC.Node.AsyncRealpathTask.create(globalObject, args, slice.vm, slice.arena); + } + if (comptime FunctionEnum == .stat or FunctionEnum == .lstat) { return JSC.Node.AsyncStatTask.create(globalObject, args, slice.vm, FunctionEnum == .lstat, slice.arena); } |