mirror of
https://github.com/oven-sh/bun
synced 2026-02-15 05:12:29 +00:00
fs.*Sync(), bun wiptest, and More ™ (#106)
* very very wip
* almost ready to fix the errors
* Update identity_context.zig
* Update base.zig
* [bun test] It runs successfully
* Remove unnecessary call
* [Bun.js] Improve JS <> Zig unicode string interop
This fixes longstanding unicode bugs with `console.log` & `fetch`.
I believe @evanwashere reported this first awhile ago
* [Bun.js] Implement `Object.is()` binding and a way to set a timeout for script execution
* Update PLCrashReport.zig
* [Bun.js] Make `console.log` more closely match Node.js and Deno
* [Bun.js] Implement formatting specifier for console.*
* Implement `console.clear()`
* bug fix
* Support console.clear()
* Buffer stderr
* [bun test] Begin implementing Node.js `fs`
* Update darwin_c.zig
* Implement more of `fs`
* `mkdir`, `mkdir` recursive, `mkdtemp`
* `open`, `read` (and pread)
* Move some things into more files
* Implement readdir
* `readFile`, `readLink`, and `realpath`
* `writeFile`, `symlink`, `chown`, `rename`, `stat`, `unlink`, `truncate`
* `lutimes`
* Implement `SystemError` and begin wiring up the `fs` module
* `"fs"` - Most of the arguments / validation
* `fs` - Rest of the arguments / validations
* Begin wiring up the `fs` module
* Fix all the build errors
* support printing typed arrays in console.log
* It...works?
* Support `require("fs")`, `import fs from 'fs';`, `import * as fs from 'fs'`
* Fix a couple bugs
* get rid of the crash reporter for now
* Update fs.exports.js
* [bun.js] slight improvement to startup time
* [bun.js] Improve error message printing
* [Bun.js] Add `Bun.gc()` to run the garbage collector manually and report heap size
* [Bun.js] Add Bun.generateHeapSnapshot to return what JS types are using memory
* [Bun.js] Add `Bun.shrink()` to tell JSC to shrink the VM size
* Improve encoding reader
* [bun.js] Improve callback & microtask performance
* Update node_fs.zig
* Implement `console.assert`
* simple test
* [Bun.js] Prepare for multiple globals/realms to support testing
* Create callbacks-overhead.mjs
* Update http.zig
* [Bun.js] Implement `queueMicrotask`
* Add test for queueMicrotask
* 😪
* [Bun.js] Implement `process.versions`, `process.pid`, `process.ppid`, `process.nextTick`, `process.versions`,
* Implement `process.env.toJSON()`
* [Bun.js] Improve performance of `fs.existsSync`
* 💅
* [Bun.js] Implement `process.chdir(str)` and `process.cwd()`, support up to 4 args in `process.nextTick`
* Make creating Zig::Process lazy
* Split processi nto separte file
* [Bun.js] Node.js Streams - Part 1/?
* [Bun.js] Node.js streams 2/?
* WIP streams
* fix crash
* Reduce allocations in many places
* swap
* Make `bun` start 2ms faster
* Always use an apiLock()
* libBacktrace doesn't really work yet
* Fix crash in the upgrade checker
* Clean up code for importing the runtime when not bundling
* 📷
* Update linker.zig
* 68!
* backtrace
* no, really backtrace
* Fix
* Linux fixes
* Fixes on Linux
* Update mimalloc
* [bun test] Automatically scan for {.test,_test,.spec,_spec}.{jsx,tsx,js,cts,mts,ts,cjs}
This commit is contained in:
97
src/javascript/jsc/node/buffer.js
Normal file
97
src/javascript/jsc/node/buffer.js
Normal file
@@ -0,0 +1,97 @@
|
||||
"use strict";
|
||||
|
||||
function createBuffer(BufferPrototype, BufferStatic, Realm) {
|
||||
"use strict";
|
||||
|
||||
var Uint8ArraySubarray = Realm.Uint8Array.prototype.subarray;
|
||||
var isUint8Array = (value) => value instanceof Realm.Uint8Array;
|
||||
var SymbolToPrimitive = Realm.Symbol.toPrimitive;
|
||||
var isArray = Realm.Array.isArray;
|
||||
var isArrayBufferLike =
|
||||
"SharedArrayBuffer" in Realm
|
||||
? () =>
|
||||
value instanceof Realm.ArrayBuffer ||
|
||||
value instanceof Realm.SharedArrayBuffer
|
||||
: () => value instanceof Realm.ArrayBuffer;
|
||||
|
||||
var BufferInstance = class BufferInstance extends Realm.Uint8Array {
|
||||
constructor(bufferOrLength, byteOffset, length) {
|
||||
super(bufferOrLength, byteOffset, length);
|
||||
}
|
||||
|
||||
static isBuffer(obj) {
|
||||
return obj instanceof BufferInstance;
|
||||
}
|
||||
|
||||
static from(value, encodingOrOffset, length) {
|
||||
switch (typeof value) {
|
||||
case "string": {
|
||||
return BufferStatic.fromString(value, encodingOrOffset, length);
|
||||
}
|
||||
case "object": {
|
||||
if (isUint8Array(value)) {
|
||||
return BufferStatic.fromUint8Array(value, encodingOrOffset, length);
|
||||
}
|
||||
|
||||
if (isArrayBufferLike(value)) {
|
||||
return new BufferInstance(value, 0, length);
|
||||
}
|
||||
|
||||
const valueOf = value.valueOf && value.valueOf();
|
||||
if (
|
||||
valueOf != null &&
|
||||
valueOf !== value &&
|
||||
(typeof valueOf === "string" || typeof valueOf === "object")
|
||||
) {
|
||||
return BufferInstance.from(valueOf, encodingOrOffset, length);
|
||||
}
|
||||
|
||||
if (typeof value[SymbolToPrimitive] === "function") {
|
||||
const primitive = value[SymbolToPrimitive]("string");
|
||||
if (typeof primitive === "string") {
|
||||
return BufferStatic.fromString(primitive, encodingOrOffset);
|
||||
}
|
||||
}
|
||||
|
||||
if (isArray(value)) {
|
||||
return BufferStatic.fromArray(value, encodingOrOffset, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new TypeError(
|
||||
"First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object."
|
||||
);
|
||||
}
|
||||
|
||||
slice(start, end) {
|
||||
return Uint8ArraySubarray.call(this, start, end);
|
||||
}
|
||||
|
||||
static get poolSize() {
|
||||
return BufferStatic._poolSize;
|
||||
}
|
||||
|
||||
static set poolSize(value) {
|
||||
BufferStatic._poolSize = value;
|
||||
}
|
||||
|
||||
get parent() {
|
||||
return this.buffer;
|
||||
}
|
||||
|
||||
get offset() {
|
||||
return this.byteOffset;
|
||||
}
|
||||
};
|
||||
|
||||
Object.assign(BufferInstance, BufferStatic);
|
||||
Object.assign(BufferInstance.prototype, BufferPrototype);
|
||||
Object.defineProperty(BufferInstance, "name", {
|
||||
value: "Buffer",
|
||||
configurable: false,
|
||||
enumerable: false,
|
||||
});
|
||||
|
||||
return BufferInstance;
|
||||
}
|
||||
553
src/javascript/jsc/node/buffer.zig
Normal file
553
src/javascript/jsc/node/buffer.zig
Normal file
@@ -0,0 +1,553 @@
|
||||
const std = @import("std");
|
||||
const _global = @import("../../../global.zig");
|
||||
const strings = _global.strings;
|
||||
const string = _global.string;
|
||||
const AsyncIO = @import("io");
|
||||
const JSC = @import("../../../jsc.zig");
|
||||
const PathString = JSC.PathString;
|
||||
const Environment = _global.Environment;
|
||||
const C = _global.C;
|
||||
const Syscall = @import("./syscall.zig");
|
||||
const os = std.os;
|
||||
const Buffer = JSC.ArrayBuffer;
|
||||
|
||||
const JSGlobalObject = JSC.JSGlobalObject;
|
||||
const ArgumentsSlice = JSC.Node.ArgumentsSlice;
|
||||
|
||||
const BufferStaticFunctionEnum = JSC.Node.DeclEnum(BufferStatic);
|
||||
|
||||
fn BufferStatic_wrap(comptime FunctionEnum: BufferStaticFunctionEnum) NodeFSFunction {
|
||||
const Function = @field(BufferStatic, @tagName(BufferStaticFunctionEnum));
|
||||
const FunctionType = @TypeOf(Function);
|
||||
|
||||
const function: std.builtin.TypeInfo.Fn = comptime @typeInfo(FunctionType).Fn;
|
||||
comptime if (function.args.len != 3) @compileError("Expected 3 arguments");
|
||||
const Arguments = comptime function.args[1].arg_type.?;
|
||||
const FormattedName = comptime [1]u8{std.ascii.toUpper(@tagName(BufferStaticFunctionEnum)[0])} ++ @tagName(BufferStaticFunctionEnum)[1..];
|
||||
const Result = JSC.JSValue;
|
||||
|
||||
const NodeBindingClosure = struct {
|
||||
pub fn bind(
|
||||
_: void,
|
||||
ctx: JSC.C.JSContextRef,
|
||||
_: JSC.C.JSObjectRef,
|
||||
_: JSC.C.JSObjectRef,
|
||||
arguments: []const JSC.C.JSValueRef,
|
||||
exception: JSC.C.ExceptionRef,
|
||||
) JSC.C.JSValueRef {
|
||||
var slice = ArgumentsSlice.init(@ptrCast([*]const JSC.JSValue, arguments.ptr)[0..arguments.len]);
|
||||
|
||||
defer {
|
||||
// TODO: fix this
|
||||
for (arguments) |arg| {
|
||||
JSC.C.JSValueUnprotect(ctx, arg);
|
||||
}
|
||||
slice.arena.deinit();
|
||||
}
|
||||
|
||||
const args = if (comptime Arguments != void)
|
||||
(Arguments.fromJS(ctx, &slice, exception) orelse return null)
|
||||
else
|
||||
Arguments{};
|
||||
if (exception.* != null) return null;
|
||||
|
||||
const result: Result = Function(
|
||||
ctx.ptr(),
|
||||
args,
|
||||
exception,
|
||||
);
|
||||
if (exception.* != null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return result.asObjectRef();
|
||||
}
|
||||
};
|
||||
|
||||
return NodeBindingClosure.bind;
|
||||
}
|
||||
|
||||
pub const BufferStatic = struct {
|
||||
pub const Arguments = struct {
|
||||
pub const Alloc = struct {
|
||||
pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Alloc {}
|
||||
};
|
||||
pub const AllocUnsafe = struct {
|
||||
pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?AllocUnsafe {}
|
||||
};
|
||||
pub const AllocUnsafeSlow = struct {
|
||||
pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?AllocUnsafeSlow {}
|
||||
};
|
||||
pub const Compare = struct {
|
||||
pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Compare {}
|
||||
};
|
||||
pub const Concat = struct {
|
||||
pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Concat {}
|
||||
};
|
||||
pub const IsEncoding = struct {
|
||||
pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?IsEncoding {}
|
||||
};
|
||||
};
|
||||
pub fn alloc(globalThis: *JSGlobalObject, args: Arguments.Alloc, exception: JSC.C.ExceptionRef) JSC.JSValue {}
|
||||
pub fn allocUnsafe(globalThis: *JSGlobalObject, args: Arguments.AllocUnsafe, exception: JSC.C.ExceptionRef) JSC.JSValue {}
|
||||
pub fn allocUnsafeSlow(globalThis: *JSGlobalObject, args: Arguments.AllocUnsafeSlow, exception: JSC.C.ExceptionRef) JSC.JSValue {}
|
||||
pub fn compare(globalThis: *JSGlobalObject, args: Arguments.Compare, exception: JSC.C.ExceptionRef) JSC.JSValue {}
|
||||
pub fn concat(globalThis: *JSGlobalObject, args: Arguments.Concat, exception: JSC.C.ExceptionRef) JSC.JSValue {}
|
||||
pub fn isEncoding(globalThis: *JSGlobalObject, args: Arguments.IsEncoding, exception: JSC.C.ExceptionRef) JSC.JSValue {}
|
||||
|
||||
pub const Class = JSC.NewClass(
|
||||
void,
|
||||
.{ .name = "Buffer" },
|
||||
.{
|
||||
.alloc = .{ .name = "alloc", .rfn = BufferStatic_wrap(.alloc) },
|
||||
.allocUnsafe = .{ .name = "allocUnsafe", .rfn = BufferStatic_wrap(.allocUnsafe) },
|
||||
.allocUnsafeSlow = .{ .name = "allocUnsafeSlow", .rfn = BufferStatic_wrap(.allocUnsafeSlow) },
|
||||
.compare = .{ .name = "compare", .rfn = BufferStatic_wrap(.compare) },
|
||||
.concat = .{ .name = "concat", .rfn = BufferStatic_wrap(.concat) },
|
||||
.isEncoding = .{ .name = "isEncoding", .rfn = BufferStatic_wrap(.isEncoding) },
|
||||
},
|
||||
.{ ._poolSize = .{ .name = "_poolSize", .get = .{ .name = "get", .rfn = BufferStatic.getPoolSize }, .set = .{ .name = "set", .rfn = BufferStatic.setPoolSize } } },
|
||||
);
|
||||
};
|
||||
|
||||
pub const BufferPrototype = struct {
|
||||
const Arguments = struct {
|
||||
pub const Compare = struct {
|
||||
pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Compare {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
pub const Copy = struct {
|
||||
pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Copy {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
pub const Equals = struct {
|
||||
pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Equals {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
pub const Fill = struct {
|
||||
pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Fill {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
pub const Includes = struct {
|
||||
pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Includes {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
pub const IndexOf = struct {
|
||||
pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?IndexOf {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
pub const LastIndexOf = struct {
|
||||
pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?LastIndexOf {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
pub const Swap16 = struct {
|
||||
pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Swap16 {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
pub const Swap32 = struct {
|
||||
pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Swap32 {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
pub const Swap64 = struct {
|
||||
pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Swap64 {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
pub const Write = struct {
|
||||
pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Write {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
pub const Read = struct {
|
||||
pub fn fromJS(ctx: JSC.C.JSContextRef, arguments: *ArgumentsSlice, exception: JSC.C.ExceptionRef) ?Read {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn WriteInt(comptime kind: Int) type {
|
||||
return struct {
|
||||
const This = @This();
|
||||
const Value = Int.native.get(kind);
|
||||
};
|
||||
}
|
||||
pub fn ReadInt(comptime kind: Int) type {
|
||||
return struct {
|
||||
const This = @This();
|
||||
const Value = Int.native.get(kind);
|
||||
};
|
||||
}
|
||||
};
|
||||
pub fn compare(this: *Buffer, globalThis: *JSC.JSGlobalObject, args: Arguments.Compare) JSC.JSValue {
|
||||
_ = this;
|
||||
_ = globalThis;
|
||||
_ = args;
|
||||
return JSC.JSValue.jsUndefined();
|
||||
}
|
||||
pub fn copy(this: *Buffer, globalThis: *JSC.JSGlobalObject, args: Arguments.Copy) JSC.JSValue {
|
||||
_ = this;
|
||||
_ = globalThis;
|
||||
_ = args;
|
||||
return JSC.JSValue.jsUndefined();
|
||||
}
|
||||
pub fn equals(this: *Buffer, globalThis: *JSC.JSGlobalObject, args: Arguments.Equals) JSC.JSValue {
|
||||
_ = this;
|
||||
_ = globalThis;
|
||||
_ = args;
|
||||
return JSC.JSValue.jsUndefined();
|
||||
}
|
||||
pub fn fill(this: *Buffer, globalThis: *JSC.JSGlobalObject, args: Arguments.Fill) JSC.JSValue {
|
||||
_ = this;
|
||||
_ = globalThis;
|
||||
_ = args;
|
||||
return JSC.JSValue.jsUndefined();
|
||||
}
|
||||
pub fn includes(this: *Buffer, globalThis: *JSC.JSGlobalObject, args: Arguments.Includes) JSC.JSValue {
|
||||
_ = this;
|
||||
_ = globalThis;
|
||||
_ = args;
|
||||
return JSC.JSValue.jsUndefined();
|
||||
}
|
||||
pub fn indexOf(this: *Buffer, globalThis: *JSC.JSGlobalObject, args: Arguments.IndexOf) JSC.JSValue {
|
||||
_ = this;
|
||||
_ = globalThis;
|
||||
_ = args;
|
||||
return JSC.JSValue.jsUndefined();
|
||||
}
|
||||
pub fn lastIndexOf(this: *Buffer, globalThis: *JSC.JSGlobalObject, args: Arguments.LastIndexOf) JSC.JSValue {
|
||||
_ = this;
|
||||
_ = globalThis;
|
||||
_ = args;
|
||||
return JSC.JSValue.jsUndefined();
|
||||
}
|
||||
pub fn swap16(this: *Buffer, globalThis: *JSC.JSGlobalObject, args: Arguments.Swap16) JSC.JSValue {
|
||||
_ = this;
|
||||
_ = globalThis;
|
||||
_ = args;
|
||||
return JSC.JSValue.jsUndefined();
|
||||
}
|
||||
pub fn swap32(this: *Buffer, globalThis: *JSC.JSGlobalObject, args: Arguments.Swap32) JSC.JSValue {
|
||||
_ = this;
|
||||
_ = globalThis;
|
||||
_ = args;
|
||||
return JSC.JSValue.jsUndefined();
|
||||
}
|
||||
pub fn swap64(this: *Buffer, globalThis: *JSC.JSGlobalObject, args: Arguments.Swap64) JSC.JSValue {
|
||||
_ = this;
|
||||
_ = globalThis;
|
||||
_ = args;
|
||||
return JSC.JSValue.jsUndefined();
|
||||
}
|
||||
pub fn write(this: *Buffer, globalThis: *JSC.JSGlobalObject, args: Arguments.Write) JSC.JSValue {
|
||||
_ = this;
|
||||
_ = globalThis;
|
||||
_ = args;
|
||||
return JSC.JSValue.jsUndefined();
|
||||
}
|
||||
pub fn read(this: *Buffer, globalThis: *JSC.JSGlobalObject, args: Arguments.Read) JSC.JSValue {
|
||||
_ = this;
|
||||
_ = globalThis;
|
||||
_ = args;
|
||||
return JSC.JSValue.jsUndefined();
|
||||
}
|
||||
|
||||
fn writeIntAny(this: *Buffer, comptime kind: Int, args: Arguments.WriteInt(kind)) JSC.JSValue {}
|
||||
fn readIntAny(this: *Buffer, comptime kind: Int, args: Arguments.ReadInt(kind)) JSC.JSValue {}
|
||||
|
||||
pub const Class = JSC.NewClass(
|
||||
void,
|
||||
.{ .name = "Buffer" },
|
||||
.{
|
||||
.compare = .{
|
||||
.name = "compare",
|
||||
.rfn = wrap(BufferPrototype.compare),
|
||||
},
|
||||
.copy = .{
|
||||
.name = "copy",
|
||||
.rfn = wrap(BufferPrototype.copy),
|
||||
},
|
||||
.equals = .{
|
||||
.name = "equals",
|
||||
.rfn = wrap(BufferPrototype.equals),
|
||||
},
|
||||
.fill = .{
|
||||
.name = "fill",
|
||||
.rfn = wrap(BufferPrototype.fill),
|
||||
},
|
||||
.includes = .{
|
||||
.name = "includes",
|
||||
.rfn = wrap(BufferPrototype.includes),
|
||||
},
|
||||
.indexOf = .{
|
||||
.name = "indexOf",
|
||||
.rfn = wrap(BufferPrototype.indexOf),
|
||||
},
|
||||
.lastIndexOf = .{
|
||||
.name = "lastIndexOf",
|
||||
.rfn = wrap(BufferPrototype.lastIndexOf),
|
||||
},
|
||||
.swap16 = .{
|
||||
.name = "swap16",
|
||||
.rfn = wrap(BufferPrototype.swap16),
|
||||
},
|
||||
.swap32 = .{
|
||||
.name = "swap32",
|
||||
.rfn = wrap(BufferPrototype.swap32),
|
||||
},
|
||||
.swap64 = .{
|
||||
.name = "swap64",
|
||||
.rfn = wrap(BufferPrototype.swap64),
|
||||
},
|
||||
.write = .{
|
||||
.name = "write",
|
||||
.rfn = wrap(BufferPrototype.write),
|
||||
},
|
||||
.read = .{
|
||||
.name = "read",
|
||||
.rfn = wrap(BufferPrototype.read),
|
||||
},
|
||||
|
||||
// -- Write --
|
||||
.writeBigInt64BE = .{
|
||||
.name = "writeBigInt64BE",
|
||||
.rfn = writeWrap(Int.BigInt64BE),
|
||||
},
|
||||
.writeBigInt64LE = .{
|
||||
.name = "writeBigInt64LE",
|
||||
.rfn = writeWrap(Int.BigInt64LE),
|
||||
},
|
||||
.writeBigUInt64BE = .{
|
||||
.name = "writeBigUInt64BE",
|
||||
.rfn = writeWrap(Int.BigUInt64BE),
|
||||
},
|
||||
.writeBigUInt64LE = .{
|
||||
.name = "writeBigUInt64LE",
|
||||
.rfn = writeWrap(Int.BigUInt64LE),
|
||||
},
|
||||
.writeDoubleBE = .{
|
||||
.name = "writeDoubleBE",
|
||||
.rfn = writeWrap(Int.DoubleBE),
|
||||
},
|
||||
.writeDoubleLE = .{
|
||||
.name = "writeDoubleLE",
|
||||
.rfn = writeWrap(Int.DoubleLE),
|
||||
},
|
||||
.writeFloatBE = .{
|
||||
.name = "writeFloatBE",
|
||||
.rfn = writeWrap(Int.FloatBE),
|
||||
},
|
||||
.writeFloatLE = .{
|
||||
.name = "writeFloatLE",
|
||||
.rfn = writeWrap(Int.FloatLE),
|
||||
},
|
||||
.writeInt8 = .{
|
||||
.name = "writeInt8",
|
||||
.rfn = writeWrap(Int.Int8),
|
||||
},
|
||||
.writeInt16BE = .{
|
||||
.name = "writeInt16BE",
|
||||
.rfn = writeWrap(Int.Int16BE),
|
||||
},
|
||||
.writeInt16LE = .{
|
||||
.name = "writeInt16LE",
|
||||
.rfn = writeWrap(Int.Int16LE),
|
||||
},
|
||||
.writeInt32BE = .{
|
||||
.name = "writeInt32BE",
|
||||
.rfn = writeWrap(Int.Int32BE),
|
||||
},
|
||||
.writeInt32LE = .{
|
||||
.name = "writeInt32LE",
|
||||
.rfn = writeWrap(Int.Int32LE),
|
||||
},
|
||||
.writeIntBE = .{
|
||||
.name = "writeIntBE",
|
||||
.rfn = writeWrap(Int.IntBE),
|
||||
},
|
||||
.writeIntLE = .{
|
||||
.name = "writeIntLE",
|
||||
.rfn = writeWrap(Int.IntLE),
|
||||
},
|
||||
.writeUInt8 = .{
|
||||
.name = "writeUInt8",
|
||||
.rfn = writeWrap(Int.UInt8),
|
||||
},
|
||||
.writeUInt16BE = .{
|
||||
.name = "writeUInt16BE",
|
||||
.rfn = writeWrap(Int.UInt16BE),
|
||||
},
|
||||
.writeUInt16LE = .{
|
||||
.name = "writeUInt16LE",
|
||||
.rfn = writeWrap(Int.UInt16LE),
|
||||
},
|
||||
.writeUInt32BE = .{
|
||||
.name = "writeUInt32BE",
|
||||
.rfn = writeWrap(Int.UInt32BE),
|
||||
},
|
||||
.writeUInt32LE = .{
|
||||
.name = "writeUInt32LE",
|
||||
.rfn = writeWrap(Int.UInt32LE),
|
||||
},
|
||||
.writeUIntBE = .{
|
||||
.name = "writeUIntBE",
|
||||
.rfn = writeWrap(Int.UIntBE),
|
||||
},
|
||||
.writeUIntLE = .{
|
||||
.name = "writeUIntLE",
|
||||
.rfn = writeWrap(Int.UIntLE),
|
||||
},
|
||||
|
||||
// -- Read --
|
||||
.readBigInt64BE = .{
|
||||
.name = "readBigInt64BE",
|
||||
.rfn = readWrap(Int.BigInt64BE),
|
||||
},
|
||||
.readBigInt64LE = .{
|
||||
.name = "readBigInt64LE",
|
||||
.rfn = readWrap(Int.BigInt64LE),
|
||||
},
|
||||
.readBigUInt64BE = .{
|
||||
.name = "readBigUInt64BE",
|
||||
.rfn = readWrap(Int.BigUInt64BE),
|
||||
},
|
||||
.readBigUInt64LE = .{
|
||||
.name = "readBigUInt64LE",
|
||||
.rfn = readWrap(Int.BigUInt64LE),
|
||||
},
|
||||
.readDoubleBE = .{
|
||||
.name = "readDoubleBE",
|
||||
.rfn = readWrap(Int.DoubleBE),
|
||||
},
|
||||
.readDoubleLE = .{
|
||||
.name = "readDoubleLE",
|
||||
.rfn = readWrap(Int.DoubleLE),
|
||||
},
|
||||
.readFloatBE = .{
|
||||
.name = "readFloatBE",
|
||||
.rfn = readWrap(Int.FloatBE),
|
||||
},
|
||||
.readFloatLE = .{
|
||||
.name = "readFloatLE",
|
||||
.rfn = readWrap(Int.FloatLE),
|
||||
},
|
||||
.readInt8 = .{
|
||||
.name = "readInt8",
|
||||
.rfn = readWrap(Int.Int8),
|
||||
},
|
||||
.readInt16BE = .{
|
||||
.name = "readInt16BE",
|
||||
.rfn = readWrap(Int.Int16BE),
|
||||
},
|
||||
.readInt16LE = .{
|
||||
.name = "readInt16LE",
|
||||
.rfn = readWrap(Int.Int16LE),
|
||||
},
|
||||
.readInt32BE = .{
|
||||
.name = "readInt32BE",
|
||||
.rfn = readWrap(Int.Int32BE),
|
||||
},
|
||||
.readInt32LE = .{
|
||||
.name = "readInt32LE",
|
||||
.rfn = readWrap(Int.Int32LE),
|
||||
},
|
||||
.readIntBE = .{
|
||||
.name = "readIntBE",
|
||||
.rfn = readWrap(Int.IntBE),
|
||||
},
|
||||
.readIntLE = .{
|
||||
.name = "readIntLE",
|
||||
.rfn = readWrap(Int.IntLE),
|
||||
},
|
||||
.readUInt8 = .{
|
||||
.name = "readUInt8",
|
||||
.rfn = readWrap(Int.UInt8),
|
||||
},
|
||||
.readUInt16BE = .{
|
||||
.name = "readUInt16BE",
|
||||
.rfn = readWrap(Int.UInt16BE),
|
||||
},
|
||||
.readUInt16LE = .{
|
||||
.name = "readUInt16LE",
|
||||
.rfn = readWrap(Int.UInt16LE),
|
||||
},
|
||||
.readUInt32BE = .{
|
||||
.name = "readUInt32BE",
|
||||
.rfn = readWrap(Int.UInt32BE),
|
||||
},
|
||||
.readUInt32LE = .{
|
||||
.name = "readUInt32LE",
|
||||
.rfn = readWrap(Int.UInt32LE),
|
||||
},
|
||||
.readUIntBE = .{
|
||||
.name = "readUIntBE",
|
||||
.rfn = readWrap(Int.UIntBE),
|
||||
},
|
||||
.readUIntLE = .{
|
||||
.name = "readUIntLE",
|
||||
.rfn = readWrap(Int.UIntLE),
|
||||
},
|
||||
},
|
||||
.{},
|
||||
);
|
||||
};
|
||||
|
||||
const Int = enum {
|
||||
BigInt64BE,
|
||||
BigInt64LE,
|
||||
BigUInt64BE,
|
||||
BigUInt64LE,
|
||||
DoubleBE,
|
||||
DoubleLE,
|
||||
FloatBE,
|
||||
FloatLE,
|
||||
Int8,
|
||||
Int16BE,
|
||||
Int16LE,
|
||||
Int32BE,
|
||||
Int32LE,
|
||||
IntBE,
|
||||
IntLE,
|
||||
UInt8,
|
||||
UInt16BE,
|
||||
UInt16LE,
|
||||
UInt32BE,
|
||||
UInt32LE,
|
||||
UIntBE,
|
||||
UIntLE,
|
||||
|
||||
const NativeMap = std.EnumArray(Int, type);
|
||||
pub const native: NativeMap = brk: {
|
||||
var map = NativeMap.initUndefined();
|
||||
map.set(.BigInt64BE, i64);
|
||||
map.set(.BigInt64LE, i64);
|
||||
map.set(.BigUInt64BE, u64);
|
||||
map.set(.BigUInt64LE, u64);
|
||||
map.set(.DoubleBE, f64);
|
||||
map.set(.DoubleLE, f64);
|
||||
map.set(.FloatBE, f32);
|
||||
map.set(.FloatLE, f32);
|
||||
map.set(.Int8, i8);
|
||||
map.set(.Int16BE, i16);
|
||||
map.set(.Int16LE, i16);
|
||||
map.set(.Int32BE, u32);
|
||||
map.set(.Int32LE, u32);
|
||||
map.set(.IntBE, i32);
|
||||
map.set(.IntLE, i32);
|
||||
map.set(.UInt8, u8);
|
||||
map.set(.UInt16BE, u16);
|
||||
map.set(.UInt16LE, u16);
|
||||
map.set(.UInt32BE, u32);
|
||||
map.set(.UInt32LE, u32);
|
||||
map.set(.UIntBE, u32);
|
||||
map.set(.UIntLE, u32);
|
||||
break :brk map;
|
||||
};
|
||||
};
|
||||
347
src/javascript/jsc/node/dir_iterator.zig
Normal file
347
src/javascript/jsc/node/dir_iterator.zig
Normal file
@@ -0,0 +1,347 @@
|
||||
// This is copied from std.fs.Dir.Iterator
|
||||
// The differences are:
|
||||
// - it returns errors in the expected format
|
||||
// - doesn't mark BADF as unreachable
|
||||
// - It uses PathString instead of []const u8
|
||||
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std");
|
||||
const os = std.os;
|
||||
|
||||
const Dir = std.fs.Dir;
|
||||
const JSC = @import("../../../jsc.zig");
|
||||
const PathString = JSC.PathString;
|
||||
|
||||
const IteratorError = error{ AccessDenied, SystemResources } || os.UnexpectedError;
|
||||
const mem = std.mem;
|
||||
const strings = @import("../../../global.zig").strings;
|
||||
const Maybe = JSC.Node.Maybe;
|
||||
const File = std.fs.File;
|
||||
const Result = Maybe(?Entry);
|
||||
|
||||
const Entry = JSC.Node.DirEnt;
|
||||
|
||||
pub const Iterator = switch (builtin.os.tag) {
|
||||
.macos, .ios, .freebsd, .netbsd, .dragonfly, .openbsd, .solaris => struct {
|
||||
dir: Dir,
|
||||
seek: i64,
|
||||
buf: [8192]u8, // TODO align(@alignOf(os.system.dirent)),
|
||||
index: usize,
|
||||
end_index: usize,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub const Error = IteratorError;
|
||||
|
||||
/// Memory such as file names referenced in this returned entry becomes invalid
|
||||
/// with subsequent calls to `next`, as well as when this `Dir` is deinitialized.
|
||||
const next = switch (builtin.os.tag) {
|
||||
.macos, .ios => nextDarwin,
|
||||
// .freebsd, .netbsd, .dragonfly, .openbsd => nextBsd,
|
||||
// .solaris => nextSolaris,
|
||||
else => @compileError("unimplemented"),
|
||||
};
|
||||
|
||||
fn nextDarwin(self: *Self) Result {
|
||||
start_over: while (true) {
|
||||
if (self.index >= self.end_index) {
|
||||
const rc = os.system.__getdirentries64(
|
||||
self.dir.fd,
|
||||
&self.buf,
|
||||
self.buf.len,
|
||||
&self.seek,
|
||||
);
|
||||
|
||||
if (rc < 1) {
|
||||
if (rc == 0) return Result{ .result = null };
|
||||
if (Result.errnoSys(rc, .getdirentries64)) |err| {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
self.index = 0;
|
||||
self.end_index = @intCast(usize, rc);
|
||||
}
|
||||
const darwin_entry = @ptrCast(*align(1) os.system.dirent, &self.buf[self.index]);
|
||||
const next_index = self.index + darwin_entry.reclen();
|
||||
self.index = next_index;
|
||||
|
||||
const name = @ptrCast([*]u8, &darwin_entry.d_name)[0..darwin_entry.d_namlen];
|
||||
|
||||
if (strings.eqlComptime(name, ".") or strings.eqlComptime(name, "..") or (darwin_entry.d_ino == 0)) {
|
||||
continue :start_over;
|
||||
}
|
||||
|
||||
const entry_kind = switch (darwin_entry.d_type) {
|
||||
os.DT.BLK => Entry.Kind.BlockDevice,
|
||||
os.DT.CHR => Entry.Kind.CharacterDevice,
|
||||
os.DT.DIR => Entry.Kind.Directory,
|
||||
os.DT.FIFO => Entry.Kind.NamedPipe,
|
||||
os.DT.LNK => Entry.Kind.SymLink,
|
||||
os.DT.REG => Entry.Kind.File,
|
||||
os.DT.SOCK => Entry.Kind.UnixDomainSocket,
|
||||
os.DT.WHT => Entry.Kind.Whiteout,
|
||||
else => Entry.Kind.Unknown,
|
||||
};
|
||||
return .{
|
||||
.result = Entry{
|
||||
.name = PathString.init(name),
|
||||
.kind = entry_kind,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
.linux => struct {
|
||||
dir: Dir,
|
||||
// The if guard is solely there to prevent compile errors from missing `linux.dirent64`
|
||||
// definition when compiling for other OSes. It doesn't do anything when compiling for Linux.
|
||||
buf: [8192]u8 align(if (builtin.os.tag != .linux) 1 else @alignOf(linux.dirent64)),
|
||||
index: usize,
|
||||
end_index: usize,
|
||||
|
||||
const Self = @This();
|
||||
const linux = os.linux;
|
||||
|
||||
pub const Error = IteratorError;
|
||||
|
||||
/// Memory such as file names referenced in this returned entry becomes invalid
|
||||
/// with subsequent calls to `next`, as well as when this `Dir` is deinitialized.
|
||||
pub fn next(self: *Self) Result {
|
||||
start_over: while (true) {
|
||||
if (self.index >= self.end_index) {
|
||||
const rc = linux.getdents64(self.dir.fd, &self.buf, self.buf.len);
|
||||
if (Result.errnoSys(rc, .getdents64)) |err| return err;
|
||||
if (rc == 0) return .{ .result = null };
|
||||
self.index = 0;
|
||||
self.end_index = rc;
|
||||
}
|
||||
const linux_entry = @ptrCast(*align(1) linux.dirent64, &self.buf[self.index]);
|
||||
const next_index = self.index + linux_entry.reclen();
|
||||
self.index = next_index;
|
||||
|
||||
const name = mem.sliceTo(@ptrCast([*:0]u8, &linux_entry.d_name), 0);
|
||||
|
||||
// skip . and .. entries
|
||||
if (strings.eqlComptime(name, ".") or strings.eqlComptime(name, "..")) {
|
||||
continue :start_over;
|
||||
}
|
||||
|
||||
const entry_kind = switch (linux_entry.d_type) {
|
||||
linux.DT.BLK => Entry.Kind.BlockDevice,
|
||||
linux.DT.CHR => Entry.Kind.CharacterDevice,
|
||||
linux.DT.DIR => Entry.Kind.Directory,
|
||||
linux.DT.FIFO => Entry.Kind.NamedPipe,
|
||||
linux.DT.LNK => Entry.Kind.SymLink,
|
||||
linux.DT.REG => Entry.Kind.File,
|
||||
linux.DT.SOCK => Entry.Kind.UnixDomainSocket,
|
||||
else => Entry.Kind.Unknown,
|
||||
};
|
||||
return .{
|
||||
.result = Entry{
|
||||
.name = PathString.init(name),
|
||||
.kind = entry_kind,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
.windows => struct {
|
||||
dir: Dir,
|
||||
buf: [8192]u8 align(@alignOf(os.windows.FILE_BOTH_DIR_INFORMATION)),
|
||||
index: usize,
|
||||
end_index: usize,
|
||||
first: bool,
|
||||
name_data: [256]u8,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub const Error = IteratorError;
|
||||
|
||||
/// Memory such as file names referenced in this returned entry becomes invalid
|
||||
/// with subsequent calls to `next`, as well as when this `Dir` is deinitialized.
|
||||
pub fn next(self: *Self) Result {
|
||||
while (true) {
|
||||
const w = os.windows;
|
||||
if (self.index >= self.end_index) {
|
||||
var io: w.IO_STATUS_BLOCK = undefined;
|
||||
const rc = w.ntdll.NtQueryDirectoryFile(
|
||||
self.dir.fd,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
&io,
|
||||
&self.buf,
|
||||
self.buf.len,
|
||||
.FileBothDirectoryInformation,
|
||||
w.FALSE,
|
||||
null,
|
||||
if (self.first) @as(w.BOOLEAN, w.TRUE) else @as(w.BOOLEAN, w.FALSE),
|
||||
);
|
||||
self.first = false;
|
||||
if (io.Information == 0) return .{ .result = null };
|
||||
self.index = 0;
|
||||
self.end_index = io.Information;
|
||||
switch (rc) {
|
||||
.SUCCESS => {},
|
||||
.ACCESS_DENIED => return error.AccessDenied, // Double-check that the Dir was opened with iteration ability
|
||||
|
||||
else => return w.unexpectedStatus(rc),
|
||||
}
|
||||
}
|
||||
|
||||
const aligned_ptr = @alignCast(@alignOf(w.FILE_BOTH_DIR_INFORMATION), &self.buf[self.index]);
|
||||
const dir_info = @ptrCast(*w.FILE_BOTH_DIR_INFORMATION, aligned_ptr);
|
||||
if (dir_info.NextEntryOffset != 0) {
|
||||
self.index += dir_info.NextEntryOffset;
|
||||
} else {
|
||||
self.index = self.buf.len;
|
||||
}
|
||||
|
||||
const name_utf16le = @ptrCast([*]u16, &dir_info.FileName)[0 .. dir_info.FileNameLength / 2];
|
||||
|
||||
if (mem.eql(u16, name_utf16le, &[_]u16{'.'}) or mem.eql(u16, name_utf16le, &[_]u16{ '.', '.' }))
|
||||
continue;
|
||||
// Trust that Windows gives us valid UTF-16LE
|
||||
const name_utf8_len = std.unicode.utf16leToUtf8(self.name_data[0..], name_utf16le) catch unreachable;
|
||||
const name_utf8 = self.name_data[0..name_utf8_len];
|
||||
const kind = blk: {
|
||||
const attrs = dir_info.FileAttributes;
|
||||
if (attrs & w.FILE_ATTRIBUTE_DIRECTORY != 0) break :blk Entry.Kind.Directory;
|
||||
if (attrs & w.FILE_ATTRIBUTE_REPARSE_POINT != 0) break :blk Entry.Kind.SymLink;
|
||||
break :blk Entry.Kind.File;
|
||||
};
|
||||
return .{
|
||||
.result = Entry{
|
||||
.name = PathString.init(name_utf8),
|
||||
.kind = kind,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
.wasi => struct {
|
||||
dir: Dir,
|
||||
buf: [8192]u8, // TODO align(@alignOf(os.wasi.dirent_t)),
|
||||
cookie: u64,
|
||||
index: usize,
|
||||
end_index: usize,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub const Error = IteratorError;
|
||||
|
||||
/// Memory such as file names referenced in this returned entry becomes invalid
|
||||
/// with subsequent calls to `next`, as well as when this `Dir` is deinitialized.
|
||||
pub fn next(self: *Self) Result {
|
||||
// We intentinally use fd_readdir even when linked with libc,
|
||||
// since its implementation is exactly the same as below,
|
||||
// and we avoid the code complexity here.
|
||||
const w = os.wasi;
|
||||
start_over: while (true) {
|
||||
if (self.index >= self.end_index) {
|
||||
var bufused: usize = undefined;
|
||||
switch (w.fd_readdir(self.dir.fd, &self.buf, self.buf.len, self.cookie, &bufused)) {
|
||||
.SUCCESS => {},
|
||||
.BADF => unreachable, // Dir is invalid or was opened without iteration ability
|
||||
.FAULT => unreachable,
|
||||
.NOTDIR => unreachable,
|
||||
.INVAL => unreachable,
|
||||
.NOTCAPABLE => return error.AccessDenied,
|
||||
else => |err| return os.unexpectedErrno(err),
|
||||
}
|
||||
if (bufused == 0) return null;
|
||||
self.index = 0;
|
||||
self.end_index = bufused;
|
||||
}
|
||||
const entry = @ptrCast(*align(1) w.dirent_t, &self.buf[self.index]);
|
||||
const entry_size = @sizeOf(w.dirent_t);
|
||||
const name_index = self.index + entry_size;
|
||||
const name = mem.span(self.buf[name_index .. name_index + entry.d_namlen]);
|
||||
|
||||
const next_index = name_index + entry.d_namlen;
|
||||
self.index = next_index;
|
||||
self.cookie = entry.d_next;
|
||||
|
||||
// skip . and .. entries
|
||||
if (strings.eqlComptime(name, ".") or strings.eqlComptime(name, "..")) {
|
||||
continue :start_over;
|
||||
}
|
||||
|
||||
const entry_kind = switch (entry.d_type) {
|
||||
.BLOCK_DEVICE => Entry.Kind.BlockDevice,
|
||||
.CHARACTER_DEVICE => Entry.Kind.CharacterDevice,
|
||||
.DIRECTORY => Entry.Kind.Directory,
|
||||
.SYMBOLIC_LINK => Entry.Kind.SymLink,
|
||||
.REGULAR_FILE => Entry.Kind.File,
|
||||
.SOCKET_STREAM, .SOCKET_DGRAM => Entry.Kind.UnixDomainSocket,
|
||||
else => Entry.Kind.Unknown,
|
||||
};
|
||||
return Entry{
|
||||
.name = name,
|
||||
.kind = entry_kind,
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
else => @compileError("unimplemented"),
|
||||
};
|
||||
|
||||
const WrappedIterator = struct {
|
||||
iter: Iterator,
|
||||
const Self = @This();
|
||||
|
||||
pub const Error = IteratorError;
|
||||
|
||||
pub inline fn next(self: *Self) Result {
|
||||
return self.iter.next();
|
||||
}
|
||||
};
|
||||
|
||||
pub fn iterate(self: Dir) WrappedIterator {
|
||||
return WrappedIterator{
|
||||
.iter = _iterate(self),
|
||||
};
|
||||
}
|
||||
|
||||
fn _iterate(self: Dir) Iterator {
|
||||
switch (builtin.os.tag) {
|
||||
.macos,
|
||||
.ios,
|
||||
.freebsd,
|
||||
.netbsd,
|
||||
.dragonfly,
|
||||
.openbsd,
|
||||
.solaris,
|
||||
=> return Iterator{
|
||||
.dir = self,
|
||||
.seek = 0,
|
||||
.index = 0,
|
||||
.end_index = 0,
|
||||
.buf = undefined,
|
||||
},
|
||||
.linux, .haiku => return Iterator{
|
||||
.dir = self,
|
||||
.index = 0,
|
||||
.end_index = 0,
|
||||
.buf = undefined,
|
||||
},
|
||||
.windows => return Iterator{
|
||||
.dir = self,
|
||||
.index = 0,
|
||||
.end_index = 0,
|
||||
.first = true,
|
||||
.buf = undefined,
|
||||
.name_data = undefined,
|
||||
},
|
||||
.wasi => return Iterator{
|
||||
.dir = self,
|
||||
.cookie = os.wasi.DIRCOOKIE_START,
|
||||
.index = 0,
|
||||
.end_index = 0,
|
||||
.buf = undefined,
|
||||
},
|
||||
else => @compileError("unimplemented"),
|
||||
}
|
||||
}
|
||||
3726
src/javascript/jsc/node/node_fs.zig
Normal file
3726
src/javascript/jsc/node/node_fs.zig
Normal file
File diff suppressed because it is too large
Load Diff
429
src/javascript/jsc/node/node_fs_binding.zig
Normal file
429
src/javascript/jsc/node/node_fs_binding.zig
Normal file
@@ -0,0 +1,429 @@
|
||||
const JSC = @import("../../../jsc.zig");
|
||||
const std = @import("std");
|
||||
const Flavor = JSC.Node.Flavor;
|
||||
const ArgumentsSlice = JSC.Node.ArgumentsSlice;
|
||||
const system = std.os.system;
|
||||
const Maybe = JSC.Node.Maybe;
|
||||
const Encoding = JSC.Node.Encoding;
|
||||
const FeatureFlags = @import("../../../global.zig").FeatureFlags;
|
||||
const Args = JSC.Node.NodeFS.Arguments;
|
||||
|
||||
const NodeFSFunction = fn (
|
||||
*JSC.Node.NodeFS,
|
||||
JSC.C.JSContextRef,
|
||||
JSC.C.JSObjectRef,
|
||||
JSC.C.JSObjectRef,
|
||||
[]const JSC.C.JSValueRef,
|
||||
JSC.C.ExceptionRef,
|
||||
) JSC.C.JSValueRef;
|
||||
|
||||
pub const toJSTrait = std.meta.trait.hasFn("toJS");
|
||||
pub const fromJSTrait = std.meta.trait.hasFn("fromJS");
|
||||
const NodeFSFunctionEnum = JSC.Node.DeclEnum(JSC.Node.NodeFS);
|
||||
|
||||
fn callSync(comptime FunctionEnum: NodeFSFunctionEnum) NodeFSFunction {
|
||||
const Function = @field(JSC.Node.NodeFS, @tagName(FunctionEnum));
|
||||
const FunctionType = @TypeOf(Function);
|
||||
|
||||
const function: std.builtin.TypeInfo.Fn = comptime @typeInfo(FunctionType).Fn;
|
||||
comptime if (function.args.len != 3) @compileError("Expected 3 arguments");
|
||||
const Arguments = comptime function.args[1].arg_type.?;
|
||||
const FormattedName = comptime [1]u8{std.ascii.toUpper(@tagName(FunctionEnum)[0])} ++ @tagName(FunctionEnum)[1..];
|
||||
const Result = comptime JSC.Node.Maybe(@field(JSC.Node.NodeFS.ReturnType, FormattedName));
|
||||
|
||||
const NodeBindingClosure = struct {
|
||||
pub fn bind(
|
||||
this: *JSC.Node.NodeFS,
|
||||
ctx: JSC.C.JSContextRef,
|
||||
_: JSC.C.JSObjectRef,
|
||||
_: JSC.C.JSObjectRef,
|
||||
arguments: []const JSC.C.JSValueRef,
|
||||
exception: JSC.C.ExceptionRef,
|
||||
) JSC.C.JSValueRef {
|
||||
var slice = ArgumentsSlice.init(@ptrCast([*]const JSC.JSValue, arguments.ptr)[0..arguments.len]);
|
||||
|
||||
defer {
|
||||
// TODO: fix this
|
||||
for (arguments) |arg| {
|
||||
JSC.C.JSValueUnprotect(ctx, arg);
|
||||
}
|
||||
slice.arena.deinit();
|
||||
}
|
||||
|
||||
const args = if (comptime Arguments != void)
|
||||
(Arguments.fromJS(ctx, &slice, exception) orelse return null)
|
||||
else
|
||||
Arguments{};
|
||||
if (exception.* != null) return null;
|
||||
|
||||
const result: Result = Function(
|
||||
this,
|
||||
args,
|
||||
comptime Flavor.sync,
|
||||
);
|
||||
return switch (result) {
|
||||
.err => |err| brk: {
|
||||
exception.* = err.toJS(ctx);
|
||||
break :brk null;
|
||||
},
|
||||
.result => |res| if (comptime Result.ReturnType != void)
|
||||
JSC.To.JS.withType(Result.ReturnType, res, ctx, exception)
|
||||
else
|
||||
JSC.C.JSValueMakeUndefined(ctx),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
return NodeBindingClosure.bind;
|
||||
}
|
||||
|
||||
fn call(comptime Function: NodeFSFunctionEnum) NodeFSFunction {
|
||||
// const FunctionType = @TypeOf(Function);
|
||||
_ = Function;
|
||||
|
||||
// const function: std.builtin.TypeInfo.Fn = comptime @typeInfo(FunctionType).Fn;
|
||||
// comptime if (function.args.len != 3) @compileError("Expected 3 arguments");
|
||||
// const Arguments = comptime function.args[2].arg_type orelse @compileError(std.fmt.comptimePrint("Function {s} expected to have an arg type at [2]", .{@typeName(FunctionType)}));
|
||||
// const Result = comptime function.return_type.?;
|
||||
// comptime if (Arguments != void and !fromJSTrait(Arguments)) @compileError(std.fmt.comptimePrint("{s} is missing fromJS()", .{@typeName(Arguments)}));
|
||||
// comptime if (Result != void and !toJSTrait(Result)) @compileError(std.fmt.comptimePrint("{s} is missing toJS()", .{@typeName(Result)}));
|
||||
const NodeBindingClosure = struct {
|
||||
pub fn bind(
|
||||
this: *JSC.Node.NodeFS,
|
||||
ctx: JSC.C.JSContextRef,
|
||||
_: JSC.C.JSObjectRef,
|
||||
_: JSC.C.JSObjectRef,
|
||||
arguments: []const JSC.C.JSValueRef,
|
||||
exception: JSC.C.ExceptionRef,
|
||||
) JSC.C.JSValueRef {
|
||||
_ = this;
|
||||
_ = ctx;
|
||||
_ = arguments;
|
||||
var err = JSC.SystemError{};
|
||||
exception.* = err.toErrorInstance(ctx.ptr()).asObjectRef();
|
||||
return null;
|
||||
// var slice = ArgumentsSlice.init(arguments);
|
||||
|
||||
// defer {
|
||||
// for (arguments.len) |arg| {
|
||||
// JSC.C.JSValueUnprotect(ctx, arg);
|
||||
// }
|
||||
// slice.arena.deinit();
|
||||
// }
|
||||
|
||||
// const args = if (comptime Arguments != void)
|
||||
// Arguments.fromJS(ctx, &slice, exception)
|
||||
// else
|
||||
// Arguments{};
|
||||
// if (exception.* != null) return null;
|
||||
|
||||
// const result: Maybe(Result) = Function(this, comptime Flavor.sync, args);
|
||||
// switch (result) {
|
||||
// .err => |err| {
|
||||
// exception.* = err.toJS(ctx);
|
||||
// return null;
|
||||
// },
|
||||
// .result => |res| {
|
||||
// return switch (comptime Result) {
|
||||
// void => JSC.JSValue.jsUndefined().asRef(),
|
||||
// else => res.toJS(ctx),
|
||||
// };
|
||||
// },
|
||||
// }
|
||||
// unreachable;
|
||||
}
|
||||
};
|
||||
return NodeBindingClosure.bind;
|
||||
}
|
||||
|
||||
pub const NodeFSBindings = JSC.NewClass(
|
||||
JSC.Node.NodeFS,
|
||||
.{ .name = "fs" },
|
||||
|
||||
.{
|
||||
.access = .{
|
||||
.name = "access",
|
||||
.rfn = call(.access),
|
||||
},
|
||||
.appendFile = .{
|
||||
.name = "appendFile",
|
||||
.rfn = call(.appendFile),
|
||||
},
|
||||
.close = .{
|
||||
.name = "close",
|
||||
.rfn = call(.close),
|
||||
},
|
||||
.copyFile = .{
|
||||
.name = "copyFile",
|
||||
.rfn = call(.copyFile),
|
||||
},
|
||||
.exists = .{
|
||||
.name = "exists",
|
||||
.rfn = call(.exists),
|
||||
},
|
||||
.chown = .{
|
||||
.name = "chown",
|
||||
.rfn = call(.chown),
|
||||
},
|
||||
.chmod = .{
|
||||
.name = "chmod",
|
||||
.rfn = call(.chmod),
|
||||
},
|
||||
.fchmod = .{
|
||||
.name = "fchmod",
|
||||
.rfn = call(.fchmod),
|
||||
},
|
||||
.fchown = .{
|
||||
.name = "fchown",
|
||||
.rfn = call(.fchown),
|
||||
},
|
||||
.fstat = .{
|
||||
.name = "fstat",
|
||||
.rfn = call(.fstat),
|
||||
},
|
||||
.fsync = .{
|
||||
.name = "fsync",
|
||||
.rfn = call(.fsync),
|
||||
},
|
||||
.ftruncate = .{
|
||||
.name = "ftruncate",
|
||||
.rfn = call(.ftruncate),
|
||||
},
|
||||
.futimes = .{
|
||||
.name = "futimes",
|
||||
.rfn = call(.futimes),
|
||||
},
|
||||
.lchmod = .{
|
||||
.name = "lchmod",
|
||||
.rfn = call(.lchmod),
|
||||
},
|
||||
.lchown = .{
|
||||
.name = "lchown",
|
||||
.rfn = call(.lchown),
|
||||
},
|
||||
.link = .{
|
||||
.name = "link",
|
||||
.rfn = call(.link),
|
||||
},
|
||||
.lstat = .{
|
||||
.name = "lstat",
|
||||
.rfn = call(.lstat),
|
||||
},
|
||||
.mkdir = .{
|
||||
.name = "mkdir",
|
||||
.rfn = call(.mkdir),
|
||||
},
|
||||
.mkdtemp = .{
|
||||
.name = "mkdtemp",
|
||||
.rfn = call(.mkdtemp),
|
||||
},
|
||||
.open = .{
|
||||
.name = "open",
|
||||
.rfn = call(.open),
|
||||
},
|
||||
.read = .{
|
||||
.name = "read",
|
||||
.rfn = call(.read),
|
||||
},
|
||||
.write = .{
|
||||
.name = "write",
|
||||
.rfn = call(.write),
|
||||
},
|
||||
.readdir = .{
|
||||
.name = "readdir",
|
||||
.rfn = call(.readdir),
|
||||
},
|
||||
.readFile = .{
|
||||
.name = "readFile",
|
||||
.rfn = call(.readFile),
|
||||
},
|
||||
.writeFile = .{
|
||||
.name = "writeFile",
|
||||
.rfn = call(.writeFile),
|
||||
},
|
||||
.readlink = .{
|
||||
.name = "readlink",
|
||||
.rfn = call(.readlink),
|
||||
},
|
||||
.realpath = .{
|
||||
.name = "realpath",
|
||||
.rfn = call(.realpath),
|
||||
},
|
||||
.rename = .{
|
||||
.name = "rename",
|
||||
.rfn = call(.rename),
|
||||
},
|
||||
.stat = .{
|
||||
.name = "stat",
|
||||
.rfn = call(.stat),
|
||||
},
|
||||
.symlink = .{
|
||||
.name = "symlink",
|
||||
.rfn = call(.symlink),
|
||||
},
|
||||
.truncate = .{
|
||||
.name = "truncate",
|
||||
.rfn = call(.truncate),
|
||||
},
|
||||
.unlink = .{
|
||||
.name = "unlink",
|
||||
.rfn = call(.unlink),
|
||||
},
|
||||
.utimes = .{
|
||||
.name = "utimes",
|
||||
.rfn = call(.utimes),
|
||||
},
|
||||
.lutimes = .{
|
||||
.name = "lutimes",
|
||||
.rfn = call(.lutimes),
|
||||
},
|
||||
|
||||
.createReadStream = .{
|
||||
.name = "createReadStream",
|
||||
.rfn = if (FeatureFlags.node_streams) callSync(.createReadStream) else call(.createReadStream),
|
||||
},
|
||||
|
||||
.createWriteStream = .{
|
||||
.name = "createWriteStream",
|
||||
.rfn = if (FeatureFlags.node_streams) callSync(.createWriteStream) else call(.createWriteStream),
|
||||
},
|
||||
|
||||
.accessSync = .{
|
||||
.name = "accessSync",
|
||||
.rfn = callSync(.access),
|
||||
},
|
||||
.appendFileSync = .{
|
||||
.name = "appendFileSync",
|
||||
.rfn = callSync(.appendFile),
|
||||
},
|
||||
.closeSync = .{
|
||||
.name = "closeSync",
|
||||
.rfn = callSync(.close),
|
||||
},
|
||||
.copyFileSync = .{
|
||||
.name = "copyFileSync",
|
||||
.rfn = callSync(.copyFile),
|
||||
},
|
||||
.existsSync = .{
|
||||
.name = "existsSync",
|
||||
.rfn = callSync(.exists),
|
||||
},
|
||||
.chownSync = .{
|
||||
.name = "chownSync",
|
||||
.rfn = callSync(.chown),
|
||||
},
|
||||
.chmodSync = .{
|
||||
.name = "chmodSync",
|
||||
.rfn = callSync(.chmod),
|
||||
},
|
||||
.fchmodSync = .{
|
||||
.name = "fchmodSync",
|
||||
.rfn = callSync(.fchmod),
|
||||
},
|
||||
.fchownSync = .{
|
||||
.name = "fchownSync",
|
||||
.rfn = callSync(.fchown),
|
||||
},
|
||||
.fstatSync = .{
|
||||
.name = "fstatSync",
|
||||
.rfn = callSync(.fstat),
|
||||
},
|
||||
.fsyncSync = .{
|
||||
.name = "fsyncSync",
|
||||
.rfn = callSync(.fsync),
|
||||
},
|
||||
.ftruncateSync = .{
|
||||
.name = "ftruncateSync",
|
||||
.rfn = callSync(.ftruncate),
|
||||
},
|
||||
.futimesSync = .{
|
||||
.name = "futimesSync",
|
||||
.rfn = callSync(.futimes),
|
||||
},
|
||||
.lchmodSync = .{
|
||||
.name = "lchmodSync",
|
||||
.rfn = callSync(.lchmod),
|
||||
},
|
||||
.lchownSync = .{
|
||||
.name = "lchownSync",
|
||||
.rfn = callSync(.lchown),
|
||||
},
|
||||
.linkSync = .{
|
||||
.name = "linkSync",
|
||||
.rfn = callSync(.link),
|
||||
},
|
||||
.lstatSync = .{
|
||||
.name = "lstatSync",
|
||||
.rfn = callSync(.lstat),
|
||||
},
|
||||
.mkdirSync = .{
|
||||
.name = "mkdirSync",
|
||||
.rfn = callSync(.mkdir),
|
||||
},
|
||||
.mkdtempSync = .{
|
||||
.name = "mkdtempSync",
|
||||
.rfn = callSync(.mkdtemp),
|
||||
},
|
||||
.openSync = .{
|
||||
.name = "openSync",
|
||||
.rfn = callSync(.open),
|
||||
},
|
||||
.readSync = .{
|
||||
.name = "readSync",
|
||||
.rfn = callSync(.read),
|
||||
},
|
||||
.writeSync = .{
|
||||
.name = "writeSync",
|
||||
.rfn = callSync(.write),
|
||||
},
|
||||
.readdirSync = .{
|
||||
.name = "readdirSync",
|
||||
.rfn = callSync(.readdir),
|
||||
},
|
||||
.readFileSync = .{
|
||||
.name = "readFileSync",
|
||||
.rfn = callSync(.readFile),
|
||||
},
|
||||
.writeFileSync = .{
|
||||
.name = "writeFileSync",
|
||||
.rfn = callSync(.writeFile),
|
||||
},
|
||||
.readlinkSync = .{
|
||||
.name = "readlinkSync",
|
||||
.rfn = callSync(.readlink),
|
||||
},
|
||||
.realpathSync = .{
|
||||
.name = "realpathSync",
|
||||
.rfn = callSync(.realpath),
|
||||
},
|
||||
.renameSync = .{
|
||||
.name = "renameSync",
|
||||
.rfn = callSync(.rename),
|
||||
},
|
||||
.statSync = .{
|
||||
.name = "statSync",
|
||||
.rfn = callSync(.stat),
|
||||
},
|
||||
.symlinkSync = .{
|
||||
.name = "symlinkSync",
|
||||
.rfn = callSync(.symlink),
|
||||
},
|
||||
.truncateSync = .{
|
||||
.name = "truncateSync",
|
||||
.rfn = callSync(.truncate),
|
||||
},
|
||||
.unlinkSync = .{
|
||||
.name = "unlinkSync",
|
||||
.rfn = callSync(.unlink),
|
||||
},
|
||||
.utimesSync = .{
|
||||
.name = "utimesSync",
|
||||
.rfn = callSync(.utimes),
|
||||
},
|
||||
.lutimesSync = .{
|
||||
.name = "lutimesSync",
|
||||
.rfn = callSync(.lutimes),
|
||||
},
|
||||
},
|
||||
.{},
|
||||
);
|
||||
1097
src/javascript/jsc/node/nodejs_error_code.zig
Normal file
1097
src/javascript/jsc/node/nodejs_error_code.zig
Normal file
File diff suppressed because it is too large
Load Diff
465
src/javascript/jsc/node/syscall.zig
Normal file
465
src/javascript/jsc/node/syscall.zig
Normal file
@@ -0,0 +1,465 @@
|
||||
// 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 darwin = os.darwin;
|
||||
const MAX_PATH_BYTES = std.fs.MAX_PATH_BYTES;
|
||||
const fd_t = std.os.fd_t;
|
||||
const C = @import("../../../global.zig").C;
|
||||
const linux = os.linux;
|
||||
const Maybe = JSC.Node.Maybe;
|
||||
|
||||
pub const system = if (Environment.isLinux) linux else darwin;
|
||||
const libc = std.os.system;
|
||||
|
||||
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,
|
||||
open,
|
||||
pread,
|
||||
pwrite,
|
||||
read,
|
||||
readlink,
|
||||
rename,
|
||||
stat,
|
||||
symlink,
|
||||
unlink,
|
||||
utimes,
|
||||
write,
|
||||
getcwd,
|
||||
chdir,
|
||||
fcopyfile,
|
||||
|
||||
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 fstat_sym = if (builtin.os.tag == .linux and builtin.link_libc)
|
||||
libc.fstat64
|
||||
else
|
||||
libc.fstat;
|
||||
|
||||
const mem = std.mem;
|
||||
|
||||
pub fn getcwd(buf: *[std.fs.MAX_PATH_BYTES]u8) Maybe([]const u8) {
|
||||
const Result = Maybe([]const u8);
|
||||
buf[0] = 0;
|
||||
const rc = std.c.getcwd(buf, std.fs.MAX_PATH_BYTES);
|
||||
return if (rc != null)
|
||||
Result{ .result = std.mem.sliceTo(rc.?[0..std.fs.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 = libc.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(libc.stat(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(C.lstat(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(fstat_sym(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(darwin.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 (darwin.getErrno(darwin.@"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 = libc.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)
|
||||
libc.pread64
|
||||
else
|
||||
libc.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)
|
||||
libc.pwrite64
|
||||
else
|
||||
libc.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);
|
||||
while (true) {
|
||||
const rc = libc.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 readlink(in: [:0]const u8, buf: []u8) Maybe(usize) {
|
||||
while (true) {
|
||||
const rc = libc.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(libc.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(libc.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: c_int) Maybe(void) {
|
||||
if (comptime !Environment.isMac) @compileError("macOS only");
|
||||
|
||||
while (true) {
|
||||
if (Maybe(void).errnoSys(darwin.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(libc.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(darwin.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 => {
|
||||
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"),
|
||||
}
|
||||
}
|
||||
|
||||
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 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 = std.mem.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 sys = 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);
|
||||
sys.code = JSC.ZigString.init(@tagName(system_errno));
|
||||
if (C.SystemErrno.labels.get(system_errno)) |label| {
|
||||
sys.message = JSC.ZigString.init(label);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.path.len > 0) {
|
||||
sys.path = JSC.ZigString.init(this.path);
|
||||
}
|
||||
|
||||
return sys;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
2065
src/javascript/jsc/node/types.zig
Normal file
2065
src/javascript/jsc/node/types.zig
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user