mirror of
https://github.com/ziglang/zig.git
synced 2024-11-15 00:26:57 +00:00
some API work on std.c, std.os, std.os.wasi
* std.c: consolidate some definitions, making them share code. For example, freebsd, dragonfly, and openbsd can all share the same `pthread_mutex_t` definition. * add type safety to std.c.O - this caught a bug where mode flags were incorrectly passed as the open flags. * 3 fewer uses of usingnamespace keyword * as per convention, remove purposeless field prefixes from struct field names even if they have those prefixes in the corresponding C code. * fix incorrect wasi libc Stat definition * remove C definitions from incorrectly being in std.os.wasi * make std.os.wasi definitions type safe * go through wasi native APIs even when linking libc because the libc APIs are problematic and wasteful * don't expose WASI definitions in std.posix * remove std.os.wasi.rights_t.ALL: this is a footgun. should it be all future rights too? or only all current rights known? both are the wrong answer.
This commit is contained in:
parent
320c4d68f5
commit
7680c5330c
605
lib/std/c.zig
605
lib/std/c.zig
@ -4,6 +4,10 @@ const c = @This();
|
||||
const page_size = std.mem.page_size;
|
||||
const iovec = std.os.iovec;
|
||||
const iovec_const = std.os.iovec_const;
|
||||
const wasi = @import("c/wasi.zig");
|
||||
const native_abi = builtin.abi;
|
||||
const native_arch = builtin.cpu.arch;
|
||||
const native_os = builtin.os.tag;
|
||||
|
||||
/// If not linking libc, returns false.
|
||||
/// If linking musl libc, returns true.
|
||||
@ -13,7 +17,7 @@ const iovec_const = std.os.iovec_const;
|
||||
pub inline fn versionCheck(comptime glibc_version: std.SemanticVersion) bool {
|
||||
return comptime blk: {
|
||||
if (!builtin.link_libc) break :blk false;
|
||||
if (builtin.abi.isMusl()) break :blk true;
|
||||
if (native_abi.isMusl()) break :blk true;
|
||||
if (builtin.target.isGnuLibC()) {
|
||||
const ver = builtin.os.version_range.linux.glibc;
|
||||
const order = ver.order(glibc_version);
|
||||
@ -27,7 +31,7 @@ pub inline fn versionCheck(comptime glibc_version: std.SemanticVersion) bool {
|
||||
};
|
||||
}
|
||||
|
||||
pub usingnamespace switch (builtin.os.tag) {
|
||||
pub usingnamespace switch (native_os) {
|
||||
.linux => @import("c/linux.zig"),
|
||||
.windows => @import("c/windows.zig"),
|
||||
.macos, .ios, .tvos, .watchos => @import("c/darwin.zig"),
|
||||
@ -36,16 +40,504 @@ pub usingnamespace switch (builtin.os.tag) {
|
||||
.dragonfly => @import("c/dragonfly.zig"),
|
||||
.openbsd => @import("c/openbsd.zig"),
|
||||
.haiku => @import("c/haiku.zig"),
|
||||
.hermit => @import("c/hermit.zig"),
|
||||
.solaris, .illumos => @import("c/solaris.zig"),
|
||||
.fuchsia => @import("c/fuchsia.zig"),
|
||||
.minix => @import("c/minix.zig"),
|
||||
.emscripten => @import("c/emscripten.zig"),
|
||||
.wasi => @import("c/wasi.zig"),
|
||||
.wasi => wasi,
|
||||
else => struct {},
|
||||
};
|
||||
|
||||
pub const MAP = switch (builtin.os.tag) {
|
||||
pub const pthread_mutex_t = switch (native_os) {
|
||||
.linux, .minix => extern struct {
|
||||
data: [data_len]u8 align(@alignOf(usize)) = [_]u8{0} ** data_len,
|
||||
|
||||
const data_len = switch (native_abi) {
|
||||
.musl, .musleabi, .musleabihf => if (@sizeOf(usize) == 8) 40 else 24,
|
||||
.gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => switch (native_arch) {
|
||||
.aarch64 => 48,
|
||||
.x86_64 => if (native_abi == .gnux32) 40 else 32,
|
||||
.mips64, .powerpc64, .powerpc64le, .sparc64 => 40,
|
||||
else => if (@sizeOf(usize) == 8) 40 else 24,
|
||||
},
|
||||
.android => if (@sizeOf(usize) == 8) 40 else 4,
|
||||
else => @compileError("unsupported ABI"),
|
||||
};
|
||||
},
|
||||
.macos, .ios, .tvos, .watchos => extern struct {
|
||||
sig: c_long = 0x32AAABA7,
|
||||
data: [data_len]u8 = [_]u8{0} ** data_len,
|
||||
|
||||
const data_len = if (@sizeOf(usize) == 8) 56 else 40;
|
||||
},
|
||||
.freebsd, .kfreebsd, .dragonfly, .openbsd => extern struct {
|
||||
inner: ?*anyopaque = null,
|
||||
},
|
||||
.hermit => extern struct {
|
||||
ptr: usize = std.math.maxInt(usize),
|
||||
},
|
||||
.netbsd => extern struct {
|
||||
magic: u32 = 0x33330003,
|
||||
errorcheck: c.padded_pthread_spin_t = 0,
|
||||
ceiling: c.padded_pthread_spin_t = 0,
|
||||
owner: usize = 0,
|
||||
waiters: ?*u8 = null,
|
||||
recursed: u32 = 0,
|
||||
spare2: ?*anyopaque = null,
|
||||
},
|
||||
.haiku => extern struct {
|
||||
flags: u32 = 0,
|
||||
lock: i32 = 0,
|
||||
unused: i32 = -42,
|
||||
owner: i32 = -1,
|
||||
owner_count: i32 = 0,
|
||||
},
|
||||
.solaris, .illumos => extern struct {
|
||||
flag1: u16 = 0,
|
||||
flag2: u8 = 0,
|
||||
ceiling: u8 = 0,
|
||||
type: u16 = 0,
|
||||
magic: u16 = 0x4d58,
|
||||
lock: u64 = 0,
|
||||
data: u64 = 0,
|
||||
},
|
||||
.fuchsia => extern struct {
|
||||
data: [40]u8 align(@alignOf(usize)) = [_]u8{0} ** 40,
|
||||
},
|
||||
.emscripten => extern struct {
|
||||
data: [24]u8 align(4) = [_]u8{0} ** 24,
|
||||
},
|
||||
else => @compileError("target libc does not have pthread_mutex_t"),
|
||||
};
|
||||
|
||||
pub const pthread_cond_t = switch (native_os) {
|
||||
.linux => extern struct {
|
||||
data: [48]u8 align(@alignOf(usize)) = [_]u8{0} ** 48,
|
||||
},
|
||||
.macos, .ios, .tvos, .watchos => extern struct {
|
||||
sig: c_long = 0x3CB0B1BB,
|
||||
data: [data_len]u8 = [_]u8{0} ** data_len,
|
||||
const data_len = if (@sizeOf(usize) == 8) 40 else 24;
|
||||
},
|
||||
.freebsd, .kfreebsd, .dragonfly, .openbsd => extern struct {
|
||||
inner: ?*anyopaque = null,
|
||||
},
|
||||
.hermit => extern struct {
|
||||
ptr: usize = std.math.maxInt(usize),
|
||||
},
|
||||
.netbsd => extern struct {
|
||||
magic: u32 = 0x55550005,
|
||||
lock: c.pthread_spin_t = 0,
|
||||
waiters_first: ?*u8 = null,
|
||||
waiters_last: ?*u8 = null,
|
||||
mutex: ?*pthread_mutex_t = null,
|
||||
private: ?*anyopaque = null,
|
||||
},
|
||||
.haiku => extern struct {
|
||||
flags: u32 = 0,
|
||||
unused: i32 = -42,
|
||||
mutex: ?*anyopaque = null,
|
||||
waiter_count: i32 = 0,
|
||||
lock: i32 = 0,
|
||||
},
|
||||
.solaris, .illumos => extern struct {
|
||||
flag: [4]u8 = [_]u8{0} ** 4,
|
||||
type: u16 = 0,
|
||||
magic: u16 = 0x4356,
|
||||
data: u64 = 0,
|
||||
},
|
||||
.fuchsia, .minix, .emscripten => extern struct {
|
||||
data: [48]u8 align(@alignOf(usize)) = [_]u8{0} ** 48,
|
||||
},
|
||||
else => @compileError("target libc does not have pthread_cond_t"),
|
||||
};
|
||||
|
||||
pub const pthread_rwlock_t = switch (native_os) {
|
||||
.linux => switch (native_abi) {
|
||||
.android => switch (@sizeOf(usize)) {
|
||||
4 => extern struct {
|
||||
data: [40]u8 align(@alignOf(usize)) = [_]u8{0} ** 40,
|
||||
},
|
||||
8 => extern struct {
|
||||
data: [56]u8 align(@alignOf(usize)) = [_]u8{0} ** 56,
|
||||
},
|
||||
else => @compileError("impossible pointer size"),
|
||||
},
|
||||
else => extern struct {
|
||||
data: [56]u8 align(@alignOf(usize)) = [_]u8{0} ** 56,
|
||||
},
|
||||
},
|
||||
.macos, .ios, .tvos, .watchos => extern struct {
|
||||
sig: c_long = 0x2DA8B3B4,
|
||||
data: [192]u8 = [_]u8{0} ** 192,
|
||||
},
|
||||
.freebsd, .kfreebsd, .dragonfly, .openbsd => extern struct {
|
||||
ptr: ?*anyopaque = null,
|
||||
},
|
||||
.hermit => extern struct {
|
||||
ptr: usize = std.math.maxInt(usize),
|
||||
},
|
||||
.netbsd => extern struct {
|
||||
magic: c_uint = 0x99990009,
|
||||
interlock: switch (builtin.cpu.arch) {
|
||||
.aarch64, .sparc, .x86_64, .x86 => u8,
|
||||
.arm, .powerpc => c_int,
|
||||
else => unreachable,
|
||||
} = 0,
|
||||
rblocked_first: ?*u8 = null,
|
||||
rblocked_last: ?*u8 = null,
|
||||
wblocked_first: ?*u8 = null,
|
||||
wblocked_last: ?*u8 = null,
|
||||
nreaders: c_uint = 0,
|
||||
owner: ?pthread_t = null,
|
||||
private: ?*anyopaque = null,
|
||||
},
|
||||
.solaris, .illumos => extern struct {
|
||||
readers: i32 = 0,
|
||||
type: u16 = 0,
|
||||
magic: u16 = 0x5257,
|
||||
mutex: pthread_mutex_t = .{},
|
||||
readercv: pthread_cond_t = .{},
|
||||
writercv: pthread_cond_t = .{},
|
||||
},
|
||||
.fuchsia => extern struct {
|
||||
size: [56]u8 align(@alignOf(usize)) = [_]u8{0} ** 56,
|
||||
},
|
||||
.emscripten => extern struct {
|
||||
size: [32]u8 align(4) = [_]u8{0} ** 32,
|
||||
},
|
||||
else => @compileError("target libc does not have pthread_rwlock_t"),
|
||||
};
|
||||
|
||||
pub const AT = switch (native_os) {
|
||||
.linux => std.os.linux.AT,
|
||||
.windows => struct {
|
||||
/// Remove directory instead of unlinking file
|
||||
pub const REMOVEDIR = 0x200;
|
||||
},
|
||||
.macos, .ios, .tvos, .watchos => struct {
|
||||
pub const FDCWD = -2;
|
||||
/// Use effective ids in access check
|
||||
pub const EACCESS = 0x0010;
|
||||
/// Act on the symlink itself not the target
|
||||
pub const SYMLINK_NOFOLLOW = 0x0020;
|
||||
/// Act on target of symlink
|
||||
pub const SYMLINK_FOLLOW = 0x0040;
|
||||
/// Path refers to directory
|
||||
pub const REMOVEDIR = 0x0080;
|
||||
},
|
||||
.freebsd, .kfreebsd => struct {
|
||||
/// Magic value that specify the use of the current working directory
|
||||
/// to determine the target of relative file paths in the openat() and
|
||||
/// similar syscalls.
|
||||
pub const FDCWD = -100;
|
||||
/// Check access using effective user and group ID
|
||||
pub const EACCESS = 0x0100;
|
||||
/// Do not follow symbolic links
|
||||
pub const SYMLINK_NOFOLLOW = 0x0200;
|
||||
/// Follow symbolic link
|
||||
pub const SYMLINK_FOLLOW = 0x0400;
|
||||
/// Remove directory instead of file
|
||||
pub const REMOVEDIR = 0x0800;
|
||||
/// Fail if not under dirfd
|
||||
pub const BENEATH = 0x1000;
|
||||
},
|
||||
.netbsd => struct {
|
||||
/// Magic value that specify the use of the current working directory
|
||||
/// to determine the target of relative file paths in the openat() and
|
||||
/// similar syscalls.
|
||||
pub const FDCWD = -100;
|
||||
/// Check access using effective user and group ID
|
||||
pub const EACCESS = 0x0100;
|
||||
/// Do not follow symbolic links
|
||||
pub const SYMLINK_NOFOLLOW = 0x0200;
|
||||
/// Follow symbolic link
|
||||
pub const SYMLINK_FOLLOW = 0x0400;
|
||||
/// Remove directory instead of file
|
||||
pub const REMOVEDIR = 0x0800;
|
||||
},
|
||||
.dragonfly => struct {
|
||||
pub const FDCWD = -328243;
|
||||
pub const SYMLINK_NOFOLLOW = 1;
|
||||
pub const REMOVEDIR = 2;
|
||||
pub const EACCESS = 4;
|
||||
pub const SYMLINK_FOLLOW = 8;
|
||||
},
|
||||
.openbsd => struct {
|
||||
/// Magic value that specify the use of the current working directory
|
||||
/// to determine the target of relative file paths in the openat() and
|
||||
/// similar syscalls.
|
||||
pub const FDCWD = -100;
|
||||
/// Check access using effective user and group ID
|
||||
pub const EACCESS = 0x01;
|
||||
/// Do not follow symbolic links
|
||||
pub const SYMLINK_NOFOLLOW = 0x02;
|
||||
/// Follow symbolic link
|
||||
pub const SYMLINK_FOLLOW = 0x04;
|
||||
/// Remove directory instead of file
|
||||
pub const REMOVEDIR = 0x08;
|
||||
},
|
||||
.haiku => struct {
|
||||
pub const FDCWD = -1;
|
||||
pub const SYMLINK_NOFOLLOW = 0x01;
|
||||
pub const SYMLINK_FOLLOW = 0x02;
|
||||
pub const REMOVEDIR = 0x04;
|
||||
pub const EACCESS = 0x08;
|
||||
},
|
||||
.solaris, .illumos => struct {
|
||||
/// Magic value that specify the use of the current working directory
|
||||
/// to determine the target of relative file paths in the openat() and
|
||||
/// similar syscalls.
|
||||
pub const FDCWD: c.fd_t = @bitCast(@as(u32, 0xffd19553));
|
||||
/// Do not follow symbolic links
|
||||
pub const SYMLINK_NOFOLLOW = 0x1000;
|
||||
/// Follow symbolic link
|
||||
pub const SYMLINK_FOLLOW = 0x2000;
|
||||
/// Remove directory instead of file
|
||||
pub const REMOVEDIR = 0x1;
|
||||
pub const TRIGGER = 0x2;
|
||||
/// Check access using effective user and group ID
|
||||
pub const EACCESS = 0x4;
|
||||
},
|
||||
.emscripten => struct {
|
||||
pub const FDCWD = -100;
|
||||
pub const SYMLINK_NOFOLLOW = 0x100;
|
||||
pub const REMOVEDIR = 0x200;
|
||||
pub const SYMLINK_FOLLOW = 0x400;
|
||||
pub const NO_AUTOMOUNT = 0x800;
|
||||
pub const EMPTY_PATH = 0x1000;
|
||||
pub const STATX_SYNC_TYPE = 0x6000;
|
||||
pub const STATX_SYNC_AS_STAT = 0x0000;
|
||||
pub const STATX_FORCE_SYNC = 0x2000;
|
||||
pub const STATX_DONT_SYNC = 0x4000;
|
||||
pub const RECURSIVE = 0x8000;
|
||||
},
|
||||
.wasi => struct {
|
||||
pub const SYMLINK_NOFOLLOW = 0x100;
|
||||
pub const SYMLINK_FOLLOW = 0x400;
|
||||
pub const REMOVEDIR: u32 = 0x4;
|
||||
/// When linking libc, we follow their convention and use -2 for current working directory.
|
||||
/// However, without libc, Zig does a different convention: it assumes the
|
||||
/// current working directory is the first preopen. This behavior can be
|
||||
/// overridden with a public function called `wasi_cwd` in the root source
|
||||
/// file.
|
||||
pub const FDCWD: c.fd_t = if (builtin.link_libc) -2 else 3;
|
||||
},
|
||||
|
||||
else => @compileError("target libc does not have AT"),
|
||||
};
|
||||
|
||||
pub const O = switch (native_os) {
|
||||
.linux => std.os.linux.O,
|
||||
.emscripten => packed struct(u32) {
|
||||
ACCMODE: std.os.ACCMODE = .RDONLY,
|
||||
_2: u4 = 0,
|
||||
CREAT: bool = false,
|
||||
EXCL: bool = false,
|
||||
NOCTTY: bool = false,
|
||||
TRUNC: bool = false,
|
||||
APPEND: bool = false,
|
||||
NONBLOCK: bool = false,
|
||||
DSYNC: bool = false,
|
||||
ASYNC: bool = false,
|
||||
DIRECT: bool = false,
|
||||
LARGEFILE: bool = false,
|
||||
DIRECTORY: bool = false,
|
||||
NOFOLLOW: bool = false,
|
||||
NOATIME: bool = false,
|
||||
CLOEXEC: bool = false,
|
||||
SYNC: bool = false,
|
||||
PATH: bool = false,
|
||||
TMPFILE: bool = false,
|
||||
_: u9 = 0,
|
||||
},
|
||||
.wasi => packed struct(u32) {
|
||||
APPEND: bool = false,
|
||||
DSYNC: bool = false,
|
||||
NONBLOCK: bool = false,
|
||||
RSYNC: bool = false,
|
||||
SYNC: bool = false,
|
||||
_5: u7 = 0,
|
||||
CREAT: bool = false,
|
||||
DIRECTORY: bool = false,
|
||||
EXCL: bool = false,
|
||||
TRUNC: bool = false,
|
||||
_16: u8 = 0,
|
||||
NOFOLLOW: bool = false,
|
||||
EXEC: bool = false,
|
||||
read: bool = false,
|
||||
SEARCH: bool = false,
|
||||
write: bool = false,
|
||||
_: u3 = 0,
|
||||
},
|
||||
.solaris => packed struct(u32) {
|
||||
ACCMODE: std.os.ACCMODE = .RDONLY,
|
||||
NDELAY: bool = false,
|
||||
APPEND: bool = false,
|
||||
SYNC: bool = false,
|
||||
_5: u1 = 0,
|
||||
DSYNC: bool = false,
|
||||
NONBLOCK: bool = false,
|
||||
CREAT: bool = false,
|
||||
TRUNC: bool = false,
|
||||
EXCL: bool = false,
|
||||
NOCTTY: bool = false,
|
||||
_12: u1 = 0,
|
||||
LARGEFILE: bool = false,
|
||||
XATTR: bool = false,
|
||||
RSYNC: bool = false,
|
||||
_16: u1 = 0,
|
||||
NOFOLLOW: bool = false,
|
||||
NOLINKS: bool = false,
|
||||
_19: u2 = 0,
|
||||
SEARCH: bool = false,
|
||||
EXEC: bool = false,
|
||||
CLOEXEC: bool = false,
|
||||
DIRECTORY: bool = false,
|
||||
DIRECT: bool = false,
|
||||
_: u6 = 0,
|
||||
},
|
||||
.netbsd => packed struct(u32) {
|
||||
ACCMODE: std.os.ACCMODE = .RDONLY,
|
||||
NONBLOCK: bool = false,
|
||||
APPEND: bool = false,
|
||||
SHLOCK: bool = false,
|
||||
EXLOCK: bool = false,
|
||||
ASYNC: bool = false,
|
||||
SYNC: bool = false,
|
||||
NOFOLLOW: bool = false,
|
||||
CREAT: bool = false,
|
||||
TRUNC: bool = false,
|
||||
EXCL: bool = false,
|
||||
_12: u3 = 0,
|
||||
NOCTTY: bool = false,
|
||||
DSYNC: bool = false,
|
||||
RSYNC: bool = false,
|
||||
ALT_IO: bool = false,
|
||||
DIRECT: bool = false,
|
||||
_20: u1 = 0,
|
||||
DIRECTORY: bool = false,
|
||||
CLOEXEC: bool = false,
|
||||
SEARCH: bool = false,
|
||||
_: u8 = 0,
|
||||
},
|
||||
.openbsd => packed struct(u32) {
|
||||
ACCMODE: std.os.ACCMODE = .RDONLY,
|
||||
NONBLOCK: bool = false,
|
||||
APPEND: bool = false,
|
||||
SHLOCK: bool = false,
|
||||
EXLOCK: bool = false,
|
||||
ASYNC: bool = false,
|
||||
SYNC: bool = false,
|
||||
NOFOLLOW: bool = false,
|
||||
CREAT: bool = false,
|
||||
TRUNC: bool = false,
|
||||
EXCL: bool = false,
|
||||
_12: u3 = 0,
|
||||
NOCTTY: bool = false,
|
||||
CLOEXEC: bool = false,
|
||||
DIRECTORY: bool = false,
|
||||
_: u14 = 0,
|
||||
},
|
||||
.haiku => packed struct(u32) {
|
||||
ACCMODE: std.os.ACCMODE = .RDONLY,
|
||||
_2: u4 = 0,
|
||||
CLOEXEC: bool = false,
|
||||
NONBLOCK: bool = false,
|
||||
EXCL: bool = false,
|
||||
CREAT: bool = false,
|
||||
TRUNC: bool = false,
|
||||
APPEND: bool = false,
|
||||
NOCTTY: bool = false,
|
||||
NOTRAVERSE: bool = false,
|
||||
_14: u2 = 0,
|
||||
SYNC: bool = false,
|
||||
RSYNC: bool = false,
|
||||
DSYNC: bool = false,
|
||||
NOFOLLOW: bool = false,
|
||||
DIRECT: bool = false,
|
||||
DIRECTORY: bool = false,
|
||||
_: u10 = 0,
|
||||
},
|
||||
.macos, .ios, .tvos, .watchos => packed struct(u32) {
|
||||
ACCMODE: std.os.ACCMODE = .RDONLY,
|
||||
NONBLOCK: bool = false,
|
||||
APPEND: bool = false,
|
||||
SHLOCK: bool = false,
|
||||
EXLOCK: bool = false,
|
||||
ASYNC: bool = false,
|
||||
SYNC: bool = false,
|
||||
NOFOLLOW: bool = false,
|
||||
CREAT: bool = false,
|
||||
TRUNC: bool = false,
|
||||
EXCL: bool = false,
|
||||
_12: u3 = 0,
|
||||
EVTONLY: bool = false,
|
||||
_16: u1 = 0,
|
||||
NOCTTY: bool = false,
|
||||
_18: u2 = 0,
|
||||
DIRECTORY: bool = false,
|
||||
SYMLINK: bool = false,
|
||||
DSYNC: bool = false,
|
||||
_23: u1 = 0,
|
||||
CLOEXEC: bool = false,
|
||||
_25: u4 = 0,
|
||||
ALERT: bool = false,
|
||||
_30: u1 = 0,
|
||||
POPUP: bool = false,
|
||||
},
|
||||
.dragonfly => packed struct(u32) {
|
||||
ACCMODE: std.os.ACCMODE = .RDONLY,
|
||||
NONBLOCK: bool = false,
|
||||
APPEND: bool = false,
|
||||
SHLOCK: bool = false,
|
||||
EXLOCK: bool = false,
|
||||
ASYNC: bool = false,
|
||||
SYNC: bool = false,
|
||||
NOFOLLOW: bool = false,
|
||||
CREAT: bool = false,
|
||||
TRUNC: bool = false,
|
||||
EXCL: bool = false,
|
||||
_12: u3 = 0,
|
||||
NOCTTY: bool = false,
|
||||
DIRECT: bool = false,
|
||||
CLOEXEC: bool = false,
|
||||
FBLOCKING: bool = false,
|
||||
FNONBLOCKING: bool = false,
|
||||
FAPPEND: bool = false,
|
||||
FOFFSET: bool = false,
|
||||
FSYNCWRITE: bool = false,
|
||||
FASYNCWRITE: bool = false,
|
||||
_24: u3 = 0,
|
||||
DIRECTORY: bool = false,
|
||||
_: u4 = 0,
|
||||
},
|
||||
.freebsd => packed struct(u32) {
|
||||
ACCMODE: std.os.ACCMODE = .RDONLY,
|
||||
NONBLOCK: bool = false,
|
||||
APPEND: bool = false,
|
||||
SHLOCK: bool = false,
|
||||
EXLOCK: bool = false,
|
||||
ASYNC: bool = false,
|
||||
SYNC: bool = false,
|
||||
NOFOLLOW: bool = false,
|
||||
CREAT: bool = false,
|
||||
TRUNC: bool = false,
|
||||
EXCL: bool = false,
|
||||
DSYNC: bool = false,
|
||||
_13: u2 = 0,
|
||||
NOCTTY: bool = false,
|
||||
DIRECT: bool = false,
|
||||
DIRECTORY: bool = false,
|
||||
NOATIME: bool = false,
|
||||
_19: u1 = 0,
|
||||
CLOEXEC: bool = false,
|
||||
PATH: bool = false,
|
||||
TMPFILE: bool = false,
|
||||
_: u9 = 0,
|
||||
},
|
||||
else => @compileError("target libc does not have O"),
|
||||
};
|
||||
|
||||
pub const MAP = switch (native_os) {
|
||||
.linux => std.os.linux.MAP,
|
||||
.emscripten => packed struct(u32) {
|
||||
TYPE: enum(u4) {
|
||||
@ -187,10 +679,10 @@ pub const MAP = switch (builtin.os.tag) {
|
||||
/// Used by libc to communicate failure. Not actually part of the underlying syscall.
|
||||
pub const MAP_FAILED: *anyopaque = @ptrFromInt(std.math.maxInt(usize));
|
||||
|
||||
pub const whence_t = if (builtin.os.tag == .wasi) std.os.wasi.whence_t else c_int;
|
||||
pub const whence_t = if (native_os == .wasi) std.os.wasi.whence_t else c_int;
|
||||
|
||||
// Unix-like systems
|
||||
pub usingnamespace switch (builtin.os.tag) {
|
||||
pub usingnamespace switch (native_os) {
|
||||
.netbsd, .windows => struct {},
|
||||
else => struct {
|
||||
pub const DIR = opaque {};
|
||||
@ -225,25 +717,40 @@ pub usingnamespace switch (builtin.os.tag) {
|
||||
},
|
||||
};
|
||||
|
||||
pub usingnamespace switch (builtin.os.tag) {
|
||||
.netbsd, .macos, .ios, .watchos, .tvos, .windows => struct {},
|
||||
else => struct {
|
||||
pub extern "c" fn fstat(fd: c.fd_t, buf: *c.Stat) c_int;
|
||||
pub extern "c" fn readdir(dp: *c.DIR) ?*c.dirent;
|
||||
pub const fstat = switch (native_os) {
|
||||
.netbsd => private.__fstat50,
|
||||
.macos, .ios, .watchos, .tvos => switch (native_arch) {
|
||||
.aarch64 => private.fstat,
|
||||
else => private.@"fstat$INODE64",
|
||||
},
|
||||
else => private.fstat,
|
||||
};
|
||||
|
||||
pub usingnamespace switch (builtin.os.tag) {
|
||||
.macos, .ios, .watchos, .tvos => struct {},
|
||||
else => struct {
|
||||
pub extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;
|
||||
pub extern "c" fn fstatat(dirfd: c.fd_t, path: [*:0]const u8, stat_buf: *c.Stat, flags: u32) c_int;
|
||||
pub const fstatat = switch (native_os) {
|
||||
.macos, .ios, .watchos, .tvos => switch (native_arch) {
|
||||
.aarch64 => private.fstatat,
|
||||
else => private.@"fstatat$INODE64",
|
||||
},
|
||||
else => private.fstatat,
|
||||
};
|
||||
|
||||
pub const readdir = switch (native_os) {
|
||||
.macos, .ios, .watchos, .tvos => switch (native_arch) {
|
||||
.aarch64 => private.readdir,
|
||||
else => private.@"readdir$INODE64",
|
||||
},
|
||||
.windows => @compileError("not available"),
|
||||
else => private.readdir,
|
||||
};
|
||||
|
||||
pub const realpath = switch (native_os) {
|
||||
.macos, .ios, .watchos, .tvos => private.@"realpath$DARWIN_EXTSN",
|
||||
else => private.realpath,
|
||||
};
|
||||
|
||||
pub fn getErrno(rc: anytype) c.E {
|
||||
if (rc == -1) {
|
||||
return @as(c.E, @enumFromInt(c._errno().*));
|
||||
return @enumFromInt(c._errno().*);
|
||||
} else {
|
||||
return .SUCCESS;
|
||||
}
|
||||
@ -263,8 +770,8 @@ pub extern "c" fn _exit(code: c_int) noreturn;
|
||||
pub extern "c" fn isatty(fd: c.fd_t) c_int;
|
||||
pub extern "c" fn close(fd: c.fd_t) c_int;
|
||||
pub extern "c" fn lseek(fd: c.fd_t, offset: c.off_t, whence: whence_t) c.off_t;
|
||||
pub extern "c" fn open(path: [*:0]const u8, oflag: c_uint, ...) c_int;
|
||||
pub extern "c" fn openat(fd: c_int, path: [*:0]const u8, oflag: c_uint, ...) c_int;
|
||||
pub extern "c" fn open(path: [*:0]const u8, oflag: O, ...) c_int;
|
||||
pub extern "c" fn openat(fd: c_int, path: [*:0]const u8, oflag: O, ...) c_int;
|
||||
pub extern "c" fn ftruncate(fd: c_int, length: c.off_t) c_int;
|
||||
pub extern "c" fn raise(sig: c_int) c_int;
|
||||
pub extern "c" fn read(fd: c.fd_t, buf: [*]u8, nbyte: usize) isize;
|
||||
@ -275,7 +782,7 @@ pub extern "c" fn writev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint) i
|
||||
pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: c.off_t) isize;
|
||||
pub extern "c" fn write(fd: c.fd_t, buf: [*]const u8, nbyte: usize) isize;
|
||||
pub extern "c" fn pwrite(fd: c.fd_t, buf: [*]const u8, nbyte: usize, offset: c.off_t) isize;
|
||||
pub extern "c" fn mmap(addr: ?*align(page_size) anyopaque, len: usize, prot: c_uint, flags: c_uint, fd: c.fd_t, offset: c.off_t) *anyopaque;
|
||||
pub extern "c" fn mmap(addr: ?*align(page_size) anyopaque, len: usize, prot: c_uint, flags: MAP, fd: c.fd_t, offset: c.off_t) *anyopaque;
|
||||
pub extern "c" fn munmap(addr: *align(page_size) const anyopaque, len: usize) c_int;
|
||||
pub extern "c" fn mprotect(addr: *align(page_size) anyopaque, len: usize, prot: c_uint) c_int;
|
||||
pub extern "c" fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8, flags: c_int) c_int;
|
||||
@ -348,7 +855,7 @@ pub extern "c" fn recv(
|
||||
arg1: ?*anyopaque,
|
||||
arg2: usize,
|
||||
arg3: c_int,
|
||||
) if (builtin.os.tag == .windows) c_int else isize;
|
||||
) if (native_os == .windows) c_int else isize;
|
||||
pub extern "c" fn recvfrom(
|
||||
sockfd: c.fd_t,
|
||||
noalias buf: *anyopaque,
|
||||
@ -356,7 +863,7 @@ pub extern "c" fn recvfrom(
|
||||
flags: u32,
|
||||
noalias src_addr: ?*c.sockaddr,
|
||||
noalias addrlen: ?*c.socklen_t,
|
||||
) if (builtin.os.tag == .windows) c_int else isize;
|
||||
) if (native_os == .windows) c_int else isize;
|
||||
pub extern "c" fn recvmsg(sockfd: c.fd_t, msg: *c.msghdr, flags: u32) isize;
|
||||
|
||||
pub extern "c" fn kill(pid: c.pid_t, sig: c_int) c_int;
|
||||
@ -492,18 +999,18 @@ pub extern "c" fn dn_expand(
|
||||
length: c_int,
|
||||
) c_int;
|
||||
|
||||
pub const PTHREAD_MUTEX_INITIALIZER = c.pthread_mutex_t{};
|
||||
pub extern "c" fn pthread_mutex_lock(mutex: *c.pthread_mutex_t) c.E;
|
||||
pub extern "c" fn pthread_mutex_unlock(mutex: *c.pthread_mutex_t) c.E;
|
||||
pub extern "c" fn pthread_mutex_trylock(mutex: *c.pthread_mutex_t) c.E;
|
||||
pub extern "c" fn pthread_mutex_destroy(mutex: *c.pthread_mutex_t) c.E;
|
||||
pub const PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{};
|
||||
pub extern "c" fn pthread_mutex_lock(mutex: *pthread_mutex_t) c.E;
|
||||
pub extern "c" fn pthread_mutex_unlock(mutex: *pthread_mutex_t) c.E;
|
||||
pub extern "c" fn pthread_mutex_trylock(mutex: *pthread_mutex_t) c.E;
|
||||
pub extern "c" fn pthread_mutex_destroy(mutex: *pthread_mutex_t) c.E;
|
||||
|
||||
pub const PTHREAD_COND_INITIALIZER = c.pthread_cond_t{};
|
||||
pub extern "c" fn pthread_cond_wait(noalias cond: *c.pthread_cond_t, noalias mutex: *c.pthread_mutex_t) c.E;
|
||||
pub extern "c" fn pthread_cond_timedwait(noalias cond: *c.pthread_cond_t, noalias mutex: *c.pthread_mutex_t, noalias abstime: *const c.timespec) c.E;
|
||||
pub extern "c" fn pthread_cond_signal(cond: *c.pthread_cond_t) c.E;
|
||||
pub extern "c" fn pthread_cond_broadcast(cond: *c.pthread_cond_t) c.E;
|
||||
pub extern "c" fn pthread_cond_destroy(cond: *c.pthread_cond_t) c.E;
|
||||
pub const PTHREAD_COND_INITIALIZER = pthread_cond_t{};
|
||||
pub extern "c" fn pthread_cond_wait(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t) c.E;
|
||||
pub extern "c" fn pthread_cond_timedwait(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t, noalias abstime: *const c.timespec) c.E;
|
||||
pub extern "c" fn pthread_cond_signal(cond: *pthread_cond_t) c.E;
|
||||
pub extern "c" fn pthread_cond_broadcast(cond: *pthread_cond_t) c.E;
|
||||
pub extern "c" fn pthread_cond_destroy(cond: *pthread_cond_t) c.E;
|
||||
|
||||
pub extern "c" fn pthread_rwlock_destroy(rwl: *c.pthread_rwlock_t) callconv(.C) c.E;
|
||||
pub extern "c" fn pthread_rwlock_rdlock(rwl: *c.pthread_rwlock_t) callconv(.C) c.E;
|
||||
@ -542,14 +1049,14 @@ pub usingnamespace if (builtin.target.isAndroid()) struct {
|
||||
// android bionic libc does not implement getcontext,
|
||||
// and std.os.linux.getcontext also cannot be built for
|
||||
// bionic libc currently.
|
||||
} else if (builtin.os.tag == .linux and builtin.target.isMusl()) struct {
|
||||
} else if (native_os == .linux and builtin.target.isMusl()) struct {
|
||||
// musl does not implement getcontext
|
||||
pub const getcontext = std.os.linux.getcontext;
|
||||
} else struct {
|
||||
pub extern "c" fn getcontext(ucp: *std.os.ucontext_t) c_int;
|
||||
};
|
||||
|
||||
pub const max_align_t = if (builtin.abi == .msvc)
|
||||
pub const max_align_t = if (native_abi == .msvc)
|
||||
f64
|
||||
else if (builtin.target.isDarwin())
|
||||
c_longdouble
|
||||
@ -558,3 +1065,25 @@ else
|
||||
a: c_longlong,
|
||||
b: c_longdouble,
|
||||
};
|
||||
|
||||
const private = struct {
|
||||
extern "c" fn fstat(fd: c.fd_t, buf: *c.Stat) c_int;
|
||||
/// On x86_64 Darwin, fstat has to be manually linked with $INODE64 suffix to
|
||||
/// force 64bit version.
|
||||
/// Note that this is fixed on aarch64 and no longer necessary.
|
||||
extern "c" fn @"fstat$INODE64"(fd: c.fd_t, buf: *c.Stat) c_int;
|
||||
|
||||
extern "c" fn fstatat(dirfd: c.fd_t, path: [*:0]const u8, stat_buf: *c.Stat, flags: u32) c_int;
|
||||
/// On x86_64 Darwin, fstatat has to be manually linked with $INODE64 suffix to
|
||||
/// force 64bit version.
|
||||
/// Note that this is fixed on aarch64 and no longer necessary.
|
||||
extern "c" fn @"fstatat$INODE64"(dirfd: c.fd_t, path_name: [*:0]const u8, buf: *c.Stat, flags: u32) c_int;
|
||||
|
||||
extern "c" fn __fstat50(fd: c.fd_t, buf: *c.Stat) c_int;
|
||||
|
||||
extern "c" fn readdir(dir: *c.DIR) ?*c.dirent;
|
||||
extern "c" fn @"readdir$INODE64"(dir: *c.DIR) ?*c.dirent;
|
||||
|
||||
extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;
|
||||
extern "c" fn @"realpath$DARWIN_EXTSN"(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;
|
||||
};
|
||||
|
@ -169,31 +169,8 @@ pub const COPYFILE_DATA = 1 << 3;
|
||||
pub const copyfile_state_t = *opaque {};
|
||||
pub extern "c" fn fcopyfile(from: fd_t, to: fd_t, state: ?copyfile_state_t, flags: u32) c_int;
|
||||
|
||||
pub extern "c" fn @"realpath$DARWIN_EXTSN"(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;
|
||||
pub const realpath = @"realpath$DARWIN_EXTSN";
|
||||
|
||||
pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: [*]u8, buf_len: usize, basep: *i64) isize;
|
||||
|
||||
const private = struct {
|
||||
extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int;
|
||||
/// On x86_64 Darwin, fstat has to be manually linked with $INODE64 suffix to
|
||||
/// force 64bit version.
|
||||
/// Note that this is fixed on aarch64 and no longer necessary.
|
||||
extern "c" fn @"fstat$INODE64"(fd: fd_t, buf: *Stat) c_int;
|
||||
|
||||
extern "c" fn fstatat(dirfd: fd_t, path: [*:0]const u8, stat_buf: *Stat, flags: u32) c_int;
|
||||
/// On x86_64 Darwin, fstatat has to be manually linked with $INODE64 suffix to
|
||||
/// force 64bit version.
|
||||
/// Note that this is fixed on aarch64 and no longer necessary.
|
||||
extern "c" fn @"fstatat$INODE64"(dirfd: fd_t, path_name: [*:0]const u8, buf: *Stat, flags: u32) c_int;
|
||||
|
||||
extern "c" fn readdir(dir: *std.c.DIR) ?*dirent;
|
||||
extern "c" fn @"readdir$INODE64"(dir: *std.c.DIR) ?*dirent;
|
||||
};
|
||||
pub const fstat = if (native_arch == .aarch64) private.fstat else private.@"fstat$INODE64";
|
||||
pub const fstatat = if (native_arch == .aarch64) private.fstatat else private.@"fstatat$INODE64";
|
||||
pub const readdir = if (native_arch == .aarch64) private.readdir else private.@"readdir$INODE64";
|
||||
|
||||
pub extern "c" fn mach_absolute_time() u64;
|
||||
pub extern "c" fn mach_continuous_time() u64;
|
||||
pub extern "c" fn mach_timebase_info(tinfo: ?*mach_timebase_info_data) kern_return_t;
|
||||
@ -866,21 +843,7 @@ pub const qos_class_t = enum(c_uint) {
|
||||
QOS_CLASS_UNSPECIFIED = 0x00,
|
||||
};
|
||||
|
||||
pub const pthread_mutex_t = extern struct {
|
||||
__sig: c_long = 0x32AAABA7,
|
||||
__opaque: [__PTHREAD_MUTEX_SIZE__]u8 = [_]u8{0} ** __PTHREAD_MUTEX_SIZE__,
|
||||
};
|
||||
pub const pthread_cond_t = extern struct {
|
||||
__sig: c_long = 0x3CB0B1BB,
|
||||
__opaque: [__PTHREAD_COND_SIZE__]u8 = [_]u8{0} ** __PTHREAD_COND_SIZE__,
|
||||
};
|
||||
pub const pthread_rwlock_t = extern struct {
|
||||
__sig: c_long = 0x2DA8B3B4,
|
||||
__opaque: [192]u8 = [_]u8{0} ** 192,
|
||||
};
|
||||
pub const sem_t = c_int;
|
||||
const __PTHREAD_MUTEX_SIZE__ = if (@sizeOf(usize) == 8) 56 else 40;
|
||||
const __PTHREAD_COND_SIZE__ = if (@sizeOf(usize) == 8) 40 else 24;
|
||||
|
||||
pub const pthread_attr_t = extern struct {
|
||||
__sig: c_long,
|
||||
@ -1202,16 +1165,12 @@ pub const Sigaction = extern struct {
|
||||
};
|
||||
|
||||
pub const dirent = extern struct {
|
||||
d_ino: u64,
|
||||
d_seekoff: u64,
|
||||
d_reclen: u16,
|
||||
d_namlen: u16,
|
||||
d_type: u8,
|
||||
d_name: [1024]u8,
|
||||
|
||||
pub fn reclen(self: dirent) u16 {
|
||||
return self.d_reclen;
|
||||
}
|
||||
ino: u64,
|
||||
seekoff: u64,
|
||||
reclen: u16,
|
||||
namlen: u16,
|
||||
type: u8,
|
||||
name: [1024]u8,
|
||||
};
|
||||
|
||||
/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
|
||||
@ -1346,49 +1305,6 @@ pub const X_OK = 1;
|
||||
pub const W_OK = 2;
|
||||
pub const R_OK = 4;
|
||||
|
||||
pub const O = struct {
|
||||
pub const PATH = 0x0000;
|
||||
/// open for reading only
|
||||
pub const RDONLY = 0x0000;
|
||||
/// open for writing only
|
||||
pub const WRONLY = 0x0001;
|
||||
/// open for reading and writing
|
||||
pub const RDWR = 0x0002;
|
||||
/// do not block on open or for data to become available
|
||||
pub const NONBLOCK = 0x0004;
|
||||
/// append on each write
|
||||
pub const APPEND = 0x0008;
|
||||
/// create file if it does not exist
|
||||
pub const CREAT = 0x0200;
|
||||
/// truncate size to 0
|
||||
pub const TRUNC = 0x0400;
|
||||
/// error if CREAT and the file exists
|
||||
pub const EXCL = 0x0800;
|
||||
/// atomically obtain a shared lock
|
||||
pub const SHLOCK = 0x0010;
|
||||
/// atomically obtain an exclusive lock
|
||||
pub const EXLOCK = 0x0020;
|
||||
/// do not follow symlinks
|
||||
pub const NOFOLLOW = 0x0100;
|
||||
/// allow open of symlinks
|
||||
pub const SYMLINK = 0x200000;
|
||||
/// descriptor requested for event notifications only
|
||||
pub const EVTONLY = 0x8000;
|
||||
/// mark as close-on-exec
|
||||
pub const CLOEXEC = 0x1000000;
|
||||
pub const ACCMODE = 3;
|
||||
pub const ALERT = 536870912;
|
||||
pub const ASYNC = 64;
|
||||
pub const DIRECTORY = 1048576;
|
||||
pub const DP_GETRAWENCRYPTED = 1;
|
||||
pub const DP_GETRAWUNENCRYPTED = 2;
|
||||
pub const DSYNC = 4194304;
|
||||
pub const FSYNC = SYNC;
|
||||
pub const NOCTTY = 131072;
|
||||
pub const POPUP = 2147483648;
|
||||
pub const SYNC = 128;
|
||||
};
|
||||
|
||||
pub const SEEK = struct {
|
||||
pub const SET = 0x0;
|
||||
pub const CUR = 0x1;
|
||||
@ -2529,18 +2445,6 @@ pub const S = struct {
|
||||
|
||||
pub const HOST_NAME_MAX = 72;
|
||||
|
||||
pub const AT = struct {
|
||||
pub const FDCWD = -2;
|
||||
/// Use effective ids in access check
|
||||
pub const EACCESS = 0x0010;
|
||||
/// Act on the symlink itself not the target
|
||||
pub const SYMLINK_NOFOLLOW = 0x0020;
|
||||
/// Act on target of symlink
|
||||
pub const SYMLINK_FOLLOW = 0x0040;
|
||||
/// Path refers to directory
|
||||
pub const REMOVEDIR = 0x0080;
|
||||
};
|
||||
|
||||
pub const addrinfo = extern struct {
|
||||
flags: i32,
|
||||
family: i32,
|
||||
|
@ -22,22 +22,11 @@ pub extern "c" fn lwp_gettid() c_int;
|
||||
|
||||
pub extern "c" fn posix_memalign(memptr: *?*anyopaque, alignment: usize, size: usize) c_int;
|
||||
|
||||
pub const pthread_mutex_t = extern struct {
|
||||
inner: ?*anyopaque = null,
|
||||
};
|
||||
pub const pthread_cond_t = extern struct {
|
||||
inner: ?*anyopaque = null,
|
||||
};
|
||||
|
||||
pub const pthread_attr_t = extern struct { // copied from freebsd
|
||||
__size: [56]u8,
|
||||
__align: c_long,
|
||||
};
|
||||
|
||||
pub const pthread_rwlock_t = extern struct {
|
||||
ptr: ?*anyopaque = null,
|
||||
};
|
||||
|
||||
pub const sem_t = ?*opaque {};
|
||||
|
||||
pub extern "c" fn pthread_setname_np(thread: std.c.pthread_t, name: [*:0]const u8) E;
|
||||
@ -394,35 +383,6 @@ pub const X_OK = 1; // test for execute or search permission
|
||||
pub const W_OK = 2; // test for write permission
|
||||
pub const R_OK = 4; // test for read permission
|
||||
|
||||
pub const O = struct {
|
||||
pub const RDONLY = 0;
|
||||
pub const NDELAY = NONBLOCK;
|
||||
pub const WRONLY = 1;
|
||||
pub const RDWR = 2;
|
||||
pub const ACCMODE = 3;
|
||||
pub const NONBLOCK = 4;
|
||||
pub const APPEND = 8;
|
||||
pub const SHLOCK = 16;
|
||||
pub const EXLOCK = 32;
|
||||
pub const ASYNC = 64;
|
||||
pub const FSYNC = 128;
|
||||
pub const SYNC = 128;
|
||||
pub const NOFOLLOW = 256;
|
||||
pub const CREAT = 512;
|
||||
pub const TRUNC = 1024;
|
||||
pub const EXCL = 2048;
|
||||
pub const NOCTTY = 32768;
|
||||
pub const DIRECT = 65536;
|
||||
pub const CLOEXEC = 131072;
|
||||
pub const FBLOCKING = 262144;
|
||||
pub const FNONBLOCKING = 524288;
|
||||
pub const FAPPEND = 1048576;
|
||||
pub const FOFFSET = 2097152;
|
||||
pub const FSYNCWRITE = 4194304;
|
||||
pub const FASYNCWRITE = 8388608;
|
||||
pub const DIRECTORY = 134217728;
|
||||
};
|
||||
|
||||
pub const SEEK = struct {
|
||||
pub const SET = 0;
|
||||
pub const CUR = 1;
|
||||
@ -458,24 +418,16 @@ pub const F = struct {
|
||||
|
||||
pub const FD_CLOEXEC = 1;
|
||||
|
||||
pub const AT = struct {
|
||||
pub const FDCWD = -328243;
|
||||
pub const SYMLINK_NOFOLLOW = 1;
|
||||
pub const REMOVEDIR = 2;
|
||||
pub const EACCESS = 4;
|
||||
pub const SYMLINK_FOLLOW = 8;
|
||||
};
|
||||
|
||||
pub const dirent = extern struct {
|
||||
d_fileno: c_ulong,
|
||||
d_namlen: u16,
|
||||
d_type: u8,
|
||||
d_unused1: u8,
|
||||
d_unused2: u32,
|
||||
d_name: [256]u8,
|
||||
fileno: c_ulong,
|
||||
namlen: u16,
|
||||
type: u8,
|
||||
unused1: u8,
|
||||
unused2: u32,
|
||||
name: [256]u8,
|
||||
|
||||
pub fn reclen(self: dirent) u16 {
|
||||
return (@offsetOf(dirent, "d_name") + self.d_namlen + 1 + 7) & ~@as(u16, 7);
|
||||
return (@offsetOf(dirent, "name") + self.namlen + 1 + 7) & ~@as(u16, 7);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -3,7 +3,6 @@ const maxInt = std.math.maxInt;
|
||||
const emscripten = std.os.emscripten;
|
||||
|
||||
pub const AF = emscripten.AF;
|
||||
pub const AT = emscripten.AT;
|
||||
pub const CLOCK = emscripten.CLOCK;
|
||||
pub const CPU_COUNT = emscripten.CPU_COUNT;
|
||||
pub const E = emscripten.E;
|
||||
@ -19,7 +18,6 @@ pub const MADV = emscripten.MADV;
|
||||
pub const MSF = emscripten.MSF;
|
||||
pub const MSG = emscripten.MSG;
|
||||
pub const NAME_MAX = emscripten.NAME_MAX;
|
||||
pub const O = emscripten.O;
|
||||
pub const PATH_MAX = emscripten.PATH_MAX;
|
||||
pub const POLL = emscripten.POLL;
|
||||
pub const PROT = emscripten.PROT;
|
||||
@ -159,19 +157,6 @@ pub const pthread_attr_t = extern struct {
|
||||
__align: c_long,
|
||||
};
|
||||
|
||||
pub const pthread_mutex_t = extern struct {
|
||||
size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(4) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
|
||||
};
|
||||
pub const pthread_cond_t = extern struct {
|
||||
size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,
|
||||
};
|
||||
pub const pthread_rwlock_t = extern struct {
|
||||
size: [32]u8 align(4) = [_]u8{0} ** 32,
|
||||
};
|
||||
|
||||
const __SIZEOF_PTHREAD_COND_T = 48;
|
||||
const __SIZEOF_PTHREAD_MUTEX_T = 24;
|
||||
|
||||
pub const pthread_key_t = c_uint;
|
||||
pub const sem_t = extern struct {
|
||||
__size: [__SIZEOF_SEM_T]u8 align(@alignOf(usize)),
|
||||
@ -189,9 +174,9 @@ pub const RTLD = struct {
|
||||
};
|
||||
|
||||
pub const dirent = struct {
|
||||
d_ino: c_uint,
|
||||
d_off: c_uint,
|
||||
d_reclen: c_ushort,
|
||||
d_type: u8,
|
||||
d_name: [256]u8,
|
||||
ino: c_uint,
|
||||
off: c_uint,
|
||||
reclen: c_ushort,
|
||||
type: u8,
|
||||
name: [256]u8,
|
||||
};
|
||||
|
@ -44,16 +44,6 @@ pub extern "c" fn sendfile(
|
||||
pub const dl_iterate_phdr_callback = *const fn (info: *dl_phdr_info, size: usize, data: ?*anyopaque) callconv(.C) c_int;
|
||||
pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*anyopaque) c_int;
|
||||
|
||||
pub const pthread_mutex_t = extern struct {
|
||||
inner: ?*anyopaque = null,
|
||||
};
|
||||
pub const pthread_cond_t = extern struct {
|
||||
inner: ?*anyopaque = null,
|
||||
};
|
||||
pub const pthread_rwlock_t = extern struct {
|
||||
ptr: ?*anyopaque = null,
|
||||
};
|
||||
|
||||
pub const pthread_attr_t = extern struct {
|
||||
inner: ?*anyopaque = null,
|
||||
};
|
||||
@ -376,23 +366,19 @@ pub const timeval = extern struct {
|
||||
|
||||
pub const dirent = extern struct {
|
||||
/// File number of entry.
|
||||
d_fileno: ino_t,
|
||||
fileno: ino_t,
|
||||
/// Directory offset of entry.
|
||||
d_off: off_t,
|
||||
off: off_t,
|
||||
/// Length of this record.
|
||||
d_reclen: u16,
|
||||
reclen: u16,
|
||||
/// File type, one of DT_.
|
||||
d_type: u8,
|
||||
_d_pad0: u8,
|
||||
/// Length of the d_name member.
|
||||
d_namlen: u16,
|
||||
_d_pad1: u16,
|
||||
type: u8,
|
||||
pad0: u8 = 0,
|
||||
/// Length of the name member.
|
||||
namlen: u16,
|
||||
pad1: u16 = 0,
|
||||
/// Name of entry.
|
||||
d_name: [255:0]u8,
|
||||
|
||||
pub fn reclen(self: dirent) u16 {
|
||||
return self.d_reclen;
|
||||
}
|
||||
name: [255:0]u8,
|
||||
};
|
||||
|
||||
pub const in_port_t = u16;
|
||||
@ -746,36 +732,6 @@ pub const X_OK = 1; // test for execute or search permission
|
||||
pub const W_OK = 2; // test for write permission
|
||||
pub const R_OK = 4; // test for read permission
|
||||
|
||||
pub const O = struct {
|
||||
pub const RDONLY = 0x0000;
|
||||
pub const WRONLY = 0x0001;
|
||||
pub const RDWR = 0x0002;
|
||||
pub const ACCMODE = 0x0003;
|
||||
|
||||
pub const SHLOCK = 0x0010;
|
||||
pub const EXLOCK = 0x0020;
|
||||
|
||||
pub const CREAT = 0x0200;
|
||||
pub const EXCL = 0x0800;
|
||||
pub const NOCTTY = 0x8000;
|
||||
pub const TRUNC = 0x0400;
|
||||
pub const APPEND = 0x0008;
|
||||
pub const NONBLOCK = 0x0004;
|
||||
pub const DSYNC = 0o10000;
|
||||
pub const SYNC = 0x0080;
|
||||
pub const RSYNC = 0o4010000;
|
||||
pub const DIRECTORY = 0x20000;
|
||||
pub const NOFOLLOW = 0x0100;
|
||||
pub const CLOEXEC = 0x00100000;
|
||||
|
||||
pub const ASYNC = 0x0040;
|
||||
pub const DIRECT = 0x00010000;
|
||||
pub const NOATIME = 0o1000000;
|
||||
pub const PATH = 0o10000000;
|
||||
pub const TMPFILE = 0o20200000;
|
||||
pub const NDELAY = NONBLOCK;
|
||||
};
|
||||
|
||||
/// Command flags for fcntl(2).
|
||||
pub const F = struct {
|
||||
/// Duplicate file descriptor.
|
||||
@ -1573,23 +1529,6 @@ pub const S = struct {
|
||||
|
||||
pub const HOST_NAME_MAX = 255;
|
||||
|
||||
pub const AT = struct {
|
||||
/// Magic value that specify the use of the current working directory
|
||||
/// to determine the target of relative file paths in the openat() and
|
||||
/// similar syscalls.
|
||||
pub const FDCWD = -100;
|
||||
/// Check access using effective user and group ID
|
||||
pub const EACCESS = 0x0100;
|
||||
/// Do not follow symbolic links
|
||||
pub const SYMLINK_NOFOLLOW = 0x0200;
|
||||
/// Follow symbolic link
|
||||
pub const SYMLINK_FOLLOW = 0x0400;
|
||||
/// Remove directory instead of file
|
||||
pub const REMOVEDIR = 0x0800;
|
||||
/// Fail if not under dirfd
|
||||
pub const BENEATH = 0x1000;
|
||||
};
|
||||
|
||||
pub const addrinfo = extern struct {
|
||||
flags: i32,
|
||||
family: i32,
|
||||
|
@ -1,11 +0,0 @@
|
||||
pub const pthread_mutex_t = extern struct {
|
||||
size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
|
||||
};
|
||||
pub const pthread_cond_t = extern struct {
|
||||
size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,
|
||||
};
|
||||
pub const pthread_rwlock_t = extern struct {
|
||||
size: [56]u8 align(@alignOf(usize)) = [_]u8{0} ** 56,
|
||||
};
|
||||
const __SIZEOF_PTHREAD_COND_T = 48;
|
||||
const __SIZEOF_PTHREAD_MUTEX_T = 40;
|
@ -45,22 +45,6 @@ pub const pthread_attr_t = extern struct {
|
||||
__stack_address: ?*anyopaque,
|
||||
};
|
||||
|
||||
pub const pthread_mutex_t = extern struct {
|
||||
flags: u32 = 0,
|
||||
lock: i32 = 0,
|
||||
unused: i32 = -42,
|
||||
owner: i32 = -1,
|
||||
owner_count: i32 = 0,
|
||||
};
|
||||
|
||||
pub const pthread_cond_t = extern struct {
|
||||
flags: u32 = 0,
|
||||
unused: i32 = -42,
|
||||
mutex: ?*anyopaque = null,
|
||||
waiter_count: i32 = 0,
|
||||
lock: i32 = 0,
|
||||
};
|
||||
|
||||
pub const EAI = enum(c_int) {
|
||||
/// address family for hostname not supported
|
||||
ADDRFAMILY = 1,
|
||||
@ -238,16 +222,12 @@ pub const timespec = extern struct {
|
||||
};
|
||||
|
||||
pub const dirent = extern struct {
|
||||
d_dev: i32,
|
||||
d_pdev: i32,
|
||||
d_ino: i64,
|
||||
d_pino: i64,
|
||||
d_reclen: u16,
|
||||
d_name: [256]u8,
|
||||
|
||||
pub fn reclen(self: dirent) u16 {
|
||||
return self.d_reclen;
|
||||
}
|
||||
dev: i32,
|
||||
pdev: i32,
|
||||
ino: i64,
|
||||
pino: i64,
|
||||
reclen: u16,
|
||||
name: [256]u8,
|
||||
};
|
||||
|
||||
pub const B_OS_NAME_LENGTH = 32; // OS.h
|
||||
@ -510,32 +490,6 @@ pub const X_OK = 1; // test for execute or search permission
|
||||
pub const W_OK = 2; // test for write permission
|
||||
pub const R_OK = 4; // test for read permission
|
||||
|
||||
pub const O = struct {
|
||||
pub const RDONLY = 0x0000;
|
||||
pub const WRONLY = 0x0001;
|
||||
pub const RDWR = 0x0002;
|
||||
pub const ACCMODE = 0x0003;
|
||||
pub const RWMASK = ACCMODE;
|
||||
|
||||
pub const EXCL = 0x0100;
|
||||
pub const CREAT = 0x0200;
|
||||
pub const TRUNC = 0x0400;
|
||||
pub const NOCTTY = 0x1000;
|
||||
pub const NOTRAVERSE = 0x2000;
|
||||
|
||||
pub const CLOEXEC = 0x00000040;
|
||||
pub const NONBLOCK = 0x00000080;
|
||||
pub const NDELAY = NONBLOCK;
|
||||
pub const APPEND = 0x00000800;
|
||||
pub const SYNC = 0x00010000;
|
||||
pub const RSYNC = 0x00020000;
|
||||
pub const DSYNC = 0x00040000;
|
||||
pub const NOFOLLOW = 0x00080000;
|
||||
pub const DIRECT = 0x00100000;
|
||||
pub const NOCACHE = DIRECT;
|
||||
pub const DIRECTORY = 0x00200000;
|
||||
};
|
||||
|
||||
pub const F = struct {
|
||||
pub const DUPFD = 0x0001;
|
||||
pub const GETFD = 0x0002;
|
||||
@ -923,14 +877,6 @@ pub const S = struct {
|
||||
|
||||
pub const HOST_NAME_MAX = 255;
|
||||
|
||||
pub const AT = struct {
|
||||
pub const FDCWD = -1;
|
||||
pub const SYMLINK_NOFOLLOW = 0x01;
|
||||
pub const SYMLINK_FOLLOW = 0x02;
|
||||
pub const REMOVEDIR = 0x04;
|
||||
pub const EACCESS = 0x08;
|
||||
};
|
||||
|
||||
pub const addrinfo = extern struct {
|
||||
flags: i32,
|
||||
family: i32,
|
||||
|
@ -1,12 +0,0 @@
|
||||
const std = @import("std");
|
||||
const maxInt = std.math.maxInt;
|
||||
|
||||
pub const pthread_mutex_t = extern struct {
|
||||
inner: usize = ~@as(usize, 0),
|
||||
};
|
||||
pub const pthread_cond_t = extern struct {
|
||||
inner: usize = ~@as(usize, 0),
|
||||
};
|
||||
pub const pthread_rwlock_t = extern struct {
|
||||
ptr: usize = maxInt(usize),
|
||||
};
|
@ -9,7 +9,6 @@ const FILE = std.c.FILE;
|
||||
|
||||
pub const AF = linux.AF;
|
||||
pub const ARCH = linux.ARCH;
|
||||
pub const AT = linux.AT;
|
||||
pub const CLOCK = linux.CLOCK;
|
||||
pub const CPU_COUNT = linux.CPU_COUNT;
|
||||
pub const E = linux.E;
|
||||
@ -28,7 +27,6 @@ pub const MSF = linux.MSF;
|
||||
pub const MMAP2_UNIT = linux.MMAP2_UNIT;
|
||||
pub const MSG = linux.MSG;
|
||||
pub const NAME_MAX = linux.NAME_MAX;
|
||||
pub const O = linux.O;
|
||||
pub const PATH_MAX = linux.PATH_MAX;
|
||||
pub const POLL = linux.POLL;
|
||||
pub const PROT = linux.PROT;
|
||||
@ -241,8 +239,8 @@ pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int;
|
||||
pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int;
|
||||
pub extern "c" fn lseek64(fd: fd_t, offset: i64, whence: c_int) i64;
|
||||
pub extern "c" fn mmap64(addr: ?*align(std.mem.page_size) anyopaque, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: i64) *anyopaque;
|
||||
pub extern "c" fn open64(path: [*:0]const u8, oflag: c_uint, ...) c_int;
|
||||
pub extern "c" fn openat64(fd: c_int, path: [*:0]const u8, oflag: c_uint, ...) c_int;
|
||||
pub extern "c" fn open64(path: [*:0]const u8, oflag: linux.O, ...) c_int;
|
||||
pub extern "c" fn openat64(fd: c_int, path: [*:0]const u8, oflag: linux.O, ...) c_int;
|
||||
pub extern "c" fn pread64(fd: fd_t, buf: [*]u8, nbyte: usize, offset: i64) isize;
|
||||
pub extern "c" fn preadv64(fd: c_int, iov: [*]const iovec, iovcnt: c_uint, offset: i64) isize;
|
||||
pub extern "c" fn pwrite64(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: i64) isize;
|
||||
@ -277,7 +275,7 @@ pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*an
|
||||
pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
|
||||
|
||||
pub extern "c" fn memfd_create(name: [*:0]const u8, flags: c_uint) c_int;
|
||||
pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;
|
||||
pub extern "c" fn pipe2(fds: *[2]fd_t, flags: linux.O) c_int;
|
||||
|
||||
pub extern "c" fn fallocate(fd: fd_t, mode: c_int, offset: off_t, len: off_t) c_int;
|
||||
|
||||
@ -313,43 +311,11 @@ pub const pthread_attr_t = extern struct {
|
||||
__align: c_long,
|
||||
};
|
||||
|
||||
pub const pthread_mutex_t = extern struct {
|
||||
size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
|
||||
};
|
||||
pub const pthread_cond_t = extern struct {
|
||||
size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,
|
||||
};
|
||||
pub const pthread_rwlock_t = switch (native_abi) {
|
||||
.android => switch (@sizeOf(usize)) {
|
||||
4 => extern struct {
|
||||
size: [40]u8 align(@alignOf(usize)) = [_]u8{0} ** 40,
|
||||
},
|
||||
8 => extern struct {
|
||||
size: [56]u8 align(@alignOf(usize)) = [_]u8{0} ** 56,
|
||||
},
|
||||
else => @compileError("impossible pointer size"),
|
||||
},
|
||||
else => extern struct {
|
||||
size: [56]u8 align(@alignOf(usize)) = [_]u8{0} ** 56,
|
||||
},
|
||||
};
|
||||
pub const pthread_key_t = c_uint;
|
||||
pub const sem_t = extern struct {
|
||||
__size: [__SIZEOF_SEM_T]u8 align(@alignOf(usize)),
|
||||
};
|
||||
|
||||
const __SIZEOF_PTHREAD_COND_T = 48;
|
||||
const __SIZEOF_PTHREAD_MUTEX_T = switch (native_abi) {
|
||||
.musl, .musleabi, .musleabihf => if (@sizeOf(usize) == 8) 40 else 24,
|
||||
.gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => switch (native_arch) {
|
||||
.aarch64 => 48,
|
||||
.x86_64 => if (native_abi == .gnux32) 40 else 32,
|
||||
.mips64, .powerpc64, .powerpc64le, .sparc64 => 40,
|
||||
else => if (@sizeOf(usize) == 8) 40 else 24,
|
||||
},
|
||||
.android => if (@sizeOf(usize) == 8) 40 else 4,
|
||||
else => @compileError("unsupported ABI"),
|
||||
};
|
||||
const __SIZEOF_SEM_T = 4 * @sizeOf(usize);
|
||||
|
||||
pub extern "c" fn pthread_setname_np(thread: std.c.pthread_t, name: [*:0]const u8) E;
|
||||
@ -365,16 +331,16 @@ pub const RTLD = struct {
|
||||
};
|
||||
|
||||
pub const dirent = struct {
|
||||
d_ino: c_uint,
|
||||
d_off: c_uint,
|
||||
d_reclen: c_ushort,
|
||||
d_type: u8,
|
||||
d_name: [256]u8,
|
||||
ino: c_uint,
|
||||
off: c_uint,
|
||||
reclen: c_ushort,
|
||||
type: u8,
|
||||
name: [256]u8,
|
||||
};
|
||||
pub const dirent64 = struct {
|
||||
d_ino: c_ulong,
|
||||
d_off: c_ulong,
|
||||
d_reclen: c_ushort,
|
||||
d_type: u8,
|
||||
d_name: [256]u8,
|
||||
ino: c_ulong,
|
||||
off: c_ulong,
|
||||
reclen: c_ushort,
|
||||
type: u8,
|
||||
name: [256]u8,
|
||||
};
|
||||
|
@ -1,18 +0,0 @@
|
||||
const builtin = @import("builtin");
|
||||
pub const pthread_mutex_t = extern struct {
|
||||
size: [__SIZEOF_PTHREAD_MUTEX_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_MUTEX_T,
|
||||
};
|
||||
pub const pthread_cond_t = extern struct {
|
||||
size: [__SIZEOF_PTHREAD_COND_T]u8 align(@alignOf(usize)) = [_]u8{0} ** __SIZEOF_PTHREAD_COND_T,
|
||||
};
|
||||
const __SIZEOF_PTHREAD_COND_T = 48;
|
||||
const __SIZEOF_PTHREAD_MUTEX_T = switch (builtin.abi) {
|
||||
.musl, .musleabi, .musleabihf => if (@sizeOf(usize) == 8) 40 else 24,
|
||||
.gnu, .gnuabin32, .gnuabi64, .gnueabi, .gnueabihf, .gnux32 => switch (builtin.cpu.arch) {
|
||||
.aarch64 => 48,
|
||||
.x86_64 => if (builtin.abi == .gnux32) 40 else 32,
|
||||
.mips64, .powerpc64, .powerpc64le, .sparc64 => 40,
|
||||
else => if (@sizeOf(usize) == 8) 40 else 24,
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
@ -18,9 +18,6 @@ pub extern "c" fn _lwp_self() lwpid_t;
|
||||
pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;
|
||||
pub extern "c" fn arc4random_buf(buf: [*]u8, len: usize) void;
|
||||
|
||||
pub extern "c" fn __fstat50(fd: fd_t, buf: *Stat) c_int;
|
||||
pub const fstat = __fstat50;
|
||||
|
||||
pub extern "c" fn __stat50(path: [*:0]const u8, buf: *Stat) c_int;
|
||||
pub const stat = __stat50;
|
||||
|
||||
@ -62,41 +59,6 @@ pub extern "c" fn posix_memalign(memptr: *?*anyopaque, alignment: usize, size: u
|
||||
pub extern "c" fn __msync13(addr: *align(std.mem.page_size) const anyopaque, len: usize, flags: c_int) c_int;
|
||||
pub const msync = __msync13;
|
||||
|
||||
pub const pthread_mutex_t = extern struct {
|
||||
magic: u32 = 0x33330003,
|
||||
errorcheck: padded_pthread_spin_t = 0,
|
||||
ceiling: padded_pthread_spin_t = 0,
|
||||
owner: usize = 0,
|
||||
waiters: ?*u8 = null,
|
||||
recursed: u32 = 0,
|
||||
spare2: ?*anyopaque = null,
|
||||
};
|
||||
|
||||
pub const pthread_cond_t = extern struct {
|
||||
magic: u32 = 0x55550005,
|
||||
lock: pthread_spin_t = 0,
|
||||
waiters_first: ?*u8 = null,
|
||||
waiters_last: ?*u8 = null,
|
||||
mutex: ?*pthread_mutex_t = null,
|
||||
private: ?*anyopaque = null,
|
||||
};
|
||||
|
||||
pub const pthread_rwlock_t = extern struct {
|
||||
magic: c_uint = 0x99990009,
|
||||
interlock: switch (builtin.cpu.arch) {
|
||||
.aarch64, .sparc, .x86_64, .x86 => u8,
|
||||
.arm, .powerpc => c_int,
|
||||
else => unreachable,
|
||||
} = 0,
|
||||
rblocked_first: ?*u8 = null,
|
||||
rblocked_last: ?*u8 = null,
|
||||
wblocked_first: ?*u8 = null,
|
||||
wblocked_last: ?*u8 = null,
|
||||
nreaders: c_uint = 0,
|
||||
owner: ?std.c.pthread_t = null,
|
||||
private: ?*anyopaque = null,
|
||||
};
|
||||
|
||||
const pthread_spin_t = switch (builtin.cpu.arch) {
|
||||
.aarch64, .aarch64_be, .aarch64_32 => u8,
|
||||
.mips, .mipsel, .mips64, .mips64el => u32,
|
||||
@ -337,15 +299,11 @@ pub const timeval = extern struct {
|
||||
pub const MAXNAMLEN = 511;
|
||||
|
||||
pub const dirent = extern struct {
|
||||
d_fileno: ino_t,
|
||||
d_reclen: u16,
|
||||
d_namlen: u16,
|
||||
d_type: u8,
|
||||
d_name: [MAXNAMLEN + 1]u8,
|
||||
|
||||
pub fn reclen(self: dirent) u16 {
|
||||
return self.d_reclen;
|
||||
}
|
||||
fileno: ino_t,
|
||||
reclen: u16,
|
||||
namlen: u16,
|
||||
type: u8,
|
||||
name: [MAXNAMLEN + 1]u8,
|
||||
};
|
||||
|
||||
pub const SOCK = struct {
|
||||
@ -630,53 +588,6 @@ pub const X_OK = 1; // test for execute or search permission
|
||||
pub const W_OK = 2; // test for write permission
|
||||
pub const R_OK = 4; // test for read permission
|
||||
|
||||
pub const O = struct {
|
||||
/// open for reading only
|
||||
pub const RDONLY = 0x00000000;
|
||||
/// open for writing only
|
||||
pub const WRONLY = 0x00000001;
|
||||
/// open for reading and writing
|
||||
pub const RDWR = 0x00000002;
|
||||
/// mask for above modes
|
||||
pub const ACCMODE = 0x00000003;
|
||||
/// no delay
|
||||
pub const NONBLOCK = 0x00000004;
|
||||
/// set append mode
|
||||
pub const APPEND = 0x00000008;
|
||||
/// open with shared file lock
|
||||
pub const SHLOCK = 0x00000010;
|
||||
/// open with exclusive file lock
|
||||
pub const EXLOCK = 0x00000020;
|
||||
/// signal pgrp when data ready
|
||||
pub const ASYNC = 0x00000040;
|
||||
/// synchronous writes
|
||||
pub const SYNC = 0x00000080;
|
||||
/// don't follow symlinks on the last
|
||||
pub const NOFOLLOW = 0x00000100;
|
||||
/// create if nonexistent
|
||||
pub const CREAT = 0x00000200;
|
||||
/// truncate to zero length
|
||||
pub const TRUNC = 0x00000400;
|
||||
/// error if already exists
|
||||
pub const EXCL = 0x00000800;
|
||||
/// don't assign controlling terminal
|
||||
pub const NOCTTY = 0x00008000;
|
||||
/// write: I/O data completion
|
||||
pub const DSYNC = 0x00010000;
|
||||
/// read: I/O completion as for write
|
||||
pub const RSYNC = 0x00020000;
|
||||
/// use alternate i/o semantics
|
||||
pub const ALT_IO = 0x00040000;
|
||||
/// direct I/O hint
|
||||
pub const DIRECT = 0x00080000;
|
||||
/// fail if not a directory
|
||||
pub const DIRECTORY = 0x00200000;
|
||||
/// set close on exec
|
||||
pub const CLOEXEC = 0x00400000;
|
||||
/// skip search permission checks
|
||||
pub const SEARCH = 0x00800000;
|
||||
};
|
||||
|
||||
pub const F = struct {
|
||||
pub const DUPFD = 0;
|
||||
pub const GETFD = 1;
|
||||
@ -1466,21 +1377,6 @@ pub const S = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const AT = struct {
|
||||
/// Magic value that specify the use of the current working directory
|
||||
/// to determine the target of relative file paths in the openat() and
|
||||
/// similar syscalls.
|
||||
pub const FDCWD = -100;
|
||||
/// Check access using effective user and group ID
|
||||
pub const EACCESS = 0x0100;
|
||||
/// Do not follow symbolic links
|
||||
pub const SYMLINK_NOFOLLOW = 0x0200;
|
||||
/// Follow symbolic link
|
||||
pub const SYMLINK_FOLLOW = 0x0400;
|
||||
/// Remove directory instead of file
|
||||
pub const REMOVEDIR = 0x0800;
|
||||
};
|
||||
|
||||
pub const HOST_NAME_MAX = 255;
|
||||
|
||||
pub const IPPROTO = struct {
|
||||
|
@ -19,15 +19,6 @@ pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;
|
||||
pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) c_int;
|
||||
pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
|
||||
|
||||
pub const pthread_mutex_t = extern struct {
|
||||
inner: ?*anyopaque = null,
|
||||
};
|
||||
pub const pthread_cond_t = extern struct {
|
||||
inner: ?*anyopaque = null,
|
||||
};
|
||||
pub const pthread_rwlock_t = extern struct {
|
||||
ptr: ?*anyopaque = null,
|
||||
};
|
||||
pub const pthread_spinlock_t = extern struct {
|
||||
inner: ?*anyopaque = null,
|
||||
};
|
||||
@ -336,17 +327,13 @@ pub const timezone = extern struct {
|
||||
pub const MAXNAMLEN = 255;
|
||||
|
||||
pub const dirent = extern struct {
|
||||
d_fileno: ino_t,
|
||||
d_off: off_t,
|
||||
d_reclen: u16,
|
||||
d_type: u8,
|
||||
d_namlen: u8,
|
||||
__d_padding: [4]u8,
|
||||
d_name: [MAXNAMLEN + 1]u8,
|
||||
|
||||
pub fn reclen(self: dirent) u16 {
|
||||
return self.d_reclen;
|
||||
}
|
||||
fileno: ino_t,
|
||||
off: off_t,
|
||||
reclen: u16,
|
||||
type: u8,
|
||||
namlen: u8,
|
||||
_: u32 align(1) = 0,
|
||||
name: [MAXNAMLEN + 1]u8,
|
||||
};
|
||||
|
||||
pub const in_port_t = u16;
|
||||
@ -489,47 +476,6 @@ pub const X_OK = 1; // test for execute or search permission
|
||||
pub const W_OK = 2; // test for write permission
|
||||
pub const R_OK = 4; // test for read permission
|
||||
|
||||
pub const O = struct {
|
||||
/// open for reading only
|
||||
pub const RDONLY = 0x00000000;
|
||||
/// open for writing only
|
||||
pub const WRONLY = 0x00000001;
|
||||
/// open for reading and writing
|
||||
pub const RDWR = 0x00000002;
|
||||
/// mask for above modes
|
||||
pub const ACCMODE = 0x00000003;
|
||||
/// no delay
|
||||
pub const NONBLOCK = 0x00000004;
|
||||
/// set append mode
|
||||
pub const APPEND = 0x00000008;
|
||||
/// open with shared file lock
|
||||
pub const SHLOCK = 0x00000010;
|
||||
/// open with exclusive file lock
|
||||
pub const EXLOCK = 0x00000020;
|
||||
/// signal pgrp when data ready
|
||||
pub const ASYNC = 0x00000040;
|
||||
/// synchronous writes
|
||||
pub const SYNC = 0x00000080;
|
||||
/// don't follow symlinks on the last
|
||||
pub const NOFOLLOW = 0x00000100;
|
||||
/// create if nonexistent
|
||||
pub const CREAT = 0x00000200;
|
||||
/// truncate to zero length
|
||||
pub const TRUNC = 0x00000400;
|
||||
/// error if already exists
|
||||
pub const EXCL = 0x00000800;
|
||||
/// don't assign controlling terminal
|
||||
pub const NOCTTY = 0x00008000;
|
||||
/// write: I/O data completion
|
||||
pub const DSYNC = SYNC;
|
||||
/// read: I/O completion as for write
|
||||
pub const RSYNC = SYNC;
|
||||
/// fail if not a directory
|
||||
pub const DIRECTORY = 0x20000;
|
||||
/// set close on exec
|
||||
pub const CLOEXEC = 0x10000;
|
||||
};
|
||||
|
||||
pub const F = struct {
|
||||
pub const DUPFD = 0;
|
||||
pub const GETFD = 1;
|
||||
@ -1312,21 +1258,6 @@ pub const S = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const AT = struct {
|
||||
/// Magic value that specify the use of the current working directory
|
||||
/// to determine the target of relative file paths in the openat() and
|
||||
/// similar syscalls.
|
||||
pub const FDCWD = -100;
|
||||
/// Check access using effective user and group ID
|
||||
pub const EACCESS = 0x01;
|
||||
/// Do not follow symbolic links
|
||||
pub const SYMLINK_NOFOLLOW = 0x02;
|
||||
/// Follow symbolic link
|
||||
pub const SYMLINK_FOLLOW = 0x04;
|
||||
/// Remove directory instead of file
|
||||
pub const REMOVEDIR = 0x08;
|
||||
};
|
||||
|
||||
pub const HOST_NAME_MAX = 255;
|
||||
|
||||
pub const IPPROTO = struct {
|
||||
|
@ -21,29 +21,6 @@ pub extern "c" fn sysconf(sc: c_int) i64;
|
||||
pub extern "c" fn signalfd(fd: fd_t, mask: *const sigset_t, flags: u32) c_int;
|
||||
pub extern "c" fn madvise(address: [*]u8, len: usize, advise: u32) c_int;
|
||||
|
||||
pub const pthread_mutex_t = extern struct {
|
||||
flag1: u16 = 0,
|
||||
flag2: u8 = 0,
|
||||
ceiling: u8 = 0,
|
||||
type: u16 = 0,
|
||||
magic: u16 = 0x4d58,
|
||||
lock: u64 = 0,
|
||||
data: u64 = 0,
|
||||
};
|
||||
pub const pthread_cond_t = extern struct {
|
||||
flag: [4]u8 = [_]u8{0} ** 4,
|
||||
type: u16 = 0,
|
||||
magic: u16 = 0x4356,
|
||||
data: u64 = 0,
|
||||
};
|
||||
pub const pthread_rwlock_t = extern struct {
|
||||
readers: i32 = 0,
|
||||
type: u16 = 0,
|
||||
magic: u16 = 0x5257,
|
||||
mutex: pthread_mutex_t = .{},
|
||||
readercv: pthread_cond_t = .{},
|
||||
writercv: pthread_cond_t = .{},
|
||||
};
|
||||
pub const pthread_attr_t = extern struct {
|
||||
mutexattr: ?*anyopaque = null,
|
||||
};
|
||||
@ -266,17 +243,13 @@ pub const MAXNAMLEN = 511;
|
||||
|
||||
pub const dirent = extern struct {
|
||||
/// Inode number of entry.
|
||||
d_ino: ino_t,
|
||||
ino: ino_t,
|
||||
/// Offset of this entry on disk.
|
||||
d_off: off_t,
|
||||
off: off_t,
|
||||
/// Length of this record.
|
||||
d_reclen: u16,
|
||||
reclen: u16,
|
||||
/// File name.
|
||||
d_name: [MAXNAMLEN:0]u8,
|
||||
|
||||
pub fn reclen(self: dirent) u16 {
|
||||
return self.d_reclen;
|
||||
}
|
||||
name: [MAXNAMLEN:0]u8,
|
||||
};
|
||||
|
||||
pub const SOCK = struct {
|
||||
@ -708,32 +681,6 @@ pub const F = struct {
|
||||
pub const RMDNY = 0x4;
|
||||
};
|
||||
|
||||
pub const O = struct {
|
||||
pub const RDONLY = 0;
|
||||
pub const WRONLY = 1;
|
||||
pub const RDWR = 2;
|
||||
pub const SEARCH = 0x200000;
|
||||
pub const EXEC = 0x400000;
|
||||
pub const NDELAY = 0x04;
|
||||
pub const APPEND = 0x08;
|
||||
pub const SYNC = 0x10;
|
||||
pub const DSYNC = 0x40;
|
||||
pub const RSYNC = 0x8000;
|
||||
pub const NONBLOCK = 0x80;
|
||||
pub const LARGEFILE = 0x2000;
|
||||
|
||||
pub const CREAT = 0x100;
|
||||
pub const TRUNC = 0x200;
|
||||
pub const EXCL = 0x400;
|
||||
pub const NOCTTY = 0x800;
|
||||
pub const XATTR = 0x4000;
|
||||
pub const NOFOLLOW = 0x20000;
|
||||
pub const NOLINKS = 0x40000;
|
||||
pub const CLOEXEC = 0x800000;
|
||||
pub const DIRECTORY = 0x1000000;
|
||||
pub const DIRECT = 0x2000000;
|
||||
};
|
||||
|
||||
pub const LOCK = struct {
|
||||
pub const SH = 1;
|
||||
pub const EX = 2;
|
||||
@ -1430,23 +1377,6 @@ pub const S = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const AT = struct {
|
||||
/// Magic value that specify the use of the current working directory
|
||||
/// to determine the target of relative file paths in the openat() and
|
||||
/// similar syscalls.
|
||||
pub const FDCWD = @as(fd_t, @bitCast(@as(u32, 0xffd19553)));
|
||||
|
||||
/// Do not follow symbolic links
|
||||
pub const SYMLINK_NOFOLLOW = 0x1000;
|
||||
/// Follow symbolic link
|
||||
pub const SYMLINK_FOLLOW = 0x2000;
|
||||
/// Remove directory instead of file
|
||||
pub const REMOVEDIR = 0x1;
|
||||
pub const TRIGGER = 0x2;
|
||||
/// Check access using effective user and group ID
|
||||
pub const EACCESS = 0x4;
|
||||
};
|
||||
|
||||
pub const POSIX_FADV = struct {
|
||||
pub const NORMAL = 0;
|
||||
pub const RANDOM = 1;
|
||||
|
@ -1,6 +1,6 @@
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("../std.zig");
|
||||
const wasi = std.os.wasi;
|
||||
const FDFLAG = wasi.FDFLAG;
|
||||
|
||||
extern threadlocal var errno: c_int;
|
||||
|
||||
@ -8,42 +8,82 @@ pub fn _errno() *c_int {
|
||||
return &errno;
|
||||
}
|
||||
|
||||
pub const AT = wasi.AT;
|
||||
pub const CLOCK = wasi.CLOCK;
|
||||
pub const E = wasi.E;
|
||||
pub const IOV_MAX = wasi.IOV_MAX;
|
||||
pub const LOCK = wasi.LOCK;
|
||||
pub const S = wasi.S;
|
||||
pub const STDERR_FILENO = wasi.STDERR_FILENO;
|
||||
pub const STDIN_FILENO = wasi.STDIN_FILENO;
|
||||
pub const STDOUT_FILENO = wasi.STDOUT_FILENO;
|
||||
pub const mode_t = u32;
|
||||
pub const time_t = i64;
|
||||
|
||||
pub const timespec = extern struct {
|
||||
tv_sec: time_t,
|
||||
tv_nsec: isize,
|
||||
|
||||
pub fn fromTimestamp(tm: wasi.timestamp_t) timespec {
|
||||
const tv_sec: wasi.timestamp_t = tm / 1_000_000_000;
|
||||
const tv_nsec = tm - tv_sec * 1_000_000_000;
|
||||
return .{
|
||||
.tv_sec = @as(time_t, @intCast(tv_sec)),
|
||||
.tv_nsec = @as(isize, @intCast(tv_nsec)),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn toTimestamp(ts: timespec) wasi.timestamp_t {
|
||||
return @as(wasi.timestamp_t, @intCast(ts.tv_sec * 1_000_000_000)) +
|
||||
@as(wasi.timestamp_t, @intCast(ts.tv_nsec));
|
||||
}
|
||||
};
|
||||
|
||||
pub const STDIN_FILENO = 0;
|
||||
pub const STDOUT_FILENO = 1;
|
||||
pub const STDERR_FILENO = 2;
|
||||
|
||||
pub const E = wasi.errno_t;
|
||||
|
||||
pub const CLOCK = wasi.clockid_t;
|
||||
pub const IOV_MAX = 1024;
|
||||
pub const LOCK = struct {
|
||||
pub const SH = 0x1;
|
||||
pub const EX = 0x2;
|
||||
pub const NB = 0x4;
|
||||
pub const UN = 0x8;
|
||||
};
|
||||
pub const S = struct {
|
||||
pub const IEXEC = @compileError("TODO audit this");
|
||||
pub const IFBLK = 0x6000;
|
||||
pub const IFCHR = 0x2000;
|
||||
pub const IFDIR = 0x4000;
|
||||
pub const IFIFO = 0xc000;
|
||||
pub const IFLNK = 0xa000;
|
||||
pub const IFMT = IFBLK | IFCHR | IFDIR | IFIFO | IFLNK | IFREG | IFSOCK;
|
||||
pub const IFREG = 0x8000;
|
||||
/// There's no concept of UNIX domain socket but we define this value here
|
||||
/// in order to line with other OSes.
|
||||
pub const IFSOCK = 0x1;
|
||||
};
|
||||
pub const fd_t = wasi.fd_t;
|
||||
pub const pid_t = c_int;
|
||||
pub const uid_t = u32;
|
||||
pub const gid_t = u32;
|
||||
pub const off_t = i64;
|
||||
pub const ino_t = wasi.ino_t;
|
||||
pub const mode_t = wasi.mode_t;
|
||||
pub const time_t = wasi.time_t;
|
||||
pub const timespec = wasi.timespec;
|
||||
pub const ino_t = wasi.inode_t;
|
||||
pub const dev_t = wasi.device_t;
|
||||
pub const nlink_t = c_ulonglong;
|
||||
pub const blksize_t = c_long;
|
||||
pub const blkcnt_t = c_longlong;
|
||||
|
||||
pub const Stat = extern struct {
|
||||
dev: i32,
|
||||
dev: dev_t,
|
||||
ino: ino_t,
|
||||
nlink: u64,
|
||||
|
||||
nlink: nlink_t,
|
||||
mode: mode_t,
|
||||
uid: uid_t,
|
||||
gid: gid_t,
|
||||
__pad0: isize,
|
||||
rdev: i32,
|
||||
__pad0: c_uint = 0,
|
||||
rdev: dev_t,
|
||||
size: off_t,
|
||||
blksize: i32,
|
||||
blocks: i64,
|
||||
|
||||
blksize: blksize_t,
|
||||
blocks: blkcnt_t,
|
||||
atim: timespec,
|
||||
mtim: timespec,
|
||||
ctim: timespec,
|
||||
__reserved: [3]c_longlong = [3]c_longlong{ 0, 0, 0 },
|
||||
|
||||
pub fn atime(self: @This()) timespec {
|
||||
return self.atim;
|
||||
@ -56,30 +96,35 @@ pub const Stat = extern struct {
|
||||
pub fn ctime(self: @This()) timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
};
|
||||
|
||||
/// Derived from
|
||||
/// https://github.com/WebAssembly/wasi-libc/blob/main/expected/wasm32-wasi/predefined-macros.txt
|
||||
pub const O = struct {
|
||||
pub const ACCMODE = (EXEC | RDWR | SEARCH);
|
||||
pub const APPEND = @as(u32, FDFLAG.APPEND);
|
||||
pub const CLOEXEC = (0);
|
||||
pub const CREAT = ((1 << 0) << 12); // = __WASI_OFLAGS_CREAT << 12
|
||||
pub const DIRECTORY = ((1 << 1) << 12); // = __WASI_OFLAGS_DIRECTORY << 12
|
||||
pub const DSYNC = @as(u32, FDFLAG.DSYNC);
|
||||
pub const EXCL = ((1 << 2) << 12); // = __WASI_OFLAGS_EXCL << 12
|
||||
pub const EXEC = (0x02000000);
|
||||
pub const NOCTTY = (0);
|
||||
pub const NOFOLLOW = (0x01000000);
|
||||
pub const NONBLOCK = @as(u32, FDFLAG.NONBLOCK);
|
||||
pub const RDONLY = (0x04000000);
|
||||
pub const RDWR = (RDONLY | WRONLY);
|
||||
pub const RSYNC = @as(u32, FDFLAG.RSYNC);
|
||||
pub const SEARCH = (0x08000000);
|
||||
pub const SYNC = @as(u32, FDFLAG.SYNC);
|
||||
pub const TRUNC = ((1 << 3) << 12); // = __WASI_OFLAGS_TRUNC << 12
|
||||
pub const TTY_INIT = (0);
|
||||
pub const WRONLY = (0x10000000);
|
||||
pub fn fromFilestat(stat: wasi.filestat_t) Stat {
|
||||
return .{
|
||||
.dev = stat.dev,
|
||||
.ino = stat.ino,
|
||||
.mode = switch (stat.filetype) {
|
||||
.UNKNOWN => 0,
|
||||
.BLOCK_DEVICE => S.IFBLK,
|
||||
.CHARACTER_DEVICE => S.IFCHR,
|
||||
.DIRECTORY => S.IFDIR,
|
||||
.REGULAR_FILE => S.IFREG,
|
||||
.SOCKET_DGRAM => S.IFSOCK,
|
||||
.SOCKET_STREAM => S.IFIFO,
|
||||
.SYMBOLIC_LINK => S.IFLNK,
|
||||
_ => 0,
|
||||
},
|
||||
.nlink = stat.nlink,
|
||||
.size = @intCast(stat.size),
|
||||
.atim = timespec.fromTimestamp(stat.atim),
|
||||
.mtim = timespec.fromTimestamp(stat.mtim),
|
||||
.ctim = timespec.fromTimestamp(stat.ctim),
|
||||
|
||||
.uid = 0,
|
||||
.gid = 0,
|
||||
.rdev = 0,
|
||||
.blksize = 0,
|
||||
.blocks = 0,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const F = struct {
|
||||
|
@ -11,7 +11,6 @@ pub extern "c" fn _msize(memblock: ?*anyopaque) usize;
|
||||
// need to verify which of these is actually supported on windows
|
||||
pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int;
|
||||
pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int;
|
||||
pub extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int;
|
||||
pub extern "c" fn getrusage(who: c_int, usage: *rusage) c_int;
|
||||
pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
|
||||
pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
|
||||
@ -200,11 +199,6 @@ pub const STRUNCATE = 80;
|
||||
|
||||
pub const F_OK = 0;
|
||||
|
||||
/// Remove directory instead of unlinking file
|
||||
pub const AT = struct {
|
||||
pub const REMOVEDIR = 0x200;
|
||||
};
|
||||
|
||||
pub const in_port_t = u16;
|
||||
pub const sa_family_t = ws2_32.ADDRESS_FAMILY;
|
||||
pub const socklen_t = ws2_32.socklen_t;
|
||||
@ -229,31 +223,4 @@ pub const SOL = ws2_32.SOL;
|
||||
pub const SO = ws2_32.SO;
|
||||
pub const PVD_CONFIG = ws2_32.PVD_CONFIG;
|
||||
|
||||
pub const O = struct {
|
||||
pub const RDONLY = 0o0;
|
||||
pub const WRONLY = 0o1;
|
||||
pub const RDWR = 0o2;
|
||||
|
||||
pub const CREAT = 0o100;
|
||||
pub const EXCL = 0o200;
|
||||
pub const NOCTTY = 0o400;
|
||||
pub const TRUNC = 0o1000;
|
||||
pub const APPEND = 0o2000;
|
||||
pub const NONBLOCK = 0o4000;
|
||||
pub const DSYNC = 0o10000;
|
||||
pub const SYNC = 0o4010000;
|
||||
pub const RSYNC = 0o4010000;
|
||||
pub const DIRECTORY = 0o200000;
|
||||
pub const NOFOLLOW = 0o400000;
|
||||
pub const CLOEXEC = 0o2000000;
|
||||
|
||||
pub const ASYNC = 0o20000;
|
||||
pub const DIRECT = 0o40000;
|
||||
pub const LARGEFILE = 0;
|
||||
pub const NOATIME = 0o1000000;
|
||||
pub const PATH = 0o10000000;
|
||||
pub const TMPFILE = 0o20200000;
|
||||
pub const NDELAY = NONBLOCK;
|
||||
};
|
||||
|
||||
pub const IFNAMESIZE = 30;
|
||||
|
@ -495,7 +495,7 @@ pub const ChildProcess = struct {
|
||||
}
|
||||
|
||||
fn spawnPosix(self: *ChildProcess) SpawnError!void {
|
||||
const pipe_flags = 0;
|
||||
const pipe_flags: os.O = .{};
|
||||
const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try os.pipe2(pipe_flags) else undefined;
|
||||
errdefer if (self.stdin_behavior == StdIo.Pipe) {
|
||||
destroyPipe(stdin_pipe);
|
||||
@ -513,7 +513,7 @@ pub const ChildProcess = struct {
|
||||
|
||||
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)
|
||||
os.openZ("/dev/null", os.O.RDWR, 0) catch |err| switch (err) {
|
||||
os.openZ("/dev/null", .{ .ACCMODE = .RDWR }, 0) catch |err| switch (err) {
|
||||
error.PathAlreadyExists => unreachable,
|
||||
error.NoSpaceLeft => unreachable,
|
||||
error.FileTooBig => unreachable,
|
||||
@ -572,7 +572,7 @@ pub const ChildProcess = struct {
|
||||
// end with eventfd
|
||||
break :blk [2]os.fd_t{ fd, fd };
|
||||
} else {
|
||||
break :blk try os.pipe2(os.O.CLOEXEC);
|
||||
break :blk try os.pipe2(.{ .CLOEXEC = true });
|
||||
}
|
||||
};
|
||||
errdefer destroyPipe(err_pipe);
|
||||
|
@ -354,6 +354,10 @@ pub const DeflateFast = struct {
|
||||
};
|
||||
|
||||
test "best speed match 1/3" {
|
||||
if (@import("builtin").os.tag == .wasi) {
|
||||
// https://github.com/ziglang/zig/issues/18885
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
|
||||
{
|
||||
@ -450,6 +454,10 @@ test "best speed match 1/3" {
|
||||
}
|
||||
|
||||
test "best speed match 2/3" {
|
||||
if (@import("builtin").os.tag == .wasi) {
|
||||
// https://github.com/ziglang/zig/issues/18885
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
|
||||
{
|
||||
|
@ -115,7 +115,7 @@ pub const ElfDynLib = struct {
|
||||
|
||||
/// Trusts the file. Malicious file will be able to execute arbitrary code.
|
||||
pub fn open(path: []const u8) !ElfDynLib {
|
||||
const fd = try os.open(path, 0, os.O.RDONLY | os.O.CLOEXEC);
|
||||
const fd = try os.open(path, .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
|
||||
defer os.close(fd);
|
||||
|
||||
const stat = try os.fstat(fd);
|
||||
|
@ -62,16 +62,16 @@ pub const Iterator = switch (builtin.os.tag) {
|
||||
self.end_index = @as(usize, @intCast(rc));
|
||||
}
|
||||
const darwin_entry = @as(*align(1) posix.system.dirent, @ptrCast(&self.buf[self.index]));
|
||||
const next_index = self.index + darwin_entry.reclen();
|
||||
const next_index = self.index + darwin_entry.reclen;
|
||||
self.index = next_index;
|
||||
|
||||
const name = @as([*]u8, @ptrCast(&darwin_entry.d_name))[0..darwin_entry.d_namlen];
|
||||
const name = @as([*]u8, @ptrCast(&darwin_entry.name))[0..darwin_entry.namlen];
|
||||
|
||||
if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..") or (darwin_entry.d_ino == 0)) {
|
||||
if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..") or (darwin_entry.ino == 0)) {
|
||||
continue :start_over;
|
||||
}
|
||||
|
||||
const entry_kind: Entry.Kind = switch (darwin_entry.d_type) {
|
||||
const entry_kind: Entry.Kind = switch (darwin_entry.type) {
|
||||
posix.DT.BLK => .block_device,
|
||||
posix.DT.CHR => .character_device,
|
||||
posix.DT.DIR => .directory,
|
||||
@ -110,14 +110,14 @@ pub const Iterator = switch (builtin.os.tag) {
|
||||
self.end_index = @as(usize, @intCast(rc));
|
||||
}
|
||||
const entry = @as(*align(1) posix.system.dirent, @ptrCast(&self.buf[self.index]));
|
||||
const next_index = self.index + entry.reclen();
|
||||
const next_index = self.index + entry.reclen;
|
||||
self.index = next_index;
|
||||
|
||||
const name = mem.sliceTo(@as([*:0]u8, @ptrCast(&entry.d_name)), 0);
|
||||
const name = mem.sliceTo(@as([*:0]u8, @ptrCast(&entry.name)), 0);
|
||||
if (mem.eql(u8, name, ".") or mem.eql(u8, name, ".."))
|
||||
continue :start_over;
|
||||
|
||||
// Solaris dirent doesn't expose d_type, so we have to call stat to get it.
|
||||
// Solaris dirent doesn't expose type, so we have to call stat to get it.
|
||||
const stat_info = posix.fstatat(
|
||||
self.dir.fd,
|
||||
name,
|
||||
@ -174,23 +174,23 @@ pub const Iterator = switch (builtin.os.tag) {
|
||||
self.end_index = @as(usize, @intCast(rc));
|
||||
}
|
||||
const bsd_entry = @as(*align(1) posix.system.dirent, @ptrCast(&self.buf[self.index]));
|
||||
const next_index = self.index + bsd_entry.reclen();
|
||||
const next_index = self.index + bsd_entry.reclen;
|
||||
self.index = next_index;
|
||||
|
||||
const name = @as([*]u8, @ptrCast(&bsd_entry.d_name))[0..bsd_entry.d_namlen];
|
||||
const name = @as([*]u8, @ptrCast(&bsd_entry.name))[0..bsd_entry.namlen];
|
||||
|
||||
const skip_zero_fileno = switch (builtin.os.tag) {
|
||||
// d_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,
|
||||
else => false,
|
||||
};
|
||||
if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..") or
|
||||
(skip_zero_fileno and bsd_entry.d_fileno == 0))
|
||||
(skip_zero_fileno and bsd_entry.fileno == 0))
|
||||
{
|
||||
continue :start_over;
|
||||
}
|
||||
|
||||
const entry_kind: Entry.Kind = switch (bsd_entry.d_type) {
|
||||
const entry_kind: Entry.Kind = switch (bsd_entry.type) {
|
||||
posix.DT.BLK => .block_device,
|
||||
posix.DT.CHR => .character_device,
|
||||
posix.DT.DIR => .directory,
|
||||
@ -256,18 +256,18 @@ pub const Iterator = switch (builtin.os.tag) {
|
||||
self.end_index = @as(usize, @intCast(rc));
|
||||
}
|
||||
const haiku_entry = @as(*align(1) posix.system.dirent, @ptrCast(&self.buf[self.index]));
|
||||
const next_index = self.index + haiku_entry.reclen();
|
||||
const next_index = self.index + haiku_entry.reclen;
|
||||
self.index = next_index;
|
||||
const name = mem.sliceTo(@as([*:0]u8, @ptrCast(&haiku_entry.d_name)), 0);
|
||||
const name = mem.sliceTo(@as([*:0]u8, @ptrCast(&haiku_entry.name)), 0);
|
||||
|
||||
if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..") or (haiku_entry.d_ino == 0)) {
|
||||
if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..") or (haiku_entry.ino == 0)) {
|
||||
continue :start_over;
|
||||
}
|
||||
|
||||
var stat_info: posix.Stat = undefined;
|
||||
const rc = posix.system._kern_read_stat(
|
||||
self.dir.fd,
|
||||
&haiku_entry.d_name,
|
||||
&haiku_entry.name,
|
||||
false,
|
||||
&stat_info,
|
||||
0,
|
||||
@ -359,17 +359,17 @@ pub const Iterator = switch (builtin.os.tag) {
|
||||
self.end_index = rc;
|
||||
}
|
||||
const linux_entry = @as(*align(1) linux.dirent64, @ptrCast(&self.buf[self.index]));
|
||||
const next_index = self.index + linux_entry.reclen();
|
||||
const next_index = self.index + linux_entry.reclen;
|
||||
self.index = next_index;
|
||||
|
||||
const name = mem.sliceTo(@as([*:0]u8, @ptrCast(&linux_entry.d_name)), 0);
|
||||
const name = mem.sliceTo(@as([*:0]u8, @ptrCast(&linux_entry.name)), 0);
|
||||
|
||||
// skip . and .. entries
|
||||
if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
|
||||
continue :start_over;
|
||||
}
|
||||
|
||||
const entry_kind: Entry.Kind = switch (linux_entry.d_type) {
|
||||
const entry_kind: Entry.Kind = switch (linux_entry.type) {
|
||||
linux.DT.BLK => .block_device,
|
||||
linux.DT.CHR => .character_device,
|
||||
linux.DT.DIR => .directory,
|
||||
@ -525,23 +525,23 @@ pub const Iterator = switch (builtin.os.tag) {
|
||||
const entry = @as(*align(1) w.dirent_t, @ptrCast(&self.buf[self.index]));
|
||||
const entry_size = @sizeOf(w.dirent_t);
|
||||
const name_index = self.index + entry_size;
|
||||
if (name_index + entry.d_namlen > self.end_index) {
|
||||
if (name_index + entry.namlen > self.end_index) {
|
||||
// This case, the name is truncated, so we need to call readdir to store the entire name.
|
||||
self.end_index = self.index; // Force fd_readdir in the next loop.
|
||||
continue :start_over;
|
||||
}
|
||||
const name = self.buf[name_index .. name_index + entry.d_namlen];
|
||||
const name = self.buf[name_index .. name_index + entry.namlen];
|
||||
|
||||
const next_index = name_index + entry.d_namlen;
|
||||
const next_index = name_index + entry.namlen;
|
||||
self.index = next_index;
|
||||
self.cookie = entry.d_next;
|
||||
self.cookie = entry.next;
|
||||
|
||||
// skip . and .. entries
|
||||
if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
|
||||
continue :start_over;
|
||||
}
|
||||
|
||||
const entry_kind: Entry.Kind = switch (entry.d_type) {
|
||||
const entry_kind: Entry.Kind = switch (entry.type) {
|
||||
.BLOCK_DEVICE => .block_device,
|
||||
.CHARACTER_DEVICE => .character_device,
|
||||
.DIRECTORY => .directory,
|
||||
@ -764,81 +764,79 @@ pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.Ope
|
||||
const path_w = try std.os.windows.sliceToPrefixedFileW(self.fd, sub_path);
|
||||
return self.openFileW(path_w.span(), flags);
|
||||
}
|
||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return self.openFileWasi(sub_path, flags);
|
||||
if (builtin.os.tag == .wasi) {
|
||||
var base: std.os.wasi.rights_t = .{};
|
||||
if (flags.isRead()) {
|
||||
base.FD_READ = true;
|
||||
base.FD_TELL = true;
|
||||
base.FD_SEEK = true;
|
||||
base.FD_FILESTAT_GET = true;
|
||||
}
|
||||
if (flags.isWrite()) {
|
||||
base.FD_WRITE = true;
|
||||
base.FD_TELL = true;
|
||||
base.FD_SEEK = true;
|
||||
base.FD_DATASYNC = true;
|
||||
base.FD_FDSTAT_SET_FLAGS = true;
|
||||
base.FD_SYNC = true;
|
||||
base.FD_ALLOCATE = true;
|
||||
base.FD_ADVISE = true;
|
||||
base.FD_FILESTAT_SET_TIMES = true;
|
||||
base.FD_FILESTAT_SET_SIZE = true;
|
||||
}
|
||||
const fd = try posix.openatWasi(self.fd, sub_path, .{}, .{}, .{}, base, .{});
|
||||
return .{ .handle = fd };
|
||||
}
|
||||
const path_c = try posix.toPosixPath(sub_path);
|
||||
return self.openFileZ(&path_c, flags);
|
||||
}
|
||||
|
||||
/// Same as `openFile` but WASI only.
|
||||
pub fn openFileWasi(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
|
||||
const w = std.os.wasi;
|
||||
var fdflags: w.fdflags_t = 0x0;
|
||||
var base: w.rights_t = 0x0;
|
||||
if (flags.isRead()) {
|
||||
base |= w.RIGHT.FD_READ | w.RIGHT.FD_TELL | w.RIGHT.FD_SEEK | w.RIGHT.FD_FILESTAT_GET;
|
||||
}
|
||||
if (flags.isWrite()) {
|
||||
fdflags |= w.FDFLAG.APPEND;
|
||||
base |= w.RIGHT.FD_WRITE |
|
||||
w.RIGHT.FD_TELL |
|
||||
w.RIGHT.FD_SEEK |
|
||||
w.RIGHT.FD_DATASYNC |
|
||||
w.RIGHT.FD_FDSTAT_SET_FLAGS |
|
||||
w.RIGHT.FD_SYNC |
|
||||
w.RIGHT.FD_ALLOCATE |
|
||||
w.RIGHT.FD_ADVISE |
|
||||
w.RIGHT.FD_FILESTAT_SET_TIMES |
|
||||
w.RIGHT.FD_FILESTAT_SET_SIZE;
|
||||
}
|
||||
const fd = try posix.openatWasi(self.fd, sub_path, 0x0, 0x0, fdflags, base, 0x0);
|
||||
return File{ .handle = fd };
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sub_path);
|
||||
return self.openFileW(path_w.span(), flags);
|
||||
switch (builtin.os.tag) {
|
||||
.windows => {
|
||||
const path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sub_path);
|
||||
return self.openFileW(path_w.span(), flags);
|
||||
},
|
||||
.wasi => {
|
||||
return openFile(self, mem.sliceTo(sub_path, 0), flags);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
var os_flags: u32 = 0;
|
||||
if (@hasDecl(posix.O, "CLOEXEC")) os_flags = posix.O.CLOEXEC;
|
||||
var os_flags: posix.O = .{
|
||||
.ACCMODE = switch (flags.mode) {
|
||||
.read_only => .RDONLY,
|
||||
.write_only => .WRONLY,
|
||||
.read_write => .RDWR,
|
||||
},
|
||||
};
|
||||
if (@hasField(posix.O, "CLOEXEC")) os_flags.CLOEXEC = true;
|
||||
if (@hasField(posix.O, "LARGEFILE")) os_flags.LARGEFILE = true;
|
||||
if (@hasField(posix.O, "NOCTTY")) os_flags.NOCTTY = !flags.allow_ctty;
|
||||
|
||||
// Use the O locking flags if the os supports them to acquire the lock
|
||||
// atomically.
|
||||
const has_flock_open_flags = @hasDecl(posix.O, "EXLOCK");
|
||||
const has_flock_open_flags = @hasField(posix.O, "EXLOCK");
|
||||
if (has_flock_open_flags) {
|
||||
// Note that the O.NONBLOCK flag is removed after the openat() call
|
||||
// Note that the NONBLOCK flag is removed after the openat() call
|
||||
// is successful.
|
||||
const nonblocking_lock_flag: u32 = if (flags.lock_nonblocking)
|
||||
posix.O.NONBLOCK
|
||||
else
|
||||
0;
|
||||
os_flags |= switch (flags.lock) {
|
||||
.none => @as(u32, 0),
|
||||
.shared => posix.O.SHLOCK | nonblocking_lock_flag,
|
||||
.exclusive => posix.O.EXLOCK | nonblocking_lock_flag,
|
||||
};
|
||||
switch (flags.lock) {
|
||||
.none => {},
|
||||
.shared => {
|
||||
os_flags.SHLOCK = true;
|
||||
os_flags.NONBLOCK = flags.lock_nonblocking;
|
||||
},
|
||||
.exclusive => {
|
||||
os_flags.EXLOCK = true;
|
||||
os_flags.NONBLOCK = flags.lock_nonblocking;
|
||||
},
|
||||
}
|
||||
}
|
||||
if (@hasDecl(posix.O, "LARGEFILE")) {
|
||||
os_flags |= posix.O.LARGEFILE;
|
||||
}
|
||||
if (@hasDecl(posix.O, "NOCTTY") and !flags.allow_ctty) {
|
||||
os_flags |= posix.O.NOCTTY;
|
||||
}
|
||||
os_flags |= switch (flags.mode) {
|
||||
.read_only => @as(u32, posix.O.RDONLY),
|
||||
.write_only => @as(u32, posix.O.WRONLY),
|
||||
.read_write => @as(u32, posix.O.RDWR),
|
||||
};
|
||||
const fd = try posix.openatZ(self.fd, sub_path, os_flags, 0);
|
||||
errdefer posix.close(fd);
|
||||
|
||||
// WASI doesn't have posix.flock so we intetinally check OS prior to the inner if block
|
||||
// since it is not compiltime-known and we need to avoid undefined symbol in Wasm.
|
||||
if (@hasDecl(posix.system, "LOCK") and builtin.target.os.tag != .wasi) {
|
||||
if (@hasDecl(posix.system, "LOCK")) {
|
||||
if (!has_flock_open_flags and flags.lock != .none) {
|
||||
// TODO: integrate async I/O
|
||||
const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0;
|
||||
@ -859,7 +857,7 @@ pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File
|
||||
error.LockedRegionLimitExceeded => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
fl_flags &= ~@as(usize, posix.O.NONBLOCK);
|
||||
fl_flags &= ~@as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
|
||||
_ = posix.fcntl(fd, posix.F.SETFL, fl_flags) catch |err| switch (err) {
|
||||
error.FileBusy => unreachable,
|
||||
error.Locked => unreachable,
|
||||
@ -870,7 +868,7 @@ pub fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File
|
||||
};
|
||||
}
|
||||
|
||||
return File{ .handle = fd };
|
||||
return .{ .handle = fd };
|
||||
}
|
||||
|
||||
/// Same as `openFile` but Windows-only and the path parameter is
|
||||
@ -918,83 +916,81 @@ pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File
|
||||
const path_w = try std.os.windows.sliceToPrefixedFileW(self.fd, sub_path);
|
||||
return self.createFileW(path_w.span(), flags);
|
||||
}
|
||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return self.createFileWasi(sub_path, flags);
|
||||
if (builtin.os.tag == .wasi) {
|
||||
return .{
|
||||
.handle = try posix.openatWasi(self.fd, sub_path, .{}, .{
|
||||
.CREAT = true,
|
||||
.TRUNC = flags.truncate,
|
||||
.EXCL = flags.exclusive,
|
||||
}, .{}, .{
|
||||
.FD_READ = flags.read,
|
||||
.FD_WRITE = true,
|
||||
.FD_DATASYNC = true,
|
||||
.FD_SEEK = true,
|
||||
.FD_TELL = true,
|
||||
.FD_FDSTAT_SET_FLAGS = true,
|
||||
.FD_SYNC = true,
|
||||
.FD_ALLOCATE = true,
|
||||
.FD_ADVISE = true,
|
||||
.FD_FILESTAT_SET_TIMES = true,
|
||||
.FD_FILESTAT_SET_SIZE = true,
|
||||
.FD_FILESTAT_GET = true,
|
||||
}, .{}),
|
||||
};
|
||||
}
|
||||
const path_c = try posix.toPosixPath(sub_path);
|
||||
return self.createFileZ(&path_c, flags);
|
||||
}
|
||||
|
||||
/// Same as `createFile` but WASI only.
|
||||
pub fn createFileWasi(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
|
||||
const w = std.os.wasi;
|
||||
var oflags = w.O.CREAT;
|
||||
var base: w.rights_t = w.RIGHT.FD_WRITE |
|
||||
w.RIGHT.FD_DATASYNC |
|
||||
w.RIGHT.FD_SEEK |
|
||||
w.RIGHT.FD_TELL |
|
||||
w.RIGHT.FD_FDSTAT_SET_FLAGS |
|
||||
w.RIGHT.FD_SYNC |
|
||||
w.RIGHT.FD_ALLOCATE |
|
||||
w.RIGHT.FD_ADVISE |
|
||||
w.RIGHT.FD_FILESTAT_SET_TIMES |
|
||||
w.RIGHT.FD_FILESTAT_SET_SIZE |
|
||||
w.RIGHT.FD_FILESTAT_GET;
|
||||
if (flags.read) {
|
||||
base |= w.RIGHT.FD_READ;
|
||||
}
|
||||
if (flags.truncate) {
|
||||
oflags |= w.O.TRUNC;
|
||||
}
|
||||
if (flags.exclusive) {
|
||||
oflags |= w.O.EXCL;
|
||||
}
|
||||
const fd = try posix.openatWasi(self.fd, sub_path, 0x0, oflags, 0x0, base, 0x0);
|
||||
return File{ .handle = fd };
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);
|
||||
return self.createFileW(path_w.span(), flags);
|
||||
switch (builtin.os.tag) {
|
||||
.windows => {
|
||||
const path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);
|
||||
return self.createFileW(path_w.span(), flags);
|
||||
},
|
||||
.wasi => {
|
||||
return createFile(self, mem.sliceTo(sub_path_c, 0), flags);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
// Use the O locking flags if the os supports them to acquire the lock
|
||||
// atomically.
|
||||
const has_flock_open_flags = @hasDecl(posix.O, "EXLOCK");
|
||||
// Note that the O.NONBLOCK flag is removed after the openat() call
|
||||
// is successful.
|
||||
const nonblocking_lock_flag: u32 = if (has_flock_open_flags and flags.lock_nonblocking)
|
||||
posix.O.NONBLOCK
|
||||
else
|
||||
0;
|
||||
const lock_flag: u32 = if (has_flock_open_flags) switch (flags.lock) {
|
||||
.none => @as(u32, 0),
|
||||
.shared => posix.O.SHLOCK | nonblocking_lock_flag,
|
||||
.exclusive => posix.O.EXLOCK | nonblocking_lock_flag,
|
||||
} else 0;
|
||||
var os_flags: std.os.O = .{
|
||||
.ACCMODE = if (flags.read) .RDWR else .WRONLY,
|
||||
.CREAT = true,
|
||||
.TRUNC = flags.truncate,
|
||||
.EXCL = flags.exclusive,
|
||||
};
|
||||
if (@hasField(posix.O, "LARGEFILE")) os_flags.LARGEFILE = true;
|
||||
if (@hasField(posix.O, "CLOEXEC")) os_flags.CLOEXEC = true;
|
||||
|
||||
// Use the O locking flags if the os supports them to acquire the lock
|
||||
// atomically. Note that the NONBLOCK flag is removed after the openat()
|
||||
// call is successful.
|
||||
const has_flock_open_flags = @hasField(posix.O, "EXLOCK");
|
||||
if (has_flock_open_flags) switch (flags.lock) {
|
||||
.none => {},
|
||||
.shared => {
|
||||
os_flags.SHLOCK = true;
|
||||
os_flags.NONBLOCK = flags.lock_nonblocking;
|
||||
},
|
||||
.exclusive => {
|
||||
os_flags.EXLOCK = true;
|
||||
os_flags.NONBLOCK = flags.lock_nonblocking;
|
||||
},
|
||||
};
|
||||
|
||||
const O_LARGEFILE = if (@hasDecl(posix.O, "LARGEFILE")) posix.O.LARGEFILE else 0;
|
||||
const os_flags = lock_flag | O_LARGEFILE | posix.O.CREAT | posix.O.CLOEXEC |
|
||||
(if (flags.truncate) @as(u32, posix.O.TRUNC) else 0) |
|
||||
(if (flags.read) @as(u32, posix.O.RDWR) else posix.O.WRONLY) |
|
||||
(if (flags.exclusive) @as(u32, posix.O.EXCL) else 0);
|
||||
const fd = try posix.openatZ(self.fd, sub_path_c, os_flags, flags.mode);
|
||||
errdefer posix.close(fd);
|
||||
|
||||
// WASI doesn't have posix.flock so we intetinally check OS prior to the inner if block
|
||||
// since it is not compiltime-known and we need to avoid undefined symbol in Wasm.
|
||||
if (builtin.target.os.tag != .wasi) {
|
||||
if (!has_flock_open_flags and flags.lock != .none) {
|
||||
// TODO: integrate async I/O
|
||||
const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0;
|
||||
try posix.flock(fd, switch (flags.lock) {
|
||||
.none => unreachable,
|
||||
.shared => posix.LOCK.SH | lock_nonblocking,
|
||||
.exclusive => posix.LOCK.EX | lock_nonblocking,
|
||||
});
|
||||
}
|
||||
if (!has_flock_open_flags and flags.lock != .none) {
|
||||
// TODO: integrate async I/O
|
||||
const lock_nonblocking: i32 = if (flags.lock_nonblocking) posix.LOCK.NB else 0;
|
||||
try posix.flock(fd, switch (flags.lock) {
|
||||
.none => unreachable,
|
||||
.shared => posix.LOCK.SH | lock_nonblocking,
|
||||
.exclusive => posix.LOCK.EX | lock_nonblocking,
|
||||
});
|
||||
}
|
||||
|
||||
if (has_flock_open_flags and flags.lock_nonblocking) {
|
||||
@ -1006,7 +1002,7 @@ pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags
|
||||
error.LockedRegionLimitExceeded => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
fl_flags &= ~@as(usize, posix.O.NONBLOCK);
|
||||
fl_flags &= ~@as(usize, 1 << @bitOffsetOf(posix.O, "NONBLOCK"));
|
||||
_ = posix.fcntl(fd, posix.F.SETFL, fl_flags) catch |err| switch (err) {
|
||||
error.FileBusy => unreachable,
|
||||
error.Locked => unreachable,
|
||||
@ -1017,7 +1013,7 @@ pub fn createFileZ(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags
|
||||
};
|
||||
}
|
||||
|
||||
return File{ .handle = fd };
|
||||
return .{ .handle = fd };
|
||||
}
|
||||
|
||||
/// Same as `createFile` but Windows-only and the path parameter is
|
||||
@ -1210,10 +1206,18 @@ pub fn realpathZ(self: Dir, pathname: [*:0]const u8, out_buffer: []u8) ![]u8 {
|
||||
return self.realpathW(pathname_w.span(), out_buffer);
|
||||
}
|
||||
|
||||
const flags = if (builtin.os.tag == .linux)
|
||||
posix.O.PATH | posix.O.NONBLOCK | posix.O.CLOEXEC
|
||||
else
|
||||
posix.O.NONBLOCK | posix.O.CLOEXEC;
|
||||
const flags: posix.O = switch (builtin.os.tag) {
|
||||
.linux => .{
|
||||
.NONBLOCK = true,
|
||||
.CLOEXEC = true,
|
||||
.PATH = true,
|
||||
},
|
||||
else => .{
|
||||
.NONBLOCK = true,
|
||||
.CLOEXEC = true,
|
||||
},
|
||||
};
|
||||
|
||||
const fd = posix.openatZ(self.fd, pathname, flags, 0) catch |err| switch (err) {
|
||||
error.FileLocksNotSupported => unreachable,
|
||||
else => |e| return e,
|
||||
@ -1334,76 +1338,85 @@ pub const OpenDirOptions = struct {
|
||||
///
|
||||
/// Asserts that the path parameter has no null bytes.
|
||||
pub fn openDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const sub_path_w = try posix.windows.sliceToPrefixedFileW(self.fd, sub_path);
|
||||
return self.openDirW(sub_path_w.span().ptr, args);
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return self.openDirWasi(sub_path, args);
|
||||
} else {
|
||||
const sub_path_c = try posix.toPosixPath(sub_path);
|
||||
return self.openDirZ(&sub_path_c, args);
|
||||
}
|
||||
}
|
||||
switch (builtin.os.tag) {
|
||||
.windows => {
|
||||
const sub_path_w = try posix.windows.sliceToPrefixedFileW(self.fd, sub_path);
|
||||
return self.openDirW(sub_path_w.span().ptr, args);
|
||||
},
|
||||
.wasi => {
|
||||
var base: std.os.wasi.rights_t = .{
|
||||
.FD_FILESTAT_GET = true,
|
||||
.FD_FDSTAT_SET_FLAGS = true,
|
||||
.FD_FILESTAT_SET_TIMES = true,
|
||||
};
|
||||
if (args.access_sub_paths) {
|
||||
base.FD_READDIR = true;
|
||||
base.PATH_CREATE_DIRECTORY = true;
|
||||
base.PATH_CREATE_FILE = true;
|
||||
base.PATH_LINK_SOURCE = true;
|
||||
base.PATH_LINK_TARGET = true;
|
||||
base.PATH_OPEN = true;
|
||||
base.PATH_READLINK = true;
|
||||
base.PATH_RENAME_SOURCE = true;
|
||||
base.PATH_RENAME_TARGET = true;
|
||||
base.PATH_FILESTAT_GET = true;
|
||||
base.PATH_FILESTAT_SET_SIZE = true;
|
||||
base.PATH_FILESTAT_SET_TIMES = true;
|
||||
base.PATH_SYMLINK = true;
|
||||
base.PATH_REMOVE_DIRECTORY = true;
|
||||
base.PATH_UNLINK_FILE = true;
|
||||
}
|
||||
|
||||
/// Same as `openDir` except only WASI.
|
||||
pub fn openDirWasi(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir {
|
||||
const w = std.os.wasi;
|
||||
var base: w.rights_t = w.RIGHT.FD_FILESTAT_GET | w.RIGHT.FD_FDSTAT_SET_FLAGS | w.RIGHT.FD_FILESTAT_SET_TIMES;
|
||||
if (args.access_sub_paths) {
|
||||
base |= w.RIGHT.FD_READDIR |
|
||||
w.RIGHT.PATH_CREATE_DIRECTORY |
|
||||
w.RIGHT.PATH_CREATE_FILE |
|
||||
w.RIGHT.PATH_LINK_SOURCE |
|
||||
w.RIGHT.PATH_LINK_TARGET |
|
||||
w.RIGHT.PATH_OPEN |
|
||||
w.RIGHT.PATH_READLINK |
|
||||
w.RIGHT.PATH_RENAME_SOURCE |
|
||||
w.RIGHT.PATH_RENAME_TARGET |
|
||||
w.RIGHT.PATH_FILESTAT_GET |
|
||||
w.RIGHT.PATH_FILESTAT_SET_SIZE |
|
||||
w.RIGHT.PATH_FILESTAT_SET_TIMES |
|
||||
w.RIGHT.PATH_SYMLINK |
|
||||
w.RIGHT.PATH_REMOVE_DIRECTORY |
|
||||
w.RIGHT.PATH_UNLINK_FILE;
|
||||
const result = posix.openatWasi(
|
||||
self.fd,
|
||||
sub_path,
|
||||
.{ .SYMLINK_FOLLOW = !args.no_follow },
|
||||
.{ .DIRECTORY = true },
|
||||
.{},
|
||||
base,
|
||||
base,
|
||||
);
|
||||
const fd = result catch |err| switch (err) {
|
||||
error.FileTooBig => unreachable, // can't happen for directories
|
||||
error.IsDir => unreachable, // we're setting DIRECTORY
|
||||
error.NoSpaceLeft => unreachable, // not setting CREAT
|
||||
error.PathAlreadyExists => unreachable, // not setting CREAT
|
||||
error.FileLocksNotSupported => unreachable, // locking folders is not supported
|
||||
error.WouldBlock => unreachable, // can't happen for directories
|
||||
error.FileBusy => unreachable, // can't happen for directories
|
||||
else => |e| return e,
|
||||
};
|
||||
return .{ .fd = fd };
|
||||
},
|
||||
else => {
|
||||
const sub_path_c = try posix.toPosixPath(sub_path);
|
||||
return self.openDirZ(&sub_path_c, args);
|
||||
},
|
||||
}
|
||||
const symlink_flags: w.lookupflags_t = if (args.no_follow) 0x0 else w.LOOKUP_SYMLINK_FOLLOW;
|
||||
// TODO do we really need all the rights here?
|
||||
const inheriting: w.rights_t = w.RIGHT.ALL ^ w.RIGHT.SOCK_SHUTDOWN;
|
||||
|
||||
const result = posix.openatWasi(
|
||||
self.fd,
|
||||
sub_path,
|
||||
symlink_flags,
|
||||
w.O.DIRECTORY,
|
||||
0x0,
|
||||
base,
|
||||
inheriting,
|
||||
);
|
||||
const fd = result catch |err| switch (err) {
|
||||
error.FileTooBig => unreachable, // can't happen for directories
|
||||
error.IsDir => unreachable, // we're providing O.DIRECTORY
|
||||
error.NoSpaceLeft => unreachable, // not providing O.CREAT
|
||||
error.PathAlreadyExists => unreachable, // not providing O.CREAT
|
||||
error.FileLocksNotSupported => unreachable, // locking folders is not supported
|
||||
error.WouldBlock => unreachable, // can't happen for directories
|
||||
error.FileBusy => unreachable, // can't happen for directories
|
||||
else => |e| return e,
|
||||
};
|
||||
return Dir{ .fd = fd };
|
||||
}
|
||||
|
||||
/// Same as `openDir` except the parameter is null-terminated.
|
||||
pub fn openDirZ(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions) OpenError!Dir {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const sub_path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);
|
||||
return self.openDirW(sub_path_w.span().ptr, args);
|
||||
}
|
||||
const symlink_flags: u32 = if (args.no_follow) posix.O.NOFOLLOW else 0x0;
|
||||
if (!args.iterate) {
|
||||
const O_PATH = if (@hasDecl(posix.O, "PATH")) posix.O.PATH else 0;
|
||||
return self.openDirFlagsZ(sub_path_c, posix.O.DIRECTORY | posix.O.RDONLY | posix.O.CLOEXEC | O_PATH | symlink_flags);
|
||||
} else {
|
||||
return self.openDirFlagsZ(sub_path_c, posix.O.DIRECTORY | posix.O.RDONLY | posix.O.CLOEXEC | symlink_flags);
|
||||
switch (builtin.os.tag) {
|
||||
.windows => {
|
||||
const sub_path_w = try std.os.windows.cStrToPrefixedFileW(self.fd, sub_path_c);
|
||||
return self.openDirW(sub_path_w.span().ptr, args);
|
||||
},
|
||||
.wasi => {
|
||||
return openDir(self, mem.sliceTo(sub_path_c, 0), args);
|
||||
},
|
||||
else => {
|
||||
var symlink_flags: posix.O = .{
|
||||
.ACCMODE = .RDONLY,
|
||||
.NOFOLLOW = args.no_follow,
|
||||
.DIRECTORY = true,
|
||||
.CLOEXEC = true,
|
||||
};
|
||||
if (@hasField(posix.O, "PATH") and !args.iterate)
|
||||
symlink_flags.PATH = true;
|
||||
|
||||
return self.openDirFlagsZ(sub_path_c, symlink_flags);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -1422,13 +1435,14 @@ pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions) Ope
|
||||
return dir;
|
||||
}
|
||||
|
||||
/// `flags` must contain `posix.O.DIRECTORY`.
|
||||
fn openDirFlagsZ(self: Dir, sub_path_c: [*:0]const u8, flags: u32) OpenError!Dir {
|
||||
/// Asserts `flags` has `DIRECTORY` set.
|
||||
fn openDirFlagsZ(self: Dir, sub_path_c: [*:0]const u8, flags: posix.O) OpenError!Dir {
|
||||
assert(flags.DIRECTORY);
|
||||
const fd = posix.openatZ(self.fd, sub_path_c, flags, 0) catch |err| switch (err) {
|
||||
error.FileTooBig => unreachable, // can't happen for directories
|
||||
error.IsDir => unreachable, // we're providing O.DIRECTORY
|
||||
error.NoSpaceLeft => unreachable, // not providing O.CREAT
|
||||
error.PathAlreadyExists => unreachable, // not providing O.CREAT
|
||||
error.IsDir => unreachable, // we're setting DIRECTORY
|
||||
error.NoSpaceLeft => unreachable, // not setting CREAT
|
||||
error.PathAlreadyExists => unreachable, // not setting CREAT
|
||||
error.FileLocksNotSupported => unreachable, // locking folders is not supported
|
||||
error.WouldBlock => unreachable, // can't happen for directories
|
||||
error.FileBusy => unreachable, // can't happen for directories
|
||||
@ -2446,8 +2460,8 @@ pub fn statFile(self: Dir, sub_path: []const u8) StatFileError!Stat {
|
||||
return file.stat();
|
||||
}
|
||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
const st = try posix.fstatatWasi(self.fd, sub_path, posix.wasi.LOOKUP_SYMLINK_FOLLOW);
|
||||
return Stat.fromSystem(st);
|
||||
const st = try posix.fstatat_wasi(self.fd, sub_path, .{ .SYMLINK_FOLLOW = true });
|
||||
return Stat.fromWasi(st);
|
||||
}
|
||||
const st = try posix.fstatat(self.fd, sub_path, 0);
|
||||
return Stat.fromSystem(st);
|
||||
@ -2507,3 +2521,4 @@ const posix = std.os;
|
||||
const mem = std.mem;
|
||||
const fs = std.fs;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
|
@ -290,49 +290,59 @@ pub const Stat = struct {
|
||||
/// Last status/metadata change time in nanoseconds, relative to UTC 1970-01-01.
|
||||
ctime: i128,
|
||||
|
||||
pub fn fromSystem(st: posix.system.Stat) Stat {
|
||||
pub fn fromSystem(st: posix.Stat) Stat {
|
||||
const atime = st.atime();
|
||||
const mtime = st.mtime();
|
||||
const ctime = st.ctime();
|
||||
const kind: Kind = if (builtin.os.tag == .wasi and !builtin.link_libc) switch (st.filetype) {
|
||||
.BLOCK_DEVICE => .block_device,
|
||||
.CHARACTER_DEVICE => .character_device,
|
||||
.DIRECTORY => .directory,
|
||||
.SYMBOLIC_LINK => .sym_link,
|
||||
.REGULAR_FILE => .file,
|
||||
.SOCKET_STREAM, .SOCKET_DGRAM => .unix_domain_socket,
|
||||
else => .unknown,
|
||||
} else blk: {
|
||||
const m = st.mode & posix.S.IFMT;
|
||||
switch (m) {
|
||||
posix.S.IFBLK => break :blk .block_device,
|
||||
posix.S.IFCHR => break :blk .character_device,
|
||||
posix.S.IFDIR => break :blk .directory,
|
||||
posix.S.IFIFO => break :blk .named_pipe,
|
||||
posix.S.IFLNK => break :blk .sym_link,
|
||||
posix.S.IFREG => break :blk .file,
|
||||
posix.S.IFSOCK => break :blk .unix_domain_socket,
|
||||
else => {},
|
||||
}
|
||||
if (builtin.os.tag.isSolarish()) switch (m) {
|
||||
posix.S.IFDOOR => break :blk .door,
|
||||
posix.S.IFPORT => break :blk .event_port,
|
||||
else => {},
|
||||
};
|
||||
|
||||
break :blk .unknown;
|
||||
};
|
||||
|
||||
return Stat{
|
||||
return .{
|
||||
.inode = st.ino,
|
||||
.size = @as(u64, @bitCast(st.size)),
|
||||
.size = @bitCast(st.size),
|
||||
.mode = st.mode,
|
||||
.kind = kind,
|
||||
.kind = k: {
|
||||
const m = st.mode & posix.S.IFMT;
|
||||
switch (m) {
|
||||
posix.S.IFBLK => break :k .block_device,
|
||||
posix.S.IFCHR => break :k .character_device,
|
||||
posix.S.IFDIR => break :k .directory,
|
||||
posix.S.IFIFO => break :k .named_pipe,
|
||||
posix.S.IFLNK => break :k .sym_link,
|
||||
posix.S.IFREG => break :k .file,
|
||||
posix.S.IFSOCK => break :k .unix_domain_socket,
|
||||
else => {},
|
||||
}
|
||||
if (builtin.os.tag.isSolarish()) switch (m) {
|
||||
posix.S.IFDOOR => break :k .door,
|
||||
posix.S.IFPORT => break :k .event_port,
|
||||
else => {},
|
||||
};
|
||||
|
||||
break :k .unknown;
|
||||
},
|
||||
.atime = @as(i128, atime.tv_sec) * std.time.ns_per_s + atime.tv_nsec,
|
||||
.mtime = @as(i128, mtime.tv_sec) * std.time.ns_per_s + mtime.tv_nsec,
|
||||
.ctime = @as(i128, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn fromWasi(st: std.os.wasi.filestat_t) Stat {
|
||||
return .{
|
||||
.inode = st.ino,
|
||||
.size = @bitCast(st.size),
|
||||
.mode = 0,
|
||||
.kind = switch (st.filetype) {
|
||||
.BLOCK_DEVICE => .block_device,
|
||||
.CHARACTER_DEVICE => .character_device,
|
||||
.DIRECTORY => .directory,
|
||||
.SYMBOLIC_LINK => .sym_link,
|
||||
.REGULAR_FILE => .file,
|
||||
.SOCKET_STREAM, .SOCKET_DGRAM => .unix_domain_socket,
|
||||
else => .unknown,
|
||||
},
|
||||
.atime = st.atim,
|
||||
.mtime = st.mtim,
|
||||
.ctime = st.ctim,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const StatError = posix.FStatError;
|
||||
@ -355,7 +365,7 @@ pub fn stat(self: File) StatError!Stat {
|
||||
.ACCESS_DENIED => return error.AccessDenied,
|
||||
else => return windows.unexpectedStatus(rc),
|
||||
}
|
||||
return Stat{
|
||||
return .{
|
||||
.inode = info.InternalInformation.IndexNumber,
|
||||
.size = @as(u64, @bitCast(info.StandardInformation.EndOfFile)),
|
||||
.mode = 0,
|
||||
@ -385,6 +395,11 @@ pub fn stat(self: File) StatError!Stat {
|
||||
};
|
||||
}
|
||||
|
||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
const st = try posix.fstat_wasi(self.handle);
|
||||
return Stat.fromWasi(st);
|
||||
}
|
||||
|
||||
const st = try posix.fstat(self.handle);
|
||||
return Stat.fromSystem(st);
|
||||
}
|
||||
@ -576,10 +591,11 @@ pub fn setPermissions(self: File, permissions: Permissions) SetPermissionsError!
|
||||
/// Cross-platform representation of file metadata.
|
||||
/// Platform-specific functionality is available through the `inner` field.
|
||||
pub const Metadata = struct {
|
||||
/// You may use the `inner` field to use platform-specific functionality
|
||||
/// Exposes platform-specific functionality.
|
||||
inner: switch (builtin.os.tag) {
|
||||
.windows => MetadataWindows,
|
||||
.linux => MetadataLinux,
|
||||
.wasi => MetadataWasi,
|
||||
else => MetadataUnix,
|
||||
},
|
||||
|
||||
@ -628,12 +644,12 @@ pub const MetadataUnix = struct {
|
||||
|
||||
/// Returns the size of the file
|
||||
pub fn size(self: Self) u64 {
|
||||
return @as(u64, @intCast(self.stat.size));
|
||||
return @intCast(self.stat.size);
|
||||
}
|
||||
|
||||
/// Returns a `Permissions` struct, representing the permissions on the file
|
||||
pub fn permissions(self: Self) Permissions {
|
||||
return Permissions{ .inner = PermissionsUnix{ .mode = self.stat.mode } };
|
||||
return .{ .inner = .{ .mode = self.stat.mode } };
|
||||
}
|
||||
|
||||
/// Returns the `Kind` of the file
|
||||
@ -756,6 +772,42 @@ pub const MetadataLinux = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const MetadataWasi = struct {
|
||||
stat: std.os.wasi.filestat_t,
|
||||
|
||||
pub fn size(self: @This()) u64 {
|
||||
return self.stat.size;
|
||||
}
|
||||
|
||||
pub fn permissions(self: @This()) Permissions {
|
||||
return .{ .inner = .{ .mode = self.stat.mode } };
|
||||
}
|
||||
|
||||
pub fn kind(self: @This()) Kind {
|
||||
return switch (self.stat.filetype) {
|
||||
.BLOCK_DEVICE => .block_device,
|
||||
.CHARACTER_DEVICE => .character_device,
|
||||
.DIRECTORY => .directory,
|
||||
.SYMBOLIC_LINK => .sym_link,
|
||||
.REGULAR_FILE => .file,
|
||||
.SOCKET_STREAM, .SOCKET_DGRAM => .unix_domain_socket,
|
||||
else => .unknown,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn accessed(self: @This()) i128 {
|
||||
return self.stat.atim;
|
||||
}
|
||||
|
||||
pub fn modified(self: @This()) i128 {
|
||||
return self.stat.mtim;
|
||||
}
|
||||
|
||||
pub fn created(self: @This()) ?i128 {
|
||||
return self.stat.ctim;
|
||||
}
|
||||
};
|
||||
|
||||
pub const MetadataWindows = struct {
|
||||
attributes: windows.DWORD,
|
||||
reparse_tag: windows.DWORD,
|
||||
@ -773,7 +825,7 @@ pub const MetadataWindows = struct {
|
||||
|
||||
/// Returns a `Permissions` struct, representing the permissions on the file
|
||||
pub fn permissions(self: Self) Permissions {
|
||||
return Permissions{ .inner = PermissionsWindows{ .attributes = self.attributes } };
|
||||
return .{ .inner = .{ .attributes = self.attributes } };
|
||||
}
|
||||
|
||||
/// Returns the `Kind` of the file.
|
||||
@ -811,7 +863,7 @@ pub const MetadataWindows = struct {
|
||||
pub const MetadataError = posix.FStatError;
|
||||
|
||||
pub fn metadata(self: File) MetadataError!Metadata {
|
||||
return Metadata{
|
||||
return .{
|
||||
.inner = switch (builtin.os.tag) {
|
||||
.windows => blk: {
|
||||
var io_status_block: windows.IO_STATUS_BLOCK = undefined;
|
||||
@ -846,7 +898,7 @@ pub fn metadata(self: File) MetadataError!Metadata {
|
||||
break :reparse_blk 0;
|
||||
};
|
||||
|
||||
break :blk MetadataWindows{
|
||||
break :blk .{
|
||||
.attributes = info.BasicInformation.FileAttributes,
|
||||
.reparse_tag = reparse_tag,
|
||||
._size = @as(u64, @bitCast(info.StandardInformation.EndOfFile)),
|
||||
@ -887,16 +939,12 @@ pub fn metadata(self: File) MetadataError!Metadata {
|
||||
else => |err| return posix.unexpectedErrno(err),
|
||||
}
|
||||
|
||||
break :blk MetadataLinux{
|
||||
break :blk .{
|
||||
.statx = stx,
|
||||
};
|
||||
},
|
||||
else => blk: {
|
||||
const st = try posix.fstat(self.handle);
|
||||
break :blk MetadataUnix{
|
||||
.stat = st,
|
||||
};
|
||||
},
|
||||
.wasi => .{ .stat = try posix.fstat_wasi(self.handle) },
|
||||
else => .{ .stat = try posix.fstat(self.handle) },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -242,7 +242,12 @@ test "File.stat on a File that is a symlink returns Kind.sym_link" {
|
||||
const sub_path_c = try os.toPosixPath("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
|
||||
const flags = os.O.NOFOLLOW | os.O.PATH | os.O.RDONLY | os.O.CLOEXEC;
|
||||
const flags: os.O = .{
|
||||
.NOFOLLOW = true,
|
||||
.PATH = true,
|
||||
.ACCMODE = .RDONLY,
|
||||
.CLOEXEC = true,
|
||||
};
|
||||
const fd = try os.openatZ(ctx.dir.fd, &sub_path_c, flags, 0);
|
||||
break :linux_symlink Dir{ .fd = fd };
|
||||
},
|
||||
|
434
lib/std/os.zig
434
lib/std/os.zig
@ -24,7 +24,6 @@ const elf = std.elf;
|
||||
const fs = std.fs;
|
||||
const dl = @import("dynamic_library.zig");
|
||||
const MAX_PATH_BYTES = std.fs.MAX_PATH_BYTES;
|
||||
const is_windows = builtin.os.tag == .windows;
|
||||
|
||||
pub const darwin = std.c;
|
||||
pub const dragonfly = std.c;
|
||||
@ -62,16 +61,21 @@ test {
|
||||
/// When not linking libc, it is the OS-specific system interface.
|
||||
pub const system = if (@hasDecl(root, "os") and root.os != @This())
|
||||
root.os.system
|
||||
else if (builtin.link_libc or is_windows)
|
||||
else if (use_libc)
|
||||
std.c
|
||||
else switch (builtin.os.tag) {
|
||||
.linux => linux,
|
||||
.plan9 => plan9,
|
||||
.wasi => wasi,
|
||||
.uefi => uefi,
|
||||
else => struct {},
|
||||
};
|
||||
|
||||
/// Whether to use libc for the POSIX API layer.
|
||||
const use_libc = builtin.link_libc or switch (builtin.os.tag) {
|
||||
.windows, .wasi => true,
|
||||
else => false,
|
||||
};
|
||||
|
||||
pub const AF = system.AF;
|
||||
pub const AF_SUN = system.AF_SUN;
|
||||
pub const ARCH = system.ARCH;
|
||||
@ -87,10 +91,7 @@ pub const F = system.F;
|
||||
pub const FD_CLOEXEC = system.FD_CLOEXEC;
|
||||
pub const Flock = system.Flock;
|
||||
pub const HOST_NAME_MAX = system.HOST_NAME_MAX;
|
||||
pub const HW = switch (builtin.os.tag) {
|
||||
.openbsd => system.HW,
|
||||
else => .{},
|
||||
};
|
||||
pub const HW = system.HW;
|
||||
pub const IFNAMESIZE = system.IFNAMESIZE;
|
||||
pub const IOV_MAX = system.IOV_MAX;
|
||||
pub const IPPROTO = system.IPPROTO;
|
||||
@ -105,19 +106,13 @@ pub const MFD = system.MFD;
|
||||
pub const MMAP2_UNIT = system.MMAP2_UNIT;
|
||||
pub const MSG = system.MSG;
|
||||
pub const NAME_MAX = system.NAME_MAX;
|
||||
pub const O = switch (builtin.os.tag) {
|
||||
// We want to expose the POSIX-like OFLAGS, so we use std.c.wasi.O instead
|
||||
// of std.os.wasi.O, which is for non-POSIX-like `wasi.path_open`, etc.
|
||||
.wasi => std.c.O,
|
||||
else => system.O,
|
||||
};
|
||||
pub const O = system.O;
|
||||
pub const PATH_MAX = system.PATH_MAX;
|
||||
pub const POLL = system.POLL;
|
||||
pub const POSIX_FADV = system.POSIX_FADV;
|
||||
pub const PR = system.PR;
|
||||
pub const PROT = system.PROT;
|
||||
pub const REG = system.REG;
|
||||
pub const RIGHT = system.RIGHT;
|
||||
pub const RLIM = system.RLIM;
|
||||
pub const RR = system.RR;
|
||||
pub const S = system.S;
|
||||
@ -151,12 +146,9 @@ pub const dl_phdr_info = system.dl_phdr_info;
|
||||
pub const empty_sigset = system.empty_sigset;
|
||||
pub const filled_sigset = system.filled_sigset;
|
||||
pub const fd_t = system.fd_t;
|
||||
pub const fdflags_t = system.fdflags_t;
|
||||
pub const fdstat_t = system.fdstat_t;
|
||||
pub const gid_t = system.gid_t;
|
||||
pub const ifreq = system.ifreq;
|
||||
pub const ino_t = system.ino_t;
|
||||
pub const lookupflags_t = system.lookupflags_t;
|
||||
pub const mcontext_t = system.mcontext_t;
|
||||
pub const mode_t = system.mode_t;
|
||||
pub const msghdr = system.msghdr;
|
||||
@ -164,14 +156,12 @@ pub const msghdr_const = system.msghdr_const;
|
||||
pub const nfds_t = system.nfds_t;
|
||||
pub const nlink_t = system.nlink_t;
|
||||
pub const off_t = system.off_t;
|
||||
pub const oflags_t = system.oflags_t;
|
||||
pub const pid_t = system.pid_t;
|
||||
pub const pollfd = system.pollfd;
|
||||
pub const port_t = system.port_t;
|
||||
pub const port_event = system.port_event;
|
||||
pub const port_notify = system.port_notify;
|
||||
pub const file_obj = system.file_obj;
|
||||
pub const rights_t = system.rights_t;
|
||||
pub const rlim_t = system.rlim_t;
|
||||
pub const rlimit = system.rlimit;
|
||||
pub const rlimit_resource = system.rlimit_resource;
|
||||
@ -209,6 +199,12 @@ pub const iovec_const = extern struct {
|
||||
iov_len: usize,
|
||||
};
|
||||
|
||||
pub const ACCMODE = enum(u2) {
|
||||
RDONLY = 0,
|
||||
WRONLY = 1,
|
||||
RDWR = 2,
|
||||
};
|
||||
|
||||
pub const LOG = struct {
|
||||
/// system is unusable
|
||||
pub const EMERG = 0;
|
||||
@ -460,13 +456,13 @@ fn fchmodat2(dirfd: fd_t, path: []const u8, mode: mode_t, flags: u32) FChmodAtEr
|
||||
|
||||
// Fallback to changing permissions using procfs:
|
||||
//
|
||||
// 1. Open `path` as an `O.PATH` descriptor.
|
||||
// 1. Open `path` as a `PATH` descriptor.
|
||||
// 2. Stat the fd and check if it isn't a symbolic link.
|
||||
// 3. Generate the procfs reference to the fd via `/proc/self/fd/{fd}`.
|
||||
// 4. Pass the procfs path to `chmod` with the `mode`.
|
||||
var pathfd: fd_t = undefined;
|
||||
while (true) {
|
||||
const rc = system.openat(dirfd, &path_c, O.PATH | O.NOFOLLOW | O.CLOEXEC, @as(mode_t, 0));
|
||||
const rc = system.openat(dirfd, &path_c, .{ .PATH = true, .NOFOLLOW = true, .CLOEXEC = true }, @as(mode_t, 0));
|
||||
switch (system.getErrno(rc)) {
|
||||
.SUCCESS => {
|
||||
pathfd = @as(fd_t, @intCast(rc));
|
||||
@ -536,8 +532,10 @@ pub const FChownError = error{
|
||||
/// any group of which the owner is a member. If the owner or group is
|
||||
/// specified as `null`, the ID is not changed.
|
||||
pub fn fchown(fd: fd_t, owner: ?uid_t, group: ?gid_t) FChownError!void {
|
||||
if (builtin.os.tag == .windows or builtin.os.tag == .wasi)
|
||||
@compileError("Unsupported OS");
|
||||
switch (builtin.os.tag) {
|
||||
.windows, .wasi => @compileError("Unsupported OS"),
|
||||
else => {},
|
||||
}
|
||||
|
||||
while (true) {
|
||||
const res = system.fchown(fd, owner orelse @as(u32, 0) -% 1, group orelse @as(u32, 0) -% 1);
|
||||
@ -675,7 +673,7 @@ pub fn getrandom(buffer: []u8) GetRandomError!void {
|
||||
}
|
||||
|
||||
fn getRandomBytesDevURandom(buf: []u8) !void {
|
||||
const fd = try openZ("/dev/urandom", O.RDONLY | O.CLOEXEC, 0);
|
||||
const fd = try openZ("/dev/urandom", .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
|
||||
defer close(fd);
|
||||
|
||||
const st = try fstat(fd);
|
||||
@ -1590,18 +1588,18 @@ pub const OpenError = error{
|
||||
/// for 64-bit targets, as well as when opening directories.
|
||||
FileTooBig,
|
||||
|
||||
/// The path refers to directory but the `O.DIRECTORY` flag was not provided.
|
||||
/// The path refers to directory but the `DIRECTORY` flag was not provided.
|
||||
IsDir,
|
||||
|
||||
/// A new path cannot be created because the device has no room for the new file.
|
||||
/// This error is only reachable when the `O.CREAT` flag is provided.
|
||||
/// This error is only reachable when the `CREAT` flag is provided.
|
||||
NoSpaceLeft,
|
||||
|
||||
/// A component used as a directory in the path was not, in fact, a directory, or
|
||||
/// `O.DIRECTORY` was specified and the path was not a directory.
|
||||
/// `DIRECTORY` was specified and the path was not a directory.
|
||||
NotDir,
|
||||
|
||||
/// The path already exists and the `O.CREAT` and `O.EXCL` flags were provided.
|
||||
/// The path already exists and the `CREAT` and `EXCL` flags were provided.
|
||||
PathAlreadyExists,
|
||||
DeviceBusy,
|
||||
|
||||
@ -1629,12 +1627,11 @@ pub const OpenError = error{
|
||||
|
||||
/// Open and possibly create a file. Keeps trying if it gets interrupted.
|
||||
/// See also `openZ`.
|
||||
pub fn open(file_path: []const u8, flags: u32, perm: mode_t) OpenError!fd_t {
|
||||
pub fn open(file_path: []const u8, flags: O, perm: mode_t) OpenError!fd_t {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.sliceToPrefixedFileW(null, file_path);
|
||||
return openW(file_path_w.span(), flags, perm);
|
||||
@compileError("Windows does not support POSIX; use Windows-specific API or cross-platform std.fs API");
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return openat(wasi.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);
|
||||
@ -1642,10 +1639,9 @@ pub fn open(file_path: []const u8, flags: u32, perm: mode_t) OpenError!fd_t {
|
||||
|
||||
/// Open and possibly create a file. Keeps trying if it gets interrupted.
|
||||
/// See also `open`.
|
||||
pub fn openZ(file_path: [*:0]const u8, flags: u32, perm: mode_t) OpenError!fd_t {
|
||||
pub fn openZ(file_path: [*:0]const u8, flags: O, perm: mode_t) OpenError!fd_t {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.cStrToPrefixedFileW(null, file_path);
|
||||
return openW(file_path_w.span(), flags, perm);
|
||||
@compileError("Windows does not support POSIX; use Windows-specific API or cross-platform std.fs API");
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return open(mem.sliceTo(file_path, 0), flags, perm);
|
||||
}
|
||||
@ -1681,64 +1677,15 @@ pub fn openZ(file_path: [*:0]const u8, flags: u32, perm: mode_t) OpenError!fd_t
|
||||
}
|
||||
}
|
||||
|
||||
fn openOptionsFromFlagsWindows(flags: u32) windows.OpenFileOptions {
|
||||
const w = windows;
|
||||
|
||||
var access_mask: w.ULONG = w.READ_CONTROL | w.FILE_WRITE_ATTRIBUTES | w.SYNCHRONIZE;
|
||||
if (flags & O.RDWR != 0) {
|
||||
access_mask |= w.GENERIC_READ | w.GENERIC_WRITE;
|
||||
} else if (flags & O.WRONLY != 0) {
|
||||
access_mask |= w.GENERIC_WRITE;
|
||||
} else {
|
||||
access_mask |= w.GENERIC_READ | w.GENERIC_WRITE;
|
||||
}
|
||||
|
||||
const filter: windows.OpenFileOptions.Filter = if (flags & O.DIRECTORY != 0) .dir_only else .file_only;
|
||||
const follow_symlinks: bool = flags & O.NOFOLLOW == 0;
|
||||
|
||||
const creation: w.ULONG = blk: {
|
||||
if (flags & O.CREAT != 0) {
|
||||
if (flags & O.EXCL != 0) {
|
||||
break :blk w.FILE_CREATE;
|
||||
}
|
||||
}
|
||||
break :blk w.FILE_OPEN;
|
||||
};
|
||||
|
||||
return .{
|
||||
.access_mask = access_mask,
|
||||
.creation = creation,
|
||||
.filter = filter,
|
||||
.follow_symlinks = follow_symlinks,
|
||||
};
|
||||
}
|
||||
|
||||
/// Windows-only. The path parameter is
|
||||
/// [WTF-16](https://simonsapin.github.io/wtf-8/#potentially-ill-formed-utf-16) encoded.
|
||||
/// Translates the POSIX open API call to a Windows API call.
|
||||
/// TODO currently, this function does not handle all flag combinations
|
||||
/// or makes use of perm argument.
|
||||
pub fn openW(file_path_w: []const u16, flags: u32, perm: mode_t) OpenError!fd_t {
|
||||
_ = perm;
|
||||
var options = openOptionsFromFlagsWindows(flags);
|
||||
options.dir = std.fs.cwd().fd;
|
||||
return windows.OpenFile(file_path_w, options) catch |err| switch (err) {
|
||||
error.WouldBlock => unreachable,
|
||||
error.PipeBusy => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
}
|
||||
|
||||
/// Open and possibly create a file. Keeps trying if it gets interrupted.
|
||||
/// `file_path` is relative to the open directory handle `dir_fd`.
|
||||
/// See also `openatZ`.
|
||||
pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) OpenError!fd_t {
|
||||
pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: O, mode: mode_t) OpenError!fd_t {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.sliceToPrefixedFileW(dir_fd, file_path);
|
||||
return openatW(dir_fd, file_path_w.span(), flags, mode);
|
||||
@compileError("Windows does not support POSIX; use Windows-specific API or cross-platform std.fs API");
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
// `mode` is ignored on WASI, which does not support unix-style file permissions
|
||||
const opts = try openOptionsFromFlagsWasi(dir_fd, flags);
|
||||
const opts = try openOptionsFromFlagsWasi(flags);
|
||||
const fd = try openatWasi(
|
||||
dir_fd,
|
||||
file_path,
|
||||
@ -1750,8 +1697,8 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) Ope
|
||||
);
|
||||
errdefer close(fd);
|
||||
|
||||
if (flags & O.WRONLY != 0) {
|
||||
const info = try fstat(fd);
|
||||
if (flags.write) {
|
||||
const info = try fstat_wasi(fd);
|
||||
if (info.filetype == .DIRECTORY)
|
||||
return error.IsDir;
|
||||
}
|
||||
@ -1762,6 +1709,37 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) Ope
|
||||
return openatZ(dir_fd, &file_path_c, flags, mode);
|
||||
}
|
||||
|
||||
pub const CommonOpenFlags = packed struct {
|
||||
ACCMODE: 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) O {
|
||||
if (builtin.os.tag == .wasi) return .{
|
||||
.read = cof.ACCMODE != .WRONLY,
|
||||
.write = cof.ACCMODE != .RDONLY,
|
||||
.CREAT = cof.CREAT,
|
||||
.EXCL = cof.EXCL,
|
||||
.DIRECTORY = cof.DIRECTORY,
|
||||
.NONBLOCK = cof.NONBLOCK,
|
||||
};
|
||||
var result: O = .{
|
||||
.ACCMODE = cof.ACCMODE,
|
||||
.CREAT = cof.CREAT,
|
||||
.EXCL = cof.EXCL,
|
||||
.DIRECTORY = cof.DIRECTORY,
|
||||
.NONBLOCK = cof.NONBLOCK,
|
||||
.CLOEXEC = cof.CLOEXEC,
|
||||
};
|
||||
if (@hasField(O, "LARGEFILE")) result.LARGEFILE = cof.LARGEFILE;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/// A struct to contain all lookup/rights flags accepted by `wasi.path_open`
|
||||
const WasiOpenOptions = struct {
|
||||
oflags: wasi.oflags_t,
|
||||
@ -1772,42 +1750,38 @@ const WasiOpenOptions = struct {
|
||||
};
|
||||
|
||||
/// Compute rights + flags corresponding to the provided POSIX access mode.
|
||||
fn openOptionsFromFlagsWasi(fd: fd_t, oflag: u32) OpenError!WasiOpenOptions {
|
||||
fn openOptionsFromFlagsWasi(oflag: O) OpenError!WasiOpenOptions {
|
||||
const w = std.os.wasi;
|
||||
|
||||
// First, discover the rights that we can derive from `fd`
|
||||
var fsb_cur: wasi.fdstat_t = undefined;
|
||||
_ = switch (w.fd_fdstat_get(fd, &fsb_cur)) {
|
||||
.SUCCESS => .{},
|
||||
.BADF => return error.InvalidHandle,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
};
|
||||
|
||||
// Next, calculate the read/write rights to request, depending on the
|
||||
// provided POSIX access mode
|
||||
var rights: w.rights_t = 0;
|
||||
if (oflag & O.RDONLY != 0) {
|
||||
rights |= w.RIGHT.FD_READ | w.RIGHT.FD_READDIR;
|
||||
var rights: w.rights_t = .{};
|
||||
if (oflag.read) {
|
||||
rights.FD_READ = true;
|
||||
rights.FD_READDIR = true;
|
||||
}
|
||||
if (oflag & O.WRONLY != 0) {
|
||||
rights |= w.RIGHT.FD_DATASYNC | w.RIGHT.FD_WRITE |
|
||||
w.RIGHT.FD_ALLOCATE | w.RIGHT.FD_FILESTAT_SET_SIZE;
|
||||
if (oflag.write) {
|
||||
rights.FD_DATASYNC = true;
|
||||
rights.FD_WRITE = true;
|
||||
rights.FD_ALLOCATE = true;
|
||||
rights.FD_FILESTAT_SET_SIZE = true;
|
||||
}
|
||||
|
||||
// Request all other rights unconditionally
|
||||
rights |= ~(w.RIGHT.FD_DATASYNC | w.RIGHT.FD_READ |
|
||||
w.RIGHT.FD_WRITE | w.RIGHT.FD_ALLOCATE |
|
||||
w.RIGHT.FD_READDIR | w.RIGHT.FD_FILESTAT_SET_SIZE);
|
||||
// https://github.com/ziglang/zig/issues/18882
|
||||
const flag_bits: u32 = @bitCast(oflag);
|
||||
const oflags_int: u16 = @as(u12, @truncate(flag_bits >> 12));
|
||||
const fs_flags_int: u16 = @as(u12, @truncate(flag_bits));
|
||||
|
||||
// But only take rights that we can actually inherit
|
||||
rights &= fsb_cur.fs_rights_inheriting;
|
||||
|
||||
return WasiOpenOptions{
|
||||
.oflags = @as(w.oflags_t, @truncate((oflag >> 12))) & 0xfff,
|
||||
.lookup_flags = if (oflag & O.NOFOLLOW == 0) w.LOOKUP_SYMLINK_FOLLOW else 0,
|
||||
return .{
|
||||
// https://github.com/ziglang/zig/issues/18882
|
||||
.oflags = @bitCast(oflags_int),
|
||||
.lookup_flags = .{
|
||||
.SYMLINK_FOLLOW = !oflag.NOFOLLOW,
|
||||
},
|
||||
.fs_rights_base = rights,
|
||||
.fs_rights_inheriting = fsb_cur.fs_rights_inheriting,
|
||||
.fs_flags = @as(w.fdflags_t, @truncate(oflag & 0xfff)),
|
||||
.fs_rights_inheriting = rights,
|
||||
// https://github.com/ziglang/zig/issues/18882
|
||||
.fs_flags = @bitCast(fs_flags_int),
|
||||
};
|
||||
}
|
||||
|
||||
@ -1815,11 +1789,11 @@ fn openOptionsFromFlagsWasi(fd: fd_t, oflag: u32) OpenError!WasiOpenOptions {
|
||||
pub fn openatWasi(
|
||||
dir_fd: fd_t,
|
||||
file_path: []const u8,
|
||||
lookup_flags: lookupflags_t,
|
||||
oflags: oflags_t,
|
||||
fdflags: fdflags_t,
|
||||
base: rights_t,
|
||||
inheriting: rights_t,
|
||||
lookup_flags: wasi.lookupflags_t,
|
||||
oflags: wasi.oflags_t,
|
||||
fdflags: wasi.fdflags_t,
|
||||
base: wasi.rights_t,
|
||||
inheriting: wasi.rights_t,
|
||||
) OpenError!fd_t {
|
||||
while (true) {
|
||||
var fd: fd_t = undefined;
|
||||
@ -1829,6 +1803,7 @@ pub fn openatWasi(
|
||||
|
||||
.FAULT => unreachable,
|
||||
.INVAL => unreachable,
|
||||
.BADF => unreachable,
|
||||
.ACCES => return error.AccessDenied,
|
||||
.FBIG => return error.FileTooBig,
|
||||
.OVERFLOW => return error.FileTooBig,
|
||||
@ -1854,10 +1829,9 @@ pub fn openatWasi(
|
||||
/// Open and possibly create a file. Keeps trying if it gets interrupted.
|
||||
/// `file_path` is relative to the open directory handle `dir_fd`.
|
||||
/// See also `openat`.
|
||||
pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t) OpenError!fd_t {
|
||||
pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: O, mode: mode_t) OpenError!fd_t {
|
||||
if (builtin.os.tag == .windows) {
|
||||
const file_path_w = try windows.cStrToPrefixedFileW(dir_fd, file_path);
|
||||
return openatW(dir_fd, file_path_w.span(), flags, mode);
|
||||
@compileError("Windows does not support POSIX; use Windows-specific API or cross-platform std.fs API");
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return openat(dir_fd, mem.sliceTo(file_path, 0), flags, mode);
|
||||
}
|
||||
@ -1897,21 +1871,6 @@ pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t)
|
||||
}
|
||||
}
|
||||
|
||||
/// Windows-only. Similar to `openat` but with pathname argument null-terminated
|
||||
/// WTF16 encoded.
|
||||
/// TODO currently, this function does not handle all flag combinations
|
||||
/// or makes use of perm argument.
|
||||
pub fn openatW(dir_fd: fd_t, file_path_w: []const u16, flags: u32, mode: mode_t) OpenError!fd_t {
|
||||
_ = mode;
|
||||
var options = openOptionsFromFlagsWindows(flags);
|
||||
options.dir = dir_fd;
|
||||
return windows.OpenFile(file_path_w, options) catch |err| switch (err) {
|
||||
error.WouldBlock => unreachable,
|
||||
error.PipeBusy => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn dup(old_fd: fd_t) !fd_t {
|
||||
const rc = system.dup(old_fd);
|
||||
return switch (errno(rc)) {
|
||||
@ -2403,42 +2362,43 @@ pub fn linkat(
|
||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
const old: RelativePathWasi = .{ .dir_fd = olddir, .relative_path = oldpath };
|
||||
const new: RelativePathWasi = .{ .dir_fd = newdir, .relative_path = newpath };
|
||||
return linkatWasi(old, new, flags);
|
||||
const old_flags: wasi.lookupflags_t = .{
|
||||
.SYMLINK_FOLLOW = (flags & AT.SYMLINK_FOLLOW) != 0,
|
||||
};
|
||||
switch (wasi.path_link(
|
||||
old.dir_fd,
|
||||
old_flags,
|
||||
old.relative_path.ptr,
|
||||
old.relative_path.len,
|
||||
new.dir_fd,
|
||||
new.relative_path.ptr,
|
||||
new.relative_path.len,
|
||||
)) {
|
||||
.SUCCESS => return,
|
||||
.ACCES => return error.AccessDenied,
|
||||
.DQUOT => return error.DiskQuota,
|
||||
.EXIST => return error.PathAlreadyExists,
|
||||
.FAULT => unreachable,
|
||||
.IO => return error.FileSystem,
|
||||
.LOOP => return error.SymLinkLoop,
|
||||
.MLINK => return error.LinkQuotaExceeded,
|
||||
.NAMETOOLONG => return error.NameTooLong,
|
||||
.NOENT => return error.FileNotFound,
|
||||
.NOMEM => return error.SystemResources,
|
||||
.NOSPC => return error.NoSpaceLeft,
|
||||
.NOTDIR => return error.NotDir,
|
||||
.PERM => return error.AccessDenied,
|
||||
.ROFS => return error.ReadOnlyFileSystem,
|
||||
.XDEV => return error.NotSameFileSystem,
|
||||
.INVAL => unreachable,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
const old = try toPosixPath(oldpath);
|
||||
const new = try toPosixPath(newpath);
|
||||
return try linkatZ(olddir, &old, newdir, &new, flags);
|
||||
}
|
||||
|
||||
/// WASI-only. The same as `linkat` but targeting WASI.
|
||||
/// See also `linkat`.
|
||||
pub fn linkatWasi(old: RelativePathWasi, new: RelativePathWasi, flags: i32) LinkatError!void {
|
||||
var old_flags: wasi.lookupflags_t = 0;
|
||||
// TODO: Why is this not defined in wasi-libc?
|
||||
if (flags & linux.AT.SYMLINK_FOLLOW != 0) old_flags |= wasi.LOOKUP_SYMLINK_FOLLOW;
|
||||
|
||||
switch (wasi.path_link(old.dir_fd, old_flags, old.relative_path.ptr, old.relative_path.len, new.dir_fd, new.relative_path.ptr, new.relative_path.len)) {
|
||||
.SUCCESS => return,
|
||||
.ACCES => return error.AccessDenied,
|
||||
.DQUOT => return error.DiskQuota,
|
||||
.EXIST => return error.PathAlreadyExists,
|
||||
.FAULT => unreachable,
|
||||
.IO => return error.FileSystem,
|
||||
.LOOP => return error.SymLinkLoop,
|
||||
.MLINK => return error.LinkQuotaExceeded,
|
||||
.NAMETOOLONG => return error.NameTooLong,
|
||||
.NOENT => return error.FileNotFound,
|
||||
.NOMEM => return error.SystemResources,
|
||||
.NOSPC => return error.NoSpaceLeft,
|
||||
.NOTDIR => return error.NotDir,
|
||||
.PERM => return error.AccessDenied,
|
||||
.ROFS => return error.ReadOnlyFileSystem,
|
||||
.XDEV => return error.NotSameFileSystem,
|
||||
.INVAL => unreachable,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub const UnlinkError = error{
|
||||
FileNotFound,
|
||||
|
||||
@ -3404,20 +3364,16 @@ pub fn isatty(handle: fd_t) bool {
|
||||
return system.isatty(handle) != 0;
|
||||
}
|
||||
if (builtin.os.tag == .wasi) {
|
||||
var statbuf: fdstat_t = undefined;
|
||||
const err = system.fd_fdstat_get(handle, &statbuf);
|
||||
if (err != .SUCCESS) {
|
||||
// errno = err;
|
||||
var statbuf: wasi.fdstat_t = undefined;
|
||||
const err = wasi.fd_fdstat_get(handle, &statbuf);
|
||||
if (err != .SUCCESS)
|
||||
return false;
|
||||
}
|
||||
|
||||
// A tty is a character device that we can't seek or tell on.
|
||||
if (statbuf.fs_filetype != .CHARACTER_DEVICE or
|
||||
(statbuf.fs_rights_base & (RIGHT.FD_SEEK | RIGHT.FD_TELL)) != 0)
|
||||
{
|
||||
// errno = ENOTTY;
|
||||
if (statbuf.fs_filetype != .CHARACTER_DEVICE)
|
||||
return false;
|
||||
if (statbuf.fs_rights_base.FD_SEEK or statbuf.fs_rights_base.FD_TELL)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -3838,11 +3794,11 @@ pub fn accept(
|
||||
/// will return a value greater than was supplied to the call.
|
||||
addr_size: ?*socklen_t,
|
||||
/// The following values can be bitwise ORed in flags to obtain different behavior:
|
||||
/// * `SOCK.NONBLOCK` - Set the `O.NONBLOCK` file status flag on the open file description (see `open`)
|
||||
/// * `SOCK.NONBLOCK` - Set the `NONBLOCK` file status flag on the open file description (see `open`)
|
||||
/// referred to by the new file descriptor. Using this flag saves extra calls to `fcntl` to achieve
|
||||
/// the same result.
|
||||
/// * `SOCK.CLOEXEC` - Set the close-on-exec (`FD_CLOEXEC`) flag on the new file descriptor. See the
|
||||
/// description of the `O.CLOEXEC` flag in `open` for reasons why this may be useful.
|
||||
/// description of the `CLOEXEC` flag in `open` for reasons why this may be useful.
|
||||
flags: u32,
|
||||
) AcceptError!socket_t {
|
||||
const have_accept4 = comptime !(builtin.target.isDarwin() or builtin.os.tag == .windows);
|
||||
@ -4278,16 +4234,7 @@ pub const FStatError = error{
|
||||
/// Return information about a file descriptor.
|
||||
pub fn fstat(fd: fd_t) FStatError!Stat {
|
||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
var stat: wasi.filestat_t = undefined;
|
||||
switch (wasi.fd_filestat_get(fd, &stat)) {
|
||||
.SUCCESS => return Stat.fromFilestat(stat),
|
||||
.INVAL => unreachable,
|
||||
.BADF => unreachable, // Always a race condition.
|
||||
.NOMEM => return error.SystemResources,
|
||||
.ACCES => return error.AccessDenied,
|
||||
.NOTCAPABLE => return error.AccessDenied,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
return Stat.fromFilestat(try fstat_wasi(fd));
|
||||
}
|
||||
if (builtin.os.tag == .windows) {
|
||||
@compileError("fstat is not yet implemented on Windows");
|
||||
@ -4306,15 +4253,30 @@ pub fn fstat(fd: fd_t) FStatError!Stat {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fstat_wasi(fd: fd_t) FStatError!wasi.filestat_t {
|
||||
var stat: wasi.filestat_t = undefined;
|
||||
switch (wasi.fd_filestat_get(fd, &stat)) {
|
||||
.SUCCESS => return stat,
|
||||
.INVAL => unreachable,
|
||||
.BADF => unreachable, // Always a race condition.
|
||||
.NOMEM => return error.SystemResources,
|
||||
.ACCES => return error.AccessDenied,
|
||||
.NOTCAPABLE => return error.AccessDenied,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub const FStatAtError = FStatError || error{ NameTooLong, FileNotFound, SymLinkLoop };
|
||||
|
||||
/// Similar to `fstat`, but returns stat of a resource pointed to by `pathname`
|
||||
/// which is relative to `dirfd` handle.
|
||||
/// See also `fstatatZ` and `fstatatWasi`.
|
||||
/// See also `fstatatZ` and `fstatat_wasi`.
|
||||
pub fn fstatat(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!Stat {
|
||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
const wasi_flags = if (flags & linux.AT.SYMLINK_NOFOLLOW == 0) wasi.LOOKUP_SYMLINK_FOLLOW else 0;
|
||||
return fstatatWasi(dirfd, pathname, wasi_flags);
|
||||
const filestat = try fstatat_wasi(dirfd, pathname, .{
|
||||
.SYMLINK_FOLLOW = (flags & AT.SYMLINK_NOFOLLOW) == 0,
|
||||
});
|
||||
return Stat.fromFilestat(filestat);
|
||||
} else if (builtin.os.tag == .windows) {
|
||||
@compileError("fstatat is not yet implemented on Windows");
|
||||
} else {
|
||||
@ -4325,10 +4287,10 @@ pub fn fstatat(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!Stat
|
||||
|
||||
/// WASI-only. Same as `fstatat` but targeting WASI.
|
||||
/// See also `fstatat`.
|
||||
pub fn fstatatWasi(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!Stat {
|
||||
pub fn fstatat_wasi(dirfd: fd_t, pathname: []const u8, flags: wasi.lookupflags_t) FStatAtError!wasi.filestat_t {
|
||||
var stat: wasi.filestat_t = undefined;
|
||||
switch (wasi.path_filestat_get(dirfd, flags, pathname.ptr, pathname.len, &stat)) {
|
||||
.SUCCESS => return Stat.fromFilestat(stat),
|
||||
.SUCCESS => return stat,
|
||||
.INVAL => unreachable,
|
||||
.BADF => unreachable, // Always a race condition.
|
||||
.NOMEM => return error.SystemResources,
|
||||
@ -4346,7 +4308,10 @@ pub fn fstatatWasi(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!S
|
||||
/// See also `fstatat`.
|
||||
pub fn fstatatZ(dirfd: fd_t, pathname: [*:0]const u8, flags: u32) FStatAtError!Stat {
|
||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
return fstatatWasi(dirfd, mem.sliceTo(pathname), flags);
|
||||
const filestat = try fstatat_wasi(dirfd, mem.sliceTo(pathname, 0), .{
|
||||
.SYMLINK_FOLLOW = (flags & AT.SYMLINK_NOFOLLOW) == 0,
|
||||
});
|
||||
return Stat.fromFilestat(filestat);
|
||||
}
|
||||
|
||||
const fstatat_sym = if (lfs64_abi) system.fstatat64 else system.fstatat;
|
||||
@ -4627,7 +4592,7 @@ pub const MMapError = error{
|
||||
|
||||
/// A file descriptor refers to a non-regular file. Or a file mapping was requested,
|
||||
/// but the file descriptor is not open for reading. Or `MAP.SHARED` was requested
|
||||
/// and `PROT_WRITE` is set, but the file descriptor is not open in `O.RDWR` mode.
|
||||
/// and `PROT_WRITE` is set, but the file descriptor is not open in `RDWR` mode.
|
||||
/// Or `PROT_WRITE` is set, but the file is append-only.
|
||||
AccessDenied,
|
||||
|
||||
@ -4795,10 +4760,12 @@ pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessErr
|
||||
const path_w = try windows.sliceToPrefixedFileW(dirfd, path);
|
||||
return faccessatW(dirfd, path_w.span().ptr, mode, flags);
|
||||
} else if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
const resolved = RelativePathWasi{ .dir_fd = dirfd, .relative_path = path };
|
||||
const resolved: RelativePathWasi = .{ .dir_fd = dirfd, .relative_path = path };
|
||||
|
||||
const file = blk: {
|
||||
break :blk fstatat(dirfd, path, flags);
|
||||
const st = blk: {
|
||||
break :blk fstatat_wasi(dirfd, path, .{
|
||||
.SYMLINK_FOLLOW = (flags & AT.SYMLINK_NOFOLLOW) == 0,
|
||||
});
|
||||
} catch |err| switch (err) {
|
||||
error.AccessDenied => return error.PermissionDenied,
|
||||
else => |e| return e,
|
||||
@ -4810,19 +4777,23 @@ pub fn faccessat(dirfd: fd_t, path: []const u8, mode: u32, flags: u32) AccessErr
|
||||
return error.PermissionDenied;
|
||||
}
|
||||
|
||||
var rights: wasi.rights_t = 0;
|
||||
var rights: wasi.rights_t = .{};
|
||||
if (mode & R_OK != 0) {
|
||||
rights |= if (file.filetype == .DIRECTORY)
|
||||
wasi.RIGHT.FD_READDIR
|
||||
else
|
||||
wasi.RIGHT.FD_READ;
|
||||
if (st.filetype == .DIRECTORY) {
|
||||
rights.FD_READDIR = true;
|
||||
} else {
|
||||
rights.FD_READ = true;
|
||||
}
|
||||
}
|
||||
if (mode & W_OK != 0) {
|
||||
rights |= wasi.RIGHT.FD_WRITE;
|
||||
rights.FD_WRITE = true;
|
||||
}
|
||||
// No validation for X_OK
|
||||
|
||||
if ((rights & directory.fs_rights_inheriting) != rights) {
|
||||
// https://github.com/ziglang/zig/issues/18882
|
||||
const rights_int: u64 = @bitCast(rights);
|
||||
const inheriting_int: u64 = @bitCast(directory.fs_rights_inheriting);
|
||||
if ((rights_int & inheriting_int) != rights_int) {
|
||||
return error.PermissionDenied;
|
||||
}
|
||||
}
|
||||
@ -4915,7 +4886,7 @@ pub fn pipe() PipeError![2]fd_t {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pipe2(flags: u32) PipeError![2]fd_t {
|
||||
pub fn pipe2(flags: O) PipeError![2]fd_t {
|
||||
if (@hasDecl(system, "pipe2")) {
|
||||
var fds: [2]fd_t = undefined;
|
||||
switch (errno(system.pipe2(&fds, flags))) {
|
||||
@ -4934,12 +4905,13 @@ pub fn pipe2(flags: u32) PipeError![2]fd_t {
|
||||
close(fds[1]);
|
||||
}
|
||||
|
||||
if (flags == 0)
|
||||
// https://github.com/ziglang/zig/issues/18882
|
||||
if (@as(u32, @bitCast(flags)) == 0)
|
||||
return fds;
|
||||
|
||||
// O.CLOEXEC is special, it's a file descriptor flag and must be set using
|
||||
// CLOEXEC is special, it's a file descriptor flag and must be set using
|
||||
// F.SETFD.
|
||||
if (flags & O.CLOEXEC != 0) {
|
||||
if (flags.CLOEXEC) {
|
||||
for (fds) |fd| {
|
||||
switch (errno(system.fcntl(fd, F.SETFD, @as(u32, FD_CLOEXEC)))) {
|
||||
.SUCCESS => {},
|
||||
@ -4950,7 +4922,11 @@ pub fn pipe2(flags: u32) PipeError![2]fd_t {
|
||||
}
|
||||
}
|
||||
|
||||
const new_flags = flags & ~@as(u32, O.CLOEXEC);
|
||||
const new_flags: u32 = f: {
|
||||
var new_flags = flags;
|
||||
new_flags.CLOEXEC = false;
|
||||
break :f @bitCast(new_flags);
|
||||
};
|
||||
// Set every other flag affecting the file status using F.SETFL.
|
||||
if (new_flags != 0) {
|
||||
for (fds) |fd| {
|
||||
@ -5289,7 +5265,7 @@ fn setSockFlags(sock: socket_t, flags: u32) !void {
|
||||
error.LockedRegionLimitExceeded => unreachable,
|
||||
else => |e| return e,
|
||||
};
|
||||
fl_flags |= O.NONBLOCK;
|
||||
fl_flags |= 1 << @bitOffsetOf(O, "NONBLOCK");
|
||||
_ = fcntl(sock, F.SETFL, fl_flags) catch |err| switch (err) {
|
||||
error.FileBusy => unreachable,
|
||||
error.Locked => unreachable,
|
||||
@ -5389,7 +5365,17 @@ pub fn realpathZ(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealP
|
||||
return realpath(mem.sliceTo(pathname, 0), out_buffer);
|
||||
}
|
||||
if (!builtin.link_libc) {
|
||||
const flags = if (builtin.os.tag == .linux) O.PATH | O.NONBLOCK | O.CLOEXEC else O.NONBLOCK | O.CLOEXEC;
|
||||
const flags: O = switch (builtin.os.tag) {
|
||||
.linux => .{
|
||||
.NONBLOCK = true,
|
||||
.CLOEXEC = true,
|
||||
.PATH = true,
|
||||
},
|
||||
else => .{
|
||||
.NONBLOCK = true,
|
||||
.CLOEXEC = true,
|
||||
},
|
||||
};
|
||||
const fd = openZ(pathname, flags, 0) catch |err| switch (err) {
|
||||
error.FileLocksNotSupported => unreachable,
|
||||
error.WouldBlock => unreachable,
|
||||
@ -5893,7 +5879,10 @@ pub fn futimens(fd: fd_t, times: *const [2]timespec) FutimensError!void {
|
||||
// this here, but we should really handle it somehow.
|
||||
const atim = times[0].toTimestamp();
|
||||
const mtim = times[1].toTimestamp();
|
||||
switch (wasi.fd_filestat_set_times(fd, atim, mtim, wasi.FILESTAT_SET_ATIM | wasi.FILESTAT_SET_MTIM)) {
|
||||
switch (wasi.fd_filestat_set_times(fd, atim, mtim, .{
|
||||
.ATIM = true,
|
||||
.MTIM = true,
|
||||
})) {
|
||||
.SUCCESS => return,
|
||||
.ACCES => return error.AccessDenied,
|
||||
.PERM => return error.PermissionDenied,
|
||||
@ -6390,7 +6379,7 @@ pub fn sendfile(
|
||||
// * Descriptor is not valid or locked
|
||||
// * an mmap(2)-like operation is not available for in_fd
|
||||
// * count is negative
|
||||
// * out_fd has the O.APPEND flag set
|
||||
// * out_fd has the APPEND flag set
|
||||
// Because of the "mmap(2)-like operation" possibility, we fall back to doing read/write
|
||||
// manually, the same as ENOSYS.
|
||||
break :sf;
|
||||
@ -6588,7 +6577,7 @@ pub const CopyFileRangeError = error{
|
||||
FileTooBig,
|
||||
InputOutput,
|
||||
/// `fd_in` is not open for reading; or `fd_out` is not open for writing;
|
||||
/// or the `O.APPEND` flag is set for `fd_out`.
|
||||
/// or the `APPEND` flag is set for `fd_out`.
|
||||
FilesOpenedWithWrongFlags,
|
||||
IsDir,
|
||||
OutOfMemory,
|
||||
@ -7425,7 +7414,7 @@ pub const TimerFdCreateError = error{
|
||||
pub const TimerFdGetError = error{InvalidHandle} || UnexpectedError;
|
||||
pub const TimerFdSetError = TimerFdGetError || error{Canceled};
|
||||
|
||||
pub fn timerfd_create(clokid: i32, flags: u32) TimerFdCreateError!fd_t {
|
||||
pub fn timerfd_create(clokid: i32, flags: linux.TFD) TimerFdCreateError!fd_t {
|
||||
const rc = linux.timerfd_create(clokid, flags);
|
||||
return switch (errno(rc)) {
|
||||
.SUCCESS => @as(fd_t, @intCast(rc)),
|
||||
@ -7439,7 +7428,12 @@ pub fn timerfd_create(clokid: i32, flags: u32) TimerFdCreateError!fd_t {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn timerfd_settime(fd: i32, flags: u32, new_value: *const linux.itimerspec, old_value: ?*linux.itimerspec) TimerFdSetError!void {
|
||||
pub fn timerfd_settime(
|
||||
fd: i32,
|
||||
flags: linux.TFD.TIMER,
|
||||
new_value: *const linux.itimerspec,
|
||||
old_value: ?*linux.itimerspec,
|
||||
) TimerFdSetError!void {
|
||||
const rc = linux.timerfd_settime(fd, flags, new_value, old_value);
|
||||
return switch (errno(rc)) {
|
||||
.SUCCESS => {},
|
||||
|
@ -127,20 +127,6 @@ pub const AF = struct {
|
||||
pub const MAX = PF.MAX;
|
||||
};
|
||||
|
||||
pub const AT = struct {
|
||||
pub const FDCWD = -100;
|
||||
pub const SYMLINK_NOFOLLOW = 0x100;
|
||||
pub const REMOVEDIR = 0x200;
|
||||
pub const SYMLINK_FOLLOW = 0x400;
|
||||
pub const NO_AUTOMOUNT = 0x800;
|
||||
pub const EMPTY_PATH = 0x1000;
|
||||
pub const STATX_SYNC_TYPE = 0x6000;
|
||||
pub const STATX_SYNC_AS_STAT = 0x0000;
|
||||
pub const STATX_FORCE_SYNC = 0x2000;
|
||||
pub const STATX_DONT_SYNC = 0x4000;
|
||||
pub const RECURSIVE = 0x8000;
|
||||
};
|
||||
|
||||
pub const CLOCK = struct {
|
||||
pub const REALTIME = 0;
|
||||
pub const MONOTONIC = 1;
|
||||
@ -479,33 +465,6 @@ pub const MSG = struct {
|
||||
pub const CMSG_CLOEXEC = 0x40000000;
|
||||
};
|
||||
|
||||
pub const O = struct {
|
||||
pub const RDONLY = 0o0;
|
||||
pub const WRONLY = 0o1;
|
||||
pub const RDWR = 0o2;
|
||||
|
||||
pub const CREAT = 0o100;
|
||||
pub const EXCL = 0o200;
|
||||
pub const NOCTTY = 0o400;
|
||||
pub const TRUNC = 0o1000;
|
||||
pub const APPEND = 0o2000;
|
||||
pub const NONBLOCK = 0o4000;
|
||||
pub const DSYNC = 0o10000;
|
||||
pub const SYNC = 0o4010000;
|
||||
pub const RSYNC = 0o4010000;
|
||||
pub const DIRECTORY = 0o200000;
|
||||
pub const NOFOLLOW = 0o400000;
|
||||
pub const CLOEXEC = 0o2000000;
|
||||
|
||||
pub const ASYNC = 0o20000;
|
||||
pub const DIRECT = 0o40000;
|
||||
pub const LARGEFILE = 0o100000;
|
||||
pub const NOATIME = 0o1000000;
|
||||
pub const PATH = 0o10000000;
|
||||
pub const TMPFILE = 0o20200000;
|
||||
pub const NDELAY = NONBLOCK;
|
||||
};
|
||||
|
||||
pub const POLL = struct {
|
||||
pub const IN = 0x001;
|
||||
pub const PRI = 0x002;
|
||||
|
@ -20,6 +20,7 @@ const is_ppc64 = native_arch.isPPC64();
|
||||
const is_sparc = native_arch.isSPARC();
|
||||
const iovec = std.os.iovec;
|
||||
const iovec_const = std.os.iovec_const;
|
||||
const ACCMODE = std.os.ACCMODE;
|
||||
|
||||
test {
|
||||
if (builtin.os.tag == .linux) {
|
||||
@ -241,12 +242,145 @@ pub const MAP = switch (native_arch) {
|
||||
else => @compileError("missing std.os.linux.MAP constants for this architecture"),
|
||||
};
|
||||
|
||||
pub const O = struct {
|
||||
pub usingnamespace arch_bits.O;
|
||||
|
||||
pub const RDONLY = 0o0;
|
||||
pub const WRONLY = 0o1;
|
||||
pub const RDWR = 0o2;
|
||||
pub const O = switch (native_arch) {
|
||||
.x86_64 => packed struct(u32) {
|
||||
ACCMODE: ACCMODE = .RDONLY,
|
||||
_2: u4 = 0,
|
||||
CREAT: bool = false,
|
||||
EXCL: bool = false,
|
||||
NOCTTY: bool = false,
|
||||
TRUNC: bool = false,
|
||||
APPEND: bool = false,
|
||||
NONBLOCK: bool = false,
|
||||
DSYNC: bool = false,
|
||||
ASYNC: bool = false,
|
||||
DIRECT: bool = false,
|
||||
_15: u1 = 0,
|
||||
DIRECTORY: bool = false,
|
||||
NOFOLLOW: bool = false,
|
||||
NOATIME: bool = false,
|
||||
CLOEXEC: bool = false,
|
||||
SYNC: bool = false,
|
||||
PATH: bool = false,
|
||||
TMPFILE: bool = false,
|
||||
_: u9 = 0,
|
||||
},
|
||||
.x86, .riscv64 => packed struct(u32) {
|
||||
ACCMODE: ACCMODE = .RDONLY,
|
||||
_2: u4 = 0,
|
||||
CREAT: bool = false,
|
||||
EXCL: bool = false,
|
||||
NOCTTY: bool = false,
|
||||
TRUNC: bool = false,
|
||||
APPEND: bool = false,
|
||||
NONBLOCK: bool = false,
|
||||
DSYNC: bool = false,
|
||||
ASYNC: bool = false,
|
||||
DIRECT: bool = false,
|
||||
LARGEFILE: bool = false,
|
||||
DIRECTORY: bool = false,
|
||||
NOFOLLOW: bool = false,
|
||||
NOATIME: bool = false,
|
||||
CLOEXEC: bool = false,
|
||||
SYNC: bool = false,
|
||||
PATH: bool = false,
|
||||
TMPFILE: bool = false,
|
||||
_: u9 = 0,
|
||||
},
|
||||
.aarch64, .aarch64_be, .arm, .thumb => packed struct(u32) {
|
||||
ACCMODE: ACCMODE = .RDONLY,
|
||||
_2: u4 = 0,
|
||||
CREAT: bool = false,
|
||||
EXCL: bool = false,
|
||||
NOCTTY: bool = false,
|
||||
TRUNC: bool = false,
|
||||
APPEND: bool = false,
|
||||
NONBLOCK: bool = false,
|
||||
DSYNC: bool = false,
|
||||
ASYNC: bool = false,
|
||||
DIRECTORY: bool = false,
|
||||
NOFOLLOW: bool = false,
|
||||
DIRECT: bool = false,
|
||||
LARGEFILE: bool = false,
|
||||
NOATIME: bool = false,
|
||||
CLOEXEC: bool = false,
|
||||
SYNC: bool = false,
|
||||
PATH: bool = false,
|
||||
TMPFILE: bool = false,
|
||||
_: u9 = 0,
|
||||
},
|
||||
.sparc64 => packed struct(u32) {
|
||||
ACCMODE: ACCMODE = .RDONLY,
|
||||
_2: u1 = 0,
|
||||
APPEND: bool = false,
|
||||
_4: u2 = 0,
|
||||
ASYNC: bool = false,
|
||||
_7: u2 = 0,
|
||||
CREAT: bool = false,
|
||||
TRUNC: bool = false,
|
||||
EXCL: bool = false,
|
||||
_12: u1 = 0,
|
||||
DSYNC: bool = false,
|
||||
NONBLOCK: bool = false,
|
||||
NOCTTY: bool = false,
|
||||
DIRECTORY: bool = false,
|
||||
NOFOLLOW: bool = false,
|
||||
_18: u2 = 0,
|
||||
DIRECT: bool = false,
|
||||
NOATIME: bool = false,
|
||||
CLOEXEC: bool = false,
|
||||
SYNC: bool = false,
|
||||
PATH: bool = false,
|
||||
TMPFILE: bool = false,
|
||||
_: u6 = 0,
|
||||
},
|
||||
.mips, .mipsel, .mips64, .mips64el => packed struct(u32) {
|
||||
ACCMODE: ACCMODE = .RDONLY,
|
||||
_2: u1 = 0,
|
||||
APPEND: bool = false,
|
||||
DSYNC: bool = false,
|
||||
_5: u2 = 0,
|
||||
NONBLOCK: bool = false,
|
||||
CREAT: bool = false,
|
||||
TRUNC: bool = false,
|
||||
EXCL: bool = false,
|
||||
NOCTTY: bool = false,
|
||||
ASYNC: bool = false,
|
||||
LARGEFILE: bool = false,
|
||||
SYNC: bool = false,
|
||||
DIRECT: bool = false,
|
||||
DIRECTORY: bool = false,
|
||||
NOFOLLOW: bool = false,
|
||||
NOATIME: bool = false,
|
||||
CLOEXEC: bool = false,
|
||||
_20: u1 = 0,
|
||||
PATH: bool = false,
|
||||
TMPFILE: bool = false,
|
||||
_: u9 = 0,
|
||||
},
|
||||
.powerpc, .powerpcle, .powerpc64, .powerpc64le => packed struct(u32) {
|
||||
ACCMODE: ACCMODE = .RDONLY,
|
||||
_2: u4 = 0,
|
||||
CREAT: bool = false,
|
||||
EXCL: bool = false,
|
||||
NOCTTY: bool = false,
|
||||
TRUNC: bool = false,
|
||||
APPEND: bool = false,
|
||||
NONBLOCK: bool = false,
|
||||
DSYNC: bool = false,
|
||||
ASYNC: bool = false,
|
||||
DIRECTORY: bool = false,
|
||||
NOFOLLOW: bool = false,
|
||||
LARGEFILE: bool = false,
|
||||
DIRECT: bool = false,
|
||||
NOATIME: bool = false,
|
||||
CLOEXEC: bool = false,
|
||||
SYNC: bool = false,
|
||||
PATH: bool = false,
|
||||
TMPFILE: bool = false,
|
||||
_: u9 = 0,
|
||||
},
|
||||
else => @compileError("missing std.os.linux.O constants for this architecture"),
|
||||
};
|
||||
|
||||
pub usingnamespace @import("linux/io_uring.zig");
|
||||
@ -620,20 +754,20 @@ pub fn umount2(special: [*:0]const u8, flags: u32) usize {
|
||||
return syscall2(.umount2, @intFromPtr(special), flags);
|
||||
}
|
||||
|
||||
pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: i64) usize {
|
||||
pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: MAP, fd: i32, offset: i64) usize {
|
||||
if (@hasField(SYS, "mmap2")) {
|
||||
// Make sure the offset is also specified in multiples of page size
|
||||
if ((offset & (MMAP2_UNIT - 1)) != 0)
|
||||
return @as(usize, @bitCast(-@as(isize, @intFromEnum(E.INVAL))));
|
||||
return @bitCast(-@as(isize, @intFromEnum(E.INVAL)));
|
||||
|
||||
return syscall6(
|
||||
.mmap2,
|
||||
@intFromPtr(address),
|
||||
length,
|
||||
prot,
|
||||
flags,
|
||||
@as(usize, @bitCast(@as(isize, fd))),
|
||||
@as(usize, @truncate(@as(u64, @bitCast(offset)) / MMAP2_UNIT)),
|
||||
@as(u32, @bitCast(flags)),
|
||||
@bitCast(@as(isize, fd)),
|
||||
@truncate(@as(u64, @bitCast(offset)) / MMAP2_UNIT),
|
||||
);
|
||||
} else {
|
||||
return syscall6(
|
||||
@ -641,8 +775,8 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, of
|
||||
@intFromPtr(address),
|
||||
length,
|
||||
prot,
|
||||
flags,
|
||||
@as(usize, @bitCast(@as(isize, fd))),
|
||||
@as(u32, @bitCast(flags)),
|
||||
@bitCast(@as(isize, fd)),
|
||||
@as(u64, @bitCast(offset)),
|
||||
);
|
||||
}
|
||||
@ -840,12 +974,12 @@ pub fn pipe(fd: *[2]i32) usize {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pipe2(fd: *[2]i32, flags: u32) usize {
|
||||
return syscall2(.pipe2, @intFromPtr(fd), flags);
|
||||
pub fn pipe2(fd: *[2]i32, flags: O) usize {
|
||||
return syscall2(.pipe2, @intFromPtr(fd), @as(u32, @bitCast(flags)));
|
||||
}
|
||||
|
||||
pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
|
||||
return syscall3(.write, @as(usize, @bitCast(@as(isize, fd))), @intFromPtr(buf), count);
|
||||
return syscall3(.write, @bitCast(@as(isize, fd)), @intFromPtr(buf), count);
|
||||
}
|
||||
|
||||
pub fn ftruncate(fd: i32, length: i64) usize {
|
||||
@ -958,15 +1092,15 @@ pub fn renameat2(oldfd: i32, oldpath: [*:0]const u8, newfd: i32, newpath: [*:0]c
|
||||
);
|
||||
}
|
||||
|
||||
pub fn open(path: [*:0]const u8, flags: u32, perm: mode_t) usize {
|
||||
pub fn open(path: [*:0]const u8, flags: O, perm: mode_t) usize {
|
||||
if (@hasField(SYS, "open")) {
|
||||
return syscall3(.open, @intFromPtr(path), flags, perm);
|
||||
return syscall3(.open, @intFromPtr(path), @as(u32, @bitCast(flags)), perm);
|
||||
} else {
|
||||
return syscall4(
|
||||
.openat,
|
||||
@as(usize, @bitCast(@as(isize, AT.FDCWD))),
|
||||
@bitCast(@as(isize, AT.FDCWD)),
|
||||
@intFromPtr(path),
|
||||
flags,
|
||||
@as(u32, @bitCast(flags)),
|
||||
perm,
|
||||
);
|
||||
}
|
||||
@ -976,9 +1110,9 @@ pub fn create(path: [*:0]const u8, perm: mode_t) usize {
|
||||
return syscall2(.creat, @intFromPtr(path), perm);
|
||||
}
|
||||
|
||||
pub fn openat(dirfd: i32, path: [*:0]const u8, flags: u32, mode: mode_t) usize {
|
||||
pub fn openat(dirfd: i32, path: [*:0]const u8, flags: O, mode: mode_t) usize {
|
||||
// dirfd could be negative, for example AT.FDCWD is -100
|
||||
return syscall4(.openat, @as(usize, @bitCast(@as(isize, dirfd))), @intFromPtr(path), flags, mode);
|
||||
return syscall4(.openat, @bitCast(@as(isize, dirfd)), @intFromPtr(path), @as(u32, @bitCast(flags)), mode);
|
||||
}
|
||||
|
||||
/// See also `clone` (from the arch-specific include)
|
||||
@ -1800,8 +1934,8 @@ pub fn eventfd(count: u32, flags: u32) usize {
|
||||
return syscall2(.eventfd2, count, flags);
|
||||
}
|
||||
|
||||
pub fn timerfd_create(clockid: i32, flags: u32) usize {
|
||||
return syscall2(.timerfd_create, @as(usize, @bitCast(@as(isize, clockid))), flags);
|
||||
pub fn timerfd_create(clockid: i32, flags: TFD) usize {
|
||||
return syscall2(.timerfd_create, @bitCast(@as(isize, clockid)), @as(u32, @bitCast(flags)));
|
||||
}
|
||||
|
||||
pub const itimerspec = extern struct {
|
||||
@ -1810,11 +1944,11 @@ pub const itimerspec = extern struct {
|
||||
};
|
||||
|
||||
pub fn timerfd_gettime(fd: i32, curr_value: *itimerspec) usize {
|
||||
return syscall2(.timerfd_gettime, @as(usize, @bitCast(@as(isize, fd))), @intFromPtr(curr_value));
|
||||
return syscall2(.timerfd_gettime, @bitCast(@as(isize, fd)), @intFromPtr(curr_value));
|
||||
}
|
||||
|
||||
pub fn timerfd_settime(fd: i32, flags: u32, new_value: *const itimerspec, old_value: ?*itimerspec) usize {
|
||||
return syscall4(.timerfd_settime, @as(usize, @bitCast(@as(isize, fd))), flags, @intFromPtr(new_value), @intFromPtr(old_value));
|
||||
pub fn timerfd_settime(fd: i32, flags: TFD.TIMER, new_value: *const itimerspec, old_value: ?*itimerspec) usize {
|
||||
return syscall4(.timerfd_settime, @bitCast(@as(isize, fd)), @as(u32, @bitCast(flags)), @intFromPtr(new_value), @intFromPtr(old_value));
|
||||
}
|
||||
|
||||
// Flags for the 'setitimer' system call
|
||||
@ -2478,19 +2612,10 @@ pub const SIG = if (is_mips) struct {
|
||||
pub const kernel_rwf = u32;
|
||||
|
||||
pub const RWF = struct {
|
||||
/// high priority request, poll if possible
|
||||
pub const HIPRI: kernel_rwf = 0x00000001;
|
||||
|
||||
/// per-IO O.DSYNC
|
||||
pub const DSYNC: kernel_rwf = 0x00000002;
|
||||
|
||||
/// per-IO O.SYNC
|
||||
pub const SYNC: kernel_rwf = 0x00000004;
|
||||
|
||||
/// per-IO, return -EAGAIN if operation would block
|
||||
pub const NOWAIT: kernel_rwf = 0x00000008;
|
||||
|
||||
/// per-IO O.APPEND
|
||||
pub const APPEND: kernel_rwf = 0x00000010;
|
||||
};
|
||||
|
||||
@ -3257,7 +3382,7 @@ pub const T = struct {
|
||||
};
|
||||
|
||||
pub const EPOLL = struct {
|
||||
pub const CLOEXEC = O.CLOEXEC;
|
||||
pub const CLOEXEC = 1 << @bitOffsetOf(O, "CLOEXEC");
|
||||
|
||||
pub const CTL_ADD = 1;
|
||||
pub const CTL_DEL = 2;
|
||||
@ -3338,8 +3463,8 @@ pub const CLONE = struct {
|
||||
|
||||
pub const EFD = struct {
|
||||
pub const SEMAPHORE = 1;
|
||||
pub const CLOEXEC = O.CLOEXEC;
|
||||
pub const NONBLOCK = O.NONBLOCK;
|
||||
pub const CLOEXEC = 1 << @bitOffsetOf(O, "CLOEXEC");
|
||||
pub const NONBLOCK = 1 << @bitOffsetOf(O, "NONBLOCK");
|
||||
};
|
||||
|
||||
pub const MS = struct {
|
||||
@ -3388,8 +3513,8 @@ pub const MNT = struct {
|
||||
pub const UMOUNT_NOFOLLOW = 8;
|
||||
|
||||
pub const IN = struct {
|
||||
pub const CLOEXEC = O.CLOEXEC;
|
||||
pub const NONBLOCK = O.NONBLOCK;
|
||||
pub const CLOEXEC = 1 << @bitOffsetOf(O, "CLOEXEC");
|
||||
pub const NONBLOCK = 1 << @bitOffsetOf(O, "NONBLOCK");
|
||||
|
||||
pub const ACCESS = 0x00000001;
|
||||
pub const MODIFY = 0x00000002;
|
||||
@ -3534,12 +3659,40 @@ pub const UTIME = struct {
|
||||
pub const OMIT = 0x3ffffffe;
|
||||
};
|
||||
|
||||
pub const TFD = struct {
|
||||
pub const NONBLOCK = O.NONBLOCK;
|
||||
pub const CLOEXEC = O.CLOEXEC;
|
||||
const TFD_TIMER = packed struct(u32) {
|
||||
ABSTIME: bool = false,
|
||||
CANCEL_ON_SET: bool = false,
|
||||
_: u30 = 0,
|
||||
};
|
||||
|
||||
pub const TIMER_ABSTIME = 1;
|
||||
pub const TIMER_CANCEL_ON_SET = (1 << 1);
|
||||
pub const TFD = switch (native_arch) {
|
||||
.sparc64 => packed struct(u32) {
|
||||
_0: u14 = 0,
|
||||
NONBLOCK: bool = false,
|
||||
_15: u7 = 0,
|
||||
CLOEXEC: bool = false,
|
||||
_: u9 = 0,
|
||||
|
||||
pub const TIMER = TFD_TIMER;
|
||||
},
|
||||
.mips, .mipsel, .mips64, .mips64el => packed struct(u32) {
|
||||
_0: u7 = 0,
|
||||
NONBLOCK: bool = false,
|
||||
_8: u11 = 0,
|
||||
CLOEXEC: bool = false,
|
||||
_: u12 = 0,
|
||||
|
||||
pub const TIMER = TFD_TIMER;
|
||||
},
|
||||
else => packed struct(u32) {
|
||||
_0: u11 = 0,
|
||||
NONBLOCK: bool = false,
|
||||
_12: u7 = 0,
|
||||
CLOEXEC: bool = false,
|
||||
_: u12 = 0,
|
||||
|
||||
pub const TIMER = TFD_TIMER;
|
||||
},
|
||||
};
|
||||
|
||||
pub const winsize = extern struct {
|
||||
@ -3603,8 +3756,8 @@ pub const empty_sigset = [_]u32{0} ** sigset_len;
|
||||
pub const filled_sigset = [_]u32{(1 << (31 & (usize_bits - 1))) - 1} ++ [_]u32{0} ** (sigset_len - 1);
|
||||
|
||||
pub const SFD = struct {
|
||||
pub const CLOEXEC = O.CLOEXEC;
|
||||
pub const NONBLOCK = O.NONBLOCK;
|
||||
pub const CLOEXEC = 1 << @bitOffsetOf(O, "CLOEXEC");
|
||||
pub const NONBLOCK = 1 << @bitOffsetOf(O, "NONBLOCK");
|
||||
};
|
||||
|
||||
pub const signalfd_siginfo = extern struct {
|
||||
@ -3865,15 +4018,11 @@ pub const inotify_event = extern struct {
|
||||
};
|
||||
|
||||
pub const dirent64 = extern struct {
|
||||
d_ino: u64,
|
||||
d_off: u64,
|
||||
d_reclen: u16,
|
||||
d_type: u8,
|
||||
d_name: u8, // field address is the address of first byte of name https://github.com/ziglang/zig/issues/173
|
||||
|
||||
pub fn reclen(self: dirent64) u16 {
|
||||
return self.d_reclen;
|
||||
}
|
||||
ino: u64,
|
||||
off: u64,
|
||||
reclen: u16,
|
||||
type: u8,
|
||||
name: u8, // field address is the address of first byte of name https://github.com/ziglang/zig/issues/173
|
||||
};
|
||||
|
||||
pub const dl_phdr_info = extern struct {
|
||||
|
@ -141,29 +141,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
|
||||
|
||||
pub const MMAP2_UNIT = 4096;
|
||||
|
||||
pub const O = struct {
|
||||
pub const CREAT = 0o100;
|
||||
pub const EXCL = 0o200;
|
||||
pub const NOCTTY = 0o400;
|
||||
pub const TRUNC = 0o1000;
|
||||
pub const APPEND = 0o2000;
|
||||
pub const NONBLOCK = 0o4000;
|
||||
pub const DSYNC = 0o10000;
|
||||
pub const SYNC = 0o4010000;
|
||||
pub const RSYNC = 0o4010000;
|
||||
pub const DIRECTORY = 0o40000;
|
||||
pub const NOFOLLOW = 0o100000;
|
||||
pub const CLOEXEC = 0o2000000;
|
||||
|
||||
pub const ASYNC = 0o20000;
|
||||
pub const DIRECT = 0o200000;
|
||||
pub const LARGEFILE = 0o400000;
|
||||
pub const NOATIME = 0o1000000;
|
||||
pub const PATH = 0o10000000;
|
||||
pub const TMPFILE = 0o20040000;
|
||||
pub const NDELAY = NONBLOCK;
|
||||
};
|
||||
|
||||
pub const F = struct {
|
||||
pub const DUPFD = 0;
|
||||
pub const GETFD = 1;
|
||||
|
@ -123,29 +123,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
|
||||
}
|
||||
}
|
||||
|
||||
pub const O = struct {
|
||||
pub const CREAT = 0o100;
|
||||
pub const EXCL = 0o200;
|
||||
pub const NOCTTY = 0o400;
|
||||
pub const TRUNC = 0o1000;
|
||||
pub const APPEND = 0o2000;
|
||||
pub const NONBLOCK = 0o4000;
|
||||
pub const DSYNC = 0o10000;
|
||||
pub const SYNC = 0o4010000;
|
||||
pub const RSYNC = 0o4010000;
|
||||
pub const DIRECTORY = 0o40000;
|
||||
pub const NOFOLLOW = 0o100000;
|
||||
pub const CLOEXEC = 0o2000000;
|
||||
|
||||
pub const ASYNC = 0o20000;
|
||||
pub const DIRECT = 0o200000;
|
||||
pub const LARGEFILE = 0o400000;
|
||||
pub const NOATIME = 0o1000000;
|
||||
pub const PATH = 0o10000000;
|
||||
pub const TMPFILE = 0o20040000;
|
||||
pub const NDELAY = NONBLOCK;
|
||||
};
|
||||
|
||||
pub const F = struct {
|
||||
pub const DUPFD = 0;
|
||||
pub const GETFD = 1;
|
||||
|
@ -760,7 +760,7 @@ pub const IO_Uring = struct {
|
||||
user_data: u64,
|
||||
fd: os.fd_t,
|
||||
path: [*:0]const u8,
|
||||
flags: u32,
|
||||
flags: linux.O,
|
||||
mode: os.mode_t,
|
||||
) !*linux.io_uring_sqe {
|
||||
const sqe = try self.get_sqe();
|
||||
@ -785,7 +785,7 @@ pub const IO_Uring = struct {
|
||||
user_data: u64,
|
||||
fd: os.fd_t,
|
||||
path: [*:0]const u8,
|
||||
flags: u32,
|
||||
flags: linux.O,
|
||||
mode: os.mode_t,
|
||||
file_index: u32,
|
||||
) !*linux.io_uring_sqe {
|
||||
@ -1658,18 +1658,18 @@ pub fn io_uring_prep_openat(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: os.fd_t,
|
||||
path: [*:0]const u8,
|
||||
flags: u32,
|
||||
flags: linux.O,
|
||||
mode: os.mode_t,
|
||||
) void {
|
||||
io_uring_prep_rw(.OPENAT, sqe, fd, @intFromPtr(path), mode, 0);
|
||||
sqe.rw_flags = flags;
|
||||
sqe.rw_flags = @bitCast(flags);
|
||||
}
|
||||
|
||||
pub fn io_uring_prep_openat_direct(
|
||||
sqe: *linux.io_uring_sqe,
|
||||
fd: os.fd_t,
|
||||
path: [*:0]const u8,
|
||||
flags: u32,
|
||||
flags: linux.O,
|
||||
mode: os.mode_t,
|
||||
file_index: u32,
|
||||
) void {
|
||||
@ -2054,7 +2054,7 @@ test "readv" {
|
||||
};
|
||||
defer ring.deinit();
|
||||
|
||||
const fd = try os.openZ("/dev/zero", os.O.RDONLY | os.O.CLOEXEC, 0);
|
||||
const fd = try os.openZ("/dev/zero", .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
|
||||
defer os.close(fd);
|
||||
|
||||
// Linux Kernel 5.4 supports IORING_REGISTER_FILES but not sparse fd sets (i.e. an fd of -1).
|
||||
@ -2361,7 +2361,7 @@ test "openat" {
|
||||
break :p @intFromPtr(workaround);
|
||||
} else @intFromPtr(path);
|
||||
|
||||
const flags: u32 = os.O.CLOEXEC | os.O.RDWR | os.O.CREAT;
|
||||
const flags: linux.O = .{ .CLOEXEC = true, .ACCMODE = .RDWR, .CREAT = true };
|
||||
const mode: os.mode_t = 0o666;
|
||||
const sqe_openat = try ring.openat(0x33333333, tmp.dir.fd, path, flags, mode);
|
||||
try testing.expectEqual(linux.io_uring_sqe{
|
||||
@ -2372,7 +2372,7 @@ test "openat" {
|
||||
.off = 0,
|
||||
.addr = path_addr,
|
||||
.len = mode,
|
||||
.rw_flags = flags,
|
||||
.rw_flags = @bitCast(flags),
|
||||
.user_data = 0x33333333,
|
||||
.buf_index = 0,
|
||||
.personality = 0,
|
||||
@ -2888,7 +2888,7 @@ test "register_files_update" {
|
||||
};
|
||||
defer ring.deinit();
|
||||
|
||||
const fd = try os.openZ("/dev/zero", os.O.RDONLY | os.O.CLOEXEC, 0);
|
||||
const fd = try os.openZ("/dev/zero", .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
|
||||
defer os.close(fd);
|
||||
|
||||
var registered_fds = [_]os.fd_t{0} ** 2;
|
||||
@ -2906,7 +2906,7 @@ test "register_files_update" {
|
||||
// Test IORING_REGISTER_FILES_UPDATE
|
||||
// Only available since Linux 5.5
|
||||
|
||||
const fd2 = try os.openZ("/dev/zero", os.O.RDONLY | os.O.CLOEXEC, 0);
|
||||
const fd2 = try os.openZ("/dev/zero", .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
|
||||
defer os.close(fd2);
|
||||
|
||||
registered_fds[fd_index] = fd2;
|
||||
@ -3311,7 +3311,7 @@ test "provide_buffers: read" {
|
||||
};
|
||||
defer ring.deinit();
|
||||
|
||||
const fd = try os.openZ("/dev/zero", os.O.RDONLY | os.O.CLOEXEC, 0);
|
||||
const fd = try os.openZ("/dev/zero", .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
|
||||
defer os.close(fd);
|
||||
|
||||
const group_id = 1337;
|
||||
@ -3443,7 +3443,7 @@ test "remove_buffers" {
|
||||
};
|
||||
defer ring.deinit();
|
||||
|
||||
const fd = try os.openZ("/dev/zero", os.O.RDONLY | os.O.CLOEXEC, 0);
|
||||
const fd = try os.openZ("/dev/zero", .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
|
||||
defer os.close(fd);
|
||||
|
||||
const group_id = 1337;
|
||||
@ -4113,7 +4113,7 @@ test "openat_direct/close_direct" {
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
const path = "test_io_uring_close_direct";
|
||||
const flags: u32 = os.O.RDWR | os.O.CREAT;
|
||||
const flags: linux.O = .{ .ACCMODE = .RDWR, .CREAT = true };
|
||||
const mode: os.mode_t = 0o666;
|
||||
const user_data: u64 = 0;
|
||||
|
||||
|
@ -213,29 +213,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
|
||||
);
|
||||
}
|
||||
|
||||
pub const O = struct {
|
||||
pub const CREAT = 0o0400;
|
||||
pub const EXCL = 0o02000;
|
||||
pub const NOCTTY = 0o04000;
|
||||
pub const TRUNC = 0o01000;
|
||||
pub const APPEND = 0o0010;
|
||||
pub const NONBLOCK = 0o0200;
|
||||
pub const DSYNC = 0o0020;
|
||||
pub const SYNC = 0o040020;
|
||||
pub const RSYNC = 0o040020;
|
||||
pub const DIRECTORY = 0o0200000;
|
||||
pub const NOFOLLOW = 0o0400000;
|
||||
pub const CLOEXEC = 0o02000000;
|
||||
|
||||
pub const ASYNC = 0o010000;
|
||||
pub const DIRECT = 0o0100000;
|
||||
pub const LARGEFILE = 0o020000;
|
||||
pub const NOATIME = 0o01000000;
|
||||
pub const PATH = 0o010000000;
|
||||
pub const TMPFILE = 0o020200000;
|
||||
pub const NDELAY = NONBLOCK;
|
||||
};
|
||||
|
||||
pub const F = struct {
|
||||
pub const DUPFD = 0;
|
||||
pub const GETFD = 1;
|
||||
|
@ -198,29 +198,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
|
||||
);
|
||||
}
|
||||
|
||||
pub const O = struct {
|
||||
pub const CREAT = 0o0400;
|
||||
pub const EXCL = 0o02000;
|
||||
pub const NOCTTY = 0o04000;
|
||||
pub const TRUNC = 0o01000;
|
||||
pub const APPEND = 0o0010;
|
||||
pub const NONBLOCK = 0o0200;
|
||||
pub const DSYNC = 0o0020;
|
||||
pub const SYNC = 0o040020;
|
||||
pub const RSYNC = 0o040020;
|
||||
pub const DIRECTORY = 0o0200000;
|
||||
pub const NOFOLLOW = 0o0400000;
|
||||
pub const CLOEXEC = 0o02000000;
|
||||
|
||||
pub const ASYNC = 0o010000;
|
||||
pub const DIRECT = 0o0100000;
|
||||
pub const LARGEFILE = 0o020000;
|
||||
pub const NOATIME = 0o01000000;
|
||||
pub const PATH = 0o010000000;
|
||||
pub const TMPFILE = 0o020200000;
|
||||
pub const NDELAY = NONBLOCK;
|
||||
};
|
||||
|
||||
pub const F = struct {
|
||||
pub const DUPFD = 0;
|
||||
pub const GETFD = 1;
|
||||
|
@ -142,29 +142,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
|
||||
);
|
||||
}
|
||||
|
||||
pub const O = struct {
|
||||
pub const CREAT = 0o100;
|
||||
pub const EXCL = 0o200;
|
||||
pub const NOCTTY = 0o400;
|
||||
pub const TRUNC = 0o1000;
|
||||
pub const APPEND = 0o2000;
|
||||
pub const NONBLOCK = 0o4000;
|
||||
pub const DSYNC = 0o10000;
|
||||
pub const SYNC = 0o4010000;
|
||||
pub const RSYNC = 0o4010000;
|
||||
pub const DIRECTORY = 0o40000;
|
||||
pub const NOFOLLOW = 0o100000;
|
||||
pub const CLOEXEC = 0o2000000;
|
||||
|
||||
pub const ASYNC = 0o20000;
|
||||
pub const DIRECT = 0o400000;
|
||||
pub const LARGEFILE = 0o200000;
|
||||
pub const NOATIME = 0o1000000;
|
||||
pub const PATH = 0o10000000;
|
||||
pub const TMPFILE = 0o20040000;
|
||||
pub const NDELAY = NONBLOCK;
|
||||
};
|
||||
|
||||
pub const F = struct {
|
||||
pub const DUPFD = 0;
|
||||
pub const GETFD = 1;
|
||||
|
@ -142,29 +142,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
|
||||
);
|
||||
}
|
||||
|
||||
pub const O = struct {
|
||||
pub const CREAT = 0o100;
|
||||
pub const EXCL = 0o200;
|
||||
pub const NOCTTY = 0o400;
|
||||
pub const TRUNC = 0o1000;
|
||||
pub const APPEND = 0o2000;
|
||||
pub const NONBLOCK = 0o4000;
|
||||
pub const DSYNC = 0o10000;
|
||||
pub const SYNC = 0o4010000;
|
||||
pub const RSYNC = 0o4010000;
|
||||
pub const DIRECTORY = 0o40000;
|
||||
pub const NOFOLLOW = 0o100000;
|
||||
pub const CLOEXEC = 0o2000000;
|
||||
|
||||
pub const ASYNC = 0o20000;
|
||||
pub const DIRECT = 0o400000;
|
||||
pub const LARGEFILE = 0o200000;
|
||||
pub const NOATIME = 0o1000000;
|
||||
pub const PATH = 0o10000000;
|
||||
pub const TMPFILE = 0o20200000;
|
||||
pub const NDELAY = NONBLOCK;
|
||||
};
|
||||
|
||||
pub const F = struct {
|
||||
pub const DUPFD = 0;
|
||||
pub const GETFD = 1;
|
||||
|
@ -110,29 +110,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
|
||||
);
|
||||
}
|
||||
|
||||
pub const O = struct {
|
||||
pub const CREAT = 0o100;
|
||||
pub const EXCL = 0o200;
|
||||
pub const NOCTTY = 0o400;
|
||||
pub const TRUNC = 0o1000;
|
||||
pub const APPEND = 0o2000;
|
||||
pub const NONBLOCK = 0o4000;
|
||||
pub const DSYNC = 0o10000;
|
||||
pub const SYNC = 0o4010000;
|
||||
pub const RSYNC = 0o4010000;
|
||||
pub const DIRECTORY = 0o200000;
|
||||
pub const NOFOLLOW = 0o400000;
|
||||
pub const CLOEXEC = 0o2000000;
|
||||
|
||||
pub const ASYNC = 0o20000;
|
||||
pub const DIRECT = 0o40000;
|
||||
pub const LARGEFILE = 0o100000;
|
||||
pub const NOATIME = 0o1000000;
|
||||
pub const PATH = 0o10000000;
|
||||
pub const TMPFILE = 0o20200000;
|
||||
pub const NDELAY = NONBLOCK;
|
||||
};
|
||||
|
||||
pub const F = struct {
|
||||
pub const DUPFD = 0;
|
||||
pub const GETFD = 1;
|
||||
|
@ -195,29 +195,6 @@ pub fn restore_rt() callconv(.C) void {
|
||||
);
|
||||
}
|
||||
|
||||
pub const O = struct {
|
||||
pub const CREAT = 0x200;
|
||||
pub const EXCL = 0x800;
|
||||
pub const NOCTTY = 0x8000;
|
||||
pub const TRUNC = 0x400;
|
||||
pub const APPEND = 0x8;
|
||||
pub const NONBLOCK = 0x4000;
|
||||
pub const SYNC = 0x802000;
|
||||
pub const DSYNC = 0x2000;
|
||||
pub const RSYNC = SYNC;
|
||||
pub const DIRECTORY = 0x10000;
|
||||
pub const NOFOLLOW = 0x20000;
|
||||
pub const CLOEXEC = 0x400000;
|
||||
|
||||
pub const ASYNC = 0x40;
|
||||
pub const DIRECT = 0x100000;
|
||||
pub const LARGEFILE = 0;
|
||||
pub const NOATIME = 0x200000;
|
||||
pub const PATH = 0x1000000;
|
||||
pub const TMPFILE = 0x2010000;
|
||||
pub const NDELAY = NONBLOCK | 0x4;
|
||||
};
|
||||
|
||||
pub const F = struct {
|
||||
pub const DUPFD = 0;
|
||||
pub const GETFD = 1;
|
||||
|
@ -37,7 +37,7 @@ test "timer" {
|
||||
var err: linux.E = linux.getErrno(epoll_fd);
|
||||
try expect(err == .SUCCESS);
|
||||
|
||||
const timer_fd = linux.timerfd_create(linux.CLOCK.MONOTONIC, 0);
|
||||
const timer_fd = linux.timerfd_create(linux.CLOCK.MONOTONIC, .{});
|
||||
try expect(linux.getErrno(timer_fd) == .SUCCESS);
|
||||
|
||||
const time_interval = linux.timespec{
|
||||
@ -50,7 +50,7 @@ test "timer" {
|
||||
.it_value = time_interval,
|
||||
};
|
||||
|
||||
err = linux.getErrno(linux.timerfd_settime(@as(i32, @intCast(timer_fd)), 0, &new_time, null));
|
||||
err = linux.getErrno(linux.timerfd_settime(@as(i32, @intCast(timer_fd)), .{}, &new_time, null));
|
||||
try expect(err == .SUCCESS);
|
||||
|
||||
var event = linux.epoll_event{
|
||||
|
@ -159,29 +159,6 @@ pub fn restore_rt() callconv(.Naked) noreturn {
|
||||
}
|
||||
}
|
||||
|
||||
pub const O = struct {
|
||||
pub const CREAT = 0o100;
|
||||
pub const EXCL = 0o200;
|
||||
pub const NOCTTY = 0o400;
|
||||
pub const TRUNC = 0o1000;
|
||||
pub const APPEND = 0o2000;
|
||||
pub const NONBLOCK = 0o4000;
|
||||
pub const DSYNC = 0o10000;
|
||||
pub const SYNC = 0o4010000;
|
||||
pub const RSYNC = 0o4010000;
|
||||
pub const DIRECTORY = 0o200000;
|
||||
pub const NOFOLLOW = 0o400000;
|
||||
pub const CLOEXEC = 0o2000000;
|
||||
|
||||
pub const ASYNC = 0o20000;
|
||||
pub const DIRECT = 0o40000;
|
||||
pub const LARGEFILE = 0o100000;
|
||||
pub const NOATIME = 0o1000000;
|
||||
pub const PATH = 0o10000000;
|
||||
pub const TMPFILE = 0o20200000;
|
||||
pub const NDELAY = NONBLOCK;
|
||||
};
|
||||
|
||||
pub const F = struct {
|
||||
pub const DUPFD = 0;
|
||||
pub const GETFD = 1;
|
||||
|
@ -131,29 +131,6 @@ pub const nlink_t = usize;
|
||||
pub const blksize_t = isize;
|
||||
pub const blkcnt_t = isize;
|
||||
|
||||
pub const O = struct {
|
||||
pub const CREAT = 0o100;
|
||||
pub const EXCL = 0o200;
|
||||
pub const NOCTTY = 0o400;
|
||||
pub const TRUNC = 0o1000;
|
||||
pub const APPEND = 0o2000;
|
||||
pub const NONBLOCK = 0o4000;
|
||||
pub const DSYNC = 0o10000;
|
||||
pub const SYNC = 0o4010000;
|
||||
pub const RSYNC = 0o4010000;
|
||||
pub const DIRECTORY = 0o200000;
|
||||
pub const NOFOLLOW = 0o400000;
|
||||
pub const CLOEXEC = 0o2000000;
|
||||
|
||||
pub const ASYNC = 0o20000;
|
||||
pub const DIRECT = 0o40000;
|
||||
pub const LARGEFILE = 0;
|
||||
pub const NOATIME = 0o1000000;
|
||||
pub const PATH = 0o10000000;
|
||||
pub const TMPFILE = 0o20200000;
|
||||
pub const NDELAY = NONBLOCK;
|
||||
};
|
||||
|
||||
pub const F = struct {
|
||||
pub const DUPFD = 0;
|
||||
pub const GETFD = 1;
|
||||
|
@ -242,17 +242,23 @@ pub fn close(fd: i32) usize {
|
||||
return syscall_bits.syscall1(.CLOSE, @bitCast(@as(isize, fd)));
|
||||
}
|
||||
pub const mode_t = i32;
|
||||
pub const O = struct {
|
||||
pub const READ = 0; // open for read
|
||||
pub const RDONLY = 0;
|
||||
pub const WRITE = 1; // write
|
||||
pub const WRONLY = 1;
|
||||
pub const RDWR = 2; // read and write
|
||||
pub const EXEC = 3; // execute, == read but check execute permission
|
||||
pub const TRUNC = 16; // or'ed in (except for exec), truncate file first
|
||||
pub const CEXEC = 32; // or'ed in (per file descriptor), close on exec
|
||||
pub const RCLOSE = 64; // or'ed in, remove on close
|
||||
pub const EXCL = 0x1000; // or'ed in, exclusive create
|
||||
|
||||
pub const AccessMode = enum(u2) {
|
||||
RDONLY,
|
||||
WRONLY,
|
||||
RDWR,
|
||||
EXEC,
|
||||
};
|
||||
|
||||
pub const O = packed struct(u32) {
|
||||
access: AccessMode,
|
||||
_2: u2 = 0,
|
||||
TRUNC: bool = false,
|
||||
CEXEC: bool = false,
|
||||
RCLOSE: bool = false,
|
||||
_7: u5 = 0,
|
||||
EXCL: bool = false,
|
||||
_: u19 = 0,
|
||||
};
|
||||
|
||||
pub const ExecData = struct {
|
||||
|
@ -87,6 +87,7 @@ test "chdir smoke test" {
|
||||
|
||||
test "open smoke test" {
|
||||
if (native_os == .wasi) return error.SkipZigTest;
|
||||
if (native_os == .windows) return error.SkipZigTest;
|
||||
|
||||
// TODO verify file attributes using `fstat`
|
||||
|
||||
@ -109,21 +110,21 @@ test "open smoke test" {
|
||||
|
||||
// Create some file using `open`.
|
||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
||||
fd = try os.open(file_path, os.O.RDWR | os.O.CREAT | os.O.EXCL, mode);
|
||||
fd = try os.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
|
||||
os.close(fd);
|
||||
|
||||
// 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" });
|
||||
try expectError(error.PathAlreadyExists, os.open(file_path, os.O.RDWR | os.O.CREAT | os.O.EXCL, mode));
|
||||
try expectError(error.PathAlreadyExists, os.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode));
|
||||
|
||||
// Try opening without `O.EXCL` flag.
|
||||
// Try opening without `EXCL` flag.
|
||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
||||
fd = try os.open(file_path, os.O.RDWR | os.O.CREAT, mode);
|
||||
fd = try os.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true }, mode);
|
||||
os.close(fd);
|
||||
|
||||
// Try opening as a directory which should fail.
|
||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
||||
try expectError(error.NotDir, os.open(file_path, os.O.RDWR | os.O.DIRECTORY, mode));
|
||||
try expectError(error.NotDir, os.open(file_path, .{ .ACCMODE = .RDWR, .DIRECTORY = true }, mode));
|
||||
|
||||
// Create some directory
|
||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
|
||||
@ -131,16 +132,17 @@ test "open smoke test" {
|
||||
|
||||
// Open dir using `open`
|
||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
|
||||
fd = try os.open(file_path, os.O.RDONLY | os.O.DIRECTORY, mode);
|
||||
fd = try os.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode);
|
||||
os.close(fd);
|
||||
|
||||
// Try opening as file which should fail.
|
||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
|
||||
try expectError(error.IsDir, os.open(file_path, os.O.RDWR, mode));
|
||||
try expectError(error.IsDir, os.open(file_path, .{ .ACCMODE = .RDWR }, mode));
|
||||
}
|
||||
|
||||
test "openat smoke test" {
|
||||
if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
|
||||
if (native_os == .windows) return error.SkipZigTest;
|
||||
|
||||
// TODO verify file attributes using `fstatat`
|
||||
|
||||
@ -151,28 +153,47 @@ test "openat smoke test" {
|
||||
const mode: os.mode_t = if (native_os == .windows) 0 else 0o666;
|
||||
|
||||
// Create some file using `openat`.
|
||||
fd = try os.openat(tmp.dir.fd, "some_file", os.O.RDWR | os.O.CREAT | os.O.EXCL, mode);
|
||||
fd = try os.openat(tmp.dir.fd, "some_file", os.CommonOpenFlags.lower(.{
|
||||
.ACCMODE = .RDWR,
|
||||
.CREAT = true,
|
||||
.EXCL = true,
|
||||
}), mode);
|
||||
os.close(fd);
|
||||
|
||||
// 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.O.RDWR | os.O.CREAT | os.O.EXCL, mode));
|
||||
try expectError(error.PathAlreadyExists, os.openat(tmp.dir.fd, "some_file", os.CommonOpenFlags.lower(.{
|
||||
.ACCMODE = .RDWR,
|
||||
.CREAT = true,
|
||||
.EXCL = true,
|
||||
}), mode));
|
||||
|
||||
// Try opening without `O.EXCL` flag.
|
||||
fd = try os.openat(tmp.dir.fd, "some_file", os.O.RDWR | os.O.CREAT, mode);
|
||||
// Try opening without `EXCL` flag.
|
||||
fd = try os.openat(tmp.dir.fd, "some_file", os.CommonOpenFlags.lower(.{
|
||||
.ACCMODE = .RDWR,
|
||||
.CREAT = true,
|
||||
}), mode);
|
||||
os.close(fd);
|
||||
|
||||
// Try opening as a directory which should fail.
|
||||
try expectError(error.NotDir, os.openat(tmp.dir.fd, "some_file", os.O.RDWR | os.O.DIRECTORY, mode));
|
||||
try expectError(error.NotDir, os.openat(tmp.dir.fd, "some_file", os.CommonOpenFlags.lower(.{
|
||||
.ACCMODE = .RDWR,
|
||||
.DIRECTORY = true,
|
||||
}), mode));
|
||||
|
||||
// Create some directory
|
||||
try os.mkdirat(tmp.dir.fd, "some_dir", mode);
|
||||
|
||||
// Open dir using `open`
|
||||
fd = try os.openat(tmp.dir.fd, "some_dir", os.O.RDONLY | os.O.DIRECTORY, mode);
|
||||
fd = try os.openat(tmp.dir.fd, "some_dir", os.CommonOpenFlags.lower(.{
|
||||
.ACCMODE = .RDONLY,
|
||||
.DIRECTORY = true,
|
||||
}), mode);
|
||||
os.close(fd);
|
||||
|
||||
// Try opening as file which should fail.
|
||||
try expectError(error.IsDir, os.openat(tmp.dir.fd, "some_dir", os.O.RDWR, mode));
|
||||
try expectError(error.IsDir, os.openat(tmp.dir.fd, "some_dir", os.CommonOpenFlags.lower(.{
|
||||
.ACCMODE = .RDWR,
|
||||
}), mode));
|
||||
}
|
||||
|
||||
test "symlink with relative paths" {
|
||||
@ -688,7 +709,7 @@ test "fcntl" {
|
||||
tmp.dir.deleteFile(test_out_file) catch {};
|
||||
}
|
||||
|
||||
// Note: The test assumes createFile opens the file with O.CLOEXEC
|
||||
// Note: The test assumes createFile opens the file with CLOEXEC
|
||||
{
|
||||
const flags = try os.fcntl(file.handle, os.F.GETFD, 0);
|
||||
try expect((flags & os.FD_CLOEXEC) != 0);
|
||||
@ -987,6 +1008,7 @@ test "POSIX file locking with fcntl" {
|
||||
|
||||
test "rename smoke test" {
|
||||
if (native_os == .wasi) return error.SkipZigTest;
|
||||
if (native_os == .windows) return error.SkipZigTest;
|
||||
|
||||
var tmp = tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
@ -1007,7 +1029,7 @@ test "rename smoke test" {
|
||||
|
||||
// Create some file using `open`.
|
||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
||||
fd = try os.open(file_path, os.O.RDWR | os.O.CREAT | os.O.EXCL, mode);
|
||||
fd = try os.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
|
||||
os.close(fd);
|
||||
|
||||
// Rename the file
|
||||
@ -1016,12 +1038,12 @@ test "rename smoke test" {
|
||||
|
||||
// Try opening renamed file
|
||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_file" });
|
||||
fd = try os.open(file_path, os.O.RDWR, mode);
|
||||
fd = try os.open(file_path, .{ .ACCMODE = .RDWR }, mode);
|
||||
os.close(fd);
|
||||
|
||||
// Try opening original file - should fail with error.FileNotFound
|
||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
||||
try expectError(error.FileNotFound, os.open(file_path, os.O.RDWR, mode));
|
||||
try expectError(error.FileNotFound, os.open(file_path, .{ .ACCMODE = .RDWR }, mode));
|
||||
|
||||
// Create some directory
|
||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
|
||||
@ -1033,16 +1055,17 @@ test "rename smoke test" {
|
||||
|
||||
// Try opening renamed directory
|
||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_other_dir" });
|
||||
fd = try os.open(file_path, os.O.RDONLY | os.O.DIRECTORY, mode);
|
||||
fd = try os.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode);
|
||||
os.close(fd);
|
||||
|
||||
// Try opening original directory - should fail with error.FileNotFound
|
||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_dir" });
|
||||
try expectError(error.FileNotFound, os.open(file_path, os.O.RDONLY | os.O.DIRECTORY, mode));
|
||||
try expectError(error.FileNotFound, os.open(file_path, .{ .ACCMODE = .RDONLY, .DIRECTORY = true }, mode));
|
||||
}
|
||||
|
||||
test "access smoke test" {
|
||||
if (native_os == .wasi) return error.SkipZigTest;
|
||||
if (native_os == .windows) return error.SkipZigTest;
|
||||
|
||||
var tmp = tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
@ -1063,7 +1086,7 @@ test "access smoke test" {
|
||||
|
||||
// Create some file using `open`.
|
||||
file_path = try fs.path.join(allocator, &[_][]const u8{ base_path, "some_file" });
|
||||
fd = try os.open(file_path, os.O.RDWR | os.O.CREAT | os.O.EXCL, mode);
|
||||
fd = try os.open(file_path, .{ .ACCMODE = .RDWR, .CREAT = true, .EXCL = true }, mode);
|
||||
os.close(fd);
|
||||
|
||||
// Try to access() the file
|
||||
@ -1088,16 +1111,15 @@ test "access smoke test" {
|
||||
}
|
||||
|
||||
test "timerfd" {
|
||||
if (native_os != .linux)
|
||||
return error.SkipZigTest;
|
||||
if (native_os != .linux) return error.SkipZigTest;
|
||||
|
||||
const linux = os.linux;
|
||||
const tfd = try os.timerfd_create(linux.CLOCK.MONOTONIC, linux.TFD.CLOEXEC);
|
||||
const tfd = try os.timerfd_create(linux.CLOCK.MONOTONIC, .{ .CLOEXEC = true });
|
||||
defer os.close(tfd);
|
||||
|
||||
// Fire event 10_000_000ns = 10ms after the os.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) } };
|
||||
try os.timerfd_settime(tfd, 0, &sit, null);
|
||||
try os.timerfd_settime(tfd, .{}, &sit, null);
|
||||
|
||||
var fds: [1]os.pollfd = .{.{ .fd = tfd, .events = os.linux.POLL.IN, .revents = 0 }};
|
||||
try expectEqual(@as(usize, 1), try os.poll(&fds, -1)); // -1 => infinite waiting
|
||||
@ -1232,7 +1254,7 @@ test "fchmodat smoke test" {
|
||||
const fd = try os.openat(
|
||||
tmp.dir.fd,
|
||||
"regfile",
|
||||
os.O.WRONLY | os.O.CREAT | os.O.EXCL | os.O.TRUNC,
|
||||
.{ .ACCMODE = .WRONLY, .CREAT = true, .EXCL = true, .TRUNC = true },
|
||||
0o644,
|
||||
);
|
||||
os.close(fd);
|
||||
|
@ -1,6 +1,7 @@
|
||||
// wasi_snapshot_preview1 spec available (in witx format) here:
|
||||
// * typenames -- https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/witx/typenames.witx
|
||||
// * module -- https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/witx/wasi_snapshot_preview1.witx
|
||||
//! wasi_snapshot_preview1 spec available (in witx format) here:
|
||||
//! * typenames -- https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/witx/typenames.witx
|
||||
//! * module -- https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/witx/wasi_snapshot_preview1.witx
|
||||
//! Note that libc API does *not* go in this file. wasi libc API goes into std/c/wasi.zig instead.
|
||||
const builtin = @import("builtin");
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
@ -16,11 +17,6 @@ comptime {
|
||||
// assert(@alignOf(u64) == 8);
|
||||
}
|
||||
|
||||
pub const F_OK = 0;
|
||||
pub const X_OK = 1;
|
||||
pub const W_OK = 2;
|
||||
pub const R_OK = 4;
|
||||
|
||||
pub const iovec_t = std.os.iovec;
|
||||
pub const ciovec_t = std.os.iovec_const;
|
||||
|
||||
@ -82,106 +78,22 @@ pub extern "wasi_snapshot_preview1" fn sock_recv(sock: fd_t, ri_data: [*]iovec_t
|
||||
pub extern "wasi_snapshot_preview1" fn sock_send(sock: fd_t, si_data: [*]const ciovec_t, si_data_len: usize, si_flags: siflags_t, so_datalen: *usize) errno_t;
|
||||
pub extern "wasi_snapshot_preview1" fn sock_shutdown(sock: fd_t, how: sdflags_t) errno_t;
|
||||
|
||||
/// Get the errno from a syscall return value, or 0 for no error.
|
||||
pub fn getErrno(r: errno_t) errno_t {
|
||||
return r;
|
||||
}
|
||||
|
||||
pub const STDIN_FILENO = 0;
|
||||
pub const STDOUT_FILENO = 1;
|
||||
pub const STDERR_FILENO = 2;
|
||||
|
||||
pub const mode_t = u32;
|
||||
|
||||
pub const time_t = i64; // match https://github.com/CraneStation/wasi-libc
|
||||
|
||||
pub const timespec = extern struct {
|
||||
tv_sec: time_t,
|
||||
tv_nsec: isize,
|
||||
|
||||
pub fn fromTimestamp(tm: timestamp_t) timespec {
|
||||
const tv_sec: timestamp_t = tm / 1_000_000_000;
|
||||
const tv_nsec = tm - tv_sec * 1_000_000_000;
|
||||
return timespec{
|
||||
.tv_sec = @as(time_t, @intCast(tv_sec)),
|
||||
.tv_nsec = @as(isize, @intCast(tv_nsec)),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn toTimestamp(ts: timespec) timestamp_t {
|
||||
const tm = @as(timestamp_t, @intCast(ts.tv_sec * 1_000_000_000)) + @as(timestamp_t, @intCast(ts.tv_nsec));
|
||||
return tm;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Stat = struct {
|
||||
dev: device_t,
|
||||
ino: inode_t,
|
||||
mode: mode_t,
|
||||
filetype: filetype_t,
|
||||
nlink: linkcount_t,
|
||||
size: filesize_t,
|
||||
atim: timespec,
|
||||
mtim: timespec,
|
||||
ctim: timespec,
|
||||
|
||||
const Self = @This();
|
||||
|
||||
pub fn fromFilestat(stat: filestat_t) Self {
|
||||
return Self{
|
||||
.dev = stat.dev,
|
||||
.ino = stat.ino,
|
||||
.mode = 0,
|
||||
.filetype = stat.filetype,
|
||||
.nlink = stat.nlink,
|
||||
.size = stat.size,
|
||||
.atim = stat.atime(),
|
||||
.mtim = stat.mtime(),
|
||||
.ctim = stat.ctime(),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn atime(self: Self) timespec {
|
||||
return self.atim;
|
||||
}
|
||||
|
||||
pub fn mtime(self: Self) timespec {
|
||||
return self.mtim;
|
||||
}
|
||||
|
||||
pub fn ctime(self: Self) timespec {
|
||||
return self.ctim;
|
||||
}
|
||||
};
|
||||
|
||||
pub const IOV_MAX = 1024;
|
||||
|
||||
pub const AT = struct {
|
||||
pub const REMOVEDIR: u32 = 0x4;
|
||||
/// When linking libc, we follow their convention and use -2 for current working directory.
|
||||
/// However, without libc, Zig does a different convention: it assumes the
|
||||
/// current working directory is the first preopen. This behavior can be
|
||||
/// overridden with a public function called `wasi_cwd` in the root source
|
||||
/// file.
|
||||
pub const FDCWD: fd_t = if (builtin.link_libc) -2 else 3;
|
||||
};
|
||||
|
||||
// As defined in the wasi_snapshot_preview1 spec file:
|
||||
// https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/witx/typenames.witx
|
||||
pub const advice_t = u8;
|
||||
pub const ADVICE_NORMAL: advice_t = 0;
|
||||
pub const ADVICE_SEQUENTIAL: advice_t = 1;
|
||||
pub const ADVICE_RANDOM: advice_t = 2;
|
||||
pub const ADVICE_WILLNEED: advice_t = 3;
|
||||
pub const ADVICE_DONTNEED: advice_t = 4;
|
||||
pub const ADVICE_NOREUSE: advice_t = 5;
|
||||
pub const advice_t = enum(u8) {
|
||||
NORMAL = 0,
|
||||
SEQUENTIAL = 1,
|
||||
RANDOM = 2,
|
||||
WILLNEED = 3,
|
||||
DONTNEED = 4,
|
||||
NOREUSE = 5,
|
||||
};
|
||||
|
||||
pub const clockid_t = u32;
|
||||
pub const CLOCK = struct {
|
||||
pub const REALTIME: clockid_t = 0;
|
||||
pub const MONOTONIC: clockid_t = 1;
|
||||
pub const PROCESS_CPUTIME_ID: clockid_t = 2;
|
||||
pub const THREAD_CPUTIME_ID: clockid_t = 3;
|
||||
pub const clockid_t = enum(u32) {
|
||||
REALTIME = 0,
|
||||
MONOTONIC = 1,
|
||||
PROCESS_CPUTIME_ID = 2,
|
||||
THREAD_CPUTIME_ID = 3,
|
||||
};
|
||||
|
||||
pub const device_t = u64;
|
||||
@ -192,10 +104,10 @@ pub const DIRCOOKIE_START: dircookie_t = 0;
|
||||
pub const dirnamlen_t = u32;
|
||||
|
||||
pub const dirent_t = extern struct {
|
||||
d_next: dircookie_t,
|
||||
d_ino: inode_t,
|
||||
d_namlen: dirnamlen_t,
|
||||
d_type: filetype_t,
|
||||
next: dircookie_t,
|
||||
ino: inode_t,
|
||||
namlen: dirnamlen_t,
|
||||
type: filetype_t,
|
||||
};
|
||||
|
||||
pub const errno_t = enum(u16) {
|
||||
@ -280,7 +192,6 @@ pub const errno_t = enum(u16) {
|
||||
NOTCAPABLE = 76,
|
||||
_,
|
||||
};
|
||||
pub const E = errno_t;
|
||||
|
||||
pub const event_t = extern struct {
|
||||
userdata: userdata_t,
|
||||
@ -297,22 +208,23 @@ pub const eventfdreadwrite_t = extern struct {
|
||||
pub const eventrwflags_t = u16;
|
||||
pub const EVENT_FD_READWRITE_HANGUP: eventrwflags_t = 0x0001;
|
||||
|
||||
pub const eventtype_t = u8;
|
||||
pub const EVENTTYPE_CLOCK: eventtype_t = 0;
|
||||
pub const EVENTTYPE_FD_READ: eventtype_t = 1;
|
||||
pub const EVENTTYPE_FD_WRITE: eventtype_t = 2;
|
||||
pub const eventtype_t = enum(u8) {
|
||||
CLOCK = 0,
|
||||
FD_READ = 1,
|
||||
FD_WRITE = 2,
|
||||
};
|
||||
|
||||
pub const exitcode_t = u32;
|
||||
|
||||
pub const fd_t = i32;
|
||||
|
||||
pub const fdflags_t = u16;
|
||||
pub const FDFLAG = struct {
|
||||
pub const APPEND: fdflags_t = 0x0001;
|
||||
pub const DSYNC: fdflags_t = 0x0002;
|
||||
pub const NONBLOCK: fdflags_t = 0x0004;
|
||||
pub const RSYNC: fdflags_t = 0x0008;
|
||||
pub const SYNC: fdflags_t = 0x0010;
|
||||
pub const fdflags_t = packed struct(u16) {
|
||||
APPEND: bool = false,
|
||||
DSYNC: bool = false,
|
||||
NONBLOCK: bool = false,
|
||||
RSYNC: bool = false,
|
||||
SYNC: bool = false,
|
||||
_: u11 = 0,
|
||||
};
|
||||
|
||||
pub const fdstat_t = extern struct {
|
||||
@ -335,21 +247,8 @@ pub const filestat_t = extern struct {
|
||||
atim: timestamp_t,
|
||||
mtim: timestamp_t,
|
||||
ctim: timestamp_t,
|
||||
|
||||
pub fn atime(self: filestat_t) timespec {
|
||||
return timespec.fromTimestamp(self.atim);
|
||||
}
|
||||
|
||||
pub fn mtime(self: filestat_t) timespec {
|
||||
return timespec.fromTimestamp(self.mtim);
|
||||
}
|
||||
|
||||
pub fn ctime(self: filestat_t) timespec {
|
||||
return timespec.fromTimestamp(self.ctim);
|
||||
}
|
||||
};
|
||||
|
||||
/// Also known as `FILETYPE`.
|
||||
pub const filetype_t = enum(u8) {
|
||||
UNKNOWN,
|
||||
BLOCK_DEVICE,
|
||||
@ -362,26 +261,29 @@ pub const filetype_t = enum(u8) {
|
||||
_,
|
||||
};
|
||||
|
||||
pub const fstflags_t = u16;
|
||||
pub const FILESTAT_SET_ATIM: fstflags_t = 0x0001;
|
||||
pub const FILESTAT_SET_ATIM_NOW: fstflags_t = 0x0002;
|
||||
pub const FILESTAT_SET_MTIM: fstflags_t = 0x0004;
|
||||
pub const FILESTAT_SET_MTIM_NOW: fstflags_t = 0x0008;
|
||||
pub const fstflags_t = packed struct(u16) {
|
||||
ATIM: bool = false,
|
||||
ATIM_NOW: bool = false,
|
||||
MTIM: bool = false,
|
||||
MTIM_NOW: bool = false,
|
||||
_: u12 = 0,
|
||||
};
|
||||
|
||||
pub const inode_t = u64;
|
||||
pub const ino_t = inode_t;
|
||||
|
||||
pub const linkcount_t = u64;
|
||||
|
||||
pub const lookupflags_t = u32;
|
||||
pub const LOOKUP_SYMLINK_FOLLOW: lookupflags_t = 0x00000001;
|
||||
pub const lookupflags_t = packed struct(u32) {
|
||||
SYMLINK_FOLLOW: bool = false,
|
||||
_: u31 = 0,
|
||||
};
|
||||
|
||||
pub const oflags_t = u16;
|
||||
pub const O = struct {
|
||||
pub const CREAT: oflags_t = 0x0001;
|
||||
pub const DIRECTORY: oflags_t = 0x0002;
|
||||
pub const EXCL: oflags_t = 0x0004;
|
||||
pub const TRUNC: oflags_t = 0x0008;
|
||||
pub const oflags_t = packed struct(u16) {
|
||||
CREAT: bool = false,
|
||||
DIRECTORY: bool = false,
|
||||
EXCL: bool = false,
|
||||
TRUNC: bool = false,
|
||||
_: u12 = 0,
|
||||
};
|
||||
|
||||
pub const preopentype_t = u8;
|
||||
@ -410,110 +312,81 @@ pub const SOCK = struct {
|
||||
pub const RECV_DATA_TRUNCATED: roflags_t = 0x0001;
|
||||
};
|
||||
|
||||
pub const rights_t = u64;
|
||||
pub const RIGHT = struct {
|
||||
pub const FD_DATASYNC: rights_t = 0x0000000000000001;
|
||||
pub const FD_READ: rights_t = 0x0000000000000002;
|
||||
pub const FD_SEEK: rights_t = 0x0000000000000004;
|
||||
pub const FD_FDSTAT_SET_FLAGS: rights_t = 0x0000000000000008;
|
||||
pub const FD_SYNC: rights_t = 0x0000000000000010;
|
||||
pub const FD_TELL: rights_t = 0x0000000000000020;
|
||||
pub const FD_WRITE: rights_t = 0x0000000000000040;
|
||||
pub const FD_ADVISE: rights_t = 0x0000000000000080;
|
||||
pub const FD_ALLOCATE: rights_t = 0x0000000000000100;
|
||||
pub const PATH_CREATE_DIRECTORY: rights_t = 0x0000000000000200;
|
||||
pub const PATH_CREATE_FILE: rights_t = 0x0000000000000400;
|
||||
pub const PATH_LINK_SOURCE: rights_t = 0x0000000000000800;
|
||||
pub const PATH_LINK_TARGET: rights_t = 0x0000000000001000;
|
||||
pub const PATH_OPEN: rights_t = 0x0000000000002000;
|
||||
pub const FD_READDIR: rights_t = 0x0000000000004000;
|
||||
pub const PATH_READLINK: rights_t = 0x0000000000008000;
|
||||
pub const PATH_RENAME_SOURCE: rights_t = 0x0000000000010000;
|
||||
pub const PATH_RENAME_TARGET: rights_t = 0x0000000000020000;
|
||||
pub const PATH_FILESTAT_GET: rights_t = 0x0000000000040000;
|
||||
pub const PATH_FILESTAT_SET_SIZE: rights_t = 0x0000000000080000;
|
||||
pub const PATH_FILESTAT_SET_TIMES: rights_t = 0x0000000000100000;
|
||||
pub const FD_FILESTAT_GET: rights_t = 0x0000000000200000;
|
||||
pub const FD_FILESTAT_SET_SIZE: rights_t = 0x0000000000400000;
|
||||
pub const FD_FILESTAT_SET_TIMES: rights_t = 0x0000000000800000;
|
||||
pub const PATH_SYMLINK: rights_t = 0x0000000001000000;
|
||||
pub const PATH_REMOVE_DIRECTORY: rights_t = 0x0000000002000000;
|
||||
pub const PATH_UNLINK_FILE: rights_t = 0x0000000004000000;
|
||||
pub const POLL_FD_READWRITE: rights_t = 0x0000000008000000;
|
||||
pub const SOCK_SHUTDOWN: rights_t = 0x0000000010000000;
|
||||
pub const SOCK_ACCEPT: rights_t = 0x0000000020000000;
|
||||
pub const ALL: rights_t = FD_DATASYNC |
|
||||
FD_READ |
|
||||
FD_SEEK |
|
||||
FD_FDSTAT_SET_FLAGS |
|
||||
FD_SYNC |
|
||||
FD_TELL |
|
||||
FD_WRITE |
|
||||
FD_ADVISE |
|
||||
FD_ALLOCATE |
|
||||
PATH_CREATE_DIRECTORY |
|
||||
PATH_CREATE_FILE |
|
||||
PATH_LINK_SOURCE |
|
||||
PATH_LINK_TARGET |
|
||||
PATH_OPEN |
|
||||
FD_READDIR |
|
||||
PATH_READLINK |
|
||||
PATH_RENAME_SOURCE |
|
||||
PATH_RENAME_TARGET |
|
||||
PATH_FILESTAT_GET |
|
||||
PATH_FILESTAT_SET_SIZE |
|
||||
PATH_FILESTAT_SET_TIMES |
|
||||
FD_FILESTAT_GET |
|
||||
FD_FILESTAT_SET_SIZE |
|
||||
FD_FILESTAT_SET_TIMES |
|
||||
PATH_SYMLINK |
|
||||
PATH_REMOVE_DIRECTORY |
|
||||
PATH_UNLINK_FILE |
|
||||
POLL_FD_READWRITE |
|
||||
SOCK_SHUTDOWN |
|
||||
SOCK_ACCEPT;
|
||||
pub const rights_t = packed struct(u64) {
|
||||
FD_DATASYNC: bool = false,
|
||||
FD_READ: bool = false,
|
||||
FD_SEEK: bool = false,
|
||||
FD_FDSTAT_SET_FLAGS: bool = false,
|
||||
FD_SYNC: bool = false,
|
||||
FD_TELL: bool = false,
|
||||
FD_WRITE: bool = false,
|
||||
FD_ADVISE: bool = false,
|
||||
FD_ALLOCATE: bool = false,
|
||||
PATH_CREATE_DIRECTORY: bool = false,
|
||||
PATH_CREATE_FILE: bool = false,
|
||||
PATH_LINK_SOURCE: bool = false,
|
||||
PATH_LINK_TARGET: bool = false,
|
||||
PATH_OPEN: bool = false,
|
||||
FD_READDIR: bool = false,
|
||||
PATH_READLINK: bool = false,
|
||||
PATH_RENAME_SOURCE: bool = false,
|
||||
PATH_RENAME_TARGET: bool = false,
|
||||
PATH_FILESTAT_GET: bool = false,
|
||||
PATH_FILESTAT_SET_SIZE: bool = false,
|
||||
PATH_FILESTAT_SET_TIMES: bool = false,
|
||||
FD_FILESTAT_GET: bool = false,
|
||||
FD_FILESTAT_SET_SIZE: bool = false,
|
||||
FD_FILESTAT_SET_TIMES: bool = false,
|
||||
PATH_SYMLINK: bool = false,
|
||||
PATH_REMOVE_DIRECTORY: bool = false,
|
||||
PATH_UNLINK_FILE: bool = false,
|
||||
POLL_FD_READWRITE: bool = false,
|
||||
SOCK_SHUTDOWN: bool = false,
|
||||
SOCK_ACCEPT: bool = false,
|
||||
_: u34 = 0,
|
||||
};
|
||||
|
||||
pub const sdflags_t = u8;
|
||||
pub const SHUT = struct {
|
||||
pub const RD: sdflags_t = 0x01;
|
||||
pub const WR: sdflags_t = 0x02;
|
||||
pub const sdflags_t = packed struct(u8) {
|
||||
RD: bool = false,
|
||||
WR: bool = false,
|
||||
_: u6 = 0,
|
||||
};
|
||||
|
||||
pub const siflags_t = u16;
|
||||
|
||||
pub const signal_t = u8;
|
||||
pub const SIGNONE: signal_t = 0;
|
||||
pub const SIGHUP: signal_t = 1;
|
||||
pub const SIGINT: signal_t = 2;
|
||||
pub const SIGQUIT: signal_t = 3;
|
||||
pub const SIGILL: signal_t = 4;
|
||||
pub const SIGTRAP: signal_t = 5;
|
||||
pub const SIGABRT: signal_t = 6;
|
||||
pub const SIGBUS: signal_t = 7;
|
||||
pub const SIGFPE: signal_t = 8;
|
||||
pub const SIGKILL: signal_t = 9;
|
||||
pub const SIGUSR1: signal_t = 10;
|
||||
pub const SIGSEGV: signal_t = 11;
|
||||
pub const SIGUSR2: signal_t = 12;
|
||||
pub const SIGPIPE: signal_t = 13;
|
||||
pub const SIGALRM: signal_t = 14;
|
||||
pub const SIGTERM: signal_t = 15;
|
||||
pub const SIGCHLD: signal_t = 16;
|
||||
pub const SIGCONT: signal_t = 17;
|
||||
pub const SIGSTOP: signal_t = 18;
|
||||
pub const SIGTSTP: signal_t = 19;
|
||||
pub const SIGTTIN: signal_t = 20;
|
||||
pub const SIGTTOU: signal_t = 21;
|
||||
pub const SIGURG: signal_t = 22;
|
||||
pub const SIGXCPU: signal_t = 23;
|
||||
pub const SIGXFSZ: signal_t = 24;
|
||||
pub const SIGVTALRM: signal_t = 25;
|
||||
pub const SIGPROF: signal_t = 26;
|
||||
pub const SIGWINCH: signal_t = 27;
|
||||
pub const SIGPOLL: signal_t = 28;
|
||||
pub const SIGPWR: signal_t = 29;
|
||||
pub const SIGSYS: signal_t = 30;
|
||||
pub const signal_t = enum(u8) {
|
||||
NONE = 0,
|
||||
HUP = 1,
|
||||
INT = 2,
|
||||
QUIT = 3,
|
||||
ILL = 4,
|
||||
TRAP = 5,
|
||||
ABRT = 6,
|
||||
BUS = 7,
|
||||
FPE = 8,
|
||||
KILL = 9,
|
||||
USR1 = 10,
|
||||
SEGV = 11,
|
||||
USR2 = 12,
|
||||
PIPE = 13,
|
||||
ALRM = 14,
|
||||
TERM = 15,
|
||||
CHLD = 16,
|
||||
CONT = 17,
|
||||
STOP = 18,
|
||||
TSTP = 19,
|
||||
TTIN = 20,
|
||||
TTOU = 21,
|
||||
URG = 22,
|
||||
XCPU = 23,
|
||||
XFSZ = 24,
|
||||
VTALRM = 25,
|
||||
PROF = 26,
|
||||
WINCH = 27,
|
||||
POLL = 28,
|
||||
PWR = 29,
|
||||
SYS = 30,
|
||||
};
|
||||
|
||||
pub const subclockflags_t = u16;
|
||||
pub const SUBSCRIPTION_CLOCK_ABSTIME: subclockflags_t = 0x0001;
|
||||
@ -545,29 +418,9 @@ pub const subscription_u_u_t = extern union {
|
||||
fd_write: subscription_fd_readwrite_t,
|
||||
};
|
||||
|
||||
/// Nanoseconds.
|
||||
pub const timestamp_t = u64;
|
||||
|
||||
pub const userdata_t = u64;
|
||||
|
||||
/// Also known as `WHENCE`.
|
||||
pub const whence_t = enum(u8) { SET, CUR, END };
|
||||
|
||||
pub const S = struct {
|
||||
pub const IEXEC = @compileError("TODO audit this");
|
||||
pub const IFBLK = 0x6000;
|
||||
pub const IFCHR = 0x2000;
|
||||
pub const IFDIR = 0x4000;
|
||||
pub const IFIFO = 0xc000;
|
||||
pub const IFLNK = 0xa000;
|
||||
pub const IFMT = IFBLK | IFCHR | IFDIR | IFIFO | IFLNK | IFREG | IFSOCK;
|
||||
pub const IFREG = 0x8000;
|
||||
// There's no concept of UNIX domain socket but we define this value here in order to line with other OSes.
|
||||
pub const IFSOCK = 0x1;
|
||||
};
|
||||
|
||||
pub const LOCK = struct {
|
||||
pub const SH = 0x1;
|
||||
pub const EX = 0x2;
|
||||
pub const NB = 0x4;
|
||||
pub const UN = 0x8;
|
||||
};
|
||||
|
@ -142,7 +142,10 @@ pub const meta = @import("meta.zig");
|
||||
/// Networking.
|
||||
pub const net = @import("net.zig");
|
||||
|
||||
/// Wrappers around OS-specific APIs.
|
||||
/// POSIX-like API layer.
|
||||
pub const posix = @import("os.zig");
|
||||
|
||||
/// Non-portable Operating System-specific API.
|
||||
pub const os = @import("os.zig");
|
||||
|
||||
pub const once = @import("once.zig").once;
|
||||
|
127
lib/std/time.zig
127
lib/std/time.zig
@ -19,19 +19,17 @@ pub fn sleep(nanoseconds: u64) void {
|
||||
if (builtin.os.tag == .wasi) {
|
||||
const w = std.os.wasi;
|
||||
const userdata: w.userdata_t = 0x0123_45678;
|
||||
const clock = w.subscription_clock_t{
|
||||
.id = w.CLOCK.MONOTONIC,
|
||||
const clock: w.subscription_clock_t = .{
|
||||
.id = .MONOTONIC,
|
||||
.timeout = nanoseconds,
|
||||
.precision = 0,
|
||||
.flags = 0,
|
||||
};
|
||||
const in = w.subscription_t{
|
||||
const in: w.subscription_t = .{
|
||||
.userdata = userdata,
|
||||
.u = w.subscription_u_t{
|
||||
.tag = w.EVENTTYPE_CLOCK,
|
||||
.u = w.subscription_u_u_t{
|
||||
.clock = clock,
|
||||
},
|
||||
.u = .{
|
||||
.tag = .CLOCK,
|
||||
.u = .{ .clock = clock },
|
||||
},
|
||||
};
|
||||
|
||||
@ -92,35 +90,36 @@ pub fn microTimestamp() i64 {
|
||||
/// before the epoch.
|
||||
/// See `std.os.clock_gettime` for a POSIX timestamp.
|
||||
pub fn nanoTimestamp() i128 {
|
||||
if (builtin.os.tag == .windows) {
|
||||
// FileTime has a granularity of 100 nanoseconds and uses the NTFS/Windows epoch,
|
||||
// which is 1601-01-01.
|
||||
const epoch_adj = epoch.windows * (ns_per_s / 100);
|
||||
var ft: os.windows.FILETIME = undefined;
|
||||
os.windows.kernel32.GetSystemTimeAsFileTime(&ft);
|
||||
const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
|
||||
return @as(i128, @as(i64, @bitCast(ft64)) + epoch_adj) * 100;
|
||||
switch (builtin.os.tag) {
|
||||
.windows => {
|
||||
// FileTime has a granularity of 100 nanoseconds and uses the NTFS/Windows epoch,
|
||||
// which is 1601-01-01.
|
||||
const epoch_adj = epoch.windows * (ns_per_s / 100);
|
||||
var ft: os.windows.FILETIME = undefined;
|
||||
os.windows.kernel32.GetSystemTimeAsFileTime(&ft);
|
||||
const ft64 = (@as(u64, ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
|
||||
return @as(i128, @as(i64, @bitCast(ft64)) + epoch_adj) * 100;
|
||||
},
|
||||
.wasi => {
|
||||
var ns: os.wasi.timestamp_t = undefined;
|
||||
const err = os.wasi.clock_time_get(.REALTIME, 1, &ns);
|
||||
assert(err == .SUCCESS);
|
||||
return ns;
|
||||
},
|
||||
.uefi => {
|
||||
var value: std.os.uefi.Time = undefined;
|
||||
const status = std.os.uefi.system_table.runtime_services.getTime(&value, null);
|
||||
assert(status == .Success);
|
||||
return value.toEpoch();
|
||||
},
|
||||
else => {
|
||||
var ts: os.timespec = undefined;
|
||||
os.clock_gettime(os.CLOCK.REALTIME, &ts) catch |err| switch (err) {
|
||||
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;
|
||||
},
|
||||
}
|
||||
|
||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
var ns: os.wasi.timestamp_t = undefined;
|
||||
const err = os.wasi.clock_time_get(os.wasi.CLOCK.REALTIME, 1, &ns);
|
||||
assert(err == .SUCCESS);
|
||||
return ns;
|
||||
}
|
||||
|
||||
if (builtin.os.tag == .uefi) {
|
||||
var value: std.os.uefi.Time = undefined;
|
||||
const status = std.os.uefi.system_table.runtime_services.getTime(&value, null);
|
||||
assert(status == .Success);
|
||||
return value.toEpoch();
|
||||
}
|
||||
|
||||
var ts: os.timespec = undefined;
|
||||
os.clock_gettime(os.CLOCK.REALTIME, &ts) catch |err| switch (err) {
|
||||
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;
|
||||
}
|
||||
|
||||
test "timestamp" {
|
||||
@ -177,43 +176,43 @@ pub const Instant = struct {
|
||||
|
||||
// true if we should use clock_gettime()
|
||||
const is_posix = switch (builtin.os.tag) {
|
||||
.wasi => builtin.link_libc,
|
||||
.windows, .uefi => false,
|
||||
.windows, .uefi, .wasi => false,
|
||||
else => true,
|
||||
};
|
||||
|
||||
/// Queries the system for the current moment of time as an Instant.
|
||||
/// This is not guaranteed to be monotonic or steadily increasing, but for most implementations it is.
|
||||
/// This is not guaranteed to be monotonic or steadily increasing, but for
|
||||
/// most implementations it is.
|
||||
/// Returns `error.Unsupported` when a suitable clock is not detected.
|
||||
pub fn now() error{Unsupported}!Instant {
|
||||
// QPC on windows doesn't fail on >= XP/2000 and includes time suspended.
|
||||
if (builtin.os.tag == .windows) {
|
||||
return Instant{ .timestamp = os.windows.QueryPerformanceCounter() };
|
||||
}
|
||||
|
||||
// On WASI without libc, use clock_time_get directly.
|
||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
var ns: os.wasi.timestamp_t = undefined;
|
||||
const rc = os.wasi.clock_time_get(os.wasi.CLOCK.MONOTONIC, 1, &ns);
|
||||
if (rc != .SUCCESS) return error.Unsupported;
|
||||
return Instant{ .timestamp = ns };
|
||||
}
|
||||
|
||||
if (builtin.os.tag == .uefi) {
|
||||
var value: std.os.uefi.Time = undefined;
|
||||
const status = std.os.uefi.system_table.runtime_services.getTime(&value, null);
|
||||
if (status != .Success) return error.Unsupported;
|
||||
return Instant{ .timestamp = value.toEpoch() };
|
||||
}
|
||||
|
||||
// On darwin, use UPTIME_RAW instead of MONOTONIC as it ticks while suspended.
|
||||
// On linux, use BOOTTIME instead of MONOTONIC as it ticks while suspended.
|
||||
// On freebsd derivatives, use MONOTONIC_FAST as currently there's no precision tradeoff.
|
||||
// On other posix systems, MONOTONIC is generally the fastest and ticks while suspended.
|
||||
const clock_id = switch (builtin.os.tag) {
|
||||
.windows => {
|
||||
// QPC on windows doesn't fail on >= XP/2000 and includes time suspended.
|
||||
return Instant{ .timestamp = os.windows.QueryPerformanceCounter() };
|
||||
},
|
||||
.wasi => {
|
||||
var ns: os.wasi.timestamp_t = undefined;
|
||||
const rc = os.wasi.clock_time_get(.MONOTONIC, 1, &ns);
|
||||
if (rc != .SUCCESS) return error.Unsupported;
|
||||
return .{ .timestamp = ns };
|
||||
},
|
||||
.uefi => {
|
||||
var value: std.os.uefi.Time = undefined;
|
||||
const status = std.os.uefi.system_table.runtime_services.getTime(&value, null);
|
||||
if (status != .Success) return error.Unsupported;
|
||||
return Instant{ .timestamp = value.toEpoch() };
|
||||
},
|
||||
// On darwin, use UPTIME_RAW instead of MONOTONIC as it ticks while
|
||||
// suspended.
|
||||
.macos, .ios, .tvos, .watchos => os.CLOCK.UPTIME_RAW,
|
||||
// On freebsd derivatives, use MONOTONIC_FAST as currently there's
|
||||
// no precision tradeoff.
|
||||
.freebsd, .dragonfly => os.CLOCK.MONOTONIC_FAST,
|
||||
// On linux, use BOOTTIME instead of MONOTONIC as it ticks while
|
||||
// suspended.
|
||||
.linux => os.CLOCK.BOOTTIME,
|
||||
// On other posix systems, MONOTONIC is generally the fastest and
|
||||
// ticks while suspended.
|
||||
else => os.CLOCK.MONOTONIC,
|
||||
};
|
||||
|
||||
@ -262,7 +261,7 @@ pub const Instant = struct {
|
||||
}
|
||||
|
||||
// WASI timestamps are directly in nanoseconds
|
||||
if (builtin.os.tag == .wasi and !builtin.link_libc) {
|
||||
if (builtin.os.tag == .wasi) {
|
||||
return self.timestamp - earlier.timestamp;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user