aboutsummaryrefslogtreecommitdiff
path: root/src/javascript/jsc/node/node_fs.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/javascript/jsc/node/node_fs.zig')
-rw-r--r--src/javascript/jsc/node/node_fs.zig3657
1 files changed, 0 insertions, 3657 deletions
diff --git a/src/javascript/jsc/node/node_fs.zig b/src/javascript/jsc/node/node_fs.zig
deleted file mode 100644
index 4a556f15c..000000000
--- a/src/javascript/jsc/node/node_fs.zig
+++ /dev/null
@@ -1,3657 +0,0 @@
-// This file contains the underlying implementation for sync & async functions
-// for interacting with the filesystem from JavaScript.
-// The top-level functions assume the arguments are already validated
-const std = @import("std");
-const bun = @import("../../../global.zig");
-const strings = bun.strings;
-const string = bun.string;
-const AsyncIO = @import("io");
-const JSC = @import("../../../jsc.zig");
-const PathString = JSC.PathString;
-const Environment = bun.Environment;
-const C = bun.C;
-const Flavor = JSC.Node.Flavor;
-const system = std.os.system;
-const Maybe = JSC.Maybe;
-const Encoding = JSC.Node.Encoding;
-const Syscall = @import("./syscall.zig");
-const Constants = @import("./node_fs_constant.zig").Constants;
-const builtin = @import("builtin");
-const os = @import("std").os;
-const darwin = os.darwin;
-const linux = os.linux;
-const PathOrBuffer = JSC.Node.PathOrBuffer;
-const PathLike = JSC.Node.PathLike;
-const PathOrFileDescriptor = JSC.Node.PathOrFileDescriptor;
-const FileDescriptor = JSC.Node.FileDescriptor;
-const DirIterator = @import("./dir_iterator.zig");
-const Path = @import("../../../resolver/resolve_path.zig");
-const FileSystem = @import("../../../fs.zig").FileSystem;
-const StringOrBuffer = JSC.Node.StringOrBuffer;
-const ArgumentsSlice = JSC.Node.ArgumentsSlice;
-const TimeLike = JSC.Node.TimeLike;
-const Mode = JSC.Node.Mode;
-
-const uid_t = std.os.uid_t;
-const gid_t = std.os.gid_t;
-
-/// u63 to allow one null bit
-const ReadPosition = u63;
-
-const Stats = JSC.Node.Stats;
-const BigIntStats = JSC.Node.BigIntStats;
-const DirEnt = JSC.Node.DirEnt;
-
-pub const FlavoredIO = struct {
- io: *AsyncIO,
-};
-
-pub const default_permission = Syscall.S.IRUSR |
- Syscall.S.IWUSR |
- Syscall.S.IRGRP |
- Syscall.S.IWGRP |
- Syscall.S.IROTH |
- Syscall.S.IWOTH;
-
-const ArrayBuffer = JSC.MarkedArrayBuffer;
-const Buffer = JSC.Buffer;
-const FileSystemFlags = JSC.Node.FileSystemFlags;
-
-// TODO: to improve performance for all of these
-// The tagged unions for each type should become regular unions
-// and the tags should be passed in as comptime arguments to the functions performing the syscalls
-// This would reduce stack size, at the cost of instruction cache misses
-const Arguments = struct {
- pub const Rename = struct {
- old_path: PathLike,
- new_path: PathLike,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Rename {
- const old_path = PathLike.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "oldPath must be a string or TypedArray",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- const new_path = PathLike.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "newPath must be a string or TypedArray",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- return Rename{ .old_path = old_path, .new_path = new_path };
- }
- };
-
- pub const Truncate = struct {
- /// Passing a file descriptor is deprecated and may result in an error being thrown in the future.
- path: PathOrFileDescriptor,
- len: JSC.WebCore.Blob.SizeType = 0,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Truncate {
- const path = PathOrFileDescriptor.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "path must be a string or TypedArray",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- const len: JSC.WebCore.Blob.SizeType = brk: {
- const len_value = arguments.next() orelse break :brk 0;
-
- if (len_value.isNumber()) {
- arguments.eat();
- break :brk len_value.to(JSC.WebCore.Blob.SizeType);
- }
-
- break :brk 0;
- };
-
- return Truncate{ .path = path, .len = len };
- }
- };
-
- pub const FTruncate = struct {
- fd: FileDescriptor,
- len: ?JSC.WebCore.Blob.SizeType = null,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?FTruncate {
- const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "file descriptor is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- }, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "file descriptor must be a number",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- arguments.eat();
-
- if (exception.* != null) return null;
-
- const len: JSC.WebCore.Blob.SizeType = brk: {
- const len_value = arguments.next() orelse break :brk 0;
- if (len_value.isNumber()) {
- arguments.eat();
- break :brk len_value.to(JSC.WebCore.Blob.SizeType);
- }
-
- break :brk 0;
- };
-
- return FTruncate{ .fd = fd, .len = len };
- }
- };
-
- pub const Chown = struct {
- path: PathLike,
- uid: uid_t = 0,
- gid: gid_t = 0,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Chown {
- const path = PathLike.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "path must be a string or TypedArray",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- const uid: uid_t = brk: {
- const uid_value = arguments.next() orelse break :brk {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "uid is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- arguments.eat();
- break :brk @intCast(uid_t, uid_value.toInt32());
- };
-
- const gid: gid_t = brk: {
- const gid_value = arguments.next() orelse break :brk {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "gid is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- arguments.eat();
- break :brk @intCast(gid_t, gid_value.toInt32());
- };
-
- return Chown{ .path = path, .uid = uid, .gid = gid };
- }
- };
-
- pub const Fchown = struct {
- fd: FileDescriptor,
- uid: uid_t,
- gid: gid_t,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Fchown {
- const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "file descriptor is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- }, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "file descriptor must be a number",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- const uid: uid_t = brk: {
- const uid_value = arguments.next() orelse break :brk {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "uid is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- arguments.eat();
- break :brk @intCast(uid_t, uid_value.toInt32());
- };
-
- const gid: gid_t = brk: {
- const gid_value = arguments.next() orelse break :brk {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "gid is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- arguments.eat();
- break :brk @intCast(gid_t, gid_value.toInt32());
- };
-
- return Fchown{ .fd = fd, .uid = uid, .gid = gid };
- }
- };
-
- pub const LChown = Chown;
-
- pub const Lutimes = struct {
- path: PathLike,
- atime: TimeLike,
- mtime: TimeLike,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Lutimes {
- const path = PathLike.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "path must be a string or TypedArray",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- const atime = JSC.Node.timeLikeFromJS(ctx, arguments.next() orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "atime is required",
- .{},
- ctx,
- exception,
- );
- }
-
- return null;
- }, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "atime must be a number or a Date",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- arguments.eat();
-
- const mtime = JSC.Node.timeLikeFromJS(ctx, arguments.next() orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "mtime is required",
- .{},
- ctx,
- exception,
- );
- }
-
- return null;
- }, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "mtime must be a number or a Date",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- arguments.eat();
-
- return Lutimes{ .path = path, .atime = atime, .mtime = mtime };
- }
- };
-
- pub const Chmod = struct {
- path: PathLike,
- mode: Mode = 0x777,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Chmod {
- const path = PathLike.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "path must be a string or TypedArray",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- const mode: Mode = JSC.Node.modeFromJS(ctx, arguments.next() orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "mode is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- }, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "mode must be a string or integer",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- arguments.eat();
-
- return Chmod{ .path = path, .mode = mode };
- }
- };
-
- pub const FChmod = struct {
- fd: FileDescriptor,
- mode: Mode = 0x777,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?FChmod {
- const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "file descriptor is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- }, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "file descriptor must be a number",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
- arguments.eat();
-
- const mode: Mode = JSC.Node.modeFromJS(ctx, arguments.next() orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "mode is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- }, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "mode must be a string or integer",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- arguments.eat();
-
- return FChmod{ .fd = fd, .mode = mode };
- }
- };
-
- pub const LCHmod = Chmod;
-
- pub const Stat = struct {
- path: PathLike,
- big_int: bool = false,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Stat {
- const path = PathLike.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "path must be a string or TypedArray",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- const big_int = brk: {
- if (arguments.next()) |next_val| {
- if (next_val.isObject()) {
- if (next_val.isCallable(ctx.ptr().vm())) break :brk false;
- arguments.eat();
-
- if (next_val.getIfPropertyExists(ctx.ptr(), "bigint")) |big_int| {
- break :brk big_int.toBoolean();
- }
- }
- }
- break :brk false;
- };
-
- if (exception.* != null) return null;
-
- return Stat{ .path = path, .big_int = big_int };
- }
- };
-
- pub const Fstat = struct {
- fd: FileDescriptor,
- big_int: bool = false,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Fstat {
- const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "file descriptor is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- }, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "file descriptor must be a number",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- const big_int = brk: {
- if (arguments.next()) |next_val| {
- if (next_val.isObject()) {
- if (next_val.isCallable(ctx.ptr().vm())) break :brk false;
- arguments.eat();
-
- if (next_val.getIfPropertyExists(ctx.ptr(), "bigint")) |big_int| {
- break :brk big_int.toBoolean();
- }
- }
- }
- break :brk false;
- };
-
- if (exception.* != null) return null;
-
- return Fstat{ .fd = fd, .big_int = big_int };
- }
- };
-
- pub const Lstat = Stat;
-
- pub const Link = struct {
- old_path: PathLike,
- new_path: PathLike,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Link {
- const old_path = PathLike.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "oldPath must be a string or TypedArray",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- const new_path = PathLike.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "newPath must be a string or TypedArray",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- return Link{ .old_path = old_path, .new_path = new_path };
- }
- };
-
- pub const Symlink = struct {
- old_path: PathLike,
- new_path: PathLike,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Symlink {
- const old_path = PathLike.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "target must be a string or TypedArray",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- const new_path = PathLike.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "path must be a string or TypedArray",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- if (arguments.next()) |next_val| {
- // The type argument is only available on Windows and
- // ignored on other platforms. It can be set to 'dir',
- // 'file', or 'junction'. If the type argument is not set,
- // Node.js will autodetect target type and use 'file' or
- // 'dir'. If the target does not exist, 'file' will be used.
- // Windows junction points require the destination path to
- // be absolute. When using 'junction', the target argument
- // will automatically be normalized to absolute path.
- if (next_val.isString()) {
- comptime if (Environment.isWindows) @compileError("Add support for type argument on Windows");
- arguments.eat();
- }
- }
-
- return Symlink{ .old_path = old_path, .new_path = new_path };
- }
- };
-
- pub const Readlink = struct {
- path: PathLike,
- encoding: Encoding = Encoding.utf8,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Readlink {
- const path = PathLike.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "path must be a string or TypedArray",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
- var encoding = Encoding.utf8;
- if (arguments.next()) |val| {
- arguments.eat();
-
- switch (val.jsType()) {
- JSC.JSValue.JSType.String, JSC.JSValue.JSType.StringObject, JSC.JSValue.JSType.DerivedStringObject => {
- encoding = Encoding.fromStringValue(val, ctx.ptr()) orelse Encoding.utf8;
- },
- else => {
- if (val.isObject()) {
- if (val.getIfPropertyExists(ctx.ptr(), "encoding")) |encoding_| {
- encoding = Encoding.fromStringValue(encoding_, ctx.ptr()) orelse Encoding.utf8;
- }
- }
- },
- }
- }
-
- return Readlink{ .path = path, .encoding = encoding };
- }
- };
-
- pub const Realpath = struct {
- path: PathLike,
- encoding: Encoding = Encoding.utf8,
-
- 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) {
- JSC.throwInvalidArguments(
- "path must be a string or TypedArray",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
- var encoding = Encoding.utf8;
- if (arguments.next()) |val| {
- arguments.eat();
-
- switch (val.jsType()) {
- JSC.JSValue.JSType.String, JSC.JSValue.JSType.StringObject, JSC.JSValue.JSType.DerivedStringObject => {
- encoding = Encoding.fromStringValue(val, ctx.ptr()) orelse Encoding.utf8;
- },
- else => {
- if (val.isObject()) {
- if (val.getIfPropertyExists(ctx.ptr(), "encoding")) |encoding_| {
- encoding = Encoding.fromStringValue(encoding_, ctx.ptr()) orelse Encoding.utf8;
- }
- }
- },
- }
- }
-
- return Realpath{ .path = path, .encoding = encoding };
- }
- };
-
- pub const Unlink = struct {
- path: PathLike,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Unlink {
- const path = PathLike.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "path must be a string or TypedArray",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- return Unlink{
- .path = path,
- };
- }
- };
-
- pub const Rm = struct {
- path: PathLike,
- force: bool = false,
- max_retries: u32 = 0,
- recursive: bool = false,
- retry_delay: c_uint = 100,
- };
-
- pub const RmDir = struct {
- path: PathLike,
-
- max_retries: u32 = 0,
- recursive: bool = false,
- retry_delay: c_uint = 100,
- };
-
- /// https://github.com/nodejs/node/blob/master/lib/fs.js#L1285
- pub const Mkdir = struct {
- path: PathLike,
- /// Indicates whether parent folders should be created.
- /// If a folder was created, the path to the first created folder will be returned.
- /// @default false
- recursive: bool = false,
- /// A file mode. If a string is passed, it is parsed as an octal integer. If not specified
- /// @default
- mode: Mode = 0o777,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Mkdir {
- const path = PathLike.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "path must be a string or TypedArray",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- var recursive = false;
- var mode: Mode = 0o777;
-
- if (arguments.next()) |val| {
- arguments.eat();
-
- if (val.isObject()) {
- if (val.getIfPropertyExists(ctx.ptr(), "recursive")) |recursive_| {
- recursive = recursive_.toBoolean();
- }
-
- if (val.getIfPropertyExists(ctx.ptr(), "mode")) |mode_| {
- mode = JSC.Node.modeFromJS(ctx, mode_, exception) orelse mode;
- }
- }
- }
-
- return Mkdir{
- .path = path,
- .recursive = recursive,
- .mode = mode,
- };
- }
- };
-
- const MkdirTemp = struct {
- prefix: string = "",
- encoding: Encoding = Encoding.utf8,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?MkdirTemp {
- const prefix_value = arguments.next() orelse return MkdirTemp{};
-
- var prefix = JSC.ZigString.Empty;
- prefix_value.toZigString(&prefix, ctx.ptr());
-
- if (exception.* != null) return null;
-
- arguments.eat();
-
- var encoding = Encoding.utf8;
-
- if (arguments.next()) |val| {
- arguments.eat();
-
- switch (val.jsType()) {
- JSC.JSValue.JSType.String, JSC.JSValue.JSType.StringObject, JSC.JSValue.JSType.DerivedStringObject => {
- encoding = Encoding.fromStringValue(val, ctx.ptr()) orelse Encoding.utf8;
- },
- else => {
- if (val.isObject()) {
- if (val.getIfPropertyExists(ctx.ptr(), "encoding")) |encoding_| {
- encoding = Encoding.fromStringValue(encoding_, ctx.ptr()) orelse Encoding.utf8;
- }
- }
- },
- }
- }
-
- return MkdirTemp{
- .prefix = prefix.slice(),
- .encoding = encoding,
- };
- }
- };
-
- pub const Readdir = struct {
- path: PathLike,
- encoding: Encoding = Encoding.utf8,
- with_file_types: bool = false,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Readdir {
- const path = PathLike.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "path must be a string or TypedArray",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- var encoding = Encoding.utf8;
- var with_file_types = false;
-
- if (arguments.next()) |val| {
- arguments.eat();
-
- switch (val.jsType()) {
- JSC.JSValue.JSType.String, JSC.JSValue.JSType.StringObject, JSC.JSValue.JSType.DerivedStringObject => {
- encoding = Encoding.fromStringValue(val, ctx.ptr()) orelse Encoding.utf8;
- },
- else => {
- if (val.isObject()) {
- if (val.getIfPropertyExists(ctx.ptr(), "encoding")) |encoding_| {
- encoding = Encoding.fromStringValue(encoding_, ctx.ptr()) orelse Encoding.utf8;
- }
-
- if (val.getIfPropertyExists(ctx.ptr(), "withFileTypes")) |with_file_types_| {
- with_file_types = with_file_types_.toBoolean();
- }
- }
- },
- }
- }
-
- return Readdir{
- .path = path,
- .encoding = encoding,
- .with_file_types = with_file_types,
- };
- }
- };
-
- pub const Close = struct {
- fd: FileDescriptor,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Close {
- const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "File descriptor is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- }, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "fd must be a number",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- return Close{
- .fd = fd,
- };
- }
- };
-
- pub const Open = struct {
- path: PathLike,
- flags: FileSystemFlags = FileSystemFlags.@"r",
- mode: Mode = default_permission,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Open {
- const path = PathLike.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "path must be a string or TypedArray",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- var flags = FileSystemFlags.@"r";
- var mode: Mode = default_permission;
-
- if (arguments.next()) |val| {
- arguments.eat();
-
- if (val.isObject()) {
- if (val.getIfPropertyExists(ctx.ptr(), "flags")) |flags_| {
- flags = FileSystemFlags.fromJS(ctx, flags_, exception) orelse flags;
- }
-
- if (val.getIfPropertyExists(ctx.ptr(), "mode")) |mode_| {
- mode = JSC.Node.modeFromJS(ctx, mode_, exception) orelse mode;
- }
- } else if (!val.isEmpty()) {
- flags = FileSystemFlags.fromJS(ctx, val, exception) orelse flags;
-
- if (arguments.nextEat()) |next| {
- mode = JSC.Node.modeFromJS(ctx, next, exception) orelse mode;
- }
- }
- }
-
- if (exception.* != null) return null;
-
- return Open{
- .path = path,
- .flags = flags,
- .mode = mode,
- };
- }
- };
-
- /// Change the file system timestamps of the object referenced by `path`.
- ///
- /// The `atime` and `mtime` arguments follow these rules:
- ///
- /// * Values can be either numbers representing Unix epoch time in seconds,`Date`s, or a numeric string like `'123456789.0'`.
- /// * If the value can not be converted to a number, or is `NaN`, `Infinity` or`-Infinity`, an `Error` will be thrown.
- /// @since v0.4.2
- pub const Utimes = Lutimes;
-
- pub const Futimes = struct {
- fd: FileDescriptor,
- atime: TimeLike,
- mtime: TimeLike,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Futimes {
- const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "File descriptor is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- }, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "fd must be a number",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- arguments.eat();
- if (exception.* != null) return null;
-
- const atime = JSC.Node.timeLikeFromJS(ctx, arguments.next() orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "atime is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- }, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "atime must be a number, Date or string",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- const mtime = JSC.Node.timeLikeFromJS(ctx, arguments.next() orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "mtime is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- }, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "mtime must be a number, Date or string",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- return Futimes{
- .fd = fd,
- .atime = atime,
- .mtime = mtime,
- };
- }
- };
-
- pub const FSync = struct {
- fd: FileDescriptor,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?FSync {
- const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "File descriptor is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- }, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "fd must be a number",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- return FSync{
- .fd = fd,
- };
- }
- };
-
- /// Write `buffer` to the file specified by `fd`. If `buffer` is a normal object, it
- /// must have an own `toString` function property.
- ///
- /// `offset` determines the part of the buffer to be written, and `length` is
- /// an integer specifying the number of bytes to write.
- ///
- /// `position` refers to the offset from the beginning of the file where this data
- /// should be written. If `typeof position !== 'number'`, the data will be written
- /// at the current position. See [`pwrite(2)`](http://man7.org/linux/man-pages/man2/pwrite.2.html).
- ///
- /// The callback will be given three arguments `(err, bytesWritten, buffer)` where`bytesWritten` specifies how many _bytes_ were written from `buffer`.
- ///
- /// If this method is invoked as its `util.promisify()` ed version, it returns
- /// a promise for an `Object` with `bytesWritten` and `buffer` properties.
- ///
- /// It is unsafe to use `fs.write()` multiple times on the same file without waiting
- /// for the callback. For this scenario, {@link createWriteStream} is
- /// recommended.
- ///
- /// On Linux, positional writes don't work when the file is opened in append mode.
- /// The kernel ignores the position argument and always appends the data to
- /// the end of the file.
- /// @since v0.0.2
- ///
- pub const Write = struct {
- fd: FileDescriptor,
- buffer: StringOrBuffer,
- // buffer_val: JSC.JSValue = JSC.JSValue.zero,
- offset: u64 = 0,
- length: u64 = std.math.maxInt(u64),
- position: ?ReadPosition = null,
- encoding: Encoding = Encoding.buffer,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Write {
- const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "File descriptor is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- }, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "fd must be a number",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- arguments.eat();
-
- if (exception.* != null) return null;
-
- const buffer = StringOrBuffer.fromJS(ctx.ptr(), arguments.arena.allocator(), arguments.next() orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "data is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- }, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "data must be a string or TypedArray",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- if (exception.* != null) return null;
-
- var args = Write{
- .fd = fd,
- .buffer = buffer,
- .encoding = switch (buffer) {
- .string => Encoding.utf8,
- .buffer => Encoding.buffer,
- },
- };
-
- arguments.eat();
-
- // TODO: make this faster by passing argument count at comptime
- if (arguments.next()) |current_| {
- parse: {
- var current = current_;
- switch (buffer) {
- // fs.write(fd, string[, position[, encoding]], callback)
- .string => {
- if (current.isNumber()) {
- args.position = current.toU32();
- arguments.eat();
- current = arguments.next() orelse break :parse;
- }
-
- if (current.isString()) {
- args.encoding = Encoding.fromStringValue(current, ctx.ptr()) orelse Encoding.utf8;
- arguments.eat();
- }
- },
- // fs.write(fd, buffer[, offset[, length[, position]]], callback)
- .buffer => {
- if (!current.isNumber()) {
- break :parse;
- }
-
- if (!current.isNumber()) break :parse;
- args.offset = current.toU32();
- arguments.eat();
- current = arguments.next() orelse break :parse;
-
- if (!current.isNumber()) break :parse;
- args.length = current.toU32();
- arguments.eat();
- current = arguments.next() orelse break :parse;
-
- if (!current.isNumber()) break :parse;
- args.position = current.toU32();
- arguments.eat();
- },
- }
- }
- }
-
- return args;
- }
- };
-
- pub const Read = struct {
- fd: FileDescriptor,
- buffer: Buffer,
- offset: u64 = 0,
- length: u64 = std.math.maxInt(u64),
- position: ?ReadPosition = null,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Read {
- const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "File descriptor is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- }, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "fd must be a number",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- arguments.eat();
-
- if (exception.* != null) return null;
-
- const buffer = Buffer.fromJS(ctx.ptr(), arguments.next() orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "buffer is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- }, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "buffer must be a TypedArray",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- arguments.eat();
-
- var args = Read{
- .fd = fd,
- .buffer = buffer,
- };
-
- if (arguments.next()) |current| {
- arguments.eat();
- if (current.isNumber()) {
- args.offset = current.toU32();
-
- if (arguments.remaining.len < 2) {
- JSC.throwInvalidArguments(
- "length and position are required",
- .{},
- ctx,
- exception,
- );
-
- return null;
- }
-
- args.length = arguments.remaining[0].toU32();
-
- if (args.length == 0) {
- JSC.throwInvalidArguments(
- "length must be greater than 0",
- .{},
- ctx,
- exception,
- );
-
- return null;
- }
-
- const position: i32 = if (arguments.remaining[1].isNumber())
- arguments.remaining[1].toInt32()
- else
- -1;
-
- args.position = if (position > -1) @intCast(ReadPosition, position) else null;
- arguments.remaining = arguments.remaining[2..];
- } else if (current.isObject()) {
- if (current.getIfPropertyExists(ctx.ptr(), "offset")) |num| {
- args.offset = num.toU32();
- }
-
- if (current.getIfPropertyExists(ctx.ptr(), "length")) |num| {
- args.length = num.toU32();
- }
-
- if (current.getIfPropertyExists(ctx.ptr(), "position")) |num| {
- const position: i32 = if (num.isEmptyOrUndefinedOrNull()) -1 else num.toInt32();
- if (position > -1) {
- args.position = @intCast(ReadPosition, position);
- }
- }
- }
- }
-
- return args;
- }
- };
-
- /// Asynchronously reads the entire contents of a file.
- /// @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
- /// If a file descriptor is provided, the underlying file will _not_ be closed automatically.
- /// @param options Either the encoding for the result, or an object that contains the encoding and an optional flag.
- /// If a flag is not provided, it defaults to `'r'`.
- pub const ReadFile = struct {
- path: PathOrFileDescriptor,
- encoding: Encoding = Encoding.utf8,
-
- flag: FileSystemFlags = FileSystemFlags.@"r",
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?ReadFile {
- const path = PathOrFileDescriptor.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "path must be a string or a file descriptor",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- var encoding = Encoding.buffer;
- var flag = FileSystemFlags.@"r";
-
- if (arguments.next()) |arg| {
- arguments.eat();
- if (arg.isString()) {
- encoding = Encoding.fromStringValue(arg, ctx.ptr()) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "Invalid encoding",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- } else if (arg.isObject()) {
- if (arg.getIfPropertyExists(ctx.ptr(), "encoding")) |encoding_| {
- if (!encoding_.isUndefinedOrNull()) {
- encoding = Encoding.fromStringValue(encoding_, ctx.ptr()) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "Invalid encoding",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- }
- }
-
- if (arg.getIfPropertyExists(ctx.ptr(), "flag")) |flag_| {
- flag = FileSystemFlags.fromJS(ctx, flag_, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "Invalid flag",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- }
- }
- }
-
- // Note: Signal is not implemented
- return ReadFile{
- .path = path,
- .encoding = encoding,
- .flag = flag,
- };
- }
- };
-
- pub const WriteFile = struct {
- encoding: Encoding = Encoding.utf8,
- flag: FileSystemFlags = FileSystemFlags.@"w",
- mode: Mode = 0666,
- file: PathOrFileDescriptor,
- data: StringOrBuffer,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?WriteFile {
- const file = PathOrFileDescriptor.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "path must be a string or a file descriptor",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- const data = StringOrBuffer.fromJS(ctx.ptr(), arguments.arena.allocator(), arguments.next() orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "data is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- }, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "data must be a string or TypedArray",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
- arguments.eat();
-
- var encoding = Encoding.buffer;
- var flag = FileSystemFlags.@"w";
- var mode: Mode = default_permission;
-
- if (arguments.next()) |arg| {
- arguments.eat();
- if (arg.isString()) {
- encoding = Encoding.fromStringValue(arg, ctx.ptr()) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "Invalid encoding",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- } else if (arg.isObject()) {
- if (arg.getIfPropertyExists(ctx.ptr(), "encoding")) |encoding_| {
- if (!encoding_.isUndefinedOrNull()) {
- encoding = Encoding.fromStringValue(encoding_, ctx.ptr()) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "Invalid encoding",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- }
- }
-
- if (arg.getIfPropertyExists(ctx.ptr(), "flag")) |flag_| {
- flag = FileSystemFlags.fromJS(ctx, flag_, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "Invalid flag",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- }
-
- if (arg.getIfPropertyExists(ctx.ptr(), "mode")) |mode_| {
- mode = JSC.Node.modeFromJS(ctx, mode_, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "Invalid flag",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- }
- }
- }
-
- // Note: Signal is not implemented
- return WriteFile{
- .file = file,
- .encoding = encoding,
- .flag = flag,
- .mode = mode,
- .data = data,
- };
- }
- };
-
- pub const AppendFile = WriteFile;
-
- pub const OpenDir = struct {
- path: PathLike,
- encoding: Encoding = Encoding.utf8,
-
- /// Number of directory entries that are buffered internally when reading from the directory. Higher values lead to better performance but higher memory usage. Default: 32
- buffer_size: c_int = 32,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?OpenDir {
- const path = PathLike.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "path must be a string or a file descriptor",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- var encoding = Encoding.buffer;
- var buffer_size: c_int = 32;
-
- if (arguments.next()) |arg| {
- arguments.eat();
- if (arg.isString()) {
- encoding = Encoding.fromStringValue(arg, ctx.ptr()) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "Invalid encoding",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- } else if (arg.isObject()) {
- if (arg.getIfPropertyExists(ctx.ptr(), "encoding")) |encoding_| {
- if (!encoding_.isUndefinedOrNull()) {
- encoding = Encoding.fromStringValue(encoding_, ctx.ptr()) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "Invalid encoding",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- }
- }
-
- if (arg.getIfPropertyExists(ctx.ptr(), "bufferSize")) |buffer_size_| {
- buffer_size = buffer_size_.toInt32();
- if (buffer_size < 0) {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "bufferSize must be > 0",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- }
- }
- }
- }
-
- return OpenDir{
- .path = path,
- .encoding = encoding,
- .buffer_size = buffer_size,
- };
- }
- };
- pub const Exists = struct {
- path: PathLike,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Exists {
- const path = PathLike.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "path must be a string or buffer",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- return Exists{
- .path = path,
- };
- }
- };
-
- pub const Access = struct {
- path: PathLike,
- mode: FileSystemFlags = FileSystemFlags.@"r",
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Access {
- const path = PathLike.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "path must be a string or buffer",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- var mode = FileSystemFlags.@"r";
-
- if (arguments.next()) |arg| {
- arguments.eat();
- if (arg.isString()) {
- mode = FileSystemFlags.fromJS(ctx, arg, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "Invalid mode",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- }
- }
-
- return Access{
- .path = path,
- .mode = mode,
- };
- }
- };
-
- pub const CreateReadStream = struct {
- file: PathOrFileDescriptor,
- flags: FileSystemFlags = FileSystemFlags.@"r",
- encoding: Encoding = Encoding.utf8,
- mode: Mode = default_permission,
- autoClose: bool = true,
- emitClose: bool = true,
- start: i32 = 0,
- end: i32 = std.math.maxInt(i32),
- highwater_mark: u32 = 64 * 1024,
- global_object: *JSC.JSGlobalObject,
-
- pub fn copyToState(this: CreateReadStream, state: *JSC.Node.Readable.State) void {
- state.encoding = this.encoding;
- state.highwater_mark = this.highwater_mark;
- state.start = this.start;
- state.end = this.end;
- }
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?CreateReadStream {
- var path = PathLike.fromJS(ctx, arguments, exception);
- if (exception.* != null) return null;
- if (path == null) arguments.eat();
-
- var stream = CreateReadStream{
- .file = undefined,
- .global_object = ctx.ptr(),
- };
- var fd: FileDescriptor = std.math.maxInt(FileDescriptor);
-
- if (arguments.next()) |arg| {
- arguments.eat();
- if (arg.isString()) {
- stream.encoding = Encoding.fromStringValue(arg, ctx.ptr()) orelse {
- if (exception.* != null) {
- JSC.throwInvalidArguments(
- "Invalid encoding",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- } else if (arg.isObject()) {
- if (arg.getIfPropertyExists(ctx.ptr(), "mode")) |mode_| {
- stream.mode = JSC.Node.modeFromJS(ctx, mode_, exception) orelse {
- if (exception.* != null) {
- JSC.throwInvalidArguments(
- "Invalid mode",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- }
-
- if (arg.getIfPropertyExists(ctx.ptr(), "encoding")) |encoding| {
- stream.encoding = Encoding.fromStringValue(encoding, ctx.ptr()) orelse {
- if (exception.* != null) {
- JSC.throwInvalidArguments(
- "Invalid encoding",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- }
-
- if (arg.getIfPropertyExists(ctx.ptr(), "flags")) |flags| {
- stream.flags = FileSystemFlags.fromJS(ctx, flags, exception) orelse {
- if (exception.* != null) {
- JSC.throwInvalidArguments(
- "Invalid flags",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- }
-
- if (arg.getIfPropertyExists(ctx.ptr(), "fd")) |flags| {
- fd = JSC.Node.fileDescriptorFromJS(ctx, flags, exception) orelse {
- if (exception.* != null) {
- JSC.throwInvalidArguments(
- "Invalid file descriptor",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- }
-
- if (arg.getIfPropertyExists(ctx.ptr(), "autoClose")) |autoClose| {
- stream.autoClose = autoClose.toBoolean();
- }
-
- if (arg.getIfPropertyExists(ctx.ptr(), "emitClose")) |emitClose| {
- stream.emitClose = emitClose.toBoolean();
- }
-
- if (arg.getIfPropertyExists(ctx.ptr(), "start")) |start| {
- stream.start = start.toInt32();
- }
-
- if (arg.getIfPropertyExists(ctx.ptr(), "end")) |end| {
- stream.end = end.toInt32();
- }
-
- if (arg.getIfPropertyExists(ctx.ptr(), "highwaterMark")) |highwaterMark| {
- stream.highwater_mark = highwaterMark.toU32();
- }
- }
- }
-
- if (fd != std.math.maxInt(FileDescriptor)) {
- stream.file = .{ .fd = fd };
- } else if (path) |path_| {
- stream.file = .{ .path = path_ };
- } else {
- JSC.throwInvalidArguments("Missing path or file descriptor", .{}, ctx, exception);
- return null;
- }
- return stream;
- }
- };
-
- pub const CreateWriteStream = struct {
- file: PathOrFileDescriptor,
- flags: FileSystemFlags = FileSystemFlags.@"w",
- encoding: Encoding = Encoding.utf8,
- mode: Mode = default_permission,
- autoClose: bool = true,
- emitClose: bool = true,
- start: i32 = 0,
- highwater_mark: u32 = 256 * 1024,
- global_object: *JSC.JSGlobalObject,
-
- pub fn copyToState(this: CreateWriteStream, state: *JSC.Node.Writable.State) void {
- state.encoding = this.encoding;
- state.highwater_mark = this.highwater_mark;
- state.start = this.start;
- state.emit_close = this.emitClose;
- }
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?CreateWriteStream {
- var path = PathLike.fromJS(ctx, arguments, exception);
- if (exception.* != null) return null;
- if (path == null) arguments.eat();
-
- var stream = CreateWriteStream{
- .file = undefined,
- .global_object = ctx.ptr(),
- };
- var fd: FileDescriptor = std.math.maxInt(FileDescriptor);
-
- if (arguments.next()) |arg| {
- arguments.eat();
- if (arg.isString()) {
- stream.encoding = Encoding.fromStringValue(arg, ctx.ptr()) orelse {
- if (exception.* != null) {
- JSC.throwInvalidArguments(
- "Invalid encoding",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- } else if (arg.isObject()) {
- if (arg.getIfPropertyExists(ctx.ptr(), "mode")) |mode_| {
- stream.mode = JSC.Node.modeFromJS(ctx, mode_, exception) orelse {
- if (exception.* != null) {
- JSC.throwInvalidArguments(
- "Invalid mode",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- }
-
- if (arg.getIfPropertyExists(ctx.ptr(), "encoding")) |encoding| {
- stream.encoding = Encoding.fromStringValue(encoding, ctx.ptr()) orelse {
- if (exception.* != null) {
- JSC.throwInvalidArguments(
- "Invalid encoding",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- }
-
- if (arg.getIfPropertyExists(ctx.ptr(), "flags")) |flags| {
- stream.flags = FileSystemFlags.fromJS(ctx, flags, exception) orelse {
- if (exception.* != null) {
- JSC.throwInvalidArguments(
- "Invalid flags",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- }
-
- if (arg.getIfPropertyExists(ctx.ptr(), "fd")) |flags| {
- fd = JSC.Node.fileDescriptorFromJS(ctx, flags, exception) orelse {
- if (exception.* != null) {
- JSC.throwInvalidArguments(
- "Invalid file descriptor",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
- }
-
- if (arg.getIfPropertyExists(ctx.ptr(), "autoClose")) |autoClose| {
- stream.autoClose = autoClose.toBoolean();
- }
-
- if (arg.getIfPropertyExists(ctx.ptr(), "emitClose")) |emitClose| {
- stream.emitClose = emitClose.toBoolean();
- }
-
- if (arg.getIfPropertyExists(ctx.ptr(), "start")) |start| {
- stream.start = start.toInt32();
- }
- }
- }
-
- if (fd != std.math.maxInt(FileDescriptor)) {
- stream.file = .{ .fd = fd };
- } else if (path) |path_| {
- stream.file = .{ .path = path_ };
- } else {
- JSC.throwInvalidArguments("Missing path or file descriptor", .{}, ctx, exception);
- return null;
- }
- return stream;
- }
- };
-
- pub const FdataSync = struct {
- fd: FileDescriptor,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?FdataSync {
- const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "File descriptor is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- }, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "fd must be a number",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- return FdataSync{
- .fd = fd,
- };
- }
- };
-
- pub const CopyFile = struct {
- src: PathLike,
- dest: PathLike,
- mode: Constants.Copyfile,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?CopyFile {
- const src = PathLike.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "src must be a string or buffer",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- const dest = PathLike.fromJS(ctx, arguments, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "dest must be a string or buffer",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- var mode: i32 = 0;
- if (arguments.next()) |arg| {
- arguments.eat();
- if (arg.isNumber()) {
- mode = arg.toInt32();
- }
- }
-
- return CopyFile{
- .src = src,
- .dest = dest,
- .mode = @intToEnum(Constants.Copyfile, mode),
- };
- }
- };
-
- pub const WriteEv = struct {
- fd: FileDescriptor,
- buffers: []const ArrayBuffer,
- position: ReadPosition,
- };
-
- pub const ReadEv = struct {
- fd: FileDescriptor,
- buffers: []ArrayBuffer,
- position: ReadPosition,
- };
-
- pub const Copy = struct {
- pub const FilterCallback = fn (source: string, destination: string) bool;
- /// Dereference symlinks
- /// @default false
- dereference: bool = false,
-
- /// When `force` is `false`, and the destination
- /// exists, throw an error.
- /// @default false
- errorOnExist: bool = false,
-
- /// Function to filter copied files/directories. Return
- /// `true` to copy the item, `false` to ignore it.
- filter: ?FilterCallback = null,
-
- /// Overwrite existing file or directory. _The copy
- /// operation will ignore errors if you set this to false and the destination
- /// exists. Use the `errorOnExist` option to change this behavior.
- /// @default true
- force: bool = true,
-
- /// When `true` timestamps from `src` will
- /// be preserved.
- /// @default false
- preserve_timestamps: bool = false,
-
- /// Copy directories recursively.
- /// @default false
- recursive: bool = false,
- };
-
- pub const UnwatchFile = void;
- pub const Watch = void;
- pub const WatchFile = void;
- pub const Fsync = struct {
- fd: FileDescriptor,
-
- pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Fsync {
- const fd = JSC.Node.fileDescriptorFromJS(ctx, arguments.next() orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "File descriptor is required",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- }, exception) orelse {
- if (exception.* == null) {
- JSC.throwInvalidArguments(
- "fd must be a number",
- .{},
- ctx,
- exception,
- );
- }
- return null;
- };
-
- if (exception.* != null) return null;
-
- return Fsync{
- .fd = fd,
- };
- }
- };
-};
-
-const Return = struct {
- pub const Access = void;
- pub const AppendFile = void;
- pub const Close = void;
- pub const CopyFile = void;
- pub const Exists = bool;
- pub const Fchmod = void;
- pub const Chmod = void;
- pub const Fchown = void;
- pub const Fdatasync = void;
- pub const Fstat = Stats;
- pub const Rm = void;
- pub const Fsync = void;
- pub const Ftruncate = void;
- pub const Futimes = void;
- pub const Lchmod = void;
- pub const Lchown = void;
- pub const Link = void;
- pub const Lstat = Stats;
- pub const Mkdir = string;
- pub const Mkdtemp = PathString;
- pub const Open = FileDescriptor;
- pub const WriteFile = void;
- pub const Read = struct {
- bytes_read: u52,
-
- pub fn toJS(this: Read, _: JSC.C.JSContextRef, _: JSC.C.ExceptionRef) JSC.C.JSValueRef {
- return JSC.JSValue.jsNumberFromUint64(this.bytes_read).asObjectRef();
- }
- };
- pub const ReadPromise = struct {
- bytes_read: u52,
- buffer_val: JSC.JSValue = JSC.JSValue.zero,
- const fields = .{
- .@"bytesRead" = JSC.ZigString.init("bytesRead"),
- .@"buffer" = JSC.ZigString.init("buffer"),
- };
- pub fn toJS(this: Read, ctx: JSC.C.JSContextRef, _: JSC.C.ExceptionRef) JSC.C.JSValueRef {
- defer if (!this.buffer_val.isEmptyOrUndefinedOrNull())
- JSC.C.JSValueUnprotect(ctx, this.buffer_val.asObjectRef());
-
- return JSC.JSValue.createObject2(
- ctx.ptr(),
- &fields.bytesRead,
- &fields.buffer,
- JSC.JSValue.jsNumberFromUint64(@intCast(u52, @minimum(std.math.maxInt(u52), this.bytes_read))),
- this.buffer_val,
- ).asObjectRef();
- }
- };
-
- pub const WritePromise = struct {
- bytes_written: u52,
- buffer: StringOrBuffer,
- buffer_val: JSC.JSValue = JSC.JSValue.zero,
- const fields = .{
- .@"bytesWritten" = JSC.ZigString.init("bytesWritten"),
- .@"buffer" = JSC.ZigString.init("buffer"),
- };
-
- // Excited for the issue that's like "cannot read file bigger than 2 GB"
- pub fn toJS(this: Write, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) JSC.C.JSValueRef {
- defer if (!this.buffer_val.isEmptyOrUndefinedOrNull() and this.buffer == .buffer)
- JSC.C.JSValueUnprotect(ctx, this.buffer_val.asObjectRef());
-
- return JSC.JSValue.createObject2(
- ctx.ptr(),
- &fields.bytesWritten,
- &fields.buffer,
- JSC.JSValue.jsNumberFromUint64(@intCast(u52, @minimum(std.math.maxInt(u52), this.bytes_written))),
- if (this.buffer == .buffer)
- this.buffer_val
- else
- JSC.JSValue.fromRef(this.buffer.toJS(ctx, exception)),
- ).asObjectRef();
- }
- };
- pub const Write = struct {
- bytes_written: u52,
- const fields = .{
- .@"bytesWritten" = JSC.ZigString.init("bytesWritten"),
- };
-
- // Excited for the issue that's like "cannot read file bigger than 2 GB"
- pub fn toJS(this: Write, _: JSC.C.JSContextRef, _: JSC.C.ExceptionRef) JSC.C.JSValueRef {
- return JSC.JSValue.jsNumberFromUint64(this.bytes_written).asObjectRef();
- }
- };
-
- pub const Readdir = union(Tag) {
- with_file_types: []const DirEnt,
- buffers: []const Buffer,
- files: []const PathString,
-
- pub const Tag = enum {
- with_file_types,
- buffers,
- files,
- };
-
- pub fn toJS(this: Readdir, ctx: JSC.C.JSContextRef, exception: JSC.C.ExceptionRef) JSC.C.JSValueRef {
- return switch (this) {
- .with_file_types => JSC.To.JS.withType([]const DirEnt, this.with_file_types, ctx, exception),
- .buffers => JSC.To.JS.withType([]const Buffer, this.buffers, ctx, exception),
- .files => JSC.To.JS.withTypeClone([]const PathString, this.files, ctx, exception, true),
- };
- }
- };
- pub const ReadFile = StringOrBuffer;
- pub const Readlink = StringOrBuffer;
- pub const Realpath = StringOrBuffer;
- pub const RealpathNative = Realpath;
- pub const Rename = void;
- pub const Rmdir = void;
- pub const Stat = Stats;
-
- pub const Symlink = void;
- pub const Truncate = void;
- pub const Unlink = void;
- pub const UnwatchFile = void;
- pub const Watch = void;
- pub const WatchFile = void;
- pub const Utimes = void;
-
- pub const CreateReadStream = *JSC.Node.Stream;
- pub const CreateWriteStream = *JSC.Node.Stream;
- pub const Chown = void;
- pub const Lutimes = void;
-};
-
-/// Bun's implementation of the Node.js "fs" module
-/// https://nodejs.org/api/fs.html
-/// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/node/fs.d.ts
-pub const NodeFS = struct {
- async_io: *AsyncIO,
-
- /// Buffer to store a temporary file path that might appear in a returned error message.
- ///
- /// We want to avoid allocating a new path buffer for every error message so that JSC can clone + GC it.
- /// That means a stack-allocated buffer won't suffice. Instead, we re-use
- /// the heap allocated buffer on the NodefS struct
- sync_error_buf: [bun.MAX_PATH_BYTES]u8 = undefined,
-
- pub const ReturnType = Return;
-
- pub fn access(this: *NodeFS, args: Arguments.Access, comptime _: Flavor) Maybe(Return.Access) {
- var path = args.path.sliceZ(&this.sync_error_buf);
- const rc = Syscall.system.access(path, @enumToInt(args.mode));
- return Maybe(Return.Access).errnoSysP(rc, .access, path) orelse Maybe(Return.Access).success;
- }
-
- pub fn appendFile(this: *NodeFS, args: Arguments.AppendFile, comptime flavor: Flavor) Maybe(Return.AppendFile) {
- var data = args.data.slice();
-
- switch (args.file) {
- .fd => |fd| {
- switch (comptime flavor) {
- .sync => {
- while (data.len > 0) {
- const written = switch (Syscall.write(fd, data)) {
- .result => |result| result,
- .err => |err| return .{ .err = err },
- };
- data = data[written..];
- }
-
- return Maybe(Return.AppendFile).success;
- },
- else => {
- _ = this;
- @compileError("Not implemented yet");
- },
- }
- },
- .path => |path_| {
- const path = path_.sliceZ(&this.sync_error_buf);
- switch (comptime flavor) {
- .sync => {
- const fd = switch (Syscall.open(path, @enumToInt(FileSystemFlags.@"a"), 000666)) {
- .result => |result| result,
- .err => |err| return .{ .err = err },
- };
-
- defer {
- _ = Syscall.close(fd);
- }
-
- while (data.len > 0) {
- const written = switch (Syscall.write(fd, data)) {
- .result => |result| result,
- .err => |err| return .{ .err = err },
- };
- data = data[written..];
- }
-
- return Maybe(Return.AppendFile).success;
- },
- else => {
- _ = this;
- @compileError("Not implemented yet");
- },
- }
- },
- }
-
- return Maybe(Return.AppendFile).todo;
- }
-
- pub fn close(this: *NodeFS, args: Arguments.Close, comptime flavor: Flavor) Maybe(Return.Close) {
- switch (comptime flavor) {
- .sync => {
- return if (Syscall.close(args.fd)) |err| .{ .err = err } else Maybe(Return.Close).success;
- },
- else => {
- _ = this;
- },
- }
-
- return .{ .err = Syscall.Error.todo };
- }
-
- /// https://github.com/libuv/libuv/pull/2233
- /// https://github.com/pnpm/pnpm/issues/2761
- /// https://github.com/libuv/libuv/pull/2578
- /// https://github.com/nodejs/node/issues/34624
- pub fn copyFile(this: *NodeFS, args: Arguments.CopyFile, comptime flavor: Flavor) Maybe(Return.CopyFile) {
- const ret = Maybe(Return.CopyFile);
-
- switch (comptime flavor) {
- .sync => {
- var src_buf: [bun.MAX_PATH_BYTES]u8 = undefined;
- var dest_buf: [bun.MAX_PATH_BYTES]u8 = undefined;
- var src = args.src.sliceZ(&src_buf);
- var dest = args.dest.sliceZ(&dest_buf);
-
- if (comptime Environment.isMac) {
- if (args.mode.isForceClone()) {
- // https://www.manpagez.com/man/2/clonefile/
- return ret.errnoSysP(C.clonefile(src, dest, 0), .clonefile, src) orelse ret.success;
- }
-
- var mode: Mode = C.darwin.COPYFILE_ACL | C.darwin.COPYFILE_DATA;
- if (args.mode.shouldntOverwrite()) {
- mode |= C.darwin.COPYFILE_EXCL;
- }
-
- return ret.errnoSysP(C.copyfile(src, dest, null, mode), .copyfile, src) orelse ret.success;
- }
-
- if (comptime Environment.isLinux) {
- const src_fd = switch (Syscall.open(src, std.os.O.RDONLY, 0644)) {
- .result => |result| result,
- .err => |err| return .{ .err = err },
- };
- defer {
- _ = Syscall.close(src_fd);
- }
-
- const stat_: linux.Stat = switch (Syscall.fstat(src_fd)) {
- .result => |result| result,
- .err => |err| return Maybe(Return.CopyFile){ .err = err },
- };
-
- if (!os.S.ISREG(stat_.mode)) {
- return Maybe(Return.CopyFile){ .err = .{ .errno = @enumToInt(C.SystemErrno.ENOTSUP) } };
- }
-
- var flags: Mode = std.os.O.CREAT | std.os.O.WRONLY | std.os.O.TRUNC;
- if (args.mode.shouldntOverwrite()) {
- flags |= std.os.O.EXCL;
- }
-
- const dest_fd = switch (Syscall.open(dest, flags, flags)) {
- .result => |result| result,
- .err => |err| return Maybe(Return.CopyFile){ .err = err },
- };
- defer {
- _ = Syscall.close(dest_fd);
- }
-
- var off_in_copy = @bitCast(i64, @as(u64, 0));
- var off_out_copy = @bitCast(i64, @as(u64, 0));
-
- // https://manpages.debian.org/testing/manpages-dev/ioctl_ficlone.2.en.html
- if (args.mode.isForceClone()) {
- return Maybe(Return.CopyFile).todo;
- }
-
- var size = @intCast(usize, @maximum(stat_.size, 0));
-
- if (size == 0) {
- // copy until EOF
- size = std.mem.page_size;
- while (true) {
- // Linux Kernel 5.3 or later
- const written = linux.copy_file_range(src_fd, &off_in_copy, dest_fd, &off_out_copy, size, 0);
- if (ret.errnoSysP(written, .copy_file_range, dest)) |err| return err;
- // wrote zero bytes means EOF
- if (written == 0) break;
- size -|= written;
- }
- } else {
- while (size > 0) {
- // Linux Kernel 5.3 or later
- const written = linux.copy_file_range(src_fd, &off_in_copy, dest_fd, &off_out_copy, size, 0);
- if (ret.errnoSysP(written, .copy_file_range, dest)) |err| return err;
- // wrote zero bytes means EOF
- if (written == 0) break;
- size -|= written;
- }
- }
-
- return ret.success;
- }
- },
- else => {
- _ = args;
- _ = this;
- _ = flavor;
- },
- }
-
- return Maybe(Return.CopyFile).todo;
- }
- pub fn exists(this: *NodeFS, args: Arguments.Exists, comptime flavor: Flavor) Maybe(Return.Exists) {
- const Ret = Maybe(Return.Exists);
- const path = args.path.sliceZ(&this.sync_error_buf);
- switch (comptime flavor) {
- .sync => {
- // access() may not work correctly on NFS file systems with UID
- // mapping enabled, because UID mapping is done on the server and
- // hidden from the client, which checks permissions. Similar
- // problems can occur to FUSE mounts.
- const rc = (system.access(path, std.os.F_OK));
- return Ret{ .result = rc == 0 };
- },
- else => {},
- }
- _ = args;
- _ = this;
- _ = flavor;
- return Ret.todo;
- }
-
- pub fn chown(this: *NodeFS, args: Arguments.Chown, comptime flavor: Flavor) Maybe(Return.Chown) {
- const path = args.path.sliceZ(&this.sync_error_buf);
-
- switch (comptime flavor) {
- .sync => return Syscall.chown(path, args.uid, args.gid),
- else => {},
- }
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Chown).todo;
- }
-
- /// This should almost never be async
- pub fn chmod(this: *NodeFS, args: Arguments.Chmod, comptime flavor: Flavor) Maybe(Return.Chmod) {
- const path = args.path.sliceZ(&this.sync_error_buf);
-
- switch (comptime flavor) {
- .sync => {
- return Maybe(Return.Chmod).errnoSysP(C.chmod(path, args.mode), .chmod, path) orelse
- Maybe(Return.Chmod).success;
- },
- else => {},
- }
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Chmod).todo;
- }
-
- /// This should almost never be async
- pub fn fchmod(this: *NodeFS, args: Arguments.FChmod, comptime flavor: Flavor) Maybe(Return.Fchmod) {
- switch (comptime flavor) {
- .sync => {
- return Syscall.fchmod(args.fd, args.mode);
- },
- else => {},
- }
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Fchmod).todo;
- }
- pub fn fchown(this: *NodeFS, args: Arguments.Fchown, comptime flavor: Flavor) Maybe(Return.Fchown) {
- switch (comptime flavor) {
- .sync => {
- return Maybe(Return.Fchown).errnoSys(C.fchown(args.fd, args.uid, args.gid), .fchown) orelse
- Maybe(Return.Fchown).success;
- },
- else => {},
- }
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Fchown).todo;
- }
- pub fn fdatasync(this: *NodeFS, args: Arguments.FdataSync, comptime flavor: Flavor) Maybe(Return.Fdatasync) {
- switch (comptime flavor) {
- .sync => return Maybe(Return.Fdatasync).errnoSys(system.fdatasync(args.fd), .fdatasync) orelse
- Maybe(Return.Fdatasync).success,
- else => {},
- }
-
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Fdatasync).todo;
- }
- pub fn fstat(this: *NodeFS, args: Arguments.Fstat, comptime flavor: Flavor) Maybe(Return.Fstat) {
- if (args.big_int) return Maybe(Return.Fstat).todo;
-
- switch (comptime flavor) {
- .sync => {
- return switch (Syscall.fstat(args.fd)) {
- .result => |result| Maybe(Return.Fstat){ .result = Stats.init(result) },
- .err => |err| Maybe(Return.Fstat){ .err = err },
- };
- },
- else => {},
- }
-
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Fstat).todo;
- }
-
- pub fn fsync(this: *NodeFS, args: Arguments.Fsync, comptime flavor: Flavor) Maybe(Return.Fsync) {
- switch (comptime flavor) {
- .sync => return Maybe(Return.Fsync).errnoSys(system.fsync(args.fd), .fsync) orelse
- Maybe(Return.Fsync).success,
- else => {},
- }
-
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Fsync).todo;
- }
-
- pub fn ftruncate(this: *NodeFS, args: Arguments.FTruncate, comptime flavor: Flavor) Maybe(Return.Ftruncate) {
- switch (comptime flavor) {
- .sync => return Maybe(Return.Ftruncate).errnoSys(system.ftruncate(args.fd, args.len orelse 0), .ftruncate) orelse
- Maybe(Return.Ftruncate).success,
- else => {},
- }
-
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Ftruncate).todo;
- }
- pub fn futimes(this: *NodeFS, args: Arguments.Futimes, comptime flavor: Flavor) Maybe(Return.Futimes) {
- var times = [2]std.os.timespec{
- .{
- .tv_sec = args.mtime,
- .tv_nsec = 0,
- },
- .{
- .tv_sec = args.atime,
- .tv_nsec = 0,
- },
- };
-
- switch (comptime flavor) {
- .sync => return if (Maybe(Return.Futimes).errnoSys(system.futimens(args.fd, &times), .futimens)) |err|
- err
- else
- Maybe(Return.Futimes).success,
- else => {},
- }
-
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Futimes).todo;
- }
-
- pub fn lchmod(this: *NodeFS, args: Arguments.LCHmod, comptime flavor: Flavor) Maybe(Return.Lchmod) {
- const path = args.path.sliceZ(&this.sync_error_buf);
-
- switch (comptime flavor) {
- .sync => {
- return Maybe(Return.Lchmod).errnoSysP(C.lchmod(path, args.mode), .lchmod, path) orelse
- Maybe(Return.Lchmod).success;
- },
- else => {},
- }
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Lchmod).todo;
- }
-
- pub fn lchown(this: *NodeFS, args: Arguments.LChown, comptime flavor: Flavor) Maybe(Return.Lchown) {
- const path = args.path.sliceZ(&this.sync_error_buf);
-
- switch (comptime flavor) {
- .sync => {
- return Maybe(Return.Lchown).errnoSysP(C.lchown(path, args.uid, args.gid), .lchown, path) orelse
- Maybe(Return.Lchown).success;
- },
- else => {},
- }
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Lchown).todo;
- }
- pub fn link(this: *NodeFS, args: Arguments.Link, comptime flavor: Flavor) Maybe(Return.Link) {
- var new_path_buf: [bun.MAX_PATH_BYTES]u8 = undefined;
- const from = args.old_path.sliceZ(&this.sync_error_buf);
- const to = args.new_path.sliceZ(&new_path_buf);
-
- switch (comptime flavor) {
- .sync => {
- return Maybe(Return.Link).errnoSysP(system.link(from, to, 0), .link, from) orelse
- Maybe(Return.Link).success;
- },
- else => {},
- }
-
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Link).todo;
- }
- pub fn lstat(this: *NodeFS, args: Arguments.Lstat, comptime flavor: Flavor) Maybe(Return.Lstat) {
- if (args.big_int) return Maybe(Return.Lstat).todo;
-
- switch (comptime flavor) {
- .sync => {
- return switch (Syscall.lstat(
- args.path.sliceZ(
- &this.sync_error_buf,
- ),
- )) {
- .result => |result| Maybe(Return.Lstat){ .result = Return.Lstat.init(result) },
- .err => |err| Maybe(Return.Lstat){ .err = err },
- };
- },
- else => {},
- }
-
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Lstat).todo;
- }
-
- pub fn mkdir(this: *NodeFS, args: Arguments.Mkdir, comptime flavor: Flavor) Maybe(Return.Mkdir) {
- return if (args.recursive) mkdirRecursive(this, args, flavor) else mkdirNonRecursive(this, args, flavor);
- }
- // Node doesn't absolute the path so we don't have to either
- fn mkdirNonRecursive(this: *NodeFS, args: Arguments.Mkdir, comptime flavor: Flavor) Maybe(Return.Mkdir) {
- switch (comptime flavor) {
- .sync => {
- const path = args.path.sliceZ(&this.sync_error_buf);
- return switch (Syscall.mkdir(path, args.mode)) {
- .result => Maybe(Return.Mkdir){ .result = "" },
- .err => |err| Maybe(Return.Mkdir){ .err = err },
- };
- },
- else => {},
- }
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Mkdir).todo;
- }
-
- // TODO: windows
- // TODO: verify this works correctly with unicode codepoints
- fn mkdirRecursive(this: *NodeFS, args: Arguments.Mkdir, comptime flavor: Flavor) Maybe(Return.Mkdir) {
- const Option = Maybe(Return.Mkdir);
- if (comptime Environment.isWindows) @compileError("This needs to be implemented on Windows.");
-
- switch (comptime flavor) {
- // The sync version does no allocation except when returning the path
- .sync => {
- var buf: [bun.MAX_PATH_BYTES]u8 = undefined;
- const path = args.path.sliceZWithForceCopy(&buf, true);
- const len = @truncate(u16, path.len);
-
- // First, attempt to create the desired directory
- // If that fails, then walk back up the path until we have a match
- switch (Syscall.mkdir(path, args.mode)) {
- .err => |err| {
- switch (err.getErrno()) {
- else => {
- @memcpy(&this.sync_error_buf, path.ptr, len);
- return .{ .err = err.withPath(this.sync_error_buf[0..len]) };
- },
-
- .EXIST => {
- return Option{ .result = "" };
- },
- // continue
- .NOENT => {},
- }
- },
- .result => {
- return Option{ .result = args.path.slice() };
- },
- }
-
- var working_mem = &this.sync_error_buf;
- @memcpy(working_mem, path.ptr, len);
-
- var i: u16 = len - 1;
-
- // iterate backwards until creating the directory works successfully
- while (i > 0) : (i -= 1) {
- if (path[i] == std.fs.path.sep) {
- working_mem[i] = 0;
- var parent: [:0]u8 = working_mem[0..i :0];
-
- switch (Syscall.mkdir(parent, args.mode)) {
- .err => |err| {
- working_mem[i] = std.fs.path.sep;
- switch (err.getErrno()) {
- .EXIST => {
- // Handle race condition
- break;
- },
- .NOENT => {
- continue;
- },
- else => return .{ .err = err.withPath(parent) },
- }
- },
- .result => {
- // We found a parent that worked
- working_mem[i] = std.fs.path.sep;
- break;
- },
- }
- }
- }
- var first_match: u16 = i;
- i += 1;
- // after we find one that works, we go forward _after_ the first working directory
- while (i < len) : (i += 1) {
- if (path[i] == std.fs.path.sep) {
- working_mem[i] = 0;
- var parent: [:0]u8 = working_mem[0..i :0];
-
- switch (Syscall.mkdir(parent, args.mode)) {
- .err => |err| {
- working_mem[i] = std.fs.path.sep;
- switch (err.getErrno()) {
- .EXIST => {
- if (Environment.allow_assert) std.debug.assert(false);
- continue;
- },
- else => return .{ .err = err },
- }
- },
-
- .result => {
- working_mem[i] = std.fs.path.sep;
- },
- }
- }
- }
-
- working_mem[len] = 0;
-
- // Our final directory will not have a trailing separator
- // so we have to create it once again
- switch (Syscall.mkdir(working_mem[0..len :0], args.mode)) {
- .err => |err| {
- switch (err.getErrno()) {
- // handle the race condition
- .EXIST => {
- var display_path: []const u8 = "";
- if (first_match != std.math.maxInt(u16)) {
- // TODO: this leaks memory
- display_path = bun.default_allocator.dupe(u8, display_path[0..first_match]) catch unreachable;
- }
- return Option{ .result = display_path };
- },
-
- // NOENT shouldn't happen here
- else => return .{
- .err = err.withPath(path),
- },
- }
- },
- .result => {
- var display_path = args.path.slice();
- if (first_match != std.math.maxInt(u16)) {
- // TODO: this leaks memory
- display_path = bun.default_allocator.dupe(u8, display_path[0..first_match]) catch unreachable;
- }
- return Option{ .result = display_path };
- },
- }
- },
- else => {},
- }
-
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Mkdir).todo;
- }
-
- pub fn mkdtemp(this: *NodeFS, args: Arguments.MkdirTemp, comptime flavor: Flavor) Maybe(Return.Mkdtemp) {
- var prefix_buf = &this.sync_error_buf;
- prefix_buf[0] = 0;
- const len = args.prefix.len;
- if (len > 0) {
- @memcpy(prefix_buf, args.prefix.ptr, len);
- prefix_buf[len] = 0;
- }
-
- const rc = C.mkdtemp(prefix_buf);
- switch (std.c.getErrno(@ptrToInt(rc))) {
- .SUCCESS => {},
- else => |errno| return .{ .err = Syscall.Error{ .errno = @truncate(Syscall.Error.Int, @enumToInt(errno)), .syscall = .mkdtemp } },
- }
-
- _ = this;
- _ = flavor;
- return .{
- .result = PathString.init(bun.default_allocator.dupe(u8, std.mem.span(rc.?)) catch unreachable),
- };
- }
- pub fn open(this: *NodeFS, args: Arguments.Open, comptime flavor: Flavor) Maybe(Return.Open) {
- switch (comptime flavor) {
- // The sync version does no allocation except when returning the path
- .sync => {
- const path = args.path.sliceZ(&this.sync_error_buf);
- return switch (Syscall.open(path, @enumToInt(args.flags), args.mode)) {
- .err => |err| .{
- .err = err.withPath(args.path.slice()),
- },
- .result => |fd| .{ .result = fd },
- };
- },
- else => {},
- }
-
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Open).todo;
- }
- pub fn openDir(this: *NodeFS, args: Arguments.OpenDir, comptime flavor: Flavor) Maybe(Return.OpenDir) {
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.OpenDir).todo;
- }
-
- fn _read(this: *NodeFS, args: Arguments.Read, comptime flavor: Flavor) Maybe(Return.Read) {
- _ = args;
- _ = this;
- _ = flavor;
- if (Environment.allow_assert) std.debug.assert(args.position == null);
-
- switch (comptime flavor) {
- // The sync version does no allocation except when returning the path
- .sync => {
- var buf = args.buffer.slice();
- buf = buf[@minimum(args.offset, buf.len)..];
- buf = buf[0..@minimum(buf.len, args.length)];
-
- return switch (Syscall.read(args.fd, buf)) {
- .err => |err| .{
- .err = err,
- },
- .result => |amt| .{
- .result = .{
- .bytes_read = @truncate(u52, amt),
- },
- },
- };
- },
- else => {},
- }
-
- return Maybe(Return.Read).todo;
- }
-
- fn _pread(this: *NodeFS, args: Arguments.Read, comptime flavor: Flavor) Maybe(Return.Read) {
- _ = this;
-
- switch (comptime flavor) {
- .sync => {
- var buf = args.buffer.slice();
- buf = buf[@minimum(args.offset, buf.len)..];
- buf = buf[0..@minimum(buf.len, args.length)];
-
- return switch (Syscall.pread(args.fd, buf, args.position.?)) {
- .err => |err| .{
- .err = err,
- },
- .result => |amt| .{
- .result = .{
- .bytes_read = @truncate(u52, amt),
- },
- },
- };
- },
- else => {},
- }
-
- return Maybe(Return.Read).todo;
- }
-
- pub fn read(this: *NodeFS, args: Arguments.Read, comptime flavor: Flavor) Maybe(Return.Read) {
- return if (args.position != null)
- this._pread(
- args,
- comptime flavor,
- )
- else
- this._read(
- args,
- comptime flavor,
- );
- }
-
- pub fn write(this: *NodeFS, args: Arguments.Write, comptime flavor: Flavor) Maybe(Return.Write) {
- return if (args.position != null) _pwrite(this, args, flavor) else _write(this, args, flavor);
- }
- fn _write(this: *NodeFS, args: Arguments.Write, comptime flavor: Flavor) Maybe(Return.Write) {
- _ = args;
- _ = this;
- _ = flavor;
-
- switch (comptime flavor) {
- .sync => {
- var buf = args.buffer.slice();
- buf = buf[@minimum(args.offset, buf.len)..];
- buf = buf[0..@minimum(buf.len, args.length)];
-
- return switch (Syscall.write(args.fd, buf)) {
- .err => |err| .{
- .err = err,
- },
- .result => |amt| .{
- .result = .{
- .bytes_written = @truncate(u52, amt),
- },
- },
- };
- },
- else => {},
- }
-
- return Maybe(Return.Write).todo;
- }
-
- fn _pwrite(this: *NodeFS, args: Arguments.Write, comptime flavor: Flavor) Maybe(Return.Write) {
- _ = args;
- _ = this;
- _ = flavor;
-
- const position = args.position.?;
-
- switch (comptime flavor) {
- .sync => {
- var buf = args.buffer.slice();
- buf = buf[@minimum(args.offset, buf.len)..];
- buf = buf[0..@minimum(args.length, buf.len)];
-
- return switch (Syscall.pwrite(args.fd, buf, position)) {
- .err => |err| .{
- .err = err,
- },
- .result => |amt| .{ .result = .{
- .bytes_written = @truncate(u52, amt),
- } },
- };
- },
- else => {},
- }
-
- return Maybe(Return.Write).todo;
- }
-
- pub fn readdir(this: *NodeFS, args: Arguments.Readdir, comptime flavor: Flavor) Maybe(Return.Readdir) {
- return switch (args.encoding) {
- .buffer => _readdir(
- this,
- args,
- Buffer,
- flavor,
- ),
- else => {
- if (!args.with_file_types) {
- return _readdir(
- this,
- args,
- PathString,
- flavor,
- );
- }
-
- return _readdir(
- this,
- args,
- DirEnt,
- flavor,
- );
- },
- };
- }
-
- pub fn _readdir(
- this: *NodeFS,
- args: Arguments.Readdir,
- comptime ExpectedType: type,
- comptime flavor: Flavor,
- ) Maybe(Return.Readdir) {
- const file_type = comptime switch (ExpectedType) {
- DirEnt => "with_file_types",
- PathString => "files",
- Buffer => "buffers",
- else => unreachable,
- };
-
- switch (comptime flavor) {
- .sync => {
- var path = args.path.sliceZ(&this.sync_error_buf);
- const flags = os.O.DIRECTORY | os.O.RDONLY;
- const fd = switch (Syscall.open(path, flags, 0)) {
- .err => |err| return .{
- .err = err.withPath(args.path.slice()),
- },
- .result => |fd_| fd_,
- };
- defer {
- _ = Syscall.close(fd);
- }
-
- var entries = std.ArrayList(ExpectedType).init(bun.default_allocator);
- var dir = std.fs.Dir{ .fd = fd };
- var iterator = DirIterator.iterate(dir);
- var entry = iterator.next();
- while (switch (entry) {
- .err => |err| {
- for (entries.items) |*item| {
- switch (comptime ExpectedType) {
- DirEnt => {
- bun.default_allocator.free(item.name.slice());
- },
- Buffer => {
- item.destroy();
- },
- PathString => {
- bun.default_allocator.free(item.slice());
- },
- else => unreachable,
- }
- }
-
- entries.deinit();
-
- return .{
- .err = err.withPath(args.path.slice()),
- };
- },
- .result => |ent| ent,
- }) |current| : (entry = iterator.next()) {
- switch (comptime ExpectedType) {
- DirEnt => {
- entries.append(.{
- .name = PathString.init(bun.default_allocator.dupe(u8, current.name.slice()) catch unreachable),
- .kind = current.kind,
- }) catch unreachable;
- },
- Buffer => {
- const slice = current.name.slice();
- entries.append(Buffer.fromString(slice, bun.default_allocator) catch unreachable) catch unreachable;
- },
- PathString => {
- entries.append(
- PathString.init(bun.default_allocator.dupe(u8, current.name.slice()) catch unreachable),
- ) catch unreachable;
- },
- else => unreachable,
- }
- }
-
- return .{ .result = @unionInit(Return.Readdir, file_type, entries.items) };
- },
- else => {},
- }
-
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Readdir).todo;
- }
- pub fn readFile(this: *NodeFS, args: Arguments.ReadFile, comptime flavor: Flavor) Maybe(Return.ReadFile) {
- var path: [:0]const u8 = undefined;
- switch (comptime flavor) {
- .sync => {
- const fd = switch (args.path) {
- .path => brk: {
- path = args.path.path.sliceZ(&this.sync_error_buf);
- break :brk switch (Syscall.open(
- path,
- os.O.RDONLY | os.O.NOCTTY,
- 0,
- )) {
- .err => |err| return .{
- .err = err.withPath(if (args.path == .path) args.path.path.slice() else ""),
- },
- .result => |fd_| fd_,
- };
- },
- .fd => |_fd| _fd,
- };
-
- defer {
- if (args.path == .path)
- _ = Syscall.close(fd);
- }
-
- const stat_ = switch (Syscall.fstat(fd)) {
- .err => |err| return .{
- .err = err,
- },
- .result => |stat_| stat_,
- };
-
- const size = @intCast(u64, @maximum(stat_.size, 0));
- var buf = std.ArrayList(u8).init(bun.default_allocator);
- buf.ensureTotalCapacityPrecise(size + 16) catch unreachable;
- buf.expandToCapacity();
- var total: usize = 0;
- while (total < size) {
- switch (Syscall.read(fd, buf.items.ptr[total..buf.capacity])) {
- .err => |err| return .{
- .err = err,
- },
- .result => |amt| {
- total += amt;
- // There are cases where stat()'s size is wrong or out of date
- if (total > size and amt != 0) {
- buf.ensureUnusedCapacity(8096) catch unreachable;
- buf.expandToCapacity();
- continue;
- }
-
- if (amt == 0) {
- break;
- }
- },
- }
- }
- buf.items.len = total;
- return switch (args.encoding) {
- .buffer => .{
- .result = .{
- .buffer = Buffer.fromBytes(buf.items, bun.default_allocator, .Uint8Array),
- },
- },
- else => .{
- .result = .{
- .string = buf.items,
- },
- },
- };
- },
- else => {},
- }
-
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.ReadFile).todo;
- }
-
- pub fn writeFile(this: *NodeFS, args: Arguments.WriteFile, comptime flavor: Flavor) Maybe(Return.WriteFile) {
- var path: [:0]const u8 = undefined;
-
- switch (comptime flavor) {
- .sync => {
- const fd = switch (args.file) {
- .path => brk: {
- path = args.file.path.sliceZ(&this.sync_error_buf);
- break :brk switch (Syscall.open(
- path,
- @enumToInt(args.flag) | os.O.NOCTTY,
- args.mode,
- )) {
- .err => |err| return .{
- .err = err.withPath(path),
- },
- .result => |fd_| fd_,
- };
- },
- .fd => |_fd| _fd,
- };
-
- defer {
- if (args.file == .path)
- _ = Syscall.close(fd);
- }
-
- var buf = args.data.slice();
- var written: usize = 0;
-
- while (buf.len > 0) {
- switch (Syscall.write(fd, buf)) {
- .err => |err| return .{
- .err = err,
- },
- .result => |amt| {
- buf = buf[amt..];
- written += amt;
- if (amt == 0) {
- break;
- }
- },
- }
- }
-
- _ = this.ftruncate(.{ .fd = fd, .len = @truncate(JSC.WebCore.Blob.SizeType, written) }, .sync);
-
- return Maybe(Return.WriteFile).success;
- },
- else => {},
- }
-
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.WriteFile).todo;
- }
-
- pub fn readlink(this: *NodeFS, args: Arguments.Readlink, comptime flavor: Flavor) Maybe(Return.Readlink) {
- var outbuf: [bun.MAX_PATH_BYTES]u8 = undefined;
- var inbuf = &this.sync_error_buf;
- switch (comptime flavor) {
- .sync => {
- const path = args.path.sliceZ(inbuf);
-
- const len = switch (Syscall.readlink(path, &outbuf)) {
- .err => |err| return .{
- .err = err.withPath(args.path.slice()),
- },
- .result => |buf_| buf_,
- };
-
- return .{
- .result = switch (args.encoding) {
- .buffer => .{
- .buffer = Buffer.fromString(outbuf[0..len], bun.default_allocator) catch unreachable,
- },
- else => .{
- .string = bun.default_allocator.dupe(u8, outbuf[0..len]) catch unreachable,
- },
- },
- };
- },
- else => {},
- }
-
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Readlink).todo;
- }
- pub fn realpath(this: *NodeFS, args: Arguments.Realpath, comptime flavor: 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 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 fd = switch (Syscall.open(path, flags, 0)) {
- .err => |err| return .{
- .err = err.withPath(path),
- },
- .result => |fd_| fd_,
- };
-
- defer {
- _ = Syscall.close(fd);
- }
-
- 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 => .{
- .string = bun.default_allocator.dupe(u8, buf) catch unreachable,
- },
- },
- };
- },
- else => {},
- }
-
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Realpath).todo;
- }
- pub const realpathNative = realpath;
- // pub fn realpathNative(this: *NodeFS, args: Arguments.Realpath, comptime flavor: Flavor) Maybe(Return.Realpath) {
- // _ = args;
- // _ = this;
- // _ = flavor;
- // return error.NotImplementedYet;
- // }
- pub fn rename(this: *NodeFS, args: Arguments.Rename, comptime flavor: Flavor) Maybe(Return.Rename) {
- var from_buf = &this.sync_error_buf;
- var to_buf: [bun.MAX_PATH_BYTES]u8 = undefined;
-
- switch (comptime flavor) {
- .sync => {
- var from = args.old_path.sliceZ(from_buf);
- var to = args.new_path.sliceZ(&to_buf);
- return Syscall.rename(from, to);
- },
- else => {},
- }
-
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Rename).todo;
- }
- pub fn rmdir(this: *NodeFS, args: Arguments.RmDir, comptime flavor: Flavor) Maybe(Return.Rmdir) {
- switch (comptime flavor) {
- .sync => {
- var dir = args.old_path.sliceZ(&this.sync_error_buf);
- _ = dir;
- },
- else => {},
- }
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Rmdir).todo;
- }
- pub fn rm(this: *NodeFS, args: Arguments.RmDir, comptime flavor: Flavor) Maybe(Return.Rm) {
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Rm).todo;
- }
- pub fn stat(this: *NodeFS, args: Arguments.Stat, comptime flavor: Flavor) Maybe(Return.Stat) {
- if (args.big_int) return Maybe(Return.Stat).todo;
-
- switch (comptime flavor) {
- .sync => {
- return @as(Maybe(Return.Stat), switch (Syscall.stat(
- args.path.sliceZ(
- &this.sync_error_buf,
- ),
- )) {
- .result => |result| Maybe(Return.Stat){ .result = Return.Stat.init(result) },
- .err => |err| Maybe(Return.Stat){ .err = err },
- });
- },
- else => {},
- }
-
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Stat).todo;
- }
-
- pub fn symlink(this: *NodeFS, args: Arguments.Symlink, comptime flavor: Flavor) Maybe(Return.Symlink) {
- var to_buf: [bun.MAX_PATH_BYTES]u8 = undefined;
-
- switch (comptime flavor) {
- .sync => {
- return Syscall.symlink(
- args.old_path.sliceZ(&this.sync_error_buf),
- args.new_path.sliceZ(&to_buf),
- );
- },
- else => {},
- }
-
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Symlink).todo;
- }
- fn _truncate(this: *NodeFS, path: PathLike, len: JSC.WebCore.Blob.SizeType, comptime flavor: Flavor) Maybe(Return.Truncate) {
- switch (comptime flavor) {
- .sync => {
- return Maybe(Return.Truncate).errno(C.truncate(path.sliceZ(&this.sync_error_buf), len)) orelse
- Maybe(Return.Truncate).success;
- },
- else => {},
- }
-
- _ = this;
- _ = flavor;
- return Maybe(Return.Truncate).todo;
- }
- pub fn truncate(this: *NodeFS, args: Arguments.Truncate, comptime flavor: Flavor) Maybe(Return.Truncate) {
- return switch (args.path) {
- .fd => |fd| this.ftruncate(
- Arguments.FTruncate{ .fd = fd, .len = args.len },
- flavor,
- ),
- .path => this._truncate(
- args.path.path,
- args.len,
- flavor,
- ),
- };
- }
- pub fn unlink(this: *NodeFS, args: Arguments.Unlink, comptime flavor: Flavor) Maybe(Return.Unlink) {
- switch (comptime flavor) {
- .sync => {
- return Maybe(Return.Unlink).errnoSysP(system.unlink(args.path.sliceZ(&this.sync_error_buf)), .unlink, args.path.slice()) orelse
- Maybe(Return.Unlink).success;
- },
- else => {},
- }
-
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Unlink).todo;
- }
- pub fn unwatchFile(this: *NodeFS, args: Arguments.UnwatchFile, comptime flavor: Flavor) Maybe(Return.UnwatchFile) {
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.UnwatchFile).todo;
- }
- pub fn utimes(this: *NodeFS, args: Arguments.Utimes, comptime flavor: Flavor) Maybe(Return.Utimes) {
- var times = [2]std.c.timeval{
- .{
- .tv_sec = args.mtime,
- // TODO: is this correct?
- .tv_usec = 0,
- },
- .{
- .tv_sec = args.atime,
- // TODO: is this correct?
- .tv_usec = 0,
- },
- };
-
- switch (comptime flavor) {
- // futimes uses the syscall version
- // we use libc because here, not for a good reason
- // just missing from the linux syscall interface in zig and I don't want to modify that right now
- .sync => return if (Maybe(Return.Utimes).errnoSysP(std.c.utimes(args.path.sliceZ(&this.sync_error_buf), &times), .utimes, args.path.slice())) |err|
- err
- else
- Maybe(Return.Utimes).success,
- else => {},
- }
-
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Utimes).todo;
- }
-
- pub fn lutimes(this: *NodeFS, args: Arguments.Lutimes, comptime flavor: Flavor) Maybe(Return.Lutimes) {
- var times = [2]std.c.timeval{
- .{
- .tv_sec = args.mtime,
- // TODO: is this correct?
- .tv_usec = 0,
- },
- .{
- .tv_sec = args.atime,
- // TODO: is this correct?
- .tv_usec = 0,
- },
- };
-
- switch (comptime flavor) {
- // futimes uses the syscall version
- // we use libc because here, not for a good reason
- // just missing from the linux syscall interface in zig and I don't want to modify that right now
- .sync => return if (Maybe(Return.Lutimes).errnoSysP(C.lutimes(args.path.sliceZ(&this.sync_error_buf), &times), .lutimes, args.path.slice())) |err|
- err
- else
- Maybe(Return.Lutimes).success,
- else => {},
- }
-
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Lutimes).todo;
- }
- pub fn watch(this: *NodeFS, args: Arguments.Watch, comptime flavor: Flavor) Maybe(Return.Watch) {
- _ = args;
- _ = this;
- _ = flavor;
- return Maybe(Return.Watch).todo;
- }
- pub fn createReadStream(this: *NodeFS, args: Arguments.CreateReadStream, comptime flavor: Flavor) Maybe(Return.CreateReadStream) {
- _ = args;
- _ = this;
- _ = flavor;
- var stream = bun.default_allocator.create(JSC.Node.Stream) catch unreachable;
- stream.* = JSC.Node.Stream{
- .sink = .{
- .readable = JSC.Node.Readable{
- .stream = stream,
- .globalObject = args.global_object,
- },
- },
- .sink_type = .readable,
- .content = undefined,
- .content_type = undefined,
- .allocator = bun.default_allocator,
- };
-
- args.file.copyToStream(args.flags, args.autoClose, args.mode, bun.default_allocator, stream) catch unreachable;
- args.copyToState(&stream.sink.readable.state);
- return Maybe(Return.CreateReadStream){ .result = stream };
- }
- pub fn createWriteStream(this: *NodeFS, args: Arguments.CreateWriteStream, comptime flavor: Flavor) Maybe(Return.CreateWriteStream) {
- _ = args;
- _ = this;
- _ = flavor;
- var stream = bun.default_allocator.create(JSC.Node.Stream) catch unreachable;
- stream.* = JSC.Node.Stream{
- .sink = .{
- .writable = JSC.Node.Writable{
- .stream = stream,
- .globalObject = args.global_object,
- },
- },
- .sink_type = .writable,
- .content = undefined,
- .content_type = undefined,
- .allocator = bun.default_allocator,
- };
- args.file.copyToStream(args.flags, args.autoClose, args.mode, bun.default_allocator, stream) catch unreachable;
- args.copyToState(&stream.sink.writable.state);
- return Maybe(Return.CreateWriteStream){ .result = stream };
- }
-};