diff options
Diffstat (limited to 'src/javascript/jsc/node/syscall.zig')
-rw-r--r-- | src/javascript/jsc/node/syscall.zig | 622 |
1 files changed, 0 insertions, 622 deletions
diff --git a/src/javascript/jsc/node/syscall.zig b/src/javascript/jsc/node/syscall.zig deleted file mode 100644 index ad4545aa9..000000000 --- a/src/javascript/jsc/node/syscall.zig +++ /dev/null @@ -1,622 +0,0 @@ -// This file is entirely based on Zig's std.os -// The differences are in error handling -const std = @import("std"); -const os = std.os; -const builtin = @import("builtin"); - -const Syscall = @This(); -const Environment = @import("../../../global.zig").Environment; -const default_allocator = @import("../../../global.zig").default_allocator; -const JSC = @import("../../../jsc.zig"); -const SystemError = JSC.SystemError; -const bun = @import("../../../global.zig"); -const MAX_PATH_BYTES = bun.MAX_PATH_BYTES; -const fd_t = bun.FileDescriptorType; -const C = @import("../../../global.zig").C; -const linux = os.linux; -const Maybe = JSC.Maybe; - -pub const system = if (Environment.isLinux) linux else @import("io").darwin; -pub const S = struct { - pub usingnamespace if (Environment.isLinux) linux.S else std.os.S; -}; -const sys = std.os.system; - -const statSym = if (Environment.isMac) - C.stat -else if (Environment.isLinux) - linux.stat -else - @compileError("STAT"); - -const fstatSym = if (Environment.isMac) - C.fstat -else if (Environment.isLinux) - linux.fstat -else - @compileError("STAT"); - -const lstat64 = if (Environment.isMac) - C.lstat -else if (Environment.isLinux) - linux.lstat -else - @compileError("STAT"); - -pub const Tag = enum(u8) { - TODO, - - access, - chmod, - chown, - clonefile, - close, - copy_file_range, - copyfile, - fchmod, - fchown, - fcntl, - fdatasync, - fstat, - fsync, - ftruncate, - futimens, - getdents64, - getdirentries64, - lchmod, - lchown, - link, - lseek, - lstat, - lutimes, - mkdir, - mkdtemp, - mmap, - munmap, - open, - pread, - pwrite, - read, - readlink, - rename, - stat, - symlink, - unlink, - utimes, - write, - getcwd, - chdir, - fcopyfile, - recv, - send, - sendfile, - splice, - - kevent, - kqueue, - pub var strings = std.EnumMap(Tag, JSC.C.JSStringRef).initFull(null); -}; -const PathString = @import("../../../global.zig").PathString; - -const mode_t = os.mode_t; - -const open_sym = system.open; - -const mem = std.mem; - -pub fn getcwd(buf: *[bun.MAX_PATH_BYTES]u8) Maybe([]const u8) { - const Result = Maybe([]const u8); - buf[0] = 0; - const rc = std.c.getcwd(buf, bun.MAX_PATH_BYTES); - return if (rc != null) - Result{ .result = std.mem.sliceTo(rc.?[0..bun.MAX_PATH_BYTES], 0) } - else - Result.errnoSys(0, .getcwd).?; -} - -pub fn fchmod(fd: JSC.Node.FileDescriptor, mode: JSC.Node.Mode) Maybe(void) { - return Maybe(void).errnoSys(C.fchmod(fd, mode), .fchmod) orelse - Maybe(void).success; -} - -pub fn chdir(destination: [:0]const u8) Maybe(void) { - const rc = sys.chdir(destination); - return Maybe(void).errnoSys(rc, .chdir) orelse Maybe(void).success; -} - -pub fn stat(path: [:0]const u8) Maybe(os.Stat) { - var stat_ = mem.zeroes(os.Stat); - if (Maybe(os.Stat).errnoSys(statSym(path, &stat_), .stat)) |err| return err; - return Maybe(os.Stat){ .result = stat_ }; -} - -pub fn lstat(path: [:0]const u8) Maybe(os.Stat) { - var stat_ = mem.zeroes(os.Stat); - if (Maybe(os.Stat).errnoSys(lstat64(path, &stat_), .lstat)) |err| return err; - return Maybe(os.Stat){ .result = stat_ }; -} - -pub fn fstat(fd: JSC.Node.FileDescriptor) Maybe(os.Stat) { - var stat_ = mem.zeroes(os.Stat); - if (Maybe(os.Stat).errnoSys(fstatSym(fd, &stat_), .fstat)) |err| return err; - return Maybe(os.Stat){ .result = stat_ }; -} - -pub fn mkdir(file_path: [:0]const u8, flags: JSC.Node.Mode) Maybe(void) { - if (comptime Environment.isMac) { - return Maybe(void).errnoSysP(system.mkdir(file_path, flags), .mkdir, file_path) orelse Maybe(void).success; - } - - if (comptime Environment.isLinux) { - return Maybe(void).errnoSysP(linux.mkdir(file_path, flags), .mkdir, file_path) orelse Maybe(void).success; - } -} - -pub fn getErrno(rc: anytype) std.os.E { - if (comptime Environment.isMac) return std.os.errno(rc); - const Type = @TypeOf(rc); - - return switch (Type) { - comptime_int, usize => std.os.linux.getErrno(@as(usize, rc)), - i32, c_int, isize => std.os.linux.getErrno(@bitCast(usize, @as(isize, rc))), - else => @compileError("Not implemented yet for type " ++ @typeName(Type)), - }; -} - -pub fn open(file_path: [:0]const u8, flags: JSC.Node.Mode, perm: JSC.Node.Mode) Maybe(JSC.Node.FileDescriptor) { - while (true) { - const rc = Syscall.system.open(file_path, flags, perm); - return switch (Syscall.getErrno(rc)) { - .SUCCESS => .{ .result = @intCast(JSC.Node.FileDescriptor, rc) }, - .INTR => continue, - else => |err| { - return Maybe(std.os.fd_t){ - .err = .{ - .errno = @truncate(Syscall.Error.Int, @enumToInt(err)), - .syscall = .open, - }, - }; - }, - }; - } - - unreachable; -} - -// The zig standard library marks BADF as unreachable -// That error is not unreachable for us -pub fn close(fd: std.os.fd_t) ?Syscall.Error { - if (comptime Environment.isMac) { - // This avoids the EINTR problem. - return switch (system.getErrno(system.@"close$NOCANCEL"(fd))) { - .BADF => Syscall.Error{ .errno = @enumToInt(os.E.BADF), .syscall = .close }, - else => null, - }; - } - - if (comptime Environment.isLinux) { - return switch (linux.getErrno(linux.close(fd))) { - .BADF => Syscall.Error{ .errno = @enumToInt(os.E.BADF), .syscall = .close }, - else => null, - }; - } - - @compileError("Not implemented yet"); -} - -const max_count = switch (builtin.os.tag) { - .linux => 0x7ffff000, - .macos, .ios, .watchos, .tvos => std.math.maxInt(i32), - else => std.math.maxInt(isize), -}; - -pub fn write(fd: os.fd_t, bytes: []const u8) Maybe(usize) { - const adjusted_len = @minimum(max_count, bytes.len); - - while (true) { - const rc = sys.write(fd, bytes.ptr, adjusted_len); - if (Maybe(usize).errnoSys(rc, .write)) |err| { - if (err.getErrno() == .INTR) continue; - return err; - } - return Maybe(usize){ .result = @intCast(usize, rc) }; - } - unreachable; -} - -const pread_sym = if (builtin.os.tag == .linux and builtin.link_libc) - sys.pread64 -else if (builtin.os.tag.isDarwin()) - system.@"pread$NOCANCEL" -else - system.pread; - -pub fn pread(fd: os.fd_t, buf: []u8, offset: i64) Maybe(usize) { - const adjusted_len = @minimum(buf.len, max_count); - const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned - while (true) { - const rc = pread_sym(fd, buf.ptr, adjusted_len, ioffset); - if (Maybe(usize).errnoSys(rc, .pread)) |err| { - if (err.getErrno() == .INTR) continue; - return err; - } - return Maybe(usize){ .result = @intCast(usize, rc) }; - } - unreachable; -} - -const pwrite_sym = if (builtin.os.tag == .linux and builtin.link_libc) - sys.pwrite64 -else - sys.pwrite; - -pub fn pwrite(fd: os.fd_t, bytes: []const u8, offset: i64) Maybe(usize) { - const adjusted_len = @minimum(bytes.len, max_count); - - const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned - while (true) { - const rc = pwrite_sym(fd, bytes.ptr, adjusted_len, ioffset); - return if (Maybe(usize).errnoSys(rc, .pwrite)) |err| { - switch (err.getErrno()) { - .INTR => continue, - else => return err, - } - } else Maybe(usize){ .result = @intCast(usize, rc) }; - } - - unreachable; -} - -pub fn read(fd: os.fd_t, buf: []u8) Maybe(usize) { - const adjusted_len = @minimum(buf.len, max_count); - if (comptime Environment.isMac) { - const rc = system.@"read$NOCANCEL"(fd, buf.ptr, adjusted_len); - if (Maybe(usize).errnoSys(rc, .read)) |err| { - return err; - } - return Maybe(usize){ .result = @intCast(usize, rc) }; - } else { - while (true) { - const rc = sys.read(fd, buf.ptr, adjusted_len); - if (Maybe(usize).errnoSys(rc, .read)) |err| { - if (err.getErrno() == .INTR) continue; - return err; - } - return Maybe(usize){ .result = @intCast(usize, rc) }; - } - } - unreachable; -} - -pub fn recv(fd: os.fd_t, buf: []u8, flag: u32) Maybe(usize) { - if (comptime Environment.isMac) { - const rc = system.@"recvfrom$NOCANCEL"(fd, buf.ptr, buf.len, flag, null, null); - if (Maybe(usize).errnoSys(rc, .recv)) |err| { - return err; - } - return Maybe(usize){ .result = @intCast(usize, rc) }; - } else { - while (true) { - const rc = linux.recvfrom(fd, buf.ptr, buf.len, flag | os.SOCK.CLOEXEC | linux.MSG.CMSG_CLOEXEC, null, null); - if (Maybe(usize).errnoSys(rc, .recv)) |err| { - if (err.getErrno() == .INTR) continue; - return err; - } - return Maybe(usize){ .result = @intCast(usize, rc) }; - } - } - unreachable; -} - -pub fn send(fd: os.fd_t, buf: []const u8, flag: u32) Maybe(usize) { - if (comptime Environment.isMac) { - const rc = system.@"sendto$NOCANCEL"(fd, buf.ptr, buf.len, flag, null, 0); - if (Maybe(usize).errnoSys(rc, .send)) |err| { - return err; - } - return Maybe(usize){ .result = @intCast(usize, rc) }; - } else { - while (true) { - const rc = linux.sendto(fd, buf.ptr, buf.len, flag | os.SOCK.CLOEXEC | os.MSG.NOSIGNAL, null, 0); - - if (Maybe(usize).errnoSys(rc, .send)) |err| { - if (err.getErrno() == .INTR) continue; - return err; - } - - return Maybe(usize){ .result = @intCast(usize, rc) }; - } - } - unreachable; -} - -pub fn readlink(in: [:0]const u8, buf: []u8) Maybe(usize) { - while (true) { - const rc = sys.readlink(in, buf.ptr, buf.len); - - if (Maybe(usize).errnoSys(rc, .readlink)) |err| { - if (err.getErrno() == .INTR) continue; - return err; - } - return Maybe(usize){ .result = @intCast(usize, rc) }; - } - unreachable; -} - -pub fn rename(from: [:0]const u8, to: [:0]const u8) Maybe(void) { - while (true) { - if (Maybe(void).errnoSys(sys.rename(from, to), .rename)) |err| { - if (err.getErrno() == .INTR) continue; - return err; - } - return Maybe(void).success; - } - unreachable; -} - -pub fn chown(path: [:0]const u8, uid: os.uid_t, gid: os.gid_t) Maybe(void) { - while (true) { - if (Maybe(void).errnoSys(C.chown(path, uid, gid), .chown)) |err| { - if (err.getErrno() == .INTR) continue; - return err; - } - return Maybe(void).success; - } - unreachable; -} - -pub fn symlink(from: [:0]const u8, to: [:0]const u8) Maybe(void) { - while (true) { - if (Maybe(void).errnoSys(sys.symlink(from, to), .symlink)) |err| { - if (err.getErrno() == .INTR) continue; - return err; - } - return Maybe(void).success; - } - unreachable; -} - -pub fn clonefile(from: [:0]const u8, to: [:0]const u8) Maybe(void) { - if (comptime !Environment.isMac) @compileError("macOS only"); - - while (true) { - if (Maybe(void).errnoSys(C.darwin.clonefile(from, to, 0), .clonefile)) |err| { - if (err.getErrno() == .INTR) continue; - return err; - } - return Maybe(void).success; - } - unreachable; -} - -pub fn copyfile(from: [:0]const u8, to: [:0]const u8, flags: c_int) Maybe(void) { - if (comptime !Environment.isMac) @compileError("macOS only"); - - while (true) { - if (Maybe(void).errnoSys(C.darwin.copyfile(from, to, null, flags), .copyfile)) |err| { - if (err.getErrno() == .INTR) continue; - return err; - } - return Maybe(void).success; - } - unreachable; -} - -pub fn fcopyfile(fd_in: std.os.fd_t, fd_out: std.os.fd_t, flags: u32) Maybe(void) { - if (comptime !Environment.isMac) @compileError("macOS only"); - - while (true) { - if (Maybe(void).errnoSys(system.fcopyfile(fd_in, fd_out, null, flags), .fcopyfile)) |err| { - if (err.getErrno() == .INTR) continue; - return err; - } - return Maybe(void).success; - } - unreachable; -} - -pub fn unlink(from: [:0]const u8) Maybe(void) { - while (true) { - if (Maybe(void).errno(sys.unlink(from), .unlink)) |err| { - if (err.getErrno() == .INTR) continue; - return err; - } - return Maybe(void).success; - } - unreachable; -} - -pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) Maybe([]u8) { - switch (comptime builtin.os.tag) { - .windows => { - const windows = std.os.windows; - var wide_buf: [windows.PATH_MAX_WIDE]u16 = undefined; - const wide_slice = windows.GetFinalPathNameByHandle(fd, .{}, wide_buf[0..]) catch { - return Maybe([]u8){ .err = .{ .errno = .EBADF } }; - }; - - // Trust that Windows gives us valid UTF-16LE. - const end_index = std.unicode.utf16leToUtf8(out_buffer, wide_slice) catch unreachable; - return .{ .result = out_buffer[0..end_index] }; - }, - .macos, .ios, .watchos, .tvos => { - // On macOS, we can use F.GETPATH fcntl command to query the OS for - // the path to the file descriptor. - @memset(out_buffer, 0, MAX_PATH_BYTES); - if (Maybe([]u8).errnoSys(system.fcntl(fd, os.F.GETPATH, out_buffer), .fcntl)) |err| { - return err; - } - const len = mem.indexOfScalar(u8, out_buffer[0..], @as(u8, 0)) orelse MAX_PATH_BYTES; - return .{ .result = out_buffer[0..len] }; - }, - .linux => { - // TODO: alpine linux may not have /proc/self - var procfs_buf: ["/proc/self/fd/-2147483648".len:0]u8 = undefined; - const proc_path = std.fmt.bufPrintZ(procfs_buf[0..], "/proc/self/fd/{d}\x00", .{fd}) catch unreachable; - - return switch (readlink(proc_path, out_buffer)) { - .err => |err| return .{ .err = err }, - .result => |len| return .{ .result = out_buffer[0..len] }, - }; - }, - // .solaris => { - // var procfs_buf: ["/proc/self/path/-2147483648".len:0]u8 = undefined; - // const proc_path = std.fmt.bufPrintZ(procfs_buf[0..], "/proc/self/path/{d}", .{fd}) catch unreachable; - - // const target = readlinkZ(proc_path, out_buffer) catch |err| switch (err) { - // error.UnsupportedReparsePointType => unreachable, - // error.NotLink => unreachable, - // else => |e| return e, - // }; - // return target; - // }, - else => @compileError("querying for canonical path of a handle is unsupported on this host"), - } -} - -/// Use of a mapped region can result in these signals: -/// * SIGSEGV - Attempted write into a region mapped as read-only. -/// * SIGBUS - Attempted access to a portion of the buffer that does not correspond to the file -fn mmap( - ptr: ?[*]align(mem.page_size) u8, - length: usize, - prot: u32, - flags: u32, - fd: os.fd_t, - offset: u64, -) Maybe([]align(mem.page_size) u8) { - const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned - const rc = std.c.mmap(ptr, length, prot, flags, fd, ioffset); - const fail = std.c.MAP.FAILED; - if (rc == fail) { - return Maybe([]align(mem.page_size) u8){ - .err = .{ .errno = @truncate(Syscall.Error.Int, @enumToInt(std.c.getErrno(@bitCast(i64, @ptrToInt(fail))))), .syscall = .mmap }, - }; - } - - return Maybe([]align(mem.page_size) u8){ .result = @ptrCast([*]align(mem.page_size) u8, @alignCast(mem.page_size, rc))[0..length] }; -} - -pub fn mmapFile(path: [:0]const u8, flags: u32, wanted_size: ?usize, offset: usize) Maybe([]align(mem.page_size) u8) { - const fd = switch (open(path, os.O.RDWR, 0)) { - .result => |fd| fd, - .err => |err| return .{ .err = err }, - }; - - var size = std.math.sub(usize, @intCast(usize, switch (fstat(fd)) { - .result => |result| result.size, - .err => |err| { - _ = close(fd); - return .{ .err = err }; - }, - }), offset) catch 0; - - if (wanted_size) |size_| size = @minimum(size, size_); - - const map = switch (mmap(null, size, os.PROT.READ | os.PROT.WRITE, flags, fd, offset)) { - .result => |map| map, - - .err => |err| { - _ = close(fd); - return .{ .err = err }; - }, - }; - - if (close(fd)) |err| { - _ = munmap(map); - return .{ .err = err }; - } - - return .{ .result = map }; -} - -pub fn munmap(memory: []align(mem.page_size) const u8) Maybe(void) { - if (Maybe(void).errnoSys(system.munmap(memory.ptr, memory.len), .munmap)) |err| { - return err; - } else return Maybe(void).success; -} - -pub const Error = struct { - const max_errno_value = brk: { - const errno_values = std.enums.values(os.E); - var err = @enumToInt(os.E.SUCCESS); - for (errno_values) |errn| { - err = @maximum(err, @enumToInt(errn)); - } - break :brk err; - }; - pub const Int: type = std.math.IntFittingRange(0, max_errno_value + 5); - - errno: Int, - syscall: Syscall.Tag = @intToEnum(Syscall.Tag, 0), - path: []const u8 = "", - - pub fn fromCode(errno: os.E, syscall: Syscall.Tag) Error { - return .{ .errno = @truncate(Int, @enumToInt(errno)), .syscall = syscall }; - } - - pub const oom = fromCode(os.E.NOMEM, .read); - - pub const retry = Error{ - .errno = if (Environment.isLinux) - @intCast(Int, @enumToInt(os.E.AGAIN)) - else if (Environment.isMac) - @intCast(Int, @enumToInt(os.E.WOULDBLOCK)) - else - @intCast(Int, @enumToInt(os.E.INTR)), - .syscall = .retry, - }; - - pub inline fn getErrno(this: Error) os.E { - return @intToEnum(os.E, this.errno); - } - - pub inline fn withPath(this: Error, path: anytype) Error { - return Error{ - .errno = this.errno, - .syscall = this.syscall, - .path = bun.span(path), - }; - } - - pub inline fn withSyscall(this: Error, syscall: Syscall) Error { - return Error{ - .errno = this.errno, - .syscall = syscall, - .path = this.path, - }; - } - - pub const todo_errno = std.math.maxInt(Int) - 1; - pub const todo = Error{ .errno = todo_errno }; - - pub fn toSystemError(this: Error) SystemError { - var err = SystemError{ - .errno = @as(c_int, this.errno) * -1, - .syscall = JSC.ZigString.init(@tagName(this.syscall)), - }; - - // errno label - if (this.errno > 0 and this.errno < C.SystemErrno.max) { - const system_errno = @intToEnum(C.SystemErrno, this.errno); - err.code = JSC.ZigString.init(@tagName(system_errno)); - if (C.SystemErrno.labels.get(system_errno)) |label| { - err.message = JSC.ZigString.init(label); - } - } - - if (this.path.len > 0) { - err.path = JSC.ZigString.init(this.path); - } - - return err; - } - - pub fn toJS(this: Error, ctx: JSC.C.JSContextRef) JSC.C.JSObjectRef { - return this.toSystemError().toErrorInstance(ctx.ptr()).asObjectRef(); - } - - pub fn toJSC(this: Error, ptr: *JSC.JSGlobalObject) JSC.JSValue { - return this.toSystemError().toErrorInstance(ptr); - } -}; |