aboutsummaryrefslogtreecommitdiff
path: root/std
diff options
context:
space:
mode:
authorhryx <codroid@gmail.com>2019-05-27 17:24:21 -0700
committerhryx <codroid@gmail.com>2019-05-27 17:24:21 -0700
commite1f3eec9cc05535b3f3b81f2fb7cd65dd4d1e841 (patch)
tree5f408ed68a686491eaf759f9cbba02beac829b38 /std
parent2aa1c5da5dded6b1b346c3a1b57443f2c459ebe9 (diff)
parent3fccc0747903f0726d6cc8ee73832cb62f1304bb (diff)
downloadzig-e1f3eec9cc05535b3f3b81f2fb7cd65dd4d1e841.tar.gz
zig-e1f3eec9cc05535b3f3b81f2fb7cd65dd4d1e841.zip
Merge branch 'master' into translate-c-userland
Diffstat (limited to 'std')
-rw-r--r--std/atomic/queue.zig12
-rw-r--r--std/atomic/stack.zig12
-rw-r--r--std/buffer.zig4
-rw-r--r--std/build.zig172
-rw-r--r--std/c.zig102
-rw-r--r--std/c/darwin.zig193
-rw-r--r--std/c/freebsd.zig150
-rw-r--r--std/c/linux.zig30
-rw-r--r--std/c/netbsd.zig146
-rw-r--r--std/child_process.zig (renamed from std/os/child_process.zig)310
-rw-r--r--std/coff.zig7
-rw-r--r--std/crypto.zig3
-rw-r--r--std/crypto/throughput_test.zig2
-rw-r--r--std/cstr.zig17
-rw-r--r--std/debug.zig199
-rw-r--r--std/dynamic_library.zig66
-rw-r--r--std/elf.zig9
-rw-r--r--std/event/fs.zig224
-rw-r--r--std/event/group.zig2
-rw-r--r--std/event/loop.zig268
-rw-r--r--std/event/net.zig168
-rw-r--r--std/event/rwlock.zig4
-rw-r--r--std/fmt.zig2
-rw-r--r--std/fs.zig808
-rw-r--r--std/fs/file.zig319
-rw-r--r--std/fs/get_app_data_dir.zig (renamed from std/os/get_app_data_dir.zig)23
-rw-r--r--std/fs/path.zig (renamed from std/os/path.zig)230
-rw-r--r--std/heap.zig371
-rw-r--r--std/io.zig54
-rw-r--r--std/io/c_out_stream.zig39
-rw-r--r--std/io/seekable_stream.zig10
-rw-r--r--std/io/test.zig31
-rw-r--r--std/mem.zig78
-rw-r--r--std/mutex.zig4
-rw-r--r--std/net.zig24
-rw-r--r--std/os.zig4639
-rw-r--r--std/os/bits.zig27
-rw-r--r--std/os/bits/darwin.zig1080
-rw-r--r--std/os/bits/freebsd.zig837
-rw-r--r--std/os/bits/linux.zig931
-rw-r--r--std/os/bits/linux/arm64.zig405
-rw-r--r--std/os/bits/linux/errno.zig (renamed from std/os/linux/errno.zig)1
-rw-r--r--std/os/bits/linux/x86_64.zig470
-rw-r--r--std/os/bits/netbsd.zig725
-rw-r--r--std/os/bits/wasi.zig (renamed from std/os/wasi/core.zig)73
-rw-r--r--std/os/bits/windows.zig167
-rw-r--r--std/os/darwin.zig888
-rw-r--r--std/os/darwin/errno.zig328
-rw-r--r--std/os/file.zig512
-rw-r--r--std/os/freebsd.zig847
-rw-r--r--std/os/freebsd/errno.zig121
-rw-r--r--std/os/get_user_id.zig104
-rw-r--r--std/os/linux.zig1114
-rw-r--r--std/os/linux/arm64.zig403
-rw-r--r--std/os/linux/test.zig2
-rw-r--r--std/os/linux/tls.zig17
-rw-r--r--std/os/linux/vdso.zig7
-rw-r--r--std/os/linux/x86_64.zig470
-rw-r--r--std/os/netbsd.zig724
-rw-r--r--std/os/netbsd/errno.zig134
-rw-r--r--std/os/test.zig88
-rw-r--r--std/os/time.zig307
-rw-r--r--std/os/wasi.zig104
-rw-r--r--std/os/windows.zig1105
-rw-r--r--std/os/windows/advapi32.zig13
-rw-r--r--std/os/windows/bits.zig527
-rw-r--r--std/os/windows/kernel32.zig79
-rw-r--r--std/os/windows/ntdll.zig2
-rw-r--r--std/os/windows/ole32.zig13
-rw-r--r--std/os/windows/shell32.zig2
-rw-r--r--std/os/windows/util.zig316
-rw-r--r--std/os/zen.zig2
-rw-r--r--std/packed_int_array.zig6
-rw-r--r--std/pdb.zig16
-rw-r--r--std/process.zig617
-rw-r--r--std/rand.zig6
-rw-r--r--std/special/bootstrap.zig12
-rw-r--r--std/special/build_runner.zig13
-rw-r--r--std/statically_initialized_mutex.zig16
-rw-r--r--std/std.zig10
-rw-r--r--std/thread.zig349
-rw-r--r--std/time.zig221
-rw-r--r--std/time/epoch.zig (renamed from std/os/epoch.zig)0
-rw-r--r--std/zig/bench.zig4
84 files changed, 11526 insertions, 11421 deletions
diff --git a/std/atomic/queue.zig b/std/atomic/queue.zig
index 431a96e64b..bf5700c51e 100644
--- a/std/atomic/queue.zig
+++ b/std/atomic/queue.zig
@@ -186,13 +186,13 @@ test "std.atomic.Queue" {
}
}
} else {
- var putters: [put_thread_count]*std.os.Thread = undefined;
+ var putters: [put_thread_count]*std.Thread = undefined;
for (putters) |*t| {
- t.* = try std.os.spawnThread(&context, startPuts);
+ t.* = try std.Thread.spawn(&context, startPuts);
}
- var getters: [put_thread_count]*std.os.Thread = undefined;
+ var getters: [put_thread_count]*std.Thread = undefined;
for (getters) |*t| {
- t.* = try std.os.spawnThread(&context, startGets);
+ t.* = try std.Thread.spawn(&context, startGets);
}
for (putters) |t|
@@ -220,7 +220,7 @@ fn startPuts(ctx: *Context) u8 {
var put_count: usize = puts_per_thread;
var r = std.rand.DefaultPrng.init(0xdeadbeef);
while (put_count != 0) : (put_count -= 1) {
- std.os.time.sleep(1); // let the os scheduler be our fuzz
+ std.time.sleep(1); // let the os scheduler be our fuzz
const x = @bitCast(i32, r.random.scalar(u32));
const node = ctx.allocator.create(Queue(i32).Node) catch unreachable;
node.* = Queue(i32).Node{
@@ -239,7 +239,7 @@ fn startGets(ctx: *Context) u8 {
const last = @atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1;
while (ctx.queue.get()) |node| {
- std.os.time.sleep(1); // let the os scheduler be our fuzz
+ std.time.sleep(1); // let the os scheduler be our fuzz
_ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);
_ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);
}
diff --git a/std/atomic/stack.zig b/std/atomic/stack.zig
index 8ae6c997aa..e9d070ac7b 100644
--- a/std/atomic/stack.zig
+++ b/std/atomic/stack.zig
@@ -120,13 +120,13 @@ test "std.atomic.stack" {
}
}
} else {
- var putters: [put_thread_count]*std.os.Thread = undefined;
+ var putters: [put_thread_count]*std.Thread = undefined;
for (putters) |*t| {
- t.* = try std.os.spawnThread(&context, startPuts);
+ t.* = try std.Thread.spawn(&context, startPuts);
}
- var getters: [put_thread_count]*std.os.Thread = undefined;
+ var getters: [put_thread_count]*std.Thread = undefined;
for (getters) |*t| {
- t.* = try std.os.spawnThread(&context, startGets);
+ t.* = try std.Thread.spawn(&context, startGets);
}
for (putters) |t|
@@ -154,7 +154,7 @@ fn startPuts(ctx: *Context) u8 {
var put_count: usize = puts_per_thread;
var r = std.rand.DefaultPrng.init(0xdeadbeef);
while (put_count != 0) : (put_count -= 1) {
- std.os.time.sleep(1); // let the os scheduler be our fuzz
+ std.time.sleep(1); // let the os scheduler be our fuzz
const x = @bitCast(i32, r.random.scalar(u32));
const node = ctx.allocator.create(Stack(i32).Node) catch unreachable;
node.* = Stack(i32).Node{
@@ -172,7 +172,7 @@ fn startGets(ctx: *Context) u8 {
const last = @atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1;
while (ctx.stack.pop()) |node| {
- std.os.time.sleep(1); // let the os scheduler be our fuzz
+ std.time.sleep(1); // let the os scheduler be our fuzz
_ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);
_ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);
}
diff --git a/std/buffer.zig b/std/buffer.zig
index 32228af558..bc6aa254da 100644
--- a/std/buffer.zig
+++ b/std/buffer.zig
@@ -139,15 +139,13 @@ pub const Buffer = struct {
};
test "simple Buffer" {
- const cstr = @import("cstr.zig");
-
var buf = try Buffer.init(debug.global_allocator, "");
testing.expect(buf.len() == 0);
try buf.append("hello");
try buf.append(" ");
try buf.append("world");
testing.expect(buf.eql("hello world"));
- testing.expect(mem.eql(u8, cstr.toSliceConst(buf.toSliceConst().ptr), buf.toSliceConst()));
+ testing.expect(mem.eql(u8, mem.toSliceConst(u8, buf.toSliceConst().ptr), buf.toSliceConst()));
var buf2 = try Buffer.initFromBuffer(buf);
testing.expect(buf.eql(buf2.toSliceConst()));
diff --git a/std/build.zig b/std/build.zig
index ff64c6cb93..d427521251 100644
--- a/std/build.zig
+++ b/std/build.zig
@@ -1,6 +1,7 @@
const std = @import("std.zig");
const builtin = @import("builtin");
const io = std.io;
+const fs = std.fs;
const mem = std.mem;
const debug = std.debug;
const assert = debug.assert;
@@ -8,12 +9,11 @@ const warn = std.debug.warn;
const ArrayList = std.ArrayList;
const HashMap = std.HashMap;
const Allocator = mem.Allocator;
-const os = std.os;
-const StdIo = os.ChildProcess.StdIo;
-const Term = os.ChildProcess.Term;
+const process = std.process;
const BufSet = std.BufSet;
const BufMap = std.BufMap;
const fmt_lib = std.fmt;
+const File = std.fs.File;
pub const FmtStep = @import("build/fmt.zig").FmtStep;
@@ -95,11 +95,11 @@ pub const Builder = struct {
pub fn init(allocator: *Allocator, zig_exe: []const u8, build_root: []const u8, cache_root: []const u8) Builder {
const env_map = allocator.create(BufMap) catch unreachable;
- env_map.* = os.getEnvMap(allocator) catch unreachable;
+ env_map.* = process.getEnvMap(allocator) catch unreachable;
var self = Builder{
.zig_exe = zig_exe,
.build_root = build_root,
- .cache_root = os.path.relative(allocator, build_root, cache_root) catch unreachable,
+ .cache_root = fs.path.relative(allocator, build_root, cache_root) catch unreachable,
.verbose = false,
.verbose_tokenize = false,
.verbose_ast = false,
@@ -153,8 +153,8 @@ pub const Builder = struct {
pub fn setInstallPrefix(self: *Builder, maybe_prefix: ?[]const u8) void {
self.prefix = maybe_prefix orelse "/usr/local"; // TODO better default
- self.lib_dir = os.path.join(self.allocator, [][]const u8{ self.prefix, "lib" }) catch unreachable;
- self.exe_dir = os.path.join(self.allocator, [][]const u8{ self.prefix, "bin" }) catch unreachable;
+ self.lib_dir = fs.path.join(self.allocator, [][]const u8{ self.prefix, "lib" }) catch unreachable;
+ self.exe_dir = fs.path.join(self.allocator, [][]const u8{ self.prefix, "bin" }) catch unreachable;
}
pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
@@ -286,7 +286,7 @@ pub const Builder = struct {
if (self.verbose) {
warn("rm {}\n", installed_file);
}
- os.deleteFile(installed_file) catch {};
+ fs.deleteFile(installed_file) catch {};
}
// TODO remove empty directories
@@ -325,7 +325,7 @@ pub const Builder = struct {
fn detectNativeSystemPaths(self: *Builder) void {
var is_nixos = false;
- if (os.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {
+ if (process.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {
is_nixos = true;
var it = mem.tokenize(nix_cflags_compile, " ");
while (true) {
@@ -344,7 +344,7 @@ pub const Builder = struct {
} else |err| {
assert(err == error.EnvironmentVariableNotFound);
}
- if (os.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| {
+ if (process.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| {
is_nixos = true;
var it = mem.tokenize(nix_ldflags, " ");
while (true) {
@@ -368,7 +368,7 @@ pub const Builder = struct {
}
if (is_nixos) return;
switch (builtin.os) {
- builtin.Os.windows => {},
+ .windows => {},
else => {
const triple = (CrossTarget{
.arch = builtin.arch,
@@ -601,7 +601,7 @@ pub const Builder = struct {
printCmd(cwd, argv);
}
- const child = os.ChildProcess.init(argv, self.allocator) catch unreachable;
+ const child = std.ChildProcess.init(argv, self.allocator) catch unreachable;
defer child.deinit();
child.cwd = cwd;
@@ -613,7 +613,7 @@ pub const Builder = struct {
};
switch (term) {
- Term.Exited => |code| {
+ .Exited => |code| {
if (code != 0) {
warn("The following command exited with error code {}:\n", code);
printCmd(cwd, argv);
@@ -630,7 +630,7 @@ pub const Builder = struct {
}
pub fn makePath(self: *Builder, path: []const u8) !void {
- os.makePath(self.allocator, self.pathFromRoot(path)) catch |err| {
+ fs.makePath(self.allocator, self.pathFromRoot(path)) catch |err| {
warn("Unable to create path {}: {}\n", path, @errorName(err));
return err;
};
@@ -651,7 +651,7 @@ pub const Builder = struct {
///::dest_rel_path is relative to prefix path or it can be an absolute path
pub fn addInstallFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep {
- const full_dest_path = os.path.resolve(
+ const full_dest_path = fs.path.resolve(
self.allocator,
[][]const u8{ self.prefix, dest_rel_path },
) catch unreachable;
@@ -668,28 +668,28 @@ pub const Builder = struct {
}
fn copyFile(self: *Builder, source_path: []const u8, dest_path: []const u8) !void {
- return self.copyFileMode(source_path, dest_path, os.File.default_mode);
+ return self.copyFileMode(source_path, dest_path, File.default_mode);
}
- fn copyFileMode(self: *Builder, source_path: []const u8, dest_path: []const u8, mode: os.File.Mode) !void {
+ fn copyFileMode(self: *Builder, source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void {
if (self.verbose) {
warn("cp {} {}\n", source_path, dest_path);
}
- const dirname = os.path.dirname(dest_path) orelse ".";
+ const dirname = fs.path.dirname(dest_path) orelse ".";
const abs_source_path = self.pathFromRoot(source_path);
- os.makePath(self.allocator, dirname) catch |err| {
+ fs.makePath(self.allocator, dirname) catch |err| {
warn("Unable to create path {}: {}\n", dirname, @errorName(err));
return err;
};
- os.copyFileMode(abs_source_path, dest_path, mode) catch |err| {
+ fs.copyFileMode(abs_source_path, dest_path, mode) catch |err| {
warn("Unable to copy {} to {}: {}\n", abs_source_path, dest_path, @errorName(err));
return err;
};
}
fn pathFromRoot(self: *Builder, rel_path: []const u8) []u8 {
- return os.path.resolve(self.allocator, [][]const u8{ self.build_root, rel_path }) catch unreachable;
+ return fs.path.resolve(self.allocator, [][]const u8{ self.build_root, rel_path }) catch unreachable;
}
pub fn fmt(self: *Builder, comptime format: []const u8, args: ...) []u8 {
@@ -701,11 +701,11 @@ pub const Builder = struct {
const exe_extension = (Target{ .Native = {} }).exeFileExt();
for (self.search_prefixes.toSliceConst()) |search_prefix| {
for (names) |name| {
- if (os.path.isAbsolute(name)) {
+ if (fs.path.isAbsolute(name)) {
return name;
}
- const full_path = try os.path.join(self.allocator, [][]const u8{ search_prefix, "bin", self.fmt("{}{}", name, exe_extension) });
- if (os.path.real(self.allocator, full_path)) |real_path| {
+ const full_path = try fs.path.join(self.allocator, [][]const u8{ search_prefix, "bin", self.fmt("{}{}", name, exe_extension) });
+ if (fs.path.real(self.allocator, full_path)) |real_path| {
return real_path;
} else |_| {
continue;
@@ -714,13 +714,13 @@ pub const Builder = struct {
}
if (self.env_map.get("PATH")) |PATH| {
for (names) |name| {
- if (os.path.isAbsolute(name)) {
+ if (fs.path.isAbsolute(name)) {
return name;
}
- var it = mem.tokenize(PATH, []u8{os.path.delimiter});
+ var it = mem.tokenize(PATH, []u8{fs.path.delimiter});
while (it.next()) |path| {
- const full_path = try os.path.join(self.allocator, [][]const u8{ path, self.fmt("{}{}", name, exe_extension) });
- if (os.path.real(self.allocator, full_path)) |real_path| {
+ const full_path = try fs.path.join(self.allocator, [][]const u8{ path, self.fmt("{}{}", name, exe_extension) });
+ if (fs.path.real(self.allocator, full_path)) |real_path| {
return real_path;
} else |_| {
continue;
@@ -729,12 +729,12 @@ pub const Builder = struct {
}
}
for (names) |name| {
- if (os.path.isAbsolute(name)) {
+ if (fs.path.isAbsolute(name)) {
return name;
}
for (paths) |path| {
- const full_path = try os.path.join(self.allocator, [][]const u8{ path, self.fmt("{}{}", name, exe_extension) });
- if (os.path.real(self.allocator, full_path)) |real_path| {
+ const full_path = try fs.path.join(self.allocator, [][]const u8{ path, self.fmt("{}{}", name, exe_extension) });
+ if (fs.path.real(self.allocator, full_path)) |real_path| {
return real_path;
} else |_| {
continue;
@@ -748,12 +748,12 @@ pub const Builder = struct {
assert(argv.len != 0);
const max_output_size = 100 * 1024;
- const child = try os.ChildProcess.init(argv, self.allocator);
+ const child = try std.ChildProcess.init(argv, self.allocator);
defer child.deinit();
- child.stdin_behavior = os.ChildProcess.StdIo.Ignore;
- child.stdout_behavior = os.ChildProcess.StdIo.Pipe;
- child.stderr_behavior = os.ChildProcess.StdIo.Inherit;
+ child.stdin_behavior = .Ignore;
+ child.stdout_behavior = .Pipe;
+ child.stderr_behavior = .Inherit;
try child.spawn();
@@ -765,7 +765,7 @@ pub const Builder = struct {
const term = child.wait() catch |err| std.debug.panic("unable to spawn {}: {}", argv[0], err);
switch (term) {
- os.ChildProcess.Term.Exited => |code| {
+ .Exited => |code| {
if (code != 0) {
warn("The following command exited with error code {}:\n", code);
printCmd(null, argv);
@@ -845,8 +845,8 @@ pub const Target = union(enum) {
}
}
- pub fn oFileExt(self: *const Target) []const u8 {
- const abi = switch (self.*) {
+ pub fn oFileExt(self: Target) []const u8 {
+ const abi = switch (self) {
Target.Native => builtin.abi,
Target.Cross => |t| t.abi,
};
@@ -856,49 +856,49 @@ pub const Target = union(enum) {
};
}
- pub fn exeFileExt(self: *const Target) []const u8 {
+ pub fn exeFileExt(self: Target) []const u8 {
return switch (self.getOs()) {
- builtin.Os.windows => ".exe",
+ .windows => ".exe",
else => "",
};
}
- pub fn libFileExt(self: *const Target) []const u8 {
+ pub fn libFileExt(self: Target) []const u8 {
return switch (self.getOs()) {
- builtin.Os.windows => ".lib",
+ .windows => ".lib",
else => ".a",
};
}
- pub fn getOs(self: *const Target) builtin.Os {
- return switch (self.*) {
+ pub fn getOs(self: Target) builtin.Os {
+ return switch (self) {
Target.Native => builtin.os,
Target.Cross => |t| t.os,
};
}
- pub fn isDarwin(self: *const Target) bool {
+ pub fn isDarwin(self: Target) bool {
return switch (self.getOs()) {
- builtin.Os.ios, builtin.Os.macosx => true,
+ .ios, .macosx, .watchos, .tvos => true,
else => false,
};
}
- pub fn isWindows(self: *const Target) bool {
+ pub fn isWindows(self: Target) bool {
return switch (self.getOs()) {
- builtin.Os.windows => true,
+ .windows => true,
else => false,
};
}
- pub fn isFreeBSD(self: *const Target) bool {
+ pub fn isFreeBSD(self: Target) bool {
return switch (self.getOs()) {
- builtin.Os.freebsd => true,
+ .freebsd => true,
else => false,
};
}
- pub fn wantSharedLibSymLinks(self: *const Target) bool {
+ pub fn wantSharedLibSymLinks(self: Target) bool {
return !self.isWindows();
}
};
@@ -1064,19 +1064,19 @@ pub const LibExeObjStep = struct {
fn computeOutFileNames(self: *LibExeObjStep) void {
switch (self.kind) {
- Kind.Obj => {
+ .Obj => {
self.out_filename = self.builder.fmt("{}{}", self.name, self.target.oFileExt());
},
- Kind.Exe => {
+ .Exe => {
self.out_filename = self.builder.fmt("{}{}", self.name, self.target.exeFileExt());
},
- Kind.Test => {
+ .Test => {
self.out_filename = self.builder.fmt("test{}", self.target.exeFileExt());
},
- Kind.Lib => {
+ .Lib => {
if (!self.is_dynamic) {
switch (self.target.getOs()) {
- builtin.Os.windows => {
+ .windows => {
self.out_filename = self.builder.fmt("{}.lib", self.name);
},
else => {
@@ -1086,13 +1086,13 @@ pub const LibExeObjStep = struct {
self.out_lib_filename = self.out_filename;
} else {
switch (self.target.getOs()) {
- builtin.Os.ios, builtin.Os.macosx => {
+ .ios, .macosx => {
self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib", self.name, self.version.major, self.version.minor, self.version.patch);
self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", self.name, self.version.major);
self.name_only_filename = self.builder.fmt("lib{}.dylib", self.name);
self.out_lib_filename = self.out_filename;
},
- builtin.Os.windows => {
+ .windows => {
self.out_filename = self.builder.fmt("{}.dll", self.name);
self.out_lib_filename = self.builder.fmt("{}.lib", self.name);
},
@@ -1227,7 +1227,7 @@ pub const LibExeObjStep = struct {
/// the make step, from a step that has declared a dependency on this one.
/// To run an executable built with zig build, use `run`, or create an install step and invoke it.
pub fn getOutputPath(self: *LibExeObjStep) []const u8 {
- return os.path.join(
+ return fs.path.join(
self.builder.allocator,
[][]const u8{ self.output_dir.?, self.out_filename },
) catch unreachable;
@@ -1237,7 +1237,7 @@ pub const LibExeObjStep = struct {
/// the make step, from a step that has declared a dependency on this one.
pub fn getOutputLibPath(self: *LibExeObjStep) []const u8 {
assert(self.kind == Kind.Lib);
- return os.path.join(
+ return fs.path.join(
self.builder.allocator,
[][]const u8{ self.output_dir.?, self.out_lib_filename },
) catch unreachable;
@@ -1248,7 +1248,7 @@ pub const LibExeObjStep = struct {
pub fn getOutputHPath(self: *LibExeObjStep) []const u8 {
assert(self.kind != Kind.Exe);
assert(!self.disable_gen_h);
- return os.path.join(
+ return fs.path.join(
self.builder.allocator,
[][]const u8{ self.output_dir.?, self.out_h_filename },
) catch unreachable;
@@ -1364,7 +1364,7 @@ pub const LibExeObjStep = struct {
try zig_args.append("--library");
try zig_args.append(full_path_lib);
- if (os.path.dirname(full_path_lib)) |dirname| {
+ if (fs.path.dirname(full_path_lib)) |dirname| {
try zig_args.append("-rpath");
try zig_args.append(dirname);
}
@@ -1390,7 +1390,7 @@ pub const LibExeObjStep = struct {
}
if (self.build_options_contents.len() > 0) {
- const build_options_file = try os.path.join(
+ const build_options_file = try fs.path.join(
builder.allocator,
[][]const u8{ builder.cache_root, builder.fmt("{}_build_options.zig", self.name) },
);
@@ -1502,7 +1502,7 @@ pub const LibExeObjStep = struct {
IncludeDir.OtherStep => |other| {
const h_path = other.getOutputHPath();
try zig_args.append("-isystem");
- try zig_args.append(os.path.dirname(h_path).?);
+ try zig_args.append(fs.path.dirname(h_path).?);
},
}
}
@@ -1575,7 +1575,7 @@ pub const LibExeObjStep = struct {
const output_path_nl = try builder.exec(zig_args.toSliceConst());
const output_path = mem.trimRight(u8, output_path_nl, "\r\n");
- self.output_dir = os.path.dirname(output_path).?;
+ self.output_dir = fs.path.dirname(output_path).?;
}
if (self.kind == Kind.Lib and self.is_dynamic and self.target.wantSharedLibSymLinks()) {
@@ -1636,20 +1636,20 @@ pub const RunStep = struct {
}
pub fn addPathDir(self: *RunStep, search_path: []const u8) void {
- const PATH = if (builtin.os == builtin.Os.windows) "Path" else "PATH";
+ const PATH = if (std.os.windows.is_the_target) "Path" else "PATH";
const env_map = self.getEnvMap();
const prev_path = env_map.get(PATH) orelse {
env_map.set(PATH, search_path) catch unreachable;
return;
};
- const new_path = self.builder.fmt("{}" ++ [1]u8{os.path.delimiter} ++ "{}", prev_path, search_path);
+ const new_path = self.builder.fmt("{}" ++ [1]u8{fs.path.delimiter} ++ "{}", prev_path, search_path);
env_map.set(PATH, new_path) catch unreachable;
}
pub fn getEnvMap(self: *RunStep) *BufMap {
return self.env_map orelse {
const env_map = self.builder.allocator.create(BufMap) catch unreachable;
- env_map.* = os.getEnvMap(self.builder.allocator) catch unreachable;
+ env_map.* = process.getEnvMap(self.builder.allocator) catch unreachable;
self.env_map = env_map;
return env_map;
};
@@ -1687,7 +1687,7 @@ pub const RunStep = struct {
switch (link_object) {
LibExeObjStep.LinkObject.OtherStep => |other| {
if (other.target.isWindows() and other.isDynamicLibrary()) {
- self.addPathDir(os.path.dirname(other.getOutputPath()).?);
+ self.addPathDir(fs.path.dirname(other.getOutputPath()).?);
self.addPathForDynLibs(other);
}
},
@@ -1717,7 +1717,7 @@ const InstallArtifactStep = struct {
.builder = builder,
.step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),
.artifact = artifact,
- .dest_file = os.path.join(
+ .dest_file = fs.path.join(
builder.allocator,
[][]const u8{ dest_dir, artifact.out_filename },
) catch unreachable,
@@ -1725,11 +1725,11 @@ const InstallArtifactStep = struct {
self.step.dependOn(&artifact.step);
builder.pushInstalledFile(self.dest_file);
if (self.artifact.kind == LibExeObjStep.Kind.Lib and self.artifact.is_dynamic) {
- builder.pushInstalledFile(os.path.join(
+ builder.pushInstalledFile(fs.path.join(
builder.allocator,
[][]const u8{ builder.lib_dir, artifact.major_only_filename },
) catch unreachable);
- builder.pushInstalledFile(os.path.join(
+ builder.pushInstalledFile(fs.path.join(
builder.allocator,
[][]const u8{ builder.lib_dir, artifact.name_only_filename },
) catch unreachable);
@@ -1742,12 +1742,12 @@ const InstallArtifactStep = struct {
const builder = self.builder;
const mode = switch (builtin.os) {
- builtin.Os.windows => {},
+ .windows => {},
else => switch (self.artifact.kind) {
- LibExeObjStep.Kind.Obj => unreachable,
- LibExeObjStep.Kind.Test => unreachable,
- LibExeObjStep.Kind.Exe => u32(0o755),
- LibExeObjStep.Kind.Lib => if (!self.artifact.is_dynamic) u32(0o666) else u32(0o755),
+ .Obj => unreachable,
+ .Test => unreachable,
+ .Exe => u32(0o755),
+ .Lib => if (!self.artifact.is_dynamic) u32(0o666) else u32(0o755),
},
};
try builder.copyFileMode(self.artifact.getOutputPath(), self.dest_file, mode);
@@ -1796,8 +1796,8 @@ pub const WriteFileStep = struct {
fn make(step: *Step) !void {
const self = @fieldParentPtr(WriteFileStep, "step", step);
const full_path = self.builder.pathFromRoot(self.file_path);
- const full_path_dir = os.path.dirname(full_path) orelse ".";
- os.makePath(self.builder.allocator, full_path_dir) catch |err| {
+ const full_path_dir = fs.path.dirname(full_path) orelse ".";
+ fs.makePath(self.builder.allocator, full_path_dir) catch |err| {
warn("unable to make path {}: {}\n", full_path_dir, @errorName(err));
return err;
};
@@ -1844,7 +1844,7 @@ pub const RemoveDirStep = struct {
const self = @fieldParentPtr(RemoveDirStep, "step", step);
const full_path = self.builder.pathFromRoot(self.dir_path);
- os.deleteTree(self.builder.allocator, full_path) catch |err| {
+ fs.deleteTree(self.builder.allocator, full_path) catch |err| {
warn("Unable to remove {}: {}\n", full_path, @errorName(err));
return err;
};
@@ -1886,23 +1886,23 @@ pub const Step = struct {
};
fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_major_only: []const u8, filename_name_only: []const u8) !void {
- const out_dir = os.path.dirname(output_path) orelse ".";
- const out_basename = os.path.basename(output_path);
+ const out_dir = fs.path.dirname(output_path) orelse ".";
+ const out_basename = fs.path.basename(output_path);
// sym link for libfoo.so.1 to libfoo.so.1.2.3
- const major_only_path = os.path.join(
+ const major_only_path = fs.path.join(
allocator,
[][]const u8{ out_dir, filename_major_only },
) catch unreachable;
- os.atomicSymLink(allocator, out_basename, major_only_path) catch |err| {
+ fs.atomicSymLink(allocator, out_basename, major_only_path) catch |err| {
warn("Unable to symlink {} -> {}\n", major_only_path, out_basename);
return err;
};
// sym link for libfoo.so to libfoo.so.1
- const name_only_path = os.path.join(
+ const name_only_path = fs.path.join(
allocator,
[][]const u8{ out_dir, filename_name_only },
) catch unreachable;
- os.atomicSymLink(allocator, filename_major_only, name_only_path) catch |err| {
+ fs.atomicSymLink(allocator, filename_major_only, name_only_path) catch |err| {
warn("Unable to symlink {} -> {}\n", name_only_path, filename_major_only);
return err;
};
diff --git a/std/c.zig b/std/c.zig
index db28105eec..4a223cc9e2 100644
--- a/std/c.zig
+++ b/std/c.zig
@@ -1,18 +1,28 @@
const builtin = @import("builtin");
-const Os = builtin.Os;
+const std = @import("std");
+const page_size = std.mem.page_size;
+
+pub use @import("os/bits.zig");
pub use switch (builtin.os) {
- Os.linux => @import("c/linux.zig"),
- Os.windows => @import("c/windows.zig"),
- Os.macosx, Os.ios => @import("c/darwin.zig"),
- Os.freebsd => @import("c/freebsd.zig"),
- Os.netbsd => @import("c/netbsd.zig"),
+ .linux => @import("c/linux.zig"),
+ .windows => @import("c/windows.zig"),
+ .macosx, .ios, .tvos, .watchos => @import("c/darwin.zig"),
+ .freebsd => @import("c/freebsd.zig"),
+ .netbsd => @import("c/netbsd.zig"),
else => struct {},
};
+pub fn getErrno(rc: var) u16 {
+ if (rc == -1) {
+ return @intCast(u16, _errno().*);
+ } else {
+ return 0;
+ }
+}
+
// TODO https://github.com/ziglang/zig/issues/265 on this whole file
-pub const FILE = @OpaqueType();
pub extern "c" fn fopen(filename: [*]const u8, modes: [*]const u8) ?*FILE;
pub extern "c" fn fclose(stream: *FILE) c_int;
pub extern "c" fn fwrite(ptr: [*]const u8, size_of_type: usize, item_count: usize, stream: *FILE) usize;
@@ -20,33 +30,38 @@ pub extern "c" fn fread(ptr: [*]u8, size_of_type: usize, item_count: usize, stre
pub extern "c" fn abort() noreturn;
pub extern "c" fn exit(code: c_int) noreturn;
-pub extern "c" fn isatty(fd: c_int) c_int;
-pub extern "c" fn close(fd: c_int) c_int;
-pub extern "c" fn fstat(fd: c_int, buf: *Stat) c_int;
-pub extern "c" fn @"fstat$INODE64"(fd: c_int, buf: *Stat) c_int;
-pub extern "c" fn lseek(fd: c_int, offset: isize, whence: c_int) isize;
-pub extern "c" fn open(path: [*]const u8, oflag: c_int, ...) c_int;
+pub extern "c" fn isatty(fd: fd_t) c_int;
+pub extern "c" fn close(fd: fd_t) c_int;
+pub extern "c" fn @"close$NOCANCEL"(fd: fd_t) c_int;
+pub extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int;
+pub extern "c" fn @"fstat$INODE64"(fd: fd_t, buf: *Stat) c_int;
+pub extern "c" fn lseek(fd: fd_t, offset: isize, whence: c_int) isize;
+pub extern "c" fn open(path: [*]const u8, oflag: c_uint, ...) c_int;
pub extern "c" fn raise(sig: c_int) c_int;
-pub extern "c" fn read(fd: c_int, buf: *c_void, nbyte: usize) isize;
-pub extern "c" fn pread(fd: c_int, buf: *c_void, nbyte: usize, offset: u64) isize;
+pub extern "c" fn read(fd: fd_t, buf: [*]u8, nbyte: usize) isize;
+pub extern "c" fn pread(fd: fd_t, buf: [*]u8, nbyte: usize, offset: u64) isize;
+pub extern "c" fn preadv(fd: c_int, iov: [*]const iovec, iovcnt: c_uint, offset: usize) isize;
+pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: usize) isize;
pub extern "c" fn stat(noalias path: [*]const u8, noalias buf: *Stat) c_int;
-pub extern "c" fn write(fd: c_int, buf: *const c_void, nbyte: usize) isize;
-pub extern "c" fn pwrite(fd: c_int, buf: *const c_void, nbyte: usize, offset: u64) isize;
-pub extern "c" fn mmap(addr: ?*c_void, len: usize, prot: c_int, flags: c_int, fd: c_int, offset: isize) ?*c_void;
-pub extern "c" fn munmap(addr: ?*c_void, len: usize) c_int;
+pub extern "c" fn write(fd: fd_t, buf: [*]const u8, nbyte: usize) isize;
+pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: u64) isize;
+pub extern "c" fn mmap(addr: ?*align(page_size) c_void, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: isize) *c_void;
+pub extern "c" fn munmap(addr: *align(page_size) c_void, len: usize) c_int;
+pub extern "c" fn mprotect(addr: *align(page_size) c_void, len: usize, prot: c_uint) c_int;
pub extern "c" fn unlink(path: [*]const u8) c_int;
pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8;
-pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_int, options: c_int) c_int;
+pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_uint, options: c_uint) c_int;
pub extern "c" fn fork() c_int;
pub extern "c" fn access(path: [*]const u8, mode: c_uint) c_int;
-pub extern "c" fn pipe(fds: *[2]c_int) c_int;
+pub extern "c" fn pipe(fds: *[2]fd_t) c_int;
+pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;
pub extern "c" fn mkdir(path: [*]const u8, mode: c_uint) c_int;
pub extern "c" fn symlink(existing: [*]const u8, new: [*]const u8) c_int;
pub extern "c" fn rename(old: [*]const u8, new: [*]const u8) c_int;
pub extern "c" fn chdir(path: [*]const u8) c_int;
pub extern "c" fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) c_int;
-pub extern "c" fn dup(fd: c_int) c_int;
-pub extern "c" fn dup2(old_fd: c_int, new_fd: c_int) c_int;
+pub extern "c" fn dup(fd: fd_t) c_int;
+pub extern "c" fn dup2(old_fd: fd_t, new_fd: fd_t) c_int;
pub extern "c" fn readlink(noalias path: [*]const u8, noalias buf: [*]u8, bufsize: usize) isize;
pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*]u8;
pub extern "c" fn sigprocmask(how: c_int, noalias set: *const sigset_t, noalias oset: ?*sigset_t) c_int;
@@ -56,6 +71,25 @@ pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
pub extern "c" fn rmdir(path: [*]const u8) c_int;
+pub extern "c" fn getenv(name: [*]const u8) ?[*]u8;
+pub extern "c" fn sysctl(name: [*]const c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
+pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
+pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int;
+
+pub extern "c" fn bind(socket: fd_t, address: ?*const sockaddr, address_len: socklen_t) c_int;
+pub extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;
+pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int;
+pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int;
+pub extern "c" fn connect(sockfd: fd_t, sock_addr: *const sockaddr, addrlen: socklen_t) c_int;
+pub extern "c" fn accept4(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t, flags: c_uint) c_int;
+pub extern "c" fn getsockopt(sockfd: fd_t, level: c_int, optname: c_int, optval: *c_void, optlen: *socklen_t) c_int;
+pub extern "c" fn kill(pid: pid_t, sig: c_int) c_int;
+pub extern "c" fn getdirentries(fd: fd_t, buf_ptr: [*]u8, nbytes: usize, basep: *i64) isize;
+pub extern "c" fn openat(fd: c_int, path: [*]const u8, flags: c_int) c_int;
+pub extern "c" fn setgid(ruid: c_uint, euid: c_uint) c_int;
+pub extern "c" fn setuid(uid: c_uint) c_int;
+pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int;
+pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int;
pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?*c_void;
pub extern "c" fn malloc(usize) ?*c_void;
@@ -63,11 +97,19 @@ pub extern "c" fn realloc(?*c_void, usize) ?*c_void;
pub extern "c" fn free(*c_void) void;
pub extern "c" fn posix_memalign(memptr: **c_void, alignment: usize, size: usize) c_int;
-pub extern "pthread" fn pthread_create(noalias newthread: *pthread_t, noalias attr: ?*const pthread_attr_t, start_routine: extern fn (?*c_void) ?*c_void, noalias arg: ?*c_void) c_int;
-pub extern "pthread" fn pthread_attr_init(attr: *pthread_attr_t) c_int;
-pub extern "pthread" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int;
-pub extern "pthread" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int;
-pub extern "pthread" fn pthread_self() pthread_t;
-pub extern "pthread" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int;
+pub extern "c" fn pthread_create(noalias newthread: *pthread_t, noalias attr: ?*const pthread_attr_t, start_routine: extern fn (?*c_void) ?*c_void, noalias arg: ?*c_void) c_int;
+pub extern "c" fn pthread_attr_init(attr: *pthread_attr_t) c_int;
+pub extern "c" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int;
+pub extern "c" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int;
+pub extern "c" fn pthread_self() pthread_t;
+pub extern "c" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int;
-pub const pthread_t = *@OpaqueType();
+pub extern "c" fn kqueue() c_int;
+pub extern "c" fn kevent(
+ kq: c_int,
+ changelist: [*]const Kevent,
+ nchanges: c_int,
+ eventlist: [*]Kevent,
+ nevents: c_int,
+ timeout: ?*const timespec,
+) c_int;
diff --git a/std/c/darwin.zig b/std/c/darwin.zig
index 0e92e8d411..e45a158f68 100644
--- a/std/c/darwin.zig
+++ b/std/c/darwin.zig
@@ -1,24 +1,19 @@
-const macho = @import("../macho.zig");
+const std = @import("../std.zig");
+const assert = std.debug.assert;
+const builtin = @import("builtin");
+const macho = std.macho;
+
+use @import("../os/bits.zig");
extern "c" fn __error() *c_int;
pub extern "c" fn _NSGetExecutablePath(buf: [*]u8, bufsize: *u32) c_int;
pub extern "c" fn _dyld_get_image_header(image_index: u32) ?*mach_header;
-pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize;
+pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: [*]u8, buf_len: usize, basep: *i64) isize;
pub extern "c" fn mach_absolute_time() u64;
pub extern "c" fn mach_timebase_info(tinfo: ?*mach_timebase_info_data) void;
-pub extern "c" fn kqueue() c_int;
-pub extern "c" fn kevent(
- kq: c_int,
- changelist: [*]const Kevent,
- nchanges: c_int,
- eventlist: [*]Kevent,
- nevents: c_int,
- timeout: ?*const timespec,
-) c_int;
-
pub extern "c" fn kevent64(
kq: c_int,
changelist: [*]const kevent64_s,
@@ -29,13 +24,6 @@ pub extern "c" fn kevent64(
timeout: ?*const timespec,
) c_int;
-pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
-pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
-pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int;
-
-pub extern "c" fn bind(socket: c_int, address: ?*const sockaddr, address_len: socklen_t) c_int;
-pub extern "c" fn socket(domain: c_int, type: c_int, protocol: c_int) c_int;
-
const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header;
/// The value of the link editor defined symbol _MH_EXECUTE_SYM is the address
@@ -48,170 +36,21 @@ const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header;
/// export a weak symbol here, to be overridden by the real one.
pub extern "c" var _mh_execute_header: mach_hdr = undefined;
comptime {
- @export("__mh_execute_header", _mh_execute_header, @import("builtin").GlobalLinkage.Weak);
+ if (std.os.darwin.is_the_target) {
+ @export("__mh_execute_header", _mh_execute_header, .Weak);
+ }
}
pub const mach_header_64 = macho.mach_header_64;
pub const mach_header = macho.mach_header;
-pub use @import("../os/darwin/errno.zig");
-
pub const _errno = __error;
-pub const in_port_t = u16;
-pub const sa_family_t = u8;
-pub const socklen_t = u32;
-pub const sockaddr = extern union {
- in: sockaddr_in,
- in6: sockaddr_in6,
-};
-pub const sockaddr_in = extern struct {
- len: u8,
- family: sa_family_t,
- port: in_port_t,
- addr: u32,
- zero: [8]u8,
-};
-pub const sockaddr_in6 = extern struct {
- len: u8,
- family: sa_family_t,
- port: in_port_t,
- flowinfo: u32,
- addr: [16]u8,
- scope_id: u32,
-};
-
-pub const timeval = extern struct {
- tv_sec: c_long,
- tv_usec: i32,
-};
-
-pub const timezone = extern struct {
- tz_minuteswest: i32,
- tz_dsttime: i32,
-};
-
-pub const mach_timebase_info_data = extern struct {
- numer: u32,
- denom: u32,
-};
-
-/// Renamed to Stat to not conflict with the stat function.
-pub const Stat = extern struct {
- dev: i32,
- mode: u16,
- nlink: u16,
- ino: u64,
- uid: u32,
- gid: u32,
- rdev: i32,
- atime: usize,
- atimensec: usize,
- mtime: usize,
- mtimensec: usize,
- ctime: usize,
- ctimensec: usize,
- birthtime: usize,
- birthtimensec: usize,
- size: i64,
- blocks: i64,
- blksize: i32,
- flags: u32,
- gen: u32,
- lspare: i32,
- qspare: [2]i64,
-};
+pub extern "c" fn mach_host_self() mach_port_t;
+pub extern "c" fn clock_get_time(clock_serv: clock_serv_t, cur_time: *mach_timespec_t) kern_return_t;
+pub extern "c" fn host_get_clock_service(host: host_t, clock_id: clock_id_t, clock_serv: ?[*]clock_serv_t) kern_return_t;
+pub extern "c" fn mach_port_deallocate(task: ipc_space_t, name: mach_port_name_t) kern_return_t;
-pub const timespec = extern struct {
- tv_sec: isize,
- tv_nsec: isize,
-};
-
-pub const sigset_t = u32;
-
-/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.
-pub const Sigaction = extern struct {
- handler: extern fn (c_int) void,
- sa_mask: sigset_t,
- sa_flags: c_int,
-};
-
-pub const dirent = extern struct {
- d_ino: usize,
- d_seekoff: usize,
- d_reclen: u16,
- d_namlen: u16,
- d_type: u8,
- d_name: u8, // field address is address of first byte of name
-};
-
-pub const pthread_attr_t = extern struct {
- __sig: c_long,
- __opaque: [56]u8,
-};
-
-/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
-pub const Kevent = extern struct {
- ident: usize,
- filter: i16,
- flags: u16,
- fflags: u32,
- data: isize,
- udata: usize,
-};
-
-// sys/types.h on macos uses #pragma pack(4) so these checks are
-// to make sure the struct is laid out the same. These values were
-// produced from C code using the offsetof macro.
-const std = @import("../std.zig");
-const assert = std.debug.assert;
-
-comptime {
- assert(@byteOffsetOf(Kevent, "ident") == 0);
- assert(@byteOffsetOf(Kevent, "filter") == 8);
- assert(@byteOffsetOf(Kevent, "flags") == 10);
- assert(@byteOffsetOf(Kevent, "fflags") == 12);
- assert(@byteOffsetOf(Kevent, "data") == 16);
- assert(@byteOffsetOf(Kevent, "udata") == 24);
-}
-
-pub const kevent64_s = extern struct {
- ident: u64,
- filter: i16,
- flags: u16,
- fflags: u32,
- data: i64,
- udata: u64,
- ext: [2]u64,
-};
-
-pub const mach_port_t = c_uint;
-pub const clock_serv_t = mach_port_t;
-pub const clock_res_t = c_int;
-pub const mach_port_name_t = natural_t;
-pub const natural_t = c_uint;
-pub const mach_timespec_t = extern struct {
- tv_sec: c_uint,
- tv_nsec: clock_res_t,
-};
-pub const kern_return_t = c_int;
-pub const host_t = mach_port_t;
-pub const CALENDAR_CLOCK = 1;
-
-pub extern fn mach_host_self() mach_port_t;
-pub extern fn clock_get_time(clock_serv: clock_serv_t, cur_time: *mach_timespec_t) kern_return_t;
-pub extern fn host_get_clock_service(host: host_t, clock_id: clock_id_t, clock_serv: ?[*]clock_serv_t) kern_return_t;
-pub extern fn mach_port_deallocate(task: ipc_space_t, name: mach_port_name_t) kern_return_t;
-
-// sys/types.h on macos uses #pragma pack() so these checks are
-// to make sure the struct is laid out the same. These values were
-// produced from C code using the offsetof macro.
-comptime {
- assert(@byteOffsetOf(kevent64_s, "ident") == 0);
- assert(@byteOffsetOf(kevent64_s, "filter") == 8);
- assert(@byteOffsetOf(kevent64_s, "flags") == 10);
- assert(@byteOffsetOf(kevent64_s, "fflags") == 12);
- assert(@byteOffsetOf(kevent64_s, "data") == 16);
- assert(@byteOffsetOf(kevent64_s, "udata") == 24);
- assert(@byteOffsetOf(kevent64_s, "ext") == 32);
+pub fn sigaddset(set: *sigset_t, signo: u5) void {
+ set.* |= u32(1) << (signo - 1);
}
diff --git a/std/c/freebsd.zig b/std/c/freebsd.zig
index 1f8e314333..70f3aeb9ca 100644
--- a/std/c/freebsd.zig
+++ b/std/c/freebsd.zig
@@ -1,154 +1,4 @@
extern "c" fn __error() *c_int;
pub const _errno = __error;
-pub extern "c" fn kqueue() c_int;
-pub extern "c" fn kevent(
- kq: c_int,
- changelist: [*]const Kevent,
- nchanges: c_int,
- eventlist: [*]Kevent,
- nevents: c_int,
- timeout: ?*const timespec,
-) c_int;
-pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
-pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
-pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int;
-pub extern "c" fn getdirentries(fd: c_int, buf_ptr: [*]u8, nbytes: usize, basep: *i64) usize;
pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize;
-pub extern "c" fn pipe2(arg0: *[2]c_int, arg1: u32) c_int;
-pub extern "c" fn preadv(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize;
-pub extern "c" fn pwritev(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize;
-pub extern "c" fn openat(fd: c_int, path: ?[*]const u8, flags: c_int) c_int;
-pub extern "c" fn setgid(ruid: c_uint, euid: c_uint) c_int;
-pub extern "c" fn setuid(uid: c_uint) c_int;
-pub extern "c" fn kill(pid: c_int, sig: c_int) c_int;
-pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int;
-pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int;
-
-/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
-pub const Kevent = extern struct {
- ident: usize,
- filter: i16,
- flags: u16,
- fflags: u32,
- data: i64,
- udata: usize,
- // TODO ext
-};
-
-pub const pthread_attr_t = extern struct {
- __size: [56]u8,
- __align: c_long,
-};
-
-pub const msghdr = extern struct {
- /// optional address
- msg_name: ?*sockaddr,
-
- /// size of address
- msg_namelen: socklen_t,
-
- /// scatter/gather array
- msg_iov: [*]iovec,
-
- /// # elements in msg_iov
- msg_iovlen: i32,
-
- /// ancillary data
- msg_control: ?*c_void,
-
- /// ancillary data buffer len
- msg_controllen: socklen_t,
-
- /// flags on received message
- msg_flags: i32,
-};
-
-pub const msghdr_const = extern struct {
- /// optional address
- msg_name: ?*const sockaddr,
-
- /// size of address
- msg_namelen: socklen_t,
-
- /// scatter/gather array
- msg_iov: [*]iovec_const,
-
- /// # elements in msg_iov
- msg_iovlen: i32,
-
- /// ancillary data
- msg_control: ?*c_void,
-
- /// ancillary data buffer len
- msg_controllen: socklen_t,
-
- /// flags on received message
- msg_flags: i32,
-};
-
-pub const Stat = extern struct {
- dev: u64,
- ino: u64,
- nlink: usize,
-
- mode: u16,
- __pad0: u16,
- uid: u32,
- gid: u32,
- __pad1: u32,
- rdev: u64,
-
- atim: timespec,
- mtim: timespec,
- ctim: timespec,
- birthtim: timespec,
-
- size: i64,
- blocks: i64,
- blksize: isize,
- flags: u32,
- gen: u64,
- __spare: [10]u64,
-};
-
-pub const timespec = extern struct {
- tv_sec: isize,
- tv_nsec: isize,
-};
-
-pub const dirent = extern struct {
- d_fileno: usize,
- d_off: i64,
- d_reclen: u16,
- d_type: u8,
- d_pad0: u8,
- d_namlen: u16,
- d_pad1: u16,
- d_name: [256]u8,
-};
-
-pub const in_port_t = u16;
-pub const sa_family_t = u16;
-
-pub const sockaddr = extern union {
- in: sockaddr_in,
- in6: sockaddr_in6,
-};
-
-pub const sockaddr_in = extern struct {
- len: u8,
- family: sa_family_t,
- port: in_port_t,
- addr: [16]u8,
- zero: [8]u8,
-};
-
-pub const sockaddr_in6 = extern struct {
- len: u8,
- family: sa_family_t,
- port: in_port_t,
- flowinfo: u32,
- addr: [16]u8,
- scope_id: u32,
-};
diff --git a/std/c/linux.zig b/std/c/linux.zig
index 48e359f361..9e028728c7 100644
--- a/std/c/linux.zig
+++ b/std/c/linux.zig
@@ -1,17 +1,27 @@
-const linux = @import("../os/linux.zig");
-pub use @import("../os/linux/errno.zig");
+const std = @import("../std.zig");
+use std.c;
-pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) c_int;
extern "c" fn __errno_location() *c_int;
pub const _errno = __errno_location;
-pub const pthread_attr_t = extern struct {
- __size: [56]u8,
- __align: c_long,
-};
+pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) c_int;
+pub extern "c" fn sched_getaffinity(pid: c_int, size: usize, set: *cpu_set_t) c_int;
+pub extern "c" fn eventfd(initval: c_uint, flags: c_uint) c_int;
+pub extern "c" fn epoll_ctl(epfd: fd_t, op: c_uint, fd: fd_t, event: *epoll_event) c_int;
+pub extern "c" fn epoll_create1(flags: c_uint) c_int;
+pub extern "c" fn epoll_wait(epfd: fd_t, events: [*]epoll_event, maxevents: c_uint, timeout: c_int) c_int;
+pub extern "c" fn epoll_pwait(
+ epfd: fd_t,
+ events: [*]epoll_event,
+ maxevents: c_int,
+ timeout: c_int,
+ sigmask: *const sigset_t,
+) c_int;
+pub extern "c" fn inotify_init1(flags: c_uint) c_int;
+pub extern "c" fn inotify_add_watch(fd: fd_t, pathname: [*]const u8, mask: u32) c_int;
/// See std.elf for constants for this
-pub extern fn getauxval(__type: c_ulong) c_ulong;
+pub extern "c" fn getauxval(__type: c_ulong) c_ulong;
-pub const dl_iterate_phdr_callback = extern fn (info: *linux.dl_phdr_info, size: usize, data: ?*c_void) c_int;
-pub extern fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int;
+pub const dl_iterate_phdr_callback = extern fn (info: *dl_phdr_info, size: usize, data: ?*c_void) c_int;
+pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int;
diff --git a/std/c/netbsd.zig b/std/c/netbsd.zig
index ef3da91bea..c677e1500b 100644
--- a/std/c/netbsd.zig
+++ b/std/c/netbsd.zig
@@ -1,150 +1,4 @@
extern "c" fn __errno() *c_int;
pub const _errno = __errno;
-pub extern "c" fn kqueue() c_int;
-pub extern "c" fn kevent(
- kq: c_int,
- changelist: [*]const Kevent,
- nchanges: c_int,
- eventlist: [*]Kevent,
- nevents: c_int,
- timeout: ?*const timespec,
-) c_int;
-pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
-pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
-pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int;
-pub extern "c" fn getdirentries(fd: c_int, buf_ptr: [*]u8, nbytes: usize, basep: *i64) usize;
pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize;
-pub extern "c" fn pipe2(arg0: *[2]c_int, arg1: u32) c_int;
-pub extern "c" fn preadv(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize;
-pub extern "c" fn pwritev(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize;
-pub extern "c" fn openat(fd: c_int, path: ?[*]const u8, flags: c_int) c_int;
-pub extern "c" fn setgid(ruid: c_uint, euid: c_uint) c_int;
-pub extern "c" fn setuid(uid: c_uint) c_int;
-pub extern "c" fn kill(pid: c_int, sig: c_int) c_int;
-pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int;
-pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int;
-
-/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
-pub const Kevent = extern struct {
- ident: usize,
- filter: i32,
- flags: u32,
- fflags: u32,
- data: i64,
- udata: usize,
-};
-
-pub const pthread_attr_t = extern struct {
- pta_magic: u32,
- pta_flags: c_int,
- pta_private: *c_void,
-};
-
-pub const msghdr = extern struct {
- /// optional address
- msg_name: ?*sockaddr,
-
- /// size of address
- msg_namelen: socklen_t,
-
- /// scatter/gather array
- msg_iov: [*]iovec,
-
- /// # elements in msg_iov
- msg_iovlen: i32,
-
- /// ancillary data
- msg_control: ?*c_void,
-
- /// ancillary data buffer len
- msg_controllen: socklen_t,
-
- /// flags on received message
- msg_flags: i32,
-};
-
-pub const msghdr_const = extern struct {
- /// optional address
- msg_name: ?*const sockaddr,
-
- /// size of address
- msg_namelen: socklen_t,
-
- /// scatter/gather array
- msg_iov: [*]iovec_const,
-
- /// # elements in msg_iov
- msg_iovlen: i32,
-
- /// ancillary data
- msg_control: ?*c_void,
-
- /// ancillary data buffer len
- msg_controllen: socklen_t,
-
- /// flags on received message
- msg_flags: i32,
-};
-
-pub const Stat = extern struct {
- dev: u64,
- mode: u32,
- ino: u64,
- nlink: usize,
-
- uid: u32,
- gid: u32,
- rdev: u64,
-
- atim: timespec,
- mtim: timespec,
- ctim: timespec,
- birthtim: timespec,
-
- size: i64,
- blocks: i64,
- blksize: isize,
- flags: u32,
- gen: u32,
- __spare: [2]u32,
-};
-
-pub const timespec = extern struct {
- tv_sec: i64,
- tv_nsec: isize,
-};
-
-pub const dirent = extern struct {
- d_fileno: u64,
- d_reclen: u16,
- d_namlen: u16,
- d_type: u8,
- d_off: i64,
- d_name: [512]u8,
-};
-
-pub const in_port_t = u16;
-pub const sa_family_t = u8;
-
-pub const sockaddr = extern union {
- in: sockaddr_in,
- in6: sockaddr_in6,
-};
-
-pub const sockaddr_in = extern struct {
- len: u8,
- family: sa_family_t,
- port: in_port_t,
- addr: u32,
- zero: [8]u8,
-};
-
-pub const sockaddr_in6 = extern struct {
- len: u8,
- family: sa_family_t,
- port: in_port_t,
- flowinfo: u32,
- addr: [16]u8,
- scope_id: u32,
-};
diff --git a/std/os/child_process.zig b/std/child_process.zig
index 3269e39c7a..1268f72c37 100644
--- a/std/os/child_process.zig
+++ b/std/child_process.zig
@@ -1,9 +1,11 @@
-const std = @import("../std.zig");
+const std = @import("std.zig");
const cstr = std.cstr;
const unicode = std.unicode;
const io = std.io;
+const fs = std.fs;
const os = std.os;
-const posix = os.posix;
+const process = std.process;
+const File = std.fs.File;
const windows = os.windows;
const mem = std.mem;
const debug = std.debug;
@@ -12,21 +14,18 @@ const Buffer = std.Buffer;
const builtin = @import("builtin");
const Os = builtin.Os;
const LinkedList = std.LinkedList;
-const windows_util = @import("windows/util.zig");
const maxInt = std.math.maxInt;
-const is_windows = builtin.os == Os.windows;
-
pub const ChildProcess = struct {
- pub pid: if (is_windows) void else i32,
- pub handle: if (is_windows) windows.HANDLE else void,
- pub thread_handle: if (is_windows) windows.HANDLE else void,
+ pub pid: if (os.windows.is_the_target) void else i32,
+ pub handle: if (os.windows.is_the_target) windows.HANDLE else void,
+ pub thread_handle: if (os.windows.is_the_target) windows.HANDLE else void,
pub allocator: *mem.Allocator,
- pub stdin: ?os.File,
- pub stdout: ?os.File,
- pub stderr: ?os.File,
+ pub stdin: ?File,
+ pub stdout: ?File,
+ pub stderr: ?File,
pub term: ?(SpawnError!Term),
@@ -40,41 +39,25 @@ pub const ChildProcess = struct {
pub stderr_behavior: StdIo,
/// Set to change the user id when spawning the child process.
- pub uid: if (is_windows) void else ?u32,
+ pub uid: if (os.windows.is_the_target) void else ?u32,
/// Set to change the group id when spawning the child process.
- pub gid: if (is_windows) void else ?u32,
+ pub gid: if (os.windows.is_the_target) void else ?u32,
/// Set to change the current working directory when spawning the child process.
pub cwd: ?[]const u8,
- err_pipe: if (is_windows) void else [2]i32,
- llnode: if (is_windows) void else LinkedList(*ChildProcess).Node,
-
- pub const SpawnError = error{
- ProcessFdQuotaExceeded,
- Unexpected,
- NotDir,
- SystemResources,
- FileNotFound,
- NameTooLong,
- SymLinkLoop,
- FileSystem,
- OutOfMemory,
- AccessDenied,
- PermissionDenied,
- InvalidUserId,
- ResourceLimitReached,
- InvalidExe,
- IsDir,
- FileBusy,
- };
+ err_pipe: if (os.windows.is_the_target) void else [2]os.fd_t,
+ llnode: if (os.windows.is_the_target) void else LinkedList(*ChildProcess).Node,
+
+ pub const SpawnError = error{OutOfMemory} || os.ExecveError || os.SetIdError ||
+ os.ChangeCurDirError || windows.CreateProcessError;
pub const Term = union(enum) {
- Exited: i32,
- Signal: i32,
- Stopped: i32,
- Unknown: i32,
+ Exited: u32,
+ Signal: u32,
+ Stopped: u32,
+ Unknown: u32,
};
pub const StdIo = enum {
@@ -99,10 +82,8 @@ pub const ChildProcess = struct {
.term = null,
.env_map = null,
.cwd = null,
- .uid = if (is_windows) {} else
- null,
- .gid = if (is_windows) {} else
- null,
+ .uid = if (os.windows.is_the_target) {} else null,
+ .gid = if (os.windows.is_the_target) {} else null,
.stdin = null,
.stdout = null,
.stderr = null,
@@ -122,7 +103,7 @@ pub const ChildProcess = struct {
/// On success must call `kill` or `wait`.
pub fn spawn(self: *ChildProcess) !void {
- if (is_windows) {
+ if (os.windows.is_the_target) {
return self.spawnWindows();
} else {
return self.spawnPosix();
@@ -136,7 +117,7 @@ pub const ChildProcess = struct {
/// Forcibly terminates child process and then cleans up all resources.
pub fn kill(self: *ChildProcess) !Term {
- if (is_windows) {
+ if (os.windows.is_the_target) {
return self.killWindows(1);
} else {
return self.killPosix();
@@ -149,12 +130,7 @@ pub const ChildProcess = struct {
return term;
}
- if (!windows.TerminateProcess(self.handle, exit_code)) {
- const err = windows.GetLastError();
- return switch (err) {
- else => os.unexpectedErrorWindows(err),
- };
- }
+ try windows.TerminateProcess(self.handle, exit_code);
try self.waitUnwrappedWindows();
return self.term.?;
}
@@ -164,23 +140,14 @@ pub const ChildProcess = struct {
self.cleanupStreams();
return term;
}
- const ret = posix.kill(self.pid, posix.SIGTERM);
- const err = posix.getErrno(ret);
- if (err > 0) {
- return switch (err) {
- posix.EINVAL => unreachable,
- posix.EPERM => error.PermissionDenied,
- posix.ESRCH => error.ProcessNotFound,
- else => os.unexpectedErrorPosix(err),
- };
- }
+ try os.kill(self.pid, os.SIGTERM);
self.waitUnwrapped();
return self.term.?;
}
/// Blocks until child process terminates and then cleans up all resources.
pub fn wait(self: *ChildProcess) !Term {
- if (is_windows) {
+ if (os.windows.is_the_target) {
return self.waitWindows();
} else {
return self.waitPosix();
@@ -188,7 +155,7 @@ pub const ChildProcess = struct {
}
pub const ExecResult = struct {
- term: os.ChildProcess.Term,
+ term: Term,
stdout: []u8,
stderr: []u8,
};
@@ -250,14 +217,14 @@ pub const ChildProcess = struct {
}
fn waitUnwrappedWindows(self: *ChildProcess) !void {
- const result = os.windowsWaitSingle(self.handle, windows.INFINITE);
+ const result = windows.WaitForSingleObject(self.handle, windows.INFINITE);
self.term = (SpawnError!Term)(x: {
var exit_code: windows.DWORD = undefined;
- if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) {
+ if (windows.kernel32.GetExitCodeProcess(self.handle, &exit_code) == 0) {
break :x Term{ .Unknown = 0 };
} else {
- break :x Term{ .Exited = @bitCast(i32, exit_code) };
+ break :x Term{ .Exited = exit_code };
}
});
@@ -268,22 +235,12 @@ pub const ChildProcess = struct {
}
fn waitUnwrapped(self: *ChildProcess) void {
- var status: i32 = undefined;
- while (true) {
- const err = posix.getErrno(posix.waitpid(self.pid, &status, 0));
- if (err > 0) {
- switch (err) {
- posix.EINTR => continue,
- else => unreachable,
- }
- }
- self.cleanupStreams();
- self.handleWaitResult(status);
- return;
- }
+ const status = os.waitpid(self.pid, 0);
+ self.cleanupStreams();
+ self.handleWaitResult(status);
}
- fn handleWaitResult(self: *ChildProcess, status: i32) void {
+ fn handleWaitResult(self: *ChildProcess, status: u32) void {
self.term = self.cleanupAfterWait(status);
}
@@ -302,7 +259,7 @@ pub const ChildProcess = struct {
}
}
- fn cleanupAfterWait(self: *ChildProcess, status: i32) !Term {
+ fn cleanupAfterWait(self: *ChildProcess, status: u32) !Term {
defer {
os.close(self.err_pipe[0]);
os.close(self.err_pipe[1]);
@@ -324,35 +281,35 @@ pub const ChildProcess = struct {
return statusToTerm(status);
}
- fn statusToTerm(status: i32) Term {
- return if (posix.WIFEXITED(status))
- Term{ .Exited = posix.WEXITSTATUS(status) }
- else if (posix.WIFSIGNALED(status))
- Term{ .Signal = posix.WTERMSIG(status) }
- else if (posix.WIFSTOPPED(status))
- Term{ .Stopped = posix.WSTOPSIG(status) }
+ fn statusToTerm(status: u32) Term {
+ return if (os.WIFEXITED(status))
+ Term{ .Exited = os.WEXITSTATUS(status) }
+ else if (os.WIFSIGNALED(status))
+ Term{ .Signal = os.WTERMSIG(status) }
+ else if (os.WIFSTOPPED(status))
+ Term{ .Stopped = os.WSTOPSIG(status) }
else
Term{ .Unknown = status };
}
fn spawnPosix(self: *ChildProcess) !void {
- const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try makePipe() else undefined;
+ const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try os.pipe() else undefined;
errdefer if (self.stdin_behavior == StdIo.Pipe) {
destroyPipe(stdin_pipe);
};
- const stdout_pipe = if (self.stdout_behavior == StdIo.Pipe) try makePipe() else undefined;
+ const stdout_pipe = if (self.stdout_behavior == StdIo.Pipe) try os.pipe() else undefined;
errdefer if (self.stdout_behavior == StdIo.Pipe) {
destroyPipe(stdout_pipe);
};
- const stderr_pipe = if (self.stderr_behavior == StdIo.Pipe) try makePipe() else undefined;
+ const stderr_pipe = if (self.stderr_behavior == StdIo.Pipe) try os.pipe() else undefined;
errdefer if (self.stderr_behavior == StdIo.Pipe) {
destroyPipe(stderr_pipe);
};
const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
- const dev_null_fd = if (any_ignore) try os.posixOpenC(c"/dev/null", posix.O_RDWR, 0) else undefined;
+ const dev_null_fd = if (any_ignore) try os.openC(c"/dev/null", os.O_RDWR, 0) else undefined;
defer {
if (any_ignore) os.close(dev_null_fd);
}
@@ -364,7 +321,7 @@ pub const ChildProcess = struct {
break :x env_map;
} else x: {
we_own_env_map = true;
- env_map_owned = try os.getEnvMap(self.allocator);
+ env_map_owned = try process.getEnvMap(self.allocator);
break :x &env_map_owned;
};
defer {
@@ -373,65 +330,58 @@ pub const ChildProcess = struct {
// This pipe is used to communicate errors between the time of fork
// and execve from the child process to the parent process.
- const err_pipe = try makePipe();
+ const err_pipe = try os.pipe();
errdefer destroyPipe(err_pipe);
- const pid_result = posix.fork();
- const pid_err = posix.getErrno(pid_result);
- if (pid_err > 0) {
- return switch (pid_err) {
- posix.EAGAIN, posix.ENOMEM, posix.ENOSYS => error.SystemResources,
- else => os.unexpectedErrorPosix(pid_err),
- };
- }
+ const pid_result = try os.fork();
if (pid_result == 0) {
// we are the child
- setUpChildIo(self.stdin_behavior, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
- setUpChildIo(self.stdout_behavior, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
- setUpChildIo(self.stderr_behavior, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
+ setUpChildIo(self.stdin_behavior, stdin_pipe[0], os.STDIN_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
+ setUpChildIo(self.stdout_behavior, stdout_pipe[1], os.STDOUT_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
+ setUpChildIo(self.stderr_behavior, stderr_pipe[1], os.STDERR_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
- if (self.stdin_behavior == StdIo.Pipe) {
+ if (self.stdin_behavior == .Pipe) {
os.close(stdin_pipe[0]);
os.close(stdin_pipe[1]);
}
- if (self.stdout_behavior == StdIo.Pipe) {
+ if (self.stdout_behavior == .Pipe) {
os.close(stdout_pipe[0]);
os.close(stdout_pipe[1]);
}
- if (self.stderr_behavior == StdIo.Pipe) {
+ if (self.stderr_behavior == .Pipe) {
os.close(stderr_pipe[0]);
os.close(stderr_pipe[1]);
}
if (self.cwd) |cwd| {
- os.changeCurDir(cwd) catch |err| forkChildErrReport(err_pipe[1], err);
+ os.chdir(cwd) catch |err| forkChildErrReport(err_pipe[1], err);
}
if (self.gid) |gid| {
- os.posix_setregid(gid, gid) catch |err| forkChildErrReport(err_pipe[1], err);
+ os.setregid(gid, gid) catch |err| forkChildErrReport(err_pipe[1], err);
}
if (self.uid) |uid| {
- os.posix_setreuid(uid, uid) catch |err| forkChildErrReport(err_pipe[1], err);
+ os.setreuid(uid, uid) catch |err| forkChildErrReport(err_pipe[1], err);
}
- os.posixExecve(self.argv, env_map, self.allocator) catch |err| forkChildErrReport(err_pipe[1], err);
+ os.execve(self.allocator, self.argv, env_map) catch |err| forkChildErrReport(err_pipe[1], err);
}
// we are the parent
const pid = @intCast(i32, pid_result);
if (self.stdin_behavior == StdIo.Pipe) {
- self.stdin = os.File.openHandle(stdin_pipe[1]);
+ self.stdin = File.openHandle(stdin_pipe[1]);
} else {
self.stdin = null;
}
if (self.stdout_behavior == StdIo.Pipe) {
- self.stdout = os.File.openHandle(stdout_pipe[0]);
+ self.stdout = File.openHandle(stdout_pipe[0]);
} else {
self.stdout = null;
}
if (self.stderr_behavior == StdIo.Pipe) {
- self.stderr = os.File.openHandle(stderr_pipe[0]);
+ self.stderr = File.openHandle(stderr_pipe[0]);
} else {
self.stderr = null;
}
@@ -462,7 +412,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 nul_handle = if (any_ignore) blk: {
- break :blk try os.windowsOpen("NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL);
+ break :blk try windows.CreateFile("NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ, null, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, null);
} else blk: {
break :blk undefined;
};
@@ -470,7 +420,7 @@ pub const ChildProcess = struct {
if (any_ignore) os.close(nul_handle);
}
if (any_ignore) {
- try windowsSetHandleInfo(nul_handle, windows.HANDLE_FLAG_INHERIT, 0);
+ try windows.SetHandleInformation(nul_handle, windows.HANDLE_FLAG_INHERIT, 0);
}
var g_hChildStd_IN_Rd: ?windows.HANDLE = null;
@@ -483,7 +433,7 @@ pub const ChildProcess = struct {
g_hChildStd_IN_Rd = nul_handle;
},
StdIo.Inherit => {
- g_hChildStd_IN_Rd = windows.GetStdHandle(windows.STD_INPUT_HANDLE);
+ g_hChildStd_IN_Rd = windows.GetStdHandle(windows.STD_INPUT_HANDLE) catch null;
},
StdIo.Close => {
g_hChildStd_IN_Rd = null;
@@ -503,7 +453,7 @@ pub const ChildProcess = struct {
g_hChildStd_OUT_Wr = nul_handle;
},
StdIo.Inherit => {
- g_hChildStd_OUT_Wr = windows.GetStdHandle(windows.STD_OUTPUT_HANDLE);
+ g_hChildStd_OUT_Wr = windows.GetStdHandle(windows.STD_OUTPUT_HANDLE) catch null;
},
StdIo.Close => {
g_hChildStd_OUT_Wr = null;
@@ -523,7 +473,7 @@ pub const ChildProcess = struct {
g_hChildStd_ERR_Wr = nul_handle;
},
StdIo.Inherit => {
- g_hChildStd_ERR_Wr = windows.GetStdHandle(windows.STD_ERROR_HANDLE);
+ g_hChildStd_ERR_Wr = windows.GetStdHandle(windows.STD_ERROR_HANDLE) catch null;
},
StdIo.Close => {
g_hChildStd_ERR_Wr = null;
@@ -565,7 +515,7 @@ pub const ChildProcess = struct {
defer if (cwd_w) |cwd| self.allocator.free(cwd);
const cwd_w_ptr = if (cwd_w) |cwd| cwd.ptr else null;
- const maybe_envp_buf = if (self.env_map) |env_map| try os.createWindowsEnvBlock(self.allocator, env_map) else null;
+ const maybe_envp_buf = if (self.env_map) |env_map| try createWindowsEnvBlock(self.allocator, env_map) else null;
defer if (maybe_envp_buf) |envp_buf| self.allocator.free(envp_buf);
const envp_ptr = if (maybe_envp_buf) |envp_buf| envp_buf.ptr else null;
@@ -573,7 +523,7 @@ pub const ChildProcess = struct {
// to match posix semantics
const app_name = x: {
if (self.cwd) |cwd| {
- const resolved = try os.path.resolve(self.allocator, [][]const u8{ cwd, self.argv[0] });
+ const resolved = try fs.path.resolve(self.allocator, [][]const u8{ cwd, self.argv[0] });
defer self.allocator.free(resolved);
break :x try cstr.addNullByte(self.allocator, resolved);
} else {
@@ -591,12 +541,12 @@ pub const ChildProcess = struct {
windowsCreateProcess(app_name_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo) catch |no_path_err| {
if (no_path_err != error.FileNotFound) return no_path_err;
- const PATH = try os.getEnvVarOwned(self.allocator, "PATH");
+ const PATH = try process.getEnvVarOwned(self.allocator, "PATH");
defer self.allocator.free(PATH);
var it = mem.tokenize(PATH, ";");
while (it.next()) |search_path| {
- const joined_path = try os.path.join(self.allocator, [][]const u8{ search_path, app_name });
+ const joined_path = try fs.path.join(self.allocator, [][]const u8{ search_path, app_name });
defer self.allocator.free(joined_path);
const joined_path_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, joined_path);
@@ -616,17 +566,17 @@ pub const ChildProcess = struct {
};
if (g_hChildStd_IN_Wr) |h| {
- self.stdin = os.File.openHandle(h);
+ self.stdin = File.openHandle(h);
} else {
self.stdin = null;
}
if (g_hChildStd_OUT_Rd) |h| {
- self.stdout = os.File.openHandle(h);
+ self.stdout = File.openHandle(h);
} else {
self.stdout = null;
}
if (g_hChildStd_ERR_Rd) |h| {
- self.stderr = os.File.openHandle(h);
+ self.stderr = File.openHandle(h);
} else {
self.stderr = null;
}
@@ -648,10 +598,10 @@ pub const ChildProcess = struct {
fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) !void {
switch (stdio) {
- StdIo.Pipe => try os.posixDup2(pipe_fd, std_fileno),
+ StdIo.Pipe => try os.dup2(pipe_fd, std_fileno),
StdIo.Close => os.close(std_fileno),
StdIo.Inherit => {},
- StdIo.Ignore => try os.posixDup2(dev_null_fd, std_fileno),
+ StdIo.Ignore => try os.dup2(dev_null_fd, std_fileno),
}
}
};
@@ -674,7 +624,7 @@ fn windowsCreateProcess(app_name: [*]u16, cmd_line: [*]u16, envp_ptr: ?[*]u16, c
// However this would imply that programs compiled with -DUNICODE could not pass
// environment variables to programs that were not, which seems unlikely.
// More investigation is needed.
- if (windows.CreateProcessW(
+ return windows.CreateProcessW(
app_name,
cmd_line,
null,
@@ -685,16 +635,7 @@ fn windowsCreateProcess(app_name: [*]u16, cmd_line: [*]u16, envp_ptr: ?[*]u16, c
cwd_ptr,
lpStartupInfo,
lpProcessInformation,
- ) == 0) {
- const err = windows.GetLastError();
- switch (err) {
- windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
- windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
- windows.ERROR.INVALID_PARAMETER => unreachable,
- windows.ERROR.INVALID_NAME => return error.InvalidName,
- else => return os.unexpectedErrorWindows(err),
- }
- }
+ );
}
/// Caller must dealloc.
@@ -740,61 +681,27 @@ fn windowsDestroyPipe(rd: ?windows.HANDLE, wr: ?windows.HANDLE) void {
if (wr) |h| os.close(h);
}
-// TODO: workaround for bug where the `const` from `&const` is dropped when the type is
-// a namespace field lookup
-const SECURITY_ATTRIBUTES = windows.SECURITY_ATTRIBUTES;
-
-fn windowsMakePipe(rd: *windows.HANDLE, wr: *windows.HANDLE, sattr: *const SECURITY_ATTRIBUTES) !void {
- if (windows.CreatePipe(rd, wr, sattr, 0) == 0) {
- const err = windows.GetLastError();
- return switch (err) {
- else => os.unexpectedErrorWindows(err),
- };
- }
-}
-
-fn windowsSetHandleInfo(h: windows.HANDLE, mask: windows.DWORD, flags: windows.DWORD) !void {
- if (windows.SetHandleInformation(h, mask, flags) == 0) {
- const err = windows.GetLastError();
- return switch (err) {
- else => os.unexpectedErrorWindows(err),
- };
- }
-}
-
-fn windowsMakePipeIn(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const SECURITY_ATTRIBUTES) !void {
+fn windowsMakePipeIn(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const windows.SECURITY_ATTRIBUTES) !void {
var rd_h: windows.HANDLE = undefined;
var wr_h: windows.HANDLE = undefined;
- try windowsMakePipe(&rd_h, &wr_h, sattr);
+ try windows.CreatePipe(&rd_h, &wr_h, sattr);
errdefer windowsDestroyPipe(rd_h, wr_h);
- try windowsSetHandleInfo(wr_h, windows.HANDLE_FLAG_INHERIT, 0);
+ try windows.SetHandleInformation(wr_h, windows.HANDLE_FLAG_INHERIT, 0);
rd.* = rd_h;
wr.* = wr_h;
}
-fn windowsMakePipeOut(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const SECURITY_ATTRIBUTES) !void {
+fn windowsMakePipeOut(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const windows.SECURITY_ATTRIBUTES) !void {
var rd_h: windows.HANDLE = undefined;
var wr_h: windows.HANDLE = undefined;
- try windowsMakePipe(&rd_h, &wr_h, sattr);
+ try windows.CreatePipe(&rd_h, &wr_h, sattr);
errdefer windowsDestroyPipe(rd_h, wr_h);
- try windowsSetHandleInfo(rd_h, windows.HANDLE_FLAG_INHERIT, 0);
+ try windows.SetHandleInformation(rd_h, windows.HANDLE_FLAG_INHERIT, 0);
rd.* = rd_h;
wr.* = wr_h;
}
-fn makePipe() ![2]i32 {
- var fds: [2]i32 = undefined;
- const err = posix.getErrno(posix.pipe(&fds));
- if (err > 0) {
- return switch (err) {
- posix.EMFILE, posix.ENFILE => error.SystemResources,
- else => os.unexpectedErrorPosix(err),
- };
- }
- return fds;
-}
-
-fn destroyPipe(pipe: [2]i32) void {
+fn destroyPipe(pipe: [2]os.fd_t) void {
os.close(pipe[0]);
os.close(pipe[1]);
}
@@ -803,17 +710,54 @@ fn destroyPipe(pipe: [2]i32) void {
// Then the child exits.
fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {
writeIntFd(fd, ErrInt(@errorToInt(err))) catch {};
- posix.exit(1);
+ os.exit(1);
}
const ErrInt = @IntType(false, @sizeOf(anyerror) * 8);
fn writeIntFd(fd: i32, value: ErrInt) !void {
- const stream = &os.File.openHandle(fd).outStream().stream;
+ const stream = &File.openHandle(fd).outStream().stream;
stream.writeIntNative(ErrInt, value) catch return error.SystemResources;
}
fn readIntFd(fd: i32) !ErrInt {
- const stream = &os.File.openHandle(fd).inStream().stream;
+ const stream = &File.openHandle(fd).inStream().stream;
return stream.readIntNative(ErrInt) catch return error.SystemResources;
}
+
+/// Caller must free result.
+pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u16 {
+ // count bytes needed
+ const max_chars_needed = x: {
+ var max_chars_needed: usize = 4; // 4 for the final 4 null bytes
+ var it = env_map.iterator();
+ while (it.next()) |pair| {
+ // +1 for '='
+ // +1 for null byte
+ max_chars_needed += pair.key.len + pair.value.len + 2;
+ }
+ break :x max_chars_needed;
+ };
+ const result = try allocator.alloc(u16, max_chars_needed);
+ errdefer allocator.free(result);
+
+ var it = env_map.iterator();
+ var i: usize = 0;
+ while (it.next()) |pair| {
+ i += try unicode.utf8ToUtf16Le(result[i..], pair.key);
+ result[i] = '=';
+ i += 1;
+ i += try unicode.utf8ToUtf16Le(result[i..], pair.value);
+ result[i] = 0;
+ i += 1;
+ }
+ result[i] = 0;
+ i += 1;
+ result[i] = 0;
+ i += 1;
+ result[i] = 0;
+ i += 1;
+ result[i] = 0;
+ i += 1;
+ return allocator.shrink(result, i);
+}
diff --git a/std/coff.zig b/std/coff.zig
index c31d2d8233..87f3f089de 100644
--- a/std/coff.zig
+++ b/std/coff.zig
@@ -3,6 +3,7 @@ const std = @import("std.zig");
const io = std.io;
const mem = std.mem;
const os = std.os;
+const File = std.fs.File;
const ArrayList = std.ArrayList;
@@ -28,7 +29,7 @@ pub const CoffError = error{
};
pub const Coff = struct {
- in_file: os.File,
+ in_file: File,
allocator: *mem.Allocator,
coff_header: CoffHeader,
@@ -77,7 +78,7 @@ pub const Coff = struct {
try self.loadOptionalHeader(&file_stream);
}
- fn loadOptionalHeader(self: *Coff, file_stream: *os.File.InStream) !void {
+ fn loadOptionalHeader(self: *Coff, file_stream: *File.InStream) !void {
const in = &file_stream.stream;
self.pe_header.magic = try in.readIntLittle(u16);
// For now we're only interested in finding the reference to the .pdb,
@@ -91,7 +92,7 @@ pub const Coff = struct {
} else
return error.InvalidPEMagic;
- try self.in_file.seekForward(skip_size);
+ try self.in_file.seekBy(skip_size);
const number_of_rva_and_sizes = try in.readIntLittle(u32);
if (number_of_rva_and_sizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
diff --git a/std/crypto.zig b/std/crypto.zig
index 2429441fc7..2b57de9e60 100644
--- a/std/crypto.zig
+++ b/std/crypto.zig
@@ -32,6 +32,9 @@ pub const chaCha20With64BitNonce = import_chaCha20.chaCha20With64BitNonce;
pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305;
pub const X25519 = @import("crypto/x25519.zig").X25519;
+const std = @import("std.zig");
+pub const randomBytes = std.os.getrandom;
+
test "crypto" {
_ = @import("crypto/blake2.zig");
_ = @import("crypto/chacha20.zig");
diff --git a/std/crypto/throughput_test.zig b/std/crypto/throughput_test.zig
index 73a2a86124..aee06571a0 100644
--- a/std/crypto/throughput_test.zig
+++ b/std/crypto/throughput_test.zig
@@ -1,6 +1,6 @@
const builtin = @import("builtin");
const std = @import("std");
-const time = std.os.time;
+const time = std.time;
const Timer = time.Timer;
const crypto = @import("../crypto.zig");
diff --git a/std/cstr.zig b/std/cstr.zig
index 49d6373732..dd28e50449 100644
--- a/std/cstr.zig
+++ b/std/cstr.zig
@@ -9,11 +9,6 @@ pub const line_sep = switch (builtin.os) {
else => "\n",
};
-/// Deprecated, use mem.len
-pub fn len(ptr: [*]const u8) usize {
- return mem.len(u8, ptr);
-}
-
pub fn cmp(a: [*]const u8, b: [*]const u8) i8 {
var index: usize = 0;
while (a[index] == b[index] and a[index] != 0) : (index += 1) {}
@@ -26,16 +21,6 @@ pub fn cmp(a: [*]const u8, b: [*]const u8) i8 {
}
}
-/// Deprecated, use mem.toSliceConst
-pub fn toSliceConst(str: [*]const u8) []const u8 {
- return mem.toSliceConst(u8, str);
-}
-
-/// Deprecated, use mem.toSlice
-pub fn toSlice(str: [*]u8) []u8 {
- return mem.toSlice(u8, str);
-}
-
test "cstr fns" {
comptime testCStrFnsImpl();
testCStrFnsImpl();
@@ -43,7 +28,7 @@ test "cstr fns" {
fn testCStrFnsImpl() void {
testing.expect(cmp(c"aoeu", c"aoez") == -1);
- testing.expect(len(c"123456789") == 9);
+ testing.expect(mem.len(u8, c"123456789") == 9);
}
/// Returns a mutable slice with 1 more byte of length which is a null byte.
diff --git a/std/debug.zig b/std/debug.zig
index 45abfda88e..e2f4a67755 100644
--- a/std/debug.zig
+++ b/std/debug.zig
@@ -3,15 +3,18 @@ const math = std.math;
const mem = std.mem;
const io = std.io;
const os = std.os;
+const fs = std.fs;
+const process = std.process;
const elf = std.elf;
const DW = std.dwarf;
const macho = std.macho;
const coff = std.coff;
const pdb = std.pdb;
-const windows = os.windows;
const ArrayList = std.ArrayList;
const builtin = @import("builtin");
const maxInt = std.math.maxInt;
+const File = std.fs.File;
+const windows = std.os.windows;
const leb = @import("debug/leb128.zig");
@@ -19,8 +22,8 @@ pub const FailingAllocator = @import("debug/failing_allocator.zig").FailingAlloc
pub const failing_allocator = &FailingAllocator.init(global_allocator, 0).allocator;
pub const runtime_safety = switch (builtin.mode) {
- builtin.Mode.Debug, builtin.Mode.ReleaseSafe => true,
- builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => false,
+ .Debug, .ReleaseSafe => true,
+ .ReleaseFast, .ReleaseSmall => false,
};
const Module = struct {
@@ -36,10 +39,10 @@ const Module = struct {
/// Tries to write to stderr, unbuffered, and ignores any error returned.
/// Does not append a newline.
-var stderr_file: os.File = undefined;
-var stderr_file_out_stream: os.File.OutStream = undefined;
+var stderr_file: File = undefined;
+var stderr_file_out_stream: File.OutStream = undefined;
-var stderr_stream: ?*io.OutStream(os.File.WriteError) = null;
+var stderr_stream: ?*io.OutStream(File.WriteError) = null;
var stderr_mutex = std.Mutex.init();
pub fn warn(comptime fmt: []const u8, args: ...) void {
const held = stderr_mutex.acquire();
@@ -48,7 +51,7 @@ pub fn warn(comptime fmt: []const u8, args: ...) void {
stderr.print(fmt, args) catch return;
}
-pub fn getStderrStream() !*io.OutStream(os.File.WriteError) {
+pub fn getStderrStream() !*io.OutStream(File.WriteError) {
if (stderr_stream) |st| {
return st;
} else {
@@ -75,13 +78,17 @@ pub fn getSelfDebugInfo() !*DebugInfo {
fn wantTtyColor() bool {
var bytes: [128]u8 = undefined;
const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
- return if (std.os.getEnvVarOwned(allocator, "ZIG_DEBUG_COLOR")) |_| true else |_| stderr_file.isTty();
+ return if (process.getEnvVarOwned(allocator, "ZIG_DEBUG_COLOR")) |_| true else |_| stderr_file.isTty();
}
/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
/// TODO multithreaded awareness
pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
const stderr = getStderrStream() catch return;
+ if (os.wasi.is_the_target) {
+ stderr.print("Unable to dump stack trace: unimplemented on WASI\n") catch return;
+ return;
+ }
const debug_info = getSelfDebugInfo() catch |err| {
stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
return;
@@ -99,47 +106,44 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
/// chopping off the irrelevant frames and shifting so that the returned addresses pointer
/// equals the passed in addresses pointer.
pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void {
- switch (builtin.os) {
- builtin.Os.windows => {
- const addrs = stack_trace.instruction_addresses;
- const u32_addrs_len = @intCast(u32, addrs.len);
- const first_addr = first_address orelse {
- stack_trace.index = windows.RtlCaptureStackBackTrace(
- 0,
- u32_addrs_len,
- @ptrCast(**c_void, addrs.ptr),
- null,
- );
- return;
- };
- var addr_buf_stack: [32]usize = undefined;
- const addr_buf = if (addr_buf_stack.len > addrs.len) addr_buf_stack[0..] else addrs;
- const n = windows.RtlCaptureStackBackTrace(0, u32_addrs_len, @ptrCast(**c_void, addr_buf.ptr), null);
- const first_index = for (addr_buf[0..n]) |addr, i| {
- if (addr == first_addr) {
- break i;
- }
- } else {
- stack_trace.index = 0;
+ if (windows.is_the_target) {
+ const addrs = stack_trace.instruction_addresses;
+ const u32_addrs_len = @intCast(u32, addrs.len);
+ const first_addr = first_address orelse {
+ stack_trace.index = windows.ntdll.RtlCaptureStackBackTrace(
+ 0,
+ u32_addrs_len,
+ @ptrCast(**c_void, addrs.ptr),
+ null,
+ );
+ return;
+ };
+ var addr_buf_stack: [32]usize = undefined;
+ const addr_buf = if (addr_buf_stack.len > addrs.len) addr_buf_stack[0..] else addrs;
+ const n = windows.ntdll.RtlCaptureStackBackTrace(0, u32_addrs_len, @ptrCast(**c_void, addr_buf.ptr), null);
+ const first_index = for (addr_buf[0..n]) |addr, i| {
+ if (addr == first_addr) {
+ break i;
+ }
+ } else {
+ stack_trace.index = 0;
+ return;
+ };
+ const slice = addr_buf[first_index..n];
+ // We use a for loop here because slice and addrs may alias.
+ for (slice) |addr, i| {
+ addrs[i] = addr;
+ }
+ stack_trace.index = slice.len;
+ } else {
+ var it = StackIterator.init(first_address);
+ for (stack_trace.instruction_addresses) |*addr, i| {
+ addr.* = it.next() orelse {
+ stack_trace.index = i;
return;
};
- const slice = addr_buf[first_index..n];
- // We use a for loop here because slice and addrs may alias.
- for (slice) |addr, i| {
- addrs[i] = addr;
- }
- stack_trace.index = slice.len;
- },
- else => {
- var it = StackIterator.init(first_address);
- for (stack_trace.instruction_addresses) |*addr, i| {
- addr.* = it.next() orelse {
- stack_trace.index = i;
- return;
- };
- }
- stack_trace.index = stack_trace.instruction_addresses.len;
- },
+ }
+ stack_trace.index = stack_trace.instruction_addresses.len;
}
}
@@ -147,6 +151,10 @@ pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace
/// TODO multithreaded awareness
pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void {
const stderr = getStderrStream() catch return;
+ if (os.wasi.is_the_target) {
+ stderr.print("Unable to dump stack trace: unimplemented on WASI\n") catch return;
+ return;
+ }
const debug_info = getSelfDebugInfo() catch |err| {
stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
return;
@@ -259,9 +267,8 @@ pub const StackIterator = struct {
};
pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {
- switch (builtin.os) {
- builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr),
- else => {},
+ if (windows.is_the_target) {
+ return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr);
}
var it = StackIterator.init(start_addr);
while (it.next()) |return_address| {
@@ -276,7 +283,7 @@ pub fn writeCurrentStackTraceWindows(
start_addr: ?usize,
) !void {
var addr_buf: [1024]usize = undefined;
- const n = windows.RtlCaptureStackBackTrace(0, addr_buf.len, @ptrCast(**c_void, &addr_buf), null);
+ const n = windows.ntdll.RtlCaptureStackBackTrace(0, addr_buf.len, @ptrCast(**c_void, &addr_buf), null);
const addrs = addr_buf[0..n];
var start_i: usize = if (start_addr) |saddr| blk: {
for (addrs) |addr, i| {
@@ -290,17 +297,18 @@ pub fn writeCurrentStackTraceWindows(
}
pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
- switch (builtin.os) {
- builtin.Os.macosx => return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color),
- builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color),
- builtin.Os.windows => return printSourceAtAddressWindows(debug_info, out_stream, address, tty_color),
- else => return error.UnsupportedOperatingSystem,
+ if (windows.is_the_target) {
+ return printSourceAtAddressWindows(debug_info, out_stream, address, tty_color);
}
+ if (os.darwin.is_the_target) {
+ return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color);
+ }
+ return printSourceAtAddressPosix(debug_info, out_stream, address, tty_color);
}
fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_address: usize, tty_color: bool) !void {
const allocator = getDebugInfoAllocator();
- const base_address = os.getBaseAddress();
+ const base_address = process.getBaseAddress();
const relative_address = relocated_address - base_address;
var coff_section: *coff.Section = undefined;
@@ -330,7 +338,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
const mod = &di.modules[mod_index];
try populateModule(di, mod);
- const obj_basename = os.path.basename(mod.obj_file_name);
+ const obj_basename = fs.path.basename(mod.obj_file_name);
var symbol_i: usize = 0;
const symbol_name = while (symbol_i != mod.symbols.len) {
@@ -510,7 +518,7 @@ const TtyColor = enum {
/// TODO this is a special case hack right now. clean it up and maybe make it part of std.fmt
fn setTtyColor(tty_color: TtyColor) void {
- if (os.supportsAnsiEscapeCodes(stderr_file.handle)) {
+ if (stderr_file.supportsAnsiEscapeCodes()) {
switch (tty_color) {
TtyColor.Red => {
stderr_file.write(RED) catch return;
@@ -540,29 +548,29 @@ fn setTtyColor(tty_color: TtyColor) void {
S.init_attrs = true;
var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
// TODO handle error
- _ = windows.GetConsoleScreenBufferInfo(stderr_file.handle, &info);
+ _ = windows.kernel32.GetConsoleScreenBufferInfo(stderr_file.handle, &info);
S.attrs = info.wAttributes;
}
// TODO handle errors
switch (tty_color) {
TtyColor.Red => {
- _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY);
+ _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY) catch {};
},
TtyColor.Green => {
- _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY);
+ _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY) catch {};
},
TtyColor.Cyan => {
- _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY);
+ _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY) catch {};
},
TtyColor.White, TtyColor.Bold => {
- _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY);
+ _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY) catch {};
},
TtyColor.Dim => {
- _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_INTENSITY);
+ _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_INTENSITY) catch {};
},
TtyColor.Reset => {
- _ = windows.SetConsoleTextAttribute(stderr_file.handle, S.attrs);
+ _ = windows.SetConsoleTextAttribute(stderr_file.handle, S.attrs) catch {};
},
}
}
@@ -633,7 +641,7 @@ fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const Mach
}
fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
- const base_addr = std.os.getBaseAddress();
+ const base_addr = process.getBaseAddress();
const adjusted_addr = 0x100000000 + (address - base_addr);
const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse {
@@ -648,7 +656,7 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt
const symbol_name = mem.toSliceConst(u8, di.strings.ptr + symbol.nlist.n_strx);
const compile_unit_name = if (symbol.ofile) |ofile| blk: {
const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx);
- break :blk os.path.basename(ofile_path);
+ break :blk fs.path.basename(ofile_path);
} else "???";
if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| {
defer line_info.deinit();
@@ -715,7 +723,7 @@ pub fn printSourceAtAddressDwarf(
}
}
-pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
+pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
return printSourceAtAddressDwarf(debug_info, out_stream, address, tty_color, printLineFromFileAnyOs);
}
@@ -775,16 +783,17 @@ pub const OpenSelfDebugInfoError = error{
};
pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo {
- switch (builtin.os) {
- builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => return openSelfDebugInfoLinux(allocator),
- builtin.Os.macosx, builtin.Os.ios => return openSelfDebugInfoMacOs(allocator),
- builtin.Os.windows => return openSelfDebugInfoWindows(allocator),
- else => return error.UnsupportedOperatingSystem,
+ if (windows.is_the_target) {
+ return openSelfDebugInfoWindows(allocator);
+ }
+ if (os.darwin.is_the_target) {
+ return openSelfDebugInfoMacOs(allocator);
}
+ return openSelfDebugInfoPosix(allocator);
}
fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
- const self_file = try os.openSelfExe();
+ const self_file = try fs.openSelfExe();
defer self_file.close();
const coff_obj = try allocator.create(coff.Coff);
@@ -811,7 +820,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
const len = try di.coff.getPdbPath(path_buf[0..]);
const raw_path = path_buf[0..len];
- const path = try os.path.resolve(allocator, [][]const u8{raw_path});
+ const path = try fs.path.resolve(allocator, [][]const u8{raw_path});
try di.pdb.openFile(di.coff, path);
@@ -893,7 +902,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
if (this_record_len % 4 != 0) {
const round_to_next_4 = (this_record_len | 0x3) + 1;
const march_forward_bytes = round_to_next_4 - this_record_len;
- try dbi.seekForward(march_forward_bytes);
+ try dbi.seekBy(@intCast(isize, march_forward_bytes));
this_record_len += march_forward_bytes;
}
@@ -1001,29 +1010,27 @@ pub fn openElfDebugInfo(
return di;
}
-fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DwarfInfo {
+fn openSelfDebugInfoPosix(allocator: *mem.Allocator) !DwarfInfo {
const S = struct {
- var self_exe_file: os.File = undefined;
+ var self_exe_file: File = undefined;
var self_exe_mmap_seekable: io.SliceSeekableInStream = undefined;
};
- S.self_exe_file = try os.openSelfExe();
+ S.self_exe_file = try fs.openSelfExe();
errdefer S.self_exe_file.close();
- const self_exe_mmap_len = try S.self_exe_file.getEndPos();
- const self_exe_mmap = os.posix.mmap(
+ const self_exe_mmap_len = mem.alignForward(try S.self_exe_file.getEndPos(), mem.page_size);
+ const self_exe_mmap = try os.mmap(
null,
self_exe_mmap_len,
- os.posix.PROT_READ,
- os.posix.MAP_SHARED,
+ os.PROT_READ,
+ os.MAP_SHARED,
S.self_exe_file.handle,
0,
);
- if (self_exe_mmap == os.posix.MAP_FAILED) return error.OutOfMemory;
- errdefer assert(os.posix.munmap(self_exe_mmap, self_exe_mmap_len) == 0);
+ errdefer os.munmap(self_exe_mmap);
- const file_mmap_slice = @intToPtr([*]const u8, self_exe_mmap)[0..self_exe_mmap_len];
- S.self_exe_mmap_seekable = io.SliceSeekableInStream.init(file_mmap_slice);
+ S.self_exe_mmap_seekable = io.SliceSeekableInStream.init(self_exe_mmap);
return openElfDebugInfo(
allocator,
@@ -1112,11 +1119,11 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
}
fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void {
- var f = try os.File.openRead(line_info.file_name);
+ var f = try File.openRead(line_info.file_name);
defer f.close();
// TODO fstat and make sure that the file has the correct size
- var buf: [os.page_size]u8 = undefined;
+ var buf: [mem.page_size]u8 = undefined;
var line: usize = 1;
var column: usize = 1;
var abs_index: usize = 0;
@@ -1195,7 +1202,7 @@ pub const DwarfInfo = struct {
};
pub const DebugInfo = switch (builtin.os) {
- builtin.Os.macosx, builtin.Os.ios => struct {
+ .macosx, .ios, .watchos, .tvos => struct {
symbols: []const MachoSymbol,
strings: []const u8,
ofiles: OFileTable,
@@ -1211,13 +1218,13 @@ pub const DebugInfo = switch (builtin.os) {
return self.ofiles.allocator;
}
},
- builtin.Os.uefi, builtin.Os.windows => struct {
+ .uefi, .windows => struct {
pdb: pdb.Pdb,
coff: *coff.Coff,
sect_contribs: []pdb.SectionContribEntry,
modules: []Module,
},
- builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => DwarfInfo,
+ .linux, .freebsd, .netbsd => DwarfInfo,
else => @compileError("Unsupported OS"),
};
@@ -1411,7 +1418,7 @@ const LineNumberProgram = struct {
return error.InvalidDebugInfo;
} else
self.include_dirs[file_entry.dir_index];
- const file_name = try os.path.join(self.file_entries.allocator, [][]const u8{ dir_name, file_entry.file_name });
+ const file_name = try fs.path.join(self.file_entries.allocator, [][]const u8{ dir_name, file_entry.file_name });
errdefer self.file_entries.allocator.free(file_name);
return LineInfo{
.line = if (self.prev_line >= 0) @intCast(u64, self.prev_line) else 0,
@@ -1938,7 +1945,7 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr
},
else => {
const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
- try di.dwarf_seekable_stream.seekForward(fwd_amt);
+ try di.dwarf_seekable_stream.seekBy(fwd_amt);
},
}
} else if (opcode >= opcode_base) {
@@ -1990,7 +1997,7 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr
else => {
if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
const len_bytes = standard_opcode_lengths[opcode - 1];
- try di.dwarf_seekable_stream.seekForward(len_bytes);
+ try di.dwarf_seekable_stream.seekBy(len_bytes);
},
}
}
diff --git a/std/dynamic_library.zig b/std/dynamic_library.zig
index 57122fd69c..3ae3b4c66a 100644
--- a/std/dynamic_library.zig
+++ b/std/dynamic_library.zig
@@ -1,21 +1,17 @@
const builtin = @import("builtin");
-const Os = builtin.Os;
const std = @import("std.zig");
const mem = std.mem;
-const cstr = std.cstr;
const os = std.os;
const assert = std.debug.assert;
const testing = std.testing;
const elf = std.elf;
-const linux = os.linux;
-const windows = os.windows;
-const win_util = @import("os/windows/util.zig");
+const windows = std.os.windows;
const maxInt = std.math.maxInt;
pub const DynLib = switch (builtin.os) {
- Os.linux => LinuxDynLib,
- Os.windows => WindowsDynLib,
+ .linux => LinuxDynLib,
+ .windows => WindowsDynLib,
else => void,
};
@@ -105,39 +101,35 @@ pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator {
pub const LinuxDynLib = struct {
elf_lib: ElfLib,
fd: i32,
- map_addr: usize,
- map_size: usize,
+ memory: []align(mem.page_size) u8,
/// Trusts the file
pub fn open(allocator: *mem.Allocator, path: []const u8) !DynLib {
- const fd = try std.os.posixOpen(path, 0, linux.O_RDONLY | linux.O_CLOEXEC);
- errdefer std.os.close(fd);
+ const fd = try os.open(path, 0, os.O_RDONLY | os.O_CLOEXEC);
+ errdefer os.close(fd);
- const size = @intCast(usize, (try std.os.posixFStat(fd)).size);
+ const size = @intCast(usize, (try os.fstat(fd)).size);
- const addr = linux.mmap(
+ const bytes = try os.mmap(
null,
size,
- linux.PROT_READ | linux.PROT_EXEC,
- linux.MAP_PRIVATE | linux.MAP_LOCKED,
+ os.PROT_READ | os.PROT_EXEC,
+ os.MAP_PRIVATE | os.MAP_LOCKED,
fd,
0,
);
- errdefer _ = linux.munmap(addr, size);
-
- const bytes = @intToPtr([*]align(std.os.page_size) u8, addr)[0..size];
+ errdefer os.munmap(bytes);
return DynLib{
.elf_lib = try ElfLib.init(bytes),
.fd = fd,
- .map_addr = addr,
- .map_size = size,
+ .memory = bytes,
};
}
pub fn close(self: *DynLib) void {
- _ = linux.munmap(self.map_addr, self.map_size);
- std.os.close(self.fd);
+ os.munmap(self.memory);
+ os.close(self.fd);
self.* = undefined;
}
@@ -149,7 +141,7 @@ pub const LinuxDynLib = struct {
pub const ElfLib = struct {
strings: [*]u8,
syms: [*]elf.Sym,
- hashtab: [*]linux.Elf_Symndx,
+ hashtab: [*]os.Elf_Symndx,
versym: ?[*]u16,
verdef: ?*elf.Verdef,
base: usize,
@@ -184,7 +176,7 @@ pub const ElfLib = struct {
var maybe_strings: ?[*]u8 = null;
var maybe_syms: ?[*]elf.Sym = null;
- var maybe_hashtab: ?[*]linux.Elf_Symndx = null;
+ var maybe_hashtab: ?[*]os.Elf_Symndx = null;
var maybe_versym: ?[*]u16 = null;
var maybe_verdef: ?*elf.Verdef = null;
@@ -195,7 +187,7 @@ pub const ElfLib = struct {
switch (dynv[i]) {
elf.DT_STRTAB => maybe_strings = @intToPtr([*]u8, p),
elf.DT_SYMTAB => maybe_syms = @intToPtr([*]elf.Sym, p),
- elf.DT_HASH => maybe_hashtab = @intToPtr([*]linux.Elf_Symndx, p),
+ elf.DT_HASH => maybe_hashtab = @intToPtr([*]os.Elf_Symndx, p),
elf.DT_VERSYM => maybe_versym = @intToPtr([*]u16, p),
elf.DT_VERDEF => maybe_verdef = @intToPtr(*elf.Verdef, p),
else => {},
@@ -225,7 +217,7 @@ pub const ElfLib = struct {
if (0 == (u32(1) << @intCast(u5, self.syms[i].st_info & 0xf) & OK_TYPES)) continue;
if (0 == (u32(1) << @intCast(u5, self.syms[i].st_info >> 4) & OK_BINDS)) continue;
if (0 == self.syms[i].st_shndx) continue;
- if (!mem.eql(u8, name, cstr.toSliceConst(self.strings + self.syms[i].st_name))) continue;
+ if (!mem.eql(u8, name, mem.toSliceConst(u8, self.strings + self.syms[i].st_name))) continue;
if (maybe_versym) |versym| {
if (!checkver(self.verdef.?, versym[i], vername, self.strings))
continue;
@@ -248,7 +240,7 @@ fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [
def = @intToPtr(*elf.Verdef, @ptrToInt(def) + def.vd_next);
}
const aux = @intToPtr(*elf.Verdaux, @ptrToInt(def) + def.vd_aux);
- return mem.eql(u8, vername, cstr.toSliceConst(strings + aux.vda_name));
+ return mem.eql(u8, vername, mem.toSliceConst(u8, strings + aux.vda_name));
}
pub const WindowsDynLib = struct {
@@ -256,36 +248,28 @@ pub const WindowsDynLib = struct {
dll: windows.HMODULE,
pub fn open(allocator: *mem.Allocator, path: []const u8) !WindowsDynLib {
- const wpath = try win_util.sliceToPrefixedFileW(path);
+ const wpath = try windows.sliceToPrefixedFileW(path);
return WindowsDynLib{
.allocator = allocator,
- .dll = windows.LoadLibraryW(&wpath) orelse {
- const err = windows.GetLastError();
- switch (err) {
- windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
- windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
- windows.ERROR.MOD_NOT_FOUND => return error.FileNotFound,
- else => return os.unexpectedErrorWindows(err),
- }
- },
+ .dll = try windows.LoadLibraryW(&wpath),
};
}
pub fn close(self: *WindowsDynLib) void {
- assert(windows.FreeLibrary(self.dll) != 0);
+ windows.FreeLibrary(self.dll);
self.* = undefined;
}
pub fn lookup(self: *WindowsDynLib, name: []const u8) ?usize {
- return @ptrToInt(windows.GetProcAddress(self.dll, name.ptr));
+ return @ptrToInt(windows.kernel32.GetProcAddress(self.dll, name.ptr));
}
};
test "dynamic_library" {
const libname = switch (builtin.os) {
- Os.linux => "invalid_so.so",
- Os.windows => "invalid_dll.dll",
+ .linux => "invalid_so.so",
+ .windows => "invalid_dll.dll",
else => return,
};
diff --git a/std/elf.zig b/std/elf.zig
index 39617d3cf4..c605a177a5 100644
--- a/std/elf.zig
+++ b/std/elf.zig
@@ -6,6 +6,7 @@ const math = std.math;
const mem = std.mem;
const debug = std.debug;
const InStream = std.stream.InStream;
+const File = std.fs.File;
pub const AT_NULL = 0;
pub const AT_IGNORE = 1;
@@ -367,7 +368,7 @@ pub const Elf = struct {
string_section: *SectionHeader,
section_headers: []SectionHeader,
allocator: *mem.Allocator,
- prealloc_file: os.File,
+ prealloc_file: File,
/// Call close when done.
pub fn openPath(elf: *Elf, allocator: *mem.Allocator, path: []const u8) !void {
@@ -375,7 +376,7 @@ pub const Elf = struct {
}
/// Call close when done.
- pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: os.File) !void {
+ pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: File) !void {
@compileError("TODO implement");
}
@@ -410,7 +411,7 @@ pub const Elf = struct {
if (version_byte != 1) return error.InvalidFormat;
// skip over padding
- try seekable_stream.seekForward(9);
+ try seekable_stream.seekBy(9);
elf.file_type = switch (try in.readInt(u16, elf.endian)) {
1 => FileType.Relocatable,
@@ -447,7 +448,7 @@ pub const Elf = struct {
}
// skip over flags
- try seekable_stream.seekForward(4);
+ try seekable_stream.seekBy(4);
const header_size = try in.readInt(u16, elf.endian);
if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) {
diff --git a/std/event/fs.zig b/std/event/fs.zig
index 9756d15a76..55731a607c 100644
--- a/std/event/fs.zig
+++ b/std/event/fs.zig
@@ -5,9 +5,10 @@ const assert = std.debug.assert;
const testing = std.testing;
const os = std.os;
const mem = std.mem;
-const posix = os.posix;
const windows = os.windows;
const Loop = event.Loop;
+const fd_t = os.fd_t;
+const File = std.fs.File;
pub const RequestNode = std.atomic.Queue(Request).Node;
@@ -30,53 +31,53 @@ pub const Request = struct {
End, // special - means the fs thread should exit
pub const PWriteV = struct {
- fd: os.FileHandle,
- iov: []const os.posix.iovec_const,
+ fd: fd_t,
+ iov: []const os.iovec_const,
offset: usize,
result: Error!void,
- pub const Error = os.PosixWriteError;
+ pub const Error = os.WriteError;
};
pub const PReadV = struct {
- fd: os.FileHandle,
- iov: []const os.posix.iovec,
+ fd: fd_t,
+ iov: []const os.iovec,
offset: usize,
result: Error!usize,
- pub const Error = os.PosixReadError;
+ pub const Error = os.ReadError;
};
pub const Open = struct {
/// must be null terminated. TODO https://github.com/ziglang/zig/issues/265
path: []const u8,
flags: u32,
- mode: os.File.Mode,
- result: Error!os.FileHandle,
+ mode: File.Mode,
+ result: Error!fd_t,
- pub const Error = os.File.OpenError;
+ pub const Error = File.OpenError;
};
pub const WriteFile = struct {
/// must be null terminated. TODO https://github.com/ziglang/zig/issues/265
path: []const u8,
contents: []const u8,
- mode: os.File.Mode,
+ mode: File.Mode,
result: Error!void,
- pub const Error = os.File.OpenError || os.File.WriteError;
+ pub const Error = File.OpenError || File.WriteError;
};
pub const Close = struct {
- fd: os.FileHandle,
+ fd: fd_t,
};
};
};
-pub const PWriteVError = error{OutOfMemory} || os.File.WriteError;
+pub const PWriteVError = error{OutOfMemory} || File.WriteError;
/// data - just the inner references - must live until pwritev promise completes.
-pub async fn pwritev(loop: *Loop, fd: os.FileHandle, data: []const []const u8, offset: usize) PWriteVError!void {
+pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: usize) PWriteVError!void {
// workaround for https://github.com/ziglang/zig/issues/1194
suspend {
resume @handle();
@@ -87,11 +88,11 @@ pub async fn pwritev(loop: *Loop, fd: os.FileHandle, data: []const []const u8, o
builtin.Os.freebsd,
builtin.Os.netbsd,
=> {
- const iovecs = try loop.allocator.alloc(os.posix.iovec_const, data.len);
+ const iovecs = try loop.allocator.alloc(os.iovec_const, data.len);
defer loop.allocator.free(iovecs);
for (data) |buf, i| {
- iovecs[i] = os.posix.iovec_const{
+ iovecs[i] = os.iovec_const{
.iov_base = buf.ptr,
.iov_len = buf.len,
};
@@ -109,7 +110,7 @@ pub async fn pwritev(loop: *Loop, fd: os.FileHandle, data: []const []const u8, o
}
/// data must outlive the returned promise
-pub async fn pwritevWindows(loop: *Loop, fd: os.FileHandle, data: []const []const u8, offset: usize) os.WindowsWriteError!void {
+pub async fn pwritevWindows(loop: *Loop, fd: fd_t, data: []const []const u8, offset: usize) os.WindowsWriteError!void {
if (data.len == 0) return;
if (data.len == 1) return await (async pwriteWindows(loop, fd, data[0], offset) catch unreachable);
@@ -121,7 +122,7 @@ pub async fn pwritevWindows(loop: *Loop, fd: os.FileHandle, data: []const []cons
}
}
-pub async fn pwriteWindows(loop: *Loop, fd: os.FileHandle, data: []const u8, offset: u64) os.WindowsWriteError!void {
+pub async fn pwriteWindows(loop: *Loop, fd: fd_t, data: []const u8, offset: u64) os.WindowsWriteError!void {
// workaround for https://github.com/ziglang/zig/issues/1194
suspend {
resume @handle();
@@ -146,33 +147,32 @@ pub async fn pwriteWindows(loop: *Loop, fd: os.FileHandle, data: []const u8, off
errdefer loop.finishOneEvent();
errdefer {
- _ = windows.CancelIoEx(fd, &resume_node.base.overlapped);
+ _ = windows.kernel32.CancelIoEx(fd, &resume_node.base.overlapped);
}
suspend {
- _ = windows.WriteFile(fd, data.ptr, @intCast(windows.DWORD, data.len), null, &resume_node.base.overlapped);
+ _ = windows.kernel32.WriteFile(fd, data.ptr, @intCast(windows.DWORD, data.len), null, &resume_node.base.overlapped);
}
var bytes_transferred: windows.DWORD = undefined;
- if (windows.GetOverlappedResult(fd, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {
- const err = windows.GetLastError();
- return switch (err) {
+ if (windows.kernel32.GetOverlappedResult(fd, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {
+ switch (windows.kernel32.GetLastError()) {
windows.ERROR.IO_PENDING => unreachable,
- windows.ERROR.INVALID_USER_BUFFER => error.SystemResources,
- windows.ERROR.NOT_ENOUGH_MEMORY => error.SystemResources,
- windows.ERROR.OPERATION_ABORTED => error.OperationAborted,
- windows.ERROR.NOT_ENOUGH_QUOTA => error.SystemResources,
- windows.ERROR.BROKEN_PIPE => error.BrokenPipe,
- else => os.unexpectedErrorWindows(err),
- };
+ windows.ERROR.INVALID_USER_BUFFER => return error.SystemResources,
+ windows.ERROR.NOT_ENOUGH_MEMORY => return error.SystemResources,
+ windows.ERROR.OPERATION_ABORTED => return error.OperationAborted,
+ windows.ERROR.NOT_ENOUGH_QUOTA => return error.SystemResources,
+ windows.ERROR.BROKEN_PIPE => return error.BrokenPipe,
+ else => |err| return windows.unexpectedError(err),
+ }
}
}
/// iovecs must live until pwritev promise completes.
pub async fn pwritevPosix(
loop: *Loop,
- fd: os.FileHandle,
- iovecs: []const posix.iovec_const,
+ fd: fd_t,
+ iovecs: []const os.iovec_const,
offset: usize,
-) os.PosixWriteError!void {
+) os.WriteError!void {
// workaround for https://github.com/ziglang/zig/issues/1194
suspend {
resume @handle();
@@ -209,10 +209,10 @@ pub async fn pwritevPosix(
return req_node.data.msg.PWriteV.result;
}
-pub const PReadVError = error{OutOfMemory} || os.File.ReadError;
+pub const PReadVError = error{OutOfMemory} || File.ReadError;
/// data - just the inner references - must live until preadv promise completes.
-pub async fn preadv(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset: usize) PReadVError!usize {
+pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PReadVError!usize {
// workaround for https://github.com/ziglang/zig/issues/1194
suspend {
resume @handle();
@@ -225,11 +225,11 @@ pub async fn preadv(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset:
builtin.Os.freebsd,
builtin.Os.netbsd,
=> {
- const iovecs = try loop.allocator.alloc(os.posix.iovec, data.len);
+ const iovecs = try loop.allocator.alloc(os.iovec, data.len);
defer loop.allocator.free(iovecs);
for (data) |buf, i| {
- iovecs[i] = os.posix.iovec{
+ iovecs[i] = os.iovec{
.iov_base = buf.ptr,
.iov_len = buf.len,
};
@@ -247,7 +247,7 @@ pub async fn preadv(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset:
}
/// data must outlive the returned promise
-pub async fn preadvWindows(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset: u64) os.WindowsReadError!usize {
+pub async fn preadvWindows(loop: *Loop, fd: fd_t, data: []const []u8, offset: u64) !usize {
assert(data.len != 0);
if (data.len == 1) return await (async preadWindows(loop, fd, data[0], offset) catch unreachable);
@@ -271,7 +271,7 @@ pub async fn preadvWindows(loop: *Loop, fd: os.FileHandle, data: []const []u8, o
}
}
-pub async fn preadWindows(loop: *Loop, fd: os.FileHandle, data: []u8, offset: u64) !usize {
+pub async fn preadWindows(loop: *Loop, fd: fd_t, data: []u8, offset: u64) !usize {
// workaround for https://github.com/ziglang/zig/issues/1194
suspend {
resume @handle();
@@ -291,25 +291,24 @@ pub async fn preadWindows(loop: *Loop, fd: os.FileHandle, data: []u8, offset: u6
},
};
// TODO only call create io completion port once per fd
- _ = windows.CreateIoCompletionPort(fd, loop.os_data.io_port, undefined, undefined);
+ _ = windows.CreateIoCompletionPort(fd, loop.os_data.io_port, undefined, undefined) catch undefined;
loop.beginOneEvent();
errdefer loop.finishOneEvent();
errdefer {
- _ = windows.CancelIoEx(fd, &resume_node.base.overlapped);
+ _ = windows.kernel32.CancelIoEx(fd, &resume_node.base.overlapped);
}
suspend {
- _ = windows.ReadFile(fd, data.ptr, @intCast(windows.DWORD, data.len), null, &resume_node.base.overlapped);
+ _ = windows.kernel32.ReadFile(fd, data.ptr, @intCast(windows.DWORD, data.len), null, &resume_node.base.overlapped);
}
var bytes_transferred: windows.DWORD = undefined;
- if (windows.GetOverlappedResult(fd, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {
- const err = windows.GetLastError();
- switch (err) {
+ if (windows.kernel32.GetOverlappedResult(fd, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {
+ switch (windows.kernel32.GetLastError()) {
windows.ERROR.IO_PENDING => unreachable,
windows.ERROR.OPERATION_ABORTED => return error.OperationAborted,
windows.ERROR.BROKEN_PIPE => return error.BrokenPipe,
windows.ERROR.HANDLE_EOF => return usize(bytes_transferred),
- else => return os.unexpectedErrorWindows(err),
+ else => |err| return windows.unexpectedError(err),
}
}
return usize(bytes_transferred);
@@ -318,10 +317,10 @@ pub async fn preadWindows(loop: *Loop, fd: os.FileHandle, data: []u8, offset: u6
/// iovecs must live until preadv promise completes
pub async fn preadvPosix(
loop: *Loop,
- fd: os.FileHandle,
- iovecs: []const posix.iovec,
+ fd: fd_t,
+ iovecs: []const os.iovec,
offset: usize,
-) os.PosixReadError!usize {
+) os.ReadError!usize {
// workaround for https://github.com/ziglang/zig/issues/1194
suspend {
resume @handle();
@@ -362,8 +361,8 @@ pub async fn openPosix(
loop: *Loop,
path: []const u8,
flags: u32,
- mode: os.File.Mode,
-) os.File.OpenError!os.FileHandle {
+ mode: File.Mode,
+) File.OpenError!fd_t {
// workaround for https://github.com/ziglang/zig/issues/1194
suspend {
resume @handle();
@@ -402,19 +401,21 @@ pub async fn openPosix(
return req_node.data.msg.Open.result;
}
-pub async fn openRead(loop: *Loop, path: []const u8) os.File.OpenError!os.FileHandle {
+pub async fn openRead(loop: *Loop, path: []const u8) File.OpenError!fd_t {
switch (builtin.os) {
builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {
- const flags = posix.O_LARGEFILE | posix.O_RDONLY | posix.O_CLOEXEC;
- return await (async openPosix(loop, path, flags, os.File.default_mode) catch unreachable);
+ const flags = os.O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC;
+ return await (async openPosix(loop, path, flags, File.default_mode) catch unreachable);
},
- builtin.Os.windows => return os.windowsOpen(
+ builtin.Os.windows => return windows.CreateFile(
path,
windows.GENERIC_READ,
windows.FILE_SHARE_READ,
+ null,
windows.OPEN_EXISTING,
windows.FILE_ATTRIBUTE_NORMAL | windows.FILE_FLAG_OVERLAPPED,
+ null,
),
else => @compileError("Unsupported OS"),
@@ -423,27 +424,29 @@ pub async fn openRead(loop: *Loop, path: []const u8) os.File.OpenError!os.FileHa
/// Creates if does not exist. Truncates the file if it exists.
/// Uses the default mode.
-pub async fn openWrite(loop: *Loop, path: []const u8) os.File.OpenError!os.FileHandle {
- return await (async openWriteMode(loop, path, os.File.default_mode) catch unreachable);
+pub async fn openWrite(loop: *Loop, path: []const u8) File.OpenError!fd_t {
+ return await (async openWriteMode(loop, path, File.default_mode) catch unreachable);
}
/// Creates if does not exist. Truncates the file if it exists.
-pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: os.File.Mode) os.File.OpenError!os.FileHandle {
+pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: File.Mode) File.OpenError!fd_t {
switch (builtin.os) {
builtin.Os.macosx,
builtin.Os.linux,
builtin.Os.freebsd,
builtin.Os.netbsd,
=> {
- const flags = posix.O_LARGEFILE | posix.O_WRONLY | posix.O_CREAT | posix.O_CLOEXEC | posix.O_TRUNC;
- return await (async openPosix(loop, path, flags, os.File.default_mode) catch unreachable);
+ const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_TRUNC;
+ return await (async openPosix(loop, path, flags, File.default_mode) catch unreachable);
},
- builtin.Os.windows => return os.windowsOpen(
+ builtin.Os.windows => return windows.CreateFile(
path,
windows.GENERIC_WRITE,
windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
+ null,
windows.CREATE_ALWAYS,
windows.FILE_ATTRIBUTE_NORMAL | windows.FILE_FLAG_OVERLAPPED,
+ null,
),
else => @compileError("Unsupported OS"),
}
@@ -453,20 +456,22 @@ pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: os.File.Mode) os
pub async fn openReadWrite(
loop: *Loop,
path: []const u8,
- mode: os.File.Mode,
-) os.File.OpenError!os.FileHandle {
+ mode: File.Mode,
+) File.OpenError!fd_t {
switch (builtin.os) {
builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {
- const flags = posix.O_LARGEFILE | posix.O_RDWR | posix.O_CREAT | posix.O_CLOEXEC;
+ const flags = os.O_LARGEFILE | os.O_RDWR | os.O_CREAT | os.O_CLOEXEC;
return await (async openPosix(loop, path, flags, mode) catch unreachable);
},
- builtin.Os.windows => return os.windowsOpen(
+ builtin.Os.windows => return windows.CreateFile(
path,
windows.GENERIC_WRITE | windows.GENERIC_READ,
windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
+ null,
windows.OPEN_ALWAYS,
windows.FILE_ATTRIBUTE_NORMAL | windows.FILE_FLAG_OVERLAPPED,
+ null,
),
else => @compileError("Unsupported OS"),
@@ -487,7 +492,7 @@ pub const CloseOperation = struct {
builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => OsDataPosix,
builtin.Os.windows => struct {
- handle: ?os.FileHandle,
+ handle: ?fd_t,
},
else => @compileError("Unsupported OS"),
@@ -551,7 +556,7 @@ pub const CloseOperation = struct {
}
}
- pub fn setHandle(self: *CloseOperation, handle: os.FileHandle) void {
+ pub fn setHandle(self: *CloseOperation, handle: fd_t) void {
switch (builtin.os) {
builtin.Os.linux,
builtin.Os.macosx,
@@ -585,7 +590,7 @@ pub const CloseOperation = struct {
}
}
- pub fn getHandle(self: *CloseOperation) os.FileHandle {
+ pub fn getHandle(self: *CloseOperation) fd_t {
switch (builtin.os) {
builtin.Os.linux,
builtin.Os.macosx,
@@ -606,11 +611,11 @@ pub const CloseOperation = struct {
/// contents must remain alive until writeFile completes.
/// TODO make this atomic or provide writeFileAtomic and rename this one to writeFileTruncate
pub async fn writeFile(loop: *Loop, path: []const u8, contents: []const u8) !void {
- return await (async writeFileMode(loop, path, contents, os.File.default_mode) catch unreachable);
+ return await (async writeFileMode(loop, path, contents, File.default_mode) catch unreachable);
}
/// contents must remain alive until writeFile completes.
-pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8, mode: os.File.Mode) !void {
+pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8, mode: File.Mode) !void {
switch (builtin.os) {
builtin.Os.linux,
builtin.Os.macosx,
@@ -623,19 +628,21 @@ pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8,
}
async fn writeFileWindows(loop: *Loop, path: []const u8, contents: []const u8) !void {
- const handle = try os.windowsOpen(
+ const handle = try windows.CreateFile(
path,
windows.GENERIC_WRITE,
windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
+ null,
windows.CREATE_ALWAYS,
windows.FILE_ATTRIBUTE_NORMAL | windows.FILE_FLAG_OVERLAPPED,
+ null,
);
defer os.close(handle);
try await (async pwriteWindows(loop, handle, contents, 0) catch unreachable);
}
-async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8, mode: os.File.Mode) !void {
+async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8, mode: File.Mode) !void {
// workaround for https://github.com/ziglang/zig/issues/1194
suspend {
resume @handle();
@@ -689,7 +696,7 @@ pub async fn readFile(loop: *Loop, file_path: []const u8, max_size: usize) ![]u8
defer list.deinit();
while (true) {
- try list.ensureCapacity(list.len + os.page_size);
+ try list.ensureCapacity(list.len + mem.page_size);
const buf = list.items[list.len..];
const buf_array = [][]u8{buf};
const amt = try await (async preadv(loop, fd, buf_array, list.len) catch unreachable);
@@ -787,7 +794,7 @@ pub fn Watch(comptime V: type) type {
switch (builtin.os) {
builtin.Os.linux => {
- const inotify_fd = try os.linuxINotifyInit1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC);
+ const inotify_fd = try os.inotify_init1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC);
errdefer os.close(inotify_fd);
var result: *Self = undefined;
@@ -880,7 +887,7 @@ pub fn Watch(comptime V: type) type {
}
async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V {
- const resolved_path = try os.path.resolve(self.channel.loop.allocator, [][]const u8{file_path});
+ const resolved_path = try std.fs.path.resolve(self.channel.loop.allocator, [][]const u8{file_path});
var resolved_path_consumed = false;
defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);
@@ -888,10 +895,7 @@ pub fn Watch(comptime V: type) type {
var close_op_consumed = false;
defer if (!close_op_consumed) close_op.finish();
- const flags = switch (builtin.os) {
- builtin.Os.macosx => posix.O_SYMLINK | posix.O_EVTONLY,
- else => 0,
- };
+ const flags = if (os.darwin.is_the_target) os.O_SYMLINK | os.O_EVTONLY else 0;
const mode = 0;
const fd = try await (async openPosix(self.channel.loop, resolved_path, flags, mode) catch unreachable);
close_op.setHandle(fd);
@@ -943,16 +947,16 @@ pub fn Watch(comptime V: type) type {
while (true) {
if (await (async self.channel.loop.bsdWaitKev(
@intCast(usize, close_op.getHandle()),
- posix.EVFILT_VNODE,
- posix.NOTE_WRITE | posix.NOTE_DELETE,
+ os.EVFILT_VNODE,
+ os.NOTE_WRITE | os.NOTE_DELETE,
) catch unreachable)) |kev| {
// TODO handle EV_ERROR
- if (kev.fflags & posix.NOTE_DELETE != 0) {
+ if (kev.fflags & os.NOTE_DELETE != 0) {
await (async self.channel.put(Self.Event{
.id = Event.Id.Delete,
.data = value_copy,
}) catch unreachable);
- } else if (kev.fflags & posix.NOTE_WRITE != 0) {
+ } else if (kev.fflags & os.NOTE_WRITE != 0) {
await (async self.channel.put(Self.Event{
.id = Event.Id.CloseWrite,
.data = value_copy,
@@ -961,6 +965,7 @@ pub fn Watch(comptime V: type) type {
} else |err| switch (err) {
error.EventNotFound => unreachable,
error.ProcessNotFound => unreachable,
+ error.Overflow => unreachable,
error.AccessDenied, error.SystemResources => |casted_err| {
await (async self.channel.put(casted_err) catch unreachable);
},
@@ -971,17 +976,17 @@ pub fn Watch(comptime V: type) type {
async fn addFileLinux(self: *Self, file_path: []const u8, value: V) !?V {
const value_copy = value;
- const dirname = os.path.dirname(file_path) orelse ".";
+ const dirname = std.fs.path.dirname(file_path) orelse ".";
const dirname_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, dirname);
var dirname_with_null_consumed = false;
defer if (!dirname_with_null_consumed) self.channel.loop.allocator.free(dirname_with_null);
- const basename = os.path.basename(file_path);
+ const basename = std.fs.path.basename(file_path);
const basename_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, basename);
var basename_with_null_consumed = false;
defer if (!basename_with_null_consumed) self.channel.loop.allocator.free(basename_with_null);
- const wd = try os.linuxINotifyAddWatchC(
+ const wd = try os.inotify_add_watchC(
self.os_data.inotify_fd,
dirname_with_null.ptr,
os.linux.IN_CLOSE_WRITE | os.linux.IN_ONLYDIR | os.linux.IN_EXCL_UNLINK,
@@ -1017,7 +1022,7 @@ pub fn Watch(comptime V: type) type {
const value_copy = value;
// TODO we might need to convert dirname and basename to canonical file paths ("short"?)
- const dirname = try std.mem.dupe(self.channel.loop.allocator, u8, os.path.dirname(file_path) orelse ".");
+ const dirname = try std.mem.dupe(self.channel.loop.allocator, u8, std.fs.path.dirname(file_path) orelse ".");
var dirname_consumed = false;
defer if (!dirname_consumed) self.channel.loop.allocator.free(dirname);
@@ -1025,13 +1030,13 @@ pub fn Watch(comptime V: type) type {
defer self.channel.loop.allocator.free(dirname_utf16le);
// TODO https://github.com/ziglang/zig/issues/265
- const basename = os.path.basename(file_path);
+ const basename = std.fs.path.basename(file_path);
const basename_utf16le_null = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, basename);
var basename_utf16le_null_consumed = false;
defer if (!basename_utf16le_null_consumed) self.channel.loop.allocator.free(basename_utf16le_null);
const basename_utf16le_no_null = basename_utf16le_null[0 .. basename_utf16le_null.len - 1];
- const dir_handle = windows.CreateFileW(
+ const dir_handle = try windows.CreateFileW(
dirname_utf16le.ptr,
windows.FILE_LIST_DIRECTORY,
windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE | windows.FILE_SHARE_WRITE,
@@ -1040,16 +1045,8 @@ pub fn Watch(comptime V: type) type {
windows.FILE_FLAG_BACKUP_SEMANTICS | windows.FILE_FLAG_OVERLAPPED,
null,
);
- if (dir_handle == windows.INVALID_HANDLE_VALUE) {
- const err = windows.GetLastError();
- switch (err) {
- windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
- windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
- else => return os.unexpectedErrorWindows(err),
- }
- }
var dir_handle_consumed = false;
- defer if (!dir_handle_consumed) os.close(dir_handle);
+ defer if (!dir_handle_consumed) windows.CloseHandle(dir_handle);
const held = await (async self.os_data.table_lock.acquire() catch unreachable);
defer held.release();
@@ -1128,7 +1125,7 @@ pub fn Watch(comptime V: type) type {
var event_buf: [4096]u8 align(@alignOf(windows.FILE_NOTIFY_INFORMATION)) = undefined;
// TODO handle this error not in the channel but in the setup
- _ = os.windowsCreateIoCompletionPort(
+ _ = windows.CreateIoCompletionPort(
dir_handle,
self.channel.loop.os_data.io_port,
undefined,
@@ -1144,10 +1141,10 @@ pub fn Watch(comptime V: type) type {
self.channel.loop.beginOneEvent();
errdefer self.channel.loop.finishOneEvent();
errdefer {
- _ = windows.CancelIoEx(dir_handle, &resume_node.base.overlapped);
+ _ = windows.kernel32.CancelIoEx(dir_handle, &resume_node.base.overlapped);
}
suspend {
- _ = windows.ReadDirectoryChangesW(
+ _ = windows.kernel32.ReadDirectoryChangesW(
dir_handle,
&event_buf,
@intCast(windows.DWORD, event_buf.len),
@@ -1163,10 +1160,9 @@ pub fn Watch(comptime V: type) type {
}
}
var bytes_transferred: windows.DWORD = undefined;
- if (windows.GetOverlappedResult(dir_handle, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {
- const errno = windows.GetLastError();
- const err = switch (errno) {
- else => os.unexpectedErrorWindows(errno),
+ if (windows.kernel32.GetOverlappedResult(dir_handle, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {
+ const err = switch (windows.kernel32.GetLastError()) {
+ else => |err| windows.unexpectedError(err),
};
await (async self.channel.put(err) catch unreachable);
} else {
@@ -1261,7 +1257,7 @@ pub fn Watch(comptime V: type) type {
ev = @ptrCast(*os.linux.inotify_event, ptr);
if (ev.mask & os.linux.IN_CLOSE_WRITE == os.linux.IN_CLOSE_WRITE) {
const basename_ptr = ptr + @sizeOf(os.linux.inotify_event);
- const basename_with_null = basename_ptr[0 .. std.cstr.len(basename_ptr) + 1];
+ const basename_with_null = basename_ptr[0 .. std.mem.len(u8, basename_ptr) + 1];
const user_value = blk: {
const held = await (async watch.os_data.table_lock.acquire() catch unreachable);
defer held.release();
@@ -1340,7 +1336,7 @@ async fn testFsWatchCantFail(loop: *Loop, result: *(anyerror!void)) void {
}
async fn testFsWatch(loop: *Loop) !void {
- const file_path = try os.path.join(loop.allocator, [][]const u8{ test_tmp_dir, "file.txt" });
+ const file_path = try std.fs.path.join(loop.allocator, [][]const u8{ test_tmp_dir, "file.txt" });
defer loop.allocator.free(file_path);
const contents =
@@ -1366,7 +1362,7 @@ async fn testFsWatch(loop: *Loop) !void {
defer if (!ev_consumed) cancel ev;
// overwrite line 2
- const fd = try await try async openReadWrite(loop, file_path, os.File.default_mode);
+ const fd = try await try async openReadWrite(loop, file_path, File.default_mode);
{
defer os.close(fd);
@@ -1388,15 +1384,15 @@ async fn testFsWatch(loop: *Loop) !void {
}
pub const OutStream = struct {
- fd: os.FileHandle,
+ fd: fd_t,
stream: Stream,
loop: *Loop,
offset: usize,
- pub const Error = os.File.WriteError;
+ pub const Error = File.WriteError;
pub const Stream = event.io.OutStream(Error);
- pub fn init(loop: *Loop, fd: os.FileHandle, offset: usize) OutStream {
+ pub fn init(loop: *Loop, fd: fd_t, offset: usize) OutStream {
return OutStream{
.fd = fd,
.loop = loop,
@@ -1414,7 +1410,7 @@ pub const OutStream = struct {
};
pub const InStream = struct {
- fd: os.FileHandle,
+ fd: fd_t,
stream: Stream,
loop: *Loop,
offset: usize,
@@ -1422,7 +1418,7 @@ pub const InStream = struct {
pub const Error = PReadVError; // TODO make this not have OutOfMemory
pub const Stream = event.io.InStream(Error);
- pub fn init(loop: *Loop, fd: os.FileHandle, offset: usize) InStream {
+ pub fn init(loop: *Loop, fd: fd_t, offset: usize) InStream {
return InStream{
.fd = fd,
.loop = loop,
diff --git a/std/event/group.zig b/std/event/group.zig
index 455d1bd60c..143efd76c3 100644
--- a/std/event/group.zig
+++ b/std/event/group.zig
@@ -155,7 +155,7 @@ async fn testGroup(loop: *Loop) void {
}
async fn sleepALittle(count: *usize) void {
- std.os.time.sleep(1 * std.os.time.millisecond);
+ std.time.sleep(1 * std.time.millisecond);
_ = @atomicRmw(usize, count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
}
diff --git a/std/event/loop.zig b/std/event/loop.zig
index 76b1f6455b..61732d78f5 100644
--- a/std/event/loop.zig
+++ b/std/event/loop.zig
@@ -7,9 +7,9 @@ const AtomicRmwOp = builtin.AtomicRmwOp;
const AtomicOrder = builtin.AtomicOrder;
const fs = std.event.fs;
const os = std.os;
-const posix = os.posix;
const windows = os.windows;
const maxInt = std.math.maxInt;
+const Thread = std.Thread;
pub const Loop = struct {
allocator: *mem.Allocator,
@@ -17,7 +17,7 @@ pub const Loop = struct {
os_data: OsData,
final_resume_node: ResumeNode,
pending_event_count: usize,
- extra_threads: []*os.Thread,
+ extra_threads: []*Thread,
// pre-allocated eventfds. all permanently active.
// this is how we send promises to be resumed on other threads.
@@ -32,7 +32,7 @@ pub const Loop = struct {
overlapped: Overlapped,
pub const overlapped_init = switch (builtin.os) {
- builtin.Os.windows => windows.OVERLAPPED{
+ .windows => windows.OVERLAPPED{
.Internal = 0,
.InternalHigh = 0,
.Offset = 0,
@@ -50,13 +50,13 @@ pub const Loop = struct {
};
pub const EventFd = switch (builtin.os) {
- builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => KEventFd,
- builtin.Os.linux => struct {
+ .macosx, .freebsd, .netbsd => KEventFd,
+ .linux => struct {
base: ResumeNode,
epoll_op: u32,
eventfd: i32,
},
- builtin.Os.windows => struct {
+ .windows => struct {
base: ResumeNode,
completion_key: usize,
},
@@ -65,15 +65,15 @@ pub const Loop = struct {
const KEventFd = struct {
base: ResumeNode,
- kevent: posix.Kevent,
+ kevent: os.Kevent,
};
pub const Basic = switch (builtin.os) {
- builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => KEventBasic,
- builtin.Os.linux => struct {
+ .macosx, .freebsd, .netbsd => KEventBasic,
+ .linux => struct {
base: ResumeNode,
},
- builtin.Os.windows => struct {
+ .windows => struct {
base: ResumeNode,
},
else => @compileError("unsupported OS"),
@@ -81,7 +81,7 @@ pub const Loop = struct {
const KEventBasic = struct {
base: ResumeNode,
- kev: posix.Kevent,
+ kev: os.Kevent,
};
};
@@ -99,7 +99,7 @@ pub const Loop = struct {
/// have the correct pointer value.
pub fn initMultiThreaded(self: *Loop, allocator: *mem.Allocator) !void {
if (builtin.single_threaded) @compileError("initMultiThreaded unavailable when building in single-threaded mode");
- const core_count = try os.cpuCount(allocator);
+ const core_count = try Thread.cpuCount();
return self.initInternal(allocator, core_count);
}
@@ -127,7 +127,7 @@ pub const Loop = struct {
);
errdefer self.allocator.free(self.eventfd_resume_nodes);
- self.extra_threads = try self.allocator.alloc(*os.Thread, extra_thread_count);
+ self.extra_threads = try self.allocator.alloc(*Thread, extra_thread_count);
errdefer self.allocator.free(self.extra_threads);
try self.initOsData(extra_thread_count);
@@ -139,15 +139,15 @@ pub const Loop = struct {
self.allocator.free(self.extra_threads);
}
- const InitOsDataError = os.LinuxEpollCreateError || mem.Allocator.Error || os.LinuxEventFdError ||
- os.SpawnThreadError || os.LinuxEpollCtlError || os.BsdKEventError ||
- os.WindowsCreateIoCompletionPortError;
+ const InitOsDataError = os.EpollCreateError || mem.Allocator.Error || os.EventFdError ||
+ Thread.SpawnError || os.EpollCtlError || os.KEventError ||
+ windows.CreateIoCompletionPortError;
const wakeup_bytes = []u8{0x1} ** 8;
fn initOsData(self: *Loop, extra_thread_count: usize) InitOsDataError!void {
switch (builtin.os) {
- builtin.Os.linux => {
+ .linux => {
self.os_data.fs_queue = std.atomic.Queue(fs.Request).init();
self.os_data.fs_queue_item = 0;
// we need another thread for the file system because Linux does not have an async
@@ -172,32 +172,32 @@ pub const Loop = struct {
.handle = undefined,
.overlapped = ResumeNode.overlapped_init,
},
- .eventfd = try os.linuxEventFd(1, posix.EFD_CLOEXEC | posix.EFD_NONBLOCK),
- .epoll_op = posix.EPOLL_CTL_ADD,
+ .eventfd = try os.eventfd(1, os.EFD_CLOEXEC | os.EFD_NONBLOCK),
+ .epoll_op = os.EPOLL_CTL_ADD,
},
.next = undefined,
};
self.available_eventfd_resume_nodes.push(eventfd_node);
}
- self.os_data.epollfd = try os.linuxEpollCreate(posix.EPOLL_CLOEXEC);
+ self.os_data.epollfd = try os.epoll_create1(os.EPOLL_CLOEXEC);
errdefer os.close(self.os_data.epollfd);
- self.os_data.final_eventfd = try os.linuxEventFd(0, posix.EFD_CLOEXEC | posix.EFD_NONBLOCK);
+ self.os_data.final_eventfd = try os.eventfd(0, os.EFD_CLOEXEC | os.EFD_NONBLOCK);
errdefer os.close(self.os_data.final_eventfd);
- self.os_data.final_eventfd_event = posix.epoll_event{
- .events = posix.EPOLLIN,
- .data = posix.epoll_data{ .ptr = @ptrToInt(&self.final_resume_node) },
+ self.os_data.final_eventfd_event = os.epoll_event{
+ .events = os.EPOLLIN,
+ .data = os.epoll_data{ .ptr = @ptrToInt(&self.final_resume_node) },
};
- try os.linuxEpollCtl(
+ try os.epoll_ctl(
self.os_data.epollfd,
- posix.EPOLL_CTL_ADD,
+ os.EPOLL_CTL_ADD,
self.os_data.final_eventfd,
&self.os_data.final_eventfd_event,
);
- self.os_data.fs_thread = try os.spawnThread(self, posixFsRun);
+ self.os_data.fs_thread = try Thread.spawn(self, posixFsRun);
errdefer {
self.posixFsRequest(&self.os_data.fs_end_request);
self.os_data.fs_thread.wait();
@@ -211,21 +211,21 @@ pub const Loop = struct {
var extra_thread_index: usize = 0;
errdefer {
// writing 8 bytes to an eventfd cannot fail
- os.posixWrite(self.os_data.final_eventfd, wakeup_bytes) catch unreachable;
+ os.write(self.os_data.final_eventfd, wakeup_bytes) catch unreachable;
while (extra_thread_index != 0) {
extra_thread_index -= 1;
self.extra_threads[extra_thread_index].wait();
}
}
while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
- self.extra_threads[extra_thread_index] = try os.spawnThread(self, workerRun);
+ self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun);
}
},
- builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
- self.os_data.kqfd = try os.bsdKQueue();
+ .macosx, .freebsd, .netbsd => {
+ self.os_data.kqfd = try os.kqueue();
errdefer os.close(self.os_data.kqfd);
- self.os_data.fs_kqfd = try os.bsdKQueue();
+ self.os_data.fs_kqfd = try os.kqueue();
errdefer os.close(self.os_data.fs_kqfd);
self.os_data.fs_queue = std.atomic.Queue(fs.Request).init();
@@ -240,7 +240,7 @@ pub const Loop = struct {
},
};
- const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
+ const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
for (self.eventfd_resume_nodes) |*eventfd_node, i| {
eventfd_node.* = std.atomic.Stack(ResumeNode.EventFd).Node{
@@ -251,10 +251,10 @@ pub const Loop = struct {
.overlapped = ResumeNode.overlapped_init,
},
// this one is for sending events
- .kevent = posix.Kevent{
+ .kevent = os.Kevent{
.ident = i,
- .filter = posix.EVFILT_USER,
- .flags = posix.EV_CLEAR | posix.EV_ADD | posix.EV_DISABLE,
+ .filter = os.EVFILT_USER,
+ .flags = os.EV_CLEAR | os.EV_ADD | os.EV_DISABLE,
.fflags = 0,
.data = 0,
.udata = @ptrToInt(&eventfd_node.data.base),
@@ -263,46 +263,46 @@ pub const Loop = struct {
.next = undefined,
};
self.available_eventfd_resume_nodes.push(eventfd_node);
- const kevent_array = (*const [1]posix.Kevent)(&eventfd_node.data.kevent);
- _ = try os.bsdKEvent(self.os_data.kqfd, kevent_array, empty_kevs, null);
- eventfd_node.data.kevent.flags = posix.EV_CLEAR | posix.EV_ENABLE;
- eventfd_node.data.kevent.fflags = posix.NOTE_TRIGGER;
+ const kevent_array = (*const [1]os.Kevent)(&eventfd_node.data.kevent);
+ _ = try os.kevent(self.os_data.kqfd, kevent_array, empty_kevs, null);
+ eventfd_node.data.kevent.flags = os.EV_CLEAR | os.EV_ENABLE;
+ eventfd_node.data.kevent.fflags = os.NOTE_TRIGGER;
}
// Pre-add so that we cannot get error.SystemResources
// later when we try to activate it.
- self.os_data.final_kevent = posix.Kevent{
+ self.os_data.final_kevent = os.Kevent{
.ident = extra_thread_count,
- .filter = posix.EVFILT_USER,
- .flags = posix.EV_ADD | posix.EV_DISABLE,
+ .filter = os.EVFILT_USER,
+ .flags = os.EV_ADD | os.EV_DISABLE,
.fflags = 0,
.data = 0,
.udata = @ptrToInt(&self.final_resume_node),
};
- const final_kev_arr = (*const [1]posix.Kevent)(&self.os_data.final_kevent);
- _ = try os.bsdKEvent(self.os_data.kqfd, final_kev_arr, empty_kevs, null);
- self.os_data.final_kevent.flags = posix.EV_ENABLE;
- self.os_data.final_kevent.fflags = posix.NOTE_TRIGGER;
+ const final_kev_arr = (*const [1]os.Kevent)(&self.os_data.final_kevent);
+ _ = try os.kevent(self.os_data.kqfd, final_kev_arr, empty_kevs, null);
+ self.os_data.final_kevent.flags = os.EV_ENABLE;
+ self.os_data.final_kevent.fflags = os.NOTE_TRIGGER;
- self.os_data.fs_kevent_wake = posix.Kevent{
+ self.os_data.fs_kevent_wake = os.Kevent{
.ident = 0,
- .filter = posix.EVFILT_USER,
- .flags = posix.EV_ADD | posix.EV_ENABLE,
- .fflags = posix.NOTE_TRIGGER,
+ .filter = os.EVFILT_USER,
+ .flags = os.EV_ADD | os.EV_ENABLE,
+ .fflags = os.NOTE_TRIGGER,
.data = 0,
.udata = undefined,
};
- self.os_data.fs_kevent_wait = posix.Kevent{
+ self.os_data.fs_kevent_wait = os.Kevent{
.ident = 0,
- .filter = posix.EVFILT_USER,
- .flags = posix.EV_ADD | posix.EV_CLEAR,
+ .filter = os.EVFILT_USER,
+ .flags = os.EV_ADD | os.EV_CLEAR,
.fflags = 0,
.data = 0,
.udata = undefined,
};
- self.os_data.fs_thread = try os.spawnThread(self, posixFsRun);
+ self.os_data.fs_thread = try Thread.spawn(self, posixFsRun);
errdefer {
self.posixFsRequest(&self.os_data.fs_end_request);
self.os_data.fs_thread.wait();
@@ -315,24 +315,24 @@ pub const Loop = struct {
var extra_thread_index: usize = 0;
errdefer {
- _ = os.bsdKEvent(self.os_data.kqfd, final_kev_arr, empty_kevs, null) catch unreachable;
+ _ = os.kevent(self.os_data.kqfd, final_kev_arr, empty_kevs, null) catch unreachable;
while (extra_thread_index != 0) {
extra_thread_index -= 1;
self.extra_threads[extra_thread_index].wait();
}
}
while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
- self.extra_threads[extra_thread_index] = try os.spawnThread(self, workerRun);
+ self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun);
}
},
- builtin.Os.windows => {
- self.os_data.io_port = try os.windowsCreateIoCompletionPort(
+ .windows => {
+ self.os_data.io_port = try windows.CreateIoCompletionPort(
windows.INVALID_HANDLE_VALUE,
null,
undefined,
maxInt(windows.DWORD),
);
- errdefer os.close(self.os_data.io_port);
+ errdefer windows.CloseHandle(self.os_data.io_port);
for (self.eventfd_resume_nodes) |*eventfd_node, i| {
eventfd_node.* = std.atomic.Stack(ResumeNode.EventFd).Node{
@@ -361,7 +361,7 @@ pub const Loop = struct {
while (i < extra_thread_index) : (i += 1) {
while (true) {
const overlapped = &self.final_resume_node.overlapped;
- os.windowsPostQueuedCompletionStatus(self.os_data.io_port, undefined, undefined, overlapped) catch continue;
+ windows.PostQueuedCompletionStatus(self.os_data.io_port, undefined, undefined, overlapped) catch continue;
break;
}
}
@@ -371,7 +371,7 @@ pub const Loop = struct {
}
}
while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
- self.extra_threads[extra_thread_index] = try os.spawnThread(self, workerRun);
+ self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun);
}
},
else => {},
@@ -380,18 +380,18 @@ pub const Loop = struct {
fn deinitOsData(self: *Loop) void {
switch (builtin.os) {
- builtin.Os.linux => {
+ .linux => {
os.close(self.os_data.final_eventfd);
while (self.available_eventfd_resume_nodes.pop()) |node| os.close(node.data.eventfd);
os.close(self.os_data.epollfd);
self.allocator.free(self.eventfd_resume_nodes);
},
- builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
+ .macosx, .freebsd, .netbsd => {
os.close(self.os_data.kqfd);
os.close(self.os_data.fs_kqfd);
},
- builtin.Os.windows => {
- os.close(self.os_data.io_port);
+ .windows => {
+ windows.CloseHandle(self.os_data.io_port);
},
else => {},
}
@@ -400,28 +400,28 @@ pub const Loop = struct {
/// resume_node must live longer than the promise that it holds a reference to.
/// flags must contain EPOLLET
pub fn linuxAddFd(self: *Loop, fd: i32, resume_node: *ResumeNode, flags: u32) !void {
- assert(flags & posix.EPOLLET == posix.EPOLLET);
+ assert(flags & os.EPOLLET == os.EPOLLET);
self.beginOneEvent();
errdefer self.finishOneEvent();
try self.linuxModFd(
fd,
- posix.EPOLL_CTL_ADD,
+ os.EPOLL_CTL_ADD,
flags,
resume_node,
);
}
pub fn linuxModFd(self: *Loop, fd: i32, op: u32, flags: u32, resume_node: *ResumeNode) !void {
- assert(flags & posix.EPOLLET == posix.EPOLLET);
+ assert(flags & os.EPOLLET == os.EPOLLET);
var ev = os.linux.epoll_event{
.events = flags,
.data = os.linux.epoll_data{ .ptr = @ptrToInt(resume_node) },
};
- try os.linuxEpollCtl(self.os_data.epollfd, op, fd, &ev);
+ try os.epoll_ctl(self.os_data.epollfd, op, fd, &ev);
}
pub fn linuxRemoveFd(self: *Loop, fd: i32) void {
- os.linuxEpollCtl(self.os_data.epollfd, os.linux.EPOLL_CTL_DEL, fd, undefined) catch {};
+ os.epoll_ctl(self.os_data.epollfd, os.linux.EPOLL_CTL_DEL, fd, undefined) catch {};
self.finishOneEvent();
}
@@ -440,7 +440,7 @@ pub const Loop = struct {
}
}
- pub async fn bsdWaitKev(self: *Loop, ident: usize, filter: i16, fflags: u32) !posix.Kevent {
+ pub async fn bsdWaitKev(self: *Loop, ident: usize, filter: i16, fflags: u32) !os.Kevent {
// TODO #1194
suspend {
resume @handle();
@@ -464,31 +464,31 @@ pub const Loop = struct {
pub fn bsdAddKev(self: *Loop, resume_node: *ResumeNode.Basic, ident: usize, filter: i16, fflags: u32) !void {
self.beginOneEvent();
errdefer self.finishOneEvent();
- var kev = posix.Kevent{
+ var kev = os.Kevent{
.ident = ident,
.filter = filter,
- .flags = posix.EV_ADD | posix.EV_ENABLE | posix.EV_CLEAR,
+ .flags = os.EV_ADD | os.EV_ENABLE | os.EV_CLEAR,
.fflags = fflags,
.data = 0,
.udata = @ptrToInt(&resume_node.base),
};
- const kevent_array = (*const [1]posix.Kevent)(&kev);
- const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
- _ = try os.bsdKEvent(self.os_data.kqfd, kevent_array, empty_kevs, null);
+ const kevent_array = (*const [1]os.Kevent)(&kev);
+ const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
+ _ = try os.kevent(self.os_data.kqfd, kevent_array, empty_kevs, null);
}
pub fn bsdRemoveKev(self: *Loop, ident: usize, filter: i16) void {
- var kev = posix.Kevent{
+ var kev = os.Kevent{
.ident = ident,
.filter = filter,
- .flags = posix.EV_DELETE,
+ .flags = os.EV_DELETE,
.fflags = 0,
.data = 0,
.udata = 0,
};
- const kevent_array = (*const [1]posix.Kevent)(&kev);
- const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
- _ = os.bsdKEvent(self.os_data.kqfd, kevent_array, empty_kevs, null) catch undefined;
+ const kevent_array = (*const [1]os.Kevent)(&kev);
+ const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
+ _ = os.kevent(self.os_data.kqfd, kevent_array, empty_kevs, null) catch undefined;
self.finishOneEvent();
}
@@ -501,18 +501,18 @@ pub const Loop = struct {
const eventfd_node = &resume_stack_node.data;
eventfd_node.base.handle = next_tick_node.data;
switch (builtin.os) {
- builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
- const kevent_array = (*const [1]posix.Kevent)(&eventfd_node.kevent);
- const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
- _ = os.bsdKEvent(self.os_data.kqfd, kevent_array, empty_kevs, null) catch {
+ .macosx, .freebsd, .netbsd => {
+ const kevent_array = (*const [1]os.Kevent)(&eventfd_node.kevent);
+ const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
+ _ = os.kevent(self.os_data.kqfd, kevent_array, empty_kevs, null) catch {
self.next_tick_queue.unget(next_tick_node);
self.available_eventfd_resume_nodes.push(resume_stack_node);
return;
};
},
- builtin.Os.linux => {
+ .linux => {
// the pending count is already accounted for
- const epoll_events = posix.EPOLLONESHOT | os.linux.EPOLLIN | os.linux.EPOLLOUT |
+ const epoll_events = os.EPOLLONESHOT | os.linux.EPOLLIN | os.linux.EPOLLOUT |
os.linux.EPOLLET;
self.linuxModFd(
eventfd_node.eventfd,
@@ -525,8 +525,8 @@ pub const Loop = struct {
return;
};
},
- builtin.Os.windows => {
- os.windowsPostQueuedCompletionStatus(
+ .windows => {
+ windows.PostQueuedCompletionStatus(
self.os_data.io_port,
undefined,
undefined,
@@ -623,26 +623,26 @@ pub const Loop = struct {
if (prev == 1) {
// cause all the threads to stop
switch (builtin.os) {
- builtin.Os.linux => {
+ .linux => {
self.posixFsRequest(&self.os_data.fs_end_request);
// writing 8 bytes to an eventfd cannot fail
- os.posixWrite(self.os_data.final_eventfd, wakeup_bytes) catch unreachable;
+ os.write(self.os_data.final_eventfd, wakeup_bytes) catch unreachable;
return;
},
- builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
+ .macosx, .freebsd, .netbsd => {
self.posixFsRequest(&self.os_data.fs_end_request);
- const final_kevent = (*const [1]posix.Kevent)(&self.os_data.final_kevent);
- const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
+ const final_kevent = (*const [1]os.Kevent)(&self.os_data.final_kevent);
+ const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
// cannot fail because we already added it and this just enables it
- _ = os.bsdKEvent(self.os_data.kqfd, final_kevent, empty_kevs, null) catch unreachable;
+ _ = os.kevent(self.os_data.kqfd, final_kevent, empty_kevs, null) catch unreachable;
return;
},
- builtin.Os.windows => {
+ .windows => {
var i: usize = 0;
while (i < self.extra_threads.len + 1) : (i += 1) {
while (true) {
const overlapped = &self.final_resume_node.overlapped;
- os.windowsPostQueuedCompletionStatus(self.os_data.io_port, undefined, undefined, overlapped) catch continue;
+ windows.PostQueuedCompletionStatus(self.os_data.io_port, undefined, undefined, overlapped) catch continue;
break;
}
}
@@ -663,10 +663,10 @@ pub const Loop = struct {
}
switch (builtin.os) {
- builtin.Os.linux => {
+ .linux => {
// only process 1 event so we don't steal from other threads
var events: [1]os.linux.epoll_event = undefined;
- const count = os.linuxEpollWait(self.os_data.epollfd, events[0..], -1);
+ const count = os.epoll_wait(self.os_data.epollfd, events[0..], -1);
for (events[0..count]) |ev| {
const resume_node = @intToPtr(*ResumeNode, ev.data.ptr);
const handle = resume_node.handle;
@@ -676,7 +676,7 @@ pub const Loop = struct {
ResumeNode.Id.Stop => return,
ResumeNode.Id.EventFd => {
const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);
- event_fd_node.epoll_op = posix.EPOLL_CTL_MOD;
+ event_fd_node.epoll_op = os.EPOLL_CTL_MOD;
const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);
self.available_eventfd_resume_nodes.push(stack_node);
},
@@ -687,10 +687,10 @@ pub const Loop = struct {
}
}
},
- builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
- var eventlist: [1]posix.Kevent = undefined;
- const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
- const count = os.bsdKEvent(self.os_data.kqfd, empty_kevs, eventlist[0..], null) catch unreachable;
+ .macosx, .freebsd, .netbsd => {
+ var eventlist: [1]os.Kevent = undefined;
+ const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
+ const count = os.kevent(self.os_data.kqfd, empty_kevs, eventlist[0..], null) catch unreachable;
for (eventlist[0..count]) |ev| {
const resume_node = @intToPtr(*ResumeNode, ev.udata);
const handle = resume_node.handle;
@@ -713,16 +713,16 @@ pub const Loop = struct {
}
}
},
- builtin.Os.windows => {
+ .windows => {
var completion_key: usize = undefined;
const overlapped = while (true) {
var nbytes: windows.DWORD = undefined;
var overlapped: ?*windows.OVERLAPPED = undefined;
- switch (os.windowsGetQueuedCompletionStatus(self.os_data.io_port, &nbytes, &completion_key, &overlapped, windows.INFINITE)) {
- os.WindowsWaitResult.Aborted => return,
- os.WindowsWaitResult.Normal => {},
- os.WindowsWaitResult.EOF => {},
- os.WindowsWaitResult.Cancelled => continue,
+ switch (windows.GetQueuedCompletionStatus(self.os_data.io_port, &nbytes, &completion_key, &overlapped, windows.INFINITE)) {
+ .Aborted => return,
+ .Normal => {},
+ .EOF => {},
+ .Cancelled => continue,
}
if (overlapped) |o| break o;
} else unreachable; // TODO else unreachable should not be necessary
@@ -751,16 +751,16 @@ pub const Loop = struct {
self.os_data.fs_queue.put(request_node);
switch (builtin.os) {
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
- const fs_kevs = (*const [1]posix.Kevent)(&self.os_data.fs_kevent_wake);
- const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
- _ = os.bsdKEvent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable;
+ const fs_kevs = (*const [1]os.Kevent)(&self.os_data.fs_kevent_wake);
+ const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
+ _ = os.kevent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable;
},
builtin.Os.linux => {
_ = @atomicRmw(i32, &self.os_data.fs_queue_item, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
const rc = os.linux.futex_wake(&self.os_data.fs_queue_item, os.linux.FUTEX_WAKE, 1);
switch (os.linux.getErrno(rc)) {
0 => {},
- posix.EINVAL => unreachable,
+ os.EINVAL => unreachable,
else => unreachable,
}
},
@@ -783,24 +783,24 @@ pub const Loop = struct {
switch (node.data.msg) {
@TagType(fs.Request.Msg).End => return,
@TagType(fs.Request.Msg).PWriteV => |*msg| {
- msg.result = os.posix_pwritev(msg.fd, msg.iov.ptr, msg.iov.len, msg.offset);
+ msg.result = os.pwritev(msg.fd, msg.iov, msg.offset);
},
@TagType(fs.Request.Msg).PReadV => |*msg| {
- msg.result = os.posix_preadv(msg.fd, msg.iov.ptr, msg.iov.len, msg.offset);
+ msg.result = os.preadv(msg.fd, msg.iov, msg.offset);
},
@TagType(fs.Request.Msg).Open => |*msg| {
- msg.result = os.posixOpenC(msg.path.ptr, msg.flags, msg.mode);
+ msg.result = os.openC(msg.path.ptr, msg.flags, msg.mode);
},
@TagType(fs.Request.Msg).Close => |*msg| os.close(msg.fd),
@TagType(fs.Request.Msg).WriteFile => |*msg| blk: {
- const flags = posix.O_LARGEFILE | posix.O_WRONLY | posix.O_CREAT |
- posix.O_CLOEXEC | posix.O_TRUNC;
- const fd = os.posixOpenC(msg.path.ptr, flags, msg.mode) catch |err| {
+ const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT |
+ os.O_CLOEXEC | os.O_TRUNC;
+ const fd = os.openC(msg.path.ptr, flags, msg.mode) catch |err| {
msg.result = err;
break :blk;
};
defer os.close(fd);
- msg.result = os.posixWrite(fd, msg.contents);
+ msg.result = os.write(fd, msg.contents);
},
}
switch (node.data.finish) {
@@ -816,14 +816,14 @@ pub const Loop = struct {
builtin.Os.linux => {
const rc = os.linux.futex_wait(&self.os_data.fs_queue_item, os.linux.FUTEX_WAIT, 0, null);
switch (os.linux.getErrno(rc)) {
- 0, posix.EINTR, posix.EAGAIN => continue,
+ 0, os.EINTR, os.EAGAIN => continue,
else => unreachable,
}
},
builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
- const fs_kevs = (*const [1]posix.Kevent)(&self.os_data.fs_kevent_wait);
- var out_kevs: [1]posix.Kevent = undefined;
- _ = os.bsdKEvent(self.os_data.fs_kqfd, fs_kevs, out_kevs[0..], null) catch unreachable;
+ const fs_kevs = (*const [1]os.Kevent)(&self.os_data.fs_kevent_wait);
+ var out_kevs: [1]os.Kevent = undefined;
+ _ = os.kevent(self.os_data.fs_kqfd, fs_kevs, out_kevs[0..], null) catch unreachable;
},
else => @compileError("Unsupported OS"),
}
@@ -831,9 +831,9 @@ pub const Loop = struct {
}
const OsData = switch (builtin.os) {
- builtin.Os.linux => LinuxOsData,
- builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => KEventData,
- builtin.Os.windows => struct {
+ .linux => LinuxOsData,
+ .macosx, .freebsd, .netbsd => KEventData,
+ .windows => struct {
io_port: windows.HANDLE,
extra_thread_count: usize,
},
@@ -842,10 +842,10 @@ pub const Loop = struct {
const KEventData = struct {
kqfd: i32,
- final_kevent: posix.Kevent,
- fs_kevent_wake: posix.Kevent,
- fs_kevent_wait: posix.Kevent,
- fs_thread: *os.Thread,
+ final_kevent: os.Kevent,
+ fs_kevent_wake: os.Kevent,
+ fs_kevent_wait: os.Kevent,
+ fs_thread: *Thread,
fs_kqfd: i32,
fs_queue: std.atomic.Queue(fs.Request),
fs_end_request: fs.RequestNode,
@@ -855,7 +855,7 @@ pub const Loop = struct {
epollfd: i32,
final_eventfd: i32,
final_eventfd_event: os.linux.epoll_event,
- fs_thread: *os.Thread,
+ fs_thread: *Thread,
fs_queue_item: i32,
fs_queue: std.atomic.Queue(fs.Request),
fs_end_request: fs.RequestNode,
diff --git a/std/event/net.zig b/std/event/net.zig
index 687c119920..f4398196e3 100644
--- a/std/event/net.zig
+++ b/std/event/net.zig
@@ -4,11 +4,12 @@ const testing = std.testing;
const event = std.event;
const mem = std.mem;
const os = std.os;
-const posix = os.posix;
const Loop = std.event.Loop;
+const File = std.fs.File;
+const fd_t = os.fd_t;
pub const Server = struct {
- handleRequestFn: async<*mem.Allocator> fn (*Server, *const std.net.Address, os.File) void,
+ handleRequestFn: async<*mem.Allocator> fn (*Server, *const std.net.Address, File) void,
loop: *Loop,
sockfd: ?i32,
@@ -40,30 +41,33 @@ pub const Server = struct {
pub fn listen(
self: *Server,
address: *const std.net.Address,
- handleRequestFn: async<*mem.Allocator> fn (*Server, *const std.net.Address, os.File) void,
+ handleRequestFn: async<*mem.Allocator> fn (*Server, *const std.net.Address, File) void,
) !void {
self.handleRequestFn = handleRequestFn;
- const sockfd = try os.posixSocket(posix.AF_INET, posix.SOCK_STREAM | posix.SOCK_CLOEXEC | posix.SOCK_NONBLOCK, posix.PROTO_tcp);
+ const sockfd = try os.socket(os.AF_INET, os.SOCK_STREAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK, os.PROTO_tcp);
errdefer os.close(sockfd);
self.sockfd = sockfd;
- try os.posixBind(sockfd, &address.os_addr);
- try os.posixListen(sockfd, posix.SOMAXCONN);
- self.listen_address = std.net.Address.initPosix(try os.posixGetSockName(sockfd));
+ try os.bind(sockfd, &address.os_addr);
+ try os.listen(sockfd, os.SOMAXCONN);
+ self.listen_address = std.net.Address.initPosix(try os.getsockname(sockfd));
self.accept_coro = try async<self.loop.allocator> Server.handler(self);
errdefer cancel self.accept_coro.?;
self.listen_resume_node.handle = self.accept_coro.?;
- try self.loop.linuxAddFd(sockfd, &self.listen_resume_node, posix.EPOLLIN | posix.EPOLLOUT | posix.EPOLLET);
+ try self.loop.linuxAddFd(sockfd, &self.listen_resume_node, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
errdefer self.loop.removeFd(sockfd);
}
/// Stop listening
pub fn close(self: *Server) void {
self.loop.linuxRemoveFd(self.sockfd.?);
- os.close(self.sockfd.?);
+ if (self.sockfd) |fd| {
+ os.close(fd);
+ self.sockfd = null;
+ }
}
pub fn deinit(self: *Server) void {
@@ -75,13 +79,13 @@ pub const Server = struct {
while (true) {
var accepted_addr: std.net.Address = undefined;
// TODO just inline the following function here and don't expose it as posixAsyncAccept
- if (os.posixAsyncAccept(self.sockfd.?, &accepted_addr.os_addr, posix.SOCK_NONBLOCK | posix.SOCK_CLOEXEC)) |accepted_fd| {
+ if (os.accept4_async(self.sockfd.?, &accepted_addr.os_addr, os.SOCK_NONBLOCK | os.SOCK_CLOEXEC)) |accepted_fd| {
if (accepted_fd == -1) {
// would block
suspend; // we will get resumed by epoll_wait in the event loop
continue;
}
- var socket = os.File.openHandle(accepted_fd);
+ var socket = File.openHandle(accepted_fd);
_ = async<self.loop.allocator> self.handleRequestFn(self, &accepted_addr, socket) catch |err| switch (err) {
error.OutOfMemory => {
socket.close();
@@ -89,14 +93,7 @@ pub const Server = struct {
},
};
} else |err| switch (err) {
- error.ProcessFdQuotaExceeded => {
- errdefer os.emfile_promise_queue.remove(&self.waiting_for_emfile_node);
- suspend {
- self.waiting_for_emfile_node = PromiseNode.init(@handle());
- os.emfile_promise_queue.append(&self.waiting_for_emfile_node);
- }
- continue;
- },
+ error.ProcessFdQuotaExceeded => @panic("TODO handle this error"),
error.ConnectionAborted => continue,
error.FileDescriptorNotASocket => unreachable,
@@ -111,24 +108,24 @@ pub const Server = struct {
};
pub async fn connectUnixSocket(loop: *Loop, path: []const u8) !i32 {
- const sockfd = try os.posixSocket(
- posix.AF_UNIX,
- posix.SOCK_STREAM | posix.SOCK_CLOEXEC | posix.SOCK_NONBLOCK,
+ const sockfd = try os.socket(
+ os.AF_UNIX,
+ os.SOCK_STREAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK,
0,
);
errdefer os.close(sockfd);
- var sock_addr = posix.sockaddr_un{
- .family = posix.AF_UNIX,
+ var sock_addr = os.sockaddr_un{
+ .family = os.AF_UNIX,
.path = undefined,
};
if (path.len > @typeOf(sock_addr.path).len) return error.NameTooLong;
mem.copy(u8, sock_addr.path[0..], path);
- const size = @intCast(u32, @sizeOf(posix.sa_family_t) + path.len);
- try os.posixConnectAsync(sockfd, &sock_addr, size);
- try await try async loop.linuxWaitFd(sockfd, posix.EPOLLIN | posix.EPOLLOUT | posix.EPOLLET);
- try os.posixGetSockOptConnectError(sockfd);
+ const size = @intCast(u32, @sizeOf(os.sa_family_t) + path.len);
+ try os.connect_async(sockfd, &sock_addr, size);
+ try await try async loop.linuxWaitFd(sockfd, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
+ try os.getsockoptError(sockfd);
return sockfd;
}
@@ -146,51 +143,49 @@ pub const ReadError = error{
};
/// returns number of bytes read. 0 means EOF.
-pub async fn read(loop: *std.event.Loop, fd: os.FileHandle, buffer: []u8) ReadError!usize {
- const iov = posix.iovec{
+pub async fn read(loop: *std.event.Loop, fd: fd_t, buffer: []u8) ReadError!usize {
+ const iov = os.iovec{
.iov_base = buffer.ptr,
.iov_len = buffer.len,
};
- const iovs: *const [1]posix.iovec = &iov;
+ const iovs: *const [1]os.iovec = &iov;
return await (async readvPosix(loop, fd, iovs, 1) catch unreachable);
}
pub const WriteError = error{};
-pub async fn write(loop: *std.event.Loop, fd: os.FileHandle, buffer: []const u8) WriteError!void {
- const iov = posix.iovec_const{
+pub async fn write(loop: *std.event.Loop, fd: fd_t, buffer: []const u8) WriteError!void {
+ const iov = os.iovec_const{
.iov_base = buffer.ptr,
.iov_len = buffer.len,
};
- const iovs: *const [1]posix.iovec_const = &iov;
+ const iovs: *const [1]os.iovec_const = &iov;
return await (async writevPosix(loop, fd, iovs, 1) catch unreachable);
}
-pub async fn writevPosix(loop: *Loop, fd: i32, iov: [*]const posix.iovec_const, count: usize) !void {
+pub async fn writevPosix(loop: *Loop, fd: i32, iov: [*]const os.iovec_const, count: usize) !void {
while (true) {
switch (builtin.os) {
- builtin.Os.macosx, builtin.Os.linux => {
- const rc = posix.writev(fd, iov, count);
- const err = posix.getErrno(rc);
- switch (err) {
+ .macosx, .linux => {
+ switch (os.errno(os.system.writev(fd, iov, count))) {
0 => return,
- posix.EINTR => continue,
- posix.ESPIPE => unreachable,
- posix.EINVAL => unreachable,
- posix.EFAULT => unreachable,
- posix.EAGAIN => {
- try await (async loop.linuxWaitFd(fd, posix.EPOLLET | posix.EPOLLOUT) catch unreachable);
+ os.EINTR => continue,
+ os.ESPIPE => unreachable,
+ os.EINVAL => unreachable,
+ os.EFAULT => unreachable,
+ os.EAGAIN => {
+ try await (async loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLOUT) catch unreachable);
continue;
},
- posix.EBADF => unreachable, // always a race condition
- posix.EDESTADDRREQ => unreachable, // connect was never called
- posix.EDQUOT => unreachable,
- posix.EFBIG => unreachable,
- posix.EIO => return error.InputOutput,
- posix.ENOSPC => unreachable,
- posix.EPERM => return error.AccessDenied,
- posix.EPIPE => unreachable,
- else => return os.unexpectedErrorPosix(err),
+ os.EBADF => unreachable, // always a race condition
+ os.EDESTADDRREQ => unreachable, // connect was never called
+ os.EDQUOT => unreachable,
+ os.EFBIG => unreachable,
+ os.EIO => return error.InputOutput,
+ os.ENOSPC => unreachable,
+ os.EPERM => return error.AccessDenied,
+ os.EPIPE => unreachable,
+ else => |err| return os.unexpectedErrno(err),
}
},
else => @compileError("Unsupported OS"),
@@ -199,27 +194,26 @@ pub async fn writevPosix(loop: *Loop, fd: i32, iov: [*]const posix.iovec_const,
}
/// returns number of bytes read. 0 means EOF.
-pub async fn readvPosix(loop: *std.event.Loop, fd: i32, iov: [*]posix.iovec, count: usize) !usize {
+pub async fn readvPosix(loop: *std.event.Loop, fd: i32, iov: [*]os.iovec, count: usize) !usize {
while (true) {
switch (builtin.os) {
builtin.Os.linux, builtin.Os.freebsd, builtin.Os.macosx => {
- const rc = posix.readv(fd, iov, count);
- const err = posix.getErrno(rc);
- switch (err) {
+ const rc = os.system.readv(fd, iov, count);
+ switch (os.errno(rc)) {
0 => return rc,
- posix.EINTR => continue,
- posix.EINVAL => unreachable,
- posix.EFAULT => unreachable,
- posix.EAGAIN => {
- try await (async loop.linuxWaitFd(fd, posix.EPOLLET | posix.EPOLLIN) catch unreachable);
+ os.EINTR => continue,
+ os.EINVAL => unreachable,
+ os.EFAULT => unreachable,
+ os.EAGAIN => {
+ try await (async loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLIN) catch unreachable);
continue;
},
- posix.EBADF => unreachable, // always a race condition
- posix.EIO => return error.InputOutput,
- posix.EISDIR => unreachable,
- posix.ENOBUFS => return error.SystemResources,
- posix.ENOMEM => return error.SystemResources,
- else => return os.unexpectedErrorPosix(err),
+ os.EBADF => unreachable, // always a race condition
+ os.EIO => return error.InputOutput,
+ os.EISDIR => unreachable,
+ os.ENOBUFS => return error.SystemResources,
+ os.ENOMEM => return error.SystemResources,
+ else => |err| return os.unexpectedErrno(err),
}
},
else => @compileError("Unsupported OS"),
@@ -227,12 +221,12 @@ pub async fn readvPosix(loop: *std.event.Loop, fd: i32, iov: [*]posix.iovec, cou
}
}
-pub async fn writev(loop: *Loop, fd: os.FileHandle, data: []const []const u8) !void {
- const iovecs = try loop.allocator.alloc(os.posix.iovec_const, data.len);
+pub async fn writev(loop: *Loop, fd: fd_t, data: []const []const u8) !void {
+ const iovecs = try loop.allocator.alloc(os.iovec_const, data.len);
defer loop.allocator.free(iovecs);
for (data) |buf, i| {
- iovecs[i] = os.posix.iovec_const{
+ iovecs[i] = os.iovec_const{
.iov_base = buf.ptr,
.iov_len = buf.len,
};
@@ -241,12 +235,12 @@ pub async fn writev(loop: *Loop, fd: os.FileHandle, data: []const []const u8) !v
return await (async writevPosix(loop, fd, iovecs.ptr, data.len) catch unreachable);
}
-pub async fn readv(loop: *Loop, fd: os.FileHandle, data: []const []u8) !usize {
- const iovecs = try loop.allocator.alloc(os.posix.iovec, data.len);
+pub async fn readv(loop: *Loop, fd: fd_t, data: []const []u8) !usize {
+ const iovecs = try loop.allocator.alloc(os.iovec, data.len);
defer loop.allocator.free(iovecs);
for (data) |buf, i| {
- iovecs[i] = os.posix.iovec{
+ iovecs[i] = os.iovec{
.iov_base = buf.ptr,
.iov_len = buf.len,
};
@@ -255,17 +249,17 @@ pub async fn readv(loop: *Loop, fd: os.FileHandle, data: []const []u8) !usize {
return await (async readvPosix(loop, fd, iovecs.ptr, data.len) catch unreachable);
}
-pub async fn connect(loop: *Loop, _address: *const std.net.Address) !os.File {
+pub async fn connect(loop: *Loop, _address: *const std.net.Address) !File {
var address = _address.*; // TODO https://github.com/ziglang/zig/issues/1592
- const sockfd = try os.posixSocket(posix.AF_INET, posix.SOCK_STREAM | posix.SOCK_CLOEXEC | posix.SOCK_NONBLOCK, posix.PROTO_tcp);
+ const sockfd = try os.socket(os.AF_INET, os.SOCK_STREAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK, os.PROTO_tcp);
errdefer os.close(sockfd);
- try os.posixConnectAsync(sockfd, &address.os_addr, @sizeOf(posix.sockaddr_in));
- try await try async loop.linuxWaitFd(sockfd, posix.EPOLLIN | posix.EPOLLOUT | posix.EPOLLET);
- try os.posixGetSockOptConnectError(sockfd);
+ try os.connect_async(sockfd, &address.os_addr, @sizeOf(os.sockaddr_in));
+ try await try async loop.linuxWaitFd(sockfd, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
+ try os.getsockoptError(sockfd);
- return os.File.openHandle(sockfd);
+ return File.openHandle(sockfd);
}
test "listen on a port, send bytes, receive bytes" {
@@ -281,7 +275,7 @@ test "listen on a port, send bytes, receive bytes" {
tcp_server: Server,
const Self = @This();
- async<*mem.Allocator> fn handler(tcp_server: *Server, _addr: *const std.net.Address, _socket: os.File) void {
+ async<*mem.Allocator> fn handler(tcp_server: *Server, _addr: *const std.net.Address, _socket: File) void {
const self = @fieldParentPtr(Self, "tcp_server", tcp_server);
var socket = _socket; // TODO https://github.com/ziglang/zig/issues/1592
defer socket.close();
@@ -294,7 +288,7 @@ test "listen on a port, send bytes, receive bytes" {
cancel @handle();
}
}
- async fn errorableHandler(self: *Self, _addr: *const std.net.Address, _socket: os.File) !void {
+ async fn errorableHandler(self: *Self, _addr: *const std.net.Address, _socket: File) !void {
const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/1592
var socket = _socket; // TODO https://github.com/ziglang/zig/issues/1592
@@ -331,14 +325,14 @@ async fn doAsyncTest(loop: *Loop, address: *const std.net.Address, server: *Serv
}
pub const OutStream = struct {
- fd: os.FileHandle,
+ fd: fd_t,
stream: Stream,
loop: *Loop,
pub const Error = WriteError;
pub const Stream = event.io.OutStream(Error);
- pub fn init(loop: *Loop, fd: os.FileHandle) OutStream {
+ pub fn init(loop: *Loop, fd: fd_t) OutStream {
return OutStream{
.fd = fd,
.loop = loop,
@@ -353,14 +347,14 @@ pub const OutStream = struct {
};
pub const InStream = struct {
- fd: os.FileHandle,
+ fd: fd_t,
stream: Stream,
loop: *Loop,
pub const Error = ReadError;
pub const Stream = event.io.InStream(Error);
- pub fn init(loop: *Loop, fd: os.FileHandle) InStream {
+ pub fn init(loop: *Loop, fd: fd_t) InStream {
return InStream{
.fd = fd,
.loop = loop,
diff --git a/std/event/rwlock.zig b/std/event/rwlock.zig
index 76b364fedc..00f3c0bc60 100644
--- a/std/event/rwlock.zig
+++ b/std/event/rwlock.zig
@@ -271,7 +271,7 @@ async fn writeRunner(lock: *RwLock) void {
var i: usize = 0;
while (i < shared_test_data.len) : (i += 1) {
- std.os.time.sleep(100 * std.os.time.microsecond);
+ std.time.sleep(100 * std.time.microsecond);
const lock_promise = async lock.acquireWrite() catch @panic("out of memory");
const handle = await lock_promise;
defer handle.release();
@@ -286,7 +286,7 @@ async fn writeRunner(lock: *RwLock) void {
async fn readRunner(lock: *RwLock) void {
suspend; // resumed by onNextTick
- std.os.time.sleep(1);
+ std.time.sleep(1);
var i: usize = 0;
while (i < shared_test_data.len) : (i += 1) {
diff --git a/std/fmt.zig b/std/fmt.zig
index 27a8abba6e..74c36f7086 100644
--- a/std/fmt.zig
+++ b/std/fmt.zig
@@ -226,7 +226,7 @@ pub fn formatType(
builtin.TypeInfo.Pointer.Size.Many => {
if (ptr_info.child == u8) {
if (fmt.len > 0 and fmt[0] == 's') {
- const len = std.cstr.len(value);
+ const len = mem.len(u8, value);
return formatText(value[0..len], fmt, context, Errors, output);
}
}
diff --git a/std/fs.zig b/std/fs.zig
new file mode 100644
index 0000000000..6d5874d7c0
--- /dev/null
+++ b/std/fs.zig
@@ -0,0 +1,808 @@
+const builtin = @import("builtin");
+const std = @import("std.zig");
+const os = std.os;
+const mem = std.mem;
+const base64 = std.base64;
+const crypto = std.crypto;
+const Allocator = std.mem.Allocator;
+const assert = std.debug.assert;
+
+pub const path = @import("fs/path.zig");
+pub const File = @import("fs/file.zig").File;
+
+pub const symLink = os.symlink;
+pub const symLinkC = os.symlinkC;
+pub const deleteFile = os.unlink;
+pub const deleteFileC = os.unlinkC;
+pub const rename = os.rename;
+pub const renameC = os.renameC;
+pub const renameW = os.renameW;
+pub const realpath = os.realpath;
+pub const realpathC = os.realpathC;
+pub const realpathW = os.realpathW;
+
+pub const getAppDataDir = @import("fs/get_app_data_dir.zig").getAppDataDir;
+pub const GetAppDataDirError = @import("fs/get_app_data_dir.zig").GetAppDataDirError;
+
+/// This represents the maximum size of a UTF-8 encoded file path.
+/// All file system operations which return a path are guaranteed to
+/// fit into a UTF-8 encoded array of this length.
+/// path being too long if it is this 0long
+pub const MAX_PATH_BYTES = switch (builtin.os) {
+ .linux, .macosx, .ios, .freebsd, .netbsd => os.PATH_MAX,
+ // Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
+ // If it would require 4 UTF-8 bytes, then there would be a surrogate
+ // pair in the UTF-16LE, and we (over)account 3 bytes for it that way.
+ // +1 for the null byte at the end, which can be encoded in 1 byte.
+ .windows => os.windows.PATH_MAX_WIDE * 3 + 1,
+ else => @compileError("Unsupported OS"),
+};
+
+// here we replace the standard +/ with -_ so that it can be used in a file name
+const b64_fs_encoder = base64.Base64Encoder.init("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", base64.standard_pad_char);
+
+/// TODO remove the allocator requirement from this API
+pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) !void {
+ if (symLink(existing_path, new_path)) {
+ return;
+ } else |err| switch (err) {
+ error.PathAlreadyExists => {},
+ else => return err, // TODO zig should know this set does not include PathAlreadyExists
+ }
+
+ const dirname = path.dirname(new_path) orelse ".";
+
+ var rand_buf: [12]u8 = undefined;
+ const tmp_path = try allocator.alloc(u8, dirname.len + 1 + base64.Base64Encoder.calcSize(rand_buf.len));
+ defer allocator.free(tmp_path);
+ mem.copy(u8, tmp_path[0..], dirname);
+ tmp_path[dirname.len] = path.sep;
+ while (true) {
+ try crypto.randomBytes(rand_buf[0..]);
+ b64_fs_encoder.encode(tmp_path[dirname.len + 1 ..], rand_buf);
+
+ if (symLink(existing_path, tmp_path)) {
+ return rename(tmp_path, new_path);
+ } else |err| switch (err) {
+ error.PathAlreadyExists => continue,
+ else => return err, // TODO zig should know this set does not include PathAlreadyExists
+ }
+ }
+}
+
+/// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is
+/// merged and readily available,
+/// there is a possibility of power loss or application termination leaving temporary files present
+/// in the same directory as dest_path.
+/// Destination file will have the same mode as the source file.
+pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void {
+ var in_file = try File.openRead(source_path);
+ defer in_file.close();
+
+ const mode = try in_file.mode();
+ const in_stream = &in_file.inStream().stream;
+
+ var atomic_file = try AtomicFile.init(dest_path, mode);
+ defer atomic_file.deinit();
+
+ var buf: [mem.page_size]u8 = undefined;
+ while (true) {
+ const amt = try in_stream.readFull(buf[0..]);
+ try atomic_file.file.write(buf[0..amt]);
+ if (amt != buf.len) {
+ return atomic_file.finish();
+ }
+ }
+}
+
+/// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is
+/// merged and readily available,
+/// there is a possibility of power loss or application termination leaving temporary files present
+pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void {
+ var in_file = try File.openRead(source_path);
+ defer in_file.close();
+
+ var atomic_file = try AtomicFile.init(dest_path, mode);
+ defer atomic_file.deinit();
+
+ var buf: [mem.page_size]u8 = undefined;
+ while (true) {
+ const amt = try in_file.read(buf[0..]);
+ try atomic_file.file.write(buf[0..amt]);
+ if (amt != buf.len) {
+ return atomic_file.finish();
+ }
+ }
+}
+
+pub const AtomicFile = struct {
+ file: File,
+ tmp_path_buf: [MAX_PATH_BYTES]u8,
+ dest_path: []const u8,
+ finished: bool,
+
+ const InitError = File.OpenError;
+
+ /// dest_path must remain valid for the lifetime of AtomicFile
+ /// call finish to atomically replace dest_path with contents
+ /// TODO once we have null terminated pointers, use the
+ /// openWriteNoClobberN function
+ pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile {
+ const dirname = path.dirname(dest_path);
+ var rand_buf: [12]u8 = undefined;
+ const dirname_component_len = if (dirname) |d| d.len + 1 else 0;
+ const encoded_rand_len = comptime base64.Base64Encoder.calcSize(rand_buf.len);
+ const tmp_path_len = dirname_component_len + encoded_rand_len;
+ var tmp_path_buf: [MAX_PATH_BYTES]u8 = undefined;
+ if (tmp_path_len >= tmp_path_buf.len) return error.NameTooLong;
+
+ if (dirname) |dir| {
+ mem.copy(u8, tmp_path_buf[0..], dir);
+ tmp_path_buf[dir.len] = path.sep;
+ }
+
+ tmp_path_buf[tmp_path_len] = 0;
+
+ while (true) {
+ try crypto.randomBytes(rand_buf[0..]);
+ b64_fs_encoder.encode(tmp_path_buf[dirname_component_len..tmp_path_len], rand_buf);
+
+ const file = File.openWriteNoClobberC(&tmp_path_buf, mode) catch |err| switch (err) {
+ error.PathAlreadyExists => continue,
+ // TODO zig should figure out that this error set does not include PathAlreadyExists since
+ // it is handled in the above switch
+ else => return err,
+ };
+
+ return AtomicFile{
+ .file = file,
+ .tmp_path_buf = tmp_path_buf,
+ .dest_path = dest_path,
+ .finished = false,
+ };
+ }
+ }
+
+ /// always call deinit, even after successful finish()
+ pub fn deinit(self: *AtomicFile) void {
+ if (!self.finished) {
+ self.file.close();
+ deleteFileC(&self.tmp_path_buf) catch {};
+ self.finished = true;
+ }
+ }
+
+ pub fn finish(self: *AtomicFile) !void {
+ assert(!self.finished);
+ self.file.close();
+ self.finished = true;
+ if (os.windows.is_the_target) {
+ const dest_path_w = try os.windows.sliceToPrefixedFileW(self.dest_path);
+ const tmp_path_w = try os.windows.cStrToPrefixedFileW(&self.tmp_path_buf);
+ return os.renameW(&tmp_path_w, &dest_path_w);
+ }
+ const dest_path_c = try os.toPosixPath(self.dest_path);
+ return os.renameC(&self.tmp_path_buf, &dest_path_c);
+ }
+};
+
+const default_new_dir_mode = 0o755;
+
+/// Create a new directory.
+pub fn makeDir(dir_path: []const u8) !void {
+ return os.mkdir(dir_path, default_new_dir_mode);
+}
+
+/// Same as `makeDir` except the parameter is a null-terminated UTF8-encoded string.
+pub fn makeDirC(dir_path: [*]const u8) !void {
+ return os.mkdirC(dir_path, default_new_dir_mode);
+}
+
+/// Same as `makeDir` except the parameter is a null-terminated UTF16LE-encoded string.
+pub fn makeDirW(dir_path: [*]const u16) !void {
+ return os.mkdirW(dir_path, default_new_dir_mode);
+}
+
+/// Calls makeDir recursively to make an entire path. Returns success if the path
+/// already exists and is a directory.
+/// This function is not atomic, and if it returns an error, the file system may
+/// have been modified regardless.
+/// TODO determine if we can remove the allocator requirement from this function
+pub fn makePath(allocator: *Allocator, full_path: []const u8) !void {
+ const resolved_path = try path.resolve(allocator, [][]const u8{full_path});
+ defer allocator.free(resolved_path);
+
+ var end_index: usize = resolved_path.len;
+ while (true) {
+ makeDir(resolved_path[0..end_index]) catch |err| switch (err) {
+ error.PathAlreadyExists => {
+ // TODO stat the file and return an error if it's not a directory
+ // this is important because otherwise a dangling symlink
+ // could cause an infinite loop
+ if (end_index == resolved_path.len) return;
+ },
+ error.FileNotFound => {
+ // march end_index backward until next path component
+ while (true) {
+ end_index -= 1;
+ if (path.isSep(resolved_path[end_index])) break;
+ }
+ continue;
+ },
+ else => return err,
+ };
+ if (end_index == resolved_path.len) return;
+ // march end_index forward until next path component
+ while (true) {
+ end_index += 1;
+ if (end_index == resolved_path.len or path.isSep(resolved_path[end_index])) break;
+ }
+ }
+}
+
+/// Returns `error.DirNotEmpty` if the directory is not empty.
+/// To delete a directory recursively, see `deleteTree`.
+pub fn deleteDir(dir_path: []const u8) !void {
+ return os.rmdir(dir_path);
+}
+
+/// Same as `deleteDir` except the parameter is a null-terminated UTF8-encoded string.
+pub fn deleteDirC(dir_path: [*]const u8) !void {
+ return os.rmdirC(dir_path);
+}
+
+/// Same as `deleteDir` except the parameter is a null-terminated UTF16LE-encoded string.
+pub fn deleteDirW(dir_path: [*]const u16) !void {
+ return os.rmdirW(dir_path);
+}
+
+/// Whether ::full_path describes a symlink, file, or directory, this function
+/// removes it. If it cannot be removed because it is a non-empty directory,
+/// this function recursively removes its entries and then tries again.
+const DeleteTreeError = error{
+ OutOfMemory,
+ AccessDenied,
+ FileTooBig,
+ IsDir,
+ SymLinkLoop,
+ ProcessFdQuotaExceeded,
+ NameTooLong,
+ SystemFdQuotaExceeded,
+ NoDevice,
+ SystemResources,
+ NoSpaceLeft,
+ PathAlreadyExists,
+ ReadOnlyFileSystem,
+ NotDir,
+ FileNotFound,
+ FileSystem,
+ FileBusy,
+ DirNotEmpty,
+ DeviceBusy,
+
+ /// On Windows, file paths must be valid Unicode.
+ InvalidUtf8,
+
+ /// On Windows, file paths cannot contain these characters:
+ /// '/', '*', '?', '"', '<', '>', '|'
+ BadPathName,
+
+ Unexpected,
+};
+
+/// TODO determine if we can remove the allocator requirement
+pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!void {
+ start_over: while (true) {
+ var got_access_denied = false;
+ // First, try deleting the item as a file. This way we don't follow sym links.
+ if (deleteFile(full_path)) {
+ return;
+ } else |err| switch (err) {
+ error.FileNotFound => return,
+ error.IsDir => {},
+ error.AccessDenied => got_access_denied = true,
+
+ error.InvalidUtf8,
+ error.SymLinkLoop,
+ error.NameTooLong,
+ error.SystemResources,
+ error.ReadOnlyFileSystem,
+ error.NotDir,
+ error.FileSystem,
+ error.FileBusy,
+ error.BadPathName,
+ error.Unexpected,
+ => return err,
+ }
+ {
+ var dir = Dir.open(allocator, full_path) catch |err| switch (err) {
+ error.NotDir => {
+ if (got_access_denied) {
+ return error.AccessDenied;
+ }
+ continue :start_over;
+ },
+
+ error.OutOfMemory,
+ error.AccessDenied,
+ error.FileTooBig,
+ error.IsDir,
+ error.SymLinkLoop,
+ error.ProcessFdQuotaExceeded,
+ error.NameTooLong,
+ error.SystemFdQuotaExceeded,
+ error.NoDevice,
+ error.FileNotFound,
+ error.SystemResources,
+ error.NoSpaceLeft,
+ error.PathAlreadyExists,
+ error.Unexpected,
+ error.InvalidUtf8,
+ error.BadPathName,
+ error.DeviceBusy,
+ => return err,
+ };
+ defer dir.close();
+
+ var full_entry_buf = std.ArrayList(u8).init(allocator);
+ defer full_entry_buf.deinit();
+
+ while (try dir.next()) |entry| {
+ try full_entry_buf.resize(full_path.len + entry.name.len + 1);
+ const full_entry_path = full_entry_buf.toSlice();
+ mem.copy(u8, full_entry_path, full_path);
+ full_entry_path[full_path.len] = path.sep;
+ mem.copy(u8, full_entry_path[full_path.len + 1 ..], entry.name);
+
+ try deleteTree(allocator, full_entry_path);
+ }
+ }
+ return deleteDir(full_path);
+ }
+}
+
+pub const Dir = struct {
+ handle: Handle,
+ allocator: *Allocator,
+
+ pub const Handle = switch (builtin.os) {
+ .macosx, .ios, .freebsd, .netbsd => struct {
+ fd: i32,
+ seek: i64,
+ buf: []u8,
+ index: usize,
+ end_index: usize,
+ },
+ .linux => struct {
+ fd: i32,
+ buf: []u8,
+ index: usize,
+ end_index: usize,
+ },
+ .windows => struct {
+ handle: os.windows.HANDLE,
+ find_file_data: os.windows.WIN32_FIND_DATAW,
+ first: bool,
+ name_data: [256]u8,
+ },
+ else => @compileError("unimplemented"),
+ };
+
+ pub const Entry = struct {
+ name: []const u8,
+ kind: Kind,
+
+ pub const Kind = enum {
+ BlockDevice,
+ CharacterDevice,
+ Directory,
+ NamedPipe,
+ SymLink,
+ File,
+ UnixDomainSocket,
+ Whiteout,
+ Unknown,
+ };
+ };
+
+ pub const OpenError = error{
+ FileNotFound,
+ NotDir,
+ AccessDenied,
+ FileTooBig,
+ IsDir,
+ SymLinkLoop,
+ ProcessFdQuotaExceeded,
+ NameTooLong,
+ SystemFdQuotaExceeded,
+ NoDevice,
+ SystemResources,
+ NoSpaceLeft,
+ PathAlreadyExists,
+ OutOfMemory,
+ InvalidUtf8,
+ BadPathName,
+ DeviceBusy,
+
+ Unexpected,
+ };
+
+ /// TODO remove the allocator requirement from this API
+ pub fn open(allocator: *Allocator, dir_path: []const u8) OpenError!Dir {
+ return Dir{
+ .allocator = allocator,
+ .handle = switch (builtin.os) {
+ .windows => blk: {
+ var find_file_data: os.windows.WIN32_FIND_DATAW = undefined;
+ const handle = try os.windows.FindFirstFile(dir_path, &find_file_data);
+ break :blk Handle{
+ .handle = handle,
+ .find_file_data = find_file_data, // TODO guaranteed copy elision
+ .first = true,
+ .name_data = undefined,
+ };
+ },
+ .macosx, .ios, .freebsd, .netbsd => Handle{
+ .fd = try os.open(dir_path, os.O_RDONLY | os.O_NONBLOCK | os.O_DIRECTORY | os.O_CLOEXEC, 0),
+ .seek = 0,
+ .index = 0,
+ .end_index = 0,
+ .buf = []u8{},
+ },
+ .linux => Handle{
+ .fd = try os.open(dir_path, os.O_RDONLY | os.O_DIRECTORY | os.O_CLOEXEC, 0),
+ .index = 0,
+ .end_index = 0,
+ .buf = []u8{},
+ },
+ else => @compileError("unimplemented"),
+ },
+ };
+ }
+
+ pub fn close(self: *Dir) void {
+ if (os.windows.is_the_target) {
+ return os.windows.FindClose(self.handle.handle);
+ }
+ self.allocator.free(self.handle.buf);
+ os.close(self.handle.fd);
+ }
+
+ /// Memory such as file names referenced in this returned entry becomes invalid
+ /// with subsequent calls to next, as well as when this `Dir` is deinitialized.
+ pub fn next(self: *Dir) !?Entry {
+ switch (builtin.os) {
+ .linux => return self.nextLinux(),
+ .macosx, .ios => return self.nextDarwin(),
+ .windows => return self.nextWindows(),
+ .freebsd => return self.nextBsd(),
+ .netbsd => return self.nextBsd(),
+ else => @compileError("unimplemented"),
+ }
+ }
+
+ fn nextDarwin(self: *Dir) !?Entry {
+ start_over: while (true) {
+ if (self.handle.index >= self.handle.end_index) {
+ if (self.handle.buf.len == 0) {
+ self.handle.buf = try self.allocator.alloc(u8, mem.page_size);
+ }
+
+ while (true) {
+ const rc = os.system.__getdirentries64(
+ self.handle.fd,
+ self.handle.buf.ptr,
+ self.handle.buf.len,
+ &self.handle.seek,
+ );
+ if (rc == 0) return null;
+ if (rc < 0) {
+ switch (os.errno(rc)) {
+ os.EBADF => unreachable,
+ os.EFAULT => unreachable,
+ os.ENOTDIR => unreachable,
+ os.EINVAL => {
+ self.handle.buf = try self.allocator.realloc(self.handle.buf, self.handle.buf.len * 2);
+ continue;
+ },
+ else => |err| return os.unexpectedErrno(err),
+ }
+ }
+ self.handle.index = 0;
+ self.handle.end_index = @intCast(usize, rc);
+ break;
+ }
+ }
+ const darwin_entry = @ptrCast(*align(1) os.dirent, &self.handle.buf[self.handle.index]);
+ const next_index = self.handle.index + darwin_entry.d_reclen;
+ self.handle.index = next_index;
+
+ const name = @ptrCast([*]u8, &darwin_entry.d_name)[0..darwin_entry.d_namlen];
+
+ if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
+ continue :start_over;
+ }
+
+ const entry_kind = switch (darwin_entry.d_type) {
+ os.DT_BLK => Entry.Kind.BlockDevice,
+ os.DT_CHR => Entry.Kind.CharacterDevice,
+ os.DT_DIR => Entry.Kind.Directory,
+ os.DT_FIFO => Entry.Kind.NamedPipe,
+ os.DT_LNK => Entry.Kind.SymLink,
+ os.DT_REG => Entry.Kind.File,
+ os.DT_SOCK => Entry.Kind.UnixDomainSocket,
+ os.DT_WHT => Entry.Kind.Whiteout,
+ else => Entry.Kind.Unknown,
+ };
+ return Entry{
+ .name = name,
+ .kind = entry_kind,
+ };
+ }
+ }
+
+ fn nextWindows(self: *Dir) !?Entry {
+ while (true) {
+ if (self.handle.first) {
+ self.handle.first = false;
+ } else {
+ if (!try os.windows.FindNextFile(self.handle.handle, &self.handle.find_file_data))
+ return null;
+ }
+ const name_utf16le = mem.toSlice(u16, self.handle.find_file_data.cFileName[0..].ptr);
+ if (mem.eql(u16, name_utf16le, []u16{'.'}) or mem.eql(u16, name_utf16le, []u16{ '.', '.' }))
+ continue;
+ // Trust that Windows gives us valid UTF-16LE
+ const name_utf8_len = std.unicode.utf16leToUtf8(self.handle.name_data[0..], name_utf16le) catch unreachable;
+ const name_utf8 = self.handle.name_data[0..name_utf8_len];
+ const kind = blk: {
+ const attrs = self.handle.find_file_data.dwFileAttributes;
+ if (attrs & os.windows.FILE_ATTRIBUTE_DIRECTORY != 0) break :blk Entry.Kind.Directory;
+ if (attrs & os.windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) break :blk Entry.Kind.SymLink;
+ if (attrs & os.windows.FILE_ATTRIBUTE_NORMAL != 0) break :blk Entry.Kind.File;
+ break :blk Entry.Kind.Unknown;
+ };
+ return Entry{
+ .name = name_utf8,
+ .kind = kind,
+ };
+ }
+ }
+
+ fn nextLinux(self: *Dir) !?Entry {
+ start_over: while (true) {
+ if (self.handle.index >= self.handle.end_index) {
+ if (self.handle.buf.len == 0) {
+ self.handle.buf = try self.allocator.alloc(u8, mem.page_size);
+ }
+
+ while (true) {
+ const rc = os.linux.getdents64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len);
+ switch (os.linux.getErrno(rc)) {
+ 0 => {},
+ os.EBADF => unreachable,
+ os.EFAULT => unreachable,
+ os.ENOTDIR => unreachable,
+ os.EINVAL => {
+ self.handle.buf = try self.allocator.realloc(self.handle.buf, self.handle.buf.len * 2);
+ continue;
+ },
+ else => |err| return os.unexpectedErrno(err),
+ }
+ if (rc == 0) return null;
+ self.handle.index = 0;
+ self.handle.end_index = rc;
+ break;
+ }
+ }
+ const linux_entry = @ptrCast(*align(1) os.dirent64, &self.handle.buf[self.handle.index]);
+ const next_index = self.handle.index + linux_entry.d_reclen;
+ self.handle.index = next_index;
+
+ const name = mem.toSlice(u8, @ptrCast([*]u8, &linux_entry.d_name));
+
+ // skip . and .. entries
+ if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
+ continue :start_over;
+ }
+
+ const entry_kind = switch (linux_entry.d_type) {
+ os.DT_BLK => Entry.Kind.BlockDevice,
+ os.DT_CHR => Entry.Kind.CharacterDevice,
+ os.DT_DIR => Entry.Kind.Directory,
+ os.DT_FIFO => Entry.Kind.NamedPipe,
+ os.DT_LNK => Entry.Kind.SymLink,
+ os.DT_REG => Entry.Kind.File,
+ os.DT_SOCK => Entry.Kind.UnixDomainSocket,
+ else => Entry.Kind.Unknown,
+ };
+ return Entry{
+ .name = name,
+ .kind = entry_kind,
+ };
+ }
+ }
+
+ fn nextBsd(self: *Dir) !?Entry {
+ start_over: while (true) {
+ if (self.handle.index >= self.handle.end_index) {
+ if (self.handle.buf.len == 0) {
+ self.handle.buf = try self.allocator.alloc(u8, mem.page_size);
+ }
+
+ while (true) {
+ const rc = os.system.getdirentries(
+ self.handle.fd,
+ self.handle.buf.ptr,
+ self.handle.buf.len,
+ &self.handle.seek,
+ );
+ switch (os.errno(rc)) {
+ 0 => {},
+ os.EBADF => unreachable,
+ os.EFAULT => unreachable,
+ os.ENOTDIR => unreachable,
+ os.EINVAL => {
+ self.handle.buf = try self.allocator.realloc(self.handle.buf, self.handle.buf.len * 2);
+ continue;
+ },
+ else => |err| return os.unexpectedErrno(err),
+ }
+ if (rc == 0) return null;
+ self.handle.index = 0;
+ self.handle.end_index = @intCast(usize, rc);
+ break;
+ }
+ }
+ const freebsd_entry = @ptrCast(*align(1) os.dirent, &self.handle.buf[self.handle.index]);
+ const next_index = self.handle.index + freebsd_entry.d_reclen;
+ self.handle.index = next_index;
+
+ const name = @ptrCast([*]u8, &freebsd_entry.d_name)[0..freebsd_entry.d_namlen];
+
+ if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
+ continue :start_over;
+ }
+
+ const entry_kind = switch (freebsd_entry.d_type) {
+ os.DT_BLK => Entry.Kind.BlockDevice,
+ os.DT_CHR => Entry.Kind.CharacterDevice,
+ os.DT_DIR => Entry.Kind.Directory,
+ os.DT_FIFO => Entry.Kind.NamedPipe,
+ os.DT_LNK => Entry.Kind.SymLink,
+ os.DT_REG => Entry.Kind.File,
+ os.DT_SOCK => Entry.Kind.UnixDomainSocket,
+ os.DT_WHT => Entry.Kind.Whiteout,
+ else => Entry.Kind.Unknown,
+ };
+ return Entry{
+ .name = name,
+ .kind = entry_kind,
+ };
+ }
+ }
+};
+
+/// Read value of a symbolic link.
+/// The return value is a slice of buffer, from index `0`.
+pub fn readLink(pathname: []const u8, buffer: *[os.PATH_MAX]u8) ![]u8 {
+ return os.readlink(pathname, buffer);
+}
+
+/// Same as `readLink`, except the `pathname` parameter is null-terminated.
+pub fn readLinkC(pathname: [*]const u8, buffer: *[os.PATH_MAX]u8) ![]u8 {
+ return os.readlinkC(pathname, buffer);
+}
+
+pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfExePathError;
+
+pub fn openSelfExe() OpenSelfExeError!File {
+ if (os.linux.is_the_target) {
+ return File.openReadC(c"/proc/self/exe");
+ }
+ if (os.windows.is_the_target) {
+ var buf: [os.windows.PATH_MAX_WIDE]u16 = undefined;
+ const wide_slice = try selfExePathW(&buf);
+ return File.openReadW(wide_slice.ptr);
+ }
+ var buf: [MAX_PATH_BYTES]u8 = undefined;
+ const self_exe_path = try selfExePath(&buf);
+ buf[self_exe_path.len] = 0;
+ return File.openReadC(self_exe_path.ptr);
+}
+
+test "openSelfExe" {
+ switch (builtin.os) {
+ .linux, .macosx, .ios, .windows, .freebsd => (try openSelfExe()).close(),
+ else => return error.SkipZigTest, // Unsupported OS.
+ }
+}
+
+pub const SelfExePathError = os.ReadLinkError || os.SysCtlError;
+
+/// Get the path to the current executable.
+/// If you only need the directory, use selfExeDirPath.
+/// If you only want an open file handle, use openSelfExe.
+/// This function may return an error if the current executable
+/// was deleted after spawning.
+/// Returned value is a slice of out_buffer.
+///
+/// On Linux, depends on procfs being mounted. If the currently executing binary has
+/// been deleted, the file path looks something like `/a/b/c/exe (deleted)`.
+/// TODO make the return type of this a null terminated pointer
+pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]u8 {
+ if (os.darwin.is_the_target) {
+ var u32_len: u32 = out_buffer.len;
+ const rc = std.c._NSGetExecutablePath(out_buffer, &u32_len);
+ if (rc != 0) return error.NameTooLong;
+ return mem.toSlice(u8, out_buffer);
+ }
+ switch (builtin.os) {
+ .linux => return os.readlinkC(c"/proc/self/exe", out_buffer),
+ .freebsd => {
+ var mib = [4]c_int{ os.CTL_KERN, os.KERN_PROC, os.KERN_PROC_PATHNAME, -1 };
+ var out_len: usize = out_buffer.len;
+ try os.sysctl(&mib, out_buffer, &out_len, null, 0);
+ // TODO could this slice from 0 to out_len instead?
+ return mem.toSlice(u8, out_buffer);
+ },
+ .netbsd => {
+ var mib = [4]c_int{ os.CTL_KERN, os.KERN_PROC_ARGS, -1, os.KERN_PROC_PATHNAME };
+ var out_len: usize = out_buffer.len;
+ try os.sysctl(&mib, out_buffer, &out_len, null, 0);
+ // TODO could this slice from 0 to out_len instead?
+ return mem.toSlice(u8, out_buffer);
+ },
+ .windows => {
+ var utf16le_buf: [os.windows.PATH_MAX_WIDE]u16 = undefined;
+ const utf16le_slice = try selfExePathW(&utf16le_buf);
+ // Trust that Windows gives us valid UTF-16LE.
+ const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
+ return out_buffer[0..end_index];
+ },
+ else => @compileError("std.fs.selfExePath not supported for this target"),
+ }
+}
+
+/// Same as `selfExePath` except the result is UTF16LE-encoded.
+pub fn selfExePathW(out_buffer: *[os.windows.PATH_MAX_WIDE]u16) SelfExePathError![]u16 {
+ return os.windows.GetModuleFileNameW(null, out_buffer, out_buffer.len);
+}
+
+/// `selfExeDirPath` except allocates the result on the heap.
+/// Caller owns returned memory.
+pub fn selfExeDirPathAlloc(allocator: *Allocator) ![]u8 {
+ var buf: [MAX_PATH_BYTES]u8 = undefined;
+ return mem.dupe(allocator, u8, try selfExeDirPath(&buf));
+}
+
+/// Get the directory path that contains the current executable.
+/// Returned value is a slice of out_buffer.
+pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const u8 {
+ if (os.linux.is_the_target) {
+ // If the currently executing binary has been deleted,
+ // the file path looks something like `/a/b/c/exe (deleted)`
+ // This path cannot be opened, but it's valid for determining the directory
+ // the executable was in when it was run.
+ const full_exe_path = try os.readlinkC(c"/proc/self/exe", out_buffer);
+ // Assume that /proc/self/exe has an absolute path, and therefore dirname
+ // will not return null.
+ return path.dirname(full_exe_path).?;
+ }
+ const self_exe_path = try selfExePath(out_buffer);
+ // Assume that the OS APIs return absolute paths, and therefore dirname
+ // will not return null.
+ return path.dirname(self_exe_path).?;
+}
+
+/// `realpath`, except caller must free the returned memory.
+pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 {
+ var buf: [MAX_PATH_BYTES]u8 = undefined;
+ return mem.dupe(allocator, u8, try os.realpath(pathname, &buf));
+}
+
+test "" {
+ _ = @import("fs/path.zig");
+ _ = @import("fs/file.zig");
+ _ = @import("fs/get_app_data_dir.zig");
+}
diff --git a/std/fs/file.zig b/std/fs/file.zig
new file mode 100644
index 0000000000..589927b823
--- /dev/null
+++ b/std/fs/file.zig
@@ -0,0 +1,319 @@
+const std = @import("../std.zig");
+const builtin = @import("builtin");
+const os = std.os;
+const io = std.io;
+const mem = std.mem;
+const math = std.math;
+const assert = std.debug.assert;
+const windows = os.windows;
+const Os = builtin.Os;
+const maxInt = std.math.maxInt;
+
+pub const File = struct {
+ /// The OS-specific file descriptor or file handle.
+ handle: os.fd_t,
+
+ pub const Mode = switch (builtin.os) {
+ Os.windows => void,
+ else => u32,
+ };
+
+ pub const default_mode = switch (builtin.os) {
+ Os.windows => {},
+ else => 0o666,
+ };
+
+ pub const OpenError = windows.CreateFileError || os.OpenError;
+
+ /// Call close to clean up.
+ pub fn openRead(path: []const u8) OpenError!File {
+ if (windows.is_the_target) {
+ const path_w = try windows.sliceToPrefixedFileW(path);
+ return openReadW(&path_w);
+ }
+ const path_c = try os.toPosixPath(path);
+ return openReadC(&path_c);
+ }
+
+ /// `openRead` except with a null terminated path
+ pub fn openReadC(path: [*]const u8) OpenError!File {
+ if (windows.is_the_target) {
+ const path_w = try windows.cStrToPrefixedFileW(path);
+ return openReadW(&path_w);
+ }
+ const flags = os.O_LARGEFILE | os.O_RDONLY;
+ const fd = try os.openC(path, flags, 0);
+ return openHandle(fd);
+ }
+
+ /// `openRead` except with a null terminated UTF16LE encoded path
+ pub fn openReadW(path_w: [*]const u16) OpenError!File {
+ const handle = try windows.CreateFileW(
+ path_w,
+ windows.GENERIC_READ,
+ windows.FILE_SHARE_READ,
+ null,
+ windows.OPEN_EXISTING,
+ windows.FILE_ATTRIBUTE_NORMAL,
+ null,
+ );
+ return openHandle(handle);
+ }
+
+ /// Calls `openWriteMode` with `default_mode` for the mode.
+ pub fn openWrite(path: []const u8) OpenError!File {
+ return openWriteMode(path, default_mode);
+ }
+
+ /// If the path does not exist it will be created.
+ /// If a file already exists in the destination it will be truncated.
+ /// Call close to clean up.
+ pub fn openWriteMode(path: []const u8, file_mode: Mode) OpenError!File {
+ if (windows.is_the_target) {
+ const path_w = try windows.sliceToPrefixedFileW(path);
+ return openWriteModeW(&path_w, file_mode);
+ }
+ const path_c = try os.toPosixPath(path);
+ return openWriteModeC(&path_c, file_mode);
+ }
+
+ /// Same as `openWriteMode` except `path` is null-terminated.
+ pub fn openWriteModeC(path: [*]const u8, file_mode: Mode) OpenError!File {
+ if (windows.is_the_target) {
+ const path_w = try windows.cStrToPrefixedFileW(path);
+ return openWriteModeW(&path_w, file_mode);
+ }
+ const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_TRUNC;
+ const fd = try os.openC(path, flags, file_mode);
+ return openHandle(fd);
+ }
+
+ /// Same as `openWriteMode` except `path` is null-terminated and UTF16LE encoded
+ pub fn openWriteModeW(path_w: [*]const u16, file_mode: Mode) OpenError!File {
+ const handle = try windows.CreateFileW(
+ path_w,
+ windows.GENERIC_WRITE,
+ windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
+ null,
+ windows.CREATE_ALWAYS,
+ windows.FILE_ATTRIBUTE_NORMAL,
+ null,
+ );
+ return openHandle(handle);
+ }
+
+ /// If the path does not exist it will be created.
+ /// If a file already exists in the destination this returns OpenError.PathAlreadyExists
+ /// Call close to clean up.
+ pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File {
+ if (windows.is_the_target) {
+ const path_w = try windows.sliceToPrefixedFileW(path);
+ return openWriteNoClobberW(&path_w, file_mode);
+ }
+ const path_c = try os.toPosixPath(path);
+ return openWriteNoClobberC(&path_c, file_mode);
+ }
+
+ pub fn openWriteNoClobberC(path: [*]const u8, file_mode: Mode) OpenError!File {
+ if (windows.is_the_target) {
+ const path_w = try windows.cStrToPrefixedFileW(path);
+ return openWriteNoClobberW(&path_w, file_mode);
+ }
+ const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_EXCL;
+ const fd = try os.openC(path, flags, file_mode);
+ return openHandle(fd);
+ }
+
+ pub fn openWriteNoClobberW(path_w: [*]const u16, file_mode: Mode) OpenError!File {
+ const handle = try windows.CreateFileW(
+ path_w,
+ windows.GENERIC_WRITE,
+ windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
+ null,
+ windows.CREATE_NEW,
+ windows.FILE_ATTRIBUTE_NORMAL,
+ null,
+ );
+ return openHandle(handle);
+ }
+
+ pub fn openHandle(handle: os.fd_t) File {
+ return File{ .handle = handle };
+ }
+
+ /// Test for the existence of `path`.
+ /// `path` is UTF8-encoded.
+ /// In general it is recommended to avoid this function. For example,
+ /// instead of testing if a file exists and then opening it, just
+ /// open it and handle the error for file not found.
+ pub fn access(path: []const u8) !void {
+ return os.access(path, os.F_OK);
+ }
+
+ /// Same as `access` except the parameter is null-terminated.
+ pub fn accessC(path: [*]const u8) !void {
+ return os.accessC(path, os.F_OK);
+ }
+
+ /// Same as `access` except the parameter is null-terminated UTF16LE-encoded.
+ pub fn accessW(path: [*]const u16) !void {
+ return os.accessW(path, os.F_OK);
+ }
+
+ /// Upon success, the stream is in an uninitialized state. To continue using it,
+ /// you must use the open() function.
+ pub fn close(self: File) void {
+ return os.close(self.handle);
+ }
+
+ /// Test whether the file refers to a terminal.
+ /// See also `supportsAnsiEscapeCodes`.
+ pub fn isTty(self: File) bool {
+ return os.isatty(self.handle);
+ }
+
+ /// Test whether ANSI escape codes will be treated as such.
+ pub fn supportsAnsiEscapeCodes(self: File) bool {
+ if (windows.is_the_target) {
+ return os.isCygwinPty(self.handle);
+ }
+ return self.isTty();
+ }
+
+ pub const SeekError = os.SeekError;
+
+ /// Repositions read/write file offset relative to the current offset.
+ pub fn seekBy(self: File, offset: i64) SeekError!void {
+ return os.lseek_CUR(self.handle, offset);
+ }
+
+ /// Repositions read/write file offset relative to the end.
+ pub fn seekFromEnd(self: File, offset: i64) SeekError!void {
+ return os.lseek_END(self.handle, offset);
+ }
+
+ /// Repositions read/write file offset relative to the beginning.
+ pub fn seekTo(self: File, offset: u64) SeekError!void {
+ return os.lseek_SET(self.handle, offset);
+ }
+
+ pub const GetPosError = os.SeekError || os.FStatError;
+
+ pub fn getPos(self: File) GetPosError!u64 {
+ return os.lseek_CUR_get(self.handle);
+ }
+
+ pub fn getEndPos(self: File) GetPosError!u64 {
+ if (windows.is_the_target) {
+ return windows.GetFileSizeEx(self.handle);
+ }
+ const stat = try os.fstat(self.handle);
+ return @bitCast(u64, stat.size);
+ }
+
+ pub const ModeError = os.FStatError;
+
+ pub fn mode(self: File) ModeError!Mode {
+ if (windows.is_the_target) {
+ return {};
+ }
+ const stat = try os.fstat(self.handle);
+ // TODO: we should be able to cast u16 to ModeError!u32, making this
+ // explicit cast not necessary
+ return Mode(stat.mode);
+ }
+
+ pub const ReadError = os.ReadError;
+
+ pub fn read(self: File, buffer: []u8) ReadError!usize {
+ return os.read(self.handle, buffer);
+ }
+
+ pub const WriteError = os.WriteError;
+
+ pub fn write(self: File, bytes: []const u8) WriteError!void {
+ return os.write(self.handle, bytes);
+ }
+
+ pub fn inStream(file: File) InStream {
+ return InStream{
+ .file = file,
+ .stream = InStream.Stream{ .readFn = InStream.readFn },
+ };
+ }
+
+ pub fn outStream(file: File) OutStream {
+ return OutStream{
+ .file = file,
+ .stream = OutStream.Stream{ .writeFn = OutStream.writeFn },
+ };
+ }
+
+ pub fn seekableStream(file: File) SeekableStream {
+ return SeekableStream{
+ .file = file,
+ .stream = SeekableStream.Stream{
+ .seekToFn = SeekableStream.seekToFn,
+ .seekByFn = SeekableStream.seekByFn,
+ .getPosFn = SeekableStream.getPosFn,
+ .getEndPosFn = SeekableStream.getEndPosFn,
+ },
+ };
+ }
+
+ /// Implementation of io.InStream trait for File
+ pub const InStream = struct {
+ file: File,
+ stream: Stream,
+
+ pub const Error = ReadError;
+ pub const Stream = io.InStream(Error);
+
+ fn readFn(in_stream: *Stream, buffer: []u8) Error!usize {
+ const self = @fieldParentPtr(InStream, "stream", in_stream);
+ return self.file.read(buffer);
+ }
+ };
+
+ /// Implementation of io.OutStream trait for File
+ pub const OutStream = struct {
+ file: File,
+ stream: Stream,
+
+ pub const Error = WriteError;
+ pub const Stream = io.OutStream(Error);
+
+ fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void {
+ const self = @fieldParentPtr(OutStream, "stream", out_stream);
+ return self.file.write(bytes);
+ }
+ };
+
+ /// Implementation of io.SeekableStream trait for File
+ pub const SeekableStream = struct {
+ file: File,
+ stream: Stream,
+
+ pub const Stream = io.SeekableStream(SeekError, GetPosError);
+
+ pub fn seekToFn(seekable_stream: *Stream, pos: u64) SeekError!void {
+ const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
+ return self.file.seekTo(pos);
+ }
+
+ pub fn seekByFn(seekable_stream: *Stream, amt: i64) SeekError!void {
+ const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
+ return self.file.seekBy(amt);
+ }
+
+ pub fn getEndPosFn(seekable_stream: *Stream) GetPosError!u64 {
+ const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
+ return self.file.getEndPos();
+ }
+
+ pub fn getPosFn(seekable_stream: *Stream) GetPosError!u64 {
+ const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
+ return self.file.getPos();
+ }
+ };
+};
diff --git a/std/os/get_app_data_dir.zig b/std/fs/get_app_data_dir.zig
index e69c03edb9..87703592c1 100644
--- a/std/os/get_app_data_dir.zig
+++ b/std/fs/get_app_data_dir.zig
@@ -2,6 +2,7 @@ const std = @import("../std.zig");
const builtin = @import("builtin");
const unicode = std.unicode;
const mem = std.mem;
+const fs = std.fs;
const os = std.os;
pub const GetAppDataDirError = error{
@@ -13,16 +14,16 @@ pub const GetAppDataDirError = error{
/// TODO determine if we can remove the allocator requirement
pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataDirError![]u8 {
switch (builtin.os) {
- builtin.Os.windows => {
+ .windows => {
var dir_path_ptr: [*]u16 = undefined;
- switch (os.windows.SHGetKnownFolderPath(
+ switch (os.windows.shell32.SHGetKnownFolderPath(
&os.windows.FOLDERID_LocalAppData,
os.windows.KF_FLAG_CREATE,
null,
&dir_path_ptr,
)) {
os.windows.S_OK => {
- defer os.windows.CoTaskMemFree(@ptrCast(*c_void, dir_path_ptr));
+ defer os.windows.ole32.CoTaskMemFree(@ptrCast(*c_void, dir_path_ptr));
const global_dir = unicode.utf16leToUtf8Alloc(allocator, utf16lePtrSlice(dir_path_ptr)) catch |err| switch (err) {
error.UnexpectedSecondSurrogateHalf => return error.AppDataDirUnavailable,
error.ExpectedSecondSurrogateHalf => return error.AppDataDirUnavailable,
@@ -30,25 +31,25 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD
error.OutOfMemory => return error.OutOfMemory,
};
defer allocator.free(global_dir);
- return os.path.join(allocator, [][]const u8{ global_dir, appname });
+ return fs.path.join(allocator, [][]const u8{ global_dir, appname });
},
os.windows.E_OUTOFMEMORY => return error.OutOfMemory,
else => return error.AppDataDirUnavailable,
}
},
- builtin.Os.macosx => {
- const home_dir = os.getEnvPosix("HOME") orelse {
+ .macosx => {
+ const home_dir = os.getenv("HOME") orelse {
// TODO look in /etc/passwd
return error.AppDataDirUnavailable;
};
- return os.path.join(allocator, [][]const u8{ home_dir, "Library", "Application Support", appname });
+ return fs.path.join(allocator, [][]const u8{ home_dir, "Library", "Application Support", appname });
},
- builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {
- const home_dir = os.getEnvPosix("HOME") orelse {
+ .linux, .freebsd, .netbsd => {
+ const home_dir = os.getenv("HOME") orelse {
// TODO look in /etc/passwd
return error.AppDataDirUnavailable;
};
- return os.path.join(allocator, [][]const u8{ home_dir, ".local", "share", appname });
+ return fs.path.join(allocator, [][]const u8{ home_dir, ".local", "share", appname });
},
else => @compileError("Unsupported OS"),
}
@@ -60,7 +61,7 @@ fn utf16lePtrSlice(ptr: [*]const u16) []const u16 {
return ptr[0..index];
}
-test "std.os.getAppDataDir" {
+test "getAppDataDir" {
var buf: [512]u8 = undefined;
const allocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
diff --git a/std/os/path.zig b/std/fs/path.zig
index fa8bb282eb..7b95a3e4d2 100644
--- a/std/os/path.zig
+++ b/std/fs/path.zig
@@ -1,33 +1,28 @@
-const std = @import("../std.zig");
const builtin = @import("builtin");
-const Os = builtin.Os;
+const std = @import("../std.zig");
const debug = std.debug;
const assert = debug.assert;
const testing = std.testing;
const mem = std.mem;
const fmt = std.fmt;
const Allocator = mem.Allocator;
-const os = std.os;
const math = std.math;
-const posix = os.posix;
-const windows = os.windows;
-const cstr = std.cstr;
-const windows_util = @import("windows/util.zig");
+const windows = std.os.windows;
+const fs = std.fs;
+const process = std.process;
pub const sep_windows = '\\';
pub const sep_posix = '/';
-pub const sep = if (is_windows) sep_windows else sep_posix;
+pub const sep = if (windows.is_the_target) sep_windows else sep_posix;
pub const sep_str = [1]u8{sep};
pub const delimiter_windows = ';';
pub const delimiter_posix = ':';
-pub const delimiter = if (is_windows) delimiter_windows else delimiter_posix;
-
-const is_windows = builtin.os == builtin.Os.windows;
+pub const delimiter = if (windows.is_the_target) delimiter_windows else delimiter_posix;
pub fn isSep(byte: u8) bool {
- if (is_windows) {
+ if (windows.is_the_target) {
return byte == '/' or byte == '\\';
} else {
return byte == '/';
@@ -77,7 +72,7 @@ fn joinSep(allocator: *Allocator, separator: u8, paths: []const []const u8) ![]u
return buf;
}
-pub const join = if (is_windows) joinWindows else joinPosix;
+pub const join = if (windows.is_the_target) joinWindows else joinPosix;
/// Naively combines a series of paths with the native path seperator.
/// Allocates memory for the result, which must be freed by the caller.
@@ -105,7 +100,7 @@ fn testJoinPosix(paths: []const []const u8, expected: []const u8) void {
testing.expectEqualSlices(u8, expected, actual);
}
-test "os.path.join" {
+test "join" {
testJoinWindows([][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c");
testJoinWindows([][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c");
testJoinWindows([][]const u8{ "c:\\a\\b\\", "c" }, "c:\\a\\b\\c");
@@ -134,7 +129,7 @@ test "os.path.join" {
}
pub fn isAbsolute(path: []const u8) bool {
- if (is_windows) {
+ if (windows.is_the_target) {
return isAbsoluteWindows(path);
} else {
return isAbsolutePosix(path);
@@ -164,7 +159,7 @@ pub fn isAbsolutePosix(path: []const u8) bool {
return path[0] == sep_posix;
}
-test "os.path.isAbsoluteWindows" {
+test "isAbsoluteWindows" {
testIsAbsoluteWindows("/", true);
testIsAbsoluteWindows("//", true);
testIsAbsoluteWindows("//server", true);
@@ -186,7 +181,7 @@ test "os.path.isAbsoluteWindows" {
testIsAbsoluteWindows("/usr/local", true);
}
-test "os.path.isAbsolutePosix" {
+test "isAbsolutePosix" {
testIsAbsolutePosix("/home/foo", true);
testIsAbsolutePosix("/home/foo/..", true);
testIsAbsolutePosix("bar/", false);
@@ -279,7 +274,7 @@ pub fn windowsParsePath(path: []const u8) WindowsPath {
return relative_path;
}
-test "os.path.windowsParsePath" {
+test "windowsParsePath" {
{
const parsed = windowsParsePath("//a/b");
testing.expect(parsed.is_abs);
@@ -313,7 +308,7 @@ test "os.path.windowsParsePath" {
}
pub fn diskDesignator(path: []const u8) []const u8 {
- if (is_windows) {
+ if (windows.is_the_target) {
return diskDesignatorWindows(path);
} else {
return "";
@@ -378,7 +373,7 @@ fn asciiEqlIgnoreCase(s1: []const u8, s2: []const u8) bool {
/// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`.
pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 {
- if (is_windows) {
+ if (windows.is_the_target) {
return resolveWindows(allocator, paths);
} else {
return resolvePosix(allocator, paths);
@@ -395,8 +390,8 @@ pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 {
/// Without performing actual syscalls, resolving `..` could be incorrect.
pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
if (paths.len == 0) {
- assert(is_windows); // resolveWindows called on non windows can't use getCwd
- return os.getCwdAlloc(allocator);
+ assert(windows.is_the_target); // resolveWindows called on non windows can't use getCwd
+ return process.getCwdAlloc(allocator);
}
// determine which disk designator we will result with, if any
@@ -490,8 +485,8 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
result_disk_designator = result[0..result_index];
},
WindowsPath.Kind.None => {
- assert(is_windows); // resolveWindows called on non windows can't use getCwd
- const cwd = try os.getCwdAlloc(allocator);
+ assert(windows.is_the_target); // resolveWindows called on non windows can't use getCwd
+ const cwd = try process.getCwdAlloc(allocator);
defer allocator.free(cwd);
const parsed_cwd = windowsParsePath(cwd);
result = try allocator.alloc(u8, max_size + parsed_cwd.disk_designator.len + 1);
@@ -505,9 +500,9 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
},
}
} else {
- assert(is_windows); // resolveWindows called on non windows can't use getCwd
+ assert(windows.is_the_target); // resolveWindows called on non windows can't use getCwd
// TODO call get cwd for the result_disk_designator instead of the global one
- const cwd = try os.getCwdAlloc(allocator);
+ const cwd = try process.getCwdAlloc(allocator);
defer allocator.free(cwd);
result = try allocator.alloc(u8, max_size + cwd.len + 1);
@@ -576,8 +571,8 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
/// Without performing actual syscalls, resolving `..` could be incorrect.
pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
if (paths.len == 0) {
- assert(!is_windows); // resolvePosix called on windows can't use getCwd
- return os.getCwdAlloc(allocator);
+ assert(!windows.is_the_target); // resolvePosix called on windows can't use getCwd
+ return process.getCwdAlloc(allocator);
}
var first_index: usize = 0;
@@ -598,8 +593,8 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
if (have_abs) {
result = try allocator.alloc(u8, max_size);
} else {
- assert(!is_windows); // resolvePosix called on windows can't use getCwd
- const cwd = try os.getCwdAlloc(allocator);
+ assert(!windows.is_the_target); // resolvePosix called on windows can't use getCwd
+ const cwd = try process.getCwdAlloc(allocator);
defer allocator.free(cwd);
result = try allocator.alloc(u8, max_size + cwd.len + 1);
mem.copy(u8, result, cwd);
@@ -637,9 +632,9 @@ pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
return allocator.shrink(result, result_index);
}
-test "os.path.resolve" {
- const cwd = try os.getCwdAlloc(debug.global_allocator);
- if (is_windows) {
+test "resolve" {
+ const cwd = try process.getCwdAlloc(debug.global_allocator);
+ if (windows.is_the_target) {
if (windowsParsePath(cwd).kind == WindowsPath.Kind.Drive) {
cwd[0] = asciiUpper(cwd[0]);
}
@@ -650,9 +645,9 @@ test "os.path.resolve" {
}
}
-test "os.path.resolveWindows" {
- if (is_windows) {
- const cwd = try os.getCwdAlloc(debug.global_allocator);
+test "resolveWindows" {
+ if (windows.is_the_target) {
+ const cwd = try process.getCwdAlloc(debug.global_allocator);
const parsed_cwd = windowsParsePath(cwd);
{
const result = testResolveWindows([][]const u8{ "/usr/local", "lib\\zig\\std\\array_list.zig" });
@@ -693,7 +688,7 @@ test "os.path.resolveWindows" {
testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "C:\\foo\\tmp.3\\", "..\\tmp.3\\cycles\\root.js" }), "C:\\foo\\tmp.3\\cycles\\root.js"));
}
-test "os.path.resolvePosix" {
+test "resolvePosix" {
testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b", "c" }), "/a/b/c"));
testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b", "c", "//d", "e///" }), "/d/e"));
testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b/c", "..", "../" }), "/a"));
@@ -717,7 +712,7 @@ fn testResolvePosix(paths: []const []const u8) []u8 {
/// If the path is a file in the current directory (no directory component)
/// then returns null
pub fn dirname(path: []const u8) ?[]const u8 {
- if (is_windows) {
+ if (windows.is_the_target) {
return dirnameWindows(path);
} else {
return dirnamePosix(path);
@@ -784,7 +779,7 @@ pub fn dirnamePosix(path: []const u8) ?[]const u8 {
return path[0..end_index];
}
-test "os.path.dirnamePosix" {
+test "dirnamePosix" {
testDirnamePosix("/a/b/c", "/a/b");
testDirnamePosix("/a/b/c///", "/a/b");
testDirnamePosix("/a", "/");
@@ -796,7 +791,7 @@ test "os.path.dirnamePosix" {
testDirnamePosix("a//", null);
}
-test "os.path.dirnameWindows" {
+test "dirnameWindows" {
testDirnameWindows("c:\\", "c:\\");
testDirnameWindows("c:\\foo", "c:\\");
testDirnameWindows("c:\\foo\\", "c:\\");
@@ -849,7 +844,7 @@ fn testDirnameWindows(input: []const u8, expected_output: ?[]const u8) void {
}
pub fn basename(path: []const u8) []const u8 {
- if (is_windows) {
+ if (windows.is_the_target) {
return basenameWindows(path);
} else {
return basenamePosix(path);
@@ -909,7 +904,7 @@ pub fn basenameWindows(path: []const u8) []const u8 {
return path[start_index + 1 .. end_index];
}
-test "os.path.basename" {
+test "basename" {
testBasename("", "");
testBasename("/", "");
testBasename("/dir/basename.ext", "basename.ext");
@@ -965,7 +960,7 @@ fn testBasenameWindows(input: []const u8, expected_output: []const u8) void {
/// string is returned.
/// On Windows this canonicalizes the drive to a capital letter and paths to `\\`.
pub fn relative(allocator: *Allocator, from: []const u8, to: []const u8) ![]u8 {
- if (is_windows) {
+ if (windows.is_the_target) {
return relativeWindows(allocator, from, to);
} else {
return relativePosix(allocator, from, to);
@@ -1090,7 +1085,7 @@ pub fn relativePosix(allocator: *Allocator, from: []const u8, to: []const u8) ![
return []u8{};
}
-test "os.path.relative" {
+test "relative" {
testRelativeWindows("c:/blah\\blah", "d:/games", "D:\\games");
testRelativeWindows("c:/aaaa/bbbb", "c:/aaaa", "..");
testRelativeWindows("c:/aaaa/bbbb", "c:/cccc", "..\\..\\cccc");
@@ -1139,150 +1134,3 @@ fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []cons
const result = relativeWindows(debug.global_allocator, from, to) catch unreachable;
testing.expectEqualSlices(u8, expected_output, result);
}
-
-pub const RealError = error{
- FileNotFound,
- AccessDenied,
- NameTooLong,
- NotSupported,
- NotDir,
- SymLinkLoop,
- InputOutput,
- FileTooBig,
- IsDir,
- ProcessFdQuotaExceeded,
- SystemFdQuotaExceeded,
- NoDevice,
- SystemResources,
- NoSpaceLeft,
- FileSystem,
- BadPathName,
- DeviceBusy,
-
- /// On Windows, file paths must be valid Unicode.
- InvalidUtf8,
-
- /// TODO remove this possibility
- PathAlreadyExists,
-
- /// TODO remove this possibility
- Unexpected,
-};
-
-/// Call from Windows-specific code if you already have a UTF-16LE encoded, null terminated string.
-/// Otherwise use `real` or `realC`.
-pub fn realW(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: [*]const u16) RealError![]u8 {
- const h_file = windows.CreateFileW(
- pathname,
- windows.GENERIC_READ,
- windows.FILE_SHARE_READ,
- null,
- windows.OPEN_EXISTING,
- windows.FILE_ATTRIBUTE_NORMAL,
- null,
- );
- if (h_file == windows.INVALID_HANDLE_VALUE) {
- const err = windows.GetLastError();
- switch (err) {
- windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
- windows.ERROR.ACCESS_DENIED => return error.AccessDenied,
- windows.ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
- else => return os.unexpectedErrorWindows(err),
- }
- }
- defer os.close(h_file);
- var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
- const casted_len = @intCast(windows.DWORD, utf16le_buf.len); // TODO shouldn't need this cast
- const result = windows.GetFinalPathNameByHandleW(h_file, &utf16le_buf, casted_len, windows.VOLUME_NAME_DOS);
- assert(result <= utf16le_buf.len);
- if (result == 0) {
- const err = windows.GetLastError();
- switch (err) {
- windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
- windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
- windows.ERROR.NOT_ENOUGH_MEMORY => return error.SystemResources,
- windows.ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
- windows.ERROR.INVALID_PARAMETER => unreachable,
- else => return os.unexpectedErrorWindows(err),
- }
- }
- const utf16le_slice = utf16le_buf[0..result];
-
- // windows returns \\?\ prepended to the path
- // we strip it because nobody wants \\?\ prepended to their path
- const prefix = []u16{ '\\', '\\', '?', '\\' };
- const start_index = if (mem.startsWith(u16, utf16le_slice, prefix)) prefix.len else 0;
-
- // Trust that Windows gives us valid UTF-16LE.
- const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice[start_index..]) catch unreachable;
- return out_buffer[0..end_index];
-}
-
-/// See `real`
-/// Use this when you have a null terminated pointer path.
-pub fn realC(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: [*]const u8) RealError![]u8 {
- switch (builtin.os) {
- Os.windows => {
- const pathname_w = try windows_util.cStrToPrefixedFileW(pathname);
- return realW(out_buffer, pathname_w);
- },
- Os.freebsd, Os.netbsd, Os.macosx, Os.ios => {
- // TODO instead of calling the libc function here, port the implementation to Zig
- const err = posix.getErrno(posix.realpath(pathname, out_buffer));
- switch (err) {
- 0 => return mem.toSlice(u8, out_buffer),
- posix.EINVAL => unreachable,
- posix.EBADF => unreachable,
- posix.EFAULT => unreachable,
- posix.EACCES => return error.AccessDenied,
- posix.ENOENT => return error.FileNotFound,
- posix.ENOTSUP => return error.NotSupported,
- posix.ENOTDIR => return error.NotDir,
- posix.ENAMETOOLONG => return error.NameTooLong,
- posix.ELOOP => return error.SymLinkLoop,
- posix.EIO => return error.InputOutput,
- else => return os.unexpectedErrorPosix(err),
- }
- },
- Os.linux => {
- const fd = try os.posixOpenC(pathname, posix.O_PATH | posix.O_NONBLOCK | posix.O_CLOEXEC, 0);
- defer os.close(fd);
-
- var buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined;
- const proc_path = fmt.bufPrint(buf[0..], "/proc/self/fd/{}\x00", fd) catch unreachable;
-
- return os.readLinkC(out_buffer, proc_path.ptr);
- },
- else => @compileError("TODO implement os.path.real for " ++ @tagName(builtin.os)),
- }
-}
-
-/// Return the canonicalized absolute pathname.
-/// Expands all symbolic links and resolves references to `.`, `..`, and
-/// extra `/` characters in ::pathname.
-/// The return value is a slice of out_buffer, and not necessarily from the beginning.
-pub fn real(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: []const u8) RealError![]u8 {
- switch (builtin.os) {
- Os.windows => {
- const pathname_w = try windows_util.sliceToPrefixedFileW(pathname);
- return realW(out_buffer, &pathname_w);
- },
- Os.macosx, Os.ios, Os.linux, Os.freebsd, Os.netbsd => {
- const pathname_c = try os.toPosixPath(pathname);
- return realC(out_buffer, &pathname_c);
- },
- else => @compileError("Unsupported OS"),
- }
-}
-
-/// `real`, except caller must free the returned memory.
-pub fn realAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 {
- var buf: [os.MAX_PATH_BYTES]u8 = undefined;
- return mem.dupe(allocator, u8, try real(&buf, pathname));
-}
-
-test "os.path.real" {
- // at least call it so it gets compiled
- var buf: [os.MAX_PATH_BYTES]u8 = undefined;
- testing.expectError(error.FileNotFound, real(&buf, "definitely_bogus_does_not_exist1234"));
-}
diff --git a/std/heap.zig b/std/heap.zig
index 3bbb35e65d..7d7774f453 100644
--- a/std/heap.zig
+++ b/std/heap.zig
@@ -5,7 +5,6 @@ const testing = std.testing;
const mem = std.mem;
const os = std.os;
const builtin = @import("builtin");
-const Os = builtin.Os;
const c = std.c;
const maxInt = std.math.maxInt;
@@ -51,201 +50,195 @@ pub const DirectAllocator = struct {
if (n == 0)
return (([*]u8)(undefined))[0..0];
- switch (builtin.os) {
- Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
- const p = os.posix;
- const alloc_size = if (alignment <= os.page_size) n else n + alignment;
- const addr = p.mmap(null, alloc_size, p.PROT_READ | p.PROT_WRITE, p.MAP_PRIVATE | p.MAP_ANONYMOUS, -1, 0);
- if (addr == p.MAP_FAILED) return error.OutOfMemory;
- if (alloc_size == n) return @intToPtr([*]u8, addr)[0..n];
-
- const aligned_addr = mem.alignForward(addr, alignment);
-
- // Unmap the extra bytes that were only requested in order to guarantee
- // that the range of memory we were provided had a proper alignment in
- // it somewhere. The extra bytes could be at the beginning, or end, or both.
- const unused_start_len = aligned_addr - addr;
- if (unused_start_len != 0) {
- const err = p.munmap(addr, unused_start_len);
- assert(p.getErrno(err) == 0);
- }
- const aligned_end_addr = std.mem.alignForward(aligned_addr + n, os.page_size);
- const unused_end_len = addr + alloc_size - aligned_end_addr;
- if (unused_end_len != 0) {
- const err = p.munmap(aligned_end_addr, unused_end_len);
- assert(p.getErrno(err) == 0);
- }
+ if (os.windows.is_the_target) {
+ const w = os.windows;
+
+ // Although officially it's at least aligned to page boundary,
+ // Windows is known to reserve pages on a 64K boundary. It's
+ // even more likely that the requested alignment is <= 64K than
+ // 4K, so we're just allocating blindly and hoping for the best.
+ // see https://devblogs.microsoft.com/oldnewthing/?p=42223
+ const addr = w.VirtualAlloc(
+ null,
+ n,
+ w.MEM_COMMIT | w.MEM_RESERVE,
+ w.PAGE_READWRITE,
+ ) catch return error.OutOfMemory;
+
+ // If the allocation is sufficiently aligned, use it.
+ if (@ptrToInt(addr) & (alignment - 1) == 0) {
+ return @ptrCast([*]u8, addr)[0..n];
+ }
- return @intToPtr([*]u8, aligned_addr)[0..n];
- },
- .windows => {
- const w = os.windows;
-
- // Although officially it's at least aligned to page boundary,
- // Windows is known to reserve pages on a 64K boundary. It's
- // even more likely that the requested alignment is <= 64K than
- // 4K, so we're just allocating blindly and hoping for the best.
- // see https://devblogs.microsoft.com/oldnewthing/?p=42223
- const addr = w.VirtualAlloc(
+ // If it wasn't, actually do an explicitely aligned allocation.
+ w.VirtualFree(addr, 0, w.MEM_RELEASE);
+ const alloc_size = n + alignment;
+
+ const final_addr = while (true) {
+ // Reserve a range of memory large enough to find a sufficiently
+ // aligned address.
+ const reserved_addr = w.VirtualAlloc(
null,
+ alloc_size,
+ w.MEM_RESERVE,
+ w.PAGE_NOACCESS,
+ ) catch return error.OutOfMemory;
+ const aligned_addr = mem.alignForward(@ptrToInt(reserved_addr), alignment);
+
+ // Release the reserved pages (not actually used).
+ w.VirtualFree(reserved_addr, 0, w.MEM_RELEASE);
+
+ // At this point, it is possible that another thread has
+ // obtained some memory space that will cause the next
+ // VirtualAlloc call to fail. To handle this, we will retry
+ // until it succeeds.
+ const ptr = w.VirtualAlloc(
+ @intToPtr(*c_void, aligned_addr),
n,
w.MEM_COMMIT | w.MEM_RESERVE,
w.PAGE_READWRITE,
- ) orelse return error.OutOfMemory;
+ ) catch continue;
- // If the allocation is sufficiently aligned, use it.
- if (@ptrToInt(addr) & (alignment - 1) == 0) {
- return @ptrCast([*]u8, addr)[0..n];
- }
+ return @ptrCast([*]u8, ptr)[0..n];
+ };
- // If it wasn't, actually do an explicitely aligned allocation.
- if (w.VirtualFree(addr, 0, w.MEM_RELEASE) == 0) unreachable;
- const alloc_size = n + alignment;
-
- const final_addr = while (true) {
- // Reserve a range of memory large enough to find a sufficiently
- // aligned address.
- const reserved_addr = w.VirtualAlloc(
- null,
- alloc_size,
- w.MEM_RESERVE,
- w.PAGE_NOACCESS,
- ) orelse return error.OutOfMemory;
- const aligned_addr = mem.alignForward(@ptrToInt(reserved_addr), alignment);
-
- // Release the reserved pages (not actually used).
- if (w.VirtualFree(reserved_addr, 0, w.MEM_RELEASE) == 0) unreachable;
-
- // At this point, it is possible that another thread has
- // obtained some memory space that will cause the next
- // VirtualAlloc call to fail. To handle this, we will retry
- // until it succeeds.
- if (w.VirtualAlloc(
- @intToPtr(*c_void, aligned_addr),
- n,
- w.MEM_COMMIT | w.MEM_RESERVE,
- w.PAGE_READWRITE,
- )) |ptr| break ptr;
- } else unreachable; // TODO else unreachable should not be necessary
-
- return @ptrCast([*]u8, final_addr)[0..n];
- },
- else => @compileError("Unsupported OS"),
+ return @ptrCast([*]u8, final_addr)[0..n];
}
+
+ const alloc_size = if (alignment <= mem.page_size) n else n + alignment;
+ const slice = os.mmap(
+ null,
+ mem.alignForward(alloc_size, mem.page_size),
+ os.PROT_READ | os.PROT_WRITE,
+ os.MAP_PRIVATE | os.MAP_ANONYMOUS,
+ -1,
+ 0,
+ ) catch return error.OutOfMemory;
+ if (alloc_size == n) return slice[0..n];
+
+ const aligned_addr = mem.alignForward(@ptrToInt(slice.ptr), alignment);
+
+ // Unmap the extra bytes that were only requested in order to guarantee
+ // that the range of memory we were provided had a proper alignment in
+ // it somewhere. The extra bytes could be at the beginning, or end, or both.
+ const unused_start_len = aligned_addr - @ptrToInt(slice.ptr);
+ if (unused_start_len != 0) {
+ os.munmap(slice[0..unused_start_len]);
+ }
+ const aligned_end_addr = mem.alignForward(aligned_addr + n, mem.page_size);
+ const unused_end_len = @ptrToInt(slice.ptr) + slice.len - aligned_end_addr;
+ if (unused_end_len != 0) {
+ os.munmap(@intToPtr([*]align(mem.page_size) u8, aligned_end_addr)[0..unused_end_len]);
+ }
+
+ return @intToPtr([*]u8, aligned_addr)[0..n];
}
- fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {
- switch (builtin.os) {
- Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
+ fn shrink(allocator: *Allocator, old_mem_unaligned: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {
+ const old_mem = @alignCast(mem.page_size, old_mem_unaligned);
+ if (os.windows.is_the_target) {
+ const w = os.windows;
+ if (new_size == 0) {
+ // From the docs:
+ // "If the dwFreeType parameter is MEM_RELEASE, this parameter
+ // must be 0 (zero). The function frees the entire region that
+ // is reserved in the initial allocation call to VirtualAlloc."
+ // So we can only use MEM_RELEASE when actually releasing the
+ // whole allocation.
+ w.VirtualFree(old_mem.ptr, 0, w.MEM_RELEASE);
+ } else {
const base_addr = @ptrToInt(old_mem.ptr);
const old_addr_end = base_addr + old_mem.len;
const new_addr_end = base_addr + new_size;
- const new_addr_end_rounded = mem.alignForward(new_addr_end, os.page_size);
+ const new_addr_end_rounded = mem.alignForward(new_addr_end, mem.page_size);
if (old_addr_end > new_addr_end_rounded) {
- _ = os.posix.munmap(new_addr_end_rounded, old_addr_end - new_addr_end_rounded);
- }
- return old_mem[0..new_size];
- },
- .windows => {
- const w = os.windows;
- if (new_size == 0) {
- // From the docs:
- // "If the dwFreeType parameter is MEM_RELEASE, this parameter
- // must be 0 (zero). The function frees the entire region that
- // is reserved in the initial allocation call to VirtualAlloc."
- // So we can only use MEM_RELEASE when actually releasing the
- // whole allocation.
- if (w.VirtualFree(old_mem.ptr, 0, w.MEM_RELEASE) == 0) unreachable;
- } else {
- const base_addr = @ptrToInt(old_mem.ptr);
- const old_addr_end = base_addr + old_mem.len;
- const new_addr_end = base_addr + new_size;
- const new_addr_end_rounded = mem.alignForward(new_addr_end, os.page_size);
- if (old_addr_end > new_addr_end_rounded) {
- // For shrinking that is not releasing, we will only
- // decommit the pages not needed anymore.
- if (w.VirtualFree(
- @intToPtr(*c_void, new_addr_end_rounded),
- old_addr_end - new_addr_end_rounded,
- w.MEM_DECOMMIT,
- ) == 0) unreachable;
- }
+ // For shrinking that is not releasing, we will only
+ // decommit the pages not needed anymore.
+ w.VirtualFree(
+ @intToPtr(*c_void, new_addr_end_rounded),
+ old_addr_end - new_addr_end_rounded,
+ w.MEM_DECOMMIT,
+ );
}
- return old_mem[0..new_size];
- },
- else => @compileError("Unsupported OS"),
+ }
+ return old_mem[0..new_size];
+ }
+ const base_addr = @ptrToInt(old_mem.ptr);
+ const old_addr_end = base_addr + old_mem.len;
+ const new_addr_end = base_addr + new_size;
+ const new_addr_end_rounded = mem.alignForward(new_addr_end, mem.page_size);
+ if (old_addr_end > new_addr_end_rounded) {
+ const ptr = @intToPtr([*]align(mem.page_size) u8, new_addr_end_rounded);
+ os.munmap(ptr[0 .. old_addr_end - new_addr_end_rounded]);
}
+ return old_mem[0..new_size];
}
- fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {
- switch (builtin.os) {
- Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
- if (new_size <= old_mem.len and new_align <= old_align) {
- return shrink(allocator, old_mem, old_align, new_size, new_align);
- }
- const result = try alloc(allocator, new_size, new_align);
- if (old_mem.len != 0) {
- @memcpy(result.ptr, old_mem.ptr, std.math.min(old_mem.len, result.len));
- _ = os.posix.munmap(@ptrToInt(old_mem.ptr), old_mem.len);
- }
- return result;
- },
- .windows => {
- if (old_mem.len == 0) {
- return alloc(allocator, new_size, new_align);
- }
-
- if (new_size <= old_mem.len and new_align <= old_align) {
- return shrink(allocator, old_mem, old_align, new_size, new_align);
- }
-
- const w = os.windows;
- const base_addr = @ptrToInt(old_mem.ptr);
+ fn realloc(allocator: *Allocator, old_mem_unaligned: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {
+ const old_mem = @alignCast(mem.page_size, old_mem_unaligned);
+ if (os.windows.is_the_target) {
+ if (old_mem.len == 0) {
+ return alloc(allocator, new_size, new_align);
+ }
- if (new_align > old_align and base_addr & (new_align - 1) != 0) {
- // Current allocation doesn't satisfy the new alignment.
- // For now we'll do a new one no matter what, but maybe
- // there is something smarter to do instead.
- const result = try alloc(allocator, new_size, new_align);
- assert(old_mem.len != 0);
- @memcpy(result.ptr, old_mem.ptr, std.math.min(old_mem.len, result.len));
- if (w.VirtualFree(old_mem.ptr, 0, w.MEM_RELEASE) == 0) unreachable;
+ if (new_size <= old_mem.len and new_align <= old_align) {
+ return shrink(allocator, old_mem, old_align, new_size, new_align);
+ }
- return result;
- }
+ const w = os.windows;
+ const base_addr = @ptrToInt(old_mem.ptr);
- const old_addr_end = base_addr + old_mem.len;
- const old_addr_end_rounded = mem.alignForward(old_addr_end, os.page_size);
- const new_addr_end = base_addr + new_size;
- const new_addr_end_rounded = mem.alignForward(new_addr_end, os.page_size);
- if (new_addr_end_rounded == old_addr_end_rounded) {
- // The reallocation fits in the already allocated pages.
- return @ptrCast([*]u8, old_mem.ptr)[0..new_size];
- }
- assert(new_addr_end_rounded > old_addr_end_rounded);
+ if (new_align > old_align and base_addr & (new_align - 1) != 0) {
+ // Current allocation doesn't satisfy the new alignment.
+ // For now we'll do a new one no matter what, but maybe
+ // there is something smarter to do instead.
+ const result = try alloc(allocator, new_size, new_align);
+ assert(old_mem.len != 0);
+ @memcpy(result.ptr, old_mem.ptr, std.math.min(old_mem.len, result.len));
+ w.VirtualFree(old_mem.ptr, 0, w.MEM_RELEASE);
- // We need to commit new pages.
- const additional_size = new_addr_end - old_addr_end_rounded;
- const realloc_addr = w.VirtualAlloc(
- @intToPtr(*c_void, old_addr_end_rounded),
- additional_size,
- w.MEM_COMMIT | w.MEM_RESERVE,
- w.PAGE_READWRITE,
- ) orelse {
- // Committing new pages at the end of the existing allocation
- // failed, we need to try a new one.
- const new_alloc_mem = try alloc(allocator, new_size, new_align);
- @memcpy(new_alloc_mem.ptr, old_mem.ptr, old_mem.len);
- if (w.VirtualFree(old_mem.ptr, 0, w.MEM_RELEASE) == 0) unreachable;
-
- return new_alloc_mem;
- };
+ return result;
+ }
- assert(@ptrToInt(realloc_addr) == old_addr_end_rounded);
+ const old_addr_end = base_addr + old_mem.len;
+ const old_addr_end_rounded = mem.alignForward(old_addr_end, mem.page_size);
+ const new_addr_end = base_addr + new_size;
+ const new_addr_end_rounded = mem.alignForward(new_addr_end, mem.page_size);
+ if (new_addr_end_rounded == old_addr_end_rounded) {
+ // The reallocation fits in the already allocated pages.
return @ptrCast([*]u8, old_mem.ptr)[0..new_size];
- },
- else => @compileError("Unsupported OS"),
+ }
+ assert(new_addr_end_rounded > old_addr_end_rounded);
+
+ // We need to commit new pages.
+ const additional_size = new_addr_end - old_addr_end_rounded;
+ const realloc_addr = w.kernel32.VirtualAlloc(
+ @intToPtr(*c_void, old_addr_end_rounded),
+ additional_size,
+ w.MEM_COMMIT | w.MEM_RESERVE,
+ w.PAGE_READWRITE,
+ ) orelse {
+ // Committing new pages at the end of the existing allocation
+ // failed, we need to try a new one.
+ const new_alloc_mem = try alloc(allocator, new_size, new_align);
+ @memcpy(new_alloc_mem.ptr, old_mem.ptr, old_mem.len);
+ w.VirtualFree(old_mem.ptr, 0, w.MEM_RELEASE);
+
+ return new_alloc_mem;
+ };
+
+ assert(@ptrToInt(realloc_addr) == old_addr_end_rounded);
+ return @ptrCast([*]u8, old_mem.ptr)[0..new_size];
+ }
+ if (new_size <= old_mem.len and new_align <= old_align) {
+ return shrink(allocator, old_mem, old_align, new_size, new_align);
}
+ const result = try alloc(allocator, new_size, new_align);
+ if (old_mem.len != 0) {
+ @memcpy(result.ptr, old_mem.ptr, std.math.min(old_mem.len, result.len));
+ os.munmap(old_mem);
+ }
+ return result;
}
};
@@ -268,7 +261,7 @@ pub const HeapAllocator = switch (builtin.os) {
pub fn deinit(self: *HeapAllocator) void {
if (self.heap_handle) |heap_handle| {
- _ = os.windows.HeapDestroy(heap_handle);
+ os.windows.HeapDestroy(heap_handle);
}
}
@@ -281,12 +274,12 @@ pub const HeapAllocator = switch (builtin.os) {
const optional_heap_handle = @atomicLoad(?HeapHandle, &self.heap_handle, builtin.AtomicOrder.SeqCst);
const heap_handle = optional_heap_handle orelse blk: {
const options = if (builtin.single_threaded) os.windows.HEAP_NO_SERIALIZE else 0;
- const hh = os.windows.HeapCreate(options, amt, 0) orelse return error.OutOfMemory;
+ const hh = os.windows.kernel32.HeapCreate(options, amt, 0) orelse return error.OutOfMemory;
const other_hh = @cmpxchgStrong(?HeapHandle, &self.heap_handle, null, hh, builtin.AtomicOrder.SeqCst, builtin.AtomicOrder.SeqCst) orelse break :blk hh;
- _ = os.windows.HeapDestroy(hh);
+ os.windows.HeapDestroy(hh);
break :blk other_hh.?; // can't be null because of the cmpxchg
};
- const ptr = os.windows.HeapAlloc(heap_handle, 0, amt) orelse return error.OutOfMemory;
+ const ptr = os.windows.kernel32.HeapAlloc(heap_handle, 0, amt) orelse return error.OutOfMemory;
const root_addr = @ptrToInt(ptr);
const adjusted_addr = mem.alignForward(root_addr, alignment);
const record_addr = adjusted_addr + n;
@@ -316,12 +309,12 @@ pub const HeapAllocator = switch (builtin.os) {
const old_ptr = @intToPtr(*c_void, root_addr);
if (new_size == 0) {
- if (os.windows.HeapFree(self.heap_handle.?, 0, old_ptr) == 0) unreachable;
+ os.windows.HeapFree(self.heap_handle.?, 0, old_ptr);
return old_mem[0..0];
}
const amt = new_size + new_align + @sizeOf(usize);
- const new_ptr = os.windows.HeapReAlloc(
+ const new_ptr = os.windows.kernel32.HeapReAlloc(
self.heap_handle.?,
0,
old_ptr,
@@ -386,7 +379,7 @@ pub const ArenaAllocator = struct {
var len = prev_len;
while (true) {
len += len / 2;
- len += os.page_size - @rem(len, os.page_size);
+ len += mem.page_size - @rem(len, mem.page_size);
if (len >= actual_min_size) break;
}
const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);
@@ -532,11 +525,11 @@ const WasmAllocator = struct {
const adjusted_index = self.end_index + (adjusted_addr - addr);
const new_end_index = adjusted_index + size;
- if (new_end_index > self.num_pages * os.page_size) {
- const required_memory = new_end_index - (self.num_pages * os.page_size);
+ if (new_end_index > self.num_pages * mem.page_size) {
+ const required_memory = new_end_index - (self.num_pages * mem.page_size);
- var num_pages: usize = required_memory / os.page_size;
- if (required_memory % os.page_size != 0) {
+ var num_pages: usize = required_memory / mem.page_size;
+ if (required_memory % mem.page_size != 0) {
num_pages += 1;
}
@@ -565,14 +558,14 @@ const WasmAllocator = struct {
// Initialize start_ptr at the first realloc
if (self.num_pages == 0) {
- self.start_ptr = @intToPtr([*]u8, @intCast(usize, @"llvm.wasm.memory.size.i32"(0)) * os.page_size);
+ self.start_ptr = @intToPtr([*]u8, @intCast(usize, @"llvm.wasm.memory.size.i32"(0)) * mem.page_size);
}
if (is_last_item(allocator, old_mem, new_align)) {
const start_index = self.end_index - old_mem.len;
const new_end_index = start_index + new_size;
- if (new_end_index > self.num_pages * os.page_size) {
+ if (new_end_index > self.num_pages * mem.page_size) {
_ = try alloc(allocator, new_end_index - self.end_index, new_align);
}
const result = self.start_ptr[start_index..new_end_index];
@@ -888,10 +881,10 @@ fn testAllocatorAligned(allocator: *mem.Allocator, comptime alignment: u29) !voi
fn testAllocatorLargeAlignment(allocator: *mem.Allocator) mem.Allocator.Error!void {
//Maybe a platform's page_size is actually the same as or
// very near usize?
- if (os.page_size << 2 > maxInt(usize)) return;
+ if (mem.page_size << 2 > maxInt(usize)) return;
const USizeShift = @IntType(false, std.math.log2(usize.bit_count));
- const large_align = u29(os.page_size << 2);
+ const large_align = u29(mem.page_size << 2);
var align_mask: usize = undefined;
_ = @shlWithOverflow(usize, ~usize(0), USizeShift(@ctz(u29, large_align)), &align_mask);
@@ -918,7 +911,7 @@ fn testAllocatorAlignedShrink(allocator: *mem.Allocator) mem.Allocator.Error!voi
var debug_buffer: [1000]u8 = undefined;
const debug_allocator = &FixedBufferAllocator.init(&debug_buffer).allocator;
- const alloc_size = os.page_size * 2 + 50;
+ const alloc_size = mem.page_size * 2 + 50;
var slice = try allocator.alignedAlloc(u8, 16, alloc_size);
defer allocator.free(slice);
@@ -927,7 +920,7 @@ fn testAllocatorAlignedShrink(allocator: *mem.Allocator) mem.Allocator.Error!voi
// which is 16 pages, hence the 32. This test may require to increase
// the size of the allocations feeding the `allocator` parameter if they
// fail, because of this high over-alignment we want to have.
- while (@ptrToInt(slice.ptr) == mem.alignForward(@ptrToInt(slice.ptr), os.page_size * 32)) {
+ while (@ptrToInt(slice.ptr) == mem.alignForward(@ptrToInt(slice.ptr), mem.page_size * 32)) {
try stuff_to_free.append(slice);
slice = try allocator.alignedAlloc(u8, 16, alloc_size);
}
@@ -938,7 +931,7 @@ fn testAllocatorAlignedShrink(allocator: *mem.Allocator) mem.Allocator.Error!voi
slice[60] = 0x34;
// realloc to a smaller size but with a larger alignment
- slice = try allocator.alignedRealloc(slice, os.page_size * 32, alloc_size / 2);
+ slice = try allocator.alignedRealloc(slice, mem.page_size * 32, alloc_size / 2);
testing.expect(slice[0] == 0x12);
testing.expect(slice[60] == 0x34);
}
diff --git a/std/io.zig b/std/io.zig
index 5e1aaf5da3..258961fdfc 100644
--- a/std/io.zig
+++ b/std/io.zig
@@ -1,38 +1,44 @@
const std = @import("std.zig");
const builtin = @import("builtin");
-const Os = builtin.Os;
const c = std.c;
const math = std.math;
const debug = std.debug;
const assert = debug.assert;
const os = std.os;
+const fs = std.fs;
const mem = std.mem;
const meta = std.meta;
const trait = meta.trait;
const Buffer = std.Buffer;
const fmt = std.fmt;
-const File = std.os.File;
+const File = std.fs.File;
const testing = std.testing;
-const is_posix = builtin.os != builtin.Os.windows;
-const is_windows = builtin.os == builtin.Os.windows;
+pub const GetStdIoError = os.windows.GetStdHandleError;
-const GetStdIoErrs = os.WindowsGetStdHandleErrs;
-
-pub fn getStdErr() GetStdIoErrs!File {
- const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_ERROR_HANDLE) else if (is_posix) os.posix.STDERR_FILENO else unreachable;
- return File.openHandle(handle);
+pub fn getStdOut() GetStdIoError!File {
+ if (os.windows.is_the_target) {
+ const handle = try os.windows.GetStdHandle(os.windows.STD_OUTPUT_HANDLE);
+ return File.openHandle(handle);
+ }
+ return File.openHandle(os.STDOUT_FILENO);
}
-pub fn getStdOut() GetStdIoErrs!File {
- const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_OUTPUT_HANDLE) else if (is_posix) os.posix.STDOUT_FILENO else unreachable;
- return File.openHandle(handle);
+pub fn getStdErr() GetStdIoError!File {
+ if (os.windows.is_the_target) {
+ const handle = try os.windows.GetStdHandle(os.windows.STD_ERROR_HANDLE);
+ return File.openHandle(handle);
+ }
+ return File.openHandle(os.STDERR_FILENO);
}
-pub fn getStdIn() GetStdIoErrs!File {
- const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_INPUT_HANDLE) else if (is_posix) os.posix.STDIN_FILENO else unreachable;
- return File.openHandle(handle);
+pub fn getStdIn() GetStdIoError!File {
+ if (os.windows.is_the_target) {
+ const handle = try os.windows.GetStdHandle(os.windows.STD_INPUT_HANDLE);
+ return File.openHandle(handle);
+ }
+ return File.openHandle(os.STDIN_FILENO);
}
pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
@@ -66,7 +72,7 @@ pub fn InStream(comptime ReadError: type) type {
return;
}
- const new_buf_size = math.min(max_size, actual_buf_len + os.page_size);
+ const new_buf_size = math.min(max_size, actual_buf_len + mem.page_size);
if (new_buf_size == actual_buf_len) return error.StreamTooLong;
try buffer.resize(new_buf_size);
}
@@ -301,7 +307,7 @@ pub fn readFileAllocAligned(allocator: *mem.Allocator, path: []const u8, comptim
}
pub fn BufferedInStream(comptime Error: type) type {
- return BufferedInStreamCustom(os.page_size, Error);
+ return BufferedInStreamCustom(mem.page_size, Error);
}
pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) type {
@@ -774,7 +780,7 @@ test "io.CountingOutStream" {
}
pub fn BufferedOutStream(comptime Error: type) type {
- return BufferedOutStreamCustom(os.page_size, Error);
+ return BufferedOutStreamCustom(mem.page_size, Error);
}
pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamError: type) type {
@@ -979,9 +985,9 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
}
pub const BufferedAtomicFile = struct {
- atomic_file: os.AtomicFile,
- file_stream: os.File.OutStream,
- buffered_stream: BufferedOutStream(os.File.WriteError),
+ atomic_file: fs.AtomicFile,
+ file_stream: File.OutStream,
+ buffered_stream: BufferedOutStream(File.WriteError),
allocator: *mem.Allocator,
pub fn create(allocator: *mem.Allocator, dest_path: []const u8) !*BufferedAtomicFile {
@@ -995,11 +1001,11 @@ pub const BufferedAtomicFile = struct {
};
errdefer allocator.destroy(self);
- self.atomic_file = try os.AtomicFile.init(dest_path, os.File.default_mode);
+ self.atomic_file = try fs.AtomicFile.init(dest_path, File.default_mode);
errdefer self.atomic_file.deinit();
self.file_stream = self.atomic_file.file.outStream();
- self.buffered_stream = BufferedOutStream(os.File.WriteError).init(&self.file_stream.stream);
+ self.buffered_stream = BufferedOutStream(File.WriteError).init(&self.file_stream.stream);
return self;
}
@@ -1014,7 +1020,7 @@ pub const BufferedAtomicFile = struct {
try self.atomic_file.finish();
}
- pub fn stream(self: *BufferedAtomicFile) *OutStream(os.File.WriteError) {
+ pub fn stream(self: *BufferedAtomicFile) *OutStream(File.WriteError) {
return &self.buffered_stream.stream;
}
};
diff --git a/std/io/c_out_stream.zig b/std/io/c_out_stream.zig
index c66b342f1e..8b341e6937 100644
--- a/std/io/c_out_stream.zig
+++ b/std/io/c_out_stream.zig
@@ -1,13 +1,13 @@
const std = @import("../std.zig");
+const os = std.os;
const OutStream = std.io.OutStream;
const builtin = @import("builtin");
-const posix = std.os.posix;
-/// TODO make std.os.FILE use *FILE when linking libc and this just becomes
-/// std.io.FileOutStream because std.os.File.write would do this when linking
+/// TODO make a proposal to make `std.fs.File` use *FILE when linking libc and this just becomes
+/// std.io.FileOutStream because std.fs.File.write would do this when linking
/// libc.
pub const COutStream = struct {
- pub const Error = std.os.File.WriteError;
+ pub const Error = std.fs.File.WriteError;
pub const Stream = OutStream(Error);
stream: Stream,
@@ -24,25 +24,20 @@ pub const COutStream = struct {
const self = @fieldParentPtr(COutStream, "stream", out_stream);
const amt_written = std.c.fwrite(bytes.ptr, 1, bytes.len, self.c_file);
if (amt_written == bytes.len) return;
- // TODO errno on windows. should we have a posix layer for windows?
- if (builtin.os == .windows) {
- return error.InputOutput;
- }
- const errno = std.c._errno().*;
- switch (errno) {
+ switch (std.c._errno().*) {
0 => unreachable,
- posix.EINVAL => unreachable,
- posix.EFAULT => unreachable,
- posix.EAGAIN => unreachable, // this is a blocking API
- posix.EBADF => unreachable, // always a race condition
- posix.EDESTADDRREQ => unreachable, // connect was never called
- posix.EDQUOT => return error.DiskQuota,
- posix.EFBIG => return error.FileTooBig,
- posix.EIO => return error.InputOutput,
- posix.ENOSPC => return error.NoSpaceLeft,
- posix.EPERM => return error.AccessDenied,
- posix.EPIPE => return error.BrokenPipe,
- else => return std.os.unexpectedErrorPosix(@intCast(usize, errno)),
+ os.EINVAL => unreachable,
+ os.EFAULT => unreachable,
+ os.EAGAIN => unreachable, // this is a blocking API
+ os.EBADF => unreachable, // always a race condition
+ os.EDESTADDRREQ => unreachable, // connect was never called
+ os.EDQUOT => return error.DiskQuota,
+ os.EFBIG => return error.FileTooBig,
+ os.EIO => return error.InputOutput,
+ os.ENOSPC => return error.NoSpaceLeft,
+ os.EPERM => return error.AccessDenied,
+ os.EPIPE => return error.BrokenPipe,
+ else => |err| return os.unexpectedErrno(@intCast(usize, err)),
}
}
};
diff --git a/std/io/seekable_stream.zig b/std/io/seekable_stream.zig
index 392e135302..86f76d8c14 100644
--- a/std/io/seekable_stream.zig
+++ b/std/io/seekable_stream.zig
@@ -8,7 +8,7 @@ pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType
pub const GetSeekPosError = GetSeekPosErrorType;
seekToFn: fn (self: *Self, pos: u64) SeekError!void,
- seekForwardFn: fn (self: *Self, pos: i64) SeekError!void,
+ seekByFn: fn (self: *Self, pos: i64) SeekError!void,
getPosFn: fn (self: *Self) GetSeekPosError!u64,
getEndPosFn: fn (self: *Self) GetSeekPosError!u64,
@@ -17,8 +17,8 @@ pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType
return self.seekToFn(self, pos);
}
- pub fn seekForward(self: *Self, amt: i64) SeekError!void {
- return self.seekForwardFn(self, amt);
+ pub fn seekBy(self: *Self, amt: i64) SeekError!void {
+ return self.seekByFn(self, amt);
}
pub fn getEndPos(self: *Self) GetSeekPosError!u64 {
@@ -52,7 +52,7 @@ pub const SliceSeekableInStream = struct {
.stream = Stream{ .readFn = readFn },
.seekable_stream = SeekableInStream{
.seekToFn = seekToFn,
- .seekForwardFn = seekForwardFn,
+ .seekByFn = seekByFn,
.getEndPosFn = getEndPosFn,
.getPosFn = getPosFn,
},
@@ -77,7 +77,7 @@ pub const SliceSeekableInStream = struct {
self.pos = usize_pos;
}
- fn seekForwardFn(in_stream: *SeekableInStream, amt: i64) SeekError!void {
+ fn seekByFn(in_stream: *SeekableInStream, amt: i64) SeekError!void {
const self = @fieldParentPtr(Self, "seekable_stream", in_stream);
if (amt < 0) {
diff --git a/std/io/test.zig b/std/io/test.zig
index 07a3c0e8dd..fc3b0f8902 100644
--- a/std/io/test.zig
+++ b/std/io/test.zig
@@ -1,3 +1,4 @@
+const builtin = @import("builtin");
const std = @import("../std.zig");
const io = std.io;
const meta = std.meta;
@@ -6,8 +7,8 @@ const DefaultPrng = std.rand.DefaultPrng;
const expect = std.testing.expect;
const expectError = std.testing.expectError;
const mem = std.mem;
-const os = std.os;
-const builtin = @import("builtin");
+const fs = std.fs;
+const File = std.fs.File;
test "write a file, read it, then delete it" {
var raw_bytes: [200 * 1024]u8 = undefined;
@@ -18,11 +19,11 @@ test "write a file, read it, then delete it" {
prng.random.bytes(data[0..]);
const tmp_file_name = "temp_test_file.txt";
{
- var file = try os.File.openWrite(tmp_file_name);
+ var file = try File.openWrite(tmp_file_name);
defer file.close();
var file_out_stream = file.outStream();
- var buf_stream = io.BufferedOutStream(os.File.WriteError).init(&file_out_stream.stream);
+ var buf_stream = io.BufferedOutStream(File.WriteError).init(&file_out_stream.stream);
const st = &buf_stream.stream;
try st.print("begin");
try st.write(data[0..]);
@@ -32,15 +33,15 @@ test "write a file, read it, then delete it" {
{
// make sure openWriteNoClobber doesn't harm the file
- if (os.File.openWriteNoClobber(tmp_file_name, os.File.default_mode)) |file| {
+ if (File.openWriteNoClobber(tmp_file_name, File.default_mode)) |file| {
unreachable;
} else |err| {
- std.debug.assert(err == os.File.OpenError.PathAlreadyExists);
+ std.debug.assert(err == File.OpenError.PathAlreadyExists);
}
}
{
- var file = try os.File.openRead(tmp_file_name);
+ var file = try File.openRead(tmp_file_name);
defer file.close();
const file_size = try file.getEndPos();
@@ -48,7 +49,7 @@ test "write a file, read it, then delete it" {
expect(file_size == expected_file_size);
var file_in_stream = file.inStream();
- var buf_stream = io.BufferedInStream(os.File.ReadError).init(&file_in_stream.stream);
+ var buf_stream = io.BufferedInStream(File.ReadError).init(&file_in_stream.stream);
const st = &buf_stream.stream;
const contents = try st.readAllAlloc(allocator, 2 * 1024);
defer allocator.free(contents);
@@ -57,7 +58,7 @@ test "write a file, read it, then delete it" {
expect(mem.eql(u8, contents["begin".len .. contents.len - "end".len], data));
expect(mem.eql(u8, contents[contents.len - "end".len ..], "end"));
}
- try os.deleteFile(tmp_file_name);
+ try fs.deleteFile(tmp_file_name);
}
test "BufferOutStream" {
@@ -273,12 +274,12 @@ test "BitOutStream" {
test "BitStreams with File Stream" {
const tmp_file_name = "temp_test_file.txt";
{
- var file = try os.File.openWrite(tmp_file_name);
+ var file = try File.openWrite(tmp_file_name);
defer file.close();
var file_out = file.outStream();
var file_out_stream = &file_out.stream;
- const OutError = os.File.WriteError;
+ const OutError = File.WriteError;
var bit_stream = io.BitOutStream(builtin.endian, OutError).init(file_out_stream);
try bit_stream.writeBits(u2(1), 1);
@@ -290,12 +291,12 @@ test "BitStreams with File Stream" {
try bit_stream.flushBits();
}
{
- var file = try os.File.openRead(tmp_file_name);
+ var file = try File.openRead(tmp_file_name);
defer file.close();
var file_in = file.inStream();
var file_in_stream = &file_in.stream;
- const InError = os.File.ReadError;
+ const InError = File.ReadError;
var bit_stream = io.BitInStream(builtin.endian, InError).init(file_in_stream);
var out_bits: usize = undefined;
@@ -315,7 +316,7 @@ test "BitStreams with File Stream" {
expectError(error.EndOfStream, bit_stream.readBitsNoEof(u1, 1));
}
- try os.deleteFile(tmp_file_name);
+ try fs.deleteFile(tmp_file_name);
}
fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void {
@@ -595,7 +596,7 @@ test "c out stream" {
const filename = c"tmp_io_test_file.txt";
const out_file = std.c.fopen(filename, c"w") orelse return error.UnableToOpenTestFile;
- defer std.os.deleteFileC(filename) catch {};
+ defer fs.deleteFileC(filename) catch {};
const out_stream = &io.COutStream.init(out_file).stream;
try out_stream.print("hi: {}\n", i32(123));
diff --git a/std/mem.zig b/std/mem.zig
index 64fe270eda..17dec85a5b 100644
--- a/std/mem.zig
+++ b/std/mem.zig
@@ -8,6 +8,11 @@ const meta = std.meta;
const trait = meta.trait;
const testing = std.testing;
+pub const page_size = switch (builtin.arch) {
+ .wasm32, .wasm64 => 64 * 1024,
+ else => 4 * 1024,
+};
+
pub const Allocator = struct {
pub const Error = error{OutOfMemory};
@@ -580,14 +585,14 @@ pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian)
test "comptime read/write int" {
comptime {
var bytes: [2]u8 = undefined;
- std.mem.writeIntLittle(u16, &bytes, 0x1234);
- const result = std.mem.readIntBig(u16, &bytes);
+ writeIntLittle(u16, &bytes, 0x1234);
+ const result = readIntBig(u16, &bytes);
testing.expect(result == 0x3412);
}
comptime {
var bytes: [2]u8 = undefined;
- std.mem.writeIntBig(u16, &bytes, 0x1234);
- const result = std.mem.readIntLittle(u16, &bytes);
+ writeIntBig(u16, &bytes, 0x1234);
+ const result = readIntLittle(u16, &bytes);
testing.expect(result == 0x3412);
}
}
@@ -1048,7 +1053,7 @@ fn testReadIntImpl() void {
}
}
-test "std.mem.writeIntSlice" {
+test "writeIntSlice" {
testWriteIntImpl();
comptime testWriteIntImpl();
}
@@ -1179,7 +1184,7 @@ pub fn reverse(comptime T: type, items: []T) void {
}
}
-test "std.mem.reverse" {
+test "reverse" {
var arr = []i32{
5,
3,
@@ -1206,7 +1211,7 @@ pub fn rotate(comptime T: type, items: []T, amount: usize) void {
reverse(T, items);
}
-test "std.mem.rotate" {
+test "rotate" {
var arr = []i32{
5,
3,
@@ -1291,14 +1296,14 @@ pub fn asBytes(ptr: var) AsBytesReturnType(@typeOf(ptr)) {
return @ptrCast(AsBytesReturnType(P), ptr);
}
-test "std.mem.asBytes" {
+test "asBytes" {
const deadbeef = u32(0xDEADBEEF);
const deadbeef_bytes = switch (builtin.endian) {
builtin.Endian.Big => "\xDE\xAD\xBE\xEF",
builtin.Endian.Little => "\xEF\xBE\xAD\xDE",
};
- testing.expect(std.mem.eql(u8, asBytes(&deadbeef), deadbeef_bytes));
+ testing.expect(eql(u8, asBytes(&deadbeef), deadbeef_bytes));
var codeface = u32(0xC0DEFACE);
for (asBytes(&codeface).*) |*b|
@@ -1318,7 +1323,7 @@ test "std.mem.asBytes" {
.c = 0xDE,
.d = 0xA1,
};
- testing.expect(std.mem.eql(u8, asBytes(&inst), "\xBE\xEF\xDE\xA1"));
+ testing.expect(eql(u8, asBytes(&inst), "\xBE\xEF\xDE\xA1"));
}
///Given any value, returns a copy of its bytes in an array.
@@ -1326,17 +1331,17 @@ pub fn toBytes(value: var) [@sizeOf(@typeOf(value))]u8 {
return asBytes(&value).*;
}
-test "std.mem.toBytes" {
+test "toBytes" {
var my_bytes = toBytes(u32(0x12345678));
switch (builtin.endian) {
- builtin.Endian.Big => testing.expect(std.mem.eql(u8, my_bytes, "\x12\x34\x56\x78")),
- builtin.Endian.Little => testing.expect(std.mem.eql(u8, my_bytes, "\x78\x56\x34\x12")),
+ builtin.Endian.Big => testing.expect(eql(u8, my_bytes, "\x12\x34\x56\x78")),
+ builtin.Endian.Little => testing.expect(eql(u8, my_bytes, "\x78\x56\x34\x12")),
}
my_bytes[0] = '\x99';
switch (builtin.endian) {
- builtin.Endian.Big => testing.expect(std.mem.eql(u8, my_bytes, "\x99\x34\x56\x78")),
- builtin.Endian.Little => testing.expect(std.mem.eql(u8, my_bytes, "\x99\x56\x34\x12")),
+ builtin.Endian.Big => testing.expect(eql(u8, my_bytes, "\x99\x34\x56\x78")),
+ builtin.Endian.Little => testing.expect(eql(u8, my_bytes, "\x99\x56\x34\x12")),
}
}
@@ -1358,7 +1363,7 @@ pub fn bytesAsValue(comptime T: type, bytes: var) BytesAsValueReturnType(T, @typ
return @ptrCast(BytesAsValueReturnType(T, @typeOf(bytes)), bytes);
}
-test "std.mem.bytesAsValue" {
+test "bytesAsValue" {
const deadbeef = u32(0xDEADBEEF);
const deadbeef_bytes = switch (builtin.endian) {
builtin.Endian.Big => "\xDE\xAD\xBE\xEF",
@@ -1400,7 +1405,7 @@ test "std.mem.bytesAsValue" {
pub fn bytesToValue(comptime T: type, bytes: var) T {
return bytesAsValue(T, &bytes).*;
}
-test "std.mem.bytesToValue" {
+test "bytesToValue" {
const deadbeef_bytes = switch (builtin.endian) {
builtin.Endian.Big => "\xDE\xAD\xBE\xEF",
builtin.Endian.Little => "\xEF\xBE\xAD\xDE",
@@ -1425,25 +1430,25 @@ pub fn subArrayPtr(ptr: var, comptime start: usize, comptime length: usize) SubA
return @ptrCast(ReturnType, &ptr[start]);
}
-test "std.mem.subArrayPtr" {
+test "subArrayPtr" {
const a1 = "abcdef";
const sub1 = subArrayPtr(&a1, 2, 3);
- testing.expect(std.mem.eql(u8, sub1.*, "cde"));
+ testing.expect(eql(u8, sub1.*, "cde"));
var a2 = "abcdef";
var sub2 = subArrayPtr(&a2, 2, 3);
- testing.expect(std.mem.eql(u8, sub2, "cde"));
+ testing.expect(eql(u8, sub2, "cde"));
sub2[1] = 'X';
- testing.expect(std.mem.eql(u8, a2, "abcXef"));
+ testing.expect(eql(u8, a2, "abcXef"));
}
/// Round an address up to the nearest aligned address
pub fn alignForward(addr: usize, alignment: usize) usize {
- return (addr + alignment - 1) & ~(alignment - 1);
+ return alignBackward(addr + (alignment - 1), alignment);
}
-test "std.mem.alignForward" {
+test "alignForward" {
testing.expect(alignForward(1, 1) == 1);
testing.expect(alignForward(2, 1) == 2);
testing.expect(alignForward(1, 2) == 2);
@@ -1457,3 +1462,30 @@ test "std.mem.alignForward" {
testing.expect(alignForward(16, 8) == 16);
testing.expect(alignForward(17, 8) == 24);
}
+
+pub fn alignBackward(addr: usize, alignment: usize) usize {
+ // 000010000 // example addr
+ // 000001111 // subtract 1
+ // 111110000 // binary not
+ return addr & ~(alignment - 1);
+}
+
+pub fn isAligned(addr: usize, alignment: usize) bool {
+ return alignBackward(addr, alignment) == addr;
+}
+
+test "isAligned" {
+ testing.expect(isAligned(0, 4));
+ testing.expect(isAligned(1, 1));
+ testing.expect(isAligned(2, 1));
+ testing.expect(isAligned(2, 2));
+ testing.expect(!isAligned(2, 4));
+ testing.expect(isAligned(3, 1));
+ testing.expect(!isAligned(3, 2));
+ testing.expect(!isAligned(3, 4));
+ testing.expect(isAligned(4, 4));
+ testing.expect(isAligned(4, 2));
+ testing.expect(isAligned(4, 1));
+ testing.expect(!isAligned(4, 8));
+ testing.expect(!isAligned(4, 16));
+}
diff --git a/std/mutex.zig b/std/mutex.zig
index 2b3ac4e366..6b8e586ea8 100644
--- a/std/mutex.zig
+++ b/std/mutex.zig
@@ -152,9 +152,9 @@ test "std.Mutex" {
testing.expect(context.data == TestContext.incr_count);
} else {
const thread_count = 10;
- var threads: [thread_count]*std.os.Thread = undefined;
+ var threads: [thread_count]*std.Thread = undefined;
for (threads) |*t| {
- t.* = try std.os.spawnThread(&context, worker);
+ t.* = try std.Thread.spawn(&context, worker);
}
for (threads) |t|
t.wait();
diff --git a/std/net.zig b/std/net.zig
index bb292efd83..b426759701 100644
--- a/std/net.zig
+++ b/std/net.zig
@@ -2,8 +2,8 @@ const std = @import("std.zig");
const builtin = @import("builtin");
const assert = std.debug.assert;
const net = @This();
-const posix = std.os.posix;
const mem = std.mem;
+const os = std.os;
pub const TmpWinAddr = struct {
family: u8,
@@ -12,7 +12,7 @@ pub const TmpWinAddr = struct {
pub const OsAddress = switch (builtin.os) {
builtin.Os.windows => TmpWinAddr,
- else => posix.sockaddr,
+ else => os.sockaddr,
};
pub const Address = struct {
@@ -20,9 +20,9 @@ pub const Address = struct {
pub fn initIp4(ip4: u32, _port: u16) Address {
return Address{
- .os_addr = posix.sockaddr{
- .in = posix.sockaddr_in{
- .family = posix.AF_INET,
+ .os_addr = os.sockaddr{
+ .in = os.sockaddr_in{
+ .family = os.AF_INET,
.port = mem.nativeToBig(u16, _port),
.addr = ip4,
.zero = []u8{0} ** 8,
@@ -33,10 +33,10 @@ pub const Address = struct {
pub fn initIp6(ip6: *const Ip6Addr, _port: u16) Address {
return Address{
- .family = posix.AF_INET6,
- .os_addr = posix.sockaddr{
- .in6 = posix.sockaddr_in6{
- .family = posix.AF_INET6,
+ .family = os.AF_INET6,
+ .os_addr = os.sockaddr{
+ .in6 = os.sockaddr_in6{
+ .family = os.AF_INET6,
.port = mem.nativeToBig(u16, _port),
.flowinfo = 0,
.addr = ip6.addr,
@@ -50,18 +50,18 @@ pub const Address = struct {
return mem.bigToNative(u16, self.os_addr.in.port);
}
- pub fn initPosix(addr: posix.sockaddr) Address {
+ pub fn initPosix(addr: os.sockaddr) Address {
return Address{ .os_addr = addr };
}
pub fn format(self: *const Address, out_stream: var) !void {
switch (self.os_addr.in.family) {
- posix.AF_INET => {
+ os.AF_INET => {
const native_endian_port = mem.bigToNative(u16, self.os_addr.in.port);
const bytes = ([]const u8)((*self.os_addr.in.addr)[0..1]);
try out_stream.print("{}.{}.{}.{}:{}", bytes[0], bytes[1], bytes[2], bytes[3], native_endian_port);
},
- posix.AF_INET6 => {
+ os.AF_INET6 => {
const native_endian_port = mem.bigToNative(u16, self.os_addr.in6.port);
try out_stream.print("[TODO render ip6 address]:{}", native_endian_port);
},
diff --git a/std/os.zig b/std/os.zig
index 9b452e89ae..be2be92f7d 100644
--- a/std/os.zig
+++ b/std/os.zig
@@ -1,495 +1,484 @@
+// This file contains thin wrappers around OS-specific APIs, with these
+// specific goals in mind:
+// * Convert "errno"-style error codes into Zig errors.
+// * When null-terminated byte buffers are required, provide APIs which accept
+// slices as well as APIs which accept null-terminated byte buffers. Same goes
+// for UTF-16LE encoding.
+// * Where operating systems share APIs, e.g. POSIX, these thin wrappers provide
+// cross platform abstracting.
+// * When there exists a corresponding libc function and linking libc, the libc
+// implementation is used. Exceptions are made for known buggy areas of libc.
+// On Linux libc can be side-stepped by using `std.os.linux` directly.
+// * For Windows, this file represents the API that libc would provide for
+// Windows. For thin wrappers around Windows-specific APIs, see `std.os.windows`.
+// Note: The Zig standard library does not support POSIX thread cancellation, and
+// in general EINTR is handled by trying again.
+
const std = @import("std.zig");
const builtin = @import("builtin");
-const Os = builtin.Os;
-const is_windows = builtin.os == Os.windows;
-const is_posix = switch (builtin.os) {
- builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => true,
- else => false,
-};
-const os = @This();
+const assert = std.debug.assert;
+const math = std.math;
+const mem = std.mem;
+const MAX_PATH_BYTES = std.fs.MAX_PATH_BYTES;
comptime {
- assert(@import("std") == std); // You have to run the std lib tests with --override-std-dir
-}
-
-test "std.os" {
- _ = @import("os/child_process.zig");
- _ = @import("os/darwin.zig");
- _ = @import("os/darwin/errno.zig");
- _ = @import("os/get_user_id.zig");
- _ = @import("os/linux.zig");
- _ = @import("os/path.zig");
- _ = @import("os/test.zig");
- _ = @import("os/time.zig");
- _ = @import("os/windows.zig");
- _ = @import("os/uefi.zig");
- _ = @import("os/wasi.zig");
- _ = @import("os/get_app_data_dir.zig");
+ assert(@import("std") == std); // std lib tests require --override-std-dir
}
-pub const windows = @import("os/windows.zig");
pub const darwin = @import("os/darwin.zig");
-pub const linux = @import("os/linux.zig");
pub const freebsd = @import("os/freebsd.zig");
+pub const linux = @import("os/linux.zig");
pub const netbsd = @import("os/netbsd.zig");
-pub const zen = @import("os/zen.zig");
pub const uefi = @import("os/uefi.zig");
pub const wasi = @import("os/wasi.zig");
+pub const windows = @import("os/windows.zig");
+pub const zen = @import("os/zen.zig");
-pub const posix = switch (builtin.os) {
- Os.linux => linux,
- Os.macosx, Os.ios => darwin,
- Os.freebsd => freebsd,
- Os.netbsd => netbsd,
- Os.zen => zen,
- Os.wasi => wasi,
- else => @compileError("Unsupported OS"),
-};
-
-pub const net = @import("net.zig");
-
-pub const ChildProcess = @import("os/child_process.zig").ChildProcess;
-pub const path = @import("os/path.zig");
-pub const File = @import("os/file.zig").File;
-pub const time = @import("os/time.zig");
-
-pub const page_size = switch (builtin.arch) {
- .wasm32, .wasm64 => 64 * 1024,
- else => 4 * 1024,
-};
-
-pub const MAX_PATH_BYTES = switch (builtin.os) {
- Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => posix.PATH_MAX,
- // Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
- // If it would require 4 UTF-8 bytes, then there would be a surrogate
- // pair in the UTF-16LE, and we (over)account 3 bytes for it that way.
- // +1 for the null byte at the end, which can be encoded in 1 byte.
- Os.windows => windows_util.PATH_MAX_WIDE * 3 + 1,
- else => @compileError("Unsupported OS"),
+/// When linking libc, this is the C API. Otherwise, it is the OS-specific system interface.
+pub const system = if (builtin.link_libc) std.c else switch (builtin.os) {
+ .macosx, .ios, .watchos, .tvos => darwin,
+ .freebsd => freebsd,
+ .linux => linux,
+ .netbsd => netbsd,
+ .wasi => wasi,
+ .windows => windows,
+ .zen => zen,
+ else => struct {},
};
-pub const UserInfo = @import("os/get_user_id.zig").UserInfo;
-pub const getUserInfo = @import("os/get_user_id.zig").getUserInfo;
-
-const windows_util = @import("os/windows/util.zig");
-pub const windowsWaitSingle = windows_util.windowsWaitSingle;
-pub const windowsWrite = windows_util.windowsWrite;
-pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;
-pub const windowsOpen = windows_util.windowsOpen;
-pub const windowsOpenW = windows_util.windowsOpenW;
-pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
-
-pub const WindowsCreateIoCompletionPortError = windows_util.WindowsCreateIoCompletionPortError;
-pub const windowsCreateIoCompletionPort = windows_util.windowsCreateIoCompletionPort;
-
-pub const WindowsPostQueuedCompletionStatusError = windows_util.WindowsPostQueuedCompletionStatusError;
-pub const windowsPostQueuedCompletionStatus = windows_util.windowsPostQueuedCompletionStatus;
-
-pub const WindowsWaitResult = windows_util.WindowsWaitResult;
-pub const windowsGetQueuedCompletionStatus = windows_util.windowsGetQueuedCompletionStatus;
-
-pub const WindowsWaitError = windows_util.WaitError;
-pub const WindowsOpenError = windows_util.OpenError;
-pub const WindowsWriteError = windows_util.WriteError;
-pub const WindowsReadError = windows_util.ReadError;
-
-pub const FileHandle = if (is_windows) windows.HANDLE else i32;
-
-pub const getAppDataDir = @import("os/get_app_data_dir.zig").getAppDataDir;
-pub const GetAppDataDirError = @import("os/get_app_data_dir.zig").GetAppDataDirError;
+pub use @import("os/bits.zig");
-const debug = std.debug;
-const assert = debug.assert;
-const testing = std.testing;
+/// See also `getenv`. Populated by startup code before main().
+pub var environ: [][*]u8 = undefined;
-const c = std.c;
+/// Populated by startup code before main().
+/// Not available on Windows. See `std.process.args`
+/// for obtaining the process arguments.
+pub var argv: [][*]u8 = undefined;
-const mem = std.mem;
-const Allocator = mem.Allocator;
+/// To obtain errno, call this function with the return value of the
+/// system function call. For some systems this will obtain the value directly
+/// from the return code; for others it will use a thread-local errno variable.
+/// Therefore, this function only returns a well-defined value when it is called
+/// directly after the system function call which one wants to learn the errno
+/// value of.
+pub const errno = system.getErrno;
-const BufMap = std.BufMap;
-const cstr = std.cstr;
+/// Closes the file descriptor.
+/// This function is not capable of returning any indication of failure. An
+/// application which wants to ensure writes have succeeded before closing
+/// must call `fsync` before `close`.
+/// Note: The Zig standard library does not support POSIX thread cancellation.
+pub fn close(fd: fd_t) void {
+ if (windows.is_the_target) {
+ return windows.CloseHandle(fd);
+ }
+ if (wasi.is_the_target) {
+ _ = wasi.fd_close(fd);
+ }
+ if (darwin.is_the_target) {
+ // This avoids the EINTR problem.
+ switch (darwin.getErrno(darwin.@"close$NOCANCEL"(fd))) {
+ EBADF => unreachable, // Always a race condition.
+ else => return,
+ }
+ }
+ switch (errno(system.close(fd))) {
+ EBADF => unreachable, // Always a race condition.
+ EINTR => return, // This is still a success. See https://github.com/ziglang/zig/issues/2425
+ else => return,
+ }
+}
-const io = std.io;
-const base64 = std.base64;
-const ArrayList = std.ArrayList;
-const Buffer = std.Buffer;
-const math = std.math;
+pub const GetRandomError = OpenError;
-/// Fills `buf` with random bytes. If linking against libc, this calls the
+/// Obtain a series of random bytes. These bytes can be used to seed user-space
+/// random number generators or for cryptographic purposes.
+/// When linking against libc, this calls the
/// appropriate OS-specific library call. Otherwise it uses the zig standard
/// library implementation.
-pub fn getRandomBytes(buf: []u8) !void {
- switch (builtin.os) {
- Os.linux => while (true) {
- // TODO check libc version and potentially call c.getrandom.
- // See #397
- const errno = posix.getErrno(posix.getrandom(buf.ptr, buf.len, 0));
- switch (errno) {
+pub fn getrandom(buf: []u8) GetRandomError!void {
+ if (windows.is_the_target) {
+ return windows.RtlGenRandom(buf);
+ }
+ if (linux.is_the_target) {
+ while (true) {
+ // Bypass libc because it's missing on even relatively new versions.
+ switch (linux.getErrno(linux.getrandom(buf.ptr, buf.len, 0))) {
0 => return,
- posix.EINVAL => unreachable,
- posix.EFAULT => unreachable,
- posix.EINTR => continue,
- posix.ENOSYS => return getRandomBytesDevURandom(buf),
- else => return unexpectedErrorPosix(errno),
- }
- },
- Os.macosx, Os.ios, Os.freebsd, Os.netbsd => return getRandomBytesDevURandom(buf),
- Os.windows => {
- // Call RtlGenRandom() instead of CryptGetRandom() on Windows
- // https://github.com/rust-lang-nursery/rand/issues/111
- // https://bugzilla.mozilla.org/show_bug.cgi?id=504270
- if (windows.RtlGenRandom(buf.ptr, buf.len) == 0) {
- const err = windows.GetLastError();
- return switch (err) {
- else => unexpectedErrorWindows(err),
- };
- }
- },
- Os.wasi => {
- const random_get_result = os.wasi.random_get(buf.ptr, buf.len);
- if (random_get_result != os.wasi.ESUCCESS) {
- return error.Unknown;
- }
- },
- Os.zen => {
- const randomness = []u8{ 42, 1, 7, 12, 22, 17, 99, 16, 26, 87, 41, 45 };
- var i: usize = 0;
- while (i < buf.len) : (i += 1) {
- if (i > randomness.len) return error.Unknown;
- buf[i] = randomness[i];
+ EINVAL => unreachable,
+ EFAULT => unreachable,
+ EINTR => continue,
+ ENOSYS => return getRandomBytesDevURandom(buf),
+ else => |err| return unexpectedErrno(err),
}
- },
- else => @compileError("Unsupported OS"),
+ }
+ }
+ if (wasi.is_the_target) {
+ switch (wasi.random_get(buf.ptr, buf.len)) {
+ 0 => return,
+ else => |err| return unexpectedErrno(err),
+ }
}
+ return getRandomBytesDevURandom(buf);
}
fn getRandomBytesDevURandom(buf: []u8) !void {
- const fd = try posixOpenC(c"/dev/urandom", posix.O_RDONLY | posix.O_CLOEXEC, 0);
+ const fd = try openC(c"/dev/urandom", O_RDONLY | O_CLOEXEC, 0);
defer close(fd);
- const stream = &File.openHandle(fd).inStream().stream;
- stream.readNoEof(buf) catch |err| switch (err) {
- error.EndOfStream => unreachable,
- error.OperationAborted => unreachable,
- error.BrokenPipe => unreachable,
- error.Unexpected => return error.Unexpected,
- error.InputOutput => return error.Unexpected,
- error.SystemResources => return error.Unexpected,
- error.IsDir => unreachable,
- };
+ const stream = &std.fs.File.openHandle(fd).inStream().stream;
+ stream.readNoEof(buf) catch return error.Unexpected;
}
-test "os.getRandomBytes" {
- var buf_a: [50]u8 = undefined;
- var buf_b: [50]u8 = undefined;
- // Call Twice
- try getRandomBytes(buf_a[0..]);
- try getRandomBytes(buf_b[0..]);
-
- // Check if random (not 100% conclusive)
- testing.expect(!mem.eql(u8, buf_a, buf_b));
-}
-
-/// Raises a signal in the current kernel thread, ending its execution.
+/// Causes abnormal process termination.
/// If linking against libc, this calls the abort() libc function. Otherwise
-/// it uses the zig standard library implementation.
+/// it raises SIGABRT followed by SIGKILL and finally lo
pub fn abort() noreturn {
@setCold(true);
if (builtin.link_libc) {
- c.abort();
+ system.abort();
}
- switch (builtin.os) {
- Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
- _ = posix.raise(posix.SIGABRT);
- _ = posix.raise(posix.SIGKILL);
- while (true) {}
- },
- Os.windows => {
- if (builtin.mode == builtin.Mode.Debug) {
- @breakpoint();
- }
- windows.ExitProcess(3);
- },
- Os.wasi => {
- _ = wasi.proc_raise(wasi.SIGABRT);
- // TODO: Is SIGKILL even necessary?
- _ = wasi.proc_raise(wasi.SIGKILL);
- while (true) {}
- },
- Os.uefi => {
- // TODO there's gotta be a better thing to do here than loop forever
- while (true) {}
- },
- else => @compileError("Unsupported OS"),
+ if (windows.is_the_target) {
+ if (builtin.mode == .Debug) {
+ @breakpoint();
+ }
+ windows.kernel32.ExitProcess(3);
}
+ if (builtin.os == .uefi) {
+ // TODO there must be a better thing to do here than loop forever
+ while (true) {}
+ }
+
+ raise(SIGABRT) catch {};
+
+ // TODO the rest of the implementation of abort() from musl libc here
+
+ raise(SIGKILL) catch {};
+ exit(127);
}
-/// Exits the program cleanly with the specified status code.
-pub fn exit(status: u8) noreturn {
- @setCold(true);
+pub const RaiseError = error{Unexpected};
+
+pub fn raise(sig: u8) RaiseError!void {
if (builtin.link_libc) {
- c.exit(status);
- }
- switch (builtin.os) {
- Os.linux => {
- if (builtin.single_threaded) {
- linux.exit(status);
- } else {
- linux.exit_group(status);
- }
- },
- Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
- posix.exit(status);
- },
- Os.windows => {
- windows.ExitProcess(status);
- },
- Os.wasi => {
- wasi.proc_exit(status);
- },
- else => @compileError("Unsupported OS"),
+ switch (errno(system.raise(sig))) {
+ 0 => return,
+ else => |err| return unexpectedErrno(err),
+ }
}
-}
-/// When a file descriptor is closed on linux, it pops the first
-/// node from this queue and resumes it.
-/// Async functions which get the EMFILE error code can suspend,
-/// putting their coroutine handle into this list.
-/// TODO make this an atomic linked list
-pub var emfile_promise_queue = std.LinkedList(promise).init();
+ if (wasi.is_the_target) {
+ switch (wasi.proc_raise(SIGABRT)) {
+ 0 => return,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
-/// Closes the file handle. Keeps trying if it gets interrupted by a signal.
-pub fn close(handle: FileHandle) void {
- if (is_windows) {
- windows_util.windowsClose(handle);
- } else {
- while (true) {
- const err = posix.getErrno(posix.close(handle));
- switch (err) {
- posix.EINTR => continue,
- else => {
- if (emfile_promise_queue.popFirst()) |p| resume p.data;
- return;
- },
- }
+ if (linux.is_the_target) {
+ var set: linux.sigset_t = undefined;
+ linux.blockAppSignals(&set);
+ const tid = linux.syscall0(linux.SYS_gettid);
+ const rc = linux.syscall2(linux.SYS_tkill, tid, sig);
+ linux.restoreSignals(&set);
+ switch (errno(rc)) {
+ 0 => return,
+ else => |err| return unexpectedErrno(err),
}
}
+
+ @compileError("std.os.raise unimplemented for this target");
}
-pub const PosixReadError = error{
+pub const KillError = error{
+ PermissionDenied,
+ Unexpected,
+};
+
+pub fn kill(pid: pid_t, sig: u8) KillError!void {
+ switch (errno(system.kill(pid, sig))) {
+ 0 => return,
+ EINVAL => unreachable, // invalid signal
+ EPERM => return error.PermissionDenied,
+ ESRCH => unreachable, // always a race condition
+ else => |err| return unexpectedErrno(err),
+ }
+}
+
+/// Exits the program cleanly with the specified status code.
+pub fn exit(status: u8) noreturn {
+ if (builtin.link_libc) {
+ system.exit(status);
+ }
+ if (windows.is_the_target) {
+ windows.kernel32.ExitProcess(status);
+ }
+ if (wasi.is_the_target) {
+ wasi.proc_exit(status);
+ }
+ if (linux.is_the_target and !builtin.single_threaded) {
+ linux.exit_group(status);
+ }
+ system.exit(status);
+}
+
+pub const ReadError = error{
InputOutput,
SystemResources,
IsDir,
+ OperationAborted,
+ BrokenPipe,
Unexpected,
};
/// Returns the number of bytes that were read, which can be less than
/// buf.len. If 0 bytes were read, that means EOF.
-pub fn posixRead(fd: i32, buf: []u8) PosixReadError!usize {
+/// This function is for blocking file descriptors only. For non-blocking, see
+/// `readAsync`.
+pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
+ if (windows.is_the_target) {
+ return windows.ReadFile(fd, buf);
+ }
+
+ if (wasi.is_the_target and !builtin.link_libc) {
+ const iovs = [1]iovec{iovec{
+ .iov_base = buf.ptr,
+ .iov_len = buf.len,
+ }};
+
+ var nread: usize = undefined;
+ switch (wasi.fd_read(fd, &iovs, iovs.len, &nread)) {
+ 0 => return nread,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+
// Linux can return EINVAL when read amount is > 0x7ffff000
// See https://github.com/ziglang/zig/pull/743#issuecomment-363158274
+ // TODO audit this. Shawn Landden says that this is not actually true.
+ // if this logic should stay, move it to std.os.linux
const max_buf_len = 0x7ffff000;
var index: usize = 0;
while (index < buf.len) {
const want_to_read = math.min(buf.len - index, usize(max_buf_len));
- const rc = posix.read(fd, buf.ptr + index, want_to_read);
- const err = posix.getErrno(rc);
- switch (err) {
+ const rc = system.read(fd, buf.ptr + index, want_to_read);
+ switch (errno(rc)) {
0 => {
- index += rc;
- if (rc == want_to_read) continue;
+ const amt_read = @intCast(usize, rc);
+ index += amt_read;
+ if (amt_read == want_to_read) continue;
// Read returned less than buf.len.
return index;
},
- posix.EINTR => continue,
- posix.EINVAL => unreachable,
- posix.EFAULT => unreachable,
- posix.EAGAIN => unreachable,
- posix.EBADF => unreachable, // always a race condition
- posix.EIO => return error.InputOutput,
- posix.EISDIR => return error.IsDir,
- posix.ENOBUFS => return error.SystemResources,
- posix.ENOMEM => return error.SystemResources,
- else => return unexpectedErrorPosix(err),
+ EINTR => continue,
+ EINVAL => unreachable,
+ EFAULT => unreachable,
+ EAGAIN => unreachable, // This function is for blocking reads.
+ EBADF => unreachable, // Always a race condition.
+ EIO => return error.InputOutput,
+ EISDIR => return error.IsDir,
+ ENOBUFS => return error.SystemResources,
+ ENOMEM => return error.SystemResources,
+ else => |err| return unexpectedErrno(err),
}
}
return index;
}
/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
-pub fn posix_preadv(fd: i32, iov: [*]const posix.iovec, count: usize, offset: u64) PosixReadError!usize {
- switch (builtin.os) {
- builtin.Os.macosx => {
- // Darwin does not have preadv but it does have pread.
- var off: usize = 0;
- var iov_i: usize = 0;
- var inner_off: usize = 0;
- while (true) {
- const v = iov[iov_i];
- const rc = darwin.pread(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
- const err = darwin.getErrno(rc);
- switch (err) {
- 0 => {
- off += rc;
- inner_off += rc;
- if (inner_off == v.iov_len) {
- iov_i += 1;
- inner_off = 0;
- if (iov_i == count) {
- return off;
- }
- }
- if (rc == 0) return off; // EOF
- continue;
- },
- posix.EINTR => continue,
- posix.EINVAL => unreachable,
- posix.EFAULT => unreachable,
- posix.ESPIPE => unreachable, // fd is not seekable
- posix.EAGAIN => unreachable, // this function is not for non blocking
- posix.EBADF => unreachable, // always a race condition
- posix.EIO => return error.InputOutput,
- posix.EISDIR => return error.IsDir,
- posix.ENOBUFS => return error.SystemResources,
- posix.ENOMEM => return error.SystemResources,
- else => return unexpectedErrorPosix(err),
- }
- }
- },
- builtin.Os.linux, builtin.Os.freebsd, Os.netbsd => while (true) {
- const rc = posix.preadv(fd, iov, count, offset);
- const err = posix.getErrno(rc);
+/// This function is for blocking file descriptors only. For non-blocking, see
+/// `preadvAsync`.
+pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) ReadError!usize {
+ if (darwin.is_the_target) {
+ // Darwin does not have preadv but it does have pread.
+ var off: usize = 0;
+ var iov_i: usize = 0;
+ var inner_off: usize = 0;
+ while (true) {
+ const v = iov[iov_i];
+ const rc = darwin.pread(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
+ const err = darwin.getErrno(rc);
switch (err) {
- 0 => return rc,
- posix.EINTR => continue,
- posix.EINVAL => unreachable,
- posix.EFAULT => unreachable,
- posix.EAGAIN => unreachable, // don't call this function for non blocking
- posix.EBADF => unreachable, // always a race condition
- posix.EIO => return error.InputOutput,
- posix.EISDIR => return error.IsDir,
- posix.ENOBUFS => return error.SystemResources,
- posix.ENOMEM => return error.SystemResources,
- else => return unexpectedErrorPosix(err),
+ 0 => {
+ const amt_read = @bitCast(usize, rc);
+ off += amt_read;
+ inner_off += amt_read;
+ if (inner_off == v.iov_len) {
+ iov_i += 1;
+ inner_off = 0;
+ if (iov_i == iov.len) {
+ return off;
+ }
+ }
+ if (rc == 0) return off; // EOF
+ continue;
+ },
+ EINTR => continue,
+ EINVAL => unreachable,
+ EFAULT => unreachable,
+ ESPIPE => unreachable, // fd is not seekable
+ EAGAIN => unreachable, // This function is for blocking reads.
+ EBADF => unreachable, // always a race condition
+ EIO => return error.InputOutput,
+ EISDIR => return error.IsDir,
+ ENOBUFS => return error.SystemResources,
+ ENOMEM => return error.SystemResources,
+ else => return unexpectedErrno(err),
}
- },
- else => @compileError("Unsupported OS"),
+ }
+ }
+ while (true) {
+ // TODO handle the case when iov_len is too large and get rid of this @intCast
+ const rc = system.preadv(fd, iov.ptr, @intCast(u32, iov.len), offset);
+ switch (errno(rc)) {
+ 0 => return @bitCast(usize, rc),
+ EINTR => continue,
+ EINVAL => unreachable,
+ EFAULT => unreachable,
+ EAGAIN => unreachable, // This function is for blocking reads.
+ EBADF => unreachable, // always a race condition
+ EIO => return error.InputOutput,
+ EISDIR => return error.IsDir,
+ ENOBUFS => return error.SystemResources,
+ ENOMEM => return error.SystemResources,
+ else => |err| return unexpectedErrno(err),
+ }
}
}
-pub const PosixWriteError = error{
+pub const WriteError = error{
DiskQuota,
FileTooBig,
InputOutput,
NoSpaceLeft,
AccessDenied,
BrokenPipe,
-
- /// See https://github.com/ziglang/zig/issues/1396
+ SystemResources,
+ OperationAborted,
Unexpected,
};
-/// Calls POSIX write, and keeps trying if it gets interrupted.
-pub fn posixWrite(fd: i32, bytes: []const u8) PosixWriteError!void {
+/// Write to a file descriptor. Keeps trying if it gets interrupted.
+/// This function is for blocking file descriptors only. For non-blocking, see
+/// `writeAsync`.
+pub fn write(fd: fd_t, bytes: []const u8) WriteError!void {
+ if (windows.is_the_target) {
+ return windows.WriteFile(fd, bytes);
+ }
+
+ if (wasi.is_the_target and !builtin.link_libc) {
+ const ciovs = [1]iovec_const{iovec_const{
+ .iov_base = bytes.ptr,
+ .iov_len = bytes.len,
+ }};
+ var nwritten: usize = undefined;
+ switch (wasi.fd_write(fd, &ciovs, ciovs.len, &nwritten)) {
+ 0 => return,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+
// Linux can return EINVAL when write amount is > 0x7ffff000
// See https://github.com/ziglang/zig/pull/743#issuecomment-363165856
+ // TODO audit this. Shawn Landden says that this is not actually true.
+ // if this logic should stay, move it to std.os.linux
const max_bytes_len = 0x7ffff000;
var index: usize = 0;
while (index < bytes.len) {
const amt_to_write = math.min(bytes.len - index, usize(max_bytes_len));
- const rc = posix.write(fd, bytes.ptr + index, amt_to_write);
- const write_err = posix.getErrno(rc);
- switch (write_err) {
+ const rc = system.write(fd, bytes.ptr + index, amt_to_write);
+ switch (errno(rc)) {
0 => {
- index += rc;
+ index += @intCast(usize, rc);
continue;
},
- posix.EINTR => continue,
- posix.EINVAL => unreachable,
- posix.EFAULT => unreachable,
- posix.EAGAIN => unreachable, // use posixAsyncWrite for non-blocking
- posix.EBADF => unreachable, // always a race condition
- posix.EDESTADDRREQ => unreachable, // connect was never called
- posix.EDQUOT => return PosixWriteError.DiskQuota,
- posix.EFBIG => return PosixWriteError.FileTooBig,
- posix.EIO => return PosixWriteError.InputOutput,
- posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
- posix.EPERM => return PosixWriteError.AccessDenied,
- posix.EPIPE => return PosixWriteError.BrokenPipe,
- else => return unexpectedErrorPosix(write_err),
+ EINTR => continue,
+ EINVAL => unreachable,
+ EFAULT => unreachable,
+ EAGAIN => unreachable, // This function is for blocking writes.
+ EBADF => unreachable, // Always a race condition.
+ EDESTADDRREQ => unreachable, // `connect` was never called.
+ EDQUOT => return error.DiskQuota,
+ EFBIG => return error.FileTooBig,
+ EIO => return error.InputOutput,
+ ENOSPC => return error.NoSpaceLeft,
+ EPERM => return error.AccessDenied,
+ EPIPE => return error.BrokenPipe,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+}
+
+/// Write multiple buffers to a file descriptor. Keeps trying if it gets interrupted.
+/// This function is for blocking file descriptors only. For non-blocking, see
+/// `pwritevAsync`.
+pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) WriteError!void {
+ if (darwin.is_the_target) {
+ // Darwin does not have pwritev but it does have pwrite.
+ var off: usize = 0;
+ var iov_i: usize = 0;
+ var inner_off: usize = 0;
+ while (true) {
+ const v = iov[iov_i];
+ const rc = darwin.pwrite(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
+ const err = darwin.getErrno(rc);
+ switch (err) {
+ 0 => {
+ const amt_written = @bitCast(usize, rc);
+ off += amt_written;
+ inner_off += amt_written;
+ if (inner_off == v.iov_len) {
+ iov_i += 1;
+ inner_off = 0;
+ if (iov_i == iov.len) {
+ return;
+ }
+ }
+ continue;
+ },
+ EINTR => continue,
+ ESPIPE => unreachable, // `fd` is not seekable.
+ EINVAL => unreachable,
+ EFAULT => unreachable,
+ EAGAIN => unreachable, // This function is for blocking writes.
+ EBADF => unreachable, // Always a race condition.
+ EDESTADDRREQ => unreachable, // `connect` was never called.
+ EDQUOT => return error.DiskQuota,
+ EFBIG => return error.FileTooBig,
+ EIO => return error.InputOutput,
+ ENOSPC => return error.NoSpaceLeft,
+ EPERM => return error.AccessDenied,
+ EPIPE => return error.BrokenPipe,
+ else => return unexpectedErrno(err),
+ }
}
}
-}
-pub fn posix_pwritev(fd: i32, iov: [*]const posix.iovec_const, count: usize, offset: u64) PosixWriteError!void {
- switch (builtin.os) {
- builtin.Os.macosx => {
- // Darwin does not have pwritev but it does have pwrite.
- var off: usize = 0;
- var iov_i: usize = 0;
- var inner_off: usize = 0;
- while (true) {
- const v = iov[iov_i];
- const rc = darwin.pwrite(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
- const err = darwin.getErrno(rc);
- switch (err) {
- 0 => {
- off += rc;
- inner_off += rc;
- if (inner_off == v.iov_len) {
- iov_i += 1;
- inner_off = 0;
- if (iov_i == count) {
- return;
- }
- }
- continue;
- },
- posix.EINTR => continue,
- posix.ESPIPE => unreachable, // fd is not seekable
- posix.EINVAL => unreachable,
- posix.EFAULT => unreachable,
- posix.EAGAIN => unreachable, // use posixAsyncPWriteV for non-blocking
- posix.EBADF => unreachable, // always a race condition
- posix.EDESTADDRREQ => unreachable, // connect was never called
- posix.EDQUOT => return PosixWriteError.DiskQuota,
- posix.EFBIG => return PosixWriteError.FileTooBig,
- posix.EIO => return PosixWriteError.InputOutput,
- posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
- posix.EPERM => return PosixWriteError.AccessDenied,
- posix.EPIPE => return PosixWriteError.BrokenPipe,
- else => return unexpectedErrorPosix(err),
- }
- }
- },
- builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => while (true) {
- const rc = posix.pwritev(fd, iov, count, offset);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return,
- posix.EINTR => continue,
- posix.EINVAL => unreachable,
- posix.EFAULT => unreachable,
- posix.EAGAIN => unreachable, // use posixAsyncPWriteV for non-blocking
- posix.EBADF => unreachable, // always a race condition
- posix.EDESTADDRREQ => unreachable, // connect was never called
- posix.EDQUOT => return PosixWriteError.DiskQuota,
- posix.EFBIG => return PosixWriteError.FileTooBig,
- posix.EIO => return PosixWriteError.InputOutput,
- posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
- posix.EPERM => return PosixWriteError.AccessDenied,
- posix.EPIPE => return PosixWriteError.BrokenPipe,
- else => return unexpectedErrorPosix(err),
- }
- },
- else => @compileError("Unsupported OS"),
+ while (true) {
+ // TODO handle the case when iov_len is too large and get rid of this @intCast
+ const rc = system.pwritev(fd, iov.ptr, @intCast(u32, iov.len), offset);
+ switch (errno(rc)) {
+ 0 => return,
+ EINTR => continue,
+ EINVAL => unreachable,
+ EFAULT => unreachable,
+ EAGAIN => unreachable, // This function is for blocking writes.
+ EBADF => unreachable, // Always a race condition.
+ EDESTADDRREQ => unreachable, // `connect` was never called.
+ EDQUOT => return error.DiskQuota,
+ EFBIG => return error.FileTooBig,
+ EIO => return error.InputOutput,
+ ENOSPC => return error.NoSpaceLeft,
+ EPERM => return error.AccessDenied,
+ EPIPE => return error.BrokenPipe,
+ else => |err| return unexpectedErrno(err),
+ }
}
}
-pub const PosixOpenError = error{
+pub const OpenError = error{
AccessDenied,
FileTooBig,
IsDir,
@@ -504,106 +493,60 @@ pub const PosixOpenError = error{
NotDir,
PathAlreadyExists,
DeviceBusy,
-
- /// See https://github.com/ziglang/zig/issues/1396
Unexpected,
};
-/// ::file_path needs to be copied in memory to add a null terminating byte.
-/// Calls POSIX open, keeps trying if it gets interrupted, and translates
-/// the return value into zig errors.
-pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize) PosixOpenError!i32 {
+/// Open and possibly create a file. Keeps trying if it gets interrupted.
+/// `file_path` needs to be copied in memory to add a null terminating byte.
+/// See also `openC`.
+pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!fd_t {
const file_path_c = try toPosixPath(file_path);
- return posixOpenC(&file_path_c, flags, perm);
+ return openC(&file_path_c, flags, perm);
}
-// TODO https://github.com/ziglang/zig/issues/265
-pub fn posixOpenC(file_path: [*]const u8, flags: u32, perm: usize) !i32 {
+/// Open and possibly create a file. Keeps trying if it gets interrupted.
+/// See also `open`.
+/// TODO https://github.com/ziglang/zig/issues/265
+pub fn openC(file_path: [*]const u8, flags: u32, perm: usize) OpenError!fd_t {
while (true) {
- const result = posix.open(file_path, flags, perm);
- const err = posix.getErrno(result);
- if (err > 0) {
- switch (err) {
- posix.EINTR => continue,
-
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.EACCES => return PosixOpenError.AccessDenied,
- posix.EFBIG, posix.EOVERFLOW => return PosixOpenError.FileTooBig,
- posix.EISDIR => return PosixOpenError.IsDir,
- posix.ELOOP => return PosixOpenError.SymLinkLoop,
- posix.EMFILE => return PosixOpenError.ProcessFdQuotaExceeded,
- posix.ENAMETOOLONG => return PosixOpenError.NameTooLong,
- posix.ENFILE => return PosixOpenError.SystemFdQuotaExceeded,
- posix.ENODEV => return PosixOpenError.NoDevice,
- posix.ENOENT => return PosixOpenError.FileNotFound,
- posix.ENOMEM => return PosixOpenError.SystemResources,
- posix.ENOSPC => return PosixOpenError.NoSpaceLeft,
- posix.ENOTDIR => return PosixOpenError.NotDir,
- posix.EPERM => return PosixOpenError.AccessDenied,
- posix.EEXIST => return PosixOpenError.PathAlreadyExists,
- posix.EBUSY => return PosixOpenError.DeviceBusy,
- else => return unexpectedErrorPosix(err),
- }
- }
- return @intCast(i32, result);
- }
-}
-
-/// Used to convert a slice to a null terminated slice on the stack.
-/// TODO well defined copy elision
-pub fn toPosixPath(file_path: []const u8) ![posix.PATH_MAX]u8 {
- var path_with_null: [posix.PATH_MAX]u8 = undefined;
- if (file_path.len >= posix.PATH_MAX) return error.NameTooLong;
- mem.copy(u8, path_with_null[0..], file_path);
- path_with_null[file_path.len] = 0;
- return path_with_null;
-}
-
-pub fn posixDup2(old_fd: i32, new_fd: i32) !void {
+ const rc = system.open(file_path, flags, perm);
+ switch (errno(rc)) {
+ 0 => return @intCast(fd_t, rc),
+ EINTR => continue,
+
+ EFAULT => unreachable,
+ EINVAL => unreachable,
+ EACCES => return error.AccessDenied,
+ EFBIG => return error.FileTooBig,
+ EOVERFLOW => return error.FileTooBig,
+ EISDIR => return error.IsDir,
+ ELOOP => return error.SymLinkLoop,
+ EMFILE => return error.ProcessFdQuotaExceeded,
+ ENAMETOOLONG => return error.NameTooLong,
+ ENFILE => return error.SystemFdQuotaExceeded,
+ ENODEV => return error.NoDevice,
+ ENOENT => return error.FileNotFound,
+ ENOMEM => return error.SystemResources,
+ ENOSPC => return error.NoSpaceLeft,
+ ENOTDIR => return error.NotDir,
+ EPERM => return error.AccessDenied,
+ EEXIST => return error.PathAlreadyExists,
+ EBUSY => return error.DeviceBusy,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+}
+
+pub fn dup2(old_fd: fd_t, new_fd: fd_t) !void {
while (true) {
- const err = posix.getErrno(posix.dup2(old_fd, new_fd));
- if (err > 0) {
- return switch (err) {
- posix.EBUSY, posix.EINTR => continue,
- posix.EMFILE => error.ProcessFdQuotaExceeded,
- posix.EINVAL => unreachable,
- else => unexpectedErrorPosix(err),
- };
- }
- return;
- }
-}
-
-pub fn createNullDelimitedEnvMap(allocator: *Allocator, env_map: *const BufMap) ![]?[*]u8 {
- const envp_count = env_map.count();
- const envp_buf = try allocator.alloc(?[*]u8, envp_count + 1);
- mem.set(?[*]u8, envp_buf, null);
- errdefer freeNullDelimitedEnvMap(allocator, envp_buf);
- {
- var it = env_map.iterator();
- var i: usize = 0;
- while (it.next()) |pair| : (i += 1) {
- const env_buf = try allocator.alloc(u8, pair.key.len + pair.value.len + 2);
- @memcpy(env_buf.ptr, pair.key.ptr, pair.key.len);
- env_buf[pair.key.len] = '=';
- @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len);
- env_buf[env_buf.len - 1] = 0;
-
- envp_buf[i] = env_buf.ptr;
+ switch (errno(system.dup2(old_fd, new_fd))) {
+ 0 => return,
+ EBUSY, EINTR => continue,
+ EMFILE => return error.ProcessFdQuotaExceeded,
+ EINVAL => unreachable,
+ else => |err| return unexpectedErrno(err),
}
- assert(i == envp_count);
- }
- assert(envp_buf[envp_count] == null);
- return envp_buf;
-}
-
-pub fn freeNullDelimitedEnvMap(allocator: *Allocator, envp_buf: []?[*]u8) void {
- for (envp_buf) |env| {
- const env_buf = if (env) |ptr| ptr[0 .. cstr.len(ptr) + 1] else break;
- allocator.free(env_buf);
}
- allocator.free(envp_buf);
}
/// This function must allocate memory to add a null terminating bytes on path and each arg.
@@ -611,34 +554,35 @@ pub fn freeNullDelimitedEnvMap(allocator: *Allocator, envp_buf: []?[*]u8) void {
/// pointers after the args and after the environment variables.
/// `argv[0]` is the executable path.
/// This function also uses the PATH environment variable to get the full path to the executable.
-pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator: *Allocator) !void {
- const argv_buf = try allocator.alloc(?[*]u8, argv.len + 1);
+/// TODO provide execveC which does not take an allocator
+pub fn execve(allocator: *mem.Allocator, argv_slice: []const []const u8, env_map: *const std.BufMap) !void {
+ const argv_buf = try allocator.alloc(?[*]u8, argv_slice.len + 1);
mem.set(?[*]u8, argv_buf, null);
defer {
for (argv_buf) |arg| {
- const arg_buf = if (arg) |ptr| cstr.toSlice(ptr) else break;
+ const arg_buf = if (arg) |ptr| mem.toSlice(u8, ptr) else break;
allocator.free(arg_buf);
}
allocator.free(argv_buf);
}
- for (argv) |arg, i| {
+ for (argv_slice) |arg, i| {
const arg_buf = try allocator.alloc(u8, arg.len + 1);
@memcpy(arg_buf.ptr, arg.ptr, arg.len);
arg_buf[arg.len] = 0;
argv_buf[i] = arg_buf.ptr;
}
- argv_buf[argv.len] = null;
+ argv_buf[argv_slice.len] = null;
const envp_buf = try createNullDelimitedEnvMap(allocator, env_map);
defer freeNullDelimitedEnvMap(allocator, envp_buf);
- const exe_path = argv[0];
+ const exe_path = argv_slice[0];
if (mem.indexOfScalar(u8, exe_path, '/') != null) {
- return posixExecveErrnoToErr(posix.getErrno(posix.execve(argv_buf[0].?, argv_buf.ptr, envp_buf.ptr)));
+ return execveErrnoToErr(errno(system.execve(argv_buf[0].?, argv_buf.ptr, envp_buf.ptr)));
}
- const PATH = getEnvPosix("PATH") orelse "/usr/local/bin:/bin/:/usr/bin";
+ const PATH = getenv("PATH") orelse "/usr/local/bin:/bin/:/usr/bin";
// PATH.len because it is >= the largest search_path
// +1 for the / to join the search path and exe_path
// +1 for the null terminating byte
@@ -652,21 +596,52 @@ pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator:
path_buf[search_path.len] = '/';
mem.copy(u8, path_buf[search_path.len + 1 ..], exe_path);
path_buf[search_path.len + exe_path.len + 1] = 0;
- err = posix.getErrno(posix.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr));
+ err = errno(system.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr));
assert(err > 0);
- if (err == posix.EACCES) {
+ if (err == EACCES) {
seen_eacces = true;
- } else if (err != posix.ENOENT) {
- return posixExecveErrnoToErr(err);
+ } else if (err != ENOENT) {
+ return execveErrnoToErr(err);
}
}
if (seen_eacces) {
- err = posix.EACCES;
+ err = EACCES;
}
- return posixExecveErrnoToErr(err);
+ return execveErrnoToErr(err);
}
-pub const PosixExecveError = error{
+pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.BufMap) ![]?[*]u8 {
+ const envp_count = env_map.count();
+ const envp_buf = try allocator.alloc(?[*]u8, envp_count + 1);
+ mem.set(?[*]u8, envp_buf, null);
+ errdefer freeNullDelimitedEnvMap(allocator, envp_buf);
+ {
+ var it = env_map.iterator();
+ var i: usize = 0;
+ while (it.next()) |pair| : (i += 1) {
+ const env_buf = try allocator.alloc(u8, pair.key.len + pair.value.len + 2);
+ @memcpy(env_buf.ptr, pair.key.ptr, pair.key.len);
+ env_buf[pair.key.len] = '=';
+ @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len);
+ env_buf[env_buf.len - 1] = 0;
+
+ envp_buf[i] = env_buf.ptr;
+ }
+ assert(i == envp_count);
+ }
+ assert(envp_buf[envp_count] == null);
+ return envp_buf;
+}
+
+pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*]u8) void {
+ for (envp_buf) |env| {
+ const env_buf = if (env) |ptr| ptr[0 .. mem.len(u8, ptr) + 1] else break;
+ allocator.free(env_buf);
+ }
+ allocator.free(envp_buf);
+}
+
+pub const ExecveError = error{
SystemResources,
AccessDenied,
InvalidExe,
@@ -675,157 +650,41 @@ pub const PosixExecveError = error{
FileNotFound,
NotDir,
FileBusy,
+ ProcessFdQuotaExceeded,
+ SystemFdQuotaExceeded,
+ NameTooLong,
- /// See https://github.com/ziglang/zig/issues/1396
Unexpected,
};
-fn posixExecveErrnoToErr(err: usize) PosixExecveError {
+fn execveErrnoToErr(err: usize) ExecveError {
assert(err > 0);
switch (err) {
- posix.EFAULT => unreachable,
- posix.E2BIG => return error.SystemResources,
- posix.EMFILE => return error.SystemResources,
- posix.ENAMETOOLONG => return error.SystemResources,
- posix.ENFILE => return error.SystemResources,
- posix.ENOMEM => return error.SystemResources,
- posix.EACCES => return error.AccessDenied,
- posix.EPERM => return error.AccessDenied,
- posix.EINVAL => return error.InvalidExe,
- posix.ENOEXEC => return error.InvalidExe,
- posix.EIO => return error.FileSystem,
- posix.ELOOP => return error.FileSystem,
- posix.EISDIR => return error.IsDir,
- posix.ENOENT => return error.FileNotFound,
- posix.ENOTDIR => return error.NotDir,
- posix.ETXTBSY => return error.FileBusy,
- else => return unexpectedErrorPosix(err),
- }
-}
-
-pub var linux_elf_aux_maybe: ?[*]std.elf.Auxv = null;
-pub var posix_environ_raw: [][*]u8 = undefined;
-
-/// See std.elf for the constants.
-pub fn linuxGetAuxVal(index: usize) usize {
- if (builtin.link_libc) {
- return usize(std.c.getauxval(index));
- } else if (linux_elf_aux_maybe) |auxv| {
- var i: usize = 0;
- while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) {
- if (auxv[i].a_type == index)
- return auxv[i].a_un.a_val;
- }
- }
- return 0;
-}
-
-pub fn getBaseAddress() usize {
- switch (builtin.os) {
- builtin.Os.linux => {
- const base = linuxGetAuxVal(std.elf.AT_BASE);
- if (base != 0) {
- return base;
- }
- const phdr = linuxGetAuxVal(std.elf.AT_PHDR);
- return phdr - @sizeOf(std.elf.Ehdr);
- },
- builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
- return @ptrToInt(&std.c._mh_execute_header);
- },
- builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)),
- else => @compileError("Unsupported OS"),
- }
-}
-
-/// Caller must free result when done.
-/// TODO make this go through libc when we have it
-pub fn getEnvMap(allocator: *Allocator) !BufMap {
- var result = BufMap.init(allocator);
- errdefer result.deinit();
-
- if (is_windows) {
- const ptr = windows.GetEnvironmentStringsW() orelse return error.OutOfMemory;
- defer assert(windows.FreeEnvironmentStringsW(ptr) != 0);
-
- var i: usize = 0;
- while (true) {
- if (ptr[i] == 0) return result;
-
- const key_start = i;
-
- while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
- const key_w = ptr[key_start..i];
- const key = try std.unicode.utf16leToUtf8Alloc(allocator, key_w);
- errdefer allocator.free(key);
-
- if (ptr[i] == '=') i += 1;
-
- const value_start = i;
- while (ptr[i] != 0) : (i += 1) {}
- const value_w = ptr[value_start..i];
- const value = try std.unicode.utf16leToUtf8Alloc(allocator, value_w);
- errdefer allocator.free(value);
-
- i += 1; // skip over null byte
-
- try result.setMove(key, value);
- }
- } else if (builtin.os == Os.wasi) {
- var environ_count: usize = undefined;
- var environ_buf_size: usize = undefined;
-
- const environ_sizes_get_ret = std.os.wasi.environ_sizes_get(&environ_count, &environ_buf_size);
- if (environ_sizes_get_ret != os.wasi.ESUCCESS) {
- return unexpectedErrorPosix(environ_sizes_get_ret);
- }
-
- // TODO: Verify that the documentation is incorrect
- // https://github.com/WebAssembly/WASI/issues/27
- var environ = try allocator.alloc(?[*]u8, environ_count + 1);
- defer allocator.free(environ);
- var environ_buf = try std.heap.wasm_allocator.alloc(u8, environ_buf_size);
- defer allocator.free(environ_buf);
-
- const environ_get_ret = std.os.wasi.environ_get(environ.ptr, environ_buf.ptr);
- if (environ_get_ret != os.wasi.ESUCCESS) {
- return unexpectedErrorPosix(environ_get_ret);
- }
-
- for (environ) |env| {
- if (env) |ptr| {
- const pair = mem.toSlice(u8, ptr);
- var parts = mem.separate(pair, "=");
- const key = parts.next().?;
- const value = parts.next().?;
- try result.set(key, value);
- }
- }
- return result;
- } else {
- for (posix_environ_raw) |ptr| {
- var line_i: usize = 0;
- while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
- const key = ptr[0..line_i];
-
- var end_i: usize = line_i;
- while (ptr[end_i] != 0) : (end_i += 1) {}
- const value = ptr[line_i + 1 .. end_i];
-
- try result.set(key, value);
- }
- return result;
- }
-}
-
-test "os.getEnvMap" {
- var env = try getEnvMap(std.debug.global_allocator);
- defer env.deinit();
-}
-
+ EFAULT => unreachable,
+ E2BIG => return error.SystemResources,
+ EMFILE => return error.ProcessFdQuotaExceeded,
+ ENAMETOOLONG => return error.NameTooLong,
+ ENFILE => return error.SystemFdQuotaExceeded,
+ ENOMEM => return error.SystemResources,
+ EACCES => return error.AccessDenied,
+ EPERM => return error.AccessDenied,
+ EINVAL => return error.InvalidExe,
+ ENOEXEC => return error.InvalidExe,
+ EIO => return error.FileSystem,
+ ELOOP => return error.FileSystem,
+ EISDIR => return error.IsDir,
+ ENOENT => return error.FileNotFound,
+ ENOTDIR => return error.NotDir,
+ ETXTBSY => return error.FileBusy,
+ else => return unexpectedErrno(err),
+ }
+}
+
+/// Get an environment variable.
+/// See also `getenvC`.
/// TODO make this go through libc when we have it
-pub fn getEnvPosix(key: []const u8) ?[]const u8 {
- for (posix_environ_raw) |ptr| {
+pub fn getenv(key: []const u8) ?[]const u8 {
+ for (environ) |ptr| {
var line_i: usize = 0;
while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
const this_key = ptr[0..line_i];
@@ -840,221 +699,134 @@ pub fn getEnvPosix(key: []const u8) ?[]const u8 {
return null;
}
-pub const GetEnvVarOwnedError = error{
- OutOfMemory,
- EnvironmentVariableNotFound,
-
- /// See https://github.com/ziglang/zig/issues/1774
- InvalidUtf8,
-};
-
-/// Caller must free returned memory.
-/// TODO make this go through libc when we have it
-pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 {
- if (is_windows) {
- const key_with_null = try std.unicode.utf8ToUtf16LeWithNull(allocator, key);
- defer allocator.free(key_with_null);
-
- var buf = try allocator.alloc(u16, 256);
- defer allocator.free(buf);
-
- while (true) {
- const windows_buf_len = math.cast(windows.DWORD, buf.len) catch return error.OutOfMemory;
- const result = windows.GetEnvironmentVariableW(key_with_null.ptr, buf.ptr, windows_buf_len);
-
- if (result == 0) {
- const err = windows.GetLastError();
- return switch (err) {
- windows.ERROR.ENVVAR_NOT_FOUND => error.EnvironmentVariableNotFound,
- else => {
- unexpectedErrorWindows(err) catch {};
- return error.EnvironmentVariableNotFound;
- },
- };
- }
-
- if (result > buf.len) {
- buf = try allocator.realloc(buf, result);
- continue;
- }
-
- return std.unicode.utf16leToUtf8Alloc(allocator, buf) catch |err| switch (err) {
- error.DanglingSurrogateHalf => return error.InvalidUtf8,
- error.ExpectedSecondSurrogateHalf => return error.InvalidUtf8,
- error.UnexpectedSecondSurrogateHalf => return error.InvalidUtf8,
- error.OutOfMemory => return error.OutOfMemory,
- };
- }
- } else {
- const result = getEnvPosix(key) orelse return error.EnvironmentVariableNotFound;
- return mem.dupe(allocator, u8, result);
- }
-}
-
-test "os.getEnvVarOwned" {
- var ga = debug.global_allocator;
- testing.expectError(error.EnvironmentVariableNotFound, getEnvVarOwned(ga, "BADENV"));
-}
-
-/// Caller must free the returned memory.
-pub fn getCwdAlloc(allocator: *Allocator) ![]u8 {
- var buf: [MAX_PATH_BYTES]u8 = undefined;
- return mem.dupe(allocator, u8, try getCwd(&buf));
-}
-
-pub const GetCwdError = error{Unexpected};
-
-/// The result is a slice of out_buffer.
-pub fn getCwd(out_buffer: *[MAX_PATH_BYTES]u8) GetCwdError![]u8 {
- switch (builtin.os) {
- Os.windows => {
- var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
- const casted_len = @intCast(windows.DWORD, utf16le_buf.len); // TODO shouldn't need this cast
- const casted_ptr = ([*]u16)(&utf16le_buf); // TODO shouldn't need this cast
- const result = windows.GetCurrentDirectoryW(casted_len, casted_ptr);
- if (result == 0) {
- const err = windows.GetLastError();
- switch (err) {
- else => return unexpectedErrorWindows(err),
- }
- }
- assert(result <= utf16le_buf.len);
- const utf16le_slice = utf16le_buf[0..result];
- // Trust that Windows gives us valid UTF-16LE.
- const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
- return out_buffer[0..end_index];
- },
- else => {
- const err = posix.getErrno(posix.getcwd(out_buffer, out_buffer.len));
- switch (err) {
- 0 => return cstr.toSlice(out_buffer),
- posix.ERANGE => unreachable,
- else => return unexpectedErrorPosix(err),
- }
- },
- }
-}
-
-test "os.getCwd" {
- // at least call it so it gets compiled
- _ = getCwdAlloc(debug.global_allocator) catch undefined;
- var buf: [MAX_PATH_BYTES]u8 = undefined;
- _ = getCwd(&buf) catch undefined;
-}
-
-pub const SymLinkError = PosixSymLinkError || WindowsSymLinkError;
-
-/// TODO add a symLinkC variant
-pub fn symLink(existing_path: []const u8, new_path: []const u8) SymLinkError!void {
- if (is_windows) {
- return symLinkWindows(existing_path, new_path);
- } else {
- return symLinkPosix(existing_path, new_path);
+/// Get an environment variable with a null-terminated name.
+/// See also `getenv`.
+/// TODO https://github.com/ziglang/zig/issues/265
+pub fn getenvC(key: [*]const u8) ?[]const u8 {
+ if (builtin.link_libc) {
+ const value = system.getenv(key) orelse return null;
+ return mem.toSliceConst(u8, value);
}
+ return getenv(mem.toSliceConst(u8, key));
}
-pub const WindowsSymLinkError = error{
+pub const GetCwdError = error{
NameTooLong,
- InvalidUtf8,
- BadPathName,
-
- /// See https://github.com/ziglang/zig/issues/1396
+ CurrentWorkingDirectoryUnlinked,
Unexpected,
};
-pub fn symLinkW(existing_path_w: [*]const u16, new_path_w: [*]const u16) WindowsSymLinkError!void {
- if (windows.CreateSymbolicLinkW(existing_path_w, new_path_w, 0) == 0) {
- const err = windows.GetLastError();
- switch (err) {
- else => return unexpectedErrorWindows(err),
- }
+/// The result is a slice of out_buffer, indexed from 0.
+pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 {
+ if (windows.is_the_target) {
+ return windows.GetCurrentDirectory(out_buffer);
}
-}
-pub fn symLinkWindows(existing_path: []const u8, new_path: []const u8) WindowsSymLinkError!void {
- const existing_path_w = try windows_util.sliceToPrefixedFileW(existing_path);
- const new_path_w = try windows_util.sliceToPrefixedFileW(new_path);
- return symLinkW(&existing_path_w, &new_path_w);
+ const err = if (builtin.link_libc) blk: {
+ break :blk if (std.c.getcwd(out_buffer.ptr, out_buffer.len)) |_| 0 else std.c._errno().*;
+ } else blk: {
+ break :blk errno(system.getcwd(out_buffer.ptr, out_buffer.len));
+ };
+ switch (err) {
+ 0 => return mem.toSlice(u8, out_buffer.ptr),
+ EFAULT => unreachable,
+ EINVAL => unreachable,
+ ENOENT => return error.CurrentWorkingDirectoryUnlinked,
+ ERANGE => return error.NameTooLong,
+ else => return unexpectedErrno(@intCast(usize, err)),
+ }
}
-pub const PosixSymLinkError = error{
+pub const SymLinkError = error{
AccessDenied,
DiskQuota,
PathAlreadyExists,
FileSystem,
SymLinkLoop,
- NameTooLong,
FileNotFound,
SystemResources,
NoSpaceLeft,
ReadOnlyFileSystem,
NotDir,
-
- /// See https://github.com/ziglang/zig/issues/1396
+ NameTooLong,
+ InvalidUtf8,
+ BadPathName,
Unexpected,
};
-pub fn symLinkPosixC(existing_path: [*]const u8, new_path: [*]const u8) PosixSymLinkError!void {
- const err = posix.getErrno(posix.symlink(existing_path, new_path));
- switch (err) {
- 0 => return,
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.EACCES => return error.AccessDenied,
- posix.EPERM => return error.AccessDenied,
- posix.EDQUOT => return error.DiskQuota,
- posix.EEXIST => return error.PathAlreadyExists,
- posix.EIO => return error.FileSystem,
- posix.ELOOP => return error.SymLinkLoop,
- posix.ENAMETOOLONG => return error.NameTooLong,
- posix.ENOENT => return error.FileNotFound,
- posix.ENOTDIR => return error.NotDir,
- posix.ENOMEM => return error.SystemResources,
- posix.ENOSPC => return error.NoSpaceLeft,
- posix.EROFS => return error.ReadOnlyFileSystem,
- else => return unexpectedErrorPosix(err),
- }
-}
-
-pub fn symLinkPosix(existing_path: []const u8, new_path: []const u8) PosixSymLinkError!void {
- const existing_path_c = try toPosixPath(existing_path);
- const new_path_c = try toPosixPath(new_path);
- return symLinkPosixC(&existing_path_c, &new_path_c);
-}
-
-// here we replace the standard +/ with -_ so that it can be used in a file name
-const b64_fs_encoder = base64.Base64Encoder.init("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", base64.standard_pad_char);
-
-/// TODO remove the allocator requirement from this API
-pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) !void {
- if (symLink(existing_path, new_path)) {
- return;
- } else |err| switch (err) {
- error.PathAlreadyExists => {},
- else => return err, // TODO zig should know this set does not include PathAlreadyExists
- }
-
- const dirname = os.path.dirname(new_path) orelse ".";
-
- var rand_buf: [12]u8 = undefined;
- const tmp_path = try allocator.alloc(u8, dirname.len + 1 + base64.Base64Encoder.calcSize(rand_buf.len));
- defer allocator.free(tmp_path);
- mem.copy(u8, tmp_path[0..], dirname);
- tmp_path[dirname.len] = os.path.sep;
- while (true) {
- try getRandomBytes(rand_buf[0..]);
- b64_fs_encoder.encode(tmp_path[dirname.len + 1 ..], rand_buf);
-
- if (symLink(existing_path, tmp_path)) {
- return rename(tmp_path, new_path);
- } else |err| switch (err) {
- error.PathAlreadyExists => continue,
- else => return err, // TODO zig should know this set does not include PathAlreadyExists
- }
+/// Creates a symbolic link named `sym_link_path` which contains the string `target_path`.
+/// A symbolic link (also known as a soft link) may point to an existing file or to a nonexistent
+/// one; the latter case is known as a dangling link.
+/// If `sym_link_path` exists, it will not be overwritten.
+/// See also `symlinkC` and `symlinkW`.
+pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!void {
+ if (windows.is_the_target) {
+ const target_path_w = try windows.sliceToPrefixedFileW(target_path);
+ const sym_link_path_w = try windows.sliceToPrefixedFileW(sym_link_path);
+ return windows.CreateSymbolicLinkW(&sym_link_path_w, &target_path_w, 0);
+ } else {
+ const target_path_c = try toPosixPath(target_path);
+ const sym_link_path_c = try toPosixPath(sym_link_path);
+ return symlinkC(&target_path_c, &sym_link_path_c);
}
}
-pub const DeleteFileError = error{
+/// This is the same as `symlink` except the parameters are null-terminated pointers.
+/// See also `symlink`.
+pub fn symlinkC(target_path: [*]const u8, sym_link_path: [*]const u8) SymLinkError!void {
+ if (windows.is_the_target) {
+ const target_path_w = try windows.cStrToPrefixedFileW(target_path);
+ const sym_link_path_w = try windows.cStrToPrefixedFileW(sym_link_path);
+ return windows.CreateSymbolicLinkW(&sym_link_path_w, &target_path_w, 0);
+ }
+ switch (errno(system.symlink(target_path, sym_link_path))) {
+ 0 => return,
+ EFAULT => unreachable,
+ EINVAL => unreachable,
+ EACCES => return error.AccessDenied,
+ EPERM => return error.AccessDenied,
+ EDQUOT => return error.DiskQuota,
+ EEXIST => return error.PathAlreadyExists,
+ EIO => return error.FileSystem,
+ ELOOP => return error.SymLinkLoop,
+ ENAMETOOLONG => return error.NameTooLong,
+ ENOENT => return error.FileNotFound,
+ ENOTDIR => return error.NotDir,
+ ENOMEM => return error.SystemResources,
+ ENOSPC => return error.NoSpaceLeft,
+ EROFS => return error.ReadOnlyFileSystem,
+ else => |err| return unexpectedErrno(err),
+ }
+}
+
+pub fn symlinkat(target_path: []const u8, newdirfd: fd_t, sym_link_path: []const u8) SymLinkError!void {
+ const target_path_c = try toPosixPath(target_path);
+ const sym_link_path_c = try toPosixPath(sym_link_path);
+ return symlinkatC(target_path_c, newdirfd, sym_link_path_c);
+}
+
+pub fn symlinkatC(target_path: [*]const u8, newdirfd: fd_t, sym_link_path: [*]const u8) SymLinkError!void {
+ switch (errno(system.symlinkat(target_path, newdirfd, sym_link_path))) {
+ 0 => return,
+ EFAULT => unreachable,
+ EINVAL => unreachable,
+ EACCES => return error.AccessDenied,
+ EPERM => return error.AccessDenied,
+ EDQUOT => return error.DiskQuota,
+ EEXIST => return error.PathAlreadyExists,
+ EIO => return error.FileSystem,
+ ELOOP => return error.SymLinkLoop,
+ ENAMETOOLONG => return error.NameTooLong,
+ ENOENT => return error.FileNotFound,
+ ENOTDIR => return error.NotDir,
+ ENOMEM => return error.SystemResources,
+ ENOSPC => return error.NoSpaceLeft,
+ EROFS => return error.ReadOnlyFileSystem,
+ else => |err| return unexpectedErrno(err),
+ }
+}
+
+pub const UnlinkError = error{
FileNotFound,
AccessDenied,
FileBusy,
@@ -1065,6 +837,7 @@ pub const DeleteFileError = error{
NotDir,
SystemResources,
ReadOnlyFileSystem,
+ Unexpected,
/// On Windows, file paths must be valid Unicode.
InvalidUtf8,
@@ -1072,225 +845,70 @@ pub const DeleteFileError = error{
/// On Windows, file paths cannot contain these characters:
/// '/', '*', '?', '"', '<', '>', '|'
BadPathName,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
};
-pub fn deleteFile(file_path: []const u8) DeleteFileError!void {
- if (builtin.os == Os.windows) {
- const file_path_w = try windows_util.sliceToPrefixedFileW(file_path);
- return deleteFileW(&file_path_w);
+/// Delete a name and possibly the file it refers to.
+/// See also `unlinkC`.
+pub fn unlink(file_path: []const u8) UnlinkError!void {
+ if (windows.is_the_target) {
+ const file_path_w = try windows.sliceToPrefixedFileW(file_path);
+ return windows.DeleteFileW(&file_path_w);
} else {
const file_path_c = try toPosixPath(file_path);
- return deleteFileC(&file_path_c);
+ return unlinkC(&file_path_c);
}
}
-pub fn deleteFileW(file_path: [*]const u16) DeleteFileError!void {
- if (windows.DeleteFileW(file_path) == 0) {
- const err = windows.GetLastError();
- switch (err) {
- windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
- windows.ERROR.ACCESS_DENIED => return error.AccessDenied,
- windows.ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
- windows.ERROR.INVALID_PARAMETER => return error.NameTooLong,
- else => return unexpectedErrorWindows(err),
- }
- }
-}
-
-pub fn deleteFileC(file_path: [*]const u8) DeleteFileError!void {
- if (is_windows) {
- const file_path_w = try windows_util.cStrToPrefixedFileW(file_path);
- return deleteFileW(&file_path_w);
- } else {
- const err = posix.getErrno(posix.unlink(file_path));
- switch (err) {
- 0 => return,
- posix.EACCES => return error.AccessDenied,
- posix.EPERM => return error.AccessDenied,
- posix.EBUSY => return error.FileBusy,
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.EIO => return error.FileSystem,
- posix.EISDIR => return error.IsDir,
- posix.ELOOP => return error.SymLinkLoop,
- posix.ENAMETOOLONG => return error.NameTooLong,
- posix.ENOENT => return error.FileNotFound,
- posix.ENOTDIR => return error.NotDir,
- posix.ENOMEM => return error.SystemResources,
- posix.EROFS => return error.ReadOnlyFileSystem,
- else => return unexpectedErrorPosix(err),
- }
- }
-}
-
-/// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is
-/// merged and readily available,
-/// there is a possibility of power loss or application termination leaving temporary files present
-/// in the same directory as dest_path.
-/// Destination file will have the same mode as the source file.
-pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void {
- var in_file = try os.File.openRead(source_path);
- defer in_file.close();
-
- const mode = try in_file.mode();
- const in_stream = &in_file.inStream().stream;
-
- var atomic_file = try AtomicFile.init(dest_path, mode);
- defer atomic_file.deinit();
-
- var buf: [page_size]u8 = undefined;
- while (true) {
- const amt = try in_stream.readFull(buf[0..]);
- try atomic_file.file.write(buf[0..amt]);
- if (amt != buf.len) {
- return atomic_file.finish();
- }
- }
-}
-
-/// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is
-/// merged and readily available,
-/// there is a possibility of power loss or application termination leaving temporary files present
-pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void {
- var in_file = try os.File.openRead(source_path);
- defer in_file.close();
-
- var atomic_file = try AtomicFile.init(dest_path, mode);
- defer atomic_file.deinit();
-
- var buf: [page_size]u8 = undefined;
- while (true) {
- const amt = try in_file.read(buf[0..]);
- try atomic_file.file.write(buf[0..amt]);
- if (amt != buf.len) {
- return atomic_file.finish();
- }
- }
-}
-
-pub const AtomicFile = struct {
- file: os.File,
- tmp_path_buf: [MAX_PATH_BYTES]u8,
- dest_path: []const u8,
- finished: bool,
-
- const InitError = os.File.OpenError;
-
- /// dest_path must remain valid for the lifetime of AtomicFile
- /// call finish to atomically replace dest_path with contents
- /// TODO once we have null terminated pointers, use the
- /// openWriteNoClobberN function
- pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile {
- const dirname = os.path.dirname(dest_path);
- var rand_buf: [12]u8 = undefined;
- const dirname_component_len = if (dirname) |d| d.len + 1 else 0;
- const encoded_rand_len = comptime base64.Base64Encoder.calcSize(rand_buf.len);
- const tmp_path_len = dirname_component_len + encoded_rand_len;
- var tmp_path_buf: [MAX_PATH_BYTES]u8 = undefined;
- if (tmp_path_len >= tmp_path_buf.len) return error.NameTooLong;
-
- if (dirname) |dir| {
- mem.copy(u8, tmp_path_buf[0..], dir);
- tmp_path_buf[dir.len] = os.path.sep;
- }
-
- tmp_path_buf[tmp_path_len] = 0;
-
- while (true) {
- try getRandomBytes(rand_buf[0..]);
- b64_fs_encoder.encode(tmp_path_buf[dirname_component_len..tmp_path_len], rand_buf);
-
- const file = os.File.openWriteNoClobberC(&tmp_path_buf, mode) catch |err| switch (err) {
- error.PathAlreadyExists => continue,
- // TODO zig should figure out that this error set does not include PathAlreadyExists since
- // it is handled in the above switch
- else => return err,
- };
-
- return AtomicFile{
- .file = file,
- .tmp_path_buf = tmp_path_buf,
- .dest_path = dest_path,
- .finished = false,
- };
- }
- }
-
- /// always call deinit, even after successful finish()
- pub fn deinit(self: *AtomicFile) void {
- if (!self.finished) {
- self.file.close();
- deleteFileC(&self.tmp_path_buf) catch {};
- self.finished = true;
- }
- }
-
- pub fn finish(self: *AtomicFile) !void {
- assert(!self.finished);
- self.file.close();
- self.finished = true;
- if (is_posix) {
- const dest_path_c = try toPosixPath(self.dest_path);
- return renameC(&self.tmp_path_buf, &dest_path_c);
- } else if (is_windows) {
- const dest_path_w = try windows_util.sliceToPrefixedFileW(self.dest_path);
- const tmp_path_w = try windows_util.cStrToPrefixedFileW(&self.tmp_path_buf);
- return renameW(&tmp_path_w, &dest_path_w);
- } else {
- @compileError("Unsupported OS");
- }
+/// Same as `unlink` except the parameter is a null terminated UTF8-encoded string.
+pub fn unlinkC(file_path: [*]const u8) UnlinkError!void {
+ if (windows.is_the_target) {
+ const file_path_w = try windows.cStrToPrefixedFileW(file_path);
+ return windows.DeleteFileW(&file_path_w);
}
+ switch (errno(system.unlink(file_path))) {
+ 0 => return,
+ EACCES => return error.AccessDenied,
+ EPERM => return error.AccessDenied,
+ EBUSY => return error.FileBusy,
+ EFAULT => unreachable,
+ EINVAL => unreachable,
+ EIO => return error.FileSystem,
+ EISDIR => return error.IsDir,
+ ELOOP => return error.SymLinkLoop,
+ ENAMETOOLONG => return error.NameTooLong,
+ ENOENT => return error.FileNotFound,
+ ENOTDIR => return error.NotDir,
+ ENOMEM => return error.SystemResources,
+ EROFS => return error.ReadOnlyFileSystem,
+ else => |err| return unexpectedErrno(err),
+ }
+}
+
+const RenameError = error{
+ AccessDenied,
+ FileBusy,
+ DiskQuota,
+ IsDir,
+ SymLinkLoop,
+ LinkQuotaExceeded,
+ NameTooLong,
+ FileNotFound,
+ NotDir,
+ SystemResources,
+ NoSpaceLeft,
+ PathAlreadyExists,
+ ReadOnlyFileSystem,
+ RenameAcrossMountPoints,
+ InvalidUtf8,
+ BadPathName,
+ Unexpected,
};
-pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) !void {
- if (is_windows) {
- const old_path_w = try windows_util.cStrToPrefixedFileW(old_path);
- const new_path_w = try windows_util.cStrToPrefixedFileW(new_path);
- return renameW(&old_path_w, &new_path_w);
- } else {
- const err = posix.getErrno(posix.rename(old_path, new_path));
- switch (err) {
- 0 => return,
- posix.EACCES => return error.AccessDenied,
- posix.EPERM => return error.AccessDenied,
- posix.EBUSY => return error.FileBusy,
- posix.EDQUOT => return error.DiskQuota,
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.EISDIR => return error.IsDir,
- posix.ELOOP => return error.SymLinkLoop,
- posix.EMLINK => return error.LinkQuotaExceeded,
- posix.ENAMETOOLONG => return error.NameTooLong,
- posix.ENOENT => return error.FileNotFound,
- posix.ENOTDIR => return error.NotDir,
- posix.ENOMEM => return error.SystemResources,
- posix.ENOSPC => return error.NoSpaceLeft,
- posix.EEXIST => return error.PathAlreadyExists,
- posix.ENOTEMPTY => return error.PathAlreadyExists,
- posix.EROFS => return error.ReadOnlyFileSystem,
- posix.EXDEV => return error.RenameAcrossMountPoints,
- else => return unexpectedErrorPosix(err),
- }
- }
-}
-
-pub fn renameW(old_path: [*]const u16, new_path: [*]const u16) !void {
- const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH;
- if (windows.MoveFileExW(old_path, new_path, flags) == 0) {
- const err = windows.GetLastError();
- switch (err) {
- else => return unexpectedErrorWindows(err),
- }
- }
-}
-
-pub fn rename(old_path: []const u8, new_path: []const u8) !void {
- if (is_windows) {
- const old_path_w = try windows_util.sliceToPrefixedFileW(old_path);
- const new_path_w = try windows_util.sliceToPrefixedFileW(new_path);
+/// Change the name or location of a file.
+pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void {
+ if (windows.is_the_target) {
+ const old_path_w = try windows.sliceToPrefixedFileW(old_path);
+ const new_path_w = try windows.sliceToPrefixedFileW(new_path);
return renameW(&old_path_w, &new_path_w);
} else {
const old_path_c = try toPosixPath(old_path);
@@ -1299,1213 +917,329 @@ pub fn rename(old_path: []const u8, new_path: []const u8) !void {
}
}
-pub fn makeDir(dir_path: []const u8) !void {
- if (is_windows) {
- return makeDirWindows(dir_path);
- } else {
- return makeDirPosix(dir_path);
- }
-}
-
-pub fn makeDirWindows(dir_path: []const u8) !void {
- const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path);
-
- if (windows.CreateDirectoryW(&dir_path_w, null) == 0) {
- const err = windows.GetLastError();
- return switch (err) {
- windows.ERROR.ALREADY_EXISTS => error.PathAlreadyExists,
- windows.ERROR.PATH_NOT_FOUND => error.FileNotFound,
- else => unexpectedErrorWindows(err),
- };
+/// Same as `rename` except the parameters are null-terminated byte arrays.
+pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) RenameError!void {
+ if (windows.is_the_target) {
+ const old_path_w = try windows.cStrToPrefixedFileW(old_path);
+ const new_path_w = try windows.cStrToPrefixedFileW(new_path);
+ return renameW(&old_path_w, &new_path_w);
}
-}
-
-pub fn makeDirPosixC(dir_path: [*]const u8) !void {
- const err = posix.getErrno(posix.mkdir(dir_path, 0o755));
- switch (err) {
+ switch (errno(system.rename(old_path, new_path))) {
0 => return,
- posix.EACCES => return error.AccessDenied,
- posix.EPERM => return error.AccessDenied,
- posix.EDQUOT => return error.DiskQuota,
- posix.EEXIST => return error.PathAlreadyExists,
- posix.EFAULT => unreachable,
- posix.ELOOP => return error.SymLinkLoop,
- posix.EMLINK => return error.LinkQuotaExceeded,
- posix.ENAMETOOLONG => return error.NameTooLong,
- posix.ENOENT => return error.FileNotFound,
- posix.ENOMEM => return error.SystemResources,
- posix.ENOSPC => return error.NoSpaceLeft,
- posix.ENOTDIR => return error.NotDir,
- posix.EROFS => return error.ReadOnlyFileSystem,
- else => return unexpectedErrorPosix(err),
- }
-}
-
-pub fn makeDirPosix(dir_path: []const u8) !void {
- const dir_path_c = try toPosixPath(dir_path);
- return makeDirPosixC(&dir_path_c);
-}
-
-/// Calls makeDir recursively to make an entire path. Returns success if the path
-/// already exists and is a directory.
-/// TODO determine if we can remove the allocator requirement from this function
-pub fn makePath(allocator: *Allocator, full_path: []const u8) !void {
- const resolved_path = try path.resolve(allocator, [][]const u8{full_path});
- defer allocator.free(resolved_path);
-
- var end_index: usize = resolved_path.len;
- while (true) {
- makeDir(resolved_path[0..end_index]) catch |err| switch (err) {
- error.PathAlreadyExists => {
- // TODO stat the file and return an error if it's not a directory
- // this is important because otherwise a dangling symlink
- // could cause an infinite loop
- if (end_index == resolved_path.len) return;
- },
- error.FileNotFound => {
- // march end_index backward until next path component
- while (true) {
- end_index -= 1;
- if (os.path.isSep(resolved_path[end_index])) break;
- }
- continue;
- },
- else => return err,
- };
- if (end_index == resolved_path.len) return;
- // march end_index forward until next path component
- while (true) {
- end_index += 1;
- if (end_index == resolved_path.len or os.path.isSep(resolved_path[end_index])) break;
- }
- }
+ EACCES => return error.AccessDenied,
+ EPERM => return error.AccessDenied,
+ EBUSY => return error.FileBusy,
+ EDQUOT => return error.DiskQuota,
+ EFAULT => unreachable,
+ EINVAL => unreachable,
+ EISDIR => return error.IsDir,
+ ELOOP => return error.SymLinkLoop,
+ EMLINK => return error.LinkQuotaExceeded,
+ ENAMETOOLONG => return error.NameTooLong,
+ ENOENT => return error.FileNotFound,
+ ENOTDIR => return error.NotDir,
+ ENOMEM => return error.SystemResources,
+ ENOSPC => return error.NoSpaceLeft,
+ EEXIST => return error.PathAlreadyExists,
+ ENOTEMPTY => return error.PathAlreadyExists,
+ EROFS => return error.ReadOnlyFileSystem,
+ EXDEV => return error.RenameAcrossMountPoints,
+ else => |err| return unexpectedErrno(err),
+ }
+}
+
+/// Same as `rename` except the parameters are null-terminated UTF16LE encoded byte arrays.
+/// Assumes target is Windows.
+pub fn renameW(old_path: [*]const u16, new_path: [*]const u16) RenameError!void {
+ const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH;
+ return windows.MoveFileExW(old_path, new_path, flags);
}
-pub const DeleteDirError = error{
+pub const MakeDirError = error{
AccessDenied,
- FileBusy,
+ DiskQuota,
+ PathAlreadyExists,
SymLinkLoop,
+ LinkQuotaExceeded,
NameTooLong,
FileNotFound,
SystemResources,
+ NoSpaceLeft,
NotDir,
- DirNotEmpty,
ReadOnlyFileSystem,
InvalidUtf8,
BadPathName,
-
- /// See https://github.com/ziglang/zig/issues/1396
Unexpected,
};
-pub fn deleteDirC(dir_path: [*]const u8) DeleteDirError!void {
- switch (builtin.os) {
- Os.windows => {
- const dir_path_w = try windows_util.cStrToPrefixedFileW(dir_path);
- return deleteDirW(&dir_path_w);
- },
- Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
- const err = posix.getErrno(posix.rmdir(dir_path));
- switch (err) {
- 0 => return,
- posix.EACCES => return error.AccessDenied,
- posix.EPERM => return error.AccessDenied,
- posix.EBUSY => return error.FileBusy,
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.ELOOP => return error.SymLinkLoop,
- posix.ENAMETOOLONG => return error.NameTooLong,
- posix.ENOENT => return error.FileNotFound,
- posix.ENOMEM => return error.SystemResources,
- posix.ENOTDIR => return error.NotDir,
- posix.EEXIST => return error.DirNotEmpty,
- posix.ENOTEMPTY => return error.DirNotEmpty,
- posix.EROFS => return error.ReadOnlyFileSystem,
- else => return unexpectedErrorPosix(err),
- }
- },
- else => @compileError("unimplemented"),
+/// Create a directory.
+/// `mode` is ignored on Windows.
+pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {
+ if (windows.is_the_target) {
+ const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);
+ return windows.CreateDirectoryW(&dir_path_w, null);
+ } else {
+ const dir_path_c = try toPosixPath(dir_path);
+ return mkdirC(&dir_path_c, mode);
}
}
-pub fn deleteDirW(dir_path_w: [*]const u16) DeleteDirError!void {
- if (windows.RemoveDirectoryW(dir_path_w) == 0) {
- const err = windows.GetLastError();
- switch (err) {
- windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
- windows.ERROR.DIR_NOT_EMPTY => return error.DirNotEmpty,
- else => return unexpectedErrorWindows(err),
- }
+/// Same as `mkdir` but the parameter is a null-terminated UTF8-encoded string.
+pub fn mkdirC(dir_path: [*]const u8, mode: u32) MakeDirError!void {
+ if (windows.is_the_target) {
+ const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
+ return windows.CreateDirectoryW(&dir_path_w, null);
}
-}
-
-/// Returns ::error.DirNotEmpty if the directory is not empty.
-/// To delete a directory recursively, see ::deleteTree
-pub fn deleteDir(dir_path: []const u8) DeleteDirError!void {
- switch (builtin.os) {
- Os.windows => {
- const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path);
- return deleteDirW(&dir_path_w);
- },
- Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
- const dir_path_c = try toPosixPath(dir_path);
- return deleteDirC(&dir_path_c);
- },
- else => @compileError("unimplemented"),
+ switch (errno(system.mkdir(dir_path, mode))) {
+ 0 => return,
+ EACCES => return error.AccessDenied,
+ EPERM => return error.AccessDenied,
+ EDQUOT => return error.DiskQuota,
+ EEXIST => return error.PathAlreadyExists,
+ EFAULT => unreachable,
+ ELOOP => return error.SymLinkLoop,
+ EMLINK => return error.LinkQuotaExceeded,
+ ENAMETOOLONG => return error.NameTooLong,
+ ENOENT => return error.FileNotFound,
+ ENOMEM => return error.SystemResources,
+ ENOSPC => return error.NoSpaceLeft,
+ ENOTDIR => return error.NotDir,
+ EROFS => return error.ReadOnlyFileSystem,
+ else => |err| return unexpectedErrno(err),
}
}
-/// Whether ::full_path describes a symlink, file, or directory, this function
-/// removes it. If it cannot be removed because it is a non-empty directory,
-/// this function recursively removes its entries and then tries again.
-const DeleteTreeError = error{
- OutOfMemory,
+pub const DeleteDirError = error{
AccessDenied,
- FileTooBig,
- IsDir,
+ FileBusy,
SymLinkLoop,
- ProcessFdQuotaExceeded,
NameTooLong,
- SystemFdQuotaExceeded,
- NoDevice,
+ FileNotFound,
SystemResources,
- NoSpaceLeft,
- PathAlreadyExists,
- ReadOnlyFileSystem,
NotDir,
- FileNotFound,
- FileSystem,
- FileBusy,
DirNotEmpty,
- DeviceBusy,
-
- /// On Windows, file paths must be valid Unicode.
+ ReadOnlyFileSystem,
InvalidUtf8,
-
- /// On Windows, file paths cannot contain these characters:
- /// '/', '*', '?', '"', '<', '>', '|'
BadPathName,
-
- /// See https://github.com/ziglang/zig/issues/1396
Unexpected,
};
-/// TODO determine if we can remove the allocator requirement
-pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!void {
- start_over: while (true) {
- var got_access_denied = false;
- // First, try deleting the item as a file. This way we don't follow sym links.
- if (deleteFile(full_path)) {
- return;
- } else |err| switch (err) {
- error.FileNotFound => return,
- error.IsDir => {},
- error.AccessDenied => got_access_denied = true,
-
- error.InvalidUtf8,
- error.SymLinkLoop,
- error.NameTooLong,
- error.SystemResources,
- error.ReadOnlyFileSystem,
- error.NotDir,
- error.FileSystem,
- error.FileBusy,
- error.BadPathName,
- error.Unexpected,
- => return err,
- }
- {
- var dir = Dir.open(allocator, full_path) catch |err| switch (err) {
- error.NotDir => {
- if (got_access_denied) {
- return error.AccessDenied;
- }
- continue :start_over;
- },
-
- error.OutOfMemory,
- error.AccessDenied,
- error.FileTooBig,
- error.IsDir,
- error.SymLinkLoop,
- error.ProcessFdQuotaExceeded,
- error.NameTooLong,
- error.SystemFdQuotaExceeded,
- error.NoDevice,
- error.FileNotFound,
- error.SystemResources,
- error.NoSpaceLeft,
- error.PathAlreadyExists,
- error.Unexpected,
- error.InvalidUtf8,
- error.BadPathName,
- error.DeviceBusy,
- => return err,
- };
- defer dir.close();
-
- var full_entry_buf = ArrayList(u8).init(allocator);
- defer full_entry_buf.deinit();
-
- while (try dir.next()) |entry| {
- try full_entry_buf.resize(full_path.len + entry.name.len + 1);
- const full_entry_path = full_entry_buf.toSlice();
- mem.copy(u8, full_entry_path, full_path);
- full_entry_path[full_path.len] = path.sep;
- mem.copy(u8, full_entry_path[full_path.len + 1 ..], entry.name);
-
- try deleteTree(allocator, full_entry_path);
- }
- }
- return deleteDir(full_path);
+/// Deletes an empty directory.
+pub fn rmdir(dir_path: []const u8) DeleteDirError!void {
+ if (windows.is_the_target) {
+ const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);
+ return windows.RemoveDirectoryW(&dir_path_w);
+ } else {
+ const dir_path_c = try toPosixPath(dir_path);
+ return rmdirC(&dir_path_c);
}
}
-pub const Dir = struct {
- handle: Handle,
- allocator: *Allocator,
-
- pub const Handle = switch (builtin.os) {
- Os.macosx, Os.ios, Os.freebsd, Os.netbsd => struct {
- fd: i32,
- seek: i64,
- buf: []u8,
- index: usize,
- end_index: usize,
- },
- Os.linux => struct {
- fd: i32,
- buf: []u8,
- index: usize,
- end_index: usize,
- },
- Os.windows => struct {
- handle: windows.HANDLE,
- find_file_data: windows.WIN32_FIND_DATAW,
- first: bool,
- name_data: [256]u8,
- },
- else => @compileError("unimplemented"),
- };
-
- pub const Entry = struct {
- name: []const u8,
- kind: Kind,
-
- pub const Kind = enum {
- BlockDevice,
- CharacterDevice,
- Directory,
- NamedPipe,
- SymLink,
- File,
- UnixDomainSocket,
- Whiteout,
- Unknown,
- };
- };
-
- pub const OpenError = error{
- FileNotFound,
- NotDir,
- AccessDenied,
- FileTooBig,
- IsDir,
- SymLinkLoop,
- ProcessFdQuotaExceeded,
- NameTooLong,
- SystemFdQuotaExceeded,
- NoDevice,
- SystemResources,
- NoSpaceLeft,
- PathAlreadyExists,
- OutOfMemory,
- InvalidUtf8,
- BadPathName,
- DeviceBusy,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
- };
-
- /// TODO remove the allocator requirement from this API
- pub fn open(allocator: *Allocator, dir_path: []const u8) OpenError!Dir {
- return Dir{
- .allocator = allocator,
- .handle = switch (builtin.os) {
- Os.windows => blk: {
- var find_file_data: windows.WIN32_FIND_DATAW = undefined;
- const handle = try windows_util.windowsFindFirstFile(dir_path, &find_file_data);
- break :blk Handle{
- .handle = handle,
- .find_file_data = find_file_data, // TODO guaranteed copy elision
- .first = true,
- .name_data = undefined,
- };
- },
- Os.macosx, Os.ios, Os.freebsd, Os.netbsd => Handle{
- .fd = try posixOpen(
- dir_path,
- posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC,
- 0,
- ),
- .seek = 0,
- .index = 0,
- .end_index = 0,
- .buf = []u8{},
- },
- Os.linux => Handle{
- .fd = try posixOpen(
- dir_path,
- posix.O_RDONLY | posix.O_DIRECTORY | posix.O_CLOEXEC,
- 0,
- ),
- .index = 0,
- .end_index = 0,
- .buf = []u8{},
- },
- else => @compileError("unimplemented"),
- },
- };
- }
-
- pub fn close(self: *Dir) void {
- switch (builtin.os) {
- Os.windows => {
- _ = windows.FindClose(self.handle.handle);
- },
- Os.macosx, Os.ios, Os.linux, Os.freebsd, Os.netbsd => {
- self.allocator.free(self.handle.buf);
- os.close(self.handle.fd);
- },
- else => @compileError("unimplemented"),
- }
- }
-
- /// Memory such as file names referenced in this returned entry becomes invalid
- /// with subsequent calls to next, as well as when this `Dir` is deinitialized.
- pub fn next(self: *Dir) !?Entry {
- switch (builtin.os) {
- Os.linux => return self.nextLinux(),
- Os.macosx, Os.ios => return self.nextDarwin(),
- Os.windows => return self.nextWindows(),
- Os.freebsd => return self.nextFreebsd(),
- Os.netbsd => return self.nextFreebsd(),
- else => @compileError("unimplemented"),
- }
- }
-
- fn nextDarwin(self: *Dir) !?Entry {
- start_over: while (true) {
- if (self.handle.index >= self.handle.end_index) {
- if (self.handle.buf.len == 0) {
- self.handle.buf = try self.allocator.alloc(u8, page_size);
- }
-
- while (true) {
- const result = posix.getdirentries64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len, &self.handle.seek);
- const err = posix.getErrno(result);
- if (err > 0) {
- switch (err) {
- posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
- posix.EINVAL => {
- self.handle.buf = try self.allocator.realloc(self.handle.buf, self.handle.buf.len * 2);
- continue;
- },
- else => return unexpectedErrorPosix(err),
- }
- }
- if (result == 0) return null;
- self.handle.index = 0;
- self.handle.end_index = result;
- break;
- }
- }
- const darwin_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]);
- const next_index = self.handle.index + darwin_entry.d_reclen;
- self.handle.index = next_index;
-
- const name = @ptrCast([*]u8, &darwin_entry.d_name)[0..darwin_entry.d_namlen];
-
- if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
- continue :start_over;
- }
-
- const entry_kind = switch (darwin_entry.d_type) {
- posix.DT_BLK => Entry.Kind.BlockDevice,
- posix.DT_CHR => Entry.Kind.CharacterDevice,
- posix.DT_DIR => Entry.Kind.Directory,
- posix.DT_FIFO => Entry.Kind.NamedPipe,
- posix.DT_LNK => Entry.Kind.SymLink,
- posix.DT_REG => Entry.Kind.File,
- posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
- posix.DT_WHT => Entry.Kind.Whiteout,
- else => Entry.Kind.Unknown,
- };
- return Entry{
- .name = name,
- .kind = entry_kind,
- };
- }
- }
-
- fn nextWindows(self: *Dir) !?Entry {
- while (true) {
- if (self.handle.first) {
- self.handle.first = false;
- } else {
- if (!try windows_util.windowsFindNextFile(self.handle.handle, &self.handle.find_file_data))
- return null;
- }
- const name_utf16le = mem.toSlice(u16, self.handle.find_file_data.cFileName[0..].ptr);
- if (mem.eql(u16, name_utf16le, []u16{'.'}) or mem.eql(u16, name_utf16le, []u16{ '.', '.' }))
- continue;
- // Trust that Windows gives us valid UTF-16LE
- const name_utf8_len = std.unicode.utf16leToUtf8(self.handle.name_data[0..], name_utf16le) catch unreachable;
- const name_utf8 = self.handle.name_data[0..name_utf8_len];
- const kind = blk: {
- const attrs = self.handle.find_file_data.dwFileAttributes;
- if (attrs & windows.FILE_ATTRIBUTE_DIRECTORY != 0) break :blk Entry.Kind.Directory;
- if (attrs & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) break :blk Entry.Kind.SymLink;
- if (attrs & windows.FILE_ATTRIBUTE_NORMAL != 0) break :blk Entry.Kind.File;
- break :blk Entry.Kind.Unknown;
- };
- return Entry{
- .name = name_utf8,
- .kind = kind,
- };
- }
+/// Same as `rmdir` except the parameter is null-terminated.
+pub fn rmdirC(dir_path: [*]const u8) DeleteDirError!void {
+ if (windows.is_the_target) {
+ const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
+ return windows.RemoveDirectoryW(&dir_path_w);
}
-
- fn nextLinux(self: *Dir) !?Entry {
- start_over: while (true) {
- if (self.handle.index >= self.handle.end_index) {
- if (self.handle.buf.len == 0) {
- self.handle.buf = try self.allocator.alloc(u8, page_size);
- }
-
- while (true) {
- const result = posix.getdents64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len);
- const err = posix.getErrno(result);
- if (err > 0) {
- switch (err) {
- posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
- posix.EINVAL => {
- self.handle.buf = try self.allocator.realloc(self.handle.buf, self.handle.buf.len * 2);
- continue;
- },
- else => return unexpectedErrorPosix(err),
- }
- }
- if (result == 0) return null;
- self.handle.index = 0;
- self.handle.end_index = result;
- break;
- }
- }
- const linux_entry = @ptrCast(*align(1) posix.dirent64, &self.handle.buf[self.handle.index]);
- const next_index = self.handle.index + linux_entry.d_reclen;
- self.handle.index = next_index;
-
- const name = cstr.toSlice(@ptrCast([*]u8, &linux_entry.d_name));
-
- // skip . and .. entries
- if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
- continue :start_over;
- }
-
- const entry_kind = switch (linux_entry.d_type) {
- posix.DT_BLK => Entry.Kind.BlockDevice,
- posix.DT_CHR => Entry.Kind.CharacterDevice,
- posix.DT_DIR => Entry.Kind.Directory,
- posix.DT_FIFO => Entry.Kind.NamedPipe,
- posix.DT_LNK => Entry.Kind.SymLink,
- posix.DT_REG => Entry.Kind.File,
- posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
- else => Entry.Kind.Unknown,
- };
- return Entry{
- .name = name,
- .kind = entry_kind,
- };
- }
- }
-
- fn nextFreebsd(self: *Dir) !?Entry {
- start_over: while (true) {
- if (self.handle.index >= self.handle.end_index) {
- if (self.handle.buf.len == 0) {
- self.handle.buf = try self.allocator.alloc(u8, page_size);
- }
-
- while (true) {
- const result = posix.getdirentries(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len, &self.handle.seek);
- const err = posix.getErrno(result);
- if (err > 0) {
- switch (err) {
- posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
- posix.EINVAL => {
- self.handle.buf = try self.allocator.realloc(self.handle.buf, self.handle.buf.len * 2);
- continue;
- },
- else => return unexpectedErrorPosix(err),
- }
- }
- if (result == 0) return null;
- self.handle.index = 0;
- self.handle.end_index = result;
- break;
- }
- }
- const freebsd_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]);
- const next_index = self.handle.index + freebsd_entry.d_reclen;
- self.handle.index = next_index;
-
- const name = @ptrCast([*]u8, &freebsd_entry.d_name)[0..freebsd_entry.d_namlen];
-
- if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
- continue :start_over;
- }
-
- const entry_kind = switch (freebsd_entry.d_type) {
- posix.DT_BLK => Entry.Kind.BlockDevice,
- posix.DT_CHR => Entry.Kind.CharacterDevice,
- posix.DT_DIR => Entry.Kind.Directory,
- posix.DT_FIFO => Entry.Kind.NamedPipe,
- posix.DT_LNK => Entry.Kind.SymLink,
- posix.DT_REG => Entry.Kind.File,
- posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
- posix.DT_WHT => Entry.Kind.Whiteout,
- else => Entry.Kind.Unknown,
- };
- return Entry{
- .name = name,
- .kind = entry_kind,
- };
- }
- }
-};
-
-pub fn changeCurDir(dir_path: []const u8) !void {
- const dir_path_c = try toPosixPath(dir_path);
- const err = posix.getErrno(posix.chdir(&dir_path_c));
- switch (err) {
+ switch (errno(system.rmdir(dir_path))) {
0 => return,
- posix.EACCES => return error.AccessDenied,
- posix.EFAULT => unreachable,
- posix.EIO => return error.FileSystem,
- posix.ELOOP => return error.SymLinkLoop,
- posix.ENAMETOOLONG => return error.NameTooLong,
- posix.ENOENT => return error.FileNotFound,
- posix.ENOMEM => return error.SystemResources,
- posix.ENOTDIR => return error.NotDir,
- else => return unexpectedErrorPosix(err),
- }
-}
-
-/// Read value of a symbolic link.
-/// The return value is a slice of out_buffer.
-pub fn readLinkC(out_buffer: *[posix.PATH_MAX]u8, pathname: [*]const u8) ![]u8 {
- const rc = posix.readlink(pathname, out_buffer, out_buffer.len);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return out_buffer[0..rc],
- posix.EACCES => return error.AccessDenied,
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.EIO => return error.FileSystem,
- posix.ELOOP => return error.SymLinkLoop,
- posix.ENAMETOOLONG => unreachable, // out_buffer is at least PATH_MAX
- posix.ENOENT => return error.FileNotFound,
- posix.ENOMEM => return error.SystemResources,
- posix.ENOTDIR => return error.NotDir,
- else => return unexpectedErrorPosix(err),
- }
-}
-
-/// Read value of a symbolic link.
-/// The return value is a slice of out_buffer.
-pub fn readLink(out_buffer: *[posix.PATH_MAX]u8, file_path: []const u8) ![]u8 {
- const file_path_c = try toPosixPath(file_path);
- return readLinkC(out_buffer, &file_path_c);
-}
-
-pub fn posix_setuid(uid: u32) !void {
- const err = posix.getErrno(posix.setuid(uid));
- if (err == 0) return;
- return switch (err) {
- posix.EAGAIN => error.ResourceLimitReached,
- posix.EINVAL => error.InvalidUserId,
- posix.EPERM => error.PermissionDenied,
- else => unexpectedErrorPosix(err),
- };
-}
-
-pub fn posix_setreuid(ruid: u32, euid: u32) !void {
- const err = posix.getErrno(posix.setreuid(ruid, euid));
- if (err == 0) return;
- return switch (err) {
- posix.EAGAIN => error.ResourceLimitReached,
- posix.EINVAL => error.InvalidUserId,
- posix.EPERM => error.PermissionDenied,
- else => unexpectedErrorPosix(err),
- };
-}
-
-pub fn posix_setgid(gid: u32) !void {
- const err = posix.getErrno(posix.setgid(gid));
- if (err == 0) return;
- return switch (err) {
- posix.EAGAIN => error.ResourceLimitReached,
- posix.EINVAL => error.InvalidUserId,
- posix.EPERM => error.PermissionDenied,
- else => unexpectedErrorPosix(err),
- };
-}
-
-pub fn posix_setregid(rgid: u32, egid: u32) !void {
- const err = posix.getErrno(posix.setregid(rgid, egid));
- if (err == 0) return;
- return switch (err) {
- posix.EAGAIN => error.ResourceLimitReached,
- posix.EINVAL => error.InvalidUserId,
- posix.EPERM => error.PermissionDenied,
- else => unexpectedErrorPosix(err),
- };
-}
-
-pub const WindowsGetStdHandleErrs = error{
- NoStdHandles,
-
- /// See https://github.com/ziglang/zig/issues/1396
+ EACCES => return error.AccessDenied,
+ EPERM => return error.AccessDenied,
+ EBUSY => return error.FileBusy,
+ EFAULT => unreachable,
+ EINVAL => unreachable,
+ ELOOP => return error.SymLinkLoop,
+ ENAMETOOLONG => return error.NameTooLong,
+ ENOENT => return error.FileNotFound,
+ ENOMEM => return error.SystemResources,
+ ENOTDIR => return error.NotDir,
+ EEXIST => return error.DirNotEmpty,
+ ENOTEMPTY => return error.DirNotEmpty,
+ EROFS => return error.ReadOnlyFileSystem,
+ else => |err| return unexpectedErrno(err),
+ }
+}
+
+pub const ChangeCurDirError = error{
+ AccessDenied,
+ FileSystem,
+ SymLinkLoop,
+ NameTooLong,
+ FileNotFound,
+ SystemResources,
+ NotDir,
Unexpected,
};
-pub fn windowsGetStdHandle(handle_id: windows.DWORD) WindowsGetStdHandleErrs!windows.HANDLE {
- if (windows.GetStdHandle(handle_id)) |handle| {
- if (handle == windows.INVALID_HANDLE_VALUE) {
- const err = windows.GetLastError();
- return switch (err) {
- else => os.unexpectedErrorWindows(err),
- };
- }
- return handle;
+/// Changes the current working directory of the calling process.
+/// `dir_path` is recommended to be a UTF-8 encoded string.
+pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
+ if (windows.is_the_target) {
+ const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);
+ @compileError("TODO implement chdir for Windows");
} else {
- return error.NoStdHandles;
+ const dir_path_c = try toPosixPath(dir_path);
+ return chdirC(&dir_path_c);
}
}
-pub const ArgIteratorPosix = struct {
- index: usize,
- count: usize,
-
- pub fn init() ArgIteratorPosix {
- return ArgIteratorPosix{
- .index = 0,
- .count = raw.len,
- };
+/// Same as `chdir` except the parameter is null-terminated.
+pub fn chdirC(dir_path: [*]const u8) ChangeCurDirError!void {
+ if (windows.is_the_target) {
+ const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
+ @compileError("TODO implement chdir for Windows");
}
-
- pub fn next(self: *ArgIteratorPosix) ?[]const u8 {
- if (self.index == self.count) return null;
-
- const s = raw[self.index];
- self.index += 1;
- return cstr.toSlice(s);
- }
-
- pub fn skip(self: *ArgIteratorPosix) bool {
- if (self.index == self.count) return false;
-
- self.index += 1;
- return true;
+ switch (errno(system.chdir(dir_path))) {
+ 0 => return,
+ EACCES => return error.AccessDenied,
+ EFAULT => unreachable,
+ EIO => return error.FileSystem,
+ ELOOP => return error.SymLinkLoop,
+ ENAMETOOLONG => return error.NameTooLong,
+ ENOENT => return error.FileNotFound,
+ ENOMEM => return error.SystemResources,
+ ENOTDIR => return error.NotDir,
+ else => |err| return unexpectedErrno(err),
}
+}
- /// This is marked as public but actually it's only meant to be used
- /// internally by zig's startup code.
- pub var raw: [][*]u8 = undefined;
+pub const ReadLinkError = error{
+ AccessDenied,
+ FileSystem,
+ SymLinkLoop,
+ NameTooLong,
+ FileNotFound,
+ SystemResources,
+ NotDir,
+ Unexpected,
};
-pub const ArgIteratorWindows = struct {
- index: usize,
- cmd_line: [*]const u8,
- in_quote: bool,
- quote_count: usize,
- seen_quote_count: usize,
-
- pub const NextError = error{OutOfMemory};
-
- pub fn init() ArgIteratorWindows {
- return initWithCmdLine(windows.GetCommandLineA());
- }
-
- pub fn initWithCmdLine(cmd_line: [*]const u8) ArgIteratorWindows {
- return ArgIteratorWindows{
- .index = 0,
- .cmd_line = cmd_line,
- .in_quote = false,
- .quote_count = countQuotes(cmd_line),
- .seen_quote_count = 0,
- };
- }
-
- /// You must free the returned memory when done.
- pub fn next(self: *ArgIteratorWindows, allocator: *Allocator) ?(NextError![]u8) {
- // march forward over whitespace
- while (true) : (self.index += 1) {
- const byte = self.cmd_line[self.index];
- switch (byte) {
- 0 => return null,
- ' ', '\t' => continue,
- else => break,
- }
- }
-
- return self.internalNext(allocator);
- }
-
- pub fn skip(self: *ArgIteratorWindows) bool {
- // march forward over whitespace
- while (true) : (self.index += 1) {
- const byte = self.cmd_line[self.index];
- switch (byte) {
- 0 => return false,
- ' ', '\t' => continue,
- else => break,
- }
- }
-
- var backslash_count: usize = 0;
- while (true) : (self.index += 1) {
- const byte = self.cmd_line[self.index];
- switch (byte) {
- 0 => return true,
- '"' => {
- const quote_is_real = backslash_count % 2 == 0;
- if (quote_is_real) {
- self.seen_quote_count += 1;
- }
- },
- '\\' => {
- backslash_count += 1;
- },
- ' ', '\t' => {
- if (self.seen_quote_count % 2 == 0 or self.seen_quote_count == self.quote_count) {
- return true;
- }
- backslash_count = 0;
- },
- else => {
- backslash_count = 0;
- continue;
- },
- }
- }
+/// Read value of a symbolic link.
+/// The return value is a slice of `out_buffer` from index 0.
+pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
+ if (windows.is_the_target) {
+ const file_path_w = try windows.sliceToPrefixedFileW(file_path);
+ @compileError("TODO implement readlink for Windows");
+ } else {
+ const file_path_c = try toPosixPath(file_path);
+ return readlinkC(&file_path_c, out_buffer);
}
+}
- fn internalNext(self: *ArgIteratorWindows, allocator: *Allocator) NextError![]u8 {
- var buf = try Buffer.initSize(allocator, 0);
- defer buf.deinit();
-
- var backslash_count: usize = 0;
- while (true) : (self.index += 1) {
- const byte = self.cmd_line[self.index];
- switch (byte) {
- 0 => return buf.toOwnedSlice(),
- '"' => {
- const quote_is_real = backslash_count % 2 == 0;
- try self.emitBackslashes(&buf, backslash_count / 2);
- backslash_count = 0;
-
- if (quote_is_real) {
- self.seen_quote_count += 1;
- if (self.seen_quote_count == self.quote_count and self.seen_quote_count % 2 == 1) {
- try buf.appendByte('"');
- }
- } else {
- try buf.appendByte('"');
- }
- },
- '\\' => {
- backslash_count += 1;
- },
- ' ', '\t' => {
- try self.emitBackslashes(&buf, backslash_count);
- backslash_count = 0;
- if (self.seen_quote_count % 2 == 1 and self.seen_quote_count != self.quote_count) {
- try buf.appendByte(byte);
- } else {
- return buf.toOwnedSlice();
- }
- },
- else => {
- try self.emitBackslashes(&buf, backslash_count);
- backslash_count = 0;
- try buf.appendByte(byte);
- },
- }
- }
+/// Same as `readlink` except `file_path` is null-terminated.
+pub fn readlinkC(file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 {
+ if (windows.is_the_target) {
+ const file_path_w = try windows.cStrToPrefixedFileW(file_path);
+ @compileError("TODO implement readlink for Windows");
}
-
- fn emitBackslashes(self: *ArgIteratorWindows, buf: *Buffer, emit_count: usize) !void {
- var i: usize = 0;
- while (i < emit_count) : (i += 1) {
- try buf.appendByte('\\');
- }
+ const rc = system.readlink(file_path, out_buffer.ptr, out_buffer.len);
+ switch (errno(rc)) {
+ 0 => return out_buffer[0..@bitCast(usize, rc)],
+ EACCES => return error.AccessDenied,
+ EFAULT => unreachable,
+ EINVAL => unreachable,
+ EIO => return error.FileSystem,
+ ELOOP => return error.SymLinkLoop,
+ ENAMETOOLONG => return error.NameTooLong,
+ ENOENT => return error.FileNotFound,
+ ENOMEM => return error.SystemResources,
+ ENOTDIR => return error.NotDir,
+ else => |err| return unexpectedErrno(err),
}
+}
- fn countQuotes(cmd_line: [*]const u8) usize {
- var result: usize = 0;
- var backslash_count: usize = 0;
- var index: usize = 0;
- while (true) : (index += 1) {
- const byte = cmd_line[index];
- switch (byte) {
- 0 => return result,
- '\\' => backslash_count += 1,
- '"' => {
- result += 1 - (backslash_count % 2);
- backslash_count = 0;
- },
- else => {
- backslash_count = 0;
- },
- }
- }
- }
+pub const SetIdError = error{
+ ResourceLimitReached,
+ InvalidUserId,
+ PermissionDenied,
+ Unexpected,
};
-pub const ArgIterator = struct {
- const InnerType = if (builtin.os == Os.windows) ArgIteratorWindows else ArgIteratorPosix;
-
- inner: InnerType,
-
- pub fn init() ArgIterator {
- if (builtin.os == Os.wasi) {
- // TODO: Figure out a compatible interface accomodating WASI
- @compileError("ArgIterator is not yet supported in WASI. Use argsAlloc and argsFree instead.");
- }
-
- return ArgIterator{ .inner = InnerType.init() };
- }
-
- pub const NextError = ArgIteratorWindows.NextError;
-
- /// You must free the returned memory when done.
- pub fn next(self: *ArgIterator, allocator: *Allocator) ?(NextError![]u8) {
- if (builtin.os == Os.windows) {
- return self.inner.next(allocator);
- } else {
- return mem.dupe(allocator, u8, self.inner.next() orelse return null);
- }
- }
-
- /// If you only are targeting posix you can call this and not need an allocator.
- pub fn nextPosix(self: *ArgIterator) ?[]const u8 {
- return self.inner.next();
- }
-
- /// Parse past 1 argument without capturing it.
- /// Returns `true` if skipped an arg, `false` if we are at the end.
- pub fn skip(self: *ArgIterator) bool {
- return self.inner.skip();
+pub fn setuid(uid: u32) SetIdError!void {
+ switch (errno(system.setuid(uid))) {
+ 0 => return,
+ EAGAIN => return error.ResourceLimitReached,
+ EINVAL => return error.InvalidUserId,
+ EPERM => return error.PermissionDenied,
+ else => |err| return unexpectedErrno(err),
}
-};
-
-pub fn args() ArgIterator {
- return ArgIterator.init();
}
-/// Caller must call argsFree on result.
-pub fn argsAlloc(allocator: *mem.Allocator) ![]const []u8 {
- if (builtin.os == Os.wasi) {
- var count: usize = undefined;
- var buf_size: usize = undefined;
-
- const args_sizes_get_ret = os.wasi.args_sizes_get(&count, &buf_size);
- if (args_sizes_get_ret != os.wasi.ESUCCESS) {
- return unexpectedErrorPosix(args_sizes_get_ret);
- }
-
- var argv = try allocator.alloc([*]u8, count);
- defer allocator.free(argv);
-
- var argv_buf = try allocator.alloc(u8, buf_size);
- const args_get_ret = os.wasi.args_get(argv.ptr, argv_buf.ptr);
- if (args_get_ret != os.wasi.ESUCCESS) {
- return unexpectedErrorPosix(args_get_ret);
- }
-
- var result_slice = try allocator.alloc([]u8, count);
-
- var i: usize = 0;
- while (i < count) : (i += 1) {
- result_slice[i] = mem.toSlice(u8, argv[i]);
- }
-
- return result_slice;
- }
-
- // TODO refactor to only make 1 allocation.
- var it = args();
- var contents = try Buffer.initSize(allocator, 0);
- defer contents.deinit();
-
- var slice_list = ArrayList(usize).init(allocator);
- defer slice_list.deinit();
-
- while (it.next(allocator)) |arg_or_err| {
- const arg = try arg_or_err;
- defer allocator.free(arg);
- try contents.append(arg);
- try slice_list.append(arg.len);
- }
-
- const contents_slice = contents.toSliceConst();
- const slice_sizes = slice_list.toSliceConst();
- const slice_list_bytes = try math.mul(usize, @sizeOf([]u8), slice_sizes.len);
- const total_bytes = try math.add(usize, slice_list_bytes, contents_slice.len);
- const buf = try allocator.alignedAlloc(u8, @alignOf([]u8), total_bytes);
- errdefer allocator.free(buf);
-
- const result_slice_list = @bytesToSlice([]u8, buf[0..slice_list_bytes]);
- const result_contents = buf[slice_list_bytes..];
- mem.copy(u8, result_contents, contents_slice);
-
- var contents_index: usize = 0;
- for (slice_sizes) |len, i| {
- const new_index = contents_index + len;
- result_slice_list[i] = result_contents[contents_index..new_index];
- contents_index = new_index;
+pub fn setreuid(ruid: u32, euid: u32) SetIdError!void {
+ switch (errno(system.setreuid(ruid, euid))) {
+ 0 => return,
+ EAGAIN => return error.ResourceLimitReached,
+ EINVAL => return error.InvalidUserId,
+ EPERM => return error.PermissionDenied,
+ else => |err| return unexpectedErrno(err),
}
-
- return result_slice_list;
}
-pub fn argsFree(allocator: *mem.Allocator, args_alloc: []const []u8) void {
- if (builtin.os == Os.wasi) {
- const last_item = args_alloc[args_alloc.len - 1];
- const last_byte_addr = @ptrToInt(last_item.ptr) + last_item.len + 1; // null terminated
- const first_item_ptr = args_alloc[0].ptr;
- const len = last_byte_addr - @ptrToInt(first_item_ptr);
- allocator.free(first_item_ptr[0..len]);
-
- return allocator.free(args_alloc);
- }
-
- var total_bytes: usize = 0;
- for (args_alloc) |arg| {
- total_bytes += @sizeOf([]u8) + arg.len;
+pub fn setgid(gid: u32) SetIdError!void {
+ switch (errno(system.setgid(gid))) {
+ 0 => return,
+ EAGAIN => return error.ResourceLimitReached,
+ EINVAL => return error.InvalidUserId,
+ EPERM => return error.PermissionDenied,
+ else => |err| return unexpectedErrno(err),
}
- const unaligned_allocated_buf = @ptrCast([*]const u8, args_alloc.ptr)[0..total_bytes];
- const aligned_allocated_buf = @alignCast(@alignOf([]u8), unaligned_allocated_buf);
- return allocator.free(aligned_allocated_buf);
}
-test "windows arg parsing" {
- testWindowsCmdLine(c"a b\tc d", [][]const u8{ "a", "b", "c", "d" });
- testWindowsCmdLine(c"\"abc\" d e", [][]const u8{ "abc", "d", "e" });
- testWindowsCmdLine(c"a\\\\\\b d\"e f\"g h", [][]const u8{ "a\\\\\\b", "de fg", "h" });
- testWindowsCmdLine(c"a\\\\\\\"b c d", [][]const u8{ "a\\\"b", "c", "d" });
- testWindowsCmdLine(c"a\\\\\\\\\"b c\" d e", [][]const u8{ "a\\\\b c", "d", "e" });
- testWindowsCmdLine(c"a b\tc \"d f", [][]const u8{ "a", "b", "c", "\"d", "f" });
-
- testWindowsCmdLine(c"\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", [][]const u8{
- ".\\..\\zig-cache\\build",
- "bin\\zig.exe",
- ".\\..",
- ".\\..\\zig-cache",
- "--help",
- });
-}
-
-fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []const u8) void {
- var it = ArgIteratorWindows.initWithCmdLine(input_cmd_line);
- for (expected_args) |expected_arg| {
- const arg = it.next(debug.global_allocator).? catch unreachable;
- testing.expectEqualSlices(u8, expected_arg, arg);
+pub fn setregid(rgid: u32, egid: u32) SetIdError!void {
+ switch (errno(system.setregid(rgid, egid))) {
+ 0 => return,
+ EAGAIN => return error.ResourceLimitReached,
+ EINVAL => return error.InvalidUserId,
+ EPERM => return error.PermissionDenied,
+ else => |err| return unexpectedErrno(err),
}
- testing.expect(it.next(debug.global_allocator) == null);
}
-// TODO make this a build variable that you can set
-const unexpected_error_tracing = false;
-const UnexpectedError = error{
- /// The Operating System returned an undocumented error code.
- Unexpected,
-};
+/// Test whether a file descriptor refers to a terminal.
+pub fn isatty(handle: fd_t) bool {
+ if (windows.is_the_target) {
+ if (isCygwinPty(handle))
+ return true;
-/// Call this when you made a syscall or something that sets errno
-/// and you get an unexpected error.
-pub fn unexpectedErrorPosix(errno: usize) UnexpectedError {
- if (unexpected_error_tracing) {
- debug.warn("unexpected errno: {}\n", errno);
- debug.dumpCurrentStackTrace(null);
+ var out: windows.DWORD = undefined;
+ return windows.kernel32.GetConsoleMode(handle, &out) != 0;
}
- return error.Unexpected;
-}
-
-/// Call this when you made a windows DLL call or something that does SetLastError
-/// and you get an unexpected error.
-pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
- if (unexpected_error_tracing) {
- debug.warn("unexpected GetLastError(): {}\n", err);
- @breakpoint();
- debug.dumpCurrentStackTrace(null);
+ if (builtin.link_libc) {
+ return system.isatty(handle) != 0;
}
- return error.Unexpected;
-}
-
-pub fn openSelfExe() !os.File {
- switch (builtin.os) {
- Os.linux => return os.File.openReadC(c"/proc/self/exe"),
- Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
- var buf: [MAX_PATH_BYTES]u8 = undefined;
- const self_exe_path = try selfExePath(&buf);
- buf[self_exe_path.len] = 0;
- return os.File.openReadC(self_exe_path.ptr);
- },
- Os.windows => {
- var buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
- const wide_slice = try selfExePathW(&buf);
- return os.File.openReadW(wide_slice.ptr);
- },
- else => @compileError("Unsupported OS"),
+ if (wasi.is_the_target) {
+ @compileError("TODO implement std.os.isatty for WASI");
}
-}
-
-test "openSelfExe" {
- switch (builtin.os) {
- Os.linux, Os.macosx, Os.ios, Os.windows, Os.freebsd => (try openSelfExe()).close(),
- else => return error.SkipZigTest, // Unsupported OS.
+ if (linux.is_the_target) {
+ var wsz: linux.winsize = undefined;
+ return linux.syscall3(linux.SYS_ioctl, @bitCast(usize, isize(handle)), linux.TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
}
+ unreachable;
}
-pub fn selfExePathW(out_buffer: *[windows_util.PATH_MAX_WIDE]u16) ![]u16 {
- const casted_len = @intCast(windows.DWORD, out_buffer.len); // TODO shouldn't need this cast
- const rc = windows.GetModuleFileNameW(null, out_buffer, casted_len);
- assert(rc <= out_buffer.len);
- if (rc == 0) {
- const err = windows.GetLastError();
- switch (err) {
- else => return unexpectedErrorWindows(err),
- }
- }
- return out_buffer[0..rc];
-}
-
-/// Get the path to the current executable.
-/// If you only need the directory, use selfExeDirPath.
-/// If you only want an open file handle, use openSelfExe.
-/// This function may return an error if the current executable
-/// was deleted after spawning.
-/// Returned value is a slice of out_buffer.
-///
-/// On Linux, depends on procfs being mounted. If the currently executing binary has
-/// been deleted, the file path looks something like `/a/b/c/exe (deleted)`.
-/// TODO make the return type of this a null terminated pointer
-pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
- switch (builtin.os) {
- Os.linux => return readLink(out_buffer, "/proc/self/exe"),
- Os.freebsd => {
- var mib = [4]c_int{ posix.CTL_KERN, posix.KERN_PROC, posix.KERN_PROC_PATHNAME, -1 };
- var out_len: usize = out_buffer.len;
- const err = posix.getErrno(posix.sysctl(&mib, 4, out_buffer, &out_len, null, 0));
-
- if (err == 0) return mem.toSlice(u8, out_buffer);
-
- return switch (err) {
- posix.EFAULT => error.BadAdress,
- posix.EPERM => error.PermissionDenied,
- else => unexpectedErrorPosix(err),
- };
- },
- Os.netbsd => {
- var mib = [4]c_int{ posix.CTL_KERN, posix.KERN_PROC_ARGS, -1, posix.KERN_PROC_PATHNAME };
- var out_len: usize = out_buffer.len;
- const err = posix.getErrno(posix.sysctl(&mib, 4, out_buffer, &out_len, null, 0));
-
- if (err == 0) return mem.toSlice(u8, out_buffer);
-
- return switch (err) {
- posix.EFAULT => error.BadAdress,
- posix.EPERM => error.PermissionDenied,
- else => unexpectedErrorPosix(err),
- };
- },
- Os.windows => {
- var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
- const utf16le_slice = try selfExePathW(&utf16le_buf);
- // Trust that Windows gives us valid UTF-16LE.
- const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
- return out_buffer[0..end_index];
- },
- Os.macosx, Os.ios => {
- var u32_len: u32 = @intCast(u32, out_buffer.len); // TODO shouldn't need this cast
- const rc = c._NSGetExecutablePath(out_buffer, &u32_len);
- if (rc != 0) return error.NameTooLong;
- return mem.toSlice(u8, out_buffer);
- },
- else => @compileError("Unsupported OS"),
- }
-}
-
-/// `selfExeDirPath` except allocates the result on the heap.
-/// Caller owns returned memory.
-pub fn selfExeDirPathAlloc(allocator: *Allocator) ![]u8 {
- var buf: [MAX_PATH_BYTES]u8 = undefined;
- return mem.dupe(allocator, u8, try selfExeDirPath(&buf));
-}
-
-/// Get the directory path that contains the current executable.
-/// Returned value is a slice of out_buffer.
-pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) ![]const u8 {
- switch (builtin.os) {
- Os.linux => {
- // If the currently executing binary has been deleted,
- // the file path looks something like `/a/b/c/exe (deleted)`
- // This path cannot be opened, but it's valid for determining the directory
- // the executable was in when it was run.
- const full_exe_path = try readLinkC(out_buffer, c"/proc/self/exe");
- // Assume that /proc/self/exe has an absolute path, and therefore dirname
- // will not return null.
- return path.dirname(full_exe_path).?;
- },
- Os.windows, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
- const self_exe_path = try selfExePath(out_buffer);
- // Assume that the OS APIs return absolute paths, and therefore dirname
- // will not return null.
- return path.dirname(self_exe_path).?;
- },
- else => @compileError("Unsupported OS"),
- }
-}
+pub fn isCygwinPty(handle: fd_t) bool {
+ if (!windows.is_the_target) return false;
-pub fn isTty(handle: FileHandle) bool {
- if (is_windows) {
- return windows_util.windowsIsTty(handle);
- } else {
- if (builtin.link_libc) {
- return c.isatty(handle) != 0;
- } else {
- return posix.isatty(handle);
- }
- }
-}
+ const size = @sizeOf(windows.FILE_NAME_INFO);
+ var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = []u8{0} ** (size + windows.MAX_PATH);
-pub fn supportsAnsiEscapeCodes(handle: FileHandle) bool {
- if (is_windows) {
- return windows_util.windowsIsCygwinPty(handle);
- } else {
- if (builtin.link_libc) {
- return c.isatty(handle) != 0;
- } else {
- return posix.isatty(handle);
- }
+ if (windows.kernel32.GetFileInformationByHandleEx(
+ handle,
+ windows.FileNameInfo,
+ @ptrCast(*c_void, &name_info_bytes),
+ name_info_bytes.len,
+ ) == 0) {
+ return false;
}
+
+ const name_info = @ptrCast(*const windows.FILE_NAME_INFO, &name_info_bytes[0]);
+ const name_bytes = name_info_bytes[size .. size + usize(name_info.FileNameLength)];
+ const name_wide = @bytesToSlice(u16, name_bytes);
+ return mem.indexOf(u16, name_wide, []u16{ 'm', 's', 'y', 's', '-' }) != null or
+ mem.indexOf(u16, name_wide, []u16{ '-', 'p', 't', 'y' }) != null;
}
-pub const PosixSocketError = error{
+pub const SocketError = error{
/// Permission to create a socket of the specified type and/or
/// pro‐tocol is denied.
PermissionDenied,
@@ -2528,25 +1262,26 @@ pub const PosixSocketError = error{
/// The protocol type or the specified protocol is not supported within this domain.
ProtocolNotSupported,
+
+ Unexpected,
};
-pub fn posixSocket(domain: u32, socket_type: u32, protocol: u32) !i32 {
- const rc = posix.socket(domain, socket_type, protocol);
- const err = posix.getErrno(rc);
- switch (err) {
+pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!i32 {
+ const rc = system.socket(domain, socket_type, protocol);
+ switch (errno(rc)) {
0 => return @intCast(i32, rc),
- posix.EACCES => return PosixSocketError.PermissionDenied,
- posix.EAFNOSUPPORT => return PosixSocketError.AddressFamilyNotSupported,
- posix.EINVAL => return PosixSocketError.ProtocolFamilyNotAvailable,
- posix.EMFILE => return PosixSocketError.ProcessFdQuotaExceeded,
- posix.ENFILE => return PosixSocketError.SystemFdQuotaExceeded,
- posix.ENOBUFS, posix.ENOMEM => return PosixSocketError.SystemResources,
- posix.EPROTONOSUPPORT => return PosixSocketError.ProtocolNotSupported,
- else => return unexpectedErrorPosix(err),
+ EACCES => return error.PermissionDenied,
+ EAFNOSUPPORT => return error.AddressFamilyNotSupported,
+ EINVAL => return error.ProtocolFamilyNotAvailable,
+ EMFILE => return error.ProcessFdQuotaExceeded,
+ ENFILE => return error.SystemFdQuotaExceeded,
+ ENOBUFS, ENOMEM => return error.SystemResources,
+ EPROTONOSUPPORT => return error.ProtocolNotSupported,
+ else => |err| return unexpectedErrno(err),
}
}
-pub const PosixBindError = error{
+pub const BindError = error{
/// The address is protected, and the user is not the superuser.
/// For UNIX domain sockets: Search permission is denied on a component
/// of the path prefix.
@@ -2580,34 +1315,32 @@ pub const PosixBindError = error{
/// The socket inode would reside on a read-only filesystem.
ReadOnlyFileSystem,
- /// See https://github.com/ziglang/zig/issues/1396
Unexpected,
};
-/// addr is `&const T` where T is one of the sockaddr
-pub fn posixBind(fd: i32, addr: *const posix.sockaddr) PosixBindError!void {
- const rc = posix.bind(fd, addr, @sizeOf(posix.sockaddr));
- const err = posix.getErrno(rc);
- switch (err) {
+/// addr is `*const T` where T is one of the sockaddr
+pub fn bind(fd: i32, addr: *const sockaddr) BindError!void {
+ const rc = system.bind(fd, addr, @sizeOf(sockaddr));
+ switch (errno(rc)) {
0 => return,
- posix.EACCES => return PosixBindError.AccessDenied,
- posix.EADDRINUSE => return PosixBindError.AddressInUse,
- posix.EBADF => unreachable, // always a race condition if this error is returned
- posix.EINVAL => unreachable,
- posix.ENOTSOCK => unreachable,
- posix.EADDRNOTAVAIL => return PosixBindError.AddressNotAvailable,
- posix.EFAULT => unreachable,
- posix.ELOOP => return PosixBindError.SymLinkLoop,
- posix.ENAMETOOLONG => return PosixBindError.NameTooLong,
- posix.ENOENT => return PosixBindError.FileNotFound,
- posix.ENOMEM => return PosixBindError.SystemResources,
- posix.ENOTDIR => return PosixBindError.NotDir,
- posix.EROFS => return PosixBindError.ReadOnlyFileSystem,
- else => return unexpectedErrorPosix(err),
- }
-}
-
-const PosixListenError = error{
+ EACCES => return error.AccessDenied,
+ EADDRINUSE => return error.AddressInUse,
+ EBADF => unreachable, // always a race condition if this error is returned
+ EINVAL => unreachable,
+ ENOTSOCK => unreachable,
+ EADDRNOTAVAIL => return error.AddressNotAvailable,
+ EFAULT => unreachable,
+ ELOOP => return error.SymLinkLoop,
+ ENAMETOOLONG => return error.NameTooLong,
+ ENOENT => return error.FileNotFound,
+ ENOMEM => return error.SystemResources,
+ ENOTDIR => return error.NotDir,
+ EROFS => return error.ReadOnlyFileSystem,
+ else => |err| return unexpectedErrno(err),
+ }
+}
+
+const ListenError = error{
/// Another socket is already listening on the same port.
/// For Internet domain sockets, the socket referred to by sockfd had not previously
/// been bound to an address and, upon attempting to bind it to an ephemeral port, it
@@ -2621,24 +1354,22 @@ const PosixListenError = error{
/// The socket is not of a type that supports the listen() operation.
OperationNotSupported,
- /// See https://github.com/ziglang/zig/issues/1396
Unexpected,
};
-pub fn posixListen(sockfd: i32, backlog: u32) PosixListenError!void {
- const rc = posix.listen(sockfd, backlog);
- const err = posix.getErrno(rc);
- switch (err) {
+pub fn listen(sockfd: i32, backlog: u32) ListenError!void {
+ const rc = system.listen(sockfd, backlog);
+ switch (errno(rc)) {
0 => return,
- posix.EADDRINUSE => return PosixListenError.AddressInUse,
- posix.EBADF => unreachable,
- posix.ENOTSOCK => return PosixListenError.FileDescriptorNotASocket,
- posix.EOPNOTSUPP => return PosixListenError.OperationNotSupported,
- else => return unexpectedErrorPosix(err),
+ EADDRINUSE => return error.AddressInUse,
+ EBADF => unreachable,
+ ENOTSOCK => return error.FileDescriptorNotASocket,
+ EOPNOTSUPP => return error.OperationNotSupported,
+ else => |err| return unexpectedErrno(err),
}
}
-pub const PosixAcceptError = error{
+pub const AcceptError = error{
ConnectionAborted,
/// The per-process limit on the number of open file descriptors has been reached.
@@ -2662,66 +1393,66 @@ pub const PosixAcceptError = error{
/// Firewall rules forbid connection.
BlockedByFirewall,
- /// See https://github.com/ziglang/zig/issues/1396
Unexpected,
};
-pub fn posixAccept(fd: i32, addr: *posix.sockaddr, flags: u32) PosixAcceptError!i32 {
+/// Accept a connection on a socket. `fd` must be opened in blocking mode.
+/// See also `accept4_async`.
+pub fn accept4(fd: i32, addr: *sockaddr, flags: u32) AcceptError!i32 {
while (true) {
- var sockaddr_size = u32(@sizeOf(posix.sockaddr));
- const rc = posix.accept4(fd, addr, &sockaddr_size, flags);
- const err = posix.getErrno(rc);
- switch (err) {
+ var sockaddr_size = u32(@sizeOf(sockaddr));
+ const rc = system.accept4(fd, addr, &sockaddr_size, flags);
+ switch (errno(rc)) {
0 => return @intCast(i32, rc),
- posix.EINTR => continue,
- else => return unexpectedErrorPosix(err),
-
- posix.EAGAIN => unreachable, // use posixAsyncAccept for non-blocking
- posix.EBADF => unreachable, // always a race condition
- posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted,
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,
- posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,
- posix.ENOBUFS => return PosixAcceptError.SystemResources,
- posix.ENOMEM => return PosixAcceptError.SystemResources,
- posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,
- posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,
- posix.EPROTO => return PosixAcceptError.ProtocolFailure,
- posix.EPERM => return PosixAcceptError.BlockedByFirewall,
+ EINTR => continue,
+ else => |err| return unexpectedErrno(err),
+
+ EAGAIN => unreachable, // This function is for blocking only.
+ EBADF => unreachable, // always a race condition
+ ECONNABORTED => return error.ConnectionAborted,
+ EFAULT => unreachable,
+ EINVAL => unreachable,
+ EMFILE => return error.ProcessFdQuotaExceeded,
+ ENFILE => return error.SystemFdQuotaExceeded,
+ ENOBUFS => return error.SystemResources,
+ ENOMEM => return error.SystemResources,
+ ENOTSOCK => return error.FileDescriptorNotASocket,
+ EOPNOTSUPP => return error.OperationNotSupported,
+ EPROTO => return error.ProtocolFailure,
+ EPERM => return error.BlockedByFirewall,
}
}
}
+/// This is the same as `accept4` except `fd` is expected to be non-blocking.
/// Returns -1 if would block.
-pub fn posixAsyncAccept(fd: i32, addr: *posix.sockaddr, flags: u32) PosixAcceptError!i32 {
+pub fn accept4_async(fd: i32, addr: *sockaddr, flags: u32) AcceptError!i32 {
while (true) {
- var sockaddr_size = u32(@sizeOf(posix.sockaddr));
- const rc = posix.accept4(fd, addr, &sockaddr_size, flags);
- const err = posix.getErrno(rc);
- switch (err) {
+ var sockaddr_size = u32(@sizeOf(sockaddr));
+ const rc = system.accept4(fd, addr, &sockaddr_size, flags);
+ switch (errno(rc)) {
0 => return @intCast(i32, rc),
- posix.EINTR => continue,
- else => return unexpectedErrorPosix(err),
-
- posix.EAGAIN => return -1,
- posix.EBADF => unreachable, // always a race condition
- posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted,
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,
- posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,
- posix.ENOBUFS => return PosixAcceptError.SystemResources,
- posix.ENOMEM => return PosixAcceptError.SystemResources,
- posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,
- posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,
- posix.EPROTO => return PosixAcceptError.ProtocolFailure,
- posix.EPERM => return PosixAcceptError.BlockedByFirewall,
+ EINTR => continue,
+ else => |err| return unexpectedErrno(err),
+
+ EAGAIN => return -1,
+ EBADF => unreachable, // always a race condition
+ ECONNABORTED => return error.ConnectionAborted,
+ EFAULT => unreachable,
+ EINVAL => unreachable,
+ EMFILE => return error.ProcessFdQuotaExceeded,
+ ENFILE => return error.SystemFdQuotaExceeded,
+ ENOBUFS => return error.SystemResources,
+ ENOMEM => return error.SystemResources,
+ ENOTSOCK => return error.FileDescriptorNotASocket,
+ EOPNOTSUPP => return error.OperationNotSupported,
+ EPROTO => return error.ProtocolFailure,
+ EPERM => return error.BlockedByFirewall,
}
}
}
-pub const LinuxEpollCreateError = error{
+pub const EpollCreateError = error{
/// The per-user limit on the number of epoll instances imposed by
/// /proc/sys/fs/epoll/max_user_instances was encountered. See epoll(7) for further
/// details.
@@ -2734,25 +1465,23 @@ pub const LinuxEpollCreateError = error{
/// There was insufficient memory to create the kernel object.
SystemResources,
- /// See https://github.com/ziglang/zig/issues/1396
Unexpected,
};
-pub fn linuxEpollCreate(flags: u32) LinuxEpollCreateError!i32 {
- const rc = posix.epoll_create1(flags);
- const err = posix.getErrno(rc);
- switch (err) {
+pub fn epoll_create1(flags: u32) EpollCreateError!i32 {
+ const rc = system.epoll_create1(flags);
+ switch (errno(rc)) {
0 => return @intCast(i32, rc),
- else => return unexpectedErrorPosix(err),
+ else => |err| return unexpectedErrno(err),
- posix.EINVAL => unreachable,
- posix.EMFILE => return LinuxEpollCreateError.ProcessFdQuotaExceeded,
- posix.ENFILE => return LinuxEpollCreateError.SystemFdQuotaExceeded,
- posix.ENOMEM => return LinuxEpollCreateError.SystemResources,
+ EINVAL => unreachable,
+ EMFILE => return error.ProcessFdQuotaExceeded,
+ ENFILE => return error.SystemFdQuotaExceeded,
+ ENOMEM => return error.SystemResources,
}
}
-pub const LinuxEpollCtlError = error{
+pub const EpollCtlError = error{
/// op was EPOLL_CTL_ADD, and the supplied file descriptor fd is already registered
/// with this epoll instance.
FileDescriptorAlreadyPresentInSet,
@@ -2777,94 +1506,88 @@ pub const LinuxEpollCtlError = error{
/// for example, a regular file or a directory.
FileDescriptorIncompatibleWithEpoll,
- /// See https://github.com/ziglang/zig/issues/1396
Unexpected,
};
-pub fn linuxEpollCtl(epfd: i32, op: u32, fd: i32, event: *linux.epoll_event) LinuxEpollCtlError!void {
- const rc = posix.epoll_ctl(epfd, op, fd, event);
- const err = posix.getErrno(rc);
- switch (err) {
+pub fn epoll_ctl(epfd: i32, op: u32, fd: i32, event: *epoll_event) EpollCtlError!void {
+ const rc = system.epoll_ctl(epfd, op, fd, event);
+ switch (errno(rc)) {
0 => return,
- else => return unexpectedErrorPosix(err),
+ else => |err| return unexpectedErrno(err),
- posix.EBADF => unreachable, // always a race condition if this happens
- posix.EEXIST => return LinuxEpollCtlError.FileDescriptorAlreadyPresentInSet,
- posix.EINVAL => unreachable,
- posix.ELOOP => return LinuxEpollCtlError.OperationCausesCircularLoop,
- posix.ENOENT => return LinuxEpollCtlError.FileDescriptorNotRegistered,
- posix.ENOMEM => return LinuxEpollCtlError.SystemResources,
- posix.ENOSPC => return LinuxEpollCtlError.UserResourceLimitReached,
- posix.EPERM => return LinuxEpollCtlError.FileDescriptorIncompatibleWithEpoll,
+ EBADF => unreachable, // always a race condition if this happens
+ EEXIST => return error.FileDescriptorAlreadyPresentInSet,
+ EINVAL => unreachable,
+ ELOOP => return error.OperationCausesCircularLoop,
+ ENOENT => return error.FileDescriptorNotRegistered,
+ ENOMEM => return error.SystemResources,
+ ENOSPC => return error.UserResourceLimitReached,
+ EPERM => return error.FileDescriptorIncompatibleWithEpoll,
}
}
-pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usize {
+/// Waits for an I/O event on an epoll file descriptor.
+/// Returns the number of file descriptors ready for the requested I/O,
+/// or zero if no file descriptor became ready during the requested timeout milliseconds.
+pub fn epoll_wait(epfd: i32, events: []epoll_event, timeout: i32) usize {
while (true) {
- const rc = posix.epoll_wait(epfd, events.ptr, @intCast(u32, events.len), timeout);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return rc,
- posix.EINTR => continue,
- posix.EBADF => unreachable,
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
+ // TODO get rid of the @intCast
+ const rc = system.epoll_wait(epfd, events.ptr, @intCast(u32, events.len), timeout);
+ switch (errno(rc)) {
+ 0 => return @intCast(usize, rc),
+ EINTR => continue,
+ EBADF => unreachable,
+ EFAULT => unreachable,
+ EINVAL => unreachable,
else => unreachable,
}
}
}
-pub const LinuxEventFdError = error{
- InvalidFlagValue,
+pub const EventFdError = error{
SystemResources,
ProcessFdQuotaExceeded,
SystemFdQuotaExceeded,
-
- /// See https://github.com/ziglang/zig/issues/1396
Unexpected,
};
-pub fn linuxEventFd(initval: u32, flags: u32) LinuxEventFdError!i32 {
- const rc = posix.eventfd(initval, flags);
- const err = posix.getErrno(rc);
- switch (err) {
+pub fn eventfd(initval: u32, flags: u32) EventFdError!i32 {
+ const rc = system.eventfd(initval, flags);
+ switch (errno(rc)) {
0 => return @intCast(i32, rc),
- else => return unexpectedErrorPosix(err),
+ else => |err| return unexpectedErrno(err),
- posix.EINVAL => return LinuxEventFdError.InvalidFlagValue,
- posix.EMFILE => return LinuxEventFdError.ProcessFdQuotaExceeded,
- posix.ENFILE => return LinuxEventFdError.SystemFdQuotaExceeded,
- posix.ENODEV => return LinuxEventFdError.SystemResources,
- posix.ENOMEM => return LinuxEventFdError.SystemResources,
+ EINVAL => unreachable, // invalid parameters
+ EMFILE => return error.ProcessFdQuotaExceeded,
+ ENFILE => return error.SystemFdQuotaExceeded,
+ ENODEV => return error.SystemResources,
+ ENOMEM => return error.SystemResources,
}
}
-pub const PosixGetSockNameError = error{
+pub const GetSockNameError = error{
/// Insufficient resources were available in the system to perform the operation.
SystemResources,
- /// See https://github.com/ziglang/zig/issues/1396
Unexpected,
};
-pub fn posixGetSockName(sockfd: i32) PosixGetSockNameError!posix.sockaddr {
- var addr: posix.sockaddr = undefined;
- var addrlen: posix.socklen_t = @sizeOf(posix.sockaddr);
- const rc = posix.getsockname(sockfd, &addr, &addrlen);
- const err = posix.getErrno(rc);
- switch (err) {
+pub fn getsockname(sockfd: i32) GetSockNameError!sockaddr {
+ var addr: sockaddr = undefined;
+ var addrlen: socklen_t = @sizeOf(sockaddr);
+ switch (errno(system.getsockname(sockfd, &addr, &addrlen))) {
0 => return addr,
- else => return unexpectedErrorPosix(err),
+ else => |err| return unexpectedErrno(err),
- posix.EBADF => unreachable,
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.ENOTSOCK => unreachable,
- posix.ENOBUFS => return PosixGetSockNameError.SystemResources,
+ EBADF => unreachable, // always a race condition
+ EFAULT => unreachable,
+ EINVAL => unreachable, // invalid parameters
+ ENOTSOCK => unreachable,
+ ENOBUFS => return error.SystemResources,
}
}
-pub const PosixConnectError = error{
+pub const ConnectError = error{
/// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket
/// file, or search permission is denied for one of the directories in the path prefix.
/// or
@@ -2897,632 +1620,828 @@ pub const PosixConnectError = error{
/// that for IP sockets the timeout may be very long when syncookies are enabled on the server.
ConnectionTimedOut,
- /// See https://github.com/ziglang/zig/issues/1396
Unexpected,
};
-pub fn posixConnect(sockfd: i32, sockaddr: *const posix.sockaddr) PosixConnectError!void {
+/// Initiate a connection on a socket.
+/// This is for blocking file descriptors only.
+/// For non-blocking, see `connect_async`.
+pub fn connect(sockfd: i32, sock_addr: *sockaddr, len: socklen_t) ConnectError!void {
while (true) {
- const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));
- const err = posix.getErrno(rc);
- switch (err) {
+ switch (errno(system.connect(sockfd, sock_addr, @sizeOf(sockaddr)))) {
0 => return,
- else => return unexpectedErrorPosix(err),
-
- posix.EACCES => return PosixConnectError.PermissionDenied,
- posix.EPERM => return PosixConnectError.PermissionDenied,
- posix.EADDRINUSE => return PosixConnectError.AddressInUse,
- posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
- posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
- posix.EAGAIN => return PosixConnectError.SystemResources,
- posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
- posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
- posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
- posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
- posix.EINPROGRESS => unreachable, // The socket is nonblocking and the connection cannot be completed immediately.
- posix.EINTR => continue,
- posix.EISCONN => unreachable, // The socket is already connected.
- posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
- posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
- posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
- posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
- }
+ EACCES => return error.PermissionDenied,
+ EPERM => return error.PermissionDenied,
+ EADDRINUSE => return error.AddressInUse,
+ EADDRNOTAVAIL => return error.AddressNotAvailable,
+ EAFNOSUPPORT => return error.AddressFamilyNotSupported,
+ EAGAIN => return error.SystemResources,
+ EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
+ EBADF => unreachable, // sockfd is not a valid open file descriptor.
+ ECONNREFUSED => return error.ConnectionRefused,
+ EFAULT => unreachable, // The socket structure address is outside the user's address space.
+ EINPROGRESS => unreachable, // The socket is nonblocking and the connection cannot be completed immediately.
+ EINTR => continue,
+ EISCONN => unreachable, // The socket is already connected.
+ ENETUNREACH => return error.NetworkUnreachable,
+ ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
+ EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
+ ETIMEDOUT => return error.ConnectionTimedOut,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+}
+
+/// Same as `connect` except it is for blocking socket file descriptors.
+/// It expects to receive EINPROGRESS`.
+pub fn connect_async(sockfd: i32, sock_addr: *sockaddr, len: socklen_t) ConnectError!void {
+ while (true) {
+ switch (errno(system.connect(sockfd, sock_addr, @sizeOf(sockaddr)))) {
+ EINTR => continue,
+ 0, EINPROGRESS => return,
+ EACCES => return error.PermissionDenied,
+ EPERM => return error.PermissionDenied,
+ EADDRINUSE => return error.AddressInUse,
+ EADDRNOTAVAIL => return error.AddressNotAvailable,
+ EAFNOSUPPORT => return error.AddressFamilyNotSupported,
+ EAGAIN => return error.SystemResources,
+ EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
+ EBADF => unreachable, // sockfd is not a valid open file descriptor.
+ ECONNREFUSED => return error.ConnectionRefused,
+ EFAULT => unreachable, // The socket structure address is outside the user's address space.
+ EISCONN => unreachable, // The socket is already connected.
+ ENETUNREACH => return error.NetworkUnreachable,
+ ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
+ EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
+ ETIMEDOUT => return error.ConnectionTimedOut,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+}
+
+pub fn getsockoptError(sockfd: i32) ConnectError!void {
+ var err_code: u32 = undefined;
+ var size: u32 = @sizeOf(u32);
+ const rc = system.getsockopt(sockfd, SOL_SOCKET, SO_ERROR, @ptrCast([*]u8, &err_code), &size);
+ assert(size == 4);
+ switch (errno(rc)) {
+ 0 => switch (err_code) {
+ 0 => return,
+ EACCES => return error.PermissionDenied,
+ EPERM => return error.PermissionDenied,
+ EADDRINUSE => return error.AddressInUse,
+ EADDRNOTAVAIL => return error.AddressNotAvailable,
+ EAFNOSUPPORT => return error.AddressFamilyNotSupported,
+ EAGAIN => return error.SystemResources,
+ EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
+ EBADF => unreachable, // sockfd is not a valid open file descriptor.
+ ECONNREFUSED => return error.ConnectionRefused,
+ EFAULT => unreachable, // The socket structure address is outside the user's address space.
+ EISCONN => unreachable, // The socket is already connected.
+ ENETUNREACH => return error.NetworkUnreachable,
+ ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
+ EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
+ ETIMEDOUT => return error.ConnectionTimedOut,
+ else => |err| return unexpectedErrno(err),
+ },
+ EBADF => unreachable, // The argument sockfd is not a valid file descriptor.
+ EFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space.
+ EINVAL => unreachable,
+ ENOPROTOOPT => unreachable, // The option is unknown at the level indicated.
+ ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
+ else => |err| return unexpectedErrno(err),
}
}
-/// Same as posixConnect except it is for blocking socket file descriptors.
-/// It expects to receive EINPROGRESS.
-pub fn posixConnectAsync(sockfd: i32, sockaddr: *const c_void, len: u32) PosixConnectError!void {
+pub fn waitpid(pid: i32, flags: u32) u32 {
+ // TODO allow implicit pointer cast from *u32 to *c_uint ?
+ const Status = if (builtin.link_libc) c_uint else u32;
+ var status: Status = undefined;
while (true) {
- const rc = posix.connect(sockfd, sockaddr, len);
- const err = posix.getErrno(rc);
- switch (err) {
- 0, posix.EINPROGRESS => return,
- else => return unexpectedErrorPosix(err),
-
- posix.EACCES => return PosixConnectError.PermissionDenied,
- posix.EPERM => return PosixConnectError.PermissionDenied,
- posix.EADDRINUSE => return PosixConnectError.AddressInUse,
- posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
- posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
- posix.EAGAIN => return PosixConnectError.SystemResources,
- posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
- posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
- posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
- posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
- posix.EINTR => continue,
- posix.EISCONN => unreachable, // The socket is already connected.
- posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
- posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
- posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
- posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
+ switch (errno(system.waitpid(pid, &status, flags))) {
+ 0 => return @bitCast(u32, status),
+ EINTR => continue,
+ ECHILD => unreachable, // The process specified does not exist. It would be a race condition to handle this error.
+ EINVAL => unreachable, // The options argument was invalid
+ else => unreachable,
}
}
}
-pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void {
- var err_code: i32 = undefined;
- var size: u32 = @sizeOf(i32);
- const rc = posix.getsockopt(sockfd, posix.SOL_SOCKET, posix.SO_ERROR, @ptrCast([*]u8, &err_code), &size);
- assert(size == 4);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => switch (err_code) {
- 0 => return,
- else => return unexpectedErrorPosix(err),
-
- posix.EACCES => return PosixConnectError.PermissionDenied,
- posix.EPERM => return PosixConnectError.PermissionDenied,
- posix.EADDRINUSE => return PosixConnectError.AddressInUse,
- posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
- posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
- posix.EAGAIN => return PosixConnectError.SystemResources,
- posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
- posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
- posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
- posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
- posix.EISCONN => unreachable, // The socket is already connected.
- posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
- posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
- posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
- posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
- },
- else => return unexpectedErrorPosix(err),
- posix.EBADF => unreachable, // The argument sockfd is not a valid file descriptor.
- posix.EFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space.
- posix.EINVAL => unreachable,
- posix.ENOPROTOOPT => unreachable, // The option is unknown at the level indicated.
- posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
+pub const FStatError = error{
+ SystemResources,
+ Unexpected,
+};
+
+pub fn fstat(fd: fd_t) FStatError!Stat {
+ var stat: Stat = undefined;
+ if (darwin.is_the_target) {
+ switch (darwin.getErrno(darwin.@"fstat$INODE64"(fd, &stat))) {
+ 0 => return stat,
+ EBADF => unreachable, // Always a race condition.
+ ENOMEM => return error.SystemResources,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+
+ switch (errno(system.fstat(fd, &stat))) {
+ 0 => return stat,
+ EBADF => unreachable, // Always a race condition.
+ ENOMEM => return error.SystemResources,
+ else => |err| return unexpectedErrno(err),
}
}
-pub const Thread = struct {
- data: Data,
+pub const KQueueError = error{
+ /// The per-process limit on the number of open file descriptors has been reached.
+ ProcessFdQuotaExceeded,
- pub const use_pthreads = is_posix and builtin.link_libc;
+ /// The system-wide limit on the total number of open files has been reached.
+ SystemFdQuotaExceeded,
- /// Represents a kernel thread handle.
- /// May be an integer or a pointer depending on the platform.
- /// On Linux and POSIX, this is the same as Id.
- pub const Handle = if (use_pthreads)
- c.pthread_t
- else switch (builtin.os) {
- builtin.Os.linux => i32,
- builtin.Os.windows => windows.HANDLE,
- else => @compileError("Unsupported OS"),
- };
+ Unexpected,
+};
- /// Represents a unique ID per thread.
- /// May be an integer or pointer depending on the platform.
- /// On Linux and POSIX, this is the same as Handle.
- pub const Id = switch (builtin.os) {
- builtin.Os.windows => windows.DWORD,
- else => Handle,
- };
+pub fn kqueue() KQueueError!i32 {
+ const rc = system.kqueue();
+ switch (errno(rc)) {
+ 0 => return @intCast(i32, rc),
+ EMFILE => return error.ProcessFdQuotaExceeded,
+ ENFILE => return error.SystemFdQuotaExceeded,
+ else => |err| return unexpectedErrno(err),
+ }
+}
- pub const Data = if (use_pthreads)
- struct {
- handle: Thread.Handle,
- mmap_addr: usize,
- mmap_len: usize,
- }
- else switch (builtin.os) {
- builtin.Os.linux => struct {
- handle: Thread.Handle,
- mmap_addr: usize,
- mmap_len: usize,
- },
- builtin.Os.windows => struct {
- handle: Thread.Handle,
- alloc_start: *c_void,
- heap_handle: windows.HANDLE,
- },
- else => @compileError("Unsupported OS"),
- };
+pub const KEventError = error{
+ /// The process does not have permission to register a filter.
+ AccessDenied,
- /// Returns the ID of the calling thread.
- /// Makes a syscall every time the function is called.
- /// On Linux and POSIX, this Id is the same as a Handle.
- pub fn getCurrentId() Id {
- if (use_pthreads) {
- return c.pthread_self();
- } else
- return switch (builtin.os) {
- builtin.Os.linux => linux.gettid(),
- builtin.Os.windows => windows.GetCurrentThreadId(),
- else => @compileError("Unsupported OS"),
- };
- }
-
- /// Returns the handle of this thread.
- /// On Linux and POSIX, this is the same as Id.
- /// On Linux, it is possible that the thread spawned with `spawnThread`
- /// finishes executing entirely before the clone syscall completes. In this
- /// case, this function will return 0 rather than the no-longer-existing thread's
- /// pid.
- pub fn handle(self: Thread) Handle {
- return self.data.handle;
- }
-
- pub fn wait(self: *const Thread) void {
- if (use_pthreads) {
- const err = c.pthread_join(self.data.handle, null);
- switch (err) {
- 0 => {},
- posix.EINVAL => unreachable,
- posix.ESRCH => unreachable,
- posix.EDEADLK => unreachable,
- else => unreachable,
- }
- assert(posix.munmap(self.data.mmap_addr, self.data.mmap_len) == 0);
- } else switch (builtin.os) {
- builtin.Os.linux => {
- while (true) {
- const pid_value = @atomicLoad(i32, &self.data.handle, .SeqCst);
- if (pid_value == 0) break;
- const rc = linux.futex_wait(&self.data.handle, linux.FUTEX_WAIT, pid_value, null);
- switch (linux.getErrno(rc)) {
- 0 => continue,
- posix.EINTR => continue,
- posix.EAGAIN => continue,
- else => unreachable,
- }
- }
- assert(posix.munmap(self.data.mmap_addr, self.data.mmap_len) == 0);
- },
- builtin.Os.windows => {
- assert(windows.WaitForSingleObject(self.data.handle, windows.INFINITE) == windows.WAIT_OBJECT_0);
- assert(windows.CloseHandle(self.data.handle) != 0);
- assert(windows.HeapFree(self.data.heap_handle, 0, self.data.alloc_start) != 0);
- },
- else => @compileError("Unsupported OS"),
+ /// The event could not be found to be modified or deleted.
+ EventNotFound,
+
+ /// No memory was available to register the event.
+ SystemResources,
+
+ /// The specified process to attach to does not exist.
+ ProcessNotFound,
+
+ /// changelist or eventlist had too many items on it.
+ /// TODO remove this possibility
+ Overflow,
+};
+
+pub fn kevent(
+ kq: i32,
+ changelist: []const Kevent,
+ eventlist: []Kevent,
+ timeout: ?*const timespec,
+) KEventError!usize {
+ while (true) {
+ const rc = system.kevent(
+ kq,
+ changelist.ptr,
+ try math.cast(c_int, changelist.len),
+ eventlist.ptr,
+ try math.cast(c_int, eventlist.len),
+ timeout,
+ );
+ switch (errno(rc)) {
+ 0 => return @intCast(usize, rc),
+ EACCES => return error.AccessDenied,
+ EFAULT => unreachable,
+ EBADF => unreachable, // Always a race condition.
+ EINTR => continue,
+ EINVAL => unreachable,
+ ENOENT => return error.EventNotFound,
+ ENOMEM => return error.SystemResources,
+ ESRCH => return error.ProcessNotFound,
+ else => unreachable,
}
}
-};
+}
-pub const SpawnThreadError = error{
- /// A system-imposed limit on the number of threads was encountered.
- /// There are a number of limits that may trigger this error:
- /// * the RLIMIT_NPROC soft resource limit (set via setrlimit(2)),
- /// which limits the number of processes and threads for a real
- /// user ID, was reached;
- /// * the kernel's system-wide limit on the number of processes and
- /// threads, /proc/sys/kernel/threads-max, was reached (see
- /// proc(5));
- /// * the maximum number of PIDs, /proc/sys/kernel/pid_max, was
- /// reached (see proc(5)); or
- /// * the PID limit (pids.max) imposed by the cgroup "process num‐
- /// ber" (PIDs) controller was reached.
- ThreadQuotaExceeded,
-
- /// The kernel cannot allocate sufficient memory to allocate a task structure
- /// for the child, or to copy those parts of the caller's context that need to
- /// be copied.
+pub const INotifyInitError = error{
+ ProcessFdQuotaExceeded,
+ SystemFdQuotaExceeded,
SystemResources,
+ Unexpected,
+};
- /// Not enough userland memory to spawn the thread.
- OutOfMemory,
+/// initialize an inotify instance
+pub fn inotify_init1(flags: u32) INotifyInitError!i32 {
+ const rc = system.inotify_init1(flags);
+ switch (errno(rc)) {
+ 0 => return @intCast(i32, rc),
+ EINVAL => unreachable,
+ EMFILE => return error.ProcessFdQuotaExceeded,
+ ENFILE => return error.SystemFdQuotaExceeded,
+ ENOMEM => return error.SystemResources,
+ else => |err| return unexpectedErrno(err),
+ }
+}
- /// See https://github.com/ziglang/zig/issues/1396
+pub const INotifyAddWatchError = error{
+ AccessDenied,
+ NameTooLong,
+ FileNotFound,
+ SystemResources,
+ UserResourceLimitReached,
Unexpected,
};
-/// caller must call wait on the returned thread
-/// fn startFn(@typeOf(context)) T
-/// where T is u8, noreturn, void, or !void
-/// caller must call wait on the returned thread
-pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread {
- if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode");
- // TODO compile-time call graph analysis to determine stack upper bound
- // https://github.com/ziglang/zig/issues/157
- const default_stack_size = 8 * 1024 * 1024;
-
- const Context = @typeOf(context);
- comptime assert(@ArgType(@typeOf(startFn), 0) == Context);
-
- if (builtin.os == builtin.Os.windows) {
- const WinThread = struct {
- const OuterContext = struct {
- thread: Thread,
- inner: Context,
- };
- extern fn threadMain(raw_arg: windows.LPVOID) windows.DWORD {
- const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*;
- switch (@typeId(@typeOf(startFn).ReturnType)) {
- builtin.TypeId.Int => {
- return startFn(arg);
- },
- builtin.TypeId.Void => {
- startFn(arg);
- return 0;
- },
- else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"),
- }
- }
- };
-
- const heap_handle = windows.GetProcessHeap() orelse return SpawnThreadError.OutOfMemory;
- const byte_count = @alignOf(WinThread.OuterContext) + @sizeOf(WinThread.OuterContext);
- const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) orelse return SpawnThreadError.OutOfMemory;
- errdefer assert(windows.HeapFree(heap_handle, 0, bytes_ptr) != 0);
- const bytes = @ptrCast([*]u8, bytes_ptr)[0..byte_count];
- const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext) catch unreachable;
- outer_context.* = WinThread.OuterContext{
- .thread = Thread{
- .data = Thread.Data{
- .heap_handle = heap_handle,
- .alloc_start = bytes_ptr,
- .handle = undefined,
- },
- },
- .inner = context,
- };
-
- const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner);
- outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse {
- const err = windows.GetLastError();
- return switch (err) {
- else => os.unexpectedErrorWindows(err),
- };
- };
- return &outer_context.thread;
- }
-
- const MainFuncs = struct {
- extern fn linuxThreadMain(ctx_addr: usize) u8 {
- const arg = if (@sizeOf(Context) == 0) {} else @intToPtr(*const Context, ctx_addr).*;
-
- switch (@typeId(@typeOf(startFn).ReturnType)) {
- builtin.TypeId.Int => {
- return startFn(arg);
- },
- builtin.TypeId.Void => {
- startFn(arg);
- return 0;
- },
- else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"),
- }
- }
- extern fn posixThreadMain(ctx: ?*c_void) ?*c_void {
- if (@sizeOf(Context) == 0) {
- _ = startFn({});
- return null;
- } else {
- _ = startFn(@ptrCast(*const Context, @alignCast(@alignOf(Context), ctx)).*);
- return null;
- }
- }
- };
+/// add a watch to an initialized inotify instance
+pub fn inotify_add_watch(inotify_fd: i32, pathname: []const u8, mask: u32) INotifyAddWatchError!i32 {
+ const pathname_c = try toPosixPath(pathname);
+ return inotify_add_watchC(inotify_fd, &pathname_c, mask);
+}
- const MAP_GROWSDOWN = if (builtin.os == builtin.Os.linux) linux.MAP_GROWSDOWN else 0;
-
- var stack_end_offset: usize = undefined;
- var thread_start_offset: usize = undefined;
- var context_start_offset: usize = undefined;
- var tls_start_offset: usize = undefined;
- const mmap_len = blk: {
- // First in memory will be the stack, which grows downwards.
- var l: usize = mem.alignForward(default_stack_size, os.page_size);
- stack_end_offset = l;
- // Above the stack, so that it can be in the same mmap call, put the Thread object.
- l = mem.alignForward(l, @alignOf(Thread));
- thread_start_offset = l;
- l += @sizeOf(Thread);
- // Next, the Context object.
- if (@sizeOf(Context) != 0) {
- l = mem.alignForward(l, @alignOf(Context));
- context_start_offset = l;
- l += @sizeOf(Context);
- }
- // Finally, the Thread Local Storage, if any.
- if (!Thread.use_pthreads) {
- if (linux.tls.tls_image) |tls_img| {
- l = mem.alignForward(l, @alignOf(usize));
- tls_start_offset = l;
- l += tls_img.alloc_size;
- }
- }
- break :blk l;
- };
- const mmap_addr = posix.mmap(null, mmap_len, posix.PROT_READ | posix.PROT_WRITE, posix.MAP_PRIVATE | posix.MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0);
- if (mmap_addr == posix.MAP_FAILED) return error.OutOfMemory;
- errdefer assert(posix.munmap(mmap_addr, mmap_len) == 0);
-
- const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(*Thread, mmap_addr + thread_start_offset));
- thread_ptr.data.mmap_addr = mmap_addr;
- thread_ptr.data.mmap_len = mmap_len;
-
- var arg: usize = undefined;
- if (@sizeOf(Context) != 0) {
- arg = mmap_addr + context_start_offset;
- const context_ptr = @alignCast(@alignOf(Context), @intToPtr(*Context, arg));
- context_ptr.* = context;
- }
-
- if (Thread.use_pthreads) {
- // use pthreads
- var attr: c.pthread_attr_t = undefined;
- if (c.pthread_attr_init(&attr) != 0) return SpawnThreadError.SystemResources;
- defer assert(c.pthread_attr_destroy(&attr) == 0);
-
- assert(c.pthread_attr_setstack(&attr, @intToPtr(*c_void, mmap_addr), stack_end_offset) == 0);
-
- const err = c.pthread_create(&thread_ptr.data.handle, &attr, MainFuncs.posixThreadMain, @intToPtr(*c_void, arg));
- switch (err) {
- 0 => return thread_ptr,
- posix.EAGAIN => return SpawnThreadError.SystemResources,
- posix.EPERM => unreachable,
- posix.EINVAL => unreachable,
- else => return unexpectedErrorPosix(@intCast(usize, err)),
- }
- } else if (builtin.os == builtin.Os.linux) {
- var flags: u32 = posix.CLONE_VM | posix.CLONE_FS | posix.CLONE_FILES | posix.CLONE_SIGHAND |
- posix.CLONE_THREAD | posix.CLONE_SYSVSEM | posix.CLONE_PARENT_SETTID | posix.CLONE_CHILD_CLEARTID |
- posix.CLONE_DETACHED;
- var newtls: usize = undefined;
- if (linux.tls.tls_image) |tls_img| {
- newtls = linux.tls.copyTLS(mmap_addr + tls_start_offset);
- flags |= posix.CLONE_SETTLS;
- }
- const rc = posix.clone(MainFuncs.linuxThreadMain, mmap_addr + stack_end_offset, flags, arg, &thread_ptr.data.handle, newtls, &thread_ptr.data.handle);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return thread_ptr,
- posix.EAGAIN => return SpawnThreadError.ThreadQuotaExceeded,
- posix.EINVAL => unreachable,
- posix.ENOMEM => return SpawnThreadError.SystemResources,
- posix.ENOSPC => unreachable,
- posix.EPERM => unreachable,
- posix.EUSERS => unreachable,
- else => return unexpectedErrorPosix(err),
- }
- } else {
- @compileError("Unsupported OS");
+/// Same as `inotify_add_watch` except pathname is null-terminated.
+pub fn inotify_add_watchC(inotify_fd: i32, pathname: [*]const u8, mask: u32) INotifyAddWatchError!i32 {
+ const rc = system.inotify_add_watch(inotify_fd, pathname, mask);
+ switch (errno(rc)) {
+ 0 => return @intCast(i32, rc),
+ EACCES => return error.AccessDenied,
+ EBADF => unreachable,
+ EFAULT => unreachable,
+ EINVAL => unreachable,
+ ENAMETOOLONG => return error.NameTooLong,
+ ENOENT => return error.FileNotFound,
+ ENOMEM => return error.SystemResources,
+ ENOSPC => return error.UserResourceLimitReached,
+ else => |err| return unexpectedErrno(err),
}
}
-pub fn posixWait(pid: i32) i32 {
- var status: i32 = undefined;
- while (true) {
- const err = posix.getErrno(posix.waitpid(pid, &status, 0));
- switch (err) {
- 0 => return status,
- posix.EINTR => continue,
- posix.ECHILD => unreachable, // The process specified does not exist. It would be a race condition to handle this error.
- posix.EINVAL => unreachable, // The options argument was invalid
- else => unreachable,
- }
+/// remove an existing watch from an inotify instance
+pub fn inotify_rm_watch(inotify_fd: i32, wd: i32) void {
+ switch (errno(system.inotify_rm_watch(inotify_fd, wd))) {
+ 0 => return,
+ EBADF => unreachable,
+ EINVAL => unreachable,
+ else => unreachable,
}
}
-pub fn posixFStat(fd: i32) !posix.Stat {
- var stat: posix.Stat = undefined;
- const err = posix.getErrno(posix.fstat(fd, &stat));
- if (err > 0) {
- return switch (err) {
- // We do not make this an error code because if you get EBADF it's always a bug,
- // since the fd could have been reused.
- posix.EBADF => unreachable,
- posix.ENOMEM => error.SystemResources,
- else => os.unexpectedErrorPosix(err),
- };
+pub const MProtectError = error{
+ AccessDenied,
+ OutOfMemory,
+ Unexpected,
+};
+
+/// `memory.len` must be page-aligned.
+pub fn mprotect(memory: [*]align(mem.page_size) u8, protection: u32) MProtectError!void {
+ assert(mem.isAligned(memory.len, mem.page_size));
+ switch (errno(system.mprotect(memory.ptr, memory.len, protection))) {
+ 0 => return,
+ EINVAL => unreachable,
+ EACCES => return error.AccessDenied,
+ ENOMEM => return error.OutOfMemory,
+ else => return unexpectedErrno(err),
}
+}
+
+pub const ForkError = error{
+ SystemResources,
+ Unexpected,
+};
- return stat;
+pub fn fork() ForkError!pid_t {
+ const rc = system.fork();
+ switch (errno(rc)) {
+ 0 => return @intCast(pid_t, rc),
+ EAGAIN => return error.SystemResources,
+ ENOMEM => return error.SystemResources,
+ else => |err| return unexpectedErrno(err),
+ }
}
-pub const CpuCountError = error{
+pub const MMapError = error{
+ /// The underlying filesystem of the specified file does not support memory mapping.
+ MemoryMappingNotSupported,
+
+ /// 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.
+ /// Or `PROT_WRITE` is set, but the file is append-only.
+ AccessDenied,
+
+ /// The `prot` argument asks for `PROT_EXEC` but the mapped area belongs to a file on
+ /// a filesystem that was mounted no-exec.
+ PermissionDenied,
+ LockedMemoryLimitExceeded,
OutOfMemory,
+ Unexpected,
+};
+
+/// Map files or devices into memory.
+/// Use of a mapped region can result in these signals:
+/// `length` must be page-aligned.
+/// * SIGSEGV - Attempted write into a region mapped as read-only.
+/// * SIGBUS - Attempted access to a portion of the buffer that does not correspond to the file
+pub fn mmap(
+ ptr: ?[*]align(mem.page_size) u8,
+ length: usize,
+ prot: u32,
+ flags: u32,
+ fd: fd_t,
+ offset: isize,
+) MMapError![]align(mem.page_size) u8 {
+ assert(mem.isAligned(length, mem.page_size));
+ const err = if (builtin.link_libc) blk: {
+ const rc = std.c.mmap(ptr, length, prot, flags, fd, offset);
+ if (rc != MAP_FAILED) return @ptrCast([*]align(mem.page_size) u8, @alignCast(mem.page_size, rc))[0..length];
+ break :blk @intCast(usize, system._errno().*);
+ } else blk: {
+ const rc = system.mmap(ptr, length, prot, flags, fd, offset);
+ const err = errno(rc);
+ if (err == 0) return @intToPtr([*]align(mem.page_size) u8, rc)[0..length];
+ break :blk err;
+ };
+ switch (err) {
+ ETXTBSY => return error.AccessDenied,
+ EACCES => return error.AccessDenied,
+ EPERM => return error.PermissionDenied,
+ EAGAIN => return error.LockedMemoryLimitExceeded,
+ EBADF => unreachable, // Always a race condition.
+ EOVERFLOW => unreachable, // The number of pages used for length + offset would overflow.
+ ENODEV => return error.MemoryMappingNotSupported,
+ EINVAL => unreachable, // Invalid parameters to mmap()
+ ENOMEM => return error.OutOfMemory,
+ else => return unexpectedErrno(err),
+ }
+}
+
+/// Deletes the mappings for the specified address range, causing
+/// further references to addresses within the range to generate invalid memory references.
+/// Note that while POSIX allows unmapping a region in the middle of an existing mapping,
+/// Zig's munmap function does not, for two reasons:
+/// * It violates the Zig principle that resource deallocation must succeed.
+/// * The Windows function, VirtualFree, has this restriction.
+pub fn munmap(memory: []align(mem.page_size) u8) void {
+ switch (errno(system.munmap(memory.ptr, memory.len))) {
+ 0 => return,
+ EINVAL => unreachable, // Invalid parameters.
+ ENOMEM => unreachable, // Attempted to unmap a region in the middle of an existing mapping.
+ else => unreachable,
+ }
+}
+
+pub const AccessError = error{
PermissionDenied,
+ FileNotFound,
+ NameTooLong,
+ InputOutput,
+ SystemResources,
+ BadPathName,
+
+ /// On Windows, file paths must be valid Unicode.
+ InvalidUtf8,
- /// See https://github.com/ziglang/zig/issues/1396
Unexpected,
};
-pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {
- switch (builtin.os) {
- builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
- var count: c_int = undefined;
- var count_len: usize = @sizeOf(c_int);
- const rc = posix.sysctlbyname(switch (builtin.os) {
- builtin.Os.macosx => c"hw.logicalcpu",
- else => c"hw.ncpu",
- }, @ptrCast(*c_void, &count), &count_len, null, 0);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return @intCast(usize, count),
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.ENOMEM => return CpuCountError.OutOfMemory,
- posix.ENOTDIR => unreachable,
- posix.EISDIR => unreachable,
- posix.ENOENT => unreachable,
- posix.EPERM => unreachable,
- else => return os.unexpectedErrorPosix(err),
- }
- },
- builtin.Os.linux => {
- const usize_count = 16;
- const allocator = std.heap.stackFallback(usize_count * @sizeOf(usize), fallback_allocator).get();
-
- var set = try allocator.alloc(usize, usize_count);
- defer allocator.free(set);
-
- while (true) {
- const rc = posix.sched_getaffinity(0, set);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => {
- if (rc < set.len * @sizeOf(usize)) {
- const result = set[0 .. rc / @sizeOf(usize)];
- var sum: usize = 0;
- for (result) |x| {
- sum += @popCount(usize, x);
- }
- return sum;
- } else {
- set = try allocator.realloc(set, set.len * 2);
- continue;
- }
- },
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.EPERM => return CpuCountError.PermissionDenied,
- posix.ESRCH => unreachable,
- else => return os.unexpectedErrorPosix(err),
- }
- }
- },
- builtin.Os.windows => {
- var system_info: windows.SYSTEM_INFO = undefined;
- windows.GetSystemInfo(&system_info);
- return @intCast(usize, system_info.dwNumberOfProcessors);
- },
- else => @compileError("unsupported OS"),
+/// check user's permissions for a file
+/// TODO currently this assumes `mode` is `F_OK` on Windows.
+pub fn access(path: []const u8, mode: u32) AccessError!void {
+ if (windows.is_the_target) {
+ const path_w = try windows.sliceToPrefixedFileW(path);
+ _ = try windows.GetFileAttributesW(&path_w);
+ return;
}
+ const path_c = try toPosixPath(path);
+ return accessC(&path_c, mode);
}
-pub const BsdKQueueError = error{
- /// The per-process limit on the number of open file descriptors has been reached.
- ProcessFdQuotaExceeded,
+/// Same as `access` except `path` is null-terminated.
+pub fn accessC(path: [*]const u8, mode: u32) AccessError!void {
+ if (windows.is_the_target) {
+ const path_w = try windows.cStrToPrefixedFileW(path);
+ _ = try windows.GetFileAttributesW(&path_w);
+ return;
+ }
+ switch (errno(system.access(path, mode))) {
+ 0 => return,
+ EACCES => return error.PermissionDenied,
+ EROFS => return error.PermissionDenied,
+ ELOOP => return error.PermissionDenied,
+ ETXTBSY => return error.PermissionDenied,
+ ENOTDIR => return error.FileNotFound,
+ ENOENT => return error.FileNotFound,
- /// The system-wide limit on the total number of open files has been reached.
+ ENAMETOOLONG => return error.NameTooLong,
+ EINVAL => unreachable,
+ EFAULT => unreachable,
+ EIO => return error.InputOutput,
+ ENOMEM => return error.SystemResources,
+ else => |err| return unexpectedErrno(err),
+ }
+}
+
+pub const PipeError = error{
SystemFdQuotaExceeded,
+ ProcessFdQuotaExceeded,
+ Unexpected,
+};
- /// See https://github.com/ziglang/zig/issues/1396
+/// Creates a unidirectional data channel that can be used for interprocess communication.
+pub fn pipe() PipeError![2]fd_t {
+ var fds: [2]fd_t = undefined;
+ switch (errno(system.pipe(&fds))) {
+ 0 => return fds,
+ EINVAL => unreachable, // Invalid parameters to pipe()
+ EFAULT => unreachable, // Invalid fds pointer
+ ENFILE => return error.SystemFdQuotaExceeded,
+ EMFILE => return error.ProcessFdQuotaExceeded,
+ else => |err| return unexpectedErrno(err),
+ }
+}
+
+pub fn pipe2(flags: u32) PipeError![2]fd_t {
+ var fds: [2]fd_t = undefined;
+ switch (errno(system.pipe2(&fds, flags))) {
+ 0 => return fds,
+ EINVAL => unreachable, // Invalid flags
+ EFAULT => unreachable, // Invalid fds pointer
+ ENFILE => return error.SystemFdQuotaExceeded,
+ EMFILE => return error.ProcessFdQuotaExceeded,
+ else => |err| return unexpectedErrno(err),
+ }
+}
+
+pub const SysCtlError = error{
+ PermissionDenied,
+ SystemResources,
+ NameTooLong,
Unexpected,
};
-pub fn bsdKQueue() BsdKQueueError!i32 {
- const rc = posix.kqueue();
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return @intCast(i32, rc),
- posix.EMFILE => return BsdKQueueError.ProcessFdQuotaExceeded,
- posix.ENFILE => return BsdKQueueError.SystemFdQuotaExceeded,
- else => return unexpectedErrorPosix(err),
+pub fn sysctl(
+ name: []const c_int,
+ oldp: ?*c_void,
+ oldlenp: ?*usize,
+ newp: ?*c_void,
+ newlen: usize,
+) SysCtlError!void {
+ const name_len = math.cast(c_uint, name.len) catch return error.NameTooLong;
+ switch (errno(system.sysctl(name.ptr, name_len, oldp, oldlenp, newp, newlen))) {
+ 0 => return,
+ EFAULT => unreachable,
+ EPERM => return error.PermissionDenied,
+ ENOMEM => return error.SystemResources,
+ else => |err| return unexpectedErrno(err),
}
}
-pub const BsdKEventError = error{
- /// The process does not have permission to register a filter.
- AccessDenied,
+pub fn sysctlbynameC(
+ name: [*]const u8,
+ oldp: ?*c_void,
+ oldlenp: ?*usize,
+ newp: ?*c_void,
+ newlen: usize,
+) SysCtlError!void {
+ switch (errno(system.sysctlbyname(name, oldp, oldlenp, newp, newlen))) {
+ 0 => return,
+ EFAULT => unreachable,
+ EPERM => return error.PermissionDenied,
+ ENOMEM => return error.SystemResources,
+ else => |err| return unexpectedErrno(err),
+ }
+}
- /// The event could not be found to be modified or deleted.
- EventNotFound,
+pub fn gettimeofday(tv: ?*timeval, tz: ?*timezone) void {
+ switch (errno(system.gettimeofday(tv, tz))) {
+ 0 => return,
+ EINVAL => unreachable,
+ else => unreachable,
+ }
+}
- /// No memory was available to register the event.
+pub const SeekError = error{
+ Unseekable,
+ Unexpected,
+};
+
+/// Repositions read/write file offset relative to the beginning.
+pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {
+ if (linux.is_the_target and !builtin.link_libc and @sizeOf(usize) == 4) {
+ switch (errno(system.llseek(fd, offset, null, SEEK_SET))) {
+ 0 => return,
+ EBADF => unreachable, // always a race condition
+ EINVAL => return error.Unseekable,
+ EOVERFLOW => return error.Unseekable,
+ ESPIPE => return error.Unseekable,
+ ENXIO => return error.Unseekable,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+ if (windows.is_the_target) {
+ return windows.SetFilePointerEx_BEGIN(fd, offset);
+ }
+ const ipos = @bitCast(i64, offset); // the OS treats this as unsigned
+ switch (errno(system.lseek(fd, ipos, SEEK_SET))) {
+ 0 => return,
+ EBADF => unreachable, // always a race condition
+ EINVAL => return error.Unseekable,
+ EOVERFLOW => return error.Unseekable,
+ ESPIPE => return error.Unseekable,
+ ENXIO => return error.Unseekable,
+ else => |err| return unexpectedErrno(err),
+ }
+}
+
+/// Repositions read/write file offset relative to the current offset.
+pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {
+ if (linux.is_the_target and !builtin.link_libc and @sizeOf(usize) == 4) {
+ switch (errno(system.llseek(fd, @bitCast(u64, offset), null, SEEK_CUR))) {
+ 0 => return,
+ EBADF => unreachable, // always a race condition
+ EINVAL => return error.Unseekable,
+ EOVERFLOW => return error.Unseekable,
+ ESPIPE => return error.Unseekable,
+ ENXIO => return error.Unseekable,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+ if (windows.is_the_target) {
+ return windows.SetFilePointerEx_CURRENT(fd, offset);
+ }
+ switch (errno(system.lseek(fd, offset, SEEK_CUR))) {
+ 0 => return,
+ EBADF => unreachable, // always a race condition
+ EINVAL => return error.Unseekable,
+ EOVERFLOW => return error.Unseekable,
+ ESPIPE => return error.Unseekable,
+ ENXIO => return error.Unseekable,
+ else => |err| return unexpectedErrno(err),
+ }
+}
+
+/// Repositions read/write file offset relative to the end.
+pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {
+ if (linux.is_the_target and !builtin.link_libc and @sizeOf(usize) == 4) {
+ switch (errno(system.llseek(fd, @bitCast(u64, offset), null, SEEK_END))) {
+ EBADF => unreachable, // always a race condition
+ EINVAL => return error.Unseekable,
+ EOVERFLOW => return error.Unseekable,
+ ESPIPE => return error.Unseekable,
+ ENXIO => return error.Unseekable,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+ if (windows.is_the_target) {
+ return windows.SetFilePointerEx_END(fd, offset);
+ }
+ switch (errno(system.lseek(fd, offset, SEEK_END))) {
+ 0 => return,
+ EBADF => unreachable, // always a race condition
+ EINVAL => return error.Unseekable,
+ EOVERFLOW => return error.Unseekable,
+ ESPIPE => return error.Unseekable,
+ ENXIO => return error.Unseekable,
+ else => |err| return unexpectedErrno(err),
+ }
+}
+
+/// Returns the read/write file offset relative to the beginning.
+pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {
+ if (linux.is_the_target and !builtin.link_libc and @sizeOf(usize) == 4) {
+ var result: u64 = undefined;
+ switch (errno(system.llseek(fd, 0, &result, SEEK_CUR))) {
+ 0 => return result,
+ EBADF => unreachable, // always a race condition
+ EINVAL => return error.Unseekable,
+ EOVERFLOW => return error.Unseekable,
+ ESPIPE => return error.Unseekable,
+ ENXIO => return error.Unseekable,
+ else => |err| return unexpectedErrno(err),
+ }
+ }
+ if (windows.is_the_target) {
+ return windows.SetFilePointerEx_CURRENT_get(fd);
+ }
+ const rc = system.lseek(fd, 0, SEEK_CUR);
+ switch (errno(rc)) {
+ 0 => return @bitCast(u64, rc),
+ EBADF => unreachable, // always a race condition
+ EINVAL => return error.Unseekable,
+ EOVERFLOW => return error.Unseekable,
+ ESPIPE => return error.Unseekable,
+ ENXIO => return error.Unseekable,
+ else => |err| return unexpectedErrno(err),
+ }
+}
+
+pub const RealPathError = error{
+ FileNotFound,
+ AccessDenied,
+ NameTooLong,
+ NotSupported,
+ NotDir,
+ SymLinkLoop,
+ InputOutput,
+ FileTooBig,
+ IsDir,
+ ProcessFdQuotaExceeded,
+ SystemFdQuotaExceeded,
+ NoDevice,
SystemResources,
+ NoSpaceLeft,
+ FileSystem,
+ BadPathName,
+ DeviceBusy,
- /// The specified process to attach to does not exist.
- ProcessNotFound,
+ SharingViolation,
+ PipeBusy,
+
+ /// On Windows, file paths must be valid Unicode.
+ InvalidUtf8,
+
+ PathAlreadyExists,
+
+ Unexpected,
};
-pub fn bsdKEvent(
- kq: i32,
- changelist: []const posix.Kevent,
- eventlist: []posix.Kevent,
- timeout: ?*const posix.timespec,
-) BsdKEventError!usize {
+/// Return the canonicalized absolute pathname.
+/// Expands all symbolic links and resolves references to `.`, `..`, and
+/// extra `/` characters in `pathname`.
+/// The return value is a slice of `out_buffer`, but not necessarily from the beginning.
+/// See also `realpathC` and `realpathW`.
+pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
+ if (windows.is_the_target) {
+ const pathname_w = try windows.sliceToPrefixedFileW(pathname);
+ return realpathW(&pathname_w, out_buffer);
+ }
+ const pathname_c = try toPosixPath(pathname);
+ return realpathC(&pathname_c, out_buffer);
+}
+
+/// Same as `realpath` except `pathname` is null-terminated.
+pub fn realpathC(pathname: [*]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
+ if (windows.is_the_target) {
+ const pathname_w = try windows.cStrToPrefixedFileW(pathname);
+ return realpathW(&pathname_w, out_buffer);
+ }
+ if (linux.is_the_target and !builtin.link_libc) {
+ const fd = try openC(pathname, linux.O_PATH | linux.O_NONBLOCK | linux.O_CLOEXEC, 0);
+ defer close(fd);
+
+ var procfs_buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined;
+ const proc_path = std.fmt.bufPrint(procfs_buf[0..], "/proc/self/fd/{}\x00", fd) catch unreachable;
+
+ return readlinkC(proc_path.ptr, out_buffer);
+ }
+ const result_path = std.c.realpath(pathname, out_buffer) orelse switch (std.c._errno().*) {
+ EINVAL => unreachable,
+ EBADF => unreachable,
+ EFAULT => unreachable,
+ EACCES => return error.AccessDenied,
+ ENOENT => return error.FileNotFound,
+ ENOTSUP => return error.NotSupported,
+ ENOTDIR => return error.NotDir,
+ ENAMETOOLONG => return error.NameTooLong,
+ ELOOP => return error.SymLinkLoop,
+ EIO => return error.InputOutput,
+ else => |err| return unexpectedErrno(@intCast(usize, err)),
+ };
+ return mem.toSlice(u8, result_path);
+}
+
+/// Same as `realpath` except `pathname` is null-terminated and UTF16LE-encoded.
+pub fn realpathW(pathname: [*]const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
+ const h_file = try windows.CreateFileW(
+ pathname,
+ windows.GENERIC_READ,
+ windows.FILE_SHARE_READ,
+ null,
+ windows.OPEN_EXISTING,
+ windows.FILE_ATTRIBUTE_NORMAL,
+ null,
+ );
+ defer windows.CloseHandle(h_file);
+
+ var wide_buf: [windows.PATH_MAX_WIDE]u16 = undefined;
+ const wide_len = try windows.GetFinalPathNameByHandleW(h_file, &wide_buf, wide_buf.len, windows.VOLUME_NAME_DOS);
+ assert(wide_len <= wide_buf.len);
+ const wide_slice = wide_buf[0..wide_len];
+
+ // Windows returns \\?\ prepended to the path.
+ // We strip it to make this function consistent across platforms.
+ const prefix = []u16{ '\\', '\\', '?', '\\' };
+ const start_index = if (mem.startsWith(u16, wide_slice, prefix)) prefix.len else 0;
+
+ // Trust that Windows gives us valid UTF-16LE.
+ const end_index = std.unicode.utf16leToUtf8(out_buffer, wide_slice[start_index..]) catch unreachable;
+ return out_buffer[0..end_index];
+}
+
+/// Spurious wakeups are possible and no precision of timing is guaranteed.
+pub fn nanosleep(seconds: u64, nanoseconds: u64) void {
+ var req = timespec{
+ .tv_sec = math.cast(isize, seconds) catch math.maxInt(isize),
+ .tv_nsec = math.cast(isize, nanoseconds) catch math.maxInt(isize),
+ };
+ var rem: timespec = undefined;
while (true) {
- const rc = posix.kevent(kq, changelist, eventlist, timeout);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return rc,
- posix.EACCES => return BsdKEventError.AccessDenied,
- posix.EFAULT => unreachable,
- posix.EBADF => unreachable,
- posix.EINTR => continue,
- posix.EINVAL => unreachable,
- posix.ENOENT => return BsdKEventError.EventNotFound,
- posix.ENOMEM => return BsdKEventError.SystemResources,
- posix.ESRCH => return BsdKEventError.ProcessNotFound,
- else => unreachable,
+ switch (errno(system.nanosleep(&req, &rem))) {
+ EFAULT => unreachable,
+ EINVAL => {
+ // Sometimes Darwin returns EINVAL for no reason.
+ // We treat it as a spurious wakeup.
+ return;
+ },
+ EINTR => {
+ req = rem;
+ continue;
+ },
+ // This prong handles success as well as unexpected errors.
+ else => return,
}
}
}
-pub fn linuxINotifyInit1(flags: u32) !i32 {
- const rc = linux.inotify_init1(flags);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return @intCast(i32, rc),
- posix.EINVAL => unreachable,
- posix.EMFILE => return error.ProcessFdQuotaExceeded,
- posix.ENFILE => return error.SystemFdQuotaExceeded,
- posix.ENOMEM => return error.SystemResources,
- else => return unexpectedErrorPosix(err),
+pub const ClockGetTimeError = error{
+ UnsupportedClock,
+ Unexpected,
+};
+
+pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void {
+ switch (errno(system.clock_gettime(clk_id, tp))) {
+ 0 => return,
+ EFAULT => unreachable,
+ EINVAL => return error.UnsupportedClock,
+ else => |err| return unexpectedErrno(err),
}
}
-pub fn linuxINotifyAddWatchC(inotify_fd: i32, pathname: [*]const u8, mask: u32) !i32 {
- const rc = linux.inotify_add_watch(inotify_fd, pathname, mask);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return @intCast(i32, rc),
- posix.EACCES => return error.AccessDenied,
- posix.EBADF => unreachable,
- posix.EFAULT => unreachable,
- posix.EINVAL => unreachable,
- posix.ENAMETOOLONG => return error.NameTooLong,
- posix.ENOENT => return error.FileNotFound,
- posix.ENOMEM => return error.SystemResources,
- posix.ENOSPC => return error.UserResourceLimitReached,
- else => return unexpectedErrorPosix(err),
+pub fn clock_getres(clk_id: i32, res: *timespec) ClockGetTimeError!void {
+ switch (errno(system.clock_getres(clk_id, res))) {
+ 0 => return,
+ EFAULT => unreachable,
+ EINVAL => return error.UnsupportedClock,
+ else => |err| return unexpectedErrno(err),
}
}
-pub fn linuxINotifyRmWatch(inotify_fd: i32, wd: i32) !void {
- const rc = linux.inotify_rm_watch(inotify_fd, wd);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return rc,
- posix.EBADF => unreachable,
- posix.EINVAL => unreachable,
- else => unreachable,
+pub const SchedGetAffinityError = error{
+ PermissionDenied,
+ Unexpected,
+};
+
+pub fn sched_getaffinity(pid: pid_t) SchedGetAffinityError!cpu_set_t {
+ var set: cpu_set_t = undefined;
+ switch (errno(system.sched_getaffinity(pid, @sizeOf(cpu_set_t), &set))) {
+ 0 => return set,
+ EFAULT => unreachable,
+ EINVAL => unreachable,
+ ESRCH => unreachable,
+ EPERM => return error.PermissionDenied,
+ else => |err| return unexpectedErrno(err),
}
}
-pub const MProtectError = error{
- AccessDenied,
- OutOfMemory,
+/// Used to convert a slice to a null terminated slice on the stack.
+/// TODO https://github.com/ziglang/zig/issues/287
+pub fn toPosixPath(file_path: []const u8) ![PATH_MAX]u8 {
+ var path_with_null: [PATH_MAX]u8 = undefined;
+ // >= rather than > to make room for the null byte
+ if (file_path.len >= PATH_MAX) return error.NameTooLong;
+ mem.copy(u8, &path_with_null, file_path);
+ path_with_null[file_path.len] = 0;
+ return path_with_null;
+}
+
+/// Whether or not error.Unexpected will print its value and a stack trace.
+/// if this happens the fix is to add the error code to the corresponding
+/// switch expression, possibly introduce a new error in the error set, and
+/// send a patch to Zig.
+pub const unexpected_error_tracing = builtin.mode == .Debug;
+
+pub const UnexpectedError = error{
+ /// The Operating System returned an undocumented error code.
+ /// This error is in theory not possible, but it would be better
+ /// to handle this error than to invoke undefined behavior.
Unexpected,
};
-/// address and length must be page-aligned
-pub fn posixMProtect(address: usize, length: usize, protection: u32) MProtectError!void {
- const negative_page_size = @bitCast(usize, -isize(page_size));
- const aligned_address = address & negative_page_size;
- const aligned_end = (address + length + page_size - 1) & negative_page_size;
- assert(address == aligned_address);
- assert(length == aligned_end - aligned_address);
- const rc = posix.mprotect(address, length, protection);
- const err = posix.getErrno(rc);
- switch (err) {
- 0 => return,
- posix.EINVAL => unreachable,
- posix.EACCES => return error.AccessDenied,
- posix.ENOMEM => return error.OutOfMemory,
- else => return unexpectedErrorPosix(err),
+/// Call this when you made a syscall or something that sets errno
+/// and you get an unexpected error.
+pub fn unexpectedErrno(err: usize) UnexpectedError {
+ if (unexpected_error_tracing) {
+ std.debug.warn("unexpected errno: {}\n", err);
+ std.debug.dumpCurrentStackTrace(null);
}
+ return error.Unexpected;
+}
+
+test "" {
+ _ = @import("os/darwin.zig");
+ _ = @import("os/freebsd.zig");
+ _ = @import("os/linux.zig");
+ _ = @import("os/netbsd.zig");
+ _ = @import("os/uefi.zig");
+ _ = @import("os/wasi.zig");
+ _ = @import("os/windows.zig");
+ _ = @import("os/zen.zig");
+
+ _ = @import("os/test.zig");
}
diff --git a/std/os/bits.zig b/std/os/bits.zig
new file mode 100644
index 0000000000..7b87cc6e4d
--- /dev/null
+++ b/std/os/bits.zig
@@ -0,0 +1,27 @@
+// Platform-dependent types and values that are used along with OS-specific APIs.
+// These are imported into `std.c`, `std.os`, and `std.os.linux`.
+
+const builtin = @import("builtin");
+
+pub use switch (builtin.os) {
+ .macosx, .ios, .tvos, .watchos => @import("bits/darwin.zig"),
+ .freebsd => @import("bits/freebsd.zig"),
+ .linux => @import("bits/linux.zig"),
+ .netbsd => @import("bits/netbsd.zig"),
+ .wasi => @import("bits/wasi.zig"),
+ .windows => @import("bits/windows.zig"),
+ else => struct {},
+};
+
+pub const pthread_t = *@OpaqueType();
+pub const FILE = @OpaqueType();
+
+pub const iovec = extern struct {
+ iov_base: [*]u8,
+ iov_len: usize,
+};
+
+pub const iovec_const = extern struct {
+ iov_base: [*]const u8,
+ iov_len: usize,
+};
diff --git a/std/os/bits/darwin.zig b/std/os/bits/darwin.zig
new file mode 100644
index 0000000000..a685735da0
--- /dev/null
+++ b/std/os/bits/darwin.zig
@@ -0,0 +1,1080 @@
+const std = @import("../../std.zig");
+const assert = std.debug.assert;
+const maxInt = std.math.maxInt;
+
+pub const fd_t = c_int;
+pub const pid_t = c_int;
+
+pub const in_port_t = u16;
+pub const sa_family_t = u8;
+pub const socklen_t = u32;
+pub const sockaddr = extern union {
+ in: sockaddr_in,
+ in6: sockaddr_in6,
+};
+pub const sockaddr_in = extern struct {
+ len: u8,
+ family: sa_family_t,
+ port: in_port_t,
+ addr: u32,
+ zero: [8]u8,
+};
+pub const sockaddr_in6 = extern struct {
+ len: u8,
+ family: sa_family_t,
+ port: in_port_t,
+ flowinfo: u32,
+ addr: [16]u8,
+ scope_id: u32,
+};
+
+pub const timeval = extern struct {
+ tv_sec: c_long,
+ tv_usec: i32,
+};
+
+pub const timezone = extern struct {
+ tz_minuteswest: i32,
+ tz_dsttime: i32,
+};
+
+pub const mach_timebase_info_data = extern struct {
+ numer: u32,
+ denom: u32,
+};
+
+/// Renamed to Stat to not conflict with the stat function.
+pub const Stat = extern struct {
+ dev: i32,
+ mode: u16,
+ nlink: u16,
+ ino: u64,
+ uid: u32,
+ gid: u32,
+ rdev: i32,
+ atime: usize,
+ atimensec: usize,
+ mtime: usize,
+ mtimensec: usize,
+ ctime: usize,
+ ctimensec: usize,
+ birthtime: usize,
+ birthtimensec: usize,
+ size: i64,
+ blocks: i64,
+ blksize: i32,
+ flags: u32,
+ gen: u32,
+ lspare: i32,
+ qspare: [2]i64,
+};
+
+pub const timespec = extern struct {
+ tv_sec: isize,
+ tv_nsec: isize,
+};
+
+pub const sigset_t = u32;
+pub const empty_sigset = sigset_t(0);
+
+/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.
+pub const Sigaction = extern struct {
+ handler: extern fn (c_int) void,
+ sa_mask: sigset_t,
+ sa_flags: c_int,
+};
+
+pub const dirent = extern struct {
+ d_ino: usize,
+ d_seekoff: usize,
+ d_reclen: u16,
+ d_namlen: u16,
+ d_type: u8,
+ d_name: u8, // field address is address of first byte of name
+};
+
+pub const pthread_attr_t = extern struct {
+ __sig: c_long,
+ __opaque: [56]u8,
+};
+
+/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
+pub const Kevent = extern struct {
+ ident: usize,
+ filter: i16,
+ flags: u16,
+ fflags: u32,
+ data: isize,
+ udata: usize,
+};
+
+// sys/types.h on macos uses #pragma pack(4) so these checks are
+// to make sure the struct is laid out the same. These values were
+// produced from C code using the offsetof macro.
+comptime {
+ assert(@byteOffsetOf(Kevent, "ident") == 0);
+ assert(@byteOffsetOf(Kevent, "filter") == 8);
+ assert(@byteOffsetOf(Kevent, "flags") == 10);
+ assert(@byteOffsetOf(Kevent, "fflags") == 12);
+ assert(@byteOffsetOf(Kevent, "data") == 16);
+ assert(@byteOffsetOf(Kevent, "udata") == 24);
+}
+
+pub const kevent64_s = extern struct {
+ ident: u64,
+ filter: i16,
+ flags: u16,
+ fflags: u32,
+ data: i64,
+ udata: u64,
+ ext: [2]u64,
+};
+
+// sys/types.h on macos uses #pragma pack() so these checks are
+// to make sure the struct is laid out the same. These values were
+// produced from C code using the offsetof macro.
+comptime {
+ assert(@byteOffsetOf(kevent64_s, "ident") == 0);
+ assert(@byteOffsetOf(kevent64_s, "filter") == 8);
+ assert(@byteOffsetOf(kevent64_s, "flags") == 10);
+ assert(@byteOffsetOf(kevent64_s, "fflags") == 12);
+ assert(@byteOffsetOf(kevent64_s, "data") == 16);
+ assert(@byteOffsetOf(kevent64_s, "udata") == 24);
+ assert(@byteOffsetOf(kevent64_s, "ext") == 32);
+}
+
+pub const mach_port_t = c_uint;
+pub const clock_serv_t = mach_port_t;
+pub const clock_res_t = c_int;
+pub const mach_port_name_t = natural_t;
+pub const natural_t = c_uint;
+pub const mach_timespec_t = extern struct {
+ tv_sec: c_uint,
+ tv_nsec: clock_res_t,
+};
+pub const kern_return_t = c_int;
+pub const host_t = mach_port_t;
+pub const CALENDAR_CLOCK = 1;
+
+pub const PATH_MAX = 1024;
+
+pub const STDIN_FILENO = 0;
+pub const STDOUT_FILENO = 1;
+pub const STDERR_FILENO = 2;
+
+/// [MC2] no permissions
+pub const PROT_NONE = 0x00;
+
+/// [MC2] pages can be read
+pub const PROT_READ = 0x01;
+
+/// [MC2] pages can be written
+pub const PROT_WRITE = 0x02;
+
+/// [MC2] pages can be executed
+pub const PROT_EXEC = 0x04;
+
+/// allocated from memory, swap space
+pub const MAP_ANONYMOUS = 0x1000;
+
+/// map from file (default)
+pub const MAP_FILE = 0x0000;
+
+/// interpret addr exactly
+pub const MAP_FIXED = 0x0010;
+
+/// region may contain semaphores
+pub const MAP_HASSEMAPHORE = 0x0200;
+
+/// changes are private
+pub const MAP_PRIVATE = 0x0002;
+
+/// share changes
+pub const MAP_SHARED = 0x0001;
+
+/// don't cache pages for this mapping
+pub const MAP_NOCACHE = 0x0400;
+
+/// don't reserve needed swap area
+pub const MAP_NORESERVE = 0x0040;
+pub const MAP_FAILED = @intToPtr(*c_void, maxInt(usize));
+
+/// [XSI] no hang in wait/no child to reap
+pub const WNOHANG = 0x00000001;
+
+/// [XSI] notify on stop, untraced child
+pub const WUNTRACED = 0x00000002;
+
+/// take signal on signal stack
+pub const SA_ONSTACK = 0x0001;
+
+/// restart system on signal return
+pub const SA_RESTART = 0x0002;
+
+/// reset to SIG_DFL when taking signal
+pub const SA_RESETHAND = 0x0004;
+
+/// do not generate SIGCHLD on child stop
+pub const SA_NOCLDSTOP = 0x0008;
+
+/// don't mask the signal we're delivering
+pub const SA_NODEFER = 0x0010;
+
+/// don't keep zombies around
+pub const SA_NOCLDWAIT = 0x0020;
+
+/// signal handler with SA_SIGINFO args
+pub const SA_SIGINFO = 0x0040;
+
+/// do not bounce off kernel's sigtramp
+pub const SA_USERTRAMP = 0x0100;
+
+/// signal handler with SA_SIGINFO args with 64bit regs information
+pub const SA_64REGSET = 0x0200;
+
+pub const O_LARGEFILE = 0x0000;
+pub const O_PATH = 0x0000;
+
+pub const F_OK = 0;
+pub const X_OK = 1;
+pub const W_OK = 2;
+pub const R_OK = 4;
+
+/// open for reading only
+pub const O_RDONLY = 0x0000;
+
+/// open for writing only
+pub const O_WRONLY = 0x0001;
+
+/// open for reading and writing
+pub const O_RDWR = 0x0002;
+
+/// do not block on open or for data to become available
+pub const O_NONBLOCK = 0x0004;
+
+/// append on each write
+pub const O_APPEND = 0x0008;
+
+/// create file if it does not exist
+pub const O_CREAT = 0x0200;
+
+/// truncate size to 0
+pub const O_TRUNC = 0x0400;
+
+/// error if O_CREAT and the file exists
+pub const O_EXCL = 0x0800;
+
+/// atomically obtain a shared lock
+pub const O_SHLOCK = 0x0010;
+
+/// atomically obtain an exclusive lock
+pub const O_EXLOCK = 0x0020;
+
+/// do not follow symlinks
+pub const O_NOFOLLOW = 0x0100;
+
+/// allow open of symlinks
+pub const O_SYMLINK = 0x200000;
+
+/// descriptor requested for event notifications only
+pub const O_EVTONLY = 0x8000;
+
+/// mark as close-on-exec
+pub const O_CLOEXEC = 0x1000000;
+
+pub const O_ACCMODE = 3;
+pub const O_ALERT = 536870912;
+pub const O_ASYNC = 64;
+pub const O_DIRECTORY = 1048576;
+pub const O_DP_GETRAWENCRYPTED = 1;
+pub const O_DP_GETRAWUNENCRYPTED = 2;
+pub const O_DSYNC = 4194304;
+pub const O_FSYNC = O_SYNC;
+pub const O_NOCTTY = 131072;
+pub const O_POPUP = 2147483648;
+pub const O_SYNC = 128;
+
+pub const SEEK_SET = 0x0;
+pub const SEEK_CUR = 0x1;
+pub const SEEK_END = 0x2;
+
+pub const DT_UNKNOWN = 0;
+pub const DT_FIFO = 1;
+pub const DT_CHR = 2;
+pub const DT_DIR = 4;
+pub const DT_BLK = 6;
+pub const DT_REG = 8;
+pub const DT_LNK = 10;
+pub const DT_SOCK = 12;
+pub const DT_WHT = 14;
+
+/// block specified signal set
+pub const SIG_BLOCK = 1;
+
+/// unblock specified signal set
+pub const SIG_UNBLOCK = 2;
+
+/// set specified signal set
+pub const SIG_SETMASK = 3;
+
+/// hangup
+pub const SIGHUP = 1;
+
+/// interrupt
+pub const SIGINT = 2;
+
+/// quit
+pub const SIGQUIT = 3;
+
+/// illegal instruction (not reset when caught)
+pub const SIGILL = 4;
+
+/// trace trap (not reset when caught)
+pub const SIGTRAP = 5;
+
+/// abort()
+pub const SIGABRT = 6;
+
+/// pollable event ([XSR] generated, not supported)
+pub const SIGPOLL = 7;
+
+/// compatibility
+pub const SIGIOT = SIGABRT;
+
+/// EMT instruction
+pub const SIGEMT = 7;
+
+/// floating point exception
+pub const SIGFPE = 8;
+
+/// kill (cannot be caught or ignored)
+pub const SIGKILL = 9;
+
+/// bus error
+pub const SIGBUS = 10;
+
+/// segmentation violation
+pub const SIGSEGV = 11;
+
+/// bad argument to system call
+pub const SIGSYS = 12;
+
+/// write on a pipe with no one to read it
+pub const SIGPIPE = 13;
+
+/// alarm clock
+pub const SIGALRM = 14;
+
+/// software termination signal from kill
+pub const SIGTERM = 15;
+
+/// urgent condition on IO channel
+pub const SIGURG = 16;
+
+/// sendable stop signal not from tty
+pub const SIGSTOP = 17;
+
+/// stop signal from tty
+pub const SIGTSTP = 18;
+
+/// continue a stopped process
+pub const SIGCONT = 19;
+
+/// to parent on child stop or exit
+pub const SIGCHLD = 20;
+
+/// to readers pgrp upon background tty read
+pub const SIGTTIN = 21;
+
+/// like TTIN for output if (tp->t_local&LTOSTOP)
+pub const SIGTTOU = 22;
+
+/// input/output possible signal
+pub const SIGIO = 23;
+
+/// exceeded CPU time limit
+pub const SIGXCPU = 24;
+
+/// exceeded file size limit
+pub const SIGXFSZ = 25;
+
+/// virtual time alarm
+pub const SIGVTALRM = 26;
+
+/// profiling time alarm
+pub const SIGPROF = 27;
+
+/// window size changes
+pub const SIGWINCH = 28;
+
+/// information request
+pub const SIGINFO = 29;
+
+/// user defined signal 1
+pub const SIGUSR1 = 30;
+
+/// user defined signal 2
+pub const SIGUSR2 = 31;
+
+/// no flag value
+pub const KEVENT_FLAG_NONE = 0x000;
+
+/// immediate timeout
+pub const KEVENT_FLAG_IMMEDIATE = 0x001;
+
+/// output events only include change
+pub const KEVENT_FLAG_ERROR_EVENTS = 0x002;
+
+/// add event to kq (implies enable)
+pub const EV_ADD = 0x0001;
+
+/// delete event from kq
+pub const EV_DELETE = 0x0002;
+
+/// enable event
+pub const EV_ENABLE = 0x0004;
+
+/// disable event (not reported)
+pub const EV_DISABLE = 0x0008;
+
+/// only report one occurrence
+pub const EV_ONESHOT = 0x0010;
+
+/// clear event state after reporting
+pub const EV_CLEAR = 0x0020;
+
+/// force immediate event output
+/// ... with or without EV_ERROR
+/// ... use KEVENT_FLAG_ERROR_EVENTS
+/// on syscalls supporting flags
+pub const EV_RECEIPT = 0x0040;
+
+/// disable event after reporting
+pub const EV_DISPATCH = 0x0080;
+
+/// unique kevent per udata value
+pub const EV_UDATA_SPECIFIC = 0x0100;
+
+/// ... in combination with EV_DELETE
+/// will defer delete until udata-specific
+/// event enabled. EINPROGRESS will be
+/// returned to indicate the deferral
+pub const EV_DISPATCH2 = EV_DISPATCH | EV_UDATA_SPECIFIC;
+
+/// report that source has vanished
+/// ... only valid with EV_DISPATCH2
+pub const EV_VANISHED = 0x0200;
+
+/// reserved by system
+pub const EV_SYSFLAGS = 0xF000;
+
+/// filter-specific flag
+pub const EV_FLAG0 = 0x1000;
+
+/// filter-specific flag
+pub const EV_FLAG1 = 0x2000;
+
+/// EOF detected
+pub const EV_EOF = 0x8000;
+
+/// error, data contains errno
+pub const EV_ERROR = 0x4000;
+
+pub const EV_POLL = EV_FLAG0;
+pub const EV_OOBAND = EV_FLAG1;
+
+pub const EVFILT_READ = -1;
+pub const EVFILT_WRITE = -2;
+
+/// attached to aio requests
+pub const EVFILT_AIO = -3;
+
+/// attached to vnodes
+pub const EVFILT_VNODE = -4;
+
+/// attached to struct proc
+pub const EVFILT_PROC = -5;
+
+/// attached to struct proc
+pub const EVFILT_SIGNAL = -6;
+
+/// timers
+pub const EVFILT_TIMER = -7;
+
+/// Mach portsets
+pub const EVFILT_MACHPORT = -8;
+
+/// Filesystem events
+pub const EVFILT_FS = -9;
+
+/// User events
+pub const EVFILT_USER = -10;
+
+/// Virtual memory events
+pub const EVFILT_VM = -12;
+
+/// Exception events
+pub const EVFILT_EXCEPT = -15;
+
+pub const EVFILT_SYSCOUNT = 17;
+
+/// On input, NOTE_TRIGGER causes the event to be triggered for output.
+pub const NOTE_TRIGGER = 0x01000000;
+
+/// ignore input fflags
+pub const NOTE_FFNOP = 0x00000000;
+
+/// and fflags
+pub const NOTE_FFAND = 0x40000000;
+
+/// or fflags
+pub const NOTE_FFOR = 0x80000000;
+
+/// copy fflags
+pub const NOTE_FFCOPY = 0xc0000000;
+
+/// mask for operations
+pub const NOTE_FFCTRLMASK = 0xc0000000;
+pub const NOTE_FFLAGSMASK = 0x00ffffff;
+
+/// low water mark
+pub const NOTE_LOWAT = 0x00000001;
+
+/// OOB data
+pub const NOTE_OOB = 0x00000002;
+
+/// vnode was removed
+pub const NOTE_DELETE = 0x00000001;
+
+/// data contents changed
+pub const NOTE_WRITE = 0x00000002;
+
+/// size increased
+pub const NOTE_EXTEND = 0x00000004;
+
+/// attributes changed
+pub const NOTE_ATTRIB = 0x00000008;
+
+/// link count changed
+pub const NOTE_LINK = 0x00000010;
+
+/// vnode was renamed
+pub const NOTE_RENAME = 0x00000020;
+
+/// vnode access was revoked
+pub const NOTE_REVOKE = 0x00000040;
+
+/// No specific vnode event: to test for EVFILT_READ activation
+pub const NOTE_NONE = 0x00000080;
+
+/// vnode was unlocked by flock(2)
+pub const NOTE_FUNLOCK = 0x00000100;
+
+/// process exited
+pub const NOTE_EXIT = 0x80000000;
+
+/// process forked
+pub const NOTE_FORK = 0x40000000;
+
+/// process exec'd
+pub const NOTE_EXEC = 0x20000000;
+
+/// shared with EVFILT_SIGNAL
+pub const NOTE_SIGNAL = 0x08000000;
+
+/// exit status to be returned, valid for child process only
+pub const NOTE_EXITSTATUS = 0x04000000;
+
+/// provide details on reasons for exit
+pub const NOTE_EXIT_DETAIL = 0x02000000;
+
+/// mask for signal & exit status
+pub const NOTE_PDATAMASK = 0x000fffff;
+pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK);
+
+pub const NOTE_EXIT_DETAIL_MASK = 0x00070000;
+pub const NOTE_EXIT_DECRYPTFAIL = 0x00010000;
+pub const NOTE_EXIT_MEMORY = 0x00020000;
+pub const NOTE_EXIT_CSERROR = 0x00040000;
+
+/// will react on memory pressure
+pub const NOTE_VM_PRESSURE = 0x80000000;
+
+/// will quit on memory pressure, possibly after cleaning up dirty state
+pub const NOTE_VM_PRESSURE_TERMINATE = 0x40000000;
+
+/// will quit immediately on memory pressure
+pub const NOTE_VM_PRESSURE_SUDDEN_TERMINATE = 0x20000000;
+
+/// there was an error
+pub const NOTE_VM_ERROR = 0x10000000;
+
+/// data is seconds
+pub const NOTE_SECONDS = 0x00000001;
+
+/// data is microseconds
+pub const NOTE_USECONDS = 0x00000002;
+
+/// data is nanoseconds
+pub const NOTE_NSECONDS = 0x00000004;
+
+/// absolute timeout
+pub const NOTE_ABSOLUTE = 0x00000008;
+
+/// ext[1] holds leeway for power aware timers
+pub const NOTE_LEEWAY = 0x00000010;
+
+/// system does minimal timer coalescing
+pub const NOTE_CRITICAL = 0x00000020;
+
+/// system does maximum timer coalescing
+pub const NOTE_BACKGROUND = 0x00000040;
+pub const NOTE_MACH_CONTINUOUS_TIME = 0x00000080;
+
+/// data is mach absolute time units
+pub const NOTE_MACHTIME = 0x00000100;
+
+pub const AF_UNSPEC = 0;
+pub const AF_LOCAL = 1;
+pub const AF_UNIX = AF_LOCAL;
+pub const AF_INET = 2;
+pub const AF_SYS_CONTROL = 2;
+pub const AF_IMPLINK = 3;
+pub const AF_PUP = 4;
+pub const AF_CHAOS = 5;
+pub const AF_NS = 6;
+pub const AF_ISO = 7;
+pub const AF_OSI = AF_ISO;
+pub const AF_ECMA = 8;
+pub const AF_DATAKIT = 9;
+pub const AF_CCITT = 10;
+pub const AF_SNA = 11;
+pub const AF_DECnet = 12;
+pub const AF_DLI = 13;
+pub const AF_LAT = 14;
+pub const AF_HYLINK = 15;
+pub const AF_APPLETALK = 16;
+pub const AF_ROUTE = 17;
+pub const AF_LINK = 18;
+pub const AF_XTP = 19;
+pub const AF_COIP = 20;
+pub const AF_CNT = 21;
+pub const AF_RTIP = 22;
+pub const AF_IPX = 23;
+pub const AF_SIP = 24;
+pub const AF_PIP = 25;
+pub const AF_ISDN = 28;
+pub const AF_E164 = AF_ISDN;
+pub const AF_KEY = 29;
+pub const AF_INET6 = 30;
+pub const AF_NATM = 31;
+pub const AF_SYSTEM = 32;
+pub const AF_NETBIOS = 33;
+pub const AF_PPP = 34;
+pub const AF_MAX = 40;
+
+pub const PF_UNSPEC = AF_UNSPEC;
+pub const PF_LOCAL = AF_LOCAL;
+pub const PF_UNIX = PF_LOCAL;
+pub const PF_INET = AF_INET;
+pub const PF_IMPLINK = AF_IMPLINK;
+pub const PF_PUP = AF_PUP;
+pub const PF_CHAOS = AF_CHAOS;
+pub const PF_NS = AF_NS;
+pub const PF_ISO = AF_ISO;
+pub const PF_OSI = AF_ISO;
+pub const PF_ECMA = AF_ECMA;
+pub const PF_DATAKIT = AF_DATAKIT;
+pub const PF_CCITT = AF_CCITT;
+pub const PF_SNA = AF_SNA;
+pub const PF_DECnet = AF_DECnet;
+pub const PF_DLI = AF_DLI;
+pub const PF_LAT = AF_LAT;
+pub const PF_HYLINK = AF_HYLINK;
+pub const PF_APPLETALK = AF_APPLETALK;
+pub const PF_ROUTE = AF_ROUTE;
+pub const PF_LINK = AF_LINK;
+pub const PF_XTP = AF_XTP;
+pub const PF_COIP = AF_COIP;
+pub const PF_CNT = AF_CNT;
+pub const PF_SIP = AF_SIP;
+pub const PF_IPX = AF_IPX;
+pub const PF_RTIP = AF_RTIP;
+pub const PF_PIP = AF_PIP;
+pub const PF_ISDN = AF_ISDN;
+pub const PF_KEY = AF_KEY;
+pub const PF_INET6 = AF_INET6;
+pub const PF_NATM = AF_NATM;
+pub const PF_SYSTEM = AF_SYSTEM;
+pub const PF_NETBIOS = AF_NETBIOS;
+pub const PF_PPP = AF_PPP;
+pub const PF_MAX = AF_MAX;
+
+pub const SYSPROTO_EVENT = 1;
+pub const SYSPROTO_CONTROL = 2;
+
+pub const SOCK_STREAM = 1;
+pub const SOCK_DGRAM = 2;
+pub const SOCK_RAW = 3;
+pub const SOCK_RDM = 4;
+pub const SOCK_SEQPACKET = 5;
+pub const SOCK_MAXADDRLEN = 255;
+
+pub const IPPROTO_ICMP = 1;
+pub const IPPROTO_ICMPV6 = 58;
+pub const IPPROTO_TCP = 6;
+pub const IPPROTO_UDP = 17;
+pub const IPPROTO_IP = 0;
+pub const IPPROTO_IPV6 = 41;
+
+fn wstatus(x: u32) u32 {
+ return x & 0o177;
+}
+const wstopped = 0o177;
+pub fn WEXITSTATUS(x: u32) u32 {
+ return x >> 8;
+}
+pub fn WTERMSIG(x: u32) u32 {
+ return wstatus(x);
+}
+pub fn WSTOPSIG(x: u32) u32 {
+ return x >> 8;
+}
+pub fn WIFEXITED(x: u32) bool {
+ return wstatus(x) == 0;
+}
+pub fn WIFSTOPPED(x: u32) bool {
+ return wstatus(x) == wstopped and WSTOPSIG(x) != 0x13;
+}
+pub fn WIFSIGNALED(x: u32) bool {
+ return wstatus(x) != wstopped and wstatus(x) != 0;
+}
+
+/// Operation not permitted
+pub const EPERM = 1;
+
+/// No such file or directory
+pub const ENOENT = 2;
+
+/// No such process
+pub const ESRCH = 3;
+
+/// Interrupted system call
+pub const EINTR = 4;
+
+/// Input/output error
+pub const EIO = 5;
+
+/// Device not configured
+pub const ENXIO = 6;
+
+/// Argument list too long
+pub const E2BIG = 7;
+
+/// Exec format error
+pub const ENOEXEC = 8;
+
+/// Bad file descriptor
+pub const EBADF = 9;
+
+/// No child processes
+pub const ECHILD = 10;
+
+/// Resource deadlock avoided
+pub const EDEADLK = 11;
+
+/// Cannot allocate memory
+pub const ENOMEM = 12;
+
+/// Permission denied
+pub const EACCES = 13;
+
+/// Bad address
+pub const EFAULT = 14;
+
+/// Block device required
+pub const ENOTBLK = 15;
+
+/// Device / Resource busy
+pub const EBUSY = 16;
+
+/// File exists
+pub const EEXIST = 17;
+
+/// Cross-device link
+pub const EXDEV = 18;
+
+/// Operation not supported by device
+pub const ENODEV = 19;
+
+/// Not a directory
+pub const ENOTDIR = 20;
+
+/// Is a directory
+pub const EISDIR = 21;
+
+/// Invalid argument
+pub const EINVAL = 22;
+
+/// Too many open files in system
+pub const ENFILE = 23;
+
+/// Too many open files
+pub const EMFILE = 24;
+
+/// Inappropriate ioctl for device
+pub const ENOTTY = 25;
+
+/// Text file busy
+pub const ETXTBSY = 26;
+
+/// File too large
+pub const EFBIG = 27;
+
+/// No space left on device
+pub const ENOSPC = 28;
+
+/// Illegal seek
+pub const ESPIPE = 29;
+
+/// Read-only file system
+pub const EROFS = 30;
+
+/// Too many links
+pub const EMLINK = 31;
+/// Broken pipe
+
+// math software
+pub const EPIPE = 32;
+
+/// Numerical argument out of domain
+pub const EDOM = 33;
+/// Result too large
+
+// non-blocking and interrupt i/o
+pub const ERANGE = 34;
+
+/// Resource temporarily unavailable
+pub const EAGAIN = 35;
+
+/// Operation would block
+pub const EWOULDBLOCK = EAGAIN;
+
+/// Operation now in progress
+pub const EINPROGRESS = 36;
+/// Operation already in progress
+
+// ipc/network software -- argument errors
+pub const EALREADY = 37;
+
+/// Socket operation on non-socket
+pub const ENOTSOCK = 38;
+
+/// Destination address required
+pub const EDESTADDRREQ = 39;
+
+/// Message too long
+pub const EMSGSIZE = 40;
+
+/// Protocol wrong type for socket
+pub const EPROTOTYPE = 41;
+
+/// Protocol not available
+pub const ENOPROTOOPT = 42;
+
+/// Protocol not supported
+pub const EPROTONOSUPPORT = 43;
+
+/// Socket type not supported
+pub const ESOCKTNOSUPPORT = 44;
+
+/// Operation not supported
+pub const ENOTSUP = 45;
+
+/// Protocol family not supported
+pub const EPFNOSUPPORT = 46;
+
+/// Address family not supported by protocol family
+pub const EAFNOSUPPORT = 47;
+
+/// Address already in use
+pub const EADDRINUSE = 48;
+/// Can't assign requested address
+
+// ipc/network software -- operational errors
+pub const EADDRNOTAVAIL = 49;
+
+/// Network is down
+pub const ENETDOWN = 50;
+
+/// Network is unreachable
+pub const ENETUNREACH = 51;
+
+/// Network dropped connection on reset
+pub const ENETRESET = 52;
+
+/// Software caused connection abort
+pub const ECONNABORTED = 53;
+
+/// Connection reset by peer
+pub const ECONNRESET = 54;
+
+/// No buffer space available
+pub const ENOBUFS = 55;
+
+/// Socket is already connected
+pub const EISCONN = 56;
+
+/// Socket is not connected
+pub const ENOTCONN = 57;
+
+/// Can't send after socket shutdown
+pub const ESHUTDOWN = 58;
+
+/// Too many references: can't splice
+pub const ETOOMANYREFS = 59;
+
+/// Operation timed out
+pub const ETIMEDOUT = 60;
+
+/// Connection refused
+pub const ECONNREFUSED = 61;
+
+/// Too many levels of symbolic links
+pub const ELOOP = 62;
+
+/// File name too long
+pub const ENAMETOOLONG = 63;
+
+/// Host is down
+pub const EHOSTDOWN = 64;
+
+/// No route to host
+pub const EHOSTUNREACH = 65;
+/// Directory not empty
+
+// quotas & mush
+pub const ENOTEMPTY = 66;
+
+/// Too many processes
+pub const EPROCLIM = 67;
+
+/// Too many users
+pub const EUSERS = 68;
+/// Disc quota exceeded
+
+// Network File System
+pub const EDQUOT = 69;
+
+/// Stale NFS file handle
+pub const ESTALE = 70;
+
+/// Too many levels of remote in path
+pub const EREMOTE = 71;
+
+/// RPC struct is bad
+pub const EBADRPC = 72;
+
+/// RPC version wrong
+pub const ERPCMISMATCH = 73;
+
+/// RPC prog. not avail
+pub const EPROGUNAVAIL = 74;
+
+/// Program version wrong
+pub const EPROGMISMATCH = 75;
+
+/// Bad procedure for program
+pub const EPROCUNAVAIL = 76;
+
+/// No locks available
+pub const ENOLCK = 77;
+
+/// Function not implemented
+pub const ENOSYS = 78;
+
+/// Inappropriate file type or format
+pub const EFTYPE = 79;
+
+/// Authentication error
+pub const EAUTH = 80;
+/// Need authenticator
+
+// Intelligent device errors
+pub const ENEEDAUTH = 81;
+
+/// Device power is off
+pub const EPWROFF = 82;
+
+/// Device error, e.g. paper out
+pub const EDEVERR = 83;
+/// Value too large to be stored in data type
+
+// Program loading errors
+pub const EOVERFLOW = 84;
+
+/// Bad executable
+pub const EBADEXEC = 85;
+
+/// Bad CPU type in executable
+pub const EBADARCH = 86;
+
+/// Shared library version mismatch
+pub const ESHLIBVERS = 87;
+
+/// Malformed Macho file
+pub const EBADMACHO = 88;
+
+/// Operation canceled
+pub const ECANCELED = 89;
+
+/// Identifier removed
+pub const EIDRM = 90;
+
+/// No message of desired type
+pub const ENOMSG = 91;
+
+/// Illegal byte sequence
+pub const EILSEQ = 92;
+
+/// Attribute not found
+pub const ENOATTR = 93;
+
+/// Bad message
+pub const EBADMSG = 94;
+
+/// Reserved
+pub const EMULTIHOP = 95;
+
+/// No message available on STREAM
+pub const ENODATA = 96;
+
+/// Reserved
+pub const ENOLINK = 97;
+
+/// No STREAM resources
+pub const ENOSR = 98;
+
+/// Not a STREAM
+pub const ENOSTR = 99;
+
+/// Protocol error
+pub const EPROTO = 100;
+
+/// STREAM ioctl timeout
+pub const ETIME = 101;
+
+/// No such policy registered
+pub const ENOPOLICY = 103;
+
+/// State not recoverable
+pub const ENOTRECOVERABLE = 104;
+
+/// Previous owner died
+pub const EOWNERDEAD = 105;
+
+/// Interface output queue is full
+pub const EQFULL = 106;
+
+/// Must be equal largest errno
+pub const ELAST = 106;
diff --git a/std/os/bits/freebsd.zig b/std/os/bits/freebsd.zig
new file mode 100644
index 0000000000..1925b75f3f
--- /dev/null
+++ b/std/os/bits/freebsd.zig
@@ -0,0 +1,837 @@
+const std = @import("../../std.zig");
+const maxInt = std.math.maxInt;
+
+pub const fd_t = c_int;
+pub const pid_t = c_int;
+
+/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
+pub const Kevent = extern struct {
+ ident: usize,
+ filter: i16,
+ flags: u16,
+ fflags: u32,
+ data: i64,
+ udata: usize,
+ // TODO ext
+};
+
+pub const pthread_attr_t = extern struct {
+ __size: [56]u8,
+ __align: c_long,
+};
+
+pub const msghdr = extern struct {
+ /// optional address
+ msg_name: ?*sockaddr,
+
+ /// size of address
+ msg_namelen: socklen_t,
+
+ /// scatter/gather array
+ msg_iov: [*]iovec,
+
+ /// # elements in msg_iov
+ msg_iovlen: i32,
+
+ /// ancillary data
+ msg_control: ?*c_void,
+
+ /// ancillary data buffer len
+ msg_controllen: socklen_t,
+
+ /// flags on received message
+ msg_flags: i32,
+};
+
+pub const msghdr_const = extern struct {
+ /// optional address
+ msg_name: ?*const sockaddr,
+
+ /// size of address
+ msg_namelen: socklen_t,
+
+ /// scatter/gather array
+ msg_iov: [*]iovec_const,
+
+ /// # elements in msg_iov
+ msg_iovlen: i32,
+
+ /// ancillary data
+ msg_control: ?*c_void,
+
+ /// ancillary data buffer len
+ msg_controllen: socklen_t,
+
+ /// flags on received message
+ msg_flags: i32,
+};
+
+pub const Stat = extern struct {
+ dev: u64,
+ ino: u64,
+ nlink: usize,
+
+ mode: u16,
+ __pad0: u16,
+ uid: u32,
+ gid: u32,
+ __pad1: u32,
+ rdev: u64,
+
+ atim: timespec,
+ mtim: timespec,
+ ctim: timespec,
+ birthtim: timespec,
+
+ size: i64,
+ blocks: i64,
+ blksize: isize,
+ flags: u32,
+ gen: u64,
+ __spare: [10]u64,
+};
+
+pub const timespec = extern struct {
+ tv_sec: isize,
+ tv_nsec: isize,
+};
+
+pub const dirent = extern struct {
+ d_fileno: usize,
+ d_off: i64,
+ d_reclen: u16,
+ d_type: u8,
+ d_pad0: u8,
+ d_namlen: u16,
+ d_pad1: u16,
+ d_name: [256]u8,
+};
+
+pub const in_port_t = u16;
+pub const sa_family_t = u16;
+
+pub const sockaddr = extern union {
+ in: sockaddr_in,
+ in6: sockaddr_in6,
+};
+
+pub const sockaddr_in = extern struct {
+ len: u8,
+ family: sa_family_t,
+ port: in_port_t,
+ addr: [16]u8,
+ zero: [8]u8,
+};
+
+pub const sockaddr_in6 = extern struct {
+ len: u8,
+ family: sa_family_t,
+ port: in_port_t,
+ flowinfo: u32,
+ addr: [16]u8,
+ scope_id: u32,
+};
+
+pub const CTL_KERN = 1;
+pub const CTL_DEBUG = 5;
+
+pub const KERN_PROC = 14; // struct: process entries
+pub const KERN_PROC_PATHNAME = 12; // path to executable
+
+pub const PATH_MAX = 1024;
+
+pub const STDIN_FILENO = 0;
+pub const STDOUT_FILENO = 1;
+pub const STDERR_FILENO = 2;
+
+pub const PROT_NONE = 0;
+pub const PROT_READ = 1;
+pub const PROT_WRITE = 2;
+pub const PROT_EXEC = 4;
+
+pub const CLOCK_REALTIME = 0;
+pub const CLOCK_VIRTUAL = 1;
+pub const CLOCK_PROF = 2;
+pub const CLOCK_MONOTONIC = 4;
+pub const CLOCK_UPTIME = 5;
+pub const CLOCK_UPTIME_PRECISE = 7;
+pub const CLOCK_UPTIME_FAST = 8;
+pub const CLOCK_REALTIME_PRECISE = 9;
+pub const CLOCK_REALTIME_FAST = 10;
+pub const CLOCK_MONOTONIC_PRECISE = 11;
+pub const CLOCK_MONOTONIC_FAST = 12;
+pub const CLOCK_SECOND = 13;
+pub const CLOCK_THREAD_CPUTIME_ID = 14;
+pub const CLOCK_PROCESS_CPUTIME_ID = 15;
+
+pub const MAP_FAILED = @intToPtr(*c_void, maxInt(usize));
+pub const MAP_SHARED = 0x0001;
+pub const MAP_PRIVATE = 0x0002;
+pub const MAP_FIXED = 0x0010;
+pub const MAP_STACK = 0x0400;
+pub const MAP_NOSYNC = 0x0800;
+pub const MAP_ANON = 0x1000;
+pub const MAP_ANONYMOUS = MAP_ANON;
+pub const MAP_FILE = 0;
+pub const MAP_NORESERVE = 0;
+
+pub const MAP_GUARD = 0x00002000;
+pub const MAP_EXCL = 0x00004000;
+pub const MAP_NOCORE = 0x00020000;
+pub const MAP_PREFAULT_READ = 0x00040000;
+pub const MAP_32BIT = 0x00080000;
+
+pub const WNOHANG = 1;
+pub const WUNTRACED = 2;
+pub const WSTOPPED = WUNTRACED;
+pub const WCONTINUED = 4;
+pub const WNOWAIT = 8;
+pub const WEXITED = 16;
+pub const WTRAPPED = 32;
+
+pub const SA_ONSTACK = 0x0001;
+pub const SA_RESTART = 0x0002;
+pub const SA_RESETHAND = 0x0004;
+pub const SA_NOCLDSTOP = 0x0008;
+pub const SA_NODEFER = 0x0010;
+pub const SA_NOCLDWAIT = 0x0020;
+pub const SA_SIGINFO = 0x0040;
+
+pub const SIGHUP = 1;
+pub const SIGINT = 2;
+pub const SIGQUIT = 3;
+pub const SIGILL = 4;
+pub const SIGTRAP = 5;
+pub const SIGABRT = 6;
+pub const SIGIOT = SIGABRT;
+pub const SIGEMT = 7;
+pub const SIGFPE = 8;
+pub const SIGKILL = 9;
+pub const SIGBUS = 10;
+pub const SIGSEGV = 11;
+pub const SIGSYS = 12;
+pub const SIGPIPE = 13;
+pub const SIGALRM = 14;
+pub const SIGTERM = 15;
+pub const SIGURG = 16;
+pub const SIGSTOP = 17;
+pub const SIGTSTP = 18;
+pub const SIGCONT = 19;
+pub const SIGCHLD = 20;
+pub const SIGTTIN = 21;
+pub const SIGTTOU = 22;
+pub const SIGIO = 23;
+pub const SIGXCPU = 24;
+pub const SIGXFSZ = 25;
+pub const SIGVTALRM = 26;
+pub const SIGPROF = 27;
+pub const SIGWINCH = 28;
+pub const SIGINFO = 29;
+pub const SIGUSR1 = 30;
+pub const SIGUSR2 = 31;
+pub const SIGTHR = 32;
+pub const SIGLWP = SIGTHR;
+pub const SIGLIBRT = 33;
+
+pub const SIGRTMIN = 65;
+pub const SIGRTMAX = 126;
+
+// access function
+pub const F_OK = 0; // test for existence of file
+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_RDONLY = 0x0000;
+pub const O_WRONLY = 0x0001;
+pub const O_RDWR = 0x0002;
+pub const O_ACCMODE = 0x0003;
+
+pub const O_CREAT = 0x0200;
+pub const O_EXCL = 0x0800;
+pub const O_NOCTTY = 0x8000;
+pub const O_TRUNC = 0x0400;
+pub const O_APPEND = 0x0008;
+pub const O_NONBLOCK = 0x0004;
+pub const O_DSYNC = 0o10000;
+pub const O_SYNC = 0x0080;
+pub const O_RSYNC = 0o4010000;
+pub const O_DIRECTORY = 0o200000;
+pub const O_NOFOLLOW = 0x0100;
+pub const O_CLOEXEC = 0x00100000;
+
+pub const O_ASYNC = 0x0040;
+pub const O_DIRECT = 0x00010000;
+pub const O_LARGEFILE = 0;
+pub const O_NOATIME = 0o1000000;
+pub const O_PATH = 0o10000000;
+pub const O_TMPFILE = 0o20200000;
+pub const O_NDELAY = O_NONBLOCK;
+
+pub const F_DUPFD = 0;
+pub const F_GETFD = 1;
+pub const F_SETFD = 2;
+pub const F_GETFL = 3;
+pub const F_SETFL = 4;
+
+pub const F_SETOWN = 8;
+pub const F_GETOWN = 9;
+pub const F_SETSIG = 10;
+pub const F_GETSIG = 11;
+
+pub const F_GETLK = 5;
+pub const F_SETLK = 6;
+pub const F_SETLKW = 7;
+
+pub const F_SETOWN_EX = 15;
+pub const F_GETOWN_EX = 16;
+
+pub const F_GETOWNER_UIDS = 17;
+
+pub const SEEK_SET = 0;
+pub const SEEK_CUR = 1;
+pub const SEEK_END = 2;
+
+pub const SIG_BLOCK = 1;
+pub const SIG_UNBLOCK = 2;
+pub const SIG_SETMASK = 3;
+
+pub const SOCK_STREAM = 1;
+pub const SOCK_DGRAM = 2;
+pub const SOCK_RAW = 3;
+pub const SOCK_RDM = 4;
+pub const SOCK_SEQPACKET = 5;
+
+pub const SOCK_CLOEXEC = 0x10000000;
+pub const SOCK_NONBLOCK = 0x20000000;
+
+pub const PROTO_ip = 0o000;
+pub const PROTO_icmp = 0o001;
+pub const PROTO_igmp = 0o002;
+pub const PROTO_ggp = 0o003;
+pub const PROTO_ipencap = 0o004;
+pub const PROTO_st = 0o005;
+pub const PROTO_tcp = 0o006;
+pub const PROTO_egp = 0o010;
+pub const PROTO_pup = 0o014;
+pub const PROTO_udp = 0o021;
+pub const PROTO_hmp = 0o024;
+pub const PROTO_xns_idp = 0o026;
+pub const PROTO_rdp = 0o033;
+pub const PROTO_iso_tp4 = 0o035;
+pub const PROTO_xtp = 0o044;
+pub const PROTO_ddp = 0o045;
+pub const PROTO_idpr_cmtp = 0o046;
+pub const PROTO_ipv6 = 0o051;
+pub const PROTO_ipv6_route = 0o053;
+pub const PROTO_ipv6_frag = 0o054;
+pub const PROTO_idrp = 0o055;
+pub const PROTO_rsvp = 0o056;
+pub const PROTO_gre = 0o057;
+pub const PROTO_esp = 0o062;
+pub const PROTO_ah = 0o063;
+pub const PROTO_skip = 0o071;
+pub const PROTO_ipv6_icmp = 0o072;
+pub const PROTO_ipv6_nonxt = 0o073;
+pub const PROTO_ipv6_opts = 0o074;
+pub const PROTO_rspf = 0o111;
+pub const PROTO_vmtp = 0o121;
+pub const PROTO_ospf = 0o131;
+pub const PROTO_ipip = 0o136;
+pub const PROTO_encap = 0o142;
+pub const PROTO_pim = 0o147;
+pub const PROTO_raw = 0o377;
+
+pub const PF_UNSPEC = 0;
+pub const PF_LOCAL = 1;
+pub const PF_UNIX = PF_LOCAL;
+pub const PF_FILE = PF_LOCAL;
+pub const PF_INET = 2;
+pub const PF_AX25 = 3;
+pub const PF_IPX = 4;
+pub const PF_APPLETALK = 5;
+pub const PF_NETROM = 6;
+pub const PF_BRIDGE = 7;
+pub const PF_ATMPVC = 8;
+pub const PF_X25 = 9;
+pub const PF_INET6 = 10;
+pub const PF_ROSE = 11;
+pub const PF_DECnet = 12;
+pub const PF_NETBEUI = 13;
+pub const PF_SECURITY = 14;
+pub const PF_KEY = 15;
+pub const PF_NETLINK = 16;
+pub const PF_ROUTE = PF_NETLINK;
+pub const PF_PACKET = 17;
+pub const PF_ASH = 18;
+pub const PF_ECONET = 19;
+pub const PF_ATMSVC = 20;
+pub const PF_RDS = 21;
+pub const PF_SNA = 22;
+pub const PF_IRDA = 23;
+pub const PF_PPPOX = 24;
+pub const PF_WANPIPE = 25;
+pub const PF_LLC = 26;
+pub const PF_IB = 27;
+pub const PF_MPLS = 28;
+pub const PF_CAN = 29;
+pub const PF_TIPC = 30;
+pub const PF_BLUETOOTH = 31;
+pub const PF_IUCV = 32;
+pub const PF_RXRPC = 33;
+pub const PF_ISDN = 34;
+pub const PF_PHONET = 35;
+pub const PF_IEEE802154 = 36;
+pub const PF_CAIF = 37;
+pub const PF_ALG = 38;
+pub const PF_NFC = 39;
+pub const PF_VSOCK = 40;
+pub const PF_MAX = 41;
+
+pub const AF_UNSPEC = PF_UNSPEC;
+pub const AF_LOCAL = PF_LOCAL;
+pub const AF_UNIX = AF_LOCAL;
+pub const AF_FILE = AF_LOCAL;
+pub const AF_INET = PF_INET;
+pub const AF_AX25 = PF_AX25;
+pub const AF_IPX = PF_IPX;
+pub const AF_APPLETALK = PF_APPLETALK;
+pub const AF_NETROM = PF_NETROM;
+pub const AF_BRIDGE = PF_BRIDGE;
+pub const AF_ATMPVC = PF_ATMPVC;
+pub const AF_X25 = PF_X25;
+pub const AF_INET6 = PF_INET6;
+pub const AF_ROSE = PF_ROSE;
+pub const AF_DECnet = PF_DECnet;
+pub const AF_NETBEUI = PF_NETBEUI;
+pub const AF_SECURITY = PF_SECURITY;
+pub const AF_KEY = PF_KEY;
+pub const AF_NETLINK = PF_NETLINK;
+pub const AF_ROUTE = PF_ROUTE;
+pub const AF_PACKET = PF_PACKET;
+pub const AF_ASH = PF_ASH;
+pub const AF_ECONET = PF_ECONET;
+pub const AF_ATMSVC = PF_ATMSVC;
+pub const AF_RDS = PF_RDS;
+pub const AF_SNA = PF_SNA;
+pub const AF_IRDA = PF_IRDA;
+pub const AF_PPPOX = PF_PPPOX;
+pub const AF_WANPIPE = PF_WANPIPE;
+pub const AF_LLC = PF_LLC;
+pub const AF_IB = PF_IB;
+pub const AF_MPLS = PF_MPLS;
+pub const AF_CAN = PF_CAN;
+pub const AF_TIPC = PF_TIPC;
+pub const AF_BLUETOOTH = PF_BLUETOOTH;
+pub const AF_IUCV = PF_IUCV;
+pub const AF_RXRPC = PF_RXRPC;
+pub const AF_ISDN = PF_ISDN;
+pub const AF_PHONET = PF_PHONET;
+pub const AF_IEEE802154 = PF_IEEE802154;
+pub const AF_CAIF = PF_CAIF;
+pub const AF_ALG = PF_ALG;
+pub const AF_NFC = PF_NFC;
+pub const AF_VSOCK = PF_VSOCK;
+pub const AF_MAX = PF_MAX;
+
+pub const DT_UNKNOWN = 0;
+pub const DT_FIFO = 1;
+pub const DT_CHR = 2;
+pub const DT_DIR = 4;
+pub const DT_BLK = 6;
+pub const DT_REG = 8;
+pub const DT_LNK = 10;
+pub const DT_SOCK = 12;
+pub const DT_WHT = 14;
+
+/// add event to kq (implies enable)
+pub const EV_ADD = 0x0001;
+
+/// delete event from kq
+pub const EV_DELETE = 0x0002;
+
+/// enable event
+pub const EV_ENABLE = 0x0004;
+
+/// disable event (not reported)
+pub const EV_DISABLE = 0x0008;
+
+/// only report one occurrence
+pub const EV_ONESHOT = 0x0010;
+
+/// clear event state after reporting
+pub const EV_CLEAR = 0x0020;
+
+/// force immediate event output
+/// ... with or without EV_ERROR
+/// ... use KEVENT_FLAG_ERROR_EVENTS
+/// on syscalls supporting flags
+pub const EV_RECEIPT = 0x0040;
+
+/// disable event after reporting
+pub const EV_DISPATCH = 0x0080;
+
+pub const EVFILT_READ = -1;
+pub const EVFILT_WRITE = -2;
+
+/// attached to aio requests
+pub const EVFILT_AIO = -3;
+
+/// attached to vnodes
+pub const EVFILT_VNODE = -4;
+
+/// attached to struct proc
+pub const EVFILT_PROC = -5;
+
+/// attached to struct proc
+pub const EVFILT_SIGNAL = -6;
+
+/// timers
+pub const EVFILT_TIMER = -7;
+
+/// Process descriptors
+pub const EVFILT_PROCDESC = -8;
+
+/// Filesystem events
+pub const EVFILT_FS = -9;
+
+pub const EVFILT_LIO = -10;
+
+/// User events
+pub const EVFILT_USER = -11;
+
+/// Sendfile events
+pub const EVFILT_SENDFILE = -12;
+
+pub const EVFILT_EMPTY = -13;
+
+/// On input, NOTE_TRIGGER causes the event to be triggered for output.
+pub const NOTE_TRIGGER = 0x01000000;
+
+/// ignore input fflags
+pub const NOTE_FFNOP = 0x00000000;
+
+/// and fflags
+pub const NOTE_FFAND = 0x40000000;
+
+/// or fflags
+pub const NOTE_FFOR = 0x80000000;
+
+/// copy fflags
+pub const NOTE_FFCOPY = 0xc0000000;
+
+/// mask for operations
+pub const NOTE_FFCTRLMASK = 0xc0000000;
+pub const NOTE_FFLAGSMASK = 0x00ffffff;
+
+/// low water mark
+pub const NOTE_LOWAT = 0x00000001;
+
+/// behave like poll()
+pub const NOTE_FILE_POLL = 0x00000002;
+
+/// vnode was removed
+pub const NOTE_DELETE = 0x00000001;
+
+/// data contents changed
+pub const NOTE_WRITE = 0x00000002;
+
+/// size increased
+pub const NOTE_EXTEND = 0x00000004;
+
+/// attributes changed
+pub const NOTE_ATTRIB = 0x00000008;
+
+/// link count changed
+pub const NOTE_LINK = 0x00000010;
+
+/// vnode was renamed
+pub const NOTE_RENAME = 0x00000020;
+
+/// vnode access was revoked
+pub const NOTE_REVOKE = 0x00000040;
+
+/// vnode was opened
+pub const NOTE_OPEN = 0x00000080;
+
+/// file closed, fd did not allow write
+pub const NOTE_CLOSE = 0x00000100;
+
+/// file closed, fd did allow write
+pub const NOTE_CLOSE_WRITE = 0x00000200;
+
+/// file was read
+pub const NOTE_READ = 0x00000400;
+
+/// process exited
+pub const NOTE_EXIT = 0x80000000;
+
+/// process forked
+pub const NOTE_FORK = 0x40000000;
+
+/// process exec'd
+pub const NOTE_EXEC = 0x20000000;
+
+/// mask for signal & exit status
+pub const NOTE_PDATAMASK = 0x000fffff;
+pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK);
+
+/// data is seconds
+pub const NOTE_SECONDS = 0x00000001;
+
+/// data is milliseconds
+pub const NOTE_MSECONDS = 0x00000002;
+
+/// data is microseconds
+pub const NOTE_USECONDS = 0x00000004;
+
+/// data is nanoseconds
+pub const NOTE_NSECONDS = 0x00000008;
+
+/// timeout is absolute
+pub const NOTE_ABSTIME = 0x00000010;
+
+pub const TCGETS = 0x5401;
+pub const TCSETS = 0x5402;
+pub const TCSETSW = 0x5403;
+pub const TCSETSF = 0x5404;
+pub const TCGETA = 0x5405;
+pub const TCSETA = 0x5406;
+pub const TCSETAW = 0x5407;
+pub const TCSETAF = 0x5408;
+pub const TCSBRK = 0x5409;
+pub const TCXONC = 0x540A;
+pub const TCFLSH = 0x540B;
+pub const TIOCEXCL = 0x540C;
+pub const TIOCNXCL = 0x540D;
+pub const TIOCSCTTY = 0x540E;
+pub const TIOCGPGRP = 0x540F;
+pub const TIOCSPGRP = 0x5410;
+pub const TIOCOUTQ = 0x5411;
+pub const TIOCSTI = 0x5412;
+pub const TIOCGWINSZ = 0x5413;
+pub const TIOCSWINSZ = 0x5414;
+pub const TIOCMGET = 0x5415;
+pub const TIOCMBIS = 0x5416;
+pub const TIOCMBIC = 0x5417;
+pub const TIOCMSET = 0x5418;
+pub const TIOCGSOFTCAR = 0x5419;
+pub const TIOCSSOFTCAR = 0x541A;
+pub const FIONREAD = 0x541B;
+pub const TIOCINQ = FIONREAD;
+pub const TIOCLINUX = 0x541C;
+pub const TIOCCONS = 0x541D;
+pub const TIOCGSERIAL = 0x541E;
+pub const TIOCSSERIAL = 0x541F;
+pub const TIOCPKT = 0x5420;
+pub const FIONBIO = 0x5421;
+pub const TIOCNOTTY = 0x5422;
+pub const TIOCSETD = 0x5423;
+pub const TIOCGETD = 0x5424;
+pub const TCSBRKP = 0x5425;
+pub const TIOCSBRK = 0x5427;
+pub const TIOCCBRK = 0x5428;
+pub const TIOCGSID = 0x5429;
+pub const TIOCGRS485 = 0x542E;
+pub const TIOCSRS485 = 0x542F;
+pub const TIOCGPTN = 0x80045430;
+pub const TIOCSPTLCK = 0x40045431;
+pub const TIOCGDEV = 0x80045432;
+pub const TCGETX = 0x5432;
+pub const TCSETX = 0x5433;
+pub const TCSETXF = 0x5434;
+pub const TCSETXW = 0x5435;
+pub const TIOCSIG = 0x40045436;
+pub const TIOCVHANGUP = 0x5437;
+pub const TIOCGPKT = 0x80045438;
+pub const TIOCGPTLCK = 0x80045439;
+pub const TIOCGEXCL = 0x80045440;
+
+pub fn WEXITSTATUS(s: u32) u32 {
+ return (s & 0xff00) >> 8;
+}
+pub fn WTERMSIG(s: u32) u32 {
+ return s & 0x7f;
+}
+pub fn WSTOPSIG(s: u32) u32 {
+ return WEXITSTATUS(s);
+}
+pub fn WIFEXITED(s: u32) bool {
+ return WTERMSIG(s) == 0;
+}
+pub fn WIFSTOPPED(s: u32) bool {
+ return @intCast(u16, (((s & 0xffff) *% 0x10001) >> 8)) > 0x7f00;
+}
+pub fn WIFSIGNALED(s: u32) bool {
+ return (s & 0xffff) -% 1 < 0xff;
+}
+
+pub const winsize = extern struct {
+ ws_row: u16,
+ ws_col: u16,
+ ws_xpixel: u16,
+ ws_ypixel: u16,
+};
+
+const NSIG = 32;
+
+pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
+pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
+pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
+
+/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
+pub const Sigaction = extern struct {
+ /// signal handler
+ __sigaction_u: extern union {
+ __sa_handler: extern fn (i32) void,
+ __sa_sigaction: extern fn (i32, *__siginfo, usize) void,
+ },
+
+ /// see signal options
+ sa_flags: u32,
+
+ /// signal mask to apply
+ sa_mask: sigset_t,
+};
+
+pub const _SIG_WORDS = 4;
+pub const _SIG_MAXSIG = 128;
+
+pub inline fn _SIG_IDX(sig: usize) usize {
+ return sig - 1;
+}
+pub inline fn _SIG_WORD(sig: usize) usize {
+ return_SIG_IDX(sig) >> 5;
+}
+pub inline fn _SIG_BIT(sig: usize) usize {
+ return 1 << (_SIG_IDX(sig) & 31);
+}
+pub inline fn _SIG_VALID(sig: usize) usize {
+ return sig <= _SIG_MAXSIG and sig > 0;
+}
+
+pub const sigset_t = extern struct {
+ __bits: [_SIG_WORDS]u32,
+};
+
+pub const EPERM = 1; // Operation not permitted
+pub const ENOENT = 2; // No such file or directory
+pub const ESRCH = 3; // No such process
+pub const EINTR = 4; // Interrupted system call
+pub const EIO = 5; // Input/output error
+pub const ENXIO = 6; // Device not configured
+pub const E2BIG = 7; // Argument list too long
+pub const ENOEXEC = 8; // Exec format error
+pub const EBADF = 9; // Bad file descriptor
+pub const ECHILD = 10; // No child processes
+pub const EDEADLK = 11; // Resource deadlock avoided
+// 11 was EAGAIN
+pub const ENOMEM = 12; // Cannot allocate memory
+pub const EACCES = 13; // Permission denied
+pub const EFAULT = 14; // Bad address
+pub const ENOTBLK = 15; // Block device required
+pub const EBUSY = 16; // Device busy
+pub const EEXIST = 17; // File exists
+pub const EXDEV = 18; // Cross-device link
+pub const ENODEV = 19; // Operation not supported by device
+pub const ENOTDIR = 20; // Not a directory
+pub const EISDIR = 21; // Is a directory
+pub const EINVAL = 22; // Invalid argument
+pub const ENFILE = 23; // Too many open files in system
+pub const EMFILE = 24; // Too many open files
+pub const ENOTTY = 25; // Inappropriate ioctl for device
+pub const ETXTBSY = 26; // Text file busy
+pub const EFBIG = 27; // File too large
+pub const ENOSPC = 28; // No space left on device
+pub const ESPIPE = 29; // Illegal seek
+pub const EROFS = 30; // Read-only filesystem
+pub const EMLINK = 31; // Too many links
+pub const EPIPE = 32; // Broken pipe
+
+// math software
+pub const EDOM = 33; // Numerical argument out of domain
+pub const ERANGE = 34; // Result too large
+
+// non-blocking and interrupt i/o
+pub const EAGAIN = 35; // Resource temporarily unavailable
+pub const EWOULDBLOCK = EAGAIN; // Operation would block
+pub const EINPROGRESS = 36; // Operation now in progress
+pub const EALREADY = 37; // Operation already in progress
+
+// ipc/network software -- argument errors
+pub const ENOTSOCK = 38; // Socket operation on non-socket
+pub const EDESTADDRREQ = 39; // Destination address required
+pub const EMSGSIZE = 40; // Message too long
+pub const EPROTOTYPE = 41; // Protocol wrong type for socket
+pub const ENOPROTOOPT = 42; // Protocol not available
+pub const EPROTONOSUPPORT = 43; // Protocol not supported
+pub const ESOCKTNOSUPPORT = 44; // Socket type not supported
+pub const EOPNOTSUPP = 45; // Operation not supported
+pub const ENOTSUP = EOPNOTSUPP; // Operation not supported
+pub const EPFNOSUPPORT = 46; // Protocol family not supported
+pub const EAFNOSUPPORT = 47; // Address family not supported by protocol family
+pub const EADDRINUSE = 48; // Address already in use
+pub const EADDRNOTAVAIL = 49; // Can't assign requested address
+
+// ipc/network software -- operational errors
+pub const ENETDOWN = 50; // Network is down
+pub const ENETUNREACH = 51; // Network is unreachable
+pub const ENETRESET = 52; // Network dropped connection on reset
+pub const ECONNABORTED = 53; // Software caused connection abort
+pub const ECONNRESET = 54; // Connection reset by peer
+pub const ENOBUFS = 55; // No buffer space available
+pub const EISCONN = 56; // Socket is already connected
+pub const ENOTCONN = 57; // Socket is not connected
+pub const ESHUTDOWN = 58; // Can't send after socket shutdown
+pub const ETOOMANYREFS = 59; // Too many references: can't splice
+pub const ETIMEDOUT = 60; // Operation timed out
+pub const ECONNREFUSED = 61; // Connection refused
+
+pub const ELOOP = 62; // Too many levels of symbolic links
+pub const ENAMETOOLONG = 63; // File name too long
+
+// should be rearranged
+pub const EHOSTDOWN = 64; // Host is down
+pub const EHOSTUNREACH = 65; // No route to host
+pub const ENOTEMPTY = 66; // Directory not empty
+
+// quotas & mush
+pub const EPROCLIM = 67; // Too many processes
+pub const EUSERS = 68; // Too many users
+pub const EDQUOT = 69; // Disc quota exceeded
+
+// Network File System
+pub const ESTALE = 70; // Stale NFS file handle
+pub const EREMOTE = 71; // Too many levels of remote in path
+pub const EBADRPC = 72; // RPC struct is bad
+pub const ERPCMISMATCH = 73; // RPC version wrong
+pub const EPROGUNAVAIL = 74; // RPC prog. not avail
+pub const EPROGMISMATCH = 75; // Program version wrong
+pub const EPROCUNAVAIL = 76; // Bad procedure for program
+
+pub const ENOLCK = 77; // No locks available
+pub const ENOSYS = 78; // Function not implemented
+
+pub const EFTYPE = 79; // Inappropriate file type or format
+pub const EAUTH = 80; // Authentication error
+pub const ENEEDAUTH = 81; // Need authenticator
+pub const EIDRM = 82; // Identifier removed
+pub const ENOMSG = 83; // No message of desired type
+pub const EOVERFLOW = 84; // Value too large to be stored in data type
+pub const ECANCELED = 85; // Operation canceled
+pub const EILSEQ = 86; // Illegal byte sequence
+pub const ENOATTR = 87; // Attribute not found
+
+pub const EDOOFUS = 88; // Programming error
+
+pub const EBADMSG = 89; // Bad message
+pub const EMULTIHOP = 90; // Multihop attempted
+pub const ENOLINK = 91; // Link has been severed
+pub const EPROTO = 92; // Protocol error
+
+pub const ENOTCAPABLE = 93; // Capabilities insufficient
+pub const ECAPMODE = 94; // Not permitted in capability mode
+pub const ENOTRECOVERABLE = 95; // State not recoverable
+pub const EOWNERDEAD = 96; // Previous owner died
+
+pub const ELAST = 96; // Must be equal largest errno
diff --git a/std/os/bits/linux.zig b/std/os/bits/linux.zig
new file mode 100644
index 0000000000..6532e72362
--- /dev/null
+++ b/std/os/bits/linux.zig
@@ -0,0 +1,931 @@
+const builtin = @import("builtin");
+const std = @import("../../std.zig");
+const maxInt = std.math.maxInt;
+use @import("../bits.zig");
+
+pub use @import("linux/errno.zig");
+pub use switch (builtin.arch) {
+ .x86_64 => @import("linux/x86_64.zig"),
+ .aarch64 => @import("linux/arm64.zig"),
+ else => struct {},
+};
+
+pub const pid_t = i32;
+pub const fd_t = i32;
+
+pub const PATH_MAX = 4096;
+pub const IOV_MAX = 1024;
+
+pub const STDIN_FILENO = 0;
+pub const STDOUT_FILENO = 1;
+pub const STDERR_FILENO = 2;
+
+pub const FUTEX_WAIT = 0;
+pub const FUTEX_WAKE = 1;
+pub const FUTEX_FD = 2;
+pub const FUTEX_REQUEUE = 3;
+pub const FUTEX_CMP_REQUEUE = 4;
+pub const FUTEX_WAKE_OP = 5;
+pub const FUTEX_LOCK_PI = 6;
+pub const FUTEX_UNLOCK_PI = 7;
+pub const FUTEX_TRYLOCK_PI = 8;
+pub const FUTEX_WAIT_BITSET = 9;
+
+pub const FUTEX_PRIVATE_FLAG = 128;
+
+pub const FUTEX_CLOCK_REALTIME = 256;
+
+pub const PROT_NONE = 0;
+pub const PROT_READ = 1;
+pub const PROT_WRITE = 2;
+pub const PROT_EXEC = 4;
+pub const PROT_GROWSDOWN = 0x01000000;
+pub const PROT_GROWSUP = 0x02000000;
+
+pub const MAP_FAILED = @intToPtr(*c_void, maxInt(usize));
+pub const MAP_SHARED = 0x01;
+pub const MAP_PRIVATE = 0x02;
+pub const MAP_TYPE = 0x0f;
+pub const MAP_FIXED = 0x10;
+pub const MAP_ANONYMOUS = 0x20;
+pub const MAP_NORESERVE = 0x4000;
+pub const MAP_GROWSDOWN = 0x0100;
+pub const MAP_DENYWRITE = 0x0800;
+pub const MAP_EXECUTABLE = 0x1000;
+pub const MAP_LOCKED = 0x2000;
+pub const MAP_POPULATE = 0x8000;
+pub const MAP_NONBLOCK = 0x10000;
+pub const MAP_STACK = 0x20000;
+pub const MAP_HUGETLB = 0x40000;
+pub const MAP_FILE = 0;
+
+pub const F_OK = 0;
+pub const X_OK = 1;
+pub const W_OK = 2;
+pub const R_OK = 4;
+
+pub const WNOHANG = 1;
+pub const WUNTRACED = 2;
+pub const WSTOPPED = 2;
+pub const WEXITED = 4;
+pub const WCONTINUED = 8;
+pub const WNOWAIT = 0x1000000;
+
+pub const SA_NOCLDSTOP = 1;
+pub const SA_NOCLDWAIT = 2;
+pub const SA_SIGINFO = 4;
+pub const SA_ONSTACK = 0x08000000;
+pub const SA_RESTART = 0x10000000;
+pub const SA_NODEFER = 0x40000000;
+pub const SA_RESETHAND = 0x80000000;
+pub const SA_RESTORER = 0x04000000;
+
+pub const SIGHUP = 1;
+pub const SIGINT = 2;
+pub const SIGQUIT = 3;
+pub const SIGILL = 4;
+pub const SIGTRAP = 5;
+pub const SIGABRT = 6;
+pub const SIGIOT = SIGABRT;
+pub const SIGBUS = 7;
+pub const SIGFPE = 8;
+pub const SIGKILL = 9;
+pub const SIGUSR1 = 10;
+pub const SIGSEGV = 11;
+pub const SIGUSR2 = 12;
+pub const SIGPIPE = 13;
+pub const SIGALRM = 14;
+pub const SIGTERM = 15;
+pub const SIGSTKFLT = 16;
+pub const SIGCHLD = 17;
+pub const SIGCONT = 18;
+pub const SIGSTOP = 19;
+pub const SIGTSTP = 20;
+pub const SIGTTIN = 21;
+pub const SIGTTOU = 22;
+pub const SIGURG = 23;
+pub const SIGXCPU = 24;
+pub const SIGXFSZ = 25;
+pub const SIGVTALRM = 26;
+pub const SIGPROF = 27;
+pub const SIGWINCH = 28;
+pub const SIGIO = 29;
+pub const SIGPOLL = 29;
+pub const SIGPWR = 30;
+pub const SIGSYS = 31;
+pub const SIGUNUSED = SIGSYS;
+
+pub const O_RDONLY = 0o0;
+pub const O_WRONLY = 0o1;
+pub const O_RDWR = 0o2;
+
+pub const SEEK_SET = 0;
+pub const SEEK_CUR = 1;
+pub const SEEK_END = 2;
+
+pub const SIG_BLOCK = 0;
+pub const SIG_UNBLOCK = 1;
+pub const SIG_SETMASK = 2;
+
+pub const PROTO_ip = 0o000;
+pub const PROTO_icmp = 0o001;
+pub const PROTO_igmp = 0o002;
+pub const PROTO_ggp = 0o003;
+pub const PROTO_ipencap = 0o004;
+pub const PROTO_st = 0o005;
+pub const PROTO_tcp = 0o006;
+pub const PROTO_egp = 0o010;
+pub const PROTO_pup = 0o014;
+pub const PROTO_udp = 0o021;
+pub const PROTO_hmp = 0o024;
+pub const PROTO_xns_idp = 0o026;
+pub const PROTO_rdp = 0o033;
+pub const PROTO_iso_tp4 = 0o035;
+pub const PROTO_xtp = 0o044;
+pub const PROTO_ddp = 0o045;
+pub const PROTO_idpr_cmtp = 0o046;
+pub const PROTO_ipv6 = 0o051;
+pub const PROTO_ipv6_route = 0o053;
+pub const PROTO_ipv6_frag = 0o054;
+pub const PROTO_idrp = 0o055;
+pub const PROTO_rsvp = 0o056;
+pub const PROTO_gre = 0o057;
+pub const PROTO_esp = 0o062;
+pub const PROTO_ah = 0o063;
+pub const PROTO_skip = 0o071;
+pub const PROTO_ipv6_icmp = 0o072;
+pub const PROTO_ipv6_nonxt = 0o073;
+pub const PROTO_ipv6_opts = 0o074;
+pub const PROTO_rspf = 0o111;
+pub const PROTO_vmtp = 0o121;
+pub const PROTO_ospf = 0o131;
+pub const PROTO_ipip = 0o136;
+pub const PROTO_encap = 0o142;
+pub const PROTO_pim = 0o147;
+pub const PROTO_raw = 0o377;
+
+pub const SHUT_RD = 0;
+pub const SHUT_WR = 1;
+pub const SHUT_RDWR = 2;
+
+pub const SOCK_STREAM = 1;
+pub const SOCK_DGRAM = 2;
+pub const SOCK_RAW = 3;
+pub const SOCK_RDM = 4;
+pub const SOCK_SEQPACKET = 5;
+pub const SOCK_DCCP = 6;
+pub const SOCK_PACKET = 10;
+pub const SOCK_CLOEXEC = 0o2000000;
+pub const SOCK_NONBLOCK = 0o4000;
+
+pub const PF_UNSPEC = 0;
+pub const PF_LOCAL = 1;
+pub const PF_UNIX = PF_LOCAL;
+pub const PF_FILE = PF_LOCAL;
+pub const PF_INET = 2;
+pub const PF_AX25 = 3;
+pub const PF_IPX = 4;
+pub const PF_APPLETALK = 5;
+pub const PF_NETROM = 6;
+pub const PF_BRIDGE = 7;
+pub const PF_ATMPVC = 8;
+pub const PF_X25 = 9;
+pub const PF_INET6 = 10;
+pub const PF_ROSE = 11;
+pub const PF_DECnet = 12;
+pub const PF_NETBEUI = 13;
+pub const PF_SECURITY = 14;
+pub const PF_KEY = 15;
+pub const PF_NETLINK = 16;
+pub const PF_ROUTE = PF_NETLINK;
+pub const PF_PACKET = 17;
+pub const PF_ASH = 18;
+pub const PF_ECONET = 19;
+pub const PF_ATMSVC = 20;
+pub const PF_RDS = 21;
+pub const PF_SNA = 22;
+pub const PF_IRDA = 23;
+pub const PF_PPPOX = 24;
+pub const PF_WANPIPE = 25;
+pub const PF_LLC = 26;
+pub const PF_IB = 27;
+pub const PF_MPLS = 28;
+pub const PF_CAN = 29;
+pub const PF_TIPC = 30;
+pub const PF_BLUETOOTH = 31;
+pub const PF_IUCV = 32;
+pub const PF_RXRPC = 33;
+pub const PF_ISDN = 34;
+pub const PF_PHONET = 35;
+pub const PF_IEEE802154 = 36;
+pub const PF_CAIF = 37;
+pub const PF_ALG = 38;
+pub const PF_NFC = 39;
+pub const PF_VSOCK = 40;
+pub const PF_KCM = 41;
+pub const PF_QIPCRTR = 42;
+pub const PF_SMC = 43;
+pub const PF_MAX = 44;
+
+pub const AF_UNSPEC = PF_UNSPEC;
+pub const AF_LOCAL = PF_LOCAL;
+pub const AF_UNIX = AF_LOCAL;
+pub const AF_FILE = AF_LOCAL;
+pub const AF_INET = PF_INET;
+pub const AF_AX25 = PF_AX25;
+pub const AF_IPX = PF_IPX;
+pub const AF_APPLETALK = PF_APPLETALK;
+pub const AF_NETROM = PF_NETROM;
+pub const AF_BRIDGE = PF_BRIDGE;
+pub const AF_ATMPVC = PF_ATMPVC;
+pub const AF_X25 = PF_X25;
+pub const AF_INET6 = PF_INET6;
+pub const AF_ROSE = PF_ROSE;
+pub const AF_DECnet = PF_DECnet;
+pub const AF_NETBEUI = PF_NETBEUI;
+pub const AF_SECURITY = PF_SECURITY;
+pub const AF_KEY = PF_KEY;
+pub const AF_NETLINK = PF_NETLINK;
+pub const AF_ROUTE = PF_ROUTE;
+pub const AF_PACKET = PF_PACKET;
+pub const AF_ASH = PF_ASH;
+pub const AF_ECONET = PF_ECONET;
+pub const AF_ATMSVC = PF_ATMSVC;
+pub const AF_RDS = PF_RDS;
+pub const AF_SNA = PF_SNA;
+pub const AF_IRDA = PF_IRDA;
+pub const AF_PPPOX = PF_PPPOX;
+pub const AF_WANPIPE = PF_WANPIPE;
+pub const AF_LLC = PF_LLC;
+pub const AF_IB = PF_IB;
+pub const AF_MPLS = PF_MPLS;
+pub const AF_CAN = PF_CAN;
+pub const AF_TIPC = PF_TIPC;
+pub const AF_BLUETOOTH = PF_BLUETOOTH;
+pub const AF_IUCV = PF_IUCV;
+pub const AF_RXRPC = PF_RXRPC;
+pub const AF_ISDN = PF_ISDN;
+pub const AF_PHONET = PF_PHONET;
+pub const AF_IEEE802154 = PF_IEEE802154;
+pub const AF_CAIF = PF_CAIF;
+pub const AF_ALG = PF_ALG;
+pub const AF_NFC = PF_NFC;
+pub const AF_VSOCK = PF_VSOCK;
+pub const AF_KCM = PF_KCM;
+pub const AF_QIPCRTR = PF_QIPCRTR;
+pub const AF_SMC = PF_SMC;
+pub const AF_MAX = PF_MAX;
+
+pub const SO_DEBUG = 1;
+pub const SO_REUSEADDR = 2;
+pub const SO_TYPE = 3;
+pub const SO_ERROR = 4;
+pub const SO_DONTROUTE = 5;
+pub const SO_BROADCAST = 6;
+pub const SO_SNDBUF = 7;
+pub const SO_RCVBUF = 8;
+pub const SO_KEEPALIVE = 9;
+pub const SO_OOBINLINE = 10;
+pub const SO_NO_CHECK = 11;
+pub const SO_PRIORITY = 12;
+pub const SO_LINGER = 13;
+pub const SO_BSDCOMPAT = 14;
+pub const SO_REUSEPORT = 15;
+pub const SO_PASSCRED = 16;
+pub const SO_PEERCRED = 17;
+pub const SO_RCVLOWAT = 18;
+pub const SO_SNDLOWAT = 19;
+pub const SO_RCVTIMEO = 20;
+pub const SO_SNDTIMEO = 21;
+pub const SO_ACCEPTCONN = 30;
+pub const SO_SNDBUFFORCE = 32;
+pub const SO_RCVBUFFORCE = 33;
+pub const SO_PROTOCOL = 38;
+pub const SO_DOMAIN = 39;
+
+pub const SO_SECURITY_AUTHENTICATION = 22;
+pub const SO_SECURITY_ENCRYPTION_TRANSPORT = 23;
+pub const SO_SECURITY_ENCRYPTION_NETWORK = 24;
+
+pub const SO_BINDTODEVICE = 25;
+
+pub const SO_ATTACH_FILTER = 26;
+pub const SO_DETACH_FILTER = 27;
+pub const SO_GET_FILTER = SO_ATTACH_FILTER;
+
+pub const SO_PEERNAME = 28;
+pub const SO_TIMESTAMP = 29;
+pub const SCM_TIMESTAMP = SO_TIMESTAMP;
+
+pub const SO_PEERSEC = 31;
+pub const SO_PASSSEC = 34;
+pub const SO_TIMESTAMPNS = 35;
+pub const SCM_TIMESTAMPNS = SO_TIMESTAMPNS;
+pub const SO_MARK = 36;
+pub const SO_TIMESTAMPING = 37;
+pub const SCM_TIMESTAMPING = SO_TIMESTAMPING;
+pub const SO_RXQ_OVFL = 40;
+pub const SO_WIFI_STATUS = 41;
+pub const SCM_WIFI_STATUS = SO_WIFI_STATUS;
+pub const SO_PEEK_OFF = 42;
+pub const SO_NOFCS = 43;
+pub const SO_LOCK_FILTER = 44;
+pub const SO_SELECT_ERR_QUEUE = 45;
+pub const SO_BUSY_POLL = 46;
+pub const SO_MAX_PACING_RATE = 47;
+pub const SO_BPF_EXTENSIONS = 48;
+pub const SO_INCOMING_CPU = 49;
+pub const SO_ATTACH_BPF = 50;
+pub const SO_DETACH_BPF = SO_DETACH_FILTER;
+pub const SO_ATTACH_REUSEPORT_CBPF = 51;
+pub const SO_ATTACH_REUSEPORT_EBPF = 52;
+pub const SO_CNX_ADVICE = 53;
+pub const SCM_TIMESTAMPING_OPT_STATS = 54;
+pub const SO_MEMINFO = 55;
+pub const SO_INCOMING_NAPI_ID = 56;
+pub const SO_COOKIE = 57;
+pub const SCM_TIMESTAMPING_PKTINFO = 58;
+pub const SO_PEERGROUPS = 59;
+pub const SO_ZEROCOPY = 60;
+
+pub const SOL_SOCKET = 1;
+
+pub const SOL_IP = 0;
+pub const SOL_IPV6 = 41;
+pub const SOL_ICMPV6 = 58;
+
+pub const SOL_RAW = 255;
+pub const SOL_DECNET = 261;
+pub const SOL_X25 = 262;
+pub const SOL_PACKET = 263;
+pub const SOL_ATM = 264;
+pub const SOL_AAL = 265;
+pub const SOL_IRDA = 266;
+pub const SOL_NETBEUI = 267;
+pub const SOL_LLC = 268;
+pub const SOL_DCCP = 269;
+pub const SOL_NETLINK = 270;
+pub const SOL_TIPC = 271;
+pub const SOL_RXRPC = 272;
+pub const SOL_PPPOL2TP = 273;
+pub const SOL_BLUETOOTH = 274;
+pub const SOL_PNPIPE = 275;
+pub const SOL_RDS = 276;
+pub const SOL_IUCV = 277;
+pub const SOL_CAIF = 278;
+pub const SOL_ALG = 279;
+pub const SOL_NFC = 280;
+pub const SOL_KCM = 281;
+pub const SOL_TLS = 282;
+
+pub const SOMAXCONN = 128;
+
+pub const MSG_OOB = 0x0001;
+pub const MSG_PEEK = 0x0002;
+pub const MSG_DONTROUTE = 0x0004;
+pub const MSG_CTRUNC = 0x0008;
+pub const MSG_PROXY = 0x0010;
+pub const MSG_TRUNC = 0x0020;
+pub const MSG_DONTWAIT = 0x0040;
+pub const MSG_EOR = 0x0080;
+pub const MSG_WAITALL = 0x0100;
+pub const MSG_FIN = 0x0200;
+pub const MSG_SYN = 0x0400;
+pub const MSG_CONFIRM = 0x0800;
+pub const MSG_RST = 0x1000;
+pub const MSG_ERRQUEUE = 0x2000;
+pub const MSG_NOSIGNAL = 0x4000;
+pub const MSG_MORE = 0x8000;
+pub const MSG_WAITFORONE = 0x10000;
+pub const MSG_BATCH = 0x40000;
+pub const MSG_ZEROCOPY = 0x4000000;
+pub const MSG_FASTOPEN = 0x20000000;
+pub const MSG_CMSG_CLOEXEC = 0x40000000;
+
+pub const DT_UNKNOWN = 0;
+pub const DT_FIFO = 1;
+pub const DT_CHR = 2;
+pub const DT_DIR = 4;
+pub const DT_BLK = 6;
+pub const DT_REG = 8;
+pub const DT_LNK = 10;
+pub const DT_SOCK = 12;
+pub const DT_WHT = 14;
+
+pub const TCGETS = 0x5401;
+pub const TCSETS = 0x5402;
+pub const TCSETSW = 0x5403;
+pub const TCSETSF = 0x5404;
+pub const TCGETA = 0x5405;
+pub const TCSETA = 0x5406;
+pub const TCSETAW = 0x5407;
+pub const TCSETAF = 0x5408;
+pub const TCSBRK = 0x5409;
+pub const TCXONC = 0x540A;
+pub const TCFLSH = 0x540B;
+pub const TIOCEXCL = 0x540C;
+pub const TIOCNXCL = 0x540D;
+pub const TIOCSCTTY = 0x540E;
+pub const TIOCGPGRP = 0x540F;
+pub const TIOCSPGRP = 0x5410;
+pub const TIOCOUTQ = 0x5411;
+pub const TIOCSTI = 0x5412;
+pub const TIOCGWINSZ = 0x5413;
+pub const TIOCSWINSZ = 0x5414;
+pub const TIOCMGET = 0x5415;
+pub const TIOCMBIS = 0x5416;
+pub const TIOCMBIC = 0x5417;
+pub const TIOCMSET = 0x5418;
+pub const TIOCGSOFTCAR = 0x5419;
+pub const TIOCSSOFTCAR = 0x541A;
+pub const FIONREAD = 0x541B;
+pub const TIOCINQ = FIONREAD;
+pub const TIOCLINUX = 0x541C;
+pub const TIOCCONS = 0x541D;
+pub const TIOCGSERIAL = 0x541E;
+pub const TIOCSSERIAL = 0x541F;
+pub const TIOCPKT = 0x5420;
+pub const FIONBIO = 0x5421;
+pub const TIOCNOTTY = 0x5422;
+pub const TIOCSETD = 0x5423;
+pub const TIOCGETD = 0x5424;
+pub const TCSBRKP = 0x5425;
+pub const TIOCSBRK = 0x5427;
+pub const TIOCCBRK = 0x5428;
+pub const TIOCGSID = 0x5429;
+pub const TIOCGRS485 = 0x542E;
+pub const TIOCSRS485 = 0x542F;
+pub const TIOCGPTN = 0x80045430;
+pub const TIOCSPTLCK = 0x40045431;
+pub const TIOCGDEV = 0x80045432;
+pub const TCGETX = 0x5432;
+pub const TCSETX = 0x5433;
+pub const TCSETXF = 0x5434;
+pub const TCSETXW = 0x5435;
+pub const TIOCSIG = 0x40045436;
+pub const TIOCVHANGUP = 0x5437;
+pub const TIOCGPKT = 0x80045438;
+pub const TIOCGPTLCK = 0x80045439;
+pub const TIOCGEXCL = 0x80045440;
+
+pub const EPOLL_CLOEXEC = O_CLOEXEC;
+
+pub const EPOLL_CTL_ADD = 1;
+pub const EPOLL_CTL_DEL = 2;
+pub const EPOLL_CTL_MOD = 3;
+
+pub const EPOLLIN = 0x001;
+pub const EPOLLPRI = 0x002;
+pub const EPOLLOUT = 0x004;
+pub const EPOLLRDNORM = 0x040;
+pub const EPOLLRDBAND = 0x080;
+pub const EPOLLWRNORM = 0x100;
+pub const EPOLLWRBAND = 0x200;
+pub const EPOLLMSG = 0x400;
+pub const EPOLLERR = 0x008;
+pub const EPOLLHUP = 0x010;
+pub const EPOLLRDHUP = 0x2000;
+pub const EPOLLEXCLUSIVE = (u32(1) << 28);
+pub const EPOLLWAKEUP = (u32(1) << 29);
+pub const EPOLLONESHOT = (u32(1) << 30);
+pub const EPOLLET = (u32(1) << 31);
+
+pub const CLOCK_REALTIME = 0;
+pub const CLOCK_MONOTONIC = 1;
+pub const CLOCK_PROCESS_CPUTIME_ID = 2;
+pub const CLOCK_THREAD_CPUTIME_ID = 3;
+pub const CLOCK_MONOTONIC_RAW = 4;
+pub const CLOCK_REALTIME_COARSE = 5;
+pub const CLOCK_MONOTONIC_COARSE = 6;
+pub const CLOCK_BOOTTIME = 7;
+pub const CLOCK_REALTIME_ALARM = 8;
+pub const CLOCK_BOOTTIME_ALARM = 9;
+pub const CLOCK_SGI_CYCLE = 10;
+pub const CLOCK_TAI = 11;
+
+pub const CSIGNAL = 0x000000ff;
+pub const CLONE_VM = 0x00000100;
+pub const CLONE_FS = 0x00000200;
+pub const CLONE_FILES = 0x00000400;
+pub const CLONE_SIGHAND = 0x00000800;
+pub const CLONE_PTRACE = 0x00002000;
+pub const CLONE_VFORK = 0x00004000;
+pub const CLONE_PARENT = 0x00008000;
+pub const CLONE_THREAD = 0x00010000;
+pub const CLONE_NEWNS = 0x00020000;
+pub const CLONE_SYSVSEM = 0x00040000;
+pub const CLONE_SETTLS = 0x00080000;
+pub const CLONE_PARENT_SETTID = 0x00100000;
+pub const CLONE_CHILD_CLEARTID = 0x00200000;
+pub const CLONE_DETACHED = 0x00400000;
+pub const CLONE_UNTRACED = 0x00800000;
+pub const CLONE_CHILD_SETTID = 0x01000000;
+pub const CLONE_NEWCGROUP = 0x02000000;
+pub const CLONE_NEWUTS = 0x04000000;
+pub const CLONE_NEWIPC = 0x08000000;
+pub const CLONE_NEWUSER = 0x10000000;
+pub const CLONE_NEWPID = 0x20000000;
+pub const CLONE_NEWNET = 0x40000000;
+pub const CLONE_IO = 0x80000000;
+
+pub const EFD_SEMAPHORE = 1;
+pub const EFD_CLOEXEC = O_CLOEXEC;
+pub const EFD_NONBLOCK = O_NONBLOCK;
+
+pub const MS_RDONLY = 1;
+pub const MS_NOSUID = 2;
+pub const MS_NODEV = 4;
+pub const MS_NOEXEC = 8;
+pub const MS_SYNCHRONOUS = 16;
+pub const MS_REMOUNT = 32;
+pub const MS_MANDLOCK = 64;
+pub const MS_DIRSYNC = 128;
+pub const MS_NOATIME = 1024;
+pub const MS_NODIRATIME = 2048;
+pub const MS_BIND = 4096;
+pub const MS_MOVE = 8192;
+pub const MS_REC = 16384;
+pub const MS_SILENT = 32768;
+pub const MS_POSIXACL = (1 << 16);
+pub const MS_UNBINDABLE = (1 << 17);
+pub const MS_PRIVATE = (1 << 18);
+pub const MS_SLAVE = (1 << 19);
+pub const MS_SHARED = (1 << 20);
+pub const MS_RELATIME = (1 << 21);
+pub const MS_KERNMOUNT = (1 << 22);
+pub const MS_I_VERSION = (1 << 23);
+pub const MS_STRICTATIME = (1 << 24);
+pub const MS_LAZYTIME = (1 << 25);
+pub const MS_NOREMOTELOCK = (1 << 27);
+pub const MS_NOSEC = (1 << 28);
+pub const MS_BORN = (1 << 29);
+pub const MS_ACTIVE = (1 << 30);
+pub const MS_NOUSER = (1 << 31);
+
+pub const MS_RMT_MASK = (MS_RDONLY | MS_SYNCHRONOUS | MS_MANDLOCK | MS_I_VERSION | MS_LAZYTIME);
+
+pub const MS_MGC_VAL = 0xc0ed0000;
+pub const MS_MGC_MSK = 0xffff0000;
+
+pub const MNT_FORCE = 1;
+pub const MNT_DETACH = 2;
+pub const MNT_EXPIRE = 4;
+pub const UMOUNT_NOFOLLOW = 8;
+
+pub const IN_CLOEXEC = O_CLOEXEC;
+pub const IN_NONBLOCK = O_NONBLOCK;
+
+pub const IN_ACCESS = 0x00000001;
+pub const IN_MODIFY = 0x00000002;
+pub const IN_ATTRIB = 0x00000004;
+pub const IN_CLOSE_WRITE = 0x00000008;
+pub const IN_CLOSE_NOWRITE = 0x00000010;
+pub const IN_CLOSE = IN_CLOSE_WRITE | IN_CLOSE_NOWRITE;
+pub const IN_OPEN = 0x00000020;
+pub const IN_MOVED_FROM = 0x00000040;
+pub const IN_MOVED_TO = 0x00000080;
+pub const IN_MOVE = IN_MOVED_FROM | IN_MOVED_TO;
+pub const IN_CREATE = 0x00000100;
+pub const IN_DELETE = 0x00000200;
+pub const IN_DELETE_SELF = 0x00000400;
+pub const IN_MOVE_SELF = 0x00000800;
+pub const IN_ALL_EVENTS = 0x00000fff;
+
+pub const IN_UNMOUNT = 0x00002000;
+pub const IN_Q_OVERFLOW = 0x00004000;
+pub const IN_IGNORED = 0x00008000;
+
+pub const IN_ONLYDIR = 0x01000000;
+pub const IN_DONT_FOLLOW = 0x02000000;
+pub const IN_EXCL_UNLINK = 0x04000000;
+pub const IN_MASK_ADD = 0x20000000;
+
+pub const IN_ISDIR = 0x40000000;
+pub const IN_ONESHOT = 0x80000000;
+
+pub const S_IFMT = 0o170000;
+
+pub const S_IFDIR = 0o040000;
+pub const S_IFCHR = 0o020000;
+pub const S_IFBLK = 0o060000;
+pub const S_IFREG = 0o100000;
+pub const S_IFIFO = 0o010000;
+pub const S_IFLNK = 0o120000;
+pub const S_IFSOCK = 0o140000;
+
+pub const S_ISUID = 0o4000;
+pub const S_ISGID = 0o2000;
+pub const S_ISVTX = 0o1000;
+pub const S_IRUSR = 0o400;
+pub const S_IWUSR = 0o200;
+pub const S_IXUSR = 0o100;
+pub const S_IRWXU = 0o700;
+pub const S_IRGRP = 0o040;
+pub const S_IWGRP = 0o020;
+pub const S_IXGRP = 0o010;
+pub const S_IRWXG = 0o070;
+pub const S_IROTH = 0o004;
+pub const S_IWOTH = 0o002;
+pub const S_IXOTH = 0o001;
+pub const S_IRWXO = 0o007;
+
+pub fn S_ISREG(m: u32) bool {
+ return m & S_IFMT == S_IFREG;
+}
+
+pub fn S_ISDIR(m: u32) bool {
+ return m & S_IFMT == S_IFDIR;
+}
+
+pub fn S_ISCHR(m: u32) bool {
+ return m & S_IFMT == S_IFCHR;
+}
+
+pub fn S_ISBLK(m: u32) bool {
+ return m & S_IFMT == S_IFBLK;
+}
+
+pub fn S_ISFIFO(m: u32) bool {
+ return m & S_IFMT == S_IFIFO;
+}
+
+pub fn S_ISLNK(m: u32) bool {
+ return m & S_IFMT == S_IFLNK;
+}
+
+pub fn S_ISSOCK(m: u32) bool {
+ return m & S_IFMT == S_IFSOCK;
+}
+
+pub const TFD_NONBLOCK = O_NONBLOCK;
+pub const TFD_CLOEXEC = O_CLOEXEC;
+
+pub const TFD_TIMER_ABSTIME = 1;
+pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1);
+
+pub fn WEXITSTATUS(s: u32) u32 {
+ return (s & 0xff00) >> 8;
+}
+pub fn WTERMSIG(s: u32) u32 {
+ return s & 0x7f;
+}
+pub fn WSTOPSIG(s: u32) u32 {
+ return WEXITSTATUS(s);
+}
+pub fn WIFEXITED(s: u32) bool {
+ return WTERMSIG(s) == 0;
+}
+pub fn WIFSTOPPED(s: u32) bool {
+ return @intCast(u16, ((s & 0xffff) *% 0x10001) >> 8) > 0x7f00;
+}
+pub fn WIFSIGNALED(s: u32) bool {
+ return (s & 0xffff) -% 1 < 0xff;
+}
+
+pub const winsize = extern struct {
+ ws_row: u16,
+ ws_col: u16,
+ ws_xpixel: u16,
+ ws_ypixel: u16,
+};
+
+pub const NSIG = 65;
+pub const sigset_t = [128 / @sizeOf(usize)]usize;
+pub const all_mask = []u32{ 0xffffffff, 0xffffffff };
+pub const app_mask = []u32{ 0xfffffffc, 0x7fffffff };
+
+pub const k_sigaction = extern struct {
+ handler: extern fn (i32) void,
+ flags: usize,
+ restorer: extern fn () void,
+ mask: [2]u32,
+};
+
+/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
+pub const Sigaction = struct {
+ handler: extern fn (i32) void,
+ mask: sigset_t,
+ flags: u32,
+};
+
+pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
+pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
+pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
+pub const empty_sigset = []usize{0} ** sigset_t.len;
+
+pub const in_port_t = u16;
+pub const sa_family_t = u16;
+pub const socklen_t = u32;
+
+/// This intentionally only has ip4 and ip6
+pub const sockaddr = extern union {
+ in: sockaddr_in,
+ in6: sockaddr_in6,
+};
+
+pub const sockaddr_in = extern struct {
+ family: sa_family_t,
+ port: in_port_t,
+ addr: u32,
+ zero: [8]u8,
+};
+
+pub const sockaddr_in6 = extern struct {
+ family: sa_family_t,
+ port: in_port_t,
+ flowinfo: u32,
+ addr: [16]u8,
+ scope_id: u32,
+};
+
+pub const sockaddr_un = extern struct {
+ family: sa_family_t,
+ path: [108]u8,
+};
+
+pub const mmsghdr = extern struct {
+ msg_hdr: msghdr,
+ msg_len: u32,
+};
+
+pub const mmsghdr_const = extern struct {
+ msg_hdr: msghdr_const,
+ msg_len: u32,
+};
+
+pub const epoll_data = extern union {
+ ptr: usize,
+ fd: i32,
+ @"u32": u32,
+ @"u64": u64,
+};
+
+// On x86_64 the structure is packed so that it matches the definition of its
+// 32bit counterpart
+pub const epoll_event = if (builtin.arch != .x86_64)
+ extern struct {
+ events: u32,
+ data: epoll_data,
+ }
+else
+ packed struct {
+ events: u32,
+ data: epoll_data,
+ };
+
+pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330;
+pub const _LINUX_CAPABILITY_U32S_1 = 1;
+
+pub const _LINUX_CAPABILITY_VERSION_2 = 0x20071026;
+pub const _LINUX_CAPABILITY_U32S_2 = 2;
+
+pub const _LINUX_CAPABILITY_VERSION_3 = 0x20080522;
+pub const _LINUX_CAPABILITY_U32S_3 = 2;
+
+pub const VFS_CAP_REVISION_MASK = 0xFF000000;
+pub const VFS_CAP_REVISION_SHIFT = 24;
+pub const VFS_CAP_FLAGS_MASK = ~VFS_CAP_REVISION_MASK;
+pub const VFS_CAP_FLAGS_EFFECTIVE = 0x000001;
+
+pub const VFS_CAP_REVISION_1 = 0x01000000;
+pub const VFS_CAP_U32_1 = 1;
+pub const XATTR_CAPS_SZ_1 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_1);
+
+pub const VFS_CAP_REVISION_2 = 0x02000000;
+pub const VFS_CAP_U32_2 = 2;
+pub const XATTR_CAPS_SZ_2 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_2);
+
+pub const XATTR_CAPS_SZ = XATTR_CAPS_SZ_2;
+pub const VFS_CAP_U32 = VFS_CAP_U32_2;
+pub const VFS_CAP_REVISION = VFS_CAP_REVISION_2;
+
+pub const vfs_cap_data = extern struct {
+ //all of these are mandated as little endian
+ //when on disk.
+ const Data = struct {
+ permitted: u32,
+ inheritable: u32,
+ };
+
+ magic_etc: u32,
+ data: [VFS_CAP_U32]Data,
+};
+
+pub const CAP_CHOWN = 0;
+pub const CAP_DAC_OVERRIDE = 1;
+pub const CAP_DAC_READ_SEARCH = 2;
+pub const CAP_FOWNER = 3;
+pub const CAP_FSETID = 4;
+pub const CAP_KILL = 5;
+pub const CAP_SETGID = 6;
+pub const CAP_SETUID = 7;
+pub const CAP_SETPCAP = 8;
+pub const CAP_LINUX_IMMUTABLE = 9;
+pub const CAP_NET_BIND_SERVICE = 10;
+pub const CAP_NET_BROADCAST = 11;
+pub const CAP_NET_ADMIN = 12;
+pub const CAP_NET_RAW = 13;
+pub const CAP_IPC_LOCK = 14;
+pub const CAP_IPC_OWNER = 15;
+pub const CAP_SYS_MODULE = 16;
+pub const CAP_SYS_RAWIO = 17;
+pub const CAP_SYS_CHROOT = 18;
+pub const CAP_SYS_PTRACE = 19;
+pub const CAP_SYS_PACCT = 20;
+pub const CAP_SYS_ADMIN = 21;
+pub const CAP_SYS_BOOT = 22;
+pub const CAP_SYS_NICE = 23;
+pub const CAP_SYS_RESOURCE = 24;
+pub const CAP_SYS_TIME = 25;
+pub const CAP_SYS_TTY_CONFIG = 26;
+pub const CAP_MKNOD = 27;
+pub const CAP_LEASE = 28;
+pub const CAP_AUDIT_WRITE = 29;
+pub const CAP_AUDIT_CONTROL = 30;
+pub const CAP_SETFCAP = 31;
+pub const CAP_MAC_OVERRIDE = 32;
+pub const CAP_MAC_ADMIN = 33;
+pub const CAP_SYSLOG = 34;
+pub const CAP_WAKE_ALARM = 35;
+pub const CAP_BLOCK_SUSPEND = 36;
+pub const CAP_AUDIT_READ = 37;
+pub const CAP_LAST_CAP = CAP_AUDIT_READ;
+
+pub fn cap_valid(u8: x) bool {
+ return x >= 0 and x <= CAP_LAST_CAP;
+}
+
+pub fn CAP_TO_MASK(cap: u8) u32 {
+ return u32(1) << u5(cap & 31);
+}
+
+pub fn CAP_TO_INDEX(cap: u8) u8 {
+ return cap >> 5;
+}
+
+pub const cap_t = extern struct {
+ hdrp: *cap_user_header_t,
+ datap: *cap_user_data_t,
+};
+
+pub const cap_user_header_t = extern struct {
+ version: u32,
+ pid: usize,
+};
+
+pub const cap_user_data_t = extern struct {
+ effective: u32,
+ permitted: u32,
+ inheritable: u32,
+};
+
+pub const inotify_event = extern struct {
+ wd: i32,
+ mask: u32,
+ cookie: u32,
+ len: u32,
+ //name: [?]u8,
+};
+
+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 const dl_phdr_info = extern struct {
+ dlpi_addr: usize,
+ dlpi_name: ?[*]const u8,
+ dlpi_phdr: [*]std.elf.Phdr,
+ dlpi_phnum: u16,
+};
+
+pub const pthread_attr_t = extern struct {
+ __size: [56]u8,
+ __align: c_long,
+};
+
+pub const CPU_SETSIZE = 128;
+pub const cpu_set_t = [CPU_SETSIZE / @sizeOf(usize)]usize;
+pub const cpu_count_t = @IntType(false, std.math.log2(CPU_SETSIZE * 8));
+
+pub fn CPU_COUNT(set: cpu_set_t) cpu_count_t {
+ var sum: cpu_count_t = 0;
+ for (set) |x| {
+ sum += @popCount(usize, x);
+ }
+ return sum;
+}
+
+// TODO port these over
+//#define CPU_SET(i, set) CPU_SET_S(i,sizeof(cpu_set_t),set)
+//#define CPU_CLR(i, set) CPU_CLR_S(i,sizeof(cpu_set_t),set)
+//#define CPU_ISSET(i, set) CPU_ISSET_S(i,sizeof(cpu_set_t),set)
+//#define CPU_AND(d,s1,s2) CPU_AND_S(sizeof(cpu_set_t),d,s1,s2)
+//#define CPU_OR(d,s1,s2) CPU_OR_S(sizeof(cpu_set_t),d,s1,s2)
+//#define CPU_XOR(d,s1,s2) CPU_XOR_S(sizeof(cpu_set_t),d,s1,s2)
+//#define CPU_COUNT(set) CPU_COUNT_S(sizeof(cpu_set_t),set)
+//#define CPU_ZERO(set) CPU_ZERO_S(sizeof(cpu_set_t),set)
+//#define CPU_EQUAL(s1,s2) CPU_EQUAL_S(sizeof(cpu_set_t),s1,s2)
diff --git a/std/os/bits/linux/arm64.zig b/std/os/bits/linux/arm64.zig
new file mode 100644
index 0000000000..8966df30d2
--- /dev/null
+++ b/std/os/bits/linux/arm64.zig
@@ -0,0 +1,405 @@
+// arm64-specific declarations that are intended to be imported into the POSIX namespace.
+// This does include Linux-only APIs.
+
+const std = @import("../../std.zig");
+const linux = std.os.linux;
+const socklen_t = linux.socklen_t;
+const iovec = linux.iovec;
+const iovec_const = linux.iovec_const;
+
+pub const SYS_io_setup = 0;
+pub const SYS_io_destroy = 1;
+pub const SYS_io_submit = 2;
+pub const SYS_io_cancel = 3;
+pub const SYS_io_getevents = 4;
+pub const SYS_setxattr = 5;
+pub const SYS_lsetxattr = 6;
+pub const SYS_fsetxattr = 7;
+pub const SYS_getxattr = 8;
+pub const SYS_lgetxattr = 9;
+pub const SYS_fgetxattr = 10;
+pub const SYS_listxattr = 11;
+pub const SYS_llistxattr = 12;
+pub const SYS_flistxattr = 13;
+pub const SYS_removexattr = 14;
+pub const SYS_lremovexattr = 15;
+pub const SYS_fremovexattr = 16;
+pub const SYS_getcwd = 17;
+pub const SYS_lookup_dcookie = 18;
+pub const SYS_eventfd2 = 19;
+pub const SYS_epoll_create1 = 20;
+pub const SYS_epoll_ctl = 21;
+pub const SYS_epoll_pwait = 22;
+pub const SYS_dup = 23;
+pub const SYS_dup3 = 24;
+pub const SYS_fcntl = 25;
+pub const SYS_inotify_init1 = 26;
+pub const SYS_inotify_add_watch = 27;
+pub const SYS_inotify_rm_watch = 28;
+pub const SYS_ioctl = 29;
+pub const SYS_ioprio_set = 30;
+pub const SYS_ioprio_get = 31;
+pub const SYS_flock = 32;
+pub const SYS_mknodat = 33;
+pub const SYS_mkdirat = 34;
+pub const SYS_unlinkat = 35;
+pub const SYS_symlinkat = 36;
+pub const SYS_linkat = 37;
+pub const SYS_renameat = 38;
+pub const SYS_umount2 = 39;
+pub const SYS_mount = 40;
+pub const SYS_pivot_root = 41;
+pub const SYS_nfsservctl = 42;
+pub const SYS_statfs = 43;
+pub const SYS_fstatfs = 44;
+pub const SYS_truncate = 45;
+pub const SYS_ftruncate = 46;
+pub const SYS_fallocate = 47;
+pub const SYS_faccessat = 48;
+pub const SYS_chdir = 49;
+pub const SYS_fchdir = 50;
+pub const SYS_chroot = 51;
+pub const SYS_fchmod = 52;
+pub const SYS_fchmodat = 53;
+pub const SYS_fchownat = 54;
+pub const SYS_fchown = 55;
+pub const SYS_openat = 56;
+pub const SYS_close = 57;
+pub const SYS_vhangup = 58;
+pub const SYS_pipe2 = 59;
+pub const SYS_quotactl = 60;
+pub const SYS_getdents64 = 61;
+pub const SYS_lseek = 62;
+pub const SYS_read = 63;
+pub const SYS_write = 64;
+pub const SYS_readv = 65;
+pub const SYS_writev = 66;
+pub const SYS_pread64 = 67;
+pub const SYS_pwrite64 = 68;
+pub const SYS_preadv = 69;
+pub const SYS_pwritev = 70;
+pub const SYS_pselect6 = 72;
+pub const SYS_ppoll = 73;
+pub const SYS_signalfd4 = 74;
+pub const SYS_vmsplice = 75;
+pub const SYS_splice = 76;
+pub const SYS_tee = 77;
+pub const SYS_readlinkat = 78;
+pub const SYS_fstatat = 79;
+pub const SYS_fstat = 80;
+pub const SYS_sync = 81;
+pub const SYS_fsync = 82;
+pub const SYS_fdatasync = 83;
+pub const SYS_sync_file_range2 = 84;
+pub const SYS_sync_file_range = 84;
+pub const SYS_timerfd_create = 85;
+pub const SYS_timerfd_settime = 86;
+pub const SYS_timerfd_gettime = 87;
+pub const SYS_utimensat = 88;
+pub const SYS_acct = 89;
+pub const SYS_capget = 90;
+pub const SYS_capset = 91;
+pub const SYS_personality = 92;
+pub const SYS_exit = 93;
+pub const SYS_exit_group = 94;
+pub const SYS_waitid = 95;
+pub const SYS_set_tid_address = 96;
+pub const SYS_unshare = 97;
+pub const SYS_futex = 98;
+pub const SYS_set_robust_list = 99;
+pub const SYS_get_robust_list = 100;
+pub const SYS_nanosleep = 101;
+pub const SYS_getitimer = 102;
+pub const SYS_setitimer = 103;
+pub const SYS_kexec_load = 104;
+pub const SYS_init_module = 105;
+pub const SYS_delete_module = 106;
+pub const SYS_timer_create = 107;
+pub const SYS_timer_gettime = 108;
+pub const SYS_timer_getoverrun = 109;
+pub const SYS_timer_settime = 110;
+pub const SYS_timer_delete = 111;
+pub const SYS_clock_settime = 112;
+pub const SYS_clock_gettime = 113;
+pub const SYS_clock_getres = 114;
+pub const SYS_clock_nanosleep = 115;
+pub const SYS_syslog = 116;
+pub const SYS_ptrace = 117;
+pub const SYS_sched_setparam = 118;
+pub const SYS_sched_setscheduler = 119;
+pub const SYS_sched_getscheduler = 120;
+pub const SYS_sched_getparam = 121;
+pub const SYS_sched_setaffinity = 122;
+pub const SYS_sched_getaffinity = 123;
+pub const SYS_sched_yield = 124;
+pub const SYS_sched_get_priority_max = 125;
+pub const SYS_sched_get_priority_min = 126;
+pub const SYS_sched_rr_get_interval = 127;
+pub const SYS_restart_syscall = 128;
+pub const SYS_kill = 129;
+pub const SYS_tkill = 130;
+pub const SYS_tgkill = 131;
+pub const SYS_sigaltstack = 132;
+pub const SYS_rt_sigsuspend = 133;
+pub const SYS_rt_sigaction = 134;
+pub const SYS_rt_sigprocmask = 135;
+pub const SYS_rt_sigpending = 136;
+pub const SYS_rt_sigtimedwait = 137;
+pub const SYS_rt_sigqueueinfo = 138;
+pub const SYS_rt_sigreturn = 139;
+pub const SYS_setpriority = 140;
+pub const SYS_getpriority = 141;
+pub const SYS_reboot = 142;
+pub const SYS_setregid = 143;
+pub const SYS_setgid = 144;
+pub const SYS_setreuid = 145;
+pub const SYS_setuid = 146;
+pub const SYS_setresuid = 147;
+pub const SYS_getresuid = 148;
+pub const SYS_setresgid = 149;
+pub const SYS_getresgid = 150;
+pub const SYS_setfsuid = 151;
+pub const SYS_setfsgid = 152;
+pub const SYS_times = 153;
+pub const SYS_setpgid = 154;
+pub const SYS_getpgid = 155;
+pub const SYS_getsid = 156;
+pub const SYS_setsid = 157;
+pub const SYS_getgroups = 158;
+pub const SYS_setgroups = 159;
+pub const SYS_uname = 160;
+pub const SYS_sethostname = 161;
+pub const SYS_setdomainname = 162;
+pub const SYS_getrlimit = 163;
+pub const SYS_setrlimit = 164;
+pub const SYS_getrusage = 165;
+pub const SYS_umask = 166;
+pub const SYS_prctl = 167;
+pub const SYS_getcpu = 168;
+pub const SYS_gettimeofday = 169;
+pub const SYS_settimeofday = 170;
+pub const SYS_adjtimex = 171;
+pub const SYS_getpid = 172;
+pub const SYS_getppid = 173;
+pub const SYS_getuid = 174;
+pub const SYS_geteuid = 175;
+pub const SYS_getgid = 176;
+pub const SYS_getegid = 177;
+pub const SYS_gettid = 178;
+pub const SYS_sysinfo = 179;
+pub const SYS_mq_open = 180;
+pub const SYS_mq_unlink = 181;
+pub const SYS_mq_timedsend = 182;
+pub const SYS_mq_timedreceive = 183;
+pub const SYS_mq_notify = 184;
+pub const SYS_mq_getsetattr = 185;
+pub const SYS_msgget = 186;
+pub const SYS_msgctl = 187;
+pub const SYS_msgrcv = 188;
+pub const SYS_msgsnd = 189;
+pub const SYS_semget = 190;
+pub const SYS_semctl = 191;
+pub const SYS_semtimedop = 192;
+pub const SYS_semop = 193;
+pub const SYS_shmget = 194;
+pub const SYS_shmctl = 195;
+pub const SYS_shmat = 196;
+pub const SYS_shmdt = 197;
+pub const SYS_socket = 198;
+pub const SYS_socketpair = 199;
+pub const SYS_bind = 200;
+pub const SYS_listen = 201;
+pub const SYS_accept = 202;
+pub const SYS_connect = 203;
+pub const SYS_getsockname = 204;
+pub const SYS_getpeername = 205;
+pub const SYS_sendto = 206;
+pub const SYS_recvfrom = 207;
+pub const SYS_setsockopt = 208;
+pub const SYS_getsockopt = 209;
+pub const SYS_shutdown = 210;
+pub const SYS_sendmsg = 211;
+pub const SYS_recvmsg = 212;
+pub const SYS_readahead = 213;
+pub const SYS_brk = 214;
+pub const SYS_munmap = 215;
+pub const SYS_mremap = 216;
+pub const SYS_add_key = 217;
+pub const SYS_request_key = 218;
+pub const SYS_keyctl = 219;
+pub const SYS_clone = 220;
+pub const SYS_execve = 221;
+pub const SYS_mmap = 222;
+pub const SYS_fadvise64 = 223;
+pub const SYS_swapon = 224;
+pub const SYS_swapoff = 225;
+pub const SYS_mprotect = 226;
+pub const SYS_msync = 227;
+pub const SYS_mlock = 228;
+pub const SYS_munlock = 229;
+pub const SYS_mlockall = 230;
+pub const SYS_munlockall = 231;
+pub const SYS_mincore = 232;
+pub const SYS_madvise = 233;
+pub const SYS_remap_file_pages = 234;
+pub const SYS_mbind = 235;
+pub const SYS_get_mempolicy = 236;
+pub const SYS_set_mempolicy = 237;
+pub const SYS_migrate_pages = 238;
+pub const SYS_move_pages = 239;
+pub const SYS_rt_tgsigqueueinfo = 240;
+pub const SYS_perf_event_open = 241;
+pub const SYS_accept4 = 242;
+pub const SYS_recvmmsg = 243;
+pub const SYS_arch_specific_syscall = 244;
+pub const SYS_wait4 = 260;
+pub const SYS_prlimit64 = 261;
+pub const SYS_fanotify_init = 262;
+pub const SYS_fanotify_mark = 263;
+pub const SYS_clock_adjtime = 266;
+pub const SYS_syncfs = 267;
+pub const SYS_setns = 268;
+pub const SYS_sendmmsg = 269;
+pub const SYS_process_vm_readv = 270;
+pub const SYS_process_vm_writev = 271;
+pub const SYS_kcmp = 272;
+pub const SYS_finit_module = 273;
+pub const SYS_sched_setattr = 274;
+pub const SYS_sched_getattr = 275;
+pub const SYS_renameat2 = 276;
+pub const SYS_seccomp = 277;
+pub const SYS_getrandom = 278;
+pub const SYS_memfd_create = 279;
+pub const SYS_bpf = 280;
+pub const SYS_execveat = 281;
+pub const SYS_userfaultfd = 282;
+pub const SYS_membarrier = 283;
+pub const SYS_mlock2 = 284;
+pub const SYS_copy_file_range = 285;
+pub const SYS_preadv2 = 286;
+pub const SYS_pwritev2 = 287;
+pub const SYS_pkey_mprotect = 288;
+pub const SYS_pkey_alloc = 289;
+pub const SYS_pkey_free = 290;
+pub const SYS_statx = 291;
+pub const SYS_io_pgetevents = 292;
+pub const SYS_rseq = 293;
+pub const SYS_kexec_file_load = 294;
+pub const SYS_pidfd_send_signal = 424;
+pub const SYS_io_uring_setup = 425;
+pub const SYS_io_uring_enter = 426;
+pub const SYS_io_uring_register = 427;
+
+pub const O_CREAT = 0o100;
+pub const O_EXCL = 0o200;
+pub const O_NOCTTY = 0o400;
+pub const O_TRUNC = 0o1000;
+pub const O_APPEND = 0o2000;
+pub const O_NONBLOCK = 0o4000;
+pub const O_DSYNC = 0o10000;
+pub const O_SYNC = 0o4010000;
+pub const O_RSYNC = 0o4010000;
+pub const O_DIRECTORY = 0o200000;
+pub const O_NOFOLLOW = 0o400000;
+pub const O_CLOEXEC = 0o2000000;
+
+pub const O_ASYNC = 0o20000;
+pub const O_DIRECT = 0o40000;
+pub const O_LARGEFILE = 0;
+pub const O_NOATIME = 0o1000000;
+pub const O_PATH = 0o10000000;
+pub const O_TMPFILE = 0o20200000;
+pub const O_NDELAY = O_NONBLOCK;
+
+pub const F_DUPFD = 0;
+pub const F_GETFD = 1;
+pub const F_SETFD = 2;
+pub const F_GETFL = 3;
+pub const F_SETFL = 4;
+
+pub const F_SETOWN = 8;
+pub const F_GETOWN = 9;
+pub const F_SETSIG = 10;
+pub const F_GETSIG = 11;
+
+pub const F_GETLK = 5;
+pub const F_SETLK = 6;
+pub const F_SETLKW = 7;
+
+pub const F_SETOWN_EX = 15;
+pub const F_GETOWN_EX = 16;
+
+pub const F_GETOWNER_UIDS = 17;
+
+pub const AT_FDCWD = -100;
+pub const AT_SYMLINK_NOFOLLOW = 0x100;
+pub const AT_REMOVEDIR = 0x200;
+pub const AT_SYMLINK_FOLLOW = 0x400;
+pub const AT_NO_AUTOMOUNT = 0x800;
+pub const AT_EMPTY_PATH = 0x1000;
+
+pub const VDSO_USEFUL = true;
+pub const VDSO_CGT_SYM = "__kernel_clock_gettime";
+pub const VDSO_CGT_VER = "LINUX_2.6.39";
+
+pub const msghdr = extern struct {
+ msg_name: ?*sockaddr,
+ msg_namelen: socklen_t,
+ msg_iov: [*]iovec,
+ msg_iovlen: i32,
+ __pad1: i32,
+ msg_control: ?*c_void,
+ msg_controllen: socklen_t,
+ __pad2: socklen_t,
+ msg_flags: i32,
+};
+
+pub const msghdr_const = extern struct {
+ msg_name: ?*const sockaddr,
+ msg_namelen: socklen_t,
+ msg_iov: [*]iovec_const,
+ msg_iovlen: i32,
+ __pad1: i32,
+ msg_control: ?*c_void,
+ msg_controllen: socklen_t,
+ __pad2: socklen_t,
+ msg_flags: i32,
+};
+
+/// Renamed to Stat to not conflict with the stat function.
+pub const Stat = extern struct {
+ dev: u64,
+ ino: u64,
+ nlink: usize,
+
+ mode: u32,
+ uid: u32,
+ gid: u32,
+ __pad0: u32,
+ rdev: u64,
+ size: i64,
+ blksize: isize,
+ blocks: i64,
+
+ atim: timespec,
+ mtim: timespec,
+ ctim: timespec,
+ __unused: [3]isize,
+};
+
+pub const timespec = extern struct {
+ tv_sec: isize,
+ tv_nsec: isize,
+};
+
+pub const timeval = extern struct {
+ tv_sec: isize,
+ tv_usec: isize,
+};
+
+pub const timezone = extern struct {
+ tz_minuteswest: i32,
+ tz_dsttime: i32,
+};
+
+pub const Elf_Symndx = u32;
diff --git a/std/os/linux/errno.zig b/std/os/bits/linux/errno.zig
index 5ad8777f92..741f76fdee 100644
--- a/std/os/linux/errno.zig
+++ b/std/os/bits/linux/errno.zig
@@ -279,6 +279,7 @@ pub const ESOCKTNOSUPPORT = 94;
/// Operation not supported on transport endpoint
pub const EOPNOTSUPP = 95;
+pub const ENOTSUP = EOPNOTSUPP;
/// Protocol family not supported
pub const EPFNOSUPPORT = 96;
diff --git a/std/os/bits/linux/x86_64.zig b/std/os/bits/linux/x86_64.zig
new file mode 100644
index 0000000000..12ac6b8d7a
--- /dev/null
+++ b/std/os/bits/linux/x86_64.zig
@@ -0,0 +1,470 @@
+// x86-64-specific declarations that are intended to be imported into the POSIX namespace.
+const std = @import("../../../std.zig");
+
+const linux = std.os.linux;
+const sockaddr = linux.sockaddr;
+const socklen_t = linux.socklen_t;
+const iovec = linux.iovec;
+const iovec_const = linux.iovec_const;
+
+pub const SYS_read = 0;
+pub const SYS_write = 1;
+pub const SYS_open = 2;
+pub const SYS_close = 3;
+pub const SYS_stat = 4;
+pub const SYS_fstat = 5;
+pub const SYS_lstat = 6;
+pub const SYS_poll = 7;
+pub const SYS_lseek = 8;
+pub const SYS_mmap = 9;
+pub const SYS_mprotect = 10;
+pub const SYS_munmap = 11;
+pub const SYS_brk = 12;
+pub const SYS_rt_sigaction = 13;
+pub const SYS_rt_sigprocmask = 14;
+pub const SYS_rt_sigreturn = 15;
+pub const SYS_ioctl = 16;
+pub const SYS_pread = 17;
+pub const SYS_pwrite = 18;
+pub const SYS_readv = 19;
+pub const SYS_writev = 20;
+pub const SYS_access = 21;
+pub const SYS_pipe = 22;
+pub const SYS_select = 23;
+pub const SYS_sched_yield = 24;
+pub const SYS_mremap = 25;
+pub const SYS_msync = 26;
+pub const SYS_mincore = 27;
+pub const SYS_madvise = 28;
+pub const SYS_shmget = 29;
+pub const SYS_shmat = 30;
+pub const SYS_shmctl = 31;
+pub const SYS_dup = 32;
+pub const SYS_dup2 = 33;
+pub const SYS_pause = 34;
+pub const SYS_nanosleep = 35;
+pub const SYS_getitimer = 36;
+pub const SYS_alarm = 37;
+pub const SYS_setitimer = 38;
+pub const SYS_getpid = 39;
+pub const SYS_sendfile = 40;
+pub const SYS_socket = 41;
+pub const SYS_connect = 42;
+pub const SYS_accept = 43;
+pub const SYS_sendto = 44;
+pub const SYS_recvfrom = 45;
+pub const SYS_sendmsg = 46;
+pub const SYS_recvmsg = 47;
+pub const SYS_shutdown = 48;
+pub const SYS_bind = 49;
+pub const SYS_listen = 50;
+pub const SYS_getsockname = 51;
+pub const SYS_getpeername = 52;
+pub const SYS_socketpair = 53;
+pub const SYS_setsockopt = 54;
+pub const SYS_getsockopt = 55;
+pub const SYS_clone = 56;
+pub const SYS_fork = 57;
+pub const SYS_vfork = 58;
+pub const SYS_execve = 59;
+pub const SYS_exit = 60;
+pub const SYS_wait4 = 61;
+pub const SYS_kill = 62;
+pub const SYS_uname = 63;
+pub const SYS_semget = 64;
+pub const SYS_semop = 65;
+pub const SYS_semctl = 66;
+pub const SYS_shmdt = 67;
+pub const SYS_msgget = 68;
+pub const SYS_msgsnd = 69;
+pub const SYS_msgrcv = 70;
+pub const SYS_msgctl = 71;
+pub const SYS_fcntl = 72;
+pub const SYS_flock = 73;
+pub const SYS_fsync = 74;
+pub const SYS_fdatasync = 75;
+pub const SYS_truncate = 76;
+pub const SYS_ftruncate = 77;
+pub const SYS_getdents = 78;
+pub const SYS_getcwd = 79;
+pub const SYS_chdir = 80;
+pub const SYS_fchdir = 81;
+pub const SYS_rename = 82;
+pub const SYS_mkdir = 83;
+pub const SYS_rmdir = 84;
+pub const SYS_creat = 85;
+pub const SYS_link = 86;
+pub const SYS_unlink = 87;
+pub const SYS_symlink = 88;
+pub const SYS_readlink = 89;
+pub const SYS_chmod = 90;
+pub const SYS_fchmod = 91;
+pub const SYS_chown = 92;
+pub const SYS_fchown = 93;
+pub const SYS_lchown = 94;
+pub const SYS_umask = 95;
+pub const SYS_gettimeofday = 96;
+pub const SYS_getrlimit = 97;
+pub const SYS_getrusage = 98;
+pub const SYS_sysinfo = 99;
+pub const SYS_times = 100;
+pub const SYS_ptrace = 101;
+pub const SYS_getuid = 102;
+pub const SYS_syslog = 103;
+pub const SYS_getgid = 104;
+pub const SYS_setuid = 105;
+pub const SYS_setgid = 106;
+pub const SYS_geteuid = 107;
+pub const SYS_getegid = 108;
+pub const SYS_setpgid = 109;
+pub const SYS_getppid = 110;
+pub const SYS_getpgrp = 111;
+pub const SYS_setsid = 112;
+pub const SYS_setreuid = 113;
+pub const SYS_setregid = 114;
+pub const SYS_getgroups = 115;
+pub const SYS_setgroups = 116;
+pub const SYS_setresuid = 117;
+pub const SYS_getresuid = 118;
+pub const SYS_setresgid = 119;
+pub const SYS_getresgid = 120;
+pub const SYS_getpgid = 121;
+pub const SYS_setfsuid = 122;
+pub const SYS_setfsgid = 123;
+pub const SYS_getsid = 124;
+pub const SYS_capget = 125;
+pub const SYS_capset = 126;
+pub const SYS_rt_sigpending = 127;
+pub const SYS_rt_sigtimedwait = 128;
+pub const SYS_rt_sigqueueinfo = 129;
+pub const SYS_rt_sigsuspend = 130;
+pub const SYS_sigaltstack = 131;
+pub const SYS_utime = 132;
+pub const SYS_mknod = 133;
+pub const SYS_uselib = 134;
+pub const SYS_personality = 135;
+pub const SYS_ustat = 136;
+pub const SYS_statfs = 137;
+pub const SYS_fstatfs = 138;
+pub const SYS_sysfs = 139;
+pub const SYS_getpriority = 140;
+pub const SYS_setpriority = 141;
+pub const SYS_sched_setparam = 142;
+pub const SYS_sched_getparam = 143;
+pub const SYS_sched_setscheduler = 144;
+pub const SYS_sched_getscheduler = 145;
+pub const SYS_sched_get_priority_max = 146;
+pub const SYS_sched_get_priority_min = 147;
+pub const SYS_sched_rr_get_interval = 148;
+pub const SYS_mlock = 149;
+pub const SYS_munlock = 150;
+pub const SYS_mlockall = 151;
+pub const SYS_munlockall = 152;
+pub const SYS_vhangup = 153;
+pub const SYS_modify_ldt = 154;
+pub const SYS_pivot_root = 155;
+pub const SYS__sysctl = 156;
+pub const SYS_prctl = 157;
+pub const SYS_arch_prctl = 158;
+pub const SYS_adjtimex = 159;
+pub const SYS_setrlimit = 160;
+pub const SYS_chroot = 161;
+pub const SYS_sync = 162;
+pub const SYS_acct = 163;
+pub const SYS_settimeofday = 164;
+pub const SYS_mount = 165;
+pub const SYS_umount2 = 166;
+pub const SYS_swapon = 167;
+pub const SYS_swapoff = 168;
+pub const SYS_reboot = 169;
+pub const SYS_sethostname = 170;
+pub const SYS_setdomainname = 171;
+pub const SYS_iopl = 172;
+pub const SYS_ioperm = 173;
+pub const SYS_create_module = 174;
+pub const SYS_init_module = 175;
+pub const SYS_delete_module = 176;
+pub const SYS_get_kernel_syms = 177;
+pub const SYS_query_module = 178;
+pub const SYS_quotactl = 179;
+pub const SYS_nfsservctl = 180;
+pub const SYS_getpmsg = 181;
+pub const SYS_putpmsg = 182;
+pub const SYS_afs_syscall = 183;
+pub const SYS_tuxcall = 184;
+pub const SYS_security = 185;
+pub const SYS_gettid = 186;
+pub const SYS_readahead = 187;
+pub const SYS_setxattr = 188;
+pub const SYS_lsetxattr = 189;
+pub const SYS_fsetxattr = 190;
+pub const SYS_getxattr = 191;
+pub const SYS_lgetxattr = 192;
+pub const SYS_fgetxattr = 193;
+pub const SYS_listxattr = 194;
+pub const SYS_llistxattr = 195;
+pub const SYS_flistxattr = 196;
+pub const SYS_removexattr = 197;
+pub const SYS_lremovexattr = 198;
+pub const SYS_fremovexattr = 199;
+pub const SYS_tkill = 200;
+pub const SYS_time = 201;
+pub const SYS_futex = 202;
+pub const SYS_sched_setaffinity = 203;
+pub const SYS_sched_getaffinity = 204;
+pub const SYS_set_thread_area = 205;
+pub const SYS_io_setup = 206;
+pub const SYS_io_destroy = 207;
+pub const SYS_io_getevents = 208;
+pub const SYS_io_submit = 209;
+pub const SYS_io_cancel = 210;
+pub const SYS_get_thread_area = 211;
+pub const SYS_lookup_dcookie = 212;
+pub const SYS_epoll_create = 213;
+pub const SYS_epoll_ctl_old = 214;
+pub const SYS_epoll_wait_old = 215;
+pub const SYS_remap_file_pages = 216;
+pub const SYS_getdents64 = 217;
+pub const SYS_set_tid_address = 218;
+pub const SYS_restart_syscall = 219;
+pub const SYS_semtimedop = 220;
+pub const SYS_fadvise64 = 221;
+pub const SYS_timer_create = 222;
+pub const SYS_timer_settime = 223;
+pub const SYS_timer_gettime = 224;
+pub const SYS_timer_getoverrun = 225;
+pub const SYS_timer_delete = 226;
+pub const SYS_clock_settime = 227;
+pub const SYS_clock_gettime = 228;
+pub const SYS_clock_getres = 229;
+pub const SYS_clock_nanosleep = 230;
+pub const SYS_exit_group = 231;
+pub const SYS_epoll_wait = 232;
+pub const SYS_epoll_ctl = 233;
+pub const SYS_tgkill = 234;
+pub const SYS_utimes = 235;
+pub const SYS_vserver = 236;
+pub const SYS_mbind = 237;
+pub const SYS_set_mempolicy = 238;
+pub const SYS_get_mempolicy = 239;
+pub const SYS_mq_open = 240;
+pub const SYS_mq_unlink = 241;
+pub const SYS_mq_timedsend = 242;
+pub const SYS_mq_timedreceive = 243;
+pub const SYS_mq_notify = 244;
+pub const SYS_mq_getsetattr = 245;
+pub const SYS_kexec_load = 246;
+pub const SYS_waitid = 247;
+pub const SYS_add_key = 248;
+pub const SYS_request_key = 249;
+pub const SYS_keyctl = 250;
+pub const SYS_ioprio_set = 251;
+pub const SYS_ioprio_get = 252;
+pub const SYS_inotify_init = 253;
+pub const SYS_inotify_add_watch = 254;
+pub const SYS_inotify_rm_watch = 255;
+pub const SYS_migrate_pages = 256;
+pub const SYS_openat = 257;
+pub const SYS_mkdirat = 258;
+pub const SYS_mknodat = 259;
+pub const SYS_fchownat = 260;
+pub const SYS_futimesat = 261;
+pub const SYS_newfstatat = 262;
+pub const SYS_fstatat = 262;
+pub const SYS_unlinkat = 263;
+pub const SYS_renameat = 264;
+pub const SYS_linkat = 265;
+pub const SYS_symlinkat = 266;
+pub const SYS_readlinkat = 267;
+pub const SYS_fchmodat = 268;
+pub const SYS_faccessat = 269;
+pub const SYS_pselect6 = 270;
+pub const SYS_ppoll = 271;
+pub const SYS_unshare = 272;
+pub const SYS_set_robust_list = 273;
+pub const SYS_get_robust_list = 274;
+pub const SYS_splice = 275;
+pub const SYS_tee = 276;
+pub const SYS_sync_file_range = 277;
+pub const SYS_vmsplice = 278;
+pub const SYS_move_pages = 279;
+pub const SYS_utimensat = 280;
+pub const SYS_epoll_pwait = 281;
+pub const SYS_signalfd = 282;
+pub const SYS_timerfd_create = 283;
+pub const SYS_eventfd = 284;
+pub const SYS_fallocate = 285;
+pub const SYS_timerfd_settime = 286;
+pub const SYS_timerfd_gettime = 287;
+pub const SYS_accept4 = 288;
+pub const SYS_signalfd4 = 289;
+pub const SYS_eventfd2 = 290;
+pub const SYS_epoll_create1 = 291;
+pub const SYS_dup3 = 292;
+pub const SYS_pipe2 = 293;
+pub const SYS_inotify_init1 = 294;
+pub const SYS_preadv = 295;
+pub const SYS_pwritev = 296;
+pub const SYS_rt_tgsigqueueinfo = 297;
+pub const SYS_perf_event_open = 298;
+pub const SYS_recvmmsg = 299;
+pub const SYS_fanotify_init = 300;
+pub const SYS_fanotify_mark = 301;
+pub const SYS_prlimit64 = 302;
+pub const SYS_name_to_handle_at = 303;
+pub const SYS_open_by_handle_at = 304;
+pub const SYS_clock_adjtime = 305;
+pub const SYS_syncfs = 306;
+pub const SYS_sendmmsg = 307;
+pub const SYS_setns = 308;
+pub const SYS_getcpu = 309;
+pub const SYS_process_vm_readv = 310;
+pub const SYS_process_vm_writev = 311;
+pub const SYS_kcmp = 312;
+pub const SYS_finit_module = 313;
+pub const SYS_sched_setattr = 314;
+pub const SYS_sched_getattr = 315;
+pub const SYS_renameat2 = 316;
+pub const SYS_seccomp = 317;
+pub const SYS_getrandom = 318;
+pub const SYS_memfd_create = 319;
+pub const SYS_kexec_file_load = 320;
+pub const SYS_bpf = 321;
+pub const SYS_execveat = 322;
+pub const SYS_userfaultfd = 323;
+pub const SYS_membarrier = 324;
+pub const SYS_mlock2 = 325;
+pub const SYS_copy_file_range = 326;
+pub const SYS_preadv2 = 327;
+pub const SYS_pwritev2 = 328;
+pub const SYS_pkey_mprotect = 329;
+pub const SYS_pkey_alloc = 330;
+pub const SYS_pkey_free = 331;
+pub const SYS_statx = 332;
+pub const SYS_io_pgetevents = 333;
+pub const SYS_rseq = 334;
+pub const SYS_pidfd_send_signal = 424;
+pub const SYS_io_uring_setup = 425;
+pub const SYS_io_uring_enter = 426;
+pub const SYS_io_uring_register = 427;
+
+pub const O_CREAT = 0o100;
+pub const O_EXCL = 0o200;
+pub const O_NOCTTY = 0o400;
+pub const O_TRUNC = 0o1000;
+pub const O_APPEND = 0o2000;
+pub const O_NONBLOCK = 0o4000;
+pub const O_DSYNC = 0o10000;
+pub const O_SYNC = 0o4010000;
+pub const O_RSYNC = 0o4010000;
+pub const O_DIRECTORY = 0o200000;
+pub const O_NOFOLLOW = 0o400000;
+pub const O_CLOEXEC = 0o2000000;
+
+pub const O_ASYNC = 0o20000;
+pub const O_DIRECT = 0o40000;
+pub const O_LARGEFILE = 0;
+pub const O_NOATIME = 0o1000000;
+pub const O_PATH = 0o10000000;
+pub const O_TMPFILE = 0o20200000;
+pub const O_NDELAY = O_NONBLOCK;
+
+pub const F_DUPFD = 0;
+pub const F_GETFD = 1;
+pub const F_SETFD = 2;
+pub const F_GETFL = 3;
+pub const F_SETFL = 4;
+
+pub const F_SETOWN = 8;
+pub const F_GETOWN = 9;
+pub const F_SETSIG = 10;
+pub const F_GETSIG = 11;
+
+pub const F_GETLK = 5;
+pub const F_SETLK = 6;
+pub const F_SETLKW = 7;
+
+pub const F_SETOWN_EX = 15;
+pub const F_GETOWN_EX = 16;
+
+pub const F_GETOWNER_UIDS = 17;
+
+pub const AT_FDCWD = -100;
+pub const AT_SYMLINK_NOFOLLOW = 0x100;
+pub const AT_REMOVEDIR = 0x200;
+pub const AT_SYMLINK_FOLLOW = 0x400;
+pub const AT_NO_AUTOMOUNT = 0x800;
+pub const AT_EMPTY_PATH = 0x1000;
+
+pub const VDSO_USEFUL = true;
+pub const VDSO_CGT_SYM = "__vdso_clock_gettime";
+pub const VDSO_CGT_VER = "LINUX_2.6";
+pub const VDSO_GETCPU_SYM = "__vdso_getcpu";
+pub const VDSO_GETCPU_VER = "LINUX_2.6";
+
+pub const ARCH_SET_GS = 0x1001;
+pub const ARCH_SET_FS = 0x1002;
+pub const ARCH_GET_FS = 0x1003;
+pub const ARCH_GET_GS = 0x1004;
+
+pub const msghdr = extern struct {
+ msg_name: ?*sockaddr,
+ msg_namelen: socklen_t,
+ msg_iov: [*]iovec,
+ msg_iovlen: i32,
+ __pad1: i32,
+ msg_control: ?*c_void,
+ msg_controllen: socklen_t,
+ __pad2: socklen_t,
+ msg_flags: i32,
+};
+
+pub const msghdr_const = extern struct {
+ msg_name: ?*const sockaddr,
+ msg_namelen: socklen_t,
+ msg_iov: [*]iovec_const,
+ msg_iovlen: i32,
+ __pad1: i32,
+ msg_control: ?*c_void,
+ msg_controllen: socklen_t,
+ __pad2: socklen_t,
+ msg_flags: i32,
+};
+
+/// Renamed to Stat to not conflict with the stat function.
+pub const Stat = extern struct {
+ dev: u64,
+ ino: u64,
+ nlink: usize,
+
+ mode: u32,
+ uid: u32,
+ gid: u32,
+ __pad0: u32,
+ rdev: u64,
+ size: i64,
+ blksize: isize,
+ blocks: i64,
+
+ atim: timespec,
+ mtim: timespec,
+ ctim: timespec,
+ __unused: [3]isize,
+};
+
+pub const timespec = extern struct {
+ tv_sec: isize,
+ tv_nsec: isize,
+};
+
+pub const timeval = extern struct {
+ tv_sec: isize,
+ tv_usec: isize,
+};
+
+pub const timezone = extern struct {
+ tz_minuteswest: i32,
+ tz_dsttime: i32,
+};
+
+pub const Elf_Symndx = u32;
diff --git a/std/os/bits/netbsd.zig b/std/os/bits/netbsd.zig
new file mode 100644
index 0000000000..fc4c2904e0
--- /dev/null
+++ b/std/os/bits/netbsd.zig
@@ -0,0 +1,725 @@
+const std = @import("../../std.zig");
+const maxInt = std.math.maxInt;
+
+pub const fd_t = c_int;
+pub const pid_t = c_int;
+
+/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
+pub const Kevent = extern struct {
+ ident: usize,
+ filter: i32,
+ flags: u32,
+ fflags: u32,
+ data: i64,
+ udata: usize,
+};
+
+pub const pthread_attr_t = extern struct {
+ pta_magic: u32,
+ pta_flags: c_int,
+ pta_private: *c_void,
+};
+
+pub const msghdr = extern struct {
+ /// optional address
+ msg_name: ?*sockaddr,
+
+ /// size of address
+ msg_namelen: socklen_t,
+
+ /// scatter/gather array
+ msg_iov: [*]iovec,
+
+ /// # elements in msg_iov
+ msg_iovlen: i32,
+
+ /// ancillary data
+ msg_control: ?*c_void,
+
+ /// ancillary data buffer len
+ msg_controllen: socklen_t,
+
+ /// flags on received message
+ msg_flags: i32,
+};
+
+pub const msghdr_const = extern struct {
+ /// optional address
+ msg_name: ?*const sockaddr,
+
+ /// size of address
+ msg_namelen: socklen_t,
+
+ /// scatter/gather array
+ msg_iov: [*]iovec_const,
+
+ /// # elements in msg_iov
+ msg_iovlen: i32,
+
+ /// ancillary data
+ msg_control: ?*c_void,
+
+ /// ancillary data buffer len
+ msg_controllen: socklen_t,
+
+ /// flags on received message
+ msg_flags: i32,
+};
+
+pub const Stat = extern struct {
+ dev: u64,
+ mode: u32,
+ ino: u64,
+ nlink: usize,
+
+ uid: u32,
+ gid: u32,
+ rdev: u64,
+
+ atim: timespec,
+ mtim: timespec,
+ ctim: timespec,
+ birthtim: timespec,
+
+ size: i64,
+ blocks: i64,
+ blksize: isize,
+ flags: u32,
+ gen: u32,
+ __spare: [2]u32,
+};
+
+pub const timespec = extern struct {
+ tv_sec: i64,
+ tv_nsec: isize,
+};
+
+pub const dirent = extern struct {
+ d_fileno: u64,
+ d_reclen: u16,
+ d_namlen: u16,
+ d_type: u8,
+ d_off: i64,
+ d_name: [512]u8,
+};
+
+pub const in_port_t = u16;
+pub const sa_family_t = u8;
+
+pub const sockaddr = extern union {
+ in: sockaddr_in,
+ in6: sockaddr_in6,
+};
+
+pub const sockaddr_in = extern struct {
+ len: u8,
+ family: sa_family_t,
+ port: in_port_t,
+ addr: u32,
+ zero: [8]u8,
+};
+
+pub const sockaddr_in6 = extern struct {
+ len: u8,
+ family: sa_family_t,
+ port: in_port_t,
+ flowinfo: u32,
+ addr: [16]u8,
+ scope_id: u32,
+};
+
+pub const CTL_KERN = 1;
+pub const CTL_DEBUG = 5;
+
+pub const KERN_PROC_ARGS = 48; // struct: process argv/env
+pub const KERN_PROC_PATHNAME = 5; // path to executable
+
+pub const PATH_MAX = 1024;
+
+pub const STDIN_FILENO = 0;
+pub const STDOUT_FILENO = 1;
+pub const STDERR_FILENO = 2;
+
+pub const PROT_NONE = 0;
+pub const PROT_READ = 1;
+pub const PROT_WRITE = 2;
+pub const PROT_EXEC = 4;
+
+pub const CLOCK_REALTIME = 0;
+pub const CLOCK_VIRTUAL = 1;
+pub const CLOCK_PROF = 2;
+pub const CLOCK_MONOTONIC = 3;
+pub const CLOCK_THREAD_CPUTIME_ID = 0x20000000;
+pub const CLOCK_PROCESS_CPUTIME_ID = 0x40000000;
+
+pub const MAP_FAILED = @intToPtr(*c_void, maxInt(usize));
+pub const MAP_SHARED = 0x0001;
+pub const MAP_PRIVATE = 0x0002;
+pub const MAP_REMAPDUP = 0x0004;
+pub const MAP_FIXED = 0x0010;
+pub const MAP_RENAME = 0x0020;
+pub const MAP_NORESERVE = 0x0040;
+pub const MAP_INHERIT = 0x0080;
+pub const MAP_HASSEMAPHORE = 0x0200;
+pub const MAP_TRYFIXED = 0x0400;
+pub const MAP_WIRED = 0x0800;
+
+pub const MAP_FILE = 0x0000;
+pub const MAP_NOSYNC = 0x0800;
+pub const MAP_ANON = 0x1000;
+pub const MAP_ANONYMOUS = MAP_ANON;
+pub const MAP_STACK = 0x2000;
+
+pub const WNOHANG = 0x00000001;
+pub const WUNTRACED = 0x00000002;
+pub const WSTOPPED = WUNTRACED;
+pub const WCONTINUED = 0x00000010;
+pub const WNOWAIT = 0x00010000;
+pub const WEXITED = 0x00000020;
+pub const WTRAPPED = 0x00000040;
+
+pub const SA_ONSTACK = 0x0001;
+pub const SA_RESTART = 0x0002;
+pub const SA_RESETHAND = 0x0004;
+pub const SA_NOCLDSTOP = 0x0008;
+pub const SA_NODEFER = 0x0010;
+pub const SA_NOCLDWAIT = 0x0020;
+pub const SA_SIGINFO = 0x0040;
+
+pub const SIGHUP = 1;
+pub const SIGINT = 2;
+pub const SIGQUIT = 3;
+pub const SIGILL = 4;
+pub const SIGTRAP = 5;
+pub const SIGABRT = 6;
+pub const SIGIOT = SIGABRT;
+pub const SIGEMT = 7;
+pub const SIGFPE = 8;
+pub const SIGKILL = 9;
+pub const SIGBUS = 10;
+pub const SIGSEGV = 11;
+pub const SIGSYS = 12;
+pub const SIGPIPE = 13;
+pub const SIGALRM = 14;
+pub const SIGTERM = 15;
+pub const SIGURG = 16;
+pub const SIGSTOP = 17;
+pub const SIGTSTP = 18;
+pub const SIGCONT = 19;
+pub const SIGCHLD = 20;
+pub const SIGTTIN = 21;
+pub const SIGTTOU = 22;
+pub const SIGIO = 23;
+pub const SIGXCPU = 24;
+pub const SIGXFSZ = 25;
+pub const SIGVTALRM = 26;
+pub const SIGPROF = 27;
+pub const SIGWINCH = 28;
+pub const SIGINFO = 29;
+pub const SIGUSR1 = 30;
+pub const SIGUSR2 = 31;
+pub const SIGPWR = 32;
+
+pub const SIGRTMIN = 33;
+pub const SIGRTMAX = 63;
+
+// access function
+pub const F_OK = 0; // test for existence of file
+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_RDONLY = 0x0000;
+pub const O_WRONLY = 0x0001;
+pub const O_RDWR = 0x0002;
+pub const O_ACCMODE = 0x0003;
+
+pub const O_CREAT = 0x0200;
+pub const O_EXCL = 0x0800;
+pub const O_NOCTTY = 0x8000;
+pub const O_TRUNC = 0x0400;
+pub const O_APPEND = 0x0008;
+pub const O_NONBLOCK = 0x0004;
+pub const O_DSYNC = 0x00010000;
+pub const O_SYNC = 0x0080;
+pub const O_RSYNC = 0x00020000;
+pub const O_DIRECTORY = 0x00080000;
+pub const O_NOFOLLOW = 0x00000100;
+pub const O_CLOEXEC = 0x00400000;
+
+pub const O_ASYNC = 0x0040;
+pub const O_DIRECT = 0x00080000;
+pub const O_LARGEFILE = 0;
+pub const O_NOATIME = 0;
+pub const O_PATH = 0;
+pub const O_TMPFILE = 0;
+pub const O_NDELAY = O_NONBLOCK;
+
+pub const F_DUPFD = 0;
+pub const F_GETFD = 1;
+pub const F_SETFD = 2;
+pub const F_GETFL = 3;
+pub const F_SETFL = 4;
+
+pub const F_GETOWN = 5;
+pub const F_SETOWN = 6;
+
+pub const F_GETLK = 7;
+pub const F_SETLK = 8;
+pub const F_SETLKW = 9;
+
+pub const SEEK_SET = 0;
+pub const SEEK_CUR = 1;
+pub const SEEK_END = 2;
+
+pub const SIG_BLOCK = 1;
+pub const SIG_UNBLOCK = 2;
+pub const SIG_SETMASK = 3;
+
+pub const SOCK_STREAM = 1;
+pub const SOCK_DGRAM = 2;
+pub const SOCK_RAW = 3;
+pub const SOCK_RDM = 4;
+pub const SOCK_SEQPACKET = 5;
+
+pub const SOCK_CLOEXEC = 0x10000000;
+pub const SOCK_NONBLOCK = 0x20000000;
+
+pub const PROTO_ip = 0;
+pub const PROTO_icmp = 1;
+pub const PROTO_igmp = 2;
+pub const PROTO_ggp = 3;
+pub const PROTO_ipencap = 4;
+pub const PROTO_tcp = 6;
+pub const PROTO_egp = 8;
+pub const PROTO_pup = 12;
+pub const PROTO_udp = 17;
+pub const PROTO_xns_idp = 22;
+pub const PROTO_iso_tp4 = 29;
+pub const PROTO_ipv6 = 41;
+pub const PROTO_ipv6_route = 43;
+pub const PROTO_ipv6_frag = 44;
+pub const PROTO_rsvp = 46;
+pub const PROTO_gre = 47;
+pub const PROTO_esp = 50;
+pub const PROTO_ah = 51;
+pub const PROTO_ipv6_icmp = 58;
+pub const PROTO_ipv6_nonxt = 59;
+pub const PROTO_ipv6_opts = 60;
+pub const PROTO_encap = 98;
+pub const PROTO_pim = 103;
+pub const PROTO_raw = 255;
+
+pub const PF_UNSPEC = 0;
+pub const PF_LOCAL = 1;
+pub const PF_UNIX = PF_LOCAL;
+pub const PF_FILE = PF_LOCAL;
+pub const PF_INET = 2;
+pub const PF_APPLETALK = 16;
+pub const PF_INET6 = 24;
+pub const PF_DECnet = 12;
+pub const PF_KEY = 29;
+pub const PF_ROUTE = 34;
+pub const PF_SNA = 11;
+pub const PF_MPLS = 33;
+pub const PF_CAN = 35;
+pub const PF_BLUETOOTH = 31;
+pub const PF_ISDN = 26;
+pub const PF_MAX = 37;
+
+pub const AF_UNSPEC = PF_UNSPEC;
+pub const AF_LOCAL = PF_LOCAL;
+pub const AF_UNIX = AF_LOCAL;
+pub const AF_FILE = AF_LOCAL;
+pub const AF_INET = PF_INET;
+pub const AF_APPLETALK = PF_APPLETALK;
+pub const AF_INET6 = PF_INET6;
+pub const AF_KEY = PF_KEY;
+pub const AF_ROUTE = PF_ROUTE;
+pub const AF_SNA = PF_SNA;
+pub const AF_MPLS = PF_MPLS;
+pub const AF_CAN = PF_CAN;
+pub const AF_BLUETOOTH = PF_BLUETOOTH;
+pub const AF_ISDN = PF_ISDN;
+pub const AF_MAX = PF_MAX;
+
+pub const DT_UNKNOWN = 0;
+pub const DT_FIFO = 1;
+pub const DT_CHR = 2;
+pub const DT_DIR = 4;
+pub const DT_BLK = 6;
+pub const DT_REG = 8;
+pub const DT_LNK = 10;
+pub const DT_SOCK = 12;
+pub const DT_WHT = 14;
+
+/// add event to kq (implies enable)
+pub const EV_ADD = 0x0001;
+
+/// delete event from kq
+pub const EV_DELETE = 0x0002;
+
+/// enable event
+pub const EV_ENABLE = 0x0004;
+
+/// disable event (not reported)
+pub const EV_DISABLE = 0x0008;
+
+/// only report one occurrence
+pub const EV_ONESHOT = 0x0010;
+
+/// clear event state after reporting
+pub const EV_CLEAR = 0x0020;
+
+/// force immediate event output
+/// ... with or without EV_ERROR
+/// ... use KEVENT_FLAG_ERROR_EVENTS
+/// on syscalls supporting flags
+pub const EV_RECEIPT = 0x0040;
+
+/// disable event after reporting
+pub const EV_DISPATCH = 0x0080;
+
+pub const EVFILT_READ = 0;
+pub const EVFILT_WRITE = 1;
+
+/// attached to aio requests
+pub const EVFILT_AIO = 2;
+
+/// attached to vnodes
+pub const EVFILT_VNODE = 3;
+
+/// attached to struct proc
+pub const EVFILT_PROC = 4;
+
+/// attached to struct proc
+pub const EVFILT_SIGNAL = 5;
+
+/// timers
+pub const EVFILT_TIMER = 6;
+
+/// Filesystem events
+pub const EVFILT_FS = 7;
+
+/// On input, NOTE_TRIGGER causes the event to be triggered for output.
+pub const NOTE_TRIGGER = 0x08000000;
+
+/// low water mark
+pub const NOTE_LOWAT = 0x00000001;
+
+/// vnode was removed
+pub const NOTE_DELETE = 0x00000001;
+
+/// data contents changed
+pub const NOTE_WRITE = 0x00000002;
+
+/// size increased
+pub const NOTE_EXTEND = 0x00000004;
+
+/// attributes changed
+pub const NOTE_ATTRIB = 0x00000008;
+
+/// link count changed
+pub const NOTE_LINK = 0x00000010;
+
+/// vnode was renamed
+pub const NOTE_RENAME = 0x00000020;
+
+/// vnode access was revoked
+pub const NOTE_REVOKE = 0x00000040;
+
+/// process exited
+pub const NOTE_EXIT = 0x80000000;
+
+/// process forked
+pub const NOTE_FORK = 0x40000000;
+
+/// process exec'd
+pub const NOTE_EXEC = 0x20000000;
+
+/// mask for signal & exit status
+pub const NOTE_PDATAMASK = 0x000fffff;
+pub const NOTE_PCTRLMASK = 0xf0000000;
+
+pub const TIOCCBRK = 0x2000747a;
+pub const TIOCCDTR = 0x20007478;
+pub const TIOCCONS = 0x80047462;
+pub const TIOCDCDTIMESTAMP = 0x40107458;
+pub const TIOCDRAIN = 0x2000745e;
+pub const TIOCEXCL = 0x2000740d;
+pub const TIOCEXT = 0x80047460;
+pub const TIOCFLAG_CDTRCTS = 0x10;
+pub const TIOCFLAG_CLOCAL = 0x2;
+pub const TIOCFLAG_CRTSCTS = 0x4;
+pub const TIOCFLAG_MDMBUF = 0x8;
+pub const TIOCFLAG_SOFTCAR = 0x1;
+pub const TIOCFLUSH = 0x80047410;
+pub const TIOCGETA = 0x402c7413;
+pub const TIOCGETD = 0x4004741a;
+pub const TIOCGFLAGS = 0x4004745d;
+pub const TIOCGLINED = 0x40207442;
+pub const TIOCGPGRP = 0x40047477;
+pub const TIOCGQSIZE = 0x40047481;
+pub const TIOCGRANTPT = 0x20007447;
+pub const TIOCGSID = 0x40047463;
+pub const TIOCGSIZE = 0x40087468;
+pub const TIOCGWINSZ = 0x40087468;
+pub const TIOCMBIC = 0x8004746b;
+pub const TIOCMBIS = 0x8004746c;
+pub const TIOCMGET = 0x4004746a;
+pub const TIOCMSET = 0x8004746d;
+pub const TIOCM_CAR = 0x40;
+pub const TIOCM_CD = 0x40;
+pub const TIOCM_CTS = 0x20;
+pub const TIOCM_DSR = 0x100;
+pub const TIOCM_DTR = 0x2;
+pub const TIOCM_LE = 0x1;
+pub const TIOCM_RI = 0x80;
+pub const TIOCM_RNG = 0x80;
+pub const TIOCM_RTS = 0x4;
+pub const TIOCM_SR = 0x10;
+pub const TIOCM_ST = 0x8;
+pub const TIOCNOTTY = 0x20007471;
+pub const TIOCNXCL = 0x2000740e;
+pub const TIOCOUTQ = 0x40047473;
+pub const TIOCPKT = 0x80047470;
+pub const TIOCPKT_DATA = 0x0;
+pub const TIOCPKT_DOSTOP = 0x20;
+pub const TIOCPKT_FLUSHREAD = 0x1;
+pub const TIOCPKT_FLUSHWRITE = 0x2;
+pub const TIOCPKT_IOCTL = 0x40;
+pub const TIOCPKT_NOSTOP = 0x10;
+pub const TIOCPKT_START = 0x8;
+pub const TIOCPKT_STOP = 0x4;
+pub const TIOCPTMGET = 0x40287446;
+pub const TIOCPTSNAME = 0x40287448;
+pub const TIOCRCVFRAME = 0x80087445;
+pub const TIOCREMOTE = 0x80047469;
+pub const TIOCSBRK = 0x2000747b;
+pub const TIOCSCTTY = 0x20007461;
+pub const TIOCSDTR = 0x20007479;
+pub const TIOCSETA = 0x802c7414;
+pub const TIOCSETAF = 0x802c7416;
+pub const TIOCSETAW = 0x802c7415;
+pub const TIOCSETD = 0x8004741b;
+pub const TIOCSFLAGS = 0x8004745c;
+pub const TIOCSIG = 0x2000745f;
+pub const TIOCSLINED = 0x80207443;
+pub const TIOCSPGRP = 0x80047476;
+pub const TIOCSQSIZE = 0x80047480;
+pub const TIOCSSIZE = 0x80087467;
+pub const TIOCSTART = 0x2000746e;
+pub const TIOCSTAT = 0x80047465;
+pub const TIOCSTI = 0x80017472;
+pub const TIOCSTOP = 0x2000746f;
+pub const TIOCSWINSZ = 0x80087467;
+pub const TIOCUCNTL = 0x80047466;
+pub const TIOCXMTFRAME = 0x80087444;
+
+pub fn WEXITSTATUS(s: u32) u32 {
+ return (s >> 8) & 0xff;
+}
+pub fn WTERMSIG(s: u32) u32 {
+ return s & 0x7f;
+}
+pub fn WSTOPSIG(s: u32) u32 {
+ return WEXITSTATUS(s);
+}
+pub fn WIFEXITED(s: u32) bool {
+ return WTERMSIG(s) == 0;
+}
+
+pub fn WIFCONTINUED(s: u32) bool {
+ return ((s & 0x7f) == 0xffff);
+}
+
+pub fn WIFSTOPPED(s: u32) bool {
+ return ((s & 0x7f != 0x7f) and !WIFCONTINUED(s));
+}
+
+pub fn WIFSIGNALED(s: u32) bool {
+ return !WIFSTOPPED(s) and !WIFCONTINUED(s) and !WIFEXITED(s);
+}
+
+pub const winsize = extern struct {
+ ws_row: u16,
+ ws_col: u16,
+ ws_xpixel: u16,
+ ws_ypixel: u16,
+};
+
+const NSIG = 32;
+
+pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
+pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
+pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
+
+/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
+pub const Sigaction = extern struct {
+ /// signal handler
+ __sigaction_u: extern union {
+ __sa_handler: extern fn (i32) void,
+ __sa_sigaction: extern fn (i32, *__siginfo, usize) void,
+ },
+
+ /// see signal options
+ sa_flags: u32,
+
+ /// signal mask to apply
+ sa_mask: sigset_t,
+};
+
+pub const _SIG_WORDS = 4;
+pub const _SIG_MAXSIG = 128;
+
+pub inline fn _SIG_IDX(sig: usize) usize {
+ return sig - 1;
+}
+pub inline fn _SIG_WORD(sig: usize) usize {
+ return_SIG_IDX(sig) >> 5;
+}
+pub inline fn _SIG_BIT(sig: usize) usize {
+ return 1 << (_SIG_IDX(sig) & 31);
+}
+pub inline fn _SIG_VALID(sig: usize) usize {
+ return sig <= _SIG_MAXSIG and sig > 0;
+}
+
+pub const sigset_t = extern struct {
+ __bits: [_SIG_WORDS]u32,
+};
+
+pub const EPERM = 1; // Operation not permitted
+pub const ENOENT = 2; // No such file or directory
+pub const ESRCH = 3; // No such process
+pub const EINTR = 4; // Interrupted system call
+pub const EIO = 5; // Input/output error
+pub const ENXIO = 6; // Device not configured
+pub const E2BIG = 7; // Argument list too long
+pub const ENOEXEC = 8; // Exec format error
+pub const EBADF = 9; // Bad file descriptor
+pub const ECHILD = 10; // No child processes
+pub const EDEADLK = 11; // Resource deadlock avoided
+// 11 was EAGAIN
+pub const ENOMEM = 12; // Cannot allocate memory
+pub const EACCES = 13; // Permission denied
+pub const EFAULT = 14; // Bad address
+pub const ENOTBLK = 15; // Block device required
+pub const EBUSY = 16; // Device busy
+pub const EEXIST = 17; // File exists
+pub const EXDEV = 18; // Cross-device link
+pub const ENODEV = 19; // Operation not supported by device
+pub const ENOTDIR = 20; // Not a directory
+pub const EISDIR = 21; // Is a directory
+pub const EINVAL = 22; // Invalid argument
+pub const ENFILE = 23; // Too many open files in system
+pub const EMFILE = 24; // Too many open files
+pub const ENOTTY = 25; // Inappropriate ioctl for device
+pub const ETXTBSY = 26; // Text file busy
+pub const EFBIG = 27; // File too large
+pub const ENOSPC = 28; // No space left on device
+pub const ESPIPE = 29; // Illegal seek
+pub const EROFS = 30; // Read-only file system
+pub const EMLINK = 31; // Too many links
+pub const EPIPE = 32; // Broken pipe
+
+// math software
+pub const EDOM = 33; // Numerical argument out of domain
+pub const ERANGE = 34; // Result too large or too small
+
+// non-blocking and interrupt i/o
+pub const EAGAIN = 35; // Resource temporarily unavailable
+pub const EWOULDBLOCK = EAGAIN; // Operation would block
+pub const EINPROGRESS = 36; // Operation now in progress
+pub const EALREADY = 37; // Operation already in progress
+
+// ipc/network software -- argument errors
+pub const ENOTSOCK = 38; // Socket operation on non-socket
+pub const EDESTADDRREQ = 39; // Destination address required
+pub const EMSGSIZE = 40; // Message too long
+pub const EPROTOTYPE = 41; // Protocol wrong type for socket
+pub const ENOPROTOOPT = 42; // Protocol option not available
+pub const EPROTONOSUPPORT = 43; // Protocol not supported
+pub const ESOCKTNOSUPPORT = 44; // Socket type not supported
+pub const EOPNOTSUPP = 45; // Operation not supported
+pub const EPFNOSUPPORT = 46; // Protocol family not supported
+pub const EAFNOSUPPORT = 47; // Address family not supported by protocol family
+pub const EADDRINUSE = 48; // Address already in use
+pub const EADDRNOTAVAIL = 49; // Can't assign requested address
+
+// ipc/network software -- operational errors
+pub const ENETDOWN = 50; // Network is down
+pub const ENETUNREACH = 51; // Network is unreachable
+pub const ENETRESET = 52; // Network dropped connection on reset
+pub const ECONNABORTED = 53; // Software caused connection abort
+pub const ECONNRESET = 54; // Connection reset by peer
+pub const ENOBUFS = 55; // No buffer space available
+pub const EISCONN = 56; // Socket is already connected
+pub const ENOTCONN = 57; // Socket is not connected
+pub const ESHUTDOWN = 58; // Can't send after socket shutdown
+pub const ETOOMANYREFS = 59; // Too many references: can't splice
+pub const ETIMEDOUT = 60; // Operation timed out
+pub const ECONNREFUSED = 61; // Connection refused
+
+pub const ELOOP = 62; // Too many levels of symbolic links
+pub const ENAMETOOLONG = 63; // File name too long
+
+// should be rearranged
+pub const EHOSTDOWN = 64; // Host is down
+pub const EHOSTUNREACH = 65; // No route to host
+pub const ENOTEMPTY = 66; // Directory not empty
+
+// quotas & mush
+pub const EPROCLIM = 67; // Too many processes
+pub const EUSERS = 68; // Too many users
+pub const EDQUOT = 69; // Disc quota exceeded
+
+// Network File System
+pub const ESTALE = 70; // Stale NFS file handle
+pub const EREMOTE = 71; // Too many levels of remote in path
+pub const EBADRPC = 72; // RPC struct is bad
+pub const ERPCMISMATCH = 73; // RPC version wrong
+pub const EPROGUNAVAIL = 74; // RPC prog. not avail
+pub const EPROGMISMATCH = 75; // Program version wrong
+pub const EPROCUNAVAIL = 76; // Bad procedure for program
+
+pub const ENOLCK = 77; // No locks available
+pub const ENOSYS = 78; // Function not implemented
+
+pub const EFTYPE = 79; // Inappropriate file type or format
+pub const EAUTH = 80; // Authentication error
+pub const ENEEDAUTH = 81; // Need authenticator
+
+// SystemV IPC
+pub const EIDRM = 82; // Identifier removed
+pub const ENOMSG = 83; // No message of desired type
+pub const EOVERFLOW = 84; // Value too large to be stored in data type
+
+// Wide/multibyte-character handling, ISO/IEC 9899/AMD1:1995
+pub const EILSEQ = 85; // Illegal byte sequence
+
+// From IEEE Std 1003.1-2001
+// Base, Realtime, Threads or Thread Priority Scheduling option errors
+pub const ENOTSUP = 86; // Not supported
+
+// Realtime option errors
+pub const ECANCELED = 87; // Operation canceled
+
+// Realtime, XSI STREAMS option errors
+pub const EBADMSG = 88; // Bad or Corrupt message
+
+// XSI STREAMS option errors
+pub const ENODATA = 89; // No message available
+pub const ENOSR = 90; // No STREAM resources
+pub const ENOSTR = 91; // Not a STREAM
+pub const ETIME = 92; // STREAM ioctl timeout
+
+// File system extended attribute errors
+pub const ENOATTR = 93; // Attribute not found
+
+// Realtime, XSI STREAMS option errors
+pub const EMULTIHOP = 94; // Multihop attempted
+pub const ENOLINK = 95; // Link has been severed
+pub const EPROTO = 96; // Protocol error
+
+pub const ELAST = 96; // Must equal largest errno
diff --git a/std/os/wasi/core.zig b/std/os/bits/wasi.zig
index f2bef73be9..93d2a82fde 100644
--- a/std/os/wasi/core.zig
+++ b/std/os/bits/wasi.zig
@@ -1,5 +1,6 @@
-// Based on https://github.com/CraneStation/wasi-sysroot/blob/wasi/libc-bottom-half/headers/public/wasi/core.h
-// and https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md
+pub const STDIN_FILENO = 0;
+pub const STDOUT_FILENO = 1;
+pub const STDERR_FILENO = 2;
pub const advice_t = u8;
pub const ADVICE_NORMAL: advice_t = 0;
@@ -9,11 +10,6 @@ pub const ADVICE_WILLNEED: advice_t = 3;
pub const ADVICE_DONTNEED: advice_t = 4;
pub const ADVICE_NOREUSE: advice_t = 5;
-pub const ciovec_t = extern struct {
- buf: [*]const u8,
- buf_len: usize,
-};
-
pub const clockid_t = u32;
pub const CLOCK_REALTIME: clockid_t = 0;
pub const CLOCK_MONOTONIC: clockid_t = 1;
@@ -182,11 +178,6 @@ pub const FILESTAT_SET_MTIM_NOW: fstflags_t = 0x0008;
pub const inode_t = u64;
-pub const iovec_t = extern struct {
- buf: [*]u8,
- buf_len: usize,
-};
-
pub const linkcount_t = u32;
pub const lookupflags_t = u32;
@@ -314,61 +305,3 @@ pub const whence_t = u8;
pub const WHENCE_CUR: whence_t = 0;
pub const WHENCE_END: whence_t = 1;
pub const WHENCE_SET: whence_t = 2;
-
-pub extern "wasi_unstable" fn args_get(argv: [*][*]u8, argv_buf: [*]u8) errno_t;
-pub extern "wasi_unstable" fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t;
-
-pub extern "wasi_unstable" fn clock_res_get(clock_id: clockid_t, resolution: *timestamp_t) errno_t;
-pub extern "wasi_unstable" fn clock_time_get(clock_id: clockid_t, precision: timestamp_t, timestamp: *timestamp_t) errno_t;
-
-pub extern "wasi_unstable" fn environ_get(environ: [*]?[*]u8, environ_buf: [*]u8) errno_t;
-pub extern "wasi_unstable" fn environ_sizes_get(environ_count: *usize, environ_buf_size: *usize) errno_t;
-
-pub extern "wasi_unstable" fn fd_advise(fd: fd_t, offset: filesize_t, len: filesize_t, advice: advice_t) errno_t;
-pub extern "wasi_unstable" fn fd_allocate(fd: fd_t, offset: filesize_t, len: filesize_t) errno_t;
-pub extern "wasi_unstable" fn fd_close(fd: fd_t) errno_t;
-pub extern "wasi_unstable" fn fd_datasync(fd: fd_t) errno_t;
-pub extern "wasi_unstable" fn fd_pread(fd: fd_t, iovs: *const iovec_t, iovs_len: usize, offset: filesize_t, nread: *usize) errno_t;
-pub extern "wasi_unstable" fn fd_pwrite(fd: fd_t, iovs: *const ciovec_t, iovs_len: usize, offset: filesize_t, nwritten: *usize) errno_t;
-pub extern "wasi_unstable" fn fd_read(fd: fd_t, iovs: *const iovec_t, iovs_len: usize, nread: *usize) errno_t;
-pub extern "wasi_unstable" fn fd_readdir(fd: fd_t, buf: [*]u8, buf_len: usize, cookie: dircookie_t, bufused: *usize) errno_t;
-pub extern "wasi_unstable" fn fd_renumber(from: fd_t, to: fd_t) errno_t;
-pub extern "wasi_unstable" fn fd_seek(fd: fd_t, offset: filedelta_t, whence: whence_t, newoffset: *filesize_t) errno_t;
-pub extern "wasi_unstable" fn fd_sync(fd: fd_t) errno_t;
-pub extern "wasi_unstable" fn fd_tell(fd: fd_t, newoffset: *filesize_t) errno_t;
-pub extern "wasi_unstable" fn fd_write(fd: fd_t, iovs: *const ciovec_t, iovs_len: usize, nwritten: *usize) errno_t;
-
-pub extern "wasi_unstable" fn fd_fdstat_get(fd: fd_t, buf: *fdstat_t) errno_t;
-pub extern "wasi_unstable" fn fd_fdstat_set_flags(fd: fd_t, flags: fdflags_t) errno_t;
-pub extern "wasi_unstable" fn fd_fdstat_set_rights(fd: fd_t, fs_rights_base: rights_t, fs_rights_inheriting: rights_t) errno_t;
-
-pub extern "wasi_unstable" fn fd_filestat_get(fd: fd_t, buf: *filestat_t) errno_t;
-pub extern "wasi_unstable" fn fd_filestat_set_size(fd: fd_t, st_size: filesize_t) errno_t;
-pub extern "wasi_unstable" fn fd_filestat_set_times(fd: fd_t, st_atim: timestamp_t, st_mtim: timestamp_t, fstflags: fstflags_t) errno_t;
-
-pub extern "wasi_unstable" fn fd_prestat_get(fd: fd_t, buf: *prestat_t) errno_t;
-pub extern "wasi_unstable" fn fd_prestat_dir_name(fd: fd_t, path: [*]u8, path_len: usize) errno_t;
-
-pub extern "wasi_unstable" fn path_create_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
-pub extern "wasi_unstable" fn path_filestat_get(fd: fd_t, flags: lookupflags_t, path: [*]const u8, path_len: usize, buf: *filestat_t) errno_t;
-pub extern "wasi_unstable" fn path_filestat_set_times(fd: fd_t, flags: lookupflags_t, path: [*]const u8, path_len: usize, st_atim: timestamp_t, st_mtim: timestamp_t, fstflags: fstflags_t) errno_t;
-pub extern "wasi_unstable" fn path_link(old_fd: fd_t, old_flags: lookupflags_t, old_path: [*]const u8, old_path_len: usize, new_fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t;
-pub extern "wasi_unstable" fn path_open(dirfd: fd_t, dirflags: lookupflags_t, path: [*]const u8, path_len: usize, oflags: oflags_t, fs_rights_base: rights_t, fs_rights_inheriting: rights_t, fs_flags: fdflags_t, fd: *fd_t) errno_t;
-pub extern "wasi_unstable" fn path_readlink(fd: fd_t, path: [*]const u8, path_len: usize, buf: [*]u8, buf_len: usize, bufused: *usize) errno_t;
-pub extern "wasi_unstable" fn path_remove_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
-pub extern "wasi_unstable" fn path_rename(old_fd: fd_t, old_path: [*]const u8, old_path_len: usize, new_fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t;
-pub extern "wasi_unstable" fn path_symlink(old_path: [*]const u8, old_path_len: usize, fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t;
-pub extern "wasi_unstable" fn path_unlink_file(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
-
-pub extern "wasi_unstable" fn poll_oneoff(in: *const subscription_t, out: *event_t, nsubscriptions: usize, nevents: *usize) errno_t;
-
-pub extern "wasi_unstable" fn proc_exit(rval: exitcode_t) noreturn;
-pub extern "wasi_unstable" fn proc_raise(sig: signal_t) errno_t;
-
-pub extern "wasi_unstable" fn random_get(buf: [*]u8, buf_len: usize) errno_t;
-
-pub extern "wasi_unstable" fn sched_yield() errno_t;
-
-pub extern "wasi_unstable" fn sock_recv(sock: fd_t, ri_data: *const iovec_t, ri_data_len: usize, ri_flags: riflags_t, ro_datalen: *usize, ro_flags: *roflags_t) errno_t;
-pub extern "wasi_unstable" 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_unstable" fn sock_shutdown(sock: fd_t, how: sdflags_t) errno_t;
diff --git a/std/os/bits/windows.zig b/std/os/bits/windows.zig
new file mode 100644
index 0000000000..a242113ba0
--- /dev/null
+++ b/std/os/bits/windows.zig
@@ -0,0 +1,167 @@
+// The reference for these types and values is Microsoft Windows's ucrt (Universal C RunTime).
+
+use @import("../windows/bits.zig");
+
+pub const fd_t = HANDLE;
+pub const pid_t = HANDLE;
+
+pub const PATH_MAX = 260;
+
+pub const time_t = c_longlong;
+
+pub const timespec = extern struct {
+ tv_sec: time_t,
+ tv_nsec: c_long,
+};
+
+pub const sig_atomic_t = c_int;
+
+/// maximum signal number + 1
+pub const NSIG = 23;
+
+// Signal types
+
+/// interrupt
+pub const SIGINT = 2;
+
+/// illegal instruction - invalid function image
+pub const SIGILL = 4;
+
+/// floating point exception
+pub const SIGFPE = 8;
+
+/// segment violation
+pub const SIGSEGV = 11;
+
+/// Software termination signal from kill
+pub const SIGTERM = 15;
+
+/// Ctrl-Break sequence
+pub const SIGBREAK = 21;
+
+/// abnormal termination triggered by abort call
+pub const SIGABRT = 22;
+
+/// SIGABRT compatible with other platforms, same as SIGABRT
+pub const SIGABRT_COMPAT = 6;
+
+// Signal action codes
+
+/// default signal action
+pub const SIG_DFL = 0;
+
+/// ignore signal
+pub const SIG_IGN = 1;
+
+/// return current value
+pub const SIG_GET = 2;
+
+/// signal gets error
+pub const SIG_SGE = 3;
+
+/// acknowledge
+pub const SIG_ACK = 4;
+
+/// Signal error value (returned by signal call on error)
+pub const SIG_ERR = -1;
+
+pub const SEEK_SET = 0;
+pub const SEEK_CUR = 1;
+pub const SEEK_END = 2;
+
+pub const EPERM = 1;
+pub const ENOENT = 2;
+pub const ESRCH = 3;
+pub const EINTR = 4;
+pub const EIO = 5;
+pub const ENXIO = 6;
+pub const E2BIG = 7;
+pub const ENOEXEC = 8;
+pub const EBADF = 9;
+pub const ECHILD = 10;
+pub const EAGAIN = 11;
+pub const ENOMEM = 12;
+pub const EACCES = 13;
+pub const EFAULT = 14;
+pub const EBUSY = 16;
+pub const EEXIST = 17;
+pub const EXDEV = 18;
+pub const ENODEV = 19;
+pub const ENOTDIR = 20;
+pub const EISDIR = 21;
+pub const ENFILE = 23;
+pub const EMFILE = 24;
+pub const ENOTTY = 25;
+pub const EFBIG = 27;
+pub const ENOSPC = 28;
+pub const ESPIPE = 29;
+pub const EROFS = 30;
+pub const EMLINK = 31;
+pub const EPIPE = 32;
+pub const EDOM = 33;
+pub const EDEADLK = 36;
+pub const ENAMETOOLONG = 38;
+pub const ENOLCK = 39;
+pub const ENOSYS = 40;
+pub const ENOTEMPTY = 41;
+
+pub const EINVAL = 22;
+pub const ERANGE = 34;
+pub const EILSEQ = 42;
+pub const STRUNCATE = 80;
+
+// Support EDEADLOCK for compatibility with older Microsoft C versions
+pub const EDEADLOCK = EDEADLK;
+
+// POSIX Supplement
+pub const EADDRINUSE = 100;
+pub const EADDRNOTAVAIL = 101;
+pub const EAFNOSUPPORT = 102;
+pub const EALREADY = 103;
+pub const EBADMSG = 104;
+pub const ECANCELED = 105;
+pub const ECONNABORTED = 106;
+pub const ECONNREFUSED = 107;
+pub const ECONNRESET = 108;
+pub const EDESTADDRREQ = 109;
+pub const EHOSTUNREACH = 110;
+pub const EIDRM = 111;
+pub const EINPROGRESS = 112;
+pub const EISCONN = 113;
+pub const ELOOP = 114;
+pub const EMSGSIZE = 115;
+pub const ENETDOWN = 116;
+pub const ENETRESET = 117;
+pub const ENETUNREACH = 118;
+pub const ENOBUFS = 119;
+pub const ENODATA = 120;
+pub const ENOLINK = 121;
+pub const ENOMSG = 122;
+pub const ENOPROTOOPT = 123;
+pub const ENOSR = 124;
+pub const ENOSTR = 125;
+pub const ENOTCONN = 126;
+pub const ENOTRECOVERABLE = 127;
+pub const ENOTSOCK = 128;
+pub const ENOTSUP = 129;
+pub const EOPNOTSUPP = 130;
+pub const EOTHER = 131;
+pub const EOVERFLOW = 132;
+pub const EOWNERDEAD = 133;
+pub const EPROTO = 134;
+pub const EPROTONOSUPPORT = 135;
+pub const EPROTOTYPE = 136;
+pub const ETIME = 137;
+pub const ETIMEDOUT = 138;
+pub const ETXTBSY = 139;
+pub const EWOULDBLOCK = 140;
+pub const EDQUOT = 10069;
+
+pub const F_OK = 0;
+
+// These are workarounds for "use of undeclared identifier" compile errors
+// TODO make the compiler even more lazy. don't emit "use of undeclared identifier" errors
+// for if branches that aren't taken.
+pub const SIGKILL = @compileError("Windows libc does not have this");
+
+
diff --git a/std/os/darwin.zig b/std/os/darwin.zig
index 04122100f4..d6e0a1b77c 100644
--- a/std/os/darwin.zig
+++ b/std/os/darwin.zig
@@ -1,885 +1,7 @@
+const builtin = @import("builtin");
const std = @import("../std.zig");
-const c = std.c;
-const assert = std.debug.assert;
-const maxInt = std.math.maxInt;
-
-pub use @import("darwin/errno.zig");
-
-pub const PATH_MAX = 1024;
-
-pub const STDIN_FILENO = 0;
-pub const STDOUT_FILENO = 1;
-pub const STDERR_FILENO = 2;
-
-/// [MC2] no permissions
-pub const PROT_NONE = 0x00;
-
-/// [MC2] pages can be read
-pub const PROT_READ = 0x01;
-
-/// [MC2] pages can be written
-pub const PROT_WRITE = 0x02;
-
-/// [MC2] pages can be executed
-pub const PROT_EXEC = 0x04;
-
-/// allocated from memory, swap space
-pub const MAP_ANONYMOUS = 0x1000;
-
-/// map from file (default)
-pub const MAP_FILE = 0x0000;
-
-/// interpret addr exactly
-pub const MAP_FIXED = 0x0010;
-
-/// region may contain semaphores
-pub const MAP_HASSEMAPHORE = 0x0200;
-
-/// changes are private
-pub const MAP_PRIVATE = 0x0002;
-
-/// share changes
-pub const MAP_SHARED = 0x0001;
-
-/// don't cache pages for this mapping
-pub const MAP_NOCACHE = 0x0400;
-
-/// don't reserve needed swap area
-pub const MAP_NORESERVE = 0x0040;
-pub const MAP_FAILED = maxInt(usize);
-
-/// [XSI] no hang in wait/no child to reap
-pub const WNOHANG = 0x00000001;
-
-/// [XSI] notify on stop, untraced child
-pub const WUNTRACED = 0x00000002;
-
-/// take signal on signal stack
-pub const SA_ONSTACK = 0x0001;
-
-/// restart system on signal return
-pub const SA_RESTART = 0x0002;
-
-/// reset to SIG_DFL when taking signal
-pub const SA_RESETHAND = 0x0004;
-
-/// do not generate SIGCHLD on child stop
-pub const SA_NOCLDSTOP = 0x0008;
-
-/// don't mask the signal we're delivering
-pub const SA_NODEFER = 0x0010;
-
-/// don't keep zombies around
-pub const SA_NOCLDWAIT = 0x0020;
-
-/// signal handler with SA_SIGINFO args
-pub const SA_SIGINFO = 0x0040;
-
-/// do not bounce off kernel's sigtramp
-pub const SA_USERTRAMP = 0x0100;
-
-/// signal handler with SA_SIGINFO args with 64bit regs information
-pub const SA_64REGSET = 0x0200;
-
-pub const O_LARGEFILE = 0x0000;
-pub const O_PATH = 0x0000;
-
-pub const F_OK = 0;
-pub const X_OK = 1;
-pub const W_OK = 2;
-pub const R_OK = 4;
-
-/// open for reading only
-pub const O_RDONLY = 0x0000;
-
-/// open for writing only
-pub const O_WRONLY = 0x0001;
-
-/// open for reading and writing
-pub const O_RDWR = 0x0002;
-
-/// do not block on open or for data to become available
-pub const O_NONBLOCK = 0x0004;
-
-/// append on each write
-pub const O_APPEND = 0x0008;
-
-/// create file if it does not exist
-pub const O_CREAT = 0x0200;
-
-/// truncate size to 0
-pub const O_TRUNC = 0x0400;
-
-/// error if O_CREAT and the file exists
-pub const O_EXCL = 0x0800;
-
-/// atomically obtain a shared lock
-pub const O_SHLOCK = 0x0010;
-
-/// atomically obtain an exclusive lock
-pub const O_EXLOCK = 0x0020;
-
-/// do not follow symlinks
-pub const O_NOFOLLOW = 0x0100;
-
-/// allow open of symlinks
-pub const O_SYMLINK = 0x200000;
-
-/// descriptor requested for event notifications only
-pub const O_EVTONLY = 0x8000;
-
-/// mark as close-on-exec
-pub const O_CLOEXEC = 0x1000000;
-
-pub const O_ACCMODE = 3;
-pub const O_ALERT = 536870912;
-pub const O_ASYNC = 64;
-pub const O_DIRECTORY = 1048576;
-pub const O_DP_GETRAWENCRYPTED = 1;
-pub const O_DP_GETRAWUNENCRYPTED = 2;
-pub const O_DSYNC = 4194304;
-pub const O_FSYNC = O_SYNC;
-pub const O_NOCTTY = 131072;
-pub const O_POPUP = 2147483648;
-pub const O_SYNC = 128;
-
-pub const SEEK_SET = 0x0;
-pub const SEEK_CUR = 0x1;
-pub const SEEK_END = 0x2;
-
-pub const DT_UNKNOWN = 0;
-pub const DT_FIFO = 1;
-pub const DT_CHR = 2;
-pub const DT_DIR = 4;
-pub const DT_BLK = 6;
-pub const DT_REG = 8;
-pub const DT_LNK = 10;
-pub const DT_SOCK = 12;
-pub const DT_WHT = 14;
-
-/// block specified signal set
-pub const SIG_BLOCK = 1;
-
-/// unblock specified signal set
-pub const SIG_UNBLOCK = 2;
-
-/// set specified signal set
-pub const SIG_SETMASK = 3;
-
-/// hangup
-pub const SIGHUP = 1;
-
-/// interrupt
-pub const SIGINT = 2;
-
-/// quit
-pub const SIGQUIT = 3;
-
-/// illegal instruction (not reset when caught)
-pub const SIGILL = 4;
-
-/// trace trap (not reset when caught)
-pub const SIGTRAP = 5;
-
-/// abort()
-pub const SIGABRT = 6;
-
-/// pollable event ([XSR] generated, not supported)
-pub const SIGPOLL = 7;
-
-/// compatibility
-pub const SIGIOT = SIGABRT;
-
-/// EMT instruction
-pub const SIGEMT = 7;
-
-/// floating point exception
-pub const SIGFPE = 8;
-
-/// kill (cannot be caught or ignored)
-pub const SIGKILL = 9;
-
-/// bus error
-pub const SIGBUS = 10;
-
-/// segmentation violation
-pub const SIGSEGV = 11;
-
-/// bad argument to system call
-pub const SIGSYS = 12;
-
-/// write on a pipe with no one to read it
-pub const SIGPIPE = 13;
-
-/// alarm clock
-pub const SIGALRM = 14;
-
-/// software termination signal from kill
-pub const SIGTERM = 15;
-
-/// urgent condition on IO channel
-pub const SIGURG = 16;
-
-/// sendable stop signal not from tty
-pub const SIGSTOP = 17;
-
-/// stop signal from tty
-pub const SIGTSTP = 18;
-
-/// continue a stopped process
-pub const SIGCONT = 19;
-
-/// to parent on child stop or exit
-pub const SIGCHLD = 20;
-
-/// to readers pgrp upon background tty read
-pub const SIGTTIN = 21;
-
-/// like TTIN for output if (tp->t_local&LTOSTOP)
-pub const SIGTTOU = 22;
-
-/// input/output possible signal
-pub const SIGIO = 23;
-
-/// exceeded CPU time limit
-pub const SIGXCPU = 24;
-
-/// exceeded file size limit
-pub const SIGXFSZ = 25;
-
-/// virtual time alarm
-pub const SIGVTALRM = 26;
-
-/// profiling time alarm
-pub const SIGPROF = 27;
-
-/// window size changes
-pub const SIGWINCH = 28;
-
-/// information request
-pub const SIGINFO = 29;
-
-/// user defined signal 1
-pub const SIGUSR1 = 30;
-
-/// user defined signal 2
-pub const SIGUSR2 = 31;
-
-/// no flag value
-pub const KEVENT_FLAG_NONE = 0x000;
-
-/// immediate timeout
-pub const KEVENT_FLAG_IMMEDIATE = 0x001;
-
-/// output events only include change
-pub const KEVENT_FLAG_ERROR_EVENTS = 0x002;
-
-/// add event to kq (implies enable)
-pub const EV_ADD = 0x0001;
-
-/// delete event from kq
-pub const EV_DELETE = 0x0002;
-
-/// enable event
-pub const EV_ENABLE = 0x0004;
-
-/// disable event (not reported)
-pub const EV_DISABLE = 0x0008;
-
-/// only report one occurrence
-pub const EV_ONESHOT = 0x0010;
-
-/// clear event state after reporting
-pub const EV_CLEAR = 0x0020;
-
-/// force immediate event output
-/// ... with or without EV_ERROR
-/// ... use KEVENT_FLAG_ERROR_EVENTS
-/// on syscalls supporting flags
-pub const EV_RECEIPT = 0x0040;
-
-/// disable event after reporting
-pub const EV_DISPATCH = 0x0080;
-
-/// unique kevent per udata value
-pub const EV_UDATA_SPECIFIC = 0x0100;
-
-/// ... in combination with EV_DELETE
-/// will defer delete until udata-specific
-/// event enabled. EINPROGRESS will be
-/// returned to indicate the deferral
-pub const EV_DISPATCH2 = EV_DISPATCH | EV_UDATA_SPECIFIC;
-
-/// report that source has vanished
-/// ... only valid with EV_DISPATCH2
-pub const EV_VANISHED = 0x0200;
-
-/// reserved by system
-pub const EV_SYSFLAGS = 0xF000;
-
-/// filter-specific flag
-pub const EV_FLAG0 = 0x1000;
-
-/// filter-specific flag
-pub const EV_FLAG1 = 0x2000;
-
-/// EOF detected
-pub const EV_EOF = 0x8000;
-
-/// error, data contains errno
-pub const EV_ERROR = 0x4000;
-
-pub const EV_POLL = EV_FLAG0;
-pub const EV_OOBAND = EV_FLAG1;
-
-pub const EVFILT_READ = -1;
-pub const EVFILT_WRITE = -2;
-
-/// attached to aio requests
-pub const EVFILT_AIO = -3;
-
-/// attached to vnodes
-pub const EVFILT_VNODE = -4;
-
-/// attached to struct proc
-pub const EVFILT_PROC = -5;
-
-/// attached to struct proc
-pub const EVFILT_SIGNAL = -6;
-
-/// timers
-pub const EVFILT_TIMER = -7;
-
-/// Mach portsets
-pub const EVFILT_MACHPORT = -8;
-
-/// Filesystem events
-pub const EVFILT_FS = -9;
-
-/// User events
-pub const EVFILT_USER = -10;
-
-/// Virtual memory events
-pub const EVFILT_VM = -12;
-
-/// Exception events
-pub const EVFILT_EXCEPT = -15;
-
-pub const EVFILT_SYSCOUNT = 17;
-
-/// On input, NOTE_TRIGGER causes the event to be triggered for output.
-pub const NOTE_TRIGGER = 0x01000000;
-
-/// ignore input fflags
-pub const NOTE_FFNOP = 0x00000000;
-
-/// and fflags
-pub const NOTE_FFAND = 0x40000000;
-
-/// or fflags
-pub const NOTE_FFOR = 0x80000000;
-
-/// copy fflags
-pub const NOTE_FFCOPY = 0xc0000000;
-
-/// mask for operations
-pub const NOTE_FFCTRLMASK = 0xc0000000;
-pub const NOTE_FFLAGSMASK = 0x00ffffff;
-
-/// low water mark
-pub const NOTE_LOWAT = 0x00000001;
-
-/// OOB data
-pub const NOTE_OOB = 0x00000002;
-
-/// vnode was removed
-pub const NOTE_DELETE = 0x00000001;
-
-/// data contents changed
-pub const NOTE_WRITE = 0x00000002;
-
-/// size increased
-pub const NOTE_EXTEND = 0x00000004;
-
-/// attributes changed
-pub const NOTE_ATTRIB = 0x00000008;
-
-/// link count changed
-pub const NOTE_LINK = 0x00000010;
-
-/// vnode was renamed
-pub const NOTE_RENAME = 0x00000020;
-
-/// vnode access was revoked
-pub const NOTE_REVOKE = 0x00000040;
-
-/// No specific vnode event: to test for EVFILT_READ activation
-pub const NOTE_NONE = 0x00000080;
-
-/// vnode was unlocked by flock(2)
-pub const NOTE_FUNLOCK = 0x00000100;
-
-/// process exited
-pub const NOTE_EXIT = 0x80000000;
-
-/// process forked
-pub const NOTE_FORK = 0x40000000;
-
-/// process exec'd
-pub const NOTE_EXEC = 0x20000000;
-
-/// shared with EVFILT_SIGNAL
-pub const NOTE_SIGNAL = 0x08000000;
-
-/// exit status to be returned, valid for child process only
-pub const NOTE_EXITSTATUS = 0x04000000;
-
-/// provide details on reasons for exit
-pub const NOTE_EXIT_DETAIL = 0x02000000;
-
-/// mask for signal & exit status
-pub const NOTE_PDATAMASK = 0x000fffff;
-pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK);
-
-pub const NOTE_EXIT_DETAIL_MASK = 0x00070000;
-pub const NOTE_EXIT_DECRYPTFAIL = 0x00010000;
-pub const NOTE_EXIT_MEMORY = 0x00020000;
-pub const NOTE_EXIT_CSERROR = 0x00040000;
-
-/// will react on memory pressure
-pub const NOTE_VM_PRESSURE = 0x80000000;
-
-/// will quit on memory pressure, possibly after cleaning up dirty state
-pub const NOTE_VM_PRESSURE_TERMINATE = 0x40000000;
-
-/// will quit immediately on memory pressure
-pub const NOTE_VM_PRESSURE_SUDDEN_TERMINATE = 0x20000000;
-
-/// there was an error
-pub const NOTE_VM_ERROR = 0x10000000;
-
-/// data is seconds
-pub const NOTE_SECONDS = 0x00000001;
-
-/// data is microseconds
-pub const NOTE_USECONDS = 0x00000002;
-
-/// data is nanoseconds
-pub const NOTE_NSECONDS = 0x00000004;
-
-/// absolute timeout
-pub const NOTE_ABSOLUTE = 0x00000008;
-
-/// ext[1] holds leeway for power aware timers
-pub const NOTE_LEEWAY = 0x00000010;
-
-/// system does minimal timer coalescing
-pub const NOTE_CRITICAL = 0x00000020;
-
-/// system does maximum timer coalescing
-pub const NOTE_BACKGROUND = 0x00000040;
-pub const NOTE_MACH_CONTINUOUS_TIME = 0x00000080;
-
-/// data is mach absolute time units
-pub const NOTE_MACHTIME = 0x00000100;
-
-pub const AF_UNSPEC = 0;
-pub const AF_LOCAL = 1;
-pub const AF_UNIX = AF_LOCAL;
-pub const AF_INET = 2;
-pub const AF_SYS_CONTROL = 2;
-pub const AF_IMPLINK = 3;
-pub const AF_PUP = 4;
-pub const AF_CHAOS = 5;
-pub const AF_NS = 6;
-pub const AF_ISO = 7;
-pub const AF_OSI = AF_ISO;
-pub const AF_ECMA = 8;
-pub const AF_DATAKIT = 9;
-pub const AF_CCITT = 10;
-pub const AF_SNA = 11;
-pub const AF_DECnet = 12;
-pub const AF_DLI = 13;
-pub const AF_LAT = 14;
-pub const AF_HYLINK = 15;
-pub const AF_APPLETALK = 16;
-pub const AF_ROUTE = 17;
-pub const AF_LINK = 18;
-pub const AF_XTP = 19;
-pub const AF_COIP = 20;
-pub const AF_CNT = 21;
-pub const AF_RTIP = 22;
-pub const AF_IPX = 23;
-pub const AF_SIP = 24;
-pub const AF_PIP = 25;
-pub const AF_ISDN = 28;
-pub const AF_E164 = AF_ISDN;
-pub const AF_KEY = 29;
-pub const AF_INET6 = 30;
-pub const AF_NATM = 31;
-pub const AF_SYSTEM = 32;
-pub const AF_NETBIOS = 33;
-pub const AF_PPP = 34;
-pub const AF_MAX = 40;
-
-pub const PF_UNSPEC = AF_UNSPEC;
-pub const PF_LOCAL = AF_LOCAL;
-pub const PF_UNIX = PF_LOCAL;
-pub const PF_INET = AF_INET;
-pub const PF_IMPLINK = AF_IMPLINK;
-pub const PF_PUP = AF_PUP;
-pub const PF_CHAOS = AF_CHAOS;
-pub const PF_NS = AF_NS;
-pub const PF_ISO = AF_ISO;
-pub const PF_OSI = AF_ISO;
-pub const PF_ECMA = AF_ECMA;
-pub const PF_DATAKIT = AF_DATAKIT;
-pub const PF_CCITT = AF_CCITT;
-pub const PF_SNA = AF_SNA;
-pub const PF_DECnet = AF_DECnet;
-pub const PF_DLI = AF_DLI;
-pub const PF_LAT = AF_LAT;
-pub const PF_HYLINK = AF_HYLINK;
-pub const PF_APPLETALK = AF_APPLETALK;
-pub const PF_ROUTE = AF_ROUTE;
-pub const PF_LINK = AF_LINK;
-pub const PF_XTP = AF_XTP;
-pub const PF_COIP = AF_COIP;
-pub const PF_CNT = AF_CNT;
-pub const PF_SIP = AF_SIP;
-pub const PF_IPX = AF_IPX;
-pub const PF_RTIP = AF_RTIP;
-pub const PF_PIP = AF_PIP;
-pub const PF_ISDN = AF_ISDN;
-pub const PF_KEY = AF_KEY;
-pub const PF_INET6 = AF_INET6;
-pub const PF_NATM = AF_NATM;
-pub const PF_SYSTEM = AF_SYSTEM;
-pub const PF_NETBIOS = AF_NETBIOS;
-pub const PF_PPP = AF_PPP;
-pub const PF_MAX = AF_MAX;
-
-pub const SYSPROTO_EVENT = 1;
-pub const SYSPROTO_CONTROL = 2;
-
-pub const SOCK_STREAM = 1;
-pub const SOCK_DGRAM = 2;
-pub const SOCK_RAW = 3;
-pub const SOCK_RDM = 4;
-pub const SOCK_SEQPACKET = 5;
-pub const SOCK_MAXADDRLEN = 255;
-
-pub const IPPROTO_ICMP = 1;
-pub const IPPROTO_ICMPV6 = 58;
-pub const IPPROTO_TCP = 6;
-pub const IPPROTO_UDP = 17;
-pub const IPPROTO_IP = 0;
-pub const IPPROTO_IPV6 = 41;
-
-fn wstatus(x: i32) i32 {
- return x & 0o177;
-}
-const wstopped = 0o177;
-pub fn WEXITSTATUS(x: i32) i32 {
- return x >> 8;
-}
-pub fn WTERMSIG(x: i32) i32 {
- return wstatus(x);
-}
-pub fn WSTOPSIG(x: i32) i32 {
- return x >> 8;
-}
-pub fn WIFEXITED(x: i32) bool {
- return wstatus(x) == 0;
-}
-pub fn WIFSTOPPED(x: i32) bool {
- return wstatus(x) == wstopped and WSTOPSIG(x) != 0x13;
-}
-pub fn WIFSIGNALED(x: i32) bool {
- return wstatus(x) != wstopped and wstatus(x) != 0;
-}
-
-/// Get the errno from a syscall return value, or 0 for no error.
-pub fn getErrno(r: usize) usize {
- const signed_r = @bitCast(isize, r);
- return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
-}
-
-pub fn close(fd: i32) usize {
- return errnoWrap(c.close(fd));
-}
-
-pub fn abort() noreturn {
- c.abort();
-}
-
-// bind(int socket, const struct sockaddr *address, socklen_t address_len)
-pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize {
- return errnoWrap(c.bind(@bitCast(c_int, fd), addr, len));
-}
-
-pub fn exit(code: i32) noreturn {
- c.exit(code);
-}
-
-pub fn isatty(fd: i32) bool {
- return c.isatty(fd) != 0;
-}
-
-pub fn fstat(fd: i32, buf: *c.Stat) usize {
- return errnoWrap(c.@"fstat$INODE64"(fd, buf));
-}
-
-pub fn lseek(fd: i32, offset: isize, whence: c_int) usize {
- return errnoWrap(c.lseek(fd, offset, whence));
-}
-
-// TODO https://github.com/ziglang/zig/issues/265 on the whole file
-pub fn open(path: [*]const u8, flags: u32, mode: usize) usize {
- return errnoWrap(c.open(path, @bitCast(c_int, flags), mode));
-}
-
-pub fn raise(sig: i32) usize {
- return errnoWrap(c.raise(sig));
-}
-
-pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
- return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte));
-}
-
-pub fn pread(fd: i32, buf: [*]u8, nbyte: usize, offset: u64) usize {
- return errnoWrap(c.pread(fd, @ptrCast(*c_void, buf), nbyte, offset));
-}
-
-pub fn stat(noalias path: [*]const u8, noalias buf: *stat) usize {
- return errnoWrap(c.stat(path, buf));
-}
-
-pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize {
- return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte));
-}
-
-pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize {
- return errnoWrap(c.pwrite(fd, @ptrCast(*const c_void, buf), nbyte, offset));
-}
-
-pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
- const ptr_result = c.mmap(
- @ptrCast(?*c_void, address),
- length,
- @bitCast(c_int, @intCast(c_uint, prot)),
- @bitCast(c_int, c_uint(flags)),
- fd,
- offset,
- );
- const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
- return errnoWrap(isize_result);
-}
-
-pub fn munmap(address: usize, length: usize) usize {
- return errnoWrap(c.munmap(@intToPtr(?*c_void, address), length));
-}
-
-pub fn unlink(path: [*]const u8) usize {
- return errnoWrap(c.unlink(path));
-}
-
-pub fn getcwd(buf: [*]u8, size: usize) usize {
- return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
-}
-
-pub fn waitpid(pid: i32, status: *i32, options: u32) usize {
- comptime assert(i32.bit_count == c_int.bit_count);
- return errnoWrap(c.waitpid(pid, @ptrCast(*c_int, status), @bitCast(c_int, options)));
-}
-
-pub fn fork() usize {
- return errnoWrap(c.fork());
-}
-
-pub fn access(path: [*]const u8, mode: u32) usize {
- return errnoWrap(c.access(path, mode));
-}
-
-pub fn pipe(fds: *[2]i32) usize {
- comptime assert(i32.bit_count == c_int.bit_count);
- return errnoWrap(c.pipe(@ptrCast(*[2]c_int, fds)));
-}
-
-pub fn getdirentries64(fd: i32, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize {
- return errnoWrap(@bitCast(isize, c.__getdirentries64(fd, buf_ptr, buf_len, basep)));
-}
-
-pub fn kqueue() usize {
- return errnoWrap(c.kqueue());
-}
-
-pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize {
- return errnoWrap(c.kevent(
- kq,
- changelist.ptr,
- @intCast(c_int, changelist.len),
- eventlist.ptr,
- @intCast(c_int, eventlist.len),
- timeout,
- ));
-}
-
-pub fn kevent64(
- kq: i32,
- changelist: []const kevent64_s,
- eventlist: []kevent64_s,
- flags: u32,
- timeout: ?*const timespec,
-) usize {
- return errnoWrap(c.kevent64(kq, changelist.ptr, changelist.len, eventlist.ptr, eventlist.len, flags, timeout));
-}
-
-pub fn mkdir(path: [*]const u8, mode: u32) usize {
- return errnoWrap(c.mkdir(path, mode));
-}
-
-pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
- return errnoWrap(c.symlink(existing, new));
-}
-
-pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
- return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen));
-}
-
-pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
- return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen));
-}
-
-pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize {
- return errnoWrap(c.sysctlnametomib(name, wibp, sizep));
-}
-
-pub fn rename(old: [*]const u8, new: [*]const u8) usize {
- return errnoWrap(c.rename(old, new));
-}
-
-pub fn rmdir(path: [*]const u8) usize {
- return errnoWrap(c.rmdir(path));
-}
-
-pub fn chdir(path: [*]const u8) usize {
- return errnoWrap(c.chdir(path));
-}
-
-pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
- return errnoWrap(c.execve(path, argv, envp));
-}
-
-pub fn dup2(old: i32, new: i32) usize {
- return errnoWrap(c.dup2(old, new));
-}
-
-pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
- return errnoWrap(c.readlink(path, buf_ptr, buf_len));
-}
-
-pub fn gettimeofday(tv: ?*timeval, tz: ?*timezone) usize {
- return errnoWrap(c.gettimeofday(tv, tz));
-}
-
-pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
- return errnoWrap(c.nanosleep(req, rem));
-}
-
-pub fn realpath(noalias filename: [*]const u8, noalias resolved_name: [*]u8) usize {
- return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
-}
-
-pub fn setreuid(ruid: u32, euid: u32) usize {
- return errnoWrap(c.setreuid(ruid, euid));
-}
-
-pub fn setregid(rgid: u32, egid: u32) usize {
- return errnoWrap(c.setregid(rgid, egid));
-}
-
-pub fn sigprocmask(flags: u32, noalias set: *const sigset_t, noalias oldset: ?*sigset_t) usize {
- return errnoWrap(c.sigprocmask(@bitCast(c_int, flags), set, oldset));
-}
-
-pub fn sigaction(sig: u5, noalias act: *const Sigaction, noalias oact: ?*Sigaction) usize {
- assert(sig != SIGKILL);
- assert(sig != SIGSTOP);
- var cact = c.Sigaction{
- .handler = @ptrCast(extern fn (c_int) void, act.handler),
- .sa_flags = @bitCast(c_int, act.flags),
- .sa_mask = act.mask,
- };
- var coact: c.Sigaction = undefined;
- const result = errnoWrap(c.sigaction(sig, &cact, &coact));
- if (result != 0) {
- return result;
- }
- if (oact) |old| {
- old.* = Sigaction{
- .handler = @ptrCast(extern fn (i32) void, coact.handler),
- .flags = @bitCast(u32, coact.sa_flags),
- .mask = coact.sa_mask,
- };
- }
- return result;
-}
-
-pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {
- return errnoWrap(c.socket(@bitCast(c_int, domain), @bitCast(c_int, socket_type), @bitCast(c_int, protocol)));
-}
-
-pub const iovec = extern struct {
- iov_base: [*]u8,
- iov_len: usize,
+pub const is_the_target = switch (builtin.os) {
+ .macosx, .tvos, .watchos, .ios => true,
+ else => false,
};
-
-pub const iovec_const = extern struct {
- iov_base: [*]const u8,
- iov_len: usize,
-};
-
-pub const sigset_t = c.sigset_t;
-pub const empty_sigset = sigset_t(0);
-
-pub const timespec = c.timespec;
-pub const Stat = c.Stat;
-pub const dirent = c.dirent;
-
-pub const in_port_t = c.in_port_t;
-pub const sa_family_t = c.sa_family_t;
-pub const socklen_t = c.socklen_t;
-
-pub const sockaddr = c.sockaddr;
-pub const sockaddr_in = c.sockaddr_in;
-pub const sockaddr_in6 = c.sockaddr_in6;
-
-/// Renamed from `kevent` to `Kevent` to avoid conflict with the syscall.
-pub const Kevent = c.Kevent;
-pub const kevent64_s = c.kevent64_s;
-
-/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
-pub const Sigaction = struct {
- handler: extern fn (i32) void,
- mask: sigset_t,
- flags: u32,
-};
-
-pub fn sigaddset(set: *sigset_t, signo: u5) void {
- set.* |= u32(1) << (signo - 1);
-}
-
-/// Takes the return value from a syscall and formats it back in the way
-/// that the kernel represents it to libc. Errno was a mistake, let's make
-/// it go away forever.
-fn errnoWrap(value: isize) usize {
- return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
-}
-
-pub const timezone = c.timezone;
-pub const timeval = c.timeval;
-pub const mach_timebase_info_data = c.mach_timebase_info_data;
-
-pub const mach_absolute_time = c.mach_absolute_time;
-pub const mach_timebase_info = c.mach_timebase_info;
+pub use std.c;
diff --git a/std/os/darwin/errno.zig b/std/os/darwin/errno.zig
deleted file mode 100644
index 438f3382ad..0000000000
--- a/std/os/darwin/errno.zig
+++ /dev/null
@@ -1,328 +0,0 @@
-/// Operation not permitted
-pub const EPERM = 1;
-
-/// No such file or directory
-pub const ENOENT = 2;
-
-/// No such process
-pub const ESRCH = 3;
-
-/// Interrupted system call
-pub const EINTR = 4;
-
-/// Input/output error
-pub const EIO = 5;
-
-/// Device not configured
-pub const ENXIO = 6;
-
-/// Argument list too long
-pub const E2BIG = 7;
-
-/// Exec format error
-pub const ENOEXEC = 8;
-
-/// Bad file descriptor
-pub const EBADF = 9;
-
-/// No child processes
-pub const ECHILD = 10;
-
-/// Resource deadlock avoided
-pub const EDEADLK = 11;
-
-/// Cannot allocate memory
-pub const ENOMEM = 12;
-
-/// Permission denied
-pub const EACCES = 13;
-
-/// Bad address
-pub const EFAULT = 14;
-
-/// Block device required
-pub const ENOTBLK = 15;
-
-/// Device / Resource busy
-pub const EBUSY = 16;
-
-/// File exists
-pub const EEXIST = 17;
-
-/// Cross-device link
-pub const EXDEV = 18;
-
-/// Operation not supported by device
-pub const ENODEV = 19;
-
-/// Not a directory
-pub const ENOTDIR = 20;
-
-/// Is a directory
-pub const EISDIR = 21;
-
-/// Invalid argument
-pub const EINVAL = 22;
-
-/// Too many open files in system
-pub const ENFILE = 23;
-
-/// Too many open files
-pub const EMFILE = 24;
-
-/// Inappropriate ioctl for device
-pub const ENOTTY = 25;
-
-/// Text file busy
-pub const ETXTBSY = 26;
-
-/// File too large
-pub const EFBIG = 27;
-
-/// No space left on device
-pub const ENOSPC = 28;
-
-/// Illegal seek
-pub const ESPIPE = 29;
-
-/// Read-only file system
-pub const EROFS = 30;
-
-/// Too many links
-pub const EMLINK = 31;
-/// Broken pipe
-
-// math software
-pub const EPIPE = 32;
-
-/// Numerical argument out of domain
-pub const EDOM = 33;
-/// Result too large
-
-// non-blocking and interrupt i/o
-pub const ERANGE = 34;
-
-/// Resource temporarily unavailable
-pub const EAGAIN = 35;
-
-/// Operation would block
-pub const EWOULDBLOCK = EAGAIN;
-
-/// Operation now in progress
-pub const EINPROGRESS = 36;
-/// Operation already in progress
-
-// ipc/network software -- argument errors
-pub const EALREADY = 37;
-
-/// Socket operation on non-socket
-pub const ENOTSOCK = 38;
-
-/// Destination address required
-pub const EDESTADDRREQ = 39;
-
-/// Message too long
-pub const EMSGSIZE = 40;
-
-/// Protocol wrong type for socket
-pub const EPROTOTYPE = 41;
-
-/// Protocol not available
-pub const ENOPROTOOPT = 42;
-
-/// Protocol not supported
-pub const EPROTONOSUPPORT = 43;
-
-/// Socket type not supported
-pub const ESOCKTNOSUPPORT = 44;
-
-/// Operation not supported
-pub const ENOTSUP = 45;
-
-/// Protocol family not supported
-pub const EPFNOSUPPORT = 46;
-
-/// Address family not supported by protocol family
-pub const EAFNOSUPPORT = 47;
-
-/// Address already in use
-pub const EADDRINUSE = 48;
-/// Can't assign requested address
-
-// ipc/network software -- operational errors
-pub const EADDRNOTAVAIL = 49;
-
-/// Network is down
-pub const ENETDOWN = 50;
-
-/// Network is unreachable
-pub const ENETUNREACH = 51;
-
-/// Network dropped connection on reset
-pub const ENETRESET = 52;
-
-/// Software caused connection abort
-pub const ECONNABORTED = 53;
-
-/// Connection reset by peer
-pub const ECONNRESET = 54;
-
-/// No buffer space available
-pub const ENOBUFS = 55;
-
-/// Socket is already connected
-pub const EISCONN = 56;
-
-/// Socket is not connected
-pub const ENOTCONN = 57;
-
-/// Can't send after socket shutdown
-pub const ESHUTDOWN = 58;
-
-/// Too many references: can't splice
-pub const ETOOMANYREFS = 59;
-
-/// Operation timed out
-pub const ETIMEDOUT = 60;
-
-/// Connection refused
-pub const ECONNREFUSED = 61;
-
-/// Too many levels of symbolic links
-pub const ELOOP = 62;
-
-/// File name too long
-pub const ENAMETOOLONG = 63;
-
-/// Host is down
-pub const EHOSTDOWN = 64;
-
-/// No route to host
-pub const EHOSTUNREACH = 65;
-/// Directory not empty
-
-// quotas & mush
-pub const ENOTEMPTY = 66;
-
-/// Too many processes
-pub const EPROCLIM = 67;
-
-/// Too many users
-pub const EUSERS = 68;
-/// Disc quota exceeded
-
-// Network File System
-pub const EDQUOT = 69;
-
-/// Stale NFS file handle
-pub const ESTALE = 70;
-
-/// Too many levels of remote in path
-pub const EREMOTE = 71;
-
-/// RPC struct is bad
-pub const EBADRPC = 72;
-
-/// RPC version wrong
-pub const ERPCMISMATCH = 73;
-
-/// RPC prog. not avail
-pub const EPROGUNAVAIL = 74;
-
-/// Program version wrong
-pub const EPROGMISMATCH = 75;
-
-/// Bad procedure for program
-pub const EPROCUNAVAIL = 76;
-
-/// No locks available
-pub const ENOLCK = 77;
-
-/// Function not implemented
-pub const ENOSYS = 78;
-
-/// Inappropriate file type or format
-pub const EFTYPE = 79;
-
-/// Authentication error
-pub const EAUTH = 80;
-/// Need authenticator
-
-// Intelligent device errors
-pub const ENEEDAUTH = 81;
-
-/// Device power is off
-pub const EPWROFF = 82;
-
-/// Device error, e.g. paper out
-pub const EDEVERR = 83;
-/// Value too large to be stored in data type
-
-// Program loading errors
-pub const EOVERFLOW = 84;
-
-/// Bad executable
-pub const EBADEXEC = 85;
-
-/// Bad CPU type in executable
-pub const EBADARCH = 86;
-
-/// Shared library version mismatch
-pub const ESHLIBVERS = 87;
-
-/// Malformed Macho file
-pub const EBADMACHO = 88;
-
-/// Operation canceled
-pub const ECANCELED = 89;
-
-/// Identifier removed
-pub const EIDRM = 90;
-
-/// No message of desired type
-pub const ENOMSG = 91;
-
-/// Illegal byte sequence
-pub const EILSEQ = 92;
-
-/// Attribute not found
-pub const ENOATTR = 93;
-
-/// Bad message
-pub const EBADMSG = 94;
-
-/// Reserved
-pub const EMULTIHOP = 95;
-
-/// No message available on STREAM
-pub const ENODATA = 96;
-
-/// Reserved
-pub const ENOLINK = 97;
-
-/// No STREAM resources
-pub const ENOSR = 98;
-
-/// Not a STREAM
-pub const ENOSTR = 99;
-
-/// Protocol error
-pub const EPROTO = 100;
-
-/// STREAM ioctl timeout
-pub const ETIME = 101;
-
-/// No such policy registered
-pub const ENOPOLICY = 103;
-
-/// State not recoverable
-pub const ENOTRECOVERABLE = 104;
-
-/// Previous owner died
-pub const EOWNERDEAD = 105;
-
-/// Interface output queue is full
-pub const EQFULL = 106;
-
-/// Must be equal largest errno
-pub const ELAST = 106;
diff --git a/std/os/file.zig b/std/os/file.zig
deleted file mode 100644
index d223d55a46..0000000000
--- a/std/os/file.zig
+++ /dev/null
@@ -1,512 +0,0 @@
-const std = @import("../std.zig");
-const builtin = @import("builtin");
-const os = std.os;
-const io = std.io;
-const mem = std.mem;
-const math = std.math;
-const assert = std.debug.assert;
-const posix = os.posix;
-const windows = os.windows;
-const Os = builtin.Os;
-const windows_util = @import("windows/util.zig");
-const maxInt = std.math.maxInt;
-
-const is_posix = builtin.os != builtin.Os.windows;
-const is_windows = builtin.os == builtin.Os.windows;
-
-pub const File = struct {
- /// The OS-specific file descriptor or file handle.
- handle: os.FileHandle,
-
- pub const Mode = switch (builtin.os) {
- Os.windows => void,
- else => u32,
- };
-
- pub const default_mode = switch (builtin.os) {
- Os.windows => {},
- else => 0o666,
- };
-
- pub const OpenError = os.WindowsOpenError || os.PosixOpenError;
-
- /// `openRead` except with a null terminated path
- pub fn openReadC(path: [*]const u8) OpenError!File {
- if (is_posix) {
- const flags = posix.O_LARGEFILE | posix.O_RDONLY;
- const fd = try os.posixOpenC(path, flags, 0);
- return openHandle(fd);
- }
- if (is_windows) {
- return openRead(mem.toSliceConst(u8, path));
- }
- @compileError("Unsupported OS");
- }
-
- /// Call close to clean up.
- pub fn openRead(path: []const u8) OpenError!File {
- if (is_posix) {
- const path_c = try os.toPosixPath(path);
- return openReadC(&path_c);
- }
- if (is_windows) {
- const path_w = try windows_util.sliceToPrefixedFileW(path);
- return openReadW(&path_w);
- }
- @compileError("Unsupported OS");
- }
-
- pub fn openReadW(path_w: [*]const u16) OpenError!File {
- const handle = try os.windowsOpenW(
- path_w,
- windows.GENERIC_READ,
- windows.FILE_SHARE_READ,
- windows.OPEN_EXISTING,
- windows.FILE_ATTRIBUTE_NORMAL,
- );
- return openHandle(handle);
- }
-
- /// Calls `openWriteMode` with os.File.default_mode for the mode.
- pub fn openWrite(path: []const u8) OpenError!File {
- return openWriteMode(path, os.File.default_mode);
- }
-
- /// If the path does not exist it will be created.
- /// If a file already exists in the destination it will be truncated.
- /// Call close to clean up.
- pub fn openWriteMode(path: []const u8, file_mode: Mode) OpenError!File {
- if (is_posix) {
- const flags = posix.O_LARGEFILE | posix.O_WRONLY | posix.O_CREAT | posix.O_CLOEXEC | posix.O_TRUNC;
- const fd = try os.posixOpen(path, flags, file_mode);
- return openHandle(fd);
- } else if (is_windows) {
- const path_w = try windows_util.sliceToPrefixedFileW(path);
- return openWriteModeW(&path_w, file_mode);
- } else {
- @compileError("TODO implement openWriteMode for this OS");
- }
- }
-
- pub fn openWriteModeW(path_w: [*]const u16, file_mode: Mode) OpenError!File {
- const handle = try os.windowsOpenW(
- path_w,
- windows.GENERIC_WRITE,
- windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
- windows.CREATE_ALWAYS,
- windows.FILE_ATTRIBUTE_NORMAL,
- );
- return openHandle(handle);
- }
-
- /// If the path does not exist it will be created.
- /// If a file already exists in the destination this returns OpenError.PathAlreadyExists
- /// Call close to clean up.
- pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File {
- if (is_posix) {
- const path_c = try os.toPosixPath(path);
- return openWriteNoClobberC(&path_c, file_mode);
- } else if (is_windows) {
- const path_w = try windows_util.sliceToPrefixedFileW(path);
- return openWriteNoClobberW(&path_w, file_mode);
- } else {
- @compileError("TODO implement openWriteMode for this OS");
- }
- }
-
- pub fn openWriteNoClobberC(path: [*]const u8, file_mode: Mode) OpenError!File {
- if (is_posix) {
- const flags = posix.O_LARGEFILE | posix.O_WRONLY | posix.O_CREAT | posix.O_CLOEXEC | posix.O_EXCL;
- const fd = try os.posixOpenC(path, flags, file_mode);
- return openHandle(fd);
- } else if (is_windows) {
- const path_w = try windows_util.cStrToPrefixedFileW(path);
- return openWriteNoClobberW(&path_w, file_mode);
- } else {
- @compileError("TODO implement openWriteMode for this OS");
- }
- }
-
- pub fn openWriteNoClobberW(path_w: [*]const u16, file_mode: Mode) OpenError!File {
- const handle = try os.windowsOpenW(
- path_w,
- windows.GENERIC_WRITE,
- windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
- windows.CREATE_NEW,
- windows.FILE_ATTRIBUTE_NORMAL,
- );
- return openHandle(handle);
- }
-
- pub fn openHandle(handle: os.FileHandle) File {
- return File{ .handle = handle };
- }
-
- pub const AccessError = error{
- PermissionDenied,
- FileNotFound,
- NameTooLong,
- InputOutput,
- SystemResources,
- BadPathName,
-
- /// On Windows, file paths must be valid Unicode.
- InvalidUtf8,
-
- Unexpected,
- };
-
- /// Call from Windows-specific code if you already have a UTF-16LE encoded, null terminated string.
- /// Otherwise use `access` or `accessC`.
- pub fn accessW(path: [*]const u16) AccessError!void {
- if (os.windows.GetFileAttributesW(path) != os.windows.INVALID_FILE_ATTRIBUTES) {
- return;
- }
-
- const err = windows.GetLastError();
- switch (err) {
- windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
- windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
- windows.ERROR.ACCESS_DENIED => return error.PermissionDenied,
- else => return os.unexpectedErrorWindows(err),
- }
- }
-
- /// Call if you have a UTF-8 encoded, null-terminated string.
- /// Otherwise use `access` or `accessW`.
- pub fn accessC(path: [*]const u8) AccessError!void {
- if (is_windows) {
- const path_w = try windows_util.cStrToPrefixedFileW(path);
- return accessW(&path_w);
- }
- if (is_posix) {
- const result = posix.access(path, posix.F_OK);
- const err = posix.getErrno(result);
- switch (err) {
- 0 => return,
- posix.EACCES => return error.PermissionDenied,
- posix.EROFS => return error.PermissionDenied,
- posix.ELOOP => return error.PermissionDenied,
- posix.ETXTBSY => return error.PermissionDenied,
- posix.ENOTDIR => return error.FileNotFound,
- posix.ENOENT => return error.FileNotFound,
-
- posix.ENAMETOOLONG => return error.NameTooLong,
- posix.EINVAL => unreachable,
- posix.EFAULT => unreachable,
- posix.EIO => return error.InputOutput,
- posix.ENOMEM => return error.SystemResources,
- else => return os.unexpectedErrorPosix(err),
- }
- }
- @compileError("Unsupported OS");
- }
-
- pub fn access(path: []const u8) AccessError!void {
- if (is_windows) {
- const path_w = try windows_util.sliceToPrefixedFileW(path);
- return accessW(&path_w);
- }
- if (is_posix) {
- var path_with_null: [posix.PATH_MAX]u8 = undefined;
- if (path.len >= posix.PATH_MAX) return error.NameTooLong;
- mem.copy(u8, path_with_null[0..], path);
- path_with_null[path.len] = 0;
- return accessC(&path_with_null);
- }
- @compileError("Unsupported OS");
- }
-
- /// Upon success, the stream is in an uninitialized state. To continue using it,
- /// you must use the open() function.
- pub fn close(self: File) void {
- os.close(self.handle);
- }
-
- /// Calls `os.isTty` on `self.handle`.
- pub fn isTty(self: File) bool {
- return os.isTty(self.handle);
- }
-
- pub const SeekError = error{
- /// TODO make this error impossible to get
- Overflow,
- Unseekable,
- Unexpected,
- };
-
- pub fn seekForward(self: File, amount: i64) SeekError!void {
- switch (builtin.os) {
- Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
- const iamount = try math.cast(isize, amount);
- const result = posix.lseek(self.handle, iamount, posix.SEEK_CUR);
- const err = posix.getErrno(result);
- if (err > 0) {
- return switch (err) {
- // We do not make this an error code because if you get EBADF it's always a bug,
- // since the fd could have been reused.
- posix.EBADF => unreachable,
- posix.EINVAL => error.Unseekable,
- posix.EOVERFLOW => error.Unseekable,
- posix.ESPIPE => error.Unseekable,
- posix.ENXIO => error.Unseekable,
- else => os.unexpectedErrorPosix(err),
- };
- }
- },
- Os.windows => {
- if (windows.SetFilePointerEx(self.handle, amount, null, windows.FILE_CURRENT) == 0) {
- const err = windows.GetLastError();
- return switch (err) {
- windows.ERROR.INVALID_PARAMETER => unreachable,
- else => os.unexpectedErrorWindows(err),
- };
- }
- },
- else => @compileError("unsupported OS"),
- }
- }
-
- pub fn seekTo(self: File, pos: u64) SeekError!void {
- switch (builtin.os) {
- Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
- const ipos = try math.cast(isize, pos);
- const result = posix.lseek(self.handle, ipos, posix.SEEK_SET);
- const err = posix.getErrno(result);
- if (err > 0) {
- return switch (err) {
- // We do not make this an error code because if you get EBADF it's always a bug,
- // since the fd could have been reused.
- posix.EBADF => unreachable,
- posix.EINVAL => error.Unseekable,
- posix.EOVERFLOW => error.Unseekable,
- posix.ESPIPE => error.Unseekable,
- posix.ENXIO => error.Unseekable,
- else => os.unexpectedErrorPosix(err),
- };
- }
- },
- Os.windows => {
- const ipos = try math.cast(isize, pos);
- if (windows.SetFilePointerEx(self.handle, ipos, null, windows.FILE_BEGIN) == 0) {
- const err = windows.GetLastError();
- return switch (err) {
- windows.ERROR.INVALID_PARAMETER => unreachable,
- windows.ERROR.INVALID_HANDLE => unreachable,
- else => os.unexpectedErrorWindows(err),
- };
- }
- },
- else => @compileError("unsupported OS: " ++ @tagName(builtin.os)),
- }
- }
-
- pub const GetSeekPosError = error{
- SystemResources,
- Unseekable,
- Unexpected,
- };
-
- pub fn getPos(self: File) GetSeekPosError!u64 {
- switch (builtin.os) {
- Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
- const result = posix.lseek(self.handle, 0, posix.SEEK_CUR);
- const err = posix.getErrno(result);
- if (err > 0) {
- return switch (err) {
- // We do not make this an error code because if you get EBADF it's always a bug,
- // since the fd could have been reused.
- posix.EBADF => unreachable,
- posix.EINVAL => error.Unseekable,
- posix.EOVERFLOW => error.Unseekable,
- posix.ESPIPE => error.Unseekable,
- posix.ENXIO => error.Unseekable,
- else => os.unexpectedErrorPosix(err),
- };
- }
- return u64(result);
- },
- Os.windows => {
- var pos: windows.LARGE_INTEGER = undefined;
- if (windows.SetFilePointerEx(self.handle, 0, &pos, windows.FILE_CURRENT) == 0) {
- const err = windows.GetLastError();
- return switch (err) {
- windows.ERROR.INVALID_PARAMETER => unreachable,
- else => os.unexpectedErrorWindows(err),
- };
- }
-
- return @intCast(u64, pos);
- },
- else => @compileError("unsupported OS"),
- }
- }
-
- pub fn getEndPos(self: File) GetSeekPosError!u64 {
- if (is_posix) {
- const stat = try os.posixFStat(self.handle);
- return @intCast(u64, stat.size);
- } else if (is_windows) {
- var file_size: windows.LARGE_INTEGER = undefined;
- if (windows.GetFileSizeEx(self.handle, &file_size) == 0) {
- const err = windows.GetLastError();
- return switch (err) {
- else => os.unexpectedErrorWindows(err),
- };
- }
- return @intCast(u64, file_size);
- } else {
- @compileError("TODO support getEndPos on this OS");
- }
- }
-
- pub const ModeError = error{
- SystemResources,
- Unexpected,
- };
-
- pub fn mode(self: File) ModeError!Mode {
- if (is_posix) {
- var stat: posix.Stat = undefined;
- const err = posix.getErrno(posix.fstat(self.handle, &stat));
- if (err > 0) {
- return switch (err) {
- // We do not make this an error code because if you get EBADF it's always a bug,
- // since the fd could have been reused.
- posix.EBADF => unreachable,
- posix.ENOMEM => error.SystemResources,
- else => os.unexpectedErrorPosix(err),
- };
- }
-
- // TODO: we should be able to cast u16 to ModeError!u32, making this
- // explicit cast not necessary
- return Mode(stat.mode);
- } else if (is_windows) {
- return {};
- } else {
- @compileError("TODO support file mode on this OS");
- }
- }
-
- pub const ReadError = os.WindowsReadError || os.PosixReadError;
-
- pub fn read(self: File, buffer: []u8) ReadError!usize {
- if (is_posix) {
- return os.posixRead(self.handle, buffer);
- } else if (is_windows) {
- var index: usize = 0;
- while (index < buffer.len) {
- const want_read_count = @intCast(windows.DWORD, math.min(windows.DWORD(maxInt(windows.DWORD)), buffer.len - index));
- var amt_read: windows.DWORD = undefined;
- if (windows.ReadFile(self.handle, buffer.ptr + index, want_read_count, &amt_read, null) == 0) {
- const err = windows.GetLastError();
- return switch (err) {
- windows.ERROR.OPERATION_ABORTED => continue,
- windows.ERROR.BROKEN_PIPE => return index,
- else => os.unexpectedErrorWindows(err),
- };
- }
- if (amt_read == 0) return index;
- index += amt_read;
- }
- return index;
- } else {
- @compileError("Unsupported OS");
- }
- }
-
- pub const WriteError = os.WindowsWriteError || os.PosixWriteError;
-
- pub fn write(self: File, bytes: []const u8) WriteError!void {
- if (is_posix) {
- try os.posixWrite(self.handle, bytes);
- } else if (is_windows) {
- try os.windowsWrite(self.handle, bytes);
- } else {
- @compileError("Unsupported OS");
- }
- }
-
- pub fn inStream(file: File) InStream {
- return InStream{
- .file = file,
- .stream = InStream.Stream{ .readFn = InStream.readFn },
- };
- }
-
- pub fn outStream(file: File) OutStream {
- return OutStream{
- .file = file,
- .stream = OutStream.Stream{ .writeFn = OutStream.writeFn },
- };
- }
-
- pub fn seekableStream(file: File) SeekableStream {
- return SeekableStream{
- .file = file,
- .stream = SeekableStream.Stream{
- .seekToFn = SeekableStream.seekToFn,
- .seekForwardFn = SeekableStream.seekForwardFn,
- .getPosFn = SeekableStream.getPosFn,
- .getEndPosFn = SeekableStream.getEndPosFn,
- },
- };
- }
-
- /// Implementation of io.InStream trait for File
- pub const InStream = struct {
- file: File,
- stream: Stream,
-
- pub const Error = ReadError;
- pub const Stream = io.InStream(Error);
-
- fn readFn(in_stream: *Stream, buffer: []u8) Error!usize {
- const self = @fieldParentPtr(InStream, "stream", in_stream);
- return self.file.read(buffer);
- }
- };
-
- /// Implementation of io.OutStream trait for File
- pub const OutStream = struct {
- file: File,
- stream: Stream,
-
- pub const Error = WriteError;
- pub const Stream = io.OutStream(Error);
-
- fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void {
- const self = @fieldParentPtr(OutStream, "stream", out_stream);
- return self.file.write(bytes);
- }
- };
-
- /// Implementation of io.SeekableStream trait for File
- pub const SeekableStream = struct {
- file: File,
- stream: Stream,
-
- pub const Stream = io.SeekableStream(SeekError, GetSeekPosError);
-
- pub fn seekToFn(seekable_stream: *Stream, pos: u64) SeekError!void {
- const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
- return self.file.seekTo(pos);
- }
-
- pub fn seekForwardFn(seekable_stream: *Stream, amt: i64) SeekError!void {
- const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
- return self.file.seekForward(amt);
- }
-
- pub fn getEndPosFn(seekable_stream: *Stream) GetSeekPosError!u64 {
- const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
- return self.file.getEndPos();
- }
-
- pub fn getPosFn(seekable_stream: *Stream) GetSeekPosError!u64 {
- const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
- return self.file.getPos();
- }
- };
-};
diff --git a/std/os/freebsd.zig b/std/os/freebsd.zig
index c806067706..c0f3382bd0 100644
--- a/std/os/freebsd.zig
+++ b/std/os/freebsd.zig
@@ -1,845 +1,4 @@
-const builtin = @import("builtin");
-
-pub use @import("freebsd/errno.zig");
-
const std = @import("../std.zig");
-const c = std.c;
-
-const assert = std.debug.assert;
-const maxInt = std.math.maxInt;
-pub const Kevent = c.Kevent;
-
-pub const CTL_KERN = 1;
-pub const CTL_DEBUG = 5;
-
-pub const KERN_PROC = 14; // struct: process entries
-pub const KERN_PROC_PATHNAME = 12; // path to executable
-
-pub const PATH_MAX = 1024;
-
-pub const STDIN_FILENO = 0;
-pub const STDOUT_FILENO = 1;
-pub const STDERR_FILENO = 2;
-
-pub const PROT_NONE = 0;
-pub const PROT_READ = 1;
-pub const PROT_WRITE = 2;
-pub const PROT_EXEC = 4;
-
-pub const CLOCK_REALTIME = 0;
-pub const CLOCK_VIRTUAL = 1;
-pub const CLOCK_PROF = 2;
-pub const CLOCK_MONOTONIC = 4;
-pub const CLOCK_UPTIME = 5;
-pub const CLOCK_UPTIME_PRECISE = 7;
-pub const CLOCK_UPTIME_FAST = 8;
-pub const CLOCK_REALTIME_PRECISE = 9;
-pub const CLOCK_REALTIME_FAST = 10;
-pub const CLOCK_MONOTONIC_PRECISE = 11;
-pub const CLOCK_MONOTONIC_FAST = 12;
-pub const CLOCK_SECOND = 13;
-pub const CLOCK_THREAD_CPUTIME_ID = 14;
-pub const CLOCK_PROCESS_CPUTIME_ID = 15;
-
-pub const MAP_FAILED = maxInt(usize);
-pub const MAP_SHARED = 0x0001;
-pub const MAP_PRIVATE = 0x0002;
-pub const MAP_FIXED = 0x0010;
-pub const MAP_STACK = 0x0400;
-pub const MAP_NOSYNC = 0x0800;
-pub const MAP_ANON = 0x1000;
-pub const MAP_ANONYMOUS = MAP_ANON;
-pub const MAP_FILE = 0;
-pub const MAP_NORESERVE = 0;
-
-pub const MAP_GUARD = 0x00002000;
-pub const MAP_EXCL = 0x00004000;
-pub const MAP_NOCORE = 0x00020000;
-pub const MAP_PREFAULT_READ = 0x00040000;
-pub const MAP_32BIT = 0x00080000;
-
-pub const WNOHANG = 1;
-pub const WUNTRACED = 2;
-pub const WSTOPPED = WUNTRACED;
-pub const WCONTINUED = 4;
-pub const WNOWAIT = 8;
-pub const WEXITED = 16;
-pub const WTRAPPED = 32;
-
-pub const SA_ONSTACK = 0x0001;
-pub const SA_RESTART = 0x0002;
-pub const SA_RESETHAND = 0x0004;
-pub const SA_NOCLDSTOP = 0x0008;
-pub const SA_NODEFER = 0x0010;
-pub const SA_NOCLDWAIT = 0x0020;
-pub const SA_SIGINFO = 0x0040;
-
-pub const SIGHUP = 1;
-pub const SIGINT = 2;
-pub const SIGQUIT = 3;
-pub const SIGILL = 4;
-pub const SIGTRAP = 5;
-pub const SIGABRT = 6;
-pub const SIGIOT = SIGABRT;
-pub const SIGEMT = 7;
-pub const SIGFPE = 8;
-pub const SIGKILL = 9;
-pub const SIGBUS = 10;
-pub const SIGSEGV = 11;
-pub const SIGSYS = 12;
-pub const SIGPIPE = 13;
-pub const SIGALRM = 14;
-pub const SIGTERM = 15;
-pub const SIGURG = 16;
-pub const SIGSTOP = 17;
-pub const SIGTSTP = 18;
-pub const SIGCONT = 19;
-pub const SIGCHLD = 20;
-pub const SIGTTIN = 21;
-pub const SIGTTOU = 22;
-pub const SIGIO = 23;
-pub const SIGXCPU = 24;
-pub const SIGXFSZ = 25;
-pub const SIGVTALRM = 26;
-pub const SIGPROF = 27;
-pub const SIGWINCH = 28;
-pub const SIGINFO = 29;
-pub const SIGUSR1 = 30;
-pub const SIGUSR2 = 31;
-pub const SIGTHR = 32;
-pub const SIGLWP = SIGTHR;
-pub const SIGLIBRT = 33;
-
-pub const SIGRTMIN = 65;
-pub const SIGRTMAX = 126;
-
-// access function
-pub const F_OK = 0; // test for existence of file
-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_RDONLY = 0x0000;
-pub const O_WRONLY = 0x0001;
-pub const O_RDWR = 0x0002;
-pub const O_ACCMODE = 0x0003;
-
-pub const O_CREAT = 0x0200;
-pub const O_EXCL = 0x0800;
-pub const O_NOCTTY = 0x8000;
-pub const O_TRUNC = 0x0400;
-pub const O_APPEND = 0x0008;
-pub const O_NONBLOCK = 0x0004;
-pub const O_DSYNC = 0o10000;
-pub const O_SYNC = 0x0080;
-pub const O_RSYNC = 0o4010000;
-pub const O_DIRECTORY = 0o200000;
-pub const O_NOFOLLOW = 0x0100;
-pub const O_CLOEXEC = 0x00100000;
-
-pub const O_ASYNC = 0x0040;
-pub const O_DIRECT = 0x00010000;
-pub const O_LARGEFILE = 0;
-pub const O_NOATIME = 0o1000000;
-pub const O_PATH = 0o10000000;
-pub const O_TMPFILE = 0o20200000;
-pub const O_NDELAY = O_NONBLOCK;
-
-pub const F_DUPFD = 0;
-pub const F_GETFD = 1;
-pub const F_SETFD = 2;
-pub const F_GETFL = 3;
-pub const F_SETFL = 4;
-
-pub const F_SETOWN = 8;
-pub const F_GETOWN = 9;
-pub const F_SETSIG = 10;
-pub const F_GETSIG = 11;
-
-pub const F_GETLK = 5;
-pub const F_SETLK = 6;
-pub const F_SETLKW = 7;
-
-pub const F_SETOWN_EX = 15;
-pub const F_GETOWN_EX = 16;
-
-pub const F_GETOWNER_UIDS = 17;
-
-pub const SEEK_SET = 0;
-pub const SEEK_CUR = 1;
-pub const SEEK_END = 2;
-
-pub const SIG_BLOCK = 1;
-pub const SIG_UNBLOCK = 2;
-pub const SIG_SETMASK = 3;
-
-pub const SOCK_STREAM = 1;
-pub const SOCK_DGRAM = 2;
-pub const SOCK_RAW = 3;
-pub const SOCK_RDM = 4;
-pub const SOCK_SEQPACKET = 5;
-
-pub const SOCK_CLOEXEC = 0x10000000;
-pub const SOCK_NONBLOCK = 0x20000000;
-
-pub const PROTO_ip = 0o000;
-pub const PROTO_icmp = 0o001;
-pub const PROTO_igmp = 0o002;
-pub const PROTO_ggp = 0o003;
-pub const PROTO_ipencap = 0o004;
-pub const PROTO_st = 0o005;
-pub const PROTO_tcp = 0o006;
-pub const PROTO_egp = 0o010;
-pub const PROTO_pup = 0o014;
-pub const PROTO_udp = 0o021;
-pub const PROTO_hmp = 0o024;
-pub const PROTO_xns_idp = 0o026;
-pub const PROTO_rdp = 0o033;
-pub const PROTO_iso_tp4 = 0o035;
-pub const PROTO_xtp = 0o044;
-pub const PROTO_ddp = 0o045;
-pub const PROTO_idpr_cmtp = 0o046;
-pub const PROTO_ipv6 = 0o051;
-pub const PROTO_ipv6_route = 0o053;
-pub const PROTO_ipv6_frag = 0o054;
-pub const PROTO_idrp = 0o055;
-pub const PROTO_rsvp = 0o056;
-pub const PROTO_gre = 0o057;
-pub const PROTO_esp = 0o062;
-pub const PROTO_ah = 0o063;
-pub const PROTO_skip = 0o071;
-pub const PROTO_ipv6_icmp = 0o072;
-pub const PROTO_ipv6_nonxt = 0o073;
-pub const PROTO_ipv6_opts = 0o074;
-pub const PROTO_rspf = 0o111;
-pub const PROTO_vmtp = 0o121;
-pub const PROTO_ospf = 0o131;
-pub const PROTO_ipip = 0o136;
-pub const PROTO_encap = 0o142;
-pub const PROTO_pim = 0o147;
-pub const PROTO_raw = 0o377;
-
-pub const PF_UNSPEC = 0;
-pub const PF_LOCAL = 1;
-pub const PF_UNIX = PF_LOCAL;
-pub const PF_FILE = PF_LOCAL;
-pub const PF_INET = 2;
-pub const PF_AX25 = 3;
-pub const PF_IPX = 4;
-pub const PF_APPLETALK = 5;
-pub const PF_NETROM = 6;
-pub const PF_BRIDGE = 7;
-pub const PF_ATMPVC = 8;
-pub const PF_X25 = 9;
-pub const PF_INET6 = 10;
-pub const PF_ROSE = 11;
-pub const PF_DECnet = 12;
-pub const PF_NETBEUI = 13;
-pub const PF_SECURITY = 14;
-pub const PF_KEY = 15;
-pub const PF_NETLINK = 16;
-pub const PF_ROUTE = PF_NETLINK;
-pub const PF_PACKET = 17;
-pub const PF_ASH = 18;
-pub const PF_ECONET = 19;
-pub const PF_ATMSVC = 20;
-pub const PF_RDS = 21;
-pub const PF_SNA = 22;
-pub const PF_IRDA = 23;
-pub const PF_PPPOX = 24;
-pub const PF_WANPIPE = 25;
-pub const PF_LLC = 26;
-pub const PF_IB = 27;
-pub const PF_MPLS = 28;
-pub const PF_CAN = 29;
-pub const PF_TIPC = 30;
-pub const PF_BLUETOOTH = 31;
-pub const PF_IUCV = 32;
-pub const PF_RXRPC = 33;
-pub const PF_ISDN = 34;
-pub const PF_PHONET = 35;
-pub const PF_IEEE802154 = 36;
-pub const PF_CAIF = 37;
-pub const PF_ALG = 38;
-pub const PF_NFC = 39;
-pub const PF_VSOCK = 40;
-pub const PF_MAX = 41;
-
-pub const AF_UNSPEC = PF_UNSPEC;
-pub const AF_LOCAL = PF_LOCAL;
-pub const AF_UNIX = AF_LOCAL;
-pub const AF_FILE = AF_LOCAL;
-pub const AF_INET = PF_INET;
-pub const AF_AX25 = PF_AX25;
-pub const AF_IPX = PF_IPX;
-pub const AF_APPLETALK = PF_APPLETALK;
-pub const AF_NETROM = PF_NETROM;
-pub const AF_BRIDGE = PF_BRIDGE;
-pub const AF_ATMPVC = PF_ATMPVC;
-pub const AF_X25 = PF_X25;
-pub const AF_INET6 = PF_INET6;
-pub const AF_ROSE = PF_ROSE;
-pub const AF_DECnet = PF_DECnet;
-pub const AF_NETBEUI = PF_NETBEUI;
-pub const AF_SECURITY = PF_SECURITY;
-pub const AF_KEY = PF_KEY;
-pub const AF_NETLINK = PF_NETLINK;
-pub const AF_ROUTE = PF_ROUTE;
-pub const AF_PACKET = PF_PACKET;
-pub const AF_ASH = PF_ASH;
-pub const AF_ECONET = PF_ECONET;
-pub const AF_ATMSVC = PF_ATMSVC;
-pub const AF_RDS = PF_RDS;
-pub const AF_SNA = PF_SNA;
-pub const AF_IRDA = PF_IRDA;
-pub const AF_PPPOX = PF_PPPOX;
-pub const AF_WANPIPE = PF_WANPIPE;
-pub const AF_LLC = PF_LLC;
-pub const AF_IB = PF_IB;
-pub const AF_MPLS = PF_MPLS;
-pub const AF_CAN = PF_CAN;
-pub const AF_TIPC = PF_TIPC;
-pub const AF_BLUETOOTH = PF_BLUETOOTH;
-pub const AF_IUCV = PF_IUCV;
-pub const AF_RXRPC = PF_RXRPC;
-pub const AF_ISDN = PF_ISDN;
-pub const AF_PHONET = PF_PHONET;
-pub const AF_IEEE802154 = PF_IEEE802154;
-pub const AF_CAIF = PF_CAIF;
-pub const AF_ALG = PF_ALG;
-pub const AF_NFC = PF_NFC;
-pub const AF_VSOCK = PF_VSOCK;
-pub const AF_MAX = PF_MAX;
-
-pub const DT_UNKNOWN = 0;
-pub const DT_FIFO = 1;
-pub const DT_CHR = 2;
-pub const DT_DIR = 4;
-pub const DT_BLK = 6;
-pub const DT_REG = 8;
-pub const DT_LNK = 10;
-pub const DT_SOCK = 12;
-pub const DT_WHT = 14;
-
-/// add event to kq (implies enable)
-pub const EV_ADD = 0x0001;
-
-/// delete event from kq
-pub const EV_DELETE = 0x0002;
-
-/// enable event
-pub const EV_ENABLE = 0x0004;
-
-/// disable event (not reported)
-pub const EV_DISABLE = 0x0008;
-
-/// only report one occurrence
-pub const EV_ONESHOT = 0x0010;
-
-/// clear event state after reporting
-pub const EV_CLEAR = 0x0020;
-
-/// force immediate event output
-/// ... with or without EV_ERROR
-/// ... use KEVENT_FLAG_ERROR_EVENTS
-/// on syscalls supporting flags
-pub const EV_RECEIPT = 0x0040;
-
-/// disable event after reporting
-pub const EV_DISPATCH = 0x0080;
-
-pub const EVFILT_READ = -1;
-pub const EVFILT_WRITE = -2;
-
-/// attached to aio requests
-pub const EVFILT_AIO = -3;
-
-/// attached to vnodes
-pub const EVFILT_VNODE = -4;
-
-/// attached to struct proc
-pub const EVFILT_PROC = -5;
-
-/// attached to struct proc
-pub const EVFILT_SIGNAL = -6;
-
-/// timers
-pub const EVFILT_TIMER = -7;
-
-/// Process descriptors
-pub const EVFILT_PROCDESC = -8;
-
-/// Filesystem events
-pub const EVFILT_FS = -9;
-
-pub const EVFILT_LIO = -10;
-
-/// User events
-pub const EVFILT_USER = -11;
-
-/// Sendfile events
-pub const EVFILT_SENDFILE = -12;
-
-pub const EVFILT_EMPTY = -13;
-
-/// On input, NOTE_TRIGGER causes the event to be triggered for output.
-pub const NOTE_TRIGGER = 0x01000000;
-
-/// ignore input fflags
-pub const NOTE_FFNOP = 0x00000000;
-
-/// and fflags
-pub const NOTE_FFAND = 0x40000000;
-
-/// or fflags
-pub const NOTE_FFOR = 0x80000000;
-
-/// copy fflags
-pub const NOTE_FFCOPY = 0xc0000000;
-
-/// mask for operations
-pub const NOTE_FFCTRLMASK = 0xc0000000;
-pub const NOTE_FFLAGSMASK = 0x00ffffff;
-
-/// low water mark
-pub const NOTE_LOWAT = 0x00000001;
-
-/// behave like poll()
-pub const NOTE_FILE_POLL = 0x00000002;
-
-/// vnode was removed
-pub const NOTE_DELETE = 0x00000001;
-
-/// data contents changed
-pub const NOTE_WRITE = 0x00000002;
-
-/// size increased
-pub const NOTE_EXTEND = 0x00000004;
-
-/// attributes changed
-pub const NOTE_ATTRIB = 0x00000008;
-
-/// link count changed
-pub const NOTE_LINK = 0x00000010;
-
-/// vnode was renamed
-pub const NOTE_RENAME = 0x00000020;
-
-/// vnode access was revoked
-pub const NOTE_REVOKE = 0x00000040;
-
-/// vnode was opened
-pub const NOTE_OPEN = 0x00000080;
-
-/// file closed, fd did not allow write
-pub const NOTE_CLOSE = 0x00000100;
-
-/// file closed, fd did allow write
-pub const NOTE_CLOSE_WRITE = 0x00000200;
-
-/// file was read
-pub const NOTE_READ = 0x00000400;
-
-/// process exited
-pub const NOTE_EXIT = 0x80000000;
-
-/// process forked
-pub const NOTE_FORK = 0x40000000;
-
-/// process exec'd
-pub const NOTE_EXEC = 0x20000000;
-
-/// mask for signal & exit status
-pub const NOTE_PDATAMASK = 0x000fffff;
-pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK);
-
-/// data is seconds
-pub const NOTE_SECONDS = 0x00000001;
-
-/// data is milliseconds
-pub const NOTE_MSECONDS = 0x00000002;
-
-/// data is microseconds
-pub const NOTE_USECONDS = 0x00000004;
-
-/// data is nanoseconds
-pub const NOTE_NSECONDS = 0x00000008;
-
-/// timeout is absolute
-pub const NOTE_ABSTIME = 0x00000010;
-
-pub const TCGETS = 0x5401;
-pub const TCSETS = 0x5402;
-pub const TCSETSW = 0x5403;
-pub const TCSETSF = 0x5404;
-pub const TCGETA = 0x5405;
-pub const TCSETA = 0x5406;
-pub const TCSETAW = 0x5407;
-pub const TCSETAF = 0x5408;
-pub const TCSBRK = 0x5409;
-pub const TCXONC = 0x540A;
-pub const TCFLSH = 0x540B;
-pub const TIOCEXCL = 0x540C;
-pub const TIOCNXCL = 0x540D;
-pub const TIOCSCTTY = 0x540E;
-pub const TIOCGPGRP = 0x540F;
-pub const TIOCSPGRP = 0x5410;
-pub const TIOCOUTQ = 0x5411;
-pub const TIOCSTI = 0x5412;
-pub const TIOCGWINSZ = 0x5413;
-pub const TIOCSWINSZ = 0x5414;
-pub const TIOCMGET = 0x5415;
-pub const TIOCMBIS = 0x5416;
-pub const TIOCMBIC = 0x5417;
-pub const TIOCMSET = 0x5418;
-pub const TIOCGSOFTCAR = 0x5419;
-pub const TIOCSSOFTCAR = 0x541A;
-pub const FIONREAD = 0x541B;
-pub const TIOCINQ = FIONREAD;
-pub const TIOCLINUX = 0x541C;
-pub const TIOCCONS = 0x541D;
-pub const TIOCGSERIAL = 0x541E;
-pub const TIOCSSERIAL = 0x541F;
-pub const TIOCPKT = 0x5420;
-pub const FIONBIO = 0x5421;
-pub const TIOCNOTTY = 0x5422;
-pub const TIOCSETD = 0x5423;
-pub const TIOCGETD = 0x5424;
-pub const TCSBRKP = 0x5425;
-pub const TIOCSBRK = 0x5427;
-pub const TIOCCBRK = 0x5428;
-pub const TIOCGSID = 0x5429;
-pub const TIOCGRS485 = 0x542E;
-pub const TIOCSRS485 = 0x542F;
-pub const TIOCGPTN = 0x80045430;
-pub const TIOCSPTLCK = 0x40045431;
-pub const TIOCGDEV = 0x80045432;
-pub const TCGETX = 0x5432;
-pub const TCSETX = 0x5433;
-pub const TCSETXF = 0x5434;
-pub const TCSETXW = 0x5435;
-pub const TIOCSIG = 0x40045436;
-pub const TIOCVHANGUP = 0x5437;
-pub const TIOCGPKT = 0x80045438;
-pub const TIOCGPTLCK = 0x80045439;
-pub const TIOCGEXCL = 0x80045440;
-
-pub const sockaddr = c.sockaddr;
-pub const sockaddr_in = c.sockaddr_in;
-pub const sockaddr_in6 = c.sockaddr_in6;
-
-fn unsigned(s: i32) u32 {
- return @bitCast(u32, s);
-}
-fn signed(s: u32) i32 {
- return @bitCast(i32, s);
-}
-pub fn WEXITSTATUS(s: i32) i32 {
- return signed((unsigned(s) & 0xff00) >> 8);
-}
-pub fn WTERMSIG(s: i32) i32 {
- return signed(unsigned(s) & 0x7f);
-}
-pub fn WSTOPSIG(s: i32) i32 {
- return WEXITSTATUS(s);
-}
-pub fn WIFEXITED(s: i32) bool {
- return WTERMSIG(s) == 0;
-}
-pub fn WIFSTOPPED(s: i32) bool {
- return @intCast(u16, (((unsigned(s) & 0xffff) *% 0x10001) >> 8)) > 0x7f00;
-}
-pub fn WIFSIGNALED(s: i32) bool {
- return (unsigned(s) & 0xffff) -% 1 < 0xff;
-}
-
-pub const winsize = extern struct {
- ws_row: u16,
- ws_col: u16,
- ws_xpixel: u16,
- ws_ypixel: u16,
-};
-
-/// Get the errno from a syscall return value, or 0 for no error.
-pub fn getErrno(r: usize) usize {
- const signed_r = @bitCast(isize, r);
- return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
-}
-
-pub fn dup2(old: i32, new: i32) usize {
- return errnoWrap(c.dup2(old, new));
-}
-
-pub fn chdir(path: [*]const u8) usize {
- return errnoWrap(c.chdir(path));
-}
-
-pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
- return errnoWrap(c.execve(path, argv, envp));
-}
-
-pub fn fork() usize {
- return errnoWrap(c.fork());
-}
-
-pub fn access(path: [*]const u8, mode: u32) usize {
- return errnoWrap(c.access(path, mode));
-}
-
-pub fn getcwd(buf: [*]u8, size: usize) usize {
- return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
-}
-
-pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize {
- return errnoWrap(@bitCast(isize, c.getdents(fd, drip, count)));
-}
-
-pub fn getdirentries(fd: i32, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize {
- return errnoWrap(@bitCast(isize, c.getdirentries(fd, buf_ptr, buf_len, basep)));
-}
-
-pub fn realpath(noalias filename: [*]const u8, noalias resolved_name: [*]u8) usize {
- return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
-}
-
-pub fn isatty(fd: i32) bool {
- return c.isatty(fd) != 0;
-}
-
-pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
- return errnoWrap(c.readlink(path, buf_ptr, buf_len));
-}
-
-pub fn mkdir(path: [*]const u8, mode: u32) usize {
- return errnoWrap(c.mkdir(path, mode));
-}
-
-pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
- const ptr_result = c.mmap(
- @ptrCast(?*c_void, address),
- length,
- @bitCast(c_int, @intCast(c_uint, prot)),
- @bitCast(c_int, c_uint(flags)),
- fd,
- offset,
- );
- const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
- return errnoWrap(isize_result);
-}
-
-pub fn munmap(address: usize, length: usize) usize {
- return errnoWrap(c.munmap(@intToPtr(?*c_void, address), length));
-}
-
-pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
- return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte));
-}
-
-pub fn rmdir(path: [*]const u8) usize {
- return errnoWrap(c.rmdir(path));
-}
-
-pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
- return errnoWrap(c.symlink(existing, new));
-}
-
-pub fn pread(fd: i32, buf: [*]u8, nbyte: usize, offset: u64) usize {
- return errnoWrap(c.pread(fd, @ptrCast(*c_void, buf), nbyte, offset));
-}
-
-pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: usize) usize {
- return errnoWrap(c.preadv(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
-}
-
-pub fn pipe(fd: *[2]i32) usize {
- return pipe2(fd, 0);
-}
-
-pub fn pipe2(fd: *[2]i32, flags: u32) usize {
- comptime assert(i32.bit_count == c_int.bit_count);
- return errnoWrap(c.pipe2(@ptrCast(*[2]c_int, fd), flags));
-}
-
-pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize {
- return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte));
-}
-
-pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize {
- return errnoWrap(c.pwrite(fd, @ptrCast(*const c_void, buf), nbyte, offset));
-}
-
-pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) usize {
- return errnoWrap(c.pwritev(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
-}
-
-pub fn rename(old: [*]const u8, new: [*]const u8) usize {
- return errnoWrap(c.rename(old, new));
-}
-
-pub fn open(path: [*]const u8, flags: u32, mode: usize) usize {
- return errnoWrap(c.open(path, @bitCast(c_int, flags), mode));
-}
-
-pub fn create(path: [*]const u8, perm: usize) usize {
- return arch.syscall2(SYS_creat, @ptrToInt(path), perm);
-}
-
-pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize {
- return errnoWrap(c.openat(@bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode));
-}
-
-pub fn close(fd: i32) usize {
- return errnoWrap(c.close(fd));
-}
-
-pub fn lseek(fd: i32, offset: isize, whence: c_int) usize {
- return errnoWrap(c.lseek(fd, offset, whence));
-}
-
-pub fn exit(code: i32) noreturn {
- c.exit(code);
-}
-
-pub fn kill(pid: i32, sig: i32) usize {
- return errnoWrap(c.kill(pid, sig));
-}
-
-pub fn unlink(path: [*]const u8) usize {
- return errnoWrap(c.unlink(path));
-}
-
-pub fn waitpid(pid: i32, status: *i32, options: u32) usize {
- comptime assert(i32.bit_count == c_int.bit_count);
- return errnoWrap(c.waitpid(pid, @ptrCast(*c_int, status), @bitCast(c_int, options)));
-}
-
-pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
- return errnoWrap(c.nanosleep(req, rem));
-}
-
-pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
- return errnoWrap(c.clock_gettime(clk_id, tp));
-}
-
-pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
- return errnoWrap(c.clock_getres(clk_id, tp));
-}
-
-pub fn setuid(uid: u32) usize {
- return errnoWrap(c.setuid(uid));
-}
-
-pub fn setgid(gid: u32) usize {
- return errnoWrap(c.setgid(gid));
-}
-
-pub fn setreuid(ruid: u32, euid: u32) usize {
- return errnoWrap(c.setreuid(ruid, euid));
-}
-
-pub fn setregid(rgid: u32, egid: u32) usize {
- return errnoWrap(c.setregid(rgid, egid));
-}
-
-const NSIG = 32;
-
-pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
-pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
-pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
-
-/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
-pub const Sigaction = extern struct {
- /// signal handler
- __sigaction_u: extern union {
- __sa_handler: extern fn (i32) void,
- __sa_sigaction: extern fn (i32, *__siginfo, usize) void,
- },
-
- /// see signal options
- sa_flags: u32,
-
- /// signal mask to apply
- sa_mask: sigset_t,
-};
-
-pub const _SIG_WORDS = 4;
-pub const _SIG_MAXSIG = 128;
-
-pub inline fn _SIG_IDX(sig: usize) usize {
- return sig - 1;
-}
-pub inline fn _SIG_WORD(sig: usize) usize {
- return_SIG_IDX(sig) >> 5;
-}
-pub inline fn _SIG_BIT(sig: usize) usize {
- return 1 << (_SIG_IDX(sig) & 31);
-}
-pub inline fn _SIG_VALID(sig: usize) usize {
- return sig <= _SIG_MAXSIG and sig > 0;
-}
-
-pub const sigset_t = extern struct {
- __bits: [_SIG_WORDS]u32,
-};
-
-pub fn raise(sig: i32) usize {
- return errnoWrap(c.raise(sig));
-}
-
-pub const Stat = c.Stat;
-pub const dirent = c.dirent;
-pub const timespec = c.timespec;
-
-pub fn fstat(fd: i32, buf: *c.Stat) usize {
- return errnoWrap(c.fstat(fd, buf));
-}
-pub const iovec = extern struct {
- iov_base: [*]u8,
- iov_len: usize,
-};
-
-pub const iovec_const = extern struct {
- iov_base: [*]const u8,
- iov_len: usize,
-};
-
-// TODO avoid libc dependency
-pub fn kqueue() usize {
- return errnoWrap(c.kqueue());
-}
-
-// TODO avoid libc dependency
-pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize {
- return errnoWrap(c.kevent(
- kq,
- changelist.ptr,
- @intCast(c_int, changelist.len),
- eventlist.ptr,
- @intCast(c_int, eventlist.len),
- timeout,
- ));
-}
-
-// TODO avoid libc dependency
-pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
- return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen));
-}
-
-// TODO avoid libc dependency
-pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
- return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen));
-}
-
-// TODO avoid libc dependency
-pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize {
- return errnoWrap(c.sysctlnametomib(name, wibp, sizep));
-}
-
-// TODO avoid libc dependency
-
-/// Takes the return value from a syscall and formats it back in the way
-/// that the kernel represents it to libc. Errno was a mistake, let's make
-/// it go away forever.
-fn errnoWrap(value: isize) usize {
- return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
-}
+const builtin = @import("builtin");
+pub const is_the_target = builtin.os == .freebsd;
+pub use std.c;
diff --git a/std/os/freebsd/errno.zig b/std/os/freebsd/errno.zig
deleted file mode 100644
index 0a0d825f5a..0000000000
--- a/std/os/freebsd/errno.zig
+++ /dev/null
@@ -1,121 +0,0 @@
-pub const EPERM = 1; // Operation not permitted
-pub const ENOENT = 2; // No such file or directory
-pub const ESRCH = 3; // No such process
-pub const EINTR = 4; // Interrupted system call
-pub const EIO = 5; // Input/output error
-pub const ENXIO = 6; // Device not configured
-pub const E2BIG = 7; // Argument list too long
-pub const ENOEXEC = 8; // Exec format error
-pub const EBADF = 9; // Bad file descriptor
-pub const ECHILD = 10; // No child processes
-pub const EDEADLK = 11; // Resource deadlock avoided
-// 11 was EAGAIN
-pub const ENOMEM = 12; // Cannot allocate memory
-pub const EACCES = 13; // Permission denied
-pub const EFAULT = 14; // Bad address
-pub const ENOTBLK = 15; // Block device required
-pub const EBUSY = 16; // Device busy
-pub const EEXIST = 17; // File exists
-pub const EXDEV = 18; // Cross-device link
-pub const ENODEV = 19; // Operation not supported by device
-pub const ENOTDIR = 20; // Not a directory
-pub const EISDIR = 21; // Is a directory
-pub const EINVAL = 22; // Invalid argument
-pub const ENFILE = 23; // Too many open files in system
-pub const EMFILE = 24; // Too many open files
-pub const ENOTTY = 25; // Inappropriate ioctl for device
-pub const ETXTBSY = 26; // Text file busy
-pub const EFBIG = 27; // File too large
-pub const ENOSPC = 28; // No space left on device
-pub const ESPIPE = 29; // Illegal seek
-pub const EROFS = 30; // Read-only filesystem
-pub const EMLINK = 31; // Too many links
-pub const EPIPE = 32; // Broken pipe
-
-// math software
-pub const EDOM = 33; // Numerical argument out of domain
-pub const ERANGE = 34; // Result too large
-
-// non-blocking and interrupt i/o
-pub const EAGAIN = 35; // Resource temporarily unavailable
-pub const EWOULDBLOCK = EAGAIN; // Operation would block
-pub const EINPROGRESS = 36; // Operation now in progress
-pub const EALREADY = 37; // Operation already in progress
-
-// ipc/network software -- argument errors
-pub const ENOTSOCK = 38; // Socket operation on non-socket
-pub const EDESTADDRREQ = 39; // Destination address required
-pub const EMSGSIZE = 40; // Message too long
-pub const EPROTOTYPE = 41; // Protocol wrong type for socket
-pub const ENOPROTOOPT = 42; // Protocol not available
-pub const EPROTONOSUPPORT = 43; // Protocol not supported
-pub const ESOCKTNOSUPPORT = 44; // Socket type not supported
-pub const EOPNOTSUPP = 45; // Operation not supported
-pub const ENOTSUP = EOPNOTSUPP; // Operation not supported
-pub const EPFNOSUPPORT = 46; // Protocol family not supported
-pub const EAFNOSUPPORT = 47; // Address family not supported by protocol family
-pub const EADDRINUSE = 48; // Address already in use
-pub const EADDRNOTAVAIL = 49; // Can't assign requested address
-
-// ipc/network software -- operational errors
-pub const ENETDOWN = 50; // Network is down
-pub const ENETUNREACH = 51; // Network is unreachable
-pub const ENETRESET = 52; // Network dropped connection on reset
-pub const ECONNABORTED = 53; // Software caused connection abort
-pub const ECONNRESET = 54; // Connection reset by peer
-pub const ENOBUFS = 55; // No buffer space available
-pub const EISCONN = 56; // Socket is already connected
-pub const ENOTCONN = 57; // Socket is not connected
-pub const ESHUTDOWN = 58; // Can't send after socket shutdown
-pub const ETOOMANYREFS = 59; // Too many references: can't splice
-pub const ETIMEDOUT = 60; // Operation timed out
-pub const ECONNREFUSED = 61; // Connection refused
-
-pub const ELOOP = 62; // Too many levels of symbolic links
-pub const ENAMETOOLONG = 63; // File name too long
-
-// should be rearranged
-pub const EHOSTDOWN = 64; // Host is down
-pub const EHOSTUNREACH = 65; // No route to host
-pub const ENOTEMPTY = 66; // Directory not empty
-
-// quotas & mush
-pub const EPROCLIM = 67; // Too many processes
-pub const EUSERS = 68; // Too many users
-pub const EDQUOT = 69; // Disc quota exceeded
-
-// Network File System
-pub const ESTALE = 70; // Stale NFS file handle
-pub const EREMOTE = 71; // Too many levels of remote in path
-pub const EBADRPC = 72; // RPC struct is bad
-pub const ERPCMISMATCH = 73; // RPC version wrong
-pub const EPROGUNAVAIL = 74; // RPC prog. not avail
-pub const EPROGMISMATCH = 75; // Program version wrong
-pub const EPROCUNAVAIL = 76; // Bad procedure for program
-
-pub const ENOLCK = 77; // No locks available
-pub const ENOSYS = 78; // Function not implemented
-
-pub const EFTYPE = 79; // Inappropriate file type or format
-pub const EAUTH = 80; // Authentication error
-pub const ENEEDAUTH = 81; // Need authenticator
-pub const EIDRM = 82; // Identifier removed
-pub const ENOMSG = 83; // No message of desired type
-pub const EOVERFLOW = 84; // Value too large to be stored in data type
-pub const ECANCELED = 85; // Operation canceled
-pub const EILSEQ = 86; // Illegal byte sequence
-pub const ENOATTR = 87; // Attribute not found
-
-pub const EDOOFUS = 88; // Programming error
-
-pub const EBADMSG = 89; // Bad message
-pub const EMULTIHOP = 90; // Multihop attempted
-pub const ENOLINK = 91; // Link has been severed
-pub const EPROTO = 92; // Protocol error
-
-pub const ENOTCAPABLE = 93; // Capabilities insufficient
-pub const ECAPMODE = 94; // Not permitted in capability mode
-pub const ENOTRECOVERABLE = 95; // State not recoverable
-pub const EOWNERDEAD = 96; // Previous owner died
-
-pub const ELAST = 96; // Must be equal largest errno
diff --git a/std/os/get_user_id.zig b/std/os/get_user_id.zig
deleted file mode 100644
index db44c6838f..0000000000
--- a/std/os/get_user_id.zig
+++ /dev/null
@@ -1,104 +0,0 @@
-const builtin = @import("builtin");
-const Os = builtin.Os;
-const os = @import("../os.zig");
-const io = @import("../io.zig");
-
-pub const UserInfo = struct {
- uid: u32,
- gid: u32,
-};
-
-/// POSIX function which gets a uid from username.
-pub fn getUserInfo(name: []const u8) !UserInfo {
- return switch (builtin.os) {
- Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => posixGetUserInfo(name),
- else => @compileError("Unsupported OS"),
- };
-}
-
-const State = enum {
- Start,
- WaitForNextLine,
- SkipPassword,
- ReadUserId,
- ReadGroupId,
-};
-
-// TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else
-// like NIS, AD, etc. See `man nss` or look at an strace for `id myuser`.
-
-pub fn posixGetUserInfo(name: []const u8) !UserInfo {
- var in_stream = try io.InStream.open("/etc/passwd", null);
- defer in_stream.close();
-
- var buf: [os.page_size]u8 = undefined;
- var name_index: usize = 0;
- var state = State.Start;
- var uid: u32 = 0;
- var gid: u32 = 0;
-
- while (true) {
- const amt_read = try in_stream.read(buf[0..]);
- for (buf[0..amt_read]) |byte| {
- switch (state) {
- State.Start => switch (byte) {
- ':' => {
- state = if (name_index == name.len) State.SkipPassword else State.WaitForNextLine;
- },
- '\n' => return error.CorruptPasswordFile,
- else => {
- if (name_index == name.len or name[name_index] != byte) {
- state = State.WaitForNextLine;
- }
- name_index += 1;
- },
- },
- State.WaitForNextLine => switch (byte) {
- '\n' => {
- name_index = 0;
- state = State.Start;
- },
- else => continue,
- },
- State.SkipPassword => switch (byte) {
- '\n' => return error.CorruptPasswordFile,
- ':' => {
- state = State.ReadUserId;
- },
- else => continue,
- },
- State.ReadUserId => switch (byte) {
- ':' => {
- state = State.ReadGroupId;
- },
- '\n' => return error.CorruptPasswordFile,
- else => {
- const digit = switch (byte) {
- '0'...'9' => byte - '0',
- else => return error.CorruptPasswordFile,
- };
- if (@mulWithOverflow(u32, uid, 10, *uid)) return error.CorruptPasswordFile;
- if (@addWithOverflow(u32, uid, digit, *uid)) return error.CorruptPasswordFile;
- },
- },
- State.ReadGroupId => switch (byte) {
- '\n', ':' => {
- return UserInfo{
- .uid = uid,
- .gid = gid,
- };
- },
- else => {
- const digit = switch (byte) {
- '0'...'9' => byte - '0',
- else => return error.CorruptPasswordFile,
- };
- if (@mulWithOverflow(u32, gid, 10, *gid)) return error.CorruptPasswordFile;
- if (@addWithOverflow(u32, gid, digit, *gid)) return error.CorruptPasswordFile;
- },
- },
- }
- }
- if (amt_read < buf.len) return error.UserNotFound;
- }
-}
diff --git a/std/os/linux.zig b/std/os/linux.zig
index ecbbf72d42..282aa19bf1 100644
--- a/std/os/linux.zig
+++ b/std/os/linux.zig
@@ -1,709 +1,61 @@
+// This file provides the system interface functions for Linux matching those
+// that are provided by libc, whether or not libc is linked. The following
+// abstractions are made:
+// * Work around kernel bugs and limitations. For example, see sendmmsg.
+// * Implement all the syscalls in the same way that libc functions will
+// provide `rename` when only the `renameat` syscall exists.
+// * Does not support POSIX thread cancellation.
const std = @import("../std.zig");
-const assert = std.debug.assert;
const builtin = @import("builtin");
+const assert = std.debug.assert;
const maxInt = std.math.maxInt;
const elf = std.elf;
-pub const tls = @import("linux/tls.zig");
const vdso = @import("linux/vdso.zig");
const dl = @import("../dynamic_library.zig");
+
+pub const is_the_target = builtin.os == .linux;
pub use switch (builtin.arch) {
- builtin.Arch.x86_64 => @import("linux/x86_64.zig"),
- builtin.Arch.i386 => @import("linux/i386.zig"),
- builtin.Arch.aarch64 => @import("linux/arm64.zig"),
- else => @compileError("unsupported arch"),
+ .x86_64 => @import("linux/x86_64.zig"),
+ .aarch64 => @import("linux/arm64.zig"),
+ else => struct {},
};
-pub use @import("linux/errno.zig");
-
-pub const PATH_MAX = 4096;
-pub const IOV_MAX = 1024;
-
-pub const STDIN_FILENO = 0;
-pub const STDOUT_FILENO = 1;
-pub const STDERR_FILENO = 2;
-
-pub const FUTEX_WAIT = 0;
-pub const FUTEX_WAKE = 1;
-pub const FUTEX_FD = 2;
-pub const FUTEX_REQUEUE = 3;
-pub const FUTEX_CMP_REQUEUE = 4;
-pub const FUTEX_WAKE_OP = 5;
-pub const FUTEX_LOCK_PI = 6;
-pub const FUTEX_UNLOCK_PI = 7;
-pub const FUTEX_TRYLOCK_PI = 8;
-pub const FUTEX_WAIT_BITSET = 9;
-
-pub const FUTEX_PRIVATE_FLAG = 128;
-
-pub const FUTEX_CLOCK_REALTIME = 256;
-
-pub const PROT_NONE = 0;
-pub const PROT_READ = 1;
-pub const PROT_WRITE = 2;
-pub const PROT_EXEC = 4;
-pub const PROT_GROWSDOWN = 0x01000000;
-pub const PROT_GROWSUP = 0x02000000;
-
-pub const MAP_FAILED = maxInt(usize);
-pub const MAP_SHARED = 0x01;
-pub const MAP_PRIVATE = 0x02;
-pub const MAP_TYPE = 0x0f;
-pub const MAP_FIXED = 0x10;
-pub const MAP_ANONYMOUS = 0x20;
-pub const MAP_NORESERVE = 0x4000;
-pub const MAP_GROWSDOWN = 0x0100;
-pub const MAP_DENYWRITE = 0x0800;
-pub const MAP_EXECUTABLE = 0x1000;
-pub const MAP_LOCKED = 0x2000;
-pub const MAP_POPULATE = 0x8000;
-pub const MAP_NONBLOCK = 0x10000;
-pub const MAP_STACK = 0x20000;
-pub const MAP_HUGETLB = 0x40000;
-pub const MAP_FILE = 0;
-
-pub const F_OK = 0;
-pub const X_OK = 1;
-pub const W_OK = 2;
-pub const R_OK = 4;
-
-pub const WNOHANG = 1;
-pub const WUNTRACED = 2;
-pub const WSTOPPED = 2;
-pub const WEXITED = 4;
-pub const WCONTINUED = 8;
-pub const WNOWAIT = 0x1000000;
-
-pub const SA_NOCLDSTOP = 1;
-pub const SA_NOCLDWAIT = 2;
-pub const SA_SIGINFO = 4;
-pub const SA_ONSTACK = 0x08000000;
-pub const SA_RESTART = 0x10000000;
-pub const SA_NODEFER = 0x40000000;
-pub const SA_RESETHAND = 0x80000000;
-pub const SA_RESTORER = 0x04000000;
-
-pub const SIGHUP = 1;
-pub const SIGINT = 2;
-pub const SIGQUIT = 3;
-pub const SIGILL = 4;
-pub const SIGTRAP = 5;
-pub const SIGABRT = 6;
-pub const SIGIOT = SIGABRT;
-pub const SIGBUS = 7;
-pub const SIGFPE = 8;
-pub const SIGKILL = 9;
-pub const SIGUSR1 = 10;
-pub const SIGSEGV = 11;
-pub const SIGUSR2 = 12;
-pub const SIGPIPE = 13;
-pub const SIGALRM = 14;
-pub const SIGTERM = 15;
-pub const SIGSTKFLT = 16;
-pub const SIGCHLD = 17;
-pub const SIGCONT = 18;
-pub const SIGSTOP = 19;
-pub const SIGTSTP = 20;
-pub const SIGTTIN = 21;
-pub const SIGTTOU = 22;
-pub const SIGURG = 23;
-pub const SIGXCPU = 24;
-pub const SIGXFSZ = 25;
-pub const SIGVTALRM = 26;
-pub const SIGPROF = 27;
-pub const SIGWINCH = 28;
-pub const SIGIO = 29;
-pub const SIGPOLL = 29;
-pub const SIGPWR = 30;
-pub const SIGSYS = 31;
-pub const SIGUNUSED = SIGSYS;
-
-pub const O_RDONLY = 0o0;
-pub const O_WRONLY = 0o1;
-pub const O_RDWR = 0o2;
-
-pub const SEEK_SET = 0;
-pub const SEEK_CUR = 1;
-pub const SEEK_END = 2;
-
-pub const SIG_BLOCK = 0;
-pub const SIG_UNBLOCK = 1;
-pub const SIG_SETMASK = 2;
-
-pub const PROTO_ip = 0o000;
-pub const PROTO_icmp = 0o001;
-pub const PROTO_igmp = 0o002;
-pub const PROTO_ggp = 0o003;
-pub const PROTO_ipencap = 0o004;
-pub const PROTO_st = 0o005;
-pub const PROTO_tcp = 0o006;
-pub const PROTO_egp = 0o010;
-pub const PROTO_pup = 0o014;
-pub const PROTO_udp = 0o021;
-pub const PROTO_hmp = 0o024;
-pub const PROTO_xns_idp = 0o026;
-pub const PROTO_rdp = 0o033;
-pub const PROTO_iso_tp4 = 0o035;
-pub const PROTO_xtp = 0o044;
-pub const PROTO_ddp = 0o045;
-pub const PROTO_idpr_cmtp = 0o046;
-pub const PROTO_ipv6 = 0o051;
-pub const PROTO_ipv6_route = 0o053;
-pub const PROTO_ipv6_frag = 0o054;
-pub const PROTO_idrp = 0o055;
-pub const PROTO_rsvp = 0o056;
-pub const PROTO_gre = 0o057;
-pub const PROTO_esp = 0o062;
-pub const PROTO_ah = 0o063;
-pub const PROTO_skip = 0o071;
-pub const PROTO_ipv6_icmp = 0o072;
-pub const PROTO_ipv6_nonxt = 0o073;
-pub const PROTO_ipv6_opts = 0o074;
-pub const PROTO_rspf = 0o111;
-pub const PROTO_vmtp = 0o121;
-pub const PROTO_ospf = 0o131;
-pub const PROTO_ipip = 0o136;
-pub const PROTO_encap = 0o142;
-pub const PROTO_pim = 0o147;
-pub const PROTO_raw = 0o377;
-
-pub const SHUT_RD = 0;
-pub const SHUT_WR = 1;
-pub const SHUT_RDWR = 2;
-
-pub const SOCK_STREAM = 1;
-pub const SOCK_DGRAM = 2;
-pub const SOCK_RAW = 3;
-pub const SOCK_RDM = 4;
-pub const SOCK_SEQPACKET = 5;
-pub const SOCK_DCCP = 6;
-pub const SOCK_PACKET = 10;
-pub const SOCK_CLOEXEC = 0o2000000;
-pub const SOCK_NONBLOCK = 0o4000;
-
-pub const PF_UNSPEC = 0;
-pub const PF_LOCAL = 1;
-pub const PF_UNIX = PF_LOCAL;
-pub const PF_FILE = PF_LOCAL;
-pub const PF_INET = 2;
-pub const PF_AX25 = 3;
-pub const PF_IPX = 4;
-pub const PF_APPLETALK = 5;
-pub const PF_NETROM = 6;
-pub const PF_BRIDGE = 7;
-pub const PF_ATMPVC = 8;
-pub const PF_X25 = 9;
-pub const PF_INET6 = 10;
-pub const PF_ROSE = 11;
-pub const PF_DECnet = 12;
-pub const PF_NETBEUI = 13;
-pub const PF_SECURITY = 14;
-pub const PF_KEY = 15;
-pub const PF_NETLINK = 16;
-pub const PF_ROUTE = PF_NETLINK;
-pub const PF_PACKET = 17;
-pub const PF_ASH = 18;
-pub const PF_ECONET = 19;
-pub const PF_ATMSVC = 20;
-pub const PF_RDS = 21;
-pub const PF_SNA = 22;
-pub const PF_IRDA = 23;
-pub const PF_PPPOX = 24;
-pub const PF_WANPIPE = 25;
-pub const PF_LLC = 26;
-pub const PF_IB = 27;
-pub const PF_MPLS = 28;
-pub const PF_CAN = 29;
-pub const PF_TIPC = 30;
-pub const PF_BLUETOOTH = 31;
-pub const PF_IUCV = 32;
-pub const PF_RXRPC = 33;
-pub const PF_ISDN = 34;
-pub const PF_PHONET = 35;
-pub const PF_IEEE802154 = 36;
-pub const PF_CAIF = 37;
-pub const PF_ALG = 38;
-pub const PF_NFC = 39;
-pub const PF_VSOCK = 40;
-pub const PF_KCM = 41;
-pub const PF_QIPCRTR = 42;
-pub const PF_SMC = 43;
-pub const PF_MAX = 44;
-
-pub const AF_UNSPEC = PF_UNSPEC;
-pub const AF_LOCAL = PF_LOCAL;
-pub const AF_UNIX = AF_LOCAL;
-pub const AF_FILE = AF_LOCAL;
-pub const AF_INET = PF_INET;
-pub const AF_AX25 = PF_AX25;
-pub const AF_IPX = PF_IPX;
-pub const AF_APPLETALK = PF_APPLETALK;
-pub const AF_NETROM = PF_NETROM;
-pub const AF_BRIDGE = PF_BRIDGE;
-pub const AF_ATMPVC = PF_ATMPVC;
-pub const AF_X25 = PF_X25;
-pub const AF_INET6 = PF_INET6;
-pub const AF_ROSE = PF_ROSE;
-pub const AF_DECnet = PF_DECnet;
-pub const AF_NETBEUI = PF_NETBEUI;
-pub const AF_SECURITY = PF_SECURITY;
-pub const AF_KEY = PF_KEY;
-pub const AF_NETLINK = PF_NETLINK;
-pub const AF_ROUTE = PF_ROUTE;
-pub const AF_PACKET = PF_PACKET;
-pub const AF_ASH = PF_ASH;
-pub const AF_ECONET = PF_ECONET;
-pub const AF_ATMSVC = PF_ATMSVC;
-pub const AF_RDS = PF_RDS;
-pub const AF_SNA = PF_SNA;
-pub const AF_IRDA = PF_IRDA;
-pub const AF_PPPOX = PF_PPPOX;
-pub const AF_WANPIPE = PF_WANPIPE;
-pub const AF_LLC = PF_LLC;
-pub const AF_IB = PF_IB;
-pub const AF_MPLS = PF_MPLS;
-pub const AF_CAN = PF_CAN;
-pub const AF_TIPC = PF_TIPC;
-pub const AF_BLUETOOTH = PF_BLUETOOTH;
-pub const AF_IUCV = PF_IUCV;
-pub const AF_RXRPC = PF_RXRPC;
-pub const AF_ISDN = PF_ISDN;
-pub const AF_PHONET = PF_PHONET;
-pub const AF_IEEE802154 = PF_IEEE802154;
-pub const AF_CAIF = PF_CAIF;
-pub const AF_ALG = PF_ALG;
-pub const AF_NFC = PF_NFC;
-pub const AF_VSOCK = PF_VSOCK;
-pub const AF_KCM = PF_KCM;
-pub const AF_QIPCRTR = PF_QIPCRTR;
-pub const AF_SMC = PF_SMC;
-pub const AF_MAX = PF_MAX;
-
-pub const SO_DEBUG = 1;
-pub const SO_REUSEADDR = 2;
-pub const SO_TYPE = 3;
-pub const SO_ERROR = 4;
-pub const SO_DONTROUTE = 5;
-pub const SO_BROADCAST = 6;
-pub const SO_SNDBUF = 7;
-pub const SO_RCVBUF = 8;
-pub const SO_KEEPALIVE = 9;
-pub const SO_OOBINLINE = 10;
-pub const SO_NO_CHECK = 11;
-pub const SO_PRIORITY = 12;
-pub const SO_LINGER = 13;
-pub const SO_BSDCOMPAT = 14;
-pub const SO_REUSEPORT = 15;
-pub const SO_PASSCRED = 16;
-pub const SO_PEERCRED = 17;
-pub const SO_RCVLOWAT = 18;
-pub const SO_SNDLOWAT = 19;
-pub const SO_RCVTIMEO = 20;
-pub const SO_SNDTIMEO = 21;
-pub const SO_ACCEPTCONN = 30;
-pub const SO_SNDBUFFORCE = 32;
-pub const SO_RCVBUFFORCE = 33;
-pub const SO_PROTOCOL = 38;
-pub const SO_DOMAIN = 39;
-
-pub const SO_SECURITY_AUTHENTICATION = 22;
-pub const SO_SECURITY_ENCRYPTION_TRANSPORT = 23;
-pub const SO_SECURITY_ENCRYPTION_NETWORK = 24;
-
-pub const SO_BINDTODEVICE = 25;
-
-pub const SO_ATTACH_FILTER = 26;
-pub const SO_DETACH_FILTER = 27;
-pub const SO_GET_FILTER = SO_ATTACH_FILTER;
-
-pub const SO_PEERNAME = 28;
-pub const SO_TIMESTAMP = 29;
-pub const SCM_TIMESTAMP = SO_TIMESTAMP;
-
-pub const SO_PEERSEC = 31;
-pub const SO_PASSSEC = 34;
-pub const SO_TIMESTAMPNS = 35;
-pub const SCM_TIMESTAMPNS = SO_TIMESTAMPNS;
-pub const SO_MARK = 36;
-pub const SO_TIMESTAMPING = 37;
-pub const SCM_TIMESTAMPING = SO_TIMESTAMPING;
-pub const SO_RXQ_OVFL = 40;
-pub const SO_WIFI_STATUS = 41;
-pub const SCM_WIFI_STATUS = SO_WIFI_STATUS;
-pub const SO_PEEK_OFF = 42;
-pub const SO_NOFCS = 43;
-pub const SO_LOCK_FILTER = 44;
-pub const SO_SELECT_ERR_QUEUE = 45;
-pub const SO_BUSY_POLL = 46;
-pub const SO_MAX_PACING_RATE = 47;
-pub const SO_BPF_EXTENSIONS = 48;
-pub const SO_INCOMING_CPU = 49;
-pub const SO_ATTACH_BPF = 50;
-pub const SO_DETACH_BPF = SO_DETACH_FILTER;
-pub const SO_ATTACH_REUSEPORT_CBPF = 51;
-pub const SO_ATTACH_REUSEPORT_EBPF = 52;
-pub const SO_CNX_ADVICE = 53;
-pub const SCM_TIMESTAMPING_OPT_STATS = 54;
-pub const SO_MEMINFO = 55;
-pub const SO_INCOMING_NAPI_ID = 56;
-pub const SO_COOKIE = 57;
-pub const SCM_TIMESTAMPING_PKTINFO = 58;
-pub const SO_PEERGROUPS = 59;
-pub const SO_ZEROCOPY = 60;
-
-pub const SOL_SOCKET = 1;
-
-pub const SOL_IP = 0;
-pub const SOL_IPV6 = 41;
-pub const SOL_ICMPV6 = 58;
-
-pub const SOL_RAW = 255;
-pub const SOL_DECNET = 261;
-pub const SOL_X25 = 262;
-pub const SOL_PACKET = 263;
-pub const SOL_ATM = 264;
-pub const SOL_AAL = 265;
-pub const SOL_IRDA = 266;
-pub const SOL_NETBEUI = 267;
-pub const SOL_LLC = 268;
-pub const SOL_DCCP = 269;
-pub const SOL_NETLINK = 270;
-pub const SOL_TIPC = 271;
-pub const SOL_RXRPC = 272;
-pub const SOL_PPPOL2TP = 273;
-pub const SOL_BLUETOOTH = 274;
-pub const SOL_PNPIPE = 275;
-pub const SOL_RDS = 276;
-pub const SOL_IUCV = 277;
-pub const SOL_CAIF = 278;
-pub const SOL_ALG = 279;
-pub const SOL_NFC = 280;
-pub const SOL_KCM = 281;
-pub const SOL_TLS = 282;
-
-pub const SOMAXCONN = 128;
-
-pub const MSG_OOB = 0x0001;
-pub const MSG_PEEK = 0x0002;
-pub const MSG_DONTROUTE = 0x0004;
-pub const MSG_CTRUNC = 0x0008;
-pub const MSG_PROXY = 0x0010;
-pub const MSG_TRUNC = 0x0020;
-pub const MSG_DONTWAIT = 0x0040;
-pub const MSG_EOR = 0x0080;
-pub const MSG_WAITALL = 0x0100;
-pub const MSG_FIN = 0x0200;
-pub const MSG_SYN = 0x0400;
-pub const MSG_CONFIRM = 0x0800;
-pub const MSG_RST = 0x1000;
-pub const MSG_ERRQUEUE = 0x2000;
-pub const MSG_NOSIGNAL = 0x4000;
-pub const MSG_MORE = 0x8000;
-pub const MSG_WAITFORONE = 0x10000;
-pub const MSG_BATCH = 0x40000;
-pub const MSG_ZEROCOPY = 0x4000000;
-pub const MSG_FASTOPEN = 0x20000000;
-pub const MSG_CMSG_CLOEXEC = 0x40000000;
-
-pub const DT_UNKNOWN = 0;
-pub const DT_FIFO = 1;
-pub const DT_CHR = 2;
-pub const DT_DIR = 4;
-pub const DT_BLK = 6;
-pub const DT_REG = 8;
-pub const DT_LNK = 10;
-pub const DT_SOCK = 12;
-pub const DT_WHT = 14;
-
-pub const TCGETS = 0x5401;
-pub const TCSETS = 0x5402;
-pub const TCSETSW = 0x5403;
-pub const TCSETSF = 0x5404;
-pub const TCGETA = 0x5405;
-pub const TCSETA = 0x5406;
-pub const TCSETAW = 0x5407;
-pub const TCSETAF = 0x5408;
-pub const TCSBRK = 0x5409;
-pub const TCXONC = 0x540A;
-pub const TCFLSH = 0x540B;
-pub const TIOCEXCL = 0x540C;
-pub const TIOCNXCL = 0x540D;
-pub const TIOCSCTTY = 0x540E;
-pub const TIOCGPGRP = 0x540F;
-pub const TIOCSPGRP = 0x5410;
-pub const TIOCOUTQ = 0x5411;
-pub const TIOCSTI = 0x5412;
-pub const TIOCGWINSZ = 0x5413;
-pub const TIOCSWINSZ = 0x5414;
-pub const TIOCMGET = 0x5415;
-pub const TIOCMBIS = 0x5416;
-pub const TIOCMBIC = 0x5417;
-pub const TIOCMSET = 0x5418;
-pub const TIOCGSOFTCAR = 0x5419;
-pub const TIOCSSOFTCAR = 0x541A;
-pub const FIONREAD = 0x541B;
-pub const TIOCINQ = FIONREAD;
-pub const TIOCLINUX = 0x541C;
-pub const TIOCCONS = 0x541D;
-pub const TIOCGSERIAL = 0x541E;
-pub const TIOCSSERIAL = 0x541F;
-pub const TIOCPKT = 0x5420;
-pub const FIONBIO = 0x5421;
-pub const TIOCNOTTY = 0x5422;
-pub const TIOCSETD = 0x5423;
-pub const TIOCGETD = 0x5424;
-pub const TCSBRKP = 0x5425;
-pub const TIOCSBRK = 0x5427;
-pub const TIOCCBRK = 0x5428;
-pub const TIOCGSID = 0x5429;
-pub const TIOCGRS485 = 0x542E;
-pub const TIOCSRS485 = 0x542F;
-pub const TIOCGPTN = 0x80045430;
-pub const TIOCSPTLCK = 0x40045431;
-pub const TIOCGDEV = 0x80045432;
-pub const TCGETX = 0x5432;
-pub const TCSETX = 0x5433;
-pub const TCSETXF = 0x5434;
-pub const TCSETXW = 0x5435;
-pub const TIOCSIG = 0x40045436;
-pub const TIOCVHANGUP = 0x5437;
-pub const TIOCGPKT = 0x80045438;
-pub const TIOCGPTLCK = 0x80045439;
-pub const TIOCGEXCL = 0x80045440;
-
-pub const EPOLL_CLOEXEC = O_CLOEXEC;
-
-pub const EPOLL_CTL_ADD = 1;
-pub const EPOLL_CTL_DEL = 2;
-pub const EPOLL_CTL_MOD = 3;
-
-pub const EPOLLIN = 0x001;
-pub const EPOLLPRI = 0x002;
-pub const EPOLLOUT = 0x004;
-pub const EPOLLRDNORM = 0x040;
-pub const EPOLLRDBAND = 0x080;
-pub const EPOLLWRNORM = 0x100;
-pub const EPOLLWRBAND = 0x200;
-pub const EPOLLMSG = 0x400;
-pub const EPOLLERR = 0x008;
-pub const EPOLLHUP = 0x010;
-pub const EPOLLRDHUP = 0x2000;
-pub const EPOLLEXCLUSIVE = (u32(1) << 28);
-pub const EPOLLWAKEUP = (u32(1) << 29);
-pub const EPOLLONESHOT = (u32(1) << 30);
-pub const EPOLLET = (u32(1) << 31);
-
-pub const CLOCK_REALTIME = 0;
-pub const CLOCK_MONOTONIC = 1;
-pub const CLOCK_PROCESS_CPUTIME_ID = 2;
-pub const CLOCK_THREAD_CPUTIME_ID = 3;
-pub const CLOCK_MONOTONIC_RAW = 4;
-pub const CLOCK_REALTIME_COARSE = 5;
-pub const CLOCK_MONOTONIC_COARSE = 6;
-pub const CLOCK_BOOTTIME = 7;
-pub const CLOCK_REALTIME_ALARM = 8;
-pub const CLOCK_BOOTTIME_ALARM = 9;
-pub const CLOCK_SGI_CYCLE = 10;
-pub const CLOCK_TAI = 11;
-
-pub const CSIGNAL = 0x000000ff;
-pub const CLONE_VM = 0x00000100;
-pub const CLONE_FS = 0x00000200;
-pub const CLONE_FILES = 0x00000400;
-pub const CLONE_SIGHAND = 0x00000800;
-pub const CLONE_PTRACE = 0x00002000;
-pub const CLONE_VFORK = 0x00004000;
-pub const CLONE_PARENT = 0x00008000;
-pub const CLONE_THREAD = 0x00010000;
-pub const CLONE_NEWNS = 0x00020000;
-pub const CLONE_SYSVSEM = 0x00040000;
-pub const CLONE_SETTLS = 0x00080000;
-pub const CLONE_PARENT_SETTID = 0x00100000;
-pub const CLONE_CHILD_CLEARTID = 0x00200000;
-pub const CLONE_DETACHED = 0x00400000;
-pub const CLONE_UNTRACED = 0x00800000;
-pub const CLONE_CHILD_SETTID = 0x01000000;
-pub const CLONE_NEWCGROUP = 0x02000000;
-pub const CLONE_NEWUTS = 0x04000000;
-pub const CLONE_NEWIPC = 0x08000000;
-pub const CLONE_NEWUSER = 0x10000000;
-pub const CLONE_NEWPID = 0x20000000;
-pub const CLONE_NEWNET = 0x40000000;
-pub const CLONE_IO = 0x80000000;
-
-pub const EFD_SEMAPHORE = 1;
-pub const EFD_CLOEXEC = O_CLOEXEC;
-pub const EFD_NONBLOCK = O_NONBLOCK;
-
-pub const MS_RDONLY = 1;
-pub const MS_NOSUID = 2;
-pub const MS_NODEV = 4;
-pub const MS_NOEXEC = 8;
-pub const MS_SYNCHRONOUS = 16;
-pub const MS_REMOUNT = 32;
-pub const MS_MANDLOCK = 64;
-pub const MS_DIRSYNC = 128;
-pub const MS_NOATIME = 1024;
-pub const MS_NODIRATIME = 2048;
-pub const MS_BIND = 4096;
-pub const MS_MOVE = 8192;
-pub const MS_REC = 16384;
-pub const MS_SILENT = 32768;
-pub const MS_POSIXACL = (1 << 16);
-pub const MS_UNBINDABLE = (1 << 17);
-pub const MS_PRIVATE = (1 << 18);
-pub const MS_SLAVE = (1 << 19);
-pub const MS_SHARED = (1 << 20);
-pub const MS_RELATIME = (1 << 21);
-pub const MS_KERNMOUNT = (1 << 22);
-pub const MS_I_VERSION = (1 << 23);
-pub const MS_STRICTATIME = (1 << 24);
-pub const MS_LAZYTIME = (1 << 25);
-pub const MS_NOREMOTELOCK = (1 << 27);
-pub const MS_NOSEC = (1 << 28);
-pub const MS_BORN = (1 << 29);
-pub const MS_ACTIVE = (1 << 30);
-pub const MS_NOUSER = (1 << 31);
-
-pub const MS_RMT_MASK = (MS_RDONLY | MS_SYNCHRONOUS | MS_MANDLOCK | MS_I_VERSION | MS_LAZYTIME);
-
-pub const MS_MGC_VAL = 0xc0ed0000;
-pub const MS_MGC_MSK = 0xffff0000;
-
-pub const MNT_FORCE = 1;
-pub const MNT_DETACH = 2;
-pub const MNT_EXPIRE = 4;
-pub const UMOUNT_NOFOLLOW = 8;
-
-pub const IN_CLOEXEC = O_CLOEXEC;
-pub const IN_NONBLOCK = O_NONBLOCK;
-
-pub const IN_ACCESS = 0x00000001;
-pub const IN_MODIFY = 0x00000002;
-pub const IN_ATTRIB = 0x00000004;
-pub const IN_CLOSE_WRITE = 0x00000008;
-pub const IN_CLOSE_NOWRITE = 0x00000010;
-pub const IN_CLOSE = IN_CLOSE_WRITE | IN_CLOSE_NOWRITE;
-pub const IN_OPEN = 0x00000020;
-pub const IN_MOVED_FROM = 0x00000040;
-pub const IN_MOVED_TO = 0x00000080;
-pub const IN_MOVE = IN_MOVED_FROM | IN_MOVED_TO;
-pub const IN_CREATE = 0x00000100;
-pub const IN_DELETE = 0x00000200;
-pub const IN_DELETE_SELF = 0x00000400;
-pub const IN_MOVE_SELF = 0x00000800;
-pub const IN_ALL_EVENTS = 0x00000fff;
-
-pub const IN_UNMOUNT = 0x00002000;
-pub const IN_Q_OVERFLOW = 0x00004000;
-pub const IN_IGNORED = 0x00008000;
-
-pub const IN_ONLYDIR = 0x01000000;
-pub const IN_DONT_FOLLOW = 0x02000000;
-pub const IN_EXCL_UNLINK = 0x04000000;
-pub const IN_MASK_ADD = 0x20000000;
-
-pub const IN_ISDIR = 0x40000000;
-pub const IN_ONESHOT = 0x80000000;
-
-pub const S_IFMT = 0o170000;
-
-pub const S_IFDIR = 0o040000;
-pub const S_IFCHR = 0o020000;
-pub const S_IFBLK = 0o060000;
-pub const S_IFREG = 0o100000;
-pub const S_IFIFO = 0o010000;
-pub const S_IFLNK = 0o120000;
-pub const S_IFSOCK = 0o140000;
-
-pub const S_ISUID = 0o4000;
-pub const S_ISGID = 0o2000;
-pub const S_ISVTX = 0o1000;
-pub const S_IRUSR = 0o400;
-pub const S_IWUSR = 0o200;
-pub const S_IXUSR = 0o100;
-pub const S_IRWXU = 0o700;
-pub const S_IRGRP = 0o040;
-pub const S_IWGRP = 0o020;
-pub const S_IXGRP = 0o010;
-pub const S_IRWXG = 0o070;
-pub const S_IROTH = 0o004;
-pub const S_IWOTH = 0o002;
-pub const S_IXOTH = 0o001;
-pub const S_IRWXO = 0o007;
-
-pub fn S_ISREG(m: u32) bool {
- return m & S_IFMT == S_IFREG;
-}
-
-pub fn S_ISDIR(m: u32) bool {
- return m & S_IFMT == S_IFDIR;
-}
-
-pub fn S_ISCHR(m: u32) bool {
- return m & S_IFMT == S_IFCHR;
-}
-
-pub fn S_ISBLK(m: u32) bool {
- return m & S_IFMT == S_IFBLK;
-}
-
-pub fn S_ISFIFO(m: u32) bool {
- return m & S_IFMT == S_IFIFO;
-}
-
-pub fn S_ISLNK(m: u32) bool {
- return m & S_IFMT == S_IFLNK;
-}
-
-pub fn S_ISSOCK(m: u32) bool {
- return m & S_IFMT == S_IFSOCK;
-}
-
-pub const TFD_NONBLOCK = O_NONBLOCK;
-pub const TFD_CLOEXEC = O_CLOEXEC;
+pub use @import("bits.zig");
+pub const tls = @import("linux/tls.zig");
-pub const TFD_TIMER_ABSTIME = 1;
-pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1);
+/// Set by startup code, used by `getauxval`.
+pub var elf_aux_maybe: ?[*]std.elf.Auxv = null;
-fn unsigned(s: i32) u32 {
- return @bitCast(u32, s);
-}
-fn signed(s: u32) i32 {
- return @bitCast(i32, s);
-}
-pub fn WEXITSTATUS(s: i32) i32 {
- return signed((unsigned(s) & 0xff00) >> 8);
-}
-pub fn WTERMSIG(s: i32) i32 {
- return signed(unsigned(s) & 0x7f);
-}
-pub fn WSTOPSIG(s: i32) i32 {
- return WEXITSTATUS(s);
-}
-pub fn WIFEXITED(s: i32) bool {
- return WTERMSIG(s) == 0;
-}
-pub fn WIFSTOPPED(s: i32) bool {
- return @intCast(u16, ((unsigned(s) & 0xffff) *% 0x10001) >> 8) > 0x7f00;
-}
-pub fn WIFSIGNALED(s: i32) bool {
- return (unsigned(s) & 0xffff) -% 1 < 0xff;
+/// See `std.elf` for the constants.
+pub fn getauxval(index: usize) usize {
+ const auxv = elf_aux_maybe orelse return 0;
+ var i: usize = 0;
+ while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) {
+ if (auxv[i].a_type == index)
+ return auxv[i].a_un.a_val;
+ }
+ return 0;
}
-pub const winsize = extern struct {
- ws_row: u16,
- ws_col: u16,
- ws_xpixel: u16,
- ws_ypixel: u16,
-};
-
/// Get the errno from a syscall return value, or 0 for no error.
-pub fn getErrno(r: usize) usize {
+pub fn getErrno(r: usize) u12 {
const signed_r = @bitCast(isize, r);
- return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
+ return if (signed_r > -4096 and signed_r < 0) @intCast(u12, -signed_r) else 0;
}
pub fn dup2(old: i32, new: i32) usize {
- return dup3(old, new, 0);
+ if (@hasDecl(@This(), "SYS_dup2")) {
+ return syscall2(SYS_dup2, @bitCast(usize, isize(old)), @bitCast(usize, isize(new)));
+ } else {
+ if (old == new) {
+ if (std.debug.runtime_safety) {
+ const rc = syscall2(SYS_fcntl, @bitCast(usize, isize(old)), F_GETFD);
+ if (@bitCast(isize, rc) < 0) return rc;
+ }
+ return @intCast(usize, old);
+ } else {
+ return syscall3(SYS_dup3, @bitCast(usize, isize(old)), @bitCast(usize, isize(new)), 0);
+ }
+ }
}
pub fn dup3(old: i32, new: i32, flags: u32) usize {
@@ -726,7 +78,11 @@ pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*
}
pub fn fork() usize {
- return clone2(SIGCHLD, 0);
+ if (@hasDecl(@This(), "SYS_fork")) {
+ return syscall0(SYS_fork);
+ } else {
+ return syscall2(SYS_clone, SIGCHLD, 0);
+ }
}
/// This must be inline, and inline call the syscall function, because if the
@@ -750,6 +106,10 @@ pub fn getcwd(buf: [*]u8, size: usize) usize {
return syscall2(SYS_getcwd, @ptrToInt(buf), size);
}
+pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize {
+ return syscall3(SYS_getdents, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count);
+}
+
pub fn getdents64(fd: i32, dirp: [*]u8, count: usize) usize {
return syscall3(SYS_getdents64, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count);
}
@@ -766,14 +126,13 @@ pub fn inotify_rm_watch(fd: i32, wd: i32) usize {
return syscall2(SYS_inotify_rm_watch, @bitCast(usize, isize(fd)), @bitCast(usize, isize(wd)));
}
-pub fn isatty(fd: i32) bool {
- var wsz: winsize = undefined;
- return syscall3(SYS_ioctl, @bitCast(usize, isize(fd)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
-}
-
// TODO https://github.com/ziglang/zig/issues/265
pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
- return readlinkat(AT_FDCWD, path, buf_ptr, buf_len);
+ if (@hasDecl(@This(), "SYS_readlink")) {
+ return syscall3(SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);
+ } else {
+ return syscall4(SYS_readlinkat, AT_FDCWD, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);
+ }
}
// TODO https://github.com/ziglang/zig/issues/265
@@ -783,7 +142,11 @@ pub fn readlinkat(dirfd: i32, noalias path: [*]const u8, noalias buf_ptr: [*]u8,
// TODO https://github.com/ziglang/zig/issues/265
pub fn mkdir(path: [*]const u8, mode: u32) usize {
- return mkdirat(AT_FDCWD, path, mode);
+ if (@hasDecl(@This(), "SYS_mkdir")) {
+ return syscall2(SYS_mkdir, @ptrToInt(path), mode);
+ } else {
+ return syscall3(SYS_mkdirat, AT_FDCWD, @ptrToInt(path), mode);
+ }
}
// TODO https://github.com/ziglang/zig/issues/265
@@ -810,12 +173,12 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, of
return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @bitCast(usize, isize(fd)), @bitCast(usize, offset));
}
-pub fn mprotect(address: usize, length: usize, protection: usize) usize {
- return syscall3(SYS_mprotect, address, length, protection);
+pub fn mprotect(address: [*]const u8, length: usize, protection: usize) usize {
+ return syscall3(SYS_mprotect, @ptrToInt(address), length, protection);
}
-pub fn munmap(address: usize, length: usize) usize {
- return syscall2(SYS_munmap, address, length);
+pub fn munmap(address: [*]const u8, length: usize) usize {
+ return syscall2(SYS_munmap, @ptrToInt(address), length);
}
pub fn read(fd: i32, buf: [*]u8, count: usize) usize {
@@ -840,12 +203,20 @@ pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) us
// TODO https://github.com/ziglang/zig/issues/265
pub fn rmdir(path: [*]const u8) usize {
- return unlinkat(AT_FDCWD, path, AT_REMOVEDIR);
+ if (@hasDecl(@This(), "SYS_rmdir")) {
+ return syscall1(SYS_rmdir, @ptrToInt(path));
+ } else {
+ return syscall3(SYS_unlinkat, AT_FDCWD, @ptrToInt(path), AT_REMOVEDIR);
+ }
}
// TODO https://github.com/ziglang/zig/issues/265
pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
- return symlinkat(existing, AT_FDCWD, new);
+ if (@hasDecl(@This(), "SYS_symlink")) {
+ return syscall2(SYS_symlink, @ptrToInt(existing), @ptrToInt(new));
+ } else {
+ return syscall3(SYS_symlinkat, @ptrToInt(existing), AT_FDCWD, @ptrToInt(new));
+ }
}
// TODO https://github.com/ziglang/zig/issues/265
@@ -860,15 +231,20 @@ pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize {
// TODO https://github.com/ziglang/zig/issues/265
pub fn access(path: [*]const u8, mode: u32) usize {
- return faccessat(AT_FDCWD, path, mode);
+ return syscall2(SYS_access, @ptrToInt(path), mode);
}
+// TODO https://github.com/ziglang/zig/issues/265
pub fn faccessat(dirfd: i32, path: [*]const u8, mode: u32) usize {
return syscall3(SYS_faccessat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode);
}
pub fn pipe(fd: *[2]i32) usize {
- return pipe2(fd, 0);
+ if (@hasDecl(@This(), "SYS_pipe")) {
+ return syscall1(SYS_pipe, @ptrToInt(fd));
+ } else {
+ return syscall2(SYS_pipe2, @ptrToInt(fd), 0);
+ }
}
pub fn pipe2(fd: *[2]i32, flags: u32) usize {
@@ -885,17 +261,51 @@ pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize {
// TODO https://github.com/ziglang/zig/issues/265
pub fn rename(old: [*]const u8, new: [*]const u8) usize {
- return renameat2(AT_FDCWD, old, AT_FDCWD, new, 0);
+ if (@hasDecl(@This(), "SYS_rename")) {
+ return syscall2(SYS_rename, @ptrToInt(old), @ptrToInt(new));
+ } else if (@hasDecl(@This(), "SYS_renameat")) {
+ return syscall4(SYS_renameat, AT_FDCWD, @ptrToInt(old), AT_FDCWD, @ptrToInt(new));
+ } else {
+ return syscall5(SYS_renameat2, AT_FDCWD, @ptrToInt(old), AT_FDCWD, @ptrToInt(new), 0);
+ }
+}
+
+pub fn renameat(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const u8) usize {
+ if (@hasDecl(@This(), "SYS_renameat")) {
+ return syscall4(
+ SYS_renameat,
+ @bitCast(usize, isize(oldfd)),
+ @ptrToInt(old),
+ @bitCast(usize, isize(newfd)),
+ @ptrToInt(new),
+ );
+ } else {
+ return syscall5(
+ SYS_renameat2,
+ @bitCast(usize, isize(oldfd)),
+ @ptrToInt(old),
+ @bitCast(usize, isize(newfd)),
+ @ptrToInt(new),
+ 0,
+ );
+ }
}
// TODO https://github.com/ziglang/zig/issues/265
pub fn renameat2(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const u8, flags: u32) usize {
- return syscall5(SYS_renameat2, @bitCast(usize, isize(oldfd)), @ptrToInt(oldpath), @bitCast(usize, isize(newfd)), @ptrToInt(newpath), flags);
+ return syscall5(
+ SYS_renameat2,
+ @bitCast(usize, isize(oldfd)),
+ @ptrToInt(oldpath),
+ @bitCast(usize, isize(newfd)),
+ @ptrToInt(newpath),
+ flags,
+ );
}
// TODO https://github.com/ziglang/zig/issues/265
pub fn open(path: [*]const u8, flags: u32, perm: usize) usize {
- return openat(AT_FDCWD, path, flags, perm);
+ return syscall3(SYS_open, @ptrToInt(path), flags, perm);
}
// TODO https://github.com/ziglang/zig/issues/265
@@ -923,8 +333,21 @@ pub fn close(fd: i32) usize {
return syscall1(SYS_close, @bitCast(usize, isize(fd)));
}
-pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize {
- return syscall3(SYS_lseek, @bitCast(usize, isize(fd)), @bitCast(usize, offset), ref_pos);
+/// Can only be called on 32 bit systems. For 64 bit see `lseek`.
+pub fn llseek(fd: i32, offset: u64, result: ?*u64, whence: usize) usize {
+ return syscall5(
+ SYS__llseek,
+ @bitCast(usize, isize(fd)),
+ @truncate(usize, offset >> 32),
+ @truncate(usize, offset),
+ @ptrToInt(result),
+ whence,
+ );
+}
+
+/// Can only be called on 64 bit systems. For 32 bit see `llseek`.
+pub fn lseek(fd: i32, offset: i64, whence: usize) usize {
+ return syscall3(SYS_lseek, @bitCast(usize, isize(fd)), @bitCast(usize, offset), whence);
}
pub fn exit(status: i32) noreturn {
@@ -947,7 +370,11 @@ pub fn kill(pid: i32, sig: i32) usize {
// TODO https://github.com/ziglang/zig/issues/265
pub fn unlink(path: [*]const u8) usize {
- return unlinkat(AT_FDCWD, path, 0);
+ if (@hasDecl(@This(), "SYS_unlink")) {
+ return syscall1(SYS_unlink, @ptrToInt(path));
+ } else {
+ return syscall3(SYS_unlinkat, AT_FDCWD, @ptrToInt(path), 0);
+ }
}
// TODO https://github.com/ziglang/zig/issues/265
@@ -955,8 +382,8 @@ pub fn unlinkat(dirfd: i32, path: [*]const u8, flags: u32) usize {
return syscall3(SYS_unlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags);
}
-pub fn waitpid(pid: i32, status: *i32, options: i32) usize {
- return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0);
+pub fn waitpid(pid: i32, status: *u32, flags: u32) usize {
+ return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), flags, 0);
}
var vdso_clock_gettime = @ptrCast(?*const c_void, init_vdso_clock_gettime);
@@ -1113,48 +540,15 @@ pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigacti
return 0;
}
-const NSIG = 65;
-const sigset_t = [128 / @sizeOf(usize)]usize;
-const all_mask = []u32{ 0xffffffff, 0xffffffff };
-const app_mask = []u32{ 0xfffffffc, 0x7fffffff };
-
-const k_sigaction = extern struct {
- handler: extern fn (i32) void,
- flags: usize,
- restorer: extern fn () void,
- mask: [2]u32,
-};
-
-/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
-pub const Sigaction = struct {
- handler: extern fn (i32) void,
- mask: sigset_t,
- flags: u32,
-};
-
-pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
-pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
-pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
-pub const empty_sigset = []usize{0} ** sigset_t.len;
-
-pub fn raise(sig: i32) usize {
- var set: sigset_t = undefined;
- blockAppSignals(&set);
- const tid = syscall0(SYS_gettid);
- const ret = syscall2(SYS_tkill, tid, @bitCast(usize, isize(sig)));
- restoreSignals(&set);
- return ret;
-}
-
-fn blockAllSignals(set: *sigset_t) void {
+pub fn blockAllSignals(set: *sigset_t) void {
_ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG / 8);
}
-fn blockAppSignals(set: *sigset_t) void {
+pub fn blockAppSignals(set: *sigset_t) void {
_ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG / 8);
}
-fn restoreSignals(set: *sigset_t) void {
+pub fn restoreSignals(set: *sigset_t) void {
_ = syscall4(SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG / 8);
}
@@ -1168,56 +562,6 @@ pub fn sigismember(set: *const sigset_t, sig: u6) bool {
return ((set.*)[@intCast(usize, s) / usize.bit_count] & (@intCast(usize, 1) << (s & (usize.bit_count - 1)))) != 0;
}
-pub const in_port_t = u16;
-pub const sa_family_t = u16;
-pub const socklen_t = u32;
-
-/// This intentionally only has ip4 and ip6
-pub const sockaddr = extern union {
- in: sockaddr_in,
- in6: sockaddr_in6,
-};
-
-pub const sockaddr_in = extern struct {
- family: sa_family_t,
- port: in_port_t,
- addr: u32,
- zero: [8]u8,
-};
-
-pub const sockaddr_in6 = extern struct {
- family: sa_family_t,
- port: in_port_t,
- flowinfo: u32,
- addr: [16]u8,
- scope_id: u32,
-};
-
-pub const sockaddr_un = extern struct {
- family: sa_family_t,
- path: [108]u8,
-};
-
-pub const iovec = extern struct {
- iov_base: [*]u8,
- iov_len: usize,
-};
-
-pub const iovec_const = extern struct {
- iov_base: [*]const u8,
- iov_len: usize,
-};
-
-pub const mmsghdr = extern struct {
- msg_hdr: msghdr,
- msg_len: u32,
-};
-
-pub const mmsghdr_const = extern struct {
- msg_hdr: msghdr_const,
- msg_len: u32,
-};
-
pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
return syscall3(SYS_getsockname, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len));
}
@@ -1328,12 +672,12 @@ pub fn fstat(fd: i32, stat_buf: *Stat) usize {
// TODO https://github.com/ziglang/zig/issues/265
pub fn stat(pathname: [*]const u8, statbuf: *Stat) usize {
- return fstatat(AT_FDCWD, pathname, statbuf, AT_NO_AUTOMOUNT);
+ return syscall2(SYS_stat, @ptrToInt(pathname), @ptrToInt(statbuf));
}
// TODO https://github.com/ziglang/zig/issues/265
pub fn lstat(pathname: [*]const u8, statbuf: *Stat) usize {
- return fstatat(AF_FDCWD, pathname, statbuf, AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT);
+ return syscall2(SYS_lstat, @ptrToInt(pathname), @ptrToInt(statbuf));
}
// TODO https://github.com/ziglang/zig/issues/265
@@ -1400,30 +744,13 @@ pub fn fremovexattr(fd: usize, name: [*]const u8) usize {
return syscall2(SYS_fremovexattr, fd, @ptrToInt(name));
}
-pub fn sched_getaffinity(pid: i32, set: []usize) usize {
- return syscall3(SYS_sched_getaffinity, @bitCast(usize, isize(pid)), set.len * @sizeOf(usize), @ptrToInt(set.ptr));
+pub fn sched_getaffinity(pid: i32, size: usize, set: *cpu_set_t) usize {
+ const rc = syscall3(SYS_sched_getaffinity, @bitCast(usize, isize(pid)), size, @ptrToInt(set));
+ if (@bitCast(isize, rc) < 0) return rc;
+ if (rc < size) @memset(@ptrCast([*]u8, set) + rc, 0, size - rc);
+ return 0;
}
-pub const epoll_data = extern union {
- ptr: usize,
- fd: i32,
- @"u32": u32,
- @"u64": u64,
-};
-
-// On x86_64 the structure is packed so that it matches the definition of its
-// 32bit counterpart
-pub const epoll_event = if (builtin.arch != .x86_64)
- extern struct {
- events: u32,
- data: epoll_data,
- }
-else
- packed struct {
- events: u32,
- data: epoll_data,
- };
-
pub fn epoll_create() usize {
return epoll_create1(0);
}
@@ -1437,7 +764,13 @@ pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: *epoll_event) usize {
}
pub fn epoll_wait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32) usize {
- return epoll_pwait(epoll_fd, events, maxevents, timeout, null);
+ return syscall4(
+ SYS_epoll_wait,
+ @bitCast(usize, isize(epoll_fd)),
+ @ptrToInt(events),
+ maxevents,
+ @bitCast(usize, isize(timeout)),
+ );
}
pub fn epoll_pwait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32, sigmask: ?*sigset_t) usize {
@@ -1473,112 +806,6 @@ pub fn timerfd_settime(fd: i32, flags: u32, new_value: *const itimerspec, old_va
return syscall4(SYS_timerfd_settime, @bitCast(usize, isize(fd)), flags, @ptrToInt(new_value), @ptrToInt(old_value));
}
-pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330;
-pub const _LINUX_CAPABILITY_U32S_1 = 1;
-
-pub const _LINUX_CAPABILITY_VERSION_2 = 0x20071026;
-pub const _LINUX_CAPABILITY_U32S_2 = 2;
-
-pub const _LINUX_CAPABILITY_VERSION_3 = 0x20080522;
-pub const _LINUX_CAPABILITY_U32S_3 = 2;
-
-pub const VFS_CAP_REVISION_MASK = 0xFF000000;
-pub const VFS_CAP_REVISION_SHIFT = 24;
-pub const VFS_CAP_FLAGS_MASK = ~VFS_CAP_REVISION_MASK;
-pub const VFS_CAP_FLAGS_EFFECTIVE = 0x000001;
-
-pub const VFS_CAP_REVISION_1 = 0x01000000;
-pub const VFS_CAP_U32_1 = 1;
-pub const XATTR_CAPS_SZ_1 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_1);
-
-pub const VFS_CAP_REVISION_2 = 0x02000000;
-pub const VFS_CAP_U32_2 = 2;
-pub const XATTR_CAPS_SZ_2 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_2);
-
-pub const XATTR_CAPS_SZ = XATTR_CAPS_SZ_2;
-pub const VFS_CAP_U32 = VFS_CAP_U32_2;
-pub const VFS_CAP_REVISION = VFS_CAP_REVISION_2;
-
-pub const vfs_cap_data = extern struct {
- //all of these are mandated as little endian
- //when on disk.
- const Data = struct {
- permitted: u32,
- inheritable: u32,
- };
-
- magic_etc: u32,
- data: [VFS_CAP_U32]Data,
-};
-
-pub const CAP_CHOWN = 0;
-pub const CAP_DAC_OVERRIDE = 1;
-pub const CAP_DAC_READ_SEARCH = 2;
-pub const CAP_FOWNER = 3;
-pub const CAP_FSETID = 4;
-pub const CAP_KILL = 5;
-pub const CAP_SETGID = 6;
-pub const CAP_SETUID = 7;
-pub const CAP_SETPCAP = 8;
-pub const CAP_LINUX_IMMUTABLE = 9;
-pub const CAP_NET_BIND_SERVICE = 10;
-pub const CAP_NET_BROADCAST = 11;
-pub const CAP_NET_ADMIN = 12;
-pub const CAP_NET_RAW = 13;
-pub const CAP_IPC_LOCK = 14;
-pub const CAP_IPC_OWNER = 15;
-pub const CAP_SYS_MODULE = 16;
-pub const CAP_SYS_RAWIO = 17;
-pub const CAP_SYS_CHROOT = 18;
-pub const CAP_SYS_PTRACE = 19;
-pub const CAP_SYS_PACCT = 20;
-pub const CAP_SYS_ADMIN = 21;
-pub const CAP_SYS_BOOT = 22;
-pub const CAP_SYS_NICE = 23;
-pub const CAP_SYS_RESOURCE = 24;
-pub const CAP_SYS_TIME = 25;
-pub const CAP_SYS_TTY_CONFIG = 26;
-pub const CAP_MKNOD = 27;
-pub const CAP_LEASE = 28;
-pub const CAP_AUDIT_WRITE = 29;
-pub const CAP_AUDIT_CONTROL = 30;
-pub const CAP_SETFCAP = 31;
-pub const CAP_MAC_OVERRIDE = 32;
-pub const CAP_MAC_ADMIN = 33;
-pub const CAP_SYSLOG = 34;
-pub const CAP_WAKE_ALARM = 35;
-pub const CAP_BLOCK_SUSPEND = 36;
-pub const CAP_AUDIT_READ = 37;
-pub const CAP_LAST_CAP = CAP_AUDIT_READ;
-
-pub fn cap_valid(u8: x) bool {
- return x >= 0 and x <= CAP_LAST_CAP;
-}
-
-pub fn CAP_TO_MASK(cap: u8) u32 {
- return u32(1) << u5(cap & 31);
-}
-
-pub fn CAP_TO_INDEX(cap: u8) u8 {
- return cap >> 5;
-}
-
-pub const cap_t = extern struct {
- hdrp: *cap_user_header_t,
- datap: *cap_user_data_t,
-};
-
-pub const cap_user_header_t = extern struct {
- version: u32,
- pid: usize,
-};
-
-pub const cap_user_data_t = extern struct {
- effective: u32,
- permitted: u32,
- inheritable: u32,
-};
-
pub fn unshare(flags: usize) usize {
return syscall1(SYS_unshare, flags);
}
@@ -1591,29 +818,6 @@ pub fn capset(hdrp: *cap_user_header_t, datap: *const cap_user_data_t) usize {
return syscall2(SYS_capset, @ptrToInt(hdrp), @ptrToInt(datap));
}
-pub const inotify_event = extern struct {
- wd: i32,
- mask: u32,
- cookie: u32,
- len: u32,
- //name: [?]u8,
-};
-
-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 const dl_phdr_info = extern struct {
- dlpi_addr: usize,
- dlpi_name: ?[*]const u8,
- dlpi_phdr: [*]elf.Phdr,
- dlpi_phnum: u16,
-};
-
// XXX: This should be weak
extern const __ehdr_start: elf.Ehdr = undefined;
@@ -1671,8 +875,8 @@ pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_inf
return last_r;
}
-test "import" {
- if (builtin.os == builtin.Os.linux) {
+test "" {
+ if (is_the_target) {
_ = @import("linux/test.zig");
}
}
diff --git a/std/os/linux/arm64.zig b/std/os/linux/arm64.zig
index d752166280..94cf8818de 100644
--- a/std/os/linux/arm64.zig
+++ b/std/os/linux/arm64.zig
@@ -1,344 +1,3 @@
-const std = @import("../../std.zig");
-const linux = std.os.linux;
-const socklen_t = linux.socklen_t;
-const iovec = linux.iovec;
-const iovec_const = linux.iovec_const;
-
-pub const SYS_io_setup = 0;
-pub const SYS_io_destroy = 1;
-pub const SYS_io_submit = 2;
-pub const SYS_io_cancel = 3;
-pub const SYS_io_getevents = 4;
-pub const SYS_setxattr = 5;
-pub const SYS_lsetxattr = 6;
-pub const SYS_fsetxattr = 7;
-pub const SYS_getxattr = 8;
-pub const SYS_lgetxattr = 9;
-pub const SYS_fgetxattr = 10;
-pub const SYS_listxattr = 11;
-pub const SYS_llistxattr = 12;
-pub const SYS_flistxattr = 13;
-pub const SYS_removexattr = 14;
-pub const SYS_lremovexattr = 15;
-pub const SYS_fremovexattr = 16;
-pub const SYS_getcwd = 17;
-pub const SYS_lookup_dcookie = 18;
-pub const SYS_eventfd2 = 19;
-pub const SYS_epoll_create1 = 20;
-pub const SYS_epoll_ctl = 21;
-pub const SYS_epoll_pwait = 22;
-pub const SYS_dup = 23;
-pub const SYS_dup3 = 24;
-pub const SYS_fcntl = 25;
-pub const SYS_inotify_init1 = 26;
-pub const SYS_inotify_add_watch = 27;
-pub const SYS_inotify_rm_watch = 28;
-pub const SYS_ioctl = 29;
-pub const SYS_ioprio_set = 30;
-pub const SYS_ioprio_get = 31;
-pub const SYS_flock = 32;
-pub const SYS_mknodat = 33;
-pub const SYS_mkdirat = 34;
-pub const SYS_unlinkat = 35;
-pub const SYS_symlinkat = 36;
-pub const SYS_linkat = 37;
-pub const SYS_renameat = 38;
-pub const SYS_umount2 = 39;
-pub const SYS_mount = 40;
-pub const SYS_pivot_root = 41;
-pub const SYS_nfsservctl = 42;
-pub const SYS_statfs = 43;
-pub const SYS_fstatfs = 44;
-pub const SYS_truncate = 45;
-pub const SYS_ftruncate = 46;
-pub const SYS_fallocate = 47;
-pub const SYS_faccessat = 48;
-pub const SYS_chdir = 49;
-pub const SYS_fchdir = 50;
-pub const SYS_chroot = 51;
-pub const SYS_fchmod = 52;
-pub const SYS_fchmodat = 53;
-pub const SYS_fchownat = 54;
-pub const SYS_fchown = 55;
-pub const SYS_openat = 56;
-pub const SYS_close = 57;
-pub const SYS_vhangup = 58;
-pub const SYS_pipe2 = 59;
-pub const SYS_quotactl = 60;
-pub const SYS_getdents64 = 61;
-pub const SYS_lseek = 62;
-pub const SYS_read = 63;
-pub const SYS_write = 64;
-pub const SYS_readv = 65;
-pub const SYS_writev = 66;
-pub const SYS_pread64 = 67;
-pub const SYS_pwrite64 = 68;
-pub const SYS_preadv = 69;
-pub const SYS_pwritev = 70;
-pub const SYS_pselect6 = 72;
-pub const SYS_ppoll = 73;
-pub const SYS_signalfd4 = 74;
-pub const SYS_vmsplice = 75;
-pub const SYS_splice = 76;
-pub const SYS_tee = 77;
-pub const SYS_readlinkat = 78;
-pub const SYS_fstatat = 79;
-pub const SYS_fstat = 80;
-pub const SYS_sync = 81;
-pub const SYS_fsync = 82;
-pub const SYS_fdatasync = 83;
-pub const SYS_sync_file_range2 = 84;
-pub const SYS_sync_file_range = 84;
-pub const SYS_timerfd_create = 85;
-pub const SYS_timerfd_settime = 86;
-pub const SYS_timerfd_gettime = 87;
-pub const SYS_utimensat = 88;
-pub const SYS_acct = 89;
-pub const SYS_capget = 90;
-pub const SYS_capset = 91;
-pub const SYS_personality = 92;
-pub const SYS_exit = 93;
-pub const SYS_exit_group = 94;
-pub const SYS_waitid = 95;
-pub const SYS_set_tid_address = 96;
-pub const SYS_unshare = 97;
-pub const SYS_futex = 98;
-pub const SYS_set_robust_list = 99;
-pub const SYS_get_robust_list = 100;
-pub const SYS_nanosleep = 101;
-pub const SYS_getitimer = 102;
-pub const SYS_setitimer = 103;
-pub const SYS_kexec_load = 104;
-pub const SYS_init_module = 105;
-pub const SYS_delete_module = 106;
-pub const SYS_timer_create = 107;
-pub const SYS_timer_gettime = 108;
-pub const SYS_timer_getoverrun = 109;
-pub const SYS_timer_settime = 110;
-pub const SYS_timer_delete = 111;
-pub const SYS_clock_settime = 112;
-pub const SYS_clock_gettime = 113;
-pub const SYS_clock_getres = 114;
-pub const SYS_clock_nanosleep = 115;
-pub const SYS_syslog = 116;
-pub const SYS_ptrace = 117;
-pub const SYS_sched_setparam = 118;
-pub const SYS_sched_setscheduler = 119;
-pub const SYS_sched_getscheduler = 120;
-pub const SYS_sched_getparam = 121;
-pub const SYS_sched_setaffinity = 122;
-pub const SYS_sched_getaffinity = 123;
-pub const SYS_sched_yield = 124;
-pub const SYS_sched_get_priority_max = 125;
-pub const SYS_sched_get_priority_min = 126;
-pub const SYS_sched_rr_get_interval = 127;
-pub const SYS_restart_syscall = 128;
-pub const SYS_kill = 129;
-pub const SYS_tkill = 130;
-pub const SYS_tgkill = 131;
-pub const SYS_sigaltstack = 132;
-pub const SYS_rt_sigsuspend = 133;
-pub const SYS_rt_sigaction = 134;
-pub const SYS_rt_sigprocmask = 135;
-pub const SYS_rt_sigpending = 136;
-pub const SYS_rt_sigtimedwait = 137;
-pub const SYS_rt_sigqueueinfo = 138;
-pub const SYS_rt_sigreturn = 139;
-pub const SYS_setpriority = 140;
-pub const SYS_getpriority = 141;
-pub const SYS_reboot = 142;
-pub const SYS_setregid = 143;
-pub const SYS_setgid = 144;
-pub const SYS_setreuid = 145;
-pub const SYS_setuid = 146;
-pub const SYS_setresuid = 147;
-pub const SYS_getresuid = 148;
-pub const SYS_setresgid = 149;
-pub const SYS_getresgid = 150;
-pub const SYS_setfsuid = 151;
-pub const SYS_setfsgid = 152;
-pub const SYS_times = 153;
-pub const SYS_setpgid = 154;
-pub const SYS_getpgid = 155;
-pub const SYS_getsid = 156;
-pub const SYS_setsid = 157;
-pub const SYS_getgroups = 158;
-pub const SYS_setgroups = 159;
-pub const SYS_uname = 160;
-pub const SYS_sethostname = 161;
-pub const SYS_setdomainname = 162;
-pub const SYS_getrlimit = 163;
-pub const SYS_setrlimit = 164;
-pub const SYS_getrusage = 165;
-pub const SYS_umask = 166;
-pub const SYS_prctl = 167;
-pub const SYS_getcpu = 168;
-pub const SYS_gettimeofday = 169;
-pub const SYS_settimeofday = 170;
-pub const SYS_adjtimex = 171;
-pub const SYS_getpid = 172;
-pub const SYS_getppid = 173;
-pub const SYS_getuid = 174;
-pub const SYS_geteuid = 175;
-pub const SYS_getgid = 176;
-pub const SYS_getegid = 177;
-pub const SYS_gettid = 178;
-pub const SYS_sysinfo = 179;
-pub const SYS_mq_open = 180;
-pub const SYS_mq_unlink = 181;
-pub const SYS_mq_timedsend = 182;
-pub const SYS_mq_timedreceive = 183;
-pub const SYS_mq_notify = 184;
-pub const SYS_mq_getsetattr = 185;
-pub const SYS_msgget = 186;
-pub const SYS_msgctl = 187;
-pub const SYS_msgrcv = 188;
-pub const SYS_msgsnd = 189;
-pub const SYS_semget = 190;
-pub const SYS_semctl = 191;
-pub const SYS_semtimedop = 192;
-pub const SYS_semop = 193;
-pub const SYS_shmget = 194;
-pub const SYS_shmctl = 195;
-pub const SYS_shmat = 196;
-pub const SYS_shmdt = 197;
-pub const SYS_socket = 198;
-pub const SYS_socketpair = 199;
-pub const SYS_bind = 200;
-pub const SYS_listen = 201;
-pub const SYS_accept = 202;
-pub const SYS_connect = 203;
-pub const SYS_getsockname = 204;
-pub const SYS_getpeername = 205;
-pub const SYS_sendto = 206;
-pub const SYS_recvfrom = 207;
-pub const SYS_setsockopt = 208;
-pub const SYS_getsockopt = 209;
-pub const SYS_shutdown = 210;
-pub const SYS_sendmsg = 211;
-pub const SYS_recvmsg = 212;
-pub const SYS_readahead = 213;
-pub const SYS_brk = 214;
-pub const SYS_munmap = 215;
-pub const SYS_mremap = 216;
-pub const SYS_add_key = 217;
-pub const SYS_request_key = 218;
-pub const SYS_keyctl = 219;
-pub const SYS_clone = 220;
-pub const SYS_execve = 221;
-pub const SYS_mmap = 222;
-pub const SYS_fadvise64 = 223;
-pub const SYS_swapon = 224;
-pub const SYS_swapoff = 225;
-pub const SYS_mprotect = 226;
-pub const SYS_msync = 227;
-pub const SYS_mlock = 228;
-pub const SYS_munlock = 229;
-pub const SYS_mlockall = 230;
-pub const SYS_munlockall = 231;
-pub const SYS_mincore = 232;
-pub const SYS_madvise = 233;
-pub const SYS_remap_file_pages = 234;
-pub const SYS_mbind = 235;
-pub const SYS_get_mempolicy = 236;
-pub const SYS_set_mempolicy = 237;
-pub const SYS_migrate_pages = 238;
-pub const SYS_move_pages = 239;
-pub const SYS_rt_tgsigqueueinfo = 240;
-pub const SYS_perf_event_open = 241;
-pub const SYS_accept4 = 242;
-pub const SYS_recvmmsg = 243;
-pub const SYS_arch_specific_syscall = 244;
-pub const SYS_wait4 = 260;
-pub const SYS_prlimit64 = 261;
-pub const SYS_fanotify_init = 262;
-pub const SYS_fanotify_mark = 263;
-pub const SYS_clock_adjtime = 266;
-pub const SYS_syncfs = 267;
-pub const SYS_setns = 268;
-pub const SYS_sendmmsg = 269;
-pub const SYS_process_vm_readv = 270;
-pub const SYS_process_vm_writev = 271;
-pub const SYS_kcmp = 272;
-pub const SYS_finit_module = 273;
-pub const SYS_sched_setattr = 274;
-pub const SYS_sched_getattr = 275;
-pub const SYS_renameat2 = 276;
-pub const SYS_seccomp = 277;
-pub const SYS_getrandom = 278;
-pub const SYS_memfd_create = 279;
-pub const SYS_bpf = 280;
-pub const SYS_execveat = 281;
-pub const SYS_userfaultfd = 282;
-pub const SYS_membarrier = 283;
-pub const SYS_mlock2 = 284;
-pub const SYS_copy_file_range = 285;
-pub const SYS_preadv2 = 286;
-pub const SYS_pwritev2 = 287;
-pub const SYS_pkey_mprotect = 288;
-pub const SYS_pkey_alloc = 289;
-pub const SYS_pkey_free = 290;
-pub const SYS_statx = 291;
-pub const SYS_io_pgetevents = 292;
-pub const SYS_rseq = 293;
-pub const SYS_kexec_file_load = 294;
-pub const SYS_pidfd_send_signal = 424;
-pub const SYS_io_uring_setup = 425;
-pub const SYS_io_uring_enter = 426;
-pub const SYS_io_uring_register = 427;
-
-pub const O_CREAT = 0o100;
-pub const O_EXCL = 0o200;
-pub const O_NOCTTY = 0o400;
-pub const O_TRUNC = 0o1000;
-pub const O_APPEND = 0o2000;
-pub const O_NONBLOCK = 0o4000;
-pub const O_DSYNC = 0o10000;
-pub const O_SYNC = 0o4010000;
-pub const O_RSYNC = 0o4010000;
-pub const O_DIRECTORY = 0o200000;
-pub const O_NOFOLLOW = 0o400000;
-pub const O_CLOEXEC = 0o2000000;
-
-pub const O_ASYNC = 0o20000;
-pub const O_DIRECT = 0o40000;
-pub const O_LARGEFILE = 0;
-pub const O_NOATIME = 0o1000000;
-pub const O_PATH = 0o10000000;
-pub const O_TMPFILE = 0o20200000;
-pub const O_NDELAY = O_NONBLOCK;
-
-pub const F_DUPFD = 0;
-pub const F_GETFD = 1;
-pub const F_SETFD = 2;
-pub const F_GETFL = 3;
-pub const F_SETFL = 4;
-
-pub const F_SETOWN = 8;
-pub const F_GETOWN = 9;
-pub const F_SETSIG = 10;
-pub const F_GETSIG = 11;
-
-pub const F_GETLK = 5;
-pub const F_SETLK = 6;
-pub const F_SETLKW = 7;
-
-pub const F_SETOWN_EX = 15;
-pub const F_GETOWN_EX = 16;
-
-pub const F_GETOWNER_UIDS = 17;
-
-pub const AT_FDCWD = -100;
-pub const AT_SYMLINK_NOFOLLOW = 0x100;
-pub const AT_REMOVEDIR = 0x200;
-pub const AT_SYMLINK_FOLLOW = 0x400;
-pub const AT_NO_AUTOMOUNT = 0x800;
-pub const AT_EMPTY_PATH = 0x1000;
-
-pub const VDSO_USEFUL = true;
-pub const VDSO_CGT_SYM = "__kernel_clock_gettime";
-pub const VDSO_CGT_VER = "LINUX_2.6.39";
-
pub fn syscall0(number: usize) usize {
return asm volatile ("svc #0"
: [ret] "={x0}" (-> usize)
@@ -419,65 +78,3 @@ pub fn syscall6(
/// This matches the libc clone function.
pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
-
-pub const msghdr = extern struct {
- msg_name: ?*sockaddr,
- msg_namelen: socklen_t,
- msg_iov: [*]iovec,
- msg_iovlen: i32,
- __pad1: i32,
- msg_control: ?*c_void,
- msg_controllen: socklen_t,
- __pad2: socklen_t,
- msg_flags: i32,
-};
-
-pub const msghdr_const = extern struct {
- msg_name: ?*const sockaddr,
- msg_namelen: socklen_t,
- msg_iov: [*]iovec_const,
- msg_iovlen: i32,
- __pad1: i32,
- msg_control: ?*c_void,
- msg_controllen: socklen_t,
- __pad2: socklen_t,
- msg_flags: i32,
-};
-
-/// Renamed to Stat to not conflict with the stat function.
-pub const Stat = extern struct {
- dev: u64,
- ino: u64,
- nlink: usize,
-
- mode: u32,
- uid: u32,
- gid: u32,
- __pad0: u32,
- rdev: u64,
- size: i64,
- blksize: isize,
- blocks: i64,
-
- atim: timespec,
- mtim: timespec,
- ctim: timespec,
- __unused: [3]isize,
-};
-
-pub const timespec = extern struct {
- tv_sec: isize,
- tv_nsec: isize,
-};
-
-pub const timeval = extern struct {
- tv_sec: isize,
- tv_usec: isize,
-};
-
-pub const timezone = extern struct {
- tz_minuteswest: i32,
- tz_dsttime: i32,
-};
-
-pub const Elf_Symndx = u32;
diff --git a/std/os/linux/test.zig b/std/os/linux/test.zig
index 1949d00298..c78b071c74 100644
--- a/std/os/linux/test.zig
+++ b/std/os/linux/test.zig
@@ -11,7 +11,7 @@ test "getpid" {
test "timer" {
const epoll_fd = linux.epoll_create();
- var err = linux.getErrno(epoll_fd);
+ var err: usize = linux.getErrno(epoll_fd);
expect(err == 0);
const timer_fd = linux.timerfd_create(linux.CLOCK_MONOTONIC, 0);
diff --git a/std/os/linux/tls.zig b/std/os/linux/tls.zig
index 8640e71e62..a10d68663b 100644
--- a/std/os/linux/tls.zig
+++ b/std/os/linux/tls.zig
@@ -1,6 +1,6 @@
const std = @import("std");
+const os = std.os;
const mem = std.mem;
-const posix = std.os.posix;
const elf = std.elf;
const builtin = @import("builtin");
const assert = std.debug.assert;
@@ -126,7 +126,7 @@ pub fn initTLS() void {
var tls_phdr: ?*elf.Phdr = null;
var img_base: usize = 0;
- const auxv = std.os.linux_elf_aux_maybe.?;
+ const auxv = std.os.linux.elf_aux_maybe.?;
var at_phent: usize = undefined;
var at_phnum: usize = undefined;
var at_phdr: usize = undefined;
@@ -237,9 +237,14 @@ pub fn allocateTLS(size: usize) usize {
return @ptrToInt(&main_thread_tls_buffer);
}
- const addr = posix.mmap(null, size, posix.PROT_READ | posix.PROT_WRITE, posix.MAP_PRIVATE | posix.MAP_ANONYMOUS, -1, 0);
+ const slice = os.mmap(
+ null,
+ size,
+ os.PROT_READ | os.PROT_WRITE,
+ os.MAP_PRIVATE | os.MAP_ANONYMOUS,
+ -1,
+ 0,
+ ) catch @panic("out of memory");
- if (posix.getErrno(addr) != 0) @panic("out of memory");
-
- return addr;
+ return @ptrToInt(slice.ptr);
}
diff --git a/std/os/linux/vdso.zig b/std/os/linux/vdso.zig
index efd69d8542..86d54bfbf8 100644
--- a/std/os/linux/vdso.zig
+++ b/std/os/linux/vdso.zig
@@ -1,12 +1,11 @@
const std = @import("../../std.zig");
const elf = std.elf;
const linux = std.os.linux;
-const cstr = std.cstr;
const mem = std.mem;
const maxInt = std.math.maxInt;
pub fn lookup(vername: []const u8, name: []const u8) usize {
- const vdso_addr = std.os.linuxGetAuxVal(std.elf.AT_SYSINFO_EHDR);
+ const vdso_addr = std.os.system.getauxval(std.elf.AT_SYSINFO_EHDR);
if (vdso_addr == 0) return 0;
const eh = @intToPtr(*elf.Ehdr, vdso_addr);
@@ -66,7 +65,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
if (0 == (u32(1) << @intCast(u5, syms[i].st_info & 0xf) & OK_TYPES)) continue;
if (0 == (u32(1) << @intCast(u5, syms[i].st_info >> 4) & OK_BINDS)) continue;
if (0 == syms[i].st_shndx) continue;
- if (!mem.eql(u8, name, cstr.toSliceConst(strings + syms[i].st_name))) continue;
+ if (!mem.eql(u8, name, mem.toSliceConst(u8, strings + syms[i].st_name))) continue;
if (maybe_versym) |versym| {
if (!checkver(maybe_verdef.?, versym[i], vername, strings))
continue;
@@ -88,5 +87,5 @@ fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [
def = @intToPtr(*elf.Verdef, @ptrToInt(def) + def.vd_next);
}
const aux = @intToPtr(*elf.Verdaux, @ptrToInt(def) + def.vd_aux);
- return mem.eql(u8, vername, cstr.toSliceConst(strings + aux.vda_name));
+ return mem.eql(u8, vername, mem.toSliceConst(u8, strings + aux.vda_name));
}
diff --git a/std/os/linux/x86_64.zig b/std/os/linux/x86_64.zig
index f00a4680a4..fa866cff4c 100644
--- a/std/os/linux/x86_64.zig
+++ b/std/os/linux/x86_64.zig
@@ -1,410 +1,4 @@
-const std = @import("../../std.zig");
-const linux = std.os.linux;
-const sockaddr = linux.sockaddr;
-const socklen_t = linux.socklen_t;
-const iovec = linux.iovec;
-const iovec_const = linux.iovec_const;
-
-pub const SYS_read = 0;
-pub const SYS_write = 1;
-pub const SYS_open = 2;
-pub const SYS_close = 3;
-pub const SYS_stat = 4;
-pub const SYS_fstat = 5;
-pub const SYS_lstat = 6;
-pub const SYS_poll = 7;
-pub const SYS_lseek = 8;
-pub const SYS_mmap = 9;
-pub const SYS_mprotect = 10;
-pub const SYS_munmap = 11;
-pub const SYS_brk = 12;
-pub const SYS_rt_sigaction = 13;
-pub const SYS_rt_sigprocmask = 14;
-pub const SYS_rt_sigreturn = 15;
-pub const SYS_ioctl = 16;
-pub const SYS_pread = 17;
-pub const SYS_pwrite = 18;
-pub const SYS_readv = 19;
-pub const SYS_writev = 20;
-pub const SYS_access = 21;
-pub const SYS_pipe = 22;
-pub const SYS_select = 23;
-pub const SYS_sched_yield = 24;
-pub const SYS_mremap = 25;
-pub const SYS_msync = 26;
-pub const SYS_mincore = 27;
-pub const SYS_madvise = 28;
-pub const SYS_shmget = 29;
-pub const SYS_shmat = 30;
-pub const SYS_shmctl = 31;
-pub const SYS_dup = 32;
-pub const SYS_dup2 = 33;
-pub const SYS_pause = 34;
-pub const SYS_nanosleep = 35;
-pub const SYS_getitimer = 36;
-pub const SYS_alarm = 37;
-pub const SYS_setitimer = 38;
-pub const SYS_getpid = 39;
-pub const SYS_sendfile = 40;
-pub const SYS_socket = 41;
-pub const SYS_connect = 42;
-pub const SYS_accept = 43;
-pub const SYS_sendto = 44;
-pub const SYS_recvfrom = 45;
-pub const SYS_sendmsg = 46;
-pub const SYS_recvmsg = 47;
-pub const SYS_shutdown = 48;
-pub const SYS_bind = 49;
-pub const SYS_listen = 50;
-pub const SYS_getsockname = 51;
-pub const SYS_getpeername = 52;
-pub const SYS_socketpair = 53;
-pub const SYS_setsockopt = 54;
-pub const SYS_getsockopt = 55;
-pub const SYS_clone = 56;
-pub const SYS_fork = 57;
-pub const SYS_vfork = 58;
-pub const SYS_execve = 59;
-pub const SYS_exit = 60;
-pub const SYS_wait4 = 61;
-pub const SYS_kill = 62;
-pub const SYS_uname = 63;
-pub const SYS_semget = 64;
-pub const SYS_semop = 65;
-pub const SYS_semctl = 66;
-pub const SYS_shmdt = 67;
-pub const SYS_msgget = 68;
-pub const SYS_msgsnd = 69;
-pub const SYS_msgrcv = 70;
-pub const SYS_msgctl = 71;
-pub const SYS_fcntl = 72;
-pub const SYS_flock = 73;
-pub const SYS_fsync = 74;
-pub const SYS_fdatasync = 75;
-pub const SYS_truncate = 76;
-pub const SYS_ftruncate = 77;
-pub const SYS_getdents = 78;
-pub const SYS_getcwd = 79;
-pub const SYS_chdir = 80;
-pub const SYS_fchdir = 81;
-pub const SYS_rename = 82;
-pub const SYS_mkdir = 83;
-pub const SYS_rmdir = 84;
-pub const SYS_creat = 85;
-pub const SYS_link = 86;
-pub const SYS_unlink = 87;
-pub const SYS_symlink = 88;
-pub const SYS_readlink = 89;
-pub const SYS_chmod = 90;
-pub const SYS_fchmod = 91;
-pub const SYS_chown = 92;
-pub const SYS_fchown = 93;
-pub const SYS_lchown = 94;
-pub const SYS_umask = 95;
-pub const SYS_gettimeofday = 96;
-pub const SYS_getrlimit = 97;
-pub const SYS_getrusage = 98;
-pub const SYS_sysinfo = 99;
-pub const SYS_times = 100;
-pub const SYS_ptrace = 101;
-pub const SYS_getuid = 102;
-pub const SYS_syslog = 103;
-pub const SYS_getgid = 104;
-pub const SYS_setuid = 105;
-pub const SYS_setgid = 106;
-pub const SYS_geteuid = 107;
-pub const SYS_getegid = 108;
-pub const SYS_setpgid = 109;
-pub const SYS_getppid = 110;
-pub const SYS_getpgrp = 111;
-pub const SYS_setsid = 112;
-pub const SYS_setreuid = 113;
-pub const SYS_setregid = 114;
-pub const SYS_getgroups = 115;
-pub const SYS_setgroups = 116;
-pub const SYS_setresuid = 117;
-pub const SYS_getresuid = 118;
-pub const SYS_setresgid = 119;
-pub const SYS_getresgid = 120;
-pub const SYS_getpgid = 121;
-pub const SYS_setfsuid = 122;
-pub const SYS_setfsgid = 123;
-pub const SYS_getsid = 124;
-pub const SYS_capget = 125;
-pub const SYS_capset = 126;
-pub const SYS_rt_sigpending = 127;
-pub const SYS_rt_sigtimedwait = 128;
-pub const SYS_rt_sigqueueinfo = 129;
-pub const SYS_rt_sigsuspend = 130;
-pub const SYS_sigaltstack = 131;
-pub const SYS_utime = 132;
-pub const SYS_mknod = 133;
-pub const SYS_uselib = 134;
-pub const SYS_personality = 135;
-pub const SYS_ustat = 136;
-pub const SYS_statfs = 137;
-pub const SYS_fstatfs = 138;
-pub const SYS_sysfs = 139;
-pub const SYS_getpriority = 140;
-pub const SYS_setpriority = 141;
-pub const SYS_sched_setparam = 142;
-pub const SYS_sched_getparam = 143;
-pub const SYS_sched_setscheduler = 144;
-pub const SYS_sched_getscheduler = 145;
-pub const SYS_sched_get_priority_max = 146;
-pub const SYS_sched_get_priority_min = 147;
-pub const SYS_sched_rr_get_interval = 148;
-pub const SYS_mlock = 149;
-pub const SYS_munlock = 150;
-pub const SYS_mlockall = 151;
-pub const SYS_munlockall = 152;
-pub const SYS_vhangup = 153;
-pub const SYS_modify_ldt = 154;
-pub const SYS_pivot_root = 155;
-pub const SYS__sysctl = 156;
-pub const SYS_prctl = 157;
-pub const SYS_arch_prctl = 158;
-pub const SYS_adjtimex = 159;
-pub const SYS_setrlimit = 160;
-pub const SYS_chroot = 161;
-pub const SYS_sync = 162;
-pub const SYS_acct = 163;
-pub const SYS_settimeofday = 164;
-pub const SYS_mount = 165;
-pub const SYS_umount2 = 166;
-pub const SYS_swapon = 167;
-pub const SYS_swapoff = 168;
-pub const SYS_reboot = 169;
-pub const SYS_sethostname = 170;
-pub const SYS_setdomainname = 171;
-pub const SYS_iopl = 172;
-pub const SYS_ioperm = 173;
-pub const SYS_create_module = 174;
-pub const SYS_init_module = 175;
-pub const SYS_delete_module = 176;
-pub const SYS_get_kernel_syms = 177;
-pub const SYS_query_module = 178;
-pub const SYS_quotactl = 179;
-pub const SYS_nfsservctl = 180;
-pub const SYS_getpmsg = 181;
-pub const SYS_putpmsg = 182;
-pub const SYS_afs_syscall = 183;
-pub const SYS_tuxcall = 184;
-pub const SYS_security = 185;
-pub const SYS_gettid = 186;
-pub const SYS_readahead = 187;
-pub const SYS_setxattr = 188;
-pub const SYS_lsetxattr = 189;
-pub const SYS_fsetxattr = 190;
-pub const SYS_getxattr = 191;
-pub const SYS_lgetxattr = 192;
-pub const SYS_fgetxattr = 193;
-pub const SYS_listxattr = 194;
-pub const SYS_llistxattr = 195;
-pub const SYS_flistxattr = 196;
-pub const SYS_removexattr = 197;
-pub const SYS_lremovexattr = 198;
-pub const SYS_fremovexattr = 199;
-pub const SYS_tkill = 200;
-pub const SYS_time = 201;
-pub const SYS_futex = 202;
-pub const SYS_sched_setaffinity = 203;
-pub const SYS_sched_getaffinity = 204;
-pub const SYS_set_thread_area = 205;
-pub const SYS_io_setup = 206;
-pub const SYS_io_destroy = 207;
-pub const SYS_io_getevents = 208;
-pub const SYS_io_submit = 209;
-pub const SYS_io_cancel = 210;
-pub const SYS_get_thread_area = 211;
-pub const SYS_lookup_dcookie = 212;
-pub const SYS_epoll_create = 213;
-pub const SYS_epoll_ctl_old = 214;
-pub const SYS_epoll_wait_old = 215;
-pub const SYS_remap_file_pages = 216;
-pub const SYS_getdents64 = 217;
-pub const SYS_set_tid_address = 218;
-pub const SYS_restart_syscall = 219;
-pub const SYS_semtimedop = 220;
-pub const SYS_fadvise64 = 221;
-pub const SYS_timer_create = 222;
-pub const SYS_timer_settime = 223;
-pub const SYS_timer_gettime = 224;
-pub const SYS_timer_getoverrun = 225;
-pub const SYS_timer_delete = 226;
-pub const SYS_clock_settime = 227;
-pub const SYS_clock_gettime = 228;
-pub const SYS_clock_getres = 229;
-pub const SYS_clock_nanosleep = 230;
-pub const SYS_exit_group = 231;
-pub const SYS_epoll_wait = 232;
-pub const SYS_epoll_ctl = 233;
-pub const SYS_tgkill = 234;
-pub const SYS_utimes = 235;
-pub const SYS_vserver = 236;
-pub const SYS_mbind = 237;
-pub const SYS_set_mempolicy = 238;
-pub const SYS_get_mempolicy = 239;
-pub const SYS_mq_open = 240;
-pub const SYS_mq_unlink = 241;
-pub const SYS_mq_timedsend = 242;
-pub const SYS_mq_timedreceive = 243;
-pub const SYS_mq_notify = 244;
-pub const SYS_mq_getsetattr = 245;
-pub const SYS_kexec_load = 246;
-pub const SYS_waitid = 247;
-pub const SYS_add_key = 248;
-pub const SYS_request_key = 249;
-pub const SYS_keyctl = 250;
-pub const SYS_ioprio_set = 251;
-pub const SYS_ioprio_get = 252;
-pub const SYS_inotify_init = 253;
-pub const SYS_inotify_add_watch = 254;
-pub const SYS_inotify_rm_watch = 255;
-pub const SYS_migrate_pages = 256;
-pub const SYS_openat = 257;
-pub const SYS_mkdirat = 258;
-pub const SYS_mknodat = 259;
-pub const SYS_fchownat = 260;
-pub const SYS_futimesat = 261;
-pub const SYS_newfstatat = 262;
-// https://github.com/ziglang/zig/issues/1439
-pub const SYS_fstatat = 262;
-pub const SYS_unlinkat = 263;
-pub const SYS_renameat = 264;
-pub const SYS_linkat = 265;
-pub const SYS_symlinkat = 266;
-pub const SYS_readlinkat = 267;
-pub const SYS_fchmodat = 268;
-pub const SYS_faccessat = 269;
-pub const SYS_pselect6 = 270;
-pub const SYS_ppoll = 271;
-pub const SYS_unshare = 272;
-pub const SYS_set_robust_list = 273;
-pub const SYS_get_robust_list = 274;
-pub const SYS_splice = 275;
-pub const SYS_tee = 276;
-pub const SYS_sync_file_range = 277;
-pub const SYS_vmsplice = 278;
-pub const SYS_move_pages = 279;
-pub const SYS_utimensat = 280;
-pub const SYS_epoll_pwait = 281;
-pub const SYS_signalfd = 282;
-pub const SYS_timerfd_create = 283;
-pub const SYS_eventfd = 284;
-pub const SYS_fallocate = 285;
-pub const SYS_timerfd_settime = 286;
-pub const SYS_timerfd_gettime = 287;
-pub const SYS_accept4 = 288;
-pub const SYS_signalfd4 = 289;
-pub const SYS_eventfd2 = 290;
-pub const SYS_epoll_create1 = 291;
-pub const SYS_dup3 = 292;
-pub const SYS_pipe2 = 293;
-pub const SYS_inotify_init1 = 294;
-pub const SYS_preadv = 295;
-pub const SYS_pwritev = 296;
-pub const SYS_rt_tgsigqueueinfo = 297;
-pub const SYS_perf_event_open = 298;
-pub const SYS_recvmmsg = 299;
-pub const SYS_fanotify_init = 300;
-pub const SYS_fanotify_mark = 301;
-pub const SYS_prlimit64 = 302;
-pub const SYS_name_to_handle_at = 303;
-pub const SYS_open_by_handle_at = 304;
-pub const SYS_clock_adjtime = 305;
-pub const SYS_syncfs = 306;
-pub const SYS_sendmmsg = 307;
-pub const SYS_setns = 308;
-pub const SYS_getcpu = 309;
-pub const SYS_process_vm_readv = 310;
-pub const SYS_process_vm_writev = 311;
-pub const SYS_kcmp = 312;
-pub const SYS_finit_module = 313;
-pub const SYS_sched_setattr = 314;
-pub const SYS_sched_getattr = 315;
-pub const SYS_renameat2 = 316;
-pub const SYS_seccomp = 317;
-pub const SYS_getrandom = 318;
-pub const SYS_memfd_create = 319;
-pub const SYS_kexec_file_load = 320;
-pub const SYS_bpf = 321;
-pub const SYS_execveat = 322;
-pub const SYS_userfaultfd = 323;
-pub const SYS_membarrier = 324;
-pub const SYS_mlock2 = 325;
-pub const SYS_copy_file_range = 326;
-pub const SYS_preadv2 = 327;
-pub const SYS_pwritev2 = 328;
-pub const SYS_pkey_mprotect = 329;
-pub const SYS_pkey_alloc = 330;
-pub const SYS_pkey_free = 331;
-pub const SYS_statx = 332;
-pub const SYS_io_pgetevents = 333;
-pub const SYS_rseq = 334;
-pub const SYS_pidfd_send_signal = 424;
-pub const SYS_io_uring_setup = 425;
-pub const SYS_io_uring_enter = 426;
-pub const SYS_io_uring_register = 427;
-
-pub const O_CREAT = 0o100;
-pub const O_EXCL = 0o200;
-pub const O_NOCTTY = 0o400;
-pub const O_TRUNC = 0o1000;
-pub const O_APPEND = 0o2000;
-pub const O_NONBLOCK = 0o4000;
-pub const O_DSYNC = 0o10000;
-pub const O_SYNC = 0o4010000;
-pub const O_RSYNC = 0o4010000;
-pub const O_DIRECTORY = 0o200000;
-pub const O_NOFOLLOW = 0o400000;
-pub const O_CLOEXEC = 0o2000000;
-
-pub const O_ASYNC = 0o20000;
-pub const O_DIRECT = 0o40000;
-pub const O_LARGEFILE = 0;
-pub const O_NOATIME = 0o1000000;
-pub const O_PATH = 0o10000000;
-pub const O_TMPFILE = 0o20200000;
-pub const O_NDELAY = O_NONBLOCK;
-
-pub const F_DUPFD = 0;
-pub const F_GETFD = 1;
-pub const F_SETFD = 2;
-pub const F_GETFL = 3;
-pub const F_SETFL = 4;
-
-pub const F_SETOWN = 8;
-pub const F_GETOWN = 9;
-pub const F_SETSIG = 10;
-pub const F_GETSIG = 11;
-
-pub const F_GETLK = 5;
-pub const F_SETLK = 6;
-pub const F_SETLKW = 7;
-
-pub const F_SETOWN_EX = 15;
-pub const F_GETOWN_EX = 16;
-
-pub const F_GETOWNER_UIDS = 17;
-
-pub const AT_FDCWD = -100;
-pub const AT_SYMLINK_NOFOLLOW = 0x100;
-pub const AT_REMOVEDIR = 0x200;
-pub const AT_SYMLINK_FOLLOW = 0x400;
-pub const AT_NO_AUTOMOUNT = 0x800;
-pub const AT_EMPTY_PATH = 0x1000;
-
-pub const VDSO_USEFUL = true;
-pub const VDSO_CGT_SYM = "__vdso_clock_gettime";
-pub const VDSO_CGT_VER = "LINUX_2.6";
-pub const VDSO_GETCPU_SYM = "__vdso_getcpu";
-pub const VDSO_GETCPU_VER = "LINUX_2.6";
-
-pub const ARCH_SET_GS = 0x1001;
-pub const ARCH_SET_FS = 0x1002;
-pub const ARCH_GET_FS = 0x1003;
-pub const ARCH_GET_GS = 0x1004;
+use @import("../bits.zig");
pub fn syscall0(number: usize) usize {
return asm volatile ("syscall"
@@ -501,65 +95,3 @@ pub nakedcc fn restore_rt() void {
: "rcx", "r11"
);
}
-
-pub const msghdr = extern struct {
- msg_name: ?*sockaddr,
- msg_namelen: socklen_t,
- msg_iov: [*]iovec,
- msg_iovlen: i32,
- __pad1: i32,
- msg_control: ?*c_void,
- msg_controllen: socklen_t,
- __pad2: socklen_t,
- msg_flags: i32,
-};
-
-pub const msghdr_const = extern struct {
- msg_name: ?*const sockaddr,
- msg_namelen: socklen_t,
- msg_iov: [*]iovec_const,
- msg_iovlen: i32,
- __pad1: i32,
- msg_control: ?*c_void,
- msg_controllen: socklen_t,
- __pad2: socklen_t,
- msg_flags: i32,
-};
-
-/// Renamed to Stat to not conflict with the stat function.
-pub const Stat = extern struct {
- dev: u64,
- ino: u64,
- nlink: usize,
-
- mode: u32,
- uid: u32,
- gid: u32,
- __pad0: u32,
- rdev: u64,
- size: i64,
- blksize: isize,
- blocks: i64,
-
- atim: timespec,
- mtim: timespec,
- ctim: timespec,
- __unused: [3]isize,
-};
-
-pub const timespec = extern struct {
- tv_sec: isize,
- tv_nsec: isize,
-};
-
-pub const timeval = extern struct {
- tv_sec: isize,
- tv_usec: isize,
-};
-
-pub const timezone = extern struct {
- tz_minuteswest: i32,
- tz_dsttime: i32,
-};
-
-pub const Elf_Symndx = u32;
diff --git a/std/os/netbsd.zig b/std/os/netbsd.zig
index 2d4b6ff124..25e72c10a8 100644
--- a/std/os/netbsd.zig
+++ b/std/os/netbsd.zig
@@ -1,724 +1,4 @@
const builtin = @import("builtin");
-
-pub use @import("netbsd/errno.zig");
-
const std = @import("../std.zig");
-const c = std.c;
-
-const assert = std.debug.assert;
-const maxInt = std.math.maxInt;
-pub const Kevent = c.Kevent;
-
-pub const CTL_KERN = 1;
-pub const CTL_DEBUG = 5;
-
-pub const KERN_PROC_ARGS = 48; // struct: process argv/env
-pub const KERN_PROC_PATHNAME = 5; // path to executable
-
-pub const PATH_MAX = 1024;
-
-pub const STDIN_FILENO = 0;
-pub const STDOUT_FILENO = 1;
-pub const STDERR_FILENO = 2;
-
-pub const PROT_NONE = 0;
-pub const PROT_READ = 1;
-pub const PROT_WRITE = 2;
-pub const PROT_EXEC = 4;
-
-pub const CLOCK_REALTIME = 0;
-pub const CLOCK_VIRTUAL = 1;
-pub const CLOCK_PROF = 2;
-pub const CLOCK_MONOTONIC = 3;
-pub const CLOCK_THREAD_CPUTIME_ID = 0x20000000;
-pub const CLOCK_PROCESS_CPUTIME_ID = 0x40000000;
-
-pub const MAP_FAILED = maxInt(usize);
-pub const MAP_SHARED = 0x0001;
-pub const MAP_PRIVATE = 0x0002;
-pub const MAP_REMAPDUP = 0x0004;
-pub const MAP_FIXED = 0x0010;
-pub const MAP_RENAME = 0x0020;
-pub const MAP_NORESERVE = 0x0040;
-pub const MAP_INHERIT = 0x0080;
-pub const MAP_HASSEMAPHORE = 0x0200;
-pub const MAP_TRYFIXED = 0x0400;
-pub const MAP_WIRED = 0x0800;
-
-pub const MAP_FILE = 0x0000;
-pub const MAP_NOSYNC = 0x0800;
-pub const MAP_ANON = 0x1000;
-pub const MAP_ANONYMOUS = MAP_ANON;
-pub const MAP_STACK = 0x2000;
-
-pub const WNOHANG = 0x00000001;
-pub const WUNTRACED = 0x00000002;
-pub const WSTOPPED = WUNTRACED;
-pub const WCONTINUED = 0x00000010;
-pub const WNOWAIT = 0x00010000;
-pub const WEXITED = 0x00000020;
-pub const WTRAPPED = 0x00000040;
-
-pub const SA_ONSTACK = 0x0001;
-pub const SA_RESTART = 0x0002;
-pub const SA_RESETHAND = 0x0004;
-pub const SA_NOCLDSTOP = 0x0008;
-pub const SA_NODEFER = 0x0010;
-pub const SA_NOCLDWAIT = 0x0020;
-pub const SA_SIGINFO = 0x0040;
-
-pub const SIGHUP = 1;
-pub const SIGINT = 2;
-pub const SIGQUIT = 3;
-pub const SIGILL = 4;
-pub const SIGTRAP = 5;
-pub const SIGABRT = 6;
-pub const SIGIOT = SIGABRT;
-pub const SIGEMT = 7;
-pub const SIGFPE = 8;
-pub const SIGKILL = 9;
-pub const SIGBUS = 10;
-pub const SIGSEGV = 11;
-pub const SIGSYS = 12;
-pub const SIGPIPE = 13;
-pub const SIGALRM = 14;
-pub const SIGTERM = 15;
-pub const SIGURG = 16;
-pub const SIGSTOP = 17;
-pub const SIGTSTP = 18;
-pub const SIGCONT = 19;
-pub const SIGCHLD = 20;
-pub const SIGTTIN = 21;
-pub const SIGTTOU = 22;
-pub const SIGIO = 23;
-pub const SIGXCPU = 24;
-pub const SIGXFSZ = 25;
-pub const SIGVTALRM = 26;
-pub const SIGPROF = 27;
-pub const SIGWINCH = 28;
-pub const SIGINFO = 29;
-pub const SIGUSR1 = 30;
-pub const SIGUSR2 = 31;
-pub const SIGPWR = 32;
-
-pub const SIGRTMIN = 33;
-pub const SIGRTMAX = 63;
-
-// access function
-pub const F_OK = 0; // test for existence of file
-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_RDONLY = 0x0000;
-pub const O_WRONLY = 0x0001;
-pub const O_RDWR = 0x0002;
-pub const O_ACCMODE = 0x0003;
-
-pub const O_CREAT = 0x0200;
-pub const O_EXCL = 0x0800;
-pub const O_NOCTTY = 0x8000;
-pub const O_TRUNC = 0x0400;
-pub const O_APPEND = 0x0008;
-pub const O_NONBLOCK = 0x0004;
-pub const O_DSYNC = 0x00010000;
-pub const O_SYNC = 0x0080;
-pub const O_RSYNC = 0x00020000;
-pub const O_DIRECTORY = 0x00080000;
-pub const O_NOFOLLOW = 0x00000100;
-pub const O_CLOEXEC = 0x00400000;
-
-pub const O_ASYNC = 0x0040;
-pub const O_DIRECT = 0x00080000;
-pub const O_LARGEFILE = 0;
-pub const O_NOATIME = 0;
-pub const O_PATH = 0;
-pub const O_TMPFILE = 0;
-pub const O_NDELAY = O_NONBLOCK;
-
-pub const F_DUPFD = 0;
-pub const F_GETFD = 1;
-pub const F_SETFD = 2;
-pub const F_GETFL = 3;
-pub const F_SETFL = 4;
-
-pub const F_GETOWN = 5;
-pub const F_SETOWN = 6;
-
-pub const F_GETLK = 7;
-pub const F_SETLK = 8;
-pub const F_SETLKW = 9;
-
-pub const SEEK_SET = 0;
-pub const SEEK_CUR = 1;
-pub const SEEK_END = 2;
-
-pub const SIG_BLOCK = 1;
-pub const SIG_UNBLOCK = 2;
-pub const SIG_SETMASK = 3;
-
-pub const SOCK_STREAM = 1;
-pub const SOCK_DGRAM = 2;
-pub const SOCK_RAW = 3;
-pub const SOCK_RDM = 4;
-pub const SOCK_SEQPACKET = 5;
-
-pub const SOCK_CLOEXEC = 0x10000000;
-pub const SOCK_NONBLOCK = 0x20000000;
-
-pub const PROTO_ip = 0;
-pub const PROTO_icmp = 1;
-pub const PROTO_igmp = 2;
-pub const PROTO_ggp = 3;
-pub const PROTO_ipencap = 4;
-pub const PROTO_tcp = 6;
-pub const PROTO_egp = 8;
-pub const PROTO_pup = 12;
-pub const PROTO_udp = 17;
-pub const PROTO_xns_idp = 22;
-pub const PROTO_iso_tp4 = 29;
-pub const PROTO_ipv6 = 41;
-pub const PROTO_ipv6_route = 43;
-pub const PROTO_ipv6_frag = 44;
-pub const PROTO_rsvp = 46;
-pub const PROTO_gre = 47;
-pub const PROTO_esp = 50;
-pub const PROTO_ah = 51;
-pub const PROTO_ipv6_icmp = 58;
-pub const PROTO_ipv6_nonxt = 59;
-pub const PROTO_ipv6_opts = 60;
-pub const PROTO_encap = 98;
-pub const PROTO_pim = 103;
-pub const PROTO_raw = 255;
-
-pub const PF_UNSPEC = 0;
-pub const PF_LOCAL = 1;
-pub const PF_UNIX = PF_LOCAL;
-pub const PF_FILE = PF_LOCAL;
-pub const PF_INET = 2;
-pub const PF_APPLETALK = 16;
-pub const PF_INET6 = 24;
-pub const PF_DECnet = 12;
-pub const PF_KEY = 29;
-pub const PF_ROUTE = 34;
-pub const PF_SNA = 11;
-pub const PF_MPLS = 33;
-pub const PF_CAN = 35;
-pub const PF_BLUETOOTH = 31;
-pub const PF_ISDN = 26;
-pub const PF_MAX = 37;
-
-pub const AF_UNSPEC = PF_UNSPEC;
-pub const AF_LOCAL = PF_LOCAL;
-pub const AF_UNIX = AF_LOCAL;
-pub const AF_FILE = AF_LOCAL;
-pub const AF_INET = PF_INET;
-pub const AF_APPLETALK = PF_APPLETALK;
-pub const AF_INET6 = PF_INET6;
-pub const AF_KEY = PF_KEY;
-pub const AF_ROUTE = PF_ROUTE;
-pub const AF_SNA = PF_SNA;
-pub const AF_MPLS = PF_MPLS;
-pub const AF_CAN = PF_CAN;
-pub const AF_BLUETOOTH = PF_BLUETOOTH;
-pub const AF_ISDN = PF_ISDN;
-pub const AF_MAX = PF_MAX;
-
-pub const DT_UNKNOWN = 0;
-pub const DT_FIFO = 1;
-pub const DT_CHR = 2;
-pub const DT_DIR = 4;
-pub const DT_BLK = 6;
-pub const DT_REG = 8;
-pub const DT_LNK = 10;
-pub const DT_SOCK = 12;
-pub const DT_WHT = 14;
-
-/// add event to kq (implies enable)
-pub const EV_ADD = 0x0001;
-
-/// delete event from kq
-pub const EV_DELETE = 0x0002;
-
-/// enable event
-pub const EV_ENABLE = 0x0004;
-
-/// disable event (not reported)
-pub const EV_DISABLE = 0x0008;
-
-/// only report one occurrence
-pub const EV_ONESHOT = 0x0010;
-
-/// clear event state after reporting
-pub const EV_CLEAR = 0x0020;
-
-/// force immediate event output
-/// ... with or without EV_ERROR
-/// ... use KEVENT_FLAG_ERROR_EVENTS
-/// on syscalls supporting flags
-pub const EV_RECEIPT = 0x0040;
-
-/// disable event after reporting
-pub const EV_DISPATCH = 0x0080;
-
-pub const EVFILT_READ = 0;
-pub const EVFILT_WRITE = 1;
-
-/// attached to aio requests
-pub const EVFILT_AIO = 2;
-
-/// attached to vnodes
-pub const EVFILT_VNODE = 3;
-
-/// attached to struct proc
-pub const EVFILT_PROC = 4;
-
-/// attached to struct proc
-pub const EVFILT_SIGNAL = 5;
-
-/// timers
-pub const EVFILT_TIMER = 6;
-
-/// Filesystem events
-pub const EVFILT_FS = 7;
-
-/// On input, NOTE_TRIGGER causes the event to be triggered for output.
-pub const NOTE_TRIGGER = 0x08000000;
-
-/// low water mark
-pub const NOTE_LOWAT = 0x00000001;
-
-/// vnode was removed
-pub const NOTE_DELETE = 0x00000001;
-
-/// data contents changed
-pub const NOTE_WRITE = 0x00000002;
-
-/// size increased
-pub const NOTE_EXTEND = 0x00000004;
-
-/// attributes changed
-pub const NOTE_ATTRIB = 0x00000008;
-
-/// link count changed
-pub const NOTE_LINK = 0x00000010;
-
-/// vnode was renamed
-pub const NOTE_RENAME = 0x00000020;
-
-/// vnode access was revoked
-pub const NOTE_REVOKE = 0x00000040;
-
-/// process exited
-pub const NOTE_EXIT = 0x80000000;
-
-/// process forked
-pub const NOTE_FORK = 0x40000000;
-
-/// process exec'd
-pub const NOTE_EXEC = 0x20000000;
-
-/// mask for signal & exit status
-pub const NOTE_PDATAMASK = 0x000fffff;
-pub const NOTE_PCTRLMASK = 0xf0000000;
-
-pub const TIOCCBRK = 0x2000747a;
-pub const TIOCCDTR = 0x20007478;
-pub const TIOCCONS = 0x80047462;
-pub const TIOCDCDTIMESTAMP = 0x40107458;
-pub const TIOCDRAIN = 0x2000745e;
-pub const TIOCEXCL = 0x2000740d;
-pub const TIOCEXT = 0x80047460;
-pub const TIOCFLAG_CDTRCTS = 0x10;
-pub const TIOCFLAG_CLOCAL = 0x2;
-pub const TIOCFLAG_CRTSCTS = 0x4;
-pub const TIOCFLAG_MDMBUF = 0x8;
-pub const TIOCFLAG_SOFTCAR = 0x1;
-pub const TIOCFLUSH = 0x80047410;
-pub const TIOCGETA = 0x402c7413;
-pub const TIOCGETD = 0x4004741a;
-pub const TIOCGFLAGS = 0x4004745d;
-pub const TIOCGLINED = 0x40207442;
-pub const TIOCGPGRP = 0x40047477;
-pub const TIOCGQSIZE = 0x40047481;
-pub const TIOCGRANTPT = 0x20007447;
-pub const TIOCGSID = 0x40047463;
-pub const TIOCGSIZE = 0x40087468;
-pub const TIOCGWINSZ = 0x40087468;
-pub const TIOCMBIC = 0x8004746b;
-pub const TIOCMBIS = 0x8004746c;
-pub const TIOCMGET = 0x4004746a;
-pub const TIOCMSET = 0x8004746d;
-pub const TIOCM_CAR = 0x40;
-pub const TIOCM_CD = 0x40;
-pub const TIOCM_CTS = 0x20;
-pub const TIOCM_DSR = 0x100;
-pub const TIOCM_DTR = 0x2;
-pub const TIOCM_LE = 0x1;
-pub const TIOCM_RI = 0x80;
-pub const TIOCM_RNG = 0x80;
-pub const TIOCM_RTS = 0x4;
-pub const TIOCM_SR = 0x10;
-pub const TIOCM_ST = 0x8;
-pub const TIOCNOTTY = 0x20007471;
-pub const TIOCNXCL = 0x2000740e;
-pub const TIOCOUTQ = 0x40047473;
-pub const TIOCPKT = 0x80047470;
-pub const TIOCPKT_DATA = 0x0;
-pub const TIOCPKT_DOSTOP = 0x20;
-pub const TIOCPKT_FLUSHREAD = 0x1;
-pub const TIOCPKT_FLUSHWRITE = 0x2;
-pub const TIOCPKT_IOCTL = 0x40;
-pub const TIOCPKT_NOSTOP = 0x10;
-pub const TIOCPKT_START = 0x8;
-pub const TIOCPKT_STOP = 0x4;
-pub const TIOCPTMGET = 0x40287446;
-pub const TIOCPTSNAME = 0x40287448;
-pub const TIOCRCVFRAME = 0x80087445;
-pub const TIOCREMOTE = 0x80047469;
-pub const TIOCSBRK = 0x2000747b;
-pub const TIOCSCTTY = 0x20007461;
-pub const TIOCSDTR = 0x20007479;
-pub const TIOCSETA = 0x802c7414;
-pub const TIOCSETAF = 0x802c7416;
-pub const TIOCSETAW = 0x802c7415;
-pub const TIOCSETD = 0x8004741b;
-pub const TIOCSFLAGS = 0x8004745c;
-pub const TIOCSIG = 0x2000745f;
-pub const TIOCSLINED = 0x80207443;
-pub const TIOCSPGRP = 0x80047476;
-pub const TIOCSQSIZE = 0x80047480;
-pub const TIOCSSIZE = 0x80087467;
-pub const TIOCSTART = 0x2000746e;
-pub const TIOCSTAT = 0x80047465;
-pub const TIOCSTI = 0x80017472;
-pub const TIOCSTOP = 0x2000746f;
-pub const TIOCSWINSZ = 0x80087467;
-pub const TIOCUCNTL = 0x80047466;
-pub const TIOCXMTFRAME = 0x80087444;
-
-pub const sockaddr = c.sockaddr;
-pub const sockaddr_in = c.sockaddr_in;
-pub const sockaddr_in6 = c.sockaddr_in6;
-
-fn unsigned(s: i32) u32 {
- return @bitCast(u32, s);
-}
-fn signed(s: u32) i32 {
- return @bitCast(i32, s);
-}
-pub fn WEXITSTATUS(s: i32) i32 {
- return signed((unsigned(s) >> 8) & 0xff);
-}
-pub fn WTERMSIG(s: i32) i32 {
- return signed(unsigned(s) & 0x7f);
-}
-pub fn WSTOPSIG(s: i32) i32 {
- return WEXITSTATUS(s);
-}
-pub fn WIFEXITED(s: i32) bool {
- return WTERMSIG(s) == 0;
-}
-
-pub fn WIFCONTINUED(s: i32) bool {
- return ((s & 0x7f) == 0xffff);
-}
-
-pub fn WIFSTOPPED(s: i32) bool {
- return ((s & 0x7f != 0x7f) and !WIFCONTINUED(s));
-}
-
-pub fn WIFSIGNALED(s: i32) bool {
- return !WIFSTOPPED(s) and !WIFCONTINUED(s) and !WIFEXITED(s);
-}
-
-pub const winsize = extern struct {
- ws_row: u16,
- ws_col: u16,
- ws_xpixel: u16,
- ws_ypixel: u16,
-};
-
-/// Get the errno from a syscall return value, or 0 for no error.
-pub fn getErrno(r: usize) usize {
- const signed_r = @bitCast(isize, r);
- return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
-}
-
-pub fn dup2(old: i32, new: i32) usize {
- return errnoWrap(c.dup2(old, new));
-}
-
-pub fn chdir(path: [*]const u8) usize {
- return errnoWrap(c.chdir(path));
-}
-
-pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
- return errnoWrap(c.execve(path, argv, envp));
-}
-
-pub fn fork() usize {
- return errnoWrap(c.fork());
-}
-
-pub fn access(path: [*]const u8, mode: u32) usize {
- return errnoWrap(c.access(path, mode));
-}
-
-pub fn getcwd(buf: [*]u8, size: usize) usize {
- return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
-}
-
-pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize {
- return errnoWrap(@bitCast(isize, c.getdents(fd, drip, count)));
-}
-
-pub fn getdirentries(fd: i32, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize {
- return errnoWrap(@bitCast(isize, c.getdirentries(fd, buf_ptr, buf_len, basep)));
-}
-
-pub fn realpath(noalias filename: [*]const u8, noalias resolved_name: [*]u8) usize {
- return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
-}
-
-pub fn isatty(fd: i32) bool {
- return c.isatty(fd) != 0;
-}
-
-pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
- return errnoWrap(c.readlink(path, buf_ptr, buf_len));
-}
-
-pub fn mkdir(path: [*]const u8, mode: u32) usize {
- return errnoWrap(c.mkdir(path, mode));
-}
-
-pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
- const ptr_result = c.mmap(
- @ptrCast(?*c_void, address),
- length,
- @bitCast(c_int, @intCast(c_uint, prot)),
- @bitCast(c_int, c_uint(flags)),
- fd,
- offset,
- );
- const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
- return errnoWrap(isize_result);
-}
-
-pub fn munmap(address: usize, length: usize) usize {
- return errnoWrap(c.munmap(@intToPtr(*c_void, address), length));
-}
-
-pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
- return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte));
-}
-
-pub fn rmdir(path: [*]const u8) usize {
- return errnoWrap(c.rmdir(path));
-}
-
-pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
- return errnoWrap(c.symlink(existing, new));
-}
-
-pub fn pread(fd: i32, buf: [*]u8, nbyte: usize, offset: u64) usize {
- return errnoWrap(c.pread(fd, @ptrCast(*c_void, buf), nbyte, offset));
-}
-
-pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: usize) usize {
- return errnoWrap(c.preadv(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
-}
-
-pub fn pipe(fd: *[2]i32) usize {
- return pipe2(fd, 0);
-}
-
-pub fn pipe2(fd: *[2]i32, flags: u32) usize {
- comptime assert(i32.bit_count == c_int.bit_count);
- return errnoWrap(c.pipe2(@ptrCast(*[2]c_int, fd), flags));
-}
-
-pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize {
- return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte));
-}
-
-pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize {
- return errnoWrap(c.pwrite(fd, @ptrCast(*const c_void, buf), nbyte, offset));
-}
-
-pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) usize {
- return errnoWrap(c.pwritev(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
-}
-
-pub fn rename(old: [*]const u8, new: [*]const u8) usize {
- return errnoWrap(c.rename(old, new));
-}
-
-pub fn open(path: [*]const u8, flags: u32, mode: usize) usize {
- return errnoWrap(c.open(path, @bitCast(c_int, flags), mode));
-}
-
-pub fn create(path: [*]const u8, perm: usize) usize {
- return arch.syscall2(SYS_creat, @ptrToInt(path), perm);
-}
-
-pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize {
- return errnoWrap(c.openat(@bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode));
-}
-
-pub fn close(fd: i32) usize {
- return errnoWrap(c.close(fd));
-}
-
-pub fn lseek(fd: i32, offset: isize, whence: c_int) usize {
- return errnoWrap(c.lseek(fd, offset, whence));
-}
-
-pub fn exit(code: i32) noreturn {
- c.exit(code);
-}
-
-pub fn kill(pid: i32, sig: i32) usize {
- return errnoWrap(c.kill(pid, sig));
-}
-
-pub fn unlink(path: [*]const u8) usize {
- return errnoWrap(c.unlink(path));
-}
-
-pub fn waitpid(pid: i32, status: *i32, options: u32) usize {
- comptime assert(i32.bit_count == c_int.bit_count);
- return errnoWrap(c.waitpid(pid, @ptrCast(*c_int, status), @bitCast(c_int, options)));
-}
-
-pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
- return errnoWrap(c.nanosleep(req, rem));
-}
-
-pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
- return errnoWrap(c.clock_gettime(clk_id, tp));
-}
-
-pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
- return errnoWrap(c.clock_getres(clk_id, tp));
-}
-
-pub fn setuid(uid: u32) usize {
- return errnoWrap(c.setuid(uid));
-}
-
-pub fn setgid(gid: u32) usize {
- return errnoWrap(c.setgid(gid));
-}
-
-pub fn setreuid(ruid: u32, euid: u32) usize {
- return errnoWrap(c.setreuid(ruid, euid));
-}
-
-pub fn setregid(rgid: u32, egid: u32) usize {
- return errnoWrap(c.setregid(rgid, egid));
-}
-
-const NSIG = 32;
-
-pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
-pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
-pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
-
-/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
-pub const Sigaction = extern struct {
- /// signal handler
- __sigaction_u: extern union {
- __sa_handler: extern fn (i32) void,
- __sa_sigaction: extern fn (i32, *__siginfo, usize) void,
- },
-
- /// see signal options
- sa_flags: u32,
-
- /// signal mask to apply
- sa_mask: sigset_t,
-};
-
-pub const _SIG_WORDS = 4;
-pub const _SIG_MAXSIG = 128;
-
-pub inline fn _SIG_IDX(sig: usize) usize {
- return sig - 1;
-}
-pub inline fn _SIG_WORD(sig: usize) usize {
- return_SIG_IDX(sig) >> 5;
-}
-pub inline fn _SIG_BIT(sig: usize) usize {
- return 1 << (_SIG_IDX(sig) & 31);
-}
-pub inline fn _SIG_VALID(sig: usize) usize {
- return sig <= _SIG_MAXSIG and sig > 0;
-}
-
-pub const sigset_t = extern struct {
- __bits: [_SIG_WORDS]u32,
-};
-
-pub fn raise(sig: i32) usize {
- return errnoWrap(c.raise(sig));
-}
-
-pub const Stat = c.Stat;
-pub const dirent = c.dirent;
-pub const timespec = c.timespec;
-
-pub fn fstat(fd: i32, buf: *c.Stat) usize {
- return errnoWrap(c.fstat(fd, buf));
-}
-pub const iovec = extern struct {
- iov_base: [*]u8,
- iov_len: usize,
-};
-
-pub const iovec_const = extern struct {
- iov_base: [*]const u8,
- iov_len: usize,
-};
-
-// TODO avoid libc dependency
-pub fn kqueue() usize {
- return errnoWrap(c.kqueue());
-}
-
-// TODO avoid libc dependency
-pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize {
- return errnoWrap(c.kevent(
- kq,
- changelist.ptr,
- @intCast(c_int, changelist.len),
- eventlist.ptr,
- @intCast(c_int, eventlist.len),
- timeout,
- ));
-}
-
-// TODO avoid libc dependency
-pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
- return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen));
-}
-
-// TODO avoid libc dependency
-pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
- return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen));
-}
-
-// TODO avoid libc dependency
-pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize {
- return errnoWrap(c.sysctlnametomib(name, wibp, sizep));
-}
-
-// TODO avoid libc dependency
-
-/// Takes the return value from a syscall and formats it back in the way
-/// that the kernel represents it to libc. Errno was a mistake, let's make
-/// it go away forever.
-fn errnoWrap(value: isize) usize {
- return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
-}
+pub const is_the_target = builtin.os == .netbsd;
+pub use std.c;
diff --git a/std/os/netbsd/errno.zig b/std/os/netbsd/errno.zig
deleted file mode 100644
index 1772c2ab07..0000000000
--- a/std/os/netbsd/errno.zig
+++ /dev/null
@@ -1,134 +0,0 @@
-pub const EPERM = 1; // Operation not permitted
-pub const ENOENT = 2; // No such file or directory
-pub const ESRCH = 3; // No such process
-pub const EINTR = 4; // Interrupted system call
-pub const EIO = 5; // Input/output error
-pub const ENXIO = 6; // Device not configured
-pub const E2BIG = 7; // Argument list too long
-pub const ENOEXEC = 8; // Exec format error
-pub const EBADF = 9; // Bad file descriptor
-pub const ECHILD = 10; // No child processes
-pub const EDEADLK = 11; // Resource deadlock avoided
-// 11 was EAGAIN
-pub const ENOMEM = 12; // Cannot allocate memory
-pub const EACCES = 13; // Permission denied
-pub const EFAULT = 14; // Bad address
-pub const ENOTBLK = 15; // Block device required
-pub const EBUSY = 16; // Device busy
-pub const EEXIST = 17; // File exists
-pub const EXDEV = 18; // Cross-device link
-pub const ENODEV = 19; // Operation not supported by device
-pub const ENOTDIR = 20; // Not a directory
-pub const EISDIR = 21; // Is a directory
-pub const EINVAL = 22; // Invalid argument
-pub const ENFILE = 23; // Too many open files in system
-pub const EMFILE = 24; // Too many open files
-pub const ENOTTY = 25; // Inappropriate ioctl for device
-pub const ETXTBSY = 26; // Text file busy
-pub const EFBIG = 27; // File too large
-pub const ENOSPC = 28; // No space left on device
-pub const ESPIPE = 29; // Illegal seek
-pub const EROFS = 30; // Read-only file system
-pub const EMLINK = 31; // Too many links
-pub const EPIPE = 32; // Broken pipe
-
-// math software
-pub const EDOM = 33; // Numerical argument out of domain
-pub const ERANGE = 34; // Result too large or too small
-
-// non-blocking and interrupt i/o
-pub const EAGAIN = 35; // Resource temporarily unavailable
-pub const EWOULDBLOCK = EAGAIN; // Operation would block
-pub const EINPROGRESS = 36; // Operation now in progress
-pub const EALREADY = 37; // Operation already in progress
-
-// ipc/network software -- argument errors
-pub const ENOTSOCK = 38; // Socket operation on non-socket
-pub const EDESTADDRREQ = 39; // Destination address required
-pub const EMSGSIZE = 40; // Message too long
-pub const EPROTOTYPE = 41; // Protocol wrong type for socket
-pub const ENOPROTOOPT = 42; // Protocol option not available
-pub const EPROTONOSUPPORT = 43; // Protocol not supported
-pub const ESOCKTNOSUPPORT = 44; // Socket type not supported
-pub const EOPNOTSUPP = 45; // Operation not supported
-pub const EPFNOSUPPORT = 46; // Protocol family not supported
-pub const EAFNOSUPPORT = 47; // Address family not supported by protocol family
-pub const EADDRINUSE = 48; // Address already in use
-pub const EADDRNOTAVAIL = 49; // Can't assign requested address
-
-// ipc/network software -- operational errors
-pub const ENETDOWN = 50; // Network is down
-pub const ENETUNREACH = 51; // Network is unreachable
-pub const ENETRESET = 52; // Network dropped connection on reset
-pub const ECONNABORTED = 53; // Software caused connection abort
-pub const ECONNRESET = 54; // Connection reset by peer
-pub const ENOBUFS = 55; // No buffer space available
-pub const EISCONN = 56; // Socket is already connected
-pub const ENOTCONN = 57; // Socket is not connected
-pub const ESHUTDOWN = 58; // Can't send after socket shutdown
-pub const ETOOMANYREFS = 59; // Too many references: can't splice
-pub const ETIMEDOUT = 60; // Operation timed out
-pub const ECONNREFUSED = 61; // Connection refused
-
-pub const ELOOP = 62; // Too many levels of symbolic links
-pub const ENAMETOOLONG = 63; // File name too long
-
-// should be rearranged
-pub const EHOSTDOWN = 64; // Host is down
-pub const EHOSTUNREACH = 65; // No route to host
-pub const ENOTEMPTY = 66; // Directory not empty
-
-// quotas & mush
-pub const EPROCLIM = 67; // Too many processes
-pub const EUSERS = 68; // Too many users
-pub const EDQUOT = 69; // Disc quota exceeded
-
-// Network File System
-pub const ESTALE = 70; // Stale NFS file handle
-pub const EREMOTE = 71; // Too many levels of remote in path
-pub const EBADRPC = 72; // RPC struct is bad
-pub const ERPCMISMATCH = 73; // RPC version wrong
-pub const EPROGUNAVAIL = 74; // RPC prog. not avail
-pub const EPROGMISMATCH = 75; // Program version wrong
-pub const EPROCUNAVAIL = 76; // Bad procedure for program
-
-pub const ENOLCK = 77; // No locks available
-pub const ENOSYS = 78; // Function not implemented
-
-pub const EFTYPE = 79; // Inappropriate file type or format
-pub const EAUTH = 80; // Authentication error
-pub const ENEEDAUTH = 81; // Need authenticator
-
-// SystemV IPC
-pub const EIDRM = 82; // Identifier removed
-pub const ENOMSG = 83; // No message of desired type
-pub const EOVERFLOW = 84; // Value too large to be stored in data type
-
-// Wide/multibyte-character handling, ISO/IEC 9899/AMD1:1995
-pub const EILSEQ = 85; // Illegal byte sequence
-
-// From IEEE Std 1003.1-2001
-// Base, Realtime, Threads or Thread Priority Scheduling option errors
-pub const ENOTSUP = 86; // Not supported
-
-// Realtime option errors
-pub const ECANCELED = 87; // Operation canceled
-
-// Realtime, XSI STREAMS option errors
-pub const EBADMSG = 88; // Bad or Corrupt message
-
-// XSI STREAMS option errors
-pub const ENODATA = 89; // No message available
-pub const ENOSR = 90; // No STREAM resources
-pub const ENOSTR = 91; // Not a STREAM
-pub const ETIME = 92; // STREAM ioctl timeout
-
-// File system extended attribute errors
-pub const ENOATTR = 93; // Attribute not found
-
-// Realtime, XSI STREAMS option errors
-pub const EMULTIHOP = 94; // Multihop attempted
-pub const ENOLINK = 95; // Link has been severed
-pub const EPROTO = 96; // Protocol error
-
-pub const ELAST = 96; // Must equal largest errno
diff --git a/std/os/test.zig b/std/os/test.zig
index 0ee6fc1f26..d4d662e97f 100644
--- a/std/os/test.zig
+++ b/std/os/test.zig
@@ -1,8 +1,12 @@
const std = @import("../std.zig");
const os = std.os;
+const testing = std.testing;
const expect = std.testing.expect;
const io = std.io;
+const fs = std.fs;
const mem = std.mem;
+const File = std.fs.File;
+const Thread = std.Thread;
const a = std.debug.global_allocator;
@@ -11,11 +15,11 @@ const AtomicRmwOp = builtin.AtomicRmwOp;
const AtomicOrder = builtin.AtomicOrder;
test "makePath, put some files in it, deleteTree" {
- try os.makePath(a, "os_test_tmp" ++ os.path.sep_str ++ "b" ++ os.path.sep_str ++ "c");
- try io.writeFile("os_test_tmp" ++ os.path.sep_str ++ "b" ++ os.path.sep_str ++ "c" ++ os.path.sep_str ++ "file.txt", "nonsense");
- try io.writeFile("os_test_tmp" ++ os.path.sep_str ++ "b" ++ os.path.sep_str ++ "file2.txt", "blah");
- try os.deleteTree(a, "os_test_tmp");
- if (os.Dir.open(a, "os_test_tmp")) |dir| {
+ try fs.makePath(a, "os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c");
+ try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c" ++ fs.path.sep_str ++ "file.txt", "nonsense");
+ try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "file2.txt", "blah");
+ try fs.deleteTree(a, "os_test_tmp");
+ if (fs.Dir.open(a, "os_test_tmp")) |dir| {
@panic("expected error");
} else |err| {
expect(err == error.FileNotFound);
@@ -23,40 +27,37 @@ test "makePath, put some files in it, deleteTree" {
}
test "access file" {
- try os.makePath(a, "os_test_tmp");
- if (os.File.access("os_test_tmp" ++ os.path.sep_str ++ "file.txt")) |ok| {
+ try fs.makePath(a, "os_test_tmp");
+ if (File.access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt")) |ok| {
@panic("expected error");
} else |err| {
expect(err == error.FileNotFound);
}
- try io.writeFile("os_test_tmp" ++ os.path.sep_str ++ "file.txt", "");
- try os.File.access("os_test_tmp" ++ os.path.sep_str ++ "file.txt");
- try os.deleteTree(a, "os_test_tmp");
+ try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", "");
+ try os.access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", os.F_OK);
+ try fs.deleteTree(a, "os_test_tmp");
}
-fn testThreadIdFn(thread_id: *os.Thread.Id) void {
- thread_id.* = os.Thread.getCurrentId();
+fn testThreadIdFn(thread_id: *Thread.Id) void {
+ thread_id.* = Thread.getCurrentId();
}
-test "std.os.Thread.getCurrentId" {
+test "std.Thread.getCurrentId" {
if (builtin.single_threaded) return error.SkipZigTest;
- var thread_current_id: os.Thread.Id = undefined;
- const thread = try os.spawnThread(&thread_current_id, testThreadIdFn);
+ var thread_current_id: Thread.Id = undefined;
+ const thread = try Thread.spawn(&thread_current_id, testThreadIdFn);
const thread_id = thread.handle();
thread.wait();
- if (os.Thread.use_pthreads) {
+ if (Thread.use_pthreads) {
expect(thread_current_id == thread_id);
+ } else if (os.windows.is_the_target) {
+ expect(Thread.getCurrentId() != thread_current_id);
} else {
- switch (builtin.os) {
- builtin.Os.windows => expect(os.Thread.getCurrentId() != thread_current_id),
- else => {
- // If the thread completes very quickly, then thread_id can be 0. See the
- // documentation comments for `std.os.Thread.handle`.
- expect(thread_id == 0 or thread_current_id == thread_id);
- },
- }
+ // If the thread completes very quickly, then thread_id can be 0. See the
+ // documentation comments for `std.Thread.handle`.
+ expect(thread_id == 0 or thread_current_id == thread_id);
}
}
@@ -65,10 +66,10 @@ test "spawn threads" {
var shared_ctx: i32 = 1;
- const thread1 = try std.os.spawnThread({}, start1);
- const thread2 = try std.os.spawnThread(&shared_ctx, start2);
- const thread3 = try std.os.spawnThread(&shared_ctx, start2);
- const thread4 = try std.os.spawnThread(&shared_ctx, start2);
+ const thread1 = try Thread.spawn({}, start1);
+ const thread2 = try Thread.spawn(&shared_ctx, start2);
+ const thread3 = try Thread.spawn(&shared_ctx, start2);
+ const thread4 = try Thread.spawn(&shared_ctx, start2);
thread1.wait();
thread2.wait();
@@ -88,7 +89,7 @@ fn start2(ctx: *i32) u8 {
}
test "cpu count" {
- const cpu_count = try std.os.cpuCount(a);
+ const cpu_count = try Thread.cpuCount();
expect(cpu_count >= 1);
}
@@ -101,7 +102,7 @@ test "AtomicFile" {
\\ this is a test file
;
{
- var af = try os.AtomicFile.init(test_out_file, os.File.default_mode);
+ var af = try fs.AtomicFile.init(test_out_file, File.default_mode);
defer af.deinit();
try af.file.write(test_content);
try af.finish();
@@ -109,13 +110,13 @@ test "AtomicFile" {
const content = try io.readFileAlloc(allocator, test_out_file);
expect(mem.eql(u8, content, test_content));
- try os.deleteFile(test_out_file);
+ try fs.deleteFile(test_out_file);
}
test "thread local storage" {
if (builtin.single_threaded) return error.SkipZigTest;
- const thread1 = try std.os.spawnThread({}, testTls);
- const thread2 = try std.os.spawnThread({}, testTls);
+ const thread1 = try Thread.spawn({}, testTls);
+ const thread2 = try Thread.spawn({}, testTls);
testTls({});
thread1.wait();
thread2.wait();
@@ -127,3 +128,24 @@ fn testTls(context: void) void {
x += 1;
if (x != 1235) @panic("bad end value");
}
+
+test "getrandom" {
+ var buf_a: [50]u8 = undefined;
+ var buf_b: [50]u8 = undefined;
+ try os.getrandom(&buf_a);
+ try os.getrandom(&buf_b);
+ // If this test fails the chance is significantly higher that there is a bug than
+ // that two sets of 50 bytes were equal.
+ expect(!mem.eql(u8, buf_a, buf_b));
+}
+
+test "getcwd" {
+ // at least call it so it gets compiled
+ var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+ _ = os.getcwd(&buf) catch undefined;
+}
+
+test "realpath" {
+ var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+ testing.expectError(error.FileNotFound, fs.realpath("definitely_bogus_does_not_exist1234", &buf));
+}
diff --git a/std/os/time.zig b/std/os/time.zig
deleted file mode 100644
index abb6412843..0000000000
--- a/std/os/time.zig
+++ /dev/null
@@ -1,307 +0,0 @@
-const std = @import("../std.zig");
-const builtin = @import("builtin");
-const Os = builtin.Os;
-const debug = std.debug;
-const testing = std.testing;
-const math = std.math;
-
-const windows = std.os.windows;
-const linux = std.os.linux;
-const darwin = std.os.darwin;
-const wasi = std.os.wasi;
-const posix = std.os.posix;
-
-pub const epoch = @import("epoch.zig");
-
-/// Spurious wakeups are possible and no precision of timing is guaranteed.
-pub fn sleep(nanoseconds: u64) void {
- switch (builtin.os) {
- Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
- const s = nanoseconds / ns_per_s;
- const ns = nanoseconds % ns_per_s;
- posixSleep(s, ns);
- },
- Os.windows => {
- const ns_per_ms = ns_per_s / ms_per_s;
- const milliseconds = nanoseconds / ns_per_ms;
- const ms_that_will_fit = std.math.cast(windows.DWORD, milliseconds) catch std.math.maxInt(windows.DWORD);
- windows.Sleep(ms_that_will_fit);
- },
- else => @compileError("Unsupported OS"),
- }
-}
-
-/// Spurious wakeups are possible and no precision of timing is guaranteed.
-pub fn posixSleep(seconds: u64, nanoseconds: u64) void {
- var req = posix.timespec{
- .tv_sec = std.math.cast(isize, seconds) catch std.math.maxInt(isize),
- .tv_nsec = std.math.cast(isize, nanoseconds) catch std.math.maxInt(isize),
- };
- var rem: posix.timespec = undefined;
- while (true) {
- const ret_val = posix.nanosleep(&req, &rem);
- const err = posix.getErrno(ret_val);
- switch (err) {
- posix.EFAULT => unreachable,
- posix.EINVAL => {
- // Sometimes Darwin returns EINVAL for no reason.
- // We treat it as a spurious wakeup.
- return;
- },
- posix.EINTR => {
- req = rem;
- continue;
- },
- // This prong handles success as well as unexpected errors.
- else => return,
- }
- }
-}
-
-/// Get the posix timestamp, UTC, in seconds
-pub fn timestamp() u64 {
- return @divFloor(milliTimestamp(), ms_per_s);
-}
-
-/// Get the posix timestamp, UTC, in milliseconds
-pub const milliTimestamp = switch (builtin.os) {
- Os.windows => milliTimestampWindows,
- Os.linux, Os.freebsd, Os.netbsd => milliTimestampPosix,
- Os.macosx, Os.ios => milliTimestampDarwin,
- Os.wasi => milliTimestampWasi,
- else => @compileError("Unsupported OS"),
-};
-
-fn milliTimestampWasi() u64 {
- var ns: wasi.timestamp_t = undefined;
-
- // TODO: Verify that precision is ignored
- const err = wasi.clock_time_get(wasi.CLOCK_REALTIME, 1, &ns);
- debug.assert(err == wasi.ESUCCESS);
-
- const ns_per_ms = 1000;
- return @divFloor(ns, ns_per_ms);
-}
-
-fn milliTimestampWindows() u64 {
- //FileTime has a granularity of 100 nanoseconds
- // and uses the NTFS/Windows epoch
- var ft: windows.FILETIME = undefined;
- windows.GetSystemTimeAsFileTime(&ft);
- const hns_per_ms = (ns_per_s / 100) / ms_per_s;
- const epoch_adj = epoch.windows * ms_per_s;
-
- const ft64 = (u64(ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
- return @divFloor(ft64, hns_per_ms) - -epoch_adj;
-}
-
-fn milliTimestampDarwin() u64 {
- var tv: darwin.timeval = undefined;
- var err = darwin.gettimeofday(&tv, null);
- debug.assert(err == 0);
- const sec_ms = tv.tv_sec * ms_per_s;
- const usec_ms = @divFloor(tv.tv_usec, us_per_s / ms_per_s);
- return @intCast(u64, sec_ms + usec_ms);
-}
-
-fn milliTimestampPosix() u64 {
- //From what I can tell there's no reason clock_gettime
- // should ever fail for us with CLOCK_REALTIME,
- // seccomp aside.
- var ts: posix.timespec = undefined;
- const err = posix.clock_gettime(posix.CLOCK_REALTIME, &ts);
- debug.assert(err == 0);
- const sec_ms = @intCast(u64, ts.tv_sec) * ms_per_s;
- const nsec_ms = @divFloor(@intCast(u64, ts.tv_nsec), ns_per_s / ms_per_s);
- return sec_ms + nsec_ms;
-}
-
-/// Multiples of a base unit (nanoseconds)
-pub const nanosecond = 1;
-pub const microsecond = 1000 * nanosecond;
-pub const millisecond = 1000 * microsecond;
-pub const second = 1000 * millisecond;
-pub const minute = 60 * second;
-pub const hour = 60 * minute;
-
-/// Divisions of a second
-pub const ns_per_s = 1000000000;
-pub const us_per_s = 1000000;
-pub const ms_per_s = 1000;
-pub const cs_per_s = 100;
-
-/// Common time divisions
-pub const s_per_min = 60;
-pub const s_per_hour = s_per_min * 60;
-pub const s_per_day = s_per_hour * 24;
-pub const s_per_week = s_per_day * 7;
-
-/// A monotonic high-performance timer.
-/// Timer.start() must be called to initialize the struct, which captures
-/// the counter frequency on windows and darwin, records the resolution,
-/// and gives the user an opportunity to check for the existnece of
-/// monotonic clocks without forcing them to check for error on each read.
-/// .resolution is in nanoseconds on all platforms but .start_time's meaning
-/// depends on the OS. On Windows and Darwin it is a hardware counter
-/// value that requires calculation to convert to a meaninful unit.
-pub const Timer = struct {
-
- //if we used resolution's value when performing the
- // performance counter calc on windows/darwin, it would
- // be less precise
- frequency: switch (builtin.os) {
- Os.windows => u64,
- Os.macosx, Os.ios => darwin.mach_timebase_info_data,
- else => void,
- },
- resolution: u64,
- start_time: u64,
-
- //At some point we may change our minds on RAW, but for now we're
- // sticking with posix standard MONOTONIC. For more information, see:
- // https://github.com/ziglang/zig/pull/933
- //
- //const monotonic_clock_id = switch(builtin.os) {
- // Os.linux => linux.CLOCK_MONOTONIC_RAW,
- // else => posix.CLOCK_MONOTONIC,
- //};
- const monotonic_clock_id = posix.CLOCK_MONOTONIC;
- /// Initialize the timer structure.
- //This gives us an opportunity to grab the counter frequency in windows.
- //On Windows: QueryPerformanceCounter will succeed on anything >= XP/2000.
- //On Posix: CLOCK_MONOTONIC will only fail if the monotonic counter is not
- // supported, or if the timespec pointer is out of bounds, which should be
- // impossible here barring cosmic rays or other such occurrences of
- // incredibly bad luck.
- //On Darwin: This cannot fail, as far as I am able to tell.
- const TimerError = error{
- TimerUnsupported,
- Unexpected,
- };
- pub fn start() TimerError!Timer {
- var self: Timer = undefined;
-
- switch (builtin.os) {
- Os.windows => {
- var freq: i64 = undefined;
- var err = windows.QueryPerformanceFrequency(&freq);
- if (err == windows.FALSE) return error.TimerUnsupported;
- self.frequency = @intCast(u64, freq);
- self.resolution = @divFloor(ns_per_s, self.frequency);
-
- var start_time: i64 = undefined;
- err = windows.QueryPerformanceCounter(&start_time);
- debug.assert(err != windows.FALSE);
- self.start_time = @intCast(u64, start_time);
- },
- Os.linux, Os.freebsd, Os.netbsd => {
- //On Linux, seccomp can do arbitrary things to our ability to call
- // syscalls, including return any errno value it wants and
- // inconsistently throwing errors. Since we can't account for
- // abuses of seccomp in a reasonable way, we'll assume that if
- // seccomp is going to block us it will at least do so consistently
- var ts: posix.timespec = undefined;
- var result = posix.clock_getres(monotonic_clock_id, &ts);
- var errno = posix.getErrno(result);
- switch (errno) {
- 0 => {},
- posix.EINVAL => return error.TimerUnsupported,
- else => return std.os.unexpectedErrorPosix(errno),
- }
- self.resolution = @intCast(u64, ts.tv_sec) * u64(ns_per_s) + @intCast(u64, ts.tv_nsec);
-
- result = posix.clock_gettime(monotonic_clock_id, &ts);
- errno = posix.getErrno(result);
- if (errno != 0) return std.os.unexpectedErrorPosix(errno);
- self.start_time = @intCast(u64, ts.tv_sec) * u64(ns_per_s) + @intCast(u64, ts.tv_nsec);
- },
- Os.macosx, Os.ios => {
- darwin.mach_timebase_info(&self.frequency);
- self.resolution = @divFloor(self.frequency.numer, self.frequency.denom);
- self.start_time = darwin.mach_absolute_time();
- },
- else => @compileError("Unsupported OS"),
- }
- return self;
- }
-
- /// Reads the timer value since start or the last reset in nanoseconds
- pub fn read(self: *Timer) u64 {
- var clock = clockNative() - self.start_time;
- return switch (builtin.os) {
- Os.windows => @divFloor(clock * ns_per_s, self.frequency),
- Os.linux, Os.freebsd, Os.netbsd => clock,
- Os.macosx, Os.ios => @divFloor(clock * self.frequency.numer, self.frequency.denom),
- else => @compileError("Unsupported OS"),
- };
- }
-
- /// Resets the timer value to 0/now.
- pub fn reset(self: *Timer) void {
- self.start_time = clockNative();
- }
-
- /// Returns the current value of the timer in nanoseconds, then resets it
- pub fn lap(self: *Timer) u64 {
- var now = clockNative();
- var lap_time = self.read();
- self.start_time = now;
- return lap_time;
- }
-
- const clockNative = switch (builtin.os) {
- Os.windows => clockWindows,
- Os.linux, Os.freebsd, Os.netbsd => clockLinux,
- Os.macosx, Os.ios => clockDarwin,
- else => @compileError("Unsupported OS"),
- };
-
- fn clockWindows() u64 {
- var result: i64 = undefined;
- var err = windows.QueryPerformanceCounter(&result);
- debug.assert(err != windows.FALSE);
- return @intCast(u64, result);
- }
-
- fn clockDarwin() u64 {
- return darwin.mach_absolute_time();
- }
-
- fn clockLinux() u64 {
- var ts: posix.timespec = undefined;
- var result = posix.clock_gettime(monotonic_clock_id, &ts);
- debug.assert(posix.getErrno(result) == 0);
- return @intCast(u64, ts.tv_sec) * u64(ns_per_s) + @intCast(u64, ts.tv_nsec);
- }
-};
-
-test "os.time.sleep" {
- sleep(1);
-}
-
-test "os.time.timestamp" {
- const ns_per_ms = (ns_per_s / ms_per_s);
- const margin = 50;
-
- const time_0 = milliTimestamp();
- sleep(ns_per_ms);
- const time_1 = milliTimestamp();
- const interval = time_1 - time_0;
- testing.expect(interval > 0 and interval < margin);
-}
-
-test "os.time.Timer" {
- const ns_per_ms = (ns_per_s / ms_per_s);
- const margin = ns_per_ms * 150;
-
- var timer = try Timer.start();
- sleep(10 * ns_per_ms);
- const time_0 = timer.read();
- testing.expect(time_0 > 0 and time_0 < margin);
-
- const time_1 = timer.lap();
- testing.expect(time_1 >= time_0);
-
- timer.reset();
- testing.expect(timer.read() < time_1);
-}
diff --git a/std/os/wasi.zig b/std/os/wasi.zig
index 2118db9a2a..adfe9e821d 100644
--- a/std/os/wasi.zig
+++ b/std/os/wasi.zig
@@ -1,42 +1,80 @@
-pub use @import("wasi/core.zig");
+// Based on https://github.com/CraneStation/wasi-sysroot/blob/wasi/libc-bottom-half/headers/public/wasi/core.h
+// and https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md
+const builtin = @import("builtin");
+const std = @import("std");
+const assert = std.debug.assert;
-pub const STDIN_FILENO = 0;
-pub const STDOUT_FILENO = 1;
-pub const STDERR_FILENO = 2;
+pub const is_the_target = builtin.os == .wasi;
+pub use @import("bits.zig");
-pub fn getErrno(r: usize) usize {
- const signed_r = @bitCast(isize, r);
- return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
+comptime {
+ assert(@alignOf(i8) == 1);
+ assert(@alignOf(u8) == 1);
+ assert(@alignOf(i16) == 2);
+ assert(@alignOf(u16) == 2);
+ assert(@alignOf(i32) == 4);
+ assert(@alignOf(u32) == 4);
+ assert(@alignOf(i64) == 8);
+ assert(@alignOf(u64) == 8);
}
-pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
- var nwritten: usize = undefined;
+pub const iovec_t = iovec;
+pub const ciovec_t = iovec_const;
- const ciovs = ciovec_t{
- .buf = buf,
- .buf_len = count,
- };
+pub extern "wasi_unstable" fn args_get(argv: [*][*]u8, argv_buf: [*]u8) errno_t;
+pub extern "wasi_unstable" fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t;
- const err = fd_write(@bitCast(fd_t, isize(fd)), &ciovs, 1, &nwritten);
- if (err == ESUCCESS) {
- return nwritten;
- } else {
- return @bitCast(usize, -isize(err));
- }
-}
+pub extern "wasi_unstable" fn clock_res_get(clock_id: clockid_t, resolution: *timestamp_t) errno_t;
+pub extern "wasi_unstable" fn clock_time_get(clock_id: clockid_t, precision: timestamp_t, timestamp: *timestamp_t) errno_t;
-pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
- var nread: usize = undefined;
+pub extern "wasi_unstable" fn environ_get(environ: [*]?[*]u8, environ_buf: [*]u8) errno_t;
+pub extern "wasi_unstable" fn environ_sizes_get(environ_count: *usize, environ_buf_size: *usize) errno_t;
- const iovs = iovec_t{
- .buf = buf,
- .buf_len = nbyte,
- };
+pub extern "wasi_unstable" fn fd_advise(fd: fd_t, offset: filesize_t, len: filesize_t, advice: advice_t) errno_t;
+pub extern "wasi_unstable" fn fd_allocate(fd: fd_t, offset: filesize_t, len: filesize_t) errno_t;
+pub extern "wasi_unstable" fn fd_close(fd: fd_t) errno_t;
+pub extern "wasi_unstable" fn fd_datasync(fd: fd_t) errno_t;
+pub extern "wasi_unstable" fn fd_pread(fd: fd_t, iovs: [*]const iovec_t, iovs_len: usize, offset: filesize_t, nread: *usize) errno_t;
+pub extern "wasi_unstable" fn fd_pwrite(fd: fd_t, iovs: [*]const ciovec_t, iovs_len: usize, offset: filesize_t, nwritten: *usize) errno_t;
+pub extern "wasi_unstable" fn fd_read(fd: fd_t, iovs: [*]const iovec_t, iovs_len: usize, nread: *usize) errno_t;
+pub extern "wasi_unstable" fn fd_readdir(fd: fd_t, buf: [*]u8, buf_len: usize, cookie: dircookie_t, bufused: *usize) errno_t;
+pub extern "wasi_unstable" fn fd_renumber(from: fd_t, to: fd_t) errno_t;
+pub extern "wasi_unstable" fn fd_seek(fd: fd_t, offset: filedelta_t, whence: whence_t, newoffset: *filesize_t) errno_t;
+pub extern "wasi_unstable" fn fd_sync(fd: fd_t) errno_t;
+pub extern "wasi_unstable" fn fd_tell(fd: fd_t, newoffset: *filesize_t) errno_t;
+pub extern "wasi_unstable" fn fd_write(fd: fd_t, iovs: [*]const ciovec_t, iovs_len: usize, nwritten: *usize) errno_t;
- const err = fd_read(@bitCast(fd_t, isize(fd)), &iovs, 1, &nread);
- if (err == ESUCCESS) {
- return nread;
- } else {
- return @bitCast(usize, -isize(err));
- }
-}
+pub extern "wasi_unstable" fn fd_fdstat_get(fd: fd_t, buf: *fdstat_t) errno_t;
+pub extern "wasi_unstable" fn fd_fdstat_set_flags(fd: fd_t, flags: fdflags_t) errno_t;
+pub extern "wasi_unstable" fn fd_fdstat_set_rights(fd: fd_t, fs_rights_base: rights_t, fs_rights_inheriting: rights_t) errno_t;
+
+pub extern "wasi_unstable" fn fd_filestat_get(fd: fd_t, buf: *filestat_t) errno_t;
+pub extern "wasi_unstable" fn fd_filestat_set_size(fd: fd_t, st_size: filesize_t) errno_t;
+pub extern "wasi_unstable" fn fd_filestat_set_times(fd: fd_t, st_atim: timestamp_t, st_mtim: timestamp_t, fstflags: fstflags_t) errno_t;
+
+pub extern "wasi_unstable" fn fd_prestat_get(fd: fd_t, buf: *prestat_t) errno_t;
+pub extern "wasi_unstable" fn fd_prestat_dir_name(fd: fd_t, path: [*]u8, path_len: usize) errno_t;
+
+pub extern "wasi_unstable" fn path_create_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
+pub extern "wasi_unstable" fn path_filestat_get(fd: fd_t, flags: lookupflags_t, path: [*]const u8, path_len: usize, buf: *filestat_t) errno_t;
+pub extern "wasi_unstable" fn path_filestat_set_times(fd: fd_t, flags: lookupflags_t, path: [*]const u8, path_len: usize, st_atim: timestamp_t, st_mtim: timestamp_t, fstflags: fstflags_t) errno_t;
+pub extern "wasi_unstable" fn path_link(old_fd: fd_t, old_flags: lookupflags_t, old_path: [*]const u8, old_path_len: usize, new_fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t;
+pub extern "wasi_unstable" fn path_open(dirfd: fd_t, dirflags: lookupflags_t, path: [*]const u8, path_len: usize, oflags: oflags_t, fs_rights_base: rights_t, fs_rights_inheriting: rights_t, fs_flags: fdflags_t, fd: *fd_t) errno_t;
+pub extern "wasi_unstable" fn path_readlink(fd: fd_t, path: [*]const u8, path_len: usize, buf: [*]u8, buf_len: usize, bufused: *usize) errno_t;
+pub extern "wasi_unstable" fn path_remove_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
+pub extern "wasi_unstable" fn path_rename(old_fd: fd_t, old_path: [*]const u8, old_path_len: usize, new_fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t;
+pub extern "wasi_unstable" fn path_symlink(old_path: [*]const u8, old_path_len: usize, fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t;
+pub extern "wasi_unstable" fn path_unlink_file(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
+
+pub extern "wasi_unstable" fn poll_oneoff(in: *const subscription_t, out: *event_t, nsubscriptions: usize, nevents: *usize) errno_t;
+
+pub extern "wasi_unstable" fn proc_exit(rval: exitcode_t) noreturn;
+pub extern "wasi_unstable" fn proc_raise(sig: signal_t) errno_t;
+
+pub extern "wasi_unstable" fn random_get(buf: [*]u8, buf_len: usize) errno_t;
+
+pub extern "wasi_unstable" fn sched_yield() errno_t;
+
+pub extern "wasi_unstable" fn sock_recv(sock: fd_t, ri_data: *const iovec_t, ri_data_len: usize, ri_flags: riflags_t, ro_datalen: *usize, ro_flags: *roflags_t) errno_t;
+pub extern "wasi_unstable" 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_unstable" fn sock_shutdown(sock: fd_t, how: sdflags_t) errno_t;
diff --git a/std/os/windows.zig b/std/os/windows.zig
index e134d87eae..526ac1cfd6 100644
--- a/std/os/windows.zig
+++ b/std/os/windows.zig
@@ -1,430 +1,767 @@
+// This file contains thin wrappers around Windows-specific APIs, with these
+// specific goals in mind:
+// * Convert "errno"-style error codes into Zig errors.
+// * When null-terminated or UTF16LE byte buffers are required, provide APIs which accept
+// slices as well as APIs which accept null-terminated UTF16LE byte buffers.
+
+const builtin = @import("builtin");
const std = @import("../std.zig");
+const mem = std.mem;
const assert = std.debug.assert;
+const math = std.math;
const maxInt = std.math.maxInt;
-pub use @import("windows/advapi32.zig");
-pub use @import("windows/kernel32.zig");
-pub use @import("windows/ntdll.zig");
-pub use @import("windows/ole32.zig");
-pub use @import("windows/shell32.zig");
-
-test "import" {
- _ = @import("windows/util.zig");
-}
-
-pub const ERROR = @import("windows/error.zig");
-
-pub const SHORT = c_short;
-pub const BOOL = c_int;
-pub const BOOLEAN = BYTE;
-pub const BYTE = u8;
-pub const CHAR = u8;
-pub const DWORD = u32;
-pub const FLOAT = f32;
-pub const HANDLE = *c_void;
-pub const HCRYPTPROV = ULONG_PTR;
-pub const HINSTANCE = *@OpaqueType();
-pub const HMODULE = *@OpaqueType();
-pub const FARPROC = *@OpaqueType();
-pub const INT = c_int;
-pub const LPBYTE = *BYTE;
-pub const LPCH = *CHAR;
-pub const LPCSTR = [*]const CHAR;
-pub const LPCTSTR = [*]const TCHAR;
-pub const LPCVOID = *const c_void;
-pub const LPDWORD = *DWORD;
-pub const LPSTR = [*]CHAR;
-pub const LPTSTR = if (UNICODE) LPWSTR else LPSTR;
-pub const LPVOID = *c_void;
-pub const LPWSTR = [*]WCHAR;
-pub const LPCWSTR = [*]const WCHAR;
-pub const PVOID = *c_void;
-pub const PWSTR = [*]WCHAR;
-pub const SIZE_T = usize;
-pub const TCHAR = if (UNICODE) WCHAR else u8;
-pub const UINT = c_uint;
-pub const ULONG_PTR = usize;
-pub const DWORD_PTR = ULONG_PTR;
-pub const UNICODE = false;
-pub const WCHAR = u16;
-pub const WORD = u16;
-pub const LARGE_INTEGER = i64;
-pub const ULONG = u32;
-pub const LONG = i32;
-pub const ULONGLONG = u64;
-pub const LONGLONG = i64;
-
-pub const TRUE = 1;
-pub const FALSE = 0;
-
-/// The standard input device. Initially, this is the console input buffer, CONIN$.
-pub const STD_INPUT_HANDLE = maxInt(DWORD) - 10 + 1;
-
-/// The standard output device. Initially, this is the active console screen buffer, CONOUT$.
-pub const STD_OUTPUT_HANDLE = maxInt(DWORD) - 11 + 1;
-
-/// The standard error device. Initially, this is the active console screen buffer, CONOUT$.
-pub const STD_ERROR_HANDLE = maxInt(DWORD) - 12 + 1;
-
-pub const INVALID_HANDLE_VALUE = @intToPtr(HANDLE, maxInt(usize));
-
-pub const INVALID_FILE_ATTRIBUTES = DWORD(maxInt(DWORD));
-
-pub const OVERLAPPED = extern struct {
- Internal: ULONG_PTR,
- InternalHigh: ULONG_PTR,
- Offset: DWORD,
- OffsetHigh: DWORD,
- hEvent: ?HANDLE,
-};
-pub const LPOVERLAPPED = *OVERLAPPED;
-
-pub const MAX_PATH = 260;
-
-// TODO issue #305
-pub const FILE_INFO_BY_HANDLE_CLASS = u32;
-pub const FileBasicInfo = 0;
-pub const FileStandardInfo = 1;
-pub const FileNameInfo = 2;
-pub const FileRenameInfo = 3;
-pub const FileDispositionInfo = 4;
-pub const FileAllocationInfo = 5;
-pub const FileEndOfFileInfo = 6;
-pub const FileStreamInfo = 7;
-pub const FileCompressionInfo = 8;
-pub const FileAttributeTagInfo = 9;
-pub const FileIdBothDirectoryInfo = 10;
-pub const FileIdBothDirectoryRestartInfo = 11;
-pub const FileIoPriorityHintInfo = 12;
-pub const FileRemoteProtocolInfo = 13;
-pub const FileFullDirectoryInfo = 14;
-pub const FileFullDirectoryRestartInfo = 15;
-pub const FileStorageInfo = 16;
-pub const FileAlignmentInfo = 17;
-pub const FileIdInfo = 18;
-pub const FileIdExtdDirectoryInfo = 19;
-pub const FileIdExtdDirectoryRestartInfo = 20;
-
-pub const FILE_NAME_INFO = extern struct {
- FileNameLength: DWORD,
- FileName: [1]WCHAR,
+pub const is_the_target = builtin.os == .windows;
+pub const advapi32 = @import("windows/advapi32.zig");
+pub const kernel32 = @import("windows/kernel32.zig");
+pub const ntdll = @import("windows/ntdll.zig");
+pub const ole32 = @import("windows/ole32.zig");
+pub const shell32 = @import("windows/shell32.zig");
+
+pub use @import("windows/bits.zig");
+
+pub const CreateFileError = error{
+ SharingViolation,
+ PathAlreadyExists,
+
+ /// When any of the path components can not be found or the file component can not
+ /// be found. Some operating systems distinguish between path components not found and
+ /// file components not found, but they are collapsed into FileNotFound to gain
+ /// consistency across operating systems.
+ FileNotFound,
+
+ AccessDenied,
+ PipeBusy,
+ NameTooLong,
+
+ /// On Windows, file paths must be valid Unicode.
+ InvalidUtf8,
+
+ /// On Windows, file paths cannot contain these characters:
+ /// '/', '*', '?', '"', '<', '>', '|'
+ BadPathName,
+
+ Unexpected,
};
-/// Return the normalized drive name. This is the default.
-pub const FILE_NAME_NORMALIZED = 0x0;
+pub fn CreateFile(
+ file_path: []const u8,
+ desired_access: DWORD,
+ share_mode: DWORD,
+ lpSecurityAttributes: ?LPSECURITY_ATTRIBUTES,
+ creation_disposition: DWORD,
+ flags_and_attrs: DWORD,
+ hTemplateFile: ?HANDLE,
+) CreateFileError!HANDLE {
+ const file_path_w = try sliceToPrefixedFileW(file_path);
+ return CreateFileW(&file_path_w, desired_access, share_mode, lpSecurityAttributes, creation_disposition, flags_and_attrs, hTemplateFile);
+}
+
+pub fn CreateFileW(
+ file_path_w: [*]const u16,
+ desired_access: DWORD,
+ share_mode: DWORD,
+ lpSecurityAttributes: ?LPSECURITY_ATTRIBUTES,
+ creation_disposition: DWORD,
+ flags_and_attrs: DWORD,
+ hTemplateFile: ?HANDLE,
+) CreateFileError!HANDLE {
+ const result = kernel32.CreateFileW(file_path_w, desired_access, share_mode, lpSecurityAttributes, creation_disposition, flags_and_attrs, hTemplateFile);
+
+ if (result == INVALID_HANDLE_VALUE) {
+ switch (kernel32.GetLastError()) {
+ ERROR.SHARING_VIOLATION => return error.SharingViolation,
+ ERROR.ALREADY_EXISTS => return error.PathAlreadyExists,
+ ERROR.FILE_EXISTS => return error.PathAlreadyExists,
+ ERROR.FILE_NOT_FOUND => return error.FileNotFound,
+ ERROR.PATH_NOT_FOUND => return error.FileNotFound,
+ ERROR.ACCESS_DENIED => return error.AccessDenied,
+ ERROR.PIPE_BUSY => return error.PipeBusy,
+ ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
+ else => |err| return unexpectedError(err),
+ }
+ }
+
+ return result;
+}
+
+pub const CreatePipeError = error{Unexpected};
-/// Return the opened file name (not normalized).
-pub const FILE_NAME_OPENED = 0x8;
+pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) CreatePipeError!void {
+ if (kernel32.CreatePipe(rd, wr, sattr, 0) == 0) {
+ switch (kernel32.GetLastError()) {
+ else => |err| return unexpectedError(err),
+ }
+ }
+}
-/// Return the path with the drive letter. This is the default.
-pub const VOLUME_NAME_DOS = 0x0;
+pub const SetHandleInformationError = error{Unexpected};
-/// Return the path with a volume GUID path instead of the drive name.
-pub const VOLUME_NAME_GUID = 0x1;
+pub fn SetHandleInformation(h: HANDLE, mask: DWORD, flags: DWORD) SetHandleInformationError!void {
+ if (kernel32.SetHandleInformation(h, mask, flags) == 0) {
+ switch (kernel32.GetLastError()) {
+ else => |err| return unexpectedError(err),
+ }
+ }
+}
-/// Return the path with no drive information.
-pub const VOLUME_NAME_NONE = 0x4;
+pub const RtlGenRandomError = error{Unexpected};
-/// Return the path with the volume device path.
-pub const VOLUME_NAME_NT = 0x2;
+/// Call RtlGenRandom() instead of CryptGetRandom() on Windows
+/// https://github.com/rust-lang-nursery/rand/issues/111
+/// https://bugzilla.mozilla.org/show_bug.cgi?id=504270
+pub fn RtlGenRandom(output: []u8) RtlGenRandomError!void {
+ if (advapi32.RtlGenRandom(output.ptr, output.len) == 0) {
+ switch (kernel32.GetLastError()) {
+ else => |err| return unexpectedError(err),
+ }
+ }
+}
-pub const SECURITY_ATTRIBUTES = extern struct {
- nLength: DWORD,
- lpSecurityDescriptor: ?*c_void,
- bInheritHandle: BOOL,
+pub const WaitForSingleObjectError = error{
+ WaitAbandoned,
+ WaitTimeOut,
+ Unexpected,
};
-pub const PSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES;
-pub const LPSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES;
-
-pub const GENERIC_READ = 0x80000000;
-pub const GENERIC_WRITE = 0x40000000;
-pub const GENERIC_EXECUTE = 0x20000000;
-pub const GENERIC_ALL = 0x10000000;
-
-pub const FILE_SHARE_DELETE = 0x00000004;
-pub const FILE_SHARE_READ = 0x00000001;
-pub const FILE_SHARE_WRITE = 0x00000002;
-
-pub const CREATE_ALWAYS = 2;
-pub const CREATE_NEW = 1;
-pub const OPEN_ALWAYS = 4;
-pub const OPEN_EXISTING = 3;
-pub const TRUNCATE_EXISTING = 5;
-
-pub const FILE_ATTRIBUTE_ARCHIVE = 0x20;
-pub const FILE_ATTRIBUTE_COMPRESSED = 0x800;
-pub const FILE_ATTRIBUTE_DEVICE = 0x40;
-pub const FILE_ATTRIBUTE_DIRECTORY = 0x10;
-pub const FILE_ATTRIBUTE_ENCRYPTED = 0x4000;
-pub const FILE_ATTRIBUTE_HIDDEN = 0x2;
-pub const FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x8000;
-pub const FILE_ATTRIBUTE_NORMAL = 0x80;
-pub const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000;
-pub const FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x20000;
-pub const FILE_ATTRIBUTE_OFFLINE = 0x1000;
-pub const FILE_ATTRIBUTE_READONLY = 0x1;
-pub const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x400000;
-pub const FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x40000;
-pub const FILE_ATTRIBUTE_REPARSE_POINT = 0x400;
-pub const FILE_ATTRIBUTE_SPARSE_FILE = 0x200;
-pub const FILE_ATTRIBUTE_SYSTEM = 0x4;
-pub const FILE_ATTRIBUTE_TEMPORARY = 0x100;
-pub const FILE_ATTRIBUTE_VIRTUAL = 0x10000;
-
-pub const PROCESS_INFORMATION = extern struct {
- hProcess: HANDLE,
- hThread: HANDLE,
- dwProcessId: DWORD,
- dwThreadId: DWORD,
+
+pub fn WaitForSingleObject(handle: HANDLE, milliseconds: DWORD) WaitForSingleObjectError!void {
+ switch (kernel32.WaitForSingleObject(handle, milliseconds)) {
+ WAIT_ABANDONED => return error.WaitAbandoned,
+ WAIT_OBJECT_0 => return,
+ WAIT_TIMEOUT => return error.WaitTimeOut,
+ WAIT_FAILED => switch (kernel32.GetLastError()) {
+ else => |err| return unexpectedError(err),
+ },
+ else => return error.Unexpected,
+ }
+}
+
+pub const FindFirstFileError = error{
+ FileNotFound,
+ InvalidUtf8,
+ BadPathName,
+ NameTooLong,
+ Unexpected,
};
-pub const STARTUPINFOW = extern struct {
- cb: DWORD,
- lpReserved: ?LPWSTR,
- lpDesktop: ?LPWSTR,
- lpTitle: ?LPWSTR,
- dwX: DWORD,
- dwY: DWORD,
- dwXSize: DWORD,
- dwYSize: DWORD,
- dwXCountChars: DWORD,
- dwYCountChars: DWORD,
- dwFillAttribute: DWORD,
- dwFlags: DWORD,
- wShowWindow: WORD,
- cbReserved2: WORD,
- lpReserved2: ?LPBYTE,
- hStdInput: ?HANDLE,
- hStdOutput: ?HANDLE,
- hStdError: ?HANDLE,
+pub fn FindFirstFile(dir_path: []const u8, find_file_data: *WIN32_FIND_DATAW) FindFirstFileError!HANDLE {
+ const dir_path_w = try sliceToPrefixedSuffixedFileW(dir_path, []u16{ '\\', '*', 0 });
+ const handle = kernel32.FindFirstFileW(&dir_path_w, find_file_data);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ switch (kernel32.GetLastError()) {
+ ERROR.FILE_NOT_FOUND => return error.FileNotFound,
+ ERROR.PATH_NOT_FOUND => return error.FileNotFound,
+ else => |err| return unexpectedError(err),
+ }
+ }
+
+ return handle;
+}
+
+pub const FindNextFileError = error{Unexpected};
+
+/// Returns `true` if there was another file, `false` otherwise.
+pub fn FindNextFile(handle: HANDLE, find_file_data: *WIN32_FIND_DATAW) FindNextFileError!bool {
+ if (kernel32.FindNextFileW(handle, find_file_data) == 0) {
+ switch (kernel32.GetLastError()) {
+ ERROR.NO_MORE_FILES => return false,
+ else => |err| return unexpectedError(err),
+ }
+ }
+ return true;
+}
+
+pub const CreateIoCompletionPortError = error{Unexpected};
+
+pub fn CreateIoCompletionPort(
+ file_handle: HANDLE,
+ existing_completion_port: ?HANDLE,
+ completion_key: usize,
+ concurrent_thread_count: DWORD,
+) CreateIoCompletionPortError!HANDLE {
+ const handle = kernel32.CreateIoCompletionPort(file_handle, existing_completion_port, completion_key, concurrent_thread_count) orelse {
+ switch (kernel32.GetLastError()) {
+ ERROR.INVALID_PARAMETER => unreachable,
+ else => |err| return unexpectedError(err),
+ }
+ };
+ return handle;
+}
+
+pub const PostQueuedCompletionStatusError = error{Unexpected};
+
+pub fn PostQueuedCompletionStatus(
+ completion_port: HANDLE,
+ bytes_transferred_count: DWORD,
+ completion_key: usize,
+ lpOverlapped: ?*OVERLAPPED,
+) PostQueuedCompletionStatusError!void {
+ if (kernel32.PostQueuedCompletionStatus(completion_port, bytes_transferred_count, completion_key, lpOverlapped) == 0) {
+ switch (kernel32.GetLastError()) {
+ else => |err| return unexpectedError(err),
+ }
+ }
+}
+
+pub const GetQueuedCompletionStatusResult = enum {
+ Normal,
+ Aborted,
+ Cancelled,
+ EOF,
};
-pub const STARTF_FORCEONFEEDBACK = 0x00000040;
-pub const STARTF_FORCEOFFFEEDBACK = 0x00000080;
-pub const STARTF_PREVENTPINNING = 0x00002000;
-pub const STARTF_RUNFULLSCREEN = 0x00000020;
-pub const STARTF_TITLEISAPPID = 0x00001000;
-pub const STARTF_TITLEISLINKNAME = 0x00000800;
-pub const STARTF_UNTRUSTEDSOURCE = 0x00008000;
-pub const STARTF_USECOUNTCHARS = 0x00000008;
-pub const STARTF_USEFILLATTRIBUTE = 0x00000010;
-pub const STARTF_USEHOTKEY = 0x00000200;
-pub const STARTF_USEPOSITION = 0x00000004;
-pub const STARTF_USESHOWWINDOW = 0x00000001;
-pub const STARTF_USESIZE = 0x00000002;
-pub const STARTF_USESTDHANDLES = 0x00000100;
-
-pub const INFINITE = 4294967295;
-
-pub const WAIT_ABANDONED = 0x00000080;
-pub const WAIT_OBJECT_0 = 0x00000000;
-pub const WAIT_TIMEOUT = 0x00000102;
-pub const WAIT_FAILED = 0xFFFFFFFF;
-
-pub const HANDLE_FLAG_INHERIT = 0x00000001;
-pub const HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x00000002;
-
-pub const MOVEFILE_COPY_ALLOWED = 2;
-pub const MOVEFILE_CREATE_HARDLINK = 16;
-pub const MOVEFILE_DELAY_UNTIL_REBOOT = 4;
-pub const MOVEFILE_FAIL_IF_NOT_TRACKABLE = 32;
-pub const MOVEFILE_REPLACE_EXISTING = 1;
-pub const MOVEFILE_WRITE_THROUGH = 8;
-
-pub const FILE_BEGIN = 0;
-pub const FILE_CURRENT = 1;
-pub const FILE_END = 2;
-
-pub const HEAP_CREATE_ENABLE_EXECUTE = 0x00040000;
-pub const HEAP_GENERATE_EXCEPTIONS = 0x00000004;
-pub const HEAP_NO_SERIALIZE = 0x00000001;
-
-// AllocationType values
-pub const MEM_COMMIT = 0x1000;
-pub const MEM_RESERVE = 0x2000;
-pub const MEM_RESET = 0x80000;
-pub const MEM_RESET_UNDO = 0x1000000;
-pub const MEM_LARGE_PAGES = 0x20000000;
-pub const MEM_PHYSICAL = 0x400000;
-pub const MEM_TOP_DOWN = 0x100000;
-pub const MEM_WRITE_WATCH = 0x200000;
-
-// Protect values
-pub const PAGE_EXECUTE = 0x10;
-pub const PAGE_EXECUTE_READ = 0x20;
-pub const PAGE_EXECUTE_READWRITE = 0x40;
-pub const PAGE_EXECUTE_WRITECOPY = 0x80;
-pub const PAGE_NOACCESS = 0x01;
-pub const PAGE_READONLY = 0x02;
-pub const PAGE_READWRITE = 0x04;
-pub const PAGE_WRITECOPY = 0x08;
-pub const PAGE_TARGETS_INVALID = 0x40000000;
-pub const PAGE_TARGETS_NO_UPDATE = 0x40000000; // Same as PAGE_TARGETS_INVALID
-pub const PAGE_GUARD = 0x100;
-pub const PAGE_NOCACHE = 0x200;
-pub const PAGE_WRITECOMBINE = 0x400;
-
-// FreeType values
-pub const MEM_COALESCE_PLACEHOLDERS = 0x1;
-pub const MEM_RESERVE_PLACEHOLDERS = 0x2;
-pub const MEM_DECOMMIT = 0x4000;
-pub const MEM_RELEASE = 0x8000;
-
-pub const PTHREAD_START_ROUTINE = extern fn (LPVOID) DWORD;
-pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE;
-
-pub const WIN32_FIND_DATAW = extern struct {
- dwFileAttributes: DWORD,
- ftCreationTime: FILETIME,
- ftLastAccessTime: FILETIME,
- ftLastWriteTime: FILETIME,
- nFileSizeHigh: DWORD,
- nFileSizeLow: DWORD,
- dwReserved0: DWORD,
- dwReserved1: DWORD,
- cFileName: [260]u16,
- cAlternateFileName: [14]u16,
+pub fn GetQueuedCompletionStatus(
+ completion_port: HANDLE,
+ bytes_transferred_count: *DWORD,
+ lpCompletionKey: *usize,
+ lpOverlapped: *?*OVERLAPPED,
+ dwMilliseconds: DWORD,
+) GetQueuedCompletionStatusResult {
+ if (kernel32.GetQueuedCompletionStatus(
+ completion_port,
+ bytes_transferred_count,
+ lpCompletionKey,
+ lpOverlapped,
+ dwMilliseconds,
+ ) == FALSE) {
+ switch (kernel32.GetLastError()) {
+ ERROR.ABANDONED_WAIT_0 => return GetQueuedCompletionStatusResult.Aborted,
+ ERROR.OPERATION_ABORTED => return GetQueuedCompletionStatusResult.Cancelled,
+ ERROR.HANDLE_EOF => return GetQueuedCompletionStatusResult.EOF,
+ else => |err| {
+ if (std.debug.runtime_safety) {
+ std.debug.panic("unexpected error: {}\n", err);
+ }
+ },
+ }
+ }
+ return GetQueuedCompletionStatusResult.Normal;
+}
+
+pub fn CloseHandle(hObject: HANDLE) void {
+ assert(kernel32.CloseHandle(hObject) != 0);
+}
+
+pub fn FindClose(hFindFile: HANDLE) void {
+ assert(kernel32.FindClose(hFindFile) != 0);
+}
+
+pub const ReadFileError = error{Unexpected};
+
+pub fn ReadFile(in_hFile: HANDLE, buffer: []u8) ReadFileError!usize {
+ var index: usize = 0;
+ while (index < buffer.len) {
+ const want_read_count = @intCast(DWORD, math.min(DWORD(maxInt(DWORD)), buffer.len - index));
+ var amt_read: DWORD = undefined;
+ if (kernel32.ReadFile(in_hFile, buffer.ptr + index, want_read_count, &amt_read, null) == 0) {
+ switch (kernel32.GetLastError()) {
+ ERROR.OPERATION_ABORTED => continue,
+ ERROR.BROKEN_PIPE => return index,
+ else => |err| return unexpectedError(err),
+ }
+ }
+ if (amt_read == 0) return index;
+ index += amt_read;
+ }
+ return index;
+}
+
+pub const WriteFileError = error{
+ SystemResources,
+ OperationAborted,
+ BrokenPipe,
+ Unexpected,
};
-pub const FILETIME = extern struct {
- dwLowDateTime: DWORD,
- dwHighDateTime: DWORD,
+/// This function is for blocking file descriptors only. For non-blocking, see
+/// `WriteFileAsync`.
+pub fn WriteFile(handle: HANDLE, bytes: []const u8) WriteFileError!void {
+ var bytes_written: DWORD = undefined;
+ // TODO replace this @intCast with a loop that writes all the bytes
+ if (kernel32.WriteFile(handle, bytes.ptr, @intCast(u32, bytes.len), &bytes_written, null) == 0) {
+ switch (kernel32.GetLastError()) {
+ ERROR.INVALID_USER_BUFFER => return error.SystemResources,
+ ERROR.NOT_ENOUGH_MEMORY => return error.SystemResources,
+ ERROR.OPERATION_ABORTED => return error.OperationAborted,
+ ERROR.NOT_ENOUGH_QUOTA => return error.SystemResources,
+ ERROR.IO_PENDING => unreachable, // this function is for blocking files only
+ ERROR.BROKEN_PIPE => return error.BrokenPipe,
+ else => |err| return unexpectedError(err),
+ }
+ }
+}
+
+pub const GetCurrentDirectoryError = error{
+ NameTooLong,
+ Unexpected,
};
-pub const SYSTEM_INFO = extern struct {
- anon1: extern union {
- dwOemId: DWORD,
- anon2: extern struct {
- wProcessorArchitecture: WORD,
- wReserved: WORD,
- },
- },
- dwPageSize: DWORD,
- lpMinimumApplicationAddress: LPVOID,
- lpMaximumApplicationAddress: LPVOID,
- dwActiveProcessorMask: DWORD_PTR,
- dwNumberOfProcessors: DWORD,
- dwProcessorType: DWORD,
- dwAllocationGranularity: DWORD,
- wProcessorLevel: WORD,
- wProcessorRevision: WORD,
+/// The result is a slice of `buffer`, indexed from 0.
+pub fn GetCurrentDirectory(buffer: []u8) GetCurrentDirectoryError![]u8 {
+ var utf16le_buf: [PATH_MAX_WIDE]u16 = undefined;
+ const result = kernel32.GetCurrentDirectoryW(utf16le_buf.len, &utf16le_buf);
+ if (result == 0) {
+ switch (kernel32.GetLastError()) {
+ else => |err| return unexpectedError(err),
+ }
+ }
+ assert(result <= utf16le_buf.len);
+ const utf16le_slice = utf16le_buf[0..result];
+ // Trust that Windows gives us valid UTF-16LE.
+ var end_index: usize = 0;
+ var it = std.unicode.Utf16LeIterator.init(utf16le_slice);
+ while (it.nextCodepoint() catch unreachable) |codepoint| {
+ const seq_len = std.unicode.utf8CodepointSequenceLength(codepoint) catch unreachable;
+ if (end_index + seq_len >= buffer.len)
+ return error.NameTooLong;
+ end_index += std.unicode.utf8Encode(codepoint, buffer[end_index..]) catch unreachable;
+ }
+ return buffer[0..end_index];
+}
+
+pub const CreateSymbolicLinkError = error{Unexpected};
+
+pub fn CreateSymbolicLink(
+ sym_link_path: []const u8,
+ target_path: []const u8,
+ flags: DWORD,
+) CreateSymbolicLinkError!void {
+ const sym_link_path_w = try sliceToPrefixedFileW(sym_link_path);
+ const target_path_w = try sliceToPrefixedFileW(target_path);
+ return CreateSymbolicLinkW(&sym_link_path_w, &target_path_w, flags);
+}
+
+pub fn CreateSymbolicLinkW(
+ sym_link_path: [*]const u16,
+ target_path: [*]const u16,
+ flags: DWORD,
+) CreateSymbolicLinkError!void {
+ if (kernel32.CreateSymbolicLinkW(sym_link_path, target_path, flags) == 0) {
+ switch (kernel32.GetLastError()) {
+ else => |err| return unexpectedError(err),
+ }
+ }
+}
+
+pub const DeleteFileError = error{
+ FileNotFound,
+ AccessDenied,
+ NameTooLong,
+ Unexpected,
};
-pub const HRESULT = c_long;
+pub fn DeleteFile(filename: []const u8) DeleteFileError!void {
+ const filename_w = try sliceToPrefixedFileW(filename);
+ return DeleteFileW(&filename_w);
+}
-pub const KNOWNFOLDERID = GUID;
-pub const GUID = extern struct {
- Data1: c_ulong,
- Data2: c_ushort,
- Data3: c_ushort,
- Data4: [8]u8,
+pub fn DeleteFileW(filename: [*]const u16) DeleteFileError!void {
+ if (kernel32.DeleteFileW(filename) == 0) {
+ switch (kernel32.GetLastError()) {
+ ERROR.FILE_NOT_FOUND => return error.FileNotFound,
+ ERROR.ACCESS_DENIED => return error.AccessDenied,
+ ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
+ ERROR.INVALID_PARAMETER => return error.NameTooLong,
+ else => |err| return unexpectedError(err),
+ }
+ }
+}
- pub fn parse(str: []const u8) GUID {
- var guid: GUID = undefined;
- var index: usize = 0;
- assert(str[index] == '{');
- index += 1;
+pub const MoveFileError = error{Unexpected};
- guid.Data1 = std.fmt.parseUnsigned(c_ulong, str[index .. index + 8], 16) catch unreachable;
- index += 8;
+pub fn MoveFileEx(old_path: []const u8, new_path: []const u8, flags: DWORD) MoveFileError!void {
+ const old_path_w = try sliceToPrefixedFileW(old_path);
+ const new_path_w = try sliceToPrefixedFileW(new_path);
+ return MoveFileExW(&old_path_w, &new_path_w, flags);
+}
- assert(str[index] == '-');
- index += 1;
+pub fn MoveFileExW(old_path: [*]const u16, new_path: [*]const u16, flags: DWORD) MoveFileError!void {
+ if (kernel32.MoveFileExW(old_path, new_path, flags) == 0) {
+ switch (kernel32.GetLastError()) {
+ else => |err| return unexpectedError(err),
+ }
+ }
+}
- guid.Data2 = std.fmt.parseUnsigned(c_ushort, str[index .. index + 4], 16) catch unreachable;
- index += 4;
+pub const CreateDirectoryError = error{
+ PathAlreadyExists,
+ FileNotFound,
+ Unexpected,
+};
- assert(str[index] == '-');
- index += 1;
+pub fn CreateDirectory(pathname: []const u8, attrs: ?*SECURITY_ATTRIBUTES) CreateDirectoryError!void {
+ const pathname_w = try sliceToPrefixedFileW(pathname);
+ return CreateDirectoryW(&pathname_w, attrs);
+}
- guid.Data3 = std.fmt.parseUnsigned(c_ushort, str[index .. index + 4], 16) catch unreachable;
- index += 4;
+pub fn CreateDirectoryW(pathname: [*]const u16, attrs: ?*SECURITY_ATTRIBUTES) CreateDirectoryError!void {
+ if (kernel32.CreateDirectoryW(pathname, attrs) == 0) {
+ switch (kernel32.GetLastError()) {
+ ERROR.ALREADY_EXISTS => return error.PathAlreadyExists,
+ ERROR.PATH_NOT_FOUND => return error.FileNotFound,
+ else => |err| return unexpectedError(err),
+ }
+ }
+}
- assert(str[index] == '-');
- index += 1;
+pub const RemoveDirectoryError = error{
+ FileNotFound,
+ DirNotEmpty,
+ Unexpected,
+};
- guid.Data4[0] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
- index += 2;
- guid.Data4[1] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
- index += 2;
+pub fn RemoveDirectory(dir_path: []const u8) RemoveDirectoryError!void {
+ const dir_path_w = try sliceToPrefixedFileW(dir_path);
+ return RemoveDirectoryW(&dir_path_w);
+}
- assert(str[index] == '-');
- index += 1;
+pub fn RemoveDirectoryW(dir_path_w: [*]const u16) RemoveDirectoryError!void {
+ if (kernel32.RemoveDirectoryW(dir_path_w) == 0) {
+ switch (kernel32.GetLastError()) {
+ ERROR.PATH_NOT_FOUND => return error.FileNotFound,
+ ERROR.DIR_NOT_EMPTY => return error.DirNotEmpty,
+ else => |err| return unexpectedError(err),
+ }
+ }
+}
- var i: usize = 2;
- while (i < guid.Data4.len) : (i += 1) {
- guid.Data4[i] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
- index += 2;
+pub const GetStdHandleError = error{
+ NoStandardHandleAttached,
+ Unexpected,
+};
+
+pub fn GetStdHandle(handle_id: DWORD) GetStdHandleError!HANDLE {
+ const handle = kernel32.GetStdHandle(handle_id) orelse return error.NoStandardHandleAttached;
+ if (handle == INVALID_HANDLE_VALUE) {
+ switch (kernel32.GetLastError()) {
+ else => |err| return unexpectedError(err),
+ }
+ }
+ return handle;
+}
+
+pub const SetFilePointerError = error{Unexpected};
+
+/// The SetFilePointerEx function with the `dwMoveMethod` parameter set to `FILE_BEGIN`.
+pub fn SetFilePointerEx_BEGIN(handle: HANDLE, offset: u64) SetFilePointerError!void {
+ // "The starting point is zero or the beginning of the file. If [FILE_BEGIN]
+ // is specified, then the liDistanceToMove parameter is interpreted as an unsigned value."
+ // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-setfilepointerex
+ const ipos = @bitCast(LARGE_INTEGER, offset);
+ if (kernel32.SetFilePointerEx(handle, ipos, null, FILE_BEGIN) == 0) {
+ switch (kernel32.GetLastError()) {
+ ERROR.INVALID_PARAMETER => unreachable,
+ ERROR.INVALID_HANDLE => unreachable,
+ else => |err| return unexpectedError(err),
+ }
+ }
+}
+
+/// The SetFilePointerEx function with the `dwMoveMethod` parameter set to `FILE_CURRENT`.
+pub fn SetFilePointerEx_CURRENT(handle: HANDLE, offset: i64) SetFilePointerError!void {
+ if (kernel32.SetFilePointerEx(handle, offset, null, FILE_CURRENT) == 0) {
+ switch (kernel32.GetLastError()) {
+ ERROR.INVALID_PARAMETER => unreachable,
+ ERROR.INVALID_HANDLE => unreachable,
+ else => |err| return unexpectedError(err),
+ }
+ }
+}
+
+/// The SetFilePointerEx function with the `dwMoveMethod` parameter set to `FILE_END`.
+pub fn SetFilePointerEx_END(handle: HANDLE, offset: i64) SetFilePointerError!void {
+ if (kernel32.SetFilePointerEx(handle, offset, null, FILE_END) == 0) {
+ switch (kernel32.GetLastError()) {
+ ERROR.INVALID_PARAMETER => unreachable,
+ ERROR.INVALID_HANDLE => unreachable,
+ else => |err| return unexpectedError(err),
}
+ }
+}
- assert(str[index] == '}');
- index += 1;
- return guid;
+/// The SetFilePointerEx function with parameters to get the current offset.
+pub fn SetFilePointerEx_CURRENT_get(handle: HANDLE) SetFilePointerError!u64 {
+ var result: LARGE_INTEGER = undefined;
+ if (kernel32.SetFilePointerEx(handle, 0, &result, FILE_CURRENT) == 0) {
+ switch (kernel32.GetLastError()) {
+ ERROR.INVALID_PARAMETER => unreachable,
+ ERROR.INVALID_HANDLE => unreachable,
+ else => |err| return unexpectedError(err),
+ }
}
+ // Based on the docs for FILE_BEGIN, it seems that the returned signed integer
+ // should be interpreted as an unsigned integer.
+ return @bitCast(u64, result);
+}
+
+pub const GetFinalPathNameByHandleError = error{
+ FileNotFound,
+ SystemResources,
+ NameTooLong,
+ Unexpected,
};
-pub const FOLDERID_LocalAppData = GUID.parse("{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}");
-
-pub const KF_FLAG_DEFAULT = 0;
-pub const KF_FLAG_NO_APPCONTAINER_REDIRECTION = 65536;
-pub const KF_FLAG_CREATE = 32768;
-pub const KF_FLAG_DONT_VERIFY = 16384;
-pub const KF_FLAG_DONT_UNEXPAND = 8192;
-pub const KF_FLAG_NO_ALIAS = 4096;
-pub const KF_FLAG_INIT = 2048;
-pub const KF_FLAG_DEFAULT_PATH = 1024;
-pub const KF_FLAG_NOT_PARENT_RELATIVE = 512;
-pub const KF_FLAG_SIMPLE_IDLIST = 256;
-pub const KF_FLAG_ALIAS_ONLY = -2147483648;
-
-pub const S_OK = 0;
-pub const E_NOTIMPL = @bitCast(c_long, c_ulong(0x80004001));
-pub const E_NOINTERFACE = @bitCast(c_long, c_ulong(0x80004002));
-pub const E_POINTER = @bitCast(c_long, c_ulong(0x80004003));
-pub const E_ABORT = @bitCast(c_long, c_ulong(0x80004004));
-pub const E_FAIL = @bitCast(c_long, c_ulong(0x80004005));
-pub const E_UNEXPECTED = @bitCast(c_long, c_ulong(0x8000FFFF));
-pub const E_ACCESSDENIED = @bitCast(c_long, c_ulong(0x80070005));
-pub const E_HANDLE = @bitCast(c_long, c_ulong(0x80070006));
-pub const E_OUTOFMEMORY = @bitCast(c_long, c_ulong(0x8007000E));
-pub const E_INVALIDARG = @bitCast(c_long, c_ulong(0x80070057));
-
-pub const FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
-pub const FILE_FLAG_DELETE_ON_CLOSE = 0x04000000;
-pub const FILE_FLAG_NO_BUFFERING = 0x20000000;
-pub const FILE_FLAG_OPEN_NO_RECALL = 0x00100000;
-pub const FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;
-pub const FILE_FLAG_OVERLAPPED = 0x40000000;
-pub const FILE_FLAG_POSIX_SEMANTICS = 0x0100000;
-pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000;
-pub const FILE_FLAG_SESSION_AWARE = 0x00800000;
-pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
-pub const FILE_FLAG_WRITE_THROUGH = 0x80000000;
-
-pub const SMALL_RECT = extern struct {
- Left: SHORT,
- Top: SHORT,
- Right: SHORT,
- Bottom: SHORT,
+pub fn GetFinalPathNameByHandleW(
+ hFile: HANDLE,
+ buf_ptr: [*]u16,
+ buf_len: DWORD,
+ flags: DWORD,
+) GetFinalPathNameByHandleError!DWORD {
+ const rc = kernel32.GetFinalPathNameByHandleW(hFile, buf_ptr, buf_len, flags);
+ if (rc == 0) {
+ switch (kernel32.GetLastError()) {
+ ERROR.FILE_NOT_FOUND => return error.FileNotFound,
+ ERROR.PATH_NOT_FOUND => return error.FileNotFound,
+ ERROR.NOT_ENOUGH_MEMORY => return error.SystemResources,
+ ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
+ ERROR.INVALID_PARAMETER => unreachable,
+ else => |err| return unexpectedError(err),
+ }
+ }
+ return rc;
+}
+
+pub const GetFileSizeError = error{Unexpected};
+
+pub fn GetFileSizeEx(hFile: HANDLE) GetFileSizeError!u64 {
+ var file_size: LARGE_INTEGER = undefined;
+ if (kernel32.GetFileSizeEx(hFile, &file_size) == 0) {
+ switch (kernel32.GetLastError()) {
+ else => |err| return unexpectedError(err),
+ }
+ }
+ return @bitCast(u64, file_size);
+}
+
+pub const GetFileAttributesError = error{
+ FileNotFound,
+ PermissionDenied,
+ Unexpected,
+};
+
+pub fn GetFileAttributes(filename: []const u8) GetFileAttributesError!DWORD {
+ const filename_w = try sliceToPrefixedFileW(filename);
+ return GetFileAttributesW(&filename_w);
+}
+
+pub fn GetFileAttributesW(lpFileName: [*]const u16) GetFileAttributesError!DWORD {
+ const rc = kernel32.GetFileAttributesW(lpFileName);
+ if (rc == INVALID_FILE_ATTRIBUTES) {
+ switch (kernel32.GetLastError()) {
+ ERROR.FILE_NOT_FOUND => return error.FileNotFound,
+ ERROR.PATH_NOT_FOUND => return error.FileNotFound,
+ ERROR.ACCESS_DENIED => return error.PermissionDenied,
+ else => |err| return unexpectedError(err),
+ }
+ }
+ return rc;
+}
+
+const GetModuleFileNameError = error{Unexpected};
+
+pub fn GetModuleFileNameW(hModule: ?HMODULE, buf_ptr: [*]u16, buf_len: DWORD) GetModuleFileNameError![]u16 {
+ const rc = kernel32.GetModuleFileNameW(hModule, buf_ptr, buf_len);
+ if (rc == 0) {
+ switch (kernel32.GetLastError()) {
+ else => |err| return unexpectedError(err),
+ }
+ }
+ return buf_ptr[0..rc];
+}
+
+pub const TerminateProcessError = error{Unexpected};
+
+pub fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) TerminateProcessError!void {
+ if (kernel32.TerminateProcess(hProcess, uExitCode) == 0) {
+ switch (kernel32.GetLastError()) {
+ else => |err| return unexpectedError(err),
+ }
+ }
+}
+
+pub const VirtualAllocError = error{Unexpected};
+
+pub fn VirtualAlloc(addr: ?LPVOID, size: usize, alloc_type: DWORD, flProtect: DWORD) VirtualAllocError!LPVOID {
+ return kernel32.VirtualAlloc(addr, size, alloc_type, flProtect) orelse {
+ switch (kernel32.GetLastError()) {
+ else => |err| return unexpectedError(err),
+ }
+ };
+}
+
+pub fn VirtualFree(lpAddress: ?LPVOID, dwSize: usize, dwFreeType: DWORD) void {
+ assert(kernel32.VirtualFree(lpAddress, dwSize, dwFreeType) != 0);
+}
+
+pub const SetConsoleTextAttributeError = error{Unexpected};
+
+pub fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) SetConsoleTextAttributeError!void {
+ if (kernel32.SetConsoleTextAttribute(hConsoleOutput, wAttributes) == 0) {
+ switch (kernel32.GetLastError()) {
+ else => |err| return unexpectedError(err),
+ }
+ }
+}
+
+pub const GetEnvironmentStringsError = error{OutOfMemory};
+
+pub fn GetEnvironmentStringsW() GetEnvironmentStringsError![*]u16 {
+ return kernel32.GetEnvironmentStringsW() orelse return error.OutOfMemory;
+}
+
+pub fn FreeEnvironmentStringsW(penv: [*]u16) void {
+ assert(kernel32.FreeEnvironmentStringsW(penv) != 0);
+}
+
+pub const GetEnvironmentVariableError = error{
+ EnvironmentVariableNotFound,
+ Unexpected,
};
-pub const COORD = extern struct {
- X: SHORT,
- Y: SHORT,
+pub fn GetEnvironmentVariableW(lpName: LPWSTR, lpBuffer: LPWSTR, nSize: DWORD) GetEnvironmentVariableError!DWORD {
+ const rc = kernel32.GetEnvironmentVariableW(lpName, lpBuffer, nSize);
+ if (rc == 0) {
+ switch (kernel32.GetLastError()) {
+ ERROR.ENVVAR_NOT_FOUND => return error.EnvironmentVariableNotFound,
+ else => |err| return unexpectedError(err),
+ }
+ }
+ return rc;
+}
+
+pub const CreateProcessError = error{
+ FileNotFound,
+ InvalidName,
+ Unexpected,
};
-pub const CREATE_UNICODE_ENVIRONMENT = 1024;
+pub fn CreateProcessW(
+ lpApplicationName: ?LPWSTR,
+ lpCommandLine: LPWSTR,
+ lpProcessAttributes: ?*SECURITY_ATTRIBUTES,
+ lpThreadAttributes: ?*SECURITY_ATTRIBUTES,
+ bInheritHandles: BOOL,
+ dwCreationFlags: DWORD,
+ lpEnvironment: ?*c_void,
+ lpCurrentDirectory: ?LPWSTR,
+ lpStartupInfo: *STARTUPINFOW,
+ lpProcessInformation: *PROCESS_INFORMATION,
+) CreateProcessError!void {
+ if (kernel32.CreateProcessW(
+ lpApplicationName,
+ lpCommandLine,
+ lpProcessAttributes,
+ lpThreadAttributes,
+ bInheritHandles,
+ dwCreationFlags,
+ lpEnvironment,
+ lpCurrentDirectory,
+ lpStartupInfo,
+ lpProcessInformation,
+ ) == 0) {
+ switch (kernel32.GetLastError()) {
+ ERROR.FILE_NOT_FOUND => return error.FileNotFound,
+ ERROR.PATH_NOT_FOUND => return error.FileNotFound,
+ ERROR.INVALID_PARAMETER => unreachable,
+ ERROR.INVALID_NAME => return error.InvalidName,
+ else => |err| return unexpectedError(err),
+ }
+ }
+}
-pub const TLS_OUT_OF_INDEXES = 4294967295;
-pub const IMAGE_TLS_DIRECTORY = extern struct {
- StartAddressOfRawData: usize,
- EndAddressOfRawData: usize,
- AddressOfIndex: usize,
- AddressOfCallBacks: usize,
- SizeOfZeroFill: u32,
- Characteristics: u32,
+pub const LoadLibraryError = error{
+ FileNotFound,
+ Unexpected,
};
-pub const IMAGE_TLS_DIRECTORY64 = IMAGE_TLS_DIRECTORY;
-pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY;
-pub const PIMAGE_TLS_CALLBACK = ?extern fn (PVOID, DWORD, PVOID) void;
+pub fn LoadLibraryW(lpLibFileName: [*]const u16) LoadLibraryError!HMODULE {
+ return kernel32.LoadLibraryW(lpLibFileName) orelse {
+ switch (kernel32.GetLastError()) {
+ ERROR.FILE_NOT_FOUND => return error.FileNotFound,
+ ERROR.PATH_NOT_FOUND => return error.FileNotFound,
+ ERROR.MOD_NOT_FOUND => return error.FileNotFound,
+ else => |err| return unexpectedError(err),
+ }
+ };
+}
+
+pub fn FreeLibrary(hModule: HMODULE) void {
+ assert(kernel32.FreeLibrary(hModule) != 0);
+}
+
+pub fn QueryPerformanceFrequency() u64 {
+ // "On systems that run Windows XP or later, the function will always succeed"
+ // https://docs.microsoft.com/en-us/windows/desktop/api/profileapi/nf-profileapi-queryperformancefrequency
+ var result: LARGE_INTEGER = undefined;
+ assert(kernel32.QueryPerformanceFrequency(&result) != 0);
+ // The kernel treats this integer as unsigned.
+ return @bitCast(u64, result);
+}
+
+pub fn QueryPerformanceCounter() u64 {
+ // "On systems that run Windows XP or later, the function will always succeed"
+ // https://docs.microsoft.com/en-us/windows/desktop/api/profileapi/nf-profileapi-queryperformancecounter
+ var result: LARGE_INTEGER = undefined;
+ assert(kernel32.QueryPerformanceCounter(&result) != 0);
+ // The kernel treats this integer as unsigned.
+ return @bitCast(u64, result);
+}
+
+pub fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter: ?*c_void, Context: ?*c_void) void {
+ assert(kernel32.InitOnceExecuteOnce(InitOnce, InitFn, Parameter, Context) != 0);
+}
+
+pub fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: *c_void) void {
+ assert(kernel32.HeapFree(hHeap, dwFlags, lpMem) != 0);
+}
+
+pub fn HeapDestroy(hHeap: HANDLE) void {
+ assert(kernel32.HeapDestroy(hHeap) != 0);
+}
+
+pub fn cStrToPrefixedFileW(s: [*]const u8) ![PATH_MAX_WIDE + 1]u16 {
+ return sliceToPrefixedFileW(mem.toSliceConst(u8, s));
+}
+
+pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 {
+ return sliceToPrefixedSuffixedFileW(s, []u16{0});
+}
+
+pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) ![PATH_MAX_WIDE + suffix.len]u16 {
+ // TODO well defined copy elision
+ var result: [PATH_MAX_WIDE + suffix.len]u16 = undefined;
+
+ // > File I/O functions in the Windows API convert "/" to "\" as part of
+ // > converting the name to an NT-style name, except when using the "\\?\"
+ // > prefix as detailed in the following sections.
+ // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
+ // Because we want the larger maximum path length for absolute paths, we
+ // disallow forward slashes in zig std lib file functions on Windows.
+ for (s) |byte| {
+ switch (byte) {
+ '/', '*', '?', '"', '<', '>', '|' => return error.BadPathName,
+ else => {},
+ }
+ }
+ const start_index = if (mem.startsWith(u8, s, "\\\\") or !std.fs.path.isAbsolute(s)) 0 else blk: {
+ const prefix = []u16{ '\\', '\\', '?', '\\' };
+ mem.copy(u16, result[0..], prefix);
+ break :blk prefix.len;
+ };
+ const end_index = start_index + try std.unicode.utf8ToUtf16Le(result[start_index..], s);
+ assert(end_index <= result.len);
+ if (end_index + suffix.len > result.len) return error.NameTooLong;
+ mem.copy(u16, result[end_index..], suffix);
+ return result;
+}
+
+/// Call this when you made a windows DLL call or something that does SetLastError
+/// and you get an unexpected error.
+pub fn unexpectedError(err: DWORD) std.os.UnexpectedError {
+ if (std.os.unexpected_error_tracing) {
+ std.debug.warn("unexpected GetLastError(): {}\n", err);
+ std.debug.dumpCurrentStackTrace(null);
+ }
+ return error.Unexpected;
+}
diff --git a/std/os/windows/advapi32.zig b/std/os/windows/advapi32.zig
index 9672767500..df3220e24c 100644
--- a/std/os/windows/advapi32.zig
+++ b/std/os/windows/advapi32.zig
@@ -1,15 +1,4 @@
-use @import("../windows.zig");
-
-pub const PROV_RSA_FULL = 1;
-
-pub const REGSAM = ACCESS_MASK;
-pub const ACCESS_MASK = DWORD;
-pub const PHKEY = *HKEY;
-pub const HKEY = *HKEY__;
-pub const HKEY__ = extern struct {
- unused: c_int,
-};
-pub const LSTATUS = LONG;
+use @import("bits.zig");
pub extern "advapi32" stdcallcc fn RegOpenKeyExW(
hKey: HKEY,
diff --git a/std/os/windows/bits.zig b/std/os/windows/bits.zig
new file mode 100644
index 0000000000..0bf2991903
--- /dev/null
+++ b/std/os/windows/bits.zig
@@ -0,0 +1,527 @@
+// Platform-dependent types and values that are used along with OS-specific APIs.
+
+const builtin = @import("builtin");
+const std = @import("../../std.zig");
+const assert = std.debug.assert;
+const maxInt = std.math.maxInt;
+
+pub const ERROR = @import("error.zig");
+
+/// The standard input device. Initially, this is the console input buffer, CONIN$.
+pub const STD_INPUT_HANDLE = maxInt(DWORD) - 10 + 1;
+
+/// The standard output device. Initially, this is the active console screen buffer, CONOUT$.
+pub const STD_OUTPUT_HANDLE = maxInt(DWORD) - 11 + 1;
+
+/// The standard error device. Initially, this is the active console screen buffer, CONOUT$.
+pub const STD_ERROR_HANDLE = maxInt(DWORD) - 12 + 1;
+
+pub const SHORT = c_short;
+pub const BOOL = c_int;
+pub const BOOLEAN = BYTE;
+pub const BYTE = u8;
+pub const CHAR = u8;
+pub const DWORD = u32;
+pub const FLOAT = f32;
+pub const HANDLE = *c_void;
+pub const HCRYPTPROV = ULONG_PTR;
+pub const HINSTANCE = *@OpaqueType();
+pub const HMODULE = *@OpaqueType();
+pub const FARPROC = *@OpaqueType();
+pub const INT = c_int;
+pub const LPBYTE = *BYTE;
+pub const LPCH = *CHAR;
+pub const LPCSTR = [*]const CHAR;
+pub const LPCTSTR = [*]const TCHAR;
+pub const LPCVOID = *const c_void;
+pub const LPDWORD = *DWORD;
+pub const LPSTR = [*]CHAR;
+pub const LPTSTR = if (UNICODE) LPWSTR else LPSTR;
+pub const LPVOID = *c_void;
+pub const LPWSTR = [*]WCHAR;
+pub const LPCWSTR = [*]const WCHAR;
+pub const PVOID = *c_void;
+pub const PWSTR = [*]WCHAR;
+pub const SIZE_T = usize;
+pub const TCHAR = if (UNICODE) WCHAR else u8;
+pub const UINT = c_uint;
+pub const ULONG_PTR = usize;
+pub const DWORD_PTR = ULONG_PTR;
+pub const UNICODE = false;
+pub const WCHAR = u16;
+pub const WORD = u16;
+pub const LARGE_INTEGER = i64;
+pub const ULONG = u32;
+pub const LONG = i32;
+pub const ULONGLONG = u64;
+pub const LONGLONG = i64;
+
+pub const TRUE = 1;
+pub const FALSE = 0;
+
+pub const INVALID_HANDLE_VALUE = @intToPtr(HANDLE, maxInt(usize));
+
+pub const INVALID_FILE_ATTRIBUTES = DWORD(maxInt(DWORD));
+
+pub const OVERLAPPED = extern struct {
+ Internal: ULONG_PTR,
+ InternalHigh: ULONG_PTR,
+ Offset: DWORD,
+ OffsetHigh: DWORD,
+ hEvent: ?HANDLE,
+};
+pub const LPOVERLAPPED = *OVERLAPPED;
+
+pub const MAX_PATH = 260;
+
+// TODO issue #305
+pub const FILE_INFO_BY_HANDLE_CLASS = u32;
+pub const FileBasicInfo = 0;
+pub const FileStandardInfo = 1;
+pub const FileNameInfo = 2;
+pub const FileRenameInfo = 3;
+pub const FileDispositionInfo = 4;
+pub const FileAllocationInfo = 5;
+pub const FileEndOfFileInfo = 6;
+pub const FileStreamInfo = 7;
+pub const FileCompressionInfo = 8;
+pub const FileAttributeTagInfo = 9;
+pub const FileIdBothDirectoryInfo = 10;
+pub const FileIdBothDirectoryRestartInfo = 11;
+pub const FileIoPriorityHintInfo = 12;
+pub const FileRemoteProtocolInfo = 13;
+pub const FileFullDirectoryInfo = 14;
+pub const FileFullDirectoryRestartInfo = 15;
+pub const FileStorageInfo = 16;
+pub const FileAlignmentInfo = 17;
+pub const FileIdInfo = 18;
+pub const FileIdExtdDirectoryInfo = 19;
+pub const FileIdExtdDirectoryRestartInfo = 20;
+
+pub const FILE_NAME_INFO = extern struct {
+ FileNameLength: DWORD,
+ FileName: [1]WCHAR,
+};
+
+/// Return the normalized drive name. This is the default.
+pub const FILE_NAME_NORMALIZED = 0x0;
+
+/// Return the opened file name (not normalized).
+pub const FILE_NAME_OPENED = 0x8;
+
+/// Return the path with the drive letter. This is the default.
+pub const VOLUME_NAME_DOS = 0x0;
+
+/// Return the path with a volume GUID path instead of the drive name.
+pub const VOLUME_NAME_GUID = 0x1;
+
+/// Return the path with no drive information.
+pub const VOLUME_NAME_NONE = 0x4;
+
+/// Return the path with the volume device path.
+pub const VOLUME_NAME_NT = 0x2;
+
+pub const SECURITY_ATTRIBUTES = extern struct {
+ nLength: DWORD,
+ lpSecurityDescriptor: ?*c_void,
+ bInheritHandle: BOOL,
+};
+pub const PSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES;
+pub const LPSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES;
+
+pub const GENERIC_READ = 0x80000000;
+pub const GENERIC_WRITE = 0x40000000;
+pub const GENERIC_EXECUTE = 0x20000000;
+pub const GENERIC_ALL = 0x10000000;
+
+pub const FILE_SHARE_DELETE = 0x00000004;
+pub const FILE_SHARE_READ = 0x00000001;
+pub const FILE_SHARE_WRITE = 0x00000002;
+
+pub const CREATE_ALWAYS = 2;
+pub const CREATE_NEW = 1;
+pub const OPEN_ALWAYS = 4;
+pub const OPEN_EXISTING = 3;
+pub const TRUNCATE_EXISTING = 5;
+
+pub const FILE_ATTRIBUTE_ARCHIVE = 0x20;
+pub const FILE_ATTRIBUTE_COMPRESSED = 0x800;
+pub const FILE_ATTRIBUTE_DEVICE = 0x40;
+pub const FILE_ATTRIBUTE_DIRECTORY = 0x10;
+pub const FILE_ATTRIBUTE_ENCRYPTED = 0x4000;
+pub const FILE_ATTRIBUTE_HIDDEN = 0x2;
+pub const FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x8000;
+pub const FILE_ATTRIBUTE_NORMAL = 0x80;
+pub const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000;
+pub const FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x20000;
+pub const FILE_ATTRIBUTE_OFFLINE = 0x1000;
+pub const FILE_ATTRIBUTE_READONLY = 0x1;
+pub const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x400000;
+pub const FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x40000;
+pub const FILE_ATTRIBUTE_REPARSE_POINT = 0x400;
+pub const FILE_ATTRIBUTE_SPARSE_FILE = 0x200;
+pub const FILE_ATTRIBUTE_SYSTEM = 0x4;
+pub const FILE_ATTRIBUTE_TEMPORARY = 0x100;
+pub const FILE_ATTRIBUTE_VIRTUAL = 0x10000;
+
+pub const PROCESS_INFORMATION = extern struct {
+ hProcess: HANDLE,
+ hThread: HANDLE,
+ dwProcessId: DWORD,
+ dwThreadId: DWORD,
+};
+
+pub const STARTUPINFOW = extern struct {
+ cb: DWORD,
+ lpReserved: ?LPWSTR,
+ lpDesktop: ?LPWSTR,
+ lpTitle: ?LPWSTR,
+ dwX: DWORD,
+ dwY: DWORD,
+ dwXSize: DWORD,
+ dwYSize: DWORD,
+ dwXCountChars: DWORD,
+ dwYCountChars: DWORD,
+ dwFillAttribute: DWORD,
+ dwFlags: DWORD,
+ wShowWindow: WORD,
+ cbReserved2: WORD,
+ lpReserved2: ?LPBYTE,
+ hStdInput: ?HANDLE,
+ hStdOutput: ?HANDLE,
+ hStdError: ?HANDLE,
+};
+
+pub const STARTF_FORCEONFEEDBACK = 0x00000040;
+pub const STARTF_FORCEOFFFEEDBACK = 0x00000080;
+pub const STARTF_PREVENTPINNING = 0x00002000;
+pub const STARTF_RUNFULLSCREEN = 0x00000020;
+pub const STARTF_TITLEISAPPID = 0x00001000;
+pub const STARTF_TITLEISLINKNAME = 0x00000800;
+pub const STARTF_UNTRUSTEDSOURCE = 0x00008000;
+pub const STARTF_USECOUNTCHARS = 0x00000008;
+pub const STARTF_USEFILLATTRIBUTE = 0x00000010;
+pub const STARTF_USEHOTKEY = 0x00000200;
+pub const STARTF_USEPOSITION = 0x00000004;
+pub const STARTF_USESHOWWINDOW = 0x00000001;
+pub const STARTF_USESIZE = 0x00000002;
+pub const STARTF_USESTDHANDLES = 0x00000100;
+
+pub const INFINITE = 4294967295;
+
+pub const WAIT_ABANDONED = 0x00000080;
+pub const WAIT_OBJECT_0 = 0x00000000;
+pub const WAIT_TIMEOUT = 0x00000102;
+pub const WAIT_FAILED = 0xFFFFFFFF;
+
+pub const HANDLE_FLAG_INHERIT = 0x00000001;
+pub const HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x00000002;
+
+pub const MOVEFILE_COPY_ALLOWED = 2;
+pub const MOVEFILE_CREATE_HARDLINK = 16;
+pub const MOVEFILE_DELAY_UNTIL_REBOOT = 4;
+pub const MOVEFILE_FAIL_IF_NOT_TRACKABLE = 32;
+pub const MOVEFILE_REPLACE_EXISTING = 1;
+pub const MOVEFILE_WRITE_THROUGH = 8;
+
+pub const FILE_BEGIN = 0;
+pub const FILE_CURRENT = 1;
+pub const FILE_END = 2;
+
+pub const HEAP_CREATE_ENABLE_EXECUTE = 0x00040000;
+pub const HEAP_GENERATE_EXCEPTIONS = 0x00000004;
+pub const HEAP_NO_SERIALIZE = 0x00000001;
+
+// AllocationType values
+pub const MEM_COMMIT = 0x1000;
+pub const MEM_RESERVE = 0x2000;
+pub const MEM_RESET = 0x80000;
+pub const MEM_RESET_UNDO = 0x1000000;
+pub const MEM_LARGE_PAGES = 0x20000000;
+pub const MEM_PHYSICAL = 0x400000;
+pub const MEM_TOP_DOWN = 0x100000;
+pub const MEM_WRITE_WATCH = 0x200000;
+
+// Protect values
+pub const PAGE_EXECUTE = 0x10;
+pub const PAGE_EXECUTE_READ = 0x20;
+pub const PAGE_EXECUTE_READWRITE = 0x40;
+pub const PAGE_EXECUTE_WRITECOPY = 0x80;
+pub const PAGE_NOACCESS = 0x01;
+pub const PAGE_READONLY = 0x02;
+pub const PAGE_READWRITE = 0x04;
+pub const PAGE_WRITECOPY = 0x08;
+pub const PAGE_TARGETS_INVALID = 0x40000000;
+pub const PAGE_TARGETS_NO_UPDATE = 0x40000000; // Same as PAGE_TARGETS_INVALID
+pub const PAGE_GUARD = 0x100;
+pub const PAGE_NOCACHE = 0x200;
+pub const PAGE_WRITECOMBINE = 0x400;
+
+// FreeType values
+pub const MEM_COALESCE_PLACEHOLDERS = 0x1;
+pub const MEM_RESERVE_PLACEHOLDERS = 0x2;
+pub const MEM_DECOMMIT = 0x4000;
+pub const MEM_RELEASE = 0x8000;
+
+pub const PTHREAD_START_ROUTINE = extern fn (LPVOID) DWORD;
+pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE;
+
+pub const WIN32_FIND_DATAW = extern struct {
+ dwFileAttributes: DWORD,
+ ftCreationTime: FILETIME,
+ ftLastAccessTime: FILETIME,
+ ftLastWriteTime: FILETIME,
+ nFileSizeHigh: DWORD,
+ nFileSizeLow: DWORD,
+ dwReserved0: DWORD,
+ dwReserved1: DWORD,
+ cFileName: [260]u16,
+ cAlternateFileName: [14]u16,
+};
+
+pub const FILETIME = extern struct {
+ dwLowDateTime: DWORD,
+ dwHighDateTime: DWORD,
+};
+
+pub const SYSTEM_INFO = extern struct {
+ anon1: extern union {
+ dwOemId: DWORD,
+ anon2: extern struct {
+ wProcessorArchitecture: WORD,
+ wReserved: WORD,
+ },
+ },
+ dwPageSize: DWORD,
+ lpMinimumApplicationAddress: LPVOID,
+ lpMaximumApplicationAddress: LPVOID,
+ dwActiveProcessorMask: DWORD_PTR,
+ dwNumberOfProcessors: DWORD,
+ dwProcessorType: DWORD,
+ dwAllocationGranularity: DWORD,
+ wProcessorLevel: WORD,
+ wProcessorRevision: WORD,
+};
+
+pub const HRESULT = c_long;
+
+pub const KNOWNFOLDERID = GUID;
+pub const GUID = extern struct {
+ Data1: c_ulong,
+ Data2: c_ushort,
+ Data3: c_ushort,
+ Data4: [8]u8,
+
+ pub fn parse(str: []const u8) GUID {
+ var guid: GUID = undefined;
+ var index: usize = 0;
+ assert(str[index] == '{');
+ index += 1;
+
+ guid.Data1 = std.fmt.parseUnsigned(c_ulong, str[index .. index + 8], 16) catch unreachable;
+ index += 8;
+
+ assert(str[index] == '-');
+ index += 1;
+
+ guid.Data2 = std.fmt.parseUnsigned(c_ushort, str[index .. index + 4], 16) catch unreachable;
+ index += 4;
+
+ assert(str[index] == '-');
+ index += 1;
+
+ guid.Data3 = std.fmt.parseUnsigned(c_ushort, str[index .. index + 4], 16) catch unreachable;
+ index += 4;
+
+ assert(str[index] == '-');
+ index += 1;
+
+ guid.Data4[0] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
+ index += 2;
+ guid.Data4[1] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
+ index += 2;
+
+ assert(str[index] == '-');
+ index += 1;
+
+ var i: usize = 2;
+ while (i < guid.Data4.len) : (i += 1) {
+ guid.Data4[i] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
+ index += 2;
+ }
+
+ assert(str[index] == '}');
+ index += 1;
+ return guid;
+ }
+};
+
+pub const FOLDERID_LocalAppData = GUID.parse("{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}");
+
+pub const KF_FLAG_DEFAULT = 0;
+pub const KF_FLAG_NO_APPCONTAINER_REDIRECTION = 65536;
+pub const KF_FLAG_CREATE = 32768;
+pub const KF_FLAG_DONT_VERIFY = 16384;
+pub const KF_FLAG_DONT_UNEXPAND = 8192;
+pub const KF_FLAG_NO_ALIAS = 4096;
+pub const KF_FLAG_INIT = 2048;
+pub const KF_FLAG_DEFAULT_PATH = 1024;
+pub const KF_FLAG_NOT_PARENT_RELATIVE = 512;
+pub const KF_FLAG_SIMPLE_IDLIST = 256;
+pub const KF_FLAG_ALIAS_ONLY = -2147483648;
+
+pub const S_OK = 0;
+pub const E_NOTIMPL = @bitCast(c_long, c_ulong(0x80004001));
+pub const E_NOINTERFACE = @bitCast(c_long, c_ulong(0x80004002));
+pub const E_POINTER = @bitCast(c_long, c_ulong(0x80004003));
+pub const E_ABORT = @bitCast(c_long, c_ulong(0x80004004));
+pub const E_FAIL = @bitCast(c_long, c_ulong(0x80004005));
+pub const E_UNEXPECTED = @bitCast(c_long, c_ulong(0x8000FFFF));
+pub const E_ACCESSDENIED = @bitCast(c_long, c_ulong(0x80070005));
+pub const E_HANDLE = @bitCast(c_long, c_ulong(0x80070006));
+pub const E_OUTOFMEMORY = @bitCast(c_long, c_ulong(0x8007000E));
+pub const E_INVALIDARG = @bitCast(c_long, c_ulong(0x80070057));
+
+pub const FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
+pub const FILE_FLAG_DELETE_ON_CLOSE = 0x04000000;
+pub const FILE_FLAG_NO_BUFFERING = 0x20000000;
+pub const FILE_FLAG_OPEN_NO_RECALL = 0x00100000;
+pub const FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;
+pub const FILE_FLAG_OVERLAPPED = 0x40000000;
+pub const FILE_FLAG_POSIX_SEMANTICS = 0x0100000;
+pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000;
+pub const FILE_FLAG_SESSION_AWARE = 0x00800000;
+pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
+pub const FILE_FLAG_WRITE_THROUGH = 0x80000000;
+
+pub const SMALL_RECT = extern struct {
+ Left: SHORT,
+ Top: SHORT,
+ Right: SHORT,
+ Bottom: SHORT,
+};
+
+pub const COORD = extern struct {
+ X: SHORT,
+ Y: SHORT,
+};
+
+pub const CREATE_UNICODE_ENVIRONMENT = 1024;
+
+pub const TLS_OUT_OF_INDEXES = 4294967295;
+pub const IMAGE_TLS_DIRECTORY = extern struct {
+ StartAddressOfRawData: usize,
+ EndAddressOfRawData: usize,
+ AddressOfIndex: usize,
+ AddressOfCallBacks: usize,
+ SizeOfZeroFill: u32,
+ Characteristics: u32,
+};
+pub const IMAGE_TLS_DIRECTORY64 = IMAGE_TLS_DIRECTORY;
+pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY;
+
+pub const PIMAGE_TLS_CALLBACK = ?extern fn (PVOID, DWORD, PVOID) void;
+
+pub const PROV_RSA_FULL = 1;
+
+pub const REGSAM = ACCESS_MASK;
+pub const ACCESS_MASK = DWORD;
+pub const PHKEY = *HKEY;
+pub const HKEY = *HKEY__;
+pub const HKEY__ = extern struct {
+ unused: c_int,
+};
+pub const LSTATUS = LONG;
+
+pub const FILE_NOTIFY_INFORMATION = extern struct {
+ NextEntryOffset: DWORD,
+ Action: DWORD,
+ FileNameLength: DWORD,
+ FileName: [1]WCHAR,
+};
+
+pub const FILE_ACTION_ADDED = 0x00000001;
+pub const FILE_ACTION_REMOVED = 0x00000002;
+pub const FILE_ACTION_MODIFIED = 0x00000003;
+pub const FILE_ACTION_RENAMED_OLD_NAME = 0x00000004;
+pub const FILE_ACTION_RENAMED_NEW_NAME = 0x00000005;
+
+pub const LPOVERLAPPED_COMPLETION_ROUTINE = ?extern fn (DWORD, DWORD, *OVERLAPPED) void;
+
+pub const FILE_LIST_DIRECTORY = 1;
+
+pub const FILE_NOTIFY_CHANGE_CREATION = 64;
+pub const FILE_NOTIFY_CHANGE_SIZE = 8;
+pub const FILE_NOTIFY_CHANGE_SECURITY = 256;
+pub const FILE_NOTIFY_CHANGE_LAST_ACCESS = 32;
+pub const FILE_NOTIFY_CHANGE_LAST_WRITE = 16;
+pub const FILE_NOTIFY_CHANGE_DIR_NAME = 2;
+pub const FILE_NOTIFY_CHANGE_FILE_NAME = 1;
+pub const FILE_NOTIFY_CHANGE_ATTRIBUTES = 4;
+
+pub const CONSOLE_SCREEN_BUFFER_INFO = extern struct {
+ dwSize: COORD,
+ dwCursorPosition: COORD,
+ wAttributes: WORD,
+ srWindow: SMALL_RECT,
+ dwMaximumWindowSize: COORD,
+};
+
+pub const FOREGROUND_BLUE = 1;
+pub const FOREGROUND_GREEN = 2;
+pub const FOREGROUND_RED = 4;
+pub const FOREGROUND_INTENSITY = 8;
+
+pub const LIST_ENTRY = extern struct {
+ Flink: *LIST_ENTRY,
+ Blink: *LIST_ENTRY,
+};
+
+pub const RTL_CRITICAL_SECTION_DEBUG = extern struct {
+ Type: WORD,
+ CreatorBackTraceIndex: WORD,
+ CriticalSection: *RTL_CRITICAL_SECTION,
+ ProcessLocksList: LIST_ENTRY,
+ EntryCount: DWORD,
+ ContentionCount: DWORD,
+ Flags: DWORD,
+ CreatorBackTraceIndexHigh: WORD,
+ SpareWORD: WORD,
+};
+
+pub const RTL_CRITICAL_SECTION = extern struct {
+ DebugInfo: *RTL_CRITICAL_SECTION_DEBUG,
+ LockCount: LONG,
+ RecursionCount: LONG,
+ OwningThread: HANDLE,
+ LockSemaphore: HANDLE,
+ SpinCount: ULONG_PTR,
+};
+
+pub const CRITICAL_SECTION = RTL_CRITICAL_SECTION;
+pub const INIT_ONCE = RTL_RUN_ONCE;
+pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE_INIT;
+pub const INIT_ONCE_FN = extern fn (InitOnce: *INIT_ONCE, Parameter: ?*c_void, Context: ?*c_void) BOOL;
+
+pub const RTL_RUN_ONCE = extern struct {
+ Ptr: ?*c_void,
+};
+
+pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE{ .Ptr = null };
+
+pub const COINIT_APARTMENTTHREADED = COINIT.COINIT_APARTMENTTHREADED;
+pub const COINIT_MULTITHREADED = COINIT.COINIT_MULTITHREADED;
+pub const COINIT_DISABLE_OLE1DDE = COINIT.COINIT_DISABLE_OLE1DDE;
+pub const COINIT_SPEED_OVER_MEMORY = COINIT.COINIT_SPEED_OVER_MEMORY;
+pub const COINIT = extern enum {
+ COINIT_APARTMENTTHREADED = 2,
+ COINIT_MULTITHREADED = 0,
+ COINIT_DISABLE_OLE1DDE = 4,
+ COINIT_SPEED_OVER_MEMORY = 8,
+};
+
+/// > The maximum path of 32,767 characters is approximate, because the "\\?\"
+/// > prefix may be expanded to a longer string by the system at run time, and
+/// > this expansion applies to the total length.
+/// from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
+pub const PATH_MAX_WIDE = 32767;
diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig
index 7e99f7eda9..2bd1824620 100644
--- a/std/os/windows/kernel32.zig
+++ b/std/os/windows/kernel32.zig
@@ -1,4 +1,4 @@
-use @import("../windows.zig");
+use @import("bits.zig");
pub extern "kernel32" stdcallcc fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) BOOL;
@@ -189,86 +189,9 @@ pub extern "kernel32" stdcallcc fn GetProcAddress(hModule: HMODULE, lpProcName:
pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) BOOL;
-pub const FILE_NOTIFY_INFORMATION = extern struct {
- NextEntryOffset: DWORD,
- Action: DWORD,
- FileNameLength: DWORD,
- FileName: [1]WCHAR,
-};
-
-pub const FILE_ACTION_ADDED = 0x00000001;
-pub const FILE_ACTION_REMOVED = 0x00000002;
-pub const FILE_ACTION_MODIFIED = 0x00000003;
-pub const FILE_ACTION_RENAMED_OLD_NAME = 0x00000004;
-pub const FILE_ACTION_RENAMED_NEW_NAME = 0x00000005;
-
-pub const LPOVERLAPPED_COMPLETION_ROUTINE = ?extern fn (DWORD, DWORD, *OVERLAPPED) void;
-
-pub const FILE_LIST_DIRECTORY = 1;
-
-pub const FILE_NOTIFY_CHANGE_CREATION = 64;
-pub const FILE_NOTIFY_CHANGE_SIZE = 8;
-pub const FILE_NOTIFY_CHANGE_SECURITY = 256;
-pub const FILE_NOTIFY_CHANGE_LAST_ACCESS = 32;
-pub const FILE_NOTIFY_CHANGE_LAST_WRITE = 16;
-pub const FILE_NOTIFY_CHANGE_DIR_NAME = 2;
-pub const FILE_NOTIFY_CHANGE_FILE_NAME = 1;
-pub const FILE_NOTIFY_CHANGE_ATTRIBUTES = 4;
-
-pub const CONSOLE_SCREEN_BUFFER_INFO = extern struct {
- dwSize: COORD,
- dwCursorPosition: COORD,
- wAttributes: WORD,
- srWindow: SMALL_RECT,
- dwMaximumWindowSize: COORD,
-};
-
-pub const FOREGROUND_BLUE = 1;
-pub const FOREGROUND_GREEN = 2;
-pub const FOREGROUND_RED = 4;
-pub const FOREGROUND_INTENSITY = 8;
-
pub extern "kernel32" stdcallcc fn InitializeCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void;
pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void;
pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void;
pub extern "kernel32" stdcallcc fn DeleteCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void;
-pub const LIST_ENTRY = extern struct {
- Flink: *LIST_ENTRY,
- Blink: *LIST_ENTRY,
-};
-
-pub const RTL_CRITICAL_SECTION_DEBUG = extern struct {
- Type: WORD,
- CreatorBackTraceIndex: WORD,
- CriticalSection: *RTL_CRITICAL_SECTION,
- ProcessLocksList: LIST_ENTRY,
- EntryCount: DWORD,
- ContentionCount: DWORD,
- Flags: DWORD,
- CreatorBackTraceIndexHigh: WORD,
- SpareWORD: WORD,
-};
-
-pub const RTL_CRITICAL_SECTION = extern struct {
- DebugInfo: *RTL_CRITICAL_SECTION_DEBUG,
- LockCount: LONG,
- RecursionCount: LONG,
- OwningThread: HANDLE,
- LockSemaphore: HANDLE,
- SpinCount: ULONG_PTR,
-};
-
-pub const CRITICAL_SECTION = RTL_CRITICAL_SECTION;
-pub const INIT_ONCE = RTL_RUN_ONCE;
-pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE_INIT;
-
pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter: ?*c_void, Context: ?*c_void) BOOL;
-
-pub const INIT_ONCE_FN = extern fn (InitOnce: *INIT_ONCE, Parameter: ?*c_void, Context: ?*c_void) BOOL;
-
-pub const RTL_RUN_ONCE = extern struct {
- Ptr: ?*c_void,
-};
-
-pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE{ .Ptr = null };
diff --git a/std/os/windows/ntdll.zig b/std/os/windows/ntdll.zig
index 1b63c1e7ec..60c03ffc07 100644
--- a/std/os/windows/ntdll.zig
+++ b/std/os/windows/ntdll.zig
@@ -1,3 +1,3 @@
-use @import("../windows.zig");
+use @import("bits.zig");
pub extern "NtDll" stdcallcc fn RtlCaptureStackBackTrace(FramesToSkip: DWORD, FramesToCapture: DWORD, BackTrace: **c_void, BackTraceHash: ?*DWORD) WORD;
diff --git a/std/os/windows/ole32.zig b/std/os/windows/ole32.zig
index 1ecfecba3c..80f5bebc36 100644
--- a/std/os/windows/ole32.zig
+++ b/std/os/windows/ole32.zig
@@ -1,17 +1,6 @@
-use @import("../windows.zig");
+use @import("bits.zig");
pub extern "ole32" stdcallcc fn CoTaskMemFree(pv: LPVOID) void;
pub extern "ole32" stdcallcc fn CoUninitialize() void;
pub extern "ole32" stdcallcc fn CoGetCurrentProcess() DWORD;
pub extern "ole32" stdcallcc fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) HRESULT;
-
-pub const COINIT_APARTMENTTHREADED = COINIT.COINIT_APARTMENTTHREADED;
-pub const COINIT_MULTITHREADED = COINIT.COINIT_MULTITHREADED;
-pub const COINIT_DISABLE_OLE1DDE = COINIT.COINIT_DISABLE_OLE1DDE;
-pub const COINIT_SPEED_OVER_MEMORY = COINIT.COINIT_SPEED_OVER_MEMORY;
-pub const COINIT = extern enum {
- COINIT_APARTMENTTHREADED = 2,
- COINIT_MULTITHREADED = 0,
- COINIT_DISABLE_OLE1DDE = 4,
- COINIT_SPEED_OVER_MEMORY = 8,
-};
diff --git a/std/os/windows/shell32.zig b/std/os/windows/shell32.zig
index 84accecb70..9f24acc5c4 100644
--- a/std/os/windows/shell32.zig
+++ b/std/os/windows/shell32.zig
@@ -1,3 +1,3 @@
-use @import("../windows.zig");
+use @import("bits.zig");
pub extern "shell32" stdcallcc fn SHGetKnownFolderPath(rfid: *const KNOWNFOLDERID, dwFlags: DWORD, hToken: ?HANDLE, ppszPath: *[*]WCHAR) HRESULT;
diff --git a/std/os/windows/util.zig b/std/os/windows/util.zig
deleted file mode 100644
index 72c84502e3..0000000000
--- a/std/os/windows/util.zig
+++ /dev/null
@@ -1,316 +0,0 @@
-const std = @import("../../std.zig");
-const builtin = @import("builtin");
-const os = std.os;
-const unicode = std.unicode;
-const windows = std.os.windows;
-const assert = std.debug.assert;
-const mem = std.mem;
-const BufMap = std.BufMap;
-const cstr = std.cstr;
-
-// > The maximum path of 32,767 characters is approximate, because the "\\?\"
-// > prefix may be expanded to a longer string by the system at run time, and
-// > this expansion applies to the total length.
-// from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
-pub const PATH_MAX_WIDE = 32767;
-
-pub const WaitError = error{
- WaitAbandoned,
- WaitTimeOut,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-pub fn windowsWaitSingle(handle: windows.HANDLE, milliseconds: windows.DWORD) WaitError!void {
- const result = windows.WaitForSingleObject(handle, milliseconds);
- return switch (result) {
- windows.WAIT_ABANDONED => error.WaitAbandoned,
- windows.WAIT_OBJECT_0 => {},
- windows.WAIT_TIMEOUT => error.WaitTimeOut,
- windows.WAIT_FAILED => x: {
- const err = windows.GetLastError();
- break :x switch (err) {
- else => os.unexpectedErrorWindows(err),
- };
- },
- else => error.Unexpected,
- };
-}
-
-pub fn windowsClose(handle: windows.HANDLE) void {
- assert(windows.CloseHandle(handle) != 0);
-}
-
-pub const ReadError = error{
- OperationAborted,
- BrokenPipe,
- Unexpected,
-};
-
-pub const WriteError = error{
- SystemResources,
- OperationAborted,
- BrokenPipe,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) WriteError!void {
- var bytes_written: windows.DWORD = undefined;
- if (windows.WriteFile(handle, bytes.ptr, @intCast(u32, bytes.len), &bytes_written, null) == 0) {
- const err = windows.GetLastError();
- return switch (err) {
- windows.ERROR.INVALID_USER_BUFFER => WriteError.SystemResources,
- windows.ERROR.NOT_ENOUGH_MEMORY => WriteError.SystemResources,
- windows.ERROR.OPERATION_ABORTED => WriteError.OperationAborted,
- windows.ERROR.NOT_ENOUGH_QUOTA => WriteError.SystemResources,
- windows.ERROR.IO_PENDING => unreachable,
- windows.ERROR.BROKEN_PIPE => WriteError.BrokenPipe,
- else => os.unexpectedErrorWindows(err),
- };
- }
-}
-
-pub fn windowsIsTty(handle: windows.HANDLE) bool {
- if (windowsIsCygwinPty(handle))
- return true;
-
- var out: windows.DWORD = undefined;
- return windows.GetConsoleMode(handle, &out) != 0;
-}
-
-pub fn windowsIsCygwinPty(handle: windows.HANDLE) bool {
- const size = @sizeOf(windows.FILE_NAME_INFO);
- var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = []u8{0} ** (size + windows.MAX_PATH);
-
- if (windows.GetFileInformationByHandleEx(
- handle,
- windows.FileNameInfo,
- @ptrCast(*c_void, &name_info_bytes[0]),
- @intCast(u32, name_info_bytes.len),
- ) == 0) {
- return false;
- }
-
- const name_info = @ptrCast(*const windows.FILE_NAME_INFO, &name_info_bytes[0]);
- const name_bytes = name_info_bytes[size .. size + usize(name_info.FileNameLength)];
- const name_wide = @bytesToSlice(u16, name_bytes);
- return mem.indexOf(u16, name_wide, []u16{ 'm', 's', 'y', 's', '-' }) != null or
- mem.indexOf(u16, name_wide, []u16{ '-', 'p', 't', 'y' }) != null;
-}
-
-pub const OpenError = error{
- SharingViolation,
- PathAlreadyExists,
-
- /// When any of the path components can not be found or the file component can not
- /// be found. Some operating systems distinguish between path components not found and
- /// file components not found, but they are collapsed into FileNotFound to gain
- /// consistency across operating systems.
- FileNotFound,
-
- AccessDenied,
- PipeBusy,
- NameTooLong,
-
- /// On Windows, file paths must be valid Unicode.
- InvalidUtf8,
-
- /// On Windows, file paths cannot contain these characters:
- /// '/', '*', '?', '"', '<', '>', '|'
- BadPathName,
-
- /// See https://github.com/ziglang/zig/issues/1396
- Unexpected,
-};
-
-pub fn windowsOpenW(
- file_path_w: [*]const u16,
- desired_access: windows.DWORD,
- share_mode: windows.DWORD,
- creation_disposition: windows.DWORD,
- flags_and_attrs: windows.DWORD,
-) OpenError!windows.HANDLE {
- const result = windows.CreateFileW(file_path_w, desired_access, share_mode, null, creation_disposition, flags_and_attrs, null);
-
- if (result == windows.INVALID_HANDLE_VALUE) {
- const err = windows.GetLastError();
- switch (err) {
- windows.ERROR.SHARING_VIOLATION => return OpenError.SharingViolation,
- windows.ERROR.ALREADY_EXISTS => return OpenError.PathAlreadyExists,
- windows.ERROR.FILE_EXISTS => return OpenError.PathAlreadyExists,
- windows.ERROR.FILE_NOT_FOUND => return OpenError.FileNotFound,
- windows.ERROR.PATH_NOT_FOUND => return OpenError.FileNotFound,
- windows.ERROR.ACCESS_DENIED => return OpenError.AccessDenied,
- windows.ERROR.PIPE_BUSY => return OpenError.PipeBusy,
- else => return os.unexpectedErrorWindows(err),
- }
- }
-
- return result;
-}
-
-pub fn windowsOpen(
- file_path: []const u8,
- desired_access: windows.DWORD,
- share_mode: windows.DWORD,
- creation_disposition: windows.DWORD,
- flags_and_attrs: windows.DWORD,
-) OpenError!windows.HANDLE {
- const file_path_w = try sliceToPrefixedFileW(file_path);
- return windowsOpenW(&file_path_w, desired_access, share_mode, creation_disposition, flags_and_attrs);
-}
-
-/// Caller must free result.
-pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u16 {
- // count bytes needed
- const max_chars_needed = x: {
- var max_chars_needed: usize = 4; // 4 for the final 4 null bytes
- var it = env_map.iterator();
- while (it.next()) |pair| {
- // +1 for '='
- // +1 for null byte
- max_chars_needed += pair.key.len + pair.value.len + 2;
- }
- break :x max_chars_needed;
- };
- const result = try allocator.alloc(u16, max_chars_needed);
- errdefer allocator.free(result);
-
- var it = env_map.iterator();
- var i: usize = 0;
- while (it.next()) |pair| {
- i += try unicode.utf8ToUtf16Le(result[i..], pair.key);
- result[i] = '=';
- i += 1;
- i += try unicode.utf8ToUtf16Le(result[i..], pair.value);
- result[i] = 0;
- i += 1;
- }
- result[i] = 0;
- i += 1;
- result[i] = 0;
- i += 1;
- result[i] = 0;
- i += 1;
- result[i] = 0;
- i += 1;
- return allocator.shrink(result, i);
-}
-
-pub fn windowsFindFirstFile(
- dir_path: []const u8,
- find_file_data: *windows.WIN32_FIND_DATAW,
-) !windows.HANDLE {
- const dir_path_w = try sliceToPrefixedSuffixedFileW(dir_path, []u16{ '\\', '*', 0 });
- const handle = windows.FindFirstFileW(&dir_path_w, find_file_data);
-
- if (handle == windows.INVALID_HANDLE_VALUE) {
- const err = windows.GetLastError();
- switch (err) {
- windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
- windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
- else => return os.unexpectedErrorWindows(err),
- }
- }
-
- return handle;
-}
-
-/// Returns `true` if there was another file, `false` otherwise.
-pub fn windowsFindNextFile(handle: windows.HANDLE, find_file_data: *windows.WIN32_FIND_DATAW) !bool {
- if (windows.FindNextFileW(handle, find_file_data) == 0) {
- const err = windows.GetLastError();
- return switch (err) {
- windows.ERROR.NO_MORE_FILES => false,
- else => os.unexpectedErrorWindows(err),
- };
- }
- return true;
-}
-
-pub const WindowsCreateIoCompletionPortError = error{Unexpected};
-
-pub fn windowsCreateIoCompletionPort(file_handle: windows.HANDLE, existing_completion_port: ?windows.HANDLE, completion_key: usize, concurrent_thread_count: windows.DWORD) !windows.HANDLE {
- const handle = windows.CreateIoCompletionPort(file_handle, existing_completion_port, completion_key, concurrent_thread_count) orelse {
- const err = windows.GetLastError();
- switch (err) {
- windows.ERROR.INVALID_PARAMETER => unreachable,
- else => return os.unexpectedErrorWindows(err),
- }
- };
- return handle;
-}
-
-pub const WindowsPostQueuedCompletionStatusError = error{Unexpected};
-
-pub fn windowsPostQueuedCompletionStatus(completion_port: windows.HANDLE, bytes_transferred_count: windows.DWORD, completion_key: usize, lpOverlapped: ?*windows.OVERLAPPED) WindowsPostQueuedCompletionStatusError!void {
- if (windows.PostQueuedCompletionStatus(completion_port, bytes_transferred_count, completion_key, lpOverlapped) == 0) {
- const err = windows.GetLastError();
- switch (err) {
- else => return os.unexpectedErrorWindows(err),
- }
- }
-}
-
-pub const WindowsWaitResult = enum {
- Normal,
- Aborted,
- Cancelled,
- EOF,
-};
-
-pub fn windowsGetQueuedCompletionStatus(completion_port: windows.HANDLE, bytes_transferred_count: *windows.DWORD, lpCompletionKey: *usize, lpOverlapped: *?*windows.OVERLAPPED, dwMilliseconds: windows.DWORD) WindowsWaitResult {
- if (windows.GetQueuedCompletionStatus(completion_port, bytes_transferred_count, lpCompletionKey, lpOverlapped, dwMilliseconds) == windows.FALSE) {
- const err = windows.GetLastError();
- switch (err) {
- windows.ERROR.ABANDONED_WAIT_0 => return WindowsWaitResult.Aborted,
- windows.ERROR.OPERATION_ABORTED => return WindowsWaitResult.Cancelled,
- windows.ERROR.HANDLE_EOF => return WindowsWaitResult.EOF,
- else => {
- if (std.debug.runtime_safety) {
- std.debug.panic("unexpected error: {}\n", err);
- }
- },
- }
- }
- return WindowsWaitResult.Normal;
-}
-
-pub fn cStrToPrefixedFileW(s: [*]const u8) ![PATH_MAX_WIDE + 1]u16 {
- return sliceToPrefixedFileW(mem.toSliceConst(u8, s));
-}
-
-pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 {
- return sliceToPrefixedSuffixedFileW(s, []u16{0});
-}
-
-pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) ![PATH_MAX_WIDE + suffix.len]u16 {
- // TODO well defined copy elision
- var result: [PATH_MAX_WIDE + suffix.len]u16 = undefined;
-
- // > File I/O functions in the Windows API convert "/" to "\" as part of
- // > converting the name to an NT-style name, except when using the "\\?\"
- // > prefix as detailed in the following sections.
- // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
- // Because we want the larger maximum path length for absolute paths, we
- // disallow forward slashes in zig std lib file functions on Windows.
- for (s) |byte| {
- switch (byte) {
- '/', '*', '?', '"', '<', '>', '|' => return error.BadPathName,
- else => {},
- }
- }
- const start_index = if (mem.startsWith(u8, s, "\\\\") or !os.path.isAbsolute(s)) 0 else blk: {
- const prefix = []u16{ '\\', '\\', '?', '\\' };
- mem.copy(u16, result[0..], prefix);
- break :blk prefix.len;
- };
- const end_index = start_index + try std.unicode.utf8ToUtf16Le(result[start_index..], s);
- assert(end_index <= result.len);
- if (end_index + suffix.len > result.len) return error.NameTooLong;
- mem.copy(u16, result[end_index..], suffix);
- return result;
-}
diff --git a/std/os/zen.zig b/std/os/zen.zig
index 0564956b24..8d2f963486 100644
--- a/std/os/zen.zig
+++ b/std/os/zen.zig
@@ -80,7 +80,7 @@ pub const STDOUT_FILENO = 1;
pub const STDERR_FILENO = 2;
// FIXME: let's borrow Linux's error numbers for now.
-use @import("linux/errno.zig");
+use @import("bits/linux/errno.zig");
// Get the errno from a syscall return value, or 0 for no error.
pub fn getErrno(r: usize) usize {
const signed_r = @bitCast(isize, r);
diff --git a/std/packed_int_array.zig b/std/packed_int_array.zig
index 065f1becd8..35cffec218 100644
--- a/std/packed_int_array.zig
+++ b/std/packed_int_array.zig
@@ -619,7 +619,7 @@ test "PackedIntArray at end of available memory" {
const PackedArray = PackedIntArray(u3, 8);
const Padded = struct {
- _: [std.os.page_size - @sizeOf(PackedArray)]u8,
+ _: [std.mem.page_size - @sizeOf(PackedArray)]u8,
p: PackedArray,
};
@@ -641,9 +641,9 @@ test "PackedIntSlice at end of available memory" {
var da = std.heap.DirectAllocator.init();
const allocator = &da.allocator;
- var page = try allocator.alloc(u8, std.os.page_size);
+ var page = try allocator.alloc(u8, std.mem.page_size);
defer allocator.free(page);
- var p = PackedSlice.init(page[std.os.page_size - 2 ..], 1);
+ var p = PackedSlice.init(page[std.mem.page_size - 2 ..], 1);
p.set(0, std.math.maxInt(u11));
}
diff --git a/std/pdb.zig b/std/pdb.zig
index f3b73663e8..ffe2120296 100644
--- a/std/pdb.zig
+++ b/std/pdb.zig
@@ -6,6 +6,7 @@ const mem = std.mem;
const os = std.os;
const warn = std.debug.warn;
const coff = std.coff;
+const File = std.fs.File;
const ArrayList = std.ArrayList;
@@ -459,7 +460,7 @@ pub const PDBStringTableHeader = packed struct {
};
pub const Pdb = struct {
- in_file: os.File,
+ in_file: File,
allocator: *mem.Allocator,
coff: *coff.Coff,
string_table: *MsfStream,
@@ -468,7 +469,7 @@ pub const Pdb = struct {
msf: Msf,
pub fn openFile(self: *Pdb, coff_ptr: *coff.Coff, file_name: []u8) !void {
- self.in_file = try os.File.openRead(file_name);
+ self.in_file = try File.openRead(file_name);
self.allocator = coff_ptr.allocator;
self.coff = coff_ptr;
@@ -492,7 +493,7 @@ const Msf = struct {
directory: MsfStream,
streams: []MsfStream,
- fn openFile(self: *Msf, allocator: *mem.Allocator, file: os.File) !void {
+ fn openFile(self: *Msf, allocator: *mem.Allocator, file: File) !void {
var file_stream = file.inStream();
const in = &file_stream.stream;
@@ -587,7 +588,7 @@ const SuperBlock = packed struct {
};
const MsfStream = struct {
- in_file: os.File,
+ in_file: File,
pos: u64,
blocks: []u32,
block_size: u32,
@@ -598,7 +599,7 @@ const MsfStream = struct {
pub const Error = @typeOf(read).ReturnType.ErrorSet;
pub const Stream = io.InStream(Error);
- fn init(block_size: u32, block_count: u32, pos: u64, file: os.File, allocator: *mem.Allocator) !MsfStream {
+ fn init(block_size: u32, block_count: u32, pos: u64, file: File, allocator: *mem.Allocator) !MsfStream {
var stream = MsfStream{
.in_file = file,
.pos = 0,
@@ -660,9 +661,8 @@ const MsfStream = struct {
return size;
}
- // XXX: The `len` parameter should be signed
- fn seekForward(self: *MsfStream, len: u64) !void {
- self.pos += len;
+ fn seekBy(self: *MsfStream, len: i64) !void {
+ self.pos = @intCast(u64, @intCast(i64, self.pos) + len);
if (self.pos >= self.blocks.len * self.block_size)
return error.EOF;
}
diff --git a/std/process.zig b/std/process.zig
new file mode 100644
index 0000000000..7c5e7fbb07
--- /dev/null
+++ b/std/process.zig
@@ -0,0 +1,617 @@
+const builtin = @import("builtin");
+const std = @import("std.zig");
+const os = std.os;
+const fs = std.fs;
+const BufMap = std.BufMap;
+const Buffer = std.Buffer;
+const mem = std.mem;
+const math = std.math;
+const Allocator = mem.Allocator;
+const assert = std.debug.assert;
+const testing = std.testing;
+
+pub const abort = os.abort;
+pub const exit = os.exit;
+pub const changeCurDir = os.chdir;
+pub const changeCurDirC = os.chdirC;
+
+/// The result is a slice of `out_buffer`, from index `0`.
+pub fn getCwd(out_buffer: *[fs.MAX_PATH_BYTES]u8) ![]u8 {
+ return os.getcwd(out_buffer);
+}
+
+/// Caller must free the returned memory.
+pub fn getCwdAlloc(allocator: *Allocator) ![]u8 {
+ var buf: [fs.MAX_PATH_BYTES]u8 = undefined;
+ return mem.dupe(allocator, u8, try os.getcwd(&buf));
+}
+
+test "getCwdAlloc" {
+ // at least call it so it gets compiled
+ var buf: [1000]u8 = undefined;
+ const allocator = &std.heap.FixedBufferAllocator.init(&buf).allocator;
+ _ = getCwdAlloc(allocator) catch undefined;
+}
+
+/// Caller must free result when done.
+/// TODO make this go through libc when we have it
+pub fn getEnvMap(allocator: *Allocator) !BufMap {
+ var result = BufMap.init(allocator);
+ errdefer result.deinit();
+
+ if (os.windows.is_the_target) {
+ const ptr = try os.windows.GetEnvironmentStringsW();
+ defer os.windows.FreeEnvironmentStringsW(ptr);
+
+ var i: usize = 0;
+ while (true) {
+ if (ptr[i] == 0) return result;
+
+ const key_start = i;
+
+ while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
+ const key_w = ptr[key_start..i];
+ const key = try std.unicode.utf16leToUtf8Alloc(allocator, key_w);
+ errdefer allocator.free(key);
+
+ if (ptr[i] == '=') i += 1;
+
+ const value_start = i;
+ while (ptr[i] != 0) : (i += 1) {}
+ const value_w = ptr[value_start..i];
+ const value = try std.unicode.utf16leToUtf8Alloc(allocator, value_w);
+ errdefer allocator.free(value);
+
+ i += 1; // skip over null byte
+
+ try result.setMove(key, value);
+ }
+ } else if (builtin.os == .wasi) {
+ var environ_count: usize = undefined;
+ var environ_buf_size: usize = undefined;
+
+ const environ_sizes_get_ret = os.wasi.environ_sizes_get(&environ_count, &environ_buf_size);
+ if (environ_sizes_get_ret != os.wasi.ESUCCESS) {
+ return os.unexpectedErrno(environ_sizes_get_ret);
+ }
+
+ // TODO: Verify that the documentation is incorrect
+ // https://github.com/WebAssembly/WASI/issues/27
+ var environ = try allocator.alloc(?[*]u8, environ_count + 1);
+ defer allocator.free(environ);
+ var environ_buf = try std.heap.wasm_allocator.alloc(u8, environ_buf_size);
+ defer allocator.free(environ_buf);
+
+ const environ_get_ret = os.wasi.environ_get(environ.ptr, environ_buf.ptr);
+ if (environ_get_ret != os.wasi.ESUCCESS) {
+ return os.unexpectedErrno(environ_get_ret);
+ }
+
+ for (environ) |env| {
+ if (env) |ptr| {
+ const pair = mem.toSlice(u8, ptr);
+ var parts = mem.separate(pair, "=");
+ const key = parts.next().?;
+ const value = parts.next().?;
+ try result.set(key, value);
+ }
+ }
+ return result;
+ } else {
+ for (os.environ) |ptr| {
+ var line_i: usize = 0;
+ while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
+ const key = ptr[0..line_i];
+
+ var end_i: usize = line_i;
+ while (ptr[end_i] != 0) : (end_i += 1) {}
+ const value = ptr[line_i + 1 .. end_i];
+
+ try result.set(key, value);
+ }
+ return result;
+ }
+}
+
+test "os.getEnvMap" {
+ var env = try getEnvMap(std.debug.global_allocator);
+ defer env.deinit();
+}
+
+pub const GetEnvVarOwnedError = error{
+ OutOfMemory,
+ EnvironmentVariableNotFound,
+
+ /// See https://github.com/ziglang/zig/issues/1774
+ InvalidUtf8,
+};
+
+/// Caller must free returned memory.
+/// TODO make this go through libc when we have it
+pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 {
+ if (os.windows.is_the_target) {
+ const key_with_null = try std.unicode.utf8ToUtf16LeWithNull(allocator, key);
+ defer allocator.free(key_with_null);
+
+ var buf = try allocator.alloc(u16, 256);
+ defer allocator.free(buf);
+
+ while (true) {
+ const windows_buf_len = math.cast(os.windows.DWORD, buf.len) catch return error.OutOfMemory;
+ const result = os.windows.GetEnvironmentVariableW(
+ key_with_null.ptr,
+ buf.ptr,
+ windows_buf_len,
+ ) catch |err| switch (err) {
+ error.Unexpected => return error.EnvironmentVariableNotFound,
+ else => |e| return e,
+ };
+
+ if (result > buf.len) {
+ buf = try allocator.realloc(buf, result);
+ continue;
+ }
+
+ return std.unicode.utf16leToUtf8Alloc(allocator, buf) catch |err| switch (err) {
+ error.DanglingSurrogateHalf => return error.InvalidUtf8,
+ error.ExpectedSecondSurrogateHalf => return error.InvalidUtf8,
+ error.UnexpectedSecondSurrogateHalf => return error.InvalidUtf8,
+ else => |e| return e,
+ };
+ }
+ } else {
+ const result = os.getenv(key) orelse return error.EnvironmentVariableNotFound;
+ return mem.dupe(allocator, u8, result);
+ }
+}
+
+test "os.getEnvVarOwned" {
+ var ga = std.debug.global_allocator;
+ testing.expectError(error.EnvironmentVariableNotFound, getEnvVarOwned(ga, "BADENV"));
+}
+
+pub const ArgIteratorPosix = struct {
+ index: usize,
+ count: usize,
+
+ pub fn init() ArgIteratorPosix {
+ return ArgIteratorPosix{
+ .index = 0,
+ .count = os.argv.len,
+ };
+ }
+
+ pub fn next(self: *ArgIteratorPosix) ?[]const u8 {
+ if (self.index == self.count) return null;
+
+ const s = os.argv[self.index];
+ self.index += 1;
+ return mem.toSlice(u8, s);
+ }
+
+ pub fn skip(self: *ArgIteratorPosix) bool {
+ if (self.index == self.count) return false;
+
+ self.index += 1;
+ return true;
+ }
+};
+
+pub const ArgIteratorWindows = struct {
+ index: usize,
+ cmd_line: [*]const u8,
+ in_quote: bool,
+ quote_count: usize,
+ seen_quote_count: usize,
+
+ pub const NextError = error{OutOfMemory};
+
+ pub fn init() ArgIteratorWindows {
+ return initWithCmdLine(os.windows.kernel32.GetCommandLineA());
+ }
+
+ pub fn initWithCmdLine(cmd_line: [*]const u8) ArgIteratorWindows {
+ return ArgIteratorWindows{
+ .index = 0,
+ .cmd_line = cmd_line,
+ .in_quote = false,
+ .quote_count = countQuotes(cmd_line),
+ .seen_quote_count = 0,
+ };
+ }
+
+ /// You must free the returned memory when done.
+ pub fn next(self: *ArgIteratorWindows, allocator: *Allocator) ?(NextError![]u8) {
+ // march forward over whitespace
+ while (true) : (self.index += 1) {
+ const byte = self.cmd_line[self.index];
+ switch (byte) {
+ 0 => return null,
+ ' ', '\t' => continue,
+ else => break,
+ }
+ }
+
+ return self.internalNext(allocator);
+ }
+
+ pub fn skip(self: *ArgIteratorWindows) bool {
+ // march forward over whitespace
+ while (true) : (self.index += 1) {
+ const byte = self.cmd_line[self.index];
+ switch (byte) {
+ 0 => return false,
+ ' ', '\t' => continue,
+ else => break,
+ }
+ }
+
+ var backslash_count: usize = 0;
+ while (true) : (self.index += 1) {
+ const byte = self.cmd_line[self.index];
+ switch (byte) {
+ 0 => return true,
+ '"' => {
+ const quote_is_real = backslash_count % 2 == 0;
+ if (quote_is_real) {
+ self.seen_quote_count += 1;
+ }
+ },
+ '\\' => {
+ backslash_count += 1;
+ },
+ ' ', '\t' => {
+ if (self.seen_quote_count % 2 == 0 or self.seen_quote_count == self.quote_count) {
+ return true;
+ }
+ backslash_count = 0;
+ },
+ else => {
+ backslash_count = 0;
+ continue;
+ },
+ }
+ }
+ }
+
+ fn internalNext(self: *ArgIteratorWindows, allocator: *Allocator) NextError![]u8 {
+ var buf = try Buffer.initSize(allocator, 0);
+ defer buf.deinit();
+
+ var backslash_count: usize = 0;
+ while (true) : (self.index += 1) {
+ const byte = self.cmd_line[self.index];
+ switch (byte) {
+ 0 => return buf.toOwnedSlice(),
+ '"' => {
+ const quote_is_real = backslash_count % 2 == 0;
+ try self.emitBackslashes(&buf, backslash_count / 2);
+ backslash_count = 0;
+
+ if (quote_is_real) {
+ self.seen_quote_count += 1;
+ if (self.seen_quote_count == self.quote_count and self.seen_quote_count % 2 == 1) {
+ try buf.appendByte('"');
+ }
+ } else {
+ try buf.appendByte('"');
+ }
+ },
+ '\\' => {
+ backslash_count += 1;
+ },
+ ' ', '\t' => {
+ try self.emitBackslashes(&buf, backslash_count);
+ backslash_count = 0;
+ if (self.seen_quote_count % 2 == 1 and self.seen_quote_count != self.quote_count) {
+ try buf.appendByte(byte);
+ } else {
+ return buf.toOwnedSlice();
+ }
+ },
+ else => {
+ try self.emitBackslashes(&buf, backslash_count);
+ backslash_count = 0;
+ try buf.appendByte(byte);
+ },
+ }
+ }
+ }
+
+ fn emitBackslashes(self: *ArgIteratorWindows, buf: *Buffer, emit_count: usize) !void {
+ var i: usize = 0;
+ while (i < emit_count) : (i += 1) {
+ try buf.appendByte('\\');
+ }
+ }
+
+ fn countQuotes(cmd_line: [*]const u8) usize {
+ var result: usize = 0;
+ var backslash_count: usize = 0;
+ var index: usize = 0;
+ while (true) : (index += 1) {
+ const byte = cmd_line[index];
+ switch (byte) {
+ 0 => return result,
+ '\\' => backslash_count += 1,
+ '"' => {
+ result += 1 - (backslash_count % 2);
+ backslash_count = 0;
+ },
+ else => {
+ backslash_count = 0;
+ },
+ }
+ }
+ }
+};
+
+pub const ArgIterator = struct {
+ const InnerType = if (builtin.os == .windows) ArgIteratorWindows else ArgIteratorPosix;
+
+ inner: InnerType,
+
+ pub fn init() ArgIterator {
+ if (builtin.os == .wasi) {
+ // TODO: Figure out a compatible interface accomodating WASI
+ @compileError("ArgIterator is not yet supported in WASI. Use argsAlloc and argsFree instead.");
+ }
+
+ return ArgIterator{ .inner = InnerType.init() };
+ }
+
+ pub const NextError = ArgIteratorWindows.NextError;
+
+ /// You must free the returned memory when done.
+ pub fn next(self: *ArgIterator, allocator: *Allocator) ?(NextError![]u8) {
+ if (builtin.os == .windows) {
+ return self.inner.next(allocator);
+ } else {
+ return mem.dupe(allocator, u8, self.inner.next() orelse return null);
+ }
+ }
+
+ /// If you only are targeting posix you can call this and not need an allocator.
+ pub fn nextPosix(self: *ArgIterator) ?[]const u8 {
+ return self.inner.next();
+ }
+
+ /// Parse past 1 argument without capturing it.
+ /// Returns `true` if skipped an arg, `false` if we are at the end.
+ pub fn skip(self: *ArgIterator) bool {
+ return self.inner.skip();
+ }
+};
+
+pub fn args() ArgIterator {
+ return ArgIterator.init();
+}
+
+/// Caller must call argsFree on result.
+pub fn argsAlloc(allocator: *mem.Allocator) ![]const []u8 {
+ if (builtin.os == .wasi) {
+ var count: usize = undefined;
+ var buf_size: usize = undefined;
+
+ const args_sizes_get_ret = os.wasi.args_sizes_get(&count, &buf_size);
+ if (args_sizes_get_ret != os.wasi.ESUCCESS) {
+ return os.unexpectedErrno(args_sizes_get_ret);
+ }
+
+ var argv = try allocator.alloc([*]u8, count);
+ defer allocator.free(argv);
+
+ var argv_buf = try allocator.alloc(u8, buf_size);
+ const args_get_ret = os.wasi.args_get(argv.ptr, argv_buf.ptr);
+ if (args_get_ret != os.wasi.ESUCCESS) {
+ return os.unexpectedErrno(args_get_ret);
+ }
+
+ var result_slice = try allocator.alloc([]u8, count);
+
+ var i: usize = 0;
+ while (i < count) : (i += 1) {
+ result_slice[i] = mem.toSlice(u8, argv[i]);
+ }
+
+ return result_slice;
+ }
+
+ // TODO refactor to only make 1 allocation.
+ var it = args();
+ var contents = try Buffer.initSize(allocator, 0);
+ defer contents.deinit();
+
+ var slice_list = std.ArrayList(usize).init(allocator);
+ defer slice_list.deinit();
+
+ while (it.next(allocator)) |arg_or_err| {
+ const arg = try arg_or_err;
+ defer allocator.free(arg);
+ try contents.append(arg);
+ try slice_list.append(arg.len);
+ }
+
+ const contents_slice = contents.toSliceConst();
+ const slice_sizes = slice_list.toSliceConst();
+ const slice_list_bytes = try math.mul(usize, @sizeOf([]u8), slice_sizes.len);
+ const total_bytes = try math.add(usize, slice_list_bytes, contents_slice.len);
+ const buf = try allocator.alignedAlloc(u8, @alignOf([]u8), total_bytes);
+ errdefer allocator.free(buf);
+
+ const result_slice_list = @bytesToSlice([]u8, buf[0..slice_list_bytes]);
+ const result_contents = buf[slice_list_bytes..];
+ mem.copy(u8, result_contents, contents_slice);
+
+ var contents_index: usize = 0;
+ for (slice_sizes) |len, i| {
+ const new_index = contents_index + len;
+ result_slice_list[i] = result_contents[contents_index..new_index];
+ contents_index = new_index;
+ }
+
+ return result_slice_list;
+}
+
+pub fn argsFree(allocator: *mem.Allocator, args_alloc: []const []u8) void {
+ if (builtin.os == .wasi) {
+ const last_item = args_alloc[args_alloc.len - 1];
+ const last_byte_addr = @ptrToInt(last_item.ptr) + last_item.len + 1; // null terminated
+ const first_item_ptr = args_alloc[0].ptr;
+ const len = last_byte_addr - @ptrToInt(first_item_ptr);
+ allocator.free(first_item_ptr[0..len]);
+
+ return allocator.free(args_alloc);
+ }
+
+ var total_bytes: usize = 0;
+ for (args_alloc) |arg| {
+ total_bytes += @sizeOf([]u8) + arg.len;
+ }
+ const unaligned_allocated_buf = @ptrCast([*]const u8, args_alloc.ptr)[0..total_bytes];
+ const aligned_allocated_buf = @alignCast(@alignOf([]u8), unaligned_allocated_buf);
+ return allocator.free(aligned_allocated_buf);
+}
+
+test "windows arg parsing" {
+ testWindowsCmdLine(c"a b\tc d", [][]const u8{ "a", "b", "c", "d" });
+ testWindowsCmdLine(c"\"abc\" d e", [][]const u8{ "abc", "d", "e" });
+ testWindowsCmdLine(c"a\\\\\\b d\"e f\"g h", [][]const u8{ "a\\\\\\b", "de fg", "h" });
+ testWindowsCmdLine(c"a\\\\\\\"b c d", [][]const u8{ "a\\\"b", "c", "d" });
+ testWindowsCmdLine(c"a\\\\\\\\\"b c\" d e", [][]const u8{ "a\\\\b c", "d", "e" });
+ testWindowsCmdLine(c"a b\tc \"d f", [][]const u8{ "a", "b", "c", "\"d", "f" });
+
+ testWindowsCmdLine(c"\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", [][]const u8{
+ ".\\..\\zig-cache\\build",
+ "bin\\zig.exe",
+ ".\\..",
+ ".\\..\\zig-cache",
+ "--help",
+ });
+}
+
+fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []const u8) void {
+ var it = ArgIteratorWindows.initWithCmdLine(input_cmd_line);
+ for (expected_args) |expected_arg| {
+ const arg = it.next(std.debug.global_allocator).? catch unreachable;
+ testing.expectEqualSlices(u8, expected_arg, arg);
+ }
+ testing.expect(it.next(std.debug.global_allocator) == null);
+}
+
+pub const UserInfo = struct {
+ uid: u32,
+ gid: u32,
+};
+
+/// POSIX function which gets a uid from username.
+pub fn getUserInfo(name: []const u8) !UserInfo {
+ return switch (builtin.os) {
+ .linux, .macosx, .watchos, .tvos, .ios, .freebsd, .netbsd => posixGetUserInfo(name),
+ else => @compileError("Unsupported OS"),
+ };
+}
+
+/// TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else
+/// like NIS, AD, etc. See `man nss` or look at an strace for `id myuser`.
+pub fn posixGetUserInfo(name: []const u8) !UserInfo {
+ var in_stream = try io.InStream.open("/etc/passwd", null);
+ defer in_stream.close();
+
+ const State = enum {
+ Start,
+ WaitForNextLine,
+ SkipPassword,
+ ReadUserId,
+ ReadGroupId,
+ };
+
+ var buf: [std.mem.page_size]u8 = undefined;
+ var name_index: usize = 0;
+ var state = State.Start;
+ var uid: u32 = 0;
+ var gid: u32 = 0;
+
+ while (true) {
+ const amt_read = try in_stream.read(buf[0..]);
+ for (buf[0..amt_read]) |byte| {
+ switch (state) {
+ .Start => switch (byte) {
+ ':' => {
+ state = if (name_index == name.len) State.SkipPassword else State.WaitForNextLine;
+ },
+ '\n' => return error.CorruptPasswordFile,
+ else => {
+ if (name_index == name.len or name[name_index] != byte) {
+ state = .WaitForNextLine;
+ }
+ name_index += 1;
+ },
+ },
+ .WaitForNextLine => switch (byte) {
+ '\n' => {
+ name_index = 0;
+ state = .Start;
+ },
+ else => continue,
+ },
+ .SkipPassword => switch (byte) {
+ '\n' => return error.CorruptPasswordFile,
+ ':' => {
+ state = .ReadUserId;
+ },
+ else => continue,
+ },
+ .ReadUserId => switch (byte) {
+ ':' => {
+ state = .ReadGroupId;
+ },
+ '\n' => return error.CorruptPasswordFile,
+ else => {
+ const digit = switch (byte) {
+ '0'...'9' => byte - '0',
+ else => return error.CorruptPasswordFile,
+ };
+ if (@mulWithOverflow(u32, uid, 10, *uid)) return error.CorruptPasswordFile;
+ if (@addWithOverflow(u32, uid, digit, *uid)) return error.CorruptPasswordFile;
+ },
+ },
+ .ReadGroupId => switch (byte) {
+ '\n', ':' => {
+ return UserInfo{
+ .uid = uid,
+ .gid = gid,
+ };
+ },
+ else => {
+ const digit = switch (byte) {
+ '0'...'9' => byte - '0',
+ else => return error.CorruptPasswordFile,
+ };
+ if (@mulWithOverflow(u32, gid, 10, *gid)) return error.CorruptPasswordFile;
+ if (@addWithOverflow(u32, gid, digit, *gid)) return error.CorruptPasswordFile;
+ },
+ },
+ }
+ }
+ if (amt_read < buf.len) return error.UserNotFound;
+ }
+}
+
+pub fn getBaseAddress() usize {
+ switch (builtin.os) {
+ .linux => {
+ const base = os.system.getauxval(std.elf.AT_BASE);
+ if (base != 0) {
+ return base;
+ }
+ const phdr = os.system.getauxval(std.elf.AT_PHDR);
+ return phdr - @sizeOf(std.elf.Ehdr);
+ },
+ .macosx, .freebsd, .netbsd => {
+ return @ptrToInt(&std.c._mh_execute_header);
+ },
+ .windows => return @ptrToInt(os.windows.kernel32.GetModuleHandleW(null)),
+ else => @compileError("Unsupported OS"),
+ }
+}
diff --git a/std/rand.zig b/std/rand.zig
index 4a6563f65a..770ae1b0a8 100644
--- a/std/rand.zig
+++ b/std/rand.zig
@@ -1,10 +1,10 @@
-// The engines provided here should be initialized from an external source. For now, getRandomBytes
-// from the os package is the most suitable. Be sure to use a CSPRNG when required, otherwise using
+// The engines provided here should be initialized from an external source. For now, randomBytes
+// from the crypto package is the most suitable. Be sure to use a CSPRNG when required, otherwise using
// a normal PRNG will be faster and use substantially less stack space.
//
// ```
// var buf: [8]u8 = undefined;
-// try std.os.getRandomBytes(buf[0..]);
+// try std.crypto.randomBytes(buf[0..]);
// const seed = mem.readIntSliceLittle(u64, buf[0..8]);
//
// var r = DefaultPrng.init(seed);
diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig
index a619a74b0f..45ce23c00f 100644
--- a/std/special/bootstrap.zig
+++ b/std/special/bootstrap.zig
@@ -62,7 +62,7 @@ extern fn WinMainCRTStartup() noreturn {
if (!builtin.single_threaded) {
_ = @import("bootstrap_windows_tls.zig");
}
- std.os.windows.ExitProcess(callMain());
+ std.os.windows.kernel32.ExitProcess(callMain());
}
// TODO https://github.com/ziglang/zig/issues/265
@@ -78,10 +78,10 @@ fn posixCallMainAndExit() noreturn {
while (envp_optional[envp_count]) |_| : (envp_count += 1) {}
const envp = @ptrCast([*][*]u8, envp_optional)[0..envp_count];
- if (builtin.os == builtin.Os.linux) {
+ if (builtin.os == .linux) {
// Find the beginning of the auxiliary vector
const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1);
- std.os.linux_elf_aux_maybe = auxv;
+ std.os.linux.elf_aux_maybe = auxv;
// Initialize the TLS area
std.os.linux.tls.initTLS();
@@ -92,14 +92,14 @@ fn posixCallMainAndExit() noreturn {
}
}
- std.os.posix.exit(callMainWithArgs(argc, argv, envp));
+ std.os.exit(callMainWithArgs(argc, argv, envp));
}
// This is marked inline because for some reason LLVM in release mode fails to inline it,
// and we want fewer call frames in stack traces.
inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 {
- std.os.ArgIteratorPosix.raw = argv[0..argc];
- std.os.posix_environ_raw = envp;
+ std.os.argv = argv[0..argc];
+ std.os.environ = envp;
return callMain();
}
diff --git a/std/special/build_runner.zig b/std/special/build_runner.zig
index dfc3838577..a0a18d21d2 100644
--- a/std/special/build_runner.zig
+++ b/std/special/build_runner.zig
@@ -3,14 +3,15 @@ const std = @import("std");
const builtin = @import("builtin");
const io = std.io;
const fmt = std.fmt;
-const os = std.os;
const Builder = std.build.Builder;
const mem = std.mem;
+const process = std.process;
const ArrayList = std.ArrayList;
const warn = std.debug.warn;
+const File = std.fs.File;
pub fn main() !void {
- var arg_it = os.args();
+ var arg_it = process.args();
// Here we use an ArenaAllocator backed by a DirectAllocator because a build is a short-lived,
// one shot program. We don't need to waste time freeing memory and finding places to squish
@@ -48,14 +49,14 @@ pub fn main() !void {
var prefix: ?[]const u8 = null;
var stderr_file = io.getStdErr();
- var stderr_file_stream: os.File.OutStream = undefined;
+ var stderr_file_stream: File.OutStream = undefined;
var stderr_stream = if (stderr_file) |f| x: {
stderr_file_stream = f.outStream();
break :x &stderr_file_stream.stream;
} else |err| err;
var stdout_file = io.getStdOut();
- var stdout_file_stream: os.File.OutStream = undefined;
+ var stdout_file_stream: File.OutStream = undefined;
var stdout_stream = if (stdout_file) |f| x: {
stdout_file_stream = f.outStream();
break :x &stdout_file_stream.stream;
@@ -138,7 +139,7 @@ pub fn main() !void {
error.InvalidStepName => {
return usageAndErr(&builder, true, try stderr_stream);
},
- error.UncleanExit => os.exit(1),
+ error.UncleanExit => process.exit(1),
else => return err,
}
};
@@ -214,7 +215,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {
fn usageAndErr(builder: *Builder, already_ran_build: bool, out_stream: var) void {
usage(builder, already_ran_build, out_stream) catch {};
- os.exit(1);
+ process.exit(1);
}
const UnwrapArgError = error{OutOfMemory};
diff --git a/std/statically_initialized_mutex.zig b/std/statically_initialized_mutex.zig
index cfcaf036d3..9c8b91c632 100644
--- a/std/statically_initialized_mutex.zig
+++ b/std/statically_initialized_mutex.zig
@@ -23,7 +23,7 @@ pub const StaticallyInitializedMutex = switch (builtin.os) {
mutex: *StaticallyInitializedMutex,
pub fn release(self: Held) void {
- windows.LeaveCriticalSection(&self.mutex.lock);
+ windows.kernel32.LeaveCriticalSection(&self.mutex.lock);
}
};
@@ -40,20 +40,20 @@ pub const StaticallyInitializedMutex = switch (builtin.os) {
Context: ?*c_void,
) windows.BOOL {
const lock = @ptrCast(*windows.CRITICAL_SECTION, @alignCast(@alignOf(windows.CRITICAL_SECTION), Parameter));
- windows.InitializeCriticalSection(lock);
+ windows.kernel32.InitializeCriticalSection(lock);
return windows.TRUE;
}
/// TODO: once https://github.com/ziglang/zig/issues/287 is solved and std.Mutex has a better
/// implementation of a runtime initialized mutex, remove this function.
pub fn deinit(self: *StaticallyInitializedMutex) void {
- assert(windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, &self.lock, null) != 0);
- windows.DeleteCriticalSection(&self.lock);
+ windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, &self.lock, null);
+ windows.kernel32.DeleteCriticalSection(&self.lock);
}
pub fn acquire(self: *StaticallyInitializedMutex) Held {
- assert(windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, &self.lock, null) != 0);
- windows.EnterCriticalSection(&self.lock);
+ windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, &self.lock, null);
+ windows.kernel32.EnterCriticalSection(&self.lock);
return Held{ .mutex = self };
}
},
@@ -96,9 +96,9 @@ test "std.StaticallyInitializedMutex" {
expect(context.data == TestContext.incr_count);
} else {
const thread_count = 10;
- var threads: [thread_count]*std.os.Thread = undefined;
+ var threads: [thread_count]*std.Thread = undefined;
for (threads) |*t| {
- t.* = try std.os.spawnThread(&context, TestContext.worker);
+ t.* = try std.Thread.spawn(&context, TestContext.worker);
}
for (threads) |t|
t.wait();
diff --git a/std/std.zig b/std/std.zig
index 8ec042fdb8..a621af1e84 100644
--- a/std/std.zig
+++ b/std/std.zig
@@ -17,6 +17,8 @@ pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex;
pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
pub const SpinLock = @import("spinlock.zig").SpinLock;
+pub const ChildProcess = @import("child_process.zig").ChildProcess;
+pub const Thread = @import("thread.zig").Thread;
pub const atomic = @import("atomic.zig");
pub const base64 = @import("base64.zig");
@@ -30,6 +32,7 @@ pub const dwarf = @import("dwarf.zig");
pub const elf = @import("elf.zig");
pub const event = @import("event.zig");
pub const fmt = @import("fmt.zig");
+pub const fs = @import("fs.zig");
pub const hash = @import("hash.zig");
pub const hash_map = @import("hash_map.zig");
pub const heap = @import("heap.zig");
@@ -43,11 +46,13 @@ pub const meta = @import("meta.zig");
pub const net = @import("net.zig");
pub const os = @import("os.zig");
pub const pdb = @import("pdb.zig");
+pub const process = @import("process.zig");
pub const rand = @import("rand.zig");
pub const rb = @import("rb.zig");
pub const sort = @import("sort.zig");
pub const ascii = @import("ascii.zig");
pub const testing = @import("testing.zig");
+pub const time = @import("time.zig");
pub const unicode = @import("unicode.zig");
pub const valgrind = @import("valgrind.zig");
pub const zig = @import("zig.zig");
@@ -65,6 +70,7 @@ test "std" {
_ = @import("statically_initialized_mutex.zig");
_ = @import("segmented_list.zig");
_ = @import("spinlock.zig");
+ _ = @import("child_process.zig");
_ = @import("ascii.zig");
_ = @import("base64.zig");
@@ -79,6 +85,7 @@ test "std" {
_ = @import("elf.zig");
_ = @import("event.zig");
_ = @import("fmt.zig");
+ _ = @import("fs.zig");
_ = @import("hash.zig");
_ = @import("heap.zig");
_ = @import("io.zig");
@@ -91,11 +98,14 @@ test "std" {
_ = @import("net.zig");
_ = @import("os.zig");
_ = @import("pdb.zig");
+ _ = @import("process.zig");
_ = @import("packed_int_array.zig");
_ = @import("priority_queue.zig");
_ = @import("rand.zig");
_ = @import("sort.zig");
_ = @import("testing.zig");
+ _ = @import("thread.zig");
+ _ = @import("time.zig");
_ = @import("unicode.zig");
_ = @import("valgrind.zig");
_ = @import("zig.zig");
diff --git a/std/thread.zig b/std/thread.zig
new file mode 100644
index 0000000000..49b2decb09
--- /dev/null
+++ b/std/thread.zig
@@ -0,0 +1,349 @@
+const builtin = @import("builtin");
+const std = @import("std.zig");
+const os = std.os;
+const mem = std.mem;
+const windows = std.os.windows;
+const c = std.c;
+const assert = std.debug.assert;
+
+pub const Thread = struct {
+ data: Data,
+
+ pub const use_pthreads = !windows.is_the_target and builtin.link_libc;
+
+ /// Represents a kernel thread handle.
+ /// May be an integer or a pointer depending on the platform.
+ /// On Linux and POSIX, this is the same as Id.
+ pub const Handle = if (use_pthreads)
+ c.pthread_t
+ else switch (builtin.os) {
+ .linux => i32,
+ .windows => windows.HANDLE,
+ else => @compileError("Unsupported OS"),
+ };
+
+ /// Represents a unique ID per thread.
+ /// May be an integer or pointer depending on the platform.
+ /// On Linux and POSIX, this is the same as Handle.
+ pub const Id = switch (builtin.os) {
+ .windows => windows.DWORD,
+ else => Handle,
+ };
+
+ pub const Data = if (use_pthreads)
+ struct {
+ handle: Thread.Handle,
+ memory: []align(mem.page_size) u8,
+ }
+ else switch (builtin.os) {
+ .linux => struct {
+ handle: Thread.Handle,
+ memory: []align(mem.page_size) u8,
+ },
+ .windows => struct {
+ handle: Thread.Handle,
+ alloc_start: *c_void,
+ heap_handle: windows.HANDLE,
+ },
+ else => @compileError("Unsupported OS"),
+ };
+
+ /// Returns the ID of the calling thread.
+ /// Makes a syscall every time the function is called.
+ /// On Linux and POSIX, this Id is the same as a Handle.
+ pub fn getCurrentId() Id {
+ if (use_pthreads) {
+ return c.pthread_self();
+ } else
+ return switch (builtin.os) {
+ .linux => os.linux.gettid(),
+ .windows => windows.kernel32.GetCurrentThreadId(),
+ else => @compileError("Unsupported OS"),
+ };
+ }
+
+ /// Returns the handle of this thread.
+ /// On Linux and POSIX, this is the same as Id.
+ /// On Linux, it is possible that the thread spawned with `spawn`
+ /// finishes executing entirely before the clone syscall completes. In this
+ /// case, this function will return 0 rather than the no-longer-existing thread's
+ /// pid.
+ pub fn handle(self: Thread) Handle {
+ return self.data.handle;
+ }
+
+ pub fn wait(self: *const Thread) void {
+ if (use_pthreads) {
+ const err = c.pthread_join(self.data.handle, null);
+ switch (err) {
+ 0 => {},
+ os.EINVAL => unreachable,
+ os.ESRCH => unreachable,
+ os.EDEADLK => unreachable,
+ else => unreachable,
+ }
+ os.munmap(self.data.memory);
+ } else switch (builtin.os) {
+ .linux => {
+ while (true) {
+ const pid_value = @atomicLoad(i32, &self.data.handle, .SeqCst);
+ if (pid_value == 0) break;
+ const rc = os.linux.futex_wait(&self.data.handle, os.linux.FUTEX_WAIT, pid_value, null);
+ switch (os.linux.getErrno(rc)) {
+ 0 => continue,
+ os.EINTR => continue,
+ os.EAGAIN => continue,
+ else => unreachable,
+ }
+ }
+ os.munmap(self.data.memory);
+ },
+ .windows => {
+ windows.WaitForSingleObject(self.data.handle, windows.INFINITE) catch unreachable;
+ windows.CloseHandle(self.data.handle);
+ windows.HeapFree(self.data.heap_handle, 0, self.data.alloc_start);
+ },
+ else => @compileError("Unsupported OS"),
+ }
+ }
+
+ pub const SpawnError = error{
+ /// A system-imposed limit on the number of threads was encountered.
+ /// There are a number of limits that may trigger this error:
+ /// * the RLIMIT_NPROC soft resource limit (set via setrlimit(2)),
+ /// which limits the number of processes and threads for a real
+ /// user ID, was reached;
+ /// * the kernel's system-wide limit on the number of processes and
+ /// threads, /proc/sys/kernel/threads-max, was reached (see
+ /// proc(5));
+ /// * the maximum number of PIDs, /proc/sys/kernel/pid_max, was
+ /// reached (see proc(5)); or
+ /// * the PID limit (pids.max) imposed by the cgroup "process num‐
+ /// ber" (PIDs) controller was reached.
+ ThreadQuotaExceeded,
+
+ /// The kernel cannot allocate sufficient memory to allocate a task structure
+ /// for the child, or to copy those parts of the caller's context that need to
+ /// be copied.
+ SystemResources,
+
+ /// Not enough userland memory to spawn the thread.
+ OutOfMemory,
+
+ /// `mlockall` is enabled, and the memory needed to spawn the thread
+ /// would exceed the limit.
+ LockedMemoryLimitExceeded,
+
+ Unexpected,
+ };
+
+ /// caller must call wait on the returned thread
+ /// fn startFn(@typeOf(context)) T
+ /// where T is u8, noreturn, void, or !void
+ /// caller must call wait on the returned thread
+ pub fn spawn(context: var, comptime startFn: var) SpawnError!*Thread {
+ if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode");
+ // TODO compile-time call graph analysis to determine stack upper bound
+ // https://github.com/ziglang/zig/issues/157
+ const default_stack_size = 8 * 1024 * 1024;
+
+ const Context = @typeOf(context);
+ comptime assert(@ArgType(@typeOf(startFn), 0) == Context);
+
+ if (builtin.os == builtin.Os.windows) {
+ const WinThread = struct {
+ const OuterContext = struct {
+ thread: Thread,
+ inner: Context,
+ };
+ extern fn threadMain(raw_arg: windows.LPVOID) windows.DWORD {
+ const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*;
+ switch (@typeId(@typeOf(startFn).ReturnType)) {
+ .Int => {
+ return startFn(arg);
+ },
+ .Void => {
+ startFn(arg);
+ return 0;
+ },
+ else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"),
+ }
+ }
+ };
+
+ const heap_handle = windows.kernel32.GetProcessHeap() orelse return error.OutOfMemory;
+ const byte_count = @alignOf(WinThread.OuterContext) + @sizeOf(WinThread.OuterContext);
+ const bytes_ptr = windows.kernel32.HeapAlloc(heap_handle, 0, byte_count) orelse return error.OutOfMemory;
+ errdefer assert(windows.kernel32.HeapFree(heap_handle, 0, bytes_ptr) != 0);
+ const bytes = @ptrCast([*]u8, bytes_ptr)[0..byte_count];
+ const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext) catch unreachable;
+ outer_context.* = WinThread.OuterContext{
+ .thread = Thread{
+ .data = Thread.Data{
+ .heap_handle = heap_handle,
+ .alloc_start = bytes_ptr,
+ .handle = undefined,
+ },
+ },
+ .inner = context,
+ };
+
+ const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner);
+ outer_context.thread.data.handle = windows.kernel32.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse {
+ switch (windows.kernel32.GetLastError()) {
+ else => |err| return windows.unexpectedError(err),
+ }
+ };
+ return &outer_context.thread;
+ }
+
+ const MainFuncs = struct {
+ extern fn linuxThreadMain(ctx_addr: usize) u8 {
+ const arg = if (@sizeOf(Context) == 0) {} else @intToPtr(*const Context, ctx_addr).*;
+
+ switch (@typeId(@typeOf(startFn).ReturnType)) {
+ .Int => {
+ return startFn(arg);
+ },
+ .Void => {
+ startFn(arg);
+ return 0;
+ },
+ else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"),
+ }
+ }
+ extern fn posixThreadMain(ctx: ?*c_void) ?*c_void {
+ if (@sizeOf(Context) == 0) {
+ _ = startFn({});
+ return null;
+ } else {
+ _ = startFn(@ptrCast(*const Context, @alignCast(@alignOf(Context), ctx)).*);
+ return null;
+ }
+ }
+ };
+
+ const MAP_GROWSDOWN = if (os.linux.is_the_target) os.linux.MAP_GROWSDOWN else 0;
+
+ var stack_end_offset: usize = undefined;
+ var thread_start_offset: usize = undefined;
+ var context_start_offset: usize = undefined;
+ var tls_start_offset: usize = undefined;
+ const mmap_len = blk: {
+ // First in memory will be the stack, which grows downwards.
+ var l: usize = mem.alignForward(default_stack_size, mem.page_size);
+ stack_end_offset = l;
+ // Above the stack, so that it can be in the same mmap call, put the Thread object.
+ l = mem.alignForward(l, @alignOf(Thread));
+ thread_start_offset = l;
+ l += @sizeOf(Thread);
+ // Next, the Context object.
+ if (@sizeOf(Context) != 0) {
+ l = mem.alignForward(l, @alignOf(Context));
+ context_start_offset = l;
+ l += @sizeOf(Context);
+ }
+ // Finally, the Thread Local Storage, if any.
+ if (!Thread.use_pthreads) {
+ if (os.linux.tls.tls_image) |tls_img| {
+ l = mem.alignForward(l, @alignOf(usize));
+ tls_start_offset = l;
+ l += tls_img.alloc_size;
+ }
+ }
+ break :blk l;
+ };
+ const mmap_slice = os.mmap(
+ null,
+ mem.alignForward(mmap_len, mem.page_size),
+ os.PROT_READ | os.PROT_WRITE,
+ os.MAP_PRIVATE | os.MAP_ANONYMOUS | MAP_GROWSDOWN,
+ -1,
+ 0,
+ ) catch |err| switch (err) {
+ error.MemoryMappingNotSupported => unreachable, // no file descriptor
+ error.AccessDenied => unreachable, // no file descriptor
+ error.PermissionDenied => unreachable, // no file descriptor
+ else => |e| return e,
+ };
+ errdefer os.munmap(mmap_slice);
+ const mmap_addr = @ptrToInt(mmap_slice.ptr);
+
+ const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(*Thread, mmap_addr + thread_start_offset));
+ thread_ptr.data.memory = mmap_slice;
+
+ var arg: usize = undefined;
+ if (@sizeOf(Context) != 0) {
+ arg = mmap_addr + context_start_offset;
+ const context_ptr = @alignCast(@alignOf(Context), @intToPtr(*Context, arg));
+ context_ptr.* = context;
+ }
+
+ if (Thread.use_pthreads) {
+ // use pthreads
+ var attr: c.pthread_attr_t = undefined;
+ if (c.pthread_attr_init(&attr) != 0) return error.SystemResources;
+ defer assert(c.pthread_attr_destroy(&attr) == 0);
+
+ assert(c.pthread_attr_setstack(&attr, mmap_slice.ptr, stack_end_offset) == 0);
+
+ const err = c.pthread_create(&thread_ptr.data.handle, &attr, MainFuncs.posixThreadMain, @intToPtr(*c_void, arg));
+ switch (err) {
+ 0 => return thread_ptr,
+ os.EAGAIN => return error.SystemResources,
+ os.EPERM => unreachable,
+ os.EINVAL => unreachable,
+ else => return os.unexpectedErrno(@intCast(usize, err)),
+ }
+ } else if (os.linux.is_the_target) {
+ var flags: u32 = os.CLONE_VM | os.CLONE_FS | os.CLONE_FILES | os.CLONE_SIGHAND |
+ os.CLONE_THREAD | os.CLONE_SYSVSEM | os.CLONE_PARENT_SETTID | os.CLONE_CHILD_CLEARTID |
+ os.CLONE_DETACHED;
+ var newtls: usize = undefined;
+ if (os.linux.tls.tls_image) |tls_img| {
+ newtls = os.linux.tls.copyTLS(mmap_addr + tls_start_offset);
+ flags |= os.CLONE_SETTLS;
+ }
+ const rc = os.linux.clone(MainFuncs.linuxThreadMain, mmap_addr + stack_end_offset, flags, arg, &thread_ptr.data.handle, newtls, &thread_ptr.data.handle);
+ switch (os.errno(rc)) {
+ 0 => return thread_ptr,
+ os.EAGAIN => return error.ThreadQuotaExceeded,
+ os.EINVAL => unreachable,
+ os.ENOMEM => return error.SystemResources,
+ os.ENOSPC => unreachable,
+ os.EPERM => unreachable,
+ os.EUSERS => unreachable,
+ else => |err| return os.unexpectedErrno(err),
+ }
+ } else {
+ @compileError("Unsupported OS");
+ }
+ }
+
+ pub const CpuCountError = error{
+ OutOfMemory,
+ PermissionDenied,
+ SystemResources,
+ Unexpected,
+ };
+
+ pub fn cpuCount() CpuCountError!usize {
+ if (os.linux.is_the_target) {
+ const cpu_set = try os.sched_getaffinity(0);
+ return usize(os.CPU_COUNT(cpu_set)); // TODO should not need this usize cast
+ }
+ if (os.windows.is_the_target) {
+ var system_info: windows.SYSTEM_INFO = undefined;
+ windows.kernel32.GetSystemInfo(&system_info);
+ return @intCast(usize, system_info.dwNumberOfProcessors);
+ }
+ var count: c_int = undefined;
+ var count_len: usize = @sizeOf(c_int);
+ const name = if (os.darwin.is_the_target) c"hw.logicalcpu" else c"hw.ncpu";
+ os.sysctlbynameC(name, &count, &count_len, null, 0) catch |err| switch (err) {
+ error.NameTooLong => unreachable,
+ else => |e| return e,
+ };
+ return @intCast(usize, count);
+ }
+};
diff --git a/std/time.zig b/std/time.zig
new file mode 100644
index 0000000000..caf6c31b31
--- /dev/null
+++ b/std/time.zig
@@ -0,0 +1,221 @@
+const builtin = @import("builtin");
+const std = @import("std.zig");
+const assert = std.debug.assert;
+const testing = std.testing;
+const os = std.os;
+const math = std.math;
+
+pub const epoch = @import("time/epoch.zig");
+
+/// Spurious wakeups are possible and no precision of timing is guaranteed.
+pub fn sleep(nanoseconds: u64) void {
+ if (os.windows.is_the_target) {
+ const ns_per_ms = ns_per_s / ms_per_s;
+ const big_ms_from_ns = nanoseconds / ns_per_ms;
+ const ms = math.cast(os.windows.DWORD, big_ms_from_ns) catch math.maxInt(os.windows.DWORD);
+ os.windows.kernel32.Sleep(ms);
+ return;
+ }
+ const s = nanoseconds / ns_per_s;
+ const ns = nanoseconds % ns_per_s;
+ std.os.nanosleep(s, ns);
+}
+
+/// Get the posix timestamp, UTC, in seconds
+/// TODO audit this function. is it possible to return an error?
+pub fn timestamp() u64 {
+ return @divFloor(milliTimestamp(), ms_per_s);
+}
+
+/// Get the posix timestamp, UTC, in milliseconds
+/// TODO audit this function. is it possible to return an error?
+pub fn milliTimestamp() u64 {
+ if (os.windows.is_the_target) {
+ //FileTime has a granularity of 100 nanoseconds
+ // and uses the NTFS/Windows epoch
+ var ft: os.windows.FILETIME = undefined;
+ os.windows.kernel32.GetSystemTimeAsFileTime(&ft);
+ const hns_per_ms = (ns_per_s / 100) / ms_per_s;
+ const epoch_adj = epoch.windows * ms_per_s;
+
+ const ft64 = (u64(ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
+ return @divFloor(ft64, hns_per_ms) - -epoch_adj;
+ }
+ if (os.wasi.is_the_target and !builtin.link_libc) {
+ var ns: os.wasi.timestamp_t = undefined;
+
+ // TODO: Verify that precision is ignored
+ const err = os.wasi.clock_time_get(os.wasi.CLOCK_REALTIME, 1, &ns);
+ assert(err == os.wasi.ESUCCESS);
+
+ const ns_per_ms = 1000;
+ return @divFloor(ns, ns_per_ms);
+ }
+ if (os.darwin.is_the_target) {
+ var tv: os.darwin.timeval = undefined;
+ var err = os.darwin.gettimeofday(&tv, null);
+ assert(err == 0);
+ const sec_ms = tv.tv_sec * ms_per_s;
+ const usec_ms = @divFloor(tv.tv_usec, us_per_s / ms_per_s);
+ return @intCast(u64, sec_ms + usec_ms);
+ }
+ var ts: os.timespec = undefined;
+ //From what I can tell there's no reason clock_gettime
+ // should ever fail for us with CLOCK_REALTIME,
+ // seccomp aside.
+ os.clock_gettime(os.CLOCK_REALTIME, &ts) catch unreachable;
+ const sec_ms = @intCast(u64, ts.tv_sec) * ms_per_s;
+ const nsec_ms = @divFloor(@intCast(u64, ts.tv_nsec), ns_per_s / ms_per_s);
+ return sec_ms + nsec_ms;
+}
+
+/// Multiples of a base unit (nanoseconds)
+pub const nanosecond = 1;
+pub const microsecond = 1000 * nanosecond;
+pub const millisecond = 1000 * microsecond;
+pub const second = 1000 * millisecond;
+pub const minute = 60 * second;
+pub const hour = 60 * minute;
+
+/// Divisions of a second
+pub const ns_per_s = 1000000000;
+pub const us_per_s = 1000000;
+pub const ms_per_s = 1000;
+pub const cs_per_s = 100;
+
+/// Common time divisions
+pub const s_per_min = 60;
+pub const s_per_hour = s_per_min * 60;
+pub const s_per_day = s_per_hour * 24;
+pub const s_per_week = s_per_day * 7;
+
+/// A monotonic high-performance timer.
+/// Timer.start() must be called to initialize the struct, which captures
+/// the counter frequency on windows and darwin, records the resolution,
+/// and gives the user an opportunity to check for the existnece of
+/// monotonic clocks without forcing them to check for error on each read.
+/// .resolution is in nanoseconds on all platforms but .start_time's meaning
+/// depends on the OS. On Windows and Darwin it is a hardware counter
+/// value that requires calculation to convert to a meaninful unit.
+pub const Timer = struct {
+ ///if we used resolution's value when performing the
+ /// performance counter calc on windows/darwin, it would
+ /// be less precise
+ frequency: switch (builtin.os) {
+ .windows => u64,
+ .macosx, .ios, .tvos, .watchos => os.darwin.mach_timebase_info_data,
+ else => void,
+ },
+ resolution: u64,
+ start_time: u64,
+
+ const Error = error{TimerUnsupported};
+
+ ///At some point we may change our minds on RAW, but for now we're
+ /// sticking with posix standard MONOTONIC. For more information, see:
+ /// https://github.com/ziglang/zig/pull/933
+ const monotonic_clock_id = os.CLOCK_MONOTONIC;
+ /// Initialize the timer structure.
+ //This gives us an opportunity to grab the counter frequency in windows.
+ //On Windows: QueryPerformanceCounter will succeed on anything >= XP/2000.
+ //On Posix: CLOCK_MONOTONIC will only fail if the monotonic counter is not
+ // supported, or if the timespec pointer is out of bounds, which should be
+ // impossible here barring cosmic rays or other such occurrences of
+ // incredibly bad luck.
+ //On Darwin: This cannot fail, as far as I am able to tell.
+ pub fn start() Error!Timer {
+ var self: Timer = undefined;
+
+ if (os.windows.is_the_target) {
+ self.frequency = os.windows.QueryPerformanceFrequency();
+ self.resolution = @divFloor(ns_per_s, self.frequency);
+ self.start_time = os.windows.QueryPerformanceCounter();
+ } else if (os.darwin.is_the_target) {
+ os.darwin.mach_timebase_info(&self.frequency);
+ self.resolution = @divFloor(self.frequency.numer, self.frequency.denom);
+ self.start_time = os.darwin.mach_absolute_time();
+ } else {
+ //On Linux, seccomp can do arbitrary things to our ability to call
+ // syscalls, including return any errno value it wants and
+ // inconsistently throwing errors. Since we can't account for
+ // abuses of seccomp in a reasonable way, we'll assume that if
+ // seccomp is going to block us it will at least do so consistently
+ var ts: os.timespec = undefined;
+ os.clock_getres(monotonic_clock_id, &ts) catch return error.TimerUnsupported;
+ self.resolution = @intCast(u64, ts.tv_sec) * u64(ns_per_s) + @intCast(u64, ts.tv_nsec);
+
+ os.clock_gettime(monotonic_clock_id, &ts) catch return error.TimerUnsupported;
+ self.start_time = @intCast(u64, ts.tv_sec) * u64(ns_per_s) + @intCast(u64, ts.tv_nsec);
+ }
+
+ return self;
+ }
+
+ /// Reads the timer value since start or the last reset in nanoseconds
+ pub fn read(self: *Timer) u64 {
+ var clock = clockNative() - self.start_time;
+ if (os.windows.is_the_target) {
+ return @divFloor(clock * ns_per_s, self.frequency);
+ }
+ if (os.darwin.is_the_target) {
+ return @divFloor(clock * self.frequency.numer, self.frequency.denom);
+ }
+ return clock;
+ }
+
+ /// Resets the timer value to 0/now.
+ pub fn reset(self: *Timer) void {
+ self.start_time = clockNative();
+ }
+
+ /// Returns the current value of the timer in nanoseconds, then resets it
+ pub fn lap(self: *Timer) u64 {
+ var now = clockNative();
+ var lap_time = self.read();
+ self.start_time = now;
+ return lap_time;
+ }
+
+ fn clockNative() u64 {
+ if (os.windows.is_the_target) {
+ return os.windows.QueryPerformanceCounter();
+ }
+ if (os.darwin.is_the_target) {
+ return os.darwin.mach_absolute_time();
+ }
+ var ts: os.timespec = undefined;
+ os.clock_gettime(monotonic_clock_id, &ts) catch unreachable;
+ return @intCast(u64, ts.tv_sec) * u64(ns_per_s) + @intCast(u64, ts.tv_nsec);
+ }
+};
+
+test "sleep" {
+ sleep(1);
+}
+
+test "timestamp" {
+ const ns_per_ms = (ns_per_s / ms_per_s);
+ const margin = 50;
+
+ const time_0 = milliTimestamp();
+ sleep(ns_per_ms);
+ const time_1 = milliTimestamp();
+ const interval = time_1 - time_0;
+ testing.expect(interval > 0 and interval < margin);
+}
+
+test "Timer" {
+ const ns_per_ms = (ns_per_s / ms_per_s);
+ const margin = ns_per_ms * 150;
+
+ var timer = try Timer.start();
+ sleep(10 * ns_per_ms);
+ const time_0 = timer.read();
+ testing.expect(time_0 > 0 and time_0 < margin);
+
+ const time_1 = timer.lap();
+ testing.expect(time_1 >= time_0);
+
+ timer.reset();
+ testing.expect(timer.read() < time_1);
+}
diff --git a/std/os/epoch.zig b/std/time/epoch.zig
index fc031521a5..fc031521a5 100644
--- a/std/os/epoch.zig
+++ b/std/time/epoch.zig
diff --git a/std/zig/bench.zig b/std/zig/bench.zig
index ed6ae9a128..b43c491c97 100644
--- a/std/zig/bench.zig
+++ b/std/zig/bench.zig
@@ -10,7 +10,7 @@ var fixed_buffer_mem: [10 * 1024 * 1024]u8 = undefined;
pub fn main() !void {
var i: usize = 0;
- var timer = try std.os.time.Timer.start();
+ var timer = try std.time.Timer.start();
const start = timer.lap();
const iterations = 100;
var memory_used: usize = 0;
@@ -19,7 +19,7 @@ pub fn main() !void {
}
const end = timer.read();
memory_used /= iterations;
- const elapsed_s = @intToFloat(f64, end - start) / std.os.time.ns_per_s;
+ const elapsed_s = @intToFloat(f64, end - start) / std.time.ns_per_s;
const bytes_per_sec = @intToFloat(f64, source.len * iterations) / elapsed_s;
const mb_per_sec = bytes_per_sec / (1024 * 1024);