mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
parent
7057bffc14
commit
cd62005f19
@ -286,7 +286,6 @@ set(ZIG_STAGE2_SOURCES
|
|||||||
"${CMAKE_SOURCE_DIR}/lib/std/multi_array_list.zig"
|
"${CMAKE_SOURCE_DIR}/lib/std/multi_array_list.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/lib/std/os.zig"
|
"${CMAKE_SOURCE_DIR}/lib/std/os.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/lib/std/os/linux.zig"
|
"${CMAKE_SOURCE_DIR}/lib/std/os/linux.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/lib/std/os/linux/errno/generic.zig"
|
|
||||||
"${CMAKE_SOURCE_DIR}/lib/std/os/linux/x86_64.zig"
|
"${CMAKE_SOURCE_DIR}/lib/std/os/linux/x86_64.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/lib/std/os/linux.zig"
|
"${CMAKE_SOURCE_DIR}/lib/std/os/linux.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/lib/std/os/linux/IoUring.zig"
|
"${CMAKE_SOURCE_DIR}/lib/std/os/linux/IoUring.zig"
|
||||||
|
|||||||
@ -882,7 +882,7 @@ fn findConfigH(b: *std.Build, config_h_path_option: ?[]const u8) ?[]const u8 {
|
|||||||
return path;
|
return path;
|
||||||
} else |_| {
|
} else |_| {
|
||||||
std.log.err("Could not open provided config.h: \"{s}\"", .{path});
|
std.log.err("Could not open provided config.h: \"{s}\"", .{path});
|
||||||
std.os.exit(1);
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1285,7 +1285,7 @@ const ElfFileHelper = struct {
|
|||||||
for (consolidated.items) |cmd| {
|
for (consolidated.items) |cmd| {
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
.write_data => |data| {
|
.write_data => |data| {
|
||||||
var iovec = [_]std.os.iovec_const{.{ .iov_base = data.data.ptr, .iov_len = data.data.len }};
|
var iovec = [_]std.posix.iovec_const{.{ .iov_base = data.data.ptr, .iov_len = data.data.len }};
|
||||||
try out_file.pwritevAll(&iovec, data.out_offset);
|
try out_file.pwritevAll(&iovec, data.out_offset);
|
||||||
},
|
},
|
||||||
.copy_range => |range| {
|
.copy_range => |range| {
|
||||||
|
|||||||
@ -144,7 +144,7 @@ pub fn main() !void {
|
|||||||
i += 1;
|
i += 1;
|
||||||
if (i == args.len) {
|
if (i == args.len) {
|
||||||
usage();
|
usage();
|
||||||
std.os.exit(1);
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
filter = args[i];
|
filter = args[i];
|
||||||
@ -152,7 +152,7 @@ pub fn main() !void {
|
|||||||
i += 1;
|
i += 1;
|
||||||
if (i == args.len) {
|
if (i == args.len) {
|
||||||
usage();
|
usage();
|
||||||
std.os.exit(1);
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const c = try std.fmt.parseUnsigned(usize, args[i], 10);
|
const c = try std.fmt.parseUnsigned(usize, args[i], 10);
|
||||||
@ -170,7 +170,7 @@ pub fn main() !void {
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
usage();
|
usage();
|
||||||
std.os.exit(1);
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,9 +5,11 @@
|
|||||||
const std = @import("std.zig");
|
const std = @import("std.zig");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
const os = std.os;
|
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const target = builtin.target;
|
const target = builtin.target;
|
||||||
|
const native_os = builtin.os.tag;
|
||||||
|
const posix = std.posix;
|
||||||
|
const windows = std.os.windows;
|
||||||
|
|
||||||
pub const Futex = @import("Thread/Futex.zig");
|
pub const Futex = @import("Thread/Futex.zig");
|
||||||
pub const ResetEvent = @import("Thread/ResetEvent.zig");
|
pub const ResetEvent = @import("Thread/ResetEvent.zig");
|
||||||
@ -18,23 +20,23 @@ pub const RwLock = @import("Thread/RwLock.zig");
|
|||||||
pub const Pool = @import("Thread/Pool.zig");
|
pub const Pool = @import("Thread/Pool.zig");
|
||||||
pub const WaitGroup = @import("Thread/WaitGroup.zig");
|
pub const WaitGroup = @import("Thread/WaitGroup.zig");
|
||||||
|
|
||||||
pub const use_pthreads = target.os.tag != .windows and target.os.tag != .wasi and builtin.link_libc;
|
pub const use_pthreads = native_os != .windows and native_os != .wasi and builtin.link_libc;
|
||||||
|
|
||||||
const Thread = @This();
|
const Thread = @This();
|
||||||
const Impl = if (target.os.tag == .windows)
|
const Impl = if (native_os == .windows)
|
||||||
WindowsThreadImpl
|
WindowsThreadImpl
|
||||||
else if (use_pthreads)
|
else if (use_pthreads)
|
||||||
PosixThreadImpl
|
PosixThreadImpl
|
||||||
else if (target.os.tag == .linux)
|
else if (native_os == .linux)
|
||||||
LinuxThreadImpl
|
LinuxThreadImpl
|
||||||
else if (target.os.tag == .wasi)
|
else if (native_os == .wasi)
|
||||||
WasiThreadImpl
|
WasiThreadImpl
|
||||||
else
|
else
|
||||||
UnsupportedImpl;
|
UnsupportedImpl;
|
||||||
|
|
||||||
impl: Impl,
|
impl: Impl,
|
||||||
|
|
||||||
pub const max_name_len = switch (target.os.tag) {
|
pub const max_name_len = switch (native_os) {
|
||||||
.linux => 15,
|
.linux => 15,
|
||||||
.windows => 31,
|
.windows => 31,
|
||||||
.macos, .ios, .watchos, .tvos => 63,
|
.macos, .ios, .watchos, .tvos => 63,
|
||||||
@ -50,7 +52,7 @@ pub const SetNameError = error{
|
|||||||
NameTooLong,
|
NameTooLong,
|
||||||
Unsupported,
|
Unsupported,
|
||||||
Unexpected,
|
Unexpected,
|
||||||
} || os.PrctlError || os.WriteError || std.fs.File.OpenError || std.fmt.BufPrintError;
|
} || posix.PrctlError || posix.WriteError || std.fs.File.OpenError || std.fmt.BufPrintError;
|
||||||
|
|
||||||
pub fn setName(self: Thread, name: []const u8) SetNameError!void {
|
pub fn setName(self: Thread, name: []const u8) SetNameError!void {
|
||||||
if (name.len > max_name_len) return error.NameTooLong;
|
if (name.len > max_name_len) return error.NameTooLong;
|
||||||
@ -62,21 +64,21 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
|
|||||||
break :blk name_buf[0..name.len :0];
|
break :blk name_buf[0..name.len :0];
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (target.os.tag) {
|
switch (native_os) {
|
||||||
.linux => if (use_pthreads) {
|
.linux => if (use_pthreads) {
|
||||||
if (self.getHandle() == std.c.pthread_self()) {
|
if (self.getHandle() == std.c.pthread_self()) {
|
||||||
// Set the name of the calling thread (no thread id required).
|
// Set the name of the calling thread (no thread id required).
|
||||||
const err = try os.prctl(.SET_NAME, .{@intFromPtr(name_with_terminator.ptr)});
|
const err = try posix.prctl(.SET_NAME, .{@intFromPtr(name_with_terminator.ptr)});
|
||||||
switch (@as(os.E, @enumFromInt(err))) {
|
switch (@as(posix.E, @enumFromInt(err))) {
|
||||||
.SUCCESS => return,
|
.SUCCESS => return,
|
||||||
else => |e| return os.unexpectedErrno(e),
|
else => |e| return posix.unexpectedErrno(e),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const err = std.c.pthread_setname_np(self.getHandle(), name_with_terminator.ptr);
|
const err = std.c.pthread_setname_np(self.getHandle(), name_with_terminator.ptr);
|
||||||
switch (err) {
|
switch (err) {
|
||||||
.SUCCESS => return,
|
.SUCCESS => return,
|
||||||
.RANGE => unreachable,
|
.RANGE => unreachable,
|
||||||
else => |e| return os.unexpectedErrno(e),
|
else => |e| return posix.unexpectedErrno(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -95,21 +97,21 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
|
|||||||
const byte_len = math.cast(c_ushort, len * 2) orelse return error.NameTooLong;
|
const byte_len = math.cast(c_ushort, len * 2) orelse return error.NameTooLong;
|
||||||
|
|
||||||
// Note: NT allocates its own copy, no use-after-free here.
|
// Note: NT allocates its own copy, no use-after-free here.
|
||||||
const unicode_string = os.windows.UNICODE_STRING{
|
const unicode_string = windows.UNICODE_STRING{
|
||||||
.Length = byte_len,
|
.Length = byte_len,
|
||||||
.MaximumLength = byte_len,
|
.MaximumLength = byte_len,
|
||||||
.Buffer = &buf,
|
.Buffer = &buf,
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (os.windows.ntdll.NtSetInformationThread(
|
switch (windows.ntdll.NtSetInformationThread(
|
||||||
self.getHandle(),
|
self.getHandle(),
|
||||||
.ThreadNameInformation,
|
.ThreadNameInformation,
|
||||||
&unicode_string,
|
&unicode_string,
|
||||||
@sizeOf(os.windows.UNICODE_STRING),
|
@sizeOf(windows.UNICODE_STRING),
|
||||||
)) {
|
)) {
|
||||||
.SUCCESS => return,
|
.SUCCESS => return,
|
||||||
.NOT_IMPLEMENTED => return error.Unsupported,
|
.NOT_IMPLEMENTED => return error.Unsupported,
|
||||||
else => |err| return os.windows.unexpectedStatus(err),
|
else => |err| return windows.unexpectedStatus(err),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.macos, .ios, .watchos, .tvos => if (use_pthreads) {
|
.macos, .ios, .watchos, .tvos => if (use_pthreads) {
|
||||||
@ -119,7 +121,7 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
|
|||||||
const err = std.c.pthread_setname_np(name_with_terminator.ptr);
|
const err = std.c.pthread_setname_np(name_with_terminator.ptr);
|
||||||
switch (err) {
|
switch (err) {
|
||||||
.SUCCESS => return,
|
.SUCCESS => return,
|
||||||
else => |e| return os.unexpectedErrno(e),
|
else => |e| return posix.unexpectedErrno(e),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.netbsd, .solaris, .illumos => if (use_pthreads) {
|
.netbsd, .solaris, .illumos => if (use_pthreads) {
|
||||||
@ -129,7 +131,7 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
|
|||||||
.INVAL => unreachable,
|
.INVAL => unreachable,
|
||||||
.SRCH => unreachable,
|
.SRCH => unreachable,
|
||||||
.NOMEM => unreachable,
|
.NOMEM => unreachable,
|
||||||
else => |e| return os.unexpectedErrno(e),
|
else => |e| return posix.unexpectedErrno(e),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.freebsd, .openbsd => if (use_pthreads) {
|
.freebsd, .openbsd => if (use_pthreads) {
|
||||||
@ -148,7 +150,7 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
|
|||||||
.FAULT => unreachable,
|
.FAULT => unreachable,
|
||||||
.NAMETOOLONG => unreachable, // already checked
|
.NAMETOOLONG => unreachable, // already checked
|
||||||
.SRCH => unreachable,
|
.SRCH => unreachable,
|
||||||
else => |e| return os.unexpectedErrno(e),
|
else => |e| return posix.unexpectedErrno(e),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
@ -159,7 +161,7 @@ pub fn setName(self: Thread, name: []const u8) SetNameError!void {
|
|||||||
pub const GetNameError = error{
|
pub const GetNameError = error{
|
||||||
Unsupported,
|
Unsupported,
|
||||||
Unexpected,
|
Unexpected,
|
||||||
} || os.PrctlError || os.ReadError || std.fs.File.OpenError || std.fmt.BufPrintError;
|
} || posix.PrctlError || posix.ReadError || std.fs.File.OpenError || std.fmt.BufPrintError;
|
||||||
|
|
||||||
/// On Windows, the result is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
|
/// On Windows, the result is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
|
||||||
/// On other platforms, the result is an opaque sequence of bytes with no particular encoding.
|
/// On other platforms, the result is an opaque sequence of bytes with no particular encoding.
|
||||||
@ -167,21 +169,21 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
|
|||||||
buffer_ptr[max_name_len] = 0;
|
buffer_ptr[max_name_len] = 0;
|
||||||
var buffer: [:0]u8 = buffer_ptr;
|
var buffer: [:0]u8 = buffer_ptr;
|
||||||
|
|
||||||
switch (target.os.tag) {
|
switch (native_os) {
|
||||||
.linux => if (use_pthreads) {
|
.linux => if (use_pthreads) {
|
||||||
if (self.getHandle() == std.c.pthread_self()) {
|
if (self.getHandle() == std.c.pthread_self()) {
|
||||||
// Get the name of the calling thread (no thread id required).
|
// Get the name of the calling thread (no thread id required).
|
||||||
const err = try os.prctl(.GET_NAME, .{@intFromPtr(buffer.ptr)});
|
const err = try posix.prctl(.GET_NAME, .{@intFromPtr(buffer.ptr)});
|
||||||
switch (@as(os.E, @enumFromInt(err))) {
|
switch (@as(posix.E, @enumFromInt(err))) {
|
||||||
.SUCCESS => return std.mem.sliceTo(buffer, 0),
|
.SUCCESS => return std.mem.sliceTo(buffer, 0),
|
||||||
else => |e| return os.unexpectedErrno(e),
|
else => |e| return posix.unexpectedErrno(e),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const err = std.c.pthread_getname_np(self.getHandle(), buffer.ptr, max_name_len + 1);
|
const err = std.c.pthread_getname_np(self.getHandle(), buffer.ptr, max_name_len + 1);
|
||||||
switch (err) {
|
switch (err) {
|
||||||
.SUCCESS => return std.mem.sliceTo(buffer, 0),
|
.SUCCESS => return std.mem.sliceTo(buffer, 0),
|
||||||
.RANGE => unreachable,
|
.RANGE => unreachable,
|
||||||
else => |e| return os.unexpectedErrno(e),
|
else => |e| return posix.unexpectedErrno(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -196,10 +198,10 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
|
|||||||
return if (data_len >= 1) buffer[0 .. data_len - 1] else null;
|
return if (data_len >= 1) buffer[0 .. data_len - 1] else null;
|
||||||
},
|
},
|
||||||
.windows => {
|
.windows => {
|
||||||
const buf_capacity = @sizeOf(os.windows.UNICODE_STRING) + (@sizeOf(u16) * max_name_len);
|
const buf_capacity = @sizeOf(windows.UNICODE_STRING) + (@sizeOf(u16) * max_name_len);
|
||||||
var buf: [buf_capacity]u8 align(@alignOf(os.windows.UNICODE_STRING)) = undefined;
|
var buf: [buf_capacity]u8 align(@alignOf(windows.UNICODE_STRING)) = undefined;
|
||||||
|
|
||||||
switch (os.windows.ntdll.NtQueryInformationThread(
|
switch (windows.ntdll.NtQueryInformationThread(
|
||||||
self.getHandle(),
|
self.getHandle(),
|
||||||
.ThreadNameInformation,
|
.ThreadNameInformation,
|
||||||
&buf,
|
&buf,
|
||||||
@ -207,12 +209,12 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
|
|||||||
null,
|
null,
|
||||||
)) {
|
)) {
|
||||||
.SUCCESS => {
|
.SUCCESS => {
|
||||||
const string = @as(*const os.windows.UNICODE_STRING, @ptrCast(&buf));
|
const string = @as(*const windows.UNICODE_STRING, @ptrCast(&buf));
|
||||||
const len = std.unicode.wtf16LeToWtf8(buffer, string.Buffer.?[0 .. string.Length / 2]);
|
const len = std.unicode.wtf16LeToWtf8(buffer, string.Buffer.?[0 .. string.Length / 2]);
|
||||||
return if (len > 0) buffer[0..len] else null;
|
return if (len > 0) buffer[0..len] else null;
|
||||||
},
|
},
|
||||||
.NOT_IMPLEMENTED => return error.Unsupported,
|
.NOT_IMPLEMENTED => return error.Unsupported,
|
||||||
else => |err| return os.windows.unexpectedStatus(err),
|
else => |err| return windows.unexpectedStatus(err),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.macos, .ios, .watchos, .tvos => if (use_pthreads) {
|
.macos, .ios, .watchos, .tvos => if (use_pthreads) {
|
||||||
@ -220,7 +222,7 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
|
|||||||
switch (err) {
|
switch (err) {
|
||||||
.SUCCESS => return std.mem.sliceTo(buffer, 0),
|
.SUCCESS => return std.mem.sliceTo(buffer, 0),
|
||||||
.SRCH => unreachable,
|
.SRCH => unreachable,
|
||||||
else => |e| return os.unexpectedErrno(e),
|
else => |e| return posix.unexpectedErrno(e),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.netbsd, .solaris, .illumos => if (use_pthreads) {
|
.netbsd, .solaris, .illumos => if (use_pthreads) {
|
||||||
@ -229,7 +231,7 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
|
|||||||
.SUCCESS => return std.mem.sliceTo(buffer, 0),
|
.SUCCESS => return std.mem.sliceTo(buffer, 0),
|
||||||
.INVAL => unreachable,
|
.INVAL => unreachable,
|
||||||
.SRCH => unreachable,
|
.SRCH => unreachable,
|
||||||
else => |e| return os.unexpectedErrno(e),
|
else => |e| return posix.unexpectedErrno(e),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.freebsd, .openbsd => if (use_pthreads) {
|
.freebsd, .openbsd => if (use_pthreads) {
|
||||||
@ -246,7 +248,7 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
|
|||||||
.INVAL => unreachable,
|
.INVAL => unreachable,
|
||||||
.FAULT => unreachable,
|
.FAULT => unreachable,
|
||||||
.SRCH => unreachable,
|
.SRCH => unreachable,
|
||||||
else => |e| return os.unexpectedErrno(e),
|
else => |e| return posix.unexpectedErrno(e),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
@ -255,7 +257,7 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Represents an ID per thread guaranteed to be unique only within a process.
|
/// Represents an ID per thread guaranteed to be unique only within a process.
|
||||||
pub const Id = switch (target.os.tag) {
|
pub const Id = switch (native_os) {
|
||||||
.linux,
|
.linux,
|
||||||
.dragonfly,
|
.dragonfly,
|
||||||
.netbsd,
|
.netbsd,
|
||||||
@ -265,7 +267,7 @@ pub const Id = switch (target.os.tag) {
|
|||||||
.wasi,
|
.wasi,
|
||||||
=> u32,
|
=> u32,
|
||||||
.macos, .ios, .watchos, .tvos => u64,
|
.macos, .ios, .watchos, .tvos => u64,
|
||||||
.windows => os.windows.DWORD,
|
.windows => windows.DWORD,
|
||||||
else => usize,
|
else => usize,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -368,13 +370,13 @@ pub const YieldError = error{
|
|||||||
|
|
||||||
/// Yields the current thread potentially allowing other threads to run.
|
/// Yields the current thread potentially allowing other threads to run.
|
||||||
pub fn yield() YieldError!void {
|
pub fn yield() YieldError!void {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
// The return value has to do with how many other threads there are; it is not
|
// The return value has to do with how many other threads there are; it is not
|
||||||
// an error condition on Windows.
|
// an error condition on Windows.
|
||||||
_ = os.windows.kernel32.SwitchToThread();
|
_ = windows.kernel32.SwitchToThread();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (os.errno(os.system.sched_yield())) {
|
switch (posix.errno(posix.system.sched_yield())) {
|
||||||
.SUCCESS => return,
|
.SUCCESS => return,
|
||||||
.NOSYS => return error.SystemCannotYield,
|
.NOSYS => return error.SystemCannotYield,
|
||||||
else => return error.SystemCannotYield,
|
else => return error.SystemCannotYield,
|
||||||
@ -390,7 +392,7 @@ const Completion = std.atomic.Value(enum(u8) {
|
|||||||
|
|
||||||
/// Used by the Thread implementations to call the spawned function with the arguments.
|
/// Used by the Thread implementations to call the spawned function with the arguments.
|
||||||
fn callFn(comptime f: anytype, args: anytype) switch (Impl) {
|
fn callFn(comptime f: anytype, args: anytype) switch (Impl) {
|
||||||
WindowsThreadImpl => std.os.windows.DWORD,
|
WindowsThreadImpl => windows.DWORD,
|
||||||
LinuxThreadImpl => u8,
|
LinuxThreadImpl => u8,
|
||||||
PosixThreadImpl => ?*anyopaque,
|
PosixThreadImpl => ?*anyopaque,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
@ -470,13 +472,11 @@ const UnsupportedImpl = struct {
|
|||||||
|
|
||||||
fn unsupported(unused: anytype) noreturn {
|
fn unsupported(unused: anytype) noreturn {
|
||||||
_ = unused;
|
_ = unused;
|
||||||
@compileError("Unsupported operating system " ++ @tagName(target.os.tag));
|
@compileError("Unsupported operating system " ++ @tagName(native_os));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const WindowsThreadImpl = struct {
|
const WindowsThreadImpl = struct {
|
||||||
const windows = os.windows;
|
|
||||||
|
|
||||||
pub const ThreadHandle = windows.HANDLE;
|
pub const ThreadHandle = windows.HANDLE;
|
||||||
|
|
||||||
fn getCurrentId() windows.DWORD {
|
fn getCurrentId() windows.DWORD {
|
||||||
@ -584,7 +584,7 @@ const PosixThreadImpl = struct {
|
|||||||
pub const ThreadHandle = c.pthread_t;
|
pub const ThreadHandle = c.pthread_t;
|
||||||
|
|
||||||
fn getCurrentId() Id {
|
fn getCurrentId() Id {
|
||||||
switch (target.os.tag) {
|
switch (native_os) {
|
||||||
.linux => {
|
.linux => {
|
||||||
return LinuxThreadImpl.getCurrentId();
|
return LinuxThreadImpl.getCurrentId();
|
||||||
},
|
},
|
||||||
@ -616,15 +616,15 @@ const PosixThreadImpl = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn getCpuCount() !usize {
|
fn getCpuCount() !usize {
|
||||||
switch (target.os.tag) {
|
switch (native_os) {
|
||||||
.linux => {
|
.linux => {
|
||||||
return LinuxThreadImpl.getCpuCount();
|
return LinuxThreadImpl.getCpuCount();
|
||||||
},
|
},
|
||||||
.openbsd => {
|
.openbsd => {
|
||||||
var count: c_int = undefined;
|
var count: c_int = undefined;
|
||||||
var count_size: usize = @sizeOf(c_int);
|
var count_size: usize = @sizeOf(c_int);
|
||||||
const mib = [_]c_int{ os.CTL.HW, os.system.HW.NCPUONLINE };
|
const mib = [_]c_int{ std.c.CTL.HW, std.c.HW.NCPUONLINE };
|
||||||
os.sysctl(&mib, &count, &count_size, null, 0) catch |err| switch (err) {
|
std.c.sysctl(&mib, &count, &count_size, null, 0) catch |err| switch (err) {
|
||||||
error.NameTooLong, error.UnknownName => unreachable,
|
error.NameTooLong, error.UnknownName => unreachable,
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
};
|
};
|
||||||
@ -634,25 +634,25 @@ const PosixThreadImpl = struct {
|
|||||||
// The "proper" way to get the cpu count would be to query
|
// The "proper" way to get the cpu count would be to query
|
||||||
// /dev/kstat via ioctls, and traverse a linked list for each
|
// /dev/kstat via ioctls, and traverse a linked list for each
|
||||||
// cpu.
|
// cpu.
|
||||||
const rc = c.sysconf(os._SC.NPROCESSORS_ONLN);
|
const rc = c.sysconf(std.c._SC.NPROCESSORS_ONLN);
|
||||||
return switch (os.errno(rc)) {
|
return switch (posix.errno(rc)) {
|
||||||
.SUCCESS => @as(usize, @intCast(rc)),
|
.SUCCESS => @as(usize, @intCast(rc)),
|
||||||
else => |err| os.unexpectedErrno(err),
|
else => |err| posix.unexpectedErrno(err),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
.haiku => {
|
.haiku => {
|
||||||
var system_info: os.system.system_info = undefined;
|
var system_info: std.c.system_info = undefined;
|
||||||
const rc = os.system.get_system_info(&system_info); // always returns B_OK
|
const rc = std.c.get_system_info(&system_info); // always returns B_OK
|
||||||
return switch (os.errno(rc)) {
|
return switch (posix.errno(rc)) {
|
||||||
.SUCCESS => @as(usize, @intCast(system_info.cpu_count)),
|
.SUCCESS => @as(usize, @intCast(system_info.cpu_count)),
|
||||||
else => |err| os.unexpectedErrno(err),
|
else => |err| posix.unexpectedErrno(err),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
var count: c_int = undefined;
|
var count: c_int = undefined;
|
||||||
var count_len: usize = @sizeOf(c_int);
|
var count_len: usize = @sizeOf(c_int);
|
||||||
const name = if (comptime target.isDarwin()) "hw.logicalcpu" else "hw.ncpu";
|
const name = if (comptime target.isDarwin()) "hw.logicalcpu" else "hw.ncpu";
|
||||||
os.sysctlbynameZ(name, &count, &count_len, null, 0) catch |err| switch (err) {
|
posix.sysctlbynameZ(name, &count, &count_len, null, 0) catch |err| switch (err) {
|
||||||
error.NameTooLong, error.UnknownName => unreachable,
|
error.NameTooLong, error.UnknownName => unreachable,
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
};
|
};
|
||||||
@ -699,7 +699,7 @@ const PosixThreadImpl = struct {
|
|||||||
.AGAIN => return error.SystemResources,
|
.AGAIN => return error.SystemResources,
|
||||||
.PERM => unreachable,
|
.PERM => unreachable,
|
||||||
.INVAL => unreachable,
|
.INVAL => unreachable,
|
||||||
else => |err| return os.unexpectedErrno(err),
|
else => |err| return posix.unexpectedErrno(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1013,7 +1013,7 @@ const WasiThreadImpl = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const LinuxThreadImpl = struct {
|
const LinuxThreadImpl = struct {
|
||||||
const linux = os.linux;
|
const linux = std.os.linux;
|
||||||
|
|
||||||
pub const ThreadHandle = i32;
|
pub const ThreadHandle = i32;
|
||||||
|
|
||||||
@ -1028,9 +1028,9 @@ const LinuxThreadImpl = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn getCpuCount() !usize {
|
fn getCpuCount() !usize {
|
||||||
const cpu_set = try os.sched_getaffinity(0);
|
const cpu_set = try posix.sched_getaffinity(0);
|
||||||
// TODO: should not need this usize cast
|
// TODO: should not need this usize cast
|
||||||
return @as(usize, os.CPU_COUNT(cpu_set));
|
return @as(usize, posix.CPU_COUNT(cpu_set));
|
||||||
}
|
}
|
||||||
|
|
||||||
thread: *ThreadCompletion,
|
thread: *ThreadCompletion,
|
||||||
@ -1228,10 +1228,10 @@ const LinuxThreadImpl = struct {
|
|||||||
// map all memory needed without read/write permissions
|
// map all memory needed without read/write permissions
|
||||||
// to avoid committing the whole region right away
|
// to avoid committing the whole region right away
|
||||||
// anonymous mapping ensures file descriptor limits are not exceeded
|
// anonymous mapping ensures file descriptor limits are not exceeded
|
||||||
const mapped = os.mmap(
|
const mapped = posix.mmap(
|
||||||
null,
|
null,
|
||||||
map_bytes,
|
map_bytes,
|
||||||
os.PROT.NONE,
|
posix.PROT.NONE,
|
||||||
.{ .TYPE = .PRIVATE, .ANONYMOUS = true },
|
.{ .TYPE = .PRIVATE, .ANONYMOUS = true },
|
||||||
-1,
|
-1,
|
||||||
0,
|
0,
|
||||||
@ -1244,24 +1244,24 @@ const LinuxThreadImpl = struct {
|
|||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
};
|
};
|
||||||
assert(mapped.len >= map_bytes);
|
assert(mapped.len >= map_bytes);
|
||||||
errdefer os.munmap(mapped);
|
errdefer posix.munmap(mapped);
|
||||||
|
|
||||||
// map everything but the guard page as read/write
|
// map everything but the guard page as read/write
|
||||||
os.mprotect(
|
posix.mprotect(
|
||||||
@alignCast(mapped[guard_offset..]),
|
@alignCast(mapped[guard_offset..]),
|
||||||
os.PROT.READ | os.PROT.WRITE,
|
posix.PROT.READ | posix.PROT.WRITE,
|
||||||
) catch |err| switch (err) {
|
) catch |err| switch (err) {
|
||||||
error.AccessDenied => unreachable,
|
error.AccessDenied => unreachable,
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Prepare the TLS segment and prepare a user_desc struct when needed on x86
|
// Prepare the TLS segment and prepare a user_desc struct when needed on x86
|
||||||
var tls_ptr = os.linux.tls.prepareTLS(mapped[tls_offset..]);
|
var tls_ptr = linux.tls.prepareTLS(mapped[tls_offset..]);
|
||||||
var user_desc: if (target.cpu.arch == .x86) os.linux.user_desc else void = undefined;
|
var user_desc: if (target.cpu.arch == .x86) linux.user_desc else void = undefined;
|
||||||
if (target.cpu.arch == .x86) {
|
if (target.cpu.arch == .x86) {
|
||||||
defer tls_ptr = @intFromPtr(&user_desc);
|
defer tls_ptr = @intFromPtr(&user_desc);
|
||||||
user_desc = .{
|
user_desc = .{
|
||||||
.entry_number = os.linux.tls.tls_image.gdt_entry_number,
|
.entry_number = linux.tls.tls_image.gdt_entry_number,
|
||||||
.base_addr = tls_ptr,
|
.base_addr = tls_ptr,
|
||||||
.limit = 0xfffff,
|
.limit = 0xfffff,
|
||||||
.flags = .{
|
.flags = .{
|
||||||
@ -1286,7 +1286,7 @@ const LinuxThreadImpl = struct {
|
|||||||
linux.CLONE.PARENT_SETTID | linux.CLONE.CHILD_CLEARTID |
|
linux.CLONE.PARENT_SETTID | linux.CLONE.CHILD_CLEARTID |
|
||||||
linux.CLONE.SIGHAND | linux.CLONE.SYSVSEM | linux.CLONE.SETTLS;
|
linux.CLONE.SIGHAND | linux.CLONE.SYSVSEM | linux.CLONE.SETTLS;
|
||||||
|
|
||||||
switch (linux.getErrno(linux.clone(
|
switch (linux.E.init(linux.clone(
|
||||||
Instance.entryFn,
|
Instance.entryFn,
|
||||||
@intFromPtr(&mapped[stack_offset]),
|
@intFromPtr(&mapped[stack_offset]),
|
||||||
flags,
|
flags,
|
||||||
@ -1302,7 +1302,7 @@ const LinuxThreadImpl = struct {
|
|||||||
.NOSPC => unreachable,
|
.NOSPC => unreachable,
|
||||||
.PERM => unreachable,
|
.PERM => unreachable,
|
||||||
.USERS => unreachable,
|
.USERS => unreachable,
|
||||||
else => |err| return os.unexpectedErrno(err),
|
else => |err| return posix.unexpectedErrno(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1319,7 +1319,7 @@ const LinuxThreadImpl = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn join(self: Impl) void {
|
fn join(self: Impl) void {
|
||||||
defer os.munmap(self.thread.mapped);
|
defer posix.munmap(self.thread.mapped);
|
||||||
|
|
||||||
var spin: u8 = 10;
|
var spin: u8 = 10;
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -1334,7 +1334,7 @@ const LinuxThreadImpl = struct {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (linux.getErrno(linux.futex_wait(
|
switch (linux.E.init(linux.futex_wait(
|
||||||
&self.thread.child_tid.raw,
|
&self.thread.child_tid.raw,
|
||||||
linux.FUTEX.WAIT,
|
linux.FUTEX.WAIT,
|
||||||
tid,
|
tid,
|
||||||
@ -1383,7 +1383,7 @@ test "setName, getName" {
|
|||||||
// Wait for the main thread to have set the thread field in the context.
|
// Wait for the main thread to have set the thread field in the context.
|
||||||
ctx.start_wait_event.wait();
|
ctx.start_wait_event.wait();
|
||||||
|
|
||||||
switch (target.os.tag) {
|
switch (native_os) {
|
||||||
.windows => testThreadName(&ctx.thread) catch |err| switch (err) {
|
.windows => testThreadName(&ctx.thread) catch |err| switch (err) {
|
||||||
error.Unsupported => return error.SkipZigTest,
|
error.Unsupported => return error.SkipZigTest,
|
||||||
else => return err,
|
else => return err,
|
||||||
@ -1406,7 +1406,7 @@ test "setName, getName" {
|
|||||||
context.start_wait_event.set();
|
context.start_wait_event.set();
|
||||||
context.test_done_event.wait();
|
context.test_done_event.wait();
|
||||||
|
|
||||||
switch (target.os.tag) {
|
switch (native_os) {
|
||||||
.macos, .ios, .watchos, .tvos => {
|
.macos, .ios, .watchos, .tvos => {
|
||||||
const res = thread.setName("foobar");
|
const res = thread.setName("foobar");
|
||||||
try std.testing.expectError(error.Unsupported, res);
|
try std.testing.expectError(error.Unsupported, res);
|
||||||
|
|||||||
@ -1,13 +1,20 @@
|
|||||||
//! Futex is a mechanism used to block (`wait`) and unblock (`wake`) threads using a 32bit memory address as hints.
|
//! A mechanism used to block (`wait`) and unblock (`wake`) threads using a
|
||||||
//! Blocking a thread is acknowledged only if the 32bit memory address is equal to a given value.
|
//! 32bit memory address as hints.
|
||||||
//! This check helps avoid block/unblock deadlocks which occur if a `wake()` happens before a `wait()`.
|
//!
|
||||||
//! Using Futex, other Thread synchronization primitives can be built which efficiently wait for cross-thread events or signals.
|
//! Blocking a thread is acknowledged only if the 32bit memory address is equal
|
||||||
|
//! to a given value. This check helps avoid block/unblock deadlocks which
|
||||||
|
//! occur if a `wake()` happens before a `wait()`.
|
||||||
|
//!
|
||||||
|
//! Using Futex, other Thread synchronization primitives can be built which
|
||||||
|
//! efficiently wait for cross-thread events or signals.
|
||||||
|
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const Futex = @This();
|
const Futex = @This();
|
||||||
|
const windows = std.os.windows;
|
||||||
|
const linux = std.os.linux;
|
||||||
|
const c = std.c;
|
||||||
|
|
||||||
const os = std.os;
|
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const atomic = std.atomic;
|
const atomic = std.atomic;
|
||||||
@ -124,18 +131,18 @@ const SingleThreadedImpl = struct {
|
|||||||
// as it's generally already a linked target and is autoloaded into all processes anyway.
|
// as it's generally already a linked target and is autoloaded into all processes anyway.
|
||||||
const WindowsImpl = struct {
|
const WindowsImpl = struct {
|
||||||
fn wait(ptr: *const atomic.Value(u32), expect: u32, timeout: ?u64) error{Timeout}!void {
|
fn wait(ptr: *const atomic.Value(u32), expect: u32, timeout: ?u64) error{Timeout}!void {
|
||||||
var timeout_value: os.windows.LARGE_INTEGER = undefined;
|
var timeout_value: windows.LARGE_INTEGER = undefined;
|
||||||
var timeout_ptr: ?*const os.windows.LARGE_INTEGER = null;
|
var timeout_ptr: ?*const windows.LARGE_INTEGER = null;
|
||||||
|
|
||||||
// NTDLL functions work with time in units of 100 nanoseconds.
|
// NTDLL functions work with time in units of 100 nanoseconds.
|
||||||
// Positive values are absolute deadlines while negative values are relative durations.
|
// Positive values are absolute deadlines while negative values are relative durations.
|
||||||
if (timeout) |delay| {
|
if (timeout) |delay| {
|
||||||
timeout_value = @as(os.windows.LARGE_INTEGER, @intCast(delay / 100));
|
timeout_value = @as(windows.LARGE_INTEGER, @intCast(delay / 100));
|
||||||
timeout_value = -timeout_value;
|
timeout_value = -timeout_value;
|
||||||
timeout_ptr = &timeout_value;
|
timeout_ptr = &timeout_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rc = os.windows.ntdll.RtlWaitOnAddress(
|
const rc = windows.ntdll.RtlWaitOnAddress(
|
||||||
ptr,
|
ptr,
|
||||||
&expect,
|
&expect,
|
||||||
@sizeOf(@TypeOf(expect)),
|
@sizeOf(@TypeOf(expect)),
|
||||||
@ -157,8 +164,8 @@ const WindowsImpl = struct {
|
|||||||
assert(max_waiters != 0);
|
assert(max_waiters != 0);
|
||||||
|
|
||||||
switch (max_waiters) {
|
switch (max_waiters) {
|
||||||
1 => os.windows.ntdll.RtlWakeAddressSingle(address),
|
1 => windows.ntdll.RtlWakeAddressSingle(address),
|
||||||
else => os.windows.ntdll.RtlWakeAddressAll(address),
|
else => windows.ntdll.RtlWakeAddressAll(address),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -189,10 +196,10 @@ const DarwinImpl = struct {
|
|||||||
var timeout_overflowed = false;
|
var timeout_overflowed = false;
|
||||||
|
|
||||||
const addr: *const anyopaque = ptr;
|
const addr: *const anyopaque = ptr;
|
||||||
const flags = os.darwin.UL_COMPARE_AND_WAIT | os.darwin.ULF_NO_ERRNO;
|
const flags = c.UL_COMPARE_AND_WAIT | c.ULF_NO_ERRNO;
|
||||||
const status = blk: {
|
const status = blk: {
|
||||||
if (supports_ulock_wait2) {
|
if (supports_ulock_wait2) {
|
||||||
break :blk os.darwin.__ulock_wait2(flags, addr, expect, timeout_ns, 0);
|
break :blk c.__ulock_wait2(flags, addr, expect, timeout_ns, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const timeout_us = std.math.cast(u32, timeout_ns / std.time.ns_per_us) orelse overflow: {
|
const timeout_us = std.math.cast(u32, timeout_ns / std.time.ns_per_us) orelse overflow: {
|
||||||
@ -200,11 +207,11 @@ const DarwinImpl = struct {
|
|||||||
break :overflow std.math.maxInt(u32);
|
break :overflow std.math.maxInt(u32);
|
||||||
};
|
};
|
||||||
|
|
||||||
break :blk os.darwin.__ulock_wait(flags, addr, expect, timeout_us);
|
break :blk c.__ulock_wait(flags, addr, expect, timeout_us);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (status >= 0) return;
|
if (status >= 0) return;
|
||||||
switch (@as(std.os.E, @enumFromInt(-status))) {
|
switch (@as(c.E, @enumFromInt(-status))) {
|
||||||
// Wait was interrupted by the OS or other spurious signalling.
|
// Wait was interrupted by the OS or other spurious signalling.
|
||||||
.INTR => {},
|
.INTR => {},
|
||||||
// Address of the futex was paged out. This is unlikely, but possible in theory, and
|
// Address of the futex was paged out. This is unlikely, but possible in theory, and
|
||||||
@ -221,17 +228,17 @@ const DarwinImpl = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn wake(ptr: *const atomic.Value(u32), max_waiters: u32) void {
|
fn wake(ptr: *const atomic.Value(u32), max_waiters: u32) void {
|
||||||
var flags: u32 = os.darwin.UL_COMPARE_AND_WAIT | os.darwin.ULF_NO_ERRNO;
|
var flags: u32 = c.UL_COMPARE_AND_WAIT | c.ULF_NO_ERRNO;
|
||||||
if (max_waiters > 1) {
|
if (max_waiters > 1) {
|
||||||
flags |= os.darwin.ULF_WAKE_ALL;
|
flags |= c.ULF_WAKE_ALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const addr: *const anyopaque = ptr;
|
const addr: *const anyopaque = ptr;
|
||||||
const status = os.darwin.__ulock_wake(flags, addr, 0);
|
const status = c.__ulock_wake(flags, addr, 0);
|
||||||
|
|
||||||
if (status >= 0) return;
|
if (status >= 0) return;
|
||||||
switch (@as(std.os.E, @enumFromInt(-status))) {
|
switch (@as(c.E, @enumFromInt(-status))) {
|
||||||
.INTR => continue, // spurious wake()
|
.INTR => continue, // spurious wake()
|
||||||
.FAULT => unreachable, // __ulock_wake doesn't generate EFAULT according to darwin pthread_cond_t
|
.FAULT => unreachable, // __ulock_wake doesn't generate EFAULT according to darwin pthread_cond_t
|
||||||
.NOENT => return, // nothing was woken up
|
.NOENT => return, // nothing was woken up
|
||||||
@ -245,20 +252,20 @@ const DarwinImpl = struct {
|
|||||||
// https://man7.org/linux/man-pages/man2/futex.2.html
|
// https://man7.org/linux/man-pages/man2/futex.2.html
|
||||||
const LinuxImpl = struct {
|
const LinuxImpl = struct {
|
||||||
fn wait(ptr: *const atomic.Value(u32), expect: u32, timeout: ?u64) error{Timeout}!void {
|
fn wait(ptr: *const atomic.Value(u32), expect: u32, timeout: ?u64) error{Timeout}!void {
|
||||||
var ts: os.timespec = undefined;
|
var ts: linux.timespec = undefined;
|
||||||
if (timeout) |timeout_ns| {
|
if (timeout) |timeout_ns| {
|
||||||
ts.tv_sec = @as(@TypeOf(ts.tv_sec), @intCast(timeout_ns / std.time.ns_per_s));
|
ts.tv_sec = @as(@TypeOf(ts.tv_sec), @intCast(timeout_ns / std.time.ns_per_s));
|
||||||
ts.tv_nsec = @as(@TypeOf(ts.tv_nsec), @intCast(timeout_ns % std.time.ns_per_s));
|
ts.tv_nsec = @as(@TypeOf(ts.tv_nsec), @intCast(timeout_ns % std.time.ns_per_s));
|
||||||
}
|
}
|
||||||
|
|
||||||
const rc = os.linux.futex_wait(
|
const rc = linux.futex_wait(
|
||||||
@as(*const i32, @ptrCast(&ptr.raw)),
|
@as(*const i32, @ptrCast(&ptr.raw)),
|
||||||
os.linux.FUTEX.PRIVATE_FLAG | os.linux.FUTEX.WAIT,
|
linux.FUTEX.PRIVATE_FLAG | linux.FUTEX.WAIT,
|
||||||
@as(i32, @bitCast(expect)),
|
@as(i32, @bitCast(expect)),
|
||||||
if (timeout != null) &ts else null,
|
if (timeout != null) &ts else null,
|
||||||
);
|
);
|
||||||
|
|
||||||
switch (os.linux.getErrno(rc)) {
|
switch (linux.E.init(rc)) {
|
||||||
.SUCCESS => {}, // notified by `wake()`
|
.SUCCESS => {}, // notified by `wake()`
|
||||||
.INTR => {}, // spurious wakeup
|
.INTR => {}, // spurious wakeup
|
||||||
.AGAIN => {}, // ptr.* != expect
|
.AGAIN => {}, // ptr.* != expect
|
||||||
@ -273,13 +280,13 @@ const LinuxImpl = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn wake(ptr: *const atomic.Value(u32), max_waiters: u32) void {
|
fn wake(ptr: *const atomic.Value(u32), max_waiters: u32) void {
|
||||||
const rc = os.linux.futex_wake(
|
const rc = linux.futex_wake(
|
||||||
@as(*const i32, @ptrCast(&ptr.raw)),
|
@as(*const i32, @ptrCast(&ptr.raw)),
|
||||||
os.linux.FUTEX.PRIVATE_FLAG | os.linux.FUTEX.WAKE,
|
linux.FUTEX.PRIVATE_FLAG | linux.FUTEX.WAKE,
|
||||||
std.math.cast(i32, max_waiters) orelse std.math.maxInt(i32),
|
std.math.cast(i32, max_waiters) orelse std.math.maxInt(i32),
|
||||||
);
|
);
|
||||||
|
|
||||||
switch (os.linux.getErrno(rc)) {
|
switch (linux.E.init(rc)) {
|
||||||
.SUCCESS => {}, // successful wake up
|
.SUCCESS => {}, // successful wake up
|
||||||
.INVAL => {}, // invalid futex_wait() on ptr done elsewhere
|
.INVAL => {}, // invalid futex_wait() on ptr done elsewhere
|
||||||
.FAULT => {}, // pointer became invalid while doing the wake
|
.FAULT => {}, // pointer became invalid while doing the wake
|
||||||
@ -292,28 +299,28 @@ const LinuxImpl = struct {
|
|||||||
const FreebsdImpl = struct {
|
const FreebsdImpl = struct {
|
||||||
fn wait(ptr: *const atomic.Value(u32), expect: u32, timeout: ?u64) error{Timeout}!void {
|
fn wait(ptr: *const atomic.Value(u32), expect: u32, timeout: ?u64) error{Timeout}!void {
|
||||||
var tm_size: usize = 0;
|
var tm_size: usize = 0;
|
||||||
var tm: os.freebsd._umtx_time = undefined;
|
var tm: c._umtx_time = undefined;
|
||||||
var tm_ptr: ?*const os.freebsd._umtx_time = null;
|
var tm_ptr: ?*const c._umtx_time = null;
|
||||||
|
|
||||||
if (timeout) |timeout_ns| {
|
if (timeout) |timeout_ns| {
|
||||||
tm_ptr = &tm;
|
tm_ptr = &tm;
|
||||||
tm_size = @sizeOf(@TypeOf(tm));
|
tm_size = @sizeOf(@TypeOf(tm));
|
||||||
|
|
||||||
tm._flags = 0; // use relative time not UMTX_ABSTIME
|
tm._flags = 0; // use relative time not UMTX_ABSTIME
|
||||||
tm._clockid = os.CLOCK.MONOTONIC;
|
tm._clockid = c.CLOCK.MONOTONIC;
|
||||||
tm._timeout.tv_sec = @as(@TypeOf(tm._timeout.tv_sec), @intCast(timeout_ns / std.time.ns_per_s));
|
tm._timeout.tv_sec = @as(@TypeOf(tm._timeout.tv_sec), @intCast(timeout_ns / std.time.ns_per_s));
|
||||||
tm._timeout.tv_nsec = @as(@TypeOf(tm._timeout.tv_nsec), @intCast(timeout_ns % std.time.ns_per_s));
|
tm._timeout.tv_nsec = @as(@TypeOf(tm._timeout.tv_nsec), @intCast(timeout_ns % std.time.ns_per_s));
|
||||||
}
|
}
|
||||||
|
|
||||||
const rc = os.freebsd._umtx_op(
|
const rc = c._umtx_op(
|
||||||
@intFromPtr(&ptr.raw),
|
@intFromPtr(&ptr.raw),
|
||||||
@intFromEnum(os.freebsd.UMTX_OP.WAIT_UINT_PRIVATE),
|
@intFromEnum(c.UMTX_OP.WAIT_UINT_PRIVATE),
|
||||||
@as(c_ulong, expect),
|
@as(c_ulong, expect),
|
||||||
tm_size,
|
tm_size,
|
||||||
@intFromPtr(tm_ptr),
|
@intFromPtr(tm_ptr),
|
||||||
);
|
);
|
||||||
|
|
||||||
switch (os.errno(rc)) {
|
switch (std.posix.errno(rc)) {
|
||||||
.SUCCESS => {},
|
.SUCCESS => {},
|
||||||
.FAULT => unreachable, // one of the args points to invalid memory
|
.FAULT => unreachable, // one of the args points to invalid memory
|
||||||
.INVAL => unreachable, // arguments should be correct
|
.INVAL => unreachable, // arguments should be correct
|
||||||
@ -327,15 +334,15 @@ const FreebsdImpl = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn wake(ptr: *const atomic.Value(u32), max_waiters: u32) void {
|
fn wake(ptr: *const atomic.Value(u32), max_waiters: u32) void {
|
||||||
const rc = os.freebsd._umtx_op(
|
const rc = c._umtx_op(
|
||||||
@intFromPtr(&ptr.raw),
|
@intFromPtr(&ptr.raw),
|
||||||
@intFromEnum(os.freebsd.UMTX_OP.WAKE_PRIVATE),
|
@intFromEnum(c.UMTX_OP.WAKE_PRIVATE),
|
||||||
@as(c_ulong, max_waiters),
|
@as(c_ulong, max_waiters),
|
||||||
0, // there is no timeout struct
|
0, // there is no timeout struct
|
||||||
0, // there is no timeout struct pointer
|
0, // there is no timeout struct pointer
|
||||||
);
|
);
|
||||||
|
|
||||||
switch (os.errno(rc)) {
|
switch (std.posix.errno(rc)) {
|
||||||
.SUCCESS => {},
|
.SUCCESS => {},
|
||||||
.FAULT => {}, // it's ok if the ptr doesn't point to valid memory
|
.FAULT => {}, // it's ok if the ptr doesn't point to valid memory
|
||||||
.INVAL => unreachable, // arguments should be correct
|
.INVAL => unreachable, // arguments should be correct
|
||||||
@ -347,21 +354,21 @@ const FreebsdImpl = struct {
|
|||||||
// https://man.openbsd.org/futex.2
|
// https://man.openbsd.org/futex.2
|
||||||
const OpenbsdImpl = struct {
|
const OpenbsdImpl = struct {
|
||||||
fn wait(ptr: *const atomic.Value(u32), expect: u32, timeout: ?u64) error{Timeout}!void {
|
fn wait(ptr: *const atomic.Value(u32), expect: u32, timeout: ?u64) error{Timeout}!void {
|
||||||
var ts: os.timespec = undefined;
|
var ts: c.timespec = undefined;
|
||||||
if (timeout) |timeout_ns| {
|
if (timeout) |timeout_ns| {
|
||||||
ts.tv_sec = @as(@TypeOf(ts.tv_sec), @intCast(timeout_ns / std.time.ns_per_s));
|
ts.tv_sec = @as(@TypeOf(ts.tv_sec), @intCast(timeout_ns / std.time.ns_per_s));
|
||||||
ts.tv_nsec = @as(@TypeOf(ts.tv_nsec), @intCast(timeout_ns % std.time.ns_per_s));
|
ts.tv_nsec = @as(@TypeOf(ts.tv_nsec), @intCast(timeout_ns % std.time.ns_per_s));
|
||||||
}
|
}
|
||||||
|
|
||||||
const rc = os.openbsd.futex(
|
const rc = c.futex(
|
||||||
@as(*const volatile u32, @ptrCast(&ptr.raw)),
|
@as(*const volatile u32, @ptrCast(&ptr.raw)),
|
||||||
os.openbsd.FUTEX_WAIT | os.openbsd.FUTEX_PRIVATE_FLAG,
|
c.FUTEX_WAIT | c.FUTEX_PRIVATE_FLAG,
|
||||||
@as(c_int, @bitCast(expect)),
|
@as(c_int, @bitCast(expect)),
|
||||||
if (timeout != null) &ts else null,
|
if (timeout != null) &ts else null,
|
||||||
null, // FUTEX_WAIT takes no requeue address
|
null, // FUTEX_WAIT takes no requeue address
|
||||||
);
|
);
|
||||||
|
|
||||||
switch (os.errno(rc)) {
|
switch (std.posix.errno(rc)) {
|
||||||
.SUCCESS => {}, // woken up by wake
|
.SUCCESS => {}, // woken up by wake
|
||||||
.NOSYS => unreachable, // the futex operation shouldn't be invalid
|
.NOSYS => unreachable, // the futex operation shouldn't be invalid
|
||||||
.FAULT => unreachable, // ptr was invalid
|
.FAULT => unreachable, // ptr was invalid
|
||||||
@ -378,9 +385,9 @@ const OpenbsdImpl = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn wake(ptr: *const atomic.Value(u32), max_waiters: u32) void {
|
fn wake(ptr: *const atomic.Value(u32), max_waiters: u32) void {
|
||||||
const rc = os.openbsd.futex(
|
const rc = c.futex(
|
||||||
@as(*const volatile u32, @ptrCast(&ptr.raw)),
|
@as(*const volatile u32, @ptrCast(&ptr.raw)),
|
||||||
os.openbsd.FUTEX_WAKE | os.openbsd.FUTEX_PRIVATE_FLAG,
|
c.FUTEX_WAKE | c.FUTEX_PRIVATE_FLAG,
|
||||||
std.math.cast(c_int, max_waiters) orelse std.math.maxInt(c_int),
|
std.math.cast(c_int, max_waiters) orelse std.math.maxInt(c_int),
|
||||||
null, // FUTEX_WAKE takes no timeout ptr
|
null, // FUTEX_WAKE takes no timeout ptr
|
||||||
null, // FUTEX_WAKE takes no requeue address
|
null, // FUTEX_WAKE takes no requeue address
|
||||||
@ -415,9 +422,9 @@ const DragonflyImpl = struct {
|
|||||||
|
|
||||||
const value = @as(c_int, @bitCast(expect));
|
const value = @as(c_int, @bitCast(expect));
|
||||||
const addr = @as(*const volatile c_int, @ptrCast(&ptr.raw));
|
const addr = @as(*const volatile c_int, @ptrCast(&ptr.raw));
|
||||||
const rc = os.dragonfly.umtx_sleep(addr, value, timeout_us);
|
const rc = c.umtx_sleep(addr, value, timeout_us);
|
||||||
|
|
||||||
switch (os.errno(rc)) {
|
switch (std.posix.errno(rc)) {
|
||||||
.SUCCESS => {},
|
.SUCCESS => {},
|
||||||
.BUSY => {}, // ptr != expect
|
.BUSY => {}, // ptr != expect
|
||||||
.AGAIN => { // maybe timed out, or paged out, or hit 2s kernel refresh
|
.AGAIN => { // maybe timed out, or paged out, or hit 2s kernel refresh
|
||||||
@ -444,7 +451,7 @@ const DragonflyImpl = struct {
|
|||||||
// > umtx_wakeup() will generally return 0 unless the address is bad.
|
// > umtx_wakeup() will generally return 0 unless the address is bad.
|
||||||
// We are fine with the address being bad (e.g. for Semaphore.post() where Semaphore.wait() frees the Semaphore)
|
// We are fine with the address being bad (e.g. for Semaphore.post() where Semaphore.wait() frees the Semaphore)
|
||||||
const addr = @as(*const volatile c_int, @ptrCast(&ptr.raw));
|
const addr = @as(*const volatile c_int, @ptrCast(&ptr.raw));
|
||||||
_ = os.dragonfly.umtx_wakeup(addr, to_wake);
|
_ = c.umtx_wakeup(addr, to_wake);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -496,8 +503,8 @@ const WasmImpl = struct {
|
|||||||
/// https://go.dev/src/runtime/sema.go
|
/// https://go.dev/src/runtime/sema.go
|
||||||
const PosixImpl = struct {
|
const PosixImpl = struct {
|
||||||
const Event = struct {
|
const Event = struct {
|
||||||
cond: std.c.pthread_cond_t,
|
cond: c.pthread_cond_t,
|
||||||
mutex: std.c.pthread_mutex_t,
|
mutex: c.pthread_mutex_t,
|
||||||
state: enum { empty, waiting, notified },
|
state: enum { empty, waiting, notified },
|
||||||
|
|
||||||
fn init(self: *Event) void {
|
fn init(self: *Event) void {
|
||||||
@ -509,18 +516,18 @@ const PosixImpl = struct {
|
|||||||
|
|
||||||
fn deinit(self: *Event) void {
|
fn deinit(self: *Event) void {
|
||||||
// Some platforms reportedly give EINVAL for statically initialized pthread types.
|
// Some platforms reportedly give EINVAL for statically initialized pthread types.
|
||||||
const rc = std.c.pthread_cond_destroy(&self.cond);
|
const rc = c.pthread_cond_destroy(&self.cond);
|
||||||
assert(rc == .SUCCESS or rc == .INVAL);
|
assert(rc == .SUCCESS or rc == .INVAL);
|
||||||
|
|
||||||
const rm = std.c.pthread_mutex_destroy(&self.mutex);
|
const rm = c.pthread_mutex_destroy(&self.mutex);
|
||||||
assert(rm == .SUCCESS or rm == .INVAL);
|
assert(rm == .SUCCESS or rm == .INVAL);
|
||||||
|
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait(self: *Event, timeout: ?u64) error{Timeout}!void {
|
fn wait(self: *Event, timeout: ?u64) error{Timeout}!void {
|
||||||
assert(std.c.pthread_mutex_lock(&self.mutex) == .SUCCESS);
|
assert(c.pthread_mutex_lock(&self.mutex) == .SUCCESS);
|
||||||
defer assert(std.c.pthread_mutex_unlock(&self.mutex) == .SUCCESS);
|
defer assert(c.pthread_mutex_unlock(&self.mutex) == .SUCCESS);
|
||||||
|
|
||||||
// Early return if the event was already set.
|
// Early return if the event was already set.
|
||||||
if (self.state == .notified) {
|
if (self.state == .notified) {
|
||||||
@ -530,9 +537,9 @@ const PosixImpl = struct {
|
|||||||
// Compute the absolute timeout if one was specified.
|
// Compute the absolute timeout if one was specified.
|
||||||
// POSIX requires that REALTIME is used by default for the pthread timedwait functions.
|
// POSIX requires that REALTIME is used by default for the pthread timedwait functions.
|
||||||
// This can be changed with pthread_condattr_setclock, but it's an extension and may not be available everywhere.
|
// This can be changed with pthread_condattr_setclock, but it's an extension and may not be available everywhere.
|
||||||
var ts: os.timespec = undefined;
|
var ts: c.timespec = undefined;
|
||||||
if (timeout) |timeout_ns| {
|
if (timeout) |timeout_ns| {
|
||||||
os.clock_gettime(os.CLOCK.REALTIME, &ts) catch unreachable;
|
c.clock_gettime(c.CLOCK.REALTIME, &ts) catch unreachable;
|
||||||
ts.tv_sec +|= @as(@TypeOf(ts.tv_sec), @intCast(timeout_ns / std.time.ns_per_s));
|
ts.tv_sec +|= @as(@TypeOf(ts.tv_sec), @intCast(timeout_ns / std.time.ns_per_s));
|
||||||
ts.tv_nsec += @as(@TypeOf(ts.tv_nsec), @intCast(timeout_ns % std.time.ns_per_s));
|
ts.tv_nsec += @as(@TypeOf(ts.tv_nsec), @intCast(timeout_ns % std.time.ns_per_s));
|
||||||
|
|
||||||
@ -549,8 +556,8 @@ const PosixImpl = struct {
|
|||||||
while (true) {
|
while (true) {
|
||||||
// Block using either pthread_cond_wait or pthread_cond_timewait if there's an absolute timeout.
|
// Block using either pthread_cond_wait or pthread_cond_timewait if there's an absolute timeout.
|
||||||
const rc = blk: {
|
const rc = blk: {
|
||||||
if (timeout == null) break :blk std.c.pthread_cond_wait(&self.cond, &self.mutex);
|
if (timeout == null) break :blk c.pthread_cond_wait(&self.cond, &self.mutex);
|
||||||
break :blk std.c.pthread_cond_timedwait(&self.cond, &self.mutex, &ts);
|
break :blk c.pthread_cond_timedwait(&self.cond, &self.mutex, &ts);
|
||||||
};
|
};
|
||||||
|
|
||||||
// After waking up, check if the event was set.
|
// After waking up, check if the event was set.
|
||||||
@ -574,8 +581,8 @@ const PosixImpl = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set(self: *Event) void {
|
fn set(self: *Event) void {
|
||||||
assert(std.c.pthread_mutex_lock(&self.mutex) == .SUCCESS);
|
assert(c.pthread_mutex_lock(&self.mutex) == .SUCCESS);
|
||||||
defer assert(std.c.pthread_mutex_unlock(&self.mutex) == .SUCCESS);
|
defer assert(c.pthread_mutex_unlock(&self.mutex) == .SUCCESS);
|
||||||
|
|
||||||
// Make sure that multiple calls to set() were not done on the same Event.
|
// Make sure that multiple calls to set() were not done on the same Event.
|
||||||
const old_state = self.state;
|
const old_state = self.state;
|
||||||
@ -586,7 +593,7 @@ const PosixImpl = struct {
|
|||||||
// the condition variable once it observes the new state, potentially causing a UAF if done unlocked.
|
// the condition variable once it observes the new state, potentially causing a UAF if done unlocked.
|
||||||
self.state = .notified;
|
self.state = .notified;
|
||||||
if (old_state == .waiting) {
|
if (old_state == .waiting) {
|
||||||
assert(std.c.pthread_cond_signal(&self.cond) == .SUCCESS);
|
assert(c.pthread_cond_signal(&self.cond) == .SUCCESS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -732,7 +739,7 @@ const PosixImpl = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Bucket = struct {
|
const Bucket = struct {
|
||||||
mutex: std.c.pthread_mutex_t align(atomic.cache_line) = .{},
|
mutex: c.pthread_mutex_t align(atomic.cache_line) = .{},
|
||||||
pending: atomic.Value(usize) = atomic.Value(usize).init(0),
|
pending: atomic.Value(usize) = atomic.Value(usize).init(0),
|
||||||
treap: Treap = .{},
|
treap: Treap = .{},
|
||||||
|
|
||||||
@ -798,8 +805,8 @@ const PosixImpl = struct {
|
|||||||
|
|
||||||
var waiter: Waiter = undefined;
|
var waiter: Waiter = undefined;
|
||||||
{
|
{
|
||||||
assert(std.c.pthread_mutex_lock(&bucket.mutex) == .SUCCESS);
|
assert(c.pthread_mutex_lock(&bucket.mutex) == .SUCCESS);
|
||||||
defer assert(std.c.pthread_mutex_unlock(&bucket.mutex) == .SUCCESS);
|
defer assert(c.pthread_mutex_unlock(&bucket.mutex) == .SUCCESS);
|
||||||
|
|
||||||
cancelled = ptr.load(.monotonic) != expect;
|
cancelled = ptr.load(.monotonic) != expect;
|
||||||
if (cancelled) {
|
if (cancelled) {
|
||||||
@ -821,8 +828,8 @@ const PosixImpl = struct {
|
|||||||
// If we return early without waiting, the waiter on the stack would be invalidated and the wake() thread risks a UAF.
|
// If we return early without waiting, the waiter on the stack would be invalidated and the wake() thread risks a UAF.
|
||||||
defer if (!cancelled) waiter.event.wait(null) catch unreachable;
|
defer if (!cancelled) waiter.event.wait(null) catch unreachable;
|
||||||
|
|
||||||
assert(std.c.pthread_mutex_lock(&bucket.mutex) == .SUCCESS);
|
assert(c.pthread_mutex_lock(&bucket.mutex) == .SUCCESS);
|
||||||
defer assert(std.c.pthread_mutex_unlock(&bucket.mutex) == .SUCCESS);
|
defer assert(c.pthread_mutex_unlock(&bucket.mutex) == .SUCCESS);
|
||||||
|
|
||||||
cancelled = WaitQueue.tryRemove(&bucket.treap, address, &waiter);
|
cancelled = WaitQueue.tryRemove(&bucket.treap, address, &waiter);
|
||||||
if (cancelled) {
|
if (cancelled) {
|
||||||
@ -871,8 +878,8 @@ const PosixImpl = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
assert(std.c.pthread_mutex_lock(&bucket.mutex) == .SUCCESS);
|
assert(c.pthread_mutex_lock(&bucket.mutex) == .SUCCESS);
|
||||||
defer assert(std.c.pthread_mutex_unlock(&bucket.mutex) == .SUCCESS);
|
defer assert(c.pthread_mutex_unlock(&bucket.mutex) == .SUCCESS);
|
||||||
|
|
||||||
// Another pending check again to avoid the WaitQueue lookup if not necessary.
|
// Another pending check again to avoid the WaitQueue lookup if not necessary.
|
||||||
if (bucket.pending.load(.monotonic) > 0) {
|
if (bucket.pending.load(.monotonic) > 0) {
|
||||||
|
|||||||
@ -23,7 +23,6 @@ const std = @import("../std.zig");
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const Mutex = @This();
|
const Mutex = @This();
|
||||||
|
|
||||||
const os = std.os;
|
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const Thread = std.Thread;
|
const Thread = std.Thread;
|
||||||
@ -117,36 +116,40 @@ const SingleThreadedImpl = struct {
|
|||||||
// SRWLOCK on windows is almost always faster than Futex solution.
|
// SRWLOCK on windows is almost always faster than Futex solution.
|
||||||
// It also implements an efficient Condition with requeue support for us.
|
// It also implements an efficient Condition with requeue support for us.
|
||||||
const WindowsImpl = struct {
|
const WindowsImpl = struct {
|
||||||
srwlock: os.windows.SRWLOCK = .{},
|
srwlock: windows.SRWLOCK = .{},
|
||||||
|
|
||||||
fn tryLock(self: *@This()) bool {
|
fn tryLock(self: *@This()) bool {
|
||||||
return os.windows.kernel32.TryAcquireSRWLockExclusive(&self.srwlock) != os.windows.FALSE;
|
return windows.kernel32.TryAcquireSRWLockExclusive(&self.srwlock) != windows.FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lock(self: *@This()) void {
|
fn lock(self: *@This()) void {
|
||||||
os.windows.kernel32.AcquireSRWLockExclusive(&self.srwlock);
|
windows.kernel32.AcquireSRWLockExclusive(&self.srwlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unlock(self: *@This()) void {
|
fn unlock(self: *@This()) void {
|
||||||
os.windows.kernel32.ReleaseSRWLockExclusive(&self.srwlock);
|
windows.kernel32.ReleaseSRWLockExclusive(&self.srwlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const windows = std.os.windows;
|
||||||
};
|
};
|
||||||
|
|
||||||
// os_unfair_lock on darwin supports priority inheritance and is generally faster than Futex solutions.
|
// os_unfair_lock on darwin supports priority inheritance and is generally faster than Futex solutions.
|
||||||
const DarwinImpl = struct {
|
const DarwinImpl = struct {
|
||||||
oul: os.darwin.os_unfair_lock = .{},
|
oul: c.os_unfair_lock = .{},
|
||||||
|
|
||||||
fn tryLock(self: *@This()) bool {
|
fn tryLock(self: *@This()) bool {
|
||||||
return os.darwin.os_unfair_lock_trylock(&self.oul);
|
return c.os_unfair_lock_trylock(&self.oul);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lock(self: *@This()) void {
|
fn lock(self: *@This()) void {
|
||||||
os.darwin.os_unfair_lock_lock(&self.oul);
|
c.os_unfair_lock_lock(&self.oul);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unlock(self: *@This()) void {
|
fn unlock(self: *@This()) void {
|
||||||
os.darwin.os_unfair_lock_unlock(&self.oul);
|
c.os_unfair_lock_unlock(&self.oul);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const c = std.c;
|
||||||
};
|
};
|
||||||
|
|
||||||
const FutexImpl = struct {
|
const FutexImpl = struct {
|
||||||
|
|||||||
@ -782,7 +782,7 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr
|
|||||||
},
|
},
|
||||||
.wasi => {
|
.wasi => {
|
||||||
std.debug.print("{s}", .{msg});
|
std.debug.print("{s}", .{msg});
|
||||||
std.os.abort();
|
std.posix.abort();
|
||||||
},
|
},
|
||||||
.uefi => {
|
.uefi => {
|
||||||
const uefi = std.os.uefi;
|
const uefi = std.os.uefi;
|
||||||
@ -830,9 +830,9 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Didn't have boot_services, just fallback to whatever.
|
// Didn't have boot_services, just fallback to whatever.
|
||||||
std.os.abort();
|
std.posix.abort();
|
||||||
},
|
},
|
||||||
.cuda, .amdhsa => std.os.abort(),
|
.cuda, .amdhsa => std.posix.abort(),
|
||||||
.plan9 => {
|
.plan9 => {
|
||||||
var status: [std.os.plan9.ERRMAX]u8 = undefined;
|
var status: [std.os.plan9.ERRMAX]u8 = undefined;
|
||||||
const len = @min(msg.len, status.len - 1);
|
const len = @min(msg.len, status.len - 1);
|
||||||
|
|||||||
@ -2,12 +2,13 @@ const std = @import("std");
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const c = @This();
|
const c = @This();
|
||||||
const page_size = std.mem.page_size;
|
const page_size = std.mem.page_size;
|
||||||
const iovec = std.os.iovec;
|
const iovec = std.posix.iovec;
|
||||||
const iovec_const = std.os.iovec_const;
|
const iovec_const = std.posix.iovec_const;
|
||||||
const wasi = @import("c/wasi.zig");
|
const wasi = @import("c/wasi.zig");
|
||||||
const native_abi = builtin.abi;
|
const native_abi = builtin.abi;
|
||||||
const native_arch = builtin.cpu.arch;
|
const native_arch = builtin.cpu.arch;
|
||||||
const native_os = builtin.os.tag;
|
const native_os = builtin.os.tag;
|
||||||
|
const linux = std.os.linux;
|
||||||
|
|
||||||
/// If not linking libc, returns false.
|
/// If not linking libc, returns false.
|
||||||
/// If linking musl libc, returns true.
|
/// If linking musl libc, returns true.
|
||||||
@ -208,7 +209,7 @@ pub const pthread_rwlock_t = switch (native_os) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const AT = switch (native_os) {
|
pub const AT = switch (native_os) {
|
||||||
.linux => std.os.linux.AT,
|
.linux => linux.AT,
|
||||||
.windows => struct {
|
.windows => struct {
|
||||||
/// Remove directory instead of unlinking file
|
/// Remove directory instead of unlinking file
|
||||||
pub const REMOVEDIR = 0x200;
|
pub const REMOVEDIR = 0x200;
|
||||||
@ -326,9 +327,9 @@ pub const AT = switch (native_os) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const O = switch (native_os) {
|
pub const O = switch (native_os) {
|
||||||
.linux => std.os.linux.O,
|
.linux => linux.O,
|
||||||
.emscripten => packed struct(u32) {
|
.emscripten => packed struct(u32) {
|
||||||
ACCMODE: std.os.ACCMODE = .RDONLY,
|
ACCMODE: std.posix.ACCMODE = .RDONLY,
|
||||||
_2: u4 = 0,
|
_2: u4 = 0,
|
||||||
CREAT: bool = false,
|
CREAT: bool = false,
|
||||||
EXCL: bool = false,
|
EXCL: bool = false,
|
||||||
@ -369,7 +370,7 @@ pub const O = switch (native_os) {
|
|||||||
_: u3 = 0,
|
_: u3 = 0,
|
||||||
},
|
},
|
||||||
.solaris, .illumos => packed struct(u32) {
|
.solaris, .illumos => packed struct(u32) {
|
||||||
ACCMODE: std.os.ACCMODE = .RDONLY,
|
ACCMODE: std.posix.ACCMODE = .RDONLY,
|
||||||
NDELAY: bool = false,
|
NDELAY: bool = false,
|
||||||
APPEND: bool = false,
|
APPEND: bool = false,
|
||||||
SYNC: bool = false,
|
SYNC: bool = false,
|
||||||
@ -396,7 +397,7 @@ pub const O = switch (native_os) {
|
|||||||
_: u6 = 0,
|
_: u6 = 0,
|
||||||
},
|
},
|
||||||
.netbsd => packed struct(u32) {
|
.netbsd => packed struct(u32) {
|
||||||
ACCMODE: std.os.ACCMODE = .RDONLY,
|
ACCMODE: std.posix.ACCMODE = .RDONLY,
|
||||||
NONBLOCK: bool = false,
|
NONBLOCK: bool = false,
|
||||||
APPEND: bool = false,
|
APPEND: bool = false,
|
||||||
SHLOCK: bool = false,
|
SHLOCK: bool = false,
|
||||||
@ -420,7 +421,7 @@ pub const O = switch (native_os) {
|
|||||||
_: u8 = 0,
|
_: u8 = 0,
|
||||||
},
|
},
|
||||||
.openbsd => packed struct(u32) {
|
.openbsd => packed struct(u32) {
|
||||||
ACCMODE: std.os.ACCMODE = .RDONLY,
|
ACCMODE: std.posix.ACCMODE = .RDONLY,
|
||||||
NONBLOCK: bool = false,
|
NONBLOCK: bool = false,
|
||||||
APPEND: bool = false,
|
APPEND: bool = false,
|
||||||
SHLOCK: bool = false,
|
SHLOCK: bool = false,
|
||||||
@ -438,7 +439,7 @@ pub const O = switch (native_os) {
|
|||||||
_: u14 = 0,
|
_: u14 = 0,
|
||||||
},
|
},
|
||||||
.haiku => packed struct(u32) {
|
.haiku => packed struct(u32) {
|
||||||
ACCMODE: std.os.ACCMODE = .RDONLY,
|
ACCMODE: std.posix.ACCMODE = .RDONLY,
|
||||||
_2: u4 = 0,
|
_2: u4 = 0,
|
||||||
CLOEXEC: bool = false,
|
CLOEXEC: bool = false,
|
||||||
NONBLOCK: bool = false,
|
NONBLOCK: bool = false,
|
||||||
@ -458,7 +459,7 @@ pub const O = switch (native_os) {
|
|||||||
_: u10 = 0,
|
_: u10 = 0,
|
||||||
},
|
},
|
||||||
.macos, .ios, .tvos, .watchos => packed struct(u32) {
|
.macos, .ios, .tvos, .watchos => packed struct(u32) {
|
||||||
ACCMODE: std.os.ACCMODE = .RDONLY,
|
ACCMODE: std.posix.ACCMODE = .RDONLY,
|
||||||
NONBLOCK: bool = false,
|
NONBLOCK: bool = false,
|
||||||
APPEND: bool = false,
|
APPEND: bool = false,
|
||||||
SHLOCK: bool = false,
|
SHLOCK: bool = false,
|
||||||
@ -485,7 +486,7 @@ pub const O = switch (native_os) {
|
|||||||
POPUP: bool = false,
|
POPUP: bool = false,
|
||||||
},
|
},
|
||||||
.dragonfly => packed struct(u32) {
|
.dragonfly => packed struct(u32) {
|
||||||
ACCMODE: std.os.ACCMODE = .RDONLY,
|
ACCMODE: std.posix.ACCMODE = .RDONLY,
|
||||||
NONBLOCK: bool = false,
|
NONBLOCK: bool = false,
|
||||||
APPEND: bool = false,
|
APPEND: bool = false,
|
||||||
SHLOCK: bool = false,
|
SHLOCK: bool = false,
|
||||||
@ -511,7 +512,7 @@ pub const O = switch (native_os) {
|
|||||||
_: u4 = 0,
|
_: u4 = 0,
|
||||||
},
|
},
|
||||||
.freebsd => packed struct(u32) {
|
.freebsd => packed struct(u32) {
|
||||||
ACCMODE: std.os.ACCMODE = .RDONLY,
|
ACCMODE: std.posix.ACCMODE = .RDONLY,
|
||||||
NONBLOCK: bool = false,
|
NONBLOCK: bool = false,
|
||||||
APPEND: bool = false,
|
APPEND: bool = false,
|
||||||
SHLOCK: bool = false,
|
SHLOCK: bool = false,
|
||||||
@ -538,7 +539,7 @@ pub const O = switch (native_os) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const MAP = switch (native_os) {
|
pub const MAP = switch (native_os) {
|
||||||
.linux => std.os.linux.MAP,
|
.linux => linux.MAP,
|
||||||
.emscripten => packed struct(u32) {
|
.emscripten => packed struct(u32) {
|
||||||
TYPE: enum(u4) {
|
TYPE: enum(u4) {
|
||||||
SHARED = 0x01,
|
SHARED = 0x01,
|
||||||
@ -683,7 +684,7 @@ pub const cc_t = u8;
|
|||||||
|
|
||||||
/// Indices into the `cc` array in the `termios` struct.
|
/// Indices into the `cc` array in the `termios` struct.
|
||||||
pub const V = switch (native_os) {
|
pub const V = switch (native_os) {
|
||||||
.linux => std.os.linux.V,
|
.linux => linux.V,
|
||||||
.macos, .ios, .tvos, .watchos, .netbsd, .openbsd => enum {
|
.macos, .ios, .tvos, .watchos, .netbsd, .openbsd => enum {
|
||||||
EOF,
|
EOF,
|
||||||
EOL,
|
EOL,
|
||||||
@ -782,7 +783,7 @@ pub const V = switch (native_os) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const NCCS = switch (native_os) {
|
pub const NCCS = switch (native_os) {
|
||||||
.linux => std.os.linux.NCCS,
|
.linux => linux.NCCS,
|
||||||
.macos, .ios, .tvos, .watchos, .freebsd, .kfreebsd, .netbsd, .openbsd, .dragonfly => 20,
|
.macos, .ios, .tvos, .watchos, .freebsd, .kfreebsd, .netbsd, .openbsd, .dragonfly => 20,
|
||||||
.haiku => 11,
|
.haiku => 11,
|
||||||
.solaris, .illumos => 19,
|
.solaris, .illumos => 19,
|
||||||
@ -791,7 +792,7 @@ pub const NCCS = switch (native_os) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const termios = switch (native_os) {
|
pub const termios = switch (native_os) {
|
||||||
.linux => std.os.linux.termios,
|
.linux => linux.termios,
|
||||||
.macos, .ios, .tvos, .watchos => extern struct {
|
.macos, .ios, .tvos, .watchos => extern struct {
|
||||||
iflag: tc_iflag_t,
|
iflag: tc_iflag_t,
|
||||||
oflag: tc_oflag_t,
|
oflag: tc_oflag_t,
|
||||||
@ -841,7 +842,7 @@ pub const termios = switch (native_os) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const tc_iflag_t = switch (native_os) {
|
pub const tc_iflag_t = switch (native_os) {
|
||||||
.linux => std.os.linux.tc_iflag_t,
|
.linux => linux.tc_iflag_t,
|
||||||
.macos, .ios, .tvos, .watchos => packed struct(u64) {
|
.macos, .ios, .tvos, .watchos => packed struct(u64) {
|
||||||
IGNBRK: bool = false,
|
IGNBRK: bool = false,
|
||||||
BRKINT: bool = false,
|
BRKINT: bool = false,
|
||||||
@ -951,7 +952,7 @@ pub const tc_iflag_t = switch (native_os) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const tc_oflag_t = switch (native_os) {
|
pub const tc_oflag_t = switch (native_os) {
|
||||||
.linux => std.os.linux.tc_oflag_t,
|
.linux => linux.tc_oflag_t,
|
||||||
.macos, .ios, .tvos, .watchos => packed struct(u64) {
|
.macos, .ios, .tvos, .watchos => packed struct(u64) {
|
||||||
OPOST: bool = false,
|
OPOST: bool = false,
|
||||||
ONLCR: bool = false,
|
ONLCR: bool = false,
|
||||||
@ -1042,13 +1043,13 @@ pub const tc_oflag_t = switch (native_os) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const CSIZE = switch (native_os) {
|
pub const CSIZE = switch (native_os) {
|
||||||
.linux => std.os.linux.CSIZE,
|
.linux => linux.CSIZE,
|
||||||
.haiku => enum(u1) { CS7, CS8 },
|
.haiku => enum(u1) { CS7, CS8 },
|
||||||
else => enum(u2) { CS5, CS6, CS7, CS8 },
|
else => enum(u2) { CS5, CS6, CS7, CS8 },
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const tc_cflag_t = switch (native_os) {
|
pub const tc_cflag_t = switch (native_os) {
|
||||||
.linux => std.os.linux.tc_cflag_t,
|
.linux => linux.tc_cflag_t,
|
||||||
.macos, .ios, .tvos, .watchos => packed struct(u64) {
|
.macos, .ios, .tvos, .watchos => packed struct(u64) {
|
||||||
CIGNORE: bool = false,
|
CIGNORE: bool = false,
|
||||||
_1: u5 = 0,
|
_1: u5 = 0,
|
||||||
@ -1184,7 +1185,7 @@ pub const tc_cflag_t = switch (native_os) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const tc_lflag_t = switch (native_os) {
|
pub const tc_lflag_t = switch (native_os) {
|
||||||
.linux => std.os.linux.tc_lflag_t,
|
.linux => linux.tc_lflag_t,
|
||||||
.macos, .ios, .tvos, .watchos => packed struct(u64) {
|
.macos, .ios, .tvos, .watchos => packed struct(u64) {
|
||||||
ECHOKE: bool = false,
|
ECHOKE: bool = false,
|
||||||
ECHOE: bool = false,
|
ECHOE: bool = false,
|
||||||
@ -1310,7 +1311,7 @@ pub const tc_lflag_t = switch (native_os) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const speed_t = switch (native_os) {
|
pub const speed_t = switch (native_os) {
|
||||||
.linux => std.os.linux.speed_t,
|
.linux => linux.speed_t,
|
||||||
.macos, .ios, .tvos, .watchos, .openbsd => enum(u64) {
|
.macos, .ios, .tvos, .watchos, .openbsd => enum(u64) {
|
||||||
B0 = 0,
|
B0 = 0,
|
||||||
B50 = 50,
|
B50 = 50,
|
||||||
@ -1605,14 +1606,6 @@ pub const stat = switch (native_os) {
|
|||||||
else => private.stat,
|
else => private.stat,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn getErrno(rc: anytype) c.E {
|
|
||||||
if (rc == -1) {
|
|
||||||
return @enumFromInt(c._errno().*);
|
|
||||||
} else {
|
|
||||||
return .SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub extern "c" var environ: [*:null]?[*:0]u8;
|
pub extern "c" var environ: [*:null]?[*:0]u8;
|
||||||
|
|
||||||
pub extern "c" fn fopen(noalias filename: [*:0]const u8, noalias modes: [*:0]const u8) ?*FILE;
|
pub extern "c" fn fopen(noalias filename: [*:0]const u8, noalias modes: [*:0]const u8) ?*FILE;
|
||||||
@ -1905,10 +1898,10 @@ pub extern "c" fn if_nametoindex([*:0]const u8) c_int;
|
|||||||
pub const getcontext = if (builtin.target.isAndroid())
|
pub const getcontext = if (builtin.target.isAndroid())
|
||||||
@compileError("android bionic libc does not implement getcontext")
|
@compileError("android bionic libc does not implement getcontext")
|
||||||
else if (native_os == .linux and builtin.target.isMusl())
|
else if (native_os == .linux and builtin.target.isMusl())
|
||||||
std.os.linux.getcontext
|
linux.getcontext
|
||||||
else
|
else
|
||||||
struct {
|
struct {
|
||||||
extern fn getcontext(ucp: *std.os.ucontext_t) c_int;
|
extern fn getcontext(ucp: *std.posix.ucontext_t) c_int;
|
||||||
}.getcontext;
|
}.getcontext;
|
||||||
|
|
||||||
pub const max_align_t = if (native_abi == .msvc)
|
pub const max_align_t = if (native_abi == .msvc)
|
||||||
|
|||||||
@ -4,7 +4,7 @@ const assert = std.debug.assert;
|
|||||||
const macho = std.macho;
|
const macho = std.macho;
|
||||||
const native_arch = builtin.target.cpu.arch;
|
const native_arch = builtin.target.cpu.arch;
|
||||||
const maxInt = std.math.maxInt;
|
const maxInt = std.math.maxInt;
|
||||||
const iovec_const = std.os.iovec_const;
|
const iovec_const = std.posix.iovec_const;
|
||||||
|
|
||||||
pub const aarch64 = @import("darwin/aarch64.zig");
|
pub const aarch64 = @import("darwin/aarch64.zig");
|
||||||
pub const x86_64 = @import("darwin/x86_64.zig");
|
pub const x86_64 = @import("darwin/x86_64.zig");
|
||||||
@ -2826,237 +2826,12 @@ pub extern "c" fn posix_spawnp(
|
|||||||
env: [*:null]?[*:0]const u8,
|
env: [*:null]?[*:0]const u8,
|
||||||
) c_int;
|
) c_int;
|
||||||
|
|
||||||
pub const PosixSpawn = struct {
|
|
||||||
const errno = std.os.errno;
|
|
||||||
const unexpectedErrno = std.os.unexpectedErrno;
|
|
||||||
|
|
||||||
pub const Error = error{
|
|
||||||
SystemResources,
|
|
||||||
InvalidFileDescriptor,
|
|
||||||
NameTooLong,
|
|
||||||
TooBig,
|
|
||||||
PermissionDenied,
|
|
||||||
InputOutput,
|
|
||||||
FileSystem,
|
|
||||||
FileNotFound,
|
|
||||||
InvalidExe,
|
|
||||||
NotDir,
|
|
||||||
FileBusy,
|
|
||||||
/// Returned when the child fails to execute either in the pre-exec() initialization step, or
|
|
||||||
/// when exec(3) is invoked.
|
|
||||||
ChildExecFailed,
|
|
||||||
} || std.os.UnexpectedError;
|
|
||||||
|
|
||||||
pub const Attr = struct {
|
|
||||||
attr: posix_spawnattr_t,
|
|
||||||
|
|
||||||
pub fn init() Error!Attr {
|
|
||||||
var attr: posix_spawnattr_t = undefined;
|
|
||||||
switch (errno(posix_spawnattr_init(&attr))) {
|
|
||||||
.SUCCESS => return Attr{ .attr = attr },
|
|
||||||
.NOMEM => return error.SystemResources,
|
|
||||||
.INVAL => unreachable,
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *Attr) void {
|
|
||||||
defer self.* = undefined;
|
|
||||||
switch (errno(posix_spawnattr_destroy(&self.attr))) {
|
|
||||||
.SUCCESS => return,
|
|
||||||
.INVAL => unreachable, // Invalid parameters.
|
|
||||||
else => unreachable,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(self: Attr) Error!u16 {
|
|
||||||
var flags: c_short = undefined;
|
|
||||||
switch (errno(posix_spawnattr_getflags(&self.attr, &flags))) {
|
|
||||||
.SUCCESS => return @as(u16, @bitCast(flags)),
|
|
||||||
.INVAL => unreachable,
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set(self: *Attr, flags: u16) Error!void {
|
|
||||||
switch (errno(posix_spawnattr_setflags(&self.attr, @as(c_short, @bitCast(flags))))) {
|
|
||||||
.SUCCESS => return,
|
|
||||||
.INVAL => unreachable,
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Actions = struct {
|
|
||||||
actions: posix_spawn_file_actions_t,
|
|
||||||
|
|
||||||
pub fn init() Error!Actions {
|
|
||||||
var actions: posix_spawn_file_actions_t = undefined;
|
|
||||||
switch (errno(posix_spawn_file_actions_init(&actions))) {
|
|
||||||
.SUCCESS => return Actions{ .actions = actions },
|
|
||||||
.NOMEM => return error.SystemResources,
|
|
||||||
.INVAL => unreachable,
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *Actions) void {
|
|
||||||
defer self.* = undefined;
|
|
||||||
switch (errno(posix_spawn_file_actions_destroy(&self.actions))) {
|
|
||||||
.SUCCESS => return,
|
|
||||||
.INVAL => unreachable, // Invalid parameters.
|
|
||||||
else => unreachable,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn open(self: *Actions, fd: fd_t, path: []const u8, flags: u32, mode: mode_t) Error!void {
|
|
||||||
const posix_path = try std.os.toPosixPath(path);
|
|
||||||
return self.openZ(fd, &posix_path, flags, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn openZ(self: *Actions, fd: fd_t, path: [*:0]const u8, flags: u32, mode: mode_t) Error!void {
|
|
||||||
switch (errno(posix_spawn_file_actions_addopen(&self.actions, fd, path, @as(c_int, @bitCast(flags)), mode))) {
|
|
||||||
.SUCCESS => return,
|
|
||||||
.BADF => return error.InvalidFileDescriptor,
|
|
||||||
.NOMEM => return error.SystemResources,
|
|
||||||
.NAMETOOLONG => return error.NameTooLong,
|
|
||||||
.INVAL => unreachable, // the value of file actions is invalid
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn close(self: *Actions, fd: fd_t) Error!void {
|
|
||||||
switch (errno(posix_spawn_file_actions_addclose(&self.actions, fd))) {
|
|
||||||
.SUCCESS => return,
|
|
||||||
.BADF => return error.InvalidFileDescriptor,
|
|
||||||
.NOMEM => return error.SystemResources,
|
|
||||||
.INVAL => unreachable, // the value of file actions is invalid
|
|
||||||
.NAMETOOLONG => unreachable,
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dup2(self: *Actions, fd: fd_t, newfd: fd_t) Error!void {
|
|
||||||
switch (errno(posix_spawn_file_actions_adddup2(&self.actions, fd, newfd))) {
|
|
||||||
.SUCCESS => return,
|
|
||||||
.BADF => return error.InvalidFileDescriptor,
|
|
||||||
.NOMEM => return error.SystemResources,
|
|
||||||
.INVAL => unreachable, // the value of file actions is invalid
|
|
||||||
.NAMETOOLONG => unreachable,
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn inherit(self: *Actions, fd: fd_t) Error!void {
|
|
||||||
switch (errno(posix_spawn_file_actions_addinherit_np(&self.actions, fd))) {
|
|
||||||
.SUCCESS => return,
|
|
||||||
.BADF => return error.InvalidFileDescriptor,
|
|
||||||
.NOMEM => return error.SystemResources,
|
|
||||||
.INVAL => unreachable, // the value of file actions is invalid
|
|
||||||
.NAMETOOLONG => unreachable,
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn chdir(self: *Actions, path: []const u8) Error!void {
|
|
||||||
const posix_path = try std.os.toPosixPath(path);
|
|
||||||
return self.chdirZ(&posix_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn chdirZ(self: *Actions, path: [*:0]const u8) Error!void {
|
|
||||||
switch (errno(posix_spawn_file_actions_addchdir_np(&self.actions, path))) {
|
|
||||||
.SUCCESS => return,
|
|
||||||
.NOMEM => return error.SystemResources,
|
|
||||||
.NAMETOOLONG => return error.NameTooLong,
|
|
||||||
.BADF => unreachable,
|
|
||||||
.INVAL => unreachable, // the value of file actions is invalid
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fchdir(self: *Actions, fd: fd_t) Error!void {
|
|
||||||
switch (errno(posix_spawn_file_actions_addfchdir_np(&self.actions, fd))) {
|
|
||||||
.SUCCESS => return,
|
|
||||||
.BADF => return error.InvalidFileDescriptor,
|
|
||||||
.NOMEM => return error.SystemResources,
|
|
||||||
.INVAL => unreachable, // the value of file actions is invalid
|
|
||||||
.NAMETOOLONG => unreachable,
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn spawn(
|
|
||||||
path: []const u8,
|
|
||||||
actions: ?Actions,
|
|
||||||
attr: ?Attr,
|
|
||||||
argv: [*:null]?[*:0]const u8,
|
|
||||||
envp: [*:null]?[*:0]const u8,
|
|
||||||
) Error!pid_t {
|
|
||||||
const posix_path = try std.os.toPosixPath(path);
|
|
||||||
return spawnZ(&posix_path, actions, attr, argv, envp);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn spawnZ(
|
|
||||||
path: [*:0]const u8,
|
|
||||||
actions: ?Actions,
|
|
||||||
attr: ?Attr,
|
|
||||||
argv: [*:null]?[*:0]const u8,
|
|
||||||
envp: [*:null]?[*:0]const u8,
|
|
||||||
) Error!pid_t {
|
|
||||||
var pid: pid_t = undefined;
|
|
||||||
switch (errno(posix_spawn(
|
|
||||||
&pid,
|
|
||||||
path,
|
|
||||||
if (actions) |a| &a.actions else null,
|
|
||||||
if (attr) |a| &a.attr else null,
|
|
||||||
argv,
|
|
||||||
envp,
|
|
||||||
))) {
|
|
||||||
.SUCCESS => return pid,
|
|
||||||
.@"2BIG" => return error.TooBig,
|
|
||||||
.NOMEM => return error.SystemResources,
|
|
||||||
.BADF => return error.InvalidFileDescriptor,
|
|
||||||
.ACCES => return error.PermissionDenied,
|
|
||||||
.IO => return error.InputOutput,
|
|
||||||
.LOOP => return error.FileSystem,
|
|
||||||
.NAMETOOLONG => return error.NameTooLong,
|
|
||||||
.NOENT => return error.FileNotFound,
|
|
||||||
.NOEXEC => return error.InvalidExe,
|
|
||||||
.NOTDIR => return error.NotDir,
|
|
||||||
.TXTBSY => return error.FileBusy,
|
|
||||||
.BADARCH => return error.InvalidExe,
|
|
||||||
.BADEXEC => return error.InvalidExe,
|
|
||||||
.FAULT => unreachable,
|
|
||||||
.INVAL => unreachable,
|
|
||||||
else => |err| return unexpectedErrno(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn waitpid(pid: pid_t, flags: u32) Error!std.os.WaitPidResult {
|
|
||||||
var status: c_int = undefined;
|
|
||||||
while (true) {
|
|
||||||
const rc = waitpid(pid, &status, @as(c_int, @intCast(flags)));
|
|
||||||
switch (errno(rc)) {
|
|
||||||
.SUCCESS => return std.os.WaitPidResult{
|
|
||||||
.pid = @as(pid_t, @intCast(rc)),
|
|
||||||
.status = @as(u32, @bitCast(status)),
|
|
||||||
},
|
|
||||||
.INTR => continue,
|
|
||||||
.CHILD => return error.ChildExecFailed,
|
|
||||||
.INVAL => unreachable, // Invalid flags.
|
|
||||||
else => unreachable,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn getKernError(err: kern_return_t) KernE {
|
pub fn getKernError(err: kern_return_t) KernE {
|
||||||
return @as(KernE, @enumFromInt(@as(u32, @truncate(@as(usize, @intCast(err))))));
|
return @as(KernE, @enumFromInt(@as(u32, @truncate(@as(usize, @intCast(err))))));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unexpectedKernError(err: KernE) std.os.UnexpectedError {
|
pub fn unexpectedKernError(err: KernE) std.posix.UnexpectedError {
|
||||||
if (std.os.unexpected_error_tracing) {
|
if (std.posix.unexpected_error_tracing) {
|
||||||
std.debug.print("unexpected error: {d}\n", .{@intFromEnum(err)});
|
std.debug.print("unexpected error: {d}\n", .{@intFromEnum(err)});
|
||||||
std.debug.dumpCurrentStackTrace(null);
|
std.debug.dumpCurrentStackTrace(null);
|
||||||
}
|
}
|
||||||
@ -3067,7 +2842,7 @@ pub const MachError = error{
|
|||||||
/// Not enough permissions held to perform the requested kernel
|
/// Not enough permissions held to perform the requested kernel
|
||||||
/// call.
|
/// call.
|
||||||
PermissionDenied,
|
PermissionDenied,
|
||||||
} || std.os.UnexpectedError;
|
} || std.posix.UnexpectedError;
|
||||||
|
|
||||||
pub const MachTask = extern struct {
|
pub const MachTask = extern struct {
|
||||||
port: mach_port_name_t,
|
port: mach_port_name_t,
|
||||||
@ -3076,8 +2851,8 @@ pub const MachTask = extern struct {
|
|||||||
return self.port != TASK_NULL;
|
return self.port != TASK_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pidForTask(self: MachTask) MachError!std.os.pid_t {
|
pub fn pidForTask(self: MachTask) MachError!std.c.pid_t {
|
||||||
var pid: std.os.pid_t = undefined;
|
var pid: std.c.pid_t = undefined;
|
||||||
switch (getKernError(pid_for_task(self.port, &pid))) {
|
switch (getKernError(pid_for_task(self.port, &pid))) {
|
||||||
.SUCCESS => return pid,
|
.SUCCESS => return pid,
|
||||||
.FAILURE => return error.PermissionDenied,
|
.FAILURE => return error.PermissionDenied,
|
||||||
@ -3517,7 +3292,7 @@ pub const MachThread = extern struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn machTaskForPid(pid: std.os.pid_t) MachError!MachTask {
|
pub fn machTaskForPid(pid: std.c.pid_t) MachError!MachTask {
|
||||||
var port: mach_port_name_t = undefined;
|
var port: mach_port_name_t = undefined;
|
||||||
switch (getKernError(task_for_pid(mach_task_self(), pid, &port))) {
|
switch (getKernError(task_for_pid(mach_task_self(), pid, &port))) {
|
||||||
.SUCCESS => {},
|
.SUCCESS => {},
|
||||||
|
|||||||
@ -2,7 +2,7 @@ const builtin = @import("builtin");
|
|||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const maxInt = std.math.maxInt;
|
const maxInt = std.math.maxInt;
|
||||||
const iovec = std.os.iovec;
|
const iovec = std.posix.iovec;
|
||||||
|
|
||||||
extern "c" threadlocal var errno: c_int;
|
extern "c" threadlocal var errno: c_int;
|
||||||
pub fn _errno() *c_int {
|
pub fn _errno() *c_int {
|
||||||
|
|||||||
@ -2,8 +2,8 @@ const std = @import("../std.zig");
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const maxInt = std.math.maxInt;
|
const maxInt = std.math.maxInt;
|
||||||
const iovec = std.os.iovec;
|
const iovec = std.posix.iovec;
|
||||||
const iovec_const = std.os.iovec_const;
|
const iovec_const = std.posix.iovec_const;
|
||||||
|
|
||||||
extern "c" fn __error() *c_int;
|
extern "c" fn __error() *c_int;
|
||||||
pub const _errno = __error;
|
pub const _errno = __error;
|
||||||
|
|||||||
@ -2,8 +2,8 @@ const std = @import("../std.zig");
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const maxInt = std.math.maxInt;
|
const maxInt = std.math.maxInt;
|
||||||
const iovec = std.os.iovec;
|
const iovec = std.posix.iovec;
|
||||||
const iovec_const = std.os.iovec_const;
|
const iovec_const = std.posix.iovec_const;
|
||||||
|
|
||||||
extern "c" fn _errnop() *c_int;
|
extern "c" fn _errnop() *c_int;
|
||||||
|
|
||||||
|
|||||||
@ -3,8 +3,8 @@ const builtin = @import("builtin");
|
|||||||
const native_abi = builtin.abi;
|
const native_abi = builtin.abi;
|
||||||
const native_arch = builtin.cpu.arch;
|
const native_arch = builtin.cpu.arch;
|
||||||
const linux = std.os.linux;
|
const linux = std.os.linux;
|
||||||
const iovec = std.os.iovec;
|
const iovec = std.posix.iovec;
|
||||||
const iovec_const = std.os.iovec_const;
|
const iovec_const = std.posix.iovec_const;
|
||||||
const FILE = std.c.FILE;
|
const FILE = std.c.FILE;
|
||||||
|
|
||||||
pub const AF = linux.AF;
|
pub const AF = linux.AF;
|
||||||
|
|||||||
@ -2,8 +2,8 @@ const std = @import("../std.zig");
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const maxInt = std.math.maxInt;
|
const maxInt = std.math.maxInt;
|
||||||
const iovec = std.os.iovec;
|
const iovec = std.posix.iovec;
|
||||||
const iovec_const = std.os.iovec_const;
|
const iovec_const = std.posix.iovec_const;
|
||||||
const timezone = std.c.timezone;
|
const timezone = std.c.timezone;
|
||||||
const rusage = std.c.rusage;
|
const rusage = std.c.rusage;
|
||||||
|
|
||||||
|
|||||||
@ -2,8 +2,8 @@ const std = @import("../std.zig");
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const maxInt = std.math.maxInt;
|
const maxInt = std.math.maxInt;
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const iovec = std.os.iovec;
|
const iovec = std.posix.iovec;
|
||||||
const iovec_const = std.os.iovec_const;
|
const iovec_const = std.posix.iovec_const;
|
||||||
|
|
||||||
extern "c" fn __errno() *c_int;
|
extern "c" fn __errno() *c_int;
|
||||||
pub const _errno = __errno;
|
pub const _errno = __errno;
|
||||||
|
|||||||
@ -2,8 +2,8 @@ const std = @import("../std.zig");
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const maxInt = std.math.maxInt;
|
const maxInt = std.math.maxInt;
|
||||||
const iovec = std.os.iovec;
|
const iovec = std.posix.iovec;
|
||||||
const iovec_const = std.os.iovec_const;
|
const iovec_const = std.posix.iovec_const;
|
||||||
const timezone = std.c.timezone;
|
const timezone = std.c.timezone;
|
||||||
|
|
||||||
extern "c" fn ___errno() *c_int;
|
extern "c" fn ___errno() *c_int;
|
||||||
|
|||||||
@ -3,30 +3,31 @@ const builtin = @import("builtin");
|
|||||||
const unicode = std.unicode;
|
const unicode = std.unicode;
|
||||||
const io = std.io;
|
const io = std.io;
|
||||||
const fs = std.fs;
|
const fs = std.fs;
|
||||||
const os = std.os;
|
|
||||||
const process = std.process;
|
const process = std.process;
|
||||||
const File = std.fs.File;
|
const File = std.fs.File;
|
||||||
const windows = os.windows;
|
const windows = std.os.windows;
|
||||||
const linux = os.linux;
|
const linux = std.os.linux;
|
||||||
|
const posix = std.posix;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
const debug = std.debug;
|
const debug = std.debug;
|
||||||
const EnvMap = process.EnvMap;
|
const EnvMap = process.EnvMap;
|
||||||
const maxInt = std.math.maxInt;
|
const maxInt = std.math.maxInt;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
const native_os = builtin.os.tag;
|
||||||
|
|
||||||
pub const ChildProcess = struct {
|
pub const ChildProcess = struct {
|
||||||
pub const Id = switch (builtin.os.tag) {
|
pub const Id = switch (native_os) {
|
||||||
.windows => windows.HANDLE,
|
.windows => windows.HANDLE,
|
||||||
.wasi => void,
|
.wasi => void,
|
||||||
else => os.pid_t,
|
else => posix.pid_t,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Available after calling `spawn()`. This becomes `undefined` after calling `wait()`.
|
/// Available after calling `spawn()`. This becomes `undefined` after calling `wait()`.
|
||||||
/// On Windows this is the hProcess.
|
/// On Windows this is the hProcess.
|
||||||
/// On POSIX this is the pid.
|
/// On POSIX this is the pid.
|
||||||
id: Id,
|
id: Id,
|
||||||
thread_handle: if (builtin.os.tag == .windows) windows.HANDLE else void,
|
thread_handle: if (native_os == .windows) windows.HANDLE else void,
|
||||||
|
|
||||||
allocator: mem.Allocator,
|
allocator: mem.Allocator,
|
||||||
|
|
||||||
@ -46,10 +47,10 @@ pub const ChildProcess = struct {
|
|||||||
stderr_behavior: StdIo,
|
stderr_behavior: StdIo,
|
||||||
|
|
||||||
/// Set to change the user id when spawning the child process.
|
/// Set to change the user id when spawning the child process.
|
||||||
uid: if (builtin.os.tag == .windows or builtin.os.tag == .wasi) void else ?os.uid_t,
|
uid: if (native_os == .windows or native_os == .wasi) void else ?posix.uid_t,
|
||||||
|
|
||||||
/// Set to change the group id when spawning the child process.
|
/// Set to change the group id when spawning the child process.
|
||||||
gid: if (builtin.os.tag == .windows or builtin.os.tag == .wasi) void else ?os.gid_t,
|
gid: if (native_os == .windows or native_os == .wasi) void else ?posix.gid_t,
|
||||||
|
|
||||||
/// Set to change the current working directory when spawning the child process.
|
/// Set to change the current working directory when spawning the child process.
|
||||||
cwd: ?[]const u8,
|
cwd: ?[]const u8,
|
||||||
@ -58,7 +59,7 @@ pub const ChildProcess = struct {
|
|||||||
/// Once that is done, `cwd` will be deprecated in favor of this field.
|
/// Once that is done, `cwd` will be deprecated in favor of this field.
|
||||||
cwd_dir: ?fs.Dir = null,
|
cwd_dir: ?fs.Dir = null,
|
||||||
|
|
||||||
err_pipe: ?if (builtin.os.tag == .windows) void else [2]os.fd_t,
|
err_pipe: ?if (native_os == .windows) void else [2]posix.fd_t,
|
||||||
|
|
||||||
expand_arg0: Arg0Expand,
|
expand_arg0: Arg0Expand,
|
||||||
|
|
||||||
@ -87,7 +88,7 @@ pub const ChildProcess = struct {
|
|||||||
/// Returns the peak resident set size of the child process, in bytes,
|
/// Returns the peak resident set size of the child process, in bytes,
|
||||||
/// if available.
|
/// if available.
|
||||||
pub inline fn getMaxRss(rus: ResourceUsageStatistics) ?usize {
|
pub inline fn getMaxRss(rus: ResourceUsageStatistics) ?usize {
|
||||||
switch (builtin.os.tag) {
|
switch (native_os) {
|
||||||
.linux => {
|
.linux => {
|
||||||
if (rus.rusage) |ru| {
|
if (rus.rusage) |ru| {
|
||||||
return @as(usize, @intCast(ru.maxrss)) * 1024;
|
return @as(usize, @intCast(ru.maxrss)) * 1024;
|
||||||
@ -114,14 +115,14 @@ pub const ChildProcess = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const rusage_init = switch (builtin.os.tag) {
|
const rusage_init = switch (native_os) {
|
||||||
.linux, .macos, .ios => @as(?std.os.rusage, null),
|
.linux, .macos, .ios => @as(?posix.rusage, null),
|
||||||
.windows => @as(?windows.VM_COUNTERS, null),
|
.windows => @as(?windows.VM_COUNTERS, null),
|
||||||
else => {},
|
else => {},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Arg0Expand = os.Arg0Expand;
|
pub const Arg0Expand = posix.Arg0Expand;
|
||||||
|
|
||||||
pub const SpawnError = error{
|
pub const SpawnError = error{
|
||||||
OutOfMemory,
|
OutOfMemory,
|
||||||
@ -136,9 +137,9 @@ pub const ChildProcess = struct {
|
|||||||
/// Windows-only. `cwd` was provided, but the path did not exist when spawning the child process.
|
/// Windows-only. `cwd` was provided, but the path did not exist when spawning the child process.
|
||||||
CurrentWorkingDirectoryUnlinked,
|
CurrentWorkingDirectoryUnlinked,
|
||||||
} ||
|
} ||
|
||||||
os.ExecveError ||
|
posix.ExecveError ||
|
||||||
os.SetIdError ||
|
posix.SetIdError ||
|
||||||
os.ChangeCurDirError ||
|
posix.ChangeCurDirError ||
|
||||||
windows.CreateProcessError ||
|
windows.CreateProcessError ||
|
||||||
windows.GetProcessMemoryInfoError ||
|
windows.GetProcessMemoryInfoError ||
|
||||||
windows.WaitForSingleObjectError;
|
windows.WaitForSingleObjectError;
|
||||||
@ -168,8 +169,8 @@ pub const ChildProcess = struct {
|
|||||||
.term = null,
|
.term = null,
|
||||||
.env_map = null,
|
.env_map = null,
|
||||||
.cwd = null,
|
.cwd = null,
|
||||||
.uid = if (builtin.os.tag == .windows or builtin.os.tag == .wasi) {} else null,
|
.uid = if (native_os == .windows or native_os == .wasi) {} else null,
|
||||||
.gid = if (builtin.os.tag == .windows or builtin.os.tag == .wasi) {} else null,
|
.gid = if (native_os == .windows or native_os == .wasi) {} else null,
|
||||||
.stdin = null,
|
.stdin = null,
|
||||||
.stdout = null,
|
.stdout = null,
|
||||||
.stderr = null,
|
.stderr = null,
|
||||||
@ -193,7 +194,7 @@ pub const ChildProcess = struct {
|
|||||||
@compileError("the target operating system cannot spawn processes");
|
@compileError("the target operating system cannot spawn processes");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
return self.spawnWindows();
|
return self.spawnWindows();
|
||||||
} else {
|
} else {
|
||||||
return self.spawnPosix();
|
return self.spawnPosix();
|
||||||
@ -207,7 +208,7 @@ pub const ChildProcess = struct {
|
|||||||
|
|
||||||
/// Forcibly terminates child process and then cleans up all resources.
|
/// Forcibly terminates child process and then cleans up all resources.
|
||||||
pub fn kill(self: *ChildProcess) !Term {
|
pub fn kill(self: *ChildProcess) !Term {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
return self.killWindows(1);
|
return self.killWindows(1);
|
||||||
} else {
|
} else {
|
||||||
return self.killPosix();
|
return self.killPosix();
|
||||||
@ -241,7 +242,7 @@ pub const ChildProcess = struct {
|
|||||||
self.cleanupStreams();
|
self.cleanupStreams();
|
||||||
return term;
|
return term;
|
||||||
}
|
}
|
||||||
os.kill(self.id, os.SIG.TERM) catch |err| switch (err) {
|
posix.kill(self.id, posix.SIG.TERM) catch |err| switch (err) {
|
||||||
error.ProcessNotFound => return error.AlreadyTerminated,
|
error.ProcessNotFound => return error.AlreadyTerminated,
|
||||||
else => return err,
|
else => return err,
|
||||||
};
|
};
|
||||||
@ -251,7 +252,7 @@ pub const ChildProcess = struct {
|
|||||||
|
|
||||||
/// Blocks until child process terminates and then cleans up all resources.
|
/// Blocks until child process terminates and then cleans up all resources.
|
||||||
pub fn wait(self: *ChildProcess) !Term {
|
pub fn wait(self: *ChildProcess) !Term {
|
||||||
const term = if (builtin.os.tag == .windows)
|
const term = if (native_os == .windows)
|
||||||
try self.waitWindows()
|
try self.waitWindows()
|
||||||
else
|
else
|
||||||
try self.waitPosix();
|
try self.waitPosix();
|
||||||
@ -318,7 +319,7 @@ pub const ChildProcess = struct {
|
|||||||
stderr.* = fifoToOwnedArrayList(poller.fifo(.stderr));
|
stderr.* = fifoToOwnedArrayList(poller.fifo(.stderr));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const RunError = os.GetCwdError || os.ReadError || SpawnError || os.PollError || error{
|
pub const RunError = posix.GetCwdError || posix.ReadError || SpawnError || posix.PollError || error{
|
||||||
StdoutStreamTooLong,
|
StdoutStreamTooLong,
|
||||||
StderrStreamTooLong,
|
StderrStreamTooLong,
|
||||||
};
|
};
|
||||||
@ -396,19 +397,19 @@ pub const ChildProcess = struct {
|
|||||||
self.resource_usage_statistics.rusage = try windows.GetProcessMemoryInfo(self.id);
|
self.resource_usage_statistics.rusage = try windows.GetProcessMemoryInfo(self.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
os.close(self.id);
|
posix.close(self.id);
|
||||||
os.close(self.thread_handle);
|
posix.close(self.thread_handle);
|
||||||
self.cleanupStreams();
|
self.cleanupStreams();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn waitUnwrapped(self: *ChildProcess) !void {
|
fn waitUnwrapped(self: *ChildProcess) !void {
|
||||||
const res: os.WaitPidResult = res: {
|
const res: posix.WaitPidResult = res: {
|
||||||
if (self.request_resource_usage_statistics) {
|
if (self.request_resource_usage_statistics) {
|
||||||
switch (builtin.os.tag) {
|
switch (native_os) {
|
||||||
.linux, .macos, .ios => {
|
.linux, .macos, .ios => {
|
||||||
var ru: std.os.rusage = undefined;
|
var ru: posix.rusage = undefined;
|
||||||
const res = os.wait4(self.id, 0, &ru);
|
const res = posix.wait4(self.id, 0, &ru);
|
||||||
self.resource_usage_statistics.rusage = ru;
|
self.resource_usage_statistics.rusage = ru;
|
||||||
break :res res;
|
break :res res;
|
||||||
},
|
},
|
||||||
@ -416,7 +417,7 @@ pub const ChildProcess = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break :res os.waitpid(self.id, 0);
|
break :res posix.waitpid(self.id, 0);
|
||||||
};
|
};
|
||||||
const status = res.status;
|
const status = res.status;
|
||||||
self.cleanupStreams();
|
self.cleanupStreams();
|
||||||
@ -446,20 +447,20 @@ pub const ChildProcess = struct {
|
|||||||
if (self.err_pipe) |err_pipe| {
|
if (self.err_pipe) |err_pipe| {
|
||||||
defer destroyPipe(err_pipe);
|
defer destroyPipe(err_pipe);
|
||||||
|
|
||||||
if (builtin.os.tag == .linux) {
|
if (native_os == .linux) {
|
||||||
var fd = [1]std.os.pollfd{std.os.pollfd{
|
var fd = [1]posix.pollfd{posix.pollfd{
|
||||||
.fd = err_pipe[0],
|
.fd = err_pipe[0],
|
||||||
.events = std.os.POLL.IN,
|
.events = posix.POLL.IN,
|
||||||
.revents = undefined,
|
.revents = undefined,
|
||||||
}};
|
}};
|
||||||
|
|
||||||
// Check if the eventfd buffer stores a non-zero value by polling
|
// Check if the eventfd buffer stores a non-zero value by polling
|
||||||
// it, that's the error code returned by the child process.
|
// it, that's the error code returned by the child process.
|
||||||
_ = std.os.poll(&fd, 0) catch unreachable;
|
_ = posix.poll(&fd, 0) catch unreachable;
|
||||||
|
|
||||||
// According to eventfd(2) the descriptor is readable if the counter
|
// According to eventfd(2) the descriptor is readable if the counter
|
||||||
// has a value greater than 0
|
// has a value greater than 0
|
||||||
if ((fd[0].revents & std.os.POLL.IN) != 0) {
|
if ((fd[0].revents & posix.POLL.IN) != 0) {
|
||||||
const err_int = try readIntFd(err_pipe[0]);
|
const err_int = try readIntFd(err_pipe[0]);
|
||||||
return @as(SpawnError, @errorCast(@errorFromInt(err_int)));
|
return @as(SpawnError, @errorCast(@errorFromInt(err_int)));
|
||||||
}
|
}
|
||||||
@ -483,36 +484,36 @@ pub const ChildProcess = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn statusToTerm(status: u32) Term {
|
fn statusToTerm(status: u32) Term {
|
||||||
return if (os.W.IFEXITED(status))
|
return if (posix.W.IFEXITED(status))
|
||||||
Term{ .Exited = os.W.EXITSTATUS(status) }
|
Term{ .Exited = posix.W.EXITSTATUS(status) }
|
||||||
else if (os.W.IFSIGNALED(status))
|
else if (posix.W.IFSIGNALED(status))
|
||||||
Term{ .Signal = os.W.TERMSIG(status) }
|
Term{ .Signal = posix.W.TERMSIG(status) }
|
||||||
else if (os.W.IFSTOPPED(status))
|
else if (posix.W.IFSTOPPED(status))
|
||||||
Term{ .Stopped = os.W.STOPSIG(status) }
|
Term{ .Stopped = posix.W.STOPSIG(status) }
|
||||||
else
|
else
|
||||||
Term{ .Unknown = status };
|
Term{ .Unknown = status };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawnPosix(self: *ChildProcess) SpawnError!void {
|
fn spawnPosix(self: *ChildProcess) SpawnError!void {
|
||||||
const pipe_flags: os.O = .{};
|
const pipe_flags: posix.O = .{};
|
||||||
const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try os.pipe2(pipe_flags) else undefined;
|
const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try posix.pipe2(pipe_flags) else undefined;
|
||||||
errdefer if (self.stdin_behavior == StdIo.Pipe) {
|
errdefer if (self.stdin_behavior == StdIo.Pipe) {
|
||||||
destroyPipe(stdin_pipe);
|
destroyPipe(stdin_pipe);
|
||||||
};
|
};
|
||||||
|
|
||||||
const stdout_pipe = if (self.stdout_behavior == StdIo.Pipe) try os.pipe2(pipe_flags) else undefined;
|
const stdout_pipe = if (self.stdout_behavior == StdIo.Pipe) try posix.pipe2(pipe_flags) else undefined;
|
||||||
errdefer if (self.stdout_behavior == StdIo.Pipe) {
|
errdefer if (self.stdout_behavior == StdIo.Pipe) {
|
||||||
destroyPipe(stdout_pipe);
|
destroyPipe(stdout_pipe);
|
||||||
};
|
};
|
||||||
|
|
||||||
const stderr_pipe = if (self.stderr_behavior == StdIo.Pipe) try os.pipe2(pipe_flags) else undefined;
|
const stderr_pipe = if (self.stderr_behavior == StdIo.Pipe) try posix.pipe2(pipe_flags) else undefined;
|
||||||
errdefer if (self.stderr_behavior == StdIo.Pipe) {
|
errdefer if (self.stderr_behavior == StdIo.Pipe) {
|
||||||
destroyPipe(stderr_pipe);
|
destroyPipe(stderr_pipe);
|
||||||
};
|
};
|
||||||
|
|
||||||
const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
|
const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
|
||||||
const dev_null_fd = if (any_ignore)
|
const dev_null_fd = if (any_ignore)
|
||||||
os.openZ("/dev/null", .{ .ACCMODE = .RDWR }, 0) catch |err| switch (err) {
|
posix.openZ("/dev/null", .{ .ACCMODE = .RDWR }, 0) catch |err| switch (err) {
|
||||||
error.PathAlreadyExists => unreachable,
|
error.PathAlreadyExists => unreachable,
|
||||||
error.NoSpaceLeft => unreachable,
|
error.NoSpaceLeft => unreachable,
|
||||||
error.FileTooBig => unreachable,
|
error.FileTooBig => unreachable,
|
||||||
@ -526,7 +527,7 @@ pub const ChildProcess = struct {
|
|||||||
else
|
else
|
||||||
undefined;
|
undefined;
|
||||||
defer {
|
defer {
|
||||||
if (any_ignore) os.close(dev_null_fd);
|
if (any_ignore) posix.close(dev_null_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
var arena_allocator = std.heap.ArenaAllocator.init(self.allocator);
|
var arena_allocator = std.heap.ArenaAllocator.init(self.allocator);
|
||||||
@ -554,7 +555,7 @@ pub const ChildProcess = struct {
|
|||||||
} else if (builtin.output_mode == .Exe) {
|
} else if (builtin.output_mode == .Exe) {
|
||||||
// Then we have Zig start code and this works.
|
// Then we have Zig start code and this works.
|
||||||
// TODO type-safety for null-termination of `os.environ`.
|
// TODO type-safety for null-termination of `os.environ`.
|
||||||
break :m @as([*:null]const ?[*:0]const u8, @ptrCast(os.environ.ptr));
|
break :m @as([*:null]const ?[*:0]const u8, @ptrCast(std.os.environ.ptr));
|
||||||
} else {
|
} else {
|
||||||
// TODO come up with a solution for this.
|
// TODO come up with a solution for this.
|
||||||
@compileError("missing std lib enhancement: ChildProcess implementation has no way to collect the environment variables to forward to the child process");
|
@compileError("missing std lib enhancement: ChildProcess implementation has no way to collect the environment variables to forward to the child process");
|
||||||
@ -564,60 +565,60 @@ pub const ChildProcess = struct {
|
|||||||
// This pipe is used to communicate errors between the time of fork
|
// This pipe is used to communicate errors between the time of fork
|
||||||
// and execve from the child process to the parent process.
|
// and execve from the child process to the parent process.
|
||||||
const err_pipe = blk: {
|
const err_pipe = blk: {
|
||||||
if (builtin.os.tag == .linux) {
|
if (native_os == .linux) {
|
||||||
const fd = try os.eventfd(0, linux.EFD.CLOEXEC);
|
const fd = try posix.eventfd(0, linux.EFD.CLOEXEC);
|
||||||
// There's no distinction between the readable and the writeable
|
// There's no distinction between the readable and the writeable
|
||||||
// end with eventfd
|
// end with eventfd
|
||||||
break :blk [2]os.fd_t{ fd, fd };
|
break :blk [2]posix.fd_t{ fd, fd };
|
||||||
} else {
|
} else {
|
||||||
break :blk try os.pipe2(.{ .CLOEXEC = true });
|
break :blk try posix.pipe2(.{ .CLOEXEC = true });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
errdefer destroyPipe(err_pipe);
|
errdefer destroyPipe(err_pipe);
|
||||||
|
|
||||||
const pid_result = try os.fork();
|
const pid_result = try posix.fork();
|
||||||
if (pid_result == 0) {
|
if (pid_result == 0) {
|
||||||
// we are the child
|
// we are the child
|
||||||
setUpChildIo(self.stdin_behavior, stdin_pipe[0], os.STDIN_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
|
setUpChildIo(self.stdin_behavior, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
|
||||||
setUpChildIo(self.stdout_behavior, stdout_pipe[1], os.STDOUT_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
|
setUpChildIo(self.stdout_behavior, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
|
||||||
setUpChildIo(self.stderr_behavior, stderr_pipe[1], os.STDERR_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
|
setUpChildIo(self.stderr_behavior, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
|
||||||
|
|
||||||
if (self.stdin_behavior == .Pipe) {
|
if (self.stdin_behavior == .Pipe) {
|
||||||
os.close(stdin_pipe[0]);
|
posix.close(stdin_pipe[0]);
|
||||||
os.close(stdin_pipe[1]);
|
posix.close(stdin_pipe[1]);
|
||||||
}
|
}
|
||||||
if (self.stdout_behavior == .Pipe) {
|
if (self.stdout_behavior == .Pipe) {
|
||||||
os.close(stdout_pipe[0]);
|
posix.close(stdout_pipe[0]);
|
||||||
os.close(stdout_pipe[1]);
|
posix.close(stdout_pipe[1]);
|
||||||
}
|
}
|
||||||
if (self.stderr_behavior == .Pipe) {
|
if (self.stderr_behavior == .Pipe) {
|
||||||
os.close(stderr_pipe[0]);
|
posix.close(stderr_pipe[0]);
|
||||||
os.close(stderr_pipe[1]);
|
posix.close(stderr_pipe[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.cwd_dir) |cwd| {
|
if (self.cwd_dir) |cwd| {
|
||||||
os.fchdir(cwd.fd) catch |err| forkChildErrReport(err_pipe[1], err);
|
posix.fchdir(cwd.fd) catch |err| forkChildErrReport(err_pipe[1], err);
|
||||||
} else if (self.cwd) |cwd| {
|
} else if (self.cwd) |cwd| {
|
||||||
os.chdir(cwd) catch |err| forkChildErrReport(err_pipe[1], err);
|
posix.chdir(cwd) catch |err| forkChildErrReport(err_pipe[1], err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.gid) |gid| {
|
if (self.gid) |gid| {
|
||||||
os.setregid(gid, gid) catch |err| forkChildErrReport(err_pipe[1], err);
|
posix.setregid(gid, gid) catch |err| forkChildErrReport(err_pipe[1], err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.uid) |uid| {
|
if (self.uid) |uid| {
|
||||||
os.setreuid(uid, uid) catch |err| forkChildErrReport(err_pipe[1], err);
|
posix.setreuid(uid, uid) catch |err| forkChildErrReport(err_pipe[1], err);
|
||||||
}
|
}
|
||||||
|
|
||||||
const err = switch (self.expand_arg0) {
|
const err = switch (self.expand_arg0) {
|
||||||
.expand => os.execvpeZ_expandArg0(.expand, argv_buf.ptr[0].?, argv_buf.ptr, envp),
|
.expand => posix.execvpeZ_expandArg0(.expand, argv_buf.ptr[0].?, argv_buf.ptr, envp),
|
||||||
.no_expand => os.execvpeZ_expandArg0(.no_expand, argv_buf.ptr[0].?, argv_buf.ptr, envp),
|
.no_expand => posix.execvpeZ_expandArg0(.no_expand, argv_buf.ptr[0].?, argv_buf.ptr, envp),
|
||||||
};
|
};
|
||||||
forkChildErrReport(err_pipe[1], err);
|
forkChildErrReport(err_pipe[1], err);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we are the parent
|
// we are the parent
|
||||||
const pid = @as(i32, @intCast(pid_result));
|
const pid: i32 = @intCast(pid_result);
|
||||||
if (self.stdin_behavior == StdIo.Pipe) {
|
if (self.stdin_behavior == StdIo.Pipe) {
|
||||||
self.stdin = File{ .handle = stdin_pipe[1] };
|
self.stdin = File{ .handle = stdin_pipe[1] };
|
||||||
} else {
|
} else {
|
||||||
@ -639,13 +640,13 @@ pub const ChildProcess = struct {
|
|||||||
self.term = null;
|
self.term = null;
|
||||||
|
|
||||||
if (self.stdin_behavior == StdIo.Pipe) {
|
if (self.stdin_behavior == StdIo.Pipe) {
|
||||||
os.close(stdin_pipe[0]);
|
posix.close(stdin_pipe[0]);
|
||||||
}
|
}
|
||||||
if (self.stdout_behavior == StdIo.Pipe) {
|
if (self.stdout_behavior == StdIo.Pipe) {
|
||||||
os.close(stdout_pipe[1]);
|
posix.close(stdout_pipe[1]);
|
||||||
}
|
}
|
||||||
if (self.stderr_behavior == StdIo.Pipe) {
|
if (self.stderr_behavior == StdIo.Pipe) {
|
||||||
os.close(stderr_pipe[1]);
|
posix.close(stderr_pipe[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -679,7 +680,7 @@ pub const ChildProcess = struct {
|
|||||||
else
|
else
|
||||||
undefined;
|
undefined;
|
||||||
defer {
|
defer {
|
||||||
if (any_ignore) os.close(nul_handle);
|
if (any_ignore) posix.close(nul_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
var g_hChildStd_IN_Rd: ?windows.HANDLE = null;
|
var g_hChildStd_IN_Rd: ?windows.HANDLE = null;
|
||||||
@ -821,8 +822,8 @@ pub const ChildProcess = struct {
|
|||||||
defer self.allocator.free(cmd_line_w);
|
defer self.allocator.free(cmd_line_w);
|
||||||
|
|
||||||
run: {
|
run: {
|
||||||
const PATH: [:0]const u16 = std.os.getenvW(unicode.utf8ToUtf16LeStringLiteral("PATH")) orelse &[_:0]u16{};
|
const PATH: [:0]const u16 = std.process.getenvW(unicode.utf8ToUtf16LeStringLiteral("PATH")) orelse &[_:0]u16{};
|
||||||
const PATHEXT: [:0]const u16 = std.os.getenvW(unicode.utf8ToUtf16LeStringLiteral("PATHEXT")) orelse &[_:0]u16{};
|
const PATHEXT: [:0]const u16 = std.process.getenvW(unicode.utf8ToUtf16LeStringLiteral("PATHEXT")) orelse &[_:0]u16{};
|
||||||
|
|
||||||
var app_buf = std.ArrayListUnmanaged(u16){};
|
var app_buf = std.ArrayListUnmanaged(u16){};
|
||||||
defer app_buf.deinit(self.allocator);
|
defer app_buf.deinit(self.allocator);
|
||||||
@ -905,22 +906,22 @@ pub const ChildProcess = struct {
|
|||||||
self.term = null;
|
self.term = null;
|
||||||
|
|
||||||
if (self.stdin_behavior == StdIo.Pipe) {
|
if (self.stdin_behavior == StdIo.Pipe) {
|
||||||
os.close(g_hChildStd_IN_Rd.?);
|
posix.close(g_hChildStd_IN_Rd.?);
|
||||||
}
|
}
|
||||||
if (self.stderr_behavior == StdIo.Pipe) {
|
if (self.stderr_behavior == StdIo.Pipe) {
|
||||||
os.close(g_hChildStd_ERR_Wr.?);
|
posix.close(g_hChildStd_ERR_Wr.?);
|
||||||
}
|
}
|
||||||
if (self.stdout_behavior == StdIo.Pipe) {
|
if (self.stdout_behavior == StdIo.Pipe) {
|
||||||
os.close(g_hChildStd_OUT_Wr.?);
|
posix.close(g_hChildStd_OUT_Wr.?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) !void {
|
fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) !void {
|
||||||
switch (stdio) {
|
switch (stdio) {
|
||||||
.Pipe => try os.dup2(pipe_fd, std_fileno),
|
.Pipe => try posix.dup2(pipe_fd, std_fileno),
|
||||||
.Close => os.close(std_fileno),
|
.Close => posix.close(std_fileno),
|
||||||
.Inherit => {},
|
.Inherit => {},
|
||||||
.Ignore => try os.dup2(dev_null_fd, std_fileno),
|
.Ignore => try posix.dup2(dev_null_fd, std_fileno),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -987,7 +988,7 @@ fn windowsCreateProcessPathExt(
|
|||||||
|
|
||||||
// This 2048 is arbitrary, we just want it to be large enough to get multiple FILE_DIRECTORY_INFORMATION entries
|
// This 2048 is arbitrary, we just want it to be large enough to get multiple FILE_DIRECTORY_INFORMATION entries
|
||||||
// returned per NtQueryDirectoryFile call.
|
// returned per NtQueryDirectoryFile call.
|
||||||
var file_information_buf: [2048]u8 align(@alignOf(os.windows.FILE_DIRECTORY_INFORMATION)) = undefined;
|
var file_information_buf: [2048]u8 align(@alignOf(windows.FILE_DIRECTORY_INFORMATION)) = undefined;
|
||||||
const file_info_maximum_single_entry_size = @sizeOf(windows.FILE_DIRECTORY_INFORMATION) + (windows.NAME_MAX * 2);
|
const file_info_maximum_single_entry_size = @sizeOf(windows.FILE_DIRECTORY_INFORMATION) + (windows.NAME_MAX * 2);
|
||||||
if (file_information_buf.len < file_info_maximum_single_entry_size) {
|
if (file_information_buf.len < file_info_maximum_single_entry_size) {
|
||||||
@compileError("file_information_buf must be large enough to contain at least one maximum size FILE_DIRECTORY_INFORMATION entry");
|
@compileError("file_information_buf must be large enough to contain at least one maximum size FILE_DIRECTORY_INFORMATION entry");
|
||||||
@ -1391,8 +1392,8 @@ fn testArgvToCommandLineWindows(argv: []const []const u8, expected_cmd_line: []c
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn windowsDestroyPipe(rd: ?windows.HANDLE, wr: ?windows.HANDLE) void {
|
fn windowsDestroyPipe(rd: ?windows.HANDLE, wr: ?windows.HANDLE) void {
|
||||||
if (rd) |h| os.close(h);
|
if (rd) |h| posix.close(h);
|
||||||
if (wr) |h| os.close(h);
|
if (wr) |h| posix.close(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn windowsMakePipeIn(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const windows.SECURITY_ATTRIBUTES) !void {
|
fn windowsMakePipeIn(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const windows.SECURITY_ATTRIBUTES) !void {
|
||||||
@ -1443,7 +1444,7 @@ fn windowsMakeAsyncPipe(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *cons
|
|||||||
else => |err| return windows.unexpectedError(err),
|
else => |err| return windows.unexpectedError(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
errdefer os.close(read_handle);
|
errdefer posix.close(read_handle);
|
||||||
|
|
||||||
var sattr_copy = sattr.*;
|
var sattr_copy = sattr.*;
|
||||||
const write_handle = windows.kernel32.CreateFileW(
|
const write_handle = windows.kernel32.CreateFileW(
|
||||||
@ -1460,7 +1461,7 @@ fn windowsMakeAsyncPipe(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *cons
|
|||||||
else => |err| return windows.unexpectedError(err),
|
else => |err| return windows.unexpectedError(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
errdefer os.close(write_handle);
|
errdefer posix.close(write_handle);
|
||||||
|
|
||||||
try windows.SetHandleInformation(read_handle, windows.HANDLE_FLAG_INHERIT, 0);
|
try windows.SetHandleInformation(read_handle, windows.HANDLE_FLAG_INHERIT, 0);
|
||||||
|
|
||||||
@ -1468,9 +1469,9 @@ fn windowsMakeAsyncPipe(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *cons
|
|||||||
wr.* = write_handle;
|
wr.* = write_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroyPipe(pipe: [2]os.fd_t) void {
|
fn destroyPipe(pipe: [2]posix.fd_t) void {
|
||||||
os.close(pipe[0]);
|
posix.close(pipe[0]);
|
||||||
if (pipe[0] != pipe[1]) os.close(pipe[1]);
|
if (pipe[0] != pipe[1]) posix.close(pipe[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Child of fork calls this to report an error to the fork parent.
|
// Child of fork calls this to report an error to the fork parent.
|
||||||
@ -1485,7 +1486,7 @@ fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {
|
|||||||
// The _exit(2) function does nothing but make the exit syscall, unlike exit(3)
|
// The _exit(2) function does nothing but make the exit syscall, unlike exit(3)
|
||||||
std.c._exit(1);
|
std.c._exit(1);
|
||||||
}
|
}
|
||||||
os.exit(1);
|
posix.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ErrInt = std.meta.Int(.unsigned, @sizeOf(anyerror) * 8);
|
const ErrInt = std.meta.Int(.unsigned, @sizeOf(anyerror) * 8);
|
||||||
|
|||||||
@ -125,7 +125,7 @@ fn rescanBSD(cb: *Bundle, gpa: Allocator, cert_file_path: []const u8) RescanBSDE
|
|||||||
cb.bytes.shrinkAndFree(gpa, cb.bytes.items.len);
|
cb.bytes.shrinkAndFree(gpa, cb.bytes.items.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
const RescanWindowsError = Allocator.Error || ParseCertError || std.os.UnexpectedError || error{FileNotFound};
|
const RescanWindowsError = Allocator.Error || ParseCertError || std.posix.UnexpectedError || error{FileNotFound};
|
||||||
|
|
||||||
fn rescanWindows(cb: *Bundle, gpa: Allocator) RescanWindowsError!void {
|
fn rescanWindows(cb: *Bundle, gpa: Allocator) RescanWindowsError!void {
|
||||||
cb.bytes.clearRetainingCapacity();
|
cb.bytes.clearRetainingCapacity();
|
||||||
|
|||||||
@ -42,7 +42,7 @@ pub fn rescanMac(cb: *Bundle, gpa: Allocator) RescanMacError!void {
|
|||||||
|
|
||||||
const table_header = try reader.readStructEndian(TableHeader, .big);
|
const table_header = try reader.readStructEndian(TableHeader, .big);
|
||||||
|
|
||||||
if (@as(std.os.darwin.cssm.DB_RECORDTYPE, @enumFromInt(table_header.table_id)) != .X509_CERTIFICATE) {
|
if (@as(std.c.cssm.DB_RECORDTYPE, @enumFromInt(table_header.table_id)) != .X509_CERTIFICATE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,8 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const os = std.os;
|
const native_os = builtin.os.tag;
|
||||||
|
const posix = std.posix;
|
||||||
|
|
||||||
/// We use this as a layer of indirection because global const pointers cannot
|
/// We use this as a layer of indirection because global const pointers cannot
|
||||||
/// point to thread-local variables.
|
/// point to thread-local variables.
|
||||||
@ -15,7 +16,7 @@ pub const interface = std.Random{
|
|||||||
.fillFn = tlsCsprngFill,
|
.fillFn = tlsCsprngFill,
|
||||||
};
|
};
|
||||||
|
|
||||||
const os_has_fork = switch (builtin.os.tag) {
|
const os_has_fork = switch (native_os) {
|
||||||
.dragonfly,
|
.dragonfly,
|
||||||
.freebsd,
|
.freebsd,
|
||||||
.ios,
|
.ios,
|
||||||
@ -41,7 +42,7 @@ const maybe_have_wipe_on_fork = builtin.os.isAtLeast(.linux, .{
|
|||||||
.minor = 14,
|
.minor = 14,
|
||||||
.patch = 0,
|
.patch = 0,
|
||||||
}) orelse true;
|
}) orelse true;
|
||||||
const is_haiku = builtin.os.tag == .haiku;
|
const is_haiku = native_os == .haiku;
|
||||||
|
|
||||||
const Rng = std.Random.DefaultCsprng;
|
const Rng = std.Random.DefaultCsprng;
|
||||||
|
|
||||||
@ -79,10 +80,10 @@ fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void {
|
|||||||
if (want_fork_safety and maybe_have_wipe_on_fork or is_haiku) {
|
if (want_fork_safety and maybe_have_wipe_on_fork or is_haiku) {
|
||||||
// Allocate a per-process page, madvise operates with page
|
// Allocate a per-process page, madvise operates with page
|
||||||
// granularity.
|
// granularity.
|
||||||
wipe_mem = os.mmap(
|
wipe_mem = posix.mmap(
|
||||||
null,
|
null,
|
||||||
@sizeOf(Context),
|
@sizeOf(Context),
|
||||||
os.PROT.READ | os.PROT.WRITE,
|
posix.PROT.READ | posix.PROT.WRITE,
|
||||||
.{ .TYPE = .PRIVATE, .ANONYMOUS = true },
|
.{ .TYPE = .PRIVATE, .ANONYMOUS = true },
|
||||||
-1,
|
-1,
|
||||||
0,
|
0,
|
||||||
@ -115,11 +116,11 @@ fn tlsCsprngFill(_: *anyopaque, buffer: []u8) void {
|
|||||||
// Qemu user-mode emulation ignores any valid/invalid madvise
|
// Qemu user-mode emulation ignores any valid/invalid madvise
|
||||||
// hint and returns success. Check if this is the case by
|
// hint and returns success. Check if this is the case by
|
||||||
// passing bogus parameters, we expect EINVAL as result.
|
// passing bogus parameters, we expect EINVAL as result.
|
||||||
if (os.madvise(wipe_mem.ptr, 0, 0xffffffff)) |_| {
|
if (posix.madvise(wipe_mem.ptr, 0, 0xffffffff)) |_| {
|
||||||
break :wof;
|
break :wof;
|
||||||
} else |_| {}
|
} else |_| {}
|
||||||
|
|
||||||
if (os.madvise(wipe_mem.ptr, wipe_mem.len, os.MADV.WIPEONFORK)) |_| {
|
if (posix.madvise(wipe_mem.ptr, wipe_mem.len, posix.MADV.WIPEONFORK)) |_| {
|
||||||
return initAndFill(buffer);
|
return initAndFill(buffer);
|
||||||
} else |_| {}
|
} else |_| {}
|
||||||
}
|
}
|
||||||
@ -164,7 +165,7 @@ fn fillWithCsprng(buffer: []u8) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn defaultRandomSeed(buffer: []u8) void {
|
pub fn defaultRandomSeed(buffer: []u8) void {
|
||||||
os.getrandom(buffer) catch @panic("getrandom() failed to provide entropy");
|
posix.getrandom(buffer) catch @panic("getrandom() failed to provide entropy");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initAndFill(buffer: []u8) void {
|
fn initAndFill(buffer: []u8) void {
|
||||||
|
|||||||
@ -62,7 +62,7 @@ pub const StreamInterface = struct {
|
|||||||
/// The `iovecs` parameter is mutable because so that function may to
|
/// The `iovecs` parameter is mutable because so that function may to
|
||||||
/// mutate the fields in order to handle partial reads from the underlying
|
/// mutate the fields in order to handle partial reads from the underlying
|
||||||
/// stream layer.
|
/// stream layer.
|
||||||
pub fn readv(this: @This(), iovecs: []std.os.iovec) ReadError!usize {
|
pub fn readv(this: @This(), iovecs: []std.posix.iovec) ReadError!usize {
|
||||||
_ = .{ this, iovecs };
|
_ = .{ this, iovecs };
|
||||||
@panic("unimplemented");
|
@panic("unimplemented");
|
||||||
}
|
}
|
||||||
@ -72,7 +72,7 @@ pub const StreamInterface = struct {
|
|||||||
|
|
||||||
/// Returns the number of bytes read, which may be less than the buffer
|
/// Returns the number of bytes read, which may be less than the buffer
|
||||||
/// space provided. A short read does not indicate end-of-stream.
|
/// space provided. A short read does not indicate end-of-stream.
|
||||||
pub fn writev(this: @This(), iovecs: []const std.os.iovec_const) WriteError!usize {
|
pub fn writev(this: @This(), iovecs: []const std.posix.iovec_const) WriteError!usize {
|
||||||
_ = .{ this, iovecs };
|
_ = .{ this, iovecs };
|
||||||
@panic("unimplemented");
|
@panic("unimplemented");
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ pub const StreamInterface = struct {
|
|||||||
/// space provided, indicating end-of-stream.
|
/// space provided, indicating end-of-stream.
|
||||||
/// The `iovecs` parameter is mutable in case this function needs to mutate
|
/// The `iovecs` parameter is mutable in case this function needs to mutate
|
||||||
/// the fields in order to handle partial writes from the underlying layer.
|
/// the fields in order to handle partial writes from the underlying layer.
|
||||||
pub fn writevAll(this: @This(), iovecs: []std.os.iovec_const) WriteError!usize {
|
pub fn writevAll(this: @This(), iovecs: []std.posix.iovec_const) WriteError!usize {
|
||||||
// This can be implemented in terms of writev, or specialized if desired.
|
// This can be implemented in terms of writev, or specialized if desired.
|
||||||
_ = .{ this, iovecs };
|
_ = .{ this, iovecs };
|
||||||
@panic("unimplemented");
|
@panic("unimplemented");
|
||||||
@ -215,7 +215,7 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
|
|||||||
} ++ int2(@intCast(out_handshake.len + host_len)) ++ out_handshake;
|
} ++ int2(@intCast(out_handshake.len + host_len)) ++ out_handshake;
|
||||||
|
|
||||||
{
|
{
|
||||||
var iovecs = [_]std.os.iovec_const{
|
var iovecs = [_]std.posix.iovec_const{
|
||||||
.{
|
.{
|
||||||
.iov_base = &plaintext_header,
|
.iov_base = &plaintext_header,
|
||||||
.iov_len = plaintext_header.len,
|
.iov_len = plaintext_header.len,
|
||||||
@ -677,7 +677,7 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
|
|||||||
P.AEAD.encrypt(ciphertext, auth_tag, &out_cleartext, ad, nonce, p.client_handshake_key);
|
P.AEAD.encrypt(ciphertext, auth_tag, &out_cleartext, ad, nonce, p.client_handshake_key);
|
||||||
|
|
||||||
const both_msgs = client_change_cipher_spec_msg ++ finished_msg;
|
const both_msgs = client_change_cipher_spec_msg ++ finished_msg;
|
||||||
var both_msgs_vec = [_]std.os.iovec_const{.{
|
var both_msgs_vec = [_]std.posix.iovec_const{.{
|
||||||
.iov_base = &both_msgs,
|
.iov_base = &both_msgs,
|
||||||
.iov_len = both_msgs.len,
|
.iov_len = both_msgs.len,
|
||||||
}};
|
}};
|
||||||
@ -755,7 +755,7 @@ pub fn writeAllEnd(c: *Client, stream: anytype, bytes: []const u8, end: bool) !v
|
|||||||
/// TLS session, or a truncation attack.
|
/// TLS session, or a truncation attack.
|
||||||
pub fn writeEnd(c: *Client, stream: anytype, bytes: []const u8, end: bool) !usize {
|
pub fn writeEnd(c: *Client, stream: anytype, bytes: []const u8, end: bool) !usize {
|
||||||
var ciphertext_buf: [tls.max_ciphertext_record_len * 4]u8 = undefined;
|
var ciphertext_buf: [tls.max_ciphertext_record_len * 4]u8 = undefined;
|
||||||
var iovecs_buf: [6]std.os.iovec_const = undefined;
|
var iovecs_buf: [6]std.posix.iovec_const = undefined;
|
||||||
var prepared = prepareCiphertextRecord(c, &iovecs_buf, &ciphertext_buf, bytes, .application_data);
|
var prepared = prepareCiphertextRecord(c, &iovecs_buf, &ciphertext_buf, bytes, .application_data);
|
||||||
if (end) {
|
if (end) {
|
||||||
prepared.iovec_end += prepareCiphertextRecord(
|
prepared.iovec_end += prepareCiphertextRecord(
|
||||||
@ -796,7 +796,7 @@ pub fn writeEnd(c: *Client, stream: anytype, bytes: []const u8, end: bool) !usiz
|
|||||||
|
|
||||||
fn prepareCiphertextRecord(
|
fn prepareCiphertextRecord(
|
||||||
c: *Client,
|
c: *Client,
|
||||||
iovecs: []std.os.iovec_const,
|
iovecs: []std.posix.iovec_const,
|
||||||
ciphertext_buf: []u8,
|
ciphertext_buf: []u8,
|
||||||
bytes: []const u8,
|
bytes: []const u8,
|
||||||
inner_content_type: tls.ContentType,
|
inner_content_type: tls.ContentType,
|
||||||
@ -885,7 +885,7 @@ pub fn eof(c: Client) bool {
|
|||||||
/// If the number read is less than `len` it means the stream reached the end.
|
/// If the number read is less than `len` it means the stream reached the end.
|
||||||
/// Reaching the end of the stream is not an error condition.
|
/// Reaching the end of the stream is not an error condition.
|
||||||
pub fn readAtLeast(c: *Client, stream: anytype, buffer: []u8, len: usize) !usize {
|
pub fn readAtLeast(c: *Client, stream: anytype, buffer: []u8, len: usize) !usize {
|
||||||
var iovecs = [1]std.os.iovec{.{ .iov_base = buffer.ptr, .iov_len = buffer.len }};
|
var iovecs = [1]std.posix.iovec{.{ .iov_base = buffer.ptr, .iov_len = buffer.len }};
|
||||||
return readvAtLeast(c, stream, &iovecs, len);
|
return readvAtLeast(c, stream, &iovecs, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -908,7 +908,7 @@ pub fn readAll(c: *Client, stream: anytype, buffer: []u8) !usize {
|
|||||||
/// stream is not an error condition.
|
/// stream is not an error condition.
|
||||||
/// The `iovecs` parameter is mutable because this function needs to mutate the fields in
|
/// The `iovecs` parameter is mutable because this function needs to mutate the fields in
|
||||||
/// order to handle partial reads from the underlying stream layer.
|
/// order to handle partial reads from the underlying stream layer.
|
||||||
pub fn readv(c: *Client, stream: anytype, iovecs: []std.os.iovec) !usize {
|
pub fn readv(c: *Client, stream: anytype, iovecs: []std.posix.iovec) !usize {
|
||||||
return readvAtLeast(c, stream, iovecs, 1);
|
return readvAtLeast(c, stream, iovecs, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -919,7 +919,7 @@ pub fn readv(c: *Client, stream: anytype, iovecs: []std.os.iovec) !usize {
|
|||||||
/// Reaching the end of the stream is not an error condition.
|
/// Reaching the end of the stream is not an error condition.
|
||||||
/// The `iovecs` parameter is mutable because this function needs to mutate the fields in
|
/// The `iovecs` parameter is mutable because this function needs to mutate the fields in
|
||||||
/// order to handle partial reads from the underlying stream layer.
|
/// order to handle partial reads from the underlying stream layer.
|
||||||
pub fn readvAtLeast(c: *Client, stream: anytype, iovecs: []std.os.iovec, len: usize) !usize {
|
pub fn readvAtLeast(c: *Client, stream: anytype, iovecs: []std.posix.iovec, len: usize) !usize {
|
||||||
if (c.eof()) return 0;
|
if (c.eof()) return 0;
|
||||||
|
|
||||||
var off_i: usize = 0;
|
var off_i: usize = 0;
|
||||||
@ -945,7 +945,7 @@ pub fn readvAtLeast(c: *Client, stream: anytype, iovecs: []std.os.iovec, len: us
|
|||||||
/// function asserts that `eof()` is `false`.
|
/// function asserts that `eof()` is `false`.
|
||||||
/// See `readv` for a higher level function that has the same, familiar API as
|
/// See `readv` for a higher level function that has the same, familiar API as
|
||||||
/// other read functions, such as `std.fs.File.read`.
|
/// other read functions, such as `std.fs.File.read`.
|
||||||
pub fn readvAdvanced(c: *Client, stream: anytype, iovecs: []const std.os.iovec) !usize {
|
pub fn readvAdvanced(c: *Client, stream: anytype, iovecs: []const std.posix.iovec) !usize {
|
||||||
var vp: VecPut = .{ .iovecs = iovecs };
|
var vp: VecPut = .{ .iovecs = iovecs };
|
||||||
|
|
||||||
// Give away the buffered cleartext we have, if any.
|
// Give away the buffered cleartext we have, if any.
|
||||||
@ -998,7 +998,7 @@ pub fn readvAdvanced(c: *Client, stream: anytype, iovecs: []const std.os.iovec)
|
|||||||
c.partial_cleartext_idx = 0;
|
c.partial_cleartext_idx = 0;
|
||||||
const first_iov = c.partially_read_buffer[c.partial_ciphertext_end..];
|
const first_iov = c.partially_read_buffer[c.partial_ciphertext_end..];
|
||||||
|
|
||||||
var ask_iovecs_buf: [2]std.os.iovec = .{
|
var ask_iovecs_buf: [2]std.posix.iovec = .{
|
||||||
.{
|
.{
|
||||||
.iov_base = first_iov.ptr,
|
.iov_base = first_iov.ptr,
|
||||||
.iov_len = first_iov.len,
|
.iov_len = first_iov.len,
|
||||||
@ -1352,7 +1352,7 @@ fn SchemeEddsa(comptime scheme: tls.SignatureScheme) type {
|
|||||||
|
|
||||||
/// Abstraction for sending multiple byte buffers to a slice of iovecs.
|
/// Abstraction for sending multiple byte buffers to a slice of iovecs.
|
||||||
const VecPut = struct {
|
const VecPut = struct {
|
||||||
iovecs: []const std.os.iovec,
|
iovecs: []const std.posix.iovec,
|
||||||
idx: usize = 0,
|
idx: usize = 0,
|
||||||
off: usize = 0,
|
off: usize = 0,
|
||||||
total: usize = 0,
|
total: usize = 0,
|
||||||
@ -1413,7 +1413,7 @@ const VecPut = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Limit iovecs to a specific byte size.
|
/// Limit iovecs to a specific byte size.
|
||||||
fn limitVecs(iovecs: []std.os.iovec, len: usize) []std.os.iovec {
|
fn limitVecs(iovecs: []std.posix.iovec, len: usize) []std.posix.iovec {
|
||||||
var bytes_left: usize = len;
|
var bytes_left: usize = len;
|
||||||
for (iovecs, 0..) |*iovec, vec_i| {
|
for (iovecs, 0..) |*iovec, vec_i| {
|
||||||
if (bytes_left <= iovec.iov_len) {
|
if (bytes_left <= iovec.iov_len) {
|
||||||
|
|||||||
@ -3,7 +3,7 @@ const builtin = @import("builtin");
|
|||||||
const math = std.math;
|
const math = std.math;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const io = std.io;
|
const io = std.io;
|
||||||
const os = std.os;
|
const posix = std.posix;
|
||||||
const fs = std.fs;
|
const fs = std.fs;
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const elf = std.elf;
|
const elf = std.elf;
|
||||||
@ -34,7 +34,7 @@ pub const sys_can_stack_trace = switch (builtin.cpu.arch) {
|
|||||||
// "Non-Emscripten WebAssembly hasn't implemented __builtin_return_address".
|
// "Non-Emscripten WebAssembly hasn't implemented __builtin_return_address".
|
||||||
.wasm32,
|
.wasm32,
|
||||||
.wasm64,
|
.wasm64,
|
||||||
=> builtin.os.tag == .emscripten,
|
=> native_os == .emscripten,
|
||||||
|
|
||||||
// `@returnAddress()` is unsupported in LLVM 13.
|
// `@returnAddress()` is unsupported in LLVM 13.
|
||||||
.bpfel,
|
.bpfel,
|
||||||
@ -192,8 +192,8 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const have_ucontext = @hasDecl(os.system, "ucontext_t") and
|
pub const have_ucontext = @hasDecl(posix.system, "ucontext_t") and
|
||||||
(builtin.os.tag != .linux or switch (builtin.cpu.arch) {
|
(native_os != .linux or switch (builtin.cpu.arch) {
|
||||||
.mips, .mipsel, .mips64, .mips64el, .riscv64 => false,
|
.mips, .mipsel, .mips64, .mips64el, .riscv64 => false,
|
||||||
else => true,
|
else => true,
|
||||||
});
|
});
|
||||||
@ -203,9 +203,9 @@ pub const have_ucontext = @hasDecl(os.system, "ucontext_t") and
|
|||||||
/// use internal pointers within this structure. To make a copy, use `copyContext`.
|
/// use internal pointers within this structure. To make a copy, use `copyContext`.
|
||||||
pub const ThreadContext = blk: {
|
pub const ThreadContext = blk: {
|
||||||
if (native_os == .windows) {
|
if (native_os == .windows) {
|
||||||
break :blk std.os.windows.CONTEXT;
|
break :blk windows.CONTEXT;
|
||||||
} else if (have_ucontext) {
|
} else if (have_ucontext) {
|
||||||
break :blk os.ucontext_t;
|
break :blk posix.ucontext_t;
|
||||||
} else {
|
} else {
|
||||||
break :blk void;
|
break :blk void;
|
||||||
}
|
}
|
||||||
@ -228,9 +228,9 @@ pub fn relocateContext(context: *ThreadContext) void {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const have_getcontext = @hasDecl(os.system, "getcontext") and
|
pub const have_getcontext = @hasDecl(posix.system, "getcontext") and
|
||||||
builtin.os.tag != .openbsd and
|
native_os != .openbsd and
|
||||||
(builtin.os.tag != .linux or switch (builtin.cpu.arch) {
|
(native_os != .linux or switch (builtin.cpu.arch) {
|
||||||
.x86,
|
.x86,
|
||||||
.x86_64,
|
.x86_64,
|
||||||
=> true,
|
=> true,
|
||||||
@ -249,7 +249,7 @@ pub inline fn getContext(context: *ThreadContext) bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = have_getcontext and os.system.getcontext(context) == 0;
|
const result = have_getcontext and posix.system.getcontext(context) == 0;
|
||||||
if (native_os == .macos) {
|
if (native_os == .macos) {
|
||||||
assert(context.mcsize == @sizeOf(std.c.mcontext_t));
|
assert(context.mcsize == @sizeOf(std.c.mcontext_t));
|
||||||
|
|
||||||
@ -470,12 +470,12 @@ pub fn panicImpl(trace: ?*const std.builtin.StackTrace, first_trace_addr: ?usize
|
|||||||
|
|
||||||
const stderr = io.getStdErr().writer();
|
const stderr = io.getStdErr().writer();
|
||||||
if (builtin.single_threaded) {
|
if (builtin.single_threaded) {
|
||||||
stderr.print("panic: ", .{}) catch os.abort();
|
stderr.print("panic: ", .{}) catch posix.abort();
|
||||||
} else {
|
} else {
|
||||||
const current_thread_id = std.Thread.getCurrentId();
|
const current_thread_id = std.Thread.getCurrentId();
|
||||||
stderr.print("thread {} panic: ", .{current_thread_id}) catch os.abort();
|
stderr.print("thread {} panic: ", .{current_thread_id}) catch posix.abort();
|
||||||
}
|
}
|
||||||
stderr.print("{s}\n", .{msg}) catch os.abort();
|
stderr.print("{s}\n", .{msg}) catch posix.abort();
|
||||||
if (trace) |t| {
|
if (trace) |t| {
|
||||||
dumpStackTrace(t.*);
|
dumpStackTrace(t.*);
|
||||||
}
|
}
|
||||||
@ -491,14 +491,14 @@ pub fn panicImpl(trace: ?*const std.builtin.StackTrace, first_trace_addr: ?usize
|
|||||||
// we're still holding the mutex but that's fine as we're going to
|
// we're still holding the mutex but that's fine as we're going to
|
||||||
// call abort()
|
// call abort()
|
||||||
const stderr = io.getStdErr().writer();
|
const stderr = io.getStdErr().writer();
|
||||||
stderr.print("Panicked during a panic. Aborting.\n", .{}) catch os.abort();
|
stderr.print("Panicked during a panic. Aborting.\n", .{}) catch posix.abort();
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
// Panicked while printing "Panicked during a panic."
|
// Panicked while printing "Panicked during a panic."
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
os.abort();
|
posix.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Must be called only after adding 1 to `panicking`. There are three callsites.
|
/// Must be called only after adding 1 to `panicking`. There are three callsites.
|
||||||
@ -584,7 +584,7 @@ pub const StackIterator = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initWithContext(first_address: ?usize, debug_info: *DebugInfo, context: *const os.ucontext_t) !StackIterator {
|
pub fn initWithContext(first_address: ?usize, debug_info: *DebugInfo, context: *const posix.ucontext_t) !StackIterator {
|
||||||
// The implementation of DWARF unwinding on aarch64-macos is not complete. However, Apple mandates that
|
// The implementation of DWARF unwinding on aarch64-macos is not complete. However, Apple mandates that
|
||||||
// the frame pointer register is always used, so on this platform we can safely use the FP-based unwinder.
|
// the frame pointer register is always used, so on this platform we can safely use the FP-based unwinder.
|
||||||
if (comptime builtin.target.isDarwin() and native_arch == .aarch64) {
|
if (comptime builtin.target.isDarwin() and native_arch == .aarch64) {
|
||||||
@ -668,12 +668,11 @@ pub const StackIterator = struct {
|
|||||||
const aligned_memory = @as([*]align(mem.page_size) u8, @ptrFromInt(aligned_address))[0..mem.page_size];
|
const aligned_memory = @as([*]align(mem.page_size) u8, @ptrFromInt(aligned_address))[0..mem.page_size];
|
||||||
|
|
||||||
if (native_os == .windows) {
|
if (native_os == .windows) {
|
||||||
const w = os.windows;
|
var memory_info: windows.MEMORY_BASIC_INFORMATION = undefined;
|
||||||
var memory_info: w.MEMORY_BASIC_INFORMATION = undefined;
|
|
||||||
|
|
||||||
// The only error this function can throw is ERROR_INVALID_PARAMETER.
|
// The only error this function can throw is ERROR_INVALID_PARAMETER.
|
||||||
// supply an address that invalid i'll be thrown.
|
// supply an address that invalid i'll be thrown.
|
||||||
const rc = w.VirtualQuery(aligned_memory, &memory_info, aligned_memory.len) catch {
|
const rc = windows.VirtualQuery(aligned_memory, &memory_info, aligned_memory.len) catch {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -683,17 +682,15 @@ pub const StackIterator = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Free pages cannot be read, they are unmapped
|
// Free pages cannot be read, they are unmapped
|
||||||
if (memory_info.State == w.MEM_FREE) {
|
if (memory_info.State == windows.MEM_FREE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else if (@hasDecl(os.system, "msync") and native_os != .wasi and native_os != .emscripten) {
|
} else if (@hasDecl(posix.system, "msync") and native_os != .wasi and native_os != .emscripten) {
|
||||||
os.msync(aligned_memory, os.MSF.ASYNC) catch |err| {
|
posix.msync(aligned_memory, posix.MSF.ASYNC) catch |err| {
|
||||||
switch (err) {
|
switch (err) {
|
||||||
os.MSyncError.UnmappedMemory => {
|
error.UnmappedMemory => return false,
|
||||||
return false;
|
|
||||||
},
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1296,7 +1293,7 @@ pub fn readElfDebugInfo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
var cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
|
var cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
const cwd_path = os.realpath(".", &cwd_buf) catch break :blk;
|
const cwd_path = posix.realpath(".", &cwd_buf) catch break :blk;
|
||||||
|
|
||||||
// <global debug directory>/<absolute folder of current binary>/<gnu_debuglink>
|
// <global debug directory>/<absolute folder of current binary>/<gnu_debuglink>
|
||||||
for (global_debug_directories) |global_directory| {
|
for (global_debug_directories) |global_directory| {
|
||||||
@ -1651,15 +1648,15 @@ fn mapWholeFile(file: File) ![]align(mem.page_size) const u8 {
|
|||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
const file_len = math.cast(usize, try file.getEndPos()) orelse math.maxInt(usize);
|
const file_len = math.cast(usize, try file.getEndPos()) orelse math.maxInt(usize);
|
||||||
const mapped_mem = try os.mmap(
|
const mapped_mem = try posix.mmap(
|
||||||
null,
|
null,
|
||||||
file_len,
|
file_len,
|
||||||
os.PROT.READ,
|
posix.PROT.READ,
|
||||||
.{ .TYPE = .SHARED },
|
.{ .TYPE = .SHARED },
|
||||||
file.handle,
|
file.handle,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
errdefer os.munmap(mapped_mem);
|
errdefer posix.munmap(mapped_mem);
|
||||||
|
|
||||||
return mapped_mem;
|
return mapped_mem;
|
||||||
}
|
}
|
||||||
@ -1997,8 +1994,8 @@ pub const DebugInfo = struct {
|
|||||||
} = .{ .address = address };
|
} = .{ .address = address };
|
||||||
const CtxTy = @TypeOf(ctx);
|
const CtxTy = @TypeOf(ctx);
|
||||||
|
|
||||||
if (os.dl_iterate_phdr(&ctx, error{Found}, struct {
|
if (posix.dl_iterate_phdr(&ctx, error{Found}, struct {
|
||||||
fn callback(info: *os.dl_phdr_info, size: usize, context: *CtxTy) !void {
|
fn callback(info: *posix.dl_phdr_info, size: usize, context: *CtxTy) !void {
|
||||||
_ = size;
|
_ = size;
|
||||||
if (context.address < info.dlpi_addr) return;
|
if (context.address < info.dlpi_addr) return;
|
||||||
const phdrs = info.dlpi_phdr[0..info.dlpi_phnum];
|
const phdrs = info.dlpi_phdr[0..info.dlpi_phnum];
|
||||||
@ -2036,8 +2033,8 @@ pub const DebugInfo = struct {
|
|||||||
} = .{ .address = address };
|
} = .{ .address = address };
|
||||||
const CtxTy = @TypeOf(ctx);
|
const CtxTy = @TypeOf(ctx);
|
||||||
|
|
||||||
if (os.dl_iterate_phdr(&ctx, error{Found}, struct {
|
if (posix.dl_iterate_phdr(&ctx, error{Found}, struct {
|
||||||
fn callback(info: *os.dl_phdr_info, size: usize, context: *CtxTy) !void {
|
fn callback(info: *posix.dl_phdr_info, size: usize, context: *CtxTy) !void {
|
||||||
_ = size;
|
_ = size;
|
||||||
// The base address is too high
|
// The base address is too high
|
||||||
if (context.address < info.dlpi_addr)
|
if (context.address < info.dlpi_addr)
|
||||||
@ -2159,7 +2156,7 @@ pub const ModuleDebugInfo = switch (native_os) {
|
|||||||
}
|
}
|
||||||
self.ofiles.deinit();
|
self.ofiles.deinit();
|
||||||
allocator.free(self.symbols);
|
allocator.free(self.symbols);
|
||||||
os.munmap(self.mapped_memory);
|
posix.munmap(self.mapped_memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loadOFile(self: *@This(), allocator: mem.Allocator, o_file_path: []const u8) !*OFileInfo {
|
fn loadOFile(self: *@This(), allocator: mem.Allocator, o_file_path: []const u8) !*OFileInfo {
|
||||||
@ -2433,8 +2430,8 @@ pub const ModuleDebugInfo = switch (native_os) {
|
|||||||
|
|
||||||
pub fn deinit(self: *@This(), allocator: mem.Allocator) void {
|
pub fn deinit(self: *@This(), allocator: mem.Allocator) void {
|
||||||
self.dwarf.deinit(allocator);
|
self.dwarf.deinit(allocator);
|
||||||
os.munmap(self.mapped_memory);
|
posix.munmap(self.mapped_memory);
|
||||||
if (self.external_mapped_memory) |m| os.munmap(m);
|
if (self.external_mapped_memory) |m| posix.munmap(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getSymbolAtAddress(self: *@This(), allocator: mem.Allocator, address: usize) !SymbolInfo {
|
pub fn getSymbolAtAddress(self: *@This(), allocator: mem.Allocator, address: usize) !SymbolInfo {
|
||||||
@ -2514,7 +2511,7 @@ pub const have_segfault_handling_support = switch (native_os) {
|
|||||||
.windows,
|
.windows,
|
||||||
=> true,
|
=> true,
|
||||||
|
|
||||||
.freebsd, .openbsd => @hasDecl(os.system, "ucontext_t"),
|
.freebsd, .openbsd => @hasDecl(std.c, "ucontext_t"),
|
||||||
else => false,
|
else => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2529,11 +2526,11 @@ pub fn maybeEnableSegfaultHandler() void {
|
|||||||
|
|
||||||
var windows_segfault_handle: ?windows.HANDLE = null;
|
var windows_segfault_handle: ?windows.HANDLE = null;
|
||||||
|
|
||||||
pub fn updateSegfaultHandler(act: ?*const os.Sigaction) error{OperationNotSupported}!void {
|
pub fn updateSegfaultHandler(act: ?*const posix.Sigaction) error{OperationNotSupported}!void {
|
||||||
try os.sigaction(os.SIG.SEGV, act, null);
|
try posix.sigaction(posix.SIG.SEGV, act, null);
|
||||||
try os.sigaction(os.SIG.ILL, act, null);
|
try posix.sigaction(posix.SIG.ILL, act, null);
|
||||||
try os.sigaction(os.SIG.BUS, act, null);
|
try posix.sigaction(posix.SIG.BUS, act, null);
|
||||||
try os.sigaction(os.SIG.FPE, act, null);
|
try posix.sigaction(posix.SIG.FPE, act, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attaches a global SIGSEGV handler which calls `@panic("segmentation fault");`
|
/// Attaches a global SIGSEGV handler which calls `@panic("segmentation fault");`
|
||||||
@ -2545,10 +2542,10 @@ pub fn attachSegfaultHandler() void {
|
|||||||
windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
|
windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var act = os.Sigaction{
|
var act = posix.Sigaction{
|
||||||
.handler = .{ .sigaction = handleSegfaultPosix },
|
.handler = .{ .sigaction = handleSegfaultPosix },
|
||||||
.mask = os.empty_sigset,
|
.mask = posix.empty_sigset,
|
||||||
.flags = (os.SA.SIGINFO | os.SA.RESTART | os.SA.RESETHAND),
|
.flags = (posix.SA.SIGINFO | posix.SA.RESTART | posix.SA.RESETHAND),
|
||||||
};
|
};
|
||||||
|
|
||||||
updateSegfaultHandler(&act) catch {
|
updateSegfaultHandler(&act) catch {
|
||||||
@ -2564,16 +2561,16 @@ fn resetSegfaultHandler() void {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var act = os.Sigaction{
|
var act = posix.Sigaction{
|
||||||
.handler = .{ .handler = os.SIG.DFL },
|
.handler = .{ .handler = posix.SIG.DFL },
|
||||||
.mask = os.empty_sigset,
|
.mask = posix.empty_sigset,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
};
|
};
|
||||||
// To avoid a double-panic, do nothing if an error happens here.
|
// To avoid a double-panic, do nothing if an error happens here.
|
||||||
updateSegfaultHandler(&act) catch {};
|
updateSegfaultHandler(&act) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handleSegfaultPosix(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) noreturn {
|
fn handleSegfaultPosix(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) noreturn {
|
||||||
// Reset to the default handler so that if a segfault happens in this handler it will crash
|
// Reset to the default handler so that if a segfault happens in this handler it will crash
|
||||||
// the process. Also when this handler returns, the original instruction will be repeated
|
// the process. Also when this handler returns, the original instruction will be repeated
|
||||||
// and the resulting segfault will crash the process rather than continually dump stack traces.
|
// and the resulting segfault will crash the process rather than continually dump stack traces.
|
||||||
@ -2612,13 +2609,13 @@ fn handleSegfaultPosix(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const any
|
|||||||
// We cannot allow the signal handler to return because when it runs the original instruction
|
// We cannot allow the signal handler to return because when it runs the original instruction
|
||||||
// again, the memory may be mapped and undefined behavior would occur rather than repeating
|
// again, the memory may be mapped and undefined behavior would occur rather than repeating
|
||||||
// the segfault. So we simply abort here.
|
// the segfault. So we simply abort here.
|
||||||
os.abort();
|
posix.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dumpSegfaultInfoPosix(sig: i32, code: i32, addr: usize, ctx_ptr: ?*const anyopaque) void {
|
fn dumpSegfaultInfoPosix(sig: i32, code: i32, addr: usize, ctx_ptr: ?*const anyopaque) void {
|
||||||
const stderr = io.getStdErr().writer();
|
const stderr = io.getStdErr().writer();
|
||||||
_ = switch (sig) {
|
_ = switch (sig) {
|
||||||
os.SIG.SEGV => if (native_arch == .x86_64 and native_os == .linux and code == 128) // SI_KERNEL
|
posix.SIG.SEGV => if (native_arch == .x86_64 and native_os == .linux and code == 128) // SI_KERNEL
|
||||||
// x86_64 doesn't have a full 64-bit virtual address space.
|
// x86_64 doesn't have a full 64-bit virtual address space.
|
||||||
// Addresses outside of that address space are non-canonical
|
// Addresses outside of that address space are non-canonical
|
||||||
// and the CPU won't provide the faulting address to us.
|
// and the CPU won't provide the faulting address to us.
|
||||||
@ -2629,11 +2626,11 @@ fn dumpSegfaultInfoPosix(sig: i32, code: i32, addr: usize, ctx_ptr: ?*const anyo
|
|||||||
stderr.print("General protection exception (no address available)\n", .{})
|
stderr.print("General protection exception (no address available)\n", .{})
|
||||||
else
|
else
|
||||||
stderr.print("Segmentation fault at address 0x{x}\n", .{addr}),
|
stderr.print("Segmentation fault at address 0x{x}\n", .{addr}),
|
||||||
os.SIG.ILL => stderr.print("Illegal instruction at address 0x{x}\n", .{addr}),
|
posix.SIG.ILL => stderr.print("Illegal instruction at address 0x{x}\n", .{addr}),
|
||||||
os.SIG.BUS => stderr.print("Bus error at address 0x{x}\n", .{addr}),
|
posix.SIG.BUS => stderr.print("Bus error at address 0x{x}\n", .{addr}),
|
||||||
os.SIG.FPE => stderr.print("Arithmetic exception at address 0x{x}\n", .{addr}),
|
posix.SIG.FPE => stderr.print("Arithmetic exception at address 0x{x}\n", .{addr}),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
} catch os.abort();
|
} catch posix.abort();
|
||||||
|
|
||||||
switch (native_arch) {
|
switch (native_arch) {
|
||||||
.x86,
|
.x86,
|
||||||
@ -2641,7 +2638,7 @@ fn dumpSegfaultInfoPosix(sig: i32, code: i32, addr: usize, ctx_ptr: ?*const anyo
|
|||||||
.arm,
|
.arm,
|
||||||
.aarch64,
|
.aarch64,
|
||||||
=> {
|
=> {
|
||||||
const ctx: *const os.ucontext_t = @ptrCast(@alignCast(ctx_ptr));
|
const ctx: *const posix.ucontext_t = @ptrCast(@alignCast(ctx_ptr));
|
||||||
dumpStackTraceFromBase(ctx);
|
dumpStackTraceFromBase(ctx);
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
@ -2684,7 +2681,7 @@ fn handleSegfaultWindowsExtra(
|
|||||||
dumpSegfaultInfoWindows(info, msg, label);
|
dumpSegfaultInfoWindows(info, msg, label);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
os.abort();
|
posix.abort();
|
||||||
} else {
|
} else {
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
0 => panicImpl(null, exception_address, "{s}", label.?),
|
0 => panicImpl(null, exception_address, "{s}", label.?),
|
||||||
@ -2707,7 +2704,7 @@ fn dumpSegfaultInfoWindows(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[
|
|||||||
1 => stderr.print("Segmentation fault at address 0x{x}\n", .{info.ExceptionRecord.ExceptionInformation[1]}),
|
1 => stderr.print("Segmentation fault at address 0x{x}\n", .{info.ExceptionRecord.ExceptionInformation[1]}),
|
||||||
2 => stderr.print("Illegal instruction at address 0x{x}\n", .{info.ContextRecord.getRegs().ip}),
|
2 => stderr.print("Illegal instruction at address 0x{x}\n", .{info.ContextRecord.getRegs().ip}),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
} catch os.abort();
|
} catch posix.abort();
|
||||||
|
|
||||||
dumpStackTraceFromBase(info.ContextRecord);
|
dumpStackTraceFromBase(info.ContextRecord);
|
||||||
}
|
}
|
||||||
@ -2722,9 +2719,9 @@ pub fn dumpStackPointerAddr(prefix: []const u8) void {
|
|||||||
test "manage resources correctly" {
|
test "manage resources correctly" {
|
||||||
if (builtin.strip_debug_info) return error.SkipZigTest;
|
if (builtin.strip_debug_info) return error.SkipZigTest;
|
||||||
|
|
||||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
if (native_os == .wasi) return error.SkipZigTest;
|
||||||
|
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
// https://github.com/ziglang/zig/issues/13963
|
// https://github.com/ziglang/zig/issues/13963
|
||||||
return error.SkipZigTest;
|
return error.SkipZigTest;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2188,12 +2188,12 @@ pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: mem.Allocator) !void {
|
|||||||
/// This function is to make it handy to comment out the return and make it
|
/// This function is to make it handy to comment out the return and make it
|
||||||
/// into a crash when working on this file.
|
/// into a crash when working on this file.
|
||||||
fn badDwarf() error{InvalidDebugInfo} {
|
fn badDwarf() error{InvalidDebugInfo} {
|
||||||
//std.os.abort(); // can be handy to uncomment when working on this file
|
//if (true) @panic("badDwarf"); // can be handy to uncomment when working on this file
|
||||||
return error.InvalidDebugInfo;
|
return error.InvalidDebugInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn missingDwarf() error{MissingDebugInfo} {
|
fn missingDwarf() error{MissingDebugInfo} {
|
||||||
//std.os.abort(); // can be handy to uncomment when working on this file
|
//if (true) @panic("missingDwarf"); // can be handy to uncomment when working on this file
|
||||||
return error.MissingDebugInfo;
|
return error.MissingDebugInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const os = std.os;
|
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
|
const native_os = builtin.os.tag;
|
||||||
|
const posix = std.posix;
|
||||||
|
|
||||||
pub fn supportsUnwinding(target: std.Target) bool {
|
pub fn supportsUnwinding(target: std.Target) bool {
|
||||||
return switch (target.cpu.arch) {
|
return switch (target.cpu.arch) {
|
||||||
@ -138,7 +139,7 @@ pub fn regBytes(
|
|||||||
reg_number: u8,
|
reg_number: u8,
|
||||||
reg_context: ?RegisterContext,
|
reg_context: ?RegisterContext,
|
||||||
) AbiError!RegBytesReturnType(@TypeOf(thread_context_ptr)) {
|
) AbiError!RegBytesReturnType(@TypeOf(thread_context_ptr)) {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
return switch (builtin.cpu.arch) {
|
return switch (builtin.cpu.arch) {
|
||||||
.x86 => switch (reg_number) {
|
.x86 => switch (reg_number) {
|
||||||
0 => mem.asBytes(&thread_context_ptr.Eax),
|
0 => mem.asBytes(&thread_context_ptr.Eax),
|
||||||
@ -193,61 +194,61 @@ pub fn regBytes(
|
|||||||
|
|
||||||
const ucontext_ptr = thread_context_ptr;
|
const ucontext_ptr = thread_context_ptr;
|
||||||
return switch (builtin.cpu.arch) {
|
return switch (builtin.cpu.arch) {
|
||||||
.x86 => switch (builtin.os.tag) {
|
.x86 => switch (native_os) {
|
||||||
.linux, .netbsd, .solaris, .illumos => switch (reg_number) {
|
.linux, .netbsd, .solaris, .illumos => switch (reg_number) {
|
||||||
0 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EAX]),
|
0 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.EAX]),
|
||||||
1 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ECX]),
|
1 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.ECX]),
|
||||||
2 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EDX]),
|
2 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.EDX]),
|
||||||
3 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBX]),
|
3 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.EBX]),
|
||||||
4...5 => if (reg_context) |r| bytes: {
|
4...5 => if (reg_context) |r| bytes: {
|
||||||
if (reg_number == 4) {
|
if (reg_number == 4) {
|
||||||
break :bytes if (r.eh_frame and r.is_macho)
|
break :bytes if (r.eh_frame and r.is_macho)
|
||||||
mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBP])
|
mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.EBP])
|
||||||
else
|
else
|
||||||
mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ESP]);
|
mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.ESP]);
|
||||||
} else {
|
} else {
|
||||||
break :bytes if (r.eh_frame and r.is_macho)
|
break :bytes if (r.eh_frame and r.is_macho)
|
||||||
mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ESP])
|
mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.ESP])
|
||||||
else
|
else
|
||||||
mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EBP]);
|
mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.EBP]);
|
||||||
}
|
}
|
||||||
} else error.RegisterContextRequired,
|
} else error.RegisterContextRequired,
|
||||||
6 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ESI]),
|
6 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.ESI]),
|
||||||
7 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EDI]),
|
7 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.EDI]),
|
||||||
8 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EIP]),
|
8 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.EIP]),
|
||||||
9 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.EFL]),
|
9 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.EFL]),
|
||||||
10 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.CS]),
|
10 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.CS]),
|
||||||
11 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.SS]),
|
11 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.SS]),
|
||||||
12 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.DS]),
|
12 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.DS]),
|
||||||
13 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.ES]),
|
13 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.ES]),
|
||||||
14 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.FS]),
|
14 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.FS]),
|
||||||
15 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.GS]),
|
15 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.GS]),
|
||||||
16...23 => error.InvalidRegister, // TODO: Support loading ST0-ST7 from mcontext.fpregs
|
16...23 => error.InvalidRegister, // TODO: Support loading ST0-ST7 from mcontext.fpregs
|
||||||
32...39 => error.InvalidRegister, // TODO: Support loading XMM0-XMM7 from mcontext.fpregs
|
32...39 => error.InvalidRegister, // TODO: Support loading XMM0-XMM7 from mcontext.fpregs
|
||||||
else => error.InvalidRegister,
|
else => error.InvalidRegister,
|
||||||
},
|
},
|
||||||
else => error.UnimplementedOs,
|
else => error.UnimplementedOs,
|
||||||
},
|
},
|
||||||
.x86_64 => switch (builtin.os.tag) {
|
.x86_64 => switch (native_os) {
|
||||||
.linux, .solaris, .illumos => switch (reg_number) {
|
.linux, .solaris, .illumos => switch (reg_number) {
|
||||||
0 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RAX]),
|
0 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.RAX]),
|
||||||
1 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RDX]),
|
1 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.RDX]),
|
||||||
2 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RCX]),
|
2 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.RCX]),
|
||||||
3 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RBX]),
|
3 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.RBX]),
|
||||||
4 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RSI]),
|
4 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.RSI]),
|
||||||
5 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RDI]),
|
5 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.RDI]),
|
||||||
6 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RBP]),
|
6 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.RBP]),
|
||||||
7 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RSP]),
|
7 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.RSP]),
|
||||||
8 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R8]),
|
8 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.R8]),
|
||||||
9 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R9]),
|
9 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.R9]),
|
||||||
10 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R10]),
|
10 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.R10]),
|
||||||
11 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R11]),
|
11 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.R11]),
|
||||||
12 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R12]),
|
12 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.R12]),
|
||||||
13 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R13]),
|
13 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.R13]),
|
||||||
14 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R14]),
|
14 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.R14]),
|
||||||
15 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.R15]),
|
15 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.R15]),
|
||||||
16 => mem.asBytes(&ucontext_ptr.mcontext.gregs[os.REG.RIP]),
|
16 => mem.asBytes(&ucontext_ptr.mcontext.gregs[posix.REG.RIP]),
|
||||||
17...32 => |i| if (builtin.os.tag.isSolarish())
|
17...32 => |i| if (native_os.isSolarish())
|
||||||
mem.asBytes(&ucontext_ptr.mcontext.fpregs.chip_state.xmm[i - 17])
|
mem.asBytes(&ucontext_ptr.mcontext.fpregs.chip_state.xmm[i - 17])
|
||||||
else
|
else
|
||||||
mem.asBytes(&ucontext_ptr.mcontext.fpregs.xmm[i - 17]),
|
mem.asBytes(&ucontext_ptr.mcontext.fpregs.xmm[i - 17]),
|
||||||
@ -317,7 +318,7 @@ pub fn regBytes(
|
|||||||
},
|
},
|
||||||
else => error.UnimplementedOs,
|
else => error.UnimplementedOs,
|
||||||
},
|
},
|
||||||
.arm => switch (builtin.os.tag) {
|
.arm => switch (native_os) {
|
||||||
.linux => switch (reg_number) {
|
.linux => switch (reg_number) {
|
||||||
0 => mem.asBytes(&ucontext_ptr.mcontext.arm_r0),
|
0 => mem.asBytes(&ucontext_ptr.mcontext.arm_r0),
|
||||||
1 => mem.asBytes(&ucontext_ptr.mcontext.arm_r1),
|
1 => mem.asBytes(&ucontext_ptr.mcontext.arm_r1),
|
||||||
@ -340,7 +341,7 @@ pub fn regBytes(
|
|||||||
},
|
},
|
||||||
else => error.UnimplementedOs,
|
else => error.UnimplementedOs,
|
||||||
},
|
},
|
||||||
.aarch64 => switch (builtin.os.tag) {
|
.aarch64 => switch (native_os) {
|
||||||
.macos, .ios => switch (reg_number) {
|
.macos, .ios => switch (reg_number) {
|
||||||
0...28 => mem.asBytes(&ucontext_ptr.mcontext.ss.regs[reg_number]),
|
0...28 => mem.asBytes(&ucontext_ptr.mcontext.ss.regs[reg_number]),
|
||||||
29 => mem.asBytes(&ucontext_ptr.mcontext.ss.fp),
|
29 => mem.asBytes(&ucontext_ptr.mcontext.ss.fp),
|
||||||
|
|||||||
@ -1,16 +1,16 @@
|
|||||||
const std = @import("std.zig");
|
const std = @import("std.zig");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const os = std.os;
|
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const elf = std.elf;
|
const elf = std.elf;
|
||||||
const windows = std.os.windows;
|
const windows = std.os.windows;
|
||||||
const system = std.os.system;
|
const native_os = builtin.os.tag;
|
||||||
|
const posix = std.posix;
|
||||||
|
|
||||||
/// Cross-platform dynamic library loading and symbol lookup.
|
/// Cross-platform dynamic library loading and symbol lookup.
|
||||||
/// Platform-specific functionality is available through the `inner` field.
|
/// Platform-specific functionality is available through the `inner` field.
|
||||||
pub const DynLib = struct {
|
pub const DynLib = struct {
|
||||||
const InnerType = switch (builtin.os.tag) {
|
const InnerType = switch (native_os) {
|
||||||
.linux => if (!builtin.link_libc or builtin.abi == .musl and builtin.link_mode == .static)
|
.linux => if (!builtin.link_libc or builtin.abi == .musl and builtin.link_mode == .static)
|
||||||
ElfDynLib
|
ElfDynLib
|
||||||
else
|
else
|
||||||
@ -125,7 +125,7 @@ pub fn linkmap_iterator(phdrs: []elf.Phdr) error{InvalidExe}!LinkMap.Iterator {
|
|||||||
pub const ElfDynLib = struct {
|
pub const ElfDynLib = struct {
|
||||||
strings: [*:0]u8,
|
strings: [*:0]u8,
|
||||||
syms: [*]elf.Sym,
|
syms: [*]elf.Sym,
|
||||||
hashtab: [*]os.Elf_Symndx,
|
hashtab: [*]posix.Elf_Symndx,
|
||||||
versym: ?[*]u16,
|
versym: ?[*]u16,
|
||||||
verdef: ?*elf.Verdef,
|
verdef: ?*elf.Verdef,
|
||||||
memory: []align(mem.page_size) u8,
|
memory: []align(mem.page_size) u8,
|
||||||
@ -138,27 +138,27 @@ pub const ElfDynLib = struct {
|
|||||||
ElfStringSectionNotFound,
|
ElfStringSectionNotFound,
|
||||||
ElfSymSectionNotFound,
|
ElfSymSectionNotFound,
|
||||||
ElfHashTableNotFound,
|
ElfHashTableNotFound,
|
||||||
} || os.OpenError || os.MMapError;
|
} || posix.OpenError || posix.MMapError;
|
||||||
|
|
||||||
/// Trusts the file. Malicious file will be able to execute arbitrary code.
|
/// Trusts the file. Malicious file will be able to execute arbitrary code.
|
||||||
pub fn open(path: []const u8) Error!ElfDynLib {
|
pub fn open(path: []const u8) Error!ElfDynLib {
|
||||||
const fd = try os.open(path, .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
|
const fd = try posix.open(path, .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
|
||||||
defer os.close(fd);
|
defer posix.close(fd);
|
||||||
|
|
||||||
const stat = try os.fstat(fd);
|
const stat = try posix.fstat(fd);
|
||||||
const size = std.math.cast(usize, stat.size) orelse return error.FileTooBig;
|
const size = std.math.cast(usize, stat.size) orelse return error.FileTooBig;
|
||||||
|
|
||||||
// This one is to read the ELF info. We do more mmapping later
|
// This one is to read the ELF info. We do more mmapping later
|
||||||
// corresponding to the actual LOAD sections.
|
// corresponding to the actual LOAD sections.
|
||||||
const file_bytes = try os.mmap(
|
const file_bytes = try posix.mmap(
|
||||||
null,
|
null,
|
||||||
mem.alignForward(usize, size, mem.page_size),
|
mem.alignForward(usize, size, mem.page_size),
|
||||||
os.PROT.READ,
|
posix.PROT.READ,
|
||||||
.{ .TYPE = .PRIVATE },
|
.{ .TYPE = .PRIVATE },
|
||||||
fd,
|
fd,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
defer os.munmap(file_bytes);
|
defer posix.munmap(file_bytes);
|
||||||
|
|
||||||
const eh = @as(*elf.Ehdr, @ptrCast(file_bytes.ptr));
|
const eh = @as(*elf.Ehdr, @ptrCast(file_bytes.ptr));
|
||||||
if (!mem.eql(u8, eh.e_ident[0..4], elf.MAGIC)) return error.NotElfFile;
|
if (!mem.eql(u8, eh.e_ident[0..4], elf.MAGIC)) return error.NotElfFile;
|
||||||
@ -188,15 +188,15 @@ pub const ElfDynLib = struct {
|
|||||||
const dynv = maybe_dynv orelse return error.MissingDynamicLinkingInformation;
|
const dynv = maybe_dynv orelse return error.MissingDynamicLinkingInformation;
|
||||||
|
|
||||||
// Reserve the entire range (with no permissions) so that we can do MAP.FIXED below.
|
// Reserve the entire range (with no permissions) so that we can do MAP.FIXED below.
|
||||||
const all_loaded_mem = try os.mmap(
|
const all_loaded_mem = try posix.mmap(
|
||||||
null,
|
null,
|
||||||
virt_addr_end,
|
virt_addr_end,
|
||||||
os.PROT.NONE,
|
posix.PROT.NONE,
|
||||||
.{ .TYPE = .PRIVATE, .ANONYMOUS = true },
|
.{ .TYPE = .PRIVATE, .ANONYMOUS = true },
|
||||||
-1,
|
-1,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
errdefer os.munmap(all_loaded_mem);
|
errdefer posix.munmap(all_loaded_mem);
|
||||||
|
|
||||||
const base = @intFromPtr(all_loaded_mem.ptr);
|
const base = @intFromPtr(all_loaded_mem.ptr);
|
||||||
|
|
||||||
@ -220,7 +220,7 @@ pub const ElfDynLib = struct {
|
|||||||
const prot = elfToMmapProt(ph.p_flags);
|
const prot = elfToMmapProt(ph.p_flags);
|
||||||
if ((ph.p_flags & elf.PF_W) == 0) {
|
if ((ph.p_flags & elf.PF_W) == 0) {
|
||||||
// If it does not need write access, it can be mapped from the fd.
|
// If it does not need write access, it can be mapped from the fd.
|
||||||
_ = try os.mmap(
|
_ = try posix.mmap(
|
||||||
ptr,
|
ptr,
|
||||||
extended_memsz,
|
extended_memsz,
|
||||||
prot,
|
prot,
|
||||||
@ -229,7 +229,7 @@ pub const ElfDynLib = struct {
|
|||||||
ph.p_offset - extra_bytes,
|
ph.p_offset - extra_bytes,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const sect_mem = try os.mmap(
|
const sect_mem = try posix.mmap(
|
||||||
ptr,
|
ptr,
|
||||||
extended_memsz,
|
extended_memsz,
|
||||||
prot,
|
prot,
|
||||||
@ -247,7 +247,7 @@ pub const ElfDynLib = struct {
|
|||||||
|
|
||||||
var maybe_strings: ?[*:0]u8 = null;
|
var maybe_strings: ?[*:0]u8 = null;
|
||||||
var maybe_syms: ?[*]elf.Sym = null;
|
var maybe_syms: ?[*]elf.Sym = null;
|
||||||
var maybe_hashtab: ?[*]os.Elf_Symndx = null;
|
var maybe_hashtab: ?[*]posix.Elf_Symndx = null;
|
||||||
var maybe_versym: ?[*]u16 = null;
|
var maybe_versym: ?[*]u16 = null;
|
||||||
var maybe_verdef: ?*elf.Verdef = null;
|
var maybe_verdef: ?*elf.Verdef = null;
|
||||||
|
|
||||||
@ -258,7 +258,7 @@ pub const ElfDynLib = struct {
|
|||||||
switch (dynv[i]) {
|
switch (dynv[i]) {
|
||||||
elf.DT_STRTAB => maybe_strings = @as([*:0]u8, @ptrFromInt(p)),
|
elf.DT_STRTAB => maybe_strings = @as([*:0]u8, @ptrFromInt(p)),
|
||||||
elf.DT_SYMTAB => maybe_syms = @as([*]elf.Sym, @ptrFromInt(p)),
|
elf.DT_SYMTAB => maybe_syms = @as([*]elf.Sym, @ptrFromInt(p)),
|
||||||
elf.DT_HASH => maybe_hashtab = @as([*]os.Elf_Symndx, @ptrFromInt(p)),
|
elf.DT_HASH => maybe_hashtab = @as([*]posix.Elf_Symndx, @ptrFromInt(p)),
|
||||||
elf.DT_VERSYM => maybe_versym = @as([*]u16, @ptrFromInt(p)),
|
elf.DT_VERSYM => maybe_versym = @as([*]u16, @ptrFromInt(p)),
|
||||||
elf.DT_VERDEF => maybe_verdef = @as(*elf.Verdef, @ptrFromInt(p)),
|
elf.DT_VERDEF => maybe_verdef = @as(*elf.Verdef, @ptrFromInt(p)),
|
||||||
else => {},
|
else => {},
|
||||||
@ -283,7 +283,7 @@ pub const ElfDynLib = struct {
|
|||||||
|
|
||||||
/// Trusts the file
|
/// Trusts the file
|
||||||
pub fn close(self: *ElfDynLib) void {
|
pub fn close(self: *ElfDynLib) void {
|
||||||
os.munmap(self.memory);
|
posix.munmap(self.memory);
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,10 +320,10 @@ pub const ElfDynLib = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn elfToMmapProt(elf_prot: u64) u32 {
|
fn elfToMmapProt(elf_prot: u64) u32 {
|
||||||
var result: u32 = os.PROT.NONE;
|
var result: u32 = posix.PROT.NONE;
|
||||||
if ((elf_prot & elf.PF_R) != 0) result |= os.PROT.READ;
|
if ((elf_prot & elf.PF_R) != 0) result |= posix.PROT.READ;
|
||||||
if ((elf_prot & elf.PF_W) != 0) result |= os.PROT.WRITE;
|
if ((elf_prot & elf.PF_W) != 0) result |= posix.PROT.WRITE;
|
||||||
if ((elf_prot & elf.PF_X) != 0) result |= os.PROT.EXEC;
|
if ((elf_prot & elf.PF_X) != 0) result |= posix.PROT.EXEC;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -343,7 +343,7 @@ fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "ElfDynLib" {
|
test "ElfDynLib" {
|
||||||
if (builtin.os.tag != .linux) {
|
if (native_os != .linux) {
|
||||||
return error.SkipZigTest;
|
return error.SkipZigTest;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,20 +419,20 @@ pub const DlDynLib = struct {
|
|||||||
handle: *anyopaque,
|
handle: *anyopaque,
|
||||||
|
|
||||||
pub fn open(path: []const u8) Error!DlDynLib {
|
pub fn open(path: []const u8) Error!DlDynLib {
|
||||||
const path_c = try os.toPosixPath(path);
|
const path_c = try posix.toPosixPath(path);
|
||||||
return openZ(&path_c);
|
return openZ(&path_c);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn openZ(path_c: [*:0]const u8) Error!DlDynLib {
|
pub fn openZ(path_c: [*:0]const u8) Error!DlDynLib {
|
||||||
return .{
|
return .{
|
||||||
.handle = system.dlopen(path_c, system.RTLD.LAZY) orelse {
|
.handle = std.c.dlopen(path_c, std.c.RTLD.LAZY) orelse {
|
||||||
return error.FileNotFound;
|
return error.FileNotFound;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(self: *DlDynLib) void {
|
pub fn close(self: *DlDynLib) void {
|
||||||
switch (std.os.errno(system.dlclose(self.handle))) {
|
switch (posix.errno(std.c.dlclose(self.handle))) {
|
||||||
.SUCCESS => return,
|
.SUCCESS => return,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
@ -442,7 +442,7 @@ pub const DlDynLib = struct {
|
|||||||
pub fn lookup(self: *DlDynLib, comptime T: type, name: [:0]const u8) ?T {
|
pub fn lookup(self: *DlDynLib, comptime T: type, name: [:0]const u8) ?T {
|
||||||
// dlsym (and other dl-functions) secretly take shadow parameter - return address on stack
|
// dlsym (and other dl-functions) secretly take shadow parameter - return address on stack
|
||||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66826
|
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66826
|
||||||
if (@call(.never_tail, system.dlsym, .{ self.handle, name.ptr })) |symbol| {
|
if (@call(.never_tail, std.c.dlsym, .{ self.handle, name.ptr })) |symbol| {
|
||||||
return @as(T, @ptrCast(@alignCast(symbol)));
|
return @as(T, @ptrCast(@alignCast(symbol)));
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
@ -453,12 +453,12 @@ pub const DlDynLib = struct {
|
|||||||
/// Returns human readable string describing most recent error than occurred from `lookup`
|
/// Returns human readable string describing most recent error than occurred from `lookup`
|
||||||
/// or `null` if no error has occurred since initialization or when `getError` was last called.
|
/// or `null` if no error has occurred since initialization or when `getError` was last called.
|
||||||
pub fn getError() ?[:0]const u8 {
|
pub fn getError() ?[:0]const u8 {
|
||||||
return mem.span(system.dlerror());
|
return mem.span(std.c.dlerror());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
test "dynamic_library" {
|
test "dynamic_library" {
|
||||||
const libname = switch (builtin.os.tag) {
|
const libname = switch (native_os) {
|
||||||
.linux, .freebsd, .openbsd, .solaris, .illumos => "invalid_so.so",
|
.linux, .freebsd, .openbsd, .solaris, .illumos => "invalid_so.so",
|
||||||
.windows => "invalid_dll.dll",
|
.windows => "invalid_dll.dll",
|
||||||
.macos, .tvos, .watchos, .ios => "invalid_dylib.dylib",
|
.macos, .tvos, .watchos, .ios => "invalid_dylib.dylib",
|
||||||
|
|||||||
169
lib/std/fs.zig
169
lib/std/fs.zig
@ -3,21 +3,23 @@
|
|||||||
const std = @import("std.zig");
|
const std = @import("std.zig");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const root = @import("root");
|
const root = @import("root");
|
||||||
const os = std.os;
|
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const base64 = std.base64;
|
const base64 = std.base64;
|
||||||
const crypto = std.crypto;
|
const crypto = std.crypto;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
const native_os = builtin.os.tag;
|
||||||
|
const posix = std.posix;
|
||||||
|
const windows = std.os.windows;
|
||||||
|
|
||||||
const is_darwin = builtin.os.tag.isDarwin();
|
const is_darwin = native_os.isDarwin();
|
||||||
|
|
||||||
pub const AtomicFile = @import("fs/AtomicFile.zig");
|
pub const AtomicFile = @import("fs/AtomicFile.zig");
|
||||||
pub const Dir = @import("fs/Dir.zig");
|
pub const Dir = @import("fs/Dir.zig");
|
||||||
pub const File = @import("fs/File.zig");
|
pub const File = @import("fs/File.zig");
|
||||||
pub const path = @import("fs/path.zig");
|
pub const path = @import("fs/path.zig");
|
||||||
|
|
||||||
pub const has_executable_bit = switch (builtin.os.tag) {
|
pub const has_executable_bit = switch (native_os) {
|
||||||
.windows, .wasi => false,
|
.windows, .wasi => false,
|
||||||
else => true,
|
else => true,
|
||||||
};
|
};
|
||||||
@ -26,36 +28,43 @@ pub const wasi = @import("fs/wasi.zig");
|
|||||||
|
|
||||||
// TODO audit these APIs with respect to Dir and absolute paths
|
// TODO audit these APIs with respect to Dir and absolute paths
|
||||||
|
|
||||||
pub const realpath = os.realpath;
|
pub const realpath = posix.realpath;
|
||||||
pub const realpathZ = os.realpathZ;
|
pub const realpathZ = posix.realpathZ;
|
||||||
pub const realpathW = os.realpathW;
|
pub const realpathW = posix.realpathW;
|
||||||
|
|
||||||
pub const getAppDataDir = @import("fs/get_app_data_dir.zig").getAppDataDir;
|
pub const getAppDataDir = @import("fs/get_app_data_dir.zig").getAppDataDir;
|
||||||
pub const GetAppDataDirError = @import("fs/get_app_data_dir.zig").GetAppDataDirError;
|
pub const GetAppDataDirError = @import("fs/get_app_data_dir.zig").GetAppDataDirError;
|
||||||
|
|
||||||
/// This represents the maximum size of a `[]u8` file path that the
|
/// Deprecated: use `max_path_bytes`.
|
||||||
/// operating system will accept. Paths, including those returned from file
|
pub const MAX_PATH_BYTES = max_path_bytes;
|
||||||
/// system operations, may be longer than this length, but such paths cannot
|
|
||||||
/// be successfully passed back in other file system operations. However,
|
/// The maximum length of a file path that the operating system will accept.
|
||||||
/// all path components returned by file system operations are assumed to
|
///
|
||||||
/// fit into a `u8` array of this length.
|
/// Paths, including those returned from file system operations, may be longer
|
||||||
|
/// than this length, but such paths cannot be successfully passed back in
|
||||||
|
/// other file system operations. However, all path components returned by file
|
||||||
|
/// system operations are assumed to fit into a `u8` array of this length.
|
||||||
|
///
|
||||||
/// The byte count includes room for a null sentinel byte.
|
/// The byte count includes room for a null sentinel byte.
|
||||||
/// On Windows, `[]u8` file paths are encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
|
///
|
||||||
/// On WASI, `[]u8` file paths are encoded as valid UTF-8.
|
/// * On Windows, `[]u8` file paths are encoded as
|
||||||
/// On other platforms, `[]u8` file paths are opaque sequences of bytes with no particular encoding.
|
/// [WTF-8](https://simonsapin.github.io/wtf-8/).
|
||||||
pub const MAX_PATH_BYTES = switch (builtin.os.tag) {
|
/// * On WASI, `[]u8` file paths are encoded as valid UTF-8.
|
||||||
.linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly, .haiku, .solaris, .illumos, .plan9, .emscripten => os.PATH_MAX,
|
/// * On other platforms, `[]u8` file paths are opaque sequences of bytes with
|
||||||
|
/// no particular encoding.
|
||||||
|
pub const max_path_bytes = switch (native_os) {
|
||||||
|
.linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly, .haiku, .solaris, .illumos, .plan9, .emscripten => posix.PATH_MAX,
|
||||||
// Each WTF-16LE code unit may be expanded to 3 WTF-8 bytes.
|
// Each WTF-16LE code unit may be expanded to 3 WTF-8 bytes.
|
||||||
// If it would require 4 WTF-8 bytes, then there would be a surrogate
|
// If it would require 4 WTF-8 bytes, then there would be a surrogate
|
||||||
// pair in the WTF-16LE, and we (over)account 3 bytes for it that way.
|
// pair in the WTF-16LE, and we (over)account 3 bytes for it that way.
|
||||||
// +1 for the null byte at the end, which can be encoded in 1 byte.
|
// +1 for the null byte at the end, which can be encoded in 1 byte.
|
||||||
.windows => os.windows.PATH_MAX_WIDE * 3 + 1,
|
.windows => windows.PATH_MAX_WIDE * 3 + 1,
|
||||||
// TODO work out what a reasonable value we should use here
|
// TODO work out what a reasonable value we should use here
|
||||||
.wasi => 4096,
|
.wasi => 4096,
|
||||||
else => if (@hasDecl(root, "os") and @hasDecl(root.os, "PATH_MAX"))
|
else => if (@hasDecl(root, "os") and @hasDecl(root.os, "PATH_MAX"))
|
||||||
root.os.PATH_MAX
|
root.os.PATH_MAX
|
||||||
else
|
else
|
||||||
@compileError("PATH_MAX not implemented for " ++ @tagName(builtin.os.tag)),
|
@compileError("PATH_MAX not implemented for " ++ @tagName(native_os)),
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This represents the maximum size of a `[]u8` file name component that
|
/// This represents the maximum size of a `[]u8` file name component that
|
||||||
@ -66,22 +75,22 @@ pub const MAX_PATH_BYTES = switch (builtin.os.tag) {
|
|||||||
/// On Windows, `[]u8` file name components are encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
|
/// On Windows, `[]u8` file name components are encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
|
||||||
/// On WASI, file name components are encoded as valid UTF-8.
|
/// On WASI, file name components are encoded as valid UTF-8.
|
||||||
/// On other platforms, `[]u8` components are an opaque sequence of bytes with no particular encoding.
|
/// On other platforms, `[]u8` components are an opaque sequence of bytes with no particular encoding.
|
||||||
pub const MAX_NAME_BYTES = switch (builtin.os.tag) {
|
pub const MAX_NAME_BYTES = switch (native_os) {
|
||||||
.linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly, .solaris, .illumos => os.NAME_MAX,
|
.linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly, .solaris, .illumos => posix.NAME_MAX,
|
||||||
// Haiku's NAME_MAX includes the null terminator, so subtract one.
|
// Haiku's NAME_MAX includes the null terminator, so subtract one.
|
||||||
.haiku => os.NAME_MAX - 1,
|
.haiku => posix.NAME_MAX - 1,
|
||||||
// Each WTF-16LE character may be expanded to 3 WTF-8 bytes.
|
// Each WTF-16LE character may be expanded to 3 WTF-8 bytes.
|
||||||
// If it would require 4 WTF-8 bytes, then there would be a surrogate
|
// If it would require 4 WTF-8 bytes, then there would be a surrogate
|
||||||
// pair in the WTF-16LE, and we (over)account 3 bytes for it that way.
|
// pair in the WTF-16LE, and we (over)account 3 bytes for it that way.
|
||||||
.windows => os.windows.NAME_MAX * 3,
|
.windows => windows.NAME_MAX * 3,
|
||||||
// For WASI, the MAX_NAME will depend on the host OS, so it needs to be
|
// For WASI, the MAX_NAME will depend on the host OS, so it needs to be
|
||||||
// as large as the largest MAX_NAME_BYTES (Windows) in order to work on any host OS.
|
// as large as the largest MAX_NAME_BYTES (Windows) in order to work on any host OS.
|
||||||
// TODO determine if this is a reasonable approach
|
// TODO determine if this is a reasonable approach
|
||||||
.wasi => os.windows.NAME_MAX * 3,
|
.wasi => windows.NAME_MAX * 3,
|
||||||
else => if (@hasDecl(root, "os") and @hasDecl(root.os, "NAME_MAX"))
|
else => if (@hasDecl(root, "os") and @hasDecl(root.os, "NAME_MAX"))
|
||||||
root.os.NAME_MAX
|
root.os.NAME_MAX
|
||||||
else
|
else
|
||||||
@compileError("NAME_MAX not implemented for " ++ @tagName(builtin.os.tag)),
|
@compileError("NAME_MAX not implemented for " ++ @tagName(native_os)),
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const base64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".*;
|
pub const base64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".*;
|
||||||
@ -167,19 +176,19 @@ pub fn copyFileAbsolute(
|
|||||||
/// On other platforms, `absolute_path` is an opaque sequence of bytes with no particular encoding.
|
/// On other platforms, `absolute_path` is an opaque sequence of bytes with no particular encoding.
|
||||||
pub fn makeDirAbsolute(absolute_path: []const u8) !void {
|
pub fn makeDirAbsolute(absolute_path: []const u8) !void {
|
||||||
assert(path.isAbsolute(absolute_path));
|
assert(path.isAbsolute(absolute_path));
|
||||||
return os.mkdir(absolute_path, Dir.default_mode);
|
return posix.mkdir(absolute_path, Dir.default_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `makeDirAbsolute` except the parameter is null-terminated.
|
/// Same as `makeDirAbsolute` except the parameter is null-terminated.
|
||||||
pub fn makeDirAbsoluteZ(absolute_path_z: [*:0]const u8) !void {
|
pub fn makeDirAbsoluteZ(absolute_path_z: [*:0]const u8) !void {
|
||||||
assert(path.isAbsoluteZ(absolute_path_z));
|
assert(path.isAbsoluteZ(absolute_path_z));
|
||||||
return os.mkdirZ(absolute_path_z, Dir.default_mode);
|
return posix.mkdirZ(absolute_path_z, Dir.default_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `makeDirAbsolute` except the parameter is a null-terminated WTF-16 LE-encoded string.
|
/// Same as `makeDirAbsolute` except the parameter is a null-terminated WTF-16 LE-encoded string.
|
||||||
pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void {
|
pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void {
|
||||||
assert(path.isAbsoluteWindowsW(absolute_path_w));
|
assert(path.isAbsoluteWindowsW(absolute_path_w));
|
||||||
return os.mkdirW(absolute_path_w, Dir.default_mode);
|
return posix.mkdirW(absolute_path_w, Dir.default_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `Dir.deleteDir` except the path is absolute.
|
/// Same as `Dir.deleteDir` except the path is absolute.
|
||||||
@ -188,19 +197,19 @@ pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void {
|
|||||||
/// On other platforms, `dir_path` is an opaque sequence of bytes with no particular encoding.
|
/// On other platforms, `dir_path` is an opaque sequence of bytes with no particular encoding.
|
||||||
pub fn deleteDirAbsolute(dir_path: []const u8) !void {
|
pub fn deleteDirAbsolute(dir_path: []const u8) !void {
|
||||||
assert(path.isAbsolute(dir_path));
|
assert(path.isAbsolute(dir_path));
|
||||||
return os.rmdir(dir_path);
|
return posix.rmdir(dir_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `deleteDirAbsolute` except the path parameter is null-terminated.
|
/// Same as `deleteDirAbsolute` except the path parameter is null-terminated.
|
||||||
pub fn deleteDirAbsoluteZ(dir_path: [*:0]const u8) !void {
|
pub fn deleteDirAbsoluteZ(dir_path: [*:0]const u8) !void {
|
||||||
assert(path.isAbsoluteZ(dir_path));
|
assert(path.isAbsoluteZ(dir_path));
|
||||||
return os.rmdirZ(dir_path);
|
return posix.rmdirZ(dir_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `deleteDirAbsolute` except the path parameter is WTF-16 and target OS is assumed Windows.
|
/// Same as `deleteDirAbsolute` except the path parameter is WTF-16 and target OS is assumed Windows.
|
||||||
pub fn deleteDirAbsoluteW(dir_path: [*:0]const u16) !void {
|
pub fn deleteDirAbsoluteW(dir_path: [*:0]const u16) !void {
|
||||||
assert(path.isAbsoluteWindowsW(dir_path));
|
assert(path.isAbsoluteWindowsW(dir_path));
|
||||||
return os.rmdirW(dir_path);
|
return posix.rmdirW(dir_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `Dir.rename` except the paths are absolute.
|
/// Same as `Dir.rename` except the paths are absolute.
|
||||||
@ -210,49 +219,49 @@ pub fn deleteDirAbsoluteW(dir_path: [*:0]const u16) !void {
|
|||||||
pub fn renameAbsolute(old_path: []const u8, new_path: []const u8) !void {
|
pub fn renameAbsolute(old_path: []const u8, new_path: []const u8) !void {
|
||||||
assert(path.isAbsolute(old_path));
|
assert(path.isAbsolute(old_path));
|
||||||
assert(path.isAbsolute(new_path));
|
assert(path.isAbsolute(new_path));
|
||||||
return os.rename(old_path, new_path);
|
return posix.rename(old_path, new_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `renameAbsolute` except the path parameters are null-terminated.
|
/// Same as `renameAbsolute` except the path parameters are null-terminated.
|
||||||
pub fn renameAbsoluteZ(old_path: [*:0]const u8, new_path: [*:0]const u8) !void {
|
pub fn renameAbsoluteZ(old_path: [*:0]const u8, new_path: [*:0]const u8) !void {
|
||||||
assert(path.isAbsoluteZ(old_path));
|
assert(path.isAbsoluteZ(old_path));
|
||||||
assert(path.isAbsoluteZ(new_path));
|
assert(path.isAbsoluteZ(new_path));
|
||||||
return os.renameZ(old_path, new_path);
|
return posix.renameZ(old_path, new_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `renameAbsolute` except the path parameters are WTF-16 and target OS is assumed Windows.
|
/// Same as `renameAbsolute` except the path parameters are WTF-16 and target OS is assumed Windows.
|
||||||
pub fn renameAbsoluteW(old_path: [*:0]const u16, new_path: [*:0]const u16) !void {
|
pub fn renameAbsoluteW(old_path: [*:0]const u16, new_path: [*:0]const u16) !void {
|
||||||
assert(path.isAbsoluteWindowsW(old_path));
|
assert(path.isAbsoluteWindowsW(old_path));
|
||||||
assert(path.isAbsoluteWindowsW(new_path));
|
assert(path.isAbsoluteWindowsW(new_path));
|
||||||
return os.renameW(old_path, new_path);
|
return posix.renameW(old_path, new_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `Dir.rename`, except `new_sub_path` is relative to `new_dir`
|
/// Same as `Dir.rename`, except `new_sub_path` is relative to `new_dir`
|
||||||
pub fn rename(old_dir: Dir, old_sub_path: []const u8, new_dir: Dir, new_sub_path: []const u8) !void {
|
pub fn rename(old_dir: Dir, old_sub_path: []const u8, new_dir: Dir, new_sub_path: []const u8) !void {
|
||||||
return os.renameat(old_dir.fd, old_sub_path, new_dir.fd, new_sub_path);
|
return posix.renameat(old_dir.fd, old_sub_path, new_dir.fd, new_sub_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `rename` except the parameters are null-terminated.
|
/// Same as `rename` except the parameters are null-terminated.
|
||||||
pub fn renameZ(old_dir: Dir, old_sub_path_z: [*:0]const u8, new_dir: Dir, new_sub_path_z: [*:0]const u8) !void {
|
pub fn renameZ(old_dir: Dir, old_sub_path_z: [*:0]const u8, new_dir: Dir, new_sub_path_z: [*:0]const u8) !void {
|
||||||
return os.renameatZ(old_dir.fd, old_sub_path_z, new_dir.fd, new_sub_path_z);
|
return posix.renameatZ(old_dir.fd, old_sub_path_z, new_dir.fd, new_sub_path_z);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `rename` except the parameters are WTF16LE, NT prefixed.
|
/// Same as `rename` except the parameters are WTF16LE, NT prefixed.
|
||||||
/// This function is Windows-only.
|
/// This function is Windows-only.
|
||||||
pub fn renameW(old_dir: Dir, old_sub_path_w: []const u16, new_dir: Dir, new_sub_path_w: []const u16) !void {
|
pub fn renameW(old_dir: Dir, old_sub_path_w: []const u16, new_dir: Dir, new_sub_path_w: []const u16) !void {
|
||||||
return os.renameatW(old_dir.fd, old_sub_path_w, new_dir.fd, new_sub_path_w);
|
return posix.renameatW(old_dir.fd, old_sub_path_w, new_dir.fd, new_sub_path_w);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a handle to the current working directory. It is not opened with iteration capability.
|
/// Returns a handle to the current working directory. It is not opened with iteration capability.
|
||||||
/// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior.
|
/// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior.
|
||||||
/// On POSIX targets, this function is comptime-callable.
|
/// On POSIX targets, this function is comptime-callable.
|
||||||
pub fn cwd() Dir {
|
pub fn cwd() Dir {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
return .{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle };
|
return .{ .fd = windows.peb().ProcessParameters.CurrentDirectory.Handle };
|
||||||
} else if (builtin.os.tag == .wasi) {
|
} else if (native_os == .wasi) {
|
||||||
return .{ .fd = std.options.wasiCwd() };
|
return .{ .fd = std.options.wasiCwd() };
|
||||||
} else {
|
} else {
|
||||||
return .{ .fd = os.AT.FDCWD };
|
return .{ .fd = posix.AT.FDCWD };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,20 +421,20 @@ pub fn deleteTreeAbsolute(absolute_path: []const u8) !void {
|
|||||||
/// On other platforms, `pathname` is an opaque sequence of bytes with no particular encoding.
|
/// On other platforms, `pathname` is an opaque sequence of bytes with no particular encoding.
|
||||||
pub fn readLinkAbsolute(pathname: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
|
pub fn readLinkAbsolute(pathname: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
|
||||||
assert(path.isAbsolute(pathname));
|
assert(path.isAbsolute(pathname));
|
||||||
return os.readlink(pathname, buffer);
|
return posix.readlink(pathname, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Windows-only. Same as `readlinkW`, except the path parameter is null-terminated, WTF16
|
/// Windows-only. Same as `readlinkW`, except the path parameter is null-terminated, WTF16
|
||||||
/// encoded.
|
/// encoded.
|
||||||
pub fn readlinkAbsoluteW(pathname_w: [*:0]const u16, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
|
pub fn readlinkAbsoluteW(pathname_w: [*:0]const u16, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
|
||||||
assert(path.isAbsoluteWindowsW(pathname_w));
|
assert(path.isAbsoluteWindowsW(pathname_w));
|
||||||
return os.readlinkW(pathname_w, buffer);
|
return posix.readlinkW(pathname_w, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `readLink`, except the path parameter is null-terminated.
|
/// Same as `readLink`, except the path parameter is null-terminated.
|
||||||
pub fn readLinkAbsoluteZ(pathname_c: [*:0]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
|
pub fn readLinkAbsoluteZ(pathname_c: [*:0]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
|
||||||
assert(path.isAbsoluteZ(pathname_c));
|
assert(path.isAbsoluteZ(pathname_c));
|
||||||
return os.readlinkZ(pathname_c, buffer);
|
return posix.readlinkZ(pathname_c, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a symbolic link named `sym_link_path` which contains the string `target_path`.
|
/// Creates a symbolic link named `sym_link_path` which contains the string `target_path`.
|
||||||
@ -443,12 +452,12 @@ pub fn symLinkAbsolute(
|
|||||||
) !void {
|
) !void {
|
||||||
assert(path.isAbsolute(target_path));
|
assert(path.isAbsolute(target_path));
|
||||||
assert(path.isAbsolute(sym_link_path));
|
assert(path.isAbsolute(sym_link_path));
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const target_path_w = try os.windows.sliceToPrefixedFileW(null, target_path);
|
const target_path_w = try windows.sliceToPrefixedFileW(null, target_path);
|
||||||
const sym_link_path_w = try os.windows.sliceToPrefixedFileW(null, sym_link_path);
|
const sym_link_path_w = try windows.sliceToPrefixedFileW(null, sym_link_path);
|
||||||
return os.windows.CreateSymbolicLink(null, sym_link_path_w.span(), target_path_w.span(), flags.is_directory);
|
return windows.CreateSymbolicLink(null, sym_link_path_w.span(), target_path_w.span(), flags.is_directory);
|
||||||
}
|
}
|
||||||
return os.symlink(target_path, sym_link_path);
|
return posix.symlink(target_path, sym_link_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Windows-only. Same as `symLinkAbsolute` except the parameters are null-terminated, WTF16 LE encoded.
|
/// Windows-only. Same as `symLinkAbsolute` except the parameters are null-terminated, WTF16 LE encoded.
|
||||||
@ -462,7 +471,7 @@ pub fn symLinkAbsoluteW(
|
|||||||
) !void {
|
) !void {
|
||||||
assert(path.isAbsoluteWindowsWTF16(target_path_w));
|
assert(path.isAbsoluteWindowsWTF16(target_path_w));
|
||||||
assert(path.isAbsoluteWindowsWTF16(sym_link_path_w));
|
assert(path.isAbsoluteWindowsWTF16(sym_link_path_w));
|
||||||
return os.windows.CreateSymbolicLink(null, sym_link_path_w, target_path_w, flags.is_directory);
|
return windows.CreateSymbolicLink(null, sym_link_path_w, target_path_w, flags.is_directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as `symLinkAbsolute` except the parameters are null-terminated pointers.
|
/// Same as `symLinkAbsolute` except the parameters are null-terminated pointers.
|
||||||
@ -474,27 +483,27 @@ pub fn symLinkAbsoluteZ(
|
|||||||
) !void {
|
) !void {
|
||||||
assert(path.isAbsoluteZ(target_path_c));
|
assert(path.isAbsoluteZ(target_path_c));
|
||||||
assert(path.isAbsoluteZ(sym_link_path_c));
|
assert(path.isAbsoluteZ(sym_link_path_c));
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const target_path_w = try os.windows.cStrToPrefixedFileW(null, target_path_c);
|
const target_path_w = try windows.cStrToPrefixedFileW(null, target_path_c);
|
||||||
const sym_link_path_w = try os.windows.cStrToPrefixedFileW(null, sym_link_path_c);
|
const sym_link_path_w = try windows.cStrToPrefixedFileW(null, sym_link_path_c);
|
||||||
return os.windows.CreateSymbolicLink(null, sym_link_path_w.span(), target_path_w.span(), flags.is_directory);
|
return windows.CreateSymbolicLink(null, sym_link_path_w.span(), target_path_w.span(), flags.is_directory);
|
||||||
}
|
}
|
||||||
return os.symlinkZ(target_path_c, sym_link_path_c);
|
return posix.symlinkZ(target_path_c, sym_link_path_c);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const OpenSelfExeError = os.OpenError || SelfExePathError || os.FlockError;
|
pub const OpenSelfExeError = posix.OpenError || SelfExePathError || posix.FlockError;
|
||||||
|
|
||||||
pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File {
|
pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File {
|
||||||
if (builtin.os.tag == .linux) {
|
if (native_os == .linux) {
|
||||||
return openFileAbsoluteZ("/proc/self/exe", flags);
|
return openFileAbsoluteZ("/proc/self/exe", flags);
|
||||||
}
|
}
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
// If ImagePathName is a symlink, then it will contain the path of the symlink,
|
// If ImagePathName is a symlink, then it will contain the path of the symlink,
|
||||||
// not the path that the symlink points to. However, because we are opening
|
// not the path that the symlink points to. However, because we are opening
|
||||||
// the file, we can let the openFileW call follow the symlink for us.
|
// the file, we can let the openFileW call follow the symlink for us.
|
||||||
const image_path_unicode_string = &os.windows.peb().ProcessParameters.ImagePathName;
|
const image_path_unicode_string = &windows.peb().ProcessParameters.ImagePathName;
|
||||||
const image_path_name = image_path_unicode_string.Buffer.?[0 .. image_path_unicode_string.Length / 2 :0];
|
const image_path_name = image_path_unicode_string.Buffer.?[0 .. image_path_unicode_string.Length / 2 :0];
|
||||||
const prefixed_path_w = try os.windows.wToPrefixedFileW(null, image_path_name);
|
const prefixed_path_w = try windows.wToPrefixedFileW(null, image_path_name);
|
||||||
return cwd().openFileW(prefixed_path_w.span(), flags);
|
return cwd().openFileW(prefixed_path_w.span(), flags);
|
||||||
}
|
}
|
||||||
// Use of MAX_PATH_BYTES here is valid as the resulting path is immediately
|
// Use of MAX_PATH_BYTES here is valid as the resulting path is immediately
|
||||||
@ -505,7 +514,7 @@ pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File {
|
|||||||
return openFileAbsoluteZ(buf[0..self_exe_path.len :0].ptr, flags);
|
return openFileAbsoluteZ(buf[0..self_exe_path.len :0].ptr, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is os.ReadLinkError || os.RealPathError with impossible errors excluded
|
// This is `posix.ReadLinkError || posix.RealPathError` with impossible errors excluded
|
||||||
pub const SelfExePathError = error{
|
pub const SelfExePathError = error{
|
||||||
FileNotFound,
|
FileNotFound,
|
||||||
AccessDenied,
|
AccessDenied,
|
||||||
@ -542,7 +551,7 @@ pub const SelfExePathError = error{
|
|||||||
/// On Windows, the volume does not contain a recognized file system. File
|
/// On Windows, the volume does not contain a recognized file system. File
|
||||||
/// system drivers might not be loaded, or the volume may be corrupt.
|
/// system drivers might not be loaded, or the volume may be corrupt.
|
||||||
UnrecognizedVolume,
|
UnrecognizedVolume,
|
||||||
} || os.SysCtlError;
|
} || posix.SysCtlError;
|
||||||
|
|
||||||
/// `selfExePath` except allocates the result on the heap.
|
/// `selfExePath` except allocates the result on the heap.
|
||||||
/// Caller owns returned memory.
|
/// Caller owns returned memory.
|
||||||
@ -580,7 +589,7 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 {
|
|||||||
if (rc != 0) return error.NameTooLong;
|
if (rc != 0) return error.NameTooLong;
|
||||||
|
|
||||||
var real_path_buf: [MAX_PATH_BYTES]u8 = undefined;
|
var real_path_buf: [MAX_PATH_BYTES]u8 = undefined;
|
||||||
const real_path = std.os.realpathZ(&symlink_path_buf, &real_path_buf) catch |err| switch (err) {
|
const real_path = std.posix.realpathZ(&symlink_path_buf, &real_path_buf) catch |err| switch (err) {
|
||||||
error.InvalidWtf8 => unreachable, // Windows-only
|
error.InvalidWtf8 => unreachable, // Windows-only
|
||||||
error.NetworkNotFound => unreachable, // Windows-only
|
error.NetworkNotFound => unreachable, // Windows-only
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
@ -590,15 +599,15 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 {
|
|||||||
@memcpy(result, real_path);
|
@memcpy(result, real_path);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
switch (builtin.os.tag) {
|
switch (native_os) {
|
||||||
.linux => return os.readlinkZ("/proc/self/exe", out_buffer) catch |err| switch (err) {
|
.linux => return posix.readlinkZ("/proc/self/exe", out_buffer) catch |err| switch (err) {
|
||||||
error.InvalidUtf8 => unreachable, // WASI-only
|
error.InvalidUtf8 => unreachable, // WASI-only
|
||||||
error.InvalidWtf8 => unreachable, // Windows-only
|
error.InvalidWtf8 => unreachable, // Windows-only
|
||||||
error.UnsupportedReparsePointType => unreachable, // Windows-only
|
error.UnsupportedReparsePointType => unreachable, // Windows-only
|
||||||
error.NetworkNotFound => unreachable, // Windows-only
|
error.NetworkNotFound => unreachable, // Windows-only
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
},
|
},
|
||||||
.solaris, .illumos => return os.readlinkZ("/proc/self/path/a.out", out_buffer) catch |err| switch (err) {
|
.solaris, .illumos => return posix.readlinkZ("/proc/self/path/a.out", out_buffer) catch |err| switch (err) {
|
||||||
error.InvalidUtf8 => unreachable, // WASI-only
|
error.InvalidUtf8 => unreachable, // WASI-only
|
||||||
error.InvalidWtf8 => unreachable, // Windows-only
|
error.InvalidWtf8 => unreachable, // Windows-only
|
||||||
error.UnsupportedReparsePointType => unreachable, // Windows-only
|
error.UnsupportedReparsePointType => unreachable, // Windows-only
|
||||||
@ -606,29 +615,29 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 {
|
|||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
},
|
},
|
||||||
.freebsd, .dragonfly => {
|
.freebsd, .dragonfly => {
|
||||||
var mib = [4]c_int{ os.CTL.KERN, os.KERN.PROC, os.KERN.PROC_PATHNAME, -1 };
|
var mib = [4]c_int{ posix.CTL.KERN, posix.KERN.PROC, posix.KERN.PROC_PATHNAME, -1 };
|
||||||
var out_len: usize = out_buffer.len;
|
var out_len: usize = out_buffer.len;
|
||||||
try os.sysctl(&mib, out_buffer.ptr, &out_len, null, 0);
|
try posix.sysctl(&mib, out_buffer.ptr, &out_len, null, 0);
|
||||||
// TODO could this slice from 0 to out_len instead?
|
// TODO could this slice from 0 to out_len instead?
|
||||||
return mem.sliceTo(out_buffer, 0);
|
return mem.sliceTo(out_buffer, 0);
|
||||||
},
|
},
|
||||||
.netbsd => {
|
.netbsd => {
|
||||||
var mib = [4]c_int{ os.CTL.KERN, os.KERN.PROC_ARGS, -1, os.KERN.PROC_PATHNAME };
|
var mib = [4]c_int{ posix.CTL.KERN, posix.KERN.PROC_ARGS, -1, posix.KERN.PROC_PATHNAME };
|
||||||
var out_len: usize = out_buffer.len;
|
var out_len: usize = out_buffer.len;
|
||||||
try os.sysctl(&mib, out_buffer.ptr, &out_len, null, 0);
|
try posix.sysctl(&mib, out_buffer.ptr, &out_len, null, 0);
|
||||||
// TODO could this slice from 0 to out_len instead?
|
// TODO could this slice from 0 to out_len instead?
|
||||||
return mem.sliceTo(out_buffer, 0);
|
return mem.sliceTo(out_buffer, 0);
|
||||||
},
|
},
|
||||||
.openbsd, .haiku => {
|
.openbsd, .haiku => {
|
||||||
// OpenBSD doesn't support getting the path of a running process, so try to guess it
|
// OpenBSD doesn't support getting the path of a running process, so try to guess it
|
||||||
if (os.argv.len == 0)
|
if (std.os.argv.len == 0)
|
||||||
return error.FileNotFound;
|
return error.FileNotFound;
|
||||||
|
|
||||||
const argv0 = mem.span(os.argv[0]);
|
const argv0 = mem.span(std.os.argv[0]);
|
||||||
if (mem.indexOf(u8, argv0, "/") != null) {
|
if (mem.indexOf(u8, argv0, "/") != null) {
|
||||||
// argv[0] is a path (relative or absolute): use realpath(3) directly
|
// argv[0] is a path (relative or absolute): use realpath(3) directly
|
||||||
var real_path_buf: [MAX_PATH_BYTES]u8 = undefined;
|
var real_path_buf: [MAX_PATH_BYTES]u8 = undefined;
|
||||||
const real_path = os.realpathZ(os.argv[0], &real_path_buf) catch |err| switch (err) {
|
const real_path = posix.realpathZ(std.os.argv[0], &real_path_buf) catch |err| switch (err) {
|
||||||
error.InvalidWtf8 => unreachable, // Windows-only
|
error.InvalidWtf8 => unreachable, // Windows-only
|
||||||
error.NetworkNotFound => unreachable, // Windows-only
|
error.NetworkNotFound => unreachable, // Windows-only
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
@ -640,17 +649,17 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 {
|
|||||||
return result;
|
return result;
|
||||||
} else if (argv0.len != 0) {
|
} else if (argv0.len != 0) {
|
||||||
// argv[0] is not empty (and not a path): search it inside PATH
|
// argv[0] is not empty (and not a path): search it inside PATH
|
||||||
const PATH = std.os.getenvZ("PATH") orelse return error.FileNotFound;
|
const PATH = posix.getenvZ("PATH") orelse return error.FileNotFound;
|
||||||
var path_it = mem.tokenizeScalar(u8, PATH, path.delimiter);
|
var path_it = mem.tokenizeScalar(u8, PATH, path.delimiter);
|
||||||
while (path_it.next()) |a_path| {
|
while (path_it.next()) |a_path| {
|
||||||
var resolved_path_buf: [MAX_PATH_BYTES - 1:0]u8 = undefined;
|
var resolved_path_buf: [MAX_PATH_BYTES - 1:0]u8 = undefined;
|
||||||
const resolved_path = std.fmt.bufPrintZ(&resolved_path_buf, "{s}/{s}", .{
|
const resolved_path = std.fmt.bufPrintZ(&resolved_path_buf, "{s}/{s}", .{
|
||||||
a_path,
|
a_path,
|
||||||
os.argv[0],
|
std.os.argv[0],
|
||||||
}) catch continue;
|
}) catch continue;
|
||||||
|
|
||||||
var real_path_buf: [MAX_PATH_BYTES]u8 = undefined;
|
var real_path_buf: [MAX_PATH_BYTES]u8 = undefined;
|
||||||
if (os.realpathZ(resolved_path, &real_path_buf)) |real_path| {
|
if (posix.realpathZ(resolved_path, &real_path_buf)) |real_path| {
|
||||||
// found a file, and hope it is the right file
|
// found a file, and hope it is the right file
|
||||||
if (real_path.len > out_buffer.len)
|
if (real_path.len > out_buffer.len)
|
||||||
return error.NameTooLong;
|
return error.NameTooLong;
|
||||||
@ -663,13 +672,13 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 {
|
|||||||
return error.FileNotFound;
|
return error.FileNotFound;
|
||||||
},
|
},
|
||||||
.windows => {
|
.windows => {
|
||||||
const image_path_unicode_string = &os.windows.peb().ProcessParameters.ImagePathName;
|
const image_path_unicode_string = &windows.peb().ProcessParameters.ImagePathName;
|
||||||
const image_path_name = image_path_unicode_string.Buffer.?[0 .. image_path_unicode_string.Length / 2 :0];
|
const image_path_name = image_path_unicode_string.Buffer.?[0 .. image_path_unicode_string.Length / 2 :0];
|
||||||
|
|
||||||
// If ImagePathName is a symlink, then it will contain the path of the
|
// If ImagePathName is a symlink, then it will contain the path of the
|
||||||
// symlink, not the path that the symlink points to. We want the path
|
// symlink, not the path that the symlink points to. We want the path
|
||||||
// that the symlink points to, though, so we need to get the realpath.
|
// that the symlink points to, though, so we need to get the realpath.
|
||||||
const pathname_w = try os.windows.wToPrefixedFileW(null, image_path_name);
|
const pathname_w = try windows.wToPrefixedFileW(null, image_path_name);
|
||||||
return std.fs.cwd().realpathW(pathname_w.span(), out_buffer) catch |err| switch (err) {
|
return std.fs.cwd().realpathW(pathname_w.span(), out_buffer) catch |err| switch (err) {
|
||||||
error.InvalidWtf8 => unreachable,
|
error.InvalidWtf8 => unreachable,
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
@ -718,11 +727,11 @@ pub fn realpathAlloc(allocator: Allocator, pathname: []const u8) ![]u8 {
|
|||||||
// paths. musl supports passing NULL but restricts the output to PATH_MAX
|
// paths. musl supports passing NULL but restricts the output to PATH_MAX
|
||||||
// anyway.
|
// anyway.
|
||||||
var buf: [MAX_PATH_BYTES]u8 = undefined;
|
var buf: [MAX_PATH_BYTES]u8 = undefined;
|
||||||
return allocator.dupe(u8, try os.realpath(pathname, &buf));
|
return allocator.dupe(u8, try posix.realpath(pathname, &buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
test {
|
test {
|
||||||
if (builtin.os.tag != .wasi) {
|
if (native_os != .wasi) {
|
||||||
_ = &makeDirAbsolute;
|
_ = &makeDirAbsolute;
|
||||||
_ = &makeDirAbsoluteZ;
|
_ = &makeDirAbsoluteZ;
|
||||||
_ = ©FileAbsolute;
|
_ = ©FileAbsolute;
|
||||||
|
|||||||
@ -85,5 +85,4 @@ const File = std.fs.File;
|
|||||||
const Dir = std.fs.Dir;
|
const Dir = std.fs.Dir;
|
||||||
const fs = std.fs;
|
const fs = std.fs;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
// https://github.com/ziglang/zig/issues/5019
|
const posix = std.posix;
|
||||||
const posix = std.os;
|
|
||||||
|
|||||||
@ -18,7 +18,7 @@ const IteratorError = error{
|
|||||||
InvalidUtf8,
|
InvalidUtf8,
|
||||||
} || posix.UnexpectedError;
|
} || posix.UnexpectedError;
|
||||||
|
|
||||||
pub const Iterator = switch (builtin.os.tag) {
|
pub const Iterator = switch (native_os) {
|
||||||
.macos, .ios, .freebsd, .netbsd, .dragonfly, .openbsd, .solaris, .illumos => struct {
|
.macos, .ios, .freebsd, .netbsd, .dragonfly, .openbsd, .solaris, .illumos => struct {
|
||||||
dir: Dir,
|
dir: Dir,
|
||||||
seek: i64,
|
seek: i64,
|
||||||
@ -34,7 +34,7 @@ pub const Iterator = switch (builtin.os.tag) {
|
|||||||
/// Memory such as file names referenced in this returned entry becomes invalid
|
/// 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.
|
/// with subsequent calls to `next`, as well as when this `Dir` is deinitialized.
|
||||||
pub fn next(self: *Self) Error!?Entry {
|
pub fn next(self: *Self) Error!?Entry {
|
||||||
switch (builtin.os.tag) {
|
switch (native_os) {
|
||||||
.macos, .ios => return self.nextDarwin(),
|
.macos, .ios => return self.nextDarwin(),
|
||||||
.freebsd, .netbsd, .dragonfly, .openbsd => return self.nextBsd(),
|
.freebsd, .netbsd, .dragonfly, .openbsd => return self.nextBsd(),
|
||||||
.solaris, .illumos => return self.nextSolaris(),
|
.solaris, .illumos => return self.nextSolaris(),
|
||||||
@ -183,7 +183,7 @@ pub const Iterator = switch (builtin.os.tag) {
|
|||||||
|
|
||||||
const name = @as([*]u8, @ptrCast(&bsd_entry.name))[0..bsd_entry.namlen];
|
const name = @as([*]u8, @ptrCast(&bsd_entry.name))[0..bsd_entry.namlen];
|
||||||
|
|
||||||
const skip_zero_fileno = switch (builtin.os.tag) {
|
const skip_zero_fileno = switch (native_os) {
|
||||||
// fileno=0 is used to mark invalid entries or deleted files.
|
// fileno=0 is used to mark invalid entries or deleted files.
|
||||||
.openbsd, .netbsd => true,
|
.openbsd, .netbsd => true,
|
||||||
else => false,
|
else => false,
|
||||||
@ -315,7 +315,7 @@ pub const Iterator = switch (builtin.os.tag) {
|
|||||||
dir: Dir,
|
dir: Dir,
|
||||||
// The if guard is solely there to prevent compile errors from missing `linux.dirent64`
|
// 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.
|
// definition when compiling for other OSes. It doesn't do anything when compiling for Linux.
|
||||||
buf: [1024]u8 align(if (builtin.os.tag != .linux) 1 else @alignOf(linux.dirent64)),
|
buf: [1024]u8 align(if (native_os != .linux) 1 else @alignOf(linux.dirent64)),
|
||||||
index: usize,
|
index: usize,
|
||||||
end_index: usize,
|
end_index: usize,
|
||||||
first_iter: bool,
|
first_iter: bool,
|
||||||
@ -348,7 +348,7 @@ pub const Iterator = switch (builtin.os.tag) {
|
|||||||
self.first_iter = false;
|
self.first_iter = false;
|
||||||
}
|
}
|
||||||
const rc = linux.getdents64(self.dir.fd, &self.buf, self.buf.len);
|
const rc = linux.getdents64(self.dir.fd, &self.buf, self.buf.len);
|
||||||
switch (linux.getErrno(rc)) {
|
switch (linux.E.init(rc)) {
|
||||||
.SUCCESS => {},
|
.SUCCESS => {},
|
||||||
.BADF => unreachable, // Dir is invalid or was opened without iteration ability
|
.BADF => unreachable, // Dir is invalid or was opened without iteration ability
|
||||||
.FAULT => unreachable,
|
.FAULT => unreachable,
|
||||||
@ -398,7 +398,7 @@ pub const Iterator = switch (builtin.os.tag) {
|
|||||||
},
|
},
|
||||||
.windows => struct {
|
.windows => struct {
|
||||||
dir: Dir,
|
dir: Dir,
|
||||||
buf: [1024]u8 align(@alignOf(std.os.windows.FILE_BOTH_DIR_INFORMATION)),
|
buf: [1024]u8 align(@alignOf(windows.FILE_BOTH_DIR_INFORMATION)),
|
||||||
index: usize,
|
index: usize,
|
||||||
end_index: usize,
|
end_index: usize,
|
||||||
first_iter: bool,
|
first_iter: bool,
|
||||||
@ -411,8 +411,8 @@ pub const Iterator = switch (builtin.os.tag) {
|
|||||||
/// Memory such as file names referenced in this returned entry becomes invalid
|
/// 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.
|
/// with subsequent calls to `next`, as well as when this `Dir` is deinitialized.
|
||||||
pub fn next(self: *Self) Error!?Entry {
|
pub fn next(self: *Self) Error!?Entry {
|
||||||
|
const w = windows;
|
||||||
while (true) {
|
while (true) {
|
||||||
const w = std.os.windows;
|
|
||||||
if (self.index >= self.end_index) {
|
if (self.index >= self.end_index) {
|
||||||
var io: w.IO_STATUS_BLOCK = undefined;
|
var io: w.IO_STATUS_BLOCK = undefined;
|
||||||
const rc = w.ntdll.NtQueryDirectoryFile(
|
const rc = w.ntdll.NtQueryDirectoryFile(
|
||||||
@ -582,7 +582,7 @@ pub fn iterateAssumeFirstIteration(self: Dir) Iterator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn iterateImpl(self: Dir, first_iter_start_value: bool) Iterator {
|
fn iterateImpl(self: Dir, first_iter_start_value: bool) Iterator {
|
||||||
switch (builtin.os.tag) {
|
switch (native_os) {
|
||||||
.macos,
|
.macos,
|
||||||
.ios,
|
.ios,
|
||||||
.freebsd,
|
.freebsd,
|
||||||
@ -770,11 +770,11 @@ pub fn close(self: *Dir) void {
|
|||||||
/// On WASI, `sub_path` should be encoded as valid UTF-8.
|
/// On WASI, `sub_path` should be encoded as valid UTF-8.
|
||||||
/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
|
/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
|
||||||
pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
|
pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const path_w = try std.os.windows.sliceToPrefixedFileW(self.fd, sub_path);
|
const path_w = try windows.sliceToPrefixedFileW(self.fd, sub_path);
|
||||||
return self.openFileW(path_w.span(), flags);
|
return self.openFileW(path_w.span(), flags);
|
||||||
}
|
}
|
||||||
if (builtin.os.tag == .wasi) {
|
if (native_os == .wasi) {
|
||||||
var base: std.os.wasi.rights_t = .{};
|
var base: std.os.wasi.rights_t = .{};
|
||||||
if (flags.isRead()) {
|
if (flags.isRead()) {
|
||||||
base.FD_READ = true;
|
base.FD_READ = true;
|
||||||
@ -803,9 +803,9 @@ pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.Ope
|
|||||||
|
|
||||||
/// Same as `openFile` but the path parameter is null-terminated.
|
/// Same as `openFile` but the path parameter is null-terminated.
|
||||||
pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {
|
pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {
|
||||||
switch (builtin.os.tag) {
|
switch (native_os) {
|
||||||
.windows => {
|
.windows => {
|
||||||
const path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sub_path);
|
const path_w = try windows.cStrToPrefixedFileW(self.fd, sub_path);
|
||||||
return self.openFileW(path_w.span(), flags);
|
return self.openFileW(path_w.span(), flags);
|
||||||
},
|
},
|
||||||
.wasi => {
|
.wasi => {
|
||||||
@ -884,7 +884,7 @@ pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File
|
|||||||
/// Same as `openFile` but Windows-only and the path parameter is
|
/// Same as `openFile` but Windows-only and the path parameter is
|
||||||
/// [WTF-16](https://simonsapin.github.io/wtf-8/#potentially-ill-formed-utf-16) encoded.
|
/// [WTF-16](https://simonsapin.github.io/wtf-8/#potentially-ill-formed-utf-16) encoded.
|
||||||
pub fn openFileW(self: Dir, sub_path_w: []const u16, flags: File.OpenFlags) File.OpenError!File {
|
pub fn openFileW(self: Dir, sub_path_w: []const u16, flags: File.OpenFlags) File.OpenError!File {
|
||||||
const w = std.os.windows;
|
const w = windows;
|
||||||
const file: File = .{
|
const file: File = .{
|
||||||
.handle = try w.OpenFile(sub_path_w, .{
|
.handle = try w.OpenFile(sub_path_w, .{
|
||||||
.dir = self.fd,
|
.dir = self.fd,
|
||||||
@ -925,11 +925,11 @@ pub fn openFileW(self: Dir, sub_path_w: []const u16, flags: File.OpenFlags) File
|
|||||||
/// On WASI, `sub_path` should be encoded as valid UTF-8.
|
/// On WASI, `sub_path` should be encoded as valid UTF-8.
|
||||||
/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
|
/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
|
||||||
pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
|
pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const path_w = try std.os.windows.sliceToPrefixedFileW(self.fd, sub_path);
|
const path_w = try windows.sliceToPrefixedFileW(self.fd, sub_path);
|
||||||
return self.createFileW(path_w.span(), flags);
|
return self.createFileW(path_w.span(), flags);
|
||||||
}
|
}
|
||||||
if (builtin.os.tag == .wasi) {
|
if (native_os == .wasi) {
|
||||||
return .{
|
return .{
|
||||||
.handle = try posix.openatWasi(self.fd, sub_path, .{}, .{
|
.handle = try posix.openatWasi(self.fd, sub_path, .{}, .{
|
||||||
.CREAT = true,
|
.CREAT = true,
|
||||||
@ -957,9 +957,9 @@ pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File
|
|||||||
|
|
||||||
/// Same as `createFile` but the path parameter is null-terminated.
|
/// Same as `createFile` but the path parameter is null-terminated.
|
||||||
pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File {
|
pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File {
|
||||||
switch (builtin.os.tag) {
|
switch (native_os) {
|
||||||
.windows => {
|
.windows => {
|
||||||
const path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);
|
const path_w = try windows.cStrToPrefixedFileW(self.fd, sub_path_c);
|
||||||
return self.createFileW(path_w.span(), flags);
|
return self.createFileW(path_w.span(), flags);
|
||||||
},
|
},
|
||||||
.wasi => {
|
.wasi => {
|
||||||
@ -968,7 +968,7 @@ pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags
|
|||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
var os_flags: std.os.O = .{
|
var os_flags: posix.O = .{
|
||||||
.ACCMODE = if (flags.read) .RDWR else .WRONLY,
|
.ACCMODE = if (flags.read) .RDWR else .WRONLY,
|
||||||
.CREAT = true,
|
.CREAT = true,
|
||||||
.TRUNC = flags.truncate,
|
.TRUNC = flags.truncate,
|
||||||
@ -1032,7 +1032,7 @@ pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags
|
|||||||
/// Same as `createFile` but Windows-only and the path parameter is
|
/// Same as `createFile` but Windows-only and the path parameter is
|
||||||
/// [WTF-16](https://simonsapin.github.io/wtf-8/#potentially-ill-formed-utf-16) encoded.
|
/// [WTF-16](https://simonsapin.github.io/wtf-8/#potentially-ill-formed-utf-16) encoded.
|
||||||
pub fn createFileW(self: Dir, sub_path_w: []const u16, flags: File.CreateFlags) File.OpenError!File {
|
pub fn createFileW(self: Dir, sub_path_w: []const u16, flags: File.CreateFlags) File.OpenError!File {
|
||||||
const w = std.os.windows;
|
const w = windows;
|
||||||
const read_flag = if (flags.read) @as(u32, w.GENERIC_READ) else 0;
|
const read_flag = if (flags.read) @as(u32, w.GENERIC_READ) else 0;
|
||||||
const file: File = .{
|
const file: File = .{
|
||||||
.handle = try w.OpenFile(sub_path_w, .{
|
.handle = try w.OpenFile(sub_path_w, .{
|
||||||
@ -1145,7 +1145,7 @@ pub fn makePath(self: Dir, sub_path: []const u8) !void {
|
|||||||
/// have been modified regardless.
|
/// have been modified regardless.
|
||||||
/// `sub_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
|
/// `sub_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
|
||||||
fn makeOpenPathAccessMaskW(self: Dir, sub_path: []const u8, access_mask: u32, no_follow: bool) OpenError!Dir {
|
fn makeOpenPathAccessMaskW(self: Dir, sub_path: []const u8, access_mask: u32, no_follow: bool) OpenError!Dir {
|
||||||
const w = std.os.windows;
|
const w = windows;
|
||||||
var it = try fs.path.componentIterator(sub_path);
|
var it = try fs.path.componentIterator(sub_path);
|
||||||
// If there are no components in the path, then create a dummy component with the full path.
|
// If there are no components in the path, then create a dummy component with the full path.
|
||||||
var component = it.last() orelse fs.path.NativeComponentIterator.Component{
|
var component = it.last() orelse fs.path.NativeComponentIterator.Component{
|
||||||
@ -1180,9 +1180,9 @@ fn makeOpenPathAccessMaskW(self: Dir, sub_path: []const u8, access_mask: u32, no
|
|||||||
/// On WASI, `sub_path` should be encoded as valid UTF-8.
|
/// On WASI, `sub_path` should be encoded as valid UTF-8.
|
||||||
/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
|
/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
|
||||||
pub fn makeOpenPath(self: Dir, sub_path: []const u8, open_dir_options: OpenDirOptions) !Dir {
|
pub fn makeOpenPath(self: Dir, sub_path: []const u8, open_dir_options: OpenDirOptions) !Dir {
|
||||||
return switch (builtin.os.tag) {
|
return switch (native_os) {
|
||||||
.windows => {
|
.windows => {
|
||||||
const w = std.os.windows;
|
const w = windows;
|
||||||
const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |
|
const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |
|
||||||
w.SYNCHRONIZE | w.FILE_TRAVERSE |
|
w.SYNCHRONIZE | w.FILE_TRAVERSE |
|
||||||
(if (open_dir_options.iterate) w.FILE_LIST_DIRECTORY else @as(u32, 0));
|
(if (open_dir_options.iterate) w.FILE_LIST_DIRECTORY else @as(u32, 0));
|
||||||
@ -1215,11 +1215,11 @@ pub const RealPathError = posix.RealPathError;
|
|||||||
/// Currently supported hosts are: Linux, macOS, and Windows.
|
/// Currently supported hosts are: Linux, macOS, and Windows.
|
||||||
/// See also `Dir.realpathZ`, `Dir.realpathW`, and `Dir.realpathAlloc`.
|
/// See also `Dir.realpathZ`, `Dir.realpathW`, and `Dir.realpathAlloc`.
|
||||||
pub fn realpath(self: Dir, pathname: []const u8, out_buffer: []u8) RealPathError![]u8 {
|
pub fn realpath(self: Dir, pathname: []const u8, out_buffer: []u8) RealPathError![]u8 {
|
||||||
if (builtin.os.tag == .wasi) {
|
if (native_os == .wasi) {
|
||||||
@compileError("realpath is not available on WASI");
|
@compileError("realpath is not available on WASI");
|
||||||
}
|
}
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const pathname_w = try std.os.windows.sliceToPrefixedFileW(self.fd, pathname);
|
const pathname_w = try windows.sliceToPrefixedFileW(self.fd, pathname);
|
||||||
return self.realpathW(pathname_w.span(), out_buffer);
|
return self.realpathW(pathname_w.span(), out_buffer);
|
||||||
}
|
}
|
||||||
const pathname_c = try posix.toPosixPath(pathname);
|
const pathname_c = try posix.toPosixPath(pathname);
|
||||||
@ -1229,12 +1229,12 @@ pub fn realpath(self: Dir, pathname: []const u8, out_buffer: []u8) RealPathError
|
|||||||
/// Same as `Dir.realpath` except `pathname` is null-terminated.
|
/// Same as `Dir.realpath` except `pathname` is null-terminated.
|
||||||
/// See also `Dir.realpath`, `realpathZ`.
|
/// See also `Dir.realpath`, `realpathZ`.
|
||||||
pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) RealPathError![]u8 {
|
pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) RealPathError![]u8 {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const pathname_w = try posix.windows.cStrToPrefixedFileW(self.fd, pathname);
|
const pathname_w = try windows.cStrToPrefixedFileW(self.fd, pathname);
|
||||||
return self.realpathW(pathname_w.span(), out_buffer);
|
return self.realpathW(pathname_w.span(), out_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
const flags: posix.O = switch (builtin.os.tag) {
|
const flags: posix.O = switch (native_os) {
|
||||||
.linux => .{
|
.linux => .{
|
||||||
.NONBLOCK = true,
|
.NONBLOCK = true,
|
||||||
.CLOEXEC = true,
|
.CLOEXEC = true,
|
||||||
@ -1255,14 +1255,8 @@ pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) RealPathE
|
|||||||
};
|
};
|
||||||
defer posix.close(fd);
|
defer posix.close(fd);
|
||||||
|
|
||||||
// Use of MAX_PATH_BYTES here is valid as the realpath function does not
|
|
||||||
// have a variant that takes an arbitrary-size buffer.
|
|
||||||
// TODO(#4812): Consider reimplementing realpath or using the POSIX.1-2008
|
|
||||||
// NULL out parameter (GNU's canonicalize_file_name) to handle overelong
|
|
||||||
// paths. musl supports passing NULL but restricts the output to PATH_MAX
|
|
||||||
// anyway.
|
|
||||||
var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
|
var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
const out_path = try posix.getFdPath(fd, &buffer);
|
const out_path = try std.os.getFdPath(fd, &buffer);
|
||||||
|
|
||||||
if (out_path.len > out_buffer.len) {
|
if (out_path.len > out_buffer.len) {
|
||||||
return error.NameTooLong;
|
return error.NameTooLong;
|
||||||
@ -1277,7 +1271,7 @@ pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) RealPathE
|
|||||||
/// The result is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
|
/// The result is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
|
||||||
/// See also `Dir.realpath`, `realpathW`.
|
/// See also `Dir.realpath`, `realpathW`.
|
||||||
pub fn realpathW(self: Dir, pathname: []const u16, out_buffer: []u8) RealPathError![]u8 {
|
pub fn realpathW(self: Dir, pathname: []const u16, out_buffer: []u8) RealPathError![]u8 {
|
||||||
const w = std.os.windows;
|
const w = windows;
|
||||||
|
|
||||||
const access_mask = w.GENERIC_READ | w.SYNCHRONIZE;
|
const access_mask = w.GENERIC_READ | w.SYNCHRONIZE;
|
||||||
const share_access = w.FILE_SHARE_READ;
|
const share_access = w.FILE_SHARE_READ;
|
||||||
@ -1331,16 +1325,16 @@ pub fn realpathAlloc(self: Dir, allocator: Allocator, pathname: []const u8) Real
|
|||||||
/// Not all targets support this. For example, WASI does not have the concept
|
/// Not all targets support this. For example, WASI does not have the concept
|
||||||
/// of a current working directory.
|
/// of a current working directory.
|
||||||
pub fn setAsCwd(self: Dir) !void {
|
pub fn setAsCwd(self: Dir) !void {
|
||||||
if (builtin.os.tag == .wasi) {
|
if (native_os == .wasi) {
|
||||||
@compileError("changing cwd is not currently possible in WASI");
|
@compileError("changing cwd is not currently possible in WASI");
|
||||||
}
|
}
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
var dir_path_buffer: [std.os.windows.PATH_MAX_WIDE]u16 = undefined;
|
var dir_path_buffer: [windows.PATH_MAX_WIDE]u16 = undefined;
|
||||||
const dir_path = try std.os.windows.GetFinalPathNameByHandle(self.fd, .{}, &dir_path_buffer);
|
const dir_path = try windows.GetFinalPathNameByHandle(self.fd, .{}, &dir_path_buffer);
|
||||||
if (builtin.link_libc) {
|
if (builtin.link_libc) {
|
||||||
return posix.chdirW(dir_path);
|
return posix.chdirW(dir_path);
|
||||||
}
|
}
|
||||||
return std.os.windows.SetCurrentDirectory(dir_path);
|
return windows.SetCurrentDirectory(dir_path);
|
||||||
}
|
}
|
||||||
try posix.fchdir(self.fd);
|
try posix.fchdir(self.fd);
|
||||||
}
|
}
|
||||||
@ -1368,9 +1362,9 @@ pub const OpenDirOptions = struct {
|
|||||||
/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
|
/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
|
||||||
/// Asserts that the path parameter has no null bytes.
|
/// Asserts that the path parameter has no null bytes.
|
||||||
pub fn openDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir {
|
pub fn openDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir {
|
||||||
switch (builtin.os.tag) {
|
switch (native_os) {
|
||||||
.windows => {
|
.windows => {
|
||||||
const sub_path_w = try posix.windows.sliceToPrefixedFileW(self.fd, sub_path);
|
const sub_path_w = try windows.sliceToPrefixedFileW(self.fd, sub_path);
|
||||||
return self.openDirW(sub_path_w.span().ptr, args);
|
return self.openDirW(sub_path_w.span().ptr, args);
|
||||||
},
|
},
|
||||||
.wasi => {
|
.wasi => {
|
||||||
@ -1427,9 +1421,9 @@ pub fn openDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!
|
|||||||
|
|
||||||
/// Same as `openDir` except the parameter is null-terminated.
|
/// Same as `openDir` except the parameter is null-terminated.
|
||||||
pub fn openDirZ(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions) OpenError!Dir {
|
pub fn openDirZ(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions) OpenError!Dir {
|
||||||
switch (builtin.os.tag) {
|
switch (native_os) {
|
||||||
.windows => {
|
.windows => {
|
||||||
const sub_path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);
|
const sub_path_w = try windows.cStrToPrefixedFileW(self.fd, sub_path_c);
|
||||||
return self.openDirW(sub_path_w.span().ptr, args);
|
return self.openDirW(sub_path_w.span().ptr, args);
|
||||||
},
|
},
|
||||||
.wasi => {
|
.wasi => {
|
||||||
@ -1453,7 +1447,7 @@ pub fn openDirZ(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions) Open
|
|||||||
/// Same as `openDir` except the path parameter is WTF-16 LE encoded, NT-prefixed.
|
/// Same as `openDir` except the path parameter is WTF-16 LE encoded, NT-prefixed.
|
||||||
/// This function asserts the target OS is Windows.
|
/// This function asserts the target OS is Windows.
|
||||||
pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions) OpenError!Dir {
|
pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions) OpenError!Dir {
|
||||||
const w = std.os.windows;
|
const w = windows;
|
||||||
// TODO remove some of these flags if args.access_sub_paths is false
|
// TODO remove some of these flags if args.access_sub_paths is false
|
||||||
const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |
|
const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |
|
||||||
w.SYNCHRONIZE | w.FILE_TRAVERSE;
|
w.SYNCHRONIZE | w.FILE_TRAVERSE;
|
||||||
@ -1487,7 +1481,7 @@ const MakeOpenDirAccessMaskWOptions = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fn makeOpenDirAccessMaskW(self: Dir, sub_path_w: [*:0]const u16, access_mask: u32, flags: MakeOpenDirAccessMaskWOptions) OpenError!Dir {
|
fn makeOpenDirAccessMaskW(self: Dir, sub_path_w: [*:0]const u16, access_mask: u32, flags: MakeOpenDirAccessMaskWOptions) OpenError!Dir {
|
||||||
const w = std.os.windows;
|
const w = windows;
|
||||||
|
|
||||||
var result = Dir{
|
var result = Dir{
|
||||||
.fd = undefined,
|
.fd = undefined,
|
||||||
@ -1545,10 +1539,10 @@ pub const DeleteFileError = posix.UnlinkError;
|
|||||||
/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
|
/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
|
||||||
/// Asserts that the path parameter has no null bytes.
|
/// Asserts that the path parameter has no null bytes.
|
||||||
pub fn deleteFile(self: Dir, sub_path: []const u8) DeleteFileError!void {
|
pub fn deleteFile(self: Dir, sub_path: []const u8) DeleteFileError!void {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const sub_path_w = try std.os.windows.sliceToPrefixedFileW(self.fd, sub_path);
|
const sub_path_w = try windows.sliceToPrefixedFileW(self.fd, sub_path);
|
||||||
return self.deleteFileW(sub_path_w.span());
|
return self.deleteFileW(sub_path_w.span());
|
||||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
} else if (native_os == .wasi and !builtin.link_libc) {
|
||||||
posix.unlinkat(self.fd, sub_path, 0) catch |err| switch (err) {
|
posix.unlinkat(self.fd, sub_path, 0) catch |err| switch (err) {
|
||||||
error.DirNotEmpty => unreachable, // not passing AT.REMOVEDIR
|
error.DirNotEmpty => unreachable, // not passing AT.REMOVEDIR
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
@ -1563,7 +1557,7 @@ pub fn deleteFile(self: Dir, sub_path: []const u8) DeleteFileError!void {
|
|||||||
pub fn deleteFileZ(self: Dir, sub_path_c: [*:0]const u8) DeleteFileError!void {
|
pub fn deleteFileZ(self: Dir, sub_path_c: [*:0]const u8) DeleteFileError!void {
|
||||||
posix.unlinkatZ(self.fd, sub_path_c, 0) catch |err| switch (err) {
|
posix.unlinkatZ(self.fd, sub_path_c, 0) catch |err| switch (err) {
|
||||||
error.DirNotEmpty => unreachable, // not passing AT.REMOVEDIR
|
error.DirNotEmpty => unreachable, // not passing AT.REMOVEDIR
|
||||||
error.AccessDenied => |e| switch (builtin.os.tag) {
|
error.AccessDenied => |e| switch (native_os) {
|
||||||
// non-Linux POSIX systems return EPERM when trying to delete a directory, so
|
// non-Linux POSIX systems return EPERM when trying to delete a directory, so
|
||||||
// we need to handle that case specifically and translate the error
|
// we need to handle that case specifically and translate the error
|
||||||
.macos, .ios, .freebsd, .netbsd, .dragonfly, .openbsd, .solaris, .illumos => {
|
.macos, .ios, .freebsd, .netbsd, .dragonfly, .openbsd, .solaris, .illumos => {
|
||||||
@ -1615,10 +1609,10 @@ pub const DeleteDirError = error{
|
|||||||
/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
|
/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
|
||||||
/// Asserts that the path parameter has no null bytes.
|
/// Asserts that the path parameter has no null bytes.
|
||||||
pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void {
|
pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const sub_path_w = try std.os.windows.sliceToPrefixedFileW(self.fd, sub_path);
|
const sub_path_w = try windows.sliceToPrefixedFileW(self.fd, sub_path);
|
||||||
return self.deleteDirW(sub_path_w.span());
|
return self.deleteDirW(sub_path_w.span());
|
||||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
} else if (native_os == .wasi and !builtin.link_libc) {
|
||||||
posix.unlinkat(self.fd, sub_path, posix.AT.REMOVEDIR) catch |err| switch (err) {
|
posix.unlinkat(self.fd, sub_path, posix.AT.REMOVEDIR) catch |err| switch (err) {
|
||||||
error.IsDir => unreachable, // not possible since we pass AT.REMOVEDIR
|
error.IsDir => unreachable, // not possible since we pass AT.REMOVEDIR
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
@ -1691,15 +1685,15 @@ pub fn symLink(
|
|||||||
sym_link_path: []const u8,
|
sym_link_path: []const u8,
|
||||||
flags: SymLinkFlags,
|
flags: SymLinkFlags,
|
||||||
) !void {
|
) !void {
|
||||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
if (native_os == .wasi and !builtin.link_libc) {
|
||||||
return self.symLinkWasi(target_path, sym_link_path, flags);
|
return self.symLinkWasi(target_path, sym_link_path, flags);
|
||||||
}
|
}
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
// Target path does not use sliceToPrefixedFileW because certain paths
|
// Target path does not use sliceToPrefixedFileW because certain paths
|
||||||
// are handled differently when creating a symlink than they would be
|
// are handled differently when creating a symlink than they would be
|
||||||
// when converting to an NT namespaced path. CreateSymbolicLink in
|
// when converting to an NT namespaced path. CreateSymbolicLink in
|
||||||
// symLinkW will handle the necessary conversion.
|
// symLinkW will handle the necessary conversion.
|
||||||
var target_path_w: std.os.windows.PathSpace = undefined;
|
var target_path_w: windows.PathSpace = undefined;
|
||||||
target_path_w.len = try std.unicode.wtf8ToWtf16Le(&target_path_w.data, target_path);
|
target_path_w.len = try std.unicode.wtf8ToWtf16Le(&target_path_w.data, target_path);
|
||||||
target_path_w.data[target_path_w.len] = 0;
|
target_path_w.data[target_path_w.len] = 0;
|
||||||
// However, we need to canonicalize any path separators to `\`, since if
|
// However, we need to canonicalize any path separators to `\`, since if
|
||||||
@ -1711,7 +1705,7 @@ pub fn symLink(
|
|||||||
mem.nativeToLittle(u16, '\\'),
|
mem.nativeToLittle(u16, '\\'),
|
||||||
);
|
);
|
||||||
|
|
||||||
const sym_link_path_w = try std.os.windows.sliceToPrefixedFileW(self.fd, sym_link_path);
|
const sym_link_path_w = try windows.sliceToPrefixedFileW(self.fd, sym_link_path);
|
||||||
return self.symLinkW(target_path_w.span(), sym_link_path_w.span(), flags);
|
return self.symLinkW(target_path_w.span(), sym_link_path_w.span(), flags);
|
||||||
}
|
}
|
||||||
const target_path_c = try posix.toPosixPath(target_path);
|
const target_path_c = try posix.toPosixPath(target_path);
|
||||||
@ -1736,9 +1730,9 @@ pub fn symLinkZ(
|
|||||||
sym_link_path_c: [*:0]const u8,
|
sym_link_path_c: [*:0]const u8,
|
||||||
flags: SymLinkFlags,
|
flags: SymLinkFlags,
|
||||||
) !void {
|
) !void {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const target_path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, target_path_c);
|
const target_path_w = try windows.cStrToPrefixedFileW(self.fd, target_path_c);
|
||||||
const sym_link_path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sym_link_path_c);
|
const sym_link_path_w = try windows.cStrToPrefixedFileW(self.fd, sym_link_path_c);
|
||||||
return self.symLinkW(target_path_w.span(), sym_link_path_w.span(), flags);
|
return self.symLinkW(target_path_w.span(), sym_link_path_w.span(), flags);
|
||||||
}
|
}
|
||||||
return posix.symlinkatZ(target_path_c, self.fd, sym_link_path_c);
|
return posix.symlinkatZ(target_path_c, self.fd, sym_link_path_c);
|
||||||
@ -1756,7 +1750,7 @@ pub fn symLinkW(
|
|||||||
sym_link_path_w: []const u16,
|
sym_link_path_w: []const u16,
|
||||||
flags: SymLinkFlags,
|
flags: SymLinkFlags,
|
||||||
) !void {
|
) !void {
|
||||||
return std.os.windows.CreateSymbolicLink(self.fd, sym_link_path_w, target_path_w, flags.is_directory);
|
return windows.CreateSymbolicLink(self.fd, sym_link_path_w, target_path_w, flags.is_directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ReadLinkError = posix.ReadLinkError;
|
pub const ReadLinkError = posix.ReadLinkError;
|
||||||
@ -1768,11 +1762,11 @@ pub const ReadLinkError = posix.ReadLinkError;
|
|||||||
/// On WASI, `sub_path` should be encoded as valid UTF-8.
|
/// On WASI, `sub_path` should be encoded as valid UTF-8.
|
||||||
/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
|
/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
|
||||||
pub fn readLink(self: Dir, sub_path: []const u8, buffer: []u8) ReadLinkError![]u8 {
|
pub fn readLink(self: Dir, sub_path: []const u8, buffer: []u8) ReadLinkError![]u8 {
|
||||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
if (native_os == .wasi and !builtin.link_libc) {
|
||||||
return self.readLinkWasi(sub_path, buffer);
|
return self.readLinkWasi(sub_path, buffer);
|
||||||
}
|
}
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const sub_path_w = try std.os.windows.sliceToPrefixedFileW(self.fd, sub_path);
|
const sub_path_w = try windows.sliceToPrefixedFileW(self.fd, sub_path);
|
||||||
return self.readLinkW(sub_path_w.span(), buffer);
|
return self.readLinkW(sub_path_w.span(), buffer);
|
||||||
}
|
}
|
||||||
const sub_path_c = try posix.toPosixPath(sub_path);
|
const sub_path_c = try posix.toPosixPath(sub_path);
|
||||||
@ -1786,8 +1780,8 @@ pub fn readLinkWasi(self: Dir, sub_path: []const u8, buffer: []u8) ![]u8 {
|
|||||||
|
|
||||||
/// Same as `readLink`, except the `sub_path_c` parameter is null-terminated.
|
/// Same as `readLink`, except the `sub_path_c` parameter is null-terminated.
|
||||||
pub fn readLinkZ(self: Dir, sub_path_c: [*:0]const u8, buffer: []u8) ![]u8 {
|
pub fn readLinkZ(self: Dir, sub_path_c: [*:0]const u8, buffer: []u8) ![]u8 {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const sub_path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);
|
const sub_path_w = try windows.cStrToPrefixedFileW(self.fd, sub_path_c);
|
||||||
return self.readLinkW(sub_path_w.span(), buffer);
|
return self.readLinkW(sub_path_w.span(), buffer);
|
||||||
}
|
}
|
||||||
return posix.readlinkatZ(self.fd, sub_path_c, buffer);
|
return posix.readlinkatZ(self.fd, sub_path_c, buffer);
|
||||||
@ -1796,7 +1790,7 @@ pub fn readLinkZ(self: Dir, sub_path_c: [*:0]const u8, buffer: []u8) ![]u8 {
|
|||||||
/// Windows-only. Same as `readLink` except the pathname parameter
|
/// Windows-only. Same as `readLink` except the pathname parameter
|
||||||
/// is WTF16 LE encoded.
|
/// is WTF16 LE encoded.
|
||||||
pub fn readLinkW(self: Dir, sub_path_w: []const u16, buffer: []u8) ![]u8 {
|
pub fn readLinkW(self: Dir, sub_path_w: []const u16, buffer: []u8) ![]u8 {
|
||||||
return std.os.windows.ReadLink(self.fd, sub_path_w, buffer);
|
return windows.ReadLink(self.fd, sub_path_w, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read all of file contents using a preallocated buffer.
|
/// Read all of file contents using a preallocated buffer.
|
||||||
@ -2319,8 +2313,8 @@ pub const AccessError = posix.AccessError;
|
|||||||
/// For example, instead of testing if a file exists and then opening it, just
|
/// For example, instead of testing if a file exists and then opening it, just
|
||||||
/// open it and handle the error for file not found.
|
/// open it and handle the error for file not found.
|
||||||
pub fn access(self: Dir, sub_path: []const u8, flags: File.OpenFlags) AccessError!void {
|
pub fn access(self: Dir, sub_path: []const u8, flags: File.OpenFlags) AccessError!void {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const sub_path_w = std.os.windows.sliceToPrefixedFileW(self.fd, sub_path) catch |err| switch (err) {
|
const sub_path_w = windows.sliceToPrefixedFileW(self.fd, sub_path) catch |err| switch (err) {
|
||||||
error.AccessDenied => return error.PermissionDenied,
|
error.AccessDenied => return error.PermissionDenied,
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
};
|
};
|
||||||
@ -2332,8 +2326,8 @@ pub fn access(self: Dir, sub_path: []const u8, flags: File.OpenFlags) AccessErro
|
|||||||
|
|
||||||
/// Same as `access` except the path parameter is null-terminated.
|
/// Same as `access` except the path parameter is null-terminated.
|
||||||
pub fn accessZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) AccessError!void {
|
pub fn accessZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) AccessError!void {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const sub_path_w = std.os.windows.cStrToPrefixedFileW(self.fd, sub_path) catch |err| switch (err) {
|
const sub_path_w = windows.cStrToPrefixedFileW(self.fd, sub_path) catch |err| switch (err) {
|
||||||
error.AccessDenied => return error.PermissionDenied,
|
error.AccessDenied => return error.PermissionDenied,
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
};
|
};
|
||||||
@ -2355,7 +2349,7 @@ pub fn accessZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) Access
|
|||||||
/// TODO currently this ignores `flags`.
|
/// TODO currently this ignores `flags`.
|
||||||
pub fn accessW(self: Dir, sub_path_w: [*:0]const u16, flags: File.OpenFlags) AccessError!void {
|
pub fn accessW(self: Dir, sub_path_w: [*:0]const u16, flags: File.OpenFlags) AccessError!void {
|
||||||
_ = flags;
|
_ = flags;
|
||||||
return posix.faccessatW(self.fd, sub_path_w, 0, 0);
|
return posix.faccessatW(self.fd, sub_path_w);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const CopyFileOptions = struct {
|
pub const CopyFileOptions = struct {
|
||||||
@ -2473,7 +2467,7 @@ fn copy_file(fd_in: posix.fd_t, fd_out: posix.fd_t, maybe_size: ?u64) CopyFileRa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (builtin.os.tag == .linux) {
|
if (native_os == .linux) {
|
||||||
// Try copy_file_range first as that works at the FS level and is the
|
// Try copy_file_range first as that works at the FS level and is the
|
||||||
// most efficient method (if available).
|
// most efficient method (if available).
|
||||||
var offset: u64 = 0;
|
var offset: u64 = 0;
|
||||||
@ -2555,12 +2549,12 @@ pub const StatFileError = File.OpenError || File.StatError || posix.FStatAtError
|
|||||||
/// On WASI, `sub_path` should be encoded as valid UTF-8.
|
/// On WASI, `sub_path` should be encoded as valid UTF-8.
|
||||||
/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
|
/// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding.
|
||||||
pub fn statFile(self: Dir, sub_path: []const u8) StatFileError!Stat {
|
pub fn statFile(self: Dir, sub_path: []const u8) StatFileError!Stat {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
var file = try self.openFile(sub_path, .{});
|
var file = try self.openFile(sub_path, .{});
|
||||||
defer file.close();
|
defer file.close();
|
||||||
return file.stat();
|
return file.stat();
|
||||||
}
|
}
|
||||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
if (native_os == .wasi and !builtin.link_libc) {
|
||||||
const st = try posix.fstatat_wasi(self.fd, sub_path, .{ .SYMLINK_FOLLOW = true });
|
const st = try posix.fstatat_wasi(self.fd, sub_path, .{ .SYMLINK_FOLLOW = true });
|
||||||
return Stat.fromWasi(st);
|
return Stat.fromWasi(st);
|
||||||
}
|
}
|
||||||
@ -2617,9 +2611,10 @@ const builtin = @import("builtin");
|
|||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const File = std.fs.File;
|
const File = std.fs.File;
|
||||||
const AtomicFile = std.fs.AtomicFile;
|
const AtomicFile = std.fs.AtomicFile;
|
||||||
// https://github.com/ziglang/zig/issues/5019
|
const posix = std.posix;
|
||||||
const posix = std.os;
|
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const fs = std.fs;
|
const fs = std.fs;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
const windows = std.os.windows;
|
||||||
|
const native_os = builtin.os.tag;
|
||||||
|
|||||||
@ -193,6 +193,58 @@ pub fn isTty(self: File) bool {
|
|||||||
return posix.isatty(self.handle);
|
return posix.isatty(self.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn isCygwinPty(file: File) bool {
|
||||||
|
if (builtin.os.tag != .windows) return false;
|
||||||
|
|
||||||
|
const handle = file.handle;
|
||||||
|
|
||||||
|
// If this is a MSYS2/cygwin pty, then it will be a named pipe with a name in one of these formats:
|
||||||
|
// msys-[...]-ptyN-[...]
|
||||||
|
// cygwin-[...]-ptyN-[...]
|
||||||
|
//
|
||||||
|
// Example: msys-1888ae32e00d56aa-pty0-to-master
|
||||||
|
|
||||||
|
// First, just check that the handle is a named pipe.
|
||||||
|
// This allows us to avoid the more costly NtQueryInformationFile call
|
||||||
|
// for handles that aren't named pipes.
|
||||||
|
{
|
||||||
|
var io_status: windows.IO_STATUS_BLOCK = undefined;
|
||||||
|
var device_info: windows.FILE_FS_DEVICE_INFORMATION = undefined;
|
||||||
|
const rc = windows.ntdll.NtQueryVolumeInformationFile(handle, &io_status, &device_info, @sizeOf(windows.FILE_FS_DEVICE_INFORMATION), .FileFsDeviceInformation);
|
||||||
|
switch (rc) {
|
||||||
|
.SUCCESS => {},
|
||||||
|
else => return false,
|
||||||
|
}
|
||||||
|
if (device_info.DeviceType != windows.FILE_DEVICE_NAMED_PIPE) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const name_bytes_offset = @offsetOf(windows.FILE_NAME_INFO, "FileName");
|
||||||
|
// `NAME_MAX` UTF-16 code units (2 bytes each)
|
||||||
|
// This buffer may not be long enough to handle *all* possible paths
|
||||||
|
// (PATH_MAX_WIDE would be necessary for that), but because we only care
|
||||||
|
// about certain paths and we know they must be within a reasonable length,
|
||||||
|
// we can use this smaller buffer and just return false on any error from
|
||||||
|
// NtQueryInformationFile.
|
||||||
|
const num_name_bytes = windows.MAX_PATH * 2;
|
||||||
|
var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = [_]u8{0} ** (name_bytes_offset + num_name_bytes);
|
||||||
|
|
||||||
|
var io_status_block: windows.IO_STATUS_BLOCK = undefined;
|
||||||
|
const rc = windows.ntdll.NtQueryInformationFile(handle, &io_status_block, &name_info_bytes, @intCast(name_info_bytes.len), .FileNameInformation);
|
||||||
|
switch (rc) {
|
||||||
|
.SUCCESS => {},
|
||||||
|
.INVALID_PARAMETER => unreachable,
|
||||||
|
else => return false,
|
||||||
|
}
|
||||||
|
|
||||||
|
const name_info: *const windows.FILE_NAME_INFO = @ptrCast(&name_info_bytes);
|
||||||
|
const name_bytes = name_info_bytes[name_bytes_offset .. name_bytes_offset + name_info.FileNameLength];
|
||||||
|
const name_wide = std.mem.bytesAsSlice(u16, name_bytes);
|
||||||
|
// The name we get from NtQueryInformationFile will be prefixed with a '\', e.g. \msys-1888ae32e00d56aa-pty0-to-master
|
||||||
|
return (std.mem.startsWith(u16, name_wide, &[_]u16{ '\\', 'm', 's', 'y', 's', '-' }) or
|
||||||
|
std.mem.startsWith(u16, name_wide, &[_]u16{ '\\', 'c', 'y', 'g', 'w', 'i', 'n', '-' })) and
|
||||||
|
std.mem.indexOf(u16, name_wide, &[_]u16{ '-', 'p', 't', 'y' }) != null;
|
||||||
|
}
|
||||||
|
|
||||||
/// Test whether ANSI escape codes will be treated as such.
|
/// Test whether ANSI escape codes will be treated as such.
|
||||||
pub fn supportsAnsiEscapeCodes(self: File) bool {
|
pub fn supportsAnsiEscapeCodes(self: File) bool {
|
||||||
if (builtin.os.tag == .windows) {
|
if (builtin.os.tag == .windows) {
|
||||||
@ -201,7 +253,7 @@ pub fn supportsAnsiEscapeCodes(self: File) bool {
|
|||||||
if (console_mode & windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING != 0) return true;
|
if (console_mode & windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING != 0) return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return posix.isCygwinPty(self.handle);
|
return self.isCygwinPty();
|
||||||
}
|
}
|
||||||
if (builtin.os.tag == .wasi) {
|
if (builtin.os.tag == .wasi) {
|
||||||
// WASI sanitizes stdout when fd is a tty so ANSI escape codes
|
// WASI sanitizes stdout when fd is a tty so ANSI escape codes
|
||||||
@ -1634,8 +1686,7 @@ const File = @This();
|
|||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
// https://github.com/ziglang/zig/issues/5019
|
const posix = std.posix;
|
||||||
const posix = std.os;
|
|
||||||
const io = std.io;
|
const io = std.io;
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
|||||||
@ -3,7 +3,8 @@ const builtin = @import("builtin");
|
|||||||
const unicode = std.unicode;
|
const unicode = std.unicode;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const fs = std.fs;
|
const fs = std.fs;
|
||||||
const os = std.os;
|
const native_os = builtin.os.tag;
|
||||||
|
const posix = std.posix;
|
||||||
|
|
||||||
pub const GetAppDataDirError = error{
|
pub const GetAppDataDirError = error{
|
||||||
OutOfMemory,
|
OutOfMemory,
|
||||||
@ -13,7 +14,7 @@ pub const GetAppDataDirError = error{
|
|||||||
/// Caller owns returned memory.
|
/// Caller owns returned memory.
|
||||||
/// TODO determine if we can remove the allocator requirement
|
/// TODO determine if we can remove the allocator requirement
|
||||||
pub fn getAppDataDir(allocator: mem.Allocator, appname: []const u8) GetAppDataDirError![]u8 {
|
pub fn getAppDataDir(allocator: mem.Allocator, appname: []const u8) GetAppDataDirError![]u8 {
|
||||||
switch (builtin.os.tag) {
|
switch (native_os) {
|
||||||
.windows => {
|
.windows => {
|
||||||
const local_app_data_dir = std.process.getEnvVarOwned(allocator, "LOCALAPPDATA") catch |err| switch (err) {
|
const local_app_data_dir = std.process.getEnvVarOwned(allocator, "LOCALAPPDATA") catch |err| switch (err) {
|
||||||
error.OutOfMemory => |e| return e,
|
error.OutOfMemory => |e| return e,
|
||||||
@ -23,18 +24,18 @@ pub fn getAppDataDir(allocator: mem.Allocator, appname: []const u8) GetAppDataDi
|
|||||||
return fs.path.join(allocator, &[_][]const u8{ local_app_data_dir, appname });
|
return fs.path.join(allocator, &[_][]const u8{ local_app_data_dir, appname });
|
||||||
},
|
},
|
||||||
.macos => {
|
.macos => {
|
||||||
const home_dir = os.getenv("HOME") orelse {
|
const home_dir = posix.getenv("HOME") orelse {
|
||||||
// TODO look in /etc/passwd
|
// TODO look in /etc/passwd
|
||||||
return error.AppDataDirUnavailable;
|
return error.AppDataDirUnavailable;
|
||||||
};
|
};
|
||||||
return fs.path.join(allocator, &[_][]const u8{ home_dir, "Library", "Application Support", appname });
|
return fs.path.join(allocator, &[_][]const u8{ home_dir, "Library", "Application Support", appname });
|
||||||
},
|
},
|
||||||
.linux, .freebsd, .netbsd, .dragonfly, .openbsd, .solaris, .illumos => {
|
.linux, .freebsd, .netbsd, .dragonfly, .openbsd, .solaris, .illumos => {
|
||||||
if (os.getenv("XDG_DATA_HOME")) |xdg| {
|
if (posix.getenv("XDG_DATA_HOME")) |xdg| {
|
||||||
return fs.path.join(allocator, &[_][]const u8{ xdg, appname });
|
return fs.path.join(allocator, &[_][]const u8{ xdg, appname });
|
||||||
}
|
}
|
||||||
|
|
||||||
const home_dir = os.getenv("HOME") orelse {
|
const home_dir = posix.getenv("HOME") orelse {
|
||||||
// TODO look in /etc/passwd
|
// TODO look in /etc/passwd
|
||||||
return error.AppDataDirUnavailable;
|
return error.AppDataDirUnavailable;
|
||||||
};
|
};
|
||||||
@ -48,7 +49,7 @@ pub fn getAppDataDir(allocator: mem.Allocator, appname: []const u8) GetAppDataDi
|
|||||||
}
|
}
|
||||||
// TODO look into directory_which
|
// TODO look into directory_which
|
||||||
const be_user_settings = 0xbbe;
|
const be_user_settings = 0xbbe;
|
||||||
const rc = os.system.find_directory(be_user_settings, -1, true, dir_path_ptr, 1);
|
const rc = std.c.find_directory(be_user_settings, -1, true, dir_path_ptr, 1);
|
||||||
const settings_dir = try allocator.dupeZ(u8, mem.sliceTo(dir_path_ptr, 0));
|
const settings_dir = try allocator.dupeZ(u8, mem.sliceTo(dir_path_ptr, 0));
|
||||||
defer allocator.free(settings_dir);
|
defer allocator.free(settings_dir);
|
||||||
switch (rc) {
|
switch (rc) {
|
||||||
@ -61,7 +62,7 @@ pub fn getAppDataDir(allocator: mem.Allocator, appname: []const u8) GetAppDataDi
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "getAppDataDir" {
|
test "getAppDataDir" {
|
||||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
if (native_os == .wasi) return error.SkipZigTest;
|
||||||
|
|
||||||
// We can't actually validate the result
|
// We can't actually validate the result
|
||||||
const dir = getAppDataDir(std.testing.allocator, "zig") catch return;
|
const dir = getAppDataDir(std.testing.allocator, "zig") catch return;
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const os = std.os;
|
|
||||||
const fs = std.fs;
|
const fs = std.fs;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const wasi = std.os.wasi;
|
const wasi = std.os.wasi;
|
||||||
|
const native_os = builtin.os.tag;
|
||||||
|
const windows = std.os.windows;
|
||||||
|
const posix = std.posix;
|
||||||
|
|
||||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||||
const Dir = std.fs.Dir;
|
const Dir = std.fs.Dir;
|
||||||
@ -25,7 +27,7 @@ const PathType = enum {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const TransformError = std.os.RealPathError || error{OutOfMemory};
|
pub const TransformError = posix.RealPathError || error{OutOfMemory};
|
||||||
pub const TransformFn = fn (allocator: mem.Allocator, dir: Dir, relative_path: [:0]const u8) TransformError![:0]const u8;
|
pub const TransformFn = fn (allocator: mem.Allocator, dir: Dir, relative_path: [:0]const u8) TransformError![:0]const u8;
|
||||||
|
|
||||||
pub fn getTransformFn(comptime path_type: PathType) TransformFn {
|
pub fn getTransformFn(comptime path_type: PathType) TransformFn {
|
||||||
@ -42,7 +44,7 @@ const PathType = enum {
|
|||||||
// The final path may not actually exist which would cause realpath to fail.
|
// The final path may not actually exist which would cause realpath to fail.
|
||||||
// So instead, we get the path of the dir and join it with the relative path.
|
// So instead, we get the path of the dir and join it with the relative path.
|
||||||
var fd_path_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
|
var fd_path_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
const dir_path = try os.getFdPath(dir.fd, &fd_path_buf);
|
const dir_path = try std.os.getFdPath(dir.fd, &fd_path_buf);
|
||||||
return fs.path.joinZ(allocator, &.{ dir_path, relative_path });
|
return fs.path.joinZ(allocator, &.{ dir_path, relative_path });
|
||||||
}
|
}
|
||||||
}.transform,
|
}.transform,
|
||||||
@ -51,8 +53,8 @@ const PathType = enum {
|
|||||||
// Any drive absolute path (C:\foo) can be converted into a UNC path by
|
// Any drive absolute path (C:\foo) can be converted into a UNC path by
|
||||||
// using '127.0.0.1' as the server name and '<drive letter>$' as the share name.
|
// using '127.0.0.1' as the server name and '<drive letter>$' as the share name.
|
||||||
var fd_path_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
|
var fd_path_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
const dir_path = try os.getFdPath(dir.fd, &fd_path_buf);
|
const dir_path = try std.os.getFdPath(dir.fd, &fd_path_buf);
|
||||||
const windows_path_type = std.os.windows.getUnprefixedPathType(u8, dir_path);
|
const windows_path_type = windows.getUnprefixedPathType(u8, dir_path);
|
||||||
switch (windows_path_type) {
|
switch (windows_path_type) {
|
||||||
.unc_absolute => return fs.path.joinZ(allocator, &.{ dir_path, relative_path }),
|
.unc_absolute => return fs.path.joinZ(allocator, &.{ dir_path, relative_path }),
|
||||||
.drive_absolute => {
|
.drive_absolute => {
|
||||||
@ -102,7 +104,7 @@ const TestContext = struct {
|
|||||||
pub fn transformPath(self: *TestContext, relative_path: [:0]const u8) ![:0]const u8 {
|
pub fn transformPath(self: *TestContext, relative_path: [:0]const u8) ![:0]const u8 {
|
||||||
const allocator = self.arena.allocator();
|
const allocator = self.arena.allocator();
|
||||||
const transformed_path = try self.transform_fn(allocator, self.dir, relative_path);
|
const transformed_path = try self.transform_fn(allocator, self.dir, relative_path);
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const transformed_sep_path = try allocator.dupeZ(u8, transformed_path);
|
const transformed_sep_path = try allocator.dupeZ(u8, transformed_path);
|
||||||
std.mem.replaceScalar(u8, transformed_sep_path, switch (self.path_sep) {
|
std.mem.replaceScalar(u8, transformed_sep_path, switch (self.path_sep) {
|
||||||
'/' => '\\',
|
'/' => '\\',
|
||||||
@ -119,7 +121,7 @@ const TestContext = struct {
|
|||||||
/// If path separators are replaced, then the result is allocated by the
|
/// If path separators are replaced, then the result is allocated by the
|
||||||
/// TestContext's arena and will be free'd during `TestContext.deinit`.
|
/// TestContext's arena and will be free'd during `TestContext.deinit`.
|
||||||
pub fn toCanonicalPathSep(self: *TestContext, path: [:0]const u8) ![:0]const u8 {
|
pub fn toCanonicalPathSep(self: *TestContext, path: [:0]const u8) ![:0]const u8 {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const allocator = self.arena.allocator();
|
const allocator = self.arena.allocator();
|
||||||
const transformed_sep_path = try allocator.dupeZ(u8, path);
|
const transformed_sep_path = try allocator.dupeZ(u8, path);
|
||||||
std.mem.replaceScalar(u8, transformed_sep_path, '/', '\\');
|
std.mem.replaceScalar(u8, transformed_sep_path, '/', '\\');
|
||||||
@ -157,7 +159,7 @@ fn testWithPathTypeIfSupported(comptime path_type: PathType, comptime path_sep:
|
|||||||
fn setupSymlink(dir: Dir, target: []const u8, link: []const u8, flags: SymLinkFlags) !void {
|
fn setupSymlink(dir: Dir, target: []const u8, link: []const u8, flags: SymLinkFlags) !void {
|
||||||
return dir.symLink(target, link, flags) catch |err| switch (err) {
|
return dir.symLink(target, link, flags) catch |err| switch (err) {
|
||||||
// Symlink requires admin privileges on windows, so this test can legitimately fail.
|
// Symlink requires admin privileges on windows, so this test can legitimately fail.
|
||||||
error.AccessDenied => if (builtin.os.tag == .windows) return error.SkipZigTest else return err,
|
error.AccessDenied => if (native_os == .windows) return error.SkipZigTest else return err,
|
||||||
else => return err,
|
else => return err,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -166,7 +168,7 @@ fn setupSymlink(dir: Dir, target: []const u8, link: []const u8, flags: SymLinkFl
|
|||||||
// AccessDenied, then make the test failure silent (it is not a Zig failure).
|
// AccessDenied, then make the test failure silent (it is not a Zig failure).
|
||||||
fn setupSymlinkAbsolute(target: []const u8, link: []const u8, flags: SymLinkFlags) !void {
|
fn setupSymlinkAbsolute(target: []const u8, link: []const u8, flags: SymLinkFlags) !void {
|
||||||
return fs.symLinkAbsolute(target, link, flags) catch |err| switch (err) {
|
return fs.symLinkAbsolute(target, link, flags) catch |err| switch (err) {
|
||||||
error.AccessDenied => if (builtin.os.tag == .windows) return error.SkipZigTest else return err,
|
error.AccessDenied => if (native_os == .windows) return error.SkipZigTest else return err,
|
||||||
else => return err,
|
else => return err,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -232,60 +234,58 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" {
|
|||||||
|
|
||||||
var symlink = switch (builtin.target.os.tag) {
|
var symlink = switch (builtin.target.os.tag) {
|
||||||
.windows => windows_symlink: {
|
.windows => windows_symlink: {
|
||||||
const w = std.os.windows;
|
const sub_path_w = try windows.cStrToPrefixedFileW(ctx.dir.fd, "symlink");
|
||||||
|
|
||||||
const sub_path_w = try std.os.windows.cStrToPrefixedFileW(ctx.dir.fd, "symlink");
|
|
||||||
|
|
||||||
var result = Dir{
|
var result = Dir{
|
||||||
.fd = undefined,
|
.fd = undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
const path_len_bytes = @as(u16, @intCast(sub_path_w.span().len * 2));
|
const path_len_bytes = @as(u16, @intCast(sub_path_w.span().len * 2));
|
||||||
var nt_name = w.UNICODE_STRING{
|
var nt_name = windows.UNICODE_STRING{
|
||||||
.Length = path_len_bytes,
|
.Length = path_len_bytes,
|
||||||
.MaximumLength = path_len_bytes,
|
.MaximumLength = path_len_bytes,
|
||||||
.Buffer = @constCast(&sub_path_w.data),
|
.Buffer = @constCast(&sub_path_w.data),
|
||||||
};
|
};
|
||||||
var attr = w.OBJECT_ATTRIBUTES{
|
var attr = windows.OBJECT_ATTRIBUTES{
|
||||||
.Length = @sizeOf(w.OBJECT_ATTRIBUTES),
|
.Length = @sizeOf(windows.OBJECT_ATTRIBUTES),
|
||||||
.RootDirectory = if (fs.path.isAbsoluteWindowsW(sub_path_w.span())) null else ctx.dir.fd,
|
.RootDirectory = if (fs.path.isAbsoluteWindowsW(sub_path_w.span())) null else ctx.dir.fd,
|
||||||
.Attributes = 0,
|
.Attributes = 0,
|
||||||
.ObjectName = &nt_name,
|
.ObjectName = &nt_name,
|
||||||
.SecurityDescriptor = null,
|
.SecurityDescriptor = null,
|
||||||
.SecurityQualityOfService = null,
|
.SecurityQualityOfService = null,
|
||||||
};
|
};
|
||||||
var io: w.IO_STATUS_BLOCK = undefined;
|
var io: windows.IO_STATUS_BLOCK = undefined;
|
||||||
const rc = w.ntdll.NtCreateFile(
|
const rc = windows.ntdll.NtCreateFile(
|
||||||
&result.fd,
|
&result.fd,
|
||||||
w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | w.SYNCHRONIZE | w.FILE_TRAVERSE,
|
windows.STANDARD_RIGHTS_READ | windows.FILE_READ_ATTRIBUTES | windows.FILE_READ_EA | windows.SYNCHRONIZE | windows.FILE_TRAVERSE,
|
||||||
&attr,
|
&attr,
|
||||||
&io,
|
&io,
|
||||||
null,
|
null,
|
||||||
w.FILE_ATTRIBUTE_NORMAL,
|
windows.FILE_ATTRIBUTE_NORMAL,
|
||||||
w.FILE_SHARE_READ | w.FILE_SHARE_WRITE,
|
windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE,
|
||||||
w.FILE_OPEN,
|
windows.FILE_OPEN,
|
||||||
// FILE_OPEN_REPARSE_POINT is the important thing here
|
// FILE_OPEN_REPARSE_POINT is the important thing here
|
||||||
w.FILE_OPEN_REPARSE_POINT | w.FILE_DIRECTORY_FILE | w.FILE_SYNCHRONOUS_IO_NONALERT | w.FILE_OPEN_FOR_BACKUP_INTENT,
|
windows.FILE_OPEN_REPARSE_POINT | windows.FILE_DIRECTORY_FILE | windows.FILE_SYNCHRONOUS_IO_NONALERT | windows.FILE_OPEN_FOR_BACKUP_INTENT,
|
||||||
null,
|
null,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
|
||||||
switch (rc) {
|
switch (rc) {
|
||||||
.SUCCESS => break :windows_symlink result,
|
.SUCCESS => break :windows_symlink result,
|
||||||
else => return w.unexpectedStatus(rc),
|
else => return windows.unexpectedStatus(rc),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.linux => linux_symlink: {
|
.linux => linux_symlink: {
|
||||||
const sub_path_c = try os.toPosixPath("symlink");
|
const sub_path_c = try posix.toPosixPath("symlink");
|
||||||
// the O_NOFOLLOW | O_PATH combination can obtain a fd to a symlink
|
// the O_NOFOLLOW | O_PATH combination can obtain a fd to a symlink
|
||||||
// note that if O_DIRECTORY is set, then this will error with ENOTDIR
|
// note that if O_DIRECTORY is set, then this will error with ENOTDIR
|
||||||
const flags: os.O = .{
|
const flags: posix.O = .{
|
||||||
.NOFOLLOW = true,
|
.NOFOLLOW = true,
|
||||||
.PATH = true,
|
.PATH = true,
|
||||||
.ACCMODE = .RDONLY,
|
.ACCMODE = .RDONLY,
|
||||||
.CLOEXEC = true,
|
.CLOEXEC = true,
|
||||||
};
|
};
|
||||||
const fd = try os.openatZ(ctx.dir.fd, &sub_path_c, flags, 0);
|
const fd = try posix.openatZ(ctx.dir.fd, &sub_path_c, flags, 0);
|
||||||
break :linux_symlink Dir{ .fd = fd };
|
break :linux_symlink Dir{ .fd = fd };
|
||||||
},
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
@ -315,7 +315,7 @@ test "openDir" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "accessAbsolute" {
|
test "accessAbsolute" {
|
||||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
if (native_os == .wasi) return error.SkipZigTest;
|
||||||
|
|
||||||
var tmp = tmpDir(.{});
|
var tmp = tmpDir(.{});
|
||||||
defer tmp.cleanup();
|
defer tmp.cleanup();
|
||||||
@ -333,7 +333,7 @@ test "accessAbsolute" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "openDirAbsolute" {
|
test "openDirAbsolute" {
|
||||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
if (native_os == .wasi) return error.SkipZigTest;
|
||||||
|
|
||||||
var tmp = tmpDir(.{});
|
var tmp = tmpDir(.{});
|
||||||
defer tmp.cleanup();
|
defer tmp.cleanup();
|
||||||
@ -361,14 +361,14 @@ test "openDirAbsolute" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "openDir cwd parent '..'" {
|
test "openDir cwd parent '..'" {
|
||||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
if (native_os == .wasi) return error.SkipZigTest;
|
||||||
|
|
||||||
var dir = try fs.cwd().openDir("..", .{});
|
var dir = try fs.cwd().openDir("..", .{});
|
||||||
defer dir.close();
|
defer dir.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
test "openDir non-cwd parent '..'" {
|
test "openDir non-cwd parent '..'" {
|
||||||
switch (builtin.os.tag) {
|
switch (native_os) {
|
||||||
.wasi, .netbsd, .openbsd => return error.SkipZigTest,
|
.wasi, .netbsd, .openbsd => return error.SkipZigTest,
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
@ -392,7 +392,7 @@ test "openDir non-cwd parent '..'" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "readLinkAbsolute" {
|
test "readLinkAbsolute" {
|
||||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
if (native_os == .wasi) return error.SkipZigTest;
|
||||||
|
|
||||||
var tmp = tmpDir(.{});
|
var tmp = tmpDir(.{});
|
||||||
defer tmp.cleanup();
|
defer tmp.cleanup();
|
||||||
@ -587,7 +587,7 @@ test "Dir.Iterator but dir is deleted during iteration" {
|
|||||||
try std.testing.expect(entry == null);
|
try std.testing.expect(entry == null);
|
||||||
|
|
||||||
// On Linux, we can opt-in to receiving a more specific error by calling `nextLinux`
|
// On Linux, we can opt-in to receiving a more specific error by calling `nextLinux`
|
||||||
if (builtin.os.tag == .linux) {
|
if (native_os == .linux) {
|
||||||
try std.testing.expectError(error.DirNotFound, iterator.nextLinux());
|
try std.testing.expectError(error.DirNotFound, iterator.nextLinux());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -744,7 +744,7 @@ test "directory operations on files" {
|
|||||||
|
|
||||||
test "file operations on directories" {
|
test "file operations on directories" {
|
||||||
// TODO: fix this test on FreeBSD. https://github.com/ziglang/zig/issues/1759
|
// TODO: fix this test on FreeBSD. https://github.com/ziglang/zig/issues/1759
|
||||||
if (builtin.os.tag == .freebsd) return error.SkipZigTest;
|
if (native_os == .freebsd) return error.SkipZigTest;
|
||||||
|
|
||||||
try testWithAllSupportedPathTypes(struct {
|
try testWithAllSupportedPathTypes(struct {
|
||||||
fn impl(ctx: *TestContext) !void {
|
fn impl(ctx: *TestContext) !void {
|
||||||
@ -754,7 +754,7 @@ test "file operations on directories" {
|
|||||||
|
|
||||||
try testing.expectError(error.IsDir, ctx.dir.createFile(test_dir_name, .{}));
|
try testing.expectError(error.IsDir, ctx.dir.createFile(test_dir_name, .{}));
|
||||||
try testing.expectError(error.IsDir, ctx.dir.deleteFile(test_dir_name));
|
try testing.expectError(error.IsDir, ctx.dir.deleteFile(test_dir_name));
|
||||||
switch (builtin.os.tag) {
|
switch (native_os) {
|
||||||
// no error when reading a directory.
|
// no error when reading a directory.
|
||||||
.dragonfly, .netbsd => {},
|
.dragonfly, .netbsd => {},
|
||||||
// Currently, WASI will return error.Unexpected (via ENOTCAPABLE) when attempting fd_read on a directory handle.
|
// Currently, WASI will return error.Unexpected (via ENOTCAPABLE) when attempting fd_read on a directory handle.
|
||||||
@ -895,7 +895,7 @@ test "Dir.rename directories" {
|
|||||||
|
|
||||||
test "Dir.rename directory onto empty dir" {
|
test "Dir.rename directory onto empty dir" {
|
||||||
// TODO: Fix on Windows, see https://github.com/ziglang/zig/issues/6364
|
// TODO: Fix on Windows, see https://github.com/ziglang/zig/issues/6364
|
||||||
if (builtin.os.tag == .windows) return error.SkipZigTest;
|
if (native_os == .windows) return error.SkipZigTest;
|
||||||
|
|
||||||
try testWithAllSupportedPathTypes(struct {
|
try testWithAllSupportedPathTypes(struct {
|
||||||
fn impl(ctx: *TestContext) !void {
|
fn impl(ctx: *TestContext) !void {
|
||||||
@ -916,7 +916,7 @@ test "Dir.rename directory onto empty dir" {
|
|||||||
|
|
||||||
test "Dir.rename directory onto non-empty dir" {
|
test "Dir.rename directory onto non-empty dir" {
|
||||||
// TODO: Fix on Windows, see https://github.com/ziglang/zig/issues/6364
|
// TODO: Fix on Windows, see https://github.com/ziglang/zig/issues/6364
|
||||||
if (builtin.os.tag == .windows) return error.SkipZigTest;
|
if (native_os == .windows) return error.SkipZigTest;
|
||||||
|
|
||||||
try testWithAllSupportedPathTypes(struct {
|
try testWithAllSupportedPathTypes(struct {
|
||||||
fn impl(ctx: *TestContext) !void {
|
fn impl(ctx: *TestContext) !void {
|
||||||
@ -942,7 +942,7 @@ test "Dir.rename directory onto non-empty dir" {
|
|||||||
|
|
||||||
test "Dir.rename file <-> dir" {
|
test "Dir.rename file <-> dir" {
|
||||||
// TODO: Fix on Windows, see https://github.com/ziglang/zig/issues/6364
|
// TODO: Fix on Windows, see https://github.com/ziglang/zig/issues/6364
|
||||||
if (builtin.os.tag == .windows) return error.SkipZigTest;
|
if (native_os == .windows) return error.SkipZigTest;
|
||||||
|
|
||||||
try testWithAllSupportedPathTypes(struct {
|
try testWithAllSupportedPathTypes(struct {
|
||||||
fn impl(ctx: *TestContext) !void {
|
fn impl(ctx: *TestContext) !void {
|
||||||
@ -979,7 +979,7 @@ test "rename" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "renameAbsolute" {
|
test "renameAbsolute" {
|
||||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
if (native_os == .wasi) return error.SkipZigTest;
|
||||||
|
|
||||||
var tmp_dir = tmpDir(.{});
|
var tmp_dir = tmpDir(.{});
|
||||||
defer tmp_dir.cleanup();
|
defer tmp_dir.cleanup();
|
||||||
@ -1032,14 +1032,14 @@ test "renameAbsolute" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "openSelfExe" {
|
test "openSelfExe" {
|
||||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
if (native_os == .wasi) return error.SkipZigTest;
|
||||||
|
|
||||||
const self_exe_file = try std.fs.openSelfExe(.{});
|
const self_exe_file = try std.fs.openSelfExe(.{});
|
||||||
self_exe_file.close();
|
self_exe_file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
test "selfExePath" {
|
test "selfExePath" {
|
||||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
if (native_os == .wasi) return error.SkipZigTest;
|
||||||
|
|
||||||
var buf: [fs.MAX_PATH_BYTES]u8 = undefined;
|
var buf: [fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
const buf_self_exe_path = try std.fs.selfExePath(&buf);
|
const buf_self_exe_path = try std.fs.selfExePath(&buf);
|
||||||
@ -1120,7 +1120,7 @@ test "makePath, put some files in it, deleteTreeMinStackSize" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "makePath in a directory that no longer exists" {
|
test "makePath in a directory that no longer exists" {
|
||||||
if (builtin.os.tag == .windows) return error.SkipZigTest; // Windows returns FileBusy if attempting to remove an open dir
|
if (native_os == .windows) return error.SkipZigTest; // Windows returns FileBusy if attempting to remove an open dir
|
||||||
|
|
||||||
var tmp = tmpDir(.{});
|
var tmp = tmpDir(.{});
|
||||||
defer tmp.cleanup();
|
defer tmp.cleanup();
|
||||||
@ -1182,7 +1182,7 @@ test "makepath relative walks" {
|
|||||||
try tmp.dir.makePath(relPath);
|
try tmp.dir.makePath(relPath);
|
||||||
|
|
||||||
// How .. is handled is different on Windows than non-Windows
|
// How .. is handled is different on Windows than non-Windows
|
||||||
switch (builtin.os.tag) {
|
switch (native_os) {
|
||||||
.windows => {
|
.windows => {
|
||||||
// On Windows, .. is resolved before passing the path to NtCreateFile,
|
// On Windows, .. is resolved before passing the path to NtCreateFile,
|
||||||
// meaning everything except `first/C` drops out.
|
// meaning everything except `first/C` drops out.
|
||||||
@ -1248,12 +1248,12 @@ test "max file name component lengths" {
|
|||||||
var tmp = tmpDir(.{ .iterate = true });
|
var tmp = tmpDir(.{ .iterate = true });
|
||||||
defer tmp.cleanup();
|
defer tmp.cleanup();
|
||||||
|
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
// U+FFFF is the character with the largest code point that is encoded as a single
|
// U+FFFF is the character with the largest code point that is encoded as a single
|
||||||
// UTF-16 code unit, so Windows allows for NAME_MAX of them.
|
// UTF-16 code unit, so Windows allows for NAME_MAX of them.
|
||||||
const maxed_windows_filename = ("\u{FFFF}".*) ** std.os.windows.NAME_MAX;
|
const maxed_windows_filename = ("\u{FFFF}".*) ** windows.NAME_MAX;
|
||||||
try testFilenameLimits(tmp.dir, &maxed_windows_filename);
|
try testFilenameLimits(tmp.dir, &maxed_windows_filename);
|
||||||
} else if (builtin.os.tag == .wasi) {
|
} else if (native_os == .wasi) {
|
||||||
// On WASI, the maxed filename depends on the host OS, so in order for this test to
|
// On WASI, the maxed filename depends on the host OS, so in order for this test to
|
||||||
// work on any host, we need to use a length that will work for all platforms
|
// work on any host, we need to use a length that will work for all platforms
|
||||||
// (i.e. the minimum MAX_NAME_BYTES of all supported platforms).
|
// (i.e. the minimum MAX_NAME_BYTES of all supported platforms).
|
||||||
@ -1274,7 +1274,7 @@ test "writev, readv" {
|
|||||||
|
|
||||||
var buf1: [line1.len]u8 = undefined;
|
var buf1: [line1.len]u8 = undefined;
|
||||||
var buf2: [line2.len]u8 = undefined;
|
var buf2: [line2.len]u8 = undefined;
|
||||||
var write_vecs = [_]std.os.iovec_const{
|
var write_vecs = [_]posix.iovec_const{
|
||||||
.{
|
.{
|
||||||
.iov_base = line1,
|
.iov_base = line1,
|
||||||
.iov_len = line1.len,
|
.iov_len = line1.len,
|
||||||
@ -1284,7 +1284,7 @@ test "writev, readv" {
|
|||||||
.iov_len = line2.len,
|
.iov_len = line2.len,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
var read_vecs = [_]std.os.iovec{
|
var read_vecs = [_]posix.iovec{
|
||||||
.{
|
.{
|
||||||
.iov_base = &buf2,
|
.iov_base = &buf2,
|
||||||
.iov_len = buf2.len,
|
.iov_len = buf2.len,
|
||||||
@ -1316,7 +1316,7 @@ test "pwritev, preadv" {
|
|||||||
|
|
||||||
var buf1: [line1.len]u8 = undefined;
|
var buf1: [line1.len]u8 = undefined;
|
||||||
var buf2: [line2.len]u8 = undefined;
|
var buf2: [line2.len]u8 = undefined;
|
||||||
var write_vecs = [_]std.os.iovec_const{
|
var write_vecs = [_]posix.iovec_const{
|
||||||
.{
|
.{
|
||||||
.iov_base = line1,
|
.iov_base = line1,
|
||||||
.iov_len = line1.len,
|
.iov_len = line1.len,
|
||||||
@ -1326,7 +1326,7 @@ test "pwritev, preadv" {
|
|||||||
.iov_len = line2.len,
|
.iov_len = line2.len,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
var read_vecs = [_]std.os.iovec{
|
var read_vecs = [_]posix.iovec{
|
||||||
.{
|
.{
|
||||||
.iov_base = &buf2,
|
.iov_base = &buf2,
|
||||||
.iov_len = buf2.len,
|
.iov_len = buf2.len,
|
||||||
@ -1376,7 +1376,7 @@ test "sendfile" {
|
|||||||
|
|
||||||
const line1 = "line1\n";
|
const line1 = "line1\n";
|
||||||
const line2 = "second line\n";
|
const line2 = "second line\n";
|
||||||
var vecs = [_]std.os.iovec_const{
|
var vecs = [_]posix.iovec_const{
|
||||||
.{
|
.{
|
||||||
.iov_base = line1,
|
.iov_base = line1,
|
||||||
.iov_len = line1.len,
|
.iov_len = line1.len,
|
||||||
@ -1399,7 +1399,7 @@ test "sendfile" {
|
|||||||
const header2 = "second header\n";
|
const header2 = "second header\n";
|
||||||
const trailer1 = "trailer1\n";
|
const trailer1 = "trailer1\n";
|
||||||
const trailer2 = "second trailer\n";
|
const trailer2 = "second trailer\n";
|
||||||
var hdtr = [_]std.os.iovec_const{
|
var hdtr = [_]posix.iovec_const{
|
||||||
.{
|
.{
|
||||||
.iov_base = header1,
|
.iov_base = header1,
|
||||||
.iov_len = header1.len,
|
.iov_len = header1.len,
|
||||||
@ -1510,7 +1510,7 @@ test "AtomicFile" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "open file with exclusive nonblocking lock twice" {
|
test "open file with exclusive nonblocking lock twice" {
|
||||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
if (native_os == .wasi) return error.SkipZigTest;
|
||||||
|
|
||||||
try testWithAllSupportedPathTypes(struct {
|
try testWithAllSupportedPathTypes(struct {
|
||||||
fn impl(ctx: *TestContext) !void {
|
fn impl(ctx: *TestContext) !void {
|
||||||
@ -1526,7 +1526,7 @@ test "open file with exclusive nonblocking lock twice" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "open file with shared and exclusive nonblocking lock" {
|
test "open file with shared and exclusive nonblocking lock" {
|
||||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
if (native_os == .wasi) return error.SkipZigTest;
|
||||||
|
|
||||||
try testWithAllSupportedPathTypes(struct {
|
try testWithAllSupportedPathTypes(struct {
|
||||||
fn impl(ctx: *TestContext) !void {
|
fn impl(ctx: *TestContext) !void {
|
||||||
@ -1542,7 +1542,7 @@ test "open file with shared and exclusive nonblocking lock" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "open file with exclusive and shared nonblocking lock" {
|
test "open file with exclusive and shared nonblocking lock" {
|
||||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
if (native_os == .wasi) return error.SkipZigTest;
|
||||||
|
|
||||||
try testWithAllSupportedPathTypes(struct {
|
try testWithAllSupportedPathTypes(struct {
|
||||||
fn impl(ctx: *TestContext) !void {
|
fn impl(ctx: *TestContext) !void {
|
||||||
@ -1601,7 +1601,7 @@ test "open file with exclusive lock twice, make sure second lock waits" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "open file with exclusive nonblocking lock twice (absolute paths)" {
|
test "open file with exclusive nonblocking lock twice (absolute paths)" {
|
||||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
if (native_os == .wasi) return error.SkipZigTest;
|
||||||
|
|
||||||
var random_bytes: [12]u8 = undefined;
|
var random_bytes: [12]u8 = undefined;
|
||||||
std.crypto.random.bytes(&random_bytes);
|
std.crypto.random.bytes(&random_bytes);
|
||||||
@ -1634,7 +1634,7 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "walker" {
|
test "walker" {
|
||||||
if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest;
|
if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
|
||||||
|
|
||||||
var tmp = tmpDir(.{ .iterate = true });
|
var tmp = tmpDir(.{ .iterate = true });
|
||||||
defer tmp.cleanup();
|
defer tmp.cleanup();
|
||||||
@ -1687,7 +1687,7 @@ test "walker" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "walker without fully iterating" {
|
test "walker without fully iterating" {
|
||||||
if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest;
|
if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
|
||||||
|
|
||||||
var tmp = tmpDir(.{ .iterate = true });
|
var tmp = tmpDir(.{ .iterate = true });
|
||||||
defer tmp.cleanup();
|
defer tmp.cleanup();
|
||||||
@ -1710,9 +1710,9 @@ test "walker without fully iterating" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "'.' and '..' in fs.Dir functions" {
|
test "'.' and '..' in fs.Dir functions" {
|
||||||
if (builtin.os.tag == .wasi and builtin.link_libc) return error.SkipZigTest;
|
if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
|
||||||
|
|
||||||
if (builtin.os.tag == .windows and builtin.cpu.arch == .aarch64) {
|
if (native_os == .windows and builtin.cpu.arch == .aarch64) {
|
||||||
// https://github.com/ziglang/zig/issues/17134
|
// https://github.com/ziglang/zig/issues/17134
|
||||||
return error.SkipZigTest;
|
return error.SkipZigTest;
|
||||||
}
|
}
|
||||||
@ -1750,7 +1750,7 @@ test "'.' and '..' in fs.Dir functions" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "'.' and '..' in absolute functions" {
|
test "'.' and '..' in absolute functions" {
|
||||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
if (native_os == .wasi) return error.SkipZigTest;
|
||||||
|
|
||||||
var tmp = tmpDir(.{});
|
var tmp = tmpDir(.{});
|
||||||
defer tmp.cleanup();
|
defer tmp.cleanup();
|
||||||
@ -1794,7 +1794,7 @@ test "'.' and '..' in absolute functions" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "chmod" {
|
test "chmod" {
|
||||||
if (builtin.os.tag == .windows or builtin.os.tag == .wasi)
|
if (native_os == .windows or native_os == .wasi)
|
||||||
return error.SkipZigTest;
|
return error.SkipZigTest;
|
||||||
|
|
||||||
var tmp = tmpDir(.{});
|
var tmp = tmpDir(.{});
|
||||||
@ -1816,7 +1816,7 @@ test "chmod" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "chown" {
|
test "chown" {
|
||||||
if (builtin.os.tag == .windows or builtin.os.tag == .wasi)
|
if (native_os == .windows or native_os == .wasi)
|
||||||
return error.SkipZigTest;
|
return error.SkipZigTest;
|
||||||
|
|
||||||
var tmp = tmpDir(.{});
|
var tmp = tmpDir(.{});
|
||||||
@ -1849,7 +1849,7 @@ test "File.Metadata" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "File.Permissions" {
|
test "File.Permissions" {
|
||||||
if (builtin.os.tag == .wasi)
|
if (native_os == .wasi)
|
||||||
return error.SkipZigTest;
|
return error.SkipZigTest;
|
||||||
|
|
||||||
var tmp = tmpDir(.{});
|
var tmp = tmpDir(.{});
|
||||||
@ -1875,7 +1875,7 @@ test "File.Permissions" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "File.PermissionsUnix" {
|
test "File.PermissionsUnix" {
|
||||||
if (builtin.os.tag == .windows or builtin.os.tag == .wasi)
|
if (native_os == .windows or native_os == .wasi)
|
||||||
return error.SkipZigTest;
|
return error.SkipZigTest;
|
||||||
|
|
||||||
var tmp = tmpDir(.{});
|
var tmp = tmpDir(.{});
|
||||||
@ -1910,7 +1910,7 @@ test "File.PermissionsUnix" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "delete a read-only file on windows" {
|
test "delete a read-only file on windows" {
|
||||||
if (builtin.os.tag != .windows)
|
if (native_os != .windows)
|
||||||
return error.SkipZigTest;
|
return error.SkipZigTest;
|
||||||
|
|
||||||
var tmp = testing.tmpDir(.{});
|
var tmp = testing.tmpDir(.{});
|
||||||
@ -1941,7 +1941,7 @@ test "delete a read-only file on windows" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "delete a setAsCwd directory on Windows" {
|
test "delete a setAsCwd directory on Windows" {
|
||||||
if (builtin.os.tag != .windows) return error.SkipZigTest;
|
if (native_os != .windows) return error.SkipZigTest;
|
||||||
|
|
||||||
var tmp = tmpDir(.{});
|
var tmp = tmpDir(.{});
|
||||||
// Set tmp dir as current working directory.
|
// Set tmp dir as current working directory.
|
||||||
@ -1956,7 +1956,7 @@ test "delete a setAsCwd directory on Windows" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "invalid UTF-8/WTF-8 paths" {
|
test "invalid UTF-8/WTF-8 paths" {
|
||||||
const expected_err = switch (builtin.os.tag) {
|
const expected_err = switch (native_os) {
|
||||||
.wasi => error.InvalidUtf8,
|
.wasi => error.InvalidUtf8,
|
||||||
.windows => error.InvalidWtf8,
|
.windows => error.InvalidWtf8,
|
||||||
else => return error.SkipZigTest,
|
else => return error.SkipZigTest,
|
||||||
@ -1993,13 +1993,13 @@ test "invalid UTF-8/WTF-8 paths" {
|
|||||||
|
|
||||||
try testing.expectError(expected_err, ctx.dir.symLink(invalid_path, invalid_path, .{}));
|
try testing.expectError(expected_err, ctx.dir.symLink(invalid_path, invalid_path, .{}));
|
||||||
try testing.expectError(expected_err, ctx.dir.symLinkZ(invalid_path, invalid_path, .{}));
|
try testing.expectError(expected_err, ctx.dir.symLinkZ(invalid_path, invalid_path, .{}));
|
||||||
if (builtin.os.tag == .wasi) {
|
if (native_os == .wasi) {
|
||||||
try testing.expectError(expected_err, ctx.dir.symLinkWasi(invalid_path, invalid_path, .{}));
|
try testing.expectError(expected_err, ctx.dir.symLinkWasi(invalid_path, invalid_path, .{}));
|
||||||
}
|
}
|
||||||
|
|
||||||
try testing.expectError(expected_err, ctx.dir.readLink(invalid_path, &[_]u8{}));
|
try testing.expectError(expected_err, ctx.dir.readLink(invalid_path, &[_]u8{}));
|
||||||
try testing.expectError(expected_err, ctx.dir.readLinkZ(invalid_path, &[_]u8{}));
|
try testing.expectError(expected_err, ctx.dir.readLinkZ(invalid_path, &[_]u8{}));
|
||||||
if (builtin.os.tag == .wasi) {
|
if (native_os == .wasi) {
|
||||||
try testing.expectError(expected_err, ctx.dir.readLinkWasi(invalid_path, &[_]u8{}));
|
try testing.expectError(expected_err, ctx.dir.readLinkWasi(invalid_path, &[_]u8{}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2023,7 +2023,7 @@ test "invalid UTF-8/WTF-8 paths" {
|
|||||||
|
|
||||||
try testing.expectError(expected_err, ctx.dir.statFile(invalid_path));
|
try testing.expectError(expected_err, ctx.dir.statFile(invalid_path));
|
||||||
|
|
||||||
if (builtin.os.tag != .wasi) {
|
if (native_os != .wasi) {
|
||||||
try testing.expectError(expected_err, ctx.dir.realpath(invalid_path, &[_]u8{}));
|
try testing.expectError(expected_err, ctx.dir.realpath(invalid_path, &[_]u8{}));
|
||||||
try testing.expectError(expected_err, ctx.dir.realpathZ(invalid_path, &[_]u8{}));
|
try testing.expectError(expected_err, ctx.dir.realpathZ(invalid_path, &[_]u8{}));
|
||||||
try testing.expectError(expected_err, ctx.dir.realpathAlloc(testing.allocator, invalid_path));
|
try testing.expectError(expected_err, ctx.dir.realpathAlloc(testing.allocator, invalid_path));
|
||||||
@ -2032,7 +2032,7 @@ test "invalid UTF-8/WTF-8 paths" {
|
|||||||
try testing.expectError(expected_err, fs.rename(ctx.dir, invalid_path, ctx.dir, invalid_path));
|
try testing.expectError(expected_err, fs.rename(ctx.dir, invalid_path, ctx.dir, invalid_path));
|
||||||
try testing.expectError(expected_err, fs.renameZ(ctx.dir, invalid_path, ctx.dir, invalid_path));
|
try testing.expectError(expected_err, fs.renameZ(ctx.dir, invalid_path, ctx.dir, invalid_path));
|
||||||
|
|
||||||
if (builtin.os.tag != .wasi and ctx.path_type != .relative) {
|
if (native_os != .wasi and ctx.path_type != .relative) {
|
||||||
try testing.expectError(expected_err, fs.updateFileAbsolute(invalid_path, invalid_path, .{}));
|
try testing.expectError(expected_err, fs.updateFileAbsolute(invalid_path, invalid_path, .{}));
|
||||||
try testing.expectError(expected_err, fs.copyFileAbsolute(invalid_path, invalid_path, .{}));
|
try testing.expectError(expected_err, fs.copyFileAbsolute(invalid_path, invalid_path, .{}));
|
||||||
try testing.expectError(expected_err, fs.makeDirAbsolute(invalid_path));
|
try testing.expectError(expected_err, fs.makeDirAbsolute(invalid_path));
|
||||||
|
|||||||
@ -367,7 +367,7 @@ pub fn main() !void {
|
|||||||
i += 1;
|
i += 1;
|
||||||
if (i == args.len) {
|
if (i == args.len) {
|
||||||
usage();
|
usage();
|
||||||
std.os.exit(1);
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
seed = try std.fmt.parseUnsigned(u32, args[i], 10);
|
seed = try std.fmt.parseUnsigned(u32, args[i], 10);
|
||||||
@ -376,7 +376,7 @@ pub fn main() !void {
|
|||||||
i += 1;
|
i += 1;
|
||||||
if (i == args.len) {
|
if (i == args.len) {
|
||||||
usage();
|
usage();
|
||||||
std.os.exit(1);
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
filter = args[i];
|
filter = args[i];
|
||||||
@ -384,7 +384,7 @@ pub fn main() !void {
|
|||||||
i += 1;
|
i += 1;
|
||||||
if (i == args.len) {
|
if (i == args.len) {
|
||||||
usage();
|
usage();
|
||||||
std.os.exit(1);
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const c = try std.fmt.parseUnsigned(usize, args[i], 10);
|
const c = try std.fmt.parseUnsigned(usize, args[i], 10);
|
||||||
@ -393,13 +393,13 @@ pub fn main() !void {
|
|||||||
i += 1;
|
i += 1;
|
||||||
if (i == args.len) {
|
if (i == args.len) {
|
||||||
usage();
|
usage();
|
||||||
std.os.exit(1);
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
key_size = try std.fmt.parseUnsigned(usize, args[i], 10);
|
key_size = try std.fmt.parseUnsigned(usize, args[i], 10);
|
||||||
if (key_size.? > block_size) {
|
if (key_size.? > block_size) {
|
||||||
try stdout.print("key_size cannot exceed block size of {}\n", .{block_size});
|
try stdout.print("key_size cannot exceed block size of {}\n", .{block_size});
|
||||||
std.os.exit(1);
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
} else if (std.mem.eql(u8, args[i], "--iterative-only")) {
|
} else if (std.mem.eql(u8, args[i], "--iterative-only")) {
|
||||||
test_iterative_only = true;
|
test_iterative_only = true;
|
||||||
@ -410,7 +410,7 @@ pub fn main() !void {
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
usage();
|
usage();
|
||||||
std.os.exit(1);
|
std.process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,9 +4,9 @@ const root = @import("root");
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const os = std.os;
|
|
||||||
const c = std.c;
|
const c = std.c;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
const windows = std.os.windows;
|
||||||
|
|
||||||
pub const LoggingAllocator = @import("heap/logging_allocator.zig").LoggingAllocator;
|
pub const LoggingAllocator = @import("heap/logging_allocator.zig").LoggingAllocator;
|
||||||
pub const loggingAllocator = @import("heap/logging_allocator.zig").loggingAllocator;
|
pub const loggingAllocator = @import("heap/logging_allocator.zig").loggingAllocator;
|
||||||
@ -263,7 +263,7 @@ pub const HeapAllocator = switch (builtin.os.tag) {
|
|||||||
.windows => struct {
|
.windows => struct {
|
||||||
heap_handle: ?HeapHandle,
|
heap_handle: ?HeapHandle,
|
||||||
|
|
||||||
const HeapHandle = os.windows.HANDLE;
|
const HeapHandle = windows.HANDLE;
|
||||||
|
|
||||||
pub fn init() HeapAllocator {
|
pub fn init() HeapAllocator {
|
||||||
return HeapAllocator{
|
return HeapAllocator{
|
||||||
@ -284,7 +284,7 @@ pub const HeapAllocator = switch (builtin.os.tag) {
|
|||||||
|
|
||||||
pub fn deinit(self: *HeapAllocator) void {
|
pub fn deinit(self: *HeapAllocator) void {
|
||||||
if (self.heap_handle) |heap_handle| {
|
if (self.heap_handle) |heap_handle| {
|
||||||
os.windows.HeapDestroy(heap_handle);
|
windows.HeapDestroy(heap_handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,13 +305,13 @@ pub const HeapAllocator = switch (builtin.os.tag) {
|
|||||||
const amt = n + ptr_align - 1 + @sizeOf(usize);
|
const amt = n + ptr_align - 1 + @sizeOf(usize);
|
||||||
const optional_heap_handle = @atomicLoad(?HeapHandle, &self.heap_handle, .seq_cst);
|
const optional_heap_handle = @atomicLoad(?HeapHandle, &self.heap_handle, .seq_cst);
|
||||||
const heap_handle = optional_heap_handle orelse blk: {
|
const heap_handle = optional_heap_handle orelse blk: {
|
||||||
const options = if (builtin.single_threaded) os.windows.HEAP_NO_SERIALIZE else 0;
|
const options = if (builtin.single_threaded) windows.HEAP_NO_SERIALIZE else 0;
|
||||||
const hh = os.windows.kernel32.HeapCreate(options, amt, 0) orelse return null;
|
const hh = windows.kernel32.HeapCreate(options, amt, 0) orelse return null;
|
||||||
const other_hh = @cmpxchgStrong(?HeapHandle, &self.heap_handle, null, hh, .seq_cst, .seq_cst) orelse break :blk hh;
|
const other_hh = @cmpxchgStrong(?HeapHandle, &self.heap_handle, null, hh, .seq_cst, .seq_cst) orelse break :blk hh;
|
||||||
os.windows.HeapDestroy(hh);
|
windows.HeapDestroy(hh);
|
||||||
break :blk other_hh.?; // can't be null because of the cmpxchg
|
break :blk other_hh.?; // can't be null because of the cmpxchg
|
||||||
};
|
};
|
||||||
const ptr = os.windows.kernel32.HeapAlloc(heap_handle, 0, amt) orelse return null;
|
const ptr = windows.kernel32.HeapAlloc(heap_handle, 0, amt) orelse return null;
|
||||||
const root_addr = @intFromPtr(ptr);
|
const root_addr = @intFromPtr(ptr);
|
||||||
const aligned_addr = mem.alignForward(usize, root_addr, ptr_align);
|
const aligned_addr = mem.alignForward(usize, root_addr, ptr_align);
|
||||||
const buf = @as([*]u8, @ptrFromInt(aligned_addr))[0..n];
|
const buf = @as([*]u8, @ptrFromInt(aligned_addr))[0..n];
|
||||||
@ -333,9 +333,9 @@ pub const HeapAllocator = switch (builtin.os.tag) {
|
|||||||
const root_addr = getRecordPtr(buf).*;
|
const root_addr = getRecordPtr(buf).*;
|
||||||
const align_offset = @intFromPtr(buf.ptr) - root_addr;
|
const align_offset = @intFromPtr(buf.ptr) - root_addr;
|
||||||
const amt = align_offset + new_size + @sizeOf(usize);
|
const amt = align_offset + new_size + @sizeOf(usize);
|
||||||
const new_ptr = os.windows.kernel32.HeapReAlloc(
|
const new_ptr = windows.kernel32.HeapReAlloc(
|
||||||
self.heap_handle.?,
|
self.heap_handle.?,
|
||||||
os.windows.HEAP_REALLOC_IN_PLACE_ONLY,
|
windows.HEAP_REALLOC_IN_PLACE_ONLY,
|
||||||
@as(*anyopaque, @ptrFromInt(root_addr)),
|
@as(*anyopaque, @ptrFromInt(root_addr)),
|
||||||
amt,
|
amt,
|
||||||
) orelse return false;
|
) orelse return false;
|
||||||
@ -353,7 +353,7 @@ pub const HeapAllocator = switch (builtin.os.tag) {
|
|||||||
_ = log2_buf_align;
|
_ = log2_buf_align;
|
||||||
_ = return_address;
|
_ = return_address;
|
||||||
const self: *HeapAllocator = @ptrCast(@alignCast(ctx));
|
const self: *HeapAllocator = @ptrCast(@alignCast(ctx));
|
||||||
os.windows.HeapFree(self.heap_handle.?, 0, @as(*anyopaque, @ptrFromInt(getRecordPtr(buf).*)));
|
windows.HeapFree(self.heap_handle.?, 0, @as(*anyopaque, @ptrFromInt(getRecordPtr(buf).*)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
else => @compileError("Unsupported OS"),
|
else => @compileError("Unsupported OS"),
|
||||||
|
|||||||
@ -2,9 +2,11 @@ const std = @import("../std.zig");
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const os = std.os;
|
|
||||||
const maxInt = std.math.maxInt;
|
const maxInt = std.math.maxInt;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
const native_os = builtin.os.tag;
|
||||||
|
const windows = std.os.windows;
|
||||||
|
const posix = std.posix;
|
||||||
|
|
||||||
pub const vtable = Allocator.VTable{
|
pub const vtable = Allocator.VTable{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
@ -19,22 +21,21 @@ fn alloc(_: *anyopaque, n: usize, log2_align: u8, ra: usize) ?[*]u8 {
|
|||||||
if (n > maxInt(usize) - (mem.page_size - 1)) return null;
|
if (n > maxInt(usize) - (mem.page_size - 1)) return null;
|
||||||
const aligned_len = mem.alignForward(usize, n, mem.page_size);
|
const aligned_len = mem.alignForward(usize, n, mem.page_size);
|
||||||
|
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const w = os.windows;
|
const addr = windows.VirtualAlloc(
|
||||||
const addr = w.VirtualAlloc(
|
|
||||||
null,
|
null,
|
||||||
aligned_len,
|
aligned_len,
|
||||||
w.MEM_COMMIT | w.MEM_RESERVE,
|
windows.MEM_COMMIT | windows.MEM_RESERVE,
|
||||||
w.PAGE_READWRITE,
|
windows.PAGE_READWRITE,
|
||||||
) catch return null;
|
) catch return null;
|
||||||
return @ptrCast(addr);
|
return @ptrCast(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
const hint = @atomicLoad(@TypeOf(std.heap.next_mmap_addr_hint), &std.heap.next_mmap_addr_hint, .unordered);
|
const hint = @atomicLoad(@TypeOf(std.heap.next_mmap_addr_hint), &std.heap.next_mmap_addr_hint, .unordered);
|
||||||
const slice = os.mmap(
|
const slice = posix.mmap(
|
||||||
hint,
|
hint,
|
||||||
aligned_len,
|
aligned_len,
|
||||||
os.PROT.READ | os.PROT.WRITE,
|
posix.PROT.READ | posix.PROT.WRITE,
|
||||||
.{ .TYPE = .PRIVATE, .ANONYMOUS = true },
|
.{ .TYPE = .PRIVATE, .ANONYMOUS = true },
|
||||||
-1,
|
-1,
|
||||||
0,
|
0,
|
||||||
@ -56,8 +57,7 @@ fn resize(
|
|||||||
_ = return_address;
|
_ = return_address;
|
||||||
const new_size_aligned = mem.alignForward(usize, new_size, mem.page_size);
|
const new_size_aligned = mem.alignForward(usize, new_size, mem.page_size);
|
||||||
|
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const w = os.windows;
|
|
||||||
if (new_size <= buf_unaligned.len) {
|
if (new_size <= buf_unaligned.len) {
|
||||||
const base_addr = @intFromPtr(buf_unaligned.ptr);
|
const base_addr = @intFromPtr(buf_unaligned.ptr);
|
||||||
const old_addr_end = base_addr + buf_unaligned.len;
|
const old_addr_end = base_addr + buf_unaligned.len;
|
||||||
@ -65,10 +65,10 @@ fn resize(
|
|||||||
if (old_addr_end > new_addr_end) {
|
if (old_addr_end > new_addr_end) {
|
||||||
// For shrinking that is not releasing, we will only
|
// For shrinking that is not releasing, we will only
|
||||||
// decommit the pages not needed anymore.
|
// decommit the pages not needed anymore.
|
||||||
w.VirtualFree(
|
windows.VirtualFree(
|
||||||
@as(*anyopaque, @ptrFromInt(new_addr_end)),
|
@as(*anyopaque, @ptrFromInt(new_addr_end)),
|
||||||
old_addr_end - new_addr_end,
|
old_addr_end - new_addr_end,
|
||||||
w.MEM_DECOMMIT,
|
windows.MEM_DECOMMIT,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -87,7 +87,7 @@ fn resize(
|
|||||||
if (new_size_aligned < buf_aligned_len) {
|
if (new_size_aligned < buf_aligned_len) {
|
||||||
const ptr = buf_unaligned.ptr + new_size_aligned;
|
const ptr = buf_unaligned.ptr + new_size_aligned;
|
||||||
// TODO: if the next_mmap_addr_hint is within the unmapped range, update it
|
// TODO: if the next_mmap_addr_hint is within the unmapped range, update it
|
||||||
os.munmap(@alignCast(ptr[0 .. buf_aligned_len - new_size_aligned]));
|
posix.munmap(@alignCast(ptr[0 .. buf_aligned_len - new_size_aligned]));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,10 +100,10 @@ fn free(_: *anyopaque, slice: []u8, log2_buf_align: u8, return_address: usize) v
|
|||||||
_ = log2_buf_align;
|
_ = log2_buf_align;
|
||||||
_ = return_address;
|
_ = return_address;
|
||||||
|
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
os.windows.VirtualFree(slice.ptr, 0, os.windows.MEM_RELEASE);
|
windows.VirtualFree(slice.ptr, 0, windows.MEM_RELEASE);
|
||||||
} else {
|
} else {
|
||||||
const buf_aligned_len = mem.alignForward(usize, slice.len, mem.page_size);
|
const buf_aligned_len = mem.alignForward(usize, slice.len, mem.page_size);
|
||||||
os.munmap(@alignCast(slice.ptr[0..buf_aligned_len]));
|
posix.munmap(@alignCast(slice.ptr[0..buf_aligned_len]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -220,7 +220,7 @@ pub const Connection = struct {
|
|||||||
|
|
||||||
pub const Protocol = enum { plain, tls };
|
pub const Protocol = enum { plain, tls };
|
||||||
|
|
||||||
pub fn readvDirectTls(conn: *Connection, buffers: []std.os.iovec) ReadError!usize {
|
pub fn readvDirectTls(conn: *Connection, buffers: []std.posix.iovec) ReadError!usize {
|
||||||
return conn.tls_client.readv(conn.stream, buffers) catch |err| {
|
return conn.tls_client.readv(conn.stream, buffers) catch |err| {
|
||||||
// https://github.com/ziglang/zig/issues/2473
|
// https://github.com/ziglang/zig/issues/2473
|
||||||
if (mem.startsWith(u8, @errorName(err), "TlsAlert")) return error.TlsAlert;
|
if (mem.startsWith(u8, @errorName(err), "TlsAlert")) return error.TlsAlert;
|
||||||
@ -234,7 +234,7 @@ pub const Connection = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn readvDirect(conn: *Connection, buffers: []std.os.iovec) ReadError!usize {
|
pub fn readvDirect(conn: *Connection, buffers: []std.posix.iovec) ReadError!usize {
|
||||||
if (conn.protocol == .tls) {
|
if (conn.protocol == .tls) {
|
||||||
if (disable_tls) unreachable;
|
if (disable_tls) unreachable;
|
||||||
|
|
||||||
@ -252,7 +252,7 @@ pub const Connection = struct {
|
|||||||
pub fn fill(conn: *Connection) ReadError!void {
|
pub fn fill(conn: *Connection) ReadError!void {
|
||||||
if (conn.read_end != conn.read_start) return;
|
if (conn.read_end != conn.read_start) return;
|
||||||
|
|
||||||
var iovecs = [1]std.os.iovec{
|
var iovecs = [1]std.posix.iovec{
|
||||||
.{ .iov_base = &conn.read_buf, .iov_len = conn.read_buf.len },
|
.{ .iov_base = &conn.read_buf, .iov_len = conn.read_buf.len },
|
||||||
};
|
};
|
||||||
const nread = try conn.readvDirect(&iovecs);
|
const nread = try conn.readvDirect(&iovecs);
|
||||||
@ -288,7 +288,7 @@ pub const Connection = struct {
|
|||||||
return available_read;
|
return available_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
var iovecs = [2]std.os.iovec{
|
var iovecs = [2]std.posix.iovec{
|
||||||
.{ .iov_base = buffer.ptr, .iov_len = buffer.len },
|
.{ .iov_base = buffer.ptr, .iov_len = buffer.len },
|
||||||
.{ .iov_base = &conn.read_buf, .iov_len = conn.read_buf.len },
|
.{ .iov_base = &conn.read_buf, .iov_len = conn.read_buf.len },
|
||||||
};
|
};
|
||||||
@ -1387,7 +1387,7 @@ pub fn connectTcp(client: *Client, host: []const u8, port: u16, protocol: Connec
|
|||||||
return &conn.data;
|
return &conn.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ConnectUnixError = Allocator.Error || std.os.SocketError || error{NameTooLong} || std.os.ConnectError;
|
pub const ConnectUnixError = Allocator.Error || std.posix.SocketError || error{NameTooLong} || std.posix.ConnectError;
|
||||||
|
|
||||||
/// Connect to `path` as a unix domain socket. This will reuse a connection if one is already open.
|
/// Connect to `path` as a unix domain socket. This will reuse a connection if one is already open.
|
||||||
///
|
///
|
||||||
|
|||||||
106
lib/std/io.zig
106
lib/std/io.zig
@ -2,74 +2,76 @@ const std = @import("std.zig");
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const root = @import("root");
|
const root = @import("root");
|
||||||
const c = std.c;
|
const c = std.c;
|
||||||
|
const is_windows = builtin.os.tag == .windows;
|
||||||
|
const windows = std.os.windows;
|
||||||
|
const posix = std.posix;
|
||||||
|
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const os = std.os;
|
|
||||||
const fs = std.fs;
|
const fs = std.fs;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const meta = std.meta;
|
const meta = std.meta;
|
||||||
const File = std.fs.File;
|
const File = std.fs.File;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
fn getStdOutHandle() os.fd_t {
|
fn getStdOutHandle() posix.fd_t {
|
||||||
if (builtin.os.tag == .windows) {
|
if (is_windows) {
|
||||||
if (builtin.zig_backend == .stage2_aarch64) {
|
if (builtin.zig_backend == .stage2_aarch64) {
|
||||||
// TODO: this is just a temporary workaround until we advance aarch64 backend further along.
|
// TODO: this is just a temporary workaround until we advance aarch64 backend further along.
|
||||||
return os.windows.GetStdHandle(os.windows.STD_OUTPUT_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;
|
return windows.GetStdHandle(windows.STD_OUTPUT_HANDLE) catch windows.INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
return os.windows.peb().ProcessParameters.hStdOutput;
|
return windows.peb().ProcessParameters.hStdOutput;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (@hasDecl(root, "os") and @hasDecl(root.os, "io") and @hasDecl(root.os.io, "getStdOutHandle")) {
|
if (@hasDecl(root, "os") and @hasDecl(root.os, "io") and @hasDecl(root.os.io, "getStdOutHandle")) {
|
||||||
return root.os.io.getStdOutHandle();
|
return root.os.io.getStdOutHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
return os.STDOUT_FILENO;
|
return posix.STDOUT_FILENO;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getStdOut() File {
|
pub fn getStdOut() File {
|
||||||
return File{ .handle = getStdOutHandle() };
|
return .{ .handle = getStdOutHandle() };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getStdErrHandle() os.fd_t {
|
fn getStdErrHandle() posix.fd_t {
|
||||||
if (builtin.os.tag == .windows) {
|
if (is_windows) {
|
||||||
if (builtin.zig_backend == .stage2_aarch64) {
|
if (builtin.zig_backend == .stage2_aarch64) {
|
||||||
// TODO: this is just a temporary workaround until we advance aarch64 backend further along.
|
// TODO: this is just a temporary workaround until we advance aarch64 backend further along.
|
||||||
return os.windows.GetStdHandle(os.windows.STD_ERROR_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;
|
return windows.GetStdHandle(windows.STD_ERROR_HANDLE) catch windows.INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
return os.windows.peb().ProcessParameters.hStdError;
|
return windows.peb().ProcessParameters.hStdError;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (@hasDecl(root, "os") and @hasDecl(root.os, "io") and @hasDecl(root.os.io, "getStdErrHandle")) {
|
if (@hasDecl(root, "os") and @hasDecl(root.os, "io") and @hasDecl(root.os.io, "getStdErrHandle")) {
|
||||||
return root.os.io.getStdErrHandle();
|
return root.os.io.getStdErrHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
return os.STDERR_FILENO;
|
return posix.STDERR_FILENO;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getStdErr() File {
|
pub fn getStdErr() File {
|
||||||
return File{ .handle = getStdErrHandle() };
|
return .{ .handle = getStdErrHandle() };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getStdInHandle() os.fd_t {
|
fn getStdInHandle() posix.fd_t {
|
||||||
if (builtin.os.tag == .windows) {
|
if (is_windows) {
|
||||||
if (builtin.zig_backend == .stage2_aarch64) {
|
if (builtin.zig_backend == .stage2_aarch64) {
|
||||||
// TODO: this is just a temporary workaround until we advance aarch64 backend further along.
|
// TODO: this is just a temporary workaround until we advance aarch64 backend further along.
|
||||||
return os.windows.GetStdHandle(os.windows.STD_INPUT_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;
|
return windows.GetStdHandle(windows.STD_INPUT_HANDLE) catch windows.INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
return os.windows.peb().ProcessParameters.hStdInput;
|
return windows.peb().ProcessParameters.hStdInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (@hasDecl(root, "os") and @hasDecl(root.os, "io") and @hasDecl(root.os.io, "getStdInHandle")) {
|
if (@hasDecl(root, "os") and @hasDecl(root.os, "io") and @hasDecl(root.os.io, "getStdInHandle")) {
|
||||||
return root.os.io.getStdInHandle();
|
return root.os.io.getStdInHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
return os.STDIN_FILENO;
|
return posix.STDIN_FILENO;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getStdIn() File {
|
pub fn getStdIn() File {
|
||||||
return File{ .handle = getStdInHandle() };
|
return .{ .handle = getStdInHandle() };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GenericReader(
|
pub fn GenericReader(
|
||||||
@ -434,10 +436,10 @@ pub fn poll(
|
|||||||
const enum_fields = @typeInfo(StreamEnum).Enum.fields;
|
const enum_fields = @typeInfo(StreamEnum).Enum.fields;
|
||||||
var result: Poller(StreamEnum) = undefined;
|
var result: Poller(StreamEnum) = undefined;
|
||||||
|
|
||||||
if (builtin.os.tag == .windows) result.windows = .{
|
if (is_windows) result.windows = .{
|
||||||
.first_read_done = false,
|
.first_read_done = false,
|
||||||
.overlapped = [1]os.windows.OVERLAPPED{
|
.overlapped = [1]windows.OVERLAPPED{
|
||||||
mem.zeroes(os.windows.OVERLAPPED),
|
mem.zeroes(windows.OVERLAPPED),
|
||||||
} ** enum_fields.len,
|
} ** enum_fields.len,
|
||||||
.active = .{
|
.active = .{
|
||||||
.count = 0,
|
.count = 0,
|
||||||
@ -453,12 +455,12 @@ pub fn poll(
|
|||||||
.head = 0,
|
.head = 0,
|
||||||
.count = 0,
|
.count = 0,
|
||||||
};
|
};
|
||||||
if (builtin.os.tag == .windows) {
|
if (is_windows) {
|
||||||
result.windows.active.handles_buf[i] = @field(files, enum_fields[i].name).handle;
|
result.windows.active.handles_buf[i] = @field(files, enum_fields[i].name).handle;
|
||||||
} else {
|
} else {
|
||||||
result.poll_fds[i] = .{
|
result.poll_fds[i] = .{
|
||||||
.fd = @field(files, enum_fields[i].name).handle,
|
.fd = @field(files, enum_fields[i].name).handle,
|
||||||
.events = os.POLL.IN,
|
.events = posix.POLL.IN,
|
||||||
.revents = undefined,
|
.revents = undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -471,16 +473,16 @@ pub const PollFifo = std.fifo.LinearFifo(u8, .Dynamic);
|
|||||||
pub fn Poller(comptime StreamEnum: type) type {
|
pub fn Poller(comptime StreamEnum: type) type {
|
||||||
return struct {
|
return struct {
|
||||||
const enum_fields = @typeInfo(StreamEnum).Enum.fields;
|
const enum_fields = @typeInfo(StreamEnum).Enum.fields;
|
||||||
const PollFd = if (builtin.os.tag == .windows) void else std.os.pollfd;
|
const PollFd = if (is_windows) void else posix.pollfd;
|
||||||
|
|
||||||
fifos: [enum_fields.len]PollFifo,
|
fifos: [enum_fields.len]PollFifo,
|
||||||
poll_fds: [enum_fields.len]PollFd,
|
poll_fds: [enum_fields.len]PollFd,
|
||||||
windows: if (builtin.os.tag == .windows) struct {
|
windows: if (is_windows) struct {
|
||||||
first_read_done: bool,
|
first_read_done: bool,
|
||||||
overlapped: [enum_fields.len]os.windows.OVERLAPPED,
|
overlapped: [enum_fields.len]windows.OVERLAPPED,
|
||||||
active: struct {
|
active: struct {
|
||||||
count: math.IntFittingRange(0, enum_fields.len),
|
count: math.IntFittingRange(0, enum_fields.len),
|
||||||
handles_buf: [enum_fields.len]os.windows.HANDLE,
|
handles_buf: [enum_fields.len]windows.HANDLE,
|
||||||
stream_map: [enum_fields.len]StreamEnum,
|
stream_map: [enum_fields.len]StreamEnum,
|
||||||
|
|
||||||
pub fn removeAt(self: *@This(), index: u32) void {
|
pub fn removeAt(self: *@This(), index: u32) void {
|
||||||
@ -497,10 +499,10 @@ pub fn Poller(comptime StreamEnum: type) type {
|
|||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
if (builtin.os.tag == .windows) {
|
if (is_windows) {
|
||||||
// cancel any pending IO to prevent clobbering OVERLAPPED value
|
// cancel any pending IO to prevent clobbering OVERLAPPED value
|
||||||
for (self.windows.active.handles_buf[0..self.windows.active.count]) |h| {
|
for (self.windows.active.handles_buf[0..self.windows.active.count]) |h| {
|
||||||
_ = os.windows.kernel32.CancelIo(h);
|
_ = windows.kernel32.CancelIo(h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline for (&self.fifos) |*q| q.deinit();
|
inline for (&self.fifos) |*q| q.deinit();
|
||||||
@ -508,7 +510,7 @@ pub fn Poller(comptime StreamEnum: type) type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll(self: *Self) !bool {
|
pub fn poll(self: *Self) !bool {
|
||||||
if (builtin.os.tag == .windows) {
|
if (is_windows) {
|
||||||
return pollWindows(self, null);
|
return pollWindows(self, null);
|
||||||
} else {
|
} else {
|
||||||
return pollPosix(self, null);
|
return pollPosix(self, null);
|
||||||
@ -516,7 +518,7 @@ pub fn Poller(comptime StreamEnum: type) type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn pollTimeout(self: *Self, nanoseconds: u64) !bool {
|
pub fn pollTimeout(self: *Self, nanoseconds: u64) !bool {
|
||||||
if (builtin.os.tag == .windows) {
|
if (is_windows) {
|
||||||
return pollWindows(self, nanoseconds);
|
return pollWindows(self, nanoseconds);
|
||||||
} else {
|
} else {
|
||||||
return pollPosix(self, nanoseconds);
|
return pollPosix(self, nanoseconds);
|
||||||
@ -554,39 +556,39 @@ pub fn Poller(comptime StreamEnum: type) type {
|
|||||||
while (true) {
|
while (true) {
|
||||||
if (self.windows.active.count == 0) return false;
|
if (self.windows.active.count == 0) return false;
|
||||||
|
|
||||||
const status = os.windows.kernel32.WaitForMultipleObjects(
|
const status = windows.kernel32.WaitForMultipleObjects(
|
||||||
self.windows.active.count,
|
self.windows.active.count,
|
||||||
&self.windows.active.handles_buf,
|
&self.windows.active.handles_buf,
|
||||||
0,
|
0,
|
||||||
if (nanoseconds) |ns|
|
if (nanoseconds) |ns|
|
||||||
@min(std.math.cast(u32, ns / std.time.ns_per_ms) orelse (os.windows.INFINITE - 1), os.windows.INFINITE - 1)
|
@min(std.math.cast(u32, ns / std.time.ns_per_ms) orelse (windows.INFINITE - 1), windows.INFINITE - 1)
|
||||||
else
|
else
|
||||||
os.windows.INFINITE,
|
windows.INFINITE,
|
||||||
);
|
);
|
||||||
if (status == os.windows.WAIT_FAILED)
|
if (status == windows.WAIT_FAILED)
|
||||||
return os.windows.unexpectedError(os.windows.kernel32.GetLastError());
|
return windows.unexpectedError(windows.kernel32.GetLastError());
|
||||||
if (status == os.windows.WAIT_TIMEOUT)
|
if (status == windows.WAIT_TIMEOUT)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (status < os.windows.WAIT_OBJECT_0 or status > os.windows.WAIT_OBJECT_0 + enum_fields.len - 1)
|
if (status < windows.WAIT_OBJECT_0 or status > windows.WAIT_OBJECT_0 + enum_fields.len - 1)
|
||||||
unreachable;
|
unreachable;
|
||||||
|
|
||||||
const active_idx = status - os.windows.WAIT_OBJECT_0;
|
const active_idx = status - windows.WAIT_OBJECT_0;
|
||||||
|
|
||||||
const handle = self.windows.active.handles_buf[active_idx];
|
const handle = self.windows.active.handles_buf[active_idx];
|
||||||
const stream_idx = @intFromEnum(self.windows.active.stream_map[active_idx]);
|
const stream_idx = @intFromEnum(self.windows.active.stream_map[active_idx]);
|
||||||
var read_bytes: u32 = undefined;
|
var read_bytes: u32 = undefined;
|
||||||
if (0 == os.windows.kernel32.GetOverlappedResult(
|
if (0 == windows.kernel32.GetOverlappedResult(
|
||||||
handle,
|
handle,
|
||||||
&self.windows.overlapped[stream_idx],
|
&self.windows.overlapped[stream_idx],
|
||||||
&read_bytes,
|
&read_bytes,
|
||||||
0,
|
0,
|
||||||
)) switch (os.windows.kernel32.GetLastError()) {
|
)) switch (windows.kernel32.GetLastError()) {
|
||||||
.BROKEN_PIPE => {
|
.BROKEN_PIPE => {
|
||||||
self.windows.active.removeAt(active_idx);
|
self.windows.active.removeAt(active_idx);
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
else => |err| return os.windows.unexpectedError(err),
|
else => |err| return windows.unexpectedError(err),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.fifos[stream_idx].update(read_bytes);
|
self.fifos[stream_idx].update(read_bytes);
|
||||||
@ -611,9 +613,9 @@ pub fn Poller(comptime StreamEnum: type) type {
|
|||||||
// allocate grows exponentially.
|
// allocate grows exponentially.
|
||||||
const bump_amt = 512;
|
const bump_amt = 512;
|
||||||
|
|
||||||
const err_mask = os.POLL.ERR | os.POLL.NVAL | os.POLL.HUP;
|
const err_mask = posix.POLL.ERR | posix.POLL.NVAL | posix.POLL.HUP;
|
||||||
|
|
||||||
const events_len = try os.poll(&self.poll_fds, if (nanoseconds) |ns|
|
const events_len = try posix.poll(&self.poll_fds, if (nanoseconds) |ns|
|
||||||
std.math.cast(i32, ns / std.time.ns_per_ms) orelse std.math.maxInt(i32)
|
std.math.cast(i32, ns / std.time.ns_per_ms) orelse std.math.maxInt(i32)
|
||||||
else
|
else
|
||||||
-1);
|
-1);
|
||||||
@ -629,9 +631,9 @@ pub fn Poller(comptime StreamEnum: type) type {
|
|||||||
// conditions.
|
// conditions.
|
||||||
// It's still possible to read after a POLL.HUP is received,
|
// It's still possible to read after a POLL.HUP is received,
|
||||||
// always check if there's some data waiting to be read first.
|
// always check if there's some data waiting to be read first.
|
||||||
if (poll_fd.revents & os.POLL.IN != 0) {
|
if (poll_fd.revents & posix.POLL.IN != 0) {
|
||||||
const buf = try q.writableWithSize(bump_amt);
|
const buf = try q.writableWithSize(bump_amt);
|
||||||
const amt = try os.read(poll_fd.fd, buf);
|
const amt = try posix.read(poll_fd.fd, buf);
|
||||||
q.update(amt);
|
q.update(amt);
|
||||||
if (amt == 0) {
|
if (amt == 0) {
|
||||||
// Remove the fd when the EOF condition is met.
|
// Remove the fd when the EOF condition is met.
|
||||||
@ -652,19 +654,19 @@ pub fn Poller(comptime StreamEnum: type) type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn windowsAsyncRead(
|
fn windowsAsyncRead(
|
||||||
handle: os.windows.HANDLE,
|
handle: windows.HANDLE,
|
||||||
overlapped: *os.windows.OVERLAPPED,
|
overlapped: *windows.OVERLAPPED,
|
||||||
fifo: *PollFifo,
|
fifo: *PollFifo,
|
||||||
bump_amt: usize,
|
bump_amt: usize,
|
||||||
) !enum { pending, closed } {
|
) !enum { pending, closed } {
|
||||||
while (true) {
|
while (true) {
|
||||||
const buf = try fifo.writableWithSize(bump_amt);
|
const buf = try fifo.writableWithSize(bump_amt);
|
||||||
var read_bytes: u32 = undefined;
|
var read_bytes: u32 = undefined;
|
||||||
const read_result = os.windows.kernel32.ReadFile(handle, buf.ptr, math.cast(u32, buf.len) orelse math.maxInt(u32), &read_bytes, overlapped);
|
const read_result = windows.kernel32.ReadFile(handle, buf.ptr, math.cast(u32, buf.len) orelse math.maxInt(u32), &read_bytes, overlapped);
|
||||||
if (read_result == 0) return switch (os.windows.kernel32.GetLastError()) {
|
if (read_result == 0) return switch (windows.kernel32.GetLastError()) {
|
||||||
.IO_PENDING => .pending,
|
.IO_PENDING => .pending,
|
||||||
.BROKEN_PIPE => .closed,
|
.BROKEN_PIPE => .closed,
|
||||||
else => |err| os.windows.unexpectedError(err),
|
else => |err| windows.unexpectedError(err),
|
||||||
};
|
};
|
||||||
fifo.update(read_bytes);
|
fifo.update(read_bytes);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@ const std = @import("../std.zig");
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const io = std.io;
|
const io = std.io;
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const os = std.os;
|
|
||||||
|
|
||||||
pub const CWriter = io.Writer(*std.c.FILE, std.fs.File.WriteError, cWriterWrite);
|
pub const CWriter = io.Writer(*std.c.FILE, std.fs.File.WriteError, cWriterWrite);
|
||||||
|
|
||||||
@ -13,7 +12,7 @@ pub fn cWriter(c_file: *std.c.FILE) CWriter {
|
|||||||
fn cWriterWrite(c_file: *std.c.FILE, bytes: []const u8) std.fs.File.WriteError!usize {
|
fn cWriterWrite(c_file: *std.c.FILE, bytes: []const u8) std.fs.File.WriteError!usize {
|
||||||
const amt_written = std.c.fwrite(bytes.ptr, 1, bytes.len, c_file);
|
const amt_written = std.c.fwrite(bytes.ptr, 1, bytes.len, c_file);
|
||||||
if (amt_written >= 0) return amt_written;
|
if (amt_written >= 0) return amt_written;
|
||||||
switch (@as(os.E, @enumFromInt(std.c._errno().*))) {
|
switch (@as(std.c.E, @enumFromInt(std.c._errno().*))) {
|
||||||
.SUCCESS => unreachable,
|
.SUCCESS => unreachable,
|
||||||
.INVAL => unreachable,
|
.INVAL => unreachable,
|
||||||
.FAULT => unreachable,
|
.FAULT => unreachable,
|
||||||
@ -26,11 +25,11 @@ fn cWriterWrite(c_file: *std.c.FILE, bytes: []const u8) std.fs.File.WriteError!u
|
|||||||
.NOSPC => return error.NoSpaceLeft,
|
.NOSPC => return error.NoSpaceLeft,
|
||||||
.PERM => return error.AccessDenied,
|
.PERM => return error.AccessDenied,
|
||||||
.PIPE => return error.BrokenPipe,
|
.PIPE => return error.BrokenPipe,
|
||||||
else => |err| return os.unexpectedErrno(err),
|
else => |err| return std.posix.unexpectedErrno(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "C Writer" {
|
test cWriter {
|
||||||
if (!builtin.link_libc or builtin.os.tag == .wasi) return error.SkipZigTest;
|
if (!builtin.link_libc or builtin.os.tag == .wasi) return error.SkipZigTest;
|
||||||
|
|
||||||
const filename = "tmp_io_test_file.txt";
|
const filename = "tmp_io_test_file.txt";
|
||||||
|
|||||||
333
lib/std/net.zig
333
lib/std/net.zig
@ -5,15 +5,16 @@ const builtin = @import("builtin");
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const net = @This();
|
const net = @This();
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const os = std.os;
|
|
||||||
const posix = std.posix;
|
const posix = std.posix;
|
||||||
const fs = std.fs;
|
const fs = std.fs;
|
||||||
const io = std.io;
|
const io = std.io;
|
||||||
const native_endian = builtin.target.cpu.arch.endian();
|
const native_endian = builtin.target.cpu.arch.endian();
|
||||||
|
const native_os = builtin.os.tag;
|
||||||
|
const windows = std.os.windows;
|
||||||
|
|
||||||
// Windows 10 added support for unix sockets in build 17063, redstone 4 is the
|
// Windows 10 added support for unix sockets in build 17063, redstone 4 is the
|
||||||
// first release to support them.
|
// first release to support them.
|
||||||
pub const has_unix_sockets = switch (builtin.os.tag) {
|
pub const has_unix_sockets = switch (native_os) {
|
||||||
.windows => builtin.os.version_range.windows.isAtLeast(.win10_rs4) orelse false,
|
.windows => builtin.os.version_range.windows.isAtLeast(.win10_rs4) orelse false,
|
||||||
else => true,
|
else => true,
|
||||||
};
|
};
|
||||||
@ -28,14 +29,14 @@ pub const IPParseError = error{
|
|||||||
pub const IPv4ParseError = IPParseError || error{NonCanonical};
|
pub const IPv4ParseError = IPParseError || error{NonCanonical};
|
||||||
|
|
||||||
pub const IPv6ParseError = IPParseError || error{InvalidIpv4Mapping};
|
pub const IPv6ParseError = IPParseError || error{InvalidIpv4Mapping};
|
||||||
pub const IPv6InterfaceError = os.SocketError || os.IoCtl_SIOCGIFINDEX_Error || error{NameTooLong};
|
pub const IPv6InterfaceError = posix.SocketError || posix.IoCtl_SIOCGIFINDEX_Error || error{NameTooLong};
|
||||||
pub const IPv6ResolveError = IPv6ParseError || IPv6InterfaceError;
|
pub const IPv6ResolveError = IPv6ParseError || IPv6InterfaceError;
|
||||||
|
|
||||||
pub const Address = extern union {
|
pub const Address = extern union {
|
||||||
any: os.sockaddr,
|
any: posix.sockaddr,
|
||||||
in: Ip4Address,
|
in: Ip4Address,
|
||||||
in6: Ip6Address,
|
in6: Ip6Address,
|
||||||
un: if (has_unix_sockets) os.sockaddr.un else void,
|
un: if (has_unix_sockets) posix.sockaddr.un else void,
|
||||||
|
|
||||||
/// Parse the given IP address string into an Address value.
|
/// Parse the given IP address string into an Address value.
|
||||||
/// It is recommended to use `resolveIp` instead, to handle
|
/// It is recommended to use `resolveIp` instead, to handle
|
||||||
@ -85,38 +86,38 @@ pub const Address = extern union {
|
|||||||
return error.InvalidIPAddressFormat;
|
return error.InvalidIPAddressFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parseExpectingFamily(name: []const u8, family: os.sa_family_t, port: u16) !Address {
|
pub fn parseExpectingFamily(name: []const u8, family: posix.sa_family_t, port: u16) !Address {
|
||||||
switch (family) {
|
switch (family) {
|
||||||
os.AF.INET => return parseIp4(name, port),
|
posix.AF.INET => return parseIp4(name, port),
|
||||||
os.AF.INET6 => return parseIp6(name, port),
|
posix.AF.INET6 => return parseIp6(name, port),
|
||||||
os.AF.UNSPEC => return parseIp(name, port),
|
posix.AF.UNSPEC => return parseIp(name, port),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parseIp6(buf: []const u8, port: u16) IPv6ParseError!Address {
|
pub fn parseIp6(buf: []const u8, port: u16) IPv6ParseError!Address {
|
||||||
return Address{ .in6 = try Ip6Address.parse(buf, port) };
|
return .{ .in6 = try Ip6Address.parse(buf, port) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolveIp6(buf: []const u8, port: u16) IPv6ResolveError!Address {
|
pub fn resolveIp6(buf: []const u8, port: u16) IPv6ResolveError!Address {
|
||||||
return Address{ .in6 = try Ip6Address.resolve(buf, port) };
|
return .{ .in6 = try Ip6Address.resolve(buf, port) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parseIp4(buf: []const u8, port: u16) IPv4ParseError!Address {
|
pub fn parseIp4(buf: []const u8, port: u16) IPv4ParseError!Address {
|
||||||
return Address{ .in = try Ip4Address.parse(buf, port) };
|
return .{ .in = try Ip4Address.parse(buf, port) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initIp4(addr: [4]u8, port: u16) Address {
|
pub fn initIp4(addr: [4]u8, port: u16) Address {
|
||||||
return Address{ .in = Ip4Address.init(addr, port) };
|
return .{ .in = Ip4Address.init(addr, port) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initIp6(addr: [16]u8, port: u16, flowinfo: u32, scope_id: u32) Address {
|
pub fn initIp6(addr: [16]u8, port: u16, flowinfo: u32, scope_id: u32) Address {
|
||||||
return Address{ .in6 = Ip6Address.init(addr, port, flowinfo, scope_id) };
|
return .{ .in6 = Ip6Address.init(addr, port, flowinfo, scope_id) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initUnix(path: []const u8) !Address {
|
pub fn initUnix(path: []const u8) !Address {
|
||||||
var sock_addr = os.sockaddr.un{
|
var sock_addr = posix.sockaddr.un{
|
||||||
.family = os.AF.UNIX,
|
.family = posix.AF.UNIX,
|
||||||
.path = undefined,
|
.path = undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -133,8 +134,8 @@ pub const Address = extern union {
|
|||||||
/// Asserts that the address is ip4 or ip6.
|
/// Asserts that the address is ip4 or ip6.
|
||||||
pub fn getPort(self: Address) u16 {
|
pub fn getPort(self: Address) u16 {
|
||||||
return switch (self.any.family) {
|
return switch (self.any.family) {
|
||||||
os.AF.INET => self.in.getPort(),
|
posix.AF.INET => self.in.getPort(),
|
||||||
os.AF.INET6 => self.in6.getPort(),
|
posix.AF.INET6 => self.in6.getPort(),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -143,8 +144,8 @@ pub const Address = extern union {
|
|||||||
/// Asserts that the address is ip4 or ip6.
|
/// Asserts that the address is ip4 or ip6.
|
||||||
pub fn setPort(self: *Address, port: u16) void {
|
pub fn setPort(self: *Address, port: u16) void {
|
||||||
switch (self.any.family) {
|
switch (self.any.family) {
|
||||||
os.AF.INET => self.in.setPort(port),
|
posix.AF.INET => self.in.setPort(port),
|
||||||
os.AF.INET6 => self.in6.setPort(port),
|
posix.AF.INET6 => self.in6.setPort(port),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,10 +153,10 @@ pub const Address = extern union {
|
|||||||
/// Asserts that `addr` is an IP address.
|
/// Asserts that `addr` is an IP address.
|
||||||
/// This function will read past the end of the pointer, with a size depending
|
/// This function will read past the end of the pointer, with a size depending
|
||||||
/// on the address family.
|
/// on the address family.
|
||||||
pub fn initPosix(addr: *align(4) const os.sockaddr) Address {
|
pub fn initPosix(addr: *align(4) const posix.sockaddr) Address {
|
||||||
switch (addr.family) {
|
switch (addr.family) {
|
||||||
os.AF.INET => return Address{ .in = Ip4Address{ .sa = @as(*const os.sockaddr.in, @ptrCast(addr)).* } },
|
posix.AF.INET => return Address{ .in = Ip4Address{ .sa = @as(*const posix.sockaddr.in, @ptrCast(addr)).* } },
|
||||||
os.AF.INET6 => return Address{ .in6 = Ip6Address{ .sa = @as(*const os.sockaddr.in6, @ptrCast(addr)).* } },
|
posix.AF.INET6 => return Address{ .in6 = Ip6Address{ .sa = @as(*const posix.sockaddr.in6, @ptrCast(addr)).* } },
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,9 +169,9 @@ pub const Address = extern union {
|
|||||||
) !void {
|
) !void {
|
||||||
if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self);
|
if (fmt.len != 0) std.fmt.invalidFmtError(fmt, self);
|
||||||
switch (self.any.family) {
|
switch (self.any.family) {
|
||||||
os.AF.INET => try self.in.format(fmt, options, out_stream),
|
posix.AF.INET => try self.in.format(fmt, options, out_stream),
|
||||||
os.AF.INET6 => try self.in6.format(fmt, options, out_stream),
|
posix.AF.INET6 => try self.in6.format(fmt, options, out_stream),
|
||||||
os.AF.UNIX => {
|
posix.AF.UNIX => {
|
||||||
if (!has_unix_sockets) {
|
if (!has_unix_sockets) {
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
@ -187,11 +188,11 @@ pub const Address = extern union {
|
|||||||
return mem.eql(u8, a_bytes, b_bytes);
|
return mem.eql(u8, a_bytes, b_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getOsSockLen(self: Address) os.socklen_t {
|
pub fn getOsSockLen(self: Address) posix.socklen_t {
|
||||||
switch (self.any.family) {
|
switch (self.any.family) {
|
||||||
os.AF.INET => return self.in.getOsSockLen(),
|
posix.AF.INET => return self.in.getOsSockLen(),
|
||||||
os.AF.INET6 => return self.in6.getOsSockLen(),
|
posix.AF.INET6 => return self.in6.getOsSockLen(),
|
||||||
os.AF.UNIX => {
|
posix.AF.UNIX => {
|
||||||
if (!has_unix_sockets) {
|
if (!has_unix_sockets) {
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
@ -204,7 +205,7 @@ pub const Address = extern union {
|
|||||||
// provide the full buffer size (e.g. getsockname, getpeername, recvfrom, accept).
|
// provide the full buffer size (e.g. getsockname, getpeername, recvfrom, accept).
|
||||||
//
|
//
|
||||||
// To access the path, std.mem.sliceTo(&address.un.path, 0) should be used.
|
// To access the path, std.mem.sliceTo(&address.un.path, 0) should be used.
|
||||||
return @as(os.socklen_t, @intCast(@sizeOf(os.sockaddr.un)));
|
return @as(posix.socklen_t, @intCast(@sizeOf(posix.sockaddr.un)));
|
||||||
},
|
},
|
||||||
|
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
@ -247,7 +248,7 @@ pub const Address = extern union {
|
|||||||
posix.SO.REUSEADDR,
|
posix.SO.REUSEADDR,
|
||||||
&mem.toBytes(@as(c_int, 1)),
|
&mem.toBytes(@as(c_int, 1)),
|
||||||
);
|
);
|
||||||
switch (builtin.os.tag) {
|
switch (native_os) {
|
||||||
.windows => {},
|
.windows => {},
|
||||||
else => try posix.setsockopt(
|
else => try posix.setsockopt(
|
||||||
sockfd,
|
sockfd,
|
||||||
@ -267,7 +268,7 @@ pub const Address = extern union {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const Ip4Address = extern struct {
|
pub const Ip4Address = extern struct {
|
||||||
sa: os.sockaddr.in,
|
sa: posix.sockaddr.in,
|
||||||
|
|
||||||
pub fn parse(buf: []const u8, port: u16) IPv4ParseError!Ip4Address {
|
pub fn parse(buf: []const u8, port: u16) IPv4ParseError!Ip4Address {
|
||||||
var result = Ip4Address{
|
var result = Ip4Address{
|
||||||
@ -330,7 +331,7 @@ pub const Ip4Address = extern struct {
|
|||||||
|
|
||||||
pub fn init(addr: [4]u8, port: u16) Ip4Address {
|
pub fn init(addr: [4]u8, port: u16) Ip4Address {
|
||||||
return Ip4Address{
|
return Ip4Address{
|
||||||
.sa = os.sockaddr.in{
|
.sa = posix.sockaddr.in{
|
||||||
.port = mem.nativeToBig(u16, port),
|
.port = mem.nativeToBig(u16, port),
|
||||||
.addr = @as(*align(1) const u32, @ptrCast(&addr)).*,
|
.addr = @as(*align(1) const u32, @ptrCast(&addr)).*,
|
||||||
},
|
},
|
||||||
@ -367,21 +368,21 @@ pub const Ip4Address = extern struct {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getOsSockLen(self: Ip4Address) os.socklen_t {
|
pub fn getOsSockLen(self: Ip4Address) posix.socklen_t {
|
||||||
_ = self;
|
_ = self;
|
||||||
return @sizeOf(os.sockaddr.in);
|
return @sizeOf(posix.sockaddr.in);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Ip6Address = extern struct {
|
pub const Ip6Address = extern struct {
|
||||||
sa: os.sockaddr.in6,
|
sa: posix.sockaddr.in6,
|
||||||
|
|
||||||
/// Parse a given IPv6 address string into an Address.
|
/// Parse a given IPv6 address string into an Address.
|
||||||
/// Assumes the Scope ID of the address is fully numeric.
|
/// Assumes the Scope ID of the address is fully numeric.
|
||||||
/// For non-numeric addresses, see `resolveIp6`.
|
/// For non-numeric addresses, see `resolveIp6`.
|
||||||
pub fn parse(buf: []const u8, port: u16) IPv6ParseError!Ip6Address {
|
pub fn parse(buf: []const u8, port: u16) IPv6ParseError!Ip6Address {
|
||||||
var result = Ip6Address{
|
var result = Ip6Address{
|
||||||
.sa = os.sockaddr.in6{
|
.sa = posix.sockaddr.in6{
|
||||||
.scope_id = 0,
|
.scope_id = 0,
|
||||||
.port = mem.nativeToBig(u16, port),
|
.port = mem.nativeToBig(u16, port),
|
||||||
.flowinfo = 0,
|
.flowinfo = 0,
|
||||||
@ -499,7 +500,7 @@ pub const Ip6Address = extern struct {
|
|||||||
pub fn resolve(buf: []const u8, port: u16) IPv6ResolveError!Ip6Address {
|
pub fn resolve(buf: []const u8, port: u16) IPv6ResolveError!Ip6Address {
|
||||||
// TODO: Unify the implementations of resolveIp6 and parseIp6.
|
// TODO: Unify the implementations of resolveIp6 and parseIp6.
|
||||||
var result = Ip6Address{
|
var result = Ip6Address{
|
||||||
.sa = os.sockaddr.in6{
|
.sa = posix.sockaddr.in6{
|
||||||
.scope_id = 0,
|
.scope_id = 0,
|
||||||
.port = mem.nativeToBig(u16, port),
|
.port = mem.nativeToBig(u16, port),
|
||||||
.flowinfo = 0,
|
.flowinfo = 0,
|
||||||
@ -516,7 +517,7 @@ pub const Ip6Address = extern struct {
|
|||||||
var abbrv = false;
|
var abbrv = false;
|
||||||
|
|
||||||
var scope_id = false;
|
var scope_id = false;
|
||||||
var scope_id_value: [os.IFNAMESIZE - 1]u8 = undefined;
|
var scope_id_value: [posix.IFNAMESIZE - 1]u8 = undefined;
|
||||||
var scope_id_index: usize = 0;
|
var scope_id_index: usize = 0;
|
||||||
|
|
||||||
for (buf, 0..) |c, i| {
|
for (buf, 0..) |c, i| {
|
||||||
@ -632,7 +633,7 @@ pub const Ip6Address = extern struct {
|
|||||||
|
|
||||||
pub fn init(addr: [16]u8, port: u16, flowinfo: u32, scope_id: u32) Ip6Address {
|
pub fn init(addr: [16]u8, port: u16, flowinfo: u32, scope_id: u32) Ip6Address {
|
||||||
return Ip6Address{
|
return Ip6Address{
|
||||||
.sa = os.sockaddr.in6{
|
.sa = posix.sockaddr.in6{
|
||||||
.addr = addr,
|
.addr = addr,
|
||||||
.port = mem.nativeToBig(u16, port),
|
.port = mem.nativeToBig(u16, port),
|
||||||
.flowinfo = flowinfo,
|
.flowinfo = flowinfo,
|
||||||
@ -702,51 +703,51 @@ pub const Ip6Address = extern struct {
|
|||||||
try std.fmt.format(out_stream, "]:{}", .{port});
|
try std.fmt.format(out_stream, "]:{}", .{port});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getOsSockLen(self: Ip6Address) os.socklen_t {
|
pub fn getOsSockLen(self: Ip6Address) posix.socklen_t {
|
||||||
_ = self;
|
_ = self;
|
||||||
return @sizeOf(os.sockaddr.in6);
|
return @sizeOf(posix.sockaddr.in6);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn connectUnixSocket(path: []const u8) !Stream {
|
pub fn connectUnixSocket(path: []const u8) !Stream {
|
||||||
const opt_non_block = 0;
|
const opt_non_block = 0;
|
||||||
const sockfd = try os.socket(
|
const sockfd = try posix.socket(
|
||||||
os.AF.UNIX,
|
posix.AF.UNIX,
|
||||||
os.SOCK.STREAM | os.SOCK.CLOEXEC | opt_non_block,
|
posix.SOCK.STREAM | posix.SOCK.CLOEXEC | opt_non_block,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
errdefer Stream.close(.{ .handle = sockfd });
|
errdefer Stream.close(.{ .handle = sockfd });
|
||||||
|
|
||||||
var addr = try std.net.Address.initUnix(path);
|
var addr = try std.net.Address.initUnix(path);
|
||||||
try os.connect(sockfd, &addr.any, addr.getOsSockLen());
|
try posix.connect(sockfd, &addr.any, addr.getOsSockLen());
|
||||||
|
|
||||||
return Stream{ .handle = sockfd };
|
return .{ .handle = sockfd };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn if_nametoindex(name: []const u8) IPv6InterfaceError!u32 {
|
fn if_nametoindex(name: []const u8) IPv6InterfaceError!u32 {
|
||||||
if (builtin.target.os.tag == .linux) {
|
if (native_os == .linux) {
|
||||||
var ifr: os.ifreq = undefined;
|
var ifr: posix.ifreq = undefined;
|
||||||
const sockfd = try os.socket(os.AF.UNIX, os.SOCK.DGRAM | os.SOCK.CLOEXEC, 0);
|
const sockfd = try posix.socket(posix.AF.UNIX, posix.SOCK.DGRAM | posix.SOCK.CLOEXEC, 0);
|
||||||
defer Stream.close(.{ .handle = sockfd });
|
defer Stream.close(.{ .handle = sockfd });
|
||||||
|
|
||||||
@memcpy(ifr.ifrn.name[0..name.len], name);
|
@memcpy(ifr.ifrn.name[0..name.len], name);
|
||||||
ifr.ifrn.name[name.len] = 0;
|
ifr.ifrn.name[name.len] = 0;
|
||||||
|
|
||||||
// TODO investigate if this needs to be integrated with evented I/O.
|
// TODO investigate if this needs to be integrated with evented I/O.
|
||||||
try os.ioctl_SIOCGIFINDEX(sockfd, &ifr);
|
try posix.ioctl_SIOCGIFINDEX(sockfd, &ifr);
|
||||||
|
|
||||||
return @as(u32, @bitCast(ifr.ifru.ivalue));
|
return @bitCast(ifr.ifru.ivalue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (comptime builtin.target.os.tag.isDarwin()) {
|
if (native_os.isDarwin()) {
|
||||||
if (name.len >= os.IFNAMESIZE)
|
if (name.len >= posix.IFNAMESIZE)
|
||||||
return error.NameTooLong;
|
return error.NameTooLong;
|
||||||
|
|
||||||
var if_name: [os.IFNAMESIZE:0]u8 = undefined;
|
var if_name: [posix.IFNAMESIZE:0]u8 = undefined;
|
||||||
@memcpy(if_name[0..name.len], name);
|
@memcpy(if_name[0..name.len], name);
|
||||||
if_name[name.len] = 0;
|
if_name[name.len] = 0;
|
||||||
const if_slice = if_name[0..name.len :0];
|
const if_slice = if_name[0..name.len :0];
|
||||||
const index = os.system.if_nametoindex(if_slice);
|
const index = std.c.if_nametoindex(if_slice);
|
||||||
if (index == 0)
|
if (index == 0)
|
||||||
return error.InterfaceNotFound;
|
return error.InterfaceNotFound;
|
||||||
return @as(u32, @bitCast(index));
|
return @as(u32, @bitCast(index));
|
||||||
@ -786,24 +787,24 @@ pub fn tcpConnectToHost(allocator: mem.Allocator, name: []const u8, port: u16) T
|
|||||||
else => return err,
|
else => return err,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return std.os.ConnectError.ConnectionRefused;
|
return posix.ConnectError.ConnectionRefused;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const TcpConnectToAddressError = std.os.SocketError || std.os.ConnectError;
|
pub const TcpConnectToAddressError = posix.SocketError || posix.ConnectError;
|
||||||
|
|
||||||
pub fn tcpConnectToAddress(address: Address) TcpConnectToAddressError!Stream {
|
pub fn tcpConnectToAddress(address: Address) TcpConnectToAddressError!Stream {
|
||||||
const nonblock = 0;
|
const nonblock = 0;
|
||||||
const sock_flags = os.SOCK.STREAM | nonblock |
|
const sock_flags = posix.SOCK.STREAM | nonblock |
|
||||||
(if (builtin.target.os.tag == .windows) 0 else os.SOCK.CLOEXEC);
|
(if (native_os == .windows) 0 else posix.SOCK.CLOEXEC);
|
||||||
const sockfd = try os.socket(address.any.family, sock_flags, os.IPPROTO.TCP);
|
const sockfd = try posix.socket(address.any.family, sock_flags, posix.IPPROTO.TCP);
|
||||||
errdefer Stream.close(.{ .handle = sockfd });
|
errdefer Stream.close(.{ .handle = sockfd });
|
||||||
|
|
||||||
try os.connect(sockfd, &address.any, address.getOsSockLen());
|
try posix.connect(sockfd, &address.any, address.getOsSockLen());
|
||||||
|
|
||||||
return Stream{ .handle = sockfd };
|
return Stream{ .handle = sockfd };
|
||||||
}
|
}
|
||||||
|
|
||||||
const GetAddressListError = std.mem.Allocator.Error || std.fs.File.OpenError || std.fs.File.ReadError || std.os.SocketError || std.os.BindError || std.os.SetSockOptError || error{
|
const GetAddressListError = std.mem.Allocator.Error || std.fs.File.OpenError || std.fs.File.ReadError || posix.SocketError || posix.BindError || posix.SetSockOptError || error{
|
||||||
// TODO: break this up into error sets from the various underlying functions
|
// TODO: break this up into error sets from the various underlying functions
|
||||||
|
|
||||||
TemporaryNameServerFailure,
|
TemporaryNameServerFailure,
|
||||||
@ -844,30 +845,30 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) Get
|
|||||||
const arena = result.arena.allocator();
|
const arena = result.arena.allocator();
|
||||||
errdefer result.deinit();
|
errdefer result.deinit();
|
||||||
|
|
||||||
if (builtin.target.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const name_c = try allocator.dupeZ(u8, name);
|
const name_c = try allocator.dupeZ(u8, name);
|
||||||
defer allocator.free(name_c);
|
defer allocator.free(name_c);
|
||||||
|
|
||||||
const port_c = try std.fmt.allocPrintZ(allocator, "{}", .{port});
|
const port_c = try std.fmt.allocPrintZ(allocator, "{}", .{port});
|
||||||
defer allocator.free(port_c);
|
defer allocator.free(port_c);
|
||||||
|
|
||||||
const ws2_32 = os.windows.ws2_32;
|
const ws2_32 = windows.ws2_32;
|
||||||
const hints = os.addrinfo{
|
const hints = posix.addrinfo{
|
||||||
.flags = ws2_32.AI.NUMERICSERV,
|
.flags = ws2_32.AI.NUMERICSERV,
|
||||||
.family = os.AF.UNSPEC,
|
.family = posix.AF.UNSPEC,
|
||||||
.socktype = os.SOCK.STREAM,
|
.socktype = posix.SOCK.STREAM,
|
||||||
.protocol = os.IPPROTO.TCP,
|
.protocol = posix.IPPROTO.TCP,
|
||||||
.canonname = null,
|
.canonname = null,
|
||||||
.addr = null,
|
.addr = null,
|
||||||
.addrlen = 0,
|
.addrlen = 0,
|
||||||
.next = null,
|
.next = null,
|
||||||
};
|
};
|
||||||
var res: ?*os.addrinfo = null;
|
var res: ?*posix.addrinfo = null;
|
||||||
var first = true;
|
var first = true;
|
||||||
while (true) {
|
while (true) {
|
||||||
const rc = ws2_32.getaddrinfo(name_c.ptr, port_c.ptr, &hints, &res);
|
const rc = ws2_32.getaddrinfo(name_c.ptr, port_c.ptr, &hints, &res);
|
||||||
switch (@as(os.windows.ws2_32.WinsockError, @enumFromInt(@as(u16, @intCast(rc))))) {
|
switch (@as(windows.ws2_32.WinsockError, @enumFromInt(@as(u16, @intCast(rc))))) {
|
||||||
@as(os.windows.ws2_32.WinsockError, @enumFromInt(0)) => break,
|
@as(windows.ws2_32.WinsockError, @enumFromInt(0)) => break,
|
||||||
.WSATRY_AGAIN => return error.TemporaryNameServerFailure,
|
.WSATRY_AGAIN => return error.TemporaryNameServerFailure,
|
||||||
.WSANO_RECOVERY => return error.NameServerFailure,
|
.WSANO_RECOVERY => return error.NameServerFailure,
|
||||||
.WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
|
.WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
|
||||||
@ -879,10 +880,10 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) Get
|
|||||||
.WSANOTINITIALISED => {
|
.WSANOTINITIALISED => {
|
||||||
if (!first) return error.Unexpected;
|
if (!first) return error.Unexpected;
|
||||||
first = false;
|
first = false;
|
||||||
try os.windows.callWSAStartup();
|
try windows.callWSAStartup();
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
else => |err| return os.windows.unexpectedWSAError(err),
|
else => |err| return windows.unexpectedWSAError(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defer ws2_32.freeaddrinfo(res);
|
defer ws2_32.freeaddrinfo(res);
|
||||||
@ -923,18 +924,18 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) Get
|
|||||||
const port_c = try std.fmt.allocPrintZ(allocator, "{}", .{port});
|
const port_c = try std.fmt.allocPrintZ(allocator, "{}", .{port});
|
||||||
defer allocator.free(port_c);
|
defer allocator.free(port_c);
|
||||||
|
|
||||||
const sys = if (builtin.target.os.tag == .windows) os.windows.ws2_32 else os.system;
|
const sys = if (native_os == .windows) windows.ws2_32 else posix.system;
|
||||||
const hints = os.addrinfo{
|
const hints = posix.addrinfo{
|
||||||
.flags = sys.AI.NUMERICSERV,
|
.flags = sys.AI.NUMERICSERV,
|
||||||
.family = os.AF.UNSPEC,
|
.family = posix.AF.UNSPEC,
|
||||||
.socktype = os.SOCK.STREAM,
|
.socktype = posix.SOCK.STREAM,
|
||||||
.protocol = os.IPPROTO.TCP,
|
.protocol = posix.IPPROTO.TCP,
|
||||||
.canonname = null,
|
.canonname = null,
|
||||||
.addr = null,
|
.addr = null,
|
||||||
.addrlen = 0,
|
.addrlen = 0,
|
||||||
.next = null,
|
.next = null,
|
||||||
};
|
};
|
||||||
var res: ?*os.addrinfo = null;
|
var res: ?*posix.addrinfo = null;
|
||||||
switch (sys.getaddrinfo(name_c.ptr, port_c.ptr, &hints, &res)) {
|
switch (sys.getaddrinfo(name_c.ptr, port_c.ptr, &hints, &res)) {
|
||||||
@as(sys.EAI, @enumFromInt(0)) => {},
|
@as(sys.EAI, @enumFromInt(0)) => {},
|
||||||
.ADDRFAMILY => return error.HostLacksNetworkAddresses,
|
.ADDRFAMILY => return error.HostLacksNetworkAddresses,
|
||||||
@ -947,8 +948,8 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) Get
|
|||||||
.NONAME => return error.UnknownHostName,
|
.NONAME => return error.UnknownHostName,
|
||||||
.SERVICE => return error.ServiceUnavailable,
|
.SERVICE => return error.ServiceUnavailable,
|
||||||
.SOCKTYPE => unreachable, // Invalid socket type requested in hints
|
.SOCKTYPE => unreachable, // Invalid socket type requested in hints
|
||||||
.SYSTEM => switch (os.errno(-1)) {
|
.SYSTEM => switch (posix.errno(-1)) {
|
||||||
else => |e| return os.unexpectedErrno(e),
|
else => |e| return posix.unexpectedErrno(e),
|
||||||
},
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
@ -983,9 +984,9 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) Get
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (builtin.target.os.tag == .linux) {
|
if (native_os == .linux) {
|
||||||
const flags = std.c.AI.NUMERICSERV;
|
const flags = std.c.AI.NUMERICSERV;
|
||||||
const family = os.AF.UNSPEC;
|
const family = posix.AF.UNSPEC;
|
||||||
var lookup_addrs = std.ArrayList(LookupAddr).init(allocator);
|
var lookup_addrs = std.ArrayList(LookupAddr).init(allocator);
|
||||||
defer lookup_addrs.deinit();
|
defer lookup_addrs.deinit();
|
||||||
|
|
||||||
@ -1026,7 +1027,7 @@ fn linuxLookupName(
|
|||||||
addrs: *std.ArrayList(LookupAddr),
|
addrs: *std.ArrayList(LookupAddr),
|
||||||
canon: *std.ArrayList(u8),
|
canon: *std.ArrayList(u8),
|
||||||
opt_name: ?[]const u8,
|
opt_name: ?[]const u8,
|
||||||
family: os.sa_family_t,
|
family: posix.sa_family_t,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
port: u16,
|
port: u16,
|
||||||
) !void {
|
) !void {
|
||||||
@ -1066,9 +1067,9 @@ fn linuxLookupName(
|
|||||||
|
|
||||||
// No further processing is needed if there are fewer than 2
|
// No further processing is needed if there are fewer than 2
|
||||||
// results or if there are only IPv4 results.
|
// results or if there are only IPv4 results.
|
||||||
if (addrs.items.len == 1 or family == os.AF.INET) return;
|
if (addrs.items.len == 1 or family == posix.AF.INET) return;
|
||||||
const all_ip4 = for (addrs.items) |addr| {
|
const all_ip4 = for (addrs.items) |addr| {
|
||||||
if (addr.addr.any.family != os.AF.INET) break false;
|
if (addr.addr.any.family != posix.AF.INET) break false;
|
||||||
} else true;
|
} else true;
|
||||||
if (all_ip4) return;
|
if (all_ip4) return;
|
||||||
|
|
||||||
@ -1081,42 +1082,42 @@ fn linuxLookupName(
|
|||||||
// A more idiomatic "ziggy" implementation would be welcome.
|
// A more idiomatic "ziggy" implementation would be welcome.
|
||||||
for (addrs.items, 0..) |*addr, i| {
|
for (addrs.items, 0..) |*addr, i| {
|
||||||
var key: i32 = 0;
|
var key: i32 = 0;
|
||||||
var sa6: os.sockaddr.in6 = undefined;
|
var sa6: posix.sockaddr.in6 = undefined;
|
||||||
@memset(@as([*]u8, @ptrCast(&sa6))[0..@sizeOf(os.sockaddr.in6)], 0);
|
@memset(@as([*]u8, @ptrCast(&sa6))[0..@sizeOf(posix.sockaddr.in6)], 0);
|
||||||
var da6 = os.sockaddr.in6{
|
var da6 = posix.sockaddr.in6{
|
||||||
.family = os.AF.INET6,
|
.family = posix.AF.INET6,
|
||||||
.scope_id = addr.addr.in6.sa.scope_id,
|
.scope_id = addr.addr.in6.sa.scope_id,
|
||||||
.port = 65535,
|
.port = 65535,
|
||||||
.flowinfo = 0,
|
.flowinfo = 0,
|
||||||
.addr = [1]u8{0} ** 16,
|
.addr = [1]u8{0} ** 16,
|
||||||
};
|
};
|
||||||
var sa4: os.sockaddr.in = undefined;
|
var sa4: posix.sockaddr.in = undefined;
|
||||||
@memset(@as([*]u8, @ptrCast(&sa4))[0..@sizeOf(os.sockaddr.in)], 0);
|
@memset(@as([*]u8, @ptrCast(&sa4))[0..@sizeOf(posix.sockaddr.in)], 0);
|
||||||
var da4 = os.sockaddr.in{
|
var da4 = posix.sockaddr.in{
|
||||||
.family = os.AF.INET,
|
.family = posix.AF.INET,
|
||||||
.port = 65535,
|
.port = 65535,
|
||||||
.addr = 0,
|
.addr = 0,
|
||||||
.zero = [1]u8{0} ** 8,
|
.zero = [1]u8{0} ** 8,
|
||||||
};
|
};
|
||||||
var sa: *align(4) os.sockaddr = undefined;
|
var sa: *align(4) posix.sockaddr = undefined;
|
||||||
var da: *align(4) os.sockaddr = undefined;
|
var da: *align(4) posix.sockaddr = undefined;
|
||||||
var salen: os.socklen_t = undefined;
|
var salen: posix.socklen_t = undefined;
|
||||||
var dalen: os.socklen_t = undefined;
|
var dalen: posix.socklen_t = undefined;
|
||||||
if (addr.addr.any.family == os.AF.INET6) {
|
if (addr.addr.any.family == posix.AF.INET6) {
|
||||||
da6.addr = addr.addr.in6.sa.addr;
|
da6.addr = addr.addr.in6.sa.addr;
|
||||||
da = @ptrCast(&da6);
|
da = @ptrCast(&da6);
|
||||||
dalen = @sizeOf(os.sockaddr.in6);
|
dalen = @sizeOf(posix.sockaddr.in6);
|
||||||
sa = @ptrCast(&sa6);
|
sa = @ptrCast(&sa6);
|
||||||
salen = @sizeOf(os.sockaddr.in6);
|
salen = @sizeOf(posix.sockaddr.in6);
|
||||||
} else {
|
} else {
|
||||||
sa6.addr[0..12].* = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff".*;
|
sa6.addr[0..12].* = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff".*;
|
||||||
da6.addr[0..12].* = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff".*;
|
da6.addr[0..12].* = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff".*;
|
||||||
mem.writeInt(u32, da6.addr[12..], addr.addr.in.sa.addr, native_endian);
|
mem.writeInt(u32, da6.addr[12..], addr.addr.in.sa.addr, native_endian);
|
||||||
da4.addr = addr.addr.in.sa.addr;
|
da4.addr = addr.addr.in.sa.addr;
|
||||||
da = @ptrCast(&da4);
|
da = @ptrCast(&da4);
|
||||||
dalen = @sizeOf(os.sockaddr.in);
|
dalen = @sizeOf(posix.sockaddr.in);
|
||||||
sa = @ptrCast(&sa4);
|
sa = @ptrCast(&sa4);
|
||||||
salen = @sizeOf(os.sockaddr.in);
|
salen = @sizeOf(posix.sockaddr.in);
|
||||||
}
|
}
|
||||||
const dpolicy = policyOf(da6.addr);
|
const dpolicy = policyOf(da6.addr);
|
||||||
const dscope: i32 = scopeOf(da6.addr);
|
const dscope: i32 = scopeOf(da6.addr);
|
||||||
@ -1124,13 +1125,13 @@ fn linuxLookupName(
|
|||||||
const dprec: i32 = dpolicy.prec;
|
const dprec: i32 = dpolicy.prec;
|
||||||
const MAXADDRS = 3;
|
const MAXADDRS = 3;
|
||||||
var prefixlen: i32 = 0;
|
var prefixlen: i32 = 0;
|
||||||
const sock_flags = os.SOCK.DGRAM | os.SOCK.CLOEXEC;
|
const sock_flags = posix.SOCK.DGRAM | posix.SOCK.CLOEXEC;
|
||||||
if (os.socket(addr.addr.any.family, sock_flags, os.IPPROTO.UDP)) |fd| syscalls: {
|
if (posix.socket(addr.addr.any.family, sock_flags, posix.IPPROTO.UDP)) |fd| syscalls: {
|
||||||
defer Stream.close(.{ .handle = fd });
|
defer Stream.close(.{ .handle = fd });
|
||||||
os.connect(fd, da, dalen) catch break :syscalls;
|
posix.connect(fd, da, dalen) catch break :syscalls;
|
||||||
key |= DAS_USABLE;
|
key |= DAS_USABLE;
|
||||||
os.getsockname(fd, sa, &salen) catch break :syscalls;
|
posix.getsockname(fd, sa, &salen) catch break :syscalls;
|
||||||
if (addr.addr.any.family == os.AF.INET) {
|
if (addr.addr.any.family == posix.AF.INET) {
|
||||||
mem.writeInt(u32, sa6.addr[12..16], sa4.addr, native_endian);
|
mem.writeInt(u32, sa6.addr[12..16], sa4.addr, native_endian);
|
||||||
}
|
}
|
||||||
if (dscope == @as(i32, scopeOf(sa6.addr))) key |= DAS_MATCHINGSCOPE;
|
if (dscope == @as(i32, scopeOf(sa6.addr))) key |= DAS_MATCHINGSCOPE;
|
||||||
@ -1267,28 +1268,28 @@ fn addrCmpLessThan(context: void, b: LookupAddr, a: LookupAddr) bool {
|
|||||||
|
|
||||||
fn linuxLookupNameFromNull(
|
fn linuxLookupNameFromNull(
|
||||||
addrs: *std.ArrayList(LookupAddr),
|
addrs: *std.ArrayList(LookupAddr),
|
||||||
family: os.sa_family_t,
|
family: posix.sa_family_t,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
port: u16,
|
port: u16,
|
||||||
) !void {
|
) !void {
|
||||||
if ((flags & std.c.AI.PASSIVE) != 0) {
|
if ((flags & std.c.AI.PASSIVE) != 0) {
|
||||||
if (family != os.AF.INET6) {
|
if (family != posix.AF.INET6) {
|
||||||
(try addrs.addOne()).* = LookupAddr{
|
(try addrs.addOne()).* = LookupAddr{
|
||||||
.addr = Address.initIp4([1]u8{0} ** 4, port),
|
.addr = Address.initIp4([1]u8{0} ** 4, port),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (family != os.AF.INET) {
|
if (family != posix.AF.INET) {
|
||||||
(try addrs.addOne()).* = LookupAddr{
|
(try addrs.addOne()).* = LookupAddr{
|
||||||
.addr = Address.initIp6([1]u8{0} ** 16, port, 0, 0),
|
.addr = Address.initIp6([1]u8{0} ** 16, port, 0, 0),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (family != os.AF.INET6) {
|
if (family != posix.AF.INET6) {
|
||||||
(try addrs.addOne()).* = LookupAddr{
|
(try addrs.addOne()).* = LookupAddr{
|
||||||
.addr = Address.initIp4([4]u8{ 127, 0, 0, 1 }, port),
|
.addr = Address.initIp4([4]u8{ 127, 0, 0, 1 }, port),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (family != os.AF.INET) {
|
if (family != posix.AF.INET) {
|
||||||
(try addrs.addOne()).* = LookupAddr{
|
(try addrs.addOne()).* = LookupAddr{
|
||||||
.addr = Address.initIp6(([1]u8{0} ** 15) ++ [1]u8{1}, port, 0, 0),
|
.addr = Address.initIp6(([1]u8{0} ** 15) ++ [1]u8{1}, port, 0, 0),
|
||||||
};
|
};
|
||||||
@ -1300,7 +1301,7 @@ fn linuxLookupNameFromHosts(
|
|||||||
addrs: *std.ArrayList(LookupAddr),
|
addrs: *std.ArrayList(LookupAddr),
|
||||||
canon: *std.ArrayList(u8),
|
canon: *std.ArrayList(u8),
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
family: os.sa_family_t,
|
family: posix.sa_family_t,
|
||||||
port: u16,
|
port: u16,
|
||||||
) !void {
|
) !void {
|
||||||
const file = fs.openFileAbsoluteZ("/etc/hosts", .{}) catch |err| switch (err) {
|
const file = fs.openFileAbsoluteZ("/etc/hosts", .{}) catch |err| switch (err) {
|
||||||
@ -1374,7 +1375,7 @@ fn linuxLookupNameFromDnsSearch(
|
|||||||
addrs: *std.ArrayList(LookupAddr),
|
addrs: *std.ArrayList(LookupAddr),
|
||||||
canon: *std.ArrayList(u8),
|
canon: *std.ArrayList(u8),
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
family: os.sa_family_t,
|
family: posix.sa_family_t,
|
||||||
port: u16,
|
port: u16,
|
||||||
) !void {
|
) !void {
|
||||||
var rc: ResolvConf = undefined;
|
var rc: ResolvConf = undefined;
|
||||||
@ -1429,7 +1430,7 @@ fn linuxLookupNameFromDns(
|
|||||||
addrs: *std.ArrayList(LookupAddr),
|
addrs: *std.ArrayList(LookupAddr),
|
||||||
canon: *std.ArrayList(u8),
|
canon: *std.ArrayList(u8),
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
family: os.sa_family_t,
|
family: posix.sa_family_t,
|
||||||
rc: ResolvConf,
|
rc: ResolvConf,
|
||||||
port: u16,
|
port: u16,
|
||||||
) !void {
|
) !void {
|
||||||
@ -1439,12 +1440,12 @@ fn linuxLookupNameFromDns(
|
|||||||
.port = port,
|
.port = port,
|
||||||
};
|
};
|
||||||
const AfRr = struct {
|
const AfRr = struct {
|
||||||
af: os.sa_family_t,
|
af: posix.sa_family_t,
|
||||||
rr: u8,
|
rr: u8,
|
||||||
};
|
};
|
||||||
const afrrs = [_]AfRr{
|
const afrrs = [_]AfRr{
|
||||||
AfRr{ .af = os.AF.INET6, .rr = os.RR.A },
|
AfRr{ .af = posix.AF.INET6, .rr = posix.RR.A },
|
||||||
AfRr{ .af = os.AF.INET, .rr = os.RR.AAAA },
|
AfRr{ .af = posix.AF.INET, .rr = posix.RR.AAAA },
|
||||||
};
|
};
|
||||||
var qbuf: [2][280]u8 = undefined;
|
var qbuf: [2][280]u8 = undefined;
|
||||||
var abuf: [2][512]u8 = undefined;
|
var abuf: [2][512]u8 = undefined;
|
||||||
@ -1454,7 +1455,7 @@ fn linuxLookupNameFromDns(
|
|||||||
|
|
||||||
for (afrrs) |afrr| {
|
for (afrrs) |afrr| {
|
||||||
if (family != afrr.af) {
|
if (family != afrr.af) {
|
||||||
const len = os.res_mkquery(0, name, 1, afrr.rr, &[_]u8{}, null, &qbuf[nq]);
|
const len = posix.res_mkquery(0, name, 1, afrr.rr, &[_]u8{}, null, &qbuf[nq]);
|
||||||
qp[nq] = qbuf[nq][0..len];
|
qp[nq] = qbuf[nq][0..len];
|
||||||
nq += 1;
|
nq += 1;
|
||||||
}
|
}
|
||||||
@ -1582,8 +1583,8 @@ fn resMSendRc(
|
|||||||
const timeout = 1000 * rc.timeout;
|
const timeout = 1000 * rc.timeout;
|
||||||
const attempts = rc.attempts;
|
const attempts = rc.attempts;
|
||||||
|
|
||||||
var sl: os.socklen_t = @sizeOf(os.sockaddr.in);
|
var sl: posix.socklen_t = @sizeOf(posix.sockaddr.in);
|
||||||
var family: os.sa_family_t = os.AF.INET;
|
var family: posix.sa_family_t = posix.AF.INET;
|
||||||
|
|
||||||
var ns_list = std.ArrayList(Address).init(rc.ns.allocator);
|
var ns_list = std.ArrayList(Address).init(rc.ns.allocator);
|
||||||
defer ns_list.deinit();
|
defer ns_list.deinit();
|
||||||
@ -1594,18 +1595,18 @@ fn resMSendRc(
|
|||||||
for (rc.ns.items, 0..) |iplit, i| {
|
for (rc.ns.items, 0..) |iplit, i| {
|
||||||
ns[i] = iplit.addr;
|
ns[i] = iplit.addr;
|
||||||
assert(ns[i].getPort() == 53);
|
assert(ns[i].getPort() == 53);
|
||||||
if (iplit.addr.any.family != os.AF.INET) {
|
if (iplit.addr.any.family != posix.AF.INET) {
|
||||||
family = os.AF.INET6;
|
family = posix.AF.INET6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const flags = os.SOCK.DGRAM | os.SOCK.CLOEXEC | os.SOCK.NONBLOCK;
|
const flags = posix.SOCK.DGRAM | posix.SOCK.CLOEXEC | posix.SOCK.NONBLOCK;
|
||||||
const fd = os.socket(family, flags, 0) catch |err| switch (err) {
|
const fd = posix.socket(family, flags, 0) catch |err| switch (err) {
|
||||||
error.AddressFamilyNotSupported => blk: {
|
error.AddressFamilyNotSupported => blk: {
|
||||||
// Handle case where system lacks IPv6 support
|
// Handle case where system lacks IPv6 support
|
||||||
if (family == os.AF.INET6) {
|
if (family == posix.AF.INET6) {
|
||||||
family = os.AF.INET;
|
family = posix.AF.INET;
|
||||||
break :blk try os.socket(os.AF.INET, flags, 0);
|
break :blk try posix.socket(posix.AF.INET, flags, 0);
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
},
|
},
|
||||||
@ -1618,33 +1619,33 @@ fn resMSendRc(
|
|||||||
// packet which is up to the caller to interpret.
|
// packet which is up to the caller to interpret.
|
||||||
|
|
||||||
// Convert any IPv4 addresses in a mixed environment to v4-mapped
|
// Convert any IPv4 addresses in a mixed environment to v4-mapped
|
||||||
if (family == os.AF.INET6) {
|
if (family == posix.AF.INET6) {
|
||||||
try os.setsockopt(
|
try posix.setsockopt(
|
||||||
fd,
|
fd,
|
||||||
os.SOL.IPV6,
|
posix.SOL.IPV6,
|
||||||
os.linux.IPV6.V6ONLY,
|
std.os.linux.IPV6.V6ONLY,
|
||||||
&mem.toBytes(@as(c_int, 0)),
|
&mem.toBytes(@as(c_int, 0)),
|
||||||
);
|
);
|
||||||
for (0..ns.len) |i| {
|
for (0..ns.len) |i| {
|
||||||
if (ns[i].any.family != os.AF.INET) continue;
|
if (ns[i].any.family != posix.AF.INET) continue;
|
||||||
mem.writeInt(u32, ns[i].in6.sa.addr[12..], ns[i].in.sa.addr, native_endian);
|
mem.writeInt(u32, ns[i].in6.sa.addr[12..], ns[i].in.sa.addr, native_endian);
|
||||||
ns[i].in6.sa.addr[0..12].* = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff".*;
|
ns[i].in6.sa.addr[0..12].* = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff".*;
|
||||||
ns[i].any.family = os.AF.INET6;
|
ns[i].any.family = posix.AF.INET6;
|
||||||
ns[i].in6.sa.flowinfo = 0;
|
ns[i].in6.sa.flowinfo = 0;
|
||||||
ns[i].in6.sa.scope_id = 0;
|
ns[i].in6.sa.scope_id = 0;
|
||||||
}
|
}
|
||||||
sl = @sizeOf(os.sockaddr.in6);
|
sl = @sizeOf(posix.sockaddr.in6);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get local address and open/bind a socket
|
// Get local address and open/bind a socket
|
||||||
var sa: Address = undefined;
|
var sa: Address = undefined;
|
||||||
@memset(@as([*]u8, @ptrCast(&sa))[0..@sizeOf(Address)], 0);
|
@memset(@as([*]u8, @ptrCast(&sa))[0..@sizeOf(Address)], 0);
|
||||||
sa.any.family = family;
|
sa.any.family = family;
|
||||||
try os.bind(fd, &sa.any, sl);
|
try posix.bind(fd, &sa.any, sl);
|
||||||
|
|
||||||
var pfd = [1]os.pollfd{os.pollfd{
|
var pfd = [1]posix.pollfd{posix.pollfd{
|
||||||
.fd = fd,
|
.fd = fd,
|
||||||
.events = os.POLL.IN,
|
.events = posix.POLL.IN,
|
||||||
.revents = undefined,
|
.revents = undefined,
|
||||||
}};
|
}};
|
||||||
const retry_interval = timeout / attempts;
|
const retry_interval = timeout / attempts;
|
||||||
@ -1663,7 +1664,7 @@ fn resMSendRc(
|
|||||||
if (answers[i].len == 0) {
|
if (answers[i].len == 0) {
|
||||||
var j: usize = 0;
|
var j: usize = 0;
|
||||||
while (j < ns.len) : (j += 1) {
|
while (j < ns.len) : (j += 1) {
|
||||||
_ = os.sendto(fd, queries[i], os.MSG.NOSIGNAL, &ns[j].any, sl) catch undefined;
|
_ = posix.sendto(fd, queries[i], posix.MSG.NOSIGNAL, &ns[j].any, sl) catch undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1673,12 +1674,12 @@ fn resMSendRc(
|
|||||||
|
|
||||||
// Wait for a response, or until time to retry
|
// Wait for a response, or until time to retry
|
||||||
const clamped_timeout = @min(@as(u31, std.math.maxInt(u31)), t1 + retry_interval - t2);
|
const clamped_timeout = @min(@as(u31, std.math.maxInt(u31)), t1 + retry_interval - t2);
|
||||||
const nevents = os.poll(&pfd, clamped_timeout) catch 0;
|
const nevents = posix.poll(&pfd, clamped_timeout) catch 0;
|
||||||
if (nevents == 0) continue;
|
if (nevents == 0) continue;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
var sl_copy = sl;
|
var sl_copy = sl;
|
||||||
const rlen = os.recvfrom(fd, answer_bufs[next], 0, &sa.any, &sl_copy) catch break;
|
const rlen = posix.recvfrom(fd, answer_bufs[next], 0, &sa.any, &sl_copy) catch break;
|
||||||
|
|
||||||
// Ignore non-identifiable packets
|
// Ignore non-identifiable packets
|
||||||
if (rlen < 4) continue;
|
if (rlen < 4) continue;
|
||||||
@ -1704,7 +1705,7 @@ fn resMSendRc(
|
|||||||
0, 3 => {},
|
0, 3 => {},
|
||||||
2 => if (servfail_retry != 0) {
|
2 => if (servfail_retry != 0) {
|
||||||
servfail_retry -= 1;
|
servfail_retry -= 1;
|
||||||
_ = os.sendto(fd, queries[i], os.MSG.NOSIGNAL, &ns[j].any, sl) catch undefined;
|
_ = posix.sendto(fd, queries[i], posix.MSG.NOSIGNAL, &ns[j].any, sl) catch undefined;
|
||||||
},
|
},
|
||||||
else => continue,
|
else => continue,
|
||||||
}
|
}
|
||||||
@ -1758,24 +1759,24 @@ fn dnsParse(
|
|||||||
|
|
||||||
fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8) !void {
|
fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8) !void {
|
||||||
switch (rr) {
|
switch (rr) {
|
||||||
os.RR.A => {
|
posix.RR.A => {
|
||||||
if (data.len != 4) return error.InvalidDnsARecord;
|
if (data.len != 4) return error.InvalidDnsARecord;
|
||||||
const new_addr = try ctx.addrs.addOne();
|
const new_addr = try ctx.addrs.addOne();
|
||||||
new_addr.* = LookupAddr{
|
new_addr.* = LookupAddr{
|
||||||
.addr = Address.initIp4(data[0..4].*, ctx.port),
|
.addr = Address.initIp4(data[0..4].*, ctx.port),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
os.RR.AAAA => {
|
posix.RR.AAAA => {
|
||||||
if (data.len != 16) return error.InvalidDnsAAAARecord;
|
if (data.len != 16) return error.InvalidDnsAAAARecord;
|
||||||
const new_addr = try ctx.addrs.addOne();
|
const new_addr = try ctx.addrs.addOne();
|
||||||
new_addr.* = LookupAddr{
|
new_addr.* = LookupAddr{
|
||||||
.addr = Address.initIp6(data[0..16].*, ctx.port, 0, 0),
|
.addr = Address.initIp6(data[0..16].*, ctx.port, 0, 0),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
os.RR.CNAME => {
|
posix.RR.CNAME => {
|
||||||
var tmp: [256]u8 = undefined;
|
var tmp: [256]u8 = undefined;
|
||||||
// Returns len of compressed name. strlen to get canon name.
|
// Returns len of compressed name. strlen to get canon name.
|
||||||
_ = try os.dn_expand(packet, data, &tmp);
|
_ = try posix.dn_expand(packet, data, &tmp);
|
||||||
const canon_name = mem.sliceTo(&tmp, 0);
|
const canon_name = mem.sliceTo(&tmp, 0);
|
||||||
if (isValidHostName(canon_name)) {
|
if (isValidHostName(canon_name)) {
|
||||||
ctx.canon.items.len = 0;
|
ctx.canon.items.len = 0;
|
||||||
@ -1792,14 +1793,14 @@ pub const Stream = struct {
|
|||||||
handle: posix.socket_t,
|
handle: posix.socket_t,
|
||||||
|
|
||||||
pub fn close(s: Stream) void {
|
pub fn close(s: Stream) void {
|
||||||
switch (builtin.os.tag) {
|
switch (native_os) {
|
||||||
.windows => std.os.windows.closesocket(s.handle) catch unreachable,
|
.windows => windows.closesocket(s.handle) catch unreachable,
|
||||||
else => posix.close(s.handle),
|
else => posix.close(s.handle),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ReadError = os.ReadError;
|
pub const ReadError = posix.ReadError;
|
||||||
pub const WriteError = os.WriteError;
|
pub const WriteError = posix.WriteError;
|
||||||
|
|
||||||
pub const Reader = io.Reader(Stream, ReadError, read);
|
pub const Reader = io.Reader(Stream, ReadError, read);
|
||||||
pub const Writer = io.Writer(Stream, WriteError, write);
|
pub const Writer = io.Writer(Stream, WriteError, write);
|
||||||
@ -1813,22 +1814,22 @@ pub const Stream = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(self: Stream, buffer: []u8) ReadError!usize {
|
pub fn read(self: Stream, buffer: []u8) ReadError!usize {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
return os.windows.ReadFile(self.handle, buffer, null);
|
return windows.ReadFile(self.handle, buffer, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return os.read(self.handle, buffer);
|
return posix.read(self.handle, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn readv(s: Stream, iovecs: []const os.iovec) ReadError!usize {
|
pub fn readv(s: Stream, iovecs: []const posix.iovec) ReadError!usize {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
// TODO improve this to use ReadFileScatter
|
// TODO improve this to use ReadFileScatter
|
||||||
if (iovecs.len == 0) return @as(usize, 0);
|
if (iovecs.len == 0) return @as(usize, 0);
|
||||||
const first = iovecs[0];
|
const first = iovecs[0];
|
||||||
return os.windows.ReadFile(s.handle, first.iov_base[0..first.iov_len], null);
|
return windows.ReadFile(s.handle, first.iov_base[0..first.iov_len], null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return os.readv(s.handle, iovecs);
|
return posix.readv(s.handle, iovecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of bytes read. If the number read is smaller than
|
/// Returns the number of bytes read. If the number read is smaller than
|
||||||
@ -1858,11 +1859,11 @@ pub const Stream = struct {
|
|||||||
/// file system thread instead of non-blocking. It needs to be reworked to properly
|
/// file system thread instead of non-blocking. It needs to be reworked to properly
|
||||||
/// use non-blocking I/O.
|
/// use non-blocking I/O.
|
||||||
pub fn write(self: Stream, buffer: []const u8) WriteError!usize {
|
pub fn write(self: Stream, buffer: []const u8) WriteError!usize {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
return os.windows.WriteFile(self.handle, buffer, null);
|
return windows.WriteFile(self.handle, buffer, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return os.write(self.handle, buffer);
|
return posix.write(self.handle, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeAll(self: Stream, bytes: []const u8) WriteError!void {
|
pub fn writeAll(self: Stream, bytes: []const u8) WriteError!void {
|
||||||
@ -1874,15 +1875,15 @@ pub const Stream = struct {
|
|||||||
|
|
||||||
/// See https://github.com/ziglang/zig/issues/7699
|
/// See https://github.com/ziglang/zig/issues/7699
|
||||||
/// See equivalent function: `std.fs.File.writev`.
|
/// See equivalent function: `std.fs.File.writev`.
|
||||||
pub fn writev(self: Stream, iovecs: []const os.iovec_const) WriteError!usize {
|
pub fn writev(self: Stream, iovecs: []const posix.iovec_const) WriteError!usize {
|
||||||
return os.writev(self.handle, iovecs);
|
return posix.writev(self.handle, iovecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The `iovecs` parameter is mutable because this function needs to mutate the fields in
|
/// The `iovecs` parameter is mutable because this function needs to mutate the fields in
|
||||||
/// order to handle partial writes from the underlying OS layer.
|
/// order to handle partial writes from the underlying OS layer.
|
||||||
/// See https://github.com/ziglang/zig/issues/7699
|
/// See https://github.com/ziglang/zig/issues/7699
|
||||||
/// See equivalent function: `std.fs.File.writevAll`.
|
/// See equivalent function: `std.fs.File.writevAll`.
|
||||||
pub fn writevAll(self: Stream, iovecs: []os.iovec_const) WriteError!void {
|
pub fn writevAll(self: Stream, iovecs: []posix.iovec_const) WriteError!void {
|
||||||
if (iovecs.len == 0) return;
|
if (iovecs.len == 0) return;
|
||||||
|
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
|
|||||||
7506
lib/std/os.zig
7506
lib/std/os.zig
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const wasi = std.os.wasi;
|
const wasi = std.os.wasi;
|
||||||
const iovec = std.os.iovec;
|
const iovec = std.posix.iovec;
|
||||||
const iovec_const = std.os.iovec_const;
|
const iovec_const = std.posix.iovec_const;
|
||||||
const c = std.c;
|
const c = std.c;
|
||||||
|
|
||||||
pub const FILE = c.FILE;
|
pub const FILE = c.FILE;
|
||||||
|
|||||||
@ -18,9 +18,9 @@ const is_mips = native_arch.isMIPS();
|
|||||||
const is_ppc = native_arch.isPPC();
|
const is_ppc = native_arch.isPPC();
|
||||||
const is_ppc64 = native_arch.isPPC64();
|
const is_ppc64 = native_arch.isPPC64();
|
||||||
const is_sparc = native_arch.isSPARC();
|
const is_sparc = native_arch.isSPARC();
|
||||||
const iovec = std.os.iovec;
|
const iovec = std.posix.iovec;
|
||||||
const iovec_const = std.os.iovec_const;
|
const iovec_const = std.posix.iovec_const;
|
||||||
const ACCMODE = std.os.ACCMODE;
|
const ACCMODE = std.posix.ACCMODE;
|
||||||
|
|
||||||
test {
|
test {
|
||||||
if (builtin.os.tag == .linux) {
|
if (builtin.os.tag == .linux) {
|
||||||
@ -451,10 +451,11 @@ fn splitValue64(val: i64) [2]u32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the errno from a syscall return value, or 0 for no error.
|
/// Get the errno from a syscall return value, or 0 for no error.
|
||||||
pub fn getErrno(r: usize) E {
|
/// The public API is exposed via the `E` namespace.
|
||||||
const signed_r = @as(isize, @bitCast(r));
|
fn errnoFromSyscall(r: usize) E {
|
||||||
|
const signed_r: isize = @bitCast(r);
|
||||||
const int = if (signed_r > -4096 and signed_r < 0) -signed_r else 0;
|
const int = if (signed_r > -4096 and signed_r < 0) -signed_r else 0;
|
||||||
return @as(E, @enumFromInt(int));
|
return @enumFromInt(int);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dup(old: i32) usize {
|
pub fn dup(old: i32) usize {
|
||||||
@ -1561,7 +1562,7 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact
|
|||||||
.sparc, .sparc64 => syscall5(.rt_sigaction, sig, ksa_arg, oldksa_arg, @intFromPtr(ksa.restorer), mask_size),
|
.sparc, .sparc64 => syscall5(.rt_sigaction, sig, ksa_arg, oldksa_arg, @intFromPtr(ksa.restorer), mask_size),
|
||||||
else => syscall4(.rt_sigaction, sig, ksa_arg, oldksa_arg, mask_size),
|
else => syscall4(.rt_sigaction, sig, ksa_arg, oldksa_arg, mask_size),
|
||||||
};
|
};
|
||||||
if (getErrno(result) != .SUCCESS) return result;
|
if (E.init(result) != .SUCCESS) return result;
|
||||||
|
|
||||||
if (oact) |old| {
|
if (oact) |old| {
|
||||||
old.handler.handler = oldksa.handler;
|
old.handler.handler = oldksa.handler;
|
||||||
@ -1648,12 +1649,12 @@ pub fn sendmmsg(fd: i32, msgvec: [*]mmsghdr_const, vlen: u32, flags: u32) usize
|
|||||||
if (next_unsent < i) {
|
if (next_unsent < i) {
|
||||||
const batch_size = i - next_unsent;
|
const batch_size = i - next_unsent;
|
||||||
const r = syscall4(.sendmmsg, @as(usize, @bitCast(@as(isize, fd))), @intFromPtr(&msgvec[next_unsent]), batch_size, flags);
|
const r = syscall4(.sendmmsg, @as(usize, @bitCast(@as(isize, fd))), @intFromPtr(&msgvec[next_unsent]), batch_size, flags);
|
||||||
if (getErrno(r) != 0) return next_unsent;
|
if (E.init(r) != 0) return next_unsent;
|
||||||
if (r < batch_size) return next_unsent + r;
|
if (r < batch_size) return next_unsent + r;
|
||||||
}
|
}
|
||||||
// send current message as own packet
|
// send current message as own packet
|
||||||
const r = sendmsg(fd, &msg.msg_hdr, flags);
|
const r = sendmsg(fd, &msg.msg_hdr, flags);
|
||||||
if (getErrno(r) != 0) return r;
|
if (E.init(r) != 0) return r;
|
||||||
// Linux limits the total bytes sent by sendmsg to INT_MAX, so this cast is safe.
|
// Linux limits the total bytes sent by sendmsg to INT_MAX, so this cast is safe.
|
||||||
msg.msg_len = @as(u32, @intCast(r));
|
msg.msg_len = @as(u32, @intCast(r));
|
||||||
next_unsent = i + 1;
|
next_unsent = i + 1;
|
||||||
@ -1665,7 +1666,7 @@ pub fn sendmmsg(fd: i32, msgvec: [*]mmsghdr_const, vlen: u32, flags: u32) usize
|
|||||||
if (next_unsent < kvlen or next_unsent == 0) { // want to make sure at least one syscall occurs (e.g. to trigger MSG.EOR)
|
if (next_unsent < kvlen or next_unsent == 0) { // want to make sure at least one syscall occurs (e.g. to trigger MSG.EOR)
|
||||||
const batch_size = kvlen - next_unsent;
|
const batch_size = kvlen - next_unsent;
|
||||||
const r = syscall4(.sendmmsg, @as(usize, @bitCast(@as(isize, fd))), @intFromPtr(&msgvec[next_unsent]), batch_size, flags);
|
const r = syscall4(.sendmmsg, @as(usize, @bitCast(@as(isize, fd))), @intFromPtr(&msgvec[next_unsent]), batch_size, flags);
|
||||||
if (getErrno(r) != 0) return r;
|
if (E.init(r) != 0) return r;
|
||||||
return next_unsent + r;
|
return next_unsent + r;
|
||||||
}
|
}
|
||||||
return kvlen;
|
return kvlen;
|
||||||
@ -2263,13 +2264,609 @@ pub fn map_shadow_stack(addr: u64, size: u64, flags: u32) usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub const E = switch (native_arch) {
|
pub const E = switch (native_arch) {
|
||||||
.mips, .mipsel => @import("linux/errno/mips.zig").E,
|
.mips, .mipsel => enum(i32) {
|
||||||
.sparc, .sparcel, .sparc64 => @import("linux/errno/sparc.zig").E,
|
/// No error occurred.
|
||||||
else => @import("linux/errno/generic.zig").E,
|
SUCCESS = 0,
|
||||||
|
|
||||||
|
PERM = 1,
|
||||||
|
NOENT = 2,
|
||||||
|
SRCH = 3,
|
||||||
|
INTR = 4,
|
||||||
|
IO = 5,
|
||||||
|
NXIO = 6,
|
||||||
|
@"2BIG" = 7,
|
||||||
|
NOEXEC = 8,
|
||||||
|
BADF = 9,
|
||||||
|
CHILD = 10,
|
||||||
|
/// Also used for WOULDBLOCK.
|
||||||
|
AGAIN = 11,
|
||||||
|
NOMEM = 12,
|
||||||
|
ACCES = 13,
|
||||||
|
FAULT = 14,
|
||||||
|
NOTBLK = 15,
|
||||||
|
BUSY = 16,
|
||||||
|
EXIST = 17,
|
||||||
|
XDEV = 18,
|
||||||
|
NODEV = 19,
|
||||||
|
NOTDIR = 20,
|
||||||
|
ISDIR = 21,
|
||||||
|
INVAL = 22,
|
||||||
|
NFILE = 23,
|
||||||
|
MFILE = 24,
|
||||||
|
NOTTY = 25,
|
||||||
|
TXTBSY = 26,
|
||||||
|
FBIG = 27,
|
||||||
|
NOSPC = 28,
|
||||||
|
SPIPE = 29,
|
||||||
|
ROFS = 30,
|
||||||
|
MLINK = 31,
|
||||||
|
PIPE = 32,
|
||||||
|
DOM = 33,
|
||||||
|
RANGE = 34,
|
||||||
|
|
||||||
|
NOMSG = 35,
|
||||||
|
IDRM = 36,
|
||||||
|
CHRNG = 37,
|
||||||
|
L2NSYNC = 38,
|
||||||
|
L3HLT = 39,
|
||||||
|
L3RST = 40,
|
||||||
|
LNRNG = 41,
|
||||||
|
UNATCH = 42,
|
||||||
|
NOCSI = 43,
|
||||||
|
L2HLT = 44,
|
||||||
|
DEADLK = 45,
|
||||||
|
NOLCK = 46,
|
||||||
|
BADE = 50,
|
||||||
|
BADR = 51,
|
||||||
|
XFULL = 52,
|
||||||
|
NOANO = 53,
|
||||||
|
BADRQC = 54,
|
||||||
|
BADSLT = 55,
|
||||||
|
DEADLOCK = 56,
|
||||||
|
BFONT = 59,
|
||||||
|
NOSTR = 60,
|
||||||
|
NODATA = 61,
|
||||||
|
TIME = 62,
|
||||||
|
NOSR = 63,
|
||||||
|
NONET = 64,
|
||||||
|
NOPKG = 65,
|
||||||
|
REMOTE = 66,
|
||||||
|
NOLINK = 67,
|
||||||
|
ADV = 68,
|
||||||
|
SRMNT = 69,
|
||||||
|
COMM = 70,
|
||||||
|
PROTO = 71,
|
||||||
|
DOTDOT = 73,
|
||||||
|
MULTIHOP = 74,
|
||||||
|
BADMSG = 77,
|
||||||
|
NAMETOOLONG = 78,
|
||||||
|
OVERFLOW = 79,
|
||||||
|
NOTUNIQ = 80,
|
||||||
|
BADFD = 81,
|
||||||
|
REMCHG = 82,
|
||||||
|
LIBACC = 83,
|
||||||
|
LIBBAD = 84,
|
||||||
|
LIBSCN = 85,
|
||||||
|
LIBMAX = 86,
|
||||||
|
LIBEXEC = 87,
|
||||||
|
ILSEQ = 88,
|
||||||
|
NOSYS = 89,
|
||||||
|
LOOP = 90,
|
||||||
|
RESTART = 91,
|
||||||
|
STRPIPE = 92,
|
||||||
|
NOTEMPTY = 93,
|
||||||
|
USERS = 94,
|
||||||
|
NOTSOCK = 95,
|
||||||
|
DESTADDRREQ = 96,
|
||||||
|
MSGSIZE = 97,
|
||||||
|
PROTOTYPE = 98,
|
||||||
|
NOPROTOOPT = 99,
|
||||||
|
PROTONOSUPPORT = 120,
|
||||||
|
SOCKTNOSUPPORT = 121,
|
||||||
|
OPNOTSUPP = 122,
|
||||||
|
PFNOSUPPORT = 123,
|
||||||
|
AFNOSUPPORT = 124,
|
||||||
|
ADDRINUSE = 125,
|
||||||
|
ADDRNOTAVAIL = 126,
|
||||||
|
NETDOWN = 127,
|
||||||
|
NETUNREACH = 128,
|
||||||
|
NETRESET = 129,
|
||||||
|
CONNABORTED = 130,
|
||||||
|
CONNRESET = 131,
|
||||||
|
NOBUFS = 132,
|
||||||
|
ISCONN = 133,
|
||||||
|
NOTCONN = 134,
|
||||||
|
UCLEAN = 135,
|
||||||
|
NOTNAM = 137,
|
||||||
|
NAVAIL = 138,
|
||||||
|
ISNAM = 139,
|
||||||
|
REMOTEIO = 140,
|
||||||
|
SHUTDOWN = 143,
|
||||||
|
TOOMANYREFS = 144,
|
||||||
|
TIMEDOUT = 145,
|
||||||
|
CONNREFUSED = 146,
|
||||||
|
HOSTDOWN = 147,
|
||||||
|
HOSTUNREACH = 148,
|
||||||
|
ALREADY = 149,
|
||||||
|
INPROGRESS = 150,
|
||||||
|
STALE = 151,
|
||||||
|
CANCELED = 158,
|
||||||
|
NOMEDIUM = 159,
|
||||||
|
MEDIUMTYPE = 160,
|
||||||
|
NOKEY = 161,
|
||||||
|
KEYEXPIRED = 162,
|
||||||
|
KEYREVOKED = 163,
|
||||||
|
KEYREJECTED = 164,
|
||||||
|
OWNERDEAD = 165,
|
||||||
|
NOTRECOVERABLE = 166,
|
||||||
|
RFKILL = 167,
|
||||||
|
HWPOISON = 168,
|
||||||
|
DQUOT = 1133,
|
||||||
|
_,
|
||||||
|
|
||||||
|
pub const init = errnoFromSyscall;
|
||||||
|
},
|
||||||
|
.sparc, .sparcel, .sparc64 => enum(i32) {
|
||||||
|
/// No error occurred.
|
||||||
|
SUCCESS = 0,
|
||||||
|
|
||||||
|
PERM = 1,
|
||||||
|
NOENT = 2,
|
||||||
|
SRCH = 3,
|
||||||
|
INTR = 4,
|
||||||
|
IO = 5,
|
||||||
|
NXIO = 6,
|
||||||
|
@"2BIG" = 7,
|
||||||
|
NOEXEC = 8,
|
||||||
|
BADF = 9,
|
||||||
|
CHILD = 10,
|
||||||
|
/// Also used for WOULDBLOCK
|
||||||
|
AGAIN = 11,
|
||||||
|
NOMEM = 12,
|
||||||
|
ACCES = 13,
|
||||||
|
FAULT = 14,
|
||||||
|
NOTBLK = 15,
|
||||||
|
BUSY = 16,
|
||||||
|
EXIST = 17,
|
||||||
|
XDEV = 18,
|
||||||
|
NODEV = 19,
|
||||||
|
NOTDIR = 20,
|
||||||
|
ISDIR = 21,
|
||||||
|
INVAL = 22,
|
||||||
|
NFILE = 23,
|
||||||
|
MFILE = 24,
|
||||||
|
NOTTY = 25,
|
||||||
|
TXTBSY = 26,
|
||||||
|
FBIG = 27,
|
||||||
|
NOSPC = 28,
|
||||||
|
SPIPE = 29,
|
||||||
|
ROFS = 30,
|
||||||
|
MLINK = 31,
|
||||||
|
PIPE = 32,
|
||||||
|
DOM = 33,
|
||||||
|
RANGE = 34,
|
||||||
|
|
||||||
|
INPROGRESS = 36,
|
||||||
|
ALREADY = 37,
|
||||||
|
NOTSOCK = 38,
|
||||||
|
DESTADDRREQ = 39,
|
||||||
|
MSGSIZE = 40,
|
||||||
|
PROTOTYPE = 41,
|
||||||
|
NOPROTOOPT = 42,
|
||||||
|
PROTONOSUPPORT = 43,
|
||||||
|
SOCKTNOSUPPORT = 44,
|
||||||
|
/// Also used for NOTSUP
|
||||||
|
OPNOTSUPP = 45,
|
||||||
|
PFNOSUPPORT = 46,
|
||||||
|
AFNOSUPPORT = 47,
|
||||||
|
ADDRINUSE = 48,
|
||||||
|
ADDRNOTAVAIL = 49,
|
||||||
|
NETDOWN = 50,
|
||||||
|
NETUNREACH = 51,
|
||||||
|
NETRESET = 52,
|
||||||
|
CONNABORTED = 53,
|
||||||
|
CONNRESET = 54,
|
||||||
|
NOBUFS = 55,
|
||||||
|
ISCONN = 56,
|
||||||
|
NOTCONN = 57,
|
||||||
|
SHUTDOWN = 58,
|
||||||
|
TOOMANYREFS = 59,
|
||||||
|
TIMEDOUT = 60,
|
||||||
|
CONNREFUSED = 61,
|
||||||
|
LOOP = 62,
|
||||||
|
NAMETOOLONG = 63,
|
||||||
|
HOSTDOWN = 64,
|
||||||
|
HOSTUNREACH = 65,
|
||||||
|
NOTEMPTY = 66,
|
||||||
|
PROCLIM = 67,
|
||||||
|
USERS = 68,
|
||||||
|
DQUOT = 69,
|
||||||
|
STALE = 70,
|
||||||
|
REMOTE = 71,
|
||||||
|
NOSTR = 72,
|
||||||
|
TIME = 73,
|
||||||
|
NOSR = 74,
|
||||||
|
NOMSG = 75,
|
||||||
|
BADMSG = 76,
|
||||||
|
IDRM = 77,
|
||||||
|
DEADLK = 78,
|
||||||
|
NOLCK = 79,
|
||||||
|
NONET = 80,
|
||||||
|
RREMOTE = 81,
|
||||||
|
NOLINK = 82,
|
||||||
|
ADV = 83,
|
||||||
|
SRMNT = 84,
|
||||||
|
COMM = 85,
|
||||||
|
PROTO = 86,
|
||||||
|
MULTIHOP = 87,
|
||||||
|
DOTDOT = 88,
|
||||||
|
REMCHG = 89,
|
||||||
|
NOSYS = 90,
|
||||||
|
STRPIPE = 91,
|
||||||
|
OVERFLOW = 92,
|
||||||
|
BADFD = 93,
|
||||||
|
CHRNG = 94,
|
||||||
|
L2NSYNC = 95,
|
||||||
|
L3HLT = 96,
|
||||||
|
L3RST = 97,
|
||||||
|
LNRNG = 98,
|
||||||
|
UNATCH = 99,
|
||||||
|
NOCSI = 100,
|
||||||
|
L2HLT = 101,
|
||||||
|
BADE = 102,
|
||||||
|
BADR = 103,
|
||||||
|
XFULL = 104,
|
||||||
|
NOANO = 105,
|
||||||
|
BADRQC = 106,
|
||||||
|
BADSLT = 107,
|
||||||
|
DEADLOCK = 108,
|
||||||
|
BFONT = 109,
|
||||||
|
LIBEXEC = 110,
|
||||||
|
NODATA = 111,
|
||||||
|
LIBBAD = 112,
|
||||||
|
NOPKG = 113,
|
||||||
|
LIBACC = 114,
|
||||||
|
NOTUNIQ = 115,
|
||||||
|
RESTART = 116,
|
||||||
|
UCLEAN = 117,
|
||||||
|
NOTNAM = 118,
|
||||||
|
NAVAIL = 119,
|
||||||
|
ISNAM = 120,
|
||||||
|
REMOTEIO = 121,
|
||||||
|
ILSEQ = 122,
|
||||||
|
LIBMAX = 123,
|
||||||
|
LIBSCN = 124,
|
||||||
|
NOMEDIUM = 125,
|
||||||
|
MEDIUMTYPE = 126,
|
||||||
|
CANCELED = 127,
|
||||||
|
NOKEY = 128,
|
||||||
|
KEYEXPIRED = 129,
|
||||||
|
KEYREVOKED = 130,
|
||||||
|
KEYREJECTED = 131,
|
||||||
|
OWNERDEAD = 132,
|
||||||
|
NOTRECOVERABLE = 133,
|
||||||
|
RFKILL = 134,
|
||||||
|
HWPOISON = 135,
|
||||||
|
_,
|
||||||
|
|
||||||
|
pub const init = errnoFromSyscall;
|
||||||
|
},
|
||||||
|
else => enum(u16) {
|
||||||
|
/// No error occurred.
|
||||||
|
/// Same code used for `NSROK`.
|
||||||
|
SUCCESS = 0,
|
||||||
|
/// Operation not permitted
|
||||||
|
PERM = 1,
|
||||||
|
/// No such file or directory
|
||||||
|
NOENT = 2,
|
||||||
|
/// No such process
|
||||||
|
SRCH = 3,
|
||||||
|
/// Interrupted system call
|
||||||
|
INTR = 4,
|
||||||
|
/// I/O error
|
||||||
|
IO = 5,
|
||||||
|
/// No such device or address
|
||||||
|
NXIO = 6,
|
||||||
|
/// Arg list too long
|
||||||
|
@"2BIG" = 7,
|
||||||
|
/// Exec format error
|
||||||
|
NOEXEC = 8,
|
||||||
|
/// Bad file number
|
||||||
|
BADF = 9,
|
||||||
|
/// No child processes
|
||||||
|
CHILD = 10,
|
||||||
|
/// Try again
|
||||||
|
/// Also means: WOULDBLOCK: operation would block
|
||||||
|
AGAIN = 11,
|
||||||
|
/// Out of memory
|
||||||
|
NOMEM = 12,
|
||||||
|
/// Permission denied
|
||||||
|
ACCES = 13,
|
||||||
|
/// Bad address
|
||||||
|
FAULT = 14,
|
||||||
|
/// Block device required
|
||||||
|
NOTBLK = 15,
|
||||||
|
/// Device or resource busy
|
||||||
|
BUSY = 16,
|
||||||
|
/// File exists
|
||||||
|
EXIST = 17,
|
||||||
|
/// Cross-device link
|
||||||
|
XDEV = 18,
|
||||||
|
/// No such device
|
||||||
|
NODEV = 19,
|
||||||
|
/// Not a directory
|
||||||
|
NOTDIR = 20,
|
||||||
|
/// Is a directory
|
||||||
|
ISDIR = 21,
|
||||||
|
/// Invalid argument
|
||||||
|
INVAL = 22,
|
||||||
|
/// File table overflow
|
||||||
|
NFILE = 23,
|
||||||
|
/// Too many open files
|
||||||
|
MFILE = 24,
|
||||||
|
/// Not a typewriter
|
||||||
|
NOTTY = 25,
|
||||||
|
/// Text file busy
|
||||||
|
TXTBSY = 26,
|
||||||
|
/// File too large
|
||||||
|
FBIG = 27,
|
||||||
|
/// No space left on device
|
||||||
|
NOSPC = 28,
|
||||||
|
/// Illegal seek
|
||||||
|
SPIPE = 29,
|
||||||
|
/// Read-only file system
|
||||||
|
ROFS = 30,
|
||||||
|
/// Too many links
|
||||||
|
MLINK = 31,
|
||||||
|
/// Broken pipe
|
||||||
|
PIPE = 32,
|
||||||
|
/// Math argument out of domain of func
|
||||||
|
DOM = 33,
|
||||||
|
/// Math result not representable
|
||||||
|
RANGE = 34,
|
||||||
|
/// Resource deadlock would occur
|
||||||
|
DEADLK = 35,
|
||||||
|
/// File name too long
|
||||||
|
NAMETOOLONG = 36,
|
||||||
|
/// No record locks available
|
||||||
|
NOLCK = 37,
|
||||||
|
/// Function not implemented
|
||||||
|
NOSYS = 38,
|
||||||
|
/// Directory not empty
|
||||||
|
NOTEMPTY = 39,
|
||||||
|
/// Too many symbolic links encountered
|
||||||
|
LOOP = 40,
|
||||||
|
/// No message of desired type
|
||||||
|
NOMSG = 42,
|
||||||
|
/// Identifier removed
|
||||||
|
IDRM = 43,
|
||||||
|
/// Channel number out of range
|
||||||
|
CHRNG = 44,
|
||||||
|
/// Level 2 not synchronized
|
||||||
|
L2NSYNC = 45,
|
||||||
|
/// Level 3 halted
|
||||||
|
L3HLT = 46,
|
||||||
|
/// Level 3 reset
|
||||||
|
L3RST = 47,
|
||||||
|
/// Link number out of range
|
||||||
|
LNRNG = 48,
|
||||||
|
/// Protocol driver not attached
|
||||||
|
UNATCH = 49,
|
||||||
|
/// No CSI structure available
|
||||||
|
NOCSI = 50,
|
||||||
|
/// Level 2 halted
|
||||||
|
L2HLT = 51,
|
||||||
|
/// Invalid exchange
|
||||||
|
BADE = 52,
|
||||||
|
/// Invalid request descriptor
|
||||||
|
BADR = 53,
|
||||||
|
/// Exchange full
|
||||||
|
XFULL = 54,
|
||||||
|
/// No anode
|
||||||
|
NOANO = 55,
|
||||||
|
/// Invalid request code
|
||||||
|
BADRQC = 56,
|
||||||
|
/// Invalid slot
|
||||||
|
BADSLT = 57,
|
||||||
|
/// Bad font file format
|
||||||
|
BFONT = 59,
|
||||||
|
/// Device not a stream
|
||||||
|
NOSTR = 60,
|
||||||
|
/// No data available
|
||||||
|
NODATA = 61,
|
||||||
|
/// Timer expired
|
||||||
|
TIME = 62,
|
||||||
|
/// Out of streams resources
|
||||||
|
NOSR = 63,
|
||||||
|
/// Machine is not on the network
|
||||||
|
NONET = 64,
|
||||||
|
/// Package not installed
|
||||||
|
NOPKG = 65,
|
||||||
|
/// Object is remote
|
||||||
|
REMOTE = 66,
|
||||||
|
/// Link has been severed
|
||||||
|
NOLINK = 67,
|
||||||
|
/// Advertise error
|
||||||
|
ADV = 68,
|
||||||
|
/// Srmount error
|
||||||
|
SRMNT = 69,
|
||||||
|
/// Communication error on send
|
||||||
|
COMM = 70,
|
||||||
|
/// Protocol error
|
||||||
|
PROTO = 71,
|
||||||
|
/// Multihop attempted
|
||||||
|
MULTIHOP = 72,
|
||||||
|
/// RFS specific error
|
||||||
|
DOTDOT = 73,
|
||||||
|
/// Not a data message
|
||||||
|
BADMSG = 74,
|
||||||
|
/// Value too large for defined data type
|
||||||
|
OVERFLOW = 75,
|
||||||
|
/// Name not unique on network
|
||||||
|
NOTUNIQ = 76,
|
||||||
|
/// File descriptor in bad state
|
||||||
|
BADFD = 77,
|
||||||
|
/// Remote address changed
|
||||||
|
REMCHG = 78,
|
||||||
|
/// Can not access a needed shared library
|
||||||
|
LIBACC = 79,
|
||||||
|
/// Accessing a corrupted shared library
|
||||||
|
LIBBAD = 80,
|
||||||
|
/// .lib section in a.out corrupted
|
||||||
|
LIBSCN = 81,
|
||||||
|
/// Attempting to link in too many shared libraries
|
||||||
|
LIBMAX = 82,
|
||||||
|
/// Cannot exec a shared library directly
|
||||||
|
LIBEXEC = 83,
|
||||||
|
/// Illegal byte sequence
|
||||||
|
ILSEQ = 84,
|
||||||
|
/// Interrupted system call should be restarted
|
||||||
|
RESTART = 85,
|
||||||
|
/// Streams pipe error
|
||||||
|
STRPIPE = 86,
|
||||||
|
/// Too many users
|
||||||
|
USERS = 87,
|
||||||
|
/// Socket operation on non-socket
|
||||||
|
NOTSOCK = 88,
|
||||||
|
/// Destination address required
|
||||||
|
DESTADDRREQ = 89,
|
||||||
|
/// Message too long
|
||||||
|
MSGSIZE = 90,
|
||||||
|
/// Protocol wrong type for socket
|
||||||
|
PROTOTYPE = 91,
|
||||||
|
/// Protocol not available
|
||||||
|
NOPROTOOPT = 92,
|
||||||
|
/// Protocol not supported
|
||||||
|
PROTONOSUPPORT = 93,
|
||||||
|
/// Socket type not supported
|
||||||
|
SOCKTNOSUPPORT = 94,
|
||||||
|
/// Operation not supported on transport endpoint
|
||||||
|
/// This code also means `NOTSUP`.
|
||||||
|
OPNOTSUPP = 95,
|
||||||
|
/// Protocol family not supported
|
||||||
|
PFNOSUPPORT = 96,
|
||||||
|
/// Address family not supported by protocol
|
||||||
|
AFNOSUPPORT = 97,
|
||||||
|
/// Address already in use
|
||||||
|
ADDRINUSE = 98,
|
||||||
|
/// Cannot assign requested address
|
||||||
|
ADDRNOTAVAIL = 99,
|
||||||
|
/// Network is down
|
||||||
|
NETDOWN = 100,
|
||||||
|
/// Network is unreachable
|
||||||
|
NETUNREACH = 101,
|
||||||
|
/// Network dropped connection because of reset
|
||||||
|
NETRESET = 102,
|
||||||
|
/// Software caused connection abort
|
||||||
|
CONNABORTED = 103,
|
||||||
|
/// Connection reset by peer
|
||||||
|
CONNRESET = 104,
|
||||||
|
/// No buffer space available
|
||||||
|
NOBUFS = 105,
|
||||||
|
/// Transport endpoint is already connected
|
||||||
|
ISCONN = 106,
|
||||||
|
/// Transport endpoint is not connected
|
||||||
|
NOTCONN = 107,
|
||||||
|
/// Cannot send after transport endpoint shutdown
|
||||||
|
SHUTDOWN = 108,
|
||||||
|
/// Too many references: cannot splice
|
||||||
|
TOOMANYREFS = 109,
|
||||||
|
/// Connection timed out
|
||||||
|
TIMEDOUT = 110,
|
||||||
|
/// Connection refused
|
||||||
|
CONNREFUSED = 111,
|
||||||
|
/// Host is down
|
||||||
|
HOSTDOWN = 112,
|
||||||
|
/// No route to host
|
||||||
|
HOSTUNREACH = 113,
|
||||||
|
/// Operation already in progress
|
||||||
|
ALREADY = 114,
|
||||||
|
/// Operation now in progress
|
||||||
|
INPROGRESS = 115,
|
||||||
|
/// Stale NFS file handle
|
||||||
|
STALE = 116,
|
||||||
|
/// Structure needs cleaning
|
||||||
|
UCLEAN = 117,
|
||||||
|
/// Not a XENIX named type file
|
||||||
|
NOTNAM = 118,
|
||||||
|
/// No XENIX semaphores available
|
||||||
|
NAVAIL = 119,
|
||||||
|
/// Is a named type file
|
||||||
|
ISNAM = 120,
|
||||||
|
/// Remote I/O error
|
||||||
|
REMOTEIO = 121,
|
||||||
|
/// Quota exceeded
|
||||||
|
DQUOT = 122,
|
||||||
|
/// No medium found
|
||||||
|
NOMEDIUM = 123,
|
||||||
|
/// Wrong medium type
|
||||||
|
MEDIUMTYPE = 124,
|
||||||
|
/// Operation canceled
|
||||||
|
CANCELED = 125,
|
||||||
|
/// Required key not available
|
||||||
|
NOKEY = 126,
|
||||||
|
/// Key has expired
|
||||||
|
KEYEXPIRED = 127,
|
||||||
|
/// Key has been revoked
|
||||||
|
KEYREVOKED = 128,
|
||||||
|
/// Key was rejected by service
|
||||||
|
KEYREJECTED = 129,
|
||||||
|
// for robust mutexes
|
||||||
|
/// Owner died
|
||||||
|
OWNERDEAD = 130,
|
||||||
|
/// State not recoverable
|
||||||
|
NOTRECOVERABLE = 131,
|
||||||
|
/// Operation not possible due to RF-kill
|
||||||
|
RFKILL = 132,
|
||||||
|
/// Memory page has hardware error
|
||||||
|
HWPOISON = 133,
|
||||||
|
// nameserver query return codes
|
||||||
|
/// DNS server returned answer with no data
|
||||||
|
NSRNODATA = 160,
|
||||||
|
/// DNS server claims query was misformatted
|
||||||
|
NSRFORMERR = 161,
|
||||||
|
/// DNS server returned general failure
|
||||||
|
NSRSERVFAIL = 162,
|
||||||
|
/// Domain name not found
|
||||||
|
NSRNOTFOUND = 163,
|
||||||
|
/// DNS server does not implement requested operation
|
||||||
|
NSRNOTIMP = 164,
|
||||||
|
/// DNS server refused query
|
||||||
|
NSRREFUSED = 165,
|
||||||
|
/// Misformatted DNS query
|
||||||
|
NSRBADQUERY = 166,
|
||||||
|
/// Misformatted domain name
|
||||||
|
NSRBADNAME = 167,
|
||||||
|
/// Unsupported address family
|
||||||
|
NSRBADFAMILY = 168,
|
||||||
|
/// Misformatted DNS reply
|
||||||
|
NSRBADRESP = 169,
|
||||||
|
/// Could not contact DNS servers
|
||||||
|
NSRCONNREFUSED = 170,
|
||||||
|
/// Timeout while contacting DNS servers
|
||||||
|
NSRTIMEOUT = 171,
|
||||||
|
/// End of file
|
||||||
|
NSROF = 172,
|
||||||
|
/// Error reading file
|
||||||
|
NSRFILE = 173,
|
||||||
|
/// Out of memory
|
||||||
|
NSRNOMEM = 174,
|
||||||
|
/// Application terminated lookup
|
||||||
|
NSRDESTRUCTION = 175,
|
||||||
|
/// Domain name is too long
|
||||||
|
NSRQUERYDOMAINTOOLONG = 176,
|
||||||
|
/// Domain name is too long
|
||||||
|
NSRCNAMELOOP = 177,
|
||||||
|
|
||||||
|
_,
|
||||||
|
|
||||||
|
pub const init = errnoFromSyscall;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const pid_t = i32;
|
pub const pid_t = i32;
|
||||||
pub const fd_t = i32;
|
pub const fd_t = i32;
|
||||||
|
pub const socket_t = i32;
|
||||||
pub const uid_t = u32;
|
pub const uid_t = u32;
|
||||||
pub const gid_t = u32;
|
pub const gid_t = u32;
|
||||||
pub const clock_t = isize;
|
pub const clock_t = isize;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -2,8 +2,8 @@ const std = @import("../../std.zig");
|
|||||||
const maxInt = std.math.maxInt;
|
const maxInt = std.math.maxInt;
|
||||||
const linux = std.os.linux;
|
const linux = std.os.linux;
|
||||||
const SYS = linux.SYS;
|
const SYS = linux.SYS;
|
||||||
const iovec = std.os.iovec;
|
const iovec = std.posix.iovec;
|
||||||
const iovec_const = std.os.iovec_const;
|
const iovec_const = std.posix.iovec_const;
|
||||||
const socklen_t = linux.socklen_t;
|
const socklen_t = linux.socklen_t;
|
||||||
const stack_t = linux.stack_t;
|
const stack_t = linux.stack_t;
|
||||||
const sigset_t = linux.sigset_t;
|
const sigset_t = linux.sigset_t;
|
||||||
|
|||||||
@ -4,8 +4,8 @@ const linux = std.os.linux;
|
|||||||
const SYS = linux.SYS;
|
const SYS = linux.SYS;
|
||||||
const socklen_t = linux.socklen_t;
|
const socklen_t = linux.socklen_t;
|
||||||
const sockaddr = linux.sockaddr;
|
const sockaddr = linux.sockaddr;
|
||||||
const iovec = std.os.iovec;
|
const iovec = std.posix.iovec;
|
||||||
const iovec_const = std.os.iovec_const;
|
const iovec_const = std.posix.iovec_const;
|
||||||
const uid_t = linux.uid_t;
|
const uid_t = linux.uid_t;
|
||||||
const gid_t = linux.gid_t;
|
const gid_t = linux.gid_t;
|
||||||
const pid_t = linux.pid_t;
|
const pid_t = linux.pid_t;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
const std = @import("../../std.zig");
|
const std = @import("../../std.zig");
|
||||||
const errno = getErrno;
|
const errno = linux.E.init;
|
||||||
const unexpectedErrno = std.os.unexpectedErrno;
|
const unexpectedErrno = std.os.unexpectedErrno;
|
||||||
const expectEqual = std.testing.expectEqual;
|
const expectEqual = std.testing.expectEqual;
|
||||||
const expectError = std.testing.expectError;
|
const expectError = std.testing.expectError;
|
||||||
@ -8,7 +8,6 @@ const expect = std.testing.expect;
|
|||||||
const linux = std.os.linux;
|
const linux = std.os.linux;
|
||||||
const fd_t = linux.fd_t;
|
const fd_t = linux.fd_t;
|
||||||
const pid_t = linux.pid_t;
|
const pid_t = linux.pid_t;
|
||||||
const getErrno = linux.getErrno;
|
|
||||||
|
|
||||||
pub const btf = @import("bpf/btf.zig");
|
pub const btf = @import("bpf/btf.zig");
|
||||||
pub const kern = @import("bpf/kern.zig");
|
pub const kern = @import("bpf/kern.zig");
|
||||||
|
|||||||
@ -1,460 +0,0 @@
|
|||||||
pub const E = enum(u16) {
|
|
||||||
/// No error occurred.
|
|
||||||
/// Same code used for `NSROK`.
|
|
||||||
SUCCESS = 0,
|
|
||||||
|
|
||||||
/// Operation not permitted
|
|
||||||
PERM = 1,
|
|
||||||
|
|
||||||
/// No such file or directory
|
|
||||||
NOENT = 2,
|
|
||||||
|
|
||||||
/// No such process
|
|
||||||
SRCH = 3,
|
|
||||||
|
|
||||||
/// Interrupted system call
|
|
||||||
INTR = 4,
|
|
||||||
|
|
||||||
/// I/O error
|
|
||||||
IO = 5,
|
|
||||||
|
|
||||||
/// No such device or address
|
|
||||||
NXIO = 6,
|
|
||||||
|
|
||||||
/// Arg list too long
|
|
||||||
@"2BIG" = 7,
|
|
||||||
|
|
||||||
/// Exec format error
|
|
||||||
NOEXEC = 8,
|
|
||||||
|
|
||||||
/// Bad file number
|
|
||||||
BADF = 9,
|
|
||||||
|
|
||||||
/// No child processes
|
|
||||||
CHILD = 10,
|
|
||||||
|
|
||||||
/// Try again
|
|
||||||
/// Also means: WOULDBLOCK: operation would block
|
|
||||||
AGAIN = 11,
|
|
||||||
|
|
||||||
/// Out of memory
|
|
||||||
NOMEM = 12,
|
|
||||||
|
|
||||||
/// Permission denied
|
|
||||||
ACCES = 13,
|
|
||||||
|
|
||||||
/// Bad address
|
|
||||||
FAULT = 14,
|
|
||||||
|
|
||||||
/// Block device required
|
|
||||||
NOTBLK = 15,
|
|
||||||
|
|
||||||
/// Device or resource busy
|
|
||||||
BUSY = 16,
|
|
||||||
|
|
||||||
/// File exists
|
|
||||||
EXIST = 17,
|
|
||||||
|
|
||||||
/// Cross-device link
|
|
||||||
XDEV = 18,
|
|
||||||
|
|
||||||
/// No such device
|
|
||||||
NODEV = 19,
|
|
||||||
|
|
||||||
/// Not a directory
|
|
||||||
NOTDIR = 20,
|
|
||||||
|
|
||||||
/// Is a directory
|
|
||||||
ISDIR = 21,
|
|
||||||
|
|
||||||
/// Invalid argument
|
|
||||||
INVAL = 22,
|
|
||||||
|
|
||||||
/// File table overflow
|
|
||||||
NFILE = 23,
|
|
||||||
|
|
||||||
/// Too many open files
|
|
||||||
MFILE = 24,
|
|
||||||
|
|
||||||
/// Not a typewriter
|
|
||||||
NOTTY = 25,
|
|
||||||
|
|
||||||
/// Text file busy
|
|
||||||
TXTBSY = 26,
|
|
||||||
|
|
||||||
/// File too large
|
|
||||||
FBIG = 27,
|
|
||||||
|
|
||||||
/// No space left on device
|
|
||||||
NOSPC = 28,
|
|
||||||
|
|
||||||
/// Illegal seek
|
|
||||||
SPIPE = 29,
|
|
||||||
|
|
||||||
/// Read-only file system
|
|
||||||
ROFS = 30,
|
|
||||||
|
|
||||||
/// Too many links
|
|
||||||
MLINK = 31,
|
|
||||||
|
|
||||||
/// Broken pipe
|
|
||||||
PIPE = 32,
|
|
||||||
|
|
||||||
/// Math argument out of domain of func
|
|
||||||
DOM = 33,
|
|
||||||
|
|
||||||
/// Math result not representable
|
|
||||||
RANGE = 34,
|
|
||||||
|
|
||||||
/// Resource deadlock would occur
|
|
||||||
DEADLK = 35,
|
|
||||||
|
|
||||||
/// File name too long
|
|
||||||
NAMETOOLONG = 36,
|
|
||||||
|
|
||||||
/// No record locks available
|
|
||||||
NOLCK = 37,
|
|
||||||
|
|
||||||
/// Function not implemented
|
|
||||||
NOSYS = 38,
|
|
||||||
|
|
||||||
/// Directory not empty
|
|
||||||
NOTEMPTY = 39,
|
|
||||||
|
|
||||||
/// Too many symbolic links encountered
|
|
||||||
LOOP = 40,
|
|
||||||
|
|
||||||
/// No message of desired type
|
|
||||||
NOMSG = 42,
|
|
||||||
|
|
||||||
/// Identifier removed
|
|
||||||
IDRM = 43,
|
|
||||||
|
|
||||||
/// Channel number out of range
|
|
||||||
CHRNG = 44,
|
|
||||||
|
|
||||||
/// Level 2 not synchronized
|
|
||||||
L2NSYNC = 45,
|
|
||||||
|
|
||||||
/// Level 3 halted
|
|
||||||
L3HLT = 46,
|
|
||||||
|
|
||||||
/// Level 3 reset
|
|
||||||
L3RST = 47,
|
|
||||||
|
|
||||||
/// Link number out of range
|
|
||||||
LNRNG = 48,
|
|
||||||
|
|
||||||
/// Protocol driver not attached
|
|
||||||
UNATCH = 49,
|
|
||||||
|
|
||||||
/// No CSI structure available
|
|
||||||
NOCSI = 50,
|
|
||||||
|
|
||||||
/// Level 2 halted
|
|
||||||
L2HLT = 51,
|
|
||||||
|
|
||||||
/// Invalid exchange
|
|
||||||
BADE = 52,
|
|
||||||
|
|
||||||
/// Invalid request descriptor
|
|
||||||
BADR = 53,
|
|
||||||
|
|
||||||
/// Exchange full
|
|
||||||
XFULL = 54,
|
|
||||||
|
|
||||||
/// No anode
|
|
||||||
NOANO = 55,
|
|
||||||
|
|
||||||
/// Invalid request code
|
|
||||||
BADRQC = 56,
|
|
||||||
|
|
||||||
/// Invalid slot
|
|
||||||
BADSLT = 57,
|
|
||||||
|
|
||||||
/// Bad font file format
|
|
||||||
BFONT = 59,
|
|
||||||
|
|
||||||
/// Device not a stream
|
|
||||||
NOSTR = 60,
|
|
||||||
|
|
||||||
/// No data available
|
|
||||||
NODATA = 61,
|
|
||||||
|
|
||||||
/// Timer expired
|
|
||||||
TIME = 62,
|
|
||||||
|
|
||||||
/// Out of streams resources
|
|
||||||
NOSR = 63,
|
|
||||||
|
|
||||||
/// Machine is not on the network
|
|
||||||
NONET = 64,
|
|
||||||
|
|
||||||
/// Package not installed
|
|
||||||
NOPKG = 65,
|
|
||||||
|
|
||||||
/// Object is remote
|
|
||||||
REMOTE = 66,
|
|
||||||
|
|
||||||
/// Link has been severed
|
|
||||||
NOLINK = 67,
|
|
||||||
|
|
||||||
/// Advertise error
|
|
||||||
ADV = 68,
|
|
||||||
|
|
||||||
/// Srmount error
|
|
||||||
SRMNT = 69,
|
|
||||||
|
|
||||||
/// Communication error on send
|
|
||||||
COMM = 70,
|
|
||||||
|
|
||||||
/// Protocol error
|
|
||||||
PROTO = 71,
|
|
||||||
|
|
||||||
/// Multihop attempted
|
|
||||||
MULTIHOP = 72,
|
|
||||||
|
|
||||||
/// RFS specific error
|
|
||||||
DOTDOT = 73,
|
|
||||||
|
|
||||||
/// Not a data message
|
|
||||||
BADMSG = 74,
|
|
||||||
|
|
||||||
/// Value too large for defined data type
|
|
||||||
OVERFLOW = 75,
|
|
||||||
|
|
||||||
/// Name not unique on network
|
|
||||||
NOTUNIQ = 76,
|
|
||||||
|
|
||||||
/// File descriptor in bad state
|
|
||||||
BADFD = 77,
|
|
||||||
|
|
||||||
/// Remote address changed
|
|
||||||
REMCHG = 78,
|
|
||||||
|
|
||||||
/// Can not access a needed shared library
|
|
||||||
LIBACC = 79,
|
|
||||||
|
|
||||||
/// Accessing a corrupted shared library
|
|
||||||
LIBBAD = 80,
|
|
||||||
|
|
||||||
/// .lib section in a.out corrupted
|
|
||||||
LIBSCN = 81,
|
|
||||||
|
|
||||||
/// Attempting to link in too many shared libraries
|
|
||||||
LIBMAX = 82,
|
|
||||||
|
|
||||||
/// Cannot exec a shared library directly
|
|
||||||
LIBEXEC = 83,
|
|
||||||
|
|
||||||
/// Illegal byte sequence
|
|
||||||
ILSEQ = 84,
|
|
||||||
|
|
||||||
/// Interrupted system call should be restarted
|
|
||||||
RESTART = 85,
|
|
||||||
|
|
||||||
/// Streams pipe error
|
|
||||||
STRPIPE = 86,
|
|
||||||
|
|
||||||
/// Too many users
|
|
||||||
USERS = 87,
|
|
||||||
|
|
||||||
/// Socket operation on non-socket
|
|
||||||
NOTSOCK = 88,
|
|
||||||
|
|
||||||
/// Destination address required
|
|
||||||
DESTADDRREQ = 89,
|
|
||||||
|
|
||||||
/// Message too long
|
|
||||||
MSGSIZE = 90,
|
|
||||||
|
|
||||||
/// Protocol wrong type for socket
|
|
||||||
PROTOTYPE = 91,
|
|
||||||
|
|
||||||
/// Protocol not available
|
|
||||||
NOPROTOOPT = 92,
|
|
||||||
|
|
||||||
/// Protocol not supported
|
|
||||||
PROTONOSUPPORT = 93,
|
|
||||||
|
|
||||||
/// Socket type not supported
|
|
||||||
SOCKTNOSUPPORT = 94,
|
|
||||||
|
|
||||||
/// Operation not supported on transport endpoint
|
|
||||||
/// This code also means `NOTSUP`.
|
|
||||||
OPNOTSUPP = 95,
|
|
||||||
|
|
||||||
/// Protocol family not supported
|
|
||||||
PFNOSUPPORT = 96,
|
|
||||||
|
|
||||||
/// Address family not supported by protocol
|
|
||||||
AFNOSUPPORT = 97,
|
|
||||||
|
|
||||||
/// Address already in use
|
|
||||||
ADDRINUSE = 98,
|
|
||||||
|
|
||||||
/// Cannot assign requested address
|
|
||||||
ADDRNOTAVAIL = 99,
|
|
||||||
|
|
||||||
/// Network is down
|
|
||||||
NETDOWN = 100,
|
|
||||||
|
|
||||||
/// Network is unreachable
|
|
||||||
NETUNREACH = 101,
|
|
||||||
|
|
||||||
/// Network dropped connection because of reset
|
|
||||||
NETRESET = 102,
|
|
||||||
|
|
||||||
/// Software caused connection abort
|
|
||||||
CONNABORTED = 103,
|
|
||||||
|
|
||||||
/// Connection reset by peer
|
|
||||||
CONNRESET = 104,
|
|
||||||
|
|
||||||
/// No buffer space available
|
|
||||||
NOBUFS = 105,
|
|
||||||
|
|
||||||
/// Transport endpoint is already connected
|
|
||||||
ISCONN = 106,
|
|
||||||
|
|
||||||
/// Transport endpoint is not connected
|
|
||||||
NOTCONN = 107,
|
|
||||||
|
|
||||||
/// Cannot send after transport endpoint shutdown
|
|
||||||
SHUTDOWN = 108,
|
|
||||||
|
|
||||||
/// Too many references: cannot splice
|
|
||||||
TOOMANYREFS = 109,
|
|
||||||
|
|
||||||
/// Connection timed out
|
|
||||||
TIMEDOUT = 110,
|
|
||||||
|
|
||||||
/// Connection refused
|
|
||||||
CONNREFUSED = 111,
|
|
||||||
|
|
||||||
/// Host is down
|
|
||||||
HOSTDOWN = 112,
|
|
||||||
|
|
||||||
/// No route to host
|
|
||||||
HOSTUNREACH = 113,
|
|
||||||
|
|
||||||
/// Operation already in progress
|
|
||||||
ALREADY = 114,
|
|
||||||
|
|
||||||
/// Operation now in progress
|
|
||||||
INPROGRESS = 115,
|
|
||||||
|
|
||||||
/// Stale NFS file handle
|
|
||||||
STALE = 116,
|
|
||||||
|
|
||||||
/// Structure needs cleaning
|
|
||||||
UCLEAN = 117,
|
|
||||||
|
|
||||||
/// Not a XENIX named type file
|
|
||||||
NOTNAM = 118,
|
|
||||||
|
|
||||||
/// No XENIX semaphores available
|
|
||||||
NAVAIL = 119,
|
|
||||||
|
|
||||||
/// Is a named type file
|
|
||||||
ISNAM = 120,
|
|
||||||
|
|
||||||
/// Remote I/O error
|
|
||||||
REMOTEIO = 121,
|
|
||||||
|
|
||||||
/// Quota exceeded
|
|
||||||
DQUOT = 122,
|
|
||||||
|
|
||||||
/// No medium found
|
|
||||||
NOMEDIUM = 123,
|
|
||||||
|
|
||||||
/// Wrong medium type
|
|
||||||
MEDIUMTYPE = 124,
|
|
||||||
|
|
||||||
/// Operation canceled
|
|
||||||
CANCELED = 125,
|
|
||||||
|
|
||||||
/// Required key not available
|
|
||||||
NOKEY = 126,
|
|
||||||
|
|
||||||
/// Key has expired
|
|
||||||
KEYEXPIRED = 127,
|
|
||||||
|
|
||||||
/// Key has been revoked
|
|
||||||
KEYREVOKED = 128,
|
|
||||||
|
|
||||||
/// Key was rejected by service
|
|
||||||
KEYREJECTED = 129,
|
|
||||||
|
|
||||||
// for robust mutexes
|
|
||||||
|
|
||||||
/// Owner died
|
|
||||||
OWNERDEAD = 130,
|
|
||||||
|
|
||||||
/// State not recoverable
|
|
||||||
NOTRECOVERABLE = 131,
|
|
||||||
|
|
||||||
/// Operation not possible due to RF-kill
|
|
||||||
RFKILL = 132,
|
|
||||||
|
|
||||||
/// Memory page has hardware error
|
|
||||||
HWPOISON = 133,
|
|
||||||
|
|
||||||
// nameserver query return codes
|
|
||||||
|
|
||||||
/// DNS server returned answer with no data
|
|
||||||
NSRNODATA = 160,
|
|
||||||
|
|
||||||
/// DNS server claims query was misformatted
|
|
||||||
NSRFORMERR = 161,
|
|
||||||
|
|
||||||
/// DNS server returned general failure
|
|
||||||
NSRSERVFAIL = 162,
|
|
||||||
|
|
||||||
/// Domain name not found
|
|
||||||
NSRNOTFOUND = 163,
|
|
||||||
|
|
||||||
/// DNS server does not implement requested operation
|
|
||||||
NSRNOTIMP = 164,
|
|
||||||
|
|
||||||
/// DNS server refused query
|
|
||||||
NSRREFUSED = 165,
|
|
||||||
|
|
||||||
/// Misformatted DNS query
|
|
||||||
NSRBADQUERY = 166,
|
|
||||||
|
|
||||||
/// Misformatted domain name
|
|
||||||
NSRBADNAME = 167,
|
|
||||||
|
|
||||||
/// Unsupported address family
|
|
||||||
NSRBADFAMILY = 168,
|
|
||||||
|
|
||||||
/// Misformatted DNS reply
|
|
||||||
NSRBADRESP = 169,
|
|
||||||
|
|
||||||
/// Could not contact DNS servers
|
|
||||||
NSRCONNREFUSED = 170,
|
|
||||||
|
|
||||||
/// Timeout while contacting DNS servers
|
|
||||||
NSRTIMEOUT = 171,
|
|
||||||
|
|
||||||
/// End of file
|
|
||||||
NSROF = 172,
|
|
||||||
|
|
||||||
/// Error reading file
|
|
||||||
NSRFILE = 173,
|
|
||||||
|
|
||||||
/// Out of memory
|
|
||||||
NSRNOMEM = 174,
|
|
||||||
|
|
||||||
/// Application terminated lookup
|
|
||||||
NSRDESTRUCTION = 175,
|
|
||||||
|
|
||||||
/// Domain name is too long
|
|
||||||
NSRQUERYDOMAINTOOLONG = 176,
|
|
||||||
|
|
||||||
/// Domain name is too long
|
|
||||||
NSRCNAMELOOP = 177,
|
|
||||||
|
|
||||||
_,
|
|
||||||
};
|
|
||||||
@ -1,141 +0,0 @@
|
|||||||
//! These are MIPS ABI compatible.
|
|
||||||
pub const E = enum(i32) {
|
|
||||||
/// No error occurred.
|
|
||||||
SUCCESS = 0,
|
|
||||||
|
|
||||||
PERM = 1,
|
|
||||||
NOENT = 2,
|
|
||||||
SRCH = 3,
|
|
||||||
INTR = 4,
|
|
||||||
IO = 5,
|
|
||||||
NXIO = 6,
|
|
||||||
@"2BIG" = 7,
|
|
||||||
NOEXEC = 8,
|
|
||||||
BADF = 9,
|
|
||||||
CHILD = 10,
|
|
||||||
/// Also used for WOULDBLOCK.
|
|
||||||
AGAIN = 11,
|
|
||||||
NOMEM = 12,
|
|
||||||
ACCES = 13,
|
|
||||||
FAULT = 14,
|
|
||||||
NOTBLK = 15,
|
|
||||||
BUSY = 16,
|
|
||||||
EXIST = 17,
|
|
||||||
XDEV = 18,
|
|
||||||
NODEV = 19,
|
|
||||||
NOTDIR = 20,
|
|
||||||
ISDIR = 21,
|
|
||||||
INVAL = 22,
|
|
||||||
NFILE = 23,
|
|
||||||
MFILE = 24,
|
|
||||||
NOTTY = 25,
|
|
||||||
TXTBSY = 26,
|
|
||||||
FBIG = 27,
|
|
||||||
NOSPC = 28,
|
|
||||||
SPIPE = 29,
|
|
||||||
ROFS = 30,
|
|
||||||
MLINK = 31,
|
|
||||||
PIPE = 32,
|
|
||||||
DOM = 33,
|
|
||||||
RANGE = 34,
|
|
||||||
|
|
||||||
NOMSG = 35,
|
|
||||||
IDRM = 36,
|
|
||||||
CHRNG = 37,
|
|
||||||
L2NSYNC = 38,
|
|
||||||
L3HLT = 39,
|
|
||||||
L3RST = 40,
|
|
||||||
LNRNG = 41,
|
|
||||||
UNATCH = 42,
|
|
||||||
NOCSI = 43,
|
|
||||||
L2HLT = 44,
|
|
||||||
DEADLK = 45,
|
|
||||||
NOLCK = 46,
|
|
||||||
BADE = 50,
|
|
||||||
BADR = 51,
|
|
||||||
XFULL = 52,
|
|
||||||
NOANO = 53,
|
|
||||||
BADRQC = 54,
|
|
||||||
BADSLT = 55,
|
|
||||||
DEADLOCK = 56,
|
|
||||||
BFONT = 59,
|
|
||||||
NOSTR = 60,
|
|
||||||
NODATA = 61,
|
|
||||||
TIME = 62,
|
|
||||||
NOSR = 63,
|
|
||||||
NONET = 64,
|
|
||||||
NOPKG = 65,
|
|
||||||
REMOTE = 66,
|
|
||||||
NOLINK = 67,
|
|
||||||
ADV = 68,
|
|
||||||
SRMNT = 69,
|
|
||||||
COMM = 70,
|
|
||||||
PROTO = 71,
|
|
||||||
DOTDOT = 73,
|
|
||||||
MULTIHOP = 74,
|
|
||||||
BADMSG = 77,
|
|
||||||
NAMETOOLONG = 78,
|
|
||||||
OVERFLOW = 79,
|
|
||||||
NOTUNIQ = 80,
|
|
||||||
BADFD = 81,
|
|
||||||
REMCHG = 82,
|
|
||||||
LIBACC = 83,
|
|
||||||
LIBBAD = 84,
|
|
||||||
LIBSCN = 85,
|
|
||||||
LIBMAX = 86,
|
|
||||||
LIBEXEC = 87,
|
|
||||||
ILSEQ = 88,
|
|
||||||
NOSYS = 89,
|
|
||||||
LOOP = 90,
|
|
||||||
RESTART = 91,
|
|
||||||
STRPIPE = 92,
|
|
||||||
NOTEMPTY = 93,
|
|
||||||
USERS = 94,
|
|
||||||
NOTSOCK = 95,
|
|
||||||
DESTADDRREQ = 96,
|
|
||||||
MSGSIZE = 97,
|
|
||||||
PROTOTYPE = 98,
|
|
||||||
NOPROTOOPT = 99,
|
|
||||||
PROTONOSUPPORT = 120,
|
|
||||||
SOCKTNOSUPPORT = 121,
|
|
||||||
OPNOTSUPP = 122,
|
|
||||||
PFNOSUPPORT = 123,
|
|
||||||
AFNOSUPPORT = 124,
|
|
||||||
ADDRINUSE = 125,
|
|
||||||
ADDRNOTAVAIL = 126,
|
|
||||||
NETDOWN = 127,
|
|
||||||
NETUNREACH = 128,
|
|
||||||
NETRESET = 129,
|
|
||||||
CONNABORTED = 130,
|
|
||||||
CONNRESET = 131,
|
|
||||||
NOBUFS = 132,
|
|
||||||
ISCONN = 133,
|
|
||||||
NOTCONN = 134,
|
|
||||||
UCLEAN = 135,
|
|
||||||
NOTNAM = 137,
|
|
||||||
NAVAIL = 138,
|
|
||||||
ISNAM = 139,
|
|
||||||
REMOTEIO = 140,
|
|
||||||
SHUTDOWN = 143,
|
|
||||||
TOOMANYREFS = 144,
|
|
||||||
TIMEDOUT = 145,
|
|
||||||
CONNREFUSED = 146,
|
|
||||||
HOSTDOWN = 147,
|
|
||||||
HOSTUNREACH = 148,
|
|
||||||
ALREADY = 149,
|
|
||||||
INPROGRESS = 150,
|
|
||||||
STALE = 151,
|
|
||||||
CANCELED = 158,
|
|
||||||
NOMEDIUM = 159,
|
|
||||||
MEDIUMTYPE = 160,
|
|
||||||
NOKEY = 161,
|
|
||||||
KEYEXPIRED = 162,
|
|
||||||
KEYREVOKED = 163,
|
|
||||||
KEYREJECTED = 164,
|
|
||||||
OWNERDEAD = 165,
|
|
||||||
NOTRECOVERABLE = 166,
|
|
||||||
RFKILL = 167,
|
|
||||||
HWPOISON = 168,
|
|
||||||
DQUOT = 1133,
|
|
||||||
_,
|
|
||||||
};
|
|
||||||
@ -1,144 +0,0 @@
|
|||||||
//! These match the SunOS error numbering scheme.
|
|
||||||
pub const E = enum(i32) {
|
|
||||||
/// No error occurred.
|
|
||||||
SUCCESS = 0,
|
|
||||||
|
|
||||||
PERM = 1,
|
|
||||||
NOENT = 2,
|
|
||||||
SRCH = 3,
|
|
||||||
INTR = 4,
|
|
||||||
IO = 5,
|
|
||||||
NXIO = 6,
|
|
||||||
@"2BIG" = 7,
|
|
||||||
NOEXEC = 8,
|
|
||||||
BADF = 9,
|
|
||||||
CHILD = 10,
|
|
||||||
/// Also used for WOULDBLOCK
|
|
||||||
AGAIN = 11,
|
|
||||||
NOMEM = 12,
|
|
||||||
ACCES = 13,
|
|
||||||
FAULT = 14,
|
|
||||||
NOTBLK = 15,
|
|
||||||
BUSY = 16,
|
|
||||||
EXIST = 17,
|
|
||||||
XDEV = 18,
|
|
||||||
NODEV = 19,
|
|
||||||
NOTDIR = 20,
|
|
||||||
ISDIR = 21,
|
|
||||||
INVAL = 22,
|
|
||||||
NFILE = 23,
|
|
||||||
MFILE = 24,
|
|
||||||
NOTTY = 25,
|
|
||||||
TXTBSY = 26,
|
|
||||||
FBIG = 27,
|
|
||||||
NOSPC = 28,
|
|
||||||
SPIPE = 29,
|
|
||||||
ROFS = 30,
|
|
||||||
MLINK = 31,
|
|
||||||
PIPE = 32,
|
|
||||||
DOM = 33,
|
|
||||||
RANGE = 34,
|
|
||||||
|
|
||||||
INPROGRESS = 36,
|
|
||||||
ALREADY = 37,
|
|
||||||
NOTSOCK = 38,
|
|
||||||
DESTADDRREQ = 39,
|
|
||||||
MSGSIZE = 40,
|
|
||||||
PROTOTYPE = 41,
|
|
||||||
NOPROTOOPT = 42,
|
|
||||||
PROTONOSUPPORT = 43,
|
|
||||||
SOCKTNOSUPPORT = 44,
|
|
||||||
/// Also used for NOTSUP
|
|
||||||
OPNOTSUPP = 45,
|
|
||||||
PFNOSUPPORT = 46,
|
|
||||||
AFNOSUPPORT = 47,
|
|
||||||
ADDRINUSE = 48,
|
|
||||||
ADDRNOTAVAIL = 49,
|
|
||||||
NETDOWN = 50,
|
|
||||||
NETUNREACH = 51,
|
|
||||||
NETRESET = 52,
|
|
||||||
CONNABORTED = 53,
|
|
||||||
CONNRESET = 54,
|
|
||||||
NOBUFS = 55,
|
|
||||||
ISCONN = 56,
|
|
||||||
NOTCONN = 57,
|
|
||||||
SHUTDOWN = 58,
|
|
||||||
TOOMANYREFS = 59,
|
|
||||||
TIMEDOUT = 60,
|
|
||||||
CONNREFUSED = 61,
|
|
||||||
LOOP = 62,
|
|
||||||
NAMETOOLONG = 63,
|
|
||||||
HOSTDOWN = 64,
|
|
||||||
HOSTUNREACH = 65,
|
|
||||||
NOTEMPTY = 66,
|
|
||||||
PROCLIM = 67,
|
|
||||||
USERS = 68,
|
|
||||||
DQUOT = 69,
|
|
||||||
STALE = 70,
|
|
||||||
REMOTE = 71,
|
|
||||||
NOSTR = 72,
|
|
||||||
TIME = 73,
|
|
||||||
NOSR = 74,
|
|
||||||
NOMSG = 75,
|
|
||||||
BADMSG = 76,
|
|
||||||
IDRM = 77,
|
|
||||||
DEADLK = 78,
|
|
||||||
NOLCK = 79,
|
|
||||||
NONET = 80,
|
|
||||||
RREMOTE = 81,
|
|
||||||
NOLINK = 82,
|
|
||||||
ADV = 83,
|
|
||||||
SRMNT = 84,
|
|
||||||
COMM = 85,
|
|
||||||
PROTO = 86,
|
|
||||||
MULTIHOP = 87,
|
|
||||||
DOTDOT = 88,
|
|
||||||
REMCHG = 89,
|
|
||||||
NOSYS = 90,
|
|
||||||
STRPIPE = 91,
|
|
||||||
OVERFLOW = 92,
|
|
||||||
BADFD = 93,
|
|
||||||
CHRNG = 94,
|
|
||||||
L2NSYNC = 95,
|
|
||||||
L3HLT = 96,
|
|
||||||
L3RST = 97,
|
|
||||||
LNRNG = 98,
|
|
||||||
UNATCH = 99,
|
|
||||||
NOCSI = 100,
|
|
||||||
L2HLT = 101,
|
|
||||||
BADE = 102,
|
|
||||||
BADR = 103,
|
|
||||||
XFULL = 104,
|
|
||||||
NOANO = 105,
|
|
||||||
BADRQC = 106,
|
|
||||||
BADSLT = 107,
|
|
||||||
DEADLOCK = 108,
|
|
||||||
BFONT = 109,
|
|
||||||
LIBEXEC = 110,
|
|
||||||
NODATA = 111,
|
|
||||||
LIBBAD = 112,
|
|
||||||
NOPKG = 113,
|
|
||||||
LIBACC = 114,
|
|
||||||
NOTUNIQ = 115,
|
|
||||||
RESTART = 116,
|
|
||||||
UCLEAN = 117,
|
|
||||||
NOTNAM = 118,
|
|
||||||
NAVAIL = 119,
|
|
||||||
ISNAM = 120,
|
|
||||||
REMOTEIO = 121,
|
|
||||||
ILSEQ = 122,
|
|
||||||
LIBMAX = 123,
|
|
||||||
LIBSCN = 124,
|
|
||||||
NOMEDIUM = 125,
|
|
||||||
MEDIUMTYPE = 126,
|
|
||||||
CANCELED = 127,
|
|
||||||
NOKEY = 128,
|
|
||||||
KEYEXPIRED = 129,
|
|
||||||
KEYREVOKED = 130,
|
|
||||||
KEYREJECTED = 131,
|
|
||||||
OWNERDEAD = 132,
|
|
||||||
NOTRECOVERABLE = 133,
|
|
||||||
RFKILL = 134,
|
|
||||||
HWPOISON = 135,
|
|
||||||
_,
|
|
||||||
};
|
|
||||||
@ -2,8 +2,7 @@
|
|||||||
//! Split into its own file to compartmentalize the initialization methods.
|
//! Split into its own file to compartmentalize the initialization methods.
|
||||||
|
|
||||||
const std = @import("../../std.zig");
|
const std = @import("../../std.zig");
|
||||||
const os = std.os;
|
const linux = std.os.linux;
|
||||||
const linux = os.linux;
|
|
||||||
|
|
||||||
pub const io_uring_sqe = extern struct {
|
pub const io_uring_sqe = extern struct {
|
||||||
opcode: linux.IORING_OP,
|
opcode: linux.IORING_OP,
|
||||||
@ -40,7 +39,7 @@ pub const io_uring_sqe = extern struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prep_fsync(sqe: *linux.io_uring_sqe, fd: os.fd_t, flags: u32) void {
|
pub fn prep_fsync(sqe: *linux.io_uring_sqe, fd: linux.fd_t, flags: u32) void {
|
||||||
sqe.* = .{
|
sqe.* = .{
|
||||||
.opcode = .FSYNC,
|
.opcode = .FSYNC,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
@ -62,7 +61,7 @@ pub const io_uring_sqe = extern struct {
|
|||||||
pub fn prep_rw(
|
pub fn prep_rw(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
op: linux.IORING_OP,
|
op: linux.IORING_OP,
|
||||||
fd: os.fd_t,
|
fd: linux.fd_t,
|
||||||
addr: u64,
|
addr: u64,
|
||||||
len: usize,
|
len: usize,
|
||||||
offset: u64,
|
offset: u64,
|
||||||
@ -85,15 +84,15 @@ pub const io_uring_sqe = extern struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prep_read(sqe: *linux.io_uring_sqe, fd: os.fd_t, buffer: []u8, offset: u64) void {
|
pub fn prep_read(sqe: *linux.io_uring_sqe, fd: linux.fd_t, buffer: []u8, offset: u64) void {
|
||||||
sqe.prep_rw(.READ, fd, @intFromPtr(buffer.ptr), buffer.len, offset);
|
sqe.prep_rw(.READ, fd, @intFromPtr(buffer.ptr), buffer.len, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prep_write(sqe: *linux.io_uring_sqe, fd: os.fd_t, buffer: []const u8, offset: u64) void {
|
pub fn prep_write(sqe: *linux.io_uring_sqe, fd: linux.fd_t, buffer: []const u8, offset: u64) void {
|
||||||
sqe.prep_rw(.WRITE, fd, @intFromPtr(buffer.ptr), buffer.len, offset);
|
sqe.prep_rw(.WRITE, fd, @intFromPtr(buffer.ptr), buffer.len, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prep_splice(sqe: *linux.io_uring_sqe, fd_in: os.fd_t, off_in: u64, fd_out: os.fd_t, off_out: u64, len: usize) void {
|
pub fn prep_splice(sqe: *linux.io_uring_sqe, fd_in: linux.fd_t, off_in: u64, fd_out: linux.fd_t, off_out: u64, len: usize) void {
|
||||||
sqe.prep_rw(.SPLICE, fd_out, undefined, len, off_out);
|
sqe.prep_rw(.SPLICE, fd_out, undefined, len, off_out);
|
||||||
sqe.addr = off_in;
|
sqe.addr = off_in;
|
||||||
sqe.splice_fd_in = fd_in;
|
sqe.splice_fd_in = fd_in;
|
||||||
@ -101,8 +100,8 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_readv(
|
pub fn prep_readv(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
fd: os.fd_t,
|
fd: linux.fd_t,
|
||||||
iovecs: []const os.iovec,
|
iovecs: []const std.posix.iovec,
|
||||||
offset: u64,
|
offset: u64,
|
||||||
) void {
|
) void {
|
||||||
sqe.prep_rw(.READV, fd, @intFromPtr(iovecs.ptr), iovecs.len, offset);
|
sqe.prep_rw(.READV, fd, @intFromPtr(iovecs.ptr), iovecs.len, offset);
|
||||||
@ -110,28 +109,28 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_writev(
|
pub fn prep_writev(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
fd: os.fd_t,
|
fd: linux.fd_t,
|
||||||
iovecs: []const os.iovec_const,
|
iovecs: []const std.posix.iovec_const,
|
||||||
offset: u64,
|
offset: u64,
|
||||||
) void {
|
) void {
|
||||||
sqe.prep_rw(.WRITEV, fd, @intFromPtr(iovecs.ptr), iovecs.len, offset);
|
sqe.prep_rw(.WRITEV, fd, @intFromPtr(iovecs.ptr), iovecs.len, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prep_read_fixed(sqe: *linux.io_uring_sqe, fd: os.fd_t, buffer: *os.iovec, offset: u64, buffer_index: u16) void {
|
pub fn prep_read_fixed(sqe: *linux.io_uring_sqe, fd: linux.fd_t, buffer: *std.posix.iovec, offset: u64, buffer_index: u16) void {
|
||||||
sqe.prep_rw(.READ_FIXED, fd, @intFromPtr(buffer.iov_base), buffer.iov_len, offset);
|
sqe.prep_rw(.READ_FIXED, fd, @intFromPtr(buffer.iov_base), buffer.iov_len, offset);
|
||||||
sqe.buf_index = buffer_index;
|
sqe.buf_index = buffer_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prep_write_fixed(sqe: *linux.io_uring_sqe, fd: os.fd_t, buffer: *os.iovec, offset: u64, buffer_index: u16) void {
|
pub fn prep_write_fixed(sqe: *linux.io_uring_sqe, fd: linux.fd_t, buffer: *std.posix.iovec, offset: u64, buffer_index: u16) void {
|
||||||
sqe.prep_rw(.WRITE_FIXED, fd, @intFromPtr(buffer.iov_base), buffer.iov_len, offset);
|
sqe.prep_rw(.WRITE_FIXED, fd, @intFromPtr(buffer.iov_base), buffer.iov_len, offset);
|
||||||
sqe.buf_index = buffer_index;
|
sqe.buf_index = buffer_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prep_accept(
|
pub fn prep_accept(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
fd: os.fd_t,
|
fd: linux.fd_t,
|
||||||
addr: ?*os.sockaddr,
|
addr: ?*linux.sockaddr,
|
||||||
addrlen: ?*os.socklen_t,
|
addrlen: ?*linux.socklen_t,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
) void {
|
) void {
|
||||||
// `addr` holds a pointer to `sockaddr`, and `addr2` holds a pointer to socklen_t`.
|
// `addr` holds a pointer to `sockaddr`, and `addr2` holds a pointer to socklen_t`.
|
||||||
@ -142,9 +141,9 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_accept_direct(
|
pub fn prep_accept_direct(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
fd: os.fd_t,
|
fd: linux.fd_t,
|
||||||
addr: ?*os.sockaddr,
|
addr: ?*linux.sockaddr,
|
||||||
addrlen: ?*os.socklen_t,
|
addrlen: ?*linux.socklen_t,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
file_index: u32,
|
file_index: u32,
|
||||||
) void {
|
) void {
|
||||||
@ -154,9 +153,9 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_multishot_accept_direct(
|
pub fn prep_multishot_accept_direct(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
fd: os.fd_t,
|
fd: linux.fd_t,
|
||||||
addr: ?*os.sockaddr,
|
addr: ?*linux.sockaddr,
|
||||||
addrlen: ?*os.socklen_t,
|
addrlen: ?*linux.socklen_t,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
) void {
|
) void {
|
||||||
prep_multishot_accept(sqe, fd, addr, addrlen, flags);
|
prep_multishot_accept(sqe, fd, addr, addrlen, flags);
|
||||||
@ -177,9 +176,9 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_connect(
|
pub fn prep_connect(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
fd: os.fd_t,
|
fd: linux.fd_t,
|
||||||
addr: *const os.sockaddr,
|
addr: *const linux.sockaddr,
|
||||||
addrlen: os.socklen_t,
|
addrlen: linux.socklen_t,
|
||||||
) void {
|
) void {
|
||||||
// `addrlen` maps to `sqe.off` (u64) instead of `sqe.len` (which is only a u32).
|
// `addrlen` maps to `sqe.off` (u64) instead of `sqe.len` (which is only a u32).
|
||||||
sqe.prep_rw(.CONNECT, fd, @intFromPtr(addr), 0, addrlen);
|
sqe.prep_rw(.CONNECT, fd, @intFromPtr(addr), 0, addrlen);
|
||||||
@ -187,22 +186,22 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_epoll_ctl(
|
pub fn prep_epoll_ctl(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
epfd: os.fd_t,
|
epfd: linux.fd_t,
|
||||||
fd: os.fd_t,
|
fd: linux.fd_t,
|
||||||
op: u32,
|
op: u32,
|
||||||
ev: ?*linux.epoll_event,
|
ev: ?*linux.epoll_event,
|
||||||
) void {
|
) void {
|
||||||
sqe.prep_rw(.EPOLL_CTL, epfd, @intFromPtr(ev), op, @intCast(fd));
|
sqe.prep_rw(.EPOLL_CTL, epfd, @intFromPtr(ev), op, @intCast(fd));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prep_recv(sqe: *linux.io_uring_sqe, fd: os.fd_t, buffer: []u8, flags: u32) void {
|
pub fn prep_recv(sqe: *linux.io_uring_sqe, fd: linux.fd_t, buffer: []u8, flags: u32) void {
|
||||||
sqe.prep_rw(.RECV, fd, @intFromPtr(buffer.ptr), buffer.len, 0);
|
sqe.prep_rw(.RECV, fd, @intFromPtr(buffer.ptr), buffer.len, 0);
|
||||||
sqe.rw_flags = flags;
|
sqe.rw_flags = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prep_recv_multishot(
|
pub fn prep_recv_multishot(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
fd: os.fd_t,
|
fd: linux.fd_t,
|
||||||
buffer: []u8,
|
buffer: []u8,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
) void {
|
) void {
|
||||||
@ -212,8 +211,8 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_recvmsg(
|
pub fn prep_recvmsg(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
fd: os.fd_t,
|
fd: linux.fd_t,
|
||||||
msg: *os.msghdr,
|
msg: *linux.msghdr,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
) void {
|
) void {
|
||||||
sqe.prep_rw(.RECVMSG, fd, @intFromPtr(msg), 1, 0);
|
sqe.prep_rw(.RECVMSG, fd, @intFromPtr(msg), 1, 0);
|
||||||
@ -222,26 +221,26 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_recvmsg_multishot(
|
pub fn prep_recvmsg_multishot(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
fd: os.fd_t,
|
fd: linux.fd_t,
|
||||||
msg: *os.msghdr,
|
msg: *linux.msghdr,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
) void {
|
) void {
|
||||||
sqe.prep_recvmsg(fd, msg, flags);
|
sqe.prep_recvmsg(fd, msg, flags);
|
||||||
sqe.ioprio |= linux.IORING_RECV_MULTISHOT;
|
sqe.ioprio |= linux.IORING_RECV_MULTISHOT;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prep_send(sqe: *linux.io_uring_sqe, fd: os.fd_t, buffer: []const u8, flags: u32) void {
|
pub fn prep_send(sqe: *linux.io_uring_sqe, fd: linux.fd_t, buffer: []const u8, flags: u32) void {
|
||||||
sqe.prep_rw(.SEND, fd, @intFromPtr(buffer.ptr), buffer.len, 0);
|
sqe.prep_rw(.SEND, fd, @intFromPtr(buffer.ptr), buffer.len, 0);
|
||||||
sqe.rw_flags = flags;
|
sqe.rw_flags = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prep_send_zc(sqe: *linux.io_uring_sqe, fd: os.fd_t, buffer: []const u8, flags: u32, zc_flags: u16) void {
|
pub fn prep_send_zc(sqe: *linux.io_uring_sqe, fd: linux.fd_t, buffer: []const u8, flags: u32, zc_flags: u16) void {
|
||||||
sqe.prep_rw(.SEND_ZC, fd, @intFromPtr(buffer.ptr), buffer.len, 0);
|
sqe.prep_rw(.SEND_ZC, fd, @intFromPtr(buffer.ptr), buffer.len, 0);
|
||||||
sqe.rw_flags = flags;
|
sqe.rw_flags = flags;
|
||||||
sqe.ioprio = zc_flags;
|
sqe.ioprio = zc_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prep_send_zc_fixed(sqe: *linux.io_uring_sqe, fd: os.fd_t, buffer: []const u8, flags: u32, zc_flags: u16, buf_index: u16) void {
|
pub fn prep_send_zc_fixed(sqe: *linux.io_uring_sqe, fd: linux.fd_t, buffer: []const u8, flags: u32, zc_flags: u16, buf_index: u16) void {
|
||||||
prep_send_zc(sqe, fd, buffer, flags, zc_flags);
|
prep_send_zc(sqe, fd, buffer, flags, zc_flags);
|
||||||
sqe.ioprio |= linux.IORING_RECVSEND_FIXED_BUF;
|
sqe.ioprio |= linux.IORING_RECVSEND_FIXED_BUF;
|
||||||
sqe.buf_index = buf_index;
|
sqe.buf_index = buf_index;
|
||||||
@ -249,8 +248,8 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_sendmsg_zc(
|
pub fn prep_sendmsg_zc(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
fd: os.fd_t,
|
fd: linux.fd_t,
|
||||||
msg: *const os.msghdr_const,
|
msg: *const linux.msghdr_const,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
) void {
|
) void {
|
||||||
prep_sendmsg(sqe, fd, msg, flags);
|
prep_sendmsg(sqe, fd, msg, flags);
|
||||||
@ -259,8 +258,8 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_sendmsg(
|
pub fn prep_sendmsg(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
fd: os.fd_t,
|
fd: linux.fd_t,
|
||||||
msg: *const os.msghdr_const,
|
msg: *const linux.msghdr_const,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
) void {
|
) void {
|
||||||
sqe.prep_rw(.SENDMSG, fd, @intFromPtr(msg), 1, 0);
|
sqe.prep_rw(.SENDMSG, fd, @intFromPtr(msg), 1, 0);
|
||||||
@ -269,10 +268,10 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_openat(
|
pub fn prep_openat(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
fd: os.fd_t,
|
fd: linux.fd_t,
|
||||||
path: [*:0]const u8,
|
path: [*:0]const u8,
|
||||||
flags: linux.O,
|
flags: linux.O,
|
||||||
mode: os.mode_t,
|
mode: linux.mode_t,
|
||||||
) void {
|
) void {
|
||||||
sqe.prep_rw(.OPENAT, fd, @intFromPtr(path), mode, 0);
|
sqe.prep_rw(.OPENAT, fd, @intFromPtr(path), mode, 0);
|
||||||
sqe.rw_flags = @bitCast(flags);
|
sqe.rw_flags = @bitCast(flags);
|
||||||
@ -280,17 +279,17 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_openat_direct(
|
pub fn prep_openat_direct(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
fd: os.fd_t,
|
fd: linux.fd_t,
|
||||||
path: [*:0]const u8,
|
path: [*:0]const u8,
|
||||||
flags: linux.O,
|
flags: linux.O,
|
||||||
mode: os.mode_t,
|
mode: linux.mode_t,
|
||||||
file_index: u32,
|
file_index: u32,
|
||||||
) void {
|
) void {
|
||||||
prep_openat(sqe, fd, path, flags, mode);
|
prep_openat(sqe, fd, path, flags, mode);
|
||||||
__io_uring_set_target_fixed_file(sqe, file_index);
|
__io_uring_set_target_fixed_file(sqe, file_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prep_close(sqe: *linux.io_uring_sqe, fd: os.fd_t) void {
|
pub fn prep_close(sqe: *linux.io_uring_sqe, fd: linux.fd_t) void {
|
||||||
sqe.* = .{
|
sqe.* = .{
|
||||||
.opcode = .CLOSE,
|
.opcode = .CLOSE,
|
||||||
.flags = 0,
|
.flags = 0,
|
||||||
@ -316,7 +315,7 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_timeout(
|
pub fn prep_timeout(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
ts: *const os.linux.kernel_timespec,
|
ts: *const linux.kernel_timespec,
|
||||||
count: u32,
|
count: u32,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
) void {
|
) void {
|
||||||
@ -345,7 +344,7 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_link_timeout(
|
pub fn prep_link_timeout(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
ts: *const os.linux.kernel_timespec,
|
ts: *const linux.kernel_timespec,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
) void {
|
) void {
|
||||||
sqe.prep_rw(.LINK_TIMEOUT, -1, @intFromPtr(ts), 1, 0);
|
sqe.prep_rw(.LINK_TIMEOUT, -1, @intFromPtr(ts), 1, 0);
|
||||||
@ -354,7 +353,7 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_poll_add(
|
pub fn prep_poll_add(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
fd: os.fd_t,
|
fd: linux.fd_t,
|
||||||
poll_mask: u32,
|
poll_mask: u32,
|
||||||
) void {
|
) void {
|
||||||
sqe.prep_rw(.POLL_ADD, fd, @intFromPtr(@as(?*anyopaque, null)), 0, 0);
|
sqe.prep_rw(.POLL_ADD, fd, @intFromPtr(@as(?*anyopaque, null)), 0, 0);
|
||||||
@ -393,7 +392,7 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_fallocate(
|
pub fn prep_fallocate(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
fd: os.fd_t,
|
fd: linux.fd_t,
|
||||||
mode: i32,
|
mode: i32,
|
||||||
offset: u64,
|
offset: u64,
|
||||||
len: u64,
|
len: u64,
|
||||||
@ -418,7 +417,7 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_statx(
|
pub fn prep_statx(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
fd: os.fd_t,
|
fd: linux.fd_t,
|
||||||
path: [*:0]const u8,
|
path: [*:0]const u8,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
mask: u32,
|
mask: u32,
|
||||||
@ -439,7 +438,7 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_shutdown(
|
pub fn prep_shutdown(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
sockfd: os.socket_t,
|
sockfd: linux.socket_t,
|
||||||
how: u32,
|
how: u32,
|
||||||
) void {
|
) void {
|
||||||
sqe.prep_rw(.SHUTDOWN, sockfd, 0, how, 0);
|
sqe.prep_rw(.SHUTDOWN, sockfd, 0, how, 0);
|
||||||
@ -447,9 +446,9 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_renameat(
|
pub fn prep_renameat(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
old_dir_fd: os.fd_t,
|
old_dir_fd: linux.fd_t,
|
||||||
old_path: [*:0]const u8,
|
old_path: [*:0]const u8,
|
||||||
new_dir_fd: os.fd_t,
|
new_dir_fd: linux.fd_t,
|
||||||
new_path: [*:0]const u8,
|
new_path: [*:0]const u8,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
) void {
|
) void {
|
||||||
@ -466,7 +465,7 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_unlinkat(
|
pub fn prep_unlinkat(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
dir_fd: os.fd_t,
|
dir_fd: linux.fd_t,
|
||||||
path: [*:0]const u8,
|
path: [*:0]const u8,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
) void {
|
) void {
|
||||||
@ -476,9 +475,9 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_mkdirat(
|
pub fn prep_mkdirat(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
dir_fd: os.fd_t,
|
dir_fd: linux.fd_t,
|
||||||
path: [*:0]const u8,
|
path: [*:0]const u8,
|
||||||
mode: os.mode_t,
|
mode: linux.mode_t,
|
||||||
) void {
|
) void {
|
||||||
sqe.prep_rw(.MKDIRAT, dir_fd, @intFromPtr(path), mode, 0);
|
sqe.prep_rw(.MKDIRAT, dir_fd, @intFromPtr(path), mode, 0);
|
||||||
}
|
}
|
||||||
@ -486,7 +485,7 @@ pub const io_uring_sqe = extern struct {
|
|||||||
pub fn prep_symlinkat(
|
pub fn prep_symlinkat(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
target: [*:0]const u8,
|
target: [*:0]const u8,
|
||||||
new_dir_fd: os.fd_t,
|
new_dir_fd: linux.fd_t,
|
||||||
link_path: [*:0]const u8,
|
link_path: [*:0]const u8,
|
||||||
) void {
|
) void {
|
||||||
sqe.prep_rw(
|
sqe.prep_rw(
|
||||||
@ -500,9 +499,9 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_linkat(
|
pub fn prep_linkat(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
old_dir_fd: os.fd_t,
|
old_dir_fd: linux.fd_t,
|
||||||
old_path: [*:0]const u8,
|
old_path: [*:0]const u8,
|
||||||
new_dir_fd: os.fd_t,
|
new_dir_fd: linux.fd_t,
|
||||||
new_path: [*:0]const u8,
|
new_path: [*:0]const u8,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
) void {
|
) void {
|
||||||
@ -541,9 +540,9 @@ pub const io_uring_sqe = extern struct {
|
|||||||
|
|
||||||
pub fn prep_multishot_accept(
|
pub fn prep_multishot_accept(
|
||||||
sqe: *linux.io_uring_sqe,
|
sqe: *linux.io_uring_sqe,
|
||||||
fd: os.fd_t,
|
fd: linux.fd_t,
|
||||||
addr: ?*os.sockaddr,
|
addr: ?*linux.sockaddr,
|
||||||
addrlen: ?*os.socklen_t,
|
addrlen: ?*linux.socklen_t,
|
||||||
flags: u32,
|
flags: u32,
|
||||||
) void {
|
) void {
|
||||||
prep_accept(sqe, fd, addr, addrlen, flags);
|
prep_accept(sqe, fd, addr, addrlen, flags);
|
||||||
|
|||||||
@ -3,8 +3,8 @@ const maxInt = std.math.maxInt;
|
|||||||
const linux = std.os.linux;
|
const linux = std.os.linux;
|
||||||
const SYS = linux.SYS;
|
const SYS = linux.SYS;
|
||||||
const socklen_t = linux.socklen_t;
|
const socklen_t = linux.socklen_t;
|
||||||
const iovec = std.os.iovec;
|
const iovec = std.posix.iovec;
|
||||||
const iovec_const = std.os.iovec_const;
|
const iovec_const = std.posix.iovec_const;
|
||||||
const uid_t = linux.uid_t;
|
const uid_t = linux.uid_t;
|
||||||
const gid_t = linux.gid_t;
|
const gid_t = linux.gid_t;
|
||||||
const pid_t = linux.pid_t;
|
const pid_t = linux.pid_t;
|
||||||
|
|||||||
@ -3,8 +3,8 @@ const maxInt = std.math.maxInt;
|
|||||||
const linux = std.os.linux;
|
const linux = std.os.linux;
|
||||||
const SYS = linux.SYS;
|
const SYS = linux.SYS;
|
||||||
const socklen_t = linux.socklen_t;
|
const socklen_t = linux.socklen_t;
|
||||||
const iovec = std.os.iovec;
|
const iovec = std.posix.iovec;
|
||||||
const iovec_const = std.os.iovec_const;
|
const iovec_const = std.posix.iovec_const;
|
||||||
const uid_t = linux.uid_t;
|
const uid_t = linux.uid_t;
|
||||||
const gid_t = linux.gid_t;
|
const gid_t = linux.gid_t;
|
||||||
const pid_t = linux.pid_t;
|
const pid_t = linux.pid_t;
|
||||||
|
|||||||
@ -3,8 +3,8 @@ const maxInt = std.math.maxInt;
|
|||||||
const linux = std.os.linux;
|
const linux = std.os.linux;
|
||||||
const SYS = linux.SYS;
|
const SYS = linux.SYS;
|
||||||
const socklen_t = linux.socklen_t;
|
const socklen_t = linux.socklen_t;
|
||||||
const iovec = std.os.iovec;
|
const iovec = std.posix.iovec;
|
||||||
const iovec_const = std.os.iovec_const;
|
const iovec_const = std.posix.iovec_const;
|
||||||
const uid_t = linux.uid_t;
|
const uid_t = linux.uid_t;
|
||||||
const gid_t = linux.gid_t;
|
const gid_t = linux.gid_t;
|
||||||
const pid_t = linux.pid_t;
|
const pid_t = linux.pid_t;
|
||||||
|
|||||||
@ -3,8 +3,8 @@ const maxInt = std.math.maxInt;
|
|||||||
const linux = std.os.linux;
|
const linux = std.os.linux;
|
||||||
const SYS = linux.SYS;
|
const SYS = linux.SYS;
|
||||||
const socklen_t = linux.socklen_t;
|
const socklen_t = linux.socklen_t;
|
||||||
const iovec = std.os.iovec;
|
const iovec = std.posix.iovec;
|
||||||
const iovec_const = std.os.iovec_const;
|
const iovec_const = std.posix.iovec_const;
|
||||||
const uid_t = linux.uid_t;
|
const uid_t = linux.uid_t;
|
||||||
const gid_t = linux.gid_t;
|
const gid_t = linux.gid_t;
|
||||||
const pid_t = linux.pid_t;
|
const pid_t = linux.pid_t;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
const std = @import("../../std.zig");
|
const std = @import("../../std.zig");
|
||||||
const iovec = std.os.iovec;
|
const iovec = std.posix.iovec;
|
||||||
const iovec_const = std.os.iovec_const;
|
const iovec_const = std.posix.iovec_const;
|
||||||
const linux = std.os.linux;
|
const linux = std.os.linux;
|
||||||
const SYS = linux.SYS;
|
const SYS = linux.SYS;
|
||||||
const uid_t = std.os.linux.uid_t;
|
const uid_t = std.os.linux.uid_t;
|
||||||
|
|||||||
@ -10,8 +10,8 @@ const linux = std.os.linux;
|
|||||||
const SYS = linux.SYS;
|
const SYS = linux.SYS;
|
||||||
const sockaddr = linux.sockaddr;
|
const sockaddr = linux.sockaddr;
|
||||||
const socklen_t = linux.socklen_t;
|
const socklen_t = linux.socklen_t;
|
||||||
const iovec = std.os.iovec;
|
const iovec = std.posix.iovec;
|
||||||
const iovec_const = std.os.iovec_const;
|
const iovec_const = std.posix.iovec_const;
|
||||||
const timespec = linux.timespec;
|
const timespec = linux.timespec;
|
||||||
|
|
||||||
pub fn syscall_pipe(fd: *[2]i32) usize {
|
pub fn syscall_pipe(fd: *[2]i32) usize {
|
||||||
|
|||||||
@ -18,7 +18,7 @@ test "fallocate" {
|
|||||||
try expect((try file.stat()).size == 0);
|
try expect((try file.stat()).size == 0);
|
||||||
|
|
||||||
const len: i64 = 65536;
|
const len: i64 = 65536;
|
||||||
switch (linux.getErrno(linux.fallocate(file.handle, 0, 0, len))) {
|
switch (linux.E.init(linux.fallocate(file.handle, 0, 0, len))) {
|
||||||
.SUCCESS => {},
|
.SUCCESS => {},
|
||||||
.NOSYS => return error.SkipZigTest,
|
.NOSYS => return error.SkipZigTest,
|
||||||
.OPNOTSUPP => return error.SkipZigTest,
|
.OPNOTSUPP => return error.SkipZigTest,
|
||||||
@ -34,11 +34,11 @@ test "getpid" {
|
|||||||
|
|
||||||
test "timer" {
|
test "timer" {
|
||||||
const epoll_fd = linux.epoll_create();
|
const epoll_fd = linux.epoll_create();
|
||||||
var err: linux.E = linux.getErrno(epoll_fd);
|
var err: linux.E = linux.E.init(epoll_fd);
|
||||||
try expect(err == .SUCCESS);
|
try expect(err == .SUCCESS);
|
||||||
|
|
||||||
const timer_fd = linux.timerfd_create(linux.CLOCK.MONOTONIC, .{});
|
const timer_fd = linux.timerfd_create(linux.CLOCK.MONOTONIC, .{});
|
||||||
try expect(linux.getErrno(timer_fd) == .SUCCESS);
|
try expect(linux.E.init(timer_fd) == .SUCCESS);
|
||||||
|
|
||||||
const time_interval = linux.timespec{
|
const time_interval = linux.timespec{
|
||||||
.tv_sec = 0,
|
.tv_sec = 0,
|
||||||
@ -50,7 +50,7 @@ test "timer" {
|
|||||||
.it_value = time_interval,
|
.it_value = time_interval,
|
||||||
};
|
};
|
||||||
|
|
||||||
err = linux.getErrno(linux.timerfd_settime(@as(i32, @intCast(timer_fd)), .{}, &new_time, null));
|
err = linux.E.init(linux.timerfd_settime(@as(i32, @intCast(timer_fd)), .{}, &new_time, null));
|
||||||
try expect(err == .SUCCESS);
|
try expect(err == .SUCCESS);
|
||||||
|
|
||||||
var event = linux.epoll_event{
|
var event = linux.epoll_event{
|
||||||
@ -58,13 +58,13 @@ test "timer" {
|
|||||||
.data = linux.epoll_data{ .ptr = 0 },
|
.data = linux.epoll_data{ .ptr = 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
err = linux.getErrno(linux.epoll_ctl(@as(i32, @intCast(epoll_fd)), linux.EPOLL.CTL_ADD, @as(i32, @intCast(timer_fd)), &event));
|
err = linux.E.init(linux.epoll_ctl(@as(i32, @intCast(epoll_fd)), linux.EPOLL.CTL_ADD, @as(i32, @intCast(timer_fd)), &event));
|
||||||
try expect(err == .SUCCESS);
|
try expect(err == .SUCCESS);
|
||||||
|
|
||||||
const events_one: linux.epoll_event = undefined;
|
const events_one: linux.epoll_event = undefined;
|
||||||
var events = [_]linux.epoll_event{events_one} ** 8;
|
var events = [_]linux.epoll_event{events_one} ** 8;
|
||||||
|
|
||||||
err = linux.getErrno(linux.epoll_wait(@as(i32, @intCast(epoll_fd)), &events, 8, -1));
|
err = linux.E.init(linux.epoll_wait(@as(i32, @intCast(epoll_fd)), &events, 8, -1));
|
||||||
try expect(err == .SUCCESS);
|
try expect(err == .SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ test "statx" {
|
|||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
var statx_buf: linux.Statx = undefined;
|
var statx_buf: linux.Statx = undefined;
|
||||||
switch (linux.getErrno(linux.statx(file.handle, "", linux.AT.EMPTY_PATH, linux.STATX_BASIC_STATS, &statx_buf))) {
|
switch (linux.E.init(linux.statx(file.handle, "", linux.AT.EMPTY_PATH, linux.STATX_BASIC_STATS, &statx_buf))) {
|
||||||
.SUCCESS => {},
|
.SUCCESS => {},
|
||||||
// The statx syscall was only introduced in linux 4.11
|
// The statx syscall was only introduced in linux 4.11
|
||||||
.NOSYS => return error.SkipZigTest,
|
.NOSYS => return error.SkipZigTest,
|
||||||
@ -85,7 +85,7 @@ test "statx" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var stat_buf: linux.Stat = undefined;
|
var stat_buf: linux.Stat = undefined;
|
||||||
switch (linux.getErrno(linux.fstatat(file.handle, "", &stat_buf, linux.AT.EMPTY_PATH))) {
|
switch (linux.E.init(linux.fstatat(file.handle, "", &stat_buf, linux.AT.EMPTY_PATH))) {
|
||||||
.SUCCESS => {},
|
.SUCCESS => {},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const os = std.os;
|
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const elf = std.elf;
|
const elf = std.elf;
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const native_arch = @import("builtin").cpu.arch;
|
const native_arch = @import("builtin").cpu.arch;
|
||||||
|
const linux = std.os.linux;
|
||||||
|
const posix = std.posix;
|
||||||
|
|
||||||
// This file implements the two TLS variants [1] used by ELF-based systems.
|
// This file implements the two TLS variants [1] used by ELF-based systems.
|
||||||
//
|
//
|
||||||
@ -111,7 +112,7 @@ pub var tls_image: TLSImage = undefined;
|
|||||||
pub fn setThreadPointer(addr: usize) void {
|
pub fn setThreadPointer(addr: usize) void {
|
||||||
switch (native_arch) {
|
switch (native_arch) {
|
||||||
.x86 => {
|
.x86 => {
|
||||||
var user_desc = std.os.linux.user_desc{
|
var user_desc: linux.user_desc = .{
|
||||||
.entry_number = tls_image.gdt_entry_number,
|
.entry_number = tls_image.gdt_entry_number,
|
||||||
.base_addr = addr,
|
.base_addr = addr,
|
||||||
.limit = 0xfffff,
|
.limit = 0xfffff,
|
||||||
@ -124,7 +125,7 @@ pub fn setThreadPointer(addr: usize) void {
|
|||||||
.useable = 1,
|
.useable = 1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const rc = std.os.linux.syscall1(.set_thread_area, @intFromPtr(&user_desc));
|
const rc = linux.syscall1(.set_thread_area, @intFromPtr(&user_desc));
|
||||||
assert(rc == 0);
|
assert(rc == 0);
|
||||||
|
|
||||||
const gdt_entry_number = user_desc.entry_number;
|
const gdt_entry_number = user_desc.entry_number;
|
||||||
@ -137,7 +138,7 @@ pub fn setThreadPointer(addr: usize) void {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
.x86_64 => {
|
.x86_64 => {
|
||||||
const rc = std.os.linux.syscall2(.arch_prctl, std.os.linux.ARCH.SET_FS, addr);
|
const rc = linux.syscall2(.arch_prctl, linux.ARCH.SET_FS, addr);
|
||||||
assert(rc == 0);
|
assert(rc == 0);
|
||||||
},
|
},
|
||||||
.aarch64, .aarch64_be => {
|
.aarch64, .aarch64_be => {
|
||||||
@ -148,7 +149,7 @@ pub fn setThreadPointer(addr: usize) void {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
.arm, .thumb => {
|
.arm, .thumb => {
|
||||||
const rc = std.os.linux.syscall1(.set_tls, addr);
|
const rc = linux.syscall1(.set_tls, addr);
|
||||||
assert(rc == 0);
|
assert(rc == 0);
|
||||||
},
|
},
|
||||||
.riscv64 => {
|
.riscv64 => {
|
||||||
@ -159,7 +160,7 @@ pub fn setThreadPointer(addr: usize) void {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
.mips, .mipsel, .mips64, .mips64el => {
|
.mips, .mipsel, .mips64, .mips64el => {
|
||||||
const rc = std.os.linux.syscall1(.set_thread_area, addr);
|
const rc = linux.syscall1(.set_thread_area, addr);
|
||||||
assert(rc == 0);
|
assert(rc == 0);
|
||||||
},
|
},
|
||||||
.powerpc, .powerpcle => {
|
.powerpc, .powerpcle => {
|
||||||
@ -320,14 +321,14 @@ pub fn initStaticTLS(phdrs: []elf.Phdr) void {
|
|||||||
break :blk main_thread_tls_buffer[0..tls_image.alloc_size];
|
break :blk main_thread_tls_buffer[0..tls_image.alloc_size];
|
||||||
}
|
}
|
||||||
|
|
||||||
const alloc_tls_area = os.mmap(
|
const alloc_tls_area = posix.mmap(
|
||||||
null,
|
null,
|
||||||
tls_image.alloc_size + tls_image.alloc_align - 1,
|
tls_image.alloc_size + tls_image.alloc_align - 1,
|
||||||
os.PROT.READ | os.PROT.WRITE,
|
posix.PROT.READ | posix.PROT.WRITE,
|
||||||
.{ .TYPE = .PRIVATE, .ANONYMOUS = true },
|
.{ .TYPE = .PRIVATE, .ANONYMOUS = true },
|
||||||
-1,
|
-1,
|
||||||
0,
|
0,
|
||||||
) catch os.abort();
|
) catch posix.abort();
|
||||||
|
|
||||||
// Make sure the slice is correctly aligned.
|
// Make sure the slice is correctly aligned.
|
||||||
const begin_addr = @intFromPtr(alloc_tls_area.ptr);
|
const begin_addr = @intFromPtr(alloc_tls_area.ptr);
|
||||||
|
|||||||
@ -5,7 +5,7 @@ const mem = std.mem;
|
|||||||
const maxInt = std.math.maxInt;
|
const maxInt = std.math.maxInt;
|
||||||
|
|
||||||
pub fn lookup(vername: []const u8, name: []const u8) usize {
|
pub fn lookup(vername: []const u8, name: []const u8) usize {
|
||||||
const vdso_addr = std.os.system.getauxval(std.elf.AT_SYSINFO_EHDR);
|
const vdso_addr = linux.getauxval(std.elf.AT_SYSINFO_EHDR);
|
||||||
if (vdso_addr == 0) return 0;
|
if (vdso_addr == 0) return 0;
|
||||||
|
|
||||||
const eh = @as(*elf.Ehdr, @ptrFromInt(vdso_addr));
|
const eh = @as(*elf.Ehdr, @ptrFromInt(vdso_addr));
|
||||||
|
|||||||
@ -3,8 +3,8 @@ const maxInt = std.math.maxInt;
|
|||||||
const linux = std.os.linux;
|
const linux = std.os.linux;
|
||||||
const SYS = linux.SYS;
|
const SYS = linux.SYS;
|
||||||
const socklen_t = linux.socklen_t;
|
const socklen_t = linux.socklen_t;
|
||||||
const iovec = std.os.iovec;
|
const iovec = std.posix.iovec;
|
||||||
const iovec_const = std.os.iovec_const;
|
const iovec_const = std.posix.iovec_const;
|
||||||
const uid_t = linux.uid_t;
|
const uid_t = linux.uid_t;
|
||||||
const gid_t = linux.gid_t;
|
const gid_t = linux.gid_t;
|
||||||
const pid_t = linux.pid_t;
|
const pid_t = linux.pid_t;
|
||||||
|
|||||||
@ -2,8 +2,8 @@ const std = @import("../../std.zig");
|
|||||||
const maxInt = std.math.maxInt;
|
const maxInt = std.math.maxInt;
|
||||||
const linux = std.os.linux;
|
const linux = std.os.linux;
|
||||||
const SYS = linux.SYS;
|
const SYS = linux.SYS;
|
||||||
const iovec = std.os.iovec;
|
const iovec = std.posix.iovec;
|
||||||
const iovec_const = std.os.iovec_const;
|
const iovec_const = std.posix.iovec_const;
|
||||||
|
|
||||||
const pid_t = linux.pid_t;
|
const pid_t = linux.pid_t;
|
||||||
const uid_t = linux.uid_t;
|
const uid_t = linux.uid_t;
|
||||||
|
|||||||
@ -11,13 +11,96 @@ pub const syscall_bits = switch (builtin.cpu.arch) {
|
|||||||
.x86_64 => @import("plan9/x86_64.zig"),
|
.x86_64 => @import("plan9/x86_64.zig"),
|
||||||
else => @compileError("more plan9 syscall implementations (needs more inline asm in stage2"),
|
else => @compileError("more plan9 syscall implementations (needs more inline asm in stage2"),
|
||||||
};
|
};
|
||||||
pub const E = @import("plan9/errno.zig").E;
|
/// Ported from /sys/include/ape/errno.h
|
||||||
/// Get the errno from a syscall return value, or 0 for no error.
|
pub const E = enum(u16) {
|
||||||
pub fn getErrno(r: usize) E {
|
SUCCESS = 0,
|
||||||
const signed_r = @as(isize, @bitCast(r));
|
DOM = 1000,
|
||||||
|
RANGE = 1001,
|
||||||
|
PLAN9 = 1002,
|
||||||
|
|
||||||
|
@"2BIG" = 1,
|
||||||
|
ACCES = 2,
|
||||||
|
AGAIN = 3,
|
||||||
|
// WOULDBLOCK = 3, // TODO errno.h has 2 names for 3
|
||||||
|
BADF = 4,
|
||||||
|
BUSY = 5,
|
||||||
|
CHILD = 6,
|
||||||
|
DEADLK = 7,
|
||||||
|
EXIST = 8,
|
||||||
|
FAULT = 9,
|
||||||
|
FBIG = 10,
|
||||||
|
INTR = 11,
|
||||||
|
INVAL = 12,
|
||||||
|
IO = 13,
|
||||||
|
ISDIR = 14,
|
||||||
|
MFILE = 15,
|
||||||
|
MLINK = 16,
|
||||||
|
NAMETOOLONG = 17,
|
||||||
|
NFILE = 18,
|
||||||
|
NODEV = 19,
|
||||||
|
NOENT = 20,
|
||||||
|
NOEXEC = 21,
|
||||||
|
NOLCK = 22,
|
||||||
|
NOMEM = 23,
|
||||||
|
NOSPC = 24,
|
||||||
|
NOSYS = 25,
|
||||||
|
NOTDIR = 26,
|
||||||
|
NOTEMPTY = 27,
|
||||||
|
NOTTY = 28,
|
||||||
|
NXIO = 29,
|
||||||
|
PERM = 30,
|
||||||
|
PIPE = 31,
|
||||||
|
ROFS = 32,
|
||||||
|
SPIPE = 33,
|
||||||
|
SRCH = 34,
|
||||||
|
XDEV = 35,
|
||||||
|
|
||||||
|
// bsd networking software
|
||||||
|
NOTSOCK = 36,
|
||||||
|
PROTONOSUPPORT = 37,
|
||||||
|
// PROTOTYPE = 37, // TODO errno.h has two names for 37
|
||||||
|
CONNREFUSED = 38,
|
||||||
|
AFNOSUPPORT = 39,
|
||||||
|
NOBUFS = 40,
|
||||||
|
OPNOTSUPP = 41,
|
||||||
|
ADDRINUSE = 42,
|
||||||
|
DESTADDRREQ = 43,
|
||||||
|
MSGSIZE = 44,
|
||||||
|
NOPROTOOPT = 45,
|
||||||
|
SOCKTNOSUPPORT = 46,
|
||||||
|
PFNOSUPPORT = 47,
|
||||||
|
ADDRNOTAVAIL = 48,
|
||||||
|
NETDOWN = 49,
|
||||||
|
NETUNREACH = 50,
|
||||||
|
NETRESET = 51,
|
||||||
|
CONNABORTED = 52,
|
||||||
|
ISCONN = 53,
|
||||||
|
NOTCONN = 54,
|
||||||
|
SHUTDOWN = 55,
|
||||||
|
TOOMANYREFS = 56,
|
||||||
|
TIMEDOUT = 57,
|
||||||
|
HOSTDOWN = 58,
|
||||||
|
HOSTUNREACH = 59,
|
||||||
|
GREG = 60,
|
||||||
|
|
||||||
|
// These added in 1003.1b-1993
|
||||||
|
CANCELED = 61,
|
||||||
|
INPROGRESS = 62,
|
||||||
|
|
||||||
|
// We just add these to be compatible with std.os, which uses them,
|
||||||
|
// They should never get used.
|
||||||
|
DQUOT,
|
||||||
|
CONNRESET,
|
||||||
|
OVERFLOW,
|
||||||
|
LOOP,
|
||||||
|
TXTBSY,
|
||||||
|
|
||||||
|
pub fn init(r: usize) E {
|
||||||
|
const signed_r: isize = @bitCast(r);
|
||||||
const int = if (signed_r > -4096 and signed_r < 0) -signed_r else 0;
|
const int = if (signed_r > -4096 and signed_r < 0) -signed_r else 0;
|
||||||
return @as(E, @enumFromInt(int));
|
return @enumFromInt(int);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
// The max bytes that can be in the errstr buff
|
// The max bytes that can be in the errstr buff
|
||||||
pub const ERRMAX = 128;
|
pub const ERRMAX = 128;
|
||||||
var errstr_buf: [ERRMAX]u8 = undefined;
|
var errstr_buf: [ERRMAX]u8 = undefined;
|
||||||
|
|||||||
@ -1,84 +0,0 @@
|
|||||||
//! Ported from /sys/include/ape/errno.h
|
|
||||||
pub const E = enum(u16) {
|
|
||||||
SUCCESS = 0,
|
|
||||||
DOM = 1000,
|
|
||||||
RANGE = 1001,
|
|
||||||
PLAN9 = 1002,
|
|
||||||
|
|
||||||
@"2BIG" = 1,
|
|
||||||
ACCES = 2,
|
|
||||||
AGAIN = 3,
|
|
||||||
// WOULDBLOCK = 3, // TODO errno.h has 2 names for 3
|
|
||||||
BADF = 4,
|
|
||||||
BUSY = 5,
|
|
||||||
CHILD = 6,
|
|
||||||
DEADLK = 7,
|
|
||||||
EXIST = 8,
|
|
||||||
FAULT = 9,
|
|
||||||
FBIG = 10,
|
|
||||||
INTR = 11,
|
|
||||||
INVAL = 12,
|
|
||||||
IO = 13,
|
|
||||||
ISDIR = 14,
|
|
||||||
MFILE = 15,
|
|
||||||
MLINK = 16,
|
|
||||||
NAMETOOLONG = 17,
|
|
||||||
NFILE = 18,
|
|
||||||
NODEV = 19,
|
|
||||||
NOENT = 20,
|
|
||||||
NOEXEC = 21,
|
|
||||||
NOLCK = 22,
|
|
||||||
NOMEM = 23,
|
|
||||||
NOSPC = 24,
|
|
||||||
NOSYS = 25,
|
|
||||||
NOTDIR = 26,
|
|
||||||
NOTEMPTY = 27,
|
|
||||||
NOTTY = 28,
|
|
||||||
NXIO = 29,
|
|
||||||
PERM = 30,
|
|
||||||
PIPE = 31,
|
|
||||||
ROFS = 32,
|
|
||||||
SPIPE = 33,
|
|
||||||
SRCH = 34,
|
|
||||||
XDEV = 35,
|
|
||||||
|
|
||||||
// bsd networking software
|
|
||||||
NOTSOCK = 36,
|
|
||||||
PROTONOSUPPORT = 37,
|
|
||||||
// PROTOTYPE = 37, // TODO errno.h has two names for 37
|
|
||||||
CONNREFUSED = 38,
|
|
||||||
AFNOSUPPORT = 39,
|
|
||||||
NOBUFS = 40,
|
|
||||||
OPNOTSUPP = 41,
|
|
||||||
ADDRINUSE = 42,
|
|
||||||
DESTADDRREQ = 43,
|
|
||||||
MSGSIZE = 44,
|
|
||||||
NOPROTOOPT = 45,
|
|
||||||
SOCKTNOSUPPORT = 46,
|
|
||||||
PFNOSUPPORT = 47,
|
|
||||||
ADDRNOTAVAIL = 48,
|
|
||||||
NETDOWN = 49,
|
|
||||||
NETUNREACH = 50,
|
|
||||||
NETRESET = 51,
|
|
||||||
CONNABORTED = 52,
|
|
||||||
ISCONN = 53,
|
|
||||||
NOTCONN = 54,
|
|
||||||
SHUTDOWN = 55,
|
|
||||||
TOOMANYREFS = 56,
|
|
||||||
TIMEDOUT = 57,
|
|
||||||
HOSTDOWN = 58,
|
|
||||||
HOSTUNREACH = 59,
|
|
||||||
GREG = 60,
|
|
||||||
|
|
||||||
// These added in 1003.1b-1993
|
|
||||||
CANCELED = 61,
|
|
||||||
INPROGRESS = 62,
|
|
||||||
|
|
||||||
// We just add these to be compatible with std.os, which uses them,
|
|
||||||
// They should never get used.
|
|
||||||
DQUOT,
|
|
||||||
CONNRESET,
|
|
||||||
OVERFLOW,
|
|
||||||
LOOP,
|
|
||||||
TXTBSY,
|
|
||||||
};
|
|
||||||
@ -17,8 +17,8 @@ comptime {
|
|||||||
// assert(@alignOf(u64) == 8);
|
// assert(@alignOf(u64) == 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const iovec_t = std.os.iovec;
|
pub const iovec_t = std.posix.iovec;
|
||||||
pub const ciovec_t = std.os.iovec_const;
|
pub const ciovec_t = std.posix.iovec_const;
|
||||||
|
|
||||||
pub extern "wasi_snapshot_preview1" fn args_get(argv: [*][*:0]u8, argv_buf: [*]u8) errno_t;
|
pub extern "wasi_snapshot_preview1" fn args_get(argv: [*][*:0]u8, argv_buf: [*]u8) errno_t;
|
||||||
pub extern "wasi_snapshot_preview1" fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t;
|
pub extern "wasi_snapshot_preview1" fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t;
|
||||||
|
|||||||
@ -11,6 +11,7 @@ const assert = std.debug.assert;
|
|||||||
const math = std.math;
|
const math = std.math;
|
||||||
const maxInt = std.math.maxInt;
|
const maxInt = std.math.maxInt;
|
||||||
const native_arch = builtin.cpu.arch;
|
const native_arch = builtin.cpu.arch;
|
||||||
|
const UnexpectedError = std.posix.UnexpectedError;
|
||||||
|
|
||||||
test {
|
test {
|
||||||
if (builtin.os.tag == .windows) {
|
if (builtin.os.tag == .windows) {
|
||||||
@ -547,7 +548,7 @@ pub const GetQueuedCompletionStatusError = error{
|
|||||||
Cancelled,
|
Cancelled,
|
||||||
EOF,
|
EOF,
|
||||||
Timeout,
|
Timeout,
|
||||||
} || std.os.UnexpectedError;
|
} || UnexpectedError;
|
||||||
|
|
||||||
pub fn GetQueuedCompletionStatusEx(
|
pub fn GetQueuedCompletionStatusEx(
|
||||||
completion_port: HANDLE,
|
completion_port: HANDLE,
|
||||||
@ -1701,7 +1702,7 @@ pub fn VirtualProtectEx(handle: HANDLE, addr: ?LPVOID, size: SIZE_T, new_prot: D
|
|||||||
.SUCCESS => return old_prot,
|
.SUCCESS => return old_prot,
|
||||||
.INVALID_ADDRESS => return error.InvalidAddress,
|
.INVALID_ADDRESS => return error.InvalidAddress,
|
||||||
// TODO: map errors
|
// TODO: map errors
|
||||||
else => |rc| return std.os.windows.unexpectedStatus(rc),
|
else => |rc| return unexpectedStatus(rc),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1946,7 +1947,7 @@ pub fn SetFileTime(
|
|||||||
pub const LockFileError = error{
|
pub const LockFileError = error{
|
||||||
SystemResources,
|
SystemResources,
|
||||||
WouldBlock,
|
WouldBlock,
|
||||||
} || std.os.UnexpectedError;
|
} || UnexpectedError;
|
||||||
|
|
||||||
pub fn LockFile(
|
pub fn LockFile(
|
||||||
FileHandle: HANDLE,
|
FileHandle: HANDLE,
|
||||||
@ -1983,7 +1984,7 @@ pub fn LockFile(
|
|||||||
|
|
||||||
pub const UnlockFileError = error{
|
pub const UnlockFileError = error{
|
||||||
RangeNotLocked,
|
RangeNotLocked,
|
||||||
} || std.os.UnexpectedError;
|
} || UnexpectedError;
|
||||||
|
|
||||||
pub fn UnlockFile(
|
pub fn UnlockFile(
|
||||||
FileHandle: HANDLE,
|
FileHandle: HANDLE,
|
||||||
@ -2672,8 +2673,8 @@ pub fn loadWinsockExtensionFunction(comptime T: type, sock: ws2_32.SOCKET, guid:
|
|||||||
|
|
||||||
/// Call this when you made a windows DLL call or something that does SetLastError
|
/// Call this when you made a windows DLL call or something that does SetLastError
|
||||||
/// and you get an unexpected error.
|
/// and you get an unexpected error.
|
||||||
pub fn unexpectedError(err: Win32Error) std.os.UnexpectedError {
|
pub fn unexpectedError(err: Win32Error) UnexpectedError {
|
||||||
if (std.os.unexpected_error_tracing) {
|
if (std.posix.unexpected_error_tracing) {
|
||||||
// 614 is the length of the longest windows error description
|
// 614 is the length of the longest windows error description
|
||||||
var buf_wstr: [614]WCHAR = undefined;
|
var buf_wstr: [614]WCHAR = undefined;
|
||||||
const len = kernel32.FormatMessageW(
|
const len = kernel32.FormatMessageW(
|
||||||
@ -2694,14 +2695,14 @@ pub fn unexpectedError(err: Win32Error) std.os.UnexpectedError {
|
|||||||
return error.Unexpected;
|
return error.Unexpected;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unexpectedWSAError(err: ws2_32.WinsockError) std.os.UnexpectedError {
|
pub fn unexpectedWSAError(err: ws2_32.WinsockError) UnexpectedError {
|
||||||
return unexpectedError(@as(Win32Error, @enumFromInt(@intFromEnum(err))));
|
return unexpectedError(@as(Win32Error, @enumFromInt(@intFromEnum(err))));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call this when you made a windows NtDll call
|
/// Call this when you made a windows NtDll call
|
||||||
/// and you get an unexpected status.
|
/// and you get an unexpected status.
|
||||||
pub fn unexpectedStatus(status: NTSTATUS) std.os.UnexpectedError {
|
pub fn unexpectedStatus(status: NTSTATUS) UnexpectedError {
|
||||||
if (std.os.unexpected_error_tracing) {
|
if (std.posix.unexpected_error_tracing) {
|
||||||
std.debug.print("error.Unexpected NTSTATUS=0x{x}\n", .{@intFromEnum(status)});
|
std.debug.print("error.Unexpected NTSTATUS=0x{x}\n", .{@intFromEnum(status)});
|
||||||
std.debug.dumpCurrentStackTrace(@returnAddress());
|
std.debug.dumpCurrentStackTrace(@returnAddress());
|
||||||
}
|
}
|
||||||
@ -4246,7 +4247,7 @@ pub const KNONVOLATILE_CONTEXT_POINTERS = switch (native_arch) {
|
|||||||
|
|
||||||
pub const EXCEPTION_POINTERS = extern struct {
|
pub const EXCEPTION_POINTERS = extern struct {
|
||||||
ExceptionRecord: *EXCEPTION_RECORD,
|
ExceptionRecord: *EXCEPTION_RECORD,
|
||||||
ContextRecord: *std.os.windows.CONTEXT,
|
ContextRecord: *CONTEXT,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const VECTORED_EXCEPTION_HANDLER = *const fn (ExceptionInfo: *EXCEPTION_POINTERS) callconv(WINAPI) c_long;
|
pub const VECTORED_EXCEPTION_HANDLER = *const fn (ExceptionInfo: *EXCEPTION_POINTERS) callconv(WINAPI) c_long;
|
||||||
|
|||||||
@ -245,7 +245,7 @@ test "loadWinsockExtensionFunction" {
|
|||||||
const LPFN_CONNECTEX = *const fn (
|
const LPFN_CONNECTEX = *const fn (
|
||||||
Socket: windows.ws2_32.SOCKET,
|
Socket: windows.ws2_32.SOCKET,
|
||||||
SockAddr: *const windows.ws2_32.sockaddr,
|
SockAddr: *const windows.ws2_32.sockaddr,
|
||||||
SockLen: std.os.socklen_t,
|
SockLen: std.posix.socklen_t,
|
||||||
SendBuf: ?*const anyopaque,
|
SendBuf: ?*const anyopaque,
|
||||||
SendBufLen: windows.DWORD,
|
SendBufLen: windows.DWORD,
|
||||||
BytesSent: *windows.DWORD,
|
BytesSent: *windows.DWORD,
|
||||||
@ -254,7 +254,7 @@ test "loadWinsockExtensionFunction" {
|
|||||||
|
|
||||||
_ = windows.loadWinsockExtensionFunction(
|
_ = windows.loadWinsockExtensionFunction(
|
||||||
LPFN_CONNECTEX,
|
LPFN_CONNECTEX,
|
||||||
try std.os.socket(std.os.AF.INET, std.os.SOCK.DGRAM, 0),
|
try std.posix.socket(std.posix.AF.INET, std.posix.SOCK.DGRAM, 0),
|
||||||
windows.ws2_32.WSAID_CONNECTEX,
|
windows.ws2_32.WSAID_CONNECTEX,
|
||||||
) catch |err| switch (err) {
|
) catch |err| switch (err) {
|
||||||
error.OperationNotSupported => unreachable,
|
error.OperationNotSupported => unreachable,
|
||||||
|
|||||||
@ -2,7 +2,6 @@ const std = @import("std.zig");
|
|||||||
const io = std.io;
|
const io = std.io;
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const os = std.os;
|
|
||||||
const coff = std.coff;
|
const coff = std.coff;
|
||||||
const fs = std.fs;
|
const fs = std.fs;
|
||||||
const File = std.fs.File;
|
const File = std.fs.File;
|
||||||
|
|||||||
7364
lib/std/posix.zig
Normal file
7364
lib/std/posix.zig
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
|||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const os = std.os;
|
const posix = std.posix;
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const expect = testing.expect;
|
const expect = testing.expect;
|
||||||
const expectEqual = testing.expectEqual;
|
const expectEqual = testing.expectEqual;
|
||||||
@ -10,6 +10,7 @@ const mem = std.mem;
|
|||||||
const elf = std.elf;
|
const elf = std.elf;
|
||||||
const File = std.fs.File;
|
const File = std.fs.File;
|
||||||
const Thread = std.Thread;
|
const Thread = std.Thread;
|
||||||
|
const linux = std.os.linux;
|
||||||
|
|
||||||
const a = std.testing.allocator;
|
const a = std.testing.allocator;
|
||||||
|
|
||||||
@ -31,26 +32,26 @@ test "chdir smoke test" {
|
|||||||
|
|
||||||
// Get current working directory path
|
// Get current working directory path
|
||||||
var old_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
|
var old_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
const old_cwd = try os.getcwd(old_cwd_buf[0..]);
|
const old_cwd = try posix.getcwd(old_cwd_buf[0..]);
|
||||||
|
|
||||||
{
|
{
|
||||||
// Firstly, changing to itself should have no effect
|
// Firstly, changing to itself should have no effect
|
||||||
try os.chdir(old_cwd);
|
try posix.chdir(old_cwd);
|
||||||
var new_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
|
var new_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
const new_cwd = try os.getcwd(new_cwd_buf[0..]);
|
const new_cwd = try posix.getcwd(new_cwd_buf[0..]);
|
||||||
try expect(mem.eql(u8, old_cwd, new_cwd));
|
try expect(mem.eql(u8, old_cwd, new_cwd));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next, change current working directory to one level above
|
// Next, change current working directory to one level above
|
||||||
if (native_os != .wasi) { // WASI does not support navigating outside of Preopens
|
if (native_os != .wasi) { // WASI does not support navigating outside of Preopens
|
||||||
const parent = fs.path.dirname(old_cwd) orelse unreachable; // old_cwd should be absolute
|
const parent = fs.path.dirname(old_cwd) orelse unreachable; // old_cwd should be absolute
|
||||||
try os.chdir(parent);
|
try posix.chdir(parent);
|
||||||
|
|
||||||
// Restore cwd because process may have other tests that do not tolerate chdir.
|
// Restore cwd because process may have other tests that do not tolerate chdir.
|
||||||
defer os.chdir(old_cwd) catch unreachable;
|
defer posix.chdir(old_cwd) catch unreachable;
|
||||||
|
|
||||||
var new_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
|
var new_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
const new_cwd = try os.getcwd(new_cwd_buf[0..]);
|
const new_cwd = try posix.getcwd(new_cwd_buf[0..]);
|
||||||
try expect(mem.eql(u8, parent, new_cwd));
|
try expect(mem.eql(u8, parent, new_cwd));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,10 +66,10 @@ test "chdir smoke test" {
|
|||||||
var tmp_dir = try fs.cwd().makeOpenPath("zig-test-tmp", .{});
|
var tmp_dir = try fs.cwd().makeOpenPath("zig-test-tmp", .{});
|
||||||
|
|
||||||
// Change current working directory to tmp directory
|
// Change current working directory to tmp directory
|
||||||
try os.chdir("zig-test-tmp");
|
try posix.chdir("zig-test-tmp");
|
||||||
|
|
||||||
var new_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
|
var new_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
const new_cwd = try os.getcwd(new_cwd_buf[0..]);
|
const new_cwd = try posix.getcwd(new_cwd_buf[0..]);
|
||||||
|
|
||||||
// On Windows, fs.path.resolve returns an uppercase drive letter, but the drive letter returned by getcwd may be lowercase
|
// On Windows, fs.path.resolve returns an uppercase drive letter, but the drive letter returned by getcwd may be lowercase
|
||||||
var resolved_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
|
var resolved_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
@ -80,7 +81,7 @@ test "chdir smoke test" {
|
|||||||
|
|
||||||
// Restore cwd because process may have other tests that do not tolerate chdir.
|
// Restore cwd because process may have other tests that do not tolerate chdir.
|
||||||
tmp_dir.close();
|
tmp_dir.close();
|
||||||
os.chdir(old_cwd) catch unreachable;
|
posix.chdir(old_cwd) catch unreachable;
|
||||||
try fs.cwd().deleteDir("zig-test-tmp");
|
try fs.cwd().deleteDir("zig-test-tmp");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,39 +106,39 @@ test "open smoke test" {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var file_path: []u8 = undefined;
|
var file_path: []u8 = undefined;
|
||||||
var fd: os.fd_t = undefined;
|
var fd: posix.fd_t = undefined;
|
||||||
const mode: os.mode_t = if (native_os == .windows) 0 else 0o666;
|
const mode: posix.mode_t = if (native_os == .windows) 0 else 0o666;
|
||||||
|
|
||||||
// Create some file using `open`.
|
// Create some file using `open`.
|
||||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
||||||
fd = try os.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
|
fd = try posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
|
||||||
os.close(fd);
|
posix.close(fd);
|
||||||
|
|
||||||
// Try this again with the same flags. This op should fail with error.PathAlreadyExists.
|
// Try this again with the same flags. This op should fail with error.PathAlreadyExists.
|
||||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
||||||
try expectError(error.PathAlreadyExists, os.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode));
|
try expectError(error.PathAlreadyExists, posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode));
|
||||||
|
|
||||||
// Try opening without `EXCL` flag.
|
// Try opening without `EXCL` flag.
|
||||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
||||||
fd = try os.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true }, mode);
|
fd = try posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true }, mode);
|
||||||
os.close(fd);
|
posix.close(fd);
|
||||||
|
|
||||||
// Try opening as a directory which should fail.
|
// Try opening as a directory which should fail.
|
||||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
||||||
try expectError(error.NotDir, os.open(file_path, .{ .ACCMODE = .RDWR, .DIRECTORY = true }, mode));
|
try expectError(error.NotDir, posix.open(file_path, .{ .ACCMODE = .RDWR, .DIRECTORY = true }, mode));
|
||||||
|
|
||||||
// Create some directory
|
// Create some directory
|
||||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
|
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
|
||||||
try os.mkdir(file_path, mode);
|
try posix.mkdir(file_path, mode);
|
||||||
|
|
||||||
// Open dir using `open`
|
// Open dir using `open`
|
||||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
|
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
|
||||||
fd = try os.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode);
|
fd = try posix.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode);
|
||||||
os.close(fd);
|
posix.close(fd);
|
||||||
|
|
||||||
// Try opening as file which should fail.
|
// Try opening as file which should fail.
|
||||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
|
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
|
||||||
try expectError(error.IsDir, os.open(file_path, .{ .ACCMODE = .RDWR }, mode));
|
try expectError(error.IsDir, posix.open(file_path, .{ .ACCMODE = .RDWR }, mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "openat smoke test" {
|
test "openat smoke test" {
|
||||||
@ -149,49 +150,49 @@ test "openat smoke test" {
|
|||||||
var tmp = tmpDir(.{});
|
var tmp = tmpDir(.{});
|
||||||
defer tmp.cleanup();
|
defer tmp.cleanup();
|
||||||
|
|
||||||
var fd: os.fd_t = undefined;
|
var fd: posix.fd_t = undefined;
|
||||||
const mode: os.mode_t = if (native_os == .windows) 0 else 0o666;
|
const mode: posix.mode_t = if (native_os == .windows) 0 else 0o666;
|
||||||
|
|
||||||
// Create some file using `openat`.
|
// Create some file using `openat`.
|
||||||
fd = try os.openat(tmp.dir.fd, "some_file", os.CommonOpenFlags.lower(.{
|
fd = try posix.openat(tmp.dir.fd, "some_file", CommonOpenFlags.lower(.{
|
||||||
.ACCMODE = .RDWR,
|
.ACCMODE = .RDWR,
|
||||||
.CREAT = true,
|
.CREAT = true,
|
||||||
.EXCL = true,
|
.EXCL = true,
|
||||||
}), mode);
|
}), mode);
|
||||||
os.close(fd);
|
posix.close(fd);
|
||||||
|
|
||||||
// Try this again with the same flags. This op should fail with error.PathAlreadyExists.
|
// Try this again with the same flags. This op should fail with error.PathAlreadyExists.
|
||||||
try expectError(error.PathAlreadyExists, os.openat(tmp.dir.fd, "some_file", os.CommonOpenFlags.lower(.{
|
try expectError(error.PathAlreadyExists, posix.openat(tmp.dir.fd, "some_file", CommonOpenFlags.lower(.{
|
||||||
.ACCMODE = .RDWR,
|
.ACCMODE = .RDWR,
|
||||||
.CREAT = true,
|
.CREAT = true,
|
||||||
.EXCL = true,
|
.EXCL = true,
|
||||||
}), mode));
|
}), mode));
|
||||||
|
|
||||||
// Try opening without `EXCL` flag.
|
// Try opening without `EXCL` flag.
|
||||||
fd = try os.openat(tmp.dir.fd, "some_file", os.CommonOpenFlags.lower(.{
|
fd = try posix.openat(tmp.dir.fd, "some_file", CommonOpenFlags.lower(.{
|
||||||
.ACCMODE = .RDWR,
|
.ACCMODE = .RDWR,
|
||||||
.CREAT = true,
|
.CREAT = true,
|
||||||
}), mode);
|
}), mode);
|
||||||
os.close(fd);
|
posix.close(fd);
|
||||||
|
|
||||||
// Try opening as a directory which should fail.
|
// Try opening as a directory which should fail.
|
||||||
try expectError(error.NotDir, os.openat(tmp.dir.fd, "some_file", os.CommonOpenFlags.lower(.{
|
try expectError(error.NotDir, posix.openat(tmp.dir.fd, "some_file", CommonOpenFlags.lower(.{
|
||||||
.ACCMODE = .RDWR,
|
.ACCMODE = .RDWR,
|
||||||
.DIRECTORY = true,
|
.DIRECTORY = true,
|
||||||
}), mode));
|
}), mode));
|
||||||
|
|
||||||
// Create some directory
|
// Create some directory
|
||||||
try os.mkdirat(tmp.dir.fd, "some_dir", mode);
|
try posix.mkdirat(tmp.dir.fd, "some_dir", mode);
|
||||||
|
|
||||||
// Open dir using `open`
|
// Open dir using `open`
|
||||||
fd = try os.openat(tmp.dir.fd, "some_dir", os.CommonOpenFlags.lower(.{
|
fd = try posix.openat(tmp.dir.fd, "some_dir", CommonOpenFlags.lower(.{
|
||||||
.ACCMODE = .RDONLY,
|
.ACCMODE = .RDONLY,
|
||||||
.DIRECTORY = true,
|
.DIRECTORY = true,
|
||||||
}), mode);
|
}), mode);
|
||||||
os.close(fd);
|
posix.close(fd);
|
||||||
|
|
||||||
// Try opening as file which should fail.
|
// Try opening as file which should fail.
|
||||||
try expectError(error.IsDir, os.openat(tmp.dir.fd, "some_dir", os.CommonOpenFlags.lower(.{
|
try expectError(error.IsDir, posix.openat(tmp.dir.fd, "some_dir", CommonOpenFlags.lower(.{
|
||||||
.ACCMODE = .RDWR,
|
.ACCMODE = .RDWR,
|
||||||
}), mode));
|
}), mode));
|
||||||
}
|
}
|
||||||
@ -211,7 +212,7 @@ test "symlink with relative paths" {
|
|||||||
try cwd.writeFile("file.txt", "nonsense");
|
try cwd.writeFile("file.txt", "nonsense");
|
||||||
|
|
||||||
if (native_os == .windows) {
|
if (native_os == .windows) {
|
||||||
os.windows.CreateSymbolicLink(
|
std.os.windows.CreateSymbolicLink(
|
||||||
cwd.fd,
|
cwd.fd,
|
||||||
&[_]u16{ 's', 'y', 'm', 'l', 'i', 'n', 'k', 'e', 'd' },
|
&[_]u16{ 's', 'y', 'm', 'l', 'i', 'n', 'k', 'e', 'd' },
|
||||||
&[_:0]u16{ 'f', 'i', 'l', 'e', '.', 't', 'x', 't' },
|
&[_:0]u16{ 'f', 'i', 'l', 'e', '.', 't', 'x', 't' },
|
||||||
@ -226,11 +227,11 @@ test "symlink with relative paths" {
|
|||||||
else => return err,
|
else => return err,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
try os.symlink("file.txt", "symlinked");
|
try posix.symlink("file.txt", "symlinked");
|
||||||
}
|
}
|
||||||
|
|
||||||
var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
|
var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
const given = try os.readlink("symlinked", buffer[0..]);
|
const given = try posix.readlink("symlinked", buffer[0..]);
|
||||||
try expect(mem.eql(u8, "file.txt", given));
|
try expect(mem.eql(u8, "file.txt", given));
|
||||||
|
|
||||||
try cwd.deleteFile("file.txt");
|
try cwd.deleteFile("file.txt");
|
||||||
@ -247,7 +248,7 @@ test "readlink on Windows" {
|
|||||||
|
|
||||||
fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void {
|
fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void {
|
||||||
var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
|
var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
const given = try os.readlink(symlink_path, buffer[0..]);
|
const given = try posix.readlink(symlink_path, buffer[0..]);
|
||||||
try expect(mem.eql(u8, target_path, given));
|
try expect(mem.eql(u8, target_path, given));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +269,7 @@ test "link with relative paths" {
|
|||||||
cwd.deleteFile("new.txt") catch {};
|
cwd.deleteFile("new.txt") catch {};
|
||||||
|
|
||||||
try cwd.writeFile("example.txt", "example");
|
try cwd.writeFile("example.txt", "example");
|
||||||
try os.link("example.txt", "new.txt", 0);
|
try posix.link("example.txt", "new.txt", 0);
|
||||||
|
|
||||||
const efd = try cwd.openFile("example.txt", .{});
|
const efd = try cwd.openFile("example.txt", .{});
|
||||||
defer efd.close();
|
defer efd.close();
|
||||||
@ -277,17 +278,17 @@ test "link with relative paths" {
|
|||||||
defer nfd.close();
|
defer nfd.close();
|
||||||
|
|
||||||
{
|
{
|
||||||
const estat = try os.fstat(efd.handle);
|
const estat = try posix.fstat(efd.handle);
|
||||||
const nstat = try os.fstat(nfd.handle);
|
const nstat = try posix.fstat(nfd.handle);
|
||||||
|
|
||||||
try testing.expectEqual(estat.ino, nstat.ino);
|
try testing.expectEqual(estat.ino, nstat.ino);
|
||||||
try testing.expectEqual(@as(@TypeOf(nstat.nlink), 2), nstat.nlink);
|
try testing.expectEqual(@as(@TypeOf(nstat.nlink), 2), nstat.nlink);
|
||||||
}
|
}
|
||||||
|
|
||||||
try os.unlink("new.txt");
|
try posix.unlink("new.txt");
|
||||||
|
|
||||||
{
|
{
|
||||||
const estat = try os.fstat(efd.handle);
|
const estat = try posix.fstat(efd.handle);
|
||||||
try testing.expectEqual(@as(@TypeOf(estat.nlink), 1), estat.nlink);
|
try testing.expectEqual(@as(@TypeOf(estat.nlink), 1), estat.nlink);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -312,7 +313,7 @@ test "linkat with different directories" {
|
|||||||
tmp.dir.deleteFile("new.txt") catch {};
|
tmp.dir.deleteFile("new.txt") catch {};
|
||||||
|
|
||||||
try cwd.writeFile("example.txt", "example");
|
try cwd.writeFile("example.txt", "example");
|
||||||
try os.linkat(cwd.fd, "example.txt", tmp.dir.fd, "new.txt", 0);
|
try posix.linkat(cwd.fd, "example.txt", tmp.dir.fd, "new.txt", 0);
|
||||||
|
|
||||||
const efd = try cwd.openFile("example.txt", .{});
|
const efd = try cwd.openFile("example.txt", .{});
|
||||||
defer efd.close();
|
defer efd.close();
|
||||||
@ -321,17 +322,17 @@ test "linkat with different directories" {
|
|||||||
|
|
||||||
{
|
{
|
||||||
defer nfd.close();
|
defer nfd.close();
|
||||||
const estat = try os.fstat(efd.handle);
|
const estat = try posix.fstat(efd.handle);
|
||||||
const nstat = try os.fstat(nfd.handle);
|
const nstat = try posix.fstat(nfd.handle);
|
||||||
|
|
||||||
try testing.expectEqual(estat.ino, nstat.ino);
|
try testing.expectEqual(estat.ino, nstat.ino);
|
||||||
try testing.expectEqual(@as(@TypeOf(nstat.nlink), 2), nstat.nlink);
|
try testing.expectEqual(@as(@TypeOf(nstat.nlink), 2), nstat.nlink);
|
||||||
}
|
}
|
||||||
|
|
||||||
try os.unlinkat(tmp.dir.fd, "new.txt", 0);
|
try posix.unlinkat(tmp.dir.fd, "new.txt", 0);
|
||||||
|
|
||||||
{
|
{
|
||||||
const estat = try os.fstat(efd.handle);
|
const estat = try posix.fstat(efd.handle);
|
||||||
try testing.expectEqual(@as(@TypeOf(estat.nlink), 1), estat.nlink);
|
try testing.expectEqual(@as(@TypeOf(estat.nlink), 1), estat.nlink);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,12 +352,12 @@ test "fstatat" {
|
|||||||
|
|
||||||
// fetch file's info on the opened fd directly
|
// fetch file's info on the opened fd directly
|
||||||
const file = try tmp.dir.openFile("file.txt", .{});
|
const file = try tmp.dir.openFile("file.txt", .{});
|
||||||
const stat = try os.fstat(file.handle);
|
const stat = try posix.fstat(file.handle);
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
// now repeat but using `fstatat` instead
|
// now repeat but using `fstatat` instead
|
||||||
const flags = if (native_os == .wasi) 0x0 else os.AT.SYMLINK_NOFOLLOW;
|
const flags = if (native_os == .wasi) 0x0 else posix.AT.SYMLINK_NOFOLLOW;
|
||||||
const statat = try os.fstatat(tmp.dir.fd, "file.txt", flags);
|
const statat = try posix.fstatat(tmp.dir.fd, "file.txt", flags);
|
||||||
try expectEqual(stat, statat);
|
try expectEqual(stat, statat);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,7 +370,7 @@ test "readlinkat" {
|
|||||||
|
|
||||||
// create a symbolic link
|
// create a symbolic link
|
||||||
if (native_os == .windows) {
|
if (native_os == .windows) {
|
||||||
os.windows.CreateSymbolicLink(
|
std.os.windows.CreateSymbolicLink(
|
||||||
tmp.dir.fd,
|
tmp.dir.fd,
|
||||||
&[_]u16{ 'l', 'i', 'n', 'k' },
|
&[_]u16{ 'l', 'i', 'n', 'k' },
|
||||||
&[_:0]u16{ 'f', 'i', 'l', 'e', '.', 't', 'x', 't' },
|
&[_:0]u16{ 'f', 'i', 'l', 'e', '.', 't', 'x', 't' },
|
||||||
@ -380,12 +381,12 @@ test "readlinkat" {
|
|||||||
else => return err,
|
else => return err,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
try os.symlinkat("file.txt", tmp.dir.fd, "link");
|
try posix.symlinkat("file.txt", tmp.dir.fd, "link");
|
||||||
}
|
}
|
||||||
|
|
||||||
// read the link
|
// read the link
|
||||||
var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
|
var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
const read_link = try os.readlinkat(tmp.dir.fd, "link", buffer[0..]);
|
const read_link = try posix.readlinkat(tmp.dir.fd, "link", buffer[0..]);
|
||||||
try expect(mem.eql(u8, "file.txt", read_link));
|
try expect(mem.eql(u8, "file.txt", read_link));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,8 +457,8 @@ fn testTls() !void {
|
|||||||
test "getrandom" {
|
test "getrandom" {
|
||||||
var buf_a: [50]u8 = undefined;
|
var buf_a: [50]u8 = undefined;
|
||||||
var buf_b: [50]u8 = undefined;
|
var buf_b: [50]u8 = undefined;
|
||||||
try os.getrandom(&buf_a);
|
try posix.getrandom(&buf_a);
|
||||||
try os.getrandom(&buf_b);
|
try posix.getrandom(&buf_b);
|
||||||
// If this test fails the chance is significantly higher that there is a bug than
|
// If this test fails the chance is significantly higher that there is a bug than
|
||||||
// that two sets of 50 bytes were equal.
|
// that two sets of 50 bytes were equal.
|
||||||
try expect(!mem.eql(u8, &buf_a, &buf_b));
|
try expect(!mem.eql(u8, &buf_a, &buf_b));
|
||||||
@ -466,23 +467,23 @@ test "getrandom" {
|
|||||||
test "getcwd" {
|
test "getcwd" {
|
||||||
// at least call it so it gets compiled
|
// at least call it so it gets compiled
|
||||||
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
_ = os.getcwd(&buf) catch undefined;
|
_ = posix.getcwd(&buf) catch undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "sigaltstack" {
|
test "sigaltstack" {
|
||||||
if (native_os == .windows or native_os == .wasi) return error.SkipZigTest;
|
if (native_os == .windows or native_os == .wasi) return error.SkipZigTest;
|
||||||
|
|
||||||
var st: os.stack_t = undefined;
|
var st: posix.stack_t = undefined;
|
||||||
try os.sigaltstack(null, &st);
|
try posix.sigaltstack(null, &st);
|
||||||
// Setting a stack size less than MINSIGSTKSZ returns ENOMEM
|
// Setting a stack size less than MINSIGSTKSZ returns ENOMEM
|
||||||
st.flags = 0;
|
st.flags = 0;
|
||||||
st.size = 1;
|
st.size = 1;
|
||||||
try testing.expectError(error.SizeTooSmall, os.sigaltstack(&st, null));
|
try testing.expectError(error.SizeTooSmall, posix.sigaltstack(&st, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the type is not available use void to avoid erroring out when `iter_fn` is
|
// If the type is not available use void to avoid erroring out when `iter_fn` is
|
||||||
// analyzed
|
// analyzed
|
||||||
const dl_phdr_info = if (@hasDecl(os.system, "dl_phdr_info")) os.dl_phdr_info else anyopaque;
|
const dl_phdr_info = if (@hasDecl(posix.system, "dl_phdr_info")) posix.dl_phdr_info else anyopaque;
|
||||||
|
|
||||||
const IterFnError = error{
|
const IterFnError = error{
|
||||||
MissingPtLoadSegment,
|
MissingPtLoadSegment,
|
||||||
@ -527,7 +528,7 @@ test "dl_iterate_phdr" {
|
|||||||
if (builtin.object_format != .elf) return error.SkipZigTest;
|
if (builtin.object_format != .elf) return error.SkipZigTest;
|
||||||
|
|
||||||
var counter: usize = 0;
|
var counter: usize = 0;
|
||||||
try os.dl_iterate_phdr(&counter, IterFnError, iter_fn);
|
try posix.dl_iterate_phdr(&counter, IterFnError, iter_fn);
|
||||||
try expect(counter != 0);
|
try expect(counter != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -535,8 +536,8 @@ test "gethostname" {
|
|||||||
if (native_os == .windows or native_os == .wasi)
|
if (native_os == .windows or native_os == .wasi)
|
||||||
return error.SkipZigTest;
|
return error.SkipZigTest;
|
||||||
|
|
||||||
var buf: [os.HOST_NAME_MAX]u8 = undefined;
|
var buf: [posix.HOST_NAME_MAX]u8 = undefined;
|
||||||
const hostname = try os.gethostname(&buf);
|
const hostname = try posix.gethostname(&buf);
|
||||||
try expect(hostname.len != 0);
|
try expect(hostname.len != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -544,13 +545,13 @@ test "pipe" {
|
|||||||
if (native_os == .windows or native_os == .wasi)
|
if (native_os == .windows or native_os == .wasi)
|
||||||
return error.SkipZigTest;
|
return error.SkipZigTest;
|
||||||
|
|
||||||
const fds = try os.pipe();
|
const fds = try posix.pipe();
|
||||||
try expect((try os.write(fds[1], "hello")) == 5);
|
try expect((try posix.write(fds[1], "hello")) == 5);
|
||||||
var buf: [16]u8 = undefined;
|
var buf: [16]u8 = undefined;
|
||||||
try expect((try os.read(fds[0], buf[0..])) == 5);
|
try expect((try posix.read(fds[0], buf[0..])) == 5);
|
||||||
try testing.expectEqualSlices(u8, buf[0..5], "hello");
|
try testing.expectEqualSlices(u8, buf[0..5], "hello");
|
||||||
os.close(fds[1]);
|
posix.close(fds[1]);
|
||||||
os.close(fds[0]);
|
posix.close(fds[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "argsAlloc" {
|
test "argsAlloc" {
|
||||||
@ -569,17 +570,17 @@ test "memfd_create" {
|
|||||||
else => return error.SkipZigTest,
|
else => return error.SkipZigTest,
|
||||||
}
|
}
|
||||||
|
|
||||||
const fd = os.memfd_create("test", 0) catch |err| switch (err) {
|
const fd = posix.memfd_create("test", 0) catch |err| switch (err) {
|
||||||
// Related: https://github.com/ziglang/zig/issues/4019
|
// Related: https://github.com/ziglang/zig/issues/4019
|
||||||
error.SystemOutdated => return error.SkipZigTest,
|
error.SystemOutdated => return error.SkipZigTest,
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
};
|
};
|
||||||
defer os.close(fd);
|
defer posix.close(fd);
|
||||||
try expect((try os.write(fd, "test")) == 4);
|
try expect((try posix.write(fd, "test")) == 4);
|
||||||
try os.lseek_SET(fd, 0);
|
try posix.lseek_SET(fd, 0);
|
||||||
|
|
||||||
var buf: [10]u8 = undefined;
|
var buf: [10]u8 = undefined;
|
||||||
const bytes_read = try os.read(fd, &buf);
|
const bytes_read = try posix.read(fd, &buf);
|
||||||
try expect(bytes_read == 4);
|
try expect(bytes_read == 4);
|
||||||
try expect(mem.eql(u8, buf[0..4], "test"));
|
try expect(mem.eql(u8, buf[0..4], "test"));
|
||||||
}
|
}
|
||||||
@ -593,15 +594,15 @@ test "mmap" {
|
|||||||
|
|
||||||
// Simple mmap() call with non page-aligned size
|
// Simple mmap() call with non page-aligned size
|
||||||
{
|
{
|
||||||
const data = try os.mmap(
|
const data = try posix.mmap(
|
||||||
null,
|
null,
|
||||||
1234,
|
1234,
|
||||||
os.PROT.READ | os.PROT.WRITE,
|
posix.PROT.READ | posix.PROT.WRITE,
|
||||||
.{ .TYPE = .PRIVATE, .ANONYMOUS = true },
|
.{ .TYPE = .PRIVATE, .ANONYMOUS = true },
|
||||||
-1,
|
-1,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
defer os.munmap(data);
|
defer posix.munmap(data);
|
||||||
|
|
||||||
try testing.expectEqual(@as(usize, 1234), data.len);
|
try testing.expectEqual(@as(usize, 1234), data.len);
|
||||||
|
|
||||||
@ -635,15 +636,15 @@ test "mmap" {
|
|||||||
const file = try tmp.dir.openFile(test_out_file, .{});
|
const file = try tmp.dir.openFile(test_out_file, .{});
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
const data = try os.mmap(
|
const data = try posix.mmap(
|
||||||
null,
|
null,
|
||||||
alloc_size,
|
alloc_size,
|
||||||
os.PROT.READ,
|
posix.PROT.READ,
|
||||||
.{ .TYPE = .PRIVATE },
|
.{ .TYPE = .PRIVATE },
|
||||||
file.handle,
|
file.handle,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
defer os.munmap(data);
|
defer posix.munmap(data);
|
||||||
|
|
||||||
var mem_stream = io.fixedBufferStream(data);
|
var mem_stream = io.fixedBufferStream(data);
|
||||||
const stream = mem_stream.reader();
|
const stream = mem_stream.reader();
|
||||||
@ -659,15 +660,15 @@ test "mmap" {
|
|||||||
const file = try tmp.dir.openFile(test_out_file, .{});
|
const file = try tmp.dir.openFile(test_out_file, .{});
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
const data = try os.mmap(
|
const data = try posix.mmap(
|
||||||
null,
|
null,
|
||||||
alloc_size / 2,
|
alloc_size / 2,
|
||||||
os.PROT.READ,
|
posix.PROT.READ,
|
||||||
.{ .TYPE = .PRIVATE },
|
.{ .TYPE = .PRIVATE },
|
||||||
file.handle,
|
file.handle,
|
||||||
alloc_size / 2,
|
alloc_size / 2,
|
||||||
);
|
);
|
||||||
defer os.munmap(data);
|
defer posix.munmap(data);
|
||||||
|
|
||||||
var mem_stream = io.fixedBufferStream(data);
|
var mem_stream = io.fixedBufferStream(data);
|
||||||
const stream = mem_stream.reader();
|
const stream = mem_stream.reader();
|
||||||
@ -683,14 +684,14 @@ test "mmap" {
|
|||||||
|
|
||||||
test "getenv" {
|
test "getenv" {
|
||||||
if (native_os == .wasi and !builtin.link_libc) {
|
if (native_os == .wasi and !builtin.link_libc) {
|
||||||
// std.os.getenv is not supported on WASI due to the need of allocation
|
// std.posix.getenv is not supported on WASI due to the need of allocation
|
||||||
return error.SkipZigTest;
|
return error.SkipZigTest;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (native_os == .windows) {
|
if (native_os == .windows) {
|
||||||
try expect(os.getenvW(&[_:0]u16{ 'B', 'O', 'G', 'U', 'S', 0x11, 0x22, 0x33, 0x44, 0x55 }) == null);
|
try expect(std.process.getenvW(&[_:0]u16{ 'B', 'O', 'G', 'U', 'S', 0x11, 0x22, 0x33, 0x44, 0x55 }) == null);
|
||||||
} else {
|
} else {
|
||||||
try expect(os.getenvZ("BOGUSDOESNOTEXISTENVVAR") == null);
|
try expect(posix.getenvZ("BOGUSDOESNOTEXISTENVVAR") == null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -711,18 +712,18 @@ test "fcntl" {
|
|||||||
|
|
||||||
// Note: The test assumes createFile opens the file with CLOEXEC
|
// Note: The test assumes createFile opens the file with CLOEXEC
|
||||||
{
|
{
|
||||||
const flags = try os.fcntl(file.handle, os.F.GETFD, 0);
|
const flags = try posix.fcntl(file.handle, posix.F.GETFD, 0);
|
||||||
try expect((flags & os.FD_CLOEXEC) != 0);
|
try expect((flags & posix.FD_CLOEXEC) != 0);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
_ = try os.fcntl(file.handle, os.F.SETFD, 0);
|
_ = try posix.fcntl(file.handle, posix.F.SETFD, 0);
|
||||||
const flags = try os.fcntl(file.handle, os.F.GETFD, 0);
|
const flags = try posix.fcntl(file.handle, posix.F.GETFD, 0);
|
||||||
try expect((flags & os.FD_CLOEXEC) == 0);
|
try expect((flags & posix.FD_CLOEXEC) == 0);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
_ = try os.fcntl(file.handle, os.F.SETFD, os.FD_CLOEXEC);
|
_ = try posix.fcntl(file.handle, posix.F.SETFD, posix.FD_CLOEXEC);
|
||||||
const flags = try os.fcntl(file.handle, os.F.GETFD, 0);
|
const flags = try posix.fcntl(file.handle, posix.F.GETFD, 0);
|
||||||
try expect((flags & os.FD_CLOEXEC) != 0);
|
try expect((flags & posix.FD_CLOEXEC) != 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -731,7 +732,7 @@ test "signalfd" {
|
|||||||
.linux, .solaris, .illumos => {},
|
.linux, .solaris, .illumos => {},
|
||||||
else => return error.SkipZigTest,
|
else => return error.SkipZigTest,
|
||||||
}
|
}
|
||||||
_ = &os.signalfd;
|
_ = &posix.signalfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "sync" {
|
test "sync" {
|
||||||
@ -748,8 +749,8 @@ test "sync" {
|
|||||||
tmp.dir.deleteFile(test_out_file) catch {};
|
tmp.dir.deleteFile(test_out_file) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
os.sync();
|
posix.sync();
|
||||||
try os.syncfs(file.handle);
|
try posix.syncfs(file.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "fsync" {
|
test "fsync" {
|
||||||
@ -768,23 +769,23 @@ test "fsync" {
|
|||||||
tmp.dir.deleteFile(test_out_file) catch {};
|
tmp.dir.deleteFile(test_out_file) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
try os.fsync(file.handle);
|
try posix.fsync(file.handle);
|
||||||
try os.fdatasync(file.handle);
|
try posix.fdatasync(file.handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "getrlimit and setrlimit" {
|
test "getrlimit and setrlimit" {
|
||||||
if (!@hasDecl(os.system, "rlimit")) {
|
if (!@hasDecl(posix.system, "rlimit")) {
|
||||||
return error.SkipZigTest;
|
return error.SkipZigTest;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline for (std.meta.fields(os.rlimit_resource)) |field| {
|
inline for (std.meta.fields(posix.rlimit_resource)) |field| {
|
||||||
const resource = @as(os.rlimit_resource, @enumFromInt(field.value));
|
const resource = @as(posix.rlimit_resource, @enumFromInt(field.value));
|
||||||
const limit = try os.getrlimit(resource);
|
const limit = try posix.getrlimit(resource);
|
||||||
|
|
||||||
// XNU kernel does not support RLIMIT_STACK if a custom stack is active,
|
// XNU kernel does not support RLIMIT_STACK if a custom stack is active,
|
||||||
// which looks to always be the case. EINVAL is returned.
|
// which looks to always be the case. EINVAL is returned.
|
||||||
// See https://github.com/apple-oss-distributions/xnu/blob/5e3eaea39dcf651e66cb99ba7d70e32cc4a99587/bsd/kern/kern_resource.c#L1173
|
// See https://github.com/apple-oss-distributions/xnu/blob/5e3eaea39dcf651e66cb99ba7d70e32cc4a99587/bsd/kern/kern_resource.c#L1173
|
||||||
if (builtin.os.tag.isDarwin() and resource == .STACK) {
|
if (native_os.isDarwin() and resource == .STACK) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -794,11 +795,11 @@ test "getrlimit and setrlimit" {
|
|||||||
// This happens for example if RLIMIT_MEMLOCK is bigger than ~2GiB.
|
// This happens for example if RLIMIT_MEMLOCK is bigger than ~2GiB.
|
||||||
// In that case the following the limit would be RLIM_INFINITY and the following setrlimit fails with EPERM.
|
// In that case the following the limit would be RLIM_INFINITY and the following setrlimit fails with EPERM.
|
||||||
if (comptime builtin.cpu.arch.isMIPS() and builtin.link_libc) {
|
if (comptime builtin.cpu.arch.isMIPS() and builtin.link_libc) {
|
||||||
if (limit.cur != os.linux.RLIM.INFINITY) {
|
if (limit.cur != linux.RLIM.INFINITY) {
|
||||||
try os.setrlimit(resource, limit);
|
try posix.setrlimit(resource, limit);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try os.setrlimit(resource, limit);
|
try posix.setrlimit(resource, limit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -807,15 +808,15 @@ test "shutdown socket" {
|
|||||||
if (native_os == .wasi)
|
if (native_os == .wasi)
|
||||||
return error.SkipZigTest;
|
return error.SkipZigTest;
|
||||||
if (native_os == .windows) {
|
if (native_os == .windows) {
|
||||||
_ = try os.windows.WSAStartup(2, 2);
|
_ = try std.os.windows.WSAStartup(2, 2);
|
||||||
}
|
}
|
||||||
defer {
|
defer {
|
||||||
if (native_os == .windows) {
|
if (native_os == .windows) {
|
||||||
os.windows.WSACleanup() catch unreachable;
|
std.os.windows.WSACleanup() catch unreachable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const sock = try os.socket(os.AF.INET, os.SOCK.STREAM, 0);
|
const sock = try posix.socket(posix.AF.INET, posix.SOCK.STREAM, 0);
|
||||||
os.shutdown(sock, .both) catch |err| switch (err) {
|
posix.shutdown(sock, .both) catch |err| switch (err) {
|
||||||
error.SocketNotConnected => {},
|
error.SocketNotConnected => {},
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
};
|
};
|
||||||
@ -838,63 +839,63 @@ test "sigaction" {
|
|||||||
const S = struct {
|
const S = struct {
|
||||||
var handler_called_count: u32 = 0;
|
var handler_called_count: u32 = 0;
|
||||||
|
|
||||||
fn handler(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) void {
|
fn handler(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) void {
|
||||||
_ = ctx_ptr;
|
_ = ctx_ptr;
|
||||||
// Check that we received the correct signal.
|
// Check that we received the correct signal.
|
||||||
switch (native_os) {
|
switch (native_os) {
|
||||||
.netbsd => {
|
.netbsd => {
|
||||||
if (sig == os.SIG.USR1 and sig == info.info.signo)
|
if (sig == posix.SIG.USR1 and sig == info.info.signo)
|
||||||
handler_called_count += 1;
|
handler_called_count += 1;
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
if (sig == os.SIG.USR1 and sig == info.signo)
|
if (sig == posix.SIG.USR1 and sig == info.signo)
|
||||||
handler_called_count += 1;
|
handler_called_count += 1;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var sa = os.Sigaction{
|
var sa: posix.Sigaction = .{
|
||||||
.handler = .{ .sigaction = &S.handler },
|
.handler = .{ .sigaction = &S.handler },
|
||||||
.mask = os.empty_sigset,
|
.mask = posix.empty_sigset,
|
||||||
.flags = os.SA.SIGINFO | os.SA.RESETHAND,
|
.flags = posix.SA.SIGINFO | posix.SA.RESETHAND,
|
||||||
};
|
};
|
||||||
var old_sa: os.Sigaction = undefined;
|
var old_sa: posix.Sigaction = undefined;
|
||||||
|
|
||||||
// Install the new signal handler.
|
// Install the new signal handler.
|
||||||
try os.sigaction(os.SIG.USR1, &sa, null);
|
try posix.sigaction(posix.SIG.USR1, &sa, null);
|
||||||
|
|
||||||
// Check that we can read it back correctly.
|
// Check that we can read it back correctly.
|
||||||
try os.sigaction(os.SIG.USR1, null, &old_sa);
|
try posix.sigaction(posix.SIG.USR1, null, &old_sa);
|
||||||
try testing.expectEqual(&S.handler, old_sa.handler.sigaction.?);
|
try testing.expectEqual(&S.handler, old_sa.handler.sigaction.?);
|
||||||
try testing.expect((old_sa.flags & os.SA.SIGINFO) != 0);
|
try testing.expect((old_sa.flags & posix.SA.SIGINFO) != 0);
|
||||||
|
|
||||||
// Invoke the handler.
|
// Invoke the handler.
|
||||||
try os.raise(os.SIG.USR1);
|
try posix.raise(posix.SIG.USR1);
|
||||||
try testing.expect(S.handler_called_count == 1);
|
try testing.expect(S.handler_called_count == 1);
|
||||||
|
|
||||||
// Check if passing RESETHAND correctly reset the handler to SIG_DFL
|
// Check if passing RESETHAND correctly reset the handler to SIG_DFL
|
||||||
try os.sigaction(os.SIG.USR1, null, &old_sa);
|
try posix.sigaction(posix.SIG.USR1, null, &old_sa);
|
||||||
try testing.expectEqual(os.SIG.DFL, old_sa.handler.handler);
|
try testing.expectEqual(posix.SIG.DFL, old_sa.handler.handler);
|
||||||
|
|
||||||
// Reinstall the signal w/o RESETHAND and re-raise
|
// Reinstall the signal w/o RESETHAND and re-raise
|
||||||
sa.flags = os.SA.SIGINFO;
|
sa.flags = posix.SA.SIGINFO;
|
||||||
try os.sigaction(os.SIG.USR1, &sa, null);
|
try posix.sigaction(posix.SIG.USR1, &sa, null);
|
||||||
try os.raise(os.SIG.USR1);
|
try posix.raise(posix.SIG.USR1);
|
||||||
try testing.expect(S.handler_called_count == 2);
|
try testing.expect(S.handler_called_count == 2);
|
||||||
|
|
||||||
// Now set the signal to ignored
|
// Now set the signal to ignored
|
||||||
sa.handler = .{ .handler = os.SIG.IGN };
|
sa.handler = .{ .handler = posix.SIG.IGN };
|
||||||
sa.flags = 0;
|
sa.flags = 0;
|
||||||
try os.sigaction(os.SIG.USR1, &sa, null);
|
try posix.sigaction(posix.SIG.USR1, &sa, null);
|
||||||
|
|
||||||
// Re-raise to ensure handler is actually ignored
|
// Re-raise to ensure handler is actually ignored
|
||||||
try os.raise(os.SIG.USR1);
|
try posix.raise(posix.SIG.USR1);
|
||||||
try testing.expect(S.handler_called_count == 2);
|
try testing.expect(S.handler_called_count == 2);
|
||||||
|
|
||||||
// Ensure that ignored state is returned when querying
|
// Ensure that ignored state is returned when querying
|
||||||
try os.sigaction(os.SIG.USR1, null, &old_sa);
|
try posix.sigaction(posix.SIG.USR1, null, &old_sa);
|
||||||
try testing.expectEqual(os.SIG.IGN, old_sa.handler.handler.?);
|
try testing.expectEqual(posix.SIG.IGN, old_sa.handler.handler.?);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "dup & dup2" {
|
test "dup & dup2" {
|
||||||
@ -910,13 +911,13 @@ test "dup & dup2" {
|
|||||||
var file = try tmp.dir.createFile("os_dup_test", .{});
|
var file = try tmp.dir.createFile("os_dup_test", .{});
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
var duped = std.fs.File{ .handle = try os.dup(file.handle) };
|
var duped = std.fs.File{ .handle = try posix.dup(file.handle) };
|
||||||
defer duped.close();
|
defer duped.close();
|
||||||
try duped.writeAll("dup");
|
try duped.writeAll("dup");
|
||||||
|
|
||||||
// Tests aren't run in parallel so using the next fd shouldn't be an issue.
|
// Tests aren't run in parallel so using the next fd shouldn't be an issue.
|
||||||
const new_fd = duped.handle + 1;
|
const new_fd = duped.handle + 1;
|
||||||
try os.dup2(file.handle, new_fd);
|
try posix.dup2(file.handle, new_fd);
|
||||||
var dup2ed = std.fs.File{ .handle = new_fd };
|
var dup2ed = std.fs.File{ .handle = new_fd };
|
||||||
defer dup2ed.close();
|
defer dup2ed.close();
|
||||||
try dup2ed.writeAll("dup2");
|
try dup2ed.writeAll("dup2");
|
||||||
@ -938,9 +939,9 @@ test "writev longer than IOV_MAX" {
|
|||||||
var file = try tmp.dir.createFile("pwritev", .{});
|
var file = try tmp.dir.createFile("pwritev", .{});
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
const iovecs = [_]os.iovec_const{.{ .iov_base = "a", .iov_len = 1 }} ** (os.IOV_MAX + 1);
|
const iovecs = [_]posix.iovec_const{.{ .iov_base = "a", .iov_len = 1 }} ** (posix.IOV_MAX + 1);
|
||||||
const amt = try file.writev(&iovecs);
|
const amt = try file.writev(&iovecs);
|
||||||
try testing.expectEqual(@as(usize, os.IOV_MAX), amt);
|
try testing.expectEqual(@as(usize, posix.IOV_MAX), amt);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "POSIX file locking with fcntl" {
|
test "POSIX file locking with fcntl" {
|
||||||
@ -964,46 +965,46 @@ test "POSIX file locking with fcntl" {
|
|||||||
const fd = file.handle;
|
const fd = file.handle;
|
||||||
|
|
||||||
// Place an exclusive lock on the first byte, and a shared lock on the second byte:
|
// Place an exclusive lock on the first byte, and a shared lock on the second byte:
|
||||||
var struct_flock = std.mem.zeroInit(os.Flock, .{ .type = os.F.WRLCK });
|
var struct_flock = std.mem.zeroInit(posix.Flock, .{ .type = posix.F.WRLCK });
|
||||||
_ = try os.fcntl(fd, os.F.SETLK, @intFromPtr(&struct_flock));
|
_ = try posix.fcntl(fd, posix.F.SETLK, @intFromPtr(&struct_flock));
|
||||||
struct_flock.start = 1;
|
struct_flock.start = 1;
|
||||||
struct_flock.type = os.F.RDLCK;
|
struct_flock.type = posix.F.RDLCK;
|
||||||
_ = try os.fcntl(fd, os.F.SETLK, @intFromPtr(&struct_flock));
|
_ = try posix.fcntl(fd, posix.F.SETLK, @intFromPtr(&struct_flock));
|
||||||
|
|
||||||
// Check the locks in a child process:
|
// Check the locks in a child process:
|
||||||
const pid = try os.fork();
|
const pid = try posix.fork();
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
// child expects be denied the exclusive lock:
|
// child expects be denied the exclusive lock:
|
||||||
struct_flock.start = 0;
|
struct_flock.start = 0;
|
||||||
struct_flock.type = os.F.WRLCK;
|
struct_flock.type = posix.F.WRLCK;
|
||||||
try expectError(error.Locked, os.fcntl(fd, os.F.SETLK, @intFromPtr(&struct_flock)));
|
try expectError(error.Locked, posix.fcntl(fd, posix.F.SETLK, @intFromPtr(&struct_flock)));
|
||||||
// child expects to get the shared lock:
|
// child expects to get the shared lock:
|
||||||
struct_flock.start = 1;
|
struct_flock.start = 1;
|
||||||
struct_flock.type = os.F.RDLCK;
|
struct_flock.type = posix.F.RDLCK;
|
||||||
_ = try os.fcntl(fd, os.F.SETLK, @intFromPtr(&struct_flock));
|
_ = try posix.fcntl(fd, posix.F.SETLK, @intFromPtr(&struct_flock));
|
||||||
// child waits for the exclusive lock in order to test deadlock:
|
// child waits for the exclusive lock in order to test deadlock:
|
||||||
struct_flock.start = 0;
|
struct_flock.start = 0;
|
||||||
struct_flock.type = os.F.WRLCK;
|
struct_flock.type = posix.F.WRLCK;
|
||||||
_ = try os.fcntl(fd, os.F.SETLKW, @intFromPtr(&struct_flock));
|
_ = try posix.fcntl(fd, posix.F.SETLKW, @intFromPtr(&struct_flock));
|
||||||
// child exits without continuing:
|
// child exits without continuing:
|
||||||
os.exit(0);
|
posix.exit(0);
|
||||||
} else {
|
} else {
|
||||||
// parent waits for child to get shared lock:
|
// parent waits for child to get shared lock:
|
||||||
std.time.sleep(1 * std.time.ns_per_ms);
|
std.time.sleep(1 * std.time.ns_per_ms);
|
||||||
// parent expects deadlock when attempting to upgrade the shared lock to exclusive:
|
// parent expects deadlock when attempting to upgrade the shared lock to exclusive:
|
||||||
struct_flock.start = 1;
|
struct_flock.start = 1;
|
||||||
struct_flock.type = os.F.WRLCK;
|
struct_flock.type = posix.F.WRLCK;
|
||||||
try expectError(error.DeadLock, os.fcntl(fd, os.F.SETLKW, @intFromPtr(&struct_flock)));
|
try expectError(error.DeadLock, posix.fcntl(fd, posix.F.SETLKW, @intFromPtr(&struct_flock)));
|
||||||
// parent releases exclusive lock:
|
// parent releases exclusive lock:
|
||||||
struct_flock.start = 0;
|
struct_flock.start = 0;
|
||||||
struct_flock.type = os.F.UNLCK;
|
struct_flock.type = posix.F.UNLCK;
|
||||||
_ = try os.fcntl(fd, os.F.SETLK, @intFromPtr(&struct_flock));
|
_ = try posix.fcntl(fd, posix.F.SETLK, @intFromPtr(&struct_flock));
|
||||||
// parent releases shared lock:
|
// parent releases shared lock:
|
||||||
struct_flock.start = 1;
|
struct_flock.start = 1;
|
||||||
struct_flock.type = os.F.UNLCK;
|
struct_flock.type = posix.F.UNLCK;
|
||||||
_ = try os.fcntl(fd, os.F.SETLK, @intFromPtr(&struct_flock));
|
_ = try posix.fcntl(fd, posix.F.SETLK, @intFromPtr(&struct_flock));
|
||||||
// parent waits for child:
|
// parent waits for child:
|
||||||
const result = os.waitpid(pid, 0);
|
const result = posix.waitpid(pid, 0);
|
||||||
try expect(result.status == 0 * 256);
|
try expect(result.status == 0 * 256);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1026,43 +1027,43 @@ test "rename smoke test" {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var file_path: []u8 = undefined;
|
var file_path: []u8 = undefined;
|
||||||
var fd: os.fd_t = undefined;
|
var fd: posix.fd_t = undefined;
|
||||||
const mode: os.mode_t = if (native_os == .windows) 0 else 0o666;
|
const mode: posix.mode_t = if (native_os == .windows) 0 else 0o666;
|
||||||
|
|
||||||
// Create some file using `open`.
|
// Create some file using `open`.
|
||||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
||||||
fd = try os.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
|
fd = try posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
|
||||||
os.close(fd);
|
posix.close(fd);
|
||||||
|
|
||||||
// Rename the file
|
// Rename the file
|
||||||
var new_file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_file" });
|
var new_file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_file" });
|
||||||
try os.rename(file_path, new_file_path);
|
try posix.rename(file_path, new_file_path);
|
||||||
|
|
||||||
// Try opening renamed file
|
// Try opening renamed file
|
||||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_file" });
|
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_file" });
|
||||||
fd = try os.open(file_path, .{ .ACCMODE = .RDWR }, mode);
|
fd = try posix.open(file_path, .{ .ACCMODE = .RDWR }, mode);
|
||||||
os.close(fd);
|
posix.close(fd);
|
||||||
|
|
||||||
// Try opening original file - should fail with error.FileNotFound
|
// Try opening original file - should fail with error.FileNotFound
|
||||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
||||||
try expectError(error.FileNotFound, os.open(file_path, .{ .ACCMODE = .RDWR }, mode));
|
try expectError(error.FileNotFound, posix.open(file_path, .{ .ACCMODE = .RDWR }, mode));
|
||||||
|
|
||||||
// Create some directory
|
// Create some directory
|
||||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
|
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
|
||||||
try os.mkdir(file_path, mode);
|
try posix.mkdir(file_path, mode);
|
||||||
|
|
||||||
// Rename the directory
|
// Rename the directory
|
||||||
new_file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_dir" });
|
new_file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_dir" });
|
||||||
try os.rename(file_path, new_file_path);
|
try posix.rename(file_path, new_file_path);
|
||||||
|
|
||||||
// Try opening renamed directory
|
// Try opening renamed directory
|
||||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_dir" });
|
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_dir" });
|
||||||
fd = try os.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode);
|
fd = try posix.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode);
|
||||||
os.close(fd);
|
posix.close(fd);
|
||||||
|
|
||||||
// Try opening original directory - should fail with error.FileNotFound
|
// Try opening original directory - should fail with error.FileNotFound
|
||||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
|
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
|
||||||
try expectError(error.FileNotFound, os.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode));
|
try expectError(error.FileNotFound, posix.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "access smoke test" {
|
test "access smoke test" {
|
||||||
@ -1083,50 +1084,49 @@ test "access smoke test" {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var file_path: []u8 = undefined;
|
var file_path: []u8 = undefined;
|
||||||
var fd: os.fd_t = undefined;
|
var fd: posix.fd_t = undefined;
|
||||||
const mode: os.mode_t = if (native_os == .windows) 0 else 0o666;
|
const mode: posix.mode_t = if (native_os == .windows) 0 else 0o666;
|
||||||
|
|
||||||
// Create some file using `open`.
|
// Create some file using `open`.
|
||||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
||||||
fd = try os.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
|
fd = try posix.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
|
||||||
os.close(fd);
|
posix.close(fd);
|
||||||
|
|
||||||
// Try to access() the file
|
// Try to access() the file
|
||||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
try os.access(file_path, os.F_OK);
|
try posix.access(file_path, posix.F_OK);
|
||||||
} else {
|
} else {
|
||||||
try os.access(file_path, os.F_OK | os.W_OK | os.R_OK);
|
try posix.access(file_path, posix.F_OK | posix.W_OK | posix.R_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to access() a non-existent file - should fail with error.FileNotFound
|
// Try to access() a non-existent file - should fail with error.FileNotFound
|
||||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_file" });
|
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_file" });
|
||||||
try expectError(error.FileNotFound, os.access(file_path, os.F_OK));
|
try expectError(error.FileNotFound, posix.access(file_path, posix.F_OK));
|
||||||
|
|
||||||
// Create some directory
|
// Create some directory
|
||||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
|
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
|
||||||
try os.mkdir(file_path, mode);
|
try posix.mkdir(file_path, mode);
|
||||||
|
|
||||||
// Try to access() the directory
|
// Try to access() the directory
|
||||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
|
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
|
||||||
try os.access(file_path, os.F_OK);
|
try posix.access(file_path, posix.F_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "timerfd" {
|
test "timerfd" {
|
||||||
if (native_os != .linux) return error.SkipZigTest;
|
if (native_os != .linux) return error.SkipZigTest;
|
||||||
|
|
||||||
const linux = os.linux;
|
const tfd = try posix.timerfd_create(linux.CLOCK.MONOTONIC, .{ .CLOEXEC = true });
|
||||||
const tfd = try os.timerfd_create(linux.CLOCK.MONOTONIC, .{ .CLOEXEC = true });
|
defer posix.close(tfd);
|
||||||
defer os.close(tfd);
|
|
||||||
|
|
||||||
// Fire event 10_000_000ns = 10ms after the os.timerfd_settime call.
|
// Fire event 10_000_000ns = 10ms after the posix.timerfd_settime call.
|
||||||
var sit: linux.itimerspec = .{ .it_interval = .{ .tv_sec = 0, .tv_nsec = 0 }, .it_value = .{ .tv_sec = 0, .tv_nsec = 10 * (1000 * 1000) } };
|
var sit: linux.itimerspec = .{ .it_interval = .{ .tv_sec = 0, .tv_nsec = 0 }, .it_value = .{ .tv_sec = 0, .tv_nsec = 10 * (1000 * 1000) } };
|
||||||
try os.timerfd_settime(tfd, .{}, &sit, null);
|
try posix.timerfd_settime(tfd, .{}, &sit, null);
|
||||||
|
|
||||||
var fds: [1]os.pollfd = .{.{ .fd = tfd, .events = os.linux.POLL.IN, .revents = 0 }};
|
var fds: [1]posix.pollfd = .{.{ .fd = tfd, .events = linux.POLL.IN, .revents = 0 }};
|
||||||
try expectEqual(@as(usize, 1), try os.poll(&fds, -1)); // -1 => infinite waiting
|
try expectEqual(@as(usize, 1), try posix.poll(&fds, -1)); // -1 => infinite waiting
|
||||||
|
|
||||||
const git = try os.timerfd_gettime(tfd);
|
const git = try posix.timerfd_gettime(tfd);
|
||||||
const expect_disarmed_timer: linux.itimerspec = .{ .it_interval = .{ .tv_sec = 0, .tv_nsec = 0 }, .it_value = .{ .tv_sec = 0, .tv_nsec = 0 } };
|
const expect_disarmed_timer: linux.itimerspec = .{ .it_interval = .{ .tv_sec = 0, .tv_nsec = 0 }, .it_value = .{ .tv_sec = 0, .tv_nsec = 0 } };
|
||||||
try expectEqual(expect_disarmed_timer, git);
|
try expectEqual(expect_disarmed_timer, git);
|
||||||
}
|
}
|
||||||
@ -1138,7 +1138,7 @@ test "isatty" {
|
|||||||
var file = try tmp.dir.createFile("foo", .{});
|
var file = try tmp.dir.createFile("foo", .{});
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
try expectEqual(os.isatty(file.handle), false);
|
try expectEqual(posix.isatty(file.handle), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "read with empty buffer" {
|
test "read with empty buffer" {
|
||||||
@ -1163,7 +1163,7 @@ test "read with empty buffer" {
|
|||||||
|
|
||||||
const bytes = try allocator.alloc(u8, 0);
|
const bytes = try allocator.alloc(u8, 0);
|
||||||
|
|
||||||
_ = try os.read(file.handle, bytes);
|
_ = try posix.read(file.handle, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "pread with empty buffer" {
|
test "pread with empty buffer" {
|
||||||
@ -1188,7 +1188,7 @@ test "pread with empty buffer" {
|
|||||||
|
|
||||||
const bytes = try allocator.alloc(u8, 0);
|
const bytes = try allocator.alloc(u8, 0);
|
||||||
|
|
||||||
_ = try os.pread(file.handle, bytes, 0);
|
_ = try posix.pread(file.handle, bytes, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "write with empty buffer" {
|
test "write with empty buffer" {
|
||||||
@ -1213,7 +1213,7 @@ test "write with empty buffer" {
|
|||||||
|
|
||||||
const bytes = try allocator.alloc(u8, 0);
|
const bytes = try allocator.alloc(u8, 0);
|
||||||
|
|
||||||
_ = try os.write(file.handle, bytes);
|
_ = try posix.write(file.handle, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "pwrite with empty buffer" {
|
test "pwrite with empty buffer" {
|
||||||
@ -1238,11 +1238,11 @@ test "pwrite with empty buffer" {
|
|||||||
|
|
||||||
const bytes = try allocator.alloc(u8, 0);
|
const bytes = try allocator.alloc(u8, 0);
|
||||||
|
|
||||||
_ = try os.pwrite(file.handle, bytes, 0);
|
_ = try posix.pwrite(file.handle, bytes, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expectMode(dir: os.fd_t, file: []const u8, mode: os.mode_t) !void {
|
fn expectMode(dir: posix.fd_t, file: []const u8, mode: posix.mode_t) !void {
|
||||||
const st = try os.fstatat(dir, file, os.AT.SYMLINK_NOFOLLOW);
|
const st = try posix.fstatat(dir, file, posix.AT.SYMLINK_NOFOLLOW);
|
||||||
try expectEqual(mode, st.mode & 0b111_111_111);
|
try expectEqual(mode, st.mode & 0b111_111_111);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1252,31 +1252,31 @@ test "fchmodat smoke test" {
|
|||||||
var tmp = tmpDir(.{});
|
var tmp = tmpDir(.{});
|
||||||
defer tmp.cleanup();
|
defer tmp.cleanup();
|
||||||
|
|
||||||
try expectError(error.FileNotFound, os.fchmodat(tmp.dir.fd, "regfile", 0o666, 0));
|
try expectError(error.FileNotFound, posix.fchmodat(tmp.dir.fd, "regfile", 0o666, 0));
|
||||||
const fd = try os.openat(
|
const fd = try posix.openat(
|
||||||
tmp.dir.fd,
|
tmp.dir.fd,
|
||||||
"regfile",
|
"regfile",
|
||||||
.{ .ACCMODE = .WRONLY, .CREAT = true, .EXCL = true, .TRUNC = true },
|
.{ .ACCMODE = .WRONLY, .CREAT = true, .EXCL = true, .TRUNC = true },
|
||||||
0o644,
|
0o644,
|
||||||
);
|
);
|
||||||
os.close(fd);
|
posix.close(fd);
|
||||||
try os.symlinkat("regfile", tmp.dir.fd, "symlink");
|
try posix.symlinkat("regfile", tmp.dir.fd, "symlink");
|
||||||
const sym_mode = blk: {
|
const sym_mode = blk: {
|
||||||
const st = try os.fstatat(tmp.dir.fd, "symlink", os.AT.SYMLINK_NOFOLLOW);
|
const st = try posix.fstatat(tmp.dir.fd, "symlink", posix.AT.SYMLINK_NOFOLLOW);
|
||||||
break :blk st.mode & 0b111_111_111;
|
break :blk st.mode & 0b111_111_111;
|
||||||
};
|
};
|
||||||
|
|
||||||
try os.fchmodat(tmp.dir.fd, "regfile", 0o640, 0);
|
try posix.fchmodat(tmp.dir.fd, "regfile", 0o640, 0);
|
||||||
try expectMode(tmp.dir.fd, "regfile", 0o640);
|
try expectMode(tmp.dir.fd, "regfile", 0o640);
|
||||||
try os.fchmodat(tmp.dir.fd, "regfile", 0o600, os.AT.SYMLINK_NOFOLLOW);
|
try posix.fchmodat(tmp.dir.fd, "regfile", 0o600, posix.AT.SYMLINK_NOFOLLOW);
|
||||||
try expectMode(tmp.dir.fd, "regfile", 0o600);
|
try expectMode(tmp.dir.fd, "regfile", 0o600);
|
||||||
|
|
||||||
try os.fchmodat(tmp.dir.fd, "symlink", 0o640, 0);
|
try posix.fchmodat(tmp.dir.fd, "symlink", 0o640, 0);
|
||||||
try expectMode(tmp.dir.fd, "regfile", 0o640);
|
try expectMode(tmp.dir.fd, "regfile", 0o640);
|
||||||
try expectMode(tmp.dir.fd, "symlink", sym_mode);
|
try expectMode(tmp.dir.fd, "symlink", sym_mode);
|
||||||
|
|
||||||
var test_link = true;
|
var test_link = true;
|
||||||
os.fchmodat(tmp.dir.fd, "symlink", 0o600, os.AT.SYMLINK_NOFOLLOW) catch |err| switch (err) {
|
posix.fchmodat(tmp.dir.fd, "symlink", 0o600, posix.AT.SYMLINK_NOFOLLOW) catch |err| switch (err) {
|
||||||
error.OperationNotSupported => test_link = false,
|
error.OperationNotSupported => test_link = false,
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
};
|
};
|
||||||
@ -1284,3 +1284,34 @@ test "fchmodat smoke test" {
|
|||||||
try expectMode(tmp.dir.fd, "symlink", 0o600);
|
try expectMode(tmp.dir.fd, "symlink", 0o600);
|
||||||
try expectMode(tmp.dir.fd, "regfile", 0o640);
|
try expectMode(tmp.dir.fd, "regfile", 0o640);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CommonOpenFlags = packed struct {
|
||||||
|
ACCMODE: posix.ACCMODE = .RDONLY,
|
||||||
|
CREAT: bool = false,
|
||||||
|
EXCL: bool = false,
|
||||||
|
LARGEFILE: bool = false,
|
||||||
|
DIRECTORY: bool = false,
|
||||||
|
CLOEXEC: bool = false,
|
||||||
|
NONBLOCK: bool = false,
|
||||||
|
|
||||||
|
pub fn lower(cof: CommonOpenFlags) posix.O {
|
||||||
|
if (native_os == .wasi) return .{
|
||||||
|
.read = cof.ACCMODE != .WRONLY,
|
||||||
|
.write = cof.ACCMODE != .RDONLY,
|
||||||
|
.CREAT = cof.CREAT,
|
||||||
|
.EXCL = cof.EXCL,
|
||||||
|
.DIRECTORY = cof.DIRECTORY,
|
||||||
|
.NONBLOCK = cof.NONBLOCK,
|
||||||
|
};
|
||||||
|
var result: posix.O = .{
|
||||||
|
.ACCMODE = cof.ACCMODE,
|
||||||
|
.CREAT = cof.CREAT,
|
||||||
|
.EXCL = cof.EXCL,
|
||||||
|
.DIRECTORY = cof.DIRECTORY,
|
||||||
|
.NONBLOCK = cof.NONBLOCK,
|
||||||
|
.CLOEXEC = cof.CLOEXEC,
|
||||||
|
};
|
||||||
|
if (@hasField(posix.O, "LARGEFILE")) result.LARGEFILE = cof.LARGEFILE;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -1,6 +1,5 @@
|
|||||||
const std = @import("std.zig");
|
const std = @import("std.zig");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const os = std.os;
|
|
||||||
const fs = std.fs;
|
const fs = std.fs;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
@ -8,20 +7,27 @@ const Allocator = mem.Allocator;
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const child_process = @import("child_process.zig");
|
const child_process = @import("child_process.zig");
|
||||||
|
const native_os = builtin.os.tag;
|
||||||
|
const posix = std.posix;
|
||||||
|
const windows = std.os.windows;
|
||||||
|
|
||||||
pub const Child = child_process.ChildProcess;
|
pub const Child = child_process.ChildProcess;
|
||||||
pub const abort = os.abort;
|
pub const abort = posix.abort;
|
||||||
pub const exit = os.exit;
|
pub const exit = posix.exit;
|
||||||
pub const changeCurDir = os.chdir;
|
pub const changeCurDir = posix.chdir;
|
||||||
pub const changeCurDirC = os.chdirC;
|
pub const changeCurDirC = posix.chdirC;
|
||||||
|
|
||||||
|
pub const GetCwdError = posix.GetCwdError;
|
||||||
|
|
||||||
/// The result is a slice of `out_buffer`, from index `0`.
|
/// The result is a slice of `out_buffer`, from index `0`.
|
||||||
/// On Windows, the result is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
|
/// On Windows, the result is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
|
||||||
/// On other platforms, the result is an opaque sequence of bytes with no particular encoding.
|
/// On other platforms, the result is an opaque sequence of bytes with no particular encoding.
|
||||||
pub fn getCwd(out_buffer: []u8) ![]u8 {
|
pub fn getCwd(out_buffer: []u8) ![]u8 {
|
||||||
return os.getcwd(out_buffer);
|
return posix.getcwd(out_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const GetCwdAllocError = Allocator.Error || posix.GetCwdError;
|
||||||
|
|
||||||
/// Caller must free the returned memory.
|
/// Caller must free the returned memory.
|
||||||
/// On Windows, the result is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
|
/// On Windows, the result is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
|
||||||
/// On other platforms, the result is an opaque sequence of bytes with no particular encoding.
|
/// On other platforms, the result is an opaque sequence of bytes with no particular encoding.
|
||||||
@ -34,7 +40,7 @@ pub fn getCwdAlloc(allocator: Allocator) ![]u8 {
|
|||||||
|
|
||||||
var current_buf: []u8 = &stack_buf;
|
var current_buf: []u8 = &stack_buf;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (os.getcwd(current_buf)) |slice| {
|
if (posix.getcwd(current_buf)) |slice| {
|
||||||
return allocator.dupe(u8, slice);
|
return allocator.dupe(u8, slice);
|
||||||
} else |err| switch (err) {
|
} else |err| switch (err) {
|
||||||
error.NameTooLong => {
|
error.NameTooLong => {
|
||||||
@ -51,7 +57,7 @@ pub fn getCwdAlloc(allocator: Allocator) ![]u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test getCwdAlloc {
|
test getCwdAlloc {
|
||||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
if (native_os == .wasi) return error.SkipZigTest;
|
||||||
|
|
||||||
const cwd = try getCwdAlloc(testing.allocator);
|
const cwd = try getCwdAlloc(testing.allocator);
|
||||||
testing.allocator.free(cwd);
|
testing.allocator.free(cwd);
|
||||||
@ -72,13 +78,13 @@ pub const EnvMap = struct {
|
|||||||
pub const EnvNameHashContext = struct {
|
pub const EnvNameHashContext = struct {
|
||||||
fn upcase(c: u21) u21 {
|
fn upcase(c: u21) u21 {
|
||||||
if (c <= std.math.maxInt(u16))
|
if (c <= std.math.maxInt(u16))
|
||||||
return std.os.windows.ntdll.RtlUpcaseUnicodeChar(@as(u16, @intCast(c)));
|
return windows.ntdll.RtlUpcaseUnicodeChar(@as(u16, @intCast(c)));
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hash(self: @This(), s: []const u8) u64 {
|
pub fn hash(self: @This(), s: []const u8) u64 {
|
||||||
_ = self;
|
_ = self;
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
var h = std.hash.Wyhash.init(0);
|
var h = std.hash.Wyhash.init(0);
|
||||||
var it = std.unicode.Wtf8View.initUnchecked(s).iterator();
|
var it = std.unicode.Wtf8View.initUnchecked(s).iterator();
|
||||||
while (it.nextCodepoint()) |cp| {
|
while (it.nextCodepoint()) |cp| {
|
||||||
@ -96,7 +102,7 @@ pub const EnvMap = struct {
|
|||||||
|
|
||||||
pub fn eql(self: @This(), a: []const u8, b: []const u8) bool {
|
pub fn eql(self: @This(), a: []const u8, b: []const u8) bool {
|
||||||
_ = self;
|
_ = self;
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
var it_a = std.unicode.Wtf8View.initUnchecked(a).iterator();
|
var it_a = std.unicode.Wtf8View.initUnchecked(a).iterator();
|
||||||
var it_b = std.unicode.Wtf8View.initUnchecked(b).iterator();
|
var it_b = std.unicode.Wtf8View.initUnchecked(b).iterator();
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -228,7 +234,7 @@ test "EnvMap" {
|
|||||||
try testing.expectEqual(@as(EnvMap.Size, 2), env.count());
|
try testing.expectEqual(@as(EnvMap.Size, 2), env.count());
|
||||||
|
|
||||||
// case insensitivity on Windows only
|
// case insensitivity on Windows only
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
try testing.expectEqualStrings("1", env.get("something_New_aNd_LONGER").?);
|
try testing.expectEqualStrings("1", env.get("something_New_aNd_LONGER").?);
|
||||||
} else {
|
} else {
|
||||||
try testing.expect(null == env.get("something_New_aNd_LONGER"));
|
try testing.expect(null == env.get("something_New_aNd_LONGER"));
|
||||||
@ -248,7 +254,7 @@ test "EnvMap" {
|
|||||||
|
|
||||||
try testing.expectEqual(@as(EnvMap.Size, 1), env.count());
|
try testing.expectEqual(@as(EnvMap.Size, 1), env.count());
|
||||||
|
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
// test Unicode case-insensitivity on Windows
|
// test Unicode case-insensitivity on Windows
|
||||||
try env.put("КИРиллИЦА", "something else");
|
try env.put("КИРиллИЦА", "something else");
|
||||||
try testing.expectEqualStrings("something else", env.get("кириллица").?);
|
try testing.expectEqualStrings("something else", env.get("кириллица").?);
|
||||||
@ -279,8 +285,8 @@ pub fn getEnvMap(allocator: Allocator) GetEnvMapError!EnvMap {
|
|||||||
var result = EnvMap.init(allocator);
|
var result = EnvMap.init(allocator);
|
||||||
errdefer result.deinit();
|
errdefer result.deinit();
|
||||||
|
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const ptr = os.windows.peb().ProcessParameters.Environment;
|
const ptr = windows.peb().ProcessParameters.Environment;
|
||||||
|
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (ptr[i] != 0) {
|
while (ptr[i] != 0) {
|
||||||
@ -310,13 +316,13 @@ pub fn getEnvMap(allocator: Allocator) GetEnvMapError!EnvMap {
|
|||||||
try result.putMove(key, value);
|
try result.putMove(key, value);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
} else if (native_os == .wasi and !builtin.link_libc) {
|
||||||
var environ_count: usize = undefined;
|
var environ_count: usize = undefined;
|
||||||
var environ_buf_size: usize = undefined;
|
var environ_buf_size: usize = undefined;
|
||||||
|
|
||||||
const environ_sizes_get_ret = os.wasi.environ_sizes_get(&environ_count, &environ_buf_size);
|
const environ_sizes_get_ret = std.os.wasi.environ_sizes_get(&environ_count, &environ_buf_size);
|
||||||
if (environ_sizes_get_ret != .SUCCESS) {
|
if (environ_sizes_get_ret != .SUCCESS) {
|
||||||
return os.unexpectedErrno(environ_sizes_get_ret);
|
return posix.unexpectedErrno(environ_sizes_get_ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (environ_count == 0) {
|
if (environ_count == 0) {
|
||||||
@ -328,9 +334,9 @@ pub fn getEnvMap(allocator: Allocator) GetEnvMapError!EnvMap {
|
|||||||
const environ_buf = try allocator.alloc(u8, environ_buf_size);
|
const environ_buf = try allocator.alloc(u8, environ_buf_size);
|
||||||
defer allocator.free(environ_buf);
|
defer allocator.free(environ_buf);
|
||||||
|
|
||||||
const environ_get_ret = os.wasi.environ_get(environ.ptr, environ_buf.ptr);
|
const environ_get_ret = std.os.wasi.environ_get(environ.ptr, environ_buf.ptr);
|
||||||
if (environ_get_ret != .SUCCESS) {
|
if (environ_get_ret != .SUCCESS) {
|
||||||
return os.unexpectedErrno(environ_get_ret);
|
return posix.unexpectedErrno(environ_get_ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (environ) |env| {
|
for (environ) |env| {
|
||||||
@ -356,7 +362,7 @@ pub fn getEnvMap(allocator: Allocator) GetEnvMapError!EnvMap {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
for (os.environ) |line| {
|
for (std.os.environ) |line| {
|
||||||
var line_i: usize = 0;
|
var line_i: usize = 0;
|
||||||
while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {}
|
while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {}
|
||||||
const key = line[0..line_i];
|
const key = line[0..line_i];
|
||||||
@ -391,37 +397,37 @@ pub const GetEnvVarOwnedError = error{
|
|||||||
/// On Windows, the value is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
|
/// On Windows, the value is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
|
||||||
/// On other platforms, the value is an opaque sequence of bytes with no particular encoding.
|
/// On other platforms, the value is an opaque sequence of bytes with no particular encoding.
|
||||||
pub fn getEnvVarOwned(allocator: Allocator, key: []const u8) GetEnvVarOwnedError![]u8 {
|
pub fn getEnvVarOwned(allocator: Allocator, key: []const u8) GetEnvVarOwnedError![]u8 {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const result_w = blk: {
|
const result_w = blk: {
|
||||||
var stack_alloc = std.heap.stackFallback(256 * @sizeOf(u16), allocator);
|
var stack_alloc = std.heap.stackFallback(256 * @sizeOf(u16), allocator);
|
||||||
const stack_allocator = stack_alloc.get();
|
const stack_allocator = stack_alloc.get();
|
||||||
const key_w = try std.unicode.wtf8ToWtf16LeAllocZ(stack_allocator, key);
|
const key_w = try std.unicode.wtf8ToWtf16LeAllocZ(stack_allocator, key);
|
||||||
defer stack_allocator.free(key_w);
|
defer stack_allocator.free(key_w);
|
||||||
|
|
||||||
break :blk std.os.getenvW(key_w) orelse return error.EnvironmentVariableNotFound;
|
break :blk getenvW(key_w) orelse return error.EnvironmentVariableNotFound;
|
||||||
};
|
};
|
||||||
// wtf16LeToWtf8Alloc can only fail with OutOfMemory
|
// wtf16LeToWtf8Alloc can only fail with OutOfMemory
|
||||||
return std.unicode.wtf16LeToWtf8Alloc(allocator, result_w);
|
return std.unicode.wtf16LeToWtf8Alloc(allocator, result_w);
|
||||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
} else if (native_os == .wasi and !builtin.link_libc) {
|
||||||
var envmap = getEnvMap(allocator) catch return error.OutOfMemory;
|
var envmap = getEnvMap(allocator) catch return error.OutOfMemory;
|
||||||
defer envmap.deinit();
|
defer envmap.deinit();
|
||||||
const val = envmap.get(key) orelse return error.EnvironmentVariableNotFound;
|
const val = envmap.get(key) orelse return error.EnvironmentVariableNotFound;
|
||||||
return allocator.dupe(u8, val);
|
return allocator.dupe(u8, val);
|
||||||
} else {
|
} else {
|
||||||
const result = os.getenv(key) orelse return error.EnvironmentVariableNotFound;
|
const result = posix.getenv(key) orelse return error.EnvironmentVariableNotFound;
|
||||||
return allocator.dupe(u8, result);
|
return allocator.dupe(u8, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// On Windows, `key` must be valid UTF-8.
|
/// On Windows, `key` must be valid UTF-8.
|
||||||
pub fn hasEnvVarConstant(comptime key: []const u8) bool {
|
pub fn hasEnvVarConstant(comptime key: []const u8) bool {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const key_w = comptime std.unicode.utf8ToUtf16LeStringLiteral(key);
|
const key_w = comptime std.unicode.utf8ToUtf16LeStringLiteral(key);
|
||||||
return std.os.getenvW(key_w) != null;
|
return getenvW(key_w) != null;
|
||||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
} else if (native_os == .wasi and !builtin.link_libc) {
|
||||||
@compileError("hasEnvVarConstant is not supported for WASI without libc");
|
@compileError("hasEnvVarConstant is not supported for WASI without libc");
|
||||||
} else {
|
} else {
|
||||||
return os.getenv(key) != null;
|
return posix.getenv(key) != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,21 +442,65 @@ pub const HasEnvVarError = error{
|
|||||||
/// On Windows, if `key` is not valid [WTF-8](https://simonsapin.github.io/wtf-8/),
|
/// On Windows, if `key` is not valid [WTF-8](https://simonsapin.github.io/wtf-8/),
|
||||||
/// then `error.InvalidWtf8` is returned.
|
/// then `error.InvalidWtf8` is returned.
|
||||||
pub fn hasEnvVar(allocator: Allocator, key: []const u8) HasEnvVarError!bool {
|
pub fn hasEnvVar(allocator: Allocator, key: []const u8) HasEnvVarError!bool {
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
var stack_alloc = std.heap.stackFallback(256 * @sizeOf(u16), allocator);
|
var stack_alloc = std.heap.stackFallback(256 * @sizeOf(u16), allocator);
|
||||||
const stack_allocator = stack_alloc.get();
|
const stack_allocator = stack_alloc.get();
|
||||||
const key_w = try std.unicode.wtf8ToWtf16LeAllocZ(stack_allocator, key);
|
const key_w = try std.unicode.wtf8ToWtf16LeAllocZ(stack_allocator, key);
|
||||||
defer stack_allocator.free(key_w);
|
defer stack_allocator.free(key_w);
|
||||||
return std.os.getenvW(key_w) != null;
|
return getenvW(key_w) != null;
|
||||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
} else if (native_os == .wasi and !builtin.link_libc) {
|
||||||
var envmap = getEnvMap(allocator) catch return error.OutOfMemory;
|
var envmap = getEnvMap(allocator) catch return error.OutOfMemory;
|
||||||
defer envmap.deinit();
|
defer envmap.deinit();
|
||||||
return envmap.getPtr(key) != null;
|
return envmap.getPtr(key) != null;
|
||||||
} else {
|
} else {
|
||||||
return os.getenv(key) != null;
|
return posix.getenv(key) != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Windows-only. Get an environment variable with a null-terminated, WTF-16 encoded name.
|
||||||
|
///
|
||||||
|
/// This function performs a Unicode-aware case-insensitive lookup using RtlEqualUnicodeString.
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
/// * `std.posix.getenv`
|
||||||
|
/// * `getEnvMap`
|
||||||
|
/// * `getEnvVarOwned`
|
||||||
|
/// * `hasEnvVarConstant`
|
||||||
|
/// * `hasEnvVar`
|
||||||
|
pub fn getenvW(key: [*:0]const u16) ?[:0]const u16 {
|
||||||
|
if (native_os != .windows) {
|
||||||
|
@compileError("Windows-only");
|
||||||
|
}
|
||||||
|
const key_slice = mem.sliceTo(key, 0);
|
||||||
|
const ptr = windows.peb().ProcessParameters.Environment;
|
||||||
|
var i: usize = 0;
|
||||||
|
while (ptr[i] != 0) {
|
||||||
|
const key_start = i;
|
||||||
|
|
||||||
|
// There are some special environment variables that start with =,
|
||||||
|
// so we need a special case to not treat = as a key/value separator
|
||||||
|
// if it's the first character.
|
||||||
|
// https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133
|
||||||
|
if (ptr[key_start] == '=') i += 1;
|
||||||
|
|
||||||
|
while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
|
||||||
|
const this_key = ptr[key_start..i];
|
||||||
|
|
||||||
|
if (ptr[i] == '=') i += 1;
|
||||||
|
|
||||||
|
const value_start = i;
|
||||||
|
while (ptr[i] != 0) : (i += 1) {}
|
||||||
|
const this_value = ptr[value_start..i :0];
|
||||||
|
|
||||||
|
if (windows.eqlIgnoreCaseWTF16(key_slice, this_key)) {
|
||||||
|
return this_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 1; // skip over null byte
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
test getEnvVarOwned {
|
test getEnvVarOwned {
|
||||||
try testing.expectError(
|
try testing.expectError(
|
||||||
error.EnvironmentVariableNotFound,
|
error.EnvironmentVariableNotFound,
|
||||||
@ -459,7 +509,7 @@ test getEnvVarOwned {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test hasEnvVarConstant {
|
test hasEnvVarConstant {
|
||||||
if (builtin.os.tag == .wasi and !builtin.link_libc) return error.SkipZigTest;
|
if (native_os == .wasi and !builtin.link_libc) return error.SkipZigTest;
|
||||||
|
|
||||||
try testing.expect(!hasEnvVarConstant("BADENV"));
|
try testing.expect(!hasEnvVarConstant("BADENV"));
|
||||||
}
|
}
|
||||||
@ -478,14 +528,14 @@ pub const ArgIteratorPosix = struct {
|
|||||||
pub fn init() ArgIteratorPosix {
|
pub fn init() ArgIteratorPosix {
|
||||||
return ArgIteratorPosix{
|
return ArgIteratorPosix{
|
||||||
.index = 0,
|
.index = 0,
|
||||||
.count = os.argv.len,
|
.count = std.os.argv.len,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next(self: *ArgIteratorPosix) ?[:0]const u8 {
|
pub fn next(self: *ArgIteratorPosix) ?[:0]const u8 {
|
||||||
if (self.index == self.count) return null;
|
if (self.index == self.count) return null;
|
||||||
|
|
||||||
const s = os.argv[self.index];
|
const s = std.os.argv[self.index];
|
||||||
self.index += 1;
|
self.index += 1;
|
||||||
return mem.sliceTo(s, 0);
|
return mem.sliceTo(s, 0);
|
||||||
}
|
}
|
||||||
@ -503,7 +553,7 @@ pub const ArgIteratorWasi = struct {
|
|||||||
index: usize,
|
index: usize,
|
||||||
args: [][:0]u8,
|
args: [][:0]u8,
|
||||||
|
|
||||||
pub const InitError = error{OutOfMemory} || os.UnexpectedError;
|
pub const InitError = error{OutOfMemory} || posix.UnexpectedError;
|
||||||
|
|
||||||
/// You must call deinit to free the internal buffer of the
|
/// You must call deinit to free the internal buffer of the
|
||||||
/// iterator after you are done.
|
/// iterator after you are done.
|
||||||
@ -517,13 +567,12 @@ pub const ArgIteratorWasi = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn internalInit(allocator: Allocator) InitError![][:0]u8 {
|
fn internalInit(allocator: Allocator) InitError![][:0]u8 {
|
||||||
const w = os.wasi;
|
|
||||||
var count: usize = undefined;
|
var count: usize = undefined;
|
||||||
var buf_size: usize = undefined;
|
var buf_size: usize = undefined;
|
||||||
|
|
||||||
switch (w.args_sizes_get(&count, &buf_size)) {
|
switch (std.os.wasi.args_sizes_get(&count, &buf_size)) {
|
||||||
.SUCCESS => {},
|
.SUCCESS => {},
|
||||||
else => |err| return os.unexpectedErrno(err),
|
else => |err| return posix.unexpectedErrno(err),
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
@ -535,9 +584,9 @@ pub const ArgIteratorWasi = struct {
|
|||||||
|
|
||||||
const argv_buf = try allocator.alloc(u8, buf_size);
|
const argv_buf = try allocator.alloc(u8, buf_size);
|
||||||
|
|
||||||
switch (w.args_get(argv.ptr, argv_buf.ptr)) {
|
switch (std.os.wasi.args_get(argv.ptr, argv_buf.ptr)) {
|
||||||
.SUCCESS => {},
|
.SUCCESS => {},
|
||||||
else => |err| return os.unexpectedErrno(err),
|
else => |err| return posix.unexpectedErrno(err),
|
||||||
}
|
}
|
||||||
|
|
||||||
var result_args = try allocator.alloc([:0]u8, count);
|
var result_args = try allocator.alloc([:0]u8, count);
|
||||||
@ -1007,7 +1056,7 @@ pub fn ArgIteratorGeneral(comptime options: ArgIteratorGeneralOptions) type {
|
|||||||
|
|
||||||
/// Cross-platform command line argument iterator.
|
/// Cross-platform command line argument iterator.
|
||||||
pub const ArgIterator = struct {
|
pub const ArgIterator = struct {
|
||||||
const InnerType = switch (builtin.os.tag) {
|
const InnerType = switch (native_os) {
|
||||||
.windows => ArgIteratorWindows,
|
.windows => ArgIteratorWindows,
|
||||||
.wasi => if (builtin.link_libc) ArgIteratorPosix else ArgIteratorWasi,
|
.wasi => if (builtin.link_libc) ArgIteratorPosix else ArgIteratorWasi,
|
||||||
else => ArgIteratorPosix,
|
else => ArgIteratorPosix,
|
||||||
@ -1018,10 +1067,10 @@ pub const ArgIterator = struct {
|
|||||||
/// Initialize the args iterator. Consider using initWithAllocator() instead
|
/// Initialize the args iterator. Consider using initWithAllocator() instead
|
||||||
/// for cross-platform compatibility.
|
/// for cross-platform compatibility.
|
||||||
pub fn init() ArgIterator {
|
pub fn init() ArgIterator {
|
||||||
if (builtin.os.tag == .wasi) {
|
if (native_os == .wasi) {
|
||||||
@compileError("In WASI, use initWithAllocator instead.");
|
@compileError("In WASI, use initWithAllocator instead.");
|
||||||
}
|
}
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
@compileError("In Windows, use initWithAllocator instead.");
|
@compileError("In Windows, use initWithAllocator instead.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1032,11 +1081,11 @@ pub const ArgIterator = struct {
|
|||||||
|
|
||||||
/// You must deinitialize iterator's internal buffers by calling `deinit` when done.
|
/// You must deinitialize iterator's internal buffers by calling `deinit` when done.
|
||||||
pub fn initWithAllocator(allocator: Allocator) InitError!ArgIterator {
|
pub fn initWithAllocator(allocator: Allocator) InitError!ArgIterator {
|
||||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
if (native_os == .wasi and !builtin.link_libc) {
|
||||||
return ArgIterator{ .inner = try InnerType.init(allocator) };
|
return ArgIterator{ .inner = try InnerType.init(allocator) };
|
||||||
}
|
}
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
const cmd_line_w = os.windows.kernel32.GetCommandLineW();
|
const cmd_line_w = windows.kernel32.GetCommandLineW();
|
||||||
return ArgIterator{ .inner = try InnerType.init(allocator, cmd_line_w) };
|
return ArgIterator{ .inner = try InnerType.init(allocator, cmd_line_w) };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1061,11 +1110,11 @@ pub const ArgIterator = struct {
|
|||||||
/// was created with `initWithAllocator` function.
|
/// was created with `initWithAllocator` function.
|
||||||
pub fn deinit(self: *ArgIterator) void {
|
pub fn deinit(self: *ArgIterator) void {
|
||||||
// Unless we're targeting WASI or Windows, this is a no-op.
|
// Unless we're targeting WASI or Windows, this is a no-op.
|
||||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
if (native_os == .wasi and !builtin.link_libc) {
|
||||||
self.inner.deinit();
|
self.inner.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
self.inner.deinit();
|
self.inner.deinit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1334,13 +1383,13 @@ fn testResponseFileCmdLine(input_cmd_line: []const u8, expected_args: []const []
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub const UserInfo = struct {
|
pub const UserInfo = struct {
|
||||||
uid: os.uid_t,
|
uid: posix.uid_t,
|
||||||
gid: os.gid_t,
|
gid: posix.gid_t,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// POSIX function which gets a uid from username.
|
/// POSIX function which gets a uid from username.
|
||||||
pub fn getUserInfo(name: []const u8) !UserInfo {
|
pub fn getUserInfo(name: []const u8) !UserInfo {
|
||||||
return switch (builtin.os.tag) {
|
return switch (native_os) {
|
||||||
.linux,
|
.linux,
|
||||||
.macos,
|
.macos,
|
||||||
.watchos,
|
.watchos,
|
||||||
@ -1376,8 +1425,8 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {
|
|||||||
var buf: [std.mem.page_size]u8 = undefined;
|
var buf: [std.mem.page_size]u8 = undefined;
|
||||||
var name_index: usize = 0;
|
var name_index: usize = 0;
|
||||||
var state = State.Start;
|
var state = State.Start;
|
||||||
var uid: os.uid_t = 0;
|
var uid: posix.uid_t = 0;
|
||||||
var gid: os.gid_t = 0;
|
var gid: posix.gid_t = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const amt_read = try reader.read(buf[0..]);
|
const amt_read = try reader.read(buf[0..]);
|
||||||
@ -1462,36 +1511,36 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getBaseAddress() usize {
|
pub fn getBaseAddress() usize {
|
||||||
switch (builtin.os.tag) {
|
switch (native_os) {
|
||||||
.linux => {
|
.linux => {
|
||||||
const base = os.system.getauxval(std.elf.AT_BASE);
|
const base = std.os.linux.getauxval(std.elf.AT_BASE);
|
||||||
if (base != 0) {
|
if (base != 0) {
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
const phdr = os.system.getauxval(std.elf.AT_PHDR);
|
const phdr = std.os.linux.getauxval(std.elf.AT_PHDR);
|
||||||
return phdr - @sizeOf(std.elf.Ehdr);
|
return phdr - @sizeOf(std.elf.Ehdr);
|
||||||
},
|
},
|
||||||
.macos, .freebsd, .netbsd => {
|
.macos, .freebsd, .netbsd => {
|
||||||
return @intFromPtr(&std.c._mh_execute_header);
|
return @intFromPtr(&std.c._mh_execute_header);
|
||||||
},
|
},
|
||||||
.windows => return @intFromPtr(os.windows.kernel32.GetModuleHandleW(null)),
|
.windows => return @intFromPtr(windows.kernel32.GetModuleHandleW(null)),
|
||||||
else => @compileError("Unsupported OS"),
|
else => @compileError("Unsupported OS"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tells whether calling the `execv` or `execve` functions will be a compile error.
|
/// Tells whether calling the `execv` or `execve` functions will be a compile error.
|
||||||
pub const can_execv = switch (builtin.os.tag) {
|
pub const can_execv = switch (native_os) {
|
||||||
.windows, .haiku, .wasi => false,
|
.windows, .haiku, .wasi => false,
|
||||||
else => true,
|
else => true,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Tells whether spawning child processes is supported (e.g. via ChildProcess)
|
/// Tells whether spawning child processes is supported (e.g. via ChildProcess)
|
||||||
pub const can_spawn = switch (builtin.os.tag) {
|
pub const can_spawn = switch (native_os) {
|
||||||
.wasi, .watchos, .tvos => false,
|
.wasi, .watchos, .tvos => false,
|
||||||
else => true,
|
else => true,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ExecvError = std.os.ExecveError || error{OutOfMemory};
|
pub const ExecvError = std.posix.ExecveError || error{OutOfMemory};
|
||||||
|
|
||||||
/// Replaces the current process image with the executed process.
|
/// Replaces the current process image with the executed process.
|
||||||
/// This function must allocate memory to add a null terminating bytes on path and each arg.
|
/// This function must allocate memory to add a null terminating bytes on path and each arg.
|
||||||
@ -1500,7 +1549,7 @@ pub const ExecvError = std.os.ExecveError || error{OutOfMemory};
|
|||||||
/// `argv[0]` is the executable path.
|
/// `argv[0]` is the executable path.
|
||||||
/// This function also uses the PATH environment variable to get the full path to the executable.
|
/// This function also uses the PATH environment variable to get the full path to the executable.
|
||||||
/// Due to the heap-allocation, it is illegal to call this function in a fork() child.
|
/// Due to the heap-allocation, it is illegal to call this function in a fork() child.
|
||||||
/// For that use case, use the `std.os` functions directly.
|
/// For that use case, use the `std.posix` functions directly.
|
||||||
pub fn execv(allocator: Allocator, argv: []const []const u8) ExecvError {
|
pub fn execv(allocator: Allocator, argv: []const []const u8) ExecvError {
|
||||||
return execve(allocator, argv, null);
|
return execve(allocator, argv, null);
|
||||||
}
|
}
|
||||||
@ -1512,7 +1561,7 @@ pub fn execv(allocator: Allocator, argv: []const []const u8) ExecvError {
|
|||||||
/// `argv[0]` is the executable path.
|
/// `argv[0]` is the executable path.
|
||||||
/// This function also uses the PATH environment variable to get the full path to the executable.
|
/// This function also uses the PATH environment variable to get the full path to the executable.
|
||||||
/// Due to the heap-allocation, it is illegal to call this function in a fork() child.
|
/// Due to the heap-allocation, it is illegal to call this function in a fork() child.
|
||||||
/// For that use case, use the `std.os` functions directly.
|
/// For that use case, use the `std.posix` functions directly.
|
||||||
pub fn execve(
|
pub fn execve(
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
argv: []const []const u8,
|
argv: []const []const u8,
|
||||||
@ -1536,14 +1585,14 @@ pub fn execve(
|
|||||||
} else if (builtin.output_mode == .Exe) {
|
} else if (builtin.output_mode == .Exe) {
|
||||||
// Then we have Zig start code and this works.
|
// Then we have Zig start code and this works.
|
||||||
// TODO type-safety for null-termination of `os.environ`.
|
// TODO type-safety for null-termination of `os.environ`.
|
||||||
break :m @as([*:null]const ?[*:0]const u8, @ptrCast(os.environ.ptr));
|
break :m @as([*:null]const ?[*:0]const u8, @ptrCast(std.os.environ.ptr));
|
||||||
} else {
|
} else {
|
||||||
// TODO come up with a solution for this.
|
// TODO come up with a solution for this.
|
||||||
@compileError("missing std lib enhancement: std.process.execv implementation has no way to collect the environment variables to forward to the child process");
|
@compileError("missing std lib enhancement: std.process.execv implementation has no way to collect the environment variables to forward to the child process");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return os.execvpeZ_expandArg0(.no_expand, argv_buf.ptr[0].?, argv_buf.ptr, envp);
|
return posix.execvpeZ_expandArg0(.no_expand, argv_buf.ptr[0].?, argv_buf.ptr, envp);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const TotalSystemMemoryError = error{
|
pub const TotalSystemMemoryError = error{
|
||||||
@ -1555,14 +1604,14 @@ pub const TotalSystemMemoryError = error{
|
|||||||
/// and Linux's /proc/meminfo reporting more memory when
|
/// and Linux's /proc/meminfo reporting more memory when
|
||||||
/// using QEMU user mode emulation.
|
/// using QEMU user mode emulation.
|
||||||
pub fn totalSystemMemory() TotalSystemMemoryError!u64 {
|
pub fn totalSystemMemory() TotalSystemMemoryError!u64 {
|
||||||
switch (builtin.os.tag) {
|
switch (native_os) {
|
||||||
.linux => {
|
.linux => {
|
||||||
return totalSystemMemoryLinux() catch return error.UnknownTotalSystemMemory;
|
return totalSystemMemoryLinux() catch return error.UnknownTotalSystemMemory;
|
||||||
},
|
},
|
||||||
.freebsd => {
|
.freebsd => {
|
||||||
var physmem: c_ulong = undefined;
|
var physmem: c_ulong = undefined;
|
||||||
var len: usize = @sizeOf(c_ulong);
|
var len: usize = @sizeOf(c_ulong);
|
||||||
os.sysctlbynameZ("hw.physmem", &physmem, &len, null, 0) catch |err| switch (err) {
|
posix.sysctlbynameZ("hw.physmem", &physmem, &len, null, 0) catch |err| switch (err) {
|
||||||
error.NameTooLong, error.UnknownName => unreachable,
|
error.NameTooLong, error.UnknownName => unreachable,
|
||||||
else => return error.UnknownTotalSystemMemory,
|
else => return error.UnknownTotalSystemMemory,
|
||||||
};
|
};
|
||||||
@ -1570,12 +1619,12 @@ pub fn totalSystemMemory() TotalSystemMemoryError!u64 {
|
|||||||
},
|
},
|
||||||
.openbsd => {
|
.openbsd => {
|
||||||
const mib: [2]c_int = [_]c_int{
|
const mib: [2]c_int = [_]c_int{
|
||||||
std.os.CTL.HW,
|
posix.CTL.HW,
|
||||||
std.os.HW.PHYSMEM64,
|
posix.HW.PHYSMEM64,
|
||||||
};
|
};
|
||||||
var physmem: i64 = undefined;
|
var physmem: i64 = undefined;
|
||||||
var len: usize = @sizeOf(@TypeOf(physmem));
|
var len: usize = @sizeOf(@TypeOf(physmem));
|
||||||
std.os.sysctl(&mib, &physmem, &len, null, 0) catch |err| switch (err) {
|
posix.sysctl(&mib, &physmem, &len, null, 0) catch |err| switch (err) {
|
||||||
error.NameTooLong => unreachable, // constant, known good value
|
error.NameTooLong => unreachable, // constant, known good value
|
||||||
error.PermissionDenied => unreachable, // only when setting values,
|
error.PermissionDenied => unreachable, // only when setting values,
|
||||||
error.SystemResources => unreachable, // memory already on the stack
|
error.SystemResources => unreachable, // memory already on the stack
|
||||||
@ -1586,11 +1635,11 @@ pub fn totalSystemMemory() TotalSystemMemoryError!u64 {
|
|||||||
return @as(u64, @bitCast(physmem));
|
return @as(u64, @bitCast(physmem));
|
||||||
},
|
},
|
||||||
.windows => {
|
.windows => {
|
||||||
var sbi: std.os.windows.SYSTEM_BASIC_INFORMATION = undefined;
|
var sbi: windows.SYSTEM_BASIC_INFORMATION = undefined;
|
||||||
const rc = std.os.windows.ntdll.NtQuerySystemInformation(
|
const rc = windows.ntdll.NtQuerySystemInformation(
|
||||||
.SystemBasicInformation,
|
.SystemBasicInformation,
|
||||||
&sbi,
|
&sbi,
|
||||||
@sizeOf(std.os.windows.SYSTEM_BASIC_INFORMATION),
|
@sizeOf(windows.SYSTEM_BASIC_INFORMATION),
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
if (rc != .SUCCESS) {
|
if (rc != .SUCCESS) {
|
||||||
|
|||||||
@ -407,7 +407,7 @@ fn posixCallMainAndExit() callconv(.C) noreturn {
|
|||||||
// FIXME: Make __aeabi_read_tp call the kernel helper kuser_get_tls
|
// FIXME: Make __aeabi_read_tp call the kernel helper kuser_get_tls
|
||||||
// For the time being use a simple abort instead of a @panic call to
|
// For the time being use a simple abort instead of a @panic call to
|
||||||
// keep the binary bloat under control.
|
// keep the binary bloat under control.
|
||||||
std.os.abort();
|
std.posix.abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -422,7 +422,7 @@ fn posixCallMainAndExit() callconv(.C) noreturn {
|
|||||||
expandStackSize(phdrs);
|
expandStackSize(phdrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
std.os.exit(callMainWithArgs(argc, argv, envp));
|
std.posix.exit(callMainWithArgs(argc, argv, envp));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expandStackSize(phdrs: []elf.Phdr) void {
|
fn expandStackSize(phdrs: []elf.Phdr) void {
|
||||||
@ -432,13 +432,13 @@ fn expandStackSize(phdrs: []elf.Phdr) void {
|
|||||||
assert(phdr.p_memsz % std.mem.page_size == 0);
|
assert(phdr.p_memsz % std.mem.page_size == 0);
|
||||||
|
|
||||||
// Silently fail if we are unable to get limits.
|
// Silently fail if we are unable to get limits.
|
||||||
const limits = std.os.getrlimit(.STACK) catch break;
|
const limits = std.posix.getrlimit(.STACK) catch break;
|
||||||
|
|
||||||
// Clamp to limits.max .
|
// Clamp to limits.max .
|
||||||
const wanted_stack_size = @min(phdr.p_memsz, limits.max);
|
const wanted_stack_size = @min(phdr.p_memsz, limits.max);
|
||||||
|
|
||||||
if (wanted_stack_size > limits.cur) {
|
if (wanted_stack_size > limits.cur) {
|
||||||
std.os.setrlimit(.STACK, .{
|
std.posix.setrlimit(.STACK, .{
|
||||||
.cur = wanted_stack_size,
|
.cur = wanted_stack_size,
|
||||||
.max = limits.max,
|
.max = limits.max,
|
||||||
}) catch {
|
}) catch {
|
||||||
@ -464,7 +464,7 @@ inline fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 {
|
|||||||
std.os.environ = envp;
|
std.os.environ = envp;
|
||||||
|
|
||||||
std.debug.maybeEnableSegfaultHandler();
|
std.debug.maybeEnableSegfaultHandler();
|
||||||
std.os.maybeIgnoreSigpipe();
|
maybeIgnoreSigpipe();
|
||||||
|
|
||||||
return callMain();
|
return callMain();
|
||||||
}
|
}
|
||||||
@ -563,3 +563,38 @@ pub fn call_wWinMain() std.os.windows.INT {
|
|||||||
// second parameter hPrevInstance, MSDN: "This parameter is always NULL"
|
// second parameter hPrevInstance, MSDN: "This parameter is always NULL"
|
||||||
return root.wWinMain(hInstance, null, lpCmdLine, nCmdShow);
|
return root.wWinMain(hInstance, null, lpCmdLine, nCmdShow);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn maybeIgnoreSigpipe() void {
|
||||||
|
const have_sigpipe_support = switch (builtin.os.tag) {
|
||||||
|
.linux,
|
||||||
|
.plan9,
|
||||||
|
.solaris,
|
||||||
|
.netbsd,
|
||||||
|
.openbsd,
|
||||||
|
.haiku,
|
||||||
|
.macos,
|
||||||
|
.ios,
|
||||||
|
.watchos,
|
||||||
|
.tvos,
|
||||||
|
.dragonfly,
|
||||||
|
.freebsd,
|
||||||
|
=> true,
|
||||||
|
|
||||||
|
else => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (have_sigpipe_support and !std.options.keep_sigpipe) {
|
||||||
|
const posix = std.posix;
|
||||||
|
const act: posix.Sigaction = .{
|
||||||
|
// Set handler to a noop function instead of `SIG.IGN` to prevent
|
||||||
|
// leaking signal disposition to a child process.
|
||||||
|
.handler = .{ .handler = noopSigHandler },
|
||||||
|
.mask = posix.empty_sigset,
|
||||||
|
.flags = 0,
|
||||||
|
};
|
||||||
|
posix.sigaction(posix.SIG.PIPE, &act, null) catch |err|
|
||||||
|
std.debug.panic("failed to set noop SIGPIPE handler: {s}", .{@errorName(err)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn noopSigHandler(_: c_int) callconv(.C) void {}
|
||||||
|
|||||||
@ -85,12 +85,11 @@ pub const math = @import("math.zig");
|
|||||||
pub const mem = @import("mem.zig");
|
pub const mem = @import("mem.zig");
|
||||||
pub const meta = @import("meta.zig");
|
pub const meta = @import("meta.zig");
|
||||||
pub const net = @import("net.zig");
|
pub const net = @import("net.zig");
|
||||||
pub const posix = @import("os.zig");
|
|
||||||
/// Non-portable Operating System-specific API.
|
|
||||||
pub const os = @import("os.zig");
|
pub const os = @import("os.zig");
|
||||||
pub const once = @import("once.zig").once;
|
pub const once = @import("once.zig").once;
|
||||||
pub const packed_int_array = @import("packed_int_array.zig");
|
pub const packed_int_array = @import("packed_int_array.zig");
|
||||||
pub const pdb = @import("pdb.zig");
|
pub const pdb = @import("pdb.zig");
|
||||||
|
pub const posix = @import("posix.zig");
|
||||||
pub const process = @import("process.zig");
|
pub const process = @import("process.zig");
|
||||||
/// Deprecated: use `Random` instead.
|
/// Deprecated: use `Random` instead.
|
||||||
pub const rand = Random;
|
pub const rand = Random;
|
||||||
@ -170,3 +169,7 @@ comptime {
|
|||||||
test {
|
test {
|
||||||
testing.refAllDecls(@This());
|
testing.refAllDecls(@This());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
comptime {
|
||||||
|
debug.assert(@import("std") == @This()); // std lib tests require --zig-lib-dir
|
||||||
|
}
|
||||||
|
|||||||
@ -2,8 +2,9 @@ const std = @import("std.zig");
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const os = std.os;
|
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
|
const windows = std.os.windows;
|
||||||
|
const posix = std.posix;
|
||||||
|
|
||||||
pub const epoch = @import("time/epoch.zig");
|
pub const epoch = @import("time/epoch.zig");
|
||||||
|
|
||||||
@ -11,8 +12,8 @@ pub const epoch = @import("time/epoch.zig");
|
|||||||
pub fn sleep(nanoseconds: u64) void {
|
pub fn sleep(nanoseconds: u64) void {
|
||||||
if (builtin.os.tag == .windows) {
|
if (builtin.os.tag == .windows) {
|
||||||
const big_ms_from_ns = nanoseconds / ns_per_ms;
|
const big_ms_from_ns = nanoseconds / ns_per_ms;
|
||||||
const ms = math.cast(os.windows.DWORD, big_ms_from_ns) orelse math.maxInt(os.windows.DWORD);
|
const ms = math.cast(windows.DWORD, big_ms_from_ns) orelse math.maxInt(windows.DWORD);
|
||||||
os.windows.kernel32.Sleep(ms);
|
windows.kernel32.Sleep(ms);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +41,7 @@ pub fn sleep(nanoseconds: u64) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (builtin.os.tag == .uefi) {
|
if (builtin.os.tag == .uefi) {
|
||||||
const boot_services = os.uefi.system_table.boot_services.?;
|
const boot_services = std.os.uefi.system_table.boot_services.?;
|
||||||
const us_from_ns = nanoseconds / ns_per_us;
|
const us_from_ns = nanoseconds / ns_per_us;
|
||||||
const us = math.cast(usize, us_from_ns) orelse math.maxInt(usize);
|
const us = math.cast(usize, us_from_ns) orelse math.maxInt(usize);
|
||||||
_ = boot_services.stall(us);
|
_ = boot_services.stall(us);
|
||||||
@ -49,7 +50,7 @@ pub fn sleep(nanoseconds: u64) void {
|
|||||||
|
|
||||||
const s = nanoseconds / ns_per_s;
|
const s = nanoseconds / ns_per_s;
|
||||||
const ns = nanoseconds % ns_per_s;
|
const ns = nanoseconds % ns_per_s;
|
||||||
std.os.nanosleep(s, ns);
|
posix.nanosleep(s, ns);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "sleep" {
|
test "sleep" {
|
||||||
@ -60,7 +61,7 @@ test "sleep" {
|
|||||||
/// Precision of timing depends on the hardware and operating system.
|
/// Precision of timing depends on the hardware and operating system.
|
||||||
/// The return value is signed because it is possible to have a date that is
|
/// The return value is signed because it is possible to have a date that is
|
||||||
/// before the epoch.
|
/// before the epoch.
|
||||||
/// See `std.os.clock_gettime` for a POSIX timestamp.
|
/// See `posix.clock_gettime` for a POSIX timestamp.
|
||||||
pub fn timestamp() i64 {
|
pub fn timestamp() i64 {
|
||||||
return @divFloor(milliTimestamp(), ms_per_s);
|
return @divFloor(milliTimestamp(), ms_per_s);
|
||||||
}
|
}
|
||||||
@ -69,7 +70,7 @@ pub fn timestamp() i64 {
|
|||||||
/// Precision of timing depends on the hardware and operating system.
|
/// Precision of timing depends on the hardware and operating system.
|
||||||
/// The return value is signed because it is possible to have a date that is
|
/// The return value is signed because it is possible to have a date that is
|
||||||
/// before the epoch.
|
/// before the epoch.
|
||||||
/// See `std.os.clock_gettime` for a POSIX timestamp.
|
/// See `posix.clock_gettime` for a POSIX timestamp.
|
||||||
pub fn milliTimestamp() i64 {
|
pub fn milliTimestamp() i64 {
|
||||||
return @as(i64, @intCast(@divFloor(nanoTimestamp(), ns_per_ms)));
|
return @as(i64, @intCast(@divFloor(nanoTimestamp(), ns_per_ms)));
|
||||||
}
|
}
|
||||||
@ -78,7 +79,7 @@ pub fn milliTimestamp() i64 {
|
|||||||
/// Precision of timing depends on the hardware and operating system.
|
/// Precision of timing depends on the hardware and operating system.
|
||||||
/// The return value is signed because it is possible to have a date that is
|
/// The return value is signed because it is possible to have a date that is
|
||||||
/// before the epoch.
|
/// before the epoch.
|
||||||
/// See `std.os.clock_gettime` for a POSIX timestamp.
|
/// See `posix.clock_gettime` for a POSIX timestamp.
|
||||||
pub fn microTimestamp() i64 {
|
pub fn microTimestamp() i64 {
|
||||||
return @as(i64, @intCast(@divFloor(nanoTimestamp(), ns_per_us)));
|
return @as(i64, @intCast(@divFloor(nanoTimestamp(), ns_per_us)));
|
||||||
}
|
}
|
||||||
@ -88,21 +89,21 @@ pub fn microTimestamp() i64 {
|
|||||||
/// On Windows this has a maximum granularity of 100 nanoseconds.
|
/// On Windows this has a maximum granularity of 100 nanoseconds.
|
||||||
/// The return value is signed because it is possible to have a date that is
|
/// The return value is signed because it is possible to have a date that is
|
||||||
/// before the epoch.
|
/// before the epoch.
|
||||||
/// See `std.os.clock_gettime` for a POSIX timestamp.
|
/// See `posix.clock_gettime` for a POSIX timestamp.
|
||||||
pub fn nanoTimestamp() i128 {
|
pub fn nanoTimestamp() i128 {
|
||||||
switch (builtin.os.tag) {
|
switch (builtin.os.tag) {
|
||||||
.windows => {
|
.windows => {
|
||||||
// FileTime has a granularity of 100 nanoseconds and uses the NTFS/Windows epoch,
|
// FileTime has a granularity of 100 nanoseconds and uses the NTFS/Windows epoch,
|
||||||
// which is 1601-01-01.
|
// which is 1601-01-01.
|
||||||
const epoch_adj = epoch.windows * (ns_per_s / 100);
|
const epoch_adj = epoch.windows * (ns_per_s / 100);
|
||||||
var ft: os.windows.FILETIME = undefined;
|
var ft: windows.FILETIME = undefined;
|
||||||
os.windows.kernel32.GetSystemTimeAsFileTime(&ft);
|
windows.kernel32.GetSystemTimeAsFileTime(&ft);
|
||||||
const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
|
const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
|
||||||
return @as(i128, @as(i64, @bitCast(ft64)) + epoch_adj) * 100;
|
return @as(i128, @as(i64, @bitCast(ft64)) + epoch_adj) * 100;
|
||||||
},
|
},
|
||||||
.wasi => {
|
.wasi => {
|
||||||
var ns: os.wasi.timestamp_t = undefined;
|
var ns: std.os.wasi.timestamp_t = undefined;
|
||||||
const err = os.wasi.clock_time_get(.REALTIME, 1, &ns);
|
const err = std.os.wasi.clock_time_get(.REALTIME, 1, &ns);
|
||||||
assert(err == .SUCCESS);
|
assert(err == .SUCCESS);
|
||||||
return ns;
|
return ns;
|
||||||
},
|
},
|
||||||
@ -113,8 +114,8 @@ pub fn nanoTimestamp() i128 {
|
|||||||
return value.toEpoch();
|
return value.toEpoch();
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
var ts: os.timespec = undefined;
|
var ts: posix.timespec = undefined;
|
||||||
os.clock_gettime(os.CLOCK.REALTIME, &ts) catch |err| switch (err) {
|
posix.clock_gettime(posix.CLOCK.REALTIME, &ts) catch |err| switch (err) {
|
||||||
error.UnsupportedClock, error.Unexpected => return 0, // "Precision of timing depends on hardware and OS".
|
error.UnsupportedClock, error.Unexpected => return 0, // "Precision of timing depends on hardware and OS".
|
||||||
};
|
};
|
||||||
return (@as(i128, ts.tv_sec) * ns_per_s) + ts.tv_nsec;
|
return (@as(i128, ts.tv_sec) * ns_per_s) + ts.tv_nsec;
|
||||||
@ -172,7 +173,7 @@ pub const s_per_week = s_per_day * 7;
|
|||||||
/// It also tries to be monotonic, but this is not a guarantee due to OS/hardware bugs.
|
/// It also tries to be monotonic, but this is not a guarantee due to OS/hardware bugs.
|
||||||
/// If you need monotonic readings for elapsed time, consider `Timer` instead.
|
/// If you need monotonic readings for elapsed time, consider `Timer` instead.
|
||||||
pub const Instant = struct {
|
pub const Instant = struct {
|
||||||
timestamp: if (is_posix) os.timespec else u64,
|
timestamp: if (is_posix) posix.timespec else u64,
|
||||||
|
|
||||||
// true if we should use clock_gettime()
|
// true if we should use clock_gettime()
|
||||||
const is_posix = switch (builtin.os.tag) {
|
const is_posix = switch (builtin.os.tag) {
|
||||||
@ -188,11 +189,11 @@ pub const Instant = struct {
|
|||||||
const clock_id = switch (builtin.os.tag) {
|
const clock_id = switch (builtin.os.tag) {
|
||||||
.windows => {
|
.windows => {
|
||||||
// QPC on windows doesn't fail on >= XP/2000 and includes time suspended.
|
// QPC on windows doesn't fail on >= XP/2000 and includes time suspended.
|
||||||
return Instant{ .timestamp = os.windows.QueryPerformanceCounter() };
|
return Instant{ .timestamp = windows.QueryPerformanceCounter() };
|
||||||
},
|
},
|
||||||
.wasi => {
|
.wasi => {
|
||||||
var ns: os.wasi.timestamp_t = undefined;
|
var ns: std.os.wasi.timestamp_t = undefined;
|
||||||
const rc = os.wasi.clock_time_get(.MONOTONIC, 1, &ns);
|
const rc = std.os.wasi.clock_time_get(.MONOTONIC, 1, &ns);
|
||||||
if (rc != .SUCCESS) return error.Unsupported;
|
if (rc != .SUCCESS) return error.Unsupported;
|
||||||
return .{ .timestamp = ns };
|
return .{ .timestamp = ns };
|
||||||
},
|
},
|
||||||
@ -204,21 +205,21 @@ pub const Instant = struct {
|
|||||||
},
|
},
|
||||||
// On darwin, use UPTIME_RAW instead of MONOTONIC as it ticks while
|
// On darwin, use UPTIME_RAW instead of MONOTONIC as it ticks while
|
||||||
// suspended.
|
// suspended.
|
||||||
.macos, .ios, .tvos, .watchos => os.CLOCK.UPTIME_RAW,
|
.macos, .ios, .tvos, .watchos => posix.CLOCK.UPTIME_RAW,
|
||||||
// On freebsd derivatives, use MONOTONIC_FAST as currently there's
|
// On freebsd derivatives, use MONOTONIC_FAST as currently there's
|
||||||
// no precision tradeoff.
|
// no precision tradeoff.
|
||||||
.freebsd, .dragonfly => os.CLOCK.MONOTONIC_FAST,
|
.freebsd, .dragonfly => posix.CLOCK.MONOTONIC_FAST,
|
||||||
// On linux, use BOOTTIME instead of MONOTONIC as it ticks while
|
// On linux, use BOOTTIME instead of MONOTONIC as it ticks while
|
||||||
// suspended.
|
// suspended.
|
||||||
.linux => os.CLOCK.BOOTTIME,
|
.linux => posix.CLOCK.BOOTTIME,
|
||||||
// On other posix systems, MONOTONIC is generally the fastest and
|
// On other posix systems, MONOTONIC is generally the fastest and
|
||||||
// ticks while suspended.
|
// ticks while suspended.
|
||||||
else => os.CLOCK.MONOTONIC,
|
else => posix.CLOCK.MONOTONIC,
|
||||||
};
|
};
|
||||||
|
|
||||||
var ts: os.timespec = undefined;
|
var ts: posix.timespec = undefined;
|
||||||
os.clock_gettime(clock_id, &ts) catch return error.Unsupported;
|
posix.clock_gettime(clock_id, &ts) catch return error.Unsupported;
|
||||||
return Instant{ .timestamp = ts };
|
return .{ .timestamp = ts };
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Quickly compares two instances between each other.
|
/// Quickly compares two instances between each other.
|
||||||
@ -245,7 +246,7 @@ pub const Instant = struct {
|
|||||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data
|
// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data
|
||||||
// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm
|
// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm
|
||||||
const qpc = self.timestamp - earlier.timestamp;
|
const qpc = self.timestamp - earlier.timestamp;
|
||||||
const qpf = os.windows.QueryPerformanceFrequency();
|
const qpf = windows.QueryPerformanceFrequency();
|
||||||
|
|
||||||
// 10Mhz (1 qpc tick every 100ns) is a common enough QPF value that we can optimize on it.
|
// 10Mhz (1 qpc tick every 100ns) is a common enough QPF value that we can optimize on it.
|
||||||
// https://github.com/microsoft/STL/blob/785143a0c73f030238ef618890fd4d6ae2b3a3a0/stl/inc/chrono#L694-L701
|
// https://github.com/microsoft/STL/blob/785143a0c73f030238ef618890fd4d6ae2b3a3a0/stl/inc/chrono#L694-L701
|
||||||
|
|||||||
@ -1002,7 +1002,7 @@ pub const EnvVar = enum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn getPosix(comptime ev: EnvVar) ?[:0]const u8 {
|
pub fn getPosix(comptime ev: EnvVar) ?[:0]const u8 {
|
||||||
return std.os.getenvZ(@tagName(ev));
|
return std.posix.getenvZ(@tagName(ev));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -146,7 +146,7 @@ pub fn serveMessage(
|
|||||||
header: OutMessage.Header,
|
header: OutMessage.Header,
|
||||||
bufs: []const []const u8,
|
bufs: []const []const u8,
|
||||||
) !void {
|
) !void {
|
||||||
var iovecs: [10]std.os.iovec_const = undefined;
|
var iovecs: [10]std.posix.iovec_const = undefined;
|
||||||
const header_le = bswap(header);
|
const header_le = bswap(header);
|
||||||
iovecs[0] = .{
|
iovecs[0] = .{
|
||||||
.iov_base = @as([*]const u8, @ptrCast(&header_le)),
|
.iov_base = @as([*]const u8, @ptrCast(&header_le)),
|
||||||
|
|||||||
@ -168,7 +168,7 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target {
|
|||||||
if (query.os_tag == null) {
|
if (query.os_tag == null) {
|
||||||
switch (builtin.target.os.tag) {
|
switch (builtin.target.os.tag) {
|
||||||
.linux => {
|
.linux => {
|
||||||
const uts = std.os.uname();
|
const uts = posix.uname();
|
||||||
const release = mem.sliceTo(&uts.release, 0);
|
const release = mem.sliceTo(&uts.release, 0);
|
||||||
// The release field sometimes has a weird format,
|
// The release field sometimes has a weird format,
|
||||||
// `Version.parse` will attempt to find some meaningful interpretation.
|
// `Version.parse` will attempt to find some meaningful interpretation.
|
||||||
@ -181,7 +181,7 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.solaris, .illumos => {
|
.solaris, .illumos => {
|
||||||
const uts = std.os.uname();
|
const uts = posix.uname();
|
||||||
const release = mem.sliceTo(&uts.release, 0);
|
const release = mem.sliceTo(&uts.release, 0);
|
||||||
if (std.SemanticVersion.parse(release)) |ver| {
|
if (std.SemanticVersion.parse(release)) |ver| {
|
||||||
os.version_range.semver.min = ver;
|
os.version_range.semver.min = ver;
|
||||||
@ -206,7 +206,7 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target {
|
|||||||
var value: u32 = undefined;
|
var value: u32 = undefined;
|
||||||
var len: usize = @sizeOf(@TypeOf(value));
|
var len: usize = @sizeOf(@TypeOf(value));
|
||||||
|
|
||||||
std.os.sysctlbynameZ(key, &value, &len, null, 0) catch |err| switch (err) {
|
posix.sysctlbynameZ(key, &value, &len, null, 0) catch |err| switch (err) {
|
||||||
error.NameTooLong => unreachable, // constant, known good value
|
error.NameTooLong => unreachable, // constant, known good value
|
||||||
error.PermissionDenied => unreachable, // only when setting values,
|
error.PermissionDenied => unreachable, // only when setting values,
|
||||||
error.SystemResources => unreachable, // memory already on the stack
|
error.SystemResources => unreachable, // memory already on the stack
|
||||||
@ -257,15 +257,15 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target {
|
|||||||
},
|
},
|
||||||
.openbsd => {
|
.openbsd => {
|
||||||
const mib: [2]c_int = [_]c_int{
|
const mib: [2]c_int = [_]c_int{
|
||||||
std.os.CTL.KERN,
|
posix.CTL.KERN,
|
||||||
std.os.KERN.OSRELEASE,
|
posix.KERN.OSRELEASE,
|
||||||
};
|
};
|
||||||
var buf: [64]u8 = undefined;
|
var buf: [64]u8 = undefined;
|
||||||
// consider that sysctl result includes null-termination
|
// consider that sysctl result includes null-termination
|
||||||
// reserve 1 byte to ensure we never overflow when appending ".0"
|
// reserve 1 byte to ensure we never overflow when appending ".0"
|
||||||
var len: usize = buf.len - 1;
|
var len: usize = buf.len - 1;
|
||||||
|
|
||||||
std.os.sysctl(&mib, &buf, &len, null, 0) catch |err| switch (err) {
|
posix.sysctl(&mib, &buf, &len, null, 0) catch |err| switch (err) {
|
||||||
error.NameTooLong => unreachable, // constant, known good value
|
error.NameTooLong => unreachable, // constant, known good value
|
||||||
error.PermissionDenied => unreachable, // only when setting values,
|
error.PermissionDenied => unreachable, // only when setting values,
|
||||||
error.SystemResources => unreachable, // memory already on the stack
|
error.SystemResources => unreachable, // memory already on the stack
|
||||||
@ -636,8 +636,8 @@ pub fn abiAndDynamicLinkerFromFile(
|
|||||||
|
|
||||||
// So far, no luck. Next we try to see if the information is
|
// So far, no luck. Next we try to see if the information is
|
||||||
// present in the symlink data for the dynamic linker path.
|
// present in the symlink data for the dynamic linker path.
|
||||||
var link_buf: [std.os.PATH_MAX]u8 = undefined;
|
var link_buf: [posix.PATH_MAX]u8 = undefined;
|
||||||
const link_name = std.os.readlink(dl_path, &link_buf) catch |err| switch (err) {
|
const link_name = posix.readlink(dl_path, &link_buf) catch |err| switch (err) {
|
||||||
error.NameTooLong => unreachable,
|
error.NameTooLong => unreachable,
|
||||||
error.InvalidUtf8 => unreachable, // WASI only
|
error.InvalidUtf8 => unreachable, // WASI only
|
||||||
error.InvalidWtf8 => unreachable, // Windows only
|
error.InvalidWtf8 => unreachable, // Windows only
|
||||||
@ -670,7 +670,7 @@ pub fn abiAndDynamicLinkerFromFile(
|
|||||||
|
|
||||||
// Nothing worked so far. Finally we fall back to hard-coded search paths.
|
// Nothing worked so far. Finally we fall back to hard-coded search paths.
|
||||||
// Some distros such as Debian keep their libc.so.6 in `/lib/$triple/`.
|
// Some distros such as Debian keep their libc.so.6 in `/lib/$triple/`.
|
||||||
var path_buf: [std.os.PATH_MAX]u8 = undefined;
|
var path_buf: [posix.PATH_MAX]u8 = undefined;
|
||||||
var index: usize = 0;
|
var index: usize = 0;
|
||||||
const prefix = "/lib/";
|
const prefix = "/lib/";
|
||||||
const cpu_arch = @tagName(result.cpu.arch);
|
const cpu_arch = @tagName(result.cpu.arch);
|
||||||
@ -1138,6 +1138,7 @@ const fs = std.fs;
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const Target = std.Target;
|
const Target = std.Target;
|
||||||
const native_endian = builtin.cpu.arch.endian();
|
const native_endian = builtin.cpu.arch.endian();
|
||||||
|
const posix = std.posix;
|
||||||
|
|
||||||
test {
|
test {
|
||||||
_ = NativePaths;
|
_ = NativePaths;
|
||||||
|
|||||||
@ -137,21 +137,21 @@ pub fn detect(arena: Allocator, native_target: std.Target) !NativePaths {
|
|||||||
// variables to search for headers and libraries.
|
// variables to search for headers and libraries.
|
||||||
// We use os.getenv here since this part won't be executed on
|
// We use os.getenv here since this part won't be executed on
|
||||||
// windows, to get rid of unnecessary error handling.
|
// windows, to get rid of unnecessary error handling.
|
||||||
if (std.os.getenv("C_INCLUDE_PATH")) |c_include_path| {
|
if (std.posix.getenv("C_INCLUDE_PATH")) |c_include_path| {
|
||||||
var it = mem.tokenizeScalar(u8, c_include_path, ':');
|
var it = mem.tokenizeScalar(u8, c_include_path, ':');
|
||||||
while (it.next()) |dir| {
|
while (it.next()) |dir| {
|
||||||
try self.addIncludeDir(dir);
|
try self.addIncludeDir(dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std.os.getenv("CPLUS_INCLUDE_PATH")) |cplus_include_path| {
|
if (std.posix.getenv("CPLUS_INCLUDE_PATH")) |cplus_include_path| {
|
||||||
var it = mem.tokenizeScalar(u8, cplus_include_path, ':');
|
var it = mem.tokenizeScalar(u8, cplus_include_path, ':');
|
||||||
while (it.next()) |dir| {
|
while (it.next()) |dir| {
|
||||||
try self.addIncludeDir(dir);
|
try self.addIncludeDir(dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std.os.getenv("LIBRARY_PATH")) |library_path| {
|
if (std.posix.getenv("LIBRARY_PATH")) |library_path| {
|
||||||
var it = mem.tokenizeScalar(u8, library_path, ':');
|
var it = mem.tokenizeScalar(u8, library_path, ':');
|
||||||
while (it.next()) |dir| {
|
while (it.next()) |dir| {
|
||||||
try self.addLibDir(dir);
|
try self.addLibDir(dir);
|
||||||
|
|||||||
@ -3,7 +3,6 @@ const builtin = @import("builtin");
|
|||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const os = std.os;
|
|
||||||
|
|
||||||
const Target = std.Target;
|
const Target = std.Target;
|
||||||
|
|
||||||
@ -397,7 +396,7 @@ test "detect" {
|
|||||||
pub fn detectNativeCpuAndFeatures() ?Target.Cpu {
|
pub fn detectNativeCpuAndFeatures() ?Target.Cpu {
|
||||||
var cpu_family: std.c.CPUFAMILY = undefined;
|
var cpu_family: std.c.CPUFAMILY = undefined;
|
||||||
var len: usize = @sizeOf(std.c.CPUFAMILY);
|
var len: usize = @sizeOf(std.c.CPUFAMILY);
|
||||||
os.sysctlbynameZ("hw.cpufamily", &cpu_family, &len, null, 0) catch |err| switch (err) {
|
std.posix.sysctlbynameZ("hw.cpufamily", &cpu_family, &len, null, 0) catch |err| switch (err) {
|
||||||
error.NameTooLong => unreachable, // constant, known good value
|
error.NameTooLong => unreachable, // constant, known good value
|
||||||
error.PermissionDenied => unreachable, // only when setting values,
|
error.PermissionDenied => unreachable, // only when setting values,
|
||||||
error.SystemResources => unreachable, // memory already on the stack
|
error.SystemResources => unreachable, // memory already on the stack
|
||||||
|
|||||||
@ -1137,7 +1137,7 @@ fn addModuleTableToCacheHash(
|
|||||||
root_mod: *Package.Module,
|
root_mod: *Package.Module,
|
||||||
main_mod: *Package.Module,
|
main_mod: *Package.Module,
|
||||||
hash_type: union(enum) { path_bytes, files: *Cache.Manifest },
|
hash_type: union(enum) { path_bytes, files: *Cache.Manifest },
|
||||||
) (error{OutOfMemory} || std.os.GetCwdError)!void {
|
) (error{OutOfMemory} || std.process.GetCwdError)!void {
|
||||||
var seen_table: std.AutoArrayHashMapUnmanaged(*Package.Module, void) = .{};
|
var seen_table: std.AutoArrayHashMapUnmanaged(*Package.Module, void) = .{};
|
||||||
defer seen_table.deinit(gpa);
|
defer seen_table.deinit(gpa);
|
||||||
|
|
||||||
@ -2741,7 +2741,7 @@ const Header = extern struct {
|
|||||||
/// saved, such as the target and most CLI flags. A cache hit will only occur
|
/// saved, such as the target and most CLI flags. A cache hit will only occur
|
||||||
/// when subsequent compiler invocations use the same set of flags.
|
/// when subsequent compiler invocations use the same set of flags.
|
||||||
pub fn saveState(comp: *Compilation) !void {
|
pub fn saveState(comp: *Compilation) !void {
|
||||||
var bufs_list: [19]std.os.iovec_const = undefined;
|
var bufs_list: [19]std.posix.iovec_const = undefined;
|
||||||
var bufs_len: usize = 0;
|
var bufs_len: usize = 0;
|
||||||
|
|
||||||
const lf = comp.bin_file orelse return;
|
const lf = comp.bin_file orelse return;
|
||||||
@ -2808,7 +2808,7 @@ pub fn saveState(comp: *Compilation) !void {
|
|||||||
try af.finish();
|
try af.finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addBuf(bufs_list: []std.os.iovec_const, bufs_len: *usize, buf: []const u8) void {
|
fn addBuf(bufs_list: []std.posix.iovec_const, bufs_len: *usize, buf: []const u8) void {
|
||||||
const i = bufs_len.*;
|
const i = bufs_len.*;
|
||||||
bufs_len.* = i + 1;
|
bufs_len.* = i + 1;
|
||||||
bufs_list[i] = .{
|
bufs_list[i] = .{
|
||||||
@ -3791,7 +3791,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
|
|||||||
break :p padding_buffer[0..n];
|
break :p padding_buffer[0..n];
|
||||||
};
|
};
|
||||||
|
|
||||||
var header_and_trailer: [2]std.os.iovec_const = .{
|
var header_and_trailer: [2]std.posix.iovec_const = .{
|
||||||
.{ .iov_base = header_bytes.ptr, .iov_len = header_bytes.len },
|
.{ .iov_base = header_bytes.ptr, .iov_len = header_bytes.len },
|
||||||
.{ .iov_base = padding.ptr, .iov_len = padding.len },
|
.{ .iov_base = padding.ptr, .iov_len = padding.len },
|
||||||
};
|
};
|
||||||
|
|||||||
224
src/DarwinPosixSpawn.zig
Normal file
224
src/DarwinPosixSpawn.zig
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
const errno = std.posix.errno;
|
||||||
|
const unexpectedErrno = std.posix.unexpectedErrno;
|
||||||
|
|
||||||
|
pub const Error = error{
|
||||||
|
SystemResources,
|
||||||
|
InvalidFileDescriptor,
|
||||||
|
NameTooLong,
|
||||||
|
TooBig,
|
||||||
|
PermissionDenied,
|
||||||
|
InputOutput,
|
||||||
|
FileSystem,
|
||||||
|
FileNotFound,
|
||||||
|
InvalidExe,
|
||||||
|
NotDir,
|
||||||
|
FileBusy,
|
||||||
|
/// Returned when the child fails to execute either in the pre-exec() initialization step, or
|
||||||
|
/// when exec(3) is invoked.
|
||||||
|
ChildExecFailed,
|
||||||
|
} || std.posix.UnexpectedError;
|
||||||
|
|
||||||
|
pub const Attr = struct {
|
||||||
|
attr: std.c.posix_spawnattr_t,
|
||||||
|
|
||||||
|
pub fn init() Error!Attr {
|
||||||
|
var attr: std.c.posix_spawnattr_t = undefined;
|
||||||
|
switch (errno(std.c.posix_spawnattr_init(&attr))) {
|
||||||
|
.SUCCESS => return Attr{ .attr = attr },
|
||||||
|
.NOMEM => return error.SystemResources,
|
||||||
|
.INVAL => unreachable,
|
||||||
|
else => |err| return unexpectedErrno(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Attr) void {
|
||||||
|
defer self.* = undefined;
|
||||||
|
switch (errno(std.c.posix_spawnattr_destroy(&self.attr))) {
|
||||||
|
.SUCCESS => return,
|
||||||
|
.INVAL => unreachable, // Invalid parameters.
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self: Attr) Error!u16 {
|
||||||
|
var flags: c_short = undefined;
|
||||||
|
switch (errno(std.c.posix_spawnattr_getflags(&self.attr, &flags))) {
|
||||||
|
.SUCCESS => return @as(u16, @bitCast(flags)),
|
||||||
|
.INVAL => unreachable,
|
||||||
|
else => |err| return unexpectedErrno(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(self: *Attr, flags: u16) Error!void {
|
||||||
|
switch (errno(std.c.posix_spawnattr_setflags(&self.attr, @as(c_short, @bitCast(flags))))) {
|
||||||
|
.SUCCESS => return,
|
||||||
|
.INVAL => unreachable,
|
||||||
|
else => |err| return unexpectedErrno(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Actions = struct {
|
||||||
|
actions: std.c.posix_spawn_file_actions_t,
|
||||||
|
|
||||||
|
pub fn init() Error!Actions {
|
||||||
|
var actions: std.c.posix_spawn_file_actions_t = undefined;
|
||||||
|
switch (errno(std.c.posix_spawn_file_actions_init(&actions))) {
|
||||||
|
.SUCCESS => return Actions{ .actions = actions },
|
||||||
|
.NOMEM => return error.SystemResources,
|
||||||
|
.INVAL => unreachable,
|
||||||
|
else => |err| return unexpectedErrno(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Actions) void {
|
||||||
|
defer self.* = undefined;
|
||||||
|
switch (errno(std.c.posix_spawn_file_actions_destroy(&self.actions))) {
|
||||||
|
.SUCCESS => return,
|
||||||
|
.INVAL => unreachable, // Invalid parameters.
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open(self: *Actions, fd: std.c.fd_t, path: []const u8, flags: u32, mode: std.c.mode_t) Error!void {
|
||||||
|
const posix_path = try std.os.toPosixPath(path);
|
||||||
|
return self.openZ(fd, &posix_path, flags, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn openZ(self: *Actions, fd: std.c.fd_t, path: [*:0]const u8, flags: u32, mode: std.c.mode_t) Error!void {
|
||||||
|
switch (errno(std.c.posix_spawn_file_actions_addopen(&self.actions, fd, path, @as(c_int, @bitCast(flags)), mode))) {
|
||||||
|
.SUCCESS => return,
|
||||||
|
.BADF => return error.InvalidFileDescriptor,
|
||||||
|
.NOMEM => return error.SystemResources,
|
||||||
|
.NAMETOOLONG => return error.NameTooLong,
|
||||||
|
.INVAL => unreachable, // the value of file actions is invalid
|
||||||
|
else => |err| return unexpectedErrno(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close(self: *Actions, fd: std.c.fd_t) Error!void {
|
||||||
|
switch (errno(std.c.posix_spawn_file_actions_addclose(&self.actions, fd))) {
|
||||||
|
.SUCCESS => return,
|
||||||
|
.BADF => return error.InvalidFileDescriptor,
|
||||||
|
.NOMEM => return error.SystemResources,
|
||||||
|
.INVAL => unreachable, // the value of file actions is invalid
|
||||||
|
.NAMETOOLONG => unreachable,
|
||||||
|
else => |err| return unexpectedErrno(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dup2(self: *Actions, fd: std.c.fd_t, newfd: std.c.fd_t) Error!void {
|
||||||
|
switch (errno(std.c.posix_spawn_file_actions_adddup2(&self.actions, fd, newfd))) {
|
||||||
|
.SUCCESS => return,
|
||||||
|
.BADF => return error.InvalidFileDescriptor,
|
||||||
|
.NOMEM => return error.SystemResources,
|
||||||
|
.INVAL => unreachable, // the value of file actions is invalid
|
||||||
|
.NAMETOOLONG => unreachable,
|
||||||
|
else => |err| return unexpectedErrno(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inherit(self: *Actions, fd: std.c.fd_t) Error!void {
|
||||||
|
switch (errno(std.c.posix_spawn_file_actions_addinherit_np(&self.actions, fd))) {
|
||||||
|
.SUCCESS => return,
|
||||||
|
.BADF => return error.InvalidFileDescriptor,
|
||||||
|
.NOMEM => return error.SystemResources,
|
||||||
|
.INVAL => unreachable, // the value of file actions is invalid
|
||||||
|
.NAMETOOLONG => unreachable,
|
||||||
|
else => |err| return unexpectedErrno(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn chdir(self: *Actions, path: []const u8) Error!void {
|
||||||
|
const posix_path = try std.os.toPosixPath(path);
|
||||||
|
return self.chdirZ(&posix_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn chdirZ(self: *Actions, path: [*:0]const u8) Error!void {
|
||||||
|
switch (errno(std.c.posix_spawn_file_actions_addchdir_np(&self.actions, path))) {
|
||||||
|
.SUCCESS => return,
|
||||||
|
.NOMEM => return error.SystemResources,
|
||||||
|
.NAMETOOLONG => return error.NameTooLong,
|
||||||
|
.BADF => unreachable,
|
||||||
|
.INVAL => unreachable, // the value of file actions is invalid
|
||||||
|
else => |err| return unexpectedErrno(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fchdir(self: *Actions, fd: std.c.fd_t) Error!void {
|
||||||
|
switch (errno(std.c.posix_spawn_file_actions_addfchdir_np(&self.actions, fd))) {
|
||||||
|
.SUCCESS => return,
|
||||||
|
.BADF => return error.InvalidFileDescriptor,
|
||||||
|
.NOMEM => return error.SystemResources,
|
||||||
|
.INVAL => unreachable, // the value of file actions is invalid
|
||||||
|
.NAMETOOLONG => unreachable,
|
||||||
|
else => |err| return unexpectedErrno(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn spawn(
|
||||||
|
path: []const u8,
|
||||||
|
actions: ?Actions,
|
||||||
|
attr: ?Attr,
|
||||||
|
argv: [*:null]?[*:0]const u8,
|
||||||
|
envp: [*:null]?[*:0]const u8,
|
||||||
|
) Error!std.c.pid_t {
|
||||||
|
const posix_path = try std.os.toPosixPath(path);
|
||||||
|
return spawnZ(&posix_path, actions, attr, argv, envp);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawnZ(
|
||||||
|
path: [*:0]const u8,
|
||||||
|
actions: ?Actions,
|
||||||
|
attr: ?Attr,
|
||||||
|
argv: [*:null]?[*:0]const u8,
|
||||||
|
envp: [*:null]?[*:0]const u8,
|
||||||
|
) Error!std.c.pid_t {
|
||||||
|
var pid: std.c.pid_t = undefined;
|
||||||
|
switch (errno(std.c.posix_spawn(
|
||||||
|
&pid,
|
||||||
|
path,
|
||||||
|
if (actions) |a| &a.actions else null,
|
||||||
|
if (attr) |a| &a.attr else null,
|
||||||
|
argv,
|
||||||
|
envp,
|
||||||
|
))) {
|
||||||
|
.SUCCESS => return pid,
|
||||||
|
.@"2BIG" => return error.TooBig,
|
||||||
|
.NOMEM => return error.SystemResources,
|
||||||
|
.BADF => return error.InvalidFileDescriptor,
|
||||||
|
.ACCES => return error.PermissionDenied,
|
||||||
|
.IO => return error.InputOutput,
|
||||||
|
.LOOP => return error.FileSystem,
|
||||||
|
.NAMETOOLONG => return error.NameTooLong,
|
||||||
|
.NOENT => return error.FileNotFound,
|
||||||
|
.NOEXEC => return error.InvalidExe,
|
||||||
|
.NOTDIR => return error.NotDir,
|
||||||
|
.TXTBSY => return error.FileBusy,
|
||||||
|
.BADARCH => return error.InvalidExe,
|
||||||
|
.BADEXEC => return error.InvalidExe,
|
||||||
|
.FAULT => unreachable,
|
||||||
|
.INVAL => unreachable,
|
||||||
|
else => |err| return unexpectedErrno(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn waitpid(pid: std.c.pid_t, flags: u32) Error!std.os.WaitPidResult {
|
||||||
|
var status: c_int = undefined;
|
||||||
|
while (true) {
|
||||||
|
const rc = waitpid(pid, &status, @as(c_int, @intCast(flags)));
|
||||||
|
switch (errno(rc)) {
|
||||||
|
.SUCCESS => return std.os.WaitPidResult{
|
||||||
|
.pid = @as(std.c.pid_t, @intCast(rc)),
|
||||||
|
.status = @as(u32, @bitCast(status)),
|
||||||
|
},
|
||||||
|
.INTR => continue,
|
||||||
|
.CHILD => return error.ChildExecFailed,
|
||||||
|
.INVAL => unreachable, // Invalid flags.
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
@ -2396,7 +2396,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
|
|||||||
.stat_inode = stat.inode,
|
.stat_inode = stat.inode,
|
||||||
.stat_mtime = stat.mtime,
|
.stat_mtime = stat.mtime,
|
||||||
};
|
};
|
||||||
var iovecs = [_]std.os.iovec_const{
|
var iovecs = [_]std.posix.iovec_const{
|
||||||
.{
|
.{
|
||||||
.iov_base = @as([*]const u8, @ptrCast(&header)),
|
.iov_base = @as([*]const u8, @ptrCast(&header)),
|
||||||
.iov_len = @sizeOf(Zir.Header),
|
.iov_len = @sizeOf(Zir.Header),
|
||||||
@ -2484,7 +2484,7 @@ fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.File)
|
|||||||
else
|
else
|
||||||
@as([*]u8, @ptrCast(zir.instructions.items(.data).ptr));
|
@as([*]u8, @ptrCast(zir.instructions.items(.data).ptr));
|
||||||
|
|
||||||
var iovecs = [_]std.os.iovec{
|
var iovecs = [_]std.posix.iovec{
|
||||||
.{
|
.{
|
||||||
.iov_base = @as([*]u8, @ptrCast(zir.instructions.items(.tag).ptr)),
|
.iov_base = @as([*]u8, @ptrCast(zir.instructions.items(.tag).ptr)),
|
||||||
.iov_len = header.instructions_len,
|
.iov_len = header.instructions_len,
|
||||||
|
|||||||
@ -482,7 +482,7 @@ fn runResource(
|
|||||||
// Compute the package hash based on the remaining files in the temporary
|
// Compute the package hash based on the remaining files in the temporary
|
||||||
// directory.
|
// directory.
|
||||||
|
|
||||||
if (builtin.os.tag == .linux and f.job_queue.work_around_btrfs_bug) {
|
if (native_os == .linux and f.job_queue.work_around_btrfs_bug) {
|
||||||
// https://github.com/ziglang/zig/issues/17095
|
// https://github.com/ziglang/zig/issues/17095
|
||||||
tmp_directory.handle.close();
|
tmp_directory.handle.close();
|
||||||
tmp_directory.handle = cache_root.handle.makeOpenPath(tmp_dir_sub_path, .{
|
tmp_directory.handle = cache_root.handle.makeOpenPath(tmp_dir_sub_path, .{
|
||||||
@ -1153,11 +1153,7 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!void {
|
|||||||
std.tar.pipeToFileSystem(out_dir, reader, .{
|
std.tar.pipeToFileSystem(out_dir, reader, .{
|
||||||
.diagnostics = &diagnostics,
|
.diagnostics = &diagnostics,
|
||||||
.strip_components = 1,
|
.strip_components = 1,
|
||||||
// TODO: we would like to set this to executable_bit_only, but two
|
// https://github.com/ziglang/zig/issues/17463
|
||||||
// things need to happen before that:
|
|
||||||
// 1. the tar implementation needs to support it
|
|
||||||
// 2. the hashing algorithm here needs to support detecting the is_executable
|
|
||||||
// bit on Windows from the ACLs (see the isExecutable function).
|
|
||||||
.mode_mode = .ignore,
|
.mode_mode = .ignore,
|
||||||
.exclude_empty_directories = true,
|
.exclude_empty_directories = true,
|
||||||
}) catch |err| return f.fail(f.location_tok, try eb.printString(
|
}) catch |err| return f.fail(f.location_tok, try eb.printString(
|
||||||
@ -1542,6 +1538,8 @@ fn hashFileFallible(dir: fs.Dir, hashed_file: *HashedFile) HashedFile.Error!void
|
|||||||
.file => {
|
.file => {
|
||||||
var file = try dir.openFile(hashed_file.fs_path, .{});
|
var file = try dir.openFile(hashed_file.fs_path, .{});
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
// When implementing https://github.com/ziglang/zig/issues/17463
|
||||||
|
// this will change to hard-coded `false`.
|
||||||
hasher.update(&.{ 0, @intFromBool(try isExecutable(file)) });
|
hasher.update(&.{ 0, @intFromBool(try isExecutable(file)) });
|
||||||
while (true) {
|
while (true) {
|
||||||
const bytes_read = try file.read(&buf);
|
const bytes_read = try file.read(&buf);
|
||||||
@ -1568,15 +1566,17 @@ fn deleteFileFallible(dir: fs.Dir, deleted_file: *DeletedFile) DeletedFile.Error
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn isExecutable(file: fs.File) !bool {
|
fn isExecutable(file: fs.File) !bool {
|
||||||
if (builtin.os.tag == .windows) {
|
// When implementing https://github.com/ziglang/zig/issues/17463
|
||||||
// TODO check the ACL on Windows.
|
// this function will not check the mode but instead check if the file is an ELF
|
||||||
|
// file or has a shebang line.
|
||||||
|
if (native_os == .windows) {
|
||||||
// Until this is implemented, this could be a false negative on
|
// Until this is implemented, this could be a false negative on
|
||||||
// Windows, which is why we do not yet set executable_bit_only above
|
// Windows, which is why we do not yet set executable_bit_only above
|
||||||
// when unpacking the tarball.
|
// when unpacking the tarball.
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
const stat = try file.stat();
|
const stat = try file.stat();
|
||||||
return (stat.mode & std.os.S.IXUSR) != 0;
|
return (stat.mode & std.posix.S.IXUSR) != 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1694,6 +1694,7 @@ const git = @import("Fetch/git.zig");
|
|||||||
const Package = @import("../Package.zig");
|
const Package = @import("../Package.zig");
|
||||||
const Manifest = Package.Manifest;
|
const Manifest = Package.Manifest;
|
||||||
const ErrorBundle = std.zig.ErrorBundle;
|
const ErrorBundle = std.zig.ErrorBundle;
|
||||||
|
const native_os = builtin.os.tag;
|
||||||
|
|
||||||
test {
|
test {
|
||||||
_ = Filter;
|
_ = Filter;
|
||||||
|
|||||||
@ -2,9 +2,10 @@ const std = @import("std");
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const build_options = @import("build_options");
|
const build_options = @import("build_options");
|
||||||
const debug = std.debug;
|
const debug = std.debug;
|
||||||
const os = std.os;
|
|
||||||
const io = std.io;
|
const io = std.io;
|
||||||
const print_zir = @import("print_zir.zig");
|
const print_zir = @import("print_zir.zig");
|
||||||
|
const windows = std.os.windows;
|
||||||
|
const posix = std.posix;
|
||||||
const native_os = builtin.os.tag;
|
const native_os = builtin.os.tag;
|
||||||
|
|
||||||
const Module = @import("Module.zig");
|
const Module = @import("Module.zig");
|
||||||
@ -156,14 +157,14 @@ pub fn attachSegfaultHandler() void {
|
|||||||
if (!debug.have_segfault_handling_support) {
|
if (!debug.have_segfault_handling_support) {
|
||||||
@compileError("segfault handler not supported for this target");
|
@compileError("segfault handler not supported for this target");
|
||||||
}
|
}
|
||||||
if (builtin.os.tag == .windows) {
|
if (native_os == .windows) {
|
||||||
_ = os.windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
|
_ = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var act = os.Sigaction{
|
var act: posix.Sigaction = .{
|
||||||
.handler = .{ .sigaction = handleSegfaultPosix },
|
.handler = .{ .sigaction = handleSegfaultPosix },
|
||||||
.mask = os.empty_sigset,
|
.mask = posix.empty_sigset,
|
||||||
.flags = (os.SA.SIGINFO | os.SA.RESTART | os.SA.RESETHAND),
|
.flags = (posix.SA.SIGINFO | posix.SA.RESTART | posix.SA.RESETHAND),
|
||||||
};
|
};
|
||||||
|
|
||||||
debug.updateSegfaultHandler(&act) catch {
|
debug.updateSegfaultHandler(&act) catch {
|
||||||
@ -171,11 +172,11 @@ pub fn attachSegfaultHandler() void {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handleSegfaultPosix(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) noreturn {
|
fn handleSegfaultPosix(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) noreturn {
|
||||||
// TODO: use alarm() here to prevent infinite loops
|
// TODO: use alarm() here to prevent infinite loops
|
||||||
PanicSwitch.preDispatch();
|
PanicSwitch.preDispatch();
|
||||||
|
|
||||||
const addr = switch (builtin.os.tag) {
|
const addr = switch (native_os) {
|
||||||
.linux => @intFromPtr(info.fields.sigfault.addr),
|
.linux => @intFromPtr(info.fields.sigfault.addr),
|
||||||
.freebsd, .macos => @intFromPtr(info.addr),
|
.freebsd, .macos => @intFromPtr(info.addr),
|
||||||
.netbsd => @intFromPtr(info.info.reason.fault.addr),
|
.netbsd => @intFromPtr(info.info.reason.fault.addr),
|
||||||
@ -186,9 +187,9 @@ fn handleSegfaultPosix(sig: i32, info: *const os.siginfo_t, ctx_ptr: ?*const any
|
|||||||
|
|
||||||
var err_buffer: [128]u8 = undefined;
|
var err_buffer: [128]u8 = undefined;
|
||||||
const error_msg = switch (sig) {
|
const error_msg = switch (sig) {
|
||||||
os.SIG.SEGV => std.fmt.bufPrint(&err_buffer, "Segmentation fault at address 0x{x}", .{addr}) catch "Segmentation fault",
|
posix.SIG.SEGV => std.fmt.bufPrint(&err_buffer, "Segmentation fault at address 0x{x}", .{addr}) catch "Segmentation fault",
|
||||||
os.SIG.ILL => std.fmt.bufPrint(&err_buffer, "Illegal instruction at address 0x{x}", .{addr}) catch "Illegal instruction",
|
posix.SIG.ILL => std.fmt.bufPrint(&err_buffer, "Illegal instruction at address 0x{x}", .{addr}) catch "Illegal instruction",
|
||||||
os.SIG.BUS => std.fmt.bufPrint(&err_buffer, "Bus error at address 0x{x}", .{addr}) catch "Bus error",
|
posix.SIG.BUS => std.fmt.bufPrint(&err_buffer, "Bus error at address 0x{x}", .{addr}) catch "Bus error",
|
||||||
else => std.fmt.bufPrint(&err_buffer, "Unknown error (signal {}) at address 0x{x}", .{ sig, addr }) catch "Unknown error",
|
else => std.fmt.bufPrint(&err_buffer, "Unknown error (signal {}) at address 0x{x}", .{ sig, addr }) catch "Unknown error",
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -210,20 +211,20 @@ const WindowsSegfaultMessage = union(enum) {
|
|||||||
illegal_instruction: void,
|
illegal_instruction: void,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn handleSegfaultWindows(info: *os.windows.EXCEPTION_POINTERS) callconv(os.windows.WINAPI) c_long {
|
fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) callconv(windows.WINAPI) c_long {
|
||||||
switch (info.ExceptionRecord.ExceptionCode) {
|
switch (info.ExceptionRecord.ExceptionCode) {
|
||||||
os.windows.EXCEPTION_DATATYPE_MISALIGNMENT => handleSegfaultWindowsExtra(info, .{ .literal = "Unaligned Memory Access" }),
|
windows.EXCEPTION_DATATYPE_MISALIGNMENT => handleSegfaultWindowsExtra(info, .{ .literal = "Unaligned Memory Access" }),
|
||||||
os.windows.EXCEPTION_ACCESS_VIOLATION => handleSegfaultWindowsExtra(info, .segfault),
|
windows.EXCEPTION_ACCESS_VIOLATION => handleSegfaultWindowsExtra(info, .segfault),
|
||||||
os.windows.EXCEPTION_ILLEGAL_INSTRUCTION => handleSegfaultWindowsExtra(info, .illegal_instruction),
|
windows.EXCEPTION_ILLEGAL_INSTRUCTION => handleSegfaultWindowsExtra(info, .illegal_instruction),
|
||||||
os.windows.EXCEPTION_STACK_OVERFLOW => handleSegfaultWindowsExtra(info, .{ .literal = "Stack Overflow" }),
|
windows.EXCEPTION_STACK_OVERFLOW => handleSegfaultWindowsExtra(info, .{ .literal = "Stack Overflow" }),
|
||||||
else => return os.windows.EXCEPTION_CONTINUE_SEARCH,
|
else => return windows.EXCEPTION_CONTINUE_SEARCH,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handleSegfaultWindowsExtra(info: *os.windows.EXCEPTION_POINTERS, comptime msg: WindowsSegfaultMessage) noreturn {
|
fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, comptime msg: WindowsSegfaultMessage) noreturn {
|
||||||
PanicSwitch.preDispatch();
|
PanicSwitch.preDispatch();
|
||||||
|
|
||||||
const stack_ctx = if (@hasDecl(os.windows, "CONTEXT"))
|
const stack_ctx = if (@hasDecl(windows, "CONTEXT"))
|
||||||
StackContext{ .exception = info.ContextRecord }
|
StackContext{ .exception = info.ContextRecord }
|
||||||
else ctx: {
|
else ctx: {
|
||||||
const addr = @intFromPtr(info.ExceptionRecord.ExceptionAddress);
|
const addr = @intFromPtr(info.ExceptionRecord.ExceptionAddress);
|
||||||
@ -488,7 +489,7 @@ const PanicSwitch = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
noinline fn abort() noreturn {
|
noinline fn abort() noreturn {
|
||||||
os.abort();
|
std.process.abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn goTo(comptime func: anytype, args: anytype) noreturn {
|
inline fn goTo(comptime func: anytype, args: anytype) noreturn {
|
||||||
|
|||||||
@ -254,7 +254,7 @@ pub const File = struct {
|
|||||||
try emit.directory.handle.copyFile(emit.sub_path, emit.directory.handle, tmp_sub_path, .{});
|
try emit.directory.handle.copyFile(emit.sub_path, emit.directory.handle, tmp_sub_path, .{});
|
||||||
try emit.directory.handle.rename(tmp_sub_path, emit.sub_path);
|
try emit.directory.handle.rename(tmp_sub_path, emit.sub_path);
|
||||||
switch (builtin.os.tag) {
|
switch (builtin.os.tag) {
|
||||||
.linux => std.os.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0) catch |err| {
|
.linux => std.posix.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0) catch |err| {
|
||||||
log.warn("ptrace failure: {s}", .{@errorName(err)});
|
log.warn("ptrace failure: {s}", .{@errorName(err)});
|
||||||
},
|
},
|
||||||
.macos => base.cast(MachO).?.ptraceAttach(pid) catch |err| {
|
.macos => base.cast(MachO).?.ptraceAttach(pid) catch |err| {
|
||||||
@ -305,7 +305,7 @@ pub const File = struct {
|
|||||||
|
|
||||||
if (base.child_pid) |pid| {
|
if (base.child_pid) |pid| {
|
||||||
switch (builtin.os.tag) {
|
switch (builtin.os.tag) {
|
||||||
.linux => std.os.ptrace(std.os.linux.PTRACE.DETACH, pid, 0, 0) catch |err| {
|
.linux => std.posix.ptrace(std.os.linux.PTRACE.DETACH, pid, 0, 0) catch |err| {
|
||||||
log.warn("ptrace failure: {s}", .{@errorName(err)});
|
log.warn("ptrace failure: {s}", .{@errorName(err)});
|
||||||
},
|
},
|
||||||
else => return error.HotSwapUnavailableOnHostOperatingSystem,
|
else => return error.HotSwapUnavailableOnHostOperatingSystem,
|
||||||
|
|||||||
@ -518,7 +518,7 @@ const Flush = struct {
|
|||||||
asm_buf: std.ArrayListUnmanaged(u8) = .{},
|
asm_buf: std.ArrayListUnmanaged(u8) = .{},
|
||||||
|
|
||||||
/// We collect a list of buffers to write, and write them all at once with pwritev 😎
|
/// We collect a list of buffers to write, and write them all at once with pwritev 😎
|
||||||
all_buffers: std.ArrayListUnmanaged(std.os.iovec_const) = .{},
|
all_buffers: std.ArrayListUnmanaged(std.posix.iovec_const) = .{},
|
||||||
/// Keeps track of the total bytes of `all_buffers`.
|
/// Keeps track of the total bytes of `all_buffers`.
|
||||||
file_size: u64 = 0,
|
file_size: u64 = 0,
|
||||||
|
|
||||||
@ -752,7 +752,7 @@ pub fn flushEmitH(module: *Module) !void {
|
|||||||
|
|
||||||
// We collect a list of buffers to write, and write them all at once with pwritev 😎
|
// We collect a list of buffers to write, and write them all at once with pwritev 😎
|
||||||
const num_buffers = emit_h.decl_table.count() + 1;
|
const num_buffers = emit_h.decl_table.count() + 1;
|
||||||
var all_buffers = try std.ArrayList(std.os.iovec_const).initCapacity(module.gpa, num_buffers);
|
var all_buffers = try std.ArrayList(std.posix.iovec_const).initCapacity(module.gpa, num_buffers);
|
||||||
defer all_buffers.deinit();
|
defer all_buffers.deinit();
|
||||||
|
|
||||||
var file_size: u64 = zig_h.len;
|
var file_size: u64 = zig_h.len;
|
||||||
|
|||||||
@ -2118,7 +2118,7 @@ fn pwriteDbgLineNops(
|
|||||||
|
|
||||||
const page_of_nops = [1]u8{DW.LNS.negate_stmt} ** 4096;
|
const page_of_nops = [1]u8{DW.LNS.negate_stmt} ** 4096;
|
||||||
const three_byte_nop = [3]u8{ DW.LNS.advance_pc, 0b1000_0000, 0 };
|
const three_byte_nop = [3]u8{ DW.LNS.advance_pc, 0b1000_0000, 0 };
|
||||||
var vecs: [512]std.os.iovec_const = undefined;
|
var vecs: [512]std.posix.iovec_const = undefined;
|
||||||
var vec_index: usize = 0;
|
var vec_index: usize = 0;
|
||||||
{
|
{
|
||||||
var padding_left = prev_padding_size;
|
var padding_left = prev_padding_size;
|
||||||
@ -2235,7 +2235,7 @@ fn pwriteDbgInfoNops(
|
|||||||
defer tracy.end();
|
defer tracy.end();
|
||||||
|
|
||||||
const page_of_nops = [1]u8{@intFromEnum(AbbrevCode.padding)} ** 4096;
|
const page_of_nops = [1]u8{@intFromEnum(AbbrevCode.padding)} ** 4096;
|
||||||
var vecs: [32]std.os.iovec_const = undefined;
|
var vecs: [32]std.posix.iovec_const = undefined;
|
||||||
var vec_index: usize = 0;
|
var vec_index: usize = 0;
|
||||||
{
|
{
|
||||||
var padding_left = prev_padding_size;
|
var padding_left = prev_padding_size;
|
||||||
@ -2807,10 +2807,10 @@ fn genIncludeDirsAndFileNames(self: *Dwarf, arena: Allocator) !struct {
|
|||||||
const full_path = try dif.mod.root.joinString(arena, dif.sub_file_path);
|
const full_path = try dif.mod.root.joinString(arena, dif.sub_file_path);
|
||||||
const dir_path = std.fs.path.dirname(full_path) orelse ".";
|
const dir_path = std.fs.path.dirname(full_path) orelse ".";
|
||||||
const sub_file_path = std.fs.path.basename(full_path);
|
const sub_file_path = std.fs.path.basename(full_path);
|
||||||
// TODO re-investigate if realpath is needed here
|
// https://github.com/ziglang/zig/issues/19353
|
||||||
var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
const resolved = if (!std.fs.path.isAbsolute(dir_path))
|
const resolved = if (!std.fs.path.isAbsolute(dir_path))
|
||||||
std.os.realpath(dir_path, &buffer) catch dir_path
|
std.posix.realpath(dir_path, &buffer) catch dir_path
|
||||||
else
|
else
|
||||||
dir_path;
|
dir_path;
|
||||||
|
|
||||||
|
|||||||
@ -422,7 +422,7 @@ pub fn createEmpty(
|
|||||||
const index: File.Index = @intCast(try self.files.addOne(gpa));
|
const index: File.Index = @intCast(try self.files.addOne(gpa));
|
||||||
self.files.set(index, .{ .zig_object = .{
|
self.files.set(index, .{ .zig_object = .{
|
||||||
.index = index,
|
.index = index,
|
||||||
.path = try std.fmt.allocPrint(arena, "{s}.o", .{std.fs.path.stem(
|
.path = try std.fmt.allocPrint(arena, "{s}.o", .{fs.path.stem(
|
||||||
zcu.main_mod.root_src_path,
|
zcu.main_mod.root_src_path,
|
||||||
)}),
|
)}),
|
||||||
} });
|
} });
|
||||||
@ -1673,7 +1673,7 @@ pub const ParseError = error{
|
|||||||
NotSupported,
|
NotSupported,
|
||||||
InvalidCharacter,
|
InvalidCharacter,
|
||||||
UnknownFileType,
|
UnknownFileType,
|
||||||
} || LdScript.Error || std.os.AccessError || std.os.SeekError || std.fs.File.OpenError || std.fs.File.ReadError;
|
} || LdScript.Error || fs.Dir.AccessError || fs.File.SeekError || fs.File.OpenError || fs.File.ReadError;
|
||||||
|
|
||||||
pub fn parsePositional(self: *Elf, path: []const u8, must_link: bool) ParseError!void {
|
pub fn parsePositional(self: *Elf, path: []const u8, must_link: bool) ParseError!void {
|
||||||
const tracy = trace(@src());
|
const tracy = trace(@src());
|
||||||
@ -1703,7 +1703,7 @@ fn parseObject(self: *Elf, path: []const u8) ParseError!void {
|
|||||||
defer tracy.end();
|
defer tracy.end();
|
||||||
|
|
||||||
const gpa = self.base.comp.gpa;
|
const gpa = self.base.comp.gpa;
|
||||||
const handle = try std.fs.cwd().openFile(path, .{});
|
const handle = try fs.cwd().openFile(path, .{});
|
||||||
const fh = try self.addFileHandle(handle);
|
const fh = try self.addFileHandle(handle);
|
||||||
|
|
||||||
const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
|
const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
|
||||||
@ -1723,7 +1723,7 @@ fn parseArchive(self: *Elf, path: []const u8, must_link: bool) ParseError!void {
|
|||||||
defer tracy.end();
|
defer tracy.end();
|
||||||
|
|
||||||
const gpa = self.base.comp.gpa;
|
const gpa = self.base.comp.gpa;
|
||||||
const handle = try std.fs.cwd().openFile(path, .{});
|
const handle = try fs.cwd().openFile(path, .{});
|
||||||
const fh = try self.addFileHandle(handle);
|
const fh = try self.addFileHandle(handle);
|
||||||
|
|
||||||
var archive = Archive{};
|
var archive = Archive{};
|
||||||
@ -1749,7 +1749,7 @@ fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void {
|
|||||||
defer tracy.end();
|
defer tracy.end();
|
||||||
|
|
||||||
const gpa = self.base.comp.gpa;
|
const gpa = self.base.comp.gpa;
|
||||||
const handle = try std.fs.cwd().openFile(lib.path, .{});
|
const handle = try fs.cwd().openFile(lib.path, .{});
|
||||||
defer handle.close();
|
defer handle.close();
|
||||||
|
|
||||||
const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
|
const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
|
||||||
@ -1770,7 +1770,7 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
|
|||||||
defer tracy.end();
|
defer tracy.end();
|
||||||
|
|
||||||
const gpa = self.base.comp.gpa;
|
const gpa = self.base.comp.gpa;
|
||||||
const in_file = try std.fs.cwd().openFile(lib.path, .{});
|
const in_file = try fs.cwd().openFile(lib.path, .{});
|
||||||
defer in_file.close();
|
defer in_file.close();
|
||||||
const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));
|
const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));
|
||||||
defer gpa.free(data);
|
defer gpa.free(data);
|
||||||
@ -5468,7 +5468,7 @@ pub fn file(self: *Elf, index: File.Index) ?File {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addFileHandle(self: *Elf, handle: std.fs.File) !File.HandleIndex {
|
pub fn addFileHandle(self: *Elf, handle: fs.File) !File.HandleIndex {
|
||||||
const gpa = self.base.comp.gpa;
|
const gpa = self.base.comp.gpa;
|
||||||
const index: File.HandleIndex = @intCast(self.file_handles.items.len);
|
const index: File.HandleIndex = @intCast(self.file_handles.items.len);
|
||||||
const fh = try self.file_handles.addOne(gpa);
|
const fh = try self.file_handles.addOne(gpa);
|
||||||
@ -6045,7 +6045,7 @@ fn fmtDumpState(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Caller owns the memory.
|
/// Caller owns the memory.
|
||||||
pub fn preadAllAlloc(allocator: Allocator, handle: std.fs.File, offset: u64, size: u64) ![]u8 {
|
pub fn preadAllAlloc(allocator: Allocator, handle: fs.File, offset: u64, size: u64) ![]u8 {
|
||||||
const buffer = try allocator.alloc(u8, math.cast(usize, size) orelse return error.Overflow);
|
const buffer = try allocator.alloc(u8, math.cast(usize, size) orelse return error.Overflow);
|
||||||
errdefer allocator.free(buffer);
|
errdefer allocator.free(buffer);
|
||||||
const amt = try handle.preadAll(buffer, offset);
|
const amt = try handle.preadAll(buffer, offset);
|
||||||
|
|||||||
@ -965,16 +965,16 @@ fn updateDeclCode(
|
|||||||
if (elf_file.base.child_pid) |pid| {
|
if (elf_file.base.child_pid) |pid| {
|
||||||
switch (builtin.os.tag) {
|
switch (builtin.os.tag) {
|
||||||
.linux => {
|
.linux => {
|
||||||
var code_vec: [1]std.os.iovec_const = .{.{
|
var code_vec: [1]std.posix.iovec_const = .{.{
|
||||||
.iov_base = code.ptr,
|
.iov_base = code.ptr,
|
||||||
.iov_len = code.len,
|
.iov_len = code.len,
|
||||||
}};
|
}};
|
||||||
var remote_vec: [1]std.os.iovec_const = .{.{
|
var remote_vec: [1]std.posix.iovec_const = .{.{
|
||||||
.iov_base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(sym.address(.{}, elf_file))))),
|
.iov_base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(sym.address(.{}, elf_file))))),
|
||||||
.iov_len = code.len,
|
.iov_len = code.len,
|
||||||
}};
|
}};
|
||||||
const rc = std.os.linux.process_vm_writev(pid, &code_vec, &remote_vec, 0);
|
const rc = std.os.linux.process_vm_writev(pid, &code_vec, &remote_vec, 0);
|
||||||
switch (std.os.errno(rc)) {
|
switch (std.os.linux.E.init(rc)) {
|
||||||
.SUCCESS => assert(rc == code.len),
|
.SUCCESS => assert(rc == code.len),
|
||||||
else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
|
else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -317,16 +317,16 @@ pub const ZigGotSection = struct {
|
|||||||
if (elf_file.base.child_pid) |pid| {
|
if (elf_file.base.child_pid) |pid| {
|
||||||
switch (builtin.os.tag) {
|
switch (builtin.os.tag) {
|
||||||
.linux => {
|
.linux => {
|
||||||
var local_vec: [1]std.os.iovec_const = .{.{
|
var local_vec: [1]std.posix.iovec_const = .{.{
|
||||||
.iov_base = &buf,
|
.iov_base = &buf,
|
||||||
.iov_len = buf.len,
|
.iov_len = buf.len,
|
||||||
}};
|
}};
|
||||||
var remote_vec: [1]std.os.iovec_const = .{.{
|
var remote_vec: [1]std.posix.iovec_const = .{.{
|
||||||
.iov_base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(vaddr)))),
|
.iov_base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(vaddr)))),
|
||||||
.iov_len = buf.len,
|
.iov_len = buf.len,
|
||||||
}};
|
}};
|
||||||
const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0);
|
const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0);
|
||||||
switch (std.os.errno(rc)) {
|
switch (std.os.linux.E.init(rc)) {
|
||||||
.SUCCESS => assert(rc == buf.len),
|
.SUCCESS => assert(rc == buf.len),
|
||||||
else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
|
else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -258,7 +258,7 @@ pub fn createEmpty(
|
|||||||
const index: File.Index = @intCast(try self.files.addOne(gpa));
|
const index: File.Index = @intCast(try self.files.addOne(gpa));
|
||||||
self.files.set(index, .{ .zig_object = .{
|
self.files.set(index, .{ .zig_object = .{
|
||||||
.index = index,
|
.index = index,
|
||||||
.path = try std.fmt.allocPrint(arena, "{s}.o", .{std.fs.path.stem(
|
.path = try std.fmt.allocPrint(arena, "{s}.o", .{fs.path.stem(
|
||||||
zcu.main_mod.root_src_path,
|
zcu.main_mod.root_src_path,
|
||||||
)}),
|
)}),
|
||||||
} });
|
} });
|
||||||
@ -843,7 +843,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (self.frameworks) |framework| {
|
for (self.frameworks) |framework| {
|
||||||
const name = std.fs.path.stem(framework.path);
|
const name = fs.path.stem(framework.path);
|
||||||
const arg = if (framework.needed)
|
const arg = if (framework.needed)
|
||||||
try std.fmt.allocPrint(arena, "-needed_framework {s}", .{name})
|
try std.fmt.allocPrint(arena, "-needed_framework {s}", .{name})
|
||||||
else if (framework.weak)
|
else if (framework.weak)
|
||||||
@ -917,7 +917,7 @@ pub const ParseError = error{
|
|||||||
NotSupported,
|
NotSupported,
|
||||||
Unhandled,
|
Unhandled,
|
||||||
UnknownFileType,
|
UnknownFileType,
|
||||||
} || std.os.SeekError || std.fs.File.OpenError || std.fs.File.ReadError || tapi.TapiError;
|
} || fs.File.SeekError || fs.File.OpenError || fs.File.ReadError || tapi.TapiError;
|
||||||
|
|
||||||
pub fn parsePositional(self: *MachO, path: []const u8, must_link: bool) ParseError!void {
|
pub fn parsePositional(self: *MachO, path: []const u8, must_link: bool) ParseError!void {
|
||||||
const tracy = trace(@src());
|
const tracy = trace(@src());
|
||||||
@ -956,7 +956,7 @@ fn parseObject(self: *MachO, path: []const u8) ParseError!void {
|
|||||||
defer tracy.end();
|
defer tracy.end();
|
||||||
|
|
||||||
const gpa = self.base.comp.gpa;
|
const gpa = self.base.comp.gpa;
|
||||||
const file = try std.fs.cwd().openFile(path, .{});
|
const file = try fs.cwd().openFile(path, .{});
|
||||||
const handle = try self.addFileHandle(file);
|
const handle = try self.addFileHandle(file);
|
||||||
const mtime: u64 = mtime: {
|
const mtime: u64 = mtime: {
|
||||||
const stat = file.stat() catch break :mtime 0;
|
const stat = file.stat() catch break :mtime 0;
|
||||||
@ -992,7 +992,7 @@ fn parseArchive(self: *MachO, lib: SystemLib, must_link: bool, fat_arch: ?fat.Ar
|
|||||||
|
|
||||||
const gpa = self.base.comp.gpa;
|
const gpa = self.base.comp.gpa;
|
||||||
|
|
||||||
const file = try std.fs.cwd().openFile(lib.path, .{});
|
const file = try fs.cwd().openFile(lib.path, .{});
|
||||||
const handle = try self.addFileHandle(file);
|
const handle = try self.addFileHandle(file);
|
||||||
|
|
||||||
var archive = Archive{};
|
var archive = Archive{};
|
||||||
@ -1029,7 +1029,7 @@ fn parseDylib(self: *MachO, lib: SystemLib, explicit: bool, fat_arch: ?fat.Arch)
|
|||||||
|
|
||||||
const gpa = self.base.comp.gpa;
|
const gpa = self.base.comp.gpa;
|
||||||
|
|
||||||
const file = try std.fs.cwd().openFile(lib.path, .{});
|
const file = try fs.cwd().openFile(lib.path, .{});
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
|
const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
|
||||||
@ -1054,7 +1054,7 @@ fn parseTbd(self: *MachO, lib: SystemLib, explicit: bool) ParseError!File.Index
|
|||||||
defer tracy.end();
|
defer tracy.end();
|
||||||
|
|
||||||
const gpa = self.base.comp.gpa;
|
const gpa = self.base.comp.gpa;
|
||||||
const file = try std.fs.cwd().openFile(lib.path, .{});
|
const file = try fs.cwd().openFile(lib.path, .{});
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
var lib_stub = LibStub.loadFromFile(gpa, file) catch return error.MalformedTbd; // TODO actually handle different errors
|
var lib_stub = LibStub.loadFromFile(gpa, file) catch return error.MalformedTbd; // TODO actually handle different errors
|
||||||
@ -1080,10 +1080,10 @@ fn parseTbd(self: *MachO, lib: SystemLib, explicit: bool) ParseError!File.Index
|
|||||||
/// image unless overriden by -no_implicit_dylibs.
|
/// image unless overriden by -no_implicit_dylibs.
|
||||||
fn isHoisted(self: *MachO, install_name: []const u8) bool {
|
fn isHoisted(self: *MachO, install_name: []const u8) bool {
|
||||||
if (self.no_implicit_dylibs) return true;
|
if (self.no_implicit_dylibs) return true;
|
||||||
if (std.fs.path.dirname(install_name)) |dirname| {
|
if (fs.path.dirname(install_name)) |dirname| {
|
||||||
if (mem.startsWith(u8, dirname, "/usr/lib")) return true;
|
if (mem.startsWith(u8, dirname, "/usr/lib")) return true;
|
||||||
if (eatPrefix(dirname, "/System/Library/Frameworks/")) |path| {
|
if (eatPrefix(dirname, "/System/Library/Frameworks/")) |path| {
|
||||||
const basename = std.fs.path.basename(install_name);
|
const basename = fs.path.basename(install_name);
|
||||||
if (mem.indexOfScalar(u8, path, '.')) |index| {
|
if (mem.indexOfScalar(u8, path, '.')) |index| {
|
||||||
if (mem.eql(u8, basename, path[0..index])) return true;
|
if (mem.eql(u8, basename, path[0..index])) return true;
|
||||||
}
|
}
|
||||||
@ -1105,7 +1105,7 @@ fn accessLibPath(
|
|||||||
test_path.clearRetainingCapacity();
|
test_path.clearRetainingCapacity();
|
||||||
try test_path.writer().print("{s}" ++ sep ++ "lib{s}{s}", .{ search_dir, name, ext });
|
try test_path.writer().print("{s}" ++ sep ++ "lib{s}{s}", .{ search_dir, name, ext });
|
||||||
try checked_paths.append(try arena.dupe(u8, test_path.items));
|
try checked_paths.append(try arena.dupe(u8, test_path.items));
|
||||||
std.fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
|
fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
|
||||||
error.FileNotFound => continue,
|
error.FileNotFound => continue,
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
};
|
};
|
||||||
@ -1133,7 +1133,7 @@ fn accessFrameworkPath(
|
|||||||
ext,
|
ext,
|
||||||
});
|
});
|
||||||
try checked_paths.append(try arena.dupe(u8, test_path.items));
|
try checked_paths.append(try arena.dupe(u8, test_path.items));
|
||||||
std.fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
|
fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
|
||||||
error.FileNotFound => continue,
|
error.FileNotFound => continue,
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
};
|
};
|
||||||
@ -1181,7 +1181,7 @@ fn parseDependentDylibs(self: *MachO) !void {
|
|||||||
|
|
||||||
const full_path = full_path: {
|
const full_path = full_path: {
|
||||||
{
|
{
|
||||||
const stem = std.fs.path.stem(id.name);
|
const stem = fs.path.stem(id.name);
|
||||||
|
|
||||||
// Framework
|
// Framework
|
||||||
for (framework_dirs) |dir| {
|
for (framework_dirs) |dir| {
|
||||||
@ -1197,18 +1197,18 @@ fn parseDependentDylibs(self: *MachO) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std.fs.path.isAbsolute(id.name)) {
|
if (fs.path.isAbsolute(id.name)) {
|
||||||
const existing_ext = std.fs.path.extension(id.name);
|
const existing_ext = fs.path.extension(id.name);
|
||||||
const path = if (existing_ext.len > 0) id.name[0 .. id.name.len - existing_ext.len] else id.name;
|
const path = if (existing_ext.len > 0) id.name[0 .. id.name.len - existing_ext.len] else id.name;
|
||||||
for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
|
for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
|
||||||
test_path.clearRetainingCapacity();
|
test_path.clearRetainingCapacity();
|
||||||
if (self.base.comp.sysroot) |root| {
|
if (self.base.comp.sysroot) |root| {
|
||||||
try test_path.writer().print("{s}" ++ std.fs.path.sep_str ++ "{s}{s}", .{ root, path, ext });
|
try test_path.writer().print("{s}" ++ fs.path.sep_str ++ "{s}{s}", .{ root, path, ext });
|
||||||
} else {
|
} else {
|
||||||
try test_path.writer().print("{s}{s}", .{ path, ext });
|
try test_path.writer().print("{s}{s}", .{ path, ext });
|
||||||
}
|
}
|
||||||
try checked_paths.append(try arena.dupe(u8, test_path.items));
|
try checked_paths.append(try arena.dupe(u8, test_path.items));
|
||||||
std.fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
|
fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
|
||||||
error.FileNotFound => continue,
|
error.FileNotFound => continue,
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
};
|
};
|
||||||
@ -1220,10 +1220,10 @@ fn parseDependentDylibs(self: *MachO) !void {
|
|||||||
const dylib = self.getFile(dylib_index).?.dylib;
|
const dylib = self.getFile(dylib_index).?.dylib;
|
||||||
for (self.getFile(dylib.umbrella).?.dylib.rpaths.keys()) |rpath| {
|
for (self.getFile(dylib.umbrella).?.dylib.rpaths.keys()) |rpath| {
|
||||||
const prefix = eatPrefix(rpath, "@loader_path/") orelse rpath;
|
const prefix = eatPrefix(rpath, "@loader_path/") orelse rpath;
|
||||||
const rel_path = try std.fs.path.join(arena, &.{ prefix, path });
|
const rel_path = try fs.path.join(arena, &.{ prefix, path });
|
||||||
try checked_paths.append(rel_path);
|
try checked_paths.append(rel_path);
|
||||||
var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
const full_path = std.fs.realpath(rel_path, &buffer) catch continue;
|
const full_path = fs.realpath(rel_path, &buffer) catch continue;
|
||||||
break :full_path try arena.dupe(u8, full_path);
|
break :full_path try arena.dupe(u8, full_path);
|
||||||
}
|
}
|
||||||
} else if (eatPrefix(id.name, "@loader_path/")) |_| {
|
} else if (eatPrefix(id.name, "@loader_path/")) |_| {
|
||||||
@ -1235,8 +1235,8 @@ fn parseDependentDylibs(self: *MachO) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try checked_paths.append(try arena.dupe(u8, id.name));
|
try checked_paths.append(try arena.dupe(u8, id.name));
|
||||||
var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
if (std.fs.realpath(id.name, &buffer)) |full_path| {
|
if (fs.realpath(id.name, &buffer)) |full_path| {
|
||||||
break :full_path try arena.dupe(u8, full_path);
|
break :full_path try arena.dupe(u8, full_path);
|
||||||
} else |_| {
|
} else |_| {
|
||||||
try self.reportMissingDependencyError(
|
try self.reportMissingDependencyError(
|
||||||
@ -3651,7 +3651,7 @@ pub fn getTarget(self: MachO) std.Target {
|
|||||||
/// into a new inode, remove the original file, and rename the copy to match
|
/// into a new inode, remove the original file, and rename the copy to match
|
||||||
/// the original file. This is super messy, but there doesn't seem any other
|
/// the original file. This is super messy, but there doesn't seem any other
|
||||||
/// way to please the XNU.
|
/// way to please the XNU.
|
||||||
pub fn invalidateKernelCache(dir: std.fs.Dir, sub_path: []const u8) !void {
|
pub fn invalidateKernelCache(dir: fs.Dir, sub_path: []const u8) !void {
|
||||||
if (comptime builtin.target.isDarwin() and builtin.target.cpu.arch == .aarch64) {
|
if (comptime builtin.target.isDarwin() and builtin.target.cpu.arch == .aarch64) {
|
||||||
try dir.copyFile(sub_path, dir, sub_path, .{});
|
try dir.copyFile(sub_path, dir, sub_path, .{});
|
||||||
}
|
}
|
||||||
@ -3839,7 +3839,7 @@ pub fn getInternalObject(self: *MachO) ?*InternalObject {
|
|||||||
return self.getFile(index).?.internal;
|
return self.getFile(index).?.internal;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addFileHandle(self: *MachO, file: std.fs.File) !File.HandleIndex {
|
pub fn addFileHandle(self: *MachO, file: fs.File) !File.HandleIndex {
|
||||||
const gpa = self.base.comp.gpa;
|
const gpa = self.base.comp.gpa;
|
||||||
const index: File.HandleIndex = @intCast(self.file_handles.items.len);
|
const index: File.HandleIndex = @intCast(self.file_handles.items.len);
|
||||||
const fh = try self.file_handles.addOne(gpa);
|
const fh = try self.file_handles.addOne(gpa);
|
||||||
@ -4530,7 +4530,7 @@ fn inferSdkVersion(comp: *Compilation, sdk_layout: SdkLayout) ?std.SemanticVersi
|
|||||||
|
|
||||||
const sdk_dir = switch (sdk_layout) {
|
const sdk_dir = switch (sdk_layout) {
|
||||||
.sdk => comp.sysroot.?,
|
.sdk => comp.sysroot.?,
|
||||||
.vendored => std.fs.path.join(arena, &.{ comp.zig_lib_directory.path.?, "libc", "darwin" }) catch return null,
|
.vendored => fs.path.join(arena, &.{ comp.zig_lib_directory.path.?, "libc", "darwin" }) catch return null,
|
||||||
};
|
};
|
||||||
if (readSdkVersionFromSettings(arena, sdk_dir)) |ver| {
|
if (readSdkVersionFromSettings(arena, sdk_dir)) |ver| {
|
||||||
return parseSdkVersion(ver);
|
return parseSdkVersion(ver);
|
||||||
@ -4541,7 +4541,7 @@ fn inferSdkVersion(comp: *Compilation, sdk_layout: SdkLayout) ?std.SemanticVersi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// infer from pathname
|
// infer from pathname
|
||||||
const stem = std.fs.path.stem(sdk_dir);
|
const stem = fs.path.stem(sdk_dir);
|
||||||
const start = for (stem, 0..) |c, i| {
|
const start = for (stem, 0..) |c, i| {
|
||||||
if (std.ascii.isDigit(c)) break i;
|
if (std.ascii.isDigit(c)) break i;
|
||||||
} else stem.len;
|
} else stem.len;
|
||||||
@ -4556,8 +4556,8 @@ fn inferSdkVersion(comp: *Compilation, sdk_layout: SdkLayout) ?std.SemanticVersi
|
|||||||
// Use property `MinimalDisplayName` to determine version.
|
// Use property `MinimalDisplayName` to determine version.
|
||||||
// The file/property is also available with vendored libc.
|
// The file/property is also available with vendored libc.
|
||||||
fn readSdkVersionFromSettings(arena: Allocator, dir: []const u8) ![]const u8 {
|
fn readSdkVersionFromSettings(arena: Allocator, dir: []const u8) ![]const u8 {
|
||||||
const sdk_path = try std.fs.path.join(arena, &.{ dir, "SDKSettings.json" });
|
const sdk_path = try fs.path.join(arena, &.{ dir, "SDKSettings.json" });
|
||||||
const contents = try std.fs.cwd().readFileAlloc(arena, sdk_path, std.math.maxInt(u16));
|
const contents = try fs.cwd().readFileAlloc(arena, sdk_path, std.math.maxInt(u16));
|
||||||
const parsed = try std.json.parseFromSlice(std.json.Value, arena, contents, .{});
|
const parsed = try std.json.parseFromSlice(std.json.Value, arena, contents, .{});
|
||||||
if (parsed.value.object.get("MinimalDisplayName")) |ver| return ver.string;
|
if (parsed.value.object.get("MinimalDisplayName")) |ver| return ver.string;
|
||||||
return error.SdkVersionFailure;
|
return error.SdkVersionFailure;
|
||||||
|
|||||||
@ -368,7 +368,7 @@ fn putFn(self: *Plan9, decl_index: InternPool.DeclIndex, out: FnDeclOutput) !voi
|
|||||||
// getting the full file path
|
// getting the full file path
|
||||||
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
const full_path = try std.fs.path.join(arena, &.{
|
const full_path = try std.fs.path.join(arena, &.{
|
||||||
file.mod.root.root_dir.path orelse try std.os.getcwd(&buf),
|
file.mod.root.root_dir.path orelse try std.posix.getcwd(&buf),
|
||||||
file.mod.root.sub_path,
|
file.mod.root.sub_path,
|
||||||
file.sub_file_path,
|
file.sub_file_path,
|
||||||
});
|
});
|
||||||
@ -722,7 +722,7 @@ pub fn flushModule(self: *Plan9, arena: Allocator, prog_node: *std.Progress.Node
|
|||||||
defer gpa.free(got_table);
|
defer gpa.free(got_table);
|
||||||
|
|
||||||
// + 4 for header, got, symbols, linecountinfo
|
// + 4 for header, got, symbols, linecountinfo
|
||||||
var iovecs = try gpa.alloc(std.os.iovec_const, self.atomCount() + 4 - self.externCount());
|
var iovecs = try gpa.alloc(std.posix.iovec_const, self.atomCount() + 4 - self.externCount());
|
||||||
defer gpa.free(iovecs);
|
defer gpa.free(iovecs);
|
||||||
|
|
||||||
const file = self.base.file.?;
|
const file = self.base.file.?;
|
||||||
|
|||||||
@ -3046,7 +3046,7 @@ fn writeToFile(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// finally, write the entire binary into the file.
|
// finally, write the entire binary into the file.
|
||||||
var iovec = [_]std.os.iovec_const{.{
|
var iovec = [_]std.posix.iovec_const{.{
|
||||||
.iov_base = binary_bytes.items.ptr,
|
.iov_base = binary_bytes.items.ptr,
|
||||||
.iov_len = binary_bytes.items.len,
|
.iov_len = binary_bytes.items.len,
|
||||||
}};
|
}};
|
||||||
@ -3709,7 +3709,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, prog_node: *std.Progress.Node) !vo
|
|||||||
// report a nice error here with the file path if it fails instead of
|
// report a nice error here with the file path if it fails instead of
|
||||||
// just returning the error code.
|
// just returning the error code.
|
||||||
// chmod does not interact with umask, so we use a conservative -rwxr--r-- here.
|
// chmod does not interact with umask, so we use a conservative -rwxr--r-- here.
|
||||||
std.os.fchmodat(fs.cwd().fd, full_out_path, 0o744, 0) catch |err| switch (err) {
|
std.posix.fchmodat(fs.cwd().fd, full_out_path, 0o744, 0) catch |err| switch (err) {
|
||||||
error.OperationNotSupported => unreachable, // Not a symlink.
|
error.OperationNotSupported => unreachable, // Not a symlink.
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -193,7 +193,7 @@ pub fn parseObject(archive: Archive, wasm_file: *const Wasm, file_offset: u32) !
|
|||||||
const object_name = try archive.parseName(header);
|
const object_name = try archive.parseName(header);
|
||||||
const name = name: {
|
const name = name: {
|
||||||
var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
const path = try std.os.realpath(archive.name, &buffer);
|
const path = try std.posix.realpath(archive.name, &buffer);
|
||||||
break :name try std.fmt.allocPrint(gpa, "{s}({s})", .{ path, object_name });
|
break :name try std.fmt.allocPrint(gpa, "{s}({s})", .{ path, object_name });
|
||||||
};
|
};
|
||||||
defer gpa.free(name);
|
defer gpa.free(name);
|
||||||
|
|||||||
16
src/main.zig
16
src/main.zig
@ -48,7 +48,7 @@ pub const panic = crash_report.panic;
|
|||||||
var wasi_preopens: fs.wasi.Preopens = undefined;
|
var wasi_preopens: fs.wasi.Preopens = undefined;
|
||||||
pub fn wasi_cwd() std.os.wasi.fd_t {
|
pub fn wasi_cwd() std.os.wasi.fd_t {
|
||||||
// Expect the first preopen to be current working directory.
|
// Expect the first preopen to be current working directory.
|
||||||
const cwd_fd: std.os.fd_t = 3;
|
const cwd_fd: std.posix.fd_t = 3;
|
||||||
assert(mem.eql(u8, wasi_preopens.names[cwd_fd], "."));
|
assert(mem.eql(u8, wasi_preopens.names[cwd_fd], "."));
|
||||||
return cwd_fd;
|
return cwd_fd;
|
||||||
}
|
}
|
||||||
@ -222,7 +222,7 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
|
|||||||
fatal("expected command argument", .{});
|
fatal("expected command argument", .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.can_execv and std.os.getenvZ("ZIG_IS_DETECTING_LIBC_PATHS") != null) {
|
if (process.can_execv and std.posix.getenvZ("ZIG_IS_DETECTING_LIBC_PATHS") != null) {
|
||||||
// In this case we have accidentally invoked ourselves as "the system C compiler"
|
// In this case we have accidentally invoked ourselves as "the system C compiler"
|
||||||
// to figure out where libc is installed. This is essentially infinite recursion
|
// to figure out where libc is installed. This is essentially infinite recursion
|
||||||
// via child process execution due to the CC environment variable pointing to Zig.
|
// via child process execution due to the CC environment variable pointing to Zig.
|
||||||
@ -4434,16 +4434,16 @@ fn runOrTestHotSwap(
|
|||||||
|
|
||||||
switch (builtin.target.os.tag) {
|
switch (builtin.target.os.tag) {
|
||||||
.macos, .ios, .tvos, .watchos => {
|
.macos, .ios, .tvos, .watchos => {
|
||||||
const PosixSpawn = std.os.darwin.PosixSpawn;
|
const PosixSpawn = @import("DarwinPosixSpawn.zig");
|
||||||
|
|
||||||
var attr = try PosixSpawn.Attr.init();
|
var attr = try PosixSpawn.Attr.init();
|
||||||
defer attr.deinit();
|
defer attr.deinit();
|
||||||
|
|
||||||
// ASLR is probably a good default for better debugging experience/programming
|
// ASLR is probably a good default for better debugging experience/programming
|
||||||
// with hot-code updates in mind. However, we can also make it work with ASLR on.
|
// with hot-code updates in mind. However, we can also make it work with ASLR on.
|
||||||
const flags: u16 = std.os.darwin.POSIX_SPAWN.SETSIGDEF |
|
const flags: u16 = std.c.POSIX_SPAWN.SETSIGDEF |
|
||||||
std.os.darwin.POSIX_SPAWN.SETSIGMASK |
|
std.c.POSIX_SPAWN.SETSIGMASK |
|
||||||
std.os.darwin.POSIX_SPAWN.DISABLE_ASLR;
|
std.c.POSIX_SPAWN.DISABLE_ASLR;
|
||||||
try attr.set(flags);
|
try attr.set(flags);
|
||||||
|
|
||||||
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
|
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
|
||||||
@ -5985,8 +5985,8 @@ fn parseCodeModel(arg: []const u8) std.builtin.CodeModel {
|
|||||||
/// garbage collector to run concurrently to zig processes, and to allow multiple
|
/// garbage collector to run concurrently to zig processes, and to allow multiple
|
||||||
/// zig processes to run concurrently with each other, without clobbering each other.
|
/// zig processes to run concurrently with each other, without clobbering each other.
|
||||||
fn gimmeMoreOfThoseSweetSweetFileDescriptors() void {
|
fn gimmeMoreOfThoseSweetSweetFileDescriptors() void {
|
||||||
if (!@hasDecl(std.os.system, "rlimit")) return;
|
const posix = std.posix;
|
||||||
const posix = std.os;
|
if (!@hasDecl(posix, "rlimit")) return;
|
||||||
|
|
||||||
var lim = posix.getrlimit(.NOFILE) catch return; // Oh well; we tried.
|
var lim = posix.getrlimit(.NOFILE) catch return; // Oh well; we tried.
|
||||||
if (comptime builtin.target.isDarwin()) {
|
if (comptime builtin.target.isDarwin()) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user