mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
Merge 0e013541ab into d0ba6642b5
This commit is contained in:
commit
351afb5d9c
16 changed files with 7161 additions and 4050 deletions
|
|
@ -473,7 +473,6 @@ set(ZIG_STAGE2_SOURCES
|
|||
lib/std/os/linux.zig
|
||||
lib/std/os/linux.zig
|
||||
lib/std/os/linux/IoUring.zig
|
||||
lib/std/os/linux/io_uring_sqe.zig
|
||||
lib/std/os/linux/x86_64.zig
|
||||
lib/std/os/linux/x86_64.zig
|
||||
lib/std/os/windows.zig
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ pub fn cwd() Dir {
|
|||
return switch (native_os) {
|
||||
.windows => .{ .handle = std.os.windows.peb().ProcessParameters.CurrentDirectory.Handle },
|
||||
.wasi => .{ .handle = std.options.wasiCwd() },
|
||||
else => .{ .handle = std.posix.AT.FDCWD },
|
||||
else => .{ .handle = std.posix.At.fdcwd },
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1353,8 +1353,7 @@ fn dirStatPathLinux(
|
|||
var path_buffer: [posix.PATH_MAX]u8 = undefined;
|
||||
const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
|
||||
|
||||
const flags: u32 = linux.AT.NO_AUTOMOUNT |
|
||||
@as(u32, if (!options.follow_symlinks) linux.AT.SYMLINK_NOFOLLOW else 0);
|
||||
const flags: linux.At = .{ .no_automount = true, .symlink_nofollow = if (!options.follow_symlinks) true else false };
|
||||
|
||||
while (true) {
|
||||
try t.checkCancel();
|
||||
|
|
@ -1363,7 +1362,15 @@ fn dirStatPathLinux(
|
|||
dir.handle,
|
||||
sub_path_posix,
|
||||
flags,
|
||||
linux.STATX_INO | linux.STATX_SIZE | linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_ATIME | linux.STATX_MTIME | linux.STATX_CTIME,
|
||||
.{
|
||||
.ino = true,
|
||||
.size = true,
|
||||
.type = true,
|
||||
.mode = true,
|
||||
.atime = true,
|
||||
.mtime = true,
|
||||
.ctime = true,
|
||||
},
|
||||
&statx,
|
||||
);
|
||||
switch (linux.errno(rc)) {
|
||||
|
|
@ -1396,12 +1403,12 @@ fn dirStatPathPosix(
|
|||
var path_buffer: [posix.PATH_MAX]u8 = undefined;
|
||||
const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
|
||||
|
||||
const flags: u32 = if (!options.follow_symlinks) posix.AT.SYMLINK_NOFOLLOW else 0;
|
||||
const flags: posix.At = .{ .symlink_nofollow = if (!options.follow_symlinks) true else false };
|
||||
|
||||
while (true) {
|
||||
try t.checkCancel();
|
||||
var stat = std.mem.zeroes(posix.Stat);
|
||||
switch (posix.errno(fstatat_sym(dir.handle, sub_path_posix, &stat, flags))) {
|
||||
switch (posix.errno(fstatat_sym(dir.handle, sub_path_posix, &stat, @bitCast(flags)))) {
|
||||
.SUCCESS => return statFromPosix(&stat),
|
||||
.INTR => continue,
|
||||
.CANCELED => return error.Canceled,
|
||||
|
|
@ -1509,8 +1516,16 @@ fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File
|
|||
const rc = linux.statx(
|
||||
file.handle,
|
||||
"",
|
||||
linux.AT.EMPTY_PATH,
|
||||
linux.STATX_INO | linux.STATX_SIZE | linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_ATIME | linux.STATX_MTIME | linux.STATX_CTIME,
|
||||
.{ .empty_path = true },
|
||||
.{
|
||||
.ino = true,
|
||||
.size = true,
|
||||
.type = true,
|
||||
.mode = true,
|
||||
.atime = true,
|
||||
.mtime = true,
|
||||
.ctime = true,
|
||||
},
|
||||
&statx,
|
||||
);
|
||||
switch (linux.errno(rc)) {
|
||||
|
|
@ -1617,7 +1632,7 @@ fn dirAccessPosix(
|
|||
var path_buffer: [posix.PATH_MAX]u8 = undefined;
|
||||
const sub_path_posix = try pathToPosix(sub_path, &path_buffer);
|
||||
|
||||
const flags: u32 = @as(u32, if (!options.follow_symlinks) posix.AT.SYMLINK_NOFOLLOW else 0);
|
||||
const flags: posix.At = .{ .symlink_nofollow = if (!options.follow_symlinks) true else false };
|
||||
|
||||
const mode: u32 =
|
||||
@as(u32, if (options.read) posix.R_OK else 0) |
|
||||
|
|
@ -1626,7 +1641,7 @@ fn dirAccessPosix(
|
|||
|
||||
while (true) {
|
||||
try t.checkCancel();
|
||||
switch (posix.errno(posix.system.faccessat(dir.handle, sub_path_posix, mode, flags))) {
|
||||
switch (posix.errno(posix.system.faccessat(dir.handle, sub_path_posix, mode, @bitCast(flags)))) {
|
||||
.SUCCESS => return,
|
||||
.INTR => continue,
|
||||
.CANCELED => return error.Canceled,
|
||||
|
|
@ -2886,7 +2901,7 @@ fn fileSeekTo(userdata: ?*anyopaque, file: Io.File, offset: u64) Io.File.SeekErr
|
|||
fn openSelfExe(userdata: ?*anyopaque, flags: Io.File.OpenFlags) Io.File.OpenSelfExeError!Io.File {
|
||||
const t: *Threaded = @ptrCast(@alignCast(userdata));
|
||||
switch (native_os) {
|
||||
.linux, .serenity => return dirOpenFilePosix(t, .{ .handle = posix.AT.FDCWD }, "/proc/self/exe", flags),
|
||||
.linux, .serenity => return dirOpenFilePosix(t, .{ .handle = posix.At.fdcwd }, "/proc/self/exe", flags),
|
||||
.windows => {
|
||||
// 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
|
||||
|
|
@ -5941,7 +5956,7 @@ pub fn futexWake(ptr: *const std.atomic.Value(u32), max_waiters: u32) void {
|
|||
.linux => {
|
||||
const linux = std.os.linux;
|
||||
switch (linux.errno(linux.futex_3arg(
|
||||
&ptr.raw,
|
||||
ptr,
|
||||
.{ .cmd = .WAKE, .private = true },
|
||||
@min(max_waiters, std.math.maxInt(i32)),
|
||||
))) {
|
||||
|
|
|
|||
|
|
@ -1217,8 +1217,8 @@ const LinuxThreadImpl = struct {
|
|||
thread: *ThreadCompletion,
|
||||
|
||||
const ThreadCompletion = struct {
|
||||
completion: Completion = Completion.init(.running),
|
||||
child_tid: std.atomic.Value(i32) = std.atomic.Value(i32).init(1),
|
||||
completion: Completion = .init(.running),
|
||||
child_tid: std.atomic.Value(i32) = .init(1),
|
||||
parent_tid: i32 = undefined,
|
||||
mapped: []align(std.heap.page_size_min) u8,
|
||||
|
||||
|
|
@ -1663,7 +1663,7 @@ const LinuxThreadImpl = struct {
|
|||
if (tid == 0) break;
|
||||
|
||||
switch (linux.errno(linux.futex_4arg(
|
||||
&self.thread.child_tid.raw,
|
||||
@ptrCast(&self.thread.child_tid),
|
||||
.{ .cmd = .WAIT, .private = false },
|
||||
@bitCast(tid),
|
||||
null,
|
||||
|
|
|
|||
|
|
@ -263,7 +263,7 @@ const LinuxImpl = struct {
|
|||
}
|
||||
|
||||
const rc = linux.futex_4arg(
|
||||
&ptr.raw,
|
||||
ptr,
|
||||
.{ .cmd = .WAIT, .private = true },
|
||||
expect,
|
||||
if (timeout != null) &ts else null,
|
||||
|
|
@ -285,7 +285,7 @@ const LinuxImpl = struct {
|
|||
|
||||
fn wake(ptr: *const atomic.Value(u32), max_waiters: u32) void {
|
||||
const rc = linux.futex_3arg(
|
||||
&ptr.raw,
|
||||
ptr,
|
||||
.{ .cmd = .WAKE, .private = true },
|
||||
@min(max_waiters, std.math.maxInt(i32)),
|
||||
);
|
||||
|
|
|
|||
1074
lib/std/c.zig
1074
lib/std/c.zig
File diff suppressed because it is too large
Load diff
|
|
@ -187,7 +187,7 @@ pub fn cwd() Dir {
|
|||
} else if (native_os == .wasi) {
|
||||
return .{ .fd = std.options.wasiCwd() };
|
||||
} else {
|
||||
return .{ .fd = posix.AT.FDCWD };
|
||||
return .{ .fd = posix.At.fdcwd };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ pub const Iterator = switch (native_os) {
|
|||
const stat_info = posix.fstatat(
|
||||
self.dir.fd,
|
||||
name,
|
||||
posix.AT.SYMLINK_NOFOLLOW,
|
||||
.{ .symlink_nofollow = true },
|
||||
) catch |err| switch (err) {
|
||||
error.NameTooLong => unreachable,
|
||||
error.SymLinkLoop => unreachable,
|
||||
|
|
@ -1112,7 +1112,7 @@ pub fn deleteFileZ(self: Dir, sub_path_c: [*:0]const u8) DeleteFileError!void {
|
|||
// directory, so we need to handle that case specifically and translate the error
|
||||
.driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos, .freebsd, .netbsd, .dragonfly, .openbsd, .illumos => {
|
||||
// Don't follow symlinks to match unlinkat (which acts on symlinks rather than follows them)
|
||||
const fstat = posix.fstatatZ(self.fd, sub_path_c, posix.AT.SYMLINK_NOFOLLOW) catch return e;
|
||||
const fstat = posix.fstatatZ(self.fd, sub_path_c, .{ .symlink_nofollow = true }) catch return e;
|
||||
const is_dir = fstat.mode & posix.S.IFMT == posix.S.IFDIR;
|
||||
return if (is_dir) error.IsDir else e;
|
||||
},
|
||||
|
|
@ -1163,7 +1163,7 @@ pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void {
|
|||
const sub_path_w = try windows.sliceToPrefixedFileW(self.fd, sub_path);
|
||||
return self.deleteDirW(sub_path_w.span());
|
||||
} 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
|
||||
else => |e| return e,
|
||||
};
|
||||
|
|
@ -1175,7 +1175,7 @@ pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void {
|
|||
|
||||
/// Same as `deleteDir` except the parameter is null-terminated.
|
||||
pub fn deleteDirZ(self: Dir, sub_path_c: [*:0]const u8) DeleteDirError!void {
|
||||
posix.unlinkatZ(self.fd, sub_path_c, posix.AT.REMOVEDIR) catch |err| switch (err) {
|
||||
posix.unlinkatZ(self.fd, sub_path_c, posix.At.REMOVEDIR) catch |err| switch (err) {
|
||||
error.IsDir => unreachable, // not possible since we pass AT.REMOVEDIR
|
||||
else => |e| return e,
|
||||
};
|
||||
|
|
@ -1184,7 +1184,7 @@ pub fn deleteDirZ(self: Dir, sub_path_c: [*:0]const u8) DeleteDirError!void {
|
|||
/// Same as `deleteDir` except the parameter is WTF16LE, NT prefixed.
|
||||
/// This function is Windows-only.
|
||||
pub fn deleteDirW(self: Dir, sub_path_w: []const u16) DeleteDirError!void {
|
||||
posix.unlinkatW(self.fd, sub_path_w, posix.AT.REMOVEDIR) catch |err| switch (err) {
|
||||
posix.unlinkatW(self.fd, sub_path_w, posix.At.REMOVEDIR) catch |err| switch (err) {
|
||||
error.IsDir => unreachable, // not possible since we pass AT.REMOVEDIR
|
||||
else => |e| return e,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -213,34 +213,6 @@ pub const X_OK = 1;
|
|||
pub const W_OK = 2;
|
||||
pub const R_OK = 4;
|
||||
|
||||
pub const W = struct {
|
||||
pub const NOHANG = 1;
|
||||
pub const UNTRACED = 2;
|
||||
pub const STOPPED = 2;
|
||||
pub const EXITED = 4;
|
||||
pub const CONTINUED = 8;
|
||||
pub const NOWAIT = 0x1000000;
|
||||
|
||||
pub fn EXITSTATUS(s: u32) u8 {
|
||||
return @as(u8, @intCast((s & 0xff00) >> 8));
|
||||
}
|
||||
pub fn TERMSIG(s: u32) u32 {
|
||||
return s & 0x7f;
|
||||
}
|
||||
pub fn STOPSIG(s: u32) u32 {
|
||||
return EXITSTATUS(s);
|
||||
}
|
||||
pub fn IFEXITED(s: u32) bool {
|
||||
return TERMSIG(s) == 0;
|
||||
}
|
||||
pub fn IFSTOPPED(s: u32) bool {
|
||||
return @as(u16, @truncate(((s & 0xffff) *% 0x10001) >> 8)) > 0x7f00;
|
||||
}
|
||||
pub fn IFSIGNALED(s: u32) bool {
|
||||
return (s & 0xffff) -% 1 < 0xff;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Flock = extern struct {
|
||||
type: i16,
|
||||
whence: i16,
|
||||
|
|
|
|||
3010
lib/std/os/linux.zig
3010
lib/std/os/linux.zig
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,679 +0,0 @@
|
|||
//! Contains only the definition of `io_uring_sqe`.
|
||||
//! Split into its own file to compartmentalize the initialization methods.
|
||||
|
||||
const std = @import("../../std.zig");
|
||||
const linux = std.os.linux;
|
||||
|
||||
pub const io_uring_sqe = extern struct {
|
||||
opcode: linux.IORING_OP,
|
||||
flags: u8,
|
||||
ioprio: u16,
|
||||
fd: i32,
|
||||
off: u64,
|
||||
addr: u64,
|
||||
len: u32,
|
||||
rw_flags: u32,
|
||||
user_data: u64,
|
||||
buf_index: u16,
|
||||
personality: u16,
|
||||
splice_fd_in: i32,
|
||||
addr3: u64,
|
||||
resv: u64,
|
||||
|
||||
pub fn prep_nop(sqe: *linux.io_uring_sqe) void {
|
||||
sqe.* = .{
|
||||
.opcode = .NOP,
|
||||
.flags = 0,
|
||||
.ioprio = 0,
|
||||
.fd = 0,
|
||||
.off = 0,
|
||||
.addr = 0,
|
||||
.len = 0,
|
||||
.rw_flags = 0,
|
||||
.user_data = 0,
|
||||
.buf_index = 0,
|
||||
.personality = 0,
|
||||
.splice_fd_in = 0,
|
||||
.addr3 = 0,
|
||||
.resv = 0,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn prep_fsync(sqe: *linux.io_uring_sqe, fd: linux.fd_t, flags: u32) void {
|
||||
sqe.* = .{
|
||||
.opcode = .FSYNC,
|
||||
.flags = 0,
|
||||
.ioprio = 0,
|
||||
.fd = fd,
|
||||
.off = 0,
|
||||
.addr = 0,
|
||||
.len = 0,
|
||||
.rw_flags = flags,
|
||||
.user_data = 0,
|
||||
.buf_index = 0,
|
||||
.personality = 0,
|
||||
.splice_fd_in = 0,
|
||||
.addr3 = 0,
|
||||
.resv = 0,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn prep_rw(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
op: linux.IORING_OP,
|
||||
fd: linux.fd_t,
|
||||
addr: u64,
|
||||
len: usize,
|
||||
offset: u64,
|
||||
) void {
|
||||
sqe.* = .{
|
||||
.opcode = op,
|
||||
.flags = 0,
|
||||
.ioprio = 0,
|
||||
.fd = fd,
|
||||
.off = offset,
|
||||
.addr = addr,
|
||||
.len = @intCast(len),
|
||||
.rw_flags = 0,
|
||||
.user_data = 0,
|
||||
.buf_index = 0,
|
||||
.personality = 0,
|
||||
.splice_fd_in = 0,
|
||||
.addr3 = 0,
|
||||
.resv = 0,
|
||||
};
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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.addr = off_in;
|
||||
sqe.splice_fd_in = fd_in;
|
||||
}
|
||||
|
||||
pub fn prep_readv(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: linux.fd_t,
|
||||
iovecs: []const std.posix.iovec,
|
||||
offset: u64,
|
||||
) void {
|
||||
sqe.prep_rw(.READV, fd, @intFromPtr(iovecs.ptr), iovecs.len, offset);
|
||||
}
|
||||
|
||||
pub fn prep_writev(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: linux.fd_t,
|
||||
iovecs: []const std.posix.iovec_const,
|
||||
offset: u64,
|
||||
) void {
|
||||
sqe.prep_rw(.WRITEV, fd, @intFromPtr(iovecs.ptr), iovecs.len, offset);
|
||||
}
|
||||
|
||||
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.base), buffer.len, offset);
|
||||
sqe.buf_index = buffer_index;
|
||||
}
|
||||
|
||||
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.base), buffer.len, offset);
|
||||
sqe.buf_index = buffer_index;
|
||||
}
|
||||
|
||||
pub fn prep_accept(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: linux.fd_t,
|
||||
addr: ?*linux.sockaddr,
|
||||
addrlen: ?*linux.socklen_t,
|
||||
flags: u32,
|
||||
) void {
|
||||
// `addr` holds a pointer to `sockaddr`, and `addr2` holds a pointer to socklen_t`.
|
||||
// `addr2` maps to `sqe.off` (u64) instead of `sqe.len` (which is only a u32).
|
||||
sqe.prep_rw(.ACCEPT, fd, @intFromPtr(addr), 0, @intFromPtr(addrlen));
|
||||
sqe.rw_flags = flags;
|
||||
}
|
||||
|
||||
pub fn prep_accept_direct(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: linux.fd_t,
|
||||
addr: ?*linux.sockaddr,
|
||||
addrlen: ?*linux.socklen_t,
|
||||
flags: u32,
|
||||
file_index: u32,
|
||||
) void {
|
||||
prep_accept(sqe, fd, addr, addrlen, flags);
|
||||
__io_uring_set_target_fixed_file(sqe, file_index);
|
||||
}
|
||||
|
||||
pub fn prep_multishot_accept_direct(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: linux.fd_t,
|
||||
addr: ?*linux.sockaddr,
|
||||
addrlen: ?*linux.socklen_t,
|
||||
flags: u32,
|
||||
) void {
|
||||
prep_multishot_accept(sqe, fd, addr, addrlen, flags);
|
||||
__io_uring_set_target_fixed_file(sqe, linux.IORING_FILE_INDEX_ALLOC);
|
||||
}
|
||||
|
||||
fn __io_uring_set_target_fixed_file(sqe: *linux.io_uring_sqe, file_index: u32) void {
|
||||
const sqe_file_index: u32 = if (file_index == linux.IORING_FILE_INDEX_ALLOC)
|
||||
linux.IORING_FILE_INDEX_ALLOC
|
||||
else
|
||||
// 0 means no fixed files, indexes should be encoded as "index + 1"
|
||||
file_index + 1;
|
||||
// This filed is overloaded in liburing:
|
||||
// splice_fd_in: i32
|
||||
// sqe_file_index: u32
|
||||
sqe.splice_fd_in = @bitCast(sqe_file_index);
|
||||
}
|
||||
|
||||
pub fn prep_connect(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: linux.fd_t,
|
||||
addr: *const linux.sockaddr,
|
||||
addrlen: linux.socklen_t,
|
||||
) void {
|
||||
// `addrlen` maps to `sqe.off` (u64) instead of `sqe.len` (which is only a u32).
|
||||
sqe.prep_rw(.CONNECT, fd, @intFromPtr(addr), 0, addrlen);
|
||||
}
|
||||
|
||||
pub fn prep_epoll_ctl(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
epfd: linux.fd_t,
|
||||
fd: linux.fd_t,
|
||||
op: u32,
|
||||
ev: ?*linux.epoll_event,
|
||||
) void {
|
||||
sqe.prep_rw(.EPOLL_CTL, epfd, @intFromPtr(ev), op, @intCast(fd));
|
||||
}
|
||||
|
||||
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.rw_flags = flags;
|
||||
}
|
||||
|
||||
pub fn prep_recv_multishot(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: linux.fd_t,
|
||||
buffer: []u8,
|
||||
flags: u32,
|
||||
) void {
|
||||
sqe.prep_recv(fd, buffer, flags);
|
||||
sqe.ioprio |= linux.IORING_RECV_MULTISHOT;
|
||||
}
|
||||
|
||||
pub fn prep_recvmsg(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: linux.fd_t,
|
||||
msg: *linux.msghdr,
|
||||
flags: u32,
|
||||
) void {
|
||||
sqe.prep_rw(.RECVMSG, fd, @intFromPtr(msg), 1, 0);
|
||||
sqe.rw_flags = flags;
|
||||
}
|
||||
|
||||
pub fn prep_recvmsg_multishot(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: linux.fd_t,
|
||||
msg: *linux.msghdr,
|
||||
flags: u32,
|
||||
) void {
|
||||
sqe.prep_recvmsg(fd, msg, flags);
|
||||
sqe.ioprio |= linux.IORING_RECV_MULTISHOT;
|
||||
}
|
||||
|
||||
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.rw_flags = flags;
|
||||
}
|
||||
|
||||
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.rw_flags = flags;
|
||||
sqe.ioprio = zc_flags;
|
||||
}
|
||||
|
||||
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);
|
||||
sqe.ioprio |= linux.IORING_RECVSEND_FIXED_BUF;
|
||||
sqe.buf_index = buf_index;
|
||||
}
|
||||
|
||||
pub fn prep_sendmsg_zc(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: linux.fd_t,
|
||||
msg: *const linux.msghdr_const,
|
||||
flags: u32,
|
||||
) void {
|
||||
prep_sendmsg(sqe, fd, msg, flags);
|
||||
sqe.opcode = .SENDMSG_ZC;
|
||||
}
|
||||
|
||||
pub fn prep_sendmsg(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: linux.fd_t,
|
||||
msg: *const linux.msghdr_const,
|
||||
flags: u32,
|
||||
) void {
|
||||
sqe.prep_rw(.SENDMSG, fd, @intFromPtr(msg), 1, 0);
|
||||
sqe.rw_flags = flags;
|
||||
}
|
||||
|
||||
pub fn prep_openat(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: linux.fd_t,
|
||||
path: [*:0]const u8,
|
||||
flags: linux.O,
|
||||
mode: linux.mode_t,
|
||||
) void {
|
||||
sqe.prep_rw(.OPENAT, fd, @intFromPtr(path), mode, 0);
|
||||
sqe.rw_flags = @bitCast(flags);
|
||||
}
|
||||
|
||||
pub fn prep_openat_direct(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: linux.fd_t,
|
||||
path: [*:0]const u8,
|
||||
flags: linux.O,
|
||||
mode: linux.mode_t,
|
||||
file_index: u32,
|
||||
) void {
|
||||
prep_openat(sqe, fd, path, flags, mode);
|
||||
__io_uring_set_target_fixed_file(sqe, file_index);
|
||||
}
|
||||
|
||||
pub fn prep_close(sqe: *linux.io_uring_sqe, fd: linux.fd_t) void {
|
||||
sqe.* = .{
|
||||
.opcode = .CLOSE,
|
||||
.flags = 0,
|
||||
.ioprio = 0,
|
||||
.fd = fd,
|
||||
.off = 0,
|
||||
.addr = 0,
|
||||
.len = 0,
|
||||
.rw_flags = 0,
|
||||
.user_data = 0,
|
||||
.buf_index = 0,
|
||||
.personality = 0,
|
||||
.splice_fd_in = 0,
|
||||
.addr3 = 0,
|
||||
.resv = 0,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn prep_close_direct(sqe: *linux.io_uring_sqe, file_index: u32) void {
|
||||
prep_close(sqe, 0);
|
||||
__io_uring_set_target_fixed_file(sqe, file_index);
|
||||
}
|
||||
|
||||
pub fn prep_timeout(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
ts: *const linux.kernel_timespec,
|
||||
count: u32,
|
||||
flags: u32,
|
||||
) void {
|
||||
sqe.prep_rw(.TIMEOUT, -1, @intFromPtr(ts), 1, count);
|
||||
sqe.rw_flags = flags;
|
||||
}
|
||||
|
||||
pub fn prep_timeout_remove(sqe: *linux.io_uring_sqe, timeout_user_data: u64, flags: u32) void {
|
||||
sqe.* = .{
|
||||
.opcode = .TIMEOUT_REMOVE,
|
||||
.flags = 0,
|
||||
.ioprio = 0,
|
||||
.fd = -1,
|
||||
.off = 0,
|
||||
.addr = timeout_user_data,
|
||||
.len = 0,
|
||||
.rw_flags = flags,
|
||||
.user_data = 0,
|
||||
.buf_index = 0,
|
||||
.personality = 0,
|
||||
.splice_fd_in = 0,
|
||||
.addr3 = 0,
|
||||
.resv = 0,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn prep_link_timeout(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
ts: *const linux.kernel_timespec,
|
||||
flags: u32,
|
||||
) void {
|
||||
sqe.prep_rw(.LINK_TIMEOUT, -1, @intFromPtr(ts), 1, 0);
|
||||
sqe.rw_flags = flags;
|
||||
}
|
||||
|
||||
pub fn prep_poll_add(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: linux.fd_t,
|
||||
poll_mask: u32,
|
||||
) void {
|
||||
sqe.prep_rw(.POLL_ADD, fd, @intFromPtr(@as(?*anyopaque, null)), 0, 0);
|
||||
// Poll masks previously used to comprise of 16 bits in the flags union of
|
||||
// a SQE, but were then extended to comprise of 32 bits in order to make
|
||||
// room for additional option flags. To ensure that the correct bits of
|
||||
// poll masks are consistently and properly read across multiple kernel
|
||||
// versions, poll masks are enforced to be little-endian.
|
||||
// https://www.spinics.net/lists/io-uring/msg02848.html
|
||||
sqe.rw_flags = std.mem.nativeToLittle(u32, poll_mask);
|
||||
}
|
||||
|
||||
pub fn prep_poll_remove(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
target_user_data: u64,
|
||||
) void {
|
||||
sqe.prep_rw(.POLL_REMOVE, -1, target_user_data, 0, 0);
|
||||
}
|
||||
|
||||
pub fn prep_poll_update(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
old_user_data: u64,
|
||||
new_user_data: u64,
|
||||
poll_mask: u32,
|
||||
flags: u32,
|
||||
) void {
|
||||
sqe.prep_rw(.POLL_REMOVE, -1, old_user_data, flags, new_user_data);
|
||||
// Poll masks previously used to comprise of 16 bits in the flags union of
|
||||
// a SQE, but were then extended to comprise of 32 bits in order to make
|
||||
// room for additional option flags. To ensure that the correct bits of
|
||||
// poll masks are consistently and properly read across multiple kernel
|
||||
// versions, poll masks are enforced to be little-endian.
|
||||
// https://www.spinics.net/lists/io-uring/msg02848.html
|
||||
sqe.rw_flags = std.mem.nativeToLittle(u32, poll_mask);
|
||||
}
|
||||
|
||||
pub fn prep_fallocate(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: linux.fd_t,
|
||||
mode: i32,
|
||||
offset: u64,
|
||||
len: u64,
|
||||
) void {
|
||||
sqe.* = .{
|
||||
.opcode = .FALLOCATE,
|
||||
.flags = 0,
|
||||
.ioprio = 0,
|
||||
.fd = fd,
|
||||
.off = offset,
|
||||
.addr = len,
|
||||
.len = @intCast(mode),
|
||||
.rw_flags = 0,
|
||||
.user_data = 0,
|
||||
.buf_index = 0,
|
||||
.personality = 0,
|
||||
.splice_fd_in = 0,
|
||||
.addr3 = 0,
|
||||
.resv = 0,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn prep_statx(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: linux.fd_t,
|
||||
path: [*:0]const u8,
|
||||
flags: u32,
|
||||
mask: u32,
|
||||
buf: *linux.Statx,
|
||||
) void {
|
||||
sqe.prep_rw(.STATX, fd, @intFromPtr(path), mask, @intFromPtr(buf));
|
||||
sqe.rw_flags = flags;
|
||||
}
|
||||
|
||||
pub fn prep_cancel(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
cancel_user_data: u64,
|
||||
flags: u32,
|
||||
) void {
|
||||
sqe.prep_rw(.ASYNC_CANCEL, -1, cancel_user_data, 0, 0);
|
||||
sqe.rw_flags = flags;
|
||||
}
|
||||
|
||||
pub fn prep_cancel_fd(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: linux.fd_t,
|
||||
flags: u32,
|
||||
) void {
|
||||
sqe.prep_rw(.ASYNC_CANCEL, fd, 0, 0, 0);
|
||||
sqe.rw_flags = flags | linux.IORING_ASYNC_CANCEL_FD;
|
||||
}
|
||||
|
||||
pub fn prep_shutdown(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
sockfd: linux.socket_t,
|
||||
how: u32,
|
||||
) void {
|
||||
sqe.prep_rw(.SHUTDOWN, sockfd, 0, how, 0);
|
||||
}
|
||||
|
||||
pub fn prep_renameat(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
old_dir_fd: linux.fd_t,
|
||||
old_path: [*:0]const u8,
|
||||
new_dir_fd: linux.fd_t,
|
||||
new_path: [*:0]const u8,
|
||||
flags: u32,
|
||||
) void {
|
||||
sqe.prep_rw(
|
||||
.RENAMEAT,
|
||||
old_dir_fd,
|
||||
@intFromPtr(old_path),
|
||||
0,
|
||||
@intFromPtr(new_path),
|
||||
);
|
||||
sqe.len = @bitCast(new_dir_fd);
|
||||
sqe.rw_flags = flags;
|
||||
}
|
||||
|
||||
pub fn prep_unlinkat(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
dir_fd: linux.fd_t,
|
||||
path: [*:0]const u8,
|
||||
flags: u32,
|
||||
) void {
|
||||
sqe.prep_rw(.UNLINKAT, dir_fd, @intFromPtr(path), 0, 0);
|
||||
sqe.rw_flags = flags;
|
||||
}
|
||||
|
||||
pub fn prep_mkdirat(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
dir_fd: linux.fd_t,
|
||||
path: [*:0]const u8,
|
||||
mode: linux.mode_t,
|
||||
) void {
|
||||
sqe.prep_rw(.MKDIRAT, dir_fd, @intFromPtr(path), mode, 0);
|
||||
}
|
||||
|
||||
pub fn prep_symlinkat(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
target: [*:0]const u8,
|
||||
new_dir_fd: linux.fd_t,
|
||||
link_path: [*:0]const u8,
|
||||
) void {
|
||||
sqe.prep_rw(
|
||||
.SYMLINKAT,
|
||||
new_dir_fd,
|
||||
@intFromPtr(target),
|
||||
0,
|
||||
@intFromPtr(link_path),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn prep_linkat(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
old_dir_fd: linux.fd_t,
|
||||
old_path: [*:0]const u8,
|
||||
new_dir_fd: linux.fd_t,
|
||||
new_path: [*:0]const u8,
|
||||
flags: u32,
|
||||
) void {
|
||||
sqe.prep_rw(
|
||||
.LINKAT,
|
||||
old_dir_fd,
|
||||
@intFromPtr(old_path),
|
||||
0,
|
||||
@intFromPtr(new_path),
|
||||
);
|
||||
sqe.len = @bitCast(new_dir_fd);
|
||||
sqe.rw_flags = flags;
|
||||
}
|
||||
|
||||
pub fn prep_files_update(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fds: []const linux.fd_t,
|
||||
offset: u32,
|
||||
) void {
|
||||
sqe.prep_rw(.FILES_UPDATE, -1, @intFromPtr(fds.ptr), fds.len, @intCast(offset));
|
||||
}
|
||||
|
||||
pub fn prep_files_update_alloc(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fds: []linux.fd_t,
|
||||
) void {
|
||||
sqe.prep_rw(.FILES_UPDATE, -1, @intFromPtr(fds.ptr), fds.len, linux.IORING_FILE_INDEX_ALLOC);
|
||||
}
|
||||
|
||||
pub fn prep_provide_buffers(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
buffers: [*]u8,
|
||||
buffer_len: usize,
|
||||
num: usize,
|
||||
group_id: usize,
|
||||
buffer_id: usize,
|
||||
) void {
|
||||
const ptr = @intFromPtr(buffers);
|
||||
sqe.prep_rw(.PROVIDE_BUFFERS, @intCast(num), ptr, buffer_len, buffer_id);
|
||||
sqe.buf_index = @intCast(group_id);
|
||||
}
|
||||
|
||||
pub fn prep_remove_buffers(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
num: usize,
|
||||
group_id: usize,
|
||||
) void {
|
||||
sqe.prep_rw(.REMOVE_BUFFERS, @intCast(num), 0, 0, 0);
|
||||
sqe.buf_index = @intCast(group_id);
|
||||
}
|
||||
|
||||
pub fn prep_multishot_accept(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: linux.fd_t,
|
||||
addr: ?*linux.sockaddr,
|
||||
addrlen: ?*linux.socklen_t,
|
||||
flags: u32,
|
||||
) void {
|
||||
prep_accept(sqe, fd, addr, addrlen, flags);
|
||||
sqe.ioprio |= linux.IORING_ACCEPT_MULTISHOT;
|
||||
}
|
||||
|
||||
pub fn prep_socket(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
domain: u32,
|
||||
socket_type: u32,
|
||||
protocol: u32,
|
||||
flags: u32,
|
||||
) void {
|
||||
sqe.prep_rw(.SOCKET, @intCast(domain), 0, protocol, socket_type);
|
||||
sqe.rw_flags = flags;
|
||||
}
|
||||
|
||||
pub fn prep_socket_direct(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
domain: u32,
|
||||
socket_type: u32,
|
||||
protocol: u32,
|
||||
flags: u32,
|
||||
file_index: u32,
|
||||
) void {
|
||||
prep_socket(sqe, domain, socket_type, protocol, flags);
|
||||
__io_uring_set_target_fixed_file(sqe, file_index);
|
||||
}
|
||||
|
||||
pub fn prep_socket_direct_alloc(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
domain: u32,
|
||||
socket_type: u32,
|
||||
protocol: u32,
|
||||
flags: u32,
|
||||
) void {
|
||||
prep_socket(sqe, domain, socket_type, protocol, flags);
|
||||
__io_uring_set_target_fixed_file(sqe, linux.IORING_FILE_INDEX_ALLOC);
|
||||
}
|
||||
|
||||
pub fn prep_waitid(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
id_type: linux.P,
|
||||
id: i32,
|
||||
infop: *linux.siginfo_t,
|
||||
options: u32,
|
||||
flags: u32,
|
||||
) void {
|
||||
sqe.prep_rw(.WAITID, id, 0, @intFromEnum(id_type), @intFromPtr(infop));
|
||||
sqe.rw_flags = flags;
|
||||
sqe.splice_fd_in = @bitCast(options);
|
||||
}
|
||||
|
||||
pub fn prep_bind(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: linux.fd_t,
|
||||
addr: *const linux.sockaddr,
|
||||
addrlen: linux.socklen_t,
|
||||
flags: u32,
|
||||
) void {
|
||||
sqe.prep_rw(.BIND, fd, @intFromPtr(addr), 0, addrlen);
|
||||
sqe.rw_flags = flags;
|
||||
}
|
||||
|
||||
pub fn prep_listen(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: linux.fd_t,
|
||||
backlog: usize,
|
||||
flags: u32,
|
||||
) void {
|
||||
sqe.prep_rw(.LISTEN, fd, 0, backlog, 0);
|
||||
sqe.rw_flags = flags;
|
||||
}
|
||||
|
||||
pub fn prep_cmd_sock(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
cmd_op: linux.IO_URING_SOCKET_OP,
|
||||
fd: linux.fd_t,
|
||||
level: u32,
|
||||
optname: u32,
|
||||
optval: u64,
|
||||
optlen: u32,
|
||||
) void {
|
||||
sqe.prep_rw(.URING_CMD, fd, 0, 0, 0);
|
||||
// off is overloaded with cmd_op, https://github.com/axboe/liburing/blob/e1003e496e66f9b0ae06674869795edf772d5500/src/include/liburing/io_uring.h#L39
|
||||
sqe.off = @intFromEnum(cmd_op);
|
||||
// addr is overloaded, https://github.com/axboe/liburing/blob/e1003e496e66f9b0ae06674869795edf772d5500/src/include/liburing/io_uring.h#L46
|
||||
sqe.addr = @bitCast(packed struct {
|
||||
level: u32,
|
||||
optname: u32,
|
||||
}{
|
||||
.level = level,
|
||||
.optname = optname,
|
||||
});
|
||||
// splice_fd_in if overloaded u32 -> i32
|
||||
sqe.splice_fd_in = @bitCast(optlen);
|
||||
// addr3 is overloaded, https://github.com/axboe/liburing/blob/e1003e496e66f9b0ae06674869795edf772d5500/src/include/liburing/io_uring.h#L102
|
||||
sqe.addr3 = optval;
|
||||
}
|
||||
|
||||
pub fn set_flags(sqe: *linux.io_uring_sqe, flags: u8) void {
|
||||
sqe.flags |= flags;
|
||||
}
|
||||
|
||||
/// This SQE forms a link with the next SQE in the submission ring. Next SQE
|
||||
/// will not be started before this one completes. Forms a chain of SQEs.
|
||||
pub fn link_next(sqe: *linux.io_uring_sqe) void {
|
||||
sqe.flags |= linux.IOSQE_IO_LINK;
|
||||
}
|
||||
};
|
||||
|
|
@ -45,34 +45,33 @@ test "timer" {
|
|||
var err: linux.E = linux.errno(epoll_fd);
|
||||
try expect(err == .SUCCESS);
|
||||
|
||||
const timer_fd = linux.timerfd_create(linux.TIMERFD_CLOCK.MONOTONIC, .{});
|
||||
const timer_fd = linux.timerfd_create(.MONOTONIC, .{});
|
||||
try expect(linux.errno(timer_fd) == .SUCCESS);
|
||||
|
||||
const time_interval = linux.timespec{
|
||||
const time_interval: linux.timespec = .{
|
||||
.sec = 0,
|
||||
.nsec = 2000000,
|
||||
};
|
||||
|
||||
const new_time = linux.itimerspec{
|
||||
const new_time: linux.itimerspec = .{
|
||||
.it_interval = time_interval,
|
||||
.it_value = time_interval,
|
||||
};
|
||||
|
||||
err = linux.errno(linux.timerfd_settime(@as(i32, @intCast(timer_fd)), .{}, &new_time, null));
|
||||
err = linux.errno(linux.timerfd_settime(@intCast(timer_fd), .{}, &new_time, null));
|
||||
try expect(err == .SUCCESS);
|
||||
|
||||
var event = linux.epoll_event{
|
||||
var event: linux.epoll_event = .{
|
||||
.events = linux.EPOLL.IN | linux.EPOLL.OUT | linux.EPOLL.ET,
|
||||
.data = linux.epoll_data{ .ptr = 0 },
|
||||
.data = .{ .ptr = 0 },
|
||||
};
|
||||
|
||||
err = linux.errno(linux.epoll_ctl(@as(i32, @intCast(epoll_fd)), linux.EPOLL.CTL_ADD, @as(i32, @intCast(timer_fd)), &event));
|
||||
err = linux.errno(linux.epoll_ctl(@intCast(epoll_fd), .ctl_add, @intCast(timer_fd), &event));
|
||||
try expect(err == .SUCCESS);
|
||||
|
||||
const events_one: linux.epoll_event = undefined;
|
||||
var events = [_]linux.epoll_event{events_one} ** 8;
|
||||
var events: [8]linux.epoll_event = @splat(undefined);
|
||||
|
||||
err = linux.errno(linux.epoll_wait(@as(i32, @intCast(epoll_fd)), &events, 8, -1));
|
||||
err = linux.errno(linux.epoll_wait(@intCast(epoll_fd), &events, 8, -1));
|
||||
try expect(err == .SUCCESS);
|
||||
}
|
||||
|
||||
|
|
@ -85,7 +84,7 @@ test "statx" {
|
|||
defer file.close();
|
||||
|
||||
var statx_buf: linux.Statx = undefined;
|
||||
switch (linux.errno(linux.statx(file.handle, "", linux.AT.EMPTY_PATH, linux.STATX_BASIC_STATS, &statx_buf))) {
|
||||
switch (linux.errno(linux.statx(file.handle, "", .{ .empty_path = true }, linux.Statx.Mask.basic_stats, &statx_buf))) {
|
||||
.SUCCESS => {},
|
||||
else => unreachable,
|
||||
}
|
||||
|
|
@ -93,17 +92,17 @@ test "statx" {
|
|||
if (builtin.cpu.arch == .riscv32 or builtin.cpu.arch.isLoongArch()) return error.SkipZigTest; // No fstatat, so the rest of the test is meaningless.
|
||||
|
||||
var stat_buf: linux.Stat = undefined;
|
||||
switch (linux.errno(linux.fstatat(file.handle, "", &stat_buf, linux.AT.EMPTY_PATH))) {
|
||||
switch (linux.errno(linux.fstatat(file.handle, "", &stat_buf, .{ .empty_path = true }))) {
|
||||
.SUCCESS => {},
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
try expect(stat_buf.mode == statx_buf.mode);
|
||||
try expect(@as(u32, @bitCast(stat_buf.uid)) == statx_buf.uid);
|
||||
try expect(@as(u32, @bitCast(stat_buf.gid)) == statx_buf.gid);
|
||||
try expect(@as(u64, @bitCast(@as(i64, stat_buf.size))) == statx_buf.size);
|
||||
try expect(@as(u64, @bitCast(@as(i64, stat_buf.blksize))) == statx_buf.blksize);
|
||||
try expect(@as(u64, @bitCast(@as(i64, stat_buf.blocks))) == statx_buf.blocks);
|
||||
try expect(stat_buf.uid == statx_buf.uid);
|
||||
try expect(stat_buf.gid == statx_buf.gid);
|
||||
try expect(stat_buf.size == statx_buf.size);
|
||||
try expect(stat_buf.blksize == statx_buf.blksize);
|
||||
try expect(stat_buf.blocks == statx_buf.blocks);
|
||||
}
|
||||
|
||||
test "user and group ids" {
|
||||
|
|
@ -190,39 +189,39 @@ comptime {
|
|||
assert(256 == @as(u32, @bitCast(linux.FUTEX_OP{ .cmd = @enumFromInt(0), .private = false, .realtime = true })));
|
||||
|
||||
// Check futex_param4 union is packed correctly
|
||||
const param_union = linux.futex_param4{
|
||||
const param_union: linux.futex_param4 = .{
|
||||
.val2 = 0xaabbcc,
|
||||
};
|
||||
assert(@intFromPtr(param_union.timeout) == 0xaabbcc);
|
||||
}
|
||||
|
||||
test "futex v1" {
|
||||
var lock: std.atomic.Value(u32) = std.atomic.Value(u32).init(1);
|
||||
var lock: std.atomic.Value(u32) = .init(1);
|
||||
var rc: usize = 0;
|
||||
|
||||
// No-op wait, lock value is not expected value
|
||||
rc = linux.futex(&lock.raw, .{ .cmd = .WAIT, .private = true }, 2, .{ .timeout = null }, null, 0);
|
||||
rc = linux.futex(&lock, .{ .cmd = .WAIT, .private = true }, 2, .{ .timeout = null }, null, 0);
|
||||
try expectEqual(.AGAIN, linux.errno(rc));
|
||||
|
||||
rc = linux.futex_4arg(&lock.raw, .{ .cmd = .WAIT, .private = true }, 2, null);
|
||||
rc = linux.futex_4arg(&lock, .{ .cmd = .WAIT, .private = true }, 2, null);
|
||||
try expectEqual(.AGAIN, linux.errno(rc));
|
||||
|
||||
// Short-fuse wait, timeout kicks in
|
||||
rc = linux.futex(&lock.raw, .{ .cmd = .WAIT, .private = true }, 1, .{ .timeout = &.{ .sec = 0, .nsec = 2 } }, null, 0);
|
||||
rc = linux.futex(&lock, .{ .cmd = .WAIT, .private = true }, 1, .{ .timeout = &.{ .sec = 0, .nsec = 2 } }, null, 0);
|
||||
try expectEqual(.TIMEDOUT, linux.errno(rc));
|
||||
|
||||
rc = linux.futex_4arg(&lock.raw, .{ .cmd = .WAIT, .private = true }, 1, &.{ .sec = 0, .nsec = 2 });
|
||||
rc = linux.futex_4arg(&lock, .{ .cmd = .WAIT, .private = true }, 1, &.{ .sec = 0, .nsec = 2 });
|
||||
try expectEqual(.TIMEDOUT, linux.errno(rc));
|
||||
|
||||
// Wakeup (no waiters)
|
||||
rc = linux.futex(&lock.raw, .{ .cmd = .WAKE, .private = true }, 2, .{ .timeout = null }, null, 0);
|
||||
rc = linux.futex(&lock, .{ .cmd = .WAKE, .private = true }, 2, .{ .timeout = null }, null, 0);
|
||||
try expectEqual(0, rc);
|
||||
|
||||
rc = linux.futex_3arg(&lock.raw, .{ .cmd = .WAKE, .private = true }, 2);
|
||||
rc = linux.futex_3arg(&lock, .{ .cmd = .WAKE, .private = true }, 2);
|
||||
try expectEqual(0, rc);
|
||||
|
||||
// CMP_REQUEUE - val3 mismatch
|
||||
rc = linux.futex(&lock.raw, .{ .cmd = .CMP_REQUEUE, .private = true }, 2, .{ .val2 = 0 }, null, 99);
|
||||
rc = linux.futex(&lock, .{ .cmd = .CMP_REQUEUE, .private = true }, 2, .{ .val2 = 0 }, null, 99);
|
||||
try expectEqual(.AGAIN, linux.errno(rc));
|
||||
|
||||
// CMP_REQUEUE - requeue (but no waiters, so ... not much)
|
||||
|
|
@ -230,14 +229,14 @@ test "futex v1" {
|
|||
const val3 = 1;
|
||||
const wake_nr = 3;
|
||||
const requeue_max = std.math.maxInt(u31);
|
||||
var target_lock: std.atomic.Value(u32) = std.atomic.Value(u32).init(1);
|
||||
rc = linux.futex(&lock.raw, .{ .cmd = .CMP_REQUEUE, .private = true }, wake_nr, .{ .val2 = requeue_max }, &target_lock.raw, val3);
|
||||
const target_lock: std.atomic.Value(u32) = .init(1);
|
||||
rc = linux.futex(&lock, .{ .cmd = .CMP_REQUEUE, .private = true }, wake_nr, .{ .val2 = requeue_max }, &target_lock, val3);
|
||||
try expectEqual(0, rc);
|
||||
}
|
||||
|
||||
// WAKE_OP - just to see if we can construct the arguments ...
|
||||
{
|
||||
var lock2: std.atomic.Value(u32) = std.atomic.Value(u32).init(1);
|
||||
const lock2: std.atomic.Value(u32) = .init(1);
|
||||
const wake1_nr = 2;
|
||||
const wake2_nr = 3;
|
||||
const wake_op = linux.FUTEX_WAKE_OP{
|
||||
|
|
@ -248,65 +247,66 @@ test "futex v1" {
|
|||
.cmdarg = 5,
|
||||
};
|
||||
|
||||
rc = linux.futex(&lock.raw, .{ .cmd = .WAKE_OP, .private = true }, wake1_nr, .{ .val2 = wake2_nr }, &lock2.raw, @bitCast(wake_op));
|
||||
rc = linux.futex(&lock, .{ .cmd = .WAKE_OP, .private = true }, wake1_nr, .{ .val2 = wake2_nr }, &lock2, @bitCast(wake_op));
|
||||
try expectEqual(0, rc);
|
||||
}
|
||||
|
||||
// WAIT_BITSET
|
||||
{
|
||||
// val1 return early
|
||||
rc = linux.futex(&lock.raw, .{ .cmd = .WAIT_BITSET, .private = true }, 2, .{ .timeout = null }, null, 0xfff);
|
||||
rc = linux.futex(&lock, .{ .cmd = .WAIT_BITSET, .private = true }, 2, .{ .timeout = null }, null, 0xfff);
|
||||
try expectEqual(.AGAIN, linux.errno(rc));
|
||||
|
||||
// timeout wait
|
||||
const timeout: linux.timespec = .{ .sec = 0, .nsec = 2 };
|
||||
rc = linux.futex(&lock.raw, .{ .cmd = .WAIT_BITSET, .private = true }, 1, .{ .timeout = &timeout }, null, 0xfff);
|
||||
rc = linux.futex(&lock, .{ .cmd = .WAIT_BITSET, .private = true }, 1, .{ .timeout = &timeout }, null, 0xfff);
|
||||
try expectEqual(.TIMEDOUT, linux.errno(rc));
|
||||
}
|
||||
|
||||
// WAKE_BITSET
|
||||
{
|
||||
rc = linux.futex(&lock.raw, .{ .cmd = .WAKE_BITSET, .private = true }, 2, .{ .timeout = null }, null, 0xfff000);
|
||||
rc = linux.futex(&lock, .{ .cmd = .WAKE_BITSET, .private = true }, 2, .{ .timeout = null }, null, 0xfff000);
|
||||
try expectEqual(0, rc);
|
||||
|
||||
// bitmask must have at least 1 bit set:
|
||||
rc = linux.futex(&lock.raw, .{ .cmd = .WAKE_BITSET, .private = true }, 2, .{ .timeout = null }, null, 0);
|
||||
rc = linux.futex(&lock, .{ .cmd = .WAKE_BITSET, .private = true }, 2, .{ .timeout = null }, null, 0);
|
||||
try expectEqual(.INVAL, linux.errno(rc));
|
||||
}
|
||||
}
|
||||
|
||||
comptime {
|
||||
assert(2 == @as(u32, @bitCast(linux.FUTEX2_FLAGS{ .size = .U32, .private = false })));
|
||||
assert(128 == @as(u32, @bitCast(linux.FUTEX2_FLAGS{ .size = @enumFromInt(0), .private = true })));
|
||||
std.debug.assert(2 == @as(u32, @bitCast(linux.Futex2.Wait{ .size = .U32, .private = false })));
|
||||
std.debug.assert(128 == @as(u32, @bitCast(linux.Futex2.Wait{ .size = @enumFromInt(0), .private = true })));
|
||||
}
|
||||
|
||||
test "futex2_waitv" {
|
||||
const locks = [_]std.atomic.Value(u32){
|
||||
std.atomic.Value(u32).init(1),
|
||||
std.atomic.Value(u32).init(1),
|
||||
std.atomic.Value(u32).init(1),
|
||||
const locks: [3]std.atomic.Value(u32) = .{
|
||||
.init(1),
|
||||
.init(1),
|
||||
.init(1),
|
||||
};
|
||||
|
||||
const futexes = [_]linux.futex2_waitone{
|
||||
const futexes: [3]linux.Futex2.WaitOne = .{
|
||||
.{
|
||||
.val = 1,
|
||||
.uaddr = @intFromPtr(&locks[0].raw),
|
||||
.uaddr = @intFromPtr(&locks[0]),
|
||||
.flags = .{ .size = .U32, .private = true },
|
||||
},
|
||||
.{
|
||||
.val = 1,
|
||||
.uaddr = @intFromPtr(&locks[1].raw),
|
||||
.uaddr = @intFromPtr(&locks[1]),
|
||||
.flags = .{ .size = .U32, .private = true },
|
||||
},
|
||||
.{
|
||||
.val = 1,
|
||||
.uaddr = @intFromPtr(&locks[2].raw),
|
||||
.uaddr = @intFromPtr(&locks[2]),
|
||||
.flags = .{ .size = .U32, .private = true },
|
||||
},
|
||||
};
|
||||
|
||||
const timeout = linux.kernel_timespec{ .sec = 0, .nsec = 2 }; // absolute timeout, so this is 1970...
|
||||
const rc = linux.futex2_waitv(&futexes, futexes.len, .{}, &timeout, .MONOTONIC);
|
||||
// absolute timeout, so this is 1970...
|
||||
const timeout: linux.kernel_timespec = .{ .sec = 0, .nsec = 2 };
|
||||
const rc = linux.futex2_waitv(futexes[0..], .{}, &timeout, .MONOTONIC);
|
||||
switch (linux.errno(rc)) {
|
||||
.NOSYS => return error.SkipZigTest, // futex2_waitv added in kernel v5.16
|
||||
else => |err| try expectEqual(.TIMEDOUT, err),
|
||||
|
|
@ -316,40 +316,40 @@ test "futex2_waitv" {
|
|||
// Futex v2 API is only supported on recent kernels (v6.7), so skip tests if the syscalls
|
||||
// return ENOSYS.
|
||||
fn futex2_skip_if_unsupported() !void {
|
||||
const lock: u32 = 0;
|
||||
const rc = linux.futex2_wake(&lock, 0, 1, .{ .size = .U32, .private = true });
|
||||
const lock: std.atomic.Value(u32) = .init(0);
|
||||
const rc = linux.futex2_wake(&lock, .empty, 1, .{ .size = .U32, .private = true });
|
||||
if (linux.errno(rc) == .NOSYS) {
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
}
|
||||
|
||||
test "futex2_wait" {
|
||||
var lock: std.atomic.Value(u32) = std.atomic.Value(u32).init(1);
|
||||
const lock: std.atomic.Value(u32) = .init(1);
|
||||
var rc: usize = 0;
|
||||
const mask = 0x1;
|
||||
const mask: linux.Futex2.Bitset = .{ .waiter1 = true };
|
||||
|
||||
try futex2_skip_if_unsupported();
|
||||
|
||||
// The API for 8,16,64 bit futexes is defined, but as of kernel v6.14
|
||||
// (at least) they're not implemented.
|
||||
if (false) {
|
||||
rc = linux.futex2_wait(&lock.raw, 1, mask, .{ .size = .U8, .private = true }, null, .MONOTONIC);
|
||||
rc = linux.futex2_wait(&lock, 1, mask, .{ .size = .U8, .private = true }, null, .MONOTONIC);
|
||||
try expectEqual(.INVAL, linux.errno(rc));
|
||||
|
||||
rc = linux.futex2_wait(&lock.raw, 1, mask, .{ .size = .U16, .private = true }, null, .MONOTONIC);
|
||||
rc = linux.futex2_wait(&lock, 1, mask, .{ .size = .U16, .private = true }, null, .MONOTONIC);
|
||||
try expectEqual(.INVAL, linux.errno(rc));
|
||||
|
||||
rc = linux.futex2_wait(&lock.raw, 1, mask, .{ .size = .U64, .private = true }, null, .MONOTONIC);
|
||||
rc = linux.futex2_wait(&lock, 1, mask, .{ .size = .U64, .private = true }, null, .MONOTONIC);
|
||||
try expectEqual(.INVAL, linux.errno(rc));
|
||||
}
|
||||
|
||||
const flags = linux.FUTEX2_FLAGS{ .size = .U32, .private = true };
|
||||
const flags: linux.Futex2.Wait = .{ .size = .U32, .private = true };
|
||||
// no-wait, lock state mismatch
|
||||
rc = linux.futex2_wait(&lock.raw, 2, mask, flags, null, .MONOTONIC);
|
||||
rc = linux.futex2_wait(&lock, 2, mask, flags, null, .MONOTONIC);
|
||||
try expectEqual(.AGAIN, linux.errno(rc));
|
||||
|
||||
// hit timeout on wait
|
||||
rc = linux.futex2_wait(&lock.raw, 1, mask, flags, &.{ .sec = 0, .nsec = 2 }, .MONOTONIC);
|
||||
rc = linux.futex2_wait(&lock, 1, mask, flags, &.{ .sec = 0, .nsec = 2 }, .MONOTONIC);
|
||||
try expectEqual(.TIMEDOUT, linux.errno(rc));
|
||||
|
||||
// timeout is absolute
|
||||
|
|
@ -363,40 +363,40 @@ test "futex2_wait" {
|
|||
.sec = curr.sec,
|
||||
.nsec = curr.nsec + 2,
|
||||
};
|
||||
rc = linux.futex2_wait(&lock.raw, 1, mask, flags, &timeout, .MONOTONIC);
|
||||
rc = linux.futex2_wait(&lock, 1, mask, flags, &timeout, .MONOTONIC);
|
||||
try expectEqual(.TIMEDOUT, linux.errno(rc));
|
||||
}
|
||||
|
||||
rc = linux.futex2_wait(&lock.raw, 1, mask, flags, &.{ .sec = 0, .nsec = 2 }, .REALTIME);
|
||||
rc = linux.futex2_wait(&lock, 1, mask, flags, &.{ .sec = 0, .nsec = 2 }, .REALTIME);
|
||||
try expectEqual(.TIMEDOUT, linux.errno(rc));
|
||||
}
|
||||
|
||||
test "futex2_wake" {
|
||||
var lock: std.atomic.Value(u32) = std.atomic.Value(u32).init(1);
|
||||
const lock: std.atomic.Value(u32) = .init(1);
|
||||
|
||||
try futex2_skip_if_unsupported();
|
||||
|
||||
const rc = linux.futex2_wake(&lock.raw, 0xFF, 1, .{ .size = .U32, .private = true });
|
||||
const rc = linux.futex2_wake(&lock, .fromInt(0xFF), 1, .{ .size = .U32, .private = true });
|
||||
try expectEqual(0, rc);
|
||||
}
|
||||
|
||||
test "futex2_requeue" {
|
||||
try futex2_skip_if_unsupported();
|
||||
|
||||
const locks = [_]std.atomic.Value(u32){
|
||||
std.atomic.Value(u32).init(1),
|
||||
std.atomic.Value(u32).init(1),
|
||||
const locks: [2]std.atomic.Value(u32) = .{
|
||||
.init(1),
|
||||
.init(1),
|
||||
};
|
||||
|
||||
const futexes = [_]linux.futex2_waitone{
|
||||
const futexes: [2]linux.Futex2.WaitOne = .{
|
||||
.{
|
||||
.val = 1,
|
||||
.uaddr = @intFromPtr(&locks[0].raw),
|
||||
.uaddr = @intFromPtr(&locks[0]),
|
||||
.flags = .{ .size = .U32, .private = true },
|
||||
},
|
||||
.{
|
||||
.val = 1,
|
||||
.uaddr = @intFromPtr(&locks[1].raw),
|
||||
.uaddr = @intFromPtr(&locks[1]),
|
||||
.flags = .{ .size = .U32, .private = true },
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -63,7 +63,9 @@ pub const AF = system.AF;
|
|||
pub const AF_SUN = system.AF_SUN;
|
||||
pub const AI = system.AI;
|
||||
pub const ARCH = system.ARCH;
|
||||
pub const AT = system.AT;
|
||||
/// DEPRECATED: use `At`
|
||||
pub const AT = At;
|
||||
pub const At = system.At;
|
||||
pub const AT_SUN = system.AT_SUN;
|
||||
pub const CLOCK = system.CLOCK;
|
||||
pub const CPU_COUNT = system.CPU_COUNT;
|
||||
|
|
@ -480,7 +482,7 @@ fn fchmodat2(dirfd: fd_t, path: []const u8, mode: mode_t, flags: u32) FChmodAtEr
|
|||
}
|
||||
defer close(pathfd);
|
||||
|
||||
const stat = fstatatZ(pathfd, "", AT.EMPTY_PATH) catch |err| switch (err) {
|
||||
const stat = fstatatZ(pathfd, "", .{ .empty_path = true }) catch |err| switch (err) {
|
||||
error.NameTooLong => unreachable,
|
||||
error.FileNotFound => unreachable,
|
||||
error.Streaming => unreachable,
|
||||
|
|
@ -1553,7 +1555,7 @@ pub fn open(file_path: []const u8, flags: O, perm: mode_t) OpenError!fd_t {
|
|||
if (native_os == .windows) {
|
||||
@compileError("Windows does not support POSIX; use Windows-specific API or cross-platform std.fs API");
|
||||
} else if (native_os == .wasi and !builtin.link_libc) {
|
||||
return openat(AT.FDCWD, file_path, flags, perm);
|
||||
return openat(At.fdcwd, file_path, flags, perm);
|
||||
}
|
||||
const file_path_c = try toPosixPath(file_path);
|
||||
return openZ(&file_path_c, flags, perm);
|
||||
|
|
@ -1943,7 +1945,7 @@ pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!
|
|||
if (native_os == .windows) {
|
||||
@compileError("symlink is not supported on Windows; use std.os.windows.CreateSymbolicLink instead");
|
||||
} else if (native_os == .wasi and !builtin.link_libc) {
|
||||
return symlinkat(target_path, AT.FDCWD, sym_link_path);
|
||||
return symlinkat(target_path, At.fdcwd, sym_link_path);
|
||||
}
|
||||
const target_path_c = try toPosixPath(target_path);
|
||||
const sym_link_path_c = try toPosixPath(sym_link_path);
|
||||
|
|
@ -2103,7 +2105,7 @@ pub fn linkZ(oldpath: [*:0]const u8, newpath: [*:0]const u8) LinkError!void {
|
|||
/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
|
||||
pub fn link(oldpath: []const u8, newpath: []const u8) LinkError!void {
|
||||
if (native_os == .wasi and !builtin.link_libc) {
|
||||
return linkat(AT.FDCWD, oldpath, AT.FDCWD, newpath, 0) catch |err| switch (err) {
|
||||
return linkat(At.fdcwd, oldpath, At.fdcwd, newpath, 0) catch |err| switch (err) {
|
||||
error.NotDir => unreachable, // link() does not support directories
|
||||
else => |e| return e,
|
||||
};
|
||||
|
|
@ -2163,7 +2165,7 @@ pub fn linkat(
|
|||
const old: RelativePathWasi = .{ .dir_fd = olddir, .relative_path = oldpath };
|
||||
const new: RelativePathWasi = .{ .dir_fd = newdir, .relative_path = newpath };
|
||||
const old_flags: wasi.lookupflags_t = .{
|
||||
.SYMLINK_FOLLOW = (flags & AT.SYMLINK_FOLLOW) != 0,
|
||||
.SYMLINK_FOLLOW = (flags & At.SYMLINK_FOLLOW) != 0,
|
||||
};
|
||||
switch (wasi.path_link(
|
||||
old.dir_fd,
|
||||
|
|
@ -2234,7 +2236,7 @@ pub const UnlinkError = error{
|
|||
/// See also `unlinkZ`.
|
||||
pub fn unlink(file_path: []const u8) UnlinkError!void {
|
||||
if (native_os == .wasi and !builtin.link_libc) {
|
||||
return unlinkat(AT.FDCWD, file_path, 0) catch |err| switch (err) {
|
||||
return unlinkat(At.fdcwd, file_path, 0) catch |err| switch (err) {
|
||||
error.DirNotEmpty => unreachable, // only occurs when targeting directories
|
||||
else => |e| return e,
|
||||
};
|
||||
|
|
@ -2308,7 +2310,7 @@ pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!vo
|
|||
/// WASI-only. Same as `unlinkat` but targeting WASI.
|
||||
/// See also `unlinkat`.
|
||||
pub fn unlinkatWasi(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!void {
|
||||
const remove_dir = (flags & AT.REMOVEDIR) != 0;
|
||||
const remove_dir = (flags & At.REMOVEDIR) != 0;
|
||||
const res = if (remove_dir)
|
||||
wasi.path_remove_directory(dirfd, file_path.ptr, file_path.len)
|
||||
else
|
||||
|
|
@ -2373,7 +2375,7 @@ pub fn unlinkatZ(dirfd: fd_t, file_path_c: [*:0]const u8, flags: u32) UnlinkatEr
|
|||
|
||||
/// Same as `unlinkat` but `sub_path_w` is WTF16LE, NT prefixed. Windows only.
|
||||
pub fn unlinkatW(dirfd: fd_t, sub_path_w: []const u16, flags: u32) UnlinkatError!void {
|
||||
const remove_dir = (flags & AT.REMOVEDIR) != 0;
|
||||
const remove_dir = (flags & At.REMOVEDIR) != 0;
|
||||
return windows.DeleteFile(sub_path_w, .{ .dir = dirfd, .remove_dir = remove_dir });
|
||||
}
|
||||
|
||||
|
|
@ -2421,7 +2423,7 @@ pub const RenameError = error{
|
|||
/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
|
||||
pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void {
|
||||
if (native_os == .wasi and !builtin.link_libc) {
|
||||
return renameat(AT.FDCWD, old_path, AT.FDCWD, new_path);
|
||||
return renameat(At.fdcwd, old_path, At.FDCWD, new_path);
|
||||
} else if (native_os == .windows) {
|
||||
const old_path_w = try windows.sliceToPrefixedFileW(null, old_path);
|
||||
const new_path_w = try windows.sliceToPrefixedFileW(null, new_path);
|
||||
|
|
@ -2644,7 +2646,7 @@ pub const MakeDirError = std.Io.Dir.MakeError;
|
|||
/// On other platforms, `dir_path` is an opaque sequence of bytes with no particular encoding.
|
||||
pub fn mkdir(dir_path: []const u8, mode: mode_t) MakeDirError!void {
|
||||
if (native_os == .wasi and !builtin.link_libc) {
|
||||
return mkdirat(AT.FDCWD, dir_path, mode);
|
||||
return mkdirat(At.fdcwd, dir_path, mode);
|
||||
} else if (native_os == .windows) {
|
||||
const dir_path_w = try windows.sliceToPrefixedFileW(null, dir_path);
|
||||
return mkdirW(dir_path_w.span(), mode);
|
||||
|
|
@ -2729,7 +2731,7 @@ pub const DeleteDirError = error{
|
|||
/// On other platforms, `dir_path` is an opaque sequence of bytes with no particular encoding.
|
||||
pub fn rmdir(dir_path: []const u8) DeleteDirError!void {
|
||||
if (native_os == .wasi and !builtin.link_libc) {
|
||||
return unlinkat(AT.FDCWD, dir_path, AT.REMOVEDIR) catch |err| switch (err) {
|
||||
return unlinkat(At.fdcwd, dir_path, At.REMOVEDIR) catch |err| switch (err) {
|
||||
error.FileSystem => unreachable, // only occurs when targeting files
|
||||
error.IsDir => unreachable, // only occurs when targeting files
|
||||
else => |e| return e,
|
||||
|
|
@ -2856,7 +2858,7 @@ pub const FchdirError = error{
|
|||
} || UnexpectedError;
|
||||
|
||||
pub fn fchdir(dirfd: fd_t) FchdirError!void {
|
||||
if (dirfd == AT.FDCWD) return;
|
||||
if (dirfd == At.fdcwd) return;
|
||||
while (true) {
|
||||
switch (errno(system.fchdir(dirfd))) {
|
||||
.SUCCESS => return,
|
||||
|
|
@ -2909,7 +2911,7 @@ pub const ReadLinkError = error{
|
|||
/// On other platforms, the result is an opaque sequence of bytes with no particular encoding.
|
||||
pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
|
||||
if (native_os == .wasi and !builtin.link_libc) {
|
||||
return readlinkat(AT.FDCWD, file_path, out_buffer);
|
||||
return readlinkat(At.fdcwd, file_path, out_buffer);
|
||||
} else if (native_os == .windows) {
|
||||
var file_path_w = try windows.sliceToPrefixedFileW(null, file_path);
|
||||
const result_w = try readlinkW(file_path_w.span(), &file_path_w.data);
|
||||
|
|
@ -3869,7 +3871,7 @@ pub const FStatAtError = FStatError || error{
|
|||
/// On WASI, `pathname` should be encoded as valid UTF-8.
|
||||
/// On other platforms, `pathname` is an opaque sequence of bytes with no particular encoding.
|
||||
/// See also `fstatatZ`.
|
||||
pub fn fstatat(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!Stat {
|
||||
pub fn fstatat(dirfd: fd_t, pathname: []const u8, flags: At) FStatAtError!Stat {
|
||||
if (native_os == .wasi and !builtin.link_libc) {
|
||||
@compileError("use std.Io instead");
|
||||
} else if (native_os == .windows) {
|
||||
|
|
@ -3882,14 +3884,14 @@ pub fn fstatat(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!Stat
|
|||
|
||||
/// Same as `fstatat` but `pathname` is null-terminated.
|
||||
/// See also `fstatat`.
|
||||
pub fn fstatatZ(dirfd: fd_t, pathname: [*:0]const u8, flags: u32) FStatAtError!Stat {
|
||||
pub fn fstatatZ(dirfd: fd_t, pathname: [*:0]const u8, flags: At) FStatAtError!Stat {
|
||||
if (native_os == .wasi and !builtin.link_libc) {
|
||||
@compileError("use std.Io instead");
|
||||
}
|
||||
|
||||
const fstatat_sym = if (lfs64_abi) system.fstatat64 else system.fstatat;
|
||||
var stat = mem.zeroes(Stat);
|
||||
switch (errno(fstatat_sym(dirfd, pathname, &stat, flags))) {
|
||||
switch (errno(fstatat_sym(dirfd, pathname, &stat, @bitCast(flags)))) {
|
||||
.SUCCESS => return stat,
|
||||
.INVAL => unreachable,
|
||||
.BADF => unreachable, // Always a race condition.
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ test "check WASI CWD" {
|
|||
|
||||
if (!builtin.link_libc) {
|
||||
// WASI without-libc hardcodes fd 3 as the FDCWD token so it can be passed directly to WASI calls
|
||||
try expectEqual(3, posix.AT.FDCWD);
|
||||
try expectEqual(3, posix.At.fdcwd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -907,7 +907,7 @@ test "pwrite with empty buffer" {
|
|||
}
|
||||
|
||||
fn expectMode(dir: posix.fd_t, file: []const u8, mode: posix.mode_t) !void {
|
||||
const st = try posix.fstatat(dir, file, posix.AT.SYMLINK_NOFOLLOW);
|
||||
const st = try posix.fstatat(dir, file, .{ .symlink_nofollow = true });
|
||||
try expectEqual(mode, st.mode & 0b111_111_111);
|
||||
}
|
||||
|
||||
|
|
@ -932,13 +932,13 @@ test "fchmodat smoke test" {
|
|||
|
||||
try posix.symlinkat("regfile", tmp.dir.fd, "symlink");
|
||||
const sym_mode = blk: {
|
||||
const st = try posix.fstatat(tmp.dir.fd, "symlink", posix.AT.SYMLINK_NOFOLLOW);
|
||||
const st = try posix.fstatat(tmp.dir.fd, "symlink", .{ .symlink_nofollow = true });
|
||||
break :blk st.mode & 0b111_111_111;
|
||||
};
|
||||
|
||||
try posix.fchmodat(tmp.dir.fd, "regfile", 0o640, 0);
|
||||
try expectMode(tmp.dir.fd, "regfile", 0o640);
|
||||
try posix.fchmodat(tmp.dir.fd, "regfile", 0o600, posix.AT.SYMLINK_NOFOLLOW);
|
||||
try posix.fchmodat(tmp.dir.fd, "regfile", 0o600, posix.At.SYMLINK_NOFOLLOW);
|
||||
try expectMode(tmp.dir.fd, "regfile", 0o600);
|
||||
|
||||
try posix.fchmodat(tmp.dir.fd, "symlink", 0o640, 0);
|
||||
|
|
@ -946,7 +946,7 @@ test "fchmodat smoke test" {
|
|||
try expectMode(tmp.dir.fd, "symlink", sym_mode);
|
||||
|
||||
var test_link = true;
|
||||
posix.fchmodat(tmp.dir.fd, "symlink", 0o600, posix.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,
|
||||
else => |e| return e,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -523,14 +523,15 @@ fn cleanupStreams(self: *ChildProcess) void {
|
|||
}
|
||||
|
||||
fn statusToTerm(status: u32) Term {
|
||||
return if (posix.W.IFEXITED(status))
|
||||
Term{ .Exited = posix.W.EXITSTATUS(status) }
|
||||
else if (posix.W.IFSIGNALED(status))
|
||||
Term{ .Signal = posix.W.TERMSIG(status) }
|
||||
else if (posix.W.IFSTOPPED(status))
|
||||
Term{ .Stopped = posix.W.STOPSIG(status) }
|
||||
const w: posix.W = @bitCast(status);
|
||||
return if (w.ifExited())
|
||||
.{ .Exited = w.exitStatus() }
|
||||
else if (w.ifSignaled())
|
||||
.{ .Signal = w.termSig() }
|
||||
else if (w.ifStopped())
|
||||
.{ .Stopped = w.stopSig() }
|
||||
else
|
||||
Term{ .Unknown = status };
|
||||
.{ .Unknown = status };
|
||||
}
|
||||
|
||||
fn spawnPosix(self: *ChildProcess) SpawnError!void {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue