authorgravatar for codroid@gmail.comhryx <codroid@gmail.com> 2019-05-27 17:24:21-07:00
committergravatar for codroid@gmail.comhryx <codroid@gmail.com> 2019-05-27 17:24:21-07:00
loge1f3eec9cc05535b3f3b81f2fb7cd65dd4d1e841
tree5f408ed68a686491eaf759f9cbba02beac829b38
parent2aa1c5da5dded6b1b346c3a1b57443f2c459ebe9
parent3fccc0747903f0726d6cc8ee73832cb62f1304bb
signaturelock-open Commit is signed but in an unrecognized format.

Merge branch 'master' into translate-c-userland


124 files changed, 14674 insertions(+), 14414 deletions(-)

CMakeLists.txt+32-27
...@@ -474,6 +474,7 @@ set(ZIG_STD_FILES...@@ -474,6 +474,7 @@ set(ZIG_STD_FILES
474 "c/linux.zig"474 "c/linux.zig"
475 "c/netbsd.zig"475 "c/netbsd.zig"
476 "c/windows.zig"476 "c/windows.zig"
477 "child_process.zig"
477 "coff.zig"478 "coff.zig"
478 "crypto.zig"479 "crypto.zig"
479 "crypto/blake2.zig"480 "crypto/blake2.zig"
...@@ -487,8 +488,8 @@ set(ZIG_STD_FILES...@@ -487,8 +488,8 @@ set(ZIG_STD_FILES
487 "crypto/x25519.zig"488 "crypto/x25519.zig"
488 "cstr.zig"489 "cstr.zig"
489 "debug.zig"490 "debug.zig"
490 "debug/leb128.zig"
491 "debug/failing_allocator.zig"491 "debug/failing_allocator.zig"
492 "debug/leb128.zig"
492 "dwarf.zig"493 "dwarf.zig"
493 "dynamic_library.zig"494 "dynamic_library.zig"
494 "elf.zig"495 "elf.zig"
...@@ -509,6 +510,10 @@ set(ZIG_STD_FILES...@@ -509,6 +510,10 @@ set(ZIG_STD_FILES
509 "fmt/errol/enum3.zig"510 "fmt/errol/enum3.zig"
510 "fmt/errol/lookup.zig"511 "fmt/errol/lookup.zig"
511 "fmt/parse_float.zig"512 "fmt/parse_float.zig"
513 "fs.zig"
514 "fs/file.zig"
515 "fs/get_app_data_dir.zig"
516 "fs/path.zig"
512 "hash.zig"517 "hash.zig"
513 "hash/adler.zig"518 "hash/adler.zig"
514 "hash/crc.zig"519 "hash/crc.zig"
...@@ -517,8 +522,8 @@ set(ZIG_STD_FILES...@@ -517,8 +522,8 @@ set(ZIG_STD_FILES
517 "hash_map.zig"522 "hash_map.zig"
518 "heap.zig"523 "heap.zig"
519 "io.zig"524 "io.zig"
520 "io/seekable_stream.zig"
521 "io/c_out_stream.zig"525 "io/c_out_stream.zig"
526 "io/seekable_stream.zig"
522 "json.zig"527 "json.zig"
523 "lazy_init.zig"528 "lazy_init.zig"
524 "linked_list.zig"529 "linked_list.zig"
...@@ -600,40 +605,39 @@ set(ZIG_STD_FILES...@@ -600,40 +605,39 @@ set(ZIG_STD_FILES
600 "mutex.zig"605 "mutex.zig"
601 "net.zig"606 "net.zig"
602 "os.zig"607 "os.zig"
603 "os/child_process.zig"608 "os/bits.zig"
609 "os/bits/darwin.zig"
610 "os/bits/freebsd.zig"
611 "os/bits/linux.zig"
612 "os/bits/linux/arm64.zig"
613 "os/bits/linux/errno.zig"
614 "os/bits/linux/x86_64.zig"
615 "os/bits/netbsd.zig"
616 "os/bits/wasi.zig"
617 "os/bits/windows.zig"
604 "os/darwin.zig"618 "os/darwin.zig"
605 "os/darwin/errno.zig"
606 "os/epoch.zig"
607 "os/file.zig"
608 "os/freebsd.zig"619 "os/freebsd.zig"
609 "os/freebsd/errno.zig"
610 "os/get_app_data_dir.zig"
611 "os/get_user_id.zig"
612 "os/linux.zig"620 "os/linux.zig"
613 "os/linux/arm64.zig"621 "os/linux/arm64.zig"
614 "os/linux/errno.zig"
615 "os/linux/tls.zig"622 "os/linux/tls.zig"
616 "os/linux/vdso.zig"623 "os/linux/vdso.zig"
617 "os/linux/x86_64.zig"624 "os/linux/x86_64.zig"
618 "os/netbsd.zig"625 "os/netbsd.zig"
619 "os/netbsd/errno.zig"
620 "os/path.zig"
621 "os/time.zig"
622 "os/uefi.zig"626 "os/uefi.zig"
623 "os/wasi.zig"627 "os/wasi.zig"
624 "os/wasi/core.zig"
625 "os/windows.zig"628 "os/windows.zig"
626 "os/windows/advapi32.zig"629 "os/windows/advapi32.zig"
630 "os/windows/bits.zig"
627 "os/windows/error.zig"631 "os/windows/error.zig"
628 "os/windows/kernel32.zig"632 "os/windows/kernel32.zig"
629 "os/windows/ntdll.zig"633 "os/windows/ntdll.zig"
630 "os/windows/ole32.zig"634 "os/windows/ole32.zig"
631 "os/windows/shell32.zig"635 "os/windows/shell32.zig"
632 "os/windows/util.zig"
633 "os/zen.zig"636 "os/zen.zig"
634 "packed_int_array.zig"637 "packed_int_array.zig"
635 "pdb.zig"638 "pdb.zig"
636 "priority_queue.zig"639 "priority_queue.zig"
640 "process.zig"
637 "rand.zig"641 "rand.zig"
638 "rand/ziggurat.zig"642 "rand/ziggurat.zig"
639 "rb.zig"643 "rb.zig"
...@@ -645,17 +649,18 @@ set(ZIG_STD_FILES...@@ -645,17 +649,18 @@ set(ZIG_STD_FILES
645 "special/build_runner.zig"649 "special/build_runner.zig"
646 "special/c.zig"650 "special/c.zig"
647 "special/compiler_rt.zig"651 "special/compiler_rt.zig"
648 "special/compiler_rt/stack_probe.zig"
649 "special/compiler_rt/arm/aeabi_fcmp.zig"
650 "special/compiler_rt/arm/aeabi_dcmp.zig"
651 "special/compiler_rt/addXf3.zig"652 "special/compiler_rt/addXf3.zig"
653 "special/compiler_rt/arm/aeabi_dcmp.zig"
654 "special/compiler_rt/arm/aeabi_fcmp.zig"
655 "special/compiler_rt/ashlti3.zig"
656 "special/compiler_rt/ashrti3.zig"
652 "special/compiler_rt/aulldiv.zig"657 "special/compiler_rt/aulldiv.zig"
653 "special/compiler_rt/aullrem.zig"658 "special/compiler_rt/aullrem.zig"
654 "special/compiler_rt/comparetf2.zig"
655 "special/compiler_rt/comparedf2.zig"659 "special/compiler_rt/comparedf2.zig"
656 "special/compiler_rt/comparesf2.zig"660 "special/compiler_rt/comparesf2.zig"
657 "special/compiler_rt/divsf3.zig"661 "special/compiler_rt/comparetf2.zig"
658 "special/compiler_rt/divdf3.zig"662 "special/compiler_rt/divdf3.zig"
663 "special/compiler_rt/divsf3.zig"
659 "special/compiler_rt/divti3.zig"664 "special/compiler_rt/divti3.zig"
660 "special/compiler_rt/extendXfYf2.zig"665 "special/compiler_rt/extendXfYf2.zig"
661 "special/compiler_rt/fixdfdi.zig"666 "special/compiler_rt/fixdfdi.zig"
...@@ -680,26 +685,25 @@ set(ZIG_STD_FILES...@@ -680,26 +685,25 @@ set(ZIG_STD_FILES
680 "special/compiler_rt/fixunstfti.zig"685 "special/compiler_rt/fixunstfti.zig"
681 "special/compiler_rt/floatdidf.zig"686 "special/compiler_rt/floatdidf.zig"
682 "special/compiler_rt/floatsiXf.zig"687 "special/compiler_rt/floatsiXf.zig"
683 "special/compiler_rt/floatunsidf.zig"
684 "special/compiler_rt/floattidf.zig"688 "special/compiler_rt/floattidf.zig"
685 "special/compiler_rt/floattisf.zig"689 "special/compiler_rt/floattisf.zig"
686 "special/compiler_rt/floattitf.zig"690 "special/compiler_rt/floattitf.zig"
687 "special/compiler_rt/floatundidf.zig"691 "special/compiler_rt/floatundidf.zig"
688 "special/compiler_rt/floatunditf.zig"692 "special/compiler_rt/floatunditf.zig"
693 "special/compiler_rt/floatunsidf.zig"
689 "special/compiler_rt/floatunsitf.zig"694 "special/compiler_rt/floatunsitf.zig"
690 "special/compiler_rt/floatuntidf.zig"695 "special/compiler_rt/floatuntidf.zig"
691 "special/compiler_rt/floatuntisf.zig"696 "special/compiler_rt/floatuntisf.zig"
692 "special/compiler_rt/floatuntitf.zig"697 "special/compiler_rt/floatuntitf.zig"
698 "special/compiler_rt/lshrti3.zig"
693 "special/compiler_rt/modti3.zig"699 "special/compiler_rt/modti3.zig"
694 "special/compiler_rt/mulXf3.zig"700 "special/compiler_rt/mulXf3.zig"
695 "special/compiler_rt/muloti4.zig"
696 "special/compiler_rt/mulodi4.zig"701 "special/compiler_rt/mulodi4.zig"
702 "special/compiler_rt/muloti4.zig"
697 "special/compiler_rt/multi3.zig"703 "special/compiler_rt/multi3.zig"
698 "special/compiler_rt/ashlti3.zig"
699 "special/compiler_rt/ashrti3.zig"
700 "special/compiler_rt/lshrti3.zig"
701 "special/compiler_rt/negXf2.zig"704 "special/compiler_rt/negXf2.zig"
702 "special/compiler_rt/popcountdi2.zig"705 "special/compiler_rt/popcountdi2.zig"
706 "special/compiler_rt/stack_probe.zig"
703 "special/compiler_rt/truncXfYf2.zig"707 "special/compiler_rt/truncXfYf2.zig"
704 "special/compiler_rt/udivmod.zig"708 "special/compiler_rt/udivmod.zig"
705 "special/compiler_rt/udivmoddi4.zig"709 "special/compiler_rt/udivmoddi4.zig"
...@@ -716,6 +720,9 @@ set(ZIG_STD_FILES...@@ -716,6 +720,9 @@ set(ZIG_STD_FILES
716 "statically_initialized_mutex.zig"720 "statically_initialized_mutex.zig"
717 "std.zig"721 "std.zig"
718 "testing.zig"722 "testing.zig"
723 "thread.zig"
724 "time.zig"
725 "time/epoch.zig"
719 "unicode.zig"726 "unicode.zig"
720 "valgrind.zig"727 "valgrind.zig"
721 "valgrind/callgrind.zig"728 "valgrind/callgrind.zig"
...@@ -6707,8 +6714,6 @@ target_link_libraries(zig0 compiler)...@@ -6707,8 +6714,6 @@ target_link_libraries(zig0 compiler)
67076714
6708if(WIN32)6715if(WIN32)
6709 set(LIBUSERLAND "${CMAKE_BINARY_DIR}/userland.lib")6716 set(LIBUSERLAND "${CMAKE_BINARY_DIR}/userland.lib")
6710elseif(APPLE)
6711 set(LIBUSERLAND "${CMAKE_BINARY_DIR}/userland.o")
6712else()6717else()
6713 set(LIBUSERLAND "${CMAKE_BINARY_DIR}/libuserland.a")6718 set(LIBUSERLAND "${CMAKE_BINARY_DIR}/libuserland.a")
6714endif()6719endif()
build.zig+17-27
...@@ -2,28 +2,28 @@ const builtin = @import("builtin");...@@ -2,28 +2,28 @@ const builtin = @import("builtin");
2const std = @import("std");2const std = @import("std");
3const Builder = std.build.Builder;3const Builder = std.build.Builder;
4const tests = @import("test/tests.zig");4const tests = @import("test/tests.zig");
5const os = std.os;
6const BufMap = std.BufMap;5const BufMap = std.BufMap;
7const warn = std.debug.warn;6const warn = std.debug.warn;
8const mem = std.mem;7const mem = std.mem;
9const ArrayList = std.ArrayList;8const ArrayList = std.ArrayList;
10const Buffer = std.Buffer;9const Buffer = std.Buffer;
11const io = std.io;10const io = std.io;
11const fs = std.fs;
1212
13pub fn build(b: *Builder) !void {13pub fn build(b: *Builder) !void {
14 const mode = b.standardReleaseOptions();14 const mode = b.standardReleaseOptions();
1515
16 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");16 var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig");
1717
18 const rel_zig_exe = try os.path.relative(b.allocator, b.build_root, b.zig_exe);18 const rel_zig_exe = try fs.path.relative(b.allocator, b.build_root, b.zig_exe);
19 const langref_out_path = os.path.join(19 const langref_out_path = fs.path.join(
20 b.allocator,20 b.allocator,
21 [][]const u8{ b.cache_root, "langref.html" },21 [][]const u8{ b.cache_root, "langref.html" },
22 ) catch unreachable;22 ) catch unreachable;
23 var docgen_cmd = docgen_exe.run();23 var docgen_cmd = docgen_exe.run();
24 docgen_cmd.addArgs([][]const u8{24 docgen_cmd.addArgs([][]const u8{
25 rel_zig_exe,25 rel_zig_exe,
26 "doc" ++ os.path.sep_str ++ "langref.html.in",26 "doc" ++ fs.path.sep_str ++ "langref.html.in",
27 langref_out_path,27 langref_out_path,
28 });28 });
29 docgen_cmd.step.dependOn(&docgen_exe.step);29 docgen_cmd.step.dependOn(&docgen_exe.step);
...@@ -137,7 +137,7 @@ fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void {...@@ -137,7 +137,7 @@ fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void {
137 for (dep.libdirs.toSliceConst()) |lib_dir| {137 for (dep.libdirs.toSliceConst()) |lib_dir| {
138 lib_exe_obj.addLibPath(lib_dir);138 lib_exe_obj.addLibPath(lib_dir);
139 }139 }
140 const lib_dir = os.path.join(140 const lib_dir = fs.path.join(
141 b.allocator,141 b.allocator,
142 [][]const u8{ dep.prefix, "lib" },142 [][]const u8{ dep.prefix, "lib" },
143 ) catch unreachable;143 ) catch unreachable;
...@@ -146,7 +146,7 @@ fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void {...@@ -146,7 +146,7 @@ fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void {
146 ([]const u8)("libncurses.a")146 ([]const u8)("libncurses.a")
147 else147 else
148 b.fmt("lib{}.a", lib);148 b.fmt("lib{}.a", lib);
149 const static_lib_name = os.path.join(149 const static_lib_name = fs.path.join(
150 b.allocator,150 b.allocator,
151 [][]const u8{ lib_dir, static_bare_name },151 [][]const u8{ lib_dir, static_bare_name },
152 ) catch unreachable;152 ) catch unreachable;
...@@ -166,10 +166,8 @@ fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void {...@@ -166,10 +166,8 @@ fn dependOnLib(b: *Builder, lib_exe_obj: var, dep: LibraryDep) void {
166}166}
167167
168fn fileExists(filename: []const u8) !bool {168fn fileExists(filename: []const u8) !bool {
169 os.File.access(filename) catch |err| switch (err) {169 fs.File.access(filename) catch |err| switch (err) {
170 error.PermissionDenied,170 error.FileNotFound => return false,
171 error.FileNotFound,
172 => return false,
173 else => return err,171 else => return err,
174 };172 };
175 return true;173 return true;
...@@ -177,7 +175,7 @@ fn fileExists(filename: []const u8) !bool {...@@ -177,7 +175,7 @@ fn fileExists(filename: []const u8) !bool {
177175
178fn addCppLib(b: *Builder, lib_exe_obj: var, cmake_binary_dir: []const u8, lib_name: []const u8) void {176fn addCppLib(b: *Builder, lib_exe_obj: var, cmake_binary_dir: []const u8, lib_name: []const u8) void {
179 const lib_prefix = if (lib_exe_obj.target.isWindows()) "" else "lib";177 const lib_prefix = if (lib_exe_obj.target.isWindows()) "" else "lib";
180 lib_exe_obj.addObjectFile(os.path.join(b.allocator, [][]const u8{178 lib_exe_obj.addObjectFile(fs.path.join(b.allocator, [][]const u8{
181 cmake_binary_dir,179 cmake_binary_dir,
182 "zig_cpp",180 "zig_cpp",
183 b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt()),181 b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt()),
...@@ -223,7 +221,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {...@@ -223,7 +221,7 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
223 if (mem.startsWith(u8, lib_arg, "-l")) {221 if (mem.startsWith(u8, lib_arg, "-l")) {
224 try result.system_libs.append(lib_arg[2..]);222 try result.system_libs.append(lib_arg[2..]);
225 } else {223 } else {
226 if (os.path.isAbsolute(lib_arg)) {224 if (fs.path.isAbsolute(lib_arg)) {
227 try result.libs.append(lib_arg);225 try result.libs.append(lib_arg);
228 } else {226 } else {
229 try result.system_libs.append(lib_arg);227 try result.system_libs.append(lib_arg);
...@@ -257,8 +255,8 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {...@@ -257,8 +255,8 @@ fn findLLVM(b: *Builder, llvm_config_exe: []const u8) !LibraryDep {
257pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void {255pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void {
258 var it = mem.tokenize(stdlib_files, ";");256 var it = mem.tokenize(stdlib_files, ";");
259 while (it.next()) |stdlib_file| {257 while (it.next()) |stdlib_file| {
260 const src_path = os.path.join(b.allocator, [][]const u8{ "std", stdlib_file }) catch unreachable;258 const src_path = fs.path.join(b.allocator, [][]const u8{ "std", stdlib_file }) catch unreachable;
261 const dest_path = os.path.join(259 const dest_path = fs.path.join(
262 b.allocator,260 b.allocator,
263 [][]const u8{ "lib", "zig", "std", stdlib_file },261 [][]const u8{ "lib", "zig", "std", stdlib_file },
264 ) catch unreachable;262 ) catch unreachable;
...@@ -269,8 +267,8 @@ pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void {...@@ -269,8 +267,8 @@ pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void {
269pub fn installCHeaders(b: *Builder, c_header_files: []const u8) void {267pub fn installCHeaders(b: *Builder, c_header_files: []const u8) void {
270 var it = mem.tokenize(c_header_files, ";");268 var it = mem.tokenize(c_header_files, ";");
271 while (it.next()) |c_header_file| {269 while (it.next()) |c_header_file| {
272 const src_path = os.path.join(b.allocator, [][]const u8{ "c_headers", c_header_file }) catch unreachable;270 const src_path = fs.path.join(b.allocator, [][]const u8{ "c_headers", c_header_file }) catch unreachable;
273 const dest_path = os.path.join(271 const dest_path = fs.path.join(
274 b.allocator,272 b.allocator,
275 [][]const u8{ "lib", "zig", "include", c_header_file },273 [][]const u8{ "lib", "zig", "include", c_header_file },
276 ) catch unreachable;274 ) catch unreachable;
...@@ -315,7 +313,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {...@@ -315,7 +313,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
315 }313 }
316 dependOnLib(b, exe, ctx.llvm);314 dependOnLib(b, exe, ctx.llvm);
317315
318 if (exe.target.getOs() == builtin.Os.linux) {316 if (exe.target.getOs() == .linux) {
319 try addCxxKnownPath(b, ctx, exe, "libstdc++.a",317 try addCxxKnownPath(b, ctx, exe, "libstdc++.a",
320 \\Unable to determine path to libstdc++.a318 \\Unable to determine path to libstdc++.a
321 \\On Fedora, install libstdc++-static and try again.319 \\On Fedora, install libstdc++-static and try again.
...@@ -385,17 +383,9 @@ const Context = struct {...@@ -385,17 +383,9 @@ const Context = struct {
385};383};
386384
387fn addLibUserlandStep(b: *Builder) void {385fn addLibUserlandStep(b: *Builder) void {
388 // Sadly macOS requires hacks to work around the buggy MACH-O linker code.386 const artifact = b.addStaticLibrary("userland", "src-self-hosted/stage1.zig");
389 const artifact = if (builtin.os == .macosx)
390 b.addObject("userland", "src-self-hosted/stage1.zig")
391 else
392 b.addStaticLibrary("userland", "src-self-hosted/stage1.zig");
393 artifact.disable_gen_h = true;387 artifact.disable_gen_h = true;
394 if (builtin.os == .macosx) {388 artifact.bundle_compiler_rt = true;
395 artifact.disable_stack_probing = true;
396 } else {
397 artifact.bundle_compiler_rt = true;
398 }
399 artifact.setTarget(builtin.arch, builtin.os, builtin.abi);389 artifact.setTarget(builtin.arch, builtin.os, builtin.abi);
400 artifact.linkSystemLibrary("c");390 artifact.linkSystemLibrary("c");
401 const libuserland_step = b.step("libuserland", "Build the userland compiler library for use in stage1");391 const libuserland_step = b.step("libuserland", "Build the userland compiler library for use in stage1");
doc/docgen.zig+30-28
...@@ -1,7 +1,9 @@...@@ -1,7 +1,9 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const std = @import("std");2const std = @import("std");
3const io = std.io;3const io = std.io;
4const os = std.os;4const fs = std.fs;
5const process = std.process;
6const ChildProcess = std.ChildProcess;
5const warn = std.debug.warn;7const warn = std.debug.warn;
6const mem = std.mem;8const mem = std.mem;
7const testing = std.testing;9const testing = std.testing;
...@@ -11,7 +13,7 @@ const max_doc_file_size = 10 * 1024 * 1024;...@@ -11,7 +13,7 @@ const max_doc_file_size = 10 * 1024 * 1024;
11const exe_ext = std.build.Target(std.build.Target.Native).exeFileExt();13const exe_ext = std.build.Target(std.build.Target.Native).exeFileExt();
12const obj_ext = std.build.Target(std.build.Target.Native).oFileExt();14const obj_ext = std.build.Target(std.build.Target.Native).oFileExt();
13const tmp_dir_name = "docgen_tmp";15const tmp_dir_name = "docgen_tmp";
14const test_out_path = tmp_dir_name ++ os.path.sep_str ++ "test" ++ exe_ext;16const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext;
1517
16pub fn main() !void {18pub fn main() !void {
17 var direct_allocator = std.heap.DirectAllocator.init();19 var direct_allocator = std.heap.DirectAllocator.init();
...@@ -22,7 +24,7 @@ pub fn main() !void {...@@ -22,7 +24,7 @@ pub fn main() !void {
2224
23 const allocator = &arena.allocator;25 const allocator = &arena.allocator;
2426
25 var args_it = os.args();27 var args_it = process.args();
2628
27 if (!args_it.skip()) @panic("expected self arg");29 if (!args_it.skip()) @panic("expected self arg");
2830
...@@ -35,10 +37,10 @@ pub fn main() !void {...@@ -35,10 +37,10 @@ pub fn main() !void {
35 const out_file_name = try (args_it.next(allocator) orelse @panic("expected output arg"));37 const out_file_name = try (args_it.next(allocator) orelse @panic("expected output arg"));
36 defer allocator.free(out_file_name);38 defer allocator.free(out_file_name);
3739
38 var in_file = try os.File.openRead(in_file_name);40 var in_file = try fs.File.openRead(in_file_name);
39 defer in_file.close();41 defer in_file.close();
4042
41 var out_file = try os.File.openWrite(out_file_name);43 var out_file = try fs.File.openWrite(out_file_name);
42 defer out_file.close();44 defer out_file.close();
4345
44 var file_in_stream = in_file.inStream();46 var file_in_stream = in_file.inStream();
...@@ -46,13 +48,13 @@ pub fn main() !void {...@@ -46,13 +48,13 @@ pub fn main() !void {
46 const input_file_bytes = try file_in_stream.stream.readAllAlloc(allocator, max_doc_file_size);48 const input_file_bytes = try file_in_stream.stream.readAllAlloc(allocator, max_doc_file_size);
4749
48 var file_out_stream = out_file.outStream();50 var file_out_stream = out_file.outStream();
49 var buffered_out_stream = io.BufferedOutStream(os.File.WriteError).init(&file_out_stream.stream);51 var buffered_out_stream = io.BufferedOutStream(fs.File.WriteError).init(&file_out_stream.stream);
5052
51 var tokenizer = Tokenizer.init(in_file_name, input_file_bytes);53 var tokenizer = Tokenizer.init(in_file_name, input_file_bytes);
52 var toc = try genToc(allocator, &tokenizer);54 var toc = try genToc(allocator, &tokenizer);
5355
54 try os.makePath(allocator, tmp_dir_name);56 try fs.makePath(allocator, tmp_dir_name);
55 defer os.deleteTree(allocator, tmp_dir_name) catch {};57 defer fs.deleteTree(allocator, tmp_dir_name) catch {};
5658
57 try genHtml(allocator, &tokenizer, &toc, &buffered_out_stream.stream, zig_exe);59 try genHtml(allocator, &tokenizer, &toc, &buffered_out_stream.stream, zig_exe);
58 try buffered_out_stream.flush();60 try buffered_out_stream.flush();
...@@ -950,7 +952,7 @@ fn tokenizeAndPrint(docgen_tokenizer: *Tokenizer, out: var, source_token: Token)...@@ -950,7 +952,7 @@ fn tokenizeAndPrint(docgen_tokenizer: *Tokenizer, out: var, source_token: Token)
950fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var, zig_exe: []const u8) !void {952fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var, zig_exe: []const u8) !void {
951 var code_progress_index: usize = 0;953 var code_progress_index: usize = 0;
952954
953 var env_map = try os.getEnvMap(allocator);955 var env_map = try process.getEnvMap(allocator);
954 try env_map.set("ZIG_DEBUG_COLOR", "1");956 try env_map.set("ZIG_DEBUG_COLOR", "1");
955957
956 const builtin_code = try getBuiltinCode(allocator, &env_map, zig_exe);958 const builtin_code = try getBuiltinCode(allocator, &env_map, zig_exe);
...@@ -1012,7 +1014,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1012,7 +1014,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1012 try tokenizeAndPrint(tokenizer, out, code.source_token);1014 try tokenizeAndPrint(tokenizer, out, code.source_token);
1013 try out.write("</pre>");1015 try out.write("</pre>");
1014 const name_plus_ext = try std.fmt.allocPrint(allocator, "{}.zig", code.name);1016 const name_plus_ext = try std.fmt.allocPrint(allocator, "{}.zig", code.name);
1015 const tmp_source_file_name = try os.path.join(1017 const tmp_source_file_name = try fs.path.join(
1016 allocator,1018 allocator,
1017 [][]const u8{ tmp_dir_name, name_plus_ext },1019 [][]const u8{ tmp_dir_name, name_plus_ext },
1018 );1020 );
...@@ -1021,7 +1023,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1021,7 +1023,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1021 switch (code.id) {1023 switch (code.id) {
1022 Code.Id.Exe => |expected_outcome| code_block: {1024 Code.Id.Exe => |expected_outcome| code_block: {
1023 const name_plus_bin_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, exe_ext);1025 const name_plus_bin_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, exe_ext);
1024 const tmp_bin_file_name = try os.path.join(1026 const tmp_bin_file_name = try fs.path.join(
1025 allocator,1027 allocator,
1026 [][]const u8{ tmp_dir_name, name_plus_bin_ext },1028 [][]const u8{ tmp_dir_name, name_plus_bin_ext },
1027 );1029 );
...@@ -1056,7 +1058,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1056,7 +1058,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1056 }1058 }
1057 for (code.link_objects) |link_object| {1059 for (code.link_objects) |link_object| {
1058 const name_with_ext = try std.fmt.allocPrint(allocator, "{}{}", link_object, obj_ext);1060 const name_with_ext = try std.fmt.allocPrint(allocator, "{}{}", link_object, obj_ext);
1059 const full_path_object = try os.path.join(1061 const full_path_object = try fs.path.join(
1060 allocator,1062 allocator,
1061 [][]const u8{ tmp_dir_name, name_with_ext },1063 [][]const u8{ tmp_dir_name, name_with_ext },
1062 );1064 );
...@@ -1076,7 +1078,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1076,7 +1078,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1076 }1078 }
1077 }1079 }
1078 if (expected_outcome == .BuildFail) {1080 if (expected_outcome == .BuildFail) {
1079 const result = try os.ChildProcess.exec(1081 const result = try ChildProcess.exec(
1080 allocator,1082 allocator,
1081 build_args.toSliceConst(),1083 build_args.toSliceConst(),
1082 null,1084 null,
...@@ -1084,7 +1086,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1084,7 +1086,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1084 max_doc_file_size,1086 max_doc_file_size,
1085 );1087 );
1086 switch (result.term) {1088 switch (result.term) {
1087 os.ChildProcess.Term.Exited => |exit_code| {1089 .Exited => |exit_code| {
1088 if (exit_code == 0) {1090 if (exit_code == 0) {
1089 warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);1091 warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
1090 for (build_args.toSliceConst()) |arg|1092 for (build_args.toSliceConst()) |arg|
...@@ -1113,7 +1115,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1113,7 +1115,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1113 if (code.target_str) |triple| {1115 if (code.target_str) |triple| {
1114 if (mem.startsWith(u8, triple, "wasm32") or1116 if (mem.startsWith(u8, triple, "wasm32") or
1115 mem.startsWith(u8, triple, "x86_64-linux") and1117 mem.startsWith(u8, triple, "x86_64-linux") and
1116 (builtin.os != builtin.Os.linux or builtin.arch != builtin.Arch.x86_64))1118 (builtin.os != .linux or builtin.arch != .x86_64))
1117 {1119 {
1118 // skip execution1120 // skip execution
1119 try out.print("</code></pre>\n");1121 try out.print("</code></pre>\n");
...@@ -1124,9 +1126,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1124,9 +1126,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1124 const run_args = [][]const u8{tmp_bin_file_name};1126 const run_args = [][]const u8{tmp_bin_file_name};
11251127
1126 const result = if (expected_outcome == ExpectedOutcome.Fail) blk: {1128 const result = if (expected_outcome == ExpectedOutcome.Fail) blk: {
1127 const result = try os.ChildProcess.exec(allocator, run_args, null, &env_map, max_doc_file_size);1129 const result = try ChildProcess.exec(allocator, run_args, null, &env_map, max_doc_file_size);
1128 switch (result.term) {1130 switch (result.term) {
1129 os.ChildProcess.Term.Exited => |exit_code| {1131 .Exited => |exit_code| {
1130 if (exit_code == 0) {1132 if (exit_code == 0) {
1131 warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);1133 warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
1132 for (run_args) |arg|1134 for (run_args) |arg|
...@@ -1216,9 +1218,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1216,9 +1218,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1216 try out.print(" --release-small");1218 try out.print(" --release-small");
1217 },1219 },
1218 }1220 }
1219 const result = try os.ChildProcess.exec(allocator, test_args.toSliceConst(), null, &env_map, max_doc_file_size);1221 const result = try ChildProcess.exec(allocator, test_args.toSliceConst(), null, &env_map, max_doc_file_size);
1220 switch (result.term) {1222 switch (result.term) {
1221 os.ChildProcess.Term.Exited => |exit_code| {1223 .Exited => |exit_code| {
1222 if (exit_code == 0) {1224 if (exit_code == 0) {
1223 warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);1225 warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
1224 for (test_args.toSliceConst()) |arg|1226 for (test_args.toSliceConst()) |arg|
...@@ -1274,9 +1276,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1274,9 +1276,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1274 },1276 },
1275 }1277 }
12761278
1277 const result = try os.ChildProcess.exec(allocator, test_args.toSliceConst(), null, &env_map, max_doc_file_size);1279 const result = try ChildProcess.exec(allocator, test_args.toSliceConst(), null, &env_map, max_doc_file_size);
1278 switch (result.term) {1280 switch (result.term) {
1279 os.ChildProcess.Term.Exited => |exit_code| {1281 .Exited => |exit_code| {
1280 if (exit_code == 0) {1282 if (exit_code == 0) {
1281 warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);1283 warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
1282 for (test_args.toSliceConst()) |arg|1284 for (test_args.toSliceConst()) |arg|
...@@ -1310,7 +1312,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1310,7 +1312,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1310 },1312 },
1311 Code.Id.Obj => |maybe_error_match| {1313 Code.Id.Obj => |maybe_error_match| {
1312 const name_plus_obj_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, obj_ext);1314 const name_plus_obj_ext = try std.fmt.allocPrint(allocator, "{}{}", code.name, obj_ext);
1313 const tmp_obj_file_name = try os.path.join(1315 const tmp_obj_file_name = try fs.path.join(
1314 allocator,1316 allocator,
1315 [][]const u8{ tmp_dir_name, name_plus_obj_ext },1317 [][]const u8{ tmp_dir_name, name_plus_obj_ext },
1316 );1318 );
...@@ -1318,7 +1320,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1318,7 +1320,7 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1318 defer build_args.deinit();1320 defer build_args.deinit();
13191321
1320 const name_plus_h_ext = try std.fmt.allocPrint(allocator, "{}.h", code.name);1322 const name_plus_h_ext = try std.fmt.allocPrint(allocator, "{}.h", code.name);
1321 const output_h_file_name = try os.path.join(1323 const output_h_file_name = try fs.path.join(
1322 allocator,1324 allocator,
1323 [][]const u8{ tmp_dir_name, name_plus_h_ext },1325 [][]const u8{ tmp_dir_name, name_plus_h_ext },
1324 );1326 );
...@@ -1367,9 +1369,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1367,9 +1369,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1367 }1369 }
13681370
1369 if (maybe_error_match) |error_match| {1371 if (maybe_error_match) |error_match| {
1370 const result = try os.ChildProcess.exec(allocator, build_args.toSliceConst(), null, &env_map, max_doc_file_size);1372 const result = try ChildProcess.exec(allocator, build_args.toSliceConst(), null, &env_map, max_doc_file_size);
1371 switch (result.term) {1373 switch (result.term) {
1372 os.ChildProcess.Term.Exited => |exit_code| {1374 .Exited => |exit_code| {
1373 if (exit_code == 0) {1375 if (exit_code == 0) {
1374 warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);1376 warn("{}\nThe following command incorrectly succeeded:\n", result.stderr);
1375 for (build_args.toSliceConst()) |arg|1377 for (build_args.toSliceConst()) |arg|
...@@ -1448,10 +1450,10 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1448,10 +1450,10 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1448 }1450 }
1449}1451}
14501452
1451fn exec(allocator: *mem.Allocator, env_map: *std.BufMap, args: []const []const u8) !os.ChildProcess.ExecResult {1453fn exec(allocator: *mem.Allocator, env_map: *std.BufMap, args: []const []const u8) !ChildProcess.ExecResult {
1452 const result = try os.ChildProcess.exec(allocator, args, null, env_map, max_doc_file_size);1454 const result = try ChildProcess.exec(allocator, args, null, env_map, max_doc_file_size);
1453 switch (result.term) {1455 switch (result.term) {
1454 os.ChildProcess.Term.Exited => |exit_code| {1456 .Exited => |exit_code| {
1455 if (exit_code != 0) {1457 if (exit_code != 0) {
1456 warn("{}\nThe following command exited with code {}:\n", result.stderr, exit_code);1458 warn("{}\nThe following command exited with code {}:\n", result.stderr, exit_code);
1457 for (args) |arg|1459 for (args) |arg|
doc/langref.html.in+38-5
...@@ -796,8 +796,8 @@ const assert = std.debug.assert;...@@ -796,8 +796,8 @@ const assert = std.debug.assert;
796threadlocal var x: i32 = 1234;796threadlocal var x: i32 = 1234;
797797
798test "thread local storage" {798test "thread local storage" {
799 const thread1 = try std.os.spawnThread({}, testTls);799 const thread1 = try std.Thread.spawn({}, testTls);
800 const thread2 = try std.os.spawnThread({}, testTls);800 const thread2 = try std.Thread.spawn({}, testTls);
801 testTls({});801 testTls({});
802 thread1.wait();802 thread1.wait();
803 thread2.wait();803 thread2.wait();
...@@ -4531,7 +4531,7 @@ const mem = std.mem;...@@ -4531,7 +4531,7 @@ const mem = std.mem;
4531test "cast *[1][*]const u8 to [*]const ?[*]const u8" {4531test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
4532 const window_name = [1][*]const u8{c"window name"};4532 const window_name = [1][*]const u8{c"window name"};
4533 const x: [*]const ?[*]const u8 = &window_name;4533 const x: [*]const ?[*]const u8 = &window_name;
4534 assert(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name"));4534 assert(mem.eql(u8, std.mem.toSliceConst(u8, x[0].?), "window name"));
4535}4535}
4536 {#code_end#}4536 {#code_end#}
4537 {#header_close#}4537 {#header_close#}
...@@ -6734,6 +6734,38 @@ export fn @"A function name that is a complete sentence."() void {}...@@ -6734,6 +6734,38 @@ export fn @"A function name that is a complete sentence."() void {}
6734 </p>6734 </p>
6735 {#header_close#}6735 {#header_close#}
67366736
6737 {#header_open|@hasDecl#}
6738 <pre>{#syntax#}@hasDecl(comptime container: type, comptime name: []const u8) bool{#endsyntax#}</pre>
6739 <p>
6740 Returns whether or not a {#link|struct#}, {#link|enum#}, or {#link|union#} has a declaration
6741 matching {#syntax#}name{#endsyntax#}.
6742 </p>
6743 {#code_begin|test#}
6744const std = @import("std");
6745const assert = std.debug.assert;
6746
6747const Foo = struct {
6748 nope: i32,
6749
6750 pub var blah = "xxx";
6751 const hi = 1;
6752};
6753
6754test "@hasDecl" {
6755 assert(@hasDecl(Foo, "blah"));
6756
6757 // Even though `hi` is private, @hasDecl returns true because this test is
6758 // in the same file scope as Foo. It would return false if Foo was declared
6759 // in a different file.
6760 assert(@hasDecl(Foo, "hi"));
6761
6762 // @hasDecl is for declarations; not fields.
6763 assert(!@hasDecl(Foo, "nope"));
6764 assert(!@hasDecl(Foo, "nope1234"));
6765}
6766 {#code_end#}
6767 {#header_close#}
6768
6737 {#header_open|@import#}6769 {#header_open|@import#}
6738 <pre>{#syntax#}@import(comptime path: []u8) type{#endsyntax#}</pre>6770 <pre>{#syntax#}@import(comptime path: []u8) type{#endsyntax#}</pre>
6739 <p>6771 <p>
...@@ -8980,8 +9012,8 @@ export fn add(a: i32, b: i32) void {...@@ -8980,8 +9012,8 @@ export fn add(a: i32, b: i32) void {
8980const std = @import("std");9012const std = @import("std");
89819013
8982pub fn main() !void {9014pub fn main() !void {
8983 const args = try std.os.argsAlloc(std.heap.wasm_allocator);9015 const args = try std.process.argsAlloc(std.heap.wasm_allocator);
8984 defer std.os.argsFree(std.heap.wasm_allocator, args);9016 defer std.process.argsFree(std.heap.wasm_allocator, args);
89859017
8986 for (args) |arg, i| {9018 for (args) |arg, i| {
8987 std.debug.warn("{}: {}\n", i, arg);9019 std.debug.warn("{}: {}\n", i, arg);
...@@ -9891,6 +9923,7 @@ keyword &lt;- KEYWORD_align / KEYWORD_and / KEYWORD_allowzero / KEYWORD_anyerror...@@ -9891,6 +9923,7 @@ keyword &lt;- KEYWORD_align / KEYWORD_and / KEYWORD_allowzero / KEYWORD_anyerror
9891 <li>Avoid local maximums.</li>9923 <li>Avoid local maximums.</li>
9892 <li>Reduce the amount one must remember.</li>9924 <li>Reduce the amount one must remember.</li>
9893 <li>Minimize energy spent on coding style.</li>9925 <li>Minimize energy spent on coding style.</li>
9926 <li>Resource deallocation must succeed.</li>
9894 <li>Together we serve end users.</li>9927 <li>Together we serve end users.</li>
9895 </ul>9928 </ul>
9896 {#header_close#}9929 {#header_close#}
example/cat/main.zig+5-4
...@@ -1,12 +1,13 @@...@@ -1,12 +1,13 @@
1const std = @import("std");1const std = @import("std");
2const io = std.io;2const io = std.io;
3const process = std.process;
4const File = std.fs.File;
3const mem = std.mem;5const mem = std.mem;
4const os = std.os;
5const warn = std.debug.warn;6const warn = std.debug.warn;
6const allocator = std.debug.global_allocator;7const allocator = std.debug.global_allocator;
78
8pub fn main() !void {9pub fn main() !void {
9 var args_it = os.args();10 var args_it = process.args();
10 const exe = try unwrapArg(args_it.next(allocator).?);11 const exe = try unwrapArg(args_it.next(allocator).?);
11 var catted_anything = false;12 var catted_anything = false;
12 var stdout_file = try io.getStdOut();13 var stdout_file = try io.getStdOut();
...@@ -20,7 +21,7 @@ pub fn main() !void {...@@ -20,7 +21,7 @@ pub fn main() !void {
20 } else if (arg[0] == '-') {21 } else if (arg[0] == '-') {
21 return usage(exe);22 return usage(exe);
22 } else {23 } else {
23 var file = os.File.openRead(arg) catch |err| {24 var file = File.openRead(arg) catch |err| {
24 warn("Unable to open file: {}\n", @errorName(err));25 warn("Unable to open file: {}\n", @errorName(err));
25 return err;26 return err;
26 };27 };
...@@ -41,7 +42,7 @@ fn usage(exe: []const u8) !void {...@@ -41,7 +42,7 @@ fn usage(exe: []const u8) !void {
41 return error.Invalid;42 return error.Invalid;
42}43}
4344
44fn cat_file(stdout: *os.File, file: *os.File) !void {45fn cat_file(stdout: *File, file: *File) !void {
45 var buf: [1024 * 4]u8 = undefined;46 var buf: [1024 * 4]u8 = undefined;
4647
47 while (true) {48 while (true) {
example/guess_number/main.zig+1-2
...@@ -2,7 +2,6 @@ const builtin = @import("builtin");...@@ -2,7 +2,6 @@ const builtin = @import("builtin");
2const std = @import("std");2const std = @import("std");
3const io = std.io;3const io = std.io;
4const fmt = std.fmt;4const fmt = std.fmt;
5const os = std.os;
65
7pub fn main() !void {6pub fn main() !void {
8 var stdout_file = try io.getStdOut();7 var stdout_file = try io.getStdOut();
...@@ -11,7 +10,7 @@ pub fn main() !void {...@@ -11,7 +10,7 @@ pub fn main() !void {
11 try stdout.print("Welcome to the Guess Number Game in Zig.\n");10 try stdout.print("Welcome to the Guess Number Game in Zig.\n");
1211
13 var seed_bytes: [@sizeOf(u64)]u8 = undefined;12 var seed_bytes: [@sizeOf(u64)]u8 = undefined;
14 os.getRandomBytes(seed_bytes[0..]) catch |err| {13 std.crypto.randomBytes(seed_bytes[0..]) catch |err| {
15 std.debug.warn("unable to seed random number generator: {}", err);14 std.debug.warn("unable to seed random number generator: {}", err);
16 return err;15 return err;
17 };16 };
example/hello_world/hello_libc.zig-1
...@@ -9,6 +9,5 @@ const msg = c"Hello, world!\n";...@@ -9,6 +9,5 @@ const msg = c"Hello, world!\n";
99
10export fn main(argc: c_int, argv: **u8) c_int {10export fn main(argc: c_int, argv: **u8) c_int {
11 if (c.printf(msg) != @intCast(c_int, c.strlen(msg))) return -1;11 if (c.printf(msg) != @intCast(c_int, c.strlen(msg))) return -1;
12
13 return 0;12 return 0;
14}13}
src-self-hosted/compilation.zig+12-12
...@@ -1,5 +1,4 @@...@@ -1,5 +1,4 @@
1const std = @import("std");1const std = @import("std");
2const os = std.os;
3const io = std.io;2const io = std.io;
4const mem = std.mem;3const mem = std.mem;
5const Allocator = mem.Allocator;4const Allocator = mem.Allocator;
...@@ -54,7 +53,7 @@ pub const ZigCompiler = struct {...@@ -54,7 +53,7 @@ pub const ZigCompiler = struct {
54 };53 };
5554
56 var seed_bytes: [@sizeOf(u64)]u8 = undefined;55 var seed_bytes: [@sizeOf(u64)]u8 = undefined;
57 try std.os.getRandomBytes(seed_bytes[0..]);56 try std.crypto.randomBytes(seed_bytes[0..]);
58 const seed = mem.readIntNative(u64, &seed_bytes);57 const seed = mem.readIntNative(u64, &seed_bytes);
5958
60 return ZigCompiler{59 return ZigCompiler{
...@@ -302,6 +301,7 @@ pub const Compilation = struct {...@@ -302,6 +301,7 @@ pub const Compilation = struct {
302 InvalidUtf8,301 InvalidUtf8,
303 BadPathName,302 BadPathName,
304 DeviceBusy,303 DeviceBusy,
304 CurrentWorkingDirectoryUnlinked,
305 };305 };
306306
307 pub const Event = union(enum) {307 pub const Event = union(enum) {
...@@ -487,7 +487,7 @@ pub const Compilation = struct {...@@ -487,7 +487,7 @@ pub const Compilation = struct {
487 comp.name = try Buffer.init(comp.arena(), name);487 comp.name = try Buffer.init(comp.arena(), name);
488 comp.llvm_triple = try target.getTriple(comp.arena());488 comp.llvm_triple = try target.getTriple(comp.arena());
489 comp.llvm_target = try Target.llvmTargetFromTriple(comp.llvm_triple);489 comp.llvm_target = try Target.llvmTargetFromTriple(comp.llvm_triple);
490 comp.zig_std_dir = try std.os.path.join(comp.arena(), [][]const u8{ zig_lib_dir, "std" });490 comp.zig_std_dir = try std.fs.path.join(comp.arena(), [][]const u8{ zig_lib_dir, "std" });
491491
492 const opt_level = switch (build_mode) {492 const opt_level = switch (build_mode) {
493 builtin.Mode.Debug => llvm.CodeGenLevelNone,493 builtin.Mode.Debug => llvm.CodeGenLevelNone,
...@@ -529,8 +529,8 @@ pub const Compilation = struct {...@@ -529,8 +529,8 @@ pub const Compilation = struct {
529 defer comp.events.destroy();529 defer comp.events.destroy();
530530
531 if (root_src_path) |root_src| {531 if (root_src_path) |root_src| {
532 const dirname = std.os.path.dirname(root_src) orelse ".";532 const dirname = std.fs.path.dirname(root_src) orelse ".";
533 const basename = std.os.path.basename(root_src);533 const basename = std.fs.path.basename(root_src);
534534
535 comp.root_package = try Package.create(comp.arena(), dirname, basename);535 comp.root_package = try Package.create(comp.arena(), dirname, basename);
536 comp.std_package = try Package.create(comp.arena(), comp.zig_std_dir, "std.zig");536 comp.std_package = try Package.create(comp.arena(), comp.zig_std_dir, "std.zig");
...@@ -558,7 +558,7 @@ pub const Compilation = struct {...@@ -558,7 +558,7 @@ pub const Compilation = struct {
558558
559 if (comp.tmp_dir.getOrNull()) |tmp_dir_result| if (tmp_dir_result.*) |tmp_dir| {559 if (comp.tmp_dir.getOrNull()) |tmp_dir_result| if (tmp_dir_result.*) |tmp_dir| {
560 // TODO evented I/O?560 // TODO evented I/O?
561 os.deleteTree(comp.arena(), tmp_dir) catch {};561 std.fs.deleteTree(comp.arena(), tmp_dir) catch {};
562 } else |_| {};562 } else |_| {};
563 }563 }
564564
...@@ -970,8 +970,8 @@ pub const Compilation = struct {...@@ -970,8 +970,8 @@ pub const Compilation = struct {
970 async fn initialCompile(self: *Compilation) !void {970 async fn initialCompile(self: *Compilation) !void {
971 if (self.root_src_path) |root_src_path| {971 if (self.root_src_path) |root_src_path| {
972 const root_scope = blk: {972 const root_scope = blk: {
973 // TODO async/await os.path.real973 // TODO async/await std.fs.realpath
974 const root_src_real_path = os.path.realAlloc(self.gpa(), root_src_path) catch |err| {974 const root_src_real_path = std.fs.realpathAlloc(self.gpa(), root_src_path) catch |err| {
975 try self.addCompileErrorCli(root_src_path, "unable to open: {}", @errorName(err));975 try self.addCompileErrorCli(root_src_path, "unable to open: {}", @errorName(err));
976 return;976 return;
977 };977 };
...@@ -1196,7 +1196,7 @@ pub const Compilation = struct {...@@ -1196,7 +1196,7 @@ pub const Compilation = struct {
1196 const file_name = try std.fmt.allocPrint(self.gpa(), "{}{}", file_prefix[0..], suffix);1196 const file_name = try std.fmt.allocPrint(self.gpa(), "{}{}", file_prefix[0..], suffix);
1197 defer self.gpa().free(file_name);1197 defer self.gpa().free(file_name);
11981198
1199 const full_path = try os.path.join(self.gpa(), [][]const u8{ tmp_dir, file_name[0..] });1199 const full_path = try std.fs.path.join(self.gpa(), [][]const u8{ tmp_dir, file_name[0..] });
1200 errdefer self.gpa().free(full_path);1200 errdefer self.gpa().free(full_path);
12011201
1202 return Buffer.fromOwnedSlice(self.gpa(), full_path);1202 return Buffer.fromOwnedSlice(self.gpa(), full_path);
...@@ -1217,8 +1217,8 @@ pub const Compilation = struct {...@@ -1217,8 +1217,8 @@ pub const Compilation = struct {
1217 const zig_dir_path = try getZigDir(self.gpa());1217 const zig_dir_path = try getZigDir(self.gpa());
1218 defer self.gpa().free(zig_dir_path);1218 defer self.gpa().free(zig_dir_path);
12191219
1220 const tmp_dir = try os.path.join(self.arena(), [][]const u8{ zig_dir_path, comp_dir_name[0..] });1220 const tmp_dir = try std.fs.path.join(self.arena(), [][]const u8{ zig_dir_path, comp_dir_name[0..] });
1221 try os.makePath(self.gpa(), tmp_dir);1221 try std.fs.makePath(self.gpa(), tmp_dir);
1222 return tmp_dir;1222 return tmp_dir;
1223 }1223 }
12241224
...@@ -1384,7 +1384,7 @@ async fn addFnToLinkSet(comp: *Compilation, fn_val: *Value.Fn) void {...@@ -1384,7 +1384,7 @@ async fn addFnToLinkSet(comp: *Compilation, fn_val: *Value.Fn) void {
1384}1384}
13851385
1386fn getZigDir(allocator: *mem.Allocator) ![]u8 {1386fn getZigDir(allocator: *mem.Allocator) ![]u8 {
1387 return os.getAppDataDir(allocator, "zig");1387 return std.fs.getAppDataDir(allocator, "zig");
1388}1388}
13891389
1390async fn analyzeFnType(1390async fn analyzeFnType(
src-self-hosted/errmsg.zig+5-4
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const std = @import("std");1const std = @import("std");
2const mem = std.mem;2const mem = std.mem;
3const os = std.os;3const fs = std.fs;
4const process = std.process;
4const Token = std.zig.Token;5const Token = std.zig.Token;
5const ast = std.zig.ast;6const ast = std.zig.ast;
6const TokenIndex = std.zig.ast.TokenIndex;7const TokenIndex = std.zig.ast.TokenIndex;
...@@ -239,10 +240,10 @@ pub const Msg = struct {...@@ -239,10 +240,10 @@ pub const Msg = struct {
239 const allocator = msg.getAllocator();240 const allocator = msg.getAllocator();
240 const tree = msg.getTree();241 const tree = msg.getTree();
241242
242 const cwd = try os.getCwdAlloc(allocator);243 const cwd = try process.getCwdAlloc(allocator);
243 defer allocator.free(cwd);244 defer allocator.free(cwd);
244245
245 const relpath = try os.path.relative(allocator, cwd, msg.realpath);246 const relpath = try fs.path.relative(allocator, cwd, msg.realpath);
246 defer allocator.free(relpath);247 defer allocator.free(relpath);
247248
248 const path = if (relpath.len < msg.realpath.len) relpath else msg.realpath;249 const path = if (relpath.len < msg.realpath.len) relpath else msg.realpath;
...@@ -276,7 +277,7 @@ pub const Msg = struct {...@@ -276,7 +277,7 @@ pub const Msg = struct {
276 try stream.write("\n");277 try stream.write("\n");
277 }278 }
278279
279 pub fn printToFile(msg: *const Msg, file: os.File, color: Color) !void {280 pub fn printToFile(msg: *const Msg, file: fs.File, color: Color) !void {
280 const color_on = switch (color) {281 const color_on = switch (color) {
281 Color.Auto => file.isTty(),282 Color.Auto => file.isTty(),
282 Color.On => true,283 Color.On => true,
src-self-hosted/introspect.zig+6-6
...@@ -2,19 +2,19 @@...@@ -2,19 +2,19 @@
22
3const std = @import("std");3const std = @import("std");
4const mem = std.mem;4const mem = std.mem;
5const os = std.os;5const fs = std.fs;
66
7const warn = std.debug.warn;7const warn = std.debug.warn;
88
9/// Caller must free result9/// Caller must free result
10pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 {10pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 {
11 const test_zig_dir = try os.path.join(allocator, [][]const u8{ test_path, "lib", "zig" });11 const test_zig_dir = try fs.path.join(allocator, [][]const u8{ test_path, "lib", "zig" });
12 errdefer allocator.free(test_zig_dir);12 errdefer allocator.free(test_zig_dir);
1313
14 const test_index_file = try os.path.join(allocator, [][]const u8{ test_zig_dir, "std", "std.zig" });14 const test_index_file = try fs.path.join(allocator, [][]const u8{ test_zig_dir, "std", "std.zig" });
15 defer allocator.free(test_index_file);15 defer allocator.free(test_index_file);
1616
17 var file = try os.File.openRead(test_index_file);17 var file = try fs.File.openRead(test_index_file);
18 file.close();18 file.close();
1919
20 return test_zig_dir;20 return test_zig_dir;
...@@ -22,12 +22,12 @@ pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![...@@ -22,12 +22,12 @@ pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![
2222
23/// Caller must free result23/// Caller must free result
24pub fn findZigLibDir(allocator: *mem.Allocator) ![]u8 {24pub fn findZigLibDir(allocator: *mem.Allocator) ![]u8 {
25 const self_exe_path = try os.selfExeDirPathAlloc(allocator);25 const self_exe_path = try fs.selfExeDirPathAlloc(allocator);
26 defer allocator.free(self_exe_path);26 defer allocator.free(self_exe_path);
2727
28 var cur_path: []const u8 = self_exe_path;28 var cur_path: []const u8 = self_exe_path;
29 while (true) {29 while (true) {
30 const test_dir = os.path.dirname(cur_path) orelse ".";30 const test_dir = fs.path.dirname(cur_path) orelse ".";
3131
32 if (mem.eql(u8, test_dir, cur_path)) {32 if (mem.eql(u8, test_dir, cur_path)) {
33 break;33 break;
src-self-hosted/libc_installation.zig+19-18
...@@ -3,6 +3,7 @@ const builtin = @import("builtin");...@@ -3,6 +3,7 @@ const builtin = @import("builtin");
3const event = std.event;3const event = std.event;
4const Target = @import("target.zig").Target;4const Target = @import("target.zig").Target;
5const c = @import("c.zig");5const c = @import("c.zig");
6const fs = std.fs;
67
7/// See the render function implementation for documentation of the fields.8/// See the render function implementation for documentation of the fields.
8pub const LibCInstallation = struct {9pub const LibCInstallation = struct {
...@@ -30,7 +31,7 @@ pub const LibCInstallation = struct {...@@ -30,7 +31,7 @@ pub const LibCInstallation = struct {
30 self: *LibCInstallation,31 self: *LibCInstallation,
31 allocator: *std.mem.Allocator,32 allocator: *std.mem.Allocator,
32 libc_file: []const u8,33 libc_file: []const u8,
33 stderr: *std.io.OutStream(std.os.File.WriteError),34 stderr: *std.io.OutStream(fs.File.WriteError),
34 ) !void {35 ) !void {
35 self.initEmpty();36 self.initEmpty();
3637
...@@ -100,7 +101,7 @@ pub const LibCInstallation = struct {...@@ -100,7 +101,7 @@ pub const LibCInstallation = struct {
100 }101 }
101 }102 }
102103
103 pub fn render(self: *const LibCInstallation, out: *std.io.OutStream(std.os.File.WriteError)) !void {104 pub fn render(self: *const LibCInstallation, out: *std.io.OutStream(fs.File.WriteError)) !void {
104 @setEvalBranchQuota(4000);105 @setEvalBranchQuota(4000);
105 try out.print(106 try out.print(
106 \\# The directory that contains `stdlib.h`.107 \\# The directory that contains `stdlib.h`.
...@@ -148,7 +149,7 @@ pub const LibCInstallation = struct {...@@ -148,7 +149,7 @@ pub const LibCInstallation = struct {
148 errdefer if (windows_sdk) |sdk| c.zig_free_windows_sdk(@ptrCast(?[*]c.ZigWindowsSDK, sdk));149 errdefer if (windows_sdk) |sdk| c.zig_free_windows_sdk(@ptrCast(?[*]c.ZigWindowsSDK, sdk));
149150
150 switch (builtin.os) {151 switch (builtin.os) {
151 builtin.Os.windows => {152 .windows => {
152 var sdk: *c.ZigWindowsSDK = undefined;153 var sdk: *c.ZigWindowsSDK = undefined;
153 switch (c.zig_find_windows_sdk(@ptrCast(?[*]?[*]c.ZigWindowsSDK, &sdk))) {154 switch (c.zig_find_windows_sdk(@ptrCast(?[*]?[*]c.ZigWindowsSDK, &sdk))) {
154 c.ZigFindWindowsSdkError.None => {155 c.ZigFindWindowsSdkError.None => {
...@@ -166,13 +167,13 @@ pub const LibCInstallation = struct {...@@ -166,13 +167,13 @@ pub const LibCInstallation = struct {
166 c.ZigFindWindowsSdkError.PathTooLong => return error.NotFound,167 c.ZigFindWindowsSdkError.PathTooLong => return error.NotFound,
167 }168 }
168 },169 },
169 builtin.Os.linux => {170 .linux => {
170 try group.call(findNativeIncludeDirLinux, self, loop);171 try group.call(findNativeIncludeDirLinux, self, loop);
171 try group.call(findNativeLibDirLinux, self, loop);172 try group.call(findNativeLibDirLinux, self, loop);
172 try group.call(findNativeStaticLibDir, self, loop);173 try group.call(findNativeStaticLibDir, self, loop);
173 try group.call(findNativeDynamicLinker, self, loop);174 try group.call(findNativeDynamicLinker, self, loop);
174 },175 },
175 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {176 .macosx, .freebsd, .netbsd => {
176 self.include_dir = try std.mem.dupe(loop.allocator, u8, "/usr/include");177 self.include_dir = try std.mem.dupe(loop.allocator, u8, "/usr/include");
177 },178 },
178 else => @compileError("unimplemented: find libc for this OS"),179 else => @compileError("unimplemented: find libc for this OS"),
...@@ -181,7 +182,7 @@ pub const LibCInstallation = struct {...@@ -181,7 +182,7 @@ pub const LibCInstallation = struct {
181 }182 }
182183
183 async fn findNativeIncludeDirLinux(self: *LibCInstallation, loop: *event.Loop) !void {184 async fn findNativeIncludeDirLinux(self: *LibCInstallation, loop: *event.Loop) !void {
184 const cc_exe = std.os.getEnvPosix("CC") orelse "cc";185 const cc_exe = std.os.getenv("CC") orelse "cc";
185 const argv = []const []const u8{186 const argv = []const []const u8{
186 cc_exe,187 cc_exe,
187 "-E",188 "-E",
...@@ -190,7 +191,7 @@ pub const LibCInstallation = struct {...@@ -190,7 +191,7 @@ pub const LibCInstallation = struct {
190 "/dev/null",191 "/dev/null",
191 };192 };
192 // TODO make this use event loop193 // TODO make this use event loop
193 const errorable_result = std.os.ChildProcess.exec(loop.allocator, argv, null, null, 1024 * 1024);194 const errorable_result = std.ChildProcess.exec(loop.allocator, argv, null, null, 1024 * 1024);
194 const exec_result = if (std.debug.runtime_safety) blk: {195 const exec_result = if (std.debug.runtime_safety) blk: {
195 break :blk errorable_result catch unreachable;196 break :blk errorable_result catch unreachable;
196 } else blk: {197 } else blk: {
...@@ -205,7 +206,7 @@ pub const LibCInstallation = struct {...@@ -205,7 +206,7 @@ pub const LibCInstallation = struct {
205 }206 }
206207
207 switch (exec_result.term) {208 switch (exec_result.term) {
208 std.os.ChildProcess.Term.Exited => |code| {209 std.ChildProcess.Term.Exited => |code| {
209 if (code != 0) return error.CCompilerExitCode;210 if (code != 0) return error.CCompilerExitCode;
210 },211 },
211 else => {212 else => {
...@@ -230,7 +231,7 @@ pub const LibCInstallation = struct {...@@ -230,7 +231,7 @@ pub const LibCInstallation = struct {
230 while (path_i < search_paths.len) : (path_i += 1) {231 while (path_i < search_paths.len) : (path_i += 1) {
231 const search_path_untrimmed = search_paths.at(search_paths.len - path_i - 1);232 const search_path_untrimmed = search_paths.at(search_paths.len - path_i - 1);
232 const search_path = std.mem.trimLeft(u8, search_path_untrimmed, " ");233 const search_path = std.mem.trimLeft(u8, search_path_untrimmed, " ");
233 const stdlib_path = try std.os.path.join(loop.allocator, [][]const u8{ search_path, "stdlib.h" });234 const stdlib_path = try fs.path.join(loop.allocator, [][]const u8{ search_path, "stdlib.h" });
234 defer loop.allocator.free(stdlib_path);235 defer loop.allocator.free(stdlib_path);
235236
236 if (try fileExists(stdlib_path)) {237 if (try fileExists(stdlib_path)) {
...@@ -254,7 +255,7 @@ pub const LibCInstallation = struct {...@@ -254,7 +255,7 @@ pub const LibCInstallation = struct {
254 const stream = &std.io.BufferOutStream.init(&result_buf).stream;255 const stream = &std.io.BufferOutStream.init(&result_buf).stream;
255 try stream.print("{}\\Include\\{}\\ucrt", search.path, search.version);256 try stream.print("{}\\Include\\{}\\ucrt", search.path, search.version);
256257
257 const stdlib_path = try std.os.path.join(258 const stdlib_path = try fs.path.join(
258 loop.allocator,259 loop.allocator,
259 [][]const u8{ result_buf.toSliceConst(), "stdlib.h" },260 [][]const u8{ result_buf.toSliceConst(), "stdlib.h" },
260 );261 );
...@@ -286,7 +287,7 @@ pub const LibCInstallation = struct {...@@ -286,7 +287,7 @@ pub const LibCInstallation = struct {
286 builtin.Arch.aarch64 => try stream.write("arm"),287 builtin.Arch.aarch64 => try stream.write("arm"),
287 else => return error.UnsupportedArchitecture,288 else => return error.UnsupportedArchitecture,
288 }289 }
289 const ucrt_lib_path = try std.os.path.join(290 const ucrt_lib_path = try fs.path.join(
290 loop.allocator,291 loop.allocator,
291 [][]const u8{ result_buf.toSliceConst(), "ucrt.lib" },292 [][]const u8{ result_buf.toSliceConst(), "ucrt.lib" },
292 );293 );
...@@ -364,7 +365,7 @@ pub const LibCInstallation = struct {...@@ -364,7 +365,7 @@ pub const LibCInstallation = struct {
364 builtin.Arch.aarch64 => try stream.write("arm\\"),365 builtin.Arch.aarch64 => try stream.write("arm\\"),
365 else => return error.UnsupportedArchitecture,366 else => return error.UnsupportedArchitecture,
366 }367 }
367 const kernel32_path = try std.os.path.join(368 const kernel32_path = try fs.path.join(
368 loop.allocator,369 loop.allocator,
369 [][]const u8{ result_buf.toSliceConst(), "kernel32.lib" },370 [][]const u8{ result_buf.toSliceConst(), "kernel32.lib" },
370 );371 );
...@@ -391,14 +392,14 @@ pub const LibCInstallation = struct {...@@ -391,14 +392,14 @@ pub const LibCInstallation = struct {
391392
392/// caller owns returned memory393/// caller owns returned memory
393async fn ccPrintFileName(loop: *event.Loop, o_file: []const u8, want_dirname: bool) ![]u8 {394async fn ccPrintFileName(loop: *event.Loop, o_file: []const u8, want_dirname: bool) ![]u8 {
394 const cc_exe = std.os.getEnvPosix("CC") orelse "cc";395 const cc_exe = std.os.getenv("CC") orelse "cc";
395 const arg1 = try std.fmt.allocPrint(loop.allocator, "-print-file-name={}", o_file);396 const arg1 = try std.fmt.allocPrint(loop.allocator, "-print-file-name={}", o_file);
396 defer loop.allocator.free(arg1);397 defer loop.allocator.free(arg1);
397 const argv = []const []const u8{ cc_exe, arg1 };398 const argv = []const []const u8{ cc_exe, arg1 };
398399
399 // TODO This simulates evented I/O for the child process exec400 // TODO This simulates evented I/O for the child process exec
400 await (async loop.yield() catch unreachable);401 await (async loop.yield() catch unreachable);
401 const errorable_result = std.os.ChildProcess.exec(loop.allocator, argv, null, null, 1024 * 1024);402 const errorable_result = std.ChildProcess.exec(loop.allocator, argv, null, null, 1024 * 1024);
402 const exec_result = if (std.debug.runtime_safety) blk: {403 const exec_result = if (std.debug.runtime_safety) blk: {
403 break :blk errorable_result catch unreachable;404 break :blk errorable_result catch unreachable;
404 } else blk: {405 } else blk: {
...@@ -412,7 +413,7 @@ async fn ccPrintFileName(loop: *event.Loop, o_file: []const u8, want_dirname: bo...@@ -412,7 +413,7 @@ async fn ccPrintFileName(loop: *event.Loop, o_file: []const u8, want_dirname: bo
412 loop.allocator.free(exec_result.stderr);413 loop.allocator.free(exec_result.stderr);
413 }414 }
414 switch (exec_result.term) {415 switch (exec_result.term) {
415 std.os.ChildProcess.Term.Exited => |code| {416 .Exited => |code| {
416 if (code != 0) return error.CCompilerExitCode;417 if (code != 0) return error.CCompilerExitCode;
417 },418 },
418 else => {419 else => {
...@@ -421,7 +422,7 @@ async fn ccPrintFileName(loop: *event.Loop, o_file: []const u8, want_dirname: bo...@@ -421,7 +422,7 @@ async fn ccPrintFileName(loop: *event.Loop, o_file: []const u8, want_dirname: bo
421 }422 }
422 var it = std.mem.tokenize(exec_result.stdout, "\n\r");423 var it = std.mem.tokenize(exec_result.stdout, "\n\r");
423 const line = it.next() orelse return error.LibCRuntimeNotFound;424 const line = it.next() orelse return error.LibCRuntimeNotFound;
424 const dirname = std.os.path.dirname(line) orelse return error.LibCRuntimeNotFound;425 const dirname = fs.path.dirname(line) orelse return error.LibCRuntimeNotFound;
425426
426 if (want_dirname) {427 if (want_dirname) {
427 return std.mem.dupe(loop.allocator, u8, dirname);428 return std.mem.dupe(loop.allocator, u8, dirname);
...@@ -459,10 +460,10 @@ fn fillSearch(search_buf: *[2]Search, sdk: *c.ZigWindowsSDK) []Search {...@@ -459,10 +460,10 @@ fn fillSearch(search_buf: *[2]Search, sdk: *c.ZigWindowsSDK) []Search {
459}460}
460461
461fn fileExists(path: []const u8) !bool {462fn fileExists(path: []const u8) !bool {
462 if (std.os.File.access(path)) |_| {463 if (fs.File.access(path)) |_| {
463 return true;464 return true;
464 } else |err| switch (err) {465 } else |err| switch (err) {
465 error.FileNotFound, error.PermissionDenied => return false,466 error.FileNotFound => return false,
466 else => return error.FileSystem,467 else => return error.FileSystem,
467 }468 }
468}469}
src-self-hosted/link.zig+3-3
...@@ -302,7 +302,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {...@@ -302,7 +302,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
302 try ctx.args.append(c"--allow-shlib-undefined");302 try ctx.args.append(c"--allow-shlib-undefined");
303 }303 }
304304
305 if (ctx.comp.target.getOs() == builtin.Os.zen) {305 if (ctx.comp.target.getOs() == .zen) {
306 try ctx.args.append(c"-e");306 try ctx.args.append(c"-e");
307 try ctx.args.append(c"_start");307 try ctx.args.append(c"_start");
308308
...@@ -311,7 +311,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {...@@ -311,7 +311,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
311}311}
312312
313fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void {313fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void {
314 const full_path = try std.os.path.join(&ctx.arena.allocator, [][]const u8{ dirname, basename });314 const full_path = try std.fs.path.join(&ctx.arena.allocator, [][]const u8{ dirname, basename });
315 const full_path_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, full_path);315 const full_path_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, full_path);
316 try ctx.args.append(full_path_with_null.ptr);316 try ctx.args.append(full_path_with_null.ptr);
317}317}
...@@ -668,7 +668,7 @@ const DarwinPlatform = struct {...@@ -668,7 +668,7 @@ const DarwinPlatform = struct {
668 break :blk ver;668 break :blk ver;
669 },669 },
670 Compilation.DarwinVersionMin.None => blk: {670 Compilation.DarwinVersionMin.None => blk: {
671 assert(comp.target.getOs() == builtin.Os.macosx);671 assert(comp.target.getOs() == .macosx);
672 result.kind = Kind.MacOS;672 result.kind = Kind.MacOS;
673 break :blk "10.10";673 break :blk "10.10";
674 },674 },
src-self-hosted/main.zig+51-48
...@@ -4,7 +4,9 @@ const builtin = @import("builtin");...@@ -4,7 +4,9 @@ const builtin = @import("builtin");
4const event = std.event;4const event = std.event;
5const os = std.os;5const os = std.os;
6const io = std.io;6const io = std.io;
7const fs = std.fs;
7const mem = std.mem;8const mem = std.mem;
9const process = std.process;
8const Allocator = mem.Allocator;10const Allocator = mem.Allocator;
9const ArrayList = std.ArrayList;11const ArrayList = std.ArrayList;
10const Buffer = std.Buffer;12const Buffer = std.Buffer;
...@@ -20,9 +22,9 @@ const Target = @import("target.zig").Target;...@@ -20,9 +22,9 @@ const Target = @import("target.zig").Target;
20const errmsg = @import("errmsg.zig");22const errmsg = @import("errmsg.zig");
21const LibCInstallation = @import("libc_installation.zig").LibCInstallation;23const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
2224
23var stderr_file: os.File = undefined;25var stderr_file: fs.File = undefined;
24var stderr: *io.OutStream(os.File.WriteError) = undefined;26var stderr: *io.OutStream(fs.File.WriteError) = undefined;
25var stdout: *io.OutStream(os.File.WriteError) = undefined;27var stdout: *io.OutStream(fs.File.WriteError) = undefined;
2628
27pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB29pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB
2830
...@@ -62,14 +64,14 @@ pub fn main() !void {...@@ -62,14 +64,14 @@ pub fn main() !void {
62 var stderr_out_stream = stderr_file.outStream();64 var stderr_out_stream = stderr_file.outStream();
63 stderr = &stderr_out_stream.stream;65 stderr = &stderr_out_stream.stream;
6466
65 const args = try os.argsAlloc(allocator);67 const args = try process.argsAlloc(allocator);
66 // TODO I'm getting unreachable code here, which shouldn't happen68 // TODO I'm getting unreachable code here, which shouldn't happen
67 //defer os.argsFree(allocator, args);69 //defer process.argsFree(allocator, args);
6870
69 if (args.len <= 1) {71 if (args.len <= 1) {
70 try stderr.write("expected command argument\n\n");72 try stderr.write("expected command argument\n\n");
71 try stderr.write(usage);73 try stderr.write(usage);
72 os.exit(1);74 process.exit(1);
73 }75 }
7476
75 const commands = []Command{77 const commands = []Command{
...@@ -125,7 +127,7 @@ pub fn main() !void {...@@ -125,7 +127,7 @@ pub fn main() !void {
125127
126 try stderr.print("unknown command: {}\n\n", args[1]);128 try stderr.print("unknown command: {}\n\n", args[1]);
127 try stderr.write(usage);129 try stderr.write(usage);
128 os.exit(1);130 process.exit(1);
129}131}
130132
131const usage_build_generic =133const usage_build_generic =
...@@ -256,7 +258,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -256,7 +258,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
256258
257 if (flags.present("help")) {259 if (flags.present("help")) {
258 try stdout.write(usage_build_generic);260 try stdout.write(usage_build_generic);
259 os.exit(0);261 process.exit(0);
260 }262 }
261263
262 const build_mode = blk: {264 const build_mode = blk: {
...@@ -324,14 +326,14 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -324,14 +326,14 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
324 cur_pkg = parent;326 cur_pkg = parent;
325 } else {327 } else {
326 try stderr.print("encountered --pkg-end with no matching --pkg-begin\n");328 try stderr.print("encountered --pkg-end with no matching --pkg-begin\n");
327 os.exit(1);329 process.exit(1);
328 }330 }
329 }331 }
330 }332 }
331333
332 if (cur_pkg.parent != null) {334 if (cur_pkg.parent != null) {
333 try stderr.print("unmatched --pkg-begin\n");335 try stderr.print("unmatched --pkg-begin\n");
334 os.exit(1);336 process.exit(1);
335 }337 }
336338
337 const provided_name = flags.single("name");339 const provided_name = flags.single("name");
...@@ -340,18 +342,18 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -340,18 +342,18 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
340 1 => flags.positionals.at(0),342 1 => flags.positionals.at(0),
341 else => {343 else => {
342 try stderr.print("unexpected extra parameter: {}\n", flags.positionals.at(1));344 try stderr.print("unexpected extra parameter: {}\n", flags.positionals.at(1));
343 os.exit(1);345 process.exit(1);
344 },346 },
345 };347 };
346348
347 const root_name = if (provided_name) |n| n else blk: {349 const root_name = if (provided_name) |n| n else blk: {
348 if (root_source_file) |file| {350 if (root_source_file) |file| {
349 const basename = os.path.basename(file);351 const basename = fs.path.basename(file);
350 var it = mem.separate(basename, ".");352 var it = mem.separate(basename, ".");
351 break :blk it.next() orelse basename;353 break :blk it.next() orelse basename;
352 } else {354 } else {
353 try stderr.write("--name [name] not provided and unable to infer\n");355 try stderr.write("--name [name] not provided and unable to infer\n");
354 os.exit(1);356 process.exit(1);
355 }357 }
356 };358 };
357359
...@@ -361,12 +363,12 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -361,12 +363,12 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
361 const link_objects = flags.many("object");363 const link_objects = flags.many("object");
362 if (root_source_file == null and link_objects.len == 0 and assembly_files.len == 0) {364 if (root_source_file == null and link_objects.len == 0 and assembly_files.len == 0) {
363 try stderr.write("Expected source file argument or at least one --object or --assembly argument\n");365 try stderr.write("Expected source file argument or at least one --object or --assembly argument\n");
364 os.exit(1);366 process.exit(1);
365 }367 }
366368
367 if (out_type == Compilation.Kind.Obj and link_objects.len != 0) {369 if (out_type == Compilation.Kind.Obj and link_objects.len != 0) {
368 try stderr.write("When building an object file, --object arguments are invalid\n");370 try stderr.write("When building an object file, --object arguments are invalid\n");
369 os.exit(1);371 process.exit(1);
370 }372 }
371373
372 var clang_argv_buf = ArrayList([]const u8).init(allocator);374 var clang_argv_buf = ArrayList([]const u8).init(allocator);
...@@ -379,7 +381,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -379,7 +381,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
379 }381 }
380 try ZigCompiler.setLlvmArgv(allocator, mllvm_flags);382 try ZigCompiler.setLlvmArgv(allocator, mllvm_flags);
381383
382 const zig_lib_dir = introspect.resolveZigLibDir(allocator) catch os.exit(1);384 const zig_lib_dir = introspect.resolveZigLibDir(allocator) catch process.exit(1);
383 defer allocator.free(zig_lib_dir);385 defer allocator.free(zig_lib_dir);
384386
385 var override_libc: LibCInstallation = undefined;387 var override_libc: LibCInstallation = undefined;
...@@ -448,7 +450,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -448,7 +450,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
448450
449 if (flags.single("mmacosx-version-min") != null and flags.single("mios-version-min") != null) {451 if (flags.single("mmacosx-version-min") != null and flags.single("mios-version-min") != null) {
450 try stderr.write("-mmacosx-version-min and -mios-version-min options not allowed together\n");452 try stderr.write("-mmacosx-version-min and -mios-version-min options not allowed together\n");
451 os.exit(1);453 process.exit(1);
452 }454 }
453455
454 if (flags.single("mmacosx-version-min")) |ver| {456 if (flags.single("mmacosx-version-min")) |ver| {
...@@ -478,16 +480,16 @@ async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {...@@ -478,16 +480,16 @@ async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {
478480
479 switch (build_event) {481 switch (build_event) {
480 Compilation.Event.Ok => {482 Compilation.Event.Ok => {
481 stderr.print("Build {} succeeded\n", count) catch os.exit(1);483 stderr.print("Build {} succeeded\n", count) catch process.exit(1);
482 },484 },
483 Compilation.Event.Error => |err| {485 Compilation.Event.Error => |err| {
484 stderr.print("Build {} failed: {}\n", count, @errorName(err)) catch os.exit(1);486 stderr.print("Build {} failed: {}\n", count, @errorName(err)) catch process.exit(1);
485 },487 },
486 Compilation.Event.Fail => |msgs| {488 Compilation.Event.Fail => |msgs| {
487 stderr.print("Build {} compile errors:\n", count) catch os.exit(1);489 stderr.print("Build {} compile errors:\n", count) catch process.exit(1);
488 for (msgs) |msg| {490 for (msgs) |msg| {
489 defer msg.destroy();491 defer msg.destroy();
490 msg.printToFile(stderr_file, color) catch os.exit(1);492 msg.printToFile(stderr_file, color) catch process.exit(1);
491 }493 }
492 },494 },
493 }495 }
...@@ -550,8 +552,8 @@ fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_fil...@@ -550,8 +552,8 @@ fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_fil
550 "Try running `zig libc` to see an example for the native target.\n",552 "Try running `zig libc` to see an example for the native target.\n",
551 libc_paths_file,553 libc_paths_file,
552 @errorName(err),554 @errorName(err),
553 ) catch os.exit(1);555 ) catch process.exit(1);
554 os.exit(1);556 process.exit(1);
555 };557 };
556}558}
557559
...@@ -565,7 +567,7 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {...@@ -565,7 +567,7 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {
565 },567 },
566 else => {568 else => {
567 try stderr.print("unexpected extra parameter: {}\n", args[1]);569 try stderr.print("unexpected extra parameter: {}\n", args[1]);
568 os.exit(1);570 process.exit(1);
569 },571 },
570 }572 }
571573
...@@ -584,10 +586,10 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {...@@ -584,10 +586,10 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {
584586
585async fn findLibCAsync(zig_compiler: *ZigCompiler) void {587async fn findLibCAsync(zig_compiler: *ZigCompiler) void {
586 const libc = (await (async zig_compiler.getNativeLibC() catch unreachable)) catch |err| {588 const libc = (await (async zig_compiler.getNativeLibC() catch unreachable)) catch |err| {
587 stderr.print("unable to find libc: {}\n", @errorName(err)) catch os.exit(1);589 stderr.print("unable to find libc: {}\n", @errorName(err)) catch process.exit(1);
588 os.exit(1);590 process.exit(1);
589 };591 };
590 libc.render(stdout) catch os.exit(1);592 libc.render(stdout) catch process.exit(1);
591}593}
592594
593fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {595fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
...@@ -596,7 +598,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -596,7 +598,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
596598
597 if (flags.present("help")) {599 if (flags.present("help")) {
598 try stdout.write(usage_fmt);600 try stdout.write(usage_fmt);
599 os.exit(0);601 process.exit(0);
600 }602 }
601603
602 const color = blk: {604 const color = blk: {
...@@ -616,7 +618,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -616,7 +618,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
616 if (flags.present("stdin")) {618 if (flags.present("stdin")) {
617 if (flags.positionals.len != 0) {619 if (flags.positionals.len != 0) {
618 try stderr.write("cannot use --stdin with positional arguments\n");620 try stderr.write("cannot use --stdin with positional arguments\n");
619 os.exit(1);621 process.exit(1);
620 }622 }
621623
622 var stdin_file = try io.getStdIn();624 var stdin_file = try io.getStdIn();
...@@ -627,7 +629,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -627,7 +629,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
627629
628 const tree = std.zig.parse(allocator, source_code) catch |err| {630 const tree = std.zig.parse(allocator, source_code) catch |err| {
629 try stderr.print("error parsing stdin: {}\n", err);631 try stderr.print("error parsing stdin: {}\n", err);
630 os.exit(1);632 process.exit(1);
631 };633 };
632 defer tree.deinit();634 defer tree.deinit();
633635
...@@ -639,12 +641,12 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -639,12 +641,12 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
639 try msg.printToFile(stderr_file, color);641 try msg.printToFile(stderr_file, color);
640 }642 }
641 if (tree.errors.len != 0) {643 if (tree.errors.len != 0) {
642 os.exit(1);644 process.exit(1);
643 }645 }
644 if (flags.present("check")) {646 if (flags.present("check")) {
645 const anything_changed = try std.zig.render(allocator, io.null_out_stream, tree);647 const anything_changed = try std.zig.render(allocator, io.null_out_stream, tree);
646 const code = if (anything_changed) u8(1) else u8(0);648 const code = if (anything_changed) u8(1) else u8(0);
647 os.exit(code);649 process.exit(code);
648 }650 }
649651
650 _ = try std.zig.render(allocator, stdout, tree);652 _ = try std.zig.render(allocator, stdout, tree);
...@@ -653,7 +655,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -653,7 +655,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
653655
654 if (flags.positionals.len == 0) {656 if (flags.positionals.len == 0) {
655 try stderr.write("expected at least one source file argument\n");657 try stderr.write("expected at least one source file argument\n");
656 os.exit(1);658 process.exit(1);
657 }659 }
658660
659 var loop: event.Loop = undefined;661 var loop: event.Loop = undefined;
...@@ -700,7 +702,8 @@ const FmtError = error{...@@ -700,7 +702,8 @@ const FmtError = error{
700 ReadOnlyFileSystem,702 ReadOnlyFileSystem,
701 LinkQuotaExceeded,703 LinkQuotaExceeded,
702 FileBusy,704 FileBusy,
703} || os.File.OpenError;705 CurrentWorkingDirectoryUnlinked,
706} || fs.File.OpenError;
704707
705async fn asyncFmtMain(708async fn asyncFmtMain(
706 loop: *event.Loop,709 loop: *event.Loop,
...@@ -725,7 +728,7 @@ async fn asyncFmtMain(...@@ -725,7 +728,7 @@ async fn asyncFmtMain(
725 }728 }
726 try await (async group.wait() catch unreachable);729 try await (async group.wait() catch unreachable);
727 if (fmt.any_error) {730 if (fmt.any_error) {
728 os.exit(1);731 process.exit(1);
729 }732 }
730}733}
731734
...@@ -747,13 +750,13 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro...@@ -747,13 +750,13 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro
747 )) catch |err| switch (err) {750 )) catch |err| switch (err) {
748 error.IsDir, error.AccessDenied => {751 error.IsDir, error.AccessDenied => {
749 // TODO make event based (and dir.next())752 // TODO make event based (and dir.next())
750 var dir = try std.os.Dir.open(fmt.loop.allocator, file_path);753 var dir = try fs.Dir.open(fmt.loop.allocator, file_path);
751 defer dir.close();754 defer dir.close();
752755
753 var group = event.Group(FmtError!void).init(fmt.loop);756 var group = event.Group(FmtError!void).init(fmt.loop);
754 while (try dir.next()) |entry| {757 while (try dir.next()) |entry| {
755 if (entry.kind == std.os.Dir.Entry.Kind.Directory or mem.endsWith(u8, entry.name, ".zig")) {758 if (entry.kind == fs.Dir.Entry.Kind.Directory or mem.endsWith(u8, entry.name, ".zig")) {
756 const full_path = try os.path.join(fmt.loop.allocator, [][]const u8{ file_path, entry.name });759 const full_path = try fs.path.join(fmt.loop.allocator, [][]const u8{ file_path, entry.name });
757 try group.call(fmtPath, fmt, full_path, check_mode);760 try group.call(fmtPath, fmt, full_path, check_mode);
758 }761 }
759 }762 }
...@@ -849,7 +852,7 @@ fn cmdTargets(allocator: *Allocator, args: []const []const u8) !void {...@@ -849,7 +852,7 @@ fn cmdTargets(allocator: *Allocator, args: []const []const u8) !void {
849}852}
850853
851fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void {854fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void {
852 try stdout.print("{}\n", std.cstr.toSliceConst(c.ZIG_VERSION_STRING));855 try stdout.print("{}\n", std.mem.toSliceConst(u8, c.ZIG_VERSION_STRING));
853}856}
854857
855const args_test_spec = []Flag{Flag.Bool("--help")};858const args_test_spec = []Flag{Flag.Bool("--help")};
...@@ -891,7 +894,7 @@ const usage_internal =...@@ -891,7 +894,7 @@ const usage_internal =
891fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void {894fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void {
892 if (args.len == 0) {895 if (args.len == 0) {
893 try stderr.write(usage_internal);896 try stderr.write(usage_internal);
894 os.exit(1);897 process.exit(1);
895 }898 }
896899
897 const sub_commands = []Command{Command{900 const sub_commands = []Command{Command{
...@@ -922,14 +925,14 @@ fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void {...@@ -922,14 +925,14 @@ fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void {
922 \\ZIG_DIA_GUIDS_LIB {}925 \\ZIG_DIA_GUIDS_LIB {}
923 \\926 \\
924 ,927 ,
925 std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR),928 std.mem.toSliceConst(u8, c.ZIG_CMAKE_BINARY_DIR),
926 std.cstr.toSliceConst(c.ZIG_CXX_COMPILER),929 std.mem.toSliceConst(u8, c.ZIG_CXX_COMPILER),
927 std.cstr.toSliceConst(c.ZIG_LLVM_CONFIG_EXE),930 std.mem.toSliceConst(u8, c.ZIG_LLVM_CONFIG_EXE),
928 std.cstr.toSliceConst(c.ZIG_LLD_INCLUDE_PATH),931 std.mem.toSliceConst(u8, c.ZIG_LLD_INCLUDE_PATH),
929 std.cstr.toSliceConst(c.ZIG_LLD_LIBRARIES),932 std.mem.toSliceConst(u8, c.ZIG_LLD_LIBRARIES),
930 std.cstr.toSliceConst(c.ZIG_STD_FILES),933 std.mem.toSliceConst(u8, c.ZIG_STD_FILES),
931 std.cstr.toSliceConst(c.ZIG_C_HEADER_FILES),934 std.mem.toSliceConst(u8, c.ZIG_C_HEADER_FILES),
932 std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB),935 std.mem.toSliceConst(u8, c.ZIG_DIA_GUIDS_LIB),
933 );936 );
934}937}
935938
src-self-hosted/stage1.zig+29-30
...@@ -1,8 +1,24 @@...@@ -1,8 +1,24 @@
1// This is Zig code that is used by both stage1 and stage2.1// This is Zig code that is used by both stage1 and stage2.
2// The prototypes in src/userland.h must match these definitions.2// The prototypes in src/userland.h must match these definitions.
33
4const std = @import("std");
5const builtin = @import("builtin");4const builtin = @import("builtin");
5const std = @import("std");
6const io = std.io;
7const mem = std.mem;
8const fs = std.fs;
9const process = std.process;
10const Allocator = mem.Allocator;
11const ArrayList = std.ArrayList;
12const Buffer = std.Buffer;
13const arg = @import("arg.zig");
14const self_hosted_main = @import("main.zig");
15const Args = arg.Args;
16const Flag = arg.Flag;
17const errmsg = @import("errmsg.zig");
18
19var stderr_file: fs.File = undefined;
20var stderr: *io.OutStream(fs.File.WriteError) = undefined;
21var stdout: *io.OutStream(fs.File.WriteError) = undefined;
622
7// ABI warning23// ABI warning
8export fn stage2_zen(ptr: *[*]const u8, len: *usize) void {24export fn stage2_zen(ptr: *[*]const u8, len: *usize) void {
...@@ -157,7 +173,7 @@ fn fmtMain(argc: c_int, argv: [*]const [*]const u8) !void {...@@ -157,7 +173,7 @@ fn fmtMain(argc: c_int, argv: [*]const [*]const u8) !void {
157173
158 if (flags.present("help")) {174 if (flags.present("help")) {
159 try stdout.write(self_hosted_main.usage_fmt);175 try stdout.write(self_hosted_main.usage_fmt);
160 os.exit(0);176 process.exit(0);
161 }177 }
162178
163 const color = blk: {179 const color = blk: {
...@@ -177,7 +193,7 @@ fn fmtMain(argc: c_int, argv: [*]const [*]const u8) !void {...@@ -177,7 +193,7 @@ fn fmtMain(argc: c_int, argv: [*]const [*]const u8) !void {
177 if (flags.present("stdin")) {193 if (flags.present("stdin")) {
178 if (flags.positionals.len != 0) {194 if (flags.positionals.len != 0) {
179 try stderr.write("cannot use --stdin with positional arguments\n");195 try stderr.write("cannot use --stdin with positional arguments\n");
180 os.exit(1);196 process.exit(1);
181 }197 }
182198
183 var stdin_file = try io.getStdIn();199 var stdin_file = try io.getStdIn();
...@@ -188,7 +204,7 @@ fn fmtMain(argc: c_int, argv: [*]const [*]const u8) !void {...@@ -188,7 +204,7 @@ fn fmtMain(argc: c_int, argv: [*]const [*]const u8) !void {
188204
189 const tree = std.zig.parse(allocator, source_code) catch |err| {205 const tree = std.zig.parse(allocator, source_code) catch |err| {
190 try stderr.print("error parsing stdin: {}\n", err);206 try stderr.print("error parsing stdin: {}\n", err);
191 os.exit(1);207 process.exit(1);
192 };208 };
193 defer tree.deinit();209 defer tree.deinit();
194210
...@@ -197,12 +213,12 @@ fn fmtMain(argc: c_int, argv: [*]const [*]const u8) !void {...@@ -197,12 +213,12 @@ fn fmtMain(argc: c_int, argv: [*]const [*]const u8) !void {
197 try printErrMsgToFile(allocator, parse_error, tree, "<stdin>", stderr_file, color);213 try printErrMsgToFile(allocator, parse_error, tree, "<stdin>", stderr_file, color);
198 }214 }
199 if (tree.errors.len != 0) {215 if (tree.errors.len != 0) {
200 os.exit(1);216 process.exit(1);
201 }217 }
202 if (flags.present("check")) {218 if (flags.present("check")) {
203 const anything_changed = try std.zig.render(allocator, io.null_out_stream, tree);219 const anything_changed = try std.zig.render(allocator, io.null_out_stream, tree);
204 const code = if (anything_changed) u8(1) else u8(0);220 const code = if (anything_changed) u8(1) else u8(0);
205 os.exit(code);221 process.exit(code);
206 }222 }
207223
208 _ = try std.zig.render(allocator, stdout, tree);224 _ = try std.zig.render(allocator, stdout, tree);
...@@ -211,7 +227,7 @@ fn fmtMain(argc: c_int, argv: [*]const [*]const u8) !void {...@@ -211,7 +227,7 @@ fn fmtMain(argc: c_int, argv: [*]const [*]const u8) !void {
211227
212 if (flags.positionals.len == 0) {228 if (flags.positionals.len == 0) {
213 try stderr.write("expected at least one source file argument\n");229 try stderr.write("expected at least one source file argument\n");
214 os.exit(1);230 process.exit(1);
215 }231 }
216232
217 var fmt = Fmt{233 var fmt = Fmt{
...@@ -227,7 +243,7 @@ fn fmtMain(argc: c_int, argv: [*]const [*]const u8) !void {...@@ -227,7 +243,7 @@ fn fmtMain(argc: c_int, argv: [*]const [*]const u8) !void {
227 try fmtPath(&fmt, file_path, check_mode);243 try fmtPath(&fmt, file_path, check_mode);
228 }244 }
229 if (fmt.any_error) {245 if (fmt.any_error) {
230 os.exit(1);246 process.exit(1);
231 }247 }
232}248}
233249
...@@ -250,7 +266,7 @@ const FmtError = error{...@@ -250,7 +266,7 @@ const FmtError = error{
250 ReadOnlyFileSystem,266 ReadOnlyFileSystem,
251 LinkQuotaExceeded,267 LinkQuotaExceeded,
252 FileBusy,268 FileBusy,
253} || os.File.OpenError;269} || fs.File.OpenError;
254270
255fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void {271fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void {
256 const file_path = try std.mem.dupe(fmt.allocator, u8, file_path_ref);272 const file_path = try std.mem.dupe(fmt.allocator, u8, file_path_ref);
...@@ -261,12 +277,12 @@ fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void...@@ -261,12 +277,12 @@ fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void
261 const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) {277 const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) {
262 error.IsDir, error.AccessDenied => {278 error.IsDir, error.AccessDenied => {
263 // TODO make event based (and dir.next())279 // TODO make event based (and dir.next())
264 var dir = try std.os.Dir.open(fmt.allocator, file_path);280 var dir = try fs.Dir.open(fmt.allocator, file_path);
265 defer dir.close();281 defer dir.close();
266282
267 while (try dir.next()) |entry| {283 while (try dir.next()) |entry| {
268 if (entry.kind == std.os.Dir.Entry.Kind.Directory or mem.endsWith(u8, entry.name, ".zig")) {284 if (entry.kind == fs.Dir.Entry.Kind.Directory or mem.endsWith(u8, entry.name, ".zig")) {
269 const full_path = try os.path.join(fmt.allocator, [][]const u8{ file_path, entry.name });285 const full_path = try fs.path.join(fmt.allocator, [][]const u8{ file_path, entry.name });
270 try fmtPath(fmt, full_path, check_mode);286 try fmtPath(fmt, full_path, check_mode);
271 }287 }
272 }288 }
...@@ -329,7 +345,7 @@ fn printErrMsgToFile(...@@ -329,7 +345,7 @@ fn printErrMsgToFile(
329 parse_error: *const ast.Error,345 parse_error: *const ast.Error,
330 tree: *ast.Tree,346 tree: *ast.Tree,
331 path: []const u8,347 path: []const u8,
332 file: os.File,348 file: fs.File,
333 color: errmsg.Color,349 color: errmsg.Color,
334) !void {350) !void {
335 const color_on = switch (color) {351 const color_on = switch (color) {
...@@ -377,20 +393,3 @@ fn printErrMsgToFile(...@@ -377,20 +393,3 @@ fn printErrMsgToFile(
377 try stream.writeByteNTimes('~', last_token.end - first_token.start);393 try stream.writeByteNTimes('~', last_token.end - first_token.start);
378 try stream.write("\n");394 try stream.write("\n");
379}395}
380
381const os = std.os;
382const io = std.io;
383const mem = std.mem;
384const Allocator = mem.Allocator;
385const ArrayList = std.ArrayList;
386const Buffer = std.Buffer;
387
388const arg = @import("arg.zig");
389const self_hosted_main = @import("main.zig");
390const Args = arg.Args;
391const Flag = arg.Flag;
392const errmsg = @import("errmsg.zig");
393
394var stderr_file: os.File = undefined;
395var stderr: *io.OutStream(os.File.WriteError) = undefined;
396var stdout: *io.OutStream(os.File.WriteError) = undefined;
src-self-hosted/test.zig+11-11
...@@ -55,12 +55,12 @@ pub const TestContext = struct {...@@ -55,12 +55,12 @@ pub const TestContext = struct {
55 self.zig_lib_dir = try introspect.resolveZigLibDir(allocator);55 self.zig_lib_dir = try introspect.resolveZigLibDir(allocator);
56 errdefer allocator.free(self.zig_lib_dir);56 errdefer allocator.free(self.zig_lib_dir);
5757
58 try std.os.makePath(allocator, tmp_dir_name);58 try std.fs.makePath(allocator, tmp_dir_name);
59 errdefer std.os.deleteTree(allocator, tmp_dir_name) catch {};59 errdefer std.fs.deleteTree(allocator, tmp_dir_name) catch {};
60 }60 }
6161
62 fn deinit(self: *TestContext) void {62 fn deinit(self: *TestContext) void {
63 std.os.deleteTree(allocator, tmp_dir_name) catch {};63 std.fs.deleteTree(allocator, tmp_dir_name) catch {};
64 allocator.free(self.zig_lib_dir);64 allocator.free(self.zig_lib_dir);
65 self.zig_compiler.deinit();65 self.zig_compiler.deinit();
66 self.loop.deinit();66 self.loop.deinit();
...@@ -87,10 +87,10 @@ pub const TestContext = struct {...@@ -87,10 +87,10 @@ pub const TestContext = struct {
87 ) !void {87 ) !void {
88 var file_index_buf: [20]u8 = undefined;88 var file_index_buf: [20]u8 = undefined;
89 const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr());89 const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr());
90 const file1_path = try std.os.path.join(allocator, [][]const u8{ tmp_dir_name, file_index, file1 });90 const file1_path = try std.fs.path.join(allocator, [][]const u8{ tmp_dir_name, file_index, file1 });
9191
92 if (std.os.path.dirname(file1_path)) |dirname| {92 if (std.fs.path.dirname(file1_path)) |dirname| {
93 try std.os.makePath(allocator, dirname);93 try std.fs.makePath(allocator, dirname);
94 }94 }
9595
96 // TODO async I/O96 // TODO async I/O
...@@ -120,11 +120,11 @@ pub const TestContext = struct {...@@ -120,11 +120,11 @@ pub const TestContext = struct {
120 ) !void {120 ) !void {
121 var file_index_buf: [20]u8 = undefined;121 var file_index_buf: [20]u8 = undefined;
122 const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr());122 const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr());
123 const file1_path = try std.os.path.join(allocator, [][]const u8{ tmp_dir_name, file_index, file1 });123 const file1_path = try std.fs.path.join(allocator, [][]const u8{ tmp_dir_name, file_index, file1 });
124124
125 const output_file = try std.fmt.allocPrint(allocator, "{}-out{}", file1_path, Target(Target.Native).exeFileExt());125 const output_file = try std.fmt.allocPrint(allocator, "{}-out{}", file1_path, Target(Target.Native).exeFileExt());
126 if (std.os.path.dirname(file1_path)) |dirname| {126 if (std.fs.path.dirname(file1_path)) |dirname| {
127 try std.os.makePath(allocator, dirname);127 try std.fs.makePath(allocator, dirname);
128 }128 }
129129
130 // TODO async I/O130 // TODO async I/O
...@@ -164,9 +164,9 @@ pub const TestContext = struct {...@@ -164,9 +164,9 @@ pub const TestContext = struct {
164 Compilation.Event.Ok => {164 Compilation.Event.Ok => {
165 const argv = []const []const u8{exe_file_2};165 const argv = []const []const u8{exe_file_2};
166 // TODO use event loop166 // TODO use event loop
167 const child = try std.os.ChildProcess.exec(allocator, argv, null, null, 1024 * 1024);167 const child = try std.ChildProcess.exec(allocator, argv, null, null, 1024 * 1024);
168 switch (child.term) {168 switch (child.term) {
169 std.os.ChildProcess.Term.Exited => |code| {169 .Exited => |code| {
170 if (code != 0) {170 if (code != 0) {
171 return error.BadReturnCode;171 return error.BadReturnCode;
172 }172 }
src-self-hosted/translate_c.zig+14-14
...@@ -152,10 +152,21 @@ pub fn translate(...@@ -152,10 +152,21 @@ pub fn translate(
152152
153 var tree_arena = std.heap.ArenaAllocator.init(backing_allocator);153 var tree_arena = std.heap.ArenaAllocator.init(backing_allocator);
154 errdefer tree_arena.deinit();154 errdefer tree_arena.deinit();
155 var arena = &tree_arena.allocator;
156155
157 const root_node = try arena.create(ast.Node.Root);156 const tree = try tree_arena.allocator.create(ast.Tree);
158 root_node.* = ast.Node.Root{157 tree.* = ast.Tree{
158 .source = undefined, // need to use Buffer.toOwnedSlice later
159 .root_node = undefined,
160 .arena_allocator = tree_arena,
161 .tokens = undefined, // can't reference the allocator yet
162 .errors = undefined, // can't reference the allocator yet
163 };
164 const arena = &tree.arena_allocator.allocator; // now we can reference the allocator
165 tree.tokens = ast.Tree.TokenList.init(arena);
166 tree.errors = ast.Tree.ErrorList.init(arena);
167
168 tree.root_node = try arena.create(ast.Node.Root);
169 tree.root_node.* = ast.Node.Root{
159 .base = ast.Node{ .id = ast.Node.Id.Root },170 .base = ast.Node{ .id = ast.Node.Id.Root },
160 .decls = ast.Node.Root.DeclList.init(arena),171 .decls = ast.Node.Root.DeclList.init(arena),
161 .doc_comments = null,172 .doc_comments = null,
...@@ -163,17 +174,6 @@ pub fn translate(...@@ -163,17 +174,6 @@ pub fn translate(
163 .eof_token = undefined,174 .eof_token = undefined,
164 };175 };
165176
166 const tree = try arena.create(ast.Tree);
167 tree.* = ast.Tree{
168 .source = undefined, // need to use Buffer.toOwnedSlice later
169 .root_node = root_node,
170 .arena_allocator = undefined,
171 .tokens = ast.Tree.TokenList.init(arena),
172 .errors = ast.Tree.ErrorList.init(arena),
173 };
174 tree.arena_allocator = tree_arena;
175 arena = &tree.arena_allocator.allocator;
176
177 var source_buffer = try std.Buffer.initSize(arena, 0);177 var source_buffer = try std.Buffer.initSize(arena, 0);
178178
179 var context = Context{179 var context = Context{
src/all_types.hpp+9
...@@ -1471,6 +1471,7 @@ enum BuiltinFnId {...@@ -1471,6 +1471,7 @@ enum BuiltinFnId {
1471 BuiltinFnIdErrorReturnTrace,1471 BuiltinFnIdErrorReturnTrace,
1472 BuiltinFnIdAtomicRmw,1472 BuiltinFnIdAtomicRmw,
1473 BuiltinFnIdAtomicLoad,1473 BuiltinFnIdAtomicLoad,
1474 BuiltinFnIdHasDecl,
1474};1475};
14751476
1476struct BuiltinFnEntry {1477struct BuiltinFnEntry {
...@@ -2297,6 +2298,7 @@ enum IrInstructionId {...@@ -2297,6 +2298,7 @@ enum IrInstructionId {
2297 IrInstructionIdArrayToVector,2298 IrInstructionIdArrayToVector,
2298 IrInstructionIdAssertZero,2299 IrInstructionIdAssertZero,
2299 IrInstructionIdAssertNonNull,2300 IrInstructionIdAssertNonNull,
2301 IrInstructionIdHasDecl,
2300};2302};
23012303
2302struct IrInstruction {2304struct IrInstruction {
...@@ -3503,6 +3505,13 @@ struct IrInstructionAssertNonNull {...@@ -3503,6 +3505,13 @@ struct IrInstructionAssertNonNull {
3503 IrInstruction *target;3505 IrInstruction *target;
3504};3506};
35053507
3508struct IrInstructionHasDecl {
3509 IrInstruction base;
3510
3511 IrInstruction *container;
3512 IrInstruction *name;
3513};
3514
3506static const size_t slice_ptr_index = 0;3515static const size_t slice_ptr_index = 0;
3507static const size_t slice_len_index = 1;3516static const size_t slice_len_index = 1;
35083517
src/codegen.cpp+2
...@@ -5616,6 +5616,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5616,6 +5616,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5616 case IrInstructionIdLoadPtr:5616 case IrInstructionIdLoadPtr:
5617 case IrInstructionIdBitCast:5617 case IrInstructionIdBitCast:
5618 case IrInstructionIdGlobalAsm:5618 case IrInstructionIdGlobalAsm:
5619 case IrInstructionIdHasDecl:
5619 zig_unreachable();5620 zig_unreachable();
56205621
5621 case IrInstructionIdDeclVarGen:5622 case IrInstructionIdDeclVarGen:
...@@ -7409,6 +7410,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -7409,6 +7410,7 @@ static void define_builtin_fns(CodeGen *g) {
7409 create_builtin_fn(g, BuiltinFnIdToBytes, "sliceToBytes", 1);7410 create_builtin_fn(g, BuiltinFnIdToBytes, "sliceToBytes", 1);
7410 create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2);7411 create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2);
7411 create_builtin_fn(g, BuiltinFnIdThis, "This", 0);7412 create_builtin_fn(g, BuiltinFnIdThis, "This", 0);
7413 create_builtin_fn(g, BuiltinFnIdHasDecl, "hasDecl", 2);
7412}7414}
74137415
7414static const char *bool_to_str(bool b) {7416static const char *bool_to_str(bool b) {
src/ir.cpp+77-10
...@@ -1011,6 +1011,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAssertNonNull *)...@@ -1011,6 +1011,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAssertNonNull *)
1011 return IrInstructionIdAssertNonNull;1011 return IrInstructionIdAssertNonNull;
1012}1012}
10131013
1014static constexpr IrInstructionId ir_instruction_id(IrInstructionHasDecl *) {
1015 return IrInstructionIdHasDecl;
1016}
1017
1014template<typename T>1018template<typename T>
1015static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {1019static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
1016 T *special_instruction = allocate<T>(1);1020 T *special_instruction = allocate<T>(1);
...@@ -3014,6 +3018,19 @@ static IrInstruction *ir_build_sqrt(IrBuilder *irb, Scope *scope, AstNode *sourc...@@ -3014,6 +3018,19 @@ static IrInstruction *ir_build_sqrt(IrBuilder *irb, Scope *scope, AstNode *sourc
3014 return &instruction->base;3018 return &instruction->base;
3015}3019}
30163020
3021static IrInstruction *ir_build_has_decl(IrBuilder *irb, Scope *scope, AstNode *source_node,
3022 IrInstruction *container, IrInstruction *name)
3023{
3024 IrInstructionHasDecl *instruction = ir_build_instruction<IrInstructionHasDecl>(irb, scope, source_node);
3025 instruction->container = container;
3026 instruction->name = name;
3027
3028 ir_ref_instruction(container, irb->current_basic_block);
3029 ir_ref_instruction(name, irb->current_basic_block);
3030
3031 return &instruction->base;
3032}
3033
3017static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *scope_is_comptime, IrInstruction *is_comptime) {3034static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *scope_is_comptime, IrInstruction *is_comptime) {
3018 IrInstructionCheckRuntimeScope *instruction = ir_build_instruction<IrInstructionCheckRuntimeScope>(irb, scope, source_node);3035 IrInstructionCheckRuntimeScope *instruction = ir_build_instruction<IrInstructionCheckRuntimeScope>(irb, scope, source_node);
3019 instruction->scope_is_comptime = scope_is_comptime;3036 instruction->scope_is_comptime = scope_is_comptime;
...@@ -5098,6 +5115,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -5098,6 +5115,21 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
5098 }5115 }
5099 return ir_lval_wrap(irb, scope, result, lval);5116 return ir_lval_wrap(irb, scope, result, lval);
5100 }5117 }
5118 case BuiltinFnIdHasDecl:
5119 {
5120 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
5121 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
5122 if (arg0_value == irb->codegen->invalid_instruction)
5123 return arg0_value;
5124
5125 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
5126 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
5127 if (arg1_value == irb->codegen->invalid_instruction)
5128 return arg1_value;
5129
5130 IrInstruction *has_decl = ir_build_has_decl(irb, scope, node, arg0_value, arg1_value);
5131 return ir_lval_wrap(irb, scope, has_decl, lval);
5132 }
5101 }5133 }
5102 zig_unreachable();5134 zig_unreachable();
5103}5135}
...@@ -11489,6 +11521,19 @@ static IrInstruction *ir_analyze_int_to_c_ptr(IrAnalyze *ira, IrInstruction *sou...@@ -11489,6 +11521,19 @@ static IrInstruction *ir_analyze_int_to_c_ptr(IrAnalyze *ira, IrInstruction *sou
11489 return ir_analyze_int_to_ptr(ira, source_instr, unsigned_integer, dest_type);11521 return ir_analyze_int_to_ptr(ira, source_instr, unsigned_integer, dest_type);
11490}11522}
1149111523
11524static bool is_pointery_and_elem_is_not_pointery(ZigType *ty) {
11525 if (ty->id == ZigTypeIdPointer) return ty->data.pointer.child_type->id != ZigTypeIdPointer;
11526 if (ty->id == ZigTypeIdFn) return true;
11527 if (ty->id == ZigTypeIdPromise) return true;
11528 if (ty->id == ZigTypeIdOptional) {
11529 ZigType *ptr_ty = ty->data.maybe.child_type;
11530 if (ptr_ty->id == ZigTypeIdPointer) return ptr_ty->data.pointer.child_type->id != ZigTypeIdPointer;
11531 if (ptr_ty->id == ZigTypeIdFn) return true;
11532 if (ptr_ty->id == ZigTypeIdPromise) return true;
11533 }
11534 return false;
11535}
11536
11492static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,11537static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
11493 ZigType *wanted_type, IrInstruction *value)11538 ZigType *wanted_type, IrInstruction *value)
11494{11539{
...@@ -11863,27 +11908,19 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -11863,27 +11908,19 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1186311908
11864 // cast from *T and [*]T to *c_void and ?*c_void11909 // cast from *T and [*]T to *c_void and ?*c_void
11865 // but don't do it if the actual type is a double pointer11910 // but don't do it if the actual type is a double pointer
11866 if (actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.child_type->id != ZigTypeIdPointer) {11911 if (is_pointery_and_elem_is_not_pointery(actual_type)) {
11867 ZigType *dest_ptr_type = nullptr;11912 ZigType *dest_ptr_type = nullptr;
11868 if (wanted_type->id == ZigTypeIdPointer &&11913 if (wanted_type->id == ZigTypeIdPointer &&
11869 wanted_type->data.pointer.ptr_len == PtrLenSingle &&
11870 wanted_type->data.pointer.child_type == ira->codegen->builtin_types.entry_c_void)11914 wanted_type->data.pointer.child_type == ira->codegen->builtin_types.entry_c_void)
11871 {11915 {
11872 dest_ptr_type = wanted_type;11916 dest_ptr_type = wanted_type;
11873 } else if (wanted_type->id == ZigTypeIdOptional &&11917 } else if (wanted_type->id == ZigTypeIdOptional &&
11874 wanted_type->data.maybe.child_type->id == ZigTypeIdPointer &&11918 wanted_type->data.maybe.child_type->id == ZigTypeIdPointer &&
11875 wanted_type->data.maybe.child_type->data.pointer.ptr_len == PtrLenSingle &&
11876 wanted_type->data.maybe.child_type->data.pointer.child_type == ira->codegen->builtin_types.entry_c_void)11919 wanted_type->data.maybe.child_type->data.pointer.child_type == ira->codegen->builtin_types.entry_c_void)
11877 {11920 {
11878 dest_ptr_type = wanted_type->data.maybe.child_type;11921 dest_ptr_type = wanted_type->data.maybe.child_type;
11879 }11922 }
11880 if (dest_ptr_type != nullptr &&11923 if (dest_ptr_type != nullptr) {
11881 (!actual_type->data.pointer.is_const || dest_ptr_type->data.pointer.is_const) &&
11882 (!actual_type->data.pointer.is_volatile || dest_ptr_type->data.pointer.is_volatile) &&
11883 actual_type->data.pointer.bit_offset_in_host == dest_ptr_type->data.pointer.bit_offset_in_host &&
11884 actual_type->data.pointer.host_int_bytes == dest_ptr_type->data.pointer.host_int_bytes &&
11885 get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, dest_ptr_type))
11886 {
11887 return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr, true);11924 return ir_analyze_ptr_cast(ira, source_instr, value, wanted_type, source_instr, true);
11888 }11925 }
11889 }11926 }
...@@ -23173,6 +23210,33 @@ static IrInstruction *ir_analyze_instruction_check_runtime_scope(IrAnalyze *ira,...@@ -23173,6 +23210,33 @@ static IrInstruction *ir_analyze_instruction_check_runtime_scope(IrAnalyze *ira,
23173 return ir_const_void(ira, &instruction->base);23210 return ir_const_void(ira, &instruction->base);
23174}23211}
2317523212
23213static IrInstruction *ir_analyze_instruction_has_decl(IrAnalyze *ira, IrInstructionHasDecl *instruction) {
23214 ZigType *container_type = ir_resolve_type(ira, instruction->container->child);
23215 if (type_is_invalid(container_type))
23216 return ira->codegen->invalid_instruction;
23217
23218 Buf *name = ir_resolve_str(ira, instruction->name->child);
23219 if (name == nullptr)
23220 return ira->codegen->invalid_instruction;
23221
23222 if (!is_container(container_type)) {
23223 ir_add_error(ira, instruction->container,
23224 buf_sprintf("expected struct, enum, or union; found '%s'", buf_ptr(&container_type->name)));
23225 return ira->codegen->invalid_instruction;
23226 }
23227
23228 ScopeDecls *container_scope = get_container_scope(container_type);
23229 Tld *tld = find_container_decl(ira->codegen, container_scope, name);
23230 if (tld == nullptr)
23231 return ir_const_bool(ira, &instruction->base, false);
23232
23233 if (tld->visib_mod == VisibModPrivate && tld->import != get_scope_import(instruction->base.scope)) {
23234 return ir_const_bool(ira, &instruction->base, false);
23235 }
23236
23237 return ir_const_bool(ira, &instruction->base, true);
23238}
23239
23176static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {23240static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
23177 switch (instruction->id) {23241 switch (instruction->id) {
23178 case IrInstructionIdInvalid:23242 case IrInstructionIdInvalid:
...@@ -23467,6 +23531,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio...@@ -23467,6 +23531,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
23467 return ir_analyze_instruction_enum_to_int(ira, (IrInstructionEnumToInt *)instruction);23531 return ir_analyze_instruction_enum_to_int(ira, (IrInstructionEnumToInt *)instruction);
23468 case IrInstructionIdCheckRuntimeScope:23532 case IrInstructionIdCheckRuntimeScope:
23469 return ir_analyze_instruction_check_runtime_scope(ira, (IrInstructionCheckRuntimeScope *)instruction);23533 return ir_analyze_instruction_check_runtime_scope(ira, (IrInstructionCheckRuntimeScope *)instruction);
23534 case IrInstructionIdHasDecl:
23535 return ir_analyze_instruction_has_decl(ira, (IrInstructionHasDecl *)instruction);
23470 }23536 }
23471 zig_unreachable();23537 zig_unreachable();
23472}23538}
...@@ -23703,6 +23769,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -23703,6 +23769,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
23703 case IrInstructionIdEnumToInt:23769 case IrInstructionIdEnumToInt:
23704 case IrInstructionIdVectorToArray:23770 case IrInstructionIdVectorToArray:
23705 case IrInstructionIdArrayToVector:23771 case IrInstructionIdArrayToVector:
23772 case IrInstructionIdHasDecl:
23706 return false;23773 return false;
2370723774
23708 case IrInstructionIdAsm:23775 case IrInstructionIdAsm:
src/ir_print.cpp+11
...@@ -1453,6 +1453,14 @@ static void ir_print_decl_var_gen(IrPrint *irp, IrInstructionDeclVarGen *decl_va...@@ -1453,6 +1453,14 @@ static void ir_print_decl_var_gen(IrPrint *irp, IrInstructionDeclVarGen *decl_va
1453 }1453 }
1454}1454}
14551455
1456static void ir_print_has_decl(IrPrint *irp, IrInstructionHasDecl *instruction) {
1457 fprintf(irp->f, "@hasDecl(");
1458 ir_print_other_instruction(irp, instruction->container);
1459 fprintf(irp->f, ",");
1460 ir_print_other_instruction(irp, instruction->name);
1461 fprintf(irp->f, ")");
1462}
1463
1456static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1464static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1457 ir_print_prefix(irp, instruction);1465 ir_print_prefix(irp, instruction);
1458 switch (instruction->id) {1466 switch (instruction->id) {
...@@ -1920,6 +1928,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1920,6 +1928,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1920 case IrInstructionIdResizeSlice:1928 case IrInstructionIdResizeSlice:
1921 ir_print_resize_slice(irp, (IrInstructionResizeSlice *)instruction);1929 ir_print_resize_slice(irp, (IrInstructionResizeSlice *)instruction);
1922 break;1930 break;
1931 case IrInstructionIdHasDecl:
1932 ir_print_has_decl(irp, (IrInstructionHasDecl *)instruction);
1933 break;
1923 }1934 }
1924 fprintf(irp->f, "\n");1935 fprintf(irp->f, "\n");
1925}1936}
src/link.cpp-8
...@@ -776,14 +776,6 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file) {...@@ -776,14 +776,6 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file) {
776}776}
777777
778static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path, OutType child_out_type) {778static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path, OutType child_out_type) {
779 // The Mach-O LLD code is not well maintained, and trips an assertion
780 // when we link compiler_rt and libc.zig as libraries rather than objects.
781 // Here we workaround this by having compiler_rt and libc.zig be objects.
782 // TODO write our own linker. https://github.com/ziglang/zig/issues/1535
783 if (parent_gen->zig_target->os == OsMacOSX) {
784 child_out_type = OutTypeObj;
785 }
786
787 CodeGen *child_gen = create_child_codegen(parent_gen, full_path, child_out_type,779 CodeGen *child_gen = create_child_codegen(parent_gen, full_path, child_out_type,
788 parent_gen->libc);780 parent_gen->libc);
789 codegen_set_out_name(child_gen, buf_create_from_str(aname));781 codegen_set_out_name(child_gen, buf_create_from_str(aname));
src/os.cpp+1-1
...@@ -1350,7 +1350,7 @@ static void init_rand() {...@@ -1350,7 +1350,7 @@ static void init_rand() {
1350 zig_panic("unable to open /dev/urandom");1350 zig_panic("unable to open /dev/urandom");
1351 }1351 }
1352 char bytes[sizeof(unsigned)];1352 char bytes[sizeof(unsigned)];
1353 size_t amt_read;1353 ssize_t amt_read;
1354 while ((amt_read = read(fd, bytes, sizeof(unsigned))) == -1) {1354 while ((amt_read = read(fd, bytes, sizeof(unsigned))) == -1) {
1355 if (errno == EINTR) continue;1355 if (errno == EINTR) continue;
1356 zig_panic("unable to read /dev/urandom");1356 zig_panic("unable to read /dev/urandom");
src/zig_llvm.cpp+1
...@@ -877,6 +877,7 @@ bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size...@@ -877,6 +877,7 @@ bool ZigLLVMWriteArchive(const char *archive_name, const char **file_names, size
877 case ZigLLVM_Linux:877 case ZigLLVM_Linux:
878 kind = object::Archive::K_GNU;878 kind = object::Archive::K_GNU;
879 break;879 break;
880 case ZigLLVM_MacOSX:
880 case ZigLLVM_Darwin:881 case ZigLLVM_Darwin:
881 case ZigLLVM_IOS:882 case ZigLLVM_IOS:
882 kind = object::Archive::K_DARWIN;883 kind = object::Archive::K_DARWIN;
std/atomic/queue.zig+6-6
...@@ -186,13 +186,13 @@ test "std.atomic.Queue" {...@@ -186,13 +186,13 @@ test "std.atomic.Queue" {
186 }186 }
187 }187 }
188 } else {188 } else {
189 var putters: [put_thread_count]*std.os.Thread = undefined;189 var putters: [put_thread_count]*std.Thread = undefined;
190 for (putters) |*t| {190 for (putters) |*t| {
191 t.* = try std.os.spawnThread(&context, startPuts);191 t.* = try std.Thread.spawn(&context, startPuts);
192 }192 }
193 var getters: [put_thread_count]*std.os.Thread = undefined;193 var getters: [put_thread_count]*std.Thread = undefined;
194 for (getters) |*t| {194 for (getters) |*t| {
195 t.* = try std.os.spawnThread(&context, startGets);195 t.* = try std.Thread.spawn(&context, startGets);
196 }196 }
197197
198 for (putters) |t|198 for (putters) |t|
...@@ -220,7 +220,7 @@ fn startPuts(ctx: *Context) u8 {...@@ -220,7 +220,7 @@ fn startPuts(ctx: *Context) u8 {
220 var put_count: usize = puts_per_thread;220 var put_count: usize = puts_per_thread;
221 var r = std.rand.DefaultPrng.init(0xdeadbeef);221 var r = std.rand.DefaultPrng.init(0xdeadbeef);
222 while (put_count != 0) : (put_count -= 1) {222 while (put_count != 0) : (put_count -= 1) {
223 std.os.time.sleep(1); // let the os scheduler be our fuzz223 std.time.sleep(1); // let the os scheduler be our fuzz
224 const x = @bitCast(i32, r.random.scalar(u32));224 const x = @bitCast(i32, r.random.scalar(u32));
225 const node = ctx.allocator.create(Queue(i32).Node) catch unreachable;225 const node = ctx.allocator.create(Queue(i32).Node) catch unreachable;
226 node.* = Queue(i32).Node{226 node.* = Queue(i32).Node{
...@@ -239,7 +239,7 @@ fn startGets(ctx: *Context) u8 {...@@ -239,7 +239,7 @@ fn startGets(ctx: *Context) u8 {
239 const last = @atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1;239 const last = @atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1;
240240
241 while (ctx.queue.get()) |node| {241 while (ctx.queue.get()) |node| {
242 std.os.time.sleep(1); // let the os scheduler be our fuzz242 std.time.sleep(1); // let the os scheduler be our fuzz
243 _ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);243 _ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);
244 _ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);244 _ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);
245 }245 }
std/atomic/stack.zig+6-6
...@@ -120,13 +120,13 @@ test "std.atomic.stack" {...@@ -120,13 +120,13 @@ test "std.atomic.stack" {
120 }120 }
121 }121 }
122 } else {122 } else {
123 var putters: [put_thread_count]*std.os.Thread = undefined;123 var putters: [put_thread_count]*std.Thread = undefined;
124 for (putters) |*t| {124 for (putters) |*t| {
125 t.* = try std.os.spawnThread(&context, startPuts);125 t.* = try std.Thread.spawn(&context, startPuts);
126 }126 }
127 var getters: [put_thread_count]*std.os.Thread = undefined;127 var getters: [put_thread_count]*std.Thread = undefined;
128 for (getters) |*t| {128 for (getters) |*t| {
129 t.* = try std.os.spawnThread(&context, startGets);129 t.* = try std.Thread.spawn(&context, startGets);
130 }130 }
131131
132 for (putters) |t|132 for (putters) |t|
...@@ -154,7 +154,7 @@ fn startPuts(ctx: *Context) u8 {...@@ -154,7 +154,7 @@ fn startPuts(ctx: *Context) u8 {
154 var put_count: usize = puts_per_thread;154 var put_count: usize = puts_per_thread;
155 var r = std.rand.DefaultPrng.init(0xdeadbeef);155 var r = std.rand.DefaultPrng.init(0xdeadbeef);
156 while (put_count != 0) : (put_count -= 1) {156 while (put_count != 0) : (put_count -= 1) {
157 std.os.time.sleep(1); // let the os scheduler be our fuzz157 std.time.sleep(1); // let the os scheduler be our fuzz
158 const x = @bitCast(i32, r.random.scalar(u32));158 const x = @bitCast(i32, r.random.scalar(u32));
159 const node = ctx.allocator.create(Stack(i32).Node) catch unreachable;159 const node = ctx.allocator.create(Stack(i32).Node) catch unreachable;
160 node.* = Stack(i32).Node{160 node.* = Stack(i32).Node{
...@@ -172,7 +172,7 @@ fn startGets(ctx: *Context) u8 {...@@ -172,7 +172,7 @@ fn startGets(ctx: *Context) u8 {
172 const last = @atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1;172 const last = @atomicLoad(u8, &ctx.puts_done, builtin.AtomicOrder.SeqCst) == 1;
173173
174 while (ctx.stack.pop()) |node| {174 while (ctx.stack.pop()) |node| {
175 std.os.time.sleep(1); // let the os scheduler be our fuzz175 std.time.sleep(1); // let the os scheduler be our fuzz
176 _ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);176 _ = @atomicRmw(isize, &ctx.get_sum, builtin.AtomicRmwOp.Add, node.data, builtin.AtomicOrder.SeqCst);
177 _ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);177 _ = @atomicRmw(usize, &ctx.get_count, builtin.AtomicRmwOp.Add, 1, builtin.AtomicOrder.SeqCst);
178 }178 }
std/buffer.zig+1-3
...@@ -139,15 +139,13 @@ pub const Buffer = struct {...@@ -139,15 +139,13 @@ pub const Buffer = struct {
139};139};
140140
141test "simple Buffer" {141test "simple Buffer" {
142 const cstr = @import("cstr.zig");
143
144 var buf = try Buffer.init(debug.global_allocator, "");142 var buf = try Buffer.init(debug.global_allocator, "");
145 testing.expect(buf.len() == 0);143 testing.expect(buf.len() == 0);
146 try buf.append("hello");144 try buf.append("hello");
147 try buf.append(" ");145 try buf.append(" ");
148 try buf.append("world");146 try buf.append("world");
149 testing.expect(buf.eql("hello world"));147 testing.expect(buf.eql("hello world"));
150 testing.expect(mem.eql(u8, cstr.toSliceConst(buf.toSliceConst().ptr), buf.toSliceConst()));148 testing.expect(mem.eql(u8, mem.toSliceConst(u8, buf.toSliceConst().ptr), buf.toSliceConst()));
151149
152 var buf2 = try Buffer.initFromBuffer(buf);150 var buf2 = try Buffer.initFromBuffer(buf);
153 testing.expect(buf.eql(buf2.toSliceConst()));151 testing.expect(buf.eql(buf2.toSliceConst()));
std/build.zig+86-86
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const std = @import("std.zig");1const std = @import("std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const io = std.io;3const io = std.io;
4const fs = std.fs;
4const mem = std.mem;5const mem = std.mem;
5const debug = std.debug;6const debug = std.debug;
6const assert = debug.assert;7const assert = debug.assert;
...@@ -8,12 +9,11 @@ const warn = std.debug.warn;...@@ -8,12 +9,11 @@ const warn = std.debug.warn;
8const ArrayList = std.ArrayList;9const ArrayList = std.ArrayList;
9const HashMap = std.HashMap;10const HashMap = std.HashMap;
10const Allocator = mem.Allocator;11const Allocator = mem.Allocator;
11const os = std.os;12const process = std.process;
12const StdIo = os.ChildProcess.StdIo;
13const Term = os.ChildProcess.Term;
14const BufSet = std.BufSet;13const BufSet = std.BufSet;
15const BufMap = std.BufMap;14const BufMap = std.BufMap;
16const fmt_lib = std.fmt;15const fmt_lib = std.fmt;
16const File = std.fs.File;
1717
18pub const FmtStep = @import("build/fmt.zig").FmtStep;18pub const FmtStep = @import("build/fmt.zig").FmtStep;
1919
...@@ -95,11 +95,11 @@ pub const Builder = struct {...@@ -95,11 +95,11 @@ pub const Builder = struct {
9595
96 pub fn init(allocator: *Allocator, zig_exe: []const u8, build_root: []const u8, cache_root: []const u8) Builder {96 pub fn init(allocator: *Allocator, zig_exe: []const u8, build_root: []const u8, cache_root: []const u8) Builder {
97 const env_map = allocator.create(BufMap) catch unreachable;97 const env_map = allocator.create(BufMap) catch unreachable;
98 env_map.* = os.getEnvMap(allocator) catch unreachable;98 env_map.* = process.getEnvMap(allocator) catch unreachable;
99 var self = Builder{99 var self = Builder{
100 .zig_exe = zig_exe,100 .zig_exe = zig_exe,
101 .build_root = build_root,101 .build_root = build_root,
102 .cache_root = os.path.relative(allocator, build_root, cache_root) catch unreachable,102 .cache_root = fs.path.relative(allocator, build_root, cache_root) catch unreachable,
103 .verbose = false,103 .verbose = false,
104 .verbose_tokenize = false,104 .verbose_tokenize = false,
105 .verbose_ast = false,105 .verbose_ast = false,
...@@ -153,8 +153,8 @@ pub const Builder = struct {...@@ -153,8 +153,8 @@ pub const Builder = struct {
153153
154 pub fn setInstallPrefix(self: *Builder, maybe_prefix: ?[]const u8) void {154 pub fn setInstallPrefix(self: *Builder, maybe_prefix: ?[]const u8) void {
155 self.prefix = maybe_prefix orelse "/usr/local"; // TODO better default155 self.prefix = maybe_prefix orelse "/usr/local"; // TODO better default
156 self.lib_dir = os.path.join(self.allocator, [][]const u8{ self.prefix, "lib" }) catch unreachable;156 self.lib_dir = fs.path.join(self.allocator, [][]const u8{ self.prefix, "lib" }) catch unreachable;
157 self.exe_dir = os.path.join(self.allocator, [][]const u8{ self.prefix, "bin" }) catch unreachable;157 self.exe_dir = fs.path.join(self.allocator, [][]const u8{ self.prefix, "bin" }) catch unreachable;
158 }158 }
159159
160 pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {160 pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
...@@ -286,7 +286,7 @@ pub const Builder = struct {...@@ -286,7 +286,7 @@ pub const Builder = struct {
286 if (self.verbose) {286 if (self.verbose) {
287 warn("rm {}\n", installed_file);287 warn("rm {}\n", installed_file);
288 }288 }
289 os.deleteFile(installed_file) catch {};289 fs.deleteFile(installed_file) catch {};
290 }290 }
291291
292 // TODO remove empty directories292 // TODO remove empty directories
...@@ -325,7 +325,7 @@ pub const Builder = struct {...@@ -325,7 +325,7 @@ pub const Builder = struct {
325325
326 fn detectNativeSystemPaths(self: *Builder) void {326 fn detectNativeSystemPaths(self: *Builder) void {
327 var is_nixos = false;327 var is_nixos = false;
328 if (os.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {328 if (process.getEnvVarOwned(self.allocator, "NIX_CFLAGS_COMPILE")) |nix_cflags_compile| {
329 is_nixos = true;329 is_nixos = true;
330 var it = mem.tokenize(nix_cflags_compile, " ");330 var it = mem.tokenize(nix_cflags_compile, " ");
331 while (true) {331 while (true) {
...@@ -344,7 +344,7 @@ pub const Builder = struct {...@@ -344,7 +344,7 @@ pub const Builder = struct {
344 } else |err| {344 } else |err| {
345 assert(err == error.EnvironmentVariableNotFound);345 assert(err == error.EnvironmentVariableNotFound);
346 }346 }
347 if (os.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| {347 if (process.getEnvVarOwned(self.allocator, "NIX_LDFLAGS")) |nix_ldflags| {
348 is_nixos = true;348 is_nixos = true;
349 var it = mem.tokenize(nix_ldflags, " ");349 var it = mem.tokenize(nix_ldflags, " ");
350 while (true) {350 while (true) {
...@@ -368,7 +368,7 @@ pub const Builder = struct {...@@ -368,7 +368,7 @@ pub const Builder = struct {
368 }368 }
369 if (is_nixos) return;369 if (is_nixos) return;
370 switch (builtin.os) {370 switch (builtin.os) {
371 builtin.Os.windows => {},371 .windows => {},
372 else => {372 else => {
373 const triple = (CrossTarget{373 const triple = (CrossTarget{
374 .arch = builtin.arch,374 .arch = builtin.arch,
...@@ -601,7 +601,7 @@ pub const Builder = struct {...@@ -601,7 +601,7 @@ pub const Builder = struct {
601 printCmd(cwd, argv);601 printCmd(cwd, argv);
602 }602 }
603603
604 const child = os.ChildProcess.init(argv, self.allocator) catch unreachable;604 const child = std.ChildProcess.init(argv, self.allocator) catch unreachable;
605 defer child.deinit();605 defer child.deinit();
606606
607 child.cwd = cwd;607 child.cwd = cwd;
...@@ -613,7 +613,7 @@ pub const Builder = struct {...@@ -613,7 +613,7 @@ pub const Builder = struct {
613 };613 };
614614
615 switch (term) {615 switch (term) {
616 Term.Exited => |code| {616 .Exited => |code| {
617 if (code != 0) {617 if (code != 0) {
618 warn("The following command exited with error code {}:\n", code);618 warn("The following command exited with error code {}:\n", code);
619 printCmd(cwd, argv);619 printCmd(cwd, argv);
...@@ -630,7 +630,7 @@ pub const Builder = struct {...@@ -630,7 +630,7 @@ pub const Builder = struct {
630 }630 }
631631
632 pub fn makePath(self: *Builder, path: []const u8) !void {632 pub fn makePath(self: *Builder, path: []const u8) !void {
633 os.makePath(self.allocator, self.pathFromRoot(path)) catch |err| {633 fs.makePath(self.allocator, self.pathFromRoot(path)) catch |err| {
634 warn("Unable to create path {}: {}\n", path, @errorName(err));634 warn("Unable to create path {}: {}\n", path, @errorName(err));
635 return err;635 return err;
636 };636 };
...@@ -651,7 +651,7 @@ pub const Builder = struct {...@@ -651,7 +651,7 @@ pub const Builder = struct {
651651
652 ///::dest_rel_path is relative to prefix path or it can be an absolute path652 ///::dest_rel_path is relative to prefix path or it can be an absolute path
653 pub fn addInstallFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep {653 pub fn addInstallFile(self: *Builder, src_path: []const u8, dest_rel_path: []const u8) *InstallFileStep {
654 const full_dest_path = os.path.resolve(654 const full_dest_path = fs.path.resolve(
655 self.allocator,655 self.allocator,
656 [][]const u8{ self.prefix, dest_rel_path },656 [][]const u8{ self.prefix, dest_rel_path },
657 ) catch unreachable;657 ) catch unreachable;
...@@ -668,28 +668,28 @@ pub const Builder = struct {...@@ -668,28 +668,28 @@ pub const Builder = struct {
668 }668 }
669669
670 fn copyFile(self: *Builder, source_path: []const u8, dest_path: []const u8) !void {670 fn copyFile(self: *Builder, source_path: []const u8, dest_path: []const u8) !void {
671 return self.copyFileMode(source_path, dest_path, os.File.default_mode);671 return self.copyFileMode(source_path, dest_path, File.default_mode);
672 }672 }
673673
674 fn copyFileMode(self: *Builder, source_path: []const u8, dest_path: []const u8, mode: os.File.Mode) !void {674 fn copyFileMode(self: *Builder, source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void {
675 if (self.verbose) {675 if (self.verbose) {
676 warn("cp {} {}\n", source_path, dest_path);676 warn("cp {} {}\n", source_path, dest_path);
677 }677 }
678678
679 const dirname = os.path.dirname(dest_path) orelse ".";679 const dirname = fs.path.dirname(dest_path) orelse ".";
680 const abs_source_path = self.pathFromRoot(source_path);680 const abs_source_path = self.pathFromRoot(source_path);
681 os.makePath(self.allocator, dirname) catch |err| {681 fs.makePath(self.allocator, dirname) catch |err| {
682 warn("Unable to create path {}: {}\n", dirname, @errorName(err));682 warn("Unable to create path {}: {}\n", dirname, @errorName(err));
683 return err;683 return err;
684 };684 };
685 os.copyFileMode(abs_source_path, dest_path, mode) catch |err| {685 fs.copyFileMode(abs_source_path, dest_path, mode) catch |err| {
686 warn("Unable to copy {} to {}: {}\n", abs_source_path, dest_path, @errorName(err));686 warn("Unable to copy {} to {}: {}\n", abs_source_path, dest_path, @errorName(err));
687 return err;687 return err;
688 };688 };
689 }689 }
690690
691 fn pathFromRoot(self: *Builder, rel_path: []const u8) []u8 {691 fn pathFromRoot(self: *Builder, rel_path: []const u8) []u8 {
692 return os.path.resolve(self.allocator, [][]const u8{ self.build_root, rel_path }) catch unreachable;692 return fs.path.resolve(self.allocator, [][]const u8{ self.build_root, rel_path }) catch unreachable;
693 }693 }
694694
695 pub fn fmt(self: *Builder, comptime format: []const u8, args: ...) []u8 {695 pub fn fmt(self: *Builder, comptime format: []const u8, args: ...) []u8 {
...@@ -701,11 +701,11 @@ pub const Builder = struct {...@@ -701,11 +701,11 @@ pub const Builder = struct {
701 const exe_extension = (Target{ .Native = {} }).exeFileExt();701 const exe_extension = (Target{ .Native = {} }).exeFileExt();
702 for (self.search_prefixes.toSliceConst()) |search_prefix| {702 for (self.search_prefixes.toSliceConst()) |search_prefix| {
703 for (names) |name| {703 for (names) |name| {
704 if (os.path.isAbsolute(name)) {704 if (fs.path.isAbsolute(name)) {
705 return name;705 return name;
706 }706 }
707 const full_path = try os.path.join(self.allocator, [][]const u8{ search_prefix, "bin", self.fmt("{}{}", name, exe_extension) });707 const full_path = try fs.path.join(self.allocator, [][]const u8{ search_prefix, "bin", self.fmt("{}{}", name, exe_extension) });
708 if (os.path.real(self.allocator, full_path)) |real_path| {708 if (fs.path.real(self.allocator, full_path)) |real_path| {
709 return real_path;709 return real_path;
710 } else |_| {710 } else |_| {
711 continue;711 continue;
...@@ -714,13 +714,13 @@ pub const Builder = struct {...@@ -714,13 +714,13 @@ pub const Builder = struct {
714 }714 }
715 if (self.env_map.get("PATH")) |PATH| {715 if (self.env_map.get("PATH")) |PATH| {
716 for (names) |name| {716 for (names) |name| {
717 if (os.path.isAbsolute(name)) {717 if (fs.path.isAbsolute(name)) {
718 return name;718 return name;
719 }719 }
720 var it = mem.tokenize(PATH, []u8{os.path.delimiter});720 var it = mem.tokenize(PATH, []u8{fs.path.delimiter});
721 while (it.next()) |path| {721 while (it.next()) |path| {
722 const full_path = try os.path.join(self.allocator, [][]const u8{ path, self.fmt("{}{}", name, exe_extension) });722 const full_path = try fs.path.join(self.allocator, [][]const u8{ path, self.fmt("{}{}", name, exe_extension) });
723 if (os.path.real(self.allocator, full_path)) |real_path| {723 if (fs.path.real(self.allocator, full_path)) |real_path| {
724 return real_path;724 return real_path;
725 } else |_| {725 } else |_| {
726 continue;726 continue;
...@@ -729,12 +729,12 @@ pub const Builder = struct {...@@ -729,12 +729,12 @@ pub const Builder = struct {
729 }729 }
730 }730 }
731 for (names) |name| {731 for (names) |name| {
732 if (os.path.isAbsolute(name)) {732 if (fs.path.isAbsolute(name)) {
733 return name;733 return name;
734 }734 }
735 for (paths) |path| {735 for (paths) |path| {
736 const full_path = try os.path.join(self.allocator, [][]const u8{ path, self.fmt("{}{}", name, exe_extension) });736 const full_path = try fs.path.join(self.allocator, [][]const u8{ path, self.fmt("{}{}", name, exe_extension) });
737 if (os.path.real(self.allocator, full_path)) |real_path| {737 if (fs.path.real(self.allocator, full_path)) |real_path| {
738 return real_path;738 return real_path;
739 } else |_| {739 } else |_| {
740 continue;740 continue;
...@@ -748,12 +748,12 @@ pub const Builder = struct {...@@ -748,12 +748,12 @@ pub const Builder = struct {
748 assert(argv.len != 0);748 assert(argv.len != 0);
749749
750 const max_output_size = 100 * 1024;750 const max_output_size = 100 * 1024;
751 const child = try os.ChildProcess.init(argv, self.allocator);751 const child = try std.ChildProcess.init(argv, self.allocator);
752 defer child.deinit();752 defer child.deinit();
753753
754 child.stdin_behavior = os.ChildProcess.StdIo.Ignore;754 child.stdin_behavior = .Ignore;
755 child.stdout_behavior = os.ChildProcess.StdIo.Pipe;755 child.stdout_behavior = .Pipe;
756 child.stderr_behavior = os.ChildProcess.StdIo.Inherit;756 child.stderr_behavior = .Inherit;
757757
758 try child.spawn();758 try child.spawn();
759759
...@@ -765,7 +765,7 @@ pub const Builder = struct {...@@ -765,7 +765,7 @@ pub const Builder = struct {
765765
766 const term = child.wait() catch |err| std.debug.panic("unable to spawn {}: {}", argv[0], err);766 const term = child.wait() catch |err| std.debug.panic("unable to spawn {}: {}", argv[0], err);
767 switch (term) {767 switch (term) {
768 os.ChildProcess.Term.Exited => |code| {768 .Exited => |code| {
769 if (code != 0) {769 if (code != 0) {
770 warn("The following command exited with error code {}:\n", code);770 warn("The following command exited with error code {}:\n", code);
771 printCmd(null, argv);771 printCmd(null, argv);
...@@ -845,8 +845,8 @@ pub const Target = union(enum) {...@@ -845,8 +845,8 @@ pub const Target = union(enum) {
845 }845 }
846 }846 }
847847
848 pub fn oFileExt(self: *const Target) []const u8 {848 pub fn oFileExt(self: Target) []const u8 {
849 const abi = switch (self.*) {849 const abi = switch (self) {
850 Target.Native => builtin.abi,850 Target.Native => builtin.abi,
851 Target.Cross => |t| t.abi,851 Target.Cross => |t| t.abi,
852 };852 };
...@@ -856,49 +856,49 @@ pub const Target = union(enum) {...@@ -856,49 +856,49 @@ pub const Target = union(enum) {
856 };856 };
857 }857 }
858858
859 pub fn exeFileExt(self: *const Target) []const u8 {859 pub fn exeFileExt(self: Target) []const u8 {
860 return switch (self.getOs()) {860 return switch (self.getOs()) {
861 builtin.Os.windows => ".exe",861 .windows => ".exe",
862 else => "",862 else => "",
863 };863 };
864 }864 }
865865
866 pub fn libFileExt(self: *const Target) []const u8 {866 pub fn libFileExt(self: Target) []const u8 {
867 return switch (self.getOs()) {867 return switch (self.getOs()) {
868 builtin.Os.windows => ".lib",868 .windows => ".lib",
869 else => ".a",869 else => ".a",
870 };870 };
871 }871 }
872872
873 pub fn getOs(self: *const Target) builtin.Os {873 pub fn getOs(self: Target) builtin.Os {
874 return switch (self.*) {874 return switch (self) {
875 Target.Native => builtin.os,875 Target.Native => builtin.os,
876 Target.Cross => |t| t.os,876 Target.Cross => |t| t.os,
877 };877 };
878 }878 }
879879
880 pub fn isDarwin(self: *const Target) bool {880 pub fn isDarwin(self: Target) bool {
881 return switch (self.getOs()) {881 return switch (self.getOs()) {
882 builtin.Os.ios, builtin.Os.macosx => true,882 .ios, .macosx, .watchos, .tvos => true,
883 else => false,883 else => false,
884 };884 };
885 }885 }
886886
887 pub fn isWindows(self: *const Target) bool {887 pub fn isWindows(self: Target) bool {
888 return switch (self.getOs()) {888 return switch (self.getOs()) {
889 builtin.Os.windows => true,889 .windows => true,
890 else => false,890 else => false,
891 };891 };
892 }892 }
893893
894 pub fn isFreeBSD(self: *const Target) bool {894 pub fn isFreeBSD(self: Target) bool {
895 return switch (self.getOs()) {895 return switch (self.getOs()) {
896 builtin.Os.freebsd => true,896 .freebsd => true,
897 else => false,897 else => false,
898 };898 };
899 }899 }
900900
901 pub fn wantSharedLibSymLinks(self: *const Target) bool {901 pub fn wantSharedLibSymLinks(self: Target) bool {
902 return !self.isWindows();902 return !self.isWindows();
903 }903 }
904};904};
...@@ -1064,19 +1064,19 @@ pub const LibExeObjStep = struct {...@@ -1064,19 +1064,19 @@ pub const LibExeObjStep = struct {
10641064
1065 fn computeOutFileNames(self: *LibExeObjStep) void {1065 fn computeOutFileNames(self: *LibExeObjStep) void {
1066 switch (self.kind) {1066 switch (self.kind) {
1067 Kind.Obj => {1067 .Obj => {
1068 self.out_filename = self.builder.fmt("{}{}", self.name, self.target.oFileExt());1068 self.out_filename = self.builder.fmt("{}{}", self.name, self.target.oFileExt());
1069 },1069 },
1070 Kind.Exe => {1070 .Exe => {
1071 self.out_filename = self.builder.fmt("{}{}", self.name, self.target.exeFileExt());1071 self.out_filename = self.builder.fmt("{}{}", self.name, self.target.exeFileExt());
1072 },1072 },
1073 Kind.Test => {1073 .Test => {
1074 self.out_filename = self.builder.fmt("test{}", self.target.exeFileExt());1074 self.out_filename = self.builder.fmt("test{}", self.target.exeFileExt());
1075 },1075 },
1076 Kind.Lib => {1076 .Lib => {
1077 if (!self.is_dynamic) {1077 if (!self.is_dynamic) {
1078 switch (self.target.getOs()) {1078 switch (self.target.getOs()) {
1079 builtin.Os.windows => {1079 .windows => {
1080 self.out_filename = self.builder.fmt("{}.lib", self.name);1080 self.out_filename = self.builder.fmt("{}.lib", self.name);
1081 },1081 },
1082 else => {1082 else => {
...@@ -1086,13 +1086,13 @@ pub const LibExeObjStep = struct {...@@ -1086,13 +1086,13 @@ pub const LibExeObjStep = struct {
1086 self.out_lib_filename = self.out_filename;1086 self.out_lib_filename = self.out_filename;
1087 } else {1087 } else {
1088 switch (self.target.getOs()) {1088 switch (self.target.getOs()) {
1089 builtin.Os.ios, builtin.Os.macosx => {1089 .ios, .macosx => {
1090 self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib", self.name, self.version.major, self.version.minor, self.version.patch);1090 self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib", self.name, self.version.major, self.version.minor, self.version.patch);
1091 self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", self.name, self.version.major);1091 self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", self.name, self.version.major);
1092 self.name_only_filename = self.builder.fmt("lib{}.dylib", self.name);1092 self.name_only_filename = self.builder.fmt("lib{}.dylib", self.name);
1093 self.out_lib_filename = self.out_filename;1093 self.out_lib_filename = self.out_filename;
1094 },1094 },
1095 builtin.Os.windows => {1095 .windows => {
1096 self.out_filename = self.builder.fmt("{}.dll", self.name);1096 self.out_filename = self.builder.fmt("{}.dll", self.name);
1097 self.out_lib_filename = self.builder.fmt("{}.lib", self.name);1097 self.out_lib_filename = self.builder.fmt("{}.lib", self.name);
1098 },1098 },
...@@ -1227,7 +1227,7 @@ pub const LibExeObjStep = struct {...@@ -1227,7 +1227,7 @@ pub const LibExeObjStep = struct {
1227 /// the make step, from a step that has declared a dependency on this one.1227 /// the make step, from a step that has declared a dependency on this one.
1228 /// To run an executable built with zig build, use `run`, or create an install step and invoke it.1228 /// To run an executable built with zig build, use `run`, or create an install step and invoke it.
1229 pub fn getOutputPath(self: *LibExeObjStep) []const u8 {1229 pub fn getOutputPath(self: *LibExeObjStep) []const u8 {
1230 return os.path.join(1230 return fs.path.join(
1231 self.builder.allocator,1231 self.builder.allocator,
1232 [][]const u8{ self.output_dir.?, self.out_filename },1232 [][]const u8{ self.output_dir.?, self.out_filename },
1233 ) catch unreachable;1233 ) catch unreachable;
...@@ -1237,7 +1237,7 @@ pub const LibExeObjStep = struct {...@@ -1237,7 +1237,7 @@ pub const LibExeObjStep = struct {
1237 /// the make step, from a step that has declared a dependency on this one.1237 /// the make step, from a step that has declared a dependency on this one.
1238 pub fn getOutputLibPath(self: *LibExeObjStep) []const u8 {1238 pub fn getOutputLibPath(self: *LibExeObjStep) []const u8 {
1239 assert(self.kind == Kind.Lib);1239 assert(self.kind == Kind.Lib);
1240 return os.path.join(1240 return fs.path.join(
1241 self.builder.allocator,1241 self.builder.allocator,
1242 [][]const u8{ self.output_dir.?, self.out_lib_filename },1242 [][]const u8{ self.output_dir.?, self.out_lib_filename },
1243 ) catch unreachable;1243 ) catch unreachable;
...@@ -1248,7 +1248,7 @@ pub const LibExeObjStep = struct {...@@ -1248,7 +1248,7 @@ pub const LibExeObjStep = struct {
1248 pub fn getOutputHPath(self: *LibExeObjStep) []const u8 {1248 pub fn getOutputHPath(self: *LibExeObjStep) []const u8 {
1249 assert(self.kind != Kind.Exe);1249 assert(self.kind != Kind.Exe);
1250 assert(!self.disable_gen_h);1250 assert(!self.disable_gen_h);
1251 return os.path.join(1251 return fs.path.join(
1252 self.builder.allocator,1252 self.builder.allocator,
1253 [][]const u8{ self.output_dir.?, self.out_h_filename },1253 [][]const u8{ self.output_dir.?, self.out_h_filename },
1254 ) catch unreachable;1254 ) catch unreachable;
...@@ -1364,7 +1364,7 @@ pub const LibExeObjStep = struct {...@@ -1364,7 +1364,7 @@ pub const LibExeObjStep = struct {
1364 try zig_args.append("--library");1364 try zig_args.append("--library");
1365 try zig_args.append(full_path_lib);1365 try zig_args.append(full_path_lib);
13661366
1367 if (os.path.dirname(full_path_lib)) |dirname| {1367 if (fs.path.dirname(full_path_lib)) |dirname| {
1368 try zig_args.append("-rpath");1368 try zig_args.append("-rpath");
1369 try zig_args.append(dirname);1369 try zig_args.append(dirname);
1370 }1370 }
...@@ -1390,7 +1390,7 @@ pub const LibExeObjStep = struct {...@@ -1390,7 +1390,7 @@ pub const LibExeObjStep = struct {
1390 }1390 }
13911391
1392 if (self.build_options_contents.len() > 0) {1392 if (self.build_options_contents.len() > 0) {
1393 const build_options_file = try os.path.join(1393 const build_options_file = try fs.path.join(
1394 builder.allocator,1394 builder.allocator,
1395 [][]const u8{ builder.cache_root, builder.fmt("{}_build_options.zig", self.name) },1395 [][]const u8{ builder.cache_root, builder.fmt("{}_build_options.zig", self.name) },
1396 );1396 );
...@@ -1502,7 +1502,7 @@ pub const LibExeObjStep = struct {...@@ -1502,7 +1502,7 @@ pub const LibExeObjStep = struct {
1502 IncludeDir.OtherStep => |other| {1502 IncludeDir.OtherStep => |other| {
1503 const h_path = other.getOutputHPath();1503 const h_path = other.getOutputHPath();
1504 try zig_args.append("-isystem");1504 try zig_args.append("-isystem");
1505 try zig_args.append(os.path.dirname(h_path).?);1505 try zig_args.append(fs.path.dirname(h_path).?);
1506 },1506 },
1507 }1507 }
1508 }1508 }
...@@ -1575,7 +1575,7 @@ pub const LibExeObjStep = struct {...@@ -1575,7 +1575,7 @@ pub const LibExeObjStep = struct {
15751575
1576 const output_path_nl = try builder.exec(zig_args.toSliceConst());1576 const output_path_nl = try builder.exec(zig_args.toSliceConst());
1577 const output_path = mem.trimRight(u8, output_path_nl, "\r\n");1577 const output_path = mem.trimRight(u8, output_path_nl, "\r\n");
1578 self.output_dir = os.path.dirname(output_path).?;1578 self.output_dir = fs.path.dirname(output_path).?;
1579 }1579 }
15801580
1581 if (self.kind == Kind.Lib and self.is_dynamic and self.target.wantSharedLibSymLinks()) {1581 if (self.kind == Kind.Lib and self.is_dynamic and self.target.wantSharedLibSymLinks()) {
...@@ -1636,20 +1636,20 @@ pub const RunStep = struct {...@@ -1636,20 +1636,20 @@ pub const RunStep = struct {
1636 }1636 }
16371637
1638 pub fn addPathDir(self: *RunStep, search_path: []const u8) void {1638 pub fn addPathDir(self: *RunStep, search_path: []const u8) void {
1639 const PATH = if (builtin.os == builtin.Os.windows) "Path" else "PATH";1639 const PATH = if (std.os.windows.is_the_target) "Path" else "PATH";
1640 const env_map = self.getEnvMap();1640 const env_map = self.getEnvMap();
1641 const prev_path = env_map.get(PATH) orelse {1641 const prev_path = env_map.get(PATH) orelse {
1642 env_map.set(PATH, search_path) catch unreachable;1642 env_map.set(PATH, search_path) catch unreachable;
1643 return;1643 return;
1644 };1644 };
1645 const new_path = self.builder.fmt("{}" ++ [1]u8{os.path.delimiter} ++ "{}", prev_path, search_path);1645 const new_path = self.builder.fmt("{}" ++ [1]u8{fs.path.delimiter} ++ "{}", prev_path, search_path);
1646 env_map.set(PATH, new_path) catch unreachable;1646 env_map.set(PATH, new_path) catch unreachable;
1647 }1647 }
16481648
1649 pub fn getEnvMap(self: *RunStep) *BufMap {1649 pub fn getEnvMap(self: *RunStep) *BufMap {
1650 return self.env_map orelse {1650 return self.env_map orelse {
1651 const env_map = self.builder.allocator.create(BufMap) catch unreachable;1651 const env_map = self.builder.allocator.create(BufMap) catch unreachable;
1652 env_map.* = os.getEnvMap(self.builder.allocator) catch unreachable;1652 env_map.* = process.getEnvMap(self.builder.allocator) catch unreachable;
1653 self.env_map = env_map;1653 self.env_map = env_map;
1654 return env_map;1654 return env_map;
1655 };1655 };
...@@ -1687,7 +1687,7 @@ pub const RunStep = struct {...@@ -1687,7 +1687,7 @@ pub const RunStep = struct {
1687 switch (link_object) {1687 switch (link_object) {
1688 LibExeObjStep.LinkObject.OtherStep => |other| {1688 LibExeObjStep.LinkObject.OtherStep => |other| {
1689 if (other.target.isWindows() and other.isDynamicLibrary()) {1689 if (other.target.isWindows() and other.isDynamicLibrary()) {
1690 self.addPathDir(os.path.dirname(other.getOutputPath()).?);1690 self.addPathDir(fs.path.dirname(other.getOutputPath()).?);
1691 self.addPathForDynLibs(other);1691 self.addPathForDynLibs(other);
1692 }1692 }
1693 },1693 },
...@@ -1717,7 +1717,7 @@ const InstallArtifactStep = struct {...@@ -1717,7 +1717,7 @@ const InstallArtifactStep = struct {
1717 .builder = builder,1717 .builder = builder,
1718 .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),1718 .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),
1719 .artifact = artifact,1719 .artifact = artifact,
1720 .dest_file = os.path.join(1720 .dest_file = fs.path.join(
1721 builder.allocator,1721 builder.allocator,
1722 [][]const u8{ dest_dir, artifact.out_filename },1722 [][]const u8{ dest_dir, artifact.out_filename },
1723 ) catch unreachable,1723 ) catch unreachable,
...@@ -1725,11 +1725,11 @@ const InstallArtifactStep = struct {...@@ -1725,11 +1725,11 @@ const InstallArtifactStep = struct {
1725 self.step.dependOn(&artifact.step);1725 self.step.dependOn(&artifact.step);
1726 builder.pushInstalledFile(self.dest_file);1726 builder.pushInstalledFile(self.dest_file);
1727 if (self.artifact.kind == LibExeObjStep.Kind.Lib and self.artifact.is_dynamic) {1727 if (self.artifact.kind == LibExeObjStep.Kind.Lib and self.artifact.is_dynamic) {
1728 builder.pushInstalledFile(os.path.join(1728 builder.pushInstalledFile(fs.path.join(
1729 builder.allocator,1729 builder.allocator,
1730 [][]const u8{ builder.lib_dir, artifact.major_only_filename },1730 [][]const u8{ builder.lib_dir, artifact.major_only_filename },
1731 ) catch unreachable);1731 ) catch unreachable);
1732 builder.pushInstalledFile(os.path.join(1732 builder.pushInstalledFile(fs.path.join(
1733 builder.allocator,1733 builder.allocator,
1734 [][]const u8{ builder.lib_dir, artifact.name_only_filename },1734 [][]const u8{ builder.lib_dir, artifact.name_only_filename },
1735 ) catch unreachable);1735 ) catch unreachable);
...@@ -1742,12 +1742,12 @@ const InstallArtifactStep = struct {...@@ -1742,12 +1742,12 @@ const InstallArtifactStep = struct {
1742 const builder = self.builder;1742 const builder = self.builder;
17431743
1744 const mode = switch (builtin.os) {1744 const mode = switch (builtin.os) {
1745 builtin.Os.windows => {},1745 .windows => {},
1746 else => switch (self.artifact.kind) {1746 else => switch (self.artifact.kind) {
1747 LibExeObjStep.Kind.Obj => unreachable,1747 .Obj => unreachable,
1748 LibExeObjStep.Kind.Test => unreachable,1748 .Test => unreachable,
1749 LibExeObjStep.Kind.Exe => u32(0o755),1749 .Exe => u32(0o755),
1750 LibExeObjStep.Kind.Lib => if (!self.artifact.is_dynamic) u32(0o666) else u32(0o755),1750 .Lib => if (!self.artifact.is_dynamic) u32(0o666) else u32(0o755),
1751 },1751 },
1752 };1752 };
1753 try builder.copyFileMode(self.artifact.getOutputPath(), self.dest_file, mode);1753 try builder.copyFileMode(self.artifact.getOutputPath(), self.dest_file, mode);
...@@ -1796,8 +1796,8 @@ pub const WriteFileStep = struct {...@@ -1796,8 +1796,8 @@ pub const WriteFileStep = struct {
1796 fn make(step: *Step) !void {1796 fn make(step: *Step) !void {
1797 const self = @fieldParentPtr(WriteFileStep, "step", step);1797 const self = @fieldParentPtr(WriteFileStep, "step", step);
1798 const full_path = self.builder.pathFromRoot(self.file_path);1798 const full_path = self.builder.pathFromRoot(self.file_path);
1799 const full_path_dir = os.path.dirname(full_path) orelse ".";1799 const full_path_dir = fs.path.dirname(full_path) orelse ".";
1800 os.makePath(self.builder.allocator, full_path_dir) catch |err| {1800 fs.makePath(self.builder.allocator, full_path_dir) catch |err| {
1801 warn("unable to make path {}: {}\n", full_path_dir, @errorName(err));1801 warn("unable to make path {}: {}\n", full_path_dir, @errorName(err));
1802 return err;1802 return err;
1803 };1803 };
...@@ -1844,7 +1844,7 @@ pub const RemoveDirStep = struct {...@@ -1844,7 +1844,7 @@ pub const RemoveDirStep = struct {
1844 const self = @fieldParentPtr(RemoveDirStep, "step", step);1844 const self = @fieldParentPtr(RemoveDirStep, "step", step);
18451845
1846 const full_path = self.builder.pathFromRoot(self.dir_path);1846 const full_path = self.builder.pathFromRoot(self.dir_path);
1847 os.deleteTree(self.builder.allocator, full_path) catch |err| {1847 fs.deleteTree(self.builder.allocator, full_path) catch |err| {
1848 warn("Unable to remove {}: {}\n", full_path, @errorName(err));1848 warn("Unable to remove {}: {}\n", full_path, @errorName(err));
1849 return err;1849 return err;
1850 };1850 };
...@@ -1886,23 +1886,23 @@ pub const Step = struct {...@@ -1886,23 +1886,23 @@ pub const Step = struct {
1886};1886};
18871887
1888fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_major_only: []const u8, filename_name_only: []const u8) !void {1888fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_major_only: []const u8, filename_name_only: []const u8) !void {
1889 const out_dir = os.path.dirname(output_path) orelse ".";1889 const out_dir = fs.path.dirname(output_path) orelse ".";
1890 const out_basename = os.path.basename(output_path);1890 const out_basename = fs.path.basename(output_path);
1891 // sym link for libfoo.so.1 to libfoo.so.1.2.31891 // sym link for libfoo.so.1 to libfoo.so.1.2.3
1892 const major_only_path = os.path.join(1892 const major_only_path = fs.path.join(
1893 allocator,1893 allocator,
1894 [][]const u8{ out_dir, filename_major_only },1894 [][]const u8{ out_dir, filename_major_only },
1895 ) catch unreachable;1895 ) catch unreachable;
1896 os.atomicSymLink(allocator, out_basename, major_only_path) catch |err| {1896 fs.atomicSymLink(allocator, out_basename, major_only_path) catch |err| {
1897 warn("Unable to symlink {} -> {}\n", major_only_path, out_basename);1897 warn("Unable to symlink {} -> {}\n", major_only_path, out_basename);
1898 return err;1898 return err;
1899 };1899 };
1900 // sym link for libfoo.so to libfoo.so.11900 // sym link for libfoo.so to libfoo.so.1
1901 const name_only_path = os.path.join(1901 const name_only_path = fs.path.join(
1902 allocator,1902 allocator,
1903 [][]const u8{ out_dir, filename_name_only },1903 [][]const u8{ out_dir, filename_name_only },
1904 ) catch unreachable;1904 ) catch unreachable;
1905 os.atomicSymLink(allocator, filename_major_only, name_only_path) catch |err| {1905 fs.atomicSymLink(allocator, filename_major_only, name_only_path) catch |err| {
1906 warn("Unable to symlink {} -> {}\n", name_only_path, filename_major_only);1906 warn("Unable to symlink {} -> {}\n", name_only_path, filename_major_only);
1907 return err;1907 return err;
1908 };1908 };
std/c.zig+72-30
...@@ -1,18 +1,28 @@...@@ -1,18 +1,28 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const Os = builtin.Os;2const std = @import("std");
3const page_size = std.mem.page_size;
4
5pub use @import("os/bits.zig");
36
4pub use switch (builtin.os) {7pub use switch (builtin.os) {
5 Os.linux => @import("c/linux.zig"),8 .linux => @import("c/linux.zig"),
6 Os.windows => @import("c/windows.zig"),9 .windows => @import("c/windows.zig"),
7 Os.macosx, Os.ios => @import("c/darwin.zig"),10 .macosx, .ios, .tvos, .watchos => @import("c/darwin.zig"),
8 Os.freebsd => @import("c/freebsd.zig"),11 .freebsd => @import("c/freebsd.zig"),
9 Os.netbsd => @import("c/netbsd.zig"),12 .netbsd => @import("c/netbsd.zig"),
10 else => struct {},13 else => struct {},
11};14};
1215
16pub fn getErrno(rc: var) u16 {
17 if (rc == -1) {
18 return @intCast(u16, _errno().*);
19 } else {
20 return 0;
21 }
22}
23
13// TODO https://github.com/ziglang/zig/issues/265 on this whole file24// TODO https://github.com/ziglang/zig/issues/265 on this whole file
1425
15pub const FILE = @OpaqueType();
16pub extern "c" fn fopen(filename: [*]const u8, modes: [*]const u8) ?*FILE;26pub extern "c" fn fopen(filename: [*]const u8, modes: [*]const u8) ?*FILE;
17pub extern "c" fn fclose(stream: *FILE) c_int;27pub extern "c" fn fclose(stream: *FILE) c_int;
18pub extern "c" fn fwrite(ptr: [*]const u8, size_of_type: usize, item_count: usize, stream: *FILE) usize;28pub 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...@@ -20,33 +30,38 @@ pub extern "c" fn fread(ptr: [*]u8, size_of_type: usize, item_count: usize, stre
2030
21pub extern "c" fn abort() noreturn;31pub extern "c" fn abort() noreturn;
22pub extern "c" fn exit(code: c_int) noreturn;32pub extern "c" fn exit(code: c_int) noreturn;
23pub extern "c" fn isatty(fd: c_int) c_int;33pub extern "c" fn isatty(fd: fd_t) c_int;
24pub extern "c" fn close(fd: c_int) c_int;34pub extern "c" fn close(fd: fd_t) c_int;
25pub extern "c" fn fstat(fd: c_int, buf: *Stat) c_int;35pub extern "c" fn @"close$NOCANCEL"(fd: fd_t) c_int;
26pub extern "c" fn @"fstat$INODE64"(fd: c_int, buf: *Stat) c_int;36pub extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int;
27pub extern "c" fn lseek(fd: c_int, offset: isize, whence: c_int) isize;37pub extern "c" fn @"fstat$INODE64"(fd: fd_t, buf: *Stat) c_int;
28pub extern "c" fn open(path: [*]const u8, oflag: c_int, ...) c_int;38pub extern "c" fn lseek(fd: fd_t, offset: isize, whence: c_int) isize;
39pub extern "c" fn open(path: [*]const u8, oflag: c_uint, ...) c_int;
29pub extern "c" fn raise(sig: c_int) c_int;40pub extern "c" fn raise(sig: c_int) c_int;
30pub extern "c" fn read(fd: c_int, buf: *c_void, nbyte: usize) isize;41pub extern "c" fn read(fd: fd_t, buf: [*]u8, nbyte: usize) isize;
31pub extern "c" fn pread(fd: c_int, buf: *c_void, nbyte: usize, offset: u64) isize;42pub extern "c" fn pread(fd: fd_t, buf: [*]u8, nbyte: usize, offset: u64) isize;
43pub extern "c" fn preadv(fd: c_int, iov: [*]const iovec, iovcnt: c_uint, offset: usize) isize;
44pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: usize) isize;
32pub extern "c" fn stat(noalias path: [*]const u8, noalias buf: *Stat) c_int;45pub extern "c" fn stat(noalias path: [*]const u8, noalias buf: *Stat) c_int;
33pub extern "c" fn write(fd: c_int, buf: *const c_void, nbyte: usize) isize;46pub extern "c" fn write(fd: fd_t, buf: [*]const u8, nbyte: usize) isize;
34pub extern "c" fn pwrite(fd: c_int, buf: *const c_void, nbyte: usize, offset: u64) isize;47pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: u64) isize;
35pub extern "c" fn mmap(addr: ?*c_void, len: usize, prot: c_int, flags: c_int, fd: c_int, offset: isize) ?*c_void;48pub 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;
36pub extern "c" fn munmap(addr: ?*c_void, len: usize) c_int;49pub extern "c" fn munmap(addr: *align(page_size) c_void, len: usize) c_int;
50pub extern "c" fn mprotect(addr: *align(page_size) c_void, len: usize, prot: c_uint) c_int;
37pub extern "c" fn unlink(path: [*]const u8) c_int;51pub extern "c" fn unlink(path: [*]const u8) c_int;
38pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8;52pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8;
39pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_int, options: c_int) c_int;53pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_uint, options: c_uint) c_int;
40pub extern "c" fn fork() c_int;54pub extern "c" fn fork() c_int;
41pub extern "c" fn access(path: [*]const u8, mode: c_uint) c_int;55pub extern "c" fn access(path: [*]const u8, mode: c_uint) c_int;
42pub extern "c" fn pipe(fds: *[2]c_int) c_int;56pub extern "c" fn pipe(fds: *[2]fd_t) c_int;
57pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;
43pub extern "c" fn mkdir(path: [*]const u8, mode: c_uint) c_int;58pub extern "c" fn mkdir(path: [*]const u8, mode: c_uint) c_int;
44pub extern "c" fn symlink(existing: [*]const u8, new: [*]const u8) c_int;59pub extern "c" fn symlink(existing: [*]const u8, new: [*]const u8) c_int;
45pub extern "c" fn rename(old: [*]const u8, new: [*]const u8) c_int;60pub extern "c" fn rename(old: [*]const u8, new: [*]const u8) c_int;
46pub extern "c" fn chdir(path: [*]const u8) c_int;61pub extern "c" fn chdir(path: [*]const u8) c_int;
47pub extern "c" fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) c_int;62pub extern "c" fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) c_int;
48pub extern "c" fn dup(fd: c_int) c_int;63pub extern "c" fn dup(fd: fd_t) c_int;
49pub extern "c" fn dup2(old_fd: c_int, new_fd: c_int) c_int;64pub extern "c" fn dup2(old_fd: fd_t, new_fd: fd_t) c_int;
50pub extern "c" fn readlink(noalias path: [*]const u8, noalias buf: [*]u8, bufsize: usize) isize;65pub extern "c" fn readlink(noalias path: [*]const u8, noalias buf: [*]u8, bufsize: usize) isize;
51pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*]u8;66pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*]u8;
52pub extern "c" fn sigprocmask(how: c_int, noalias set: *const sigset_t, noalias oset: ?*sigset_t) c_int;67pub 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;...@@ -56,6 +71,25 @@ pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
56pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;71pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
57pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;72pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
58pub extern "c" fn rmdir(path: [*]const u8) c_int;73pub extern "c" fn rmdir(path: [*]const u8) c_int;
74pub extern "c" fn getenv(name: [*]const u8) ?[*]u8;
75pub extern "c" fn sysctl(name: [*]const c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
76pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
77pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int;
78
79pub extern "c" fn bind(socket: fd_t, address: ?*const sockaddr, address_len: socklen_t) c_int;
80pub extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int;
81pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int;
82pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int;
83pub extern "c" fn connect(sockfd: fd_t, sock_addr: *const sockaddr, addrlen: socklen_t) c_int;
84pub extern "c" fn accept4(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t, flags: c_uint) c_int;
85pub extern "c" fn getsockopt(sockfd: fd_t, level: c_int, optname: c_int, optval: *c_void, optlen: *socklen_t) c_int;
86pub extern "c" fn kill(pid: pid_t, sig: c_int) c_int;
87pub extern "c" fn getdirentries(fd: fd_t, buf_ptr: [*]u8, nbytes: usize, basep: *i64) isize;
88pub extern "c" fn openat(fd: c_int, path: [*]const u8, flags: c_int) c_int;
89pub extern "c" fn setgid(ruid: c_uint, euid: c_uint) c_int;
90pub extern "c" fn setuid(uid: c_uint) c_int;
91pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int;
92pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int;
5993
60pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?*c_void;94pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?*c_void;
61pub extern "c" fn malloc(usize) ?*c_void;95pub extern "c" fn malloc(usize) ?*c_void;
...@@ -63,11 +97,19 @@ pub extern "c" fn realloc(?*c_void, usize) ?*c_void;...@@ -63,11 +97,19 @@ pub extern "c" fn realloc(?*c_void, usize) ?*c_void;
63pub extern "c" fn free(*c_void) void;97pub extern "c" fn free(*c_void) void;
64pub extern "c" fn posix_memalign(memptr: **c_void, alignment: usize, size: usize) c_int;98pub extern "c" fn posix_memalign(memptr: **c_void, alignment: usize, size: usize) c_int;
6599
66pub 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;100pub 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;
67pub extern "pthread" fn pthread_attr_init(attr: *pthread_attr_t) c_int;101pub extern "c" fn pthread_attr_init(attr: *pthread_attr_t) c_int;
68pub extern "pthread" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int;102pub extern "c" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int;
69pub extern "pthread" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int;103pub extern "c" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int;
70pub extern "pthread" fn pthread_self() pthread_t;104pub extern "c" fn pthread_self() pthread_t;
71pub extern "pthread" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int;105pub extern "c" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int;
72106
73pub const pthread_t = *@OpaqueType();107pub extern "c" fn kqueue() c_int;
108pub extern "c" fn kevent(
109 kq: c_int,
110 changelist: [*]const Kevent,
111 nchanges: c_int,
112 eventlist: [*]Kevent,
113 nevents: c_int,
114 timeout: ?*const timespec,
115) c_int;
std/c/darwin.zig+16-177
...@@ -1,24 +1,19 @@...@@ -1,24 +1,19 @@
1const macho = @import("../macho.zig");1const std = @import("../std.zig");
2const assert = std.debug.assert;
3const builtin = @import("builtin");
4const macho = std.macho;
5
6use @import("../os/bits.zig");
27
3extern "c" fn __error() *c_int;8extern "c" fn __error() *c_int;
4pub extern "c" fn _NSGetExecutablePath(buf: [*]u8, bufsize: *u32) c_int;9pub extern "c" fn _NSGetExecutablePath(buf: [*]u8, bufsize: *u32) c_int;
5pub extern "c" fn _dyld_get_image_header(image_index: u32) ?*mach_header;10pub extern "c" fn _dyld_get_image_header(image_index: u32) ?*mach_header;
611
7pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize;12pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: [*]u8, buf_len: usize, basep: *i64) isize;
813
9pub extern "c" fn mach_absolute_time() u64;14pub extern "c" fn mach_absolute_time() u64;
10pub extern "c" fn mach_timebase_info(tinfo: ?*mach_timebase_info_data) void;15pub extern "c" fn mach_timebase_info(tinfo: ?*mach_timebase_info_data) void;
1116
12pub extern "c" fn kqueue() c_int;
13pub extern "c" fn kevent(
14 kq: c_int,
15 changelist: [*]const Kevent,
16 nchanges: c_int,
17 eventlist: [*]Kevent,
18 nevents: c_int,
19 timeout: ?*const timespec,
20) c_int;
21
22pub extern "c" fn kevent64(17pub extern "c" fn kevent64(
23 kq: c_int,18 kq: c_int,
24 changelist: [*]const kevent64_s,19 changelist: [*]const kevent64_s,
...@@ -29,13 +24,6 @@ pub extern "c" fn kevent64(...@@ -29,13 +24,6 @@ pub extern "c" fn kevent64(
29 timeout: ?*const timespec,24 timeout: ?*const timespec,
30) c_int;25) c_int;
3126
32pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
33pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
34pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int;
35
36pub extern "c" fn bind(socket: c_int, address: ?*const sockaddr, address_len: socklen_t) c_int;
37pub extern "c" fn socket(domain: c_int, type: c_int, protocol: c_int) c_int;
38
39const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header;27const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header;
4028
41/// The value of the link editor defined symbol _MH_EXECUTE_SYM is the address29/// 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;...@@ -48,170 +36,21 @@ const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header;
48/// export a weak symbol here, to be overridden by the real one.36/// export a weak symbol here, to be overridden by the real one.
49pub extern "c" var _mh_execute_header: mach_hdr = undefined;37pub extern "c" var _mh_execute_header: mach_hdr = undefined;
50comptime {38comptime {
51 @export("__mh_execute_header", _mh_execute_header, @import("builtin").GlobalLinkage.Weak);39 if (std.os.darwin.is_the_target) {
40 @export("__mh_execute_header", _mh_execute_header, .Weak);
41 }
52}42}
5343
54pub const mach_header_64 = macho.mach_header_64;44pub const mach_header_64 = macho.mach_header_64;
55pub const mach_header = macho.mach_header;45pub const mach_header = macho.mach_header;
5646
57pub use @import("../os/darwin/errno.zig");
58
59pub const _errno = __error;47pub const _errno = __error;
6048
61pub const in_port_t = u16;49pub extern "c" fn mach_host_self() mach_port_t;
62pub const sa_family_t = u8;50pub extern "c" fn clock_get_time(clock_serv: clock_serv_t, cur_time: *mach_timespec_t) kern_return_t;
63pub const socklen_t = u32;51pub extern "c" fn host_get_clock_service(host: host_t, clock_id: clock_id_t, clock_serv: ?[*]clock_serv_t) kern_return_t;
64pub const sockaddr = extern union {52pub extern "c" fn mach_port_deallocate(task: ipc_space_t, name: mach_port_name_t) kern_return_t;
65 in: sockaddr_in,
66 in6: sockaddr_in6,
67};
68pub const sockaddr_in = extern struct {
69 len: u8,
70 family: sa_family_t,
71 port: in_port_t,
72 addr: u32,
73 zero: [8]u8,
74};
75pub const sockaddr_in6 = extern struct {
76 len: u8,
77 family: sa_family_t,
78 port: in_port_t,
79 flowinfo: u32,
80 addr: [16]u8,
81 scope_id: u32,
82};
83
84pub const timeval = extern struct {
85 tv_sec: c_long,
86 tv_usec: i32,
87};
88
89pub const timezone = extern struct {
90 tz_minuteswest: i32,
91 tz_dsttime: i32,
92};
93
94pub const mach_timebase_info_data = extern struct {
95 numer: u32,
96 denom: u32,
97};
98
99/// Renamed to Stat to not conflict with the stat function.
100pub const Stat = extern struct {
101 dev: i32,
102 mode: u16,
103 nlink: u16,
104 ino: u64,
105 uid: u32,
106 gid: u32,
107 rdev: i32,
108 atime: usize,
109 atimensec: usize,
110 mtime: usize,
111 mtimensec: usize,
112 ctime: usize,
113 ctimensec: usize,
114 birthtime: usize,
115 birthtimensec: usize,
116 size: i64,
117 blocks: i64,
118 blksize: i32,
119 flags: u32,
120 gen: u32,
121 lspare: i32,
122 qspare: [2]i64,
123};
12453
125pub const timespec = extern struct {54pub fn sigaddset(set: *sigset_t, signo: u5) void {
126 tv_sec: isize,55 set.* |= u32(1) << (signo - 1);
127 tv_nsec: isize,
128};
129
130pub const sigset_t = u32;
131
132/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.
133pub const Sigaction = extern struct {
134 handler: extern fn (c_int) void,
135 sa_mask: sigset_t,
136 sa_flags: c_int,
137};
138
139pub const dirent = extern struct {
140 d_ino: usize,
141 d_seekoff: usize,
142 d_reclen: u16,
143 d_namlen: u16,
144 d_type: u8,
145 d_name: u8, // field address is address of first byte of name
146};
147
148pub const pthread_attr_t = extern struct {
149 __sig: c_long,
150 __opaque: [56]u8,
151};
152
153/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
154pub const Kevent = extern struct {
155 ident: usize,
156 filter: i16,
157 flags: u16,
158 fflags: u32,
159 data: isize,
160 udata: usize,
161};
162
163// sys/types.h on macos uses #pragma pack(4) so these checks are
164// to make sure the struct is laid out the same. These values were
165// produced from C code using the offsetof macro.
166const std = @import("../std.zig");
167const assert = std.debug.assert;
168
169comptime {
170 assert(@byteOffsetOf(Kevent, "ident") == 0);
171 assert(@byteOffsetOf(Kevent, "filter") == 8);
172 assert(@byteOffsetOf(Kevent, "flags") == 10);
173 assert(@byteOffsetOf(Kevent, "fflags") == 12);
174 assert(@byteOffsetOf(Kevent, "data") == 16);
175 assert(@byteOffsetOf(Kevent, "udata") == 24);
176}
177
178pub const kevent64_s = extern struct {
179 ident: u64,
180 filter: i16,
181 flags: u16,
182 fflags: u32,
183 data: i64,
184 udata: u64,
185 ext: [2]u64,
186};
187
188pub const mach_port_t = c_uint;
189pub const clock_serv_t = mach_port_t;
190pub const clock_res_t = c_int;
191pub const mach_port_name_t = natural_t;
192pub const natural_t = c_uint;
193pub const mach_timespec_t = extern struct {
194 tv_sec: c_uint,
195 tv_nsec: clock_res_t,
196};
197pub const kern_return_t = c_int;
198pub const host_t = mach_port_t;
199pub const CALENDAR_CLOCK = 1;
200
201pub extern fn mach_host_self() mach_port_t;
202pub extern fn clock_get_time(clock_serv: clock_serv_t, cur_time: *mach_timespec_t) kern_return_t;
203pub extern fn host_get_clock_service(host: host_t, clock_id: clock_id_t, clock_serv: ?[*]clock_serv_t) kern_return_t;
204pub extern fn mach_port_deallocate(task: ipc_space_t, name: mach_port_name_t) kern_return_t;
205
206// sys/types.h on macos uses #pragma pack() so these checks are
207// to make sure the struct is laid out the same. These values were
208// produced from C code using the offsetof macro.
209comptime {
210 assert(@byteOffsetOf(kevent64_s, "ident") == 0);
211 assert(@byteOffsetOf(kevent64_s, "filter") == 8);
212 assert(@byteOffsetOf(kevent64_s, "flags") == 10);
213 assert(@byteOffsetOf(kevent64_s, "fflags") == 12);
214 assert(@byteOffsetOf(kevent64_s, "data") == 16);
215 assert(@byteOffsetOf(kevent64_s, "udata") == 24);
216 assert(@byteOffsetOf(kevent64_s, "ext") == 32);
217}56}
std/c/freebsd.zig-150
...@@ -1,154 +1,4 @@...@@ -1,154 +1,4 @@
1extern "c" fn __error() *c_int;1extern "c" fn __error() *c_int;
2pub const _errno = __error;2pub const _errno = __error;
33
4pub extern "c" fn kqueue() c_int;
5pub extern "c" fn kevent(
6 kq: c_int,
7 changelist: [*]const Kevent,
8 nchanges: c_int,
9 eventlist: [*]Kevent,
10 nevents: c_int,
11 timeout: ?*const timespec,
12) c_int;
13pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
14pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
15pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int;
16pub extern "c" fn getdirentries(fd: c_int, buf_ptr: [*]u8, nbytes: usize, basep: *i64) usize;
17pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize;4pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize;
18pub extern "c" fn pipe2(arg0: *[2]c_int, arg1: u32) c_int;
19pub extern "c" fn preadv(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize;
20pub extern "c" fn pwritev(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize;
21pub extern "c" fn openat(fd: c_int, path: ?[*]const u8, flags: c_int) c_int;
22pub extern "c" fn setgid(ruid: c_uint, euid: c_uint) c_int;
23pub extern "c" fn setuid(uid: c_uint) c_int;
24pub extern "c" fn kill(pid: c_int, sig: c_int) c_int;
25pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int;
26pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int;
27
28/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
29pub const Kevent = extern struct {
30 ident: usize,
31 filter: i16,
32 flags: u16,
33 fflags: u32,
34 data: i64,
35 udata: usize,
36 // TODO ext
37};
38
39pub const pthread_attr_t = extern struct {
40 __size: [56]u8,
41 __align: c_long,
42};
43
44pub const msghdr = extern struct {
45 /// optional address
46 msg_name: ?*sockaddr,
47
48 /// size of address
49 msg_namelen: socklen_t,
50
51 /// scatter/gather array
52 msg_iov: [*]iovec,
53
54 /// # elements in msg_iov
55 msg_iovlen: i32,
56
57 /// ancillary data
58 msg_control: ?*c_void,
59
60 /// ancillary data buffer len
61 msg_controllen: socklen_t,
62
63 /// flags on received message
64 msg_flags: i32,
65};
66
67pub const msghdr_const = extern struct {
68 /// optional address
69 msg_name: ?*const sockaddr,
70
71 /// size of address
72 msg_namelen: socklen_t,
73
74 /// scatter/gather array
75 msg_iov: [*]iovec_const,
76
77 /// # elements in msg_iov
78 msg_iovlen: i32,
79
80 /// ancillary data
81 msg_control: ?*c_void,
82
83 /// ancillary data buffer len
84 msg_controllen: socklen_t,
85
86 /// flags on received message
87 msg_flags: i32,
88};
89
90pub const Stat = extern struct {
91 dev: u64,
92 ino: u64,
93 nlink: usize,
94
95 mode: u16,
96 __pad0: u16,
97 uid: u32,
98 gid: u32,
99 __pad1: u32,
100 rdev: u64,
101
102 atim: timespec,
103 mtim: timespec,
104 ctim: timespec,
105 birthtim: timespec,
106
107 size: i64,
108 blocks: i64,
109 blksize: isize,
110 flags: u32,
111 gen: u64,
112 __spare: [10]u64,
113};
114
115pub const timespec = extern struct {
116 tv_sec: isize,
117 tv_nsec: isize,
118};
119
120pub const dirent = extern struct {
121 d_fileno: usize,
122 d_off: i64,
123 d_reclen: u16,
124 d_type: u8,
125 d_pad0: u8,
126 d_namlen: u16,
127 d_pad1: u16,
128 d_name: [256]u8,
129};
130
131pub const in_port_t = u16;
132pub const sa_family_t = u16;
133
134pub const sockaddr = extern union {
135 in: sockaddr_in,
136 in6: sockaddr_in6,
137};
138
139pub const sockaddr_in = extern struct {
140 len: u8,
141 family: sa_family_t,
142 port: in_port_t,
143 addr: [16]u8,
144 zero: [8]u8,
145};
146
147pub const sockaddr_in6 = extern struct {
148 len: u8,
149 family: sa_family_t,
150 port: in_port_t,
151 flowinfo: u32,
152 addr: [16]u8,
153 scope_id: u32,
154};
std/c/linux.zig+20-10
...@@ -1,17 +1,27 @@...@@ -1,17 +1,27 @@
1const linux = @import("../os/linux.zig");1const std = @import("../std.zig");
2pub use @import("../os/linux/errno.zig");2use std.c;
33
4pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) c_int;
5extern "c" fn __errno_location() *c_int;4extern "c" fn __errno_location() *c_int;
6pub const _errno = __errno_location;5pub const _errno = __errno_location;
76
8pub const pthread_attr_t = extern struct {7pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) c_int;
9 __size: [56]u8,8pub extern "c" fn sched_getaffinity(pid: c_int, size: usize, set: *cpu_set_t) c_int;
10 __align: c_long,9pub extern "c" fn eventfd(initval: c_uint, flags: c_uint) c_int;
11};10pub extern "c" fn epoll_ctl(epfd: fd_t, op: c_uint, fd: fd_t, event: *epoll_event) c_int;
11pub extern "c" fn epoll_create1(flags: c_uint) c_int;
12pub extern "c" fn epoll_wait(epfd: fd_t, events: [*]epoll_event, maxevents: c_uint, timeout: c_int) c_int;
13pub extern "c" fn epoll_pwait(
14 epfd: fd_t,
15 events: [*]epoll_event,
16 maxevents: c_int,
17 timeout: c_int,
18 sigmask: *const sigset_t,
19) c_int;
20pub extern "c" fn inotify_init1(flags: c_uint) c_int;
21pub extern "c" fn inotify_add_watch(fd: fd_t, pathname: [*]const u8, mask: u32) c_int;
1222
13/// See std.elf for constants for this23/// See std.elf for constants for this
14pub extern fn getauxval(__type: c_ulong) c_ulong;24pub extern "c" fn getauxval(__type: c_ulong) c_ulong;
1525
16pub const dl_iterate_phdr_callback = extern fn (info: *linux.dl_phdr_info, size: usize, data: ?*c_void) c_int;26pub const dl_iterate_phdr_callback = extern fn (info: *dl_phdr_info, size: usize, data: ?*c_void) c_int;
17pub extern fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int;27pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int;
std/c/netbsd.zig-146
...@@ -1,150 +1,4 @@...@@ -1,150 +1,4 @@
1extern "c" fn __errno() *c_int;1extern "c" fn __errno() *c_int;
2pub const _errno = __errno;2pub const _errno = __errno;
33
4pub extern "c" fn kqueue() c_int;
5pub extern "c" fn kevent(
6 kq: c_int,
7 changelist: [*]const Kevent,
8 nchanges: c_int,
9 eventlist: [*]Kevent,
10 nevents: c_int,
11 timeout: ?*const timespec,
12) c_int;
13pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
14pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
15pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int;
16pub extern "c" fn getdirentries(fd: c_int, buf_ptr: [*]u8, nbytes: usize, basep: *i64) usize;
17pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize;4pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize;
18pub extern "c" fn pipe2(arg0: *[2]c_int, arg1: u32) c_int;
19pub extern "c" fn preadv(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize;
20pub extern "c" fn pwritev(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize;
21pub extern "c" fn openat(fd: c_int, path: ?[*]const u8, flags: c_int) c_int;
22pub extern "c" fn setgid(ruid: c_uint, euid: c_uint) c_int;
23pub extern "c" fn setuid(uid: c_uint) c_int;
24pub extern "c" fn kill(pid: c_int, sig: c_int) c_int;
25pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int;
26pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int;
27
28/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
29pub const Kevent = extern struct {
30 ident: usize,
31 filter: i32,
32 flags: u32,
33 fflags: u32,
34 data: i64,
35 udata: usize,
36};
37
38pub const pthread_attr_t = extern struct {
39 pta_magic: u32,
40 pta_flags: c_int,
41 pta_private: *c_void,
42};
43
44pub const msghdr = extern struct {
45 /// optional address
46 msg_name: ?*sockaddr,
47
48 /// size of address
49 msg_namelen: socklen_t,
50
51 /// scatter/gather array
52 msg_iov: [*]iovec,
53
54 /// # elements in msg_iov
55 msg_iovlen: i32,
56
57 /// ancillary data
58 msg_control: ?*c_void,
59
60 /// ancillary data buffer len
61 msg_controllen: socklen_t,
62
63 /// flags on received message
64 msg_flags: i32,
65};
66
67pub const msghdr_const = extern struct {
68 /// optional address
69 msg_name: ?*const sockaddr,
70
71 /// size of address
72 msg_namelen: socklen_t,
73
74 /// scatter/gather array
75 msg_iov: [*]iovec_const,
76
77 /// # elements in msg_iov
78 msg_iovlen: i32,
79
80 /// ancillary data
81 msg_control: ?*c_void,
82
83 /// ancillary data buffer len
84 msg_controllen: socklen_t,
85
86 /// flags on received message
87 msg_flags: i32,
88};
89
90pub const Stat = extern struct {
91 dev: u64,
92 mode: u32,
93 ino: u64,
94 nlink: usize,
95
96 uid: u32,
97 gid: u32,
98 rdev: u64,
99
100 atim: timespec,
101 mtim: timespec,
102 ctim: timespec,
103 birthtim: timespec,
104
105 size: i64,
106 blocks: i64,
107 blksize: isize,
108 flags: u32,
109 gen: u32,
110 __spare: [2]u32,
111};
112
113pub const timespec = extern struct {
114 tv_sec: i64,
115 tv_nsec: isize,
116};
117
118pub const dirent = extern struct {
119 d_fileno: u64,
120 d_reclen: u16,
121 d_namlen: u16,
122 d_type: u8,
123 d_off: i64,
124 d_name: [512]u8,
125};
126
127pub const in_port_t = u16;
128pub const sa_family_t = u8;
129
130pub const sockaddr = extern union {
131 in: sockaddr_in,
132 in6: sockaddr_in6,
133};
134
135pub const sockaddr_in = extern struct {
136 len: u8,
137 family: sa_family_t,
138 port: in_port_t,
139 addr: u32,
140 zero: [8]u8,
141};
142
143pub const sockaddr_in6 = extern struct {
144 len: u8,
145 family: sa_family_t,
146 port: in_port_t,
147 flowinfo: u32,
148 addr: [16]u8,
149 scope_id: u32,
150};
std/child_process.zig created+763
...@@ -0,0 +1,763 @@
1const std = @import("std.zig");
2const cstr = std.cstr;
3const unicode = std.unicode;
4const io = std.io;
5const fs = std.fs;
6const os = std.os;
7const process = std.process;
8const File = std.fs.File;
9const windows = os.windows;
10const mem = std.mem;
11const debug = std.debug;
12const BufMap = std.BufMap;
13const Buffer = std.Buffer;
14const builtin = @import("builtin");
15const Os = builtin.Os;
16const LinkedList = std.LinkedList;
17const maxInt = std.math.maxInt;
18
19pub const ChildProcess = struct {
20 pub pid: if (os.windows.is_the_target) void else i32,
21 pub handle: if (os.windows.is_the_target) windows.HANDLE else void,
22 pub thread_handle: if (os.windows.is_the_target) windows.HANDLE else void,
23
24 pub allocator: *mem.Allocator,
25
26 pub stdin: ?File,
27 pub stdout: ?File,
28 pub stderr: ?File,
29
30 pub term: ?(SpawnError!Term),
31
32 pub argv: []const []const u8,
33
34 /// Leave as null to use the current env map using the supplied allocator.
35 pub env_map: ?*const BufMap,
36
37 pub stdin_behavior: StdIo,
38 pub stdout_behavior: StdIo,
39 pub stderr_behavior: StdIo,
40
41 /// Set to change the user id when spawning the child process.
42 pub uid: if (os.windows.is_the_target) void else ?u32,
43
44 /// Set to change the group id when spawning the child process.
45 pub gid: if (os.windows.is_the_target) void else ?u32,
46
47 /// Set to change the current working directory when spawning the child process.
48 pub cwd: ?[]const u8,
49
50 err_pipe: if (os.windows.is_the_target) void else [2]os.fd_t,
51 llnode: if (os.windows.is_the_target) void else LinkedList(*ChildProcess).Node,
52
53 pub const SpawnError = error{OutOfMemory} || os.ExecveError || os.SetIdError ||
54 os.ChangeCurDirError || windows.CreateProcessError;
55
56 pub const Term = union(enum) {
57 Exited: u32,
58 Signal: u32,
59 Stopped: u32,
60 Unknown: u32,
61 };
62
63 pub const StdIo = enum {
64 Inherit,
65 Ignore,
66 Pipe,
67 Close,
68 };
69
70 /// First argument in argv is the executable.
71 /// On success must call deinit.
72 pub fn init(argv: []const []const u8, allocator: *mem.Allocator) !*ChildProcess {
73 const child = try allocator.create(ChildProcess);
74 child.* = ChildProcess{
75 .allocator = allocator,
76 .argv = argv,
77 .pid = undefined,
78 .handle = undefined,
79 .thread_handle = undefined,
80 .err_pipe = undefined,
81 .llnode = undefined,
82 .term = null,
83 .env_map = null,
84 .cwd = null,
85 .uid = if (os.windows.is_the_target) {} else null,
86 .gid = if (os.windows.is_the_target) {} else null,
87 .stdin = null,
88 .stdout = null,
89 .stderr = null,
90 .stdin_behavior = StdIo.Inherit,
91 .stdout_behavior = StdIo.Inherit,
92 .stderr_behavior = StdIo.Inherit,
93 };
94 errdefer allocator.destroy(child);
95 return child;
96 }
97
98 pub fn setUserName(self: *ChildProcess, name: []const u8) !void {
99 const user_info = try os.getUserInfo(name);
100 self.uid = user_info.uid;
101 self.gid = user_info.gid;
102 }
103
104 /// On success must call `kill` or `wait`.
105 pub fn spawn(self: *ChildProcess) !void {
106 if (os.windows.is_the_target) {
107 return self.spawnWindows();
108 } else {
109 return self.spawnPosix();
110 }
111 }
112
113 pub fn spawnAndWait(self: *ChildProcess) !Term {
114 try self.spawn();
115 return self.wait();
116 }
117
118 /// Forcibly terminates child process and then cleans up all resources.
119 pub fn kill(self: *ChildProcess) !Term {
120 if (os.windows.is_the_target) {
121 return self.killWindows(1);
122 } else {
123 return self.killPosix();
124 }
125 }
126
127 pub fn killWindows(self: *ChildProcess, exit_code: windows.UINT) !Term {
128 if (self.term) |term| {
129 self.cleanupStreams();
130 return term;
131 }
132
133 try windows.TerminateProcess(self.handle, exit_code);
134 try self.waitUnwrappedWindows();
135 return self.term.?;
136 }
137
138 pub fn killPosix(self: *ChildProcess) !Term {
139 if (self.term) |term| {
140 self.cleanupStreams();
141 return term;
142 }
143 try os.kill(self.pid, os.SIGTERM);
144 self.waitUnwrapped();
145 return self.term.?;
146 }
147
148 /// Blocks until child process terminates and then cleans up all resources.
149 pub fn wait(self: *ChildProcess) !Term {
150 if (os.windows.is_the_target) {
151 return self.waitWindows();
152 } else {
153 return self.waitPosix();
154 }
155 }
156
157 pub const ExecResult = struct {
158 term: Term,
159 stdout: []u8,
160 stderr: []u8,
161 };
162
163 /// Spawns a child process, waits for it, collecting stdout and stderr, and then returns.
164 /// If it succeeds, the caller owns result.stdout and result.stderr memory.
165 pub fn exec(allocator: *mem.Allocator, argv: []const []const u8, cwd: ?[]const u8, env_map: ?*const BufMap, max_output_size: usize) !ExecResult {
166 const child = try ChildProcess.init(argv, allocator);
167 defer child.deinit();
168
169 child.stdin_behavior = ChildProcess.StdIo.Ignore;
170 child.stdout_behavior = ChildProcess.StdIo.Pipe;
171 child.stderr_behavior = ChildProcess.StdIo.Pipe;
172 child.cwd = cwd;
173 child.env_map = env_map;
174
175 try child.spawn();
176
177 var stdout = Buffer.initNull(allocator);
178 var stderr = Buffer.initNull(allocator);
179 defer Buffer.deinit(&stdout);
180 defer Buffer.deinit(&stderr);
181
182 var stdout_file_in_stream = child.stdout.?.inStream();
183 var stderr_file_in_stream = child.stderr.?.inStream();
184
185 try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);
186 try stderr_file_in_stream.stream.readAllBuffer(&stderr, max_output_size);
187
188 return ExecResult{
189 .term = try child.wait(),
190 .stdout = stdout.toOwnedSlice(),
191 .stderr = stderr.toOwnedSlice(),
192 };
193 }
194
195 fn waitWindows(self: *ChildProcess) !Term {
196 if (self.term) |term| {
197 self.cleanupStreams();
198 return term;
199 }
200
201 try self.waitUnwrappedWindows();
202 return self.term.?;
203 }
204
205 fn waitPosix(self: *ChildProcess) !Term {
206 if (self.term) |term| {
207 self.cleanupStreams();
208 return term;
209 }
210
211 self.waitUnwrapped();
212 return self.term.?;
213 }
214
215 pub fn deinit(self: *ChildProcess) void {
216 self.allocator.destroy(self);
217 }
218
219 fn waitUnwrappedWindows(self: *ChildProcess) !void {
220 const result = windows.WaitForSingleObject(self.handle, windows.INFINITE);
221
222 self.term = (SpawnError!Term)(x: {
223 var exit_code: windows.DWORD = undefined;
224 if (windows.kernel32.GetExitCodeProcess(self.handle, &exit_code) == 0) {
225 break :x Term{ .Unknown = 0 };
226 } else {
227 break :x Term{ .Exited = exit_code };
228 }
229 });
230
231 os.close(self.handle);
232 os.close(self.thread_handle);
233 self.cleanupStreams();
234 return result;
235 }
236
237 fn waitUnwrapped(self: *ChildProcess) void {
238 const status = os.waitpid(self.pid, 0);
239 self.cleanupStreams();
240 self.handleWaitResult(status);
241 }
242
243 fn handleWaitResult(self: *ChildProcess, status: u32) void {
244 self.term = self.cleanupAfterWait(status);
245 }
246
247 fn cleanupStreams(self: *ChildProcess) void {
248 if (self.stdin) |*stdin| {
249 stdin.close();
250 self.stdin = null;
251 }
252 if (self.stdout) |*stdout| {
253 stdout.close();
254 self.stdout = null;
255 }
256 if (self.stderr) |*stderr| {
257 stderr.close();
258 self.stderr = null;
259 }
260 }
261
262 fn cleanupAfterWait(self: *ChildProcess, status: u32) !Term {
263 defer {
264 os.close(self.err_pipe[0]);
265 os.close(self.err_pipe[1]);
266 }
267
268 // Write maxInt(ErrInt) to the write end of the err_pipe. This is after
269 // waitpid, so this write is guaranteed to be after the child
270 // pid potentially wrote an error. This way we can do a blocking
271 // read on the error pipe and either get maxInt(ErrInt) (no error) or
272 // an error code.
273 try writeIntFd(self.err_pipe[1], maxInt(ErrInt));
274 const err_int = try readIntFd(self.err_pipe[0]);
275 // Here we potentially return the fork child's error
276 // from the parent pid.
277 if (err_int != maxInt(ErrInt)) {
278 return @errSetCast(SpawnError, @intToError(err_int));
279 }
280
281 return statusToTerm(status);
282 }
283
284 fn statusToTerm(status: u32) Term {
285 return if (os.WIFEXITED(status))
286 Term{ .Exited = os.WEXITSTATUS(status) }
287 else if (os.WIFSIGNALED(status))
288 Term{ .Signal = os.WTERMSIG(status) }
289 else if (os.WIFSTOPPED(status))
290 Term{ .Stopped = os.WSTOPSIG(status) }
291 else
292 Term{ .Unknown = status };
293 }
294
295 fn spawnPosix(self: *ChildProcess) !void {
296 const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try os.pipe() else undefined;
297 errdefer if (self.stdin_behavior == StdIo.Pipe) {
298 destroyPipe(stdin_pipe);
299 };
300
301 const stdout_pipe = if (self.stdout_behavior == StdIo.Pipe) try os.pipe() else undefined;
302 errdefer if (self.stdout_behavior == StdIo.Pipe) {
303 destroyPipe(stdout_pipe);
304 };
305
306 const stderr_pipe = if (self.stderr_behavior == StdIo.Pipe) try os.pipe() else undefined;
307 errdefer if (self.stderr_behavior == StdIo.Pipe) {
308 destroyPipe(stderr_pipe);
309 };
310
311 const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
312 const dev_null_fd = if (any_ignore) try os.openC(c"/dev/null", os.O_RDWR, 0) else undefined;
313 defer {
314 if (any_ignore) os.close(dev_null_fd);
315 }
316
317 var env_map_owned: BufMap = undefined;
318 var we_own_env_map: bool = undefined;
319 const env_map = if (self.env_map) |env_map| x: {
320 we_own_env_map = false;
321 break :x env_map;
322 } else x: {
323 we_own_env_map = true;
324 env_map_owned = try process.getEnvMap(self.allocator);
325 break :x &env_map_owned;
326 };
327 defer {
328 if (we_own_env_map) env_map_owned.deinit();
329 }
330
331 // This pipe is used to communicate errors between the time of fork
332 // and execve from the child process to the parent process.
333 const err_pipe = try os.pipe();
334 errdefer destroyPipe(err_pipe);
335
336 const pid_result = try os.fork();
337 if (pid_result == 0) {
338 // we are the child
339 setUpChildIo(self.stdin_behavior, stdin_pipe[0], os.STDIN_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
340 setUpChildIo(self.stdout_behavior, stdout_pipe[1], os.STDOUT_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
341 setUpChildIo(self.stderr_behavior, stderr_pipe[1], os.STDERR_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
342
343 if (self.stdin_behavior == .Pipe) {
344 os.close(stdin_pipe[0]);
345 os.close(stdin_pipe[1]);
346 }
347 if (self.stdout_behavior == .Pipe) {
348 os.close(stdout_pipe[0]);
349 os.close(stdout_pipe[1]);
350 }
351 if (self.stderr_behavior == .Pipe) {
352 os.close(stderr_pipe[0]);
353 os.close(stderr_pipe[1]);
354 }
355
356 if (self.cwd) |cwd| {
357 os.chdir(cwd) catch |err| forkChildErrReport(err_pipe[1], err);
358 }
359
360 if (self.gid) |gid| {
361 os.setregid(gid, gid) catch |err| forkChildErrReport(err_pipe[1], err);
362 }
363
364 if (self.uid) |uid| {
365 os.setreuid(uid, uid) catch |err| forkChildErrReport(err_pipe[1], err);
366 }
367
368 os.execve(self.allocator, self.argv, env_map) catch |err| forkChildErrReport(err_pipe[1], err);
369 }
370
371 // we are the parent
372 const pid = @intCast(i32, pid_result);
373 if (self.stdin_behavior == StdIo.Pipe) {
374 self.stdin = File.openHandle(stdin_pipe[1]);
375 } else {
376 self.stdin = null;
377 }
378 if (self.stdout_behavior == StdIo.Pipe) {
379 self.stdout = File.openHandle(stdout_pipe[0]);
380 } else {
381 self.stdout = null;
382 }
383 if (self.stderr_behavior == StdIo.Pipe) {
384 self.stderr = File.openHandle(stderr_pipe[0]);
385 } else {
386 self.stderr = null;
387 }
388
389 self.pid = pid;
390 self.err_pipe = err_pipe;
391 self.llnode = LinkedList(*ChildProcess).Node.init(self);
392 self.term = null;
393
394 if (self.stdin_behavior == StdIo.Pipe) {
395 os.close(stdin_pipe[0]);
396 }
397 if (self.stdout_behavior == StdIo.Pipe) {
398 os.close(stdout_pipe[1]);
399 }
400 if (self.stderr_behavior == StdIo.Pipe) {
401 os.close(stderr_pipe[1]);
402 }
403 }
404
405 fn spawnWindows(self: *ChildProcess) !void {
406 const saAttr = windows.SECURITY_ATTRIBUTES{
407 .nLength = @sizeOf(windows.SECURITY_ATTRIBUTES),
408 .bInheritHandle = windows.TRUE,
409 .lpSecurityDescriptor = null,
410 };
411
412 const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
413
414 const nul_handle = if (any_ignore) blk: {
415 break :blk try windows.CreateFile("NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ, null, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL, null);
416 } else blk: {
417 break :blk undefined;
418 };
419 defer {
420 if (any_ignore) os.close(nul_handle);
421 }
422 if (any_ignore) {
423 try windows.SetHandleInformation(nul_handle, windows.HANDLE_FLAG_INHERIT, 0);
424 }
425
426 var g_hChildStd_IN_Rd: ?windows.HANDLE = null;
427 var g_hChildStd_IN_Wr: ?windows.HANDLE = null;
428 switch (self.stdin_behavior) {
429 StdIo.Pipe => {
430 try windowsMakePipeIn(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr);
431 },
432 StdIo.Ignore => {
433 g_hChildStd_IN_Rd = nul_handle;
434 },
435 StdIo.Inherit => {
436 g_hChildStd_IN_Rd = windows.GetStdHandle(windows.STD_INPUT_HANDLE) catch null;
437 },
438 StdIo.Close => {
439 g_hChildStd_IN_Rd = null;
440 },
441 }
442 errdefer if (self.stdin_behavior == StdIo.Pipe) {
443 windowsDestroyPipe(g_hChildStd_IN_Rd, g_hChildStd_IN_Wr);
444 };
445
446 var g_hChildStd_OUT_Rd: ?windows.HANDLE = null;
447 var g_hChildStd_OUT_Wr: ?windows.HANDLE = null;
448 switch (self.stdout_behavior) {
449 StdIo.Pipe => {
450 try windowsMakePipeOut(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr);
451 },
452 StdIo.Ignore => {
453 g_hChildStd_OUT_Wr = nul_handle;
454 },
455 StdIo.Inherit => {
456 g_hChildStd_OUT_Wr = windows.GetStdHandle(windows.STD_OUTPUT_HANDLE) catch null;
457 },
458 StdIo.Close => {
459 g_hChildStd_OUT_Wr = null;
460 },
461 }
462 errdefer if (self.stdin_behavior == StdIo.Pipe) {
463 windowsDestroyPipe(g_hChildStd_OUT_Rd, g_hChildStd_OUT_Wr);
464 };
465
466 var g_hChildStd_ERR_Rd: ?windows.HANDLE = null;
467 var g_hChildStd_ERR_Wr: ?windows.HANDLE = null;
468 switch (self.stderr_behavior) {
469 StdIo.Pipe => {
470 try windowsMakePipeOut(&g_hChildStd_ERR_Rd, &g_hChildStd_ERR_Wr, &saAttr);
471 },
472 StdIo.Ignore => {
473 g_hChildStd_ERR_Wr = nul_handle;
474 },
475 StdIo.Inherit => {
476 g_hChildStd_ERR_Wr = windows.GetStdHandle(windows.STD_ERROR_HANDLE) catch null;
477 },
478 StdIo.Close => {
479 g_hChildStd_ERR_Wr = null;
480 },
481 }
482 errdefer if (self.stdin_behavior == StdIo.Pipe) {
483 windowsDestroyPipe(g_hChildStd_ERR_Rd, g_hChildStd_ERR_Wr);
484 };
485
486 const cmd_line = try windowsCreateCommandLine(self.allocator, self.argv);
487 defer self.allocator.free(cmd_line);
488
489 var siStartInfo = windows.STARTUPINFOW{
490 .cb = @sizeOf(windows.STARTUPINFOW),
491 .hStdError = g_hChildStd_ERR_Wr,
492 .hStdOutput = g_hChildStd_OUT_Wr,
493 .hStdInput = g_hChildStd_IN_Rd,
494 .dwFlags = windows.STARTF_USESTDHANDLES,
495
496 .lpReserved = null,
497 .lpDesktop = null,
498 .lpTitle = null,
499 .dwX = 0,
500 .dwY = 0,
501 .dwXSize = 0,
502 .dwYSize = 0,
503 .dwXCountChars = 0,
504 .dwYCountChars = 0,
505 .dwFillAttribute = 0,
506 .wShowWindow = 0,
507 .cbReserved2 = 0,
508 .lpReserved2 = null,
509 };
510 var piProcInfo: windows.PROCESS_INFORMATION = undefined;
511
512 const cwd_slice = if (self.cwd) |cwd| try cstr.addNullByte(self.allocator, cwd) else null;
513 defer if (cwd_slice) |cwd| self.allocator.free(cwd);
514 const cwd_w = if (cwd_slice) |cwd| try unicode.utf8ToUtf16LeWithNull(self.allocator, cwd) else null;
515 defer if (cwd_w) |cwd| self.allocator.free(cwd);
516 const cwd_w_ptr = if (cwd_w) |cwd| cwd.ptr else null;
517
518 const maybe_envp_buf = if (self.env_map) |env_map| try createWindowsEnvBlock(self.allocator, env_map) else null;
519 defer if (maybe_envp_buf) |envp_buf| self.allocator.free(envp_buf);
520 const envp_ptr = if (maybe_envp_buf) |envp_buf| envp_buf.ptr else null;
521
522 // the cwd set in ChildProcess is in effect when choosing the executable path
523 // to match posix semantics
524 const app_name = x: {
525 if (self.cwd) |cwd| {
526 const resolved = try fs.path.resolve(self.allocator, [][]const u8{ cwd, self.argv[0] });
527 defer self.allocator.free(resolved);
528 break :x try cstr.addNullByte(self.allocator, resolved);
529 } else {
530 break :x try cstr.addNullByte(self.allocator, self.argv[0]);
531 }
532 };
533 defer self.allocator.free(app_name);
534
535 const app_name_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, app_name);
536 defer self.allocator.free(app_name_w);
537
538 const cmd_line_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, cmd_line);
539 defer self.allocator.free(cmd_line_w);
540
541 windowsCreateProcess(app_name_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo) catch |no_path_err| {
542 if (no_path_err != error.FileNotFound) return no_path_err;
543
544 const PATH = try process.getEnvVarOwned(self.allocator, "PATH");
545 defer self.allocator.free(PATH);
546
547 var it = mem.tokenize(PATH, ";");
548 while (it.next()) |search_path| {
549 const joined_path = try fs.path.join(self.allocator, [][]const u8{ search_path, app_name });
550 defer self.allocator.free(joined_path);
551
552 const joined_path_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, joined_path);
553 defer self.allocator.free(joined_path_w);
554
555 if (windowsCreateProcess(joined_path_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo)) |_| {
556 break;
557 } else |err| if (err == error.FileNotFound) {
558 continue;
559 } else {
560 return err;
561 }
562 } else {
563 // Every other error would have been returned earlier.
564 return error.FileNotFound;
565 }
566 };
567
568 if (g_hChildStd_IN_Wr) |h| {
569 self.stdin = File.openHandle(h);
570 } else {
571 self.stdin = null;
572 }
573 if (g_hChildStd_OUT_Rd) |h| {
574 self.stdout = File.openHandle(h);
575 } else {
576 self.stdout = null;
577 }
578 if (g_hChildStd_ERR_Rd) |h| {
579 self.stderr = File.openHandle(h);
580 } else {
581 self.stderr = null;
582 }
583
584 self.handle = piProcInfo.hProcess;
585 self.thread_handle = piProcInfo.hThread;
586 self.term = null;
587
588 if (self.stdin_behavior == StdIo.Pipe) {
589 os.close(g_hChildStd_IN_Rd.?);
590 }
591 if (self.stderr_behavior == StdIo.Pipe) {
592 os.close(g_hChildStd_ERR_Wr.?);
593 }
594 if (self.stdout_behavior == StdIo.Pipe) {
595 os.close(g_hChildStd_OUT_Wr.?);
596 }
597 }
598
599 fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) !void {
600 switch (stdio) {
601 StdIo.Pipe => try os.dup2(pipe_fd, std_fileno),
602 StdIo.Close => os.close(std_fileno),
603 StdIo.Inherit => {},
604 StdIo.Ignore => try os.dup2(dev_null_fd, std_fileno),
605 }
606 }
607};
608
609fn windowsCreateProcess(app_name: [*]u16, cmd_line: [*]u16, envp_ptr: ?[*]u16, cwd_ptr: ?[*]u16, lpStartupInfo: *windows.STARTUPINFOW, lpProcessInformation: *windows.PROCESS_INFORMATION) !void {
610 // TODO the docs for environment pointer say:
611 // > A pointer to the environment block for the new process. If this parameter
612 // > is NULL, the new process uses the environment of the calling process.
613 // > ...
614 // > An environment block can contain either Unicode or ANSI characters. If
615 // > the environment block pointed to by lpEnvironment contains Unicode
616 // > characters, be sure that dwCreationFlags includes CREATE_UNICODE_ENVIRONMENT.
617 // > If this parameter is NULL and the environment block of the parent process
618 // > contains Unicode characters, you must also ensure that dwCreationFlags
619 // > includes CREATE_UNICODE_ENVIRONMENT.
620 // This seems to imply that we have to somehow know whether our process parent passed
621 // CREATE_UNICODE_ENVIRONMENT if we want to pass NULL for the environment parameter.
622 // Since we do not know this information that would imply that we must not pass NULL
623 // for the parameter.
624 // However this would imply that programs compiled with -DUNICODE could not pass
625 // environment variables to programs that were not, which seems unlikely.
626 // More investigation is needed.
627 return windows.CreateProcessW(
628 app_name,
629 cmd_line,
630 null,
631 null,
632 windows.TRUE,
633 windows.CREATE_UNICODE_ENVIRONMENT,
634 @ptrCast(?*c_void, envp_ptr),
635 cwd_ptr,
636 lpStartupInfo,
637 lpProcessInformation,
638 );
639}
640
641/// Caller must dealloc.
642/// Guarantees a null byte at result[result.len].
643fn windowsCreateCommandLine(allocator: *mem.Allocator, argv: []const []const u8) ![]u8 {
644 var buf = try Buffer.initSize(allocator, 0);
645 defer buf.deinit();
646
647 var buf_stream = &io.BufferOutStream.init(&buf).stream;
648
649 for (argv) |arg, arg_i| {
650 if (arg_i != 0) try buf.appendByte(' ');
651 if (mem.indexOfAny(u8, arg, " \t\n\"") == null) {
652 try buf.append(arg);
653 continue;
654 }
655 try buf.appendByte('"');
656 var backslash_count: usize = 0;
657 for (arg) |byte| {
658 switch (byte) {
659 '\\' => backslash_count += 1,
660 '"' => {
661 try buf_stream.writeByteNTimes('\\', backslash_count * 2 + 1);
662 try buf.appendByte('"');
663 backslash_count = 0;
664 },
665 else => {
666 try buf_stream.writeByteNTimes('\\', backslash_count);
667 try buf.appendByte(byte);
668 backslash_count = 0;
669 },
670 }
671 }
672 try buf_stream.writeByteNTimes('\\', backslash_count * 2);
673 try buf.appendByte('"');
674 }
675
676 return buf.toOwnedSlice();
677}
678
679fn windowsDestroyPipe(rd: ?windows.HANDLE, wr: ?windows.HANDLE) void {
680 if (rd) |h| os.close(h);
681 if (wr) |h| os.close(h);
682}
683
684fn windowsMakePipeIn(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const windows.SECURITY_ATTRIBUTES) !void {
685 var rd_h: windows.HANDLE = undefined;
686 var wr_h: windows.HANDLE = undefined;
687 try windows.CreatePipe(&rd_h, &wr_h, sattr);
688 errdefer windowsDestroyPipe(rd_h, wr_h);
689 try windows.SetHandleInformation(wr_h, windows.HANDLE_FLAG_INHERIT, 0);
690 rd.* = rd_h;
691 wr.* = wr_h;
692}
693
694fn windowsMakePipeOut(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const windows.SECURITY_ATTRIBUTES) !void {
695 var rd_h: windows.HANDLE = undefined;
696 var wr_h: windows.HANDLE = undefined;
697 try windows.CreatePipe(&rd_h, &wr_h, sattr);
698 errdefer windowsDestroyPipe(rd_h, wr_h);
699 try windows.SetHandleInformation(rd_h, windows.HANDLE_FLAG_INHERIT, 0);
700 rd.* = rd_h;
701 wr.* = wr_h;
702}
703
704fn destroyPipe(pipe: [2]os.fd_t) void {
705 os.close(pipe[0]);
706 os.close(pipe[1]);
707}
708
709// Child of fork calls this to report an error to the fork parent.
710// Then the child exits.
711fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {
712 writeIntFd(fd, ErrInt(@errorToInt(err))) catch {};
713 os.exit(1);
714}
715
716const ErrInt = @IntType(false, @sizeOf(anyerror) * 8);
717
718fn writeIntFd(fd: i32, value: ErrInt) !void {
719 const stream = &File.openHandle(fd).outStream().stream;
720 stream.writeIntNative(ErrInt, value) catch return error.SystemResources;
721}
722
723fn readIntFd(fd: i32) !ErrInt {
724 const stream = &File.openHandle(fd).inStream().stream;
725 return stream.readIntNative(ErrInt) catch return error.SystemResources;
726}
727
728/// Caller must free result.
729pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u16 {
730 // count bytes needed
731 const max_chars_needed = x: {
732 var max_chars_needed: usize = 4; // 4 for the final 4 null bytes
733 var it = env_map.iterator();
734 while (it.next()) |pair| {
735 // +1 for '='
736 // +1 for null byte
737 max_chars_needed += pair.key.len + pair.value.len + 2;
738 }
739 break :x max_chars_needed;
740 };
741 const result = try allocator.alloc(u16, max_chars_needed);
742 errdefer allocator.free(result);
743
744 var it = env_map.iterator();
745 var i: usize = 0;
746 while (it.next()) |pair| {
747 i += try unicode.utf8ToUtf16Le(result[i..], pair.key);
748 result[i] = '=';
749 i += 1;
750 i += try unicode.utf8ToUtf16Le(result[i..], pair.value);
751 result[i] = 0;
752 i += 1;
753 }
754 result[i] = 0;
755 i += 1;
756 result[i] = 0;
757 i += 1;
758 result[i] = 0;
759 i += 1;
760 result[i] = 0;
761 i += 1;
762 return allocator.shrink(result, i);
763}
std/coff.zig+4-3
...@@ -3,6 +3,7 @@ const std = @import("std.zig");...@@ -3,6 +3,7 @@ const std = @import("std.zig");
3const io = std.io;3const io = std.io;
4const mem = std.mem;4const mem = std.mem;
5const os = std.os;5const os = std.os;
6const File = std.fs.File;
67
7const ArrayList = std.ArrayList;8const ArrayList = std.ArrayList;
89
...@@ -28,7 +29,7 @@ pub const CoffError = error{...@@ -28,7 +29,7 @@ pub const CoffError = error{
28};29};
2930
30pub const Coff = struct {31pub const Coff = struct {
31 in_file: os.File,32 in_file: File,
32 allocator: *mem.Allocator,33 allocator: *mem.Allocator,
3334
34 coff_header: CoffHeader,35 coff_header: CoffHeader,
...@@ -77,7 +78,7 @@ pub const Coff = struct {...@@ -77,7 +78,7 @@ pub const Coff = struct {
77 try self.loadOptionalHeader(&file_stream);78 try self.loadOptionalHeader(&file_stream);
78 }79 }
7980
80 fn loadOptionalHeader(self: *Coff, file_stream: *os.File.InStream) !void {81 fn loadOptionalHeader(self: *Coff, file_stream: *File.InStream) !void {
81 const in = &file_stream.stream;82 const in = &file_stream.stream;
82 self.pe_header.magic = try in.readIntLittle(u16);83 self.pe_header.magic = try in.readIntLittle(u16);
83 // For now we're only interested in finding the reference to the .pdb,84 // For now we're only interested in finding the reference to the .pdb,
...@@ -91,7 +92,7 @@ pub const Coff = struct {...@@ -91,7 +92,7 @@ pub const Coff = struct {
91 } else92 } else
92 return error.InvalidPEMagic;93 return error.InvalidPEMagic;
9394
94 try self.in_file.seekForward(skip_size);95 try self.in_file.seekBy(skip_size);
9596
96 const number_of_rva_and_sizes = try in.readIntLittle(u32);97 const number_of_rva_and_sizes = try in.readIntLittle(u32);
97 if (number_of_rva_and_sizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)98 if (number_of_rva_and_sizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
std/crypto.zig+3
...@@ -32,6 +32,9 @@ pub const chaCha20With64BitNonce = import_chaCha20.chaCha20With64BitNonce;...@@ -32,6 +32,9 @@ pub const chaCha20With64BitNonce = import_chaCha20.chaCha20With64BitNonce;
32pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305;32pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305;
33pub const X25519 = @import("crypto/x25519.zig").X25519;33pub const X25519 = @import("crypto/x25519.zig").X25519;
3434
35const std = @import("std.zig");
36pub const randomBytes = std.os.getrandom;
37
35test "crypto" {38test "crypto" {
36 _ = @import("crypto/blake2.zig");39 _ = @import("crypto/blake2.zig");
37 _ = @import("crypto/chacha20.zig");40 _ = @import("crypto/chacha20.zig");
std/crypto/throughput_test.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const std = @import("std");2const std = @import("std");
3const time = std.os.time;3const time = std.time;
4const Timer = time.Timer;4const Timer = time.Timer;
5const crypto = @import("../crypto.zig");5const crypto = @import("../crypto.zig");
66
std/cstr.zig+1-16
...@@ -9,11 +9,6 @@ pub const line_sep = switch (builtin.os) {...@@ -9,11 +9,6 @@ pub const line_sep = switch (builtin.os) {
9 else => "\n",9 else => "\n",
10};10};
1111
12/// Deprecated, use mem.len
13pub fn len(ptr: [*]const u8) usize {
14 return mem.len(u8, ptr);
15}
16
17pub fn cmp(a: [*]const u8, b: [*]const u8) i8 {12pub fn cmp(a: [*]const u8, b: [*]const u8) i8 {
18 var index: usize = 0;13 var index: usize = 0;
19 while (a[index] == b[index] and a[index] != 0) : (index += 1) {}14 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 {...@@ -26,16 +21,6 @@ pub fn cmp(a: [*]const u8, b: [*]const u8) i8 {
26 }21 }
27}22}
2823
29/// Deprecated, use mem.toSliceConst
30pub fn toSliceConst(str: [*]const u8) []const u8 {
31 return mem.toSliceConst(u8, str);
32}
33
34/// Deprecated, use mem.toSlice
35pub fn toSlice(str: [*]u8) []u8 {
36 return mem.toSlice(u8, str);
37}
38
39test "cstr fns" {24test "cstr fns" {
40 comptime testCStrFnsImpl();25 comptime testCStrFnsImpl();
41 testCStrFnsImpl();26 testCStrFnsImpl();
...@@ -43,7 +28,7 @@ test "cstr fns" {...@@ -43,7 +28,7 @@ test "cstr fns" {
4328
44fn testCStrFnsImpl() void {29fn testCStrFnsImpl() void {
45 testing.expect(cmp(c"aoeu", c"aoez") == -1);30 testing.expect(cmp(c"aoeu", c"aoez") == -1);
46 testing.expect(len(c"123456789") == 9);31 testing.expect(mem.len(u8, c"123456789") == 9);
47}32}
4833
49/// Returns a mutable slice with 1 more byte of length which is a null byte.34/// Returns a mutable slice with 1 more byte of length which is a null byte.
std/debug.zig+103-96
...@@ -3,15 +3,18 @@ const math = std.math;...@@ -3,15 +3,18 @@ const math = std.math;
3const mem = std.mem;3const mem = std.mem;
4const io = std.io;4const io = std.io;
5const os = std.os;5const os = std.os;
6const fs = std.fs;
7const process = std.process;
6const elf = std.elf;8const elf = std.elf;
7const DW = std.dwarf;9const DW = std.dwarf;
8const macho = std.macho;10const macho = std.macho;
9const coff = std.coff;11const coff = std.coff;
10const pdb = std.pdb;12const pdb = std.pdb;
11const windows = os.windows;
12const ArrayList = std.ArrayList;13const ArrayList = std.ArrayList;
13const builtin = @import("builtin");14const builtin = @import("builtin");
14const maxInt = std.math.maxInt;15const maxInt = std.math.maxInt;
16const File = std.fs.File;
17const windows = std.os.windows;
1518
16const leb = @import("debug/leb128.zig");19const leb = @import("debug/leb128.zig");
1720
...@@ -19,8 +22,8 @@ pub const FailingAllocator = @import("debug/failing_allocator.zig").FailingAlloc...@@ -19,8 +22,8 @@ pub const FailingAllocator = @import("debug/failing_allocator.zig").FailingAlloc
19pub const failing_allocator = &FailingAllocator.init(global_allocator, 0).allocator;22pub const failing_allocator = &FailingAllocator.init(global_allocator, 0).allocator;
2023
21pub const runtime_safety = switch (builtin.mode) {24pub const runtime_safety = switch (builtin.mode) {
22 builtin.Mode.Debug, builtin.Mode.ReleaseSafe => true,25 .Debug, .ReleaseSafe => true,
23 builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => false,26 .ReleaseFast, .ReleaseSmall => false,
24};27};
2528
26const Module = struct {29const Module = struct {
...@@ -36,10 +39,10 @@ const Module = struct {...@@ -36,10 +39,10 @@ const Module = struct {
3639
37/// Tries to write to stderr, unbuffered, and ignores any error returned.40/// Tries to write to stderr, unbuffered, and ignores any error returned.
38/// Does not append a newline.41/// Does not append a newline.
39var stderr_file: os.File = undefined;42var stderr_file: File = undefined;
40var stderr_file_out_stream: os.File.OutStream = undefined;43var stderr_file_out_stream: File.OutStream = undefined;
4144
42var stderr_stream: ?*io.OutStream(os.File.WriteError) = null;45var stderr_stream: ?*io.OutStream(File.WriteError) = null;
43var stderr_mutex = std.Mutex.init();46var stderr_mutex = std.Mutex.init();
44pub fn warn(comptime fmt: []const u8, args: ...) void {47pub fn warn(comptime fmt: []const u8, args: ...) void {
45 const held = stderr_mutex.acquire();48 const held = stderr_mutex.acquire();
...@@ -48,7 +51,7 @@ pub fn warn(comptime fmt: []const u8, args: ...) void {...@@ -48,7 +51,7 @@ pub fn warn(comptime fmt: []const u8, args: ...) void {
48 stderr.print(fmt, args) catch return;51 stderr.print(fmt, args) catch return;
49}52}
5053
51pub fn getStderrStream() !*io.OutStream(os.File.WriteError) {54pub fn getStderrStream() !*io.OutStream(File.WriteError) {
52 if (stderr_stream) |st| {55 if (stderr_stream) |st| {
53 return st;56 return st;
54 } else {57 } else {
...@@ -75,13 +78,17 @@ pub fn getSelfDebugInfo() !*DebugInfo {...@@ -75,13 +78,17 @@ pub fn getSelfDebugInfo() !*DebugInfo {
75fn wantTtyColor() bool {78fn wantTtyColor() bool {
76 var bytes: [128]u8 = undefined;79 var bytes: [128]u8 = undefined;
77 const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;80 const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
78 return if (std.os.getEnvVarOwned(allocator, "ZIG_DEBUG_COLOR")) |_| true else |_| stderr_file.isTty();81 return if (process.getEnvVarOwned(allocator, "ZIG_DEBUG_COLOR")) |_| true else |_| stderr_file.isTty();
79}82}
8083
81/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.84/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
82/// TODO multithreaded awareness85/// TODO multithreaded awareness
83pub fn dumpCurrentStackTrace(start_addr: ?usize) void {86pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
84 const stderr = getStderrStream() catch return;87 const stderr = getStderrStream() catch return;
88 if (os.wasi.is_the_target) {
89 stderr.print("Unable to dump stack trace: unimplemented on WASI\n") catch return;
90 return;
91 }
85 const debug_info = getSelfDebugInfo() catch |err| {92 const debug_info = getSelfDebugInfo() catch |err| {
86 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;93 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
87 return;94 return;
...@@ -99,47 +106,44 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {...@@ -99,47 +106,44 @@ pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
99/// chopping off the irrelevant frames and shifting so that the returned addresses pointer106/// chopping off the irrelevant frames and shifting so that the returned addresses pointer
100/// equals the passed in addresses pointer.107/// equals the passed in addresses pointer.
101pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void {108pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void {
102 switch (builtin.os) {109 if (windows.is_the_target) {
103 builtin.Os.windows => {110 const addrs = stack_trace.instruction_addresses;
104 const addrs = stack_trace.instruction_addresses;111 const u32_addrs_len = @intCast(u32, addrs.len);
105 const u32_addrs_len = @intCast(u32, addrs.len);112 const first_addr = first_address orelse {
106 const first_addr = first_address orelse {113 stack_trace.index = windows.ntdll.RtlCaptureStackBackTrace(
107 stack_trace.index = windows.RtlCaptureStackBackTrace(114 0,
108 0,115 u32_addrs_len,
109 u32_addrs_len,116 @ptrCast(**c_void, addrs.ptr),
110 @ptrCast(**c_void, addrs.ptr),117 null,
111 null,118 );
112 );119 return;
113 return;120 };
114 };121 var addr_buf_stack: [32]usize = undefined;
115 var addr_buf_stack: [32]usize = undefined;122 const addr_buf = if (addr_buf_stack.len > addrs.len) addr_buf_stack[0..] else addrs;
116 const addr_buf = if (addr_buf_stack.len > addrs.len) addr_buf_stack[0..] else addrs;123 const n = windows.ntdll.RtlCaptureStackBackTrace(0, u32_addrs_len, @ptrCast(**c_void, addr_buf.ptr), null);
117 const n = windows.RtlCaptureStackBackTrace(0, u32_addrs_len, @ptrCast(**c_void, addr_buf.ptr), null);124 const first_index = for (addr_buf[0..n]) |addr, i| {
118 const first_index = for (addr_buf[0..n]) |addr, i| {125 if (addr == first_addr) {
119 if (addr == first_addr) {126 break i;
120 break i;127 }
121 }128 } else {
122 } else {129 stack_trace.index = 0;
123 stack_trace.index = 0;130 return;
131 };
132 const slice = addr_buf[first_index..n];
133 // We use a for loop here because slice and addrs may alias.
134 for (slice) |addr, i| {
135 addrs[i] = addr;
136 }
137 stack_trace.index = slice.len;
138 } else {
139 var it = StackIterator.init(first_address);
140 for (stack_trace.instruction_addresses) |*addr, i| {
141 addr.* = it.next() orelse {
142 stack_trace.index = i;
124 return;143 return;
125 };144 };
126 const slice = addr_buf[first_index..n];145 }
127 // We use a for loop here because slice and addrs may alias.146 stack_trace.index = stack_trace.instruction_addresses.len;
128 for (slice) |addr, i| {
129 addrs[i] = addr;
130 }
131 stack_trace.index = slice.len;
132 },
133 else => {
134 var it = StackIterator.init(first_address);
135 for (stack_trace.instruction_addresses) |*addr, i| {
136 addr.* = it.next() orelse {
137 stack_trace.index = i;
138 return;
139 };
140 }
141 stack_trace.index = stack_trace.instruction_addresses.len;
142 },
143 }147 }
144}148}
145149
...@@ -147,6 +151,10 @@ pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace...@@ -147,6 +151,10 @@ pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace
147/// TODO multithreaded awareness151/// TODO multithreaded awareness
148pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void {152pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void {
149 const stderr = getStderrStream() catch return;153 const stderr = getStderrStream() catch return;
154 if (os.wasi.is_the_target) {
155 stderr.print("Unable to dump stack trace: unimplemented on WASI\n") catch return;
156 return;
157 }
150 const debug_info = getSelfDebugInfo() catch |err| {158 const debug_info = getSelfDebugInfo() catch |err| {
151 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;159 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", @errorName(err)) catch return;
152 return;160 return;
...@@ -259,9 +267,8 @@ pub const StackIterator = struct {...@@ -259,9 +267,8 @@ pub const StackIterator = struct {
259};267};
260268
261pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {269pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {
262 switch (builtin.os) {270 if (windows.is_the_target) {
263 builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr),271 return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr);
264 else => {},
265 }272 }
266 var it = StackIterator.init(start_addr);273 var it = StackIterator.init(start_addr);
267 while (it.next()) |return_address| {274 while (it.next()) |return_address| {
...@@ -276,7 +283,7 @@ pub fn writeCurrentStackTraceWindows(...@@ -276,7 +283,7 @@ pub fn writeCurrentStackTraceWindows(
276 start_addr: ?usize,283 start_addr: ?usize,
277) !void {284) !void {
278 var addr_buf: [1024]usize = undefined;285 var addr_buf: [1024]usize = undefined;
279 const n = windows.RtlCaptureStackBackTrace(0, addr_buf.len, @ptrCast(**c_void, &addr_buf), null);286 const n = windows.ntdll.RtlCaptureStackBackTrace(0, addr_buf.len, @ptrCast(**c_void, &addr_buf), null);
280 const addrs = addr_buf[0..n];287 const addrs = addr_buf[0..n];
281 var start_i: usize = if (start_addr) |saddr| blk: {288 var start_i: usize = if (start_addr) |saddr| blk: {
282 for (addrs) |addr, i| {289 for (addrs) |addr, i| {
...@@ -290,17 +297,18 @@ pub fn writeCurrentStackTraceWindows(...@@ -290,17 +297,18 @@ pub fn writeCurrentStackTraceWindows(
290}297}
291298
292pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {299pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
293 switch (builtin.os) {300 if (windows.is_the_target) {
294 builtin.Os.macosx => return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color),301 return printSourceAtAddressWindows(debug_info, out_stream, address, tty_color);
295 builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => return printSourceAtAddressLinux(debug_info, out_stream, address, tty_color),
296 builtin.Os.windows => return printSourceAtAddressWindows(debug_info, out_stream, address, tty_color),
297 else => return error.UnsupportedOperatingSystem,
298 }302 }
303 if (os.darwin.is_the_target) {
304 return printSourceAtAddressMacOs(debug_info, out_stream, address, tty_color);
305 }
306 return printSourceAtAddressPosix(debug_info, out_stream, address, tty_color);
299}307}
300308
301fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_address: usize, tty_color: bool) !void {309fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_address: usize, tty_color: bool) !void {
302 const allocator = getDebugInfoAllocator();310 const allocator = getDebugInfoAllocator();
303 const base_address = os.getBaseAddress();311 const base_address = process.getBaseAddress();
304 const relative_address = relocated_address - base_address;312 const relative_address = relocated_address - base_address;
305313
306 var coff_section: *coff.Section = undefined;314 var coff_section: *coff.Section = undefined;
...@@ -330,7 +338,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres...@@ -330,7 +338,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
330338
331 const mod = &di.modules[mod_index];339 const mod = &di.modules[mod_index];
332 try populateModule(di, mod);340 try populateModule(di, mod);
333 const obj_basename = os.path.basename(mod.obj_file_name);341 const obj_basename = fs.path.basename(mod.obj_file_name);
334342
335 var symbol_i: usize = 0;343 var symbol_i: usize = 0;
336 const symbol_name = while (symbol_i != mod.symbols.len) {344 const symbol_name = while (symbol_i != mod.symbols.len) {
...@@ -510,7 +518,7 @@ const TtyColor = enum {...@@ -510,7 +518,7 @@ const TtyColor = enum {
510518
511/// TODO this is a special case hack right now. clean it up and maybe make it part of std.fmt519/// TODO this is a special case hack right now. clean it up and maybe make it part of std.fmt
512fn setTtyColor(tty_color: TtyColor) void {520fn setTtyColor(tty_color: TtyColor) void {
513 if (os.supportsAnsiEscapeCodes(stderr_file.handle)) {521 if (stderr_file.supportsAnsiEscapeCodes()) {
514 switch (tty_color) {522 switch (tty_color) {
515 TtyColor.Red => {523 TtyColor.Red => {
516 stderr_file.write(RED) catch return;524 stderr_file.write(RED) catch return;
...@@ -540,29 +548,29 @@ fn setTtyColor(tty_color: TtyColor) void {...@@ -540,29 +548,29 @@ fn setTtyColor(tty_color: TtyColor) void {
540 S.init_attrs = true;548 S.init_attrs = true;
541 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;549 var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
542 // TODO handle error550 // TODO handle error
543 _ = windows.GetConsoleScreenBufferInfo(stderr_file.handle, &info);551 _ = windows.kernel32.GetConsoleScreenBufferInfo(stderr_file.handle, &info);
544 S.attrs = info.wAttributes;552 S.attrs = info.wAttributes;
545 }553 }
546554
547 // TODO handle errors555 // TODO handle errors
548 switch (tty_color) {556 switch (tty_color) {
549 TtyColor.Red => {557 TtyColor.Red => {
550 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY);558 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_INTENSITY) catch {};
551 },559 },
552 TtyColor.Green => {560 TtyColor.Green => {
553 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY);561 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_INTENSITY) catch {};
554 },562 },
555 TtyColor.Cyan => {563 TtyColor.Cyan => {
556 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY);564 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY) catch {};
557 },565 },
558 TtyColor.White, TtyColor.Bold => {566 TtyColor.White, TtyColor.Bold => {
559 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY);567 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_RED | windows.FOREGROUND_GREEN | windows.FOREGROUND_BLUE | windows.FOREGROUND_INTENSITY) catch {};
560 },568 },
561 TtyColor.Dim => {569 TtyColor.Dim => {
562 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_INTENSITY);570 _ = windows.SetConsoleTextAttribute(stderr_file.handle, windows.FOREGROUND_INTENSITY) catch {};
563 },571 },
564 TtyColor.Reset => {572 TtyColor.Reset => {
565 _ = windows.SetConsoleTextAttribute(stderr_file.handle, S.attrs);573 _ = windows.SetConsoleTextAttribute(stderr_file.handle, S.attrs) catch {};
566 },574 },
567 }575 }
568 }576 }
...@@ -633,7 +641,7 @@ fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const Mach...@@ -633,7 +641,7 @@ fn machoSearchSymbols(symbols: []const MachoSymbol, address: usize) ?*const Mach
633}641}
634642
635fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {643fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
636 const base_addr = std.os.getBaseAddress();644 const base_addr = process.getBaseAddress();
637 const adjusted_addr = 0x100000000 + (address - base_addr);645 const adjusted_addr = 0x100000000 + (address - base_addr);
638646
639 const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse {647 const symbol = machoSearchSymbols(di.symbols, adjusted_addr) orelse {
...@@ -648,7 +656,7 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt...@@ -648,7 +656,7 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt
648 const symbol_name = mem.toSliceConst(u8, di.strings.ptr + symbol.nlist.n_strx);656 const symbol_name = mem.toSliceConst(u8, di.strings.ptr + symbol.nlist.n_strx);
649 const compile_unit_name = if (symbol.ofile) |ofile| blk: {657 const compile_unit_name = if (symbol.ofile) |ofile| blk: {
650 const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx);658 const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx);
651 break :blk os.path.basename(ofile_path);659 break :blk fs.path.basename(ofile_path);
652 } else "???";660 } else "???";
653 if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| {661 if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| {
654 defer line_info.deinit();662 defer line_info.deinit();
...@@ -715,7 +723,7 @@ pub fn printSourceAtAddressDwarf(...@@ -715,7 +723,7 @@ pub fn printSourceAtAddressDwarf(
715 }723 }
716}724}
717725
718pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {726pub fn printSourceAtAddressPosix(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
719 return printSourceAtAddressDwarf(debug_info, out_stream, address, tty_color, printLineFromFileAnyOs);727 return printSourceAtAddressDwarf(debug_info, out_stream, address, tty_color, printLineFromFileAnyOs);
720}728}
721729
...@@ -775,16 +783,17 @@ pub const OpenSelfDebugInfoError = error{...@@ -775,16 +783,17 @@ pub const OpenSelfDebugInfoError = error{
775};783};
776784
777pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo {785pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo {
778 switch (builtin.os) {786 if (windows.is_the_target) {
779 builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => return openSelfDebugInfoLinux(allocator),787 return openSelfDebugInfoWindows(allocator);
780 builtin.Os.macosx, builtin.Os.ios => return openSelfDebugInfoMacOs(allocator),788 }
781 builtin.Os.windows => return openSelfDebugInfoWindows(allocator),789 if (os.darwin.is_the_target) {
782 else => return error.UnsupportedOperatingSystem,790 return openSelfDebugInfoMacOs(allocator);
783 }791 }
792 return openSelfDebugInfoPosix(allocator);
784}793}
785794
786fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {795fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
787 const self_file = try os.openSelfExe();796 const self_file = try fs.openSelfExe();
788 defer self_file.close();797 defer self_file.close();
789798
790 const coff_obj = try allocator.create(coff.Coff);799 const coff_obj = try allocator.create(coff.Coff);
...@@ -811,7 +820,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {...@@ -811,7 +820,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
811 const len = try di.coff.getPdbPath(path_buf[0..]);820 const len = try di.coff.getPdbPath(path_buf[0..]);
812 const raw_path = path_buf[0..len];821 const raw_path = path_buf[0..len];
813822
814 const path = try os.path.resolve(allocator, [][]const u8{raw_path});823 const path = try fs.path.resolve(allocator, [][]const u8{raw_path});
815824
816 try di.pdb.openFile(di.coff, path);825 try di.pdb.openFile(di.coff, path);
817826
...@@ -893,7 +902,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {...@@ -893,7 +902,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
893 if (this_record_len % 4 != 0) {902 if (this_record_len % 4 != 0) {
894 const round_to_next_4 = (this_record_len | 0x3) + 1;903 const round_to_next_4 = (this_record_len | 0x3) + 1;
895 const march_forward_bytes = round_to_next_4 - this_record_len;904 const march_forward_bytes = round_to_next_4 - this_record_len;
896 try dbi.seekForward(march_forward_bytes);905 try dbi.seekBy(@intCast(isize, march_forward_bytes));
897 this_record_len += march_forward_bytes;906 this_record_len += march_forward_bytes;
898 }907 }
899908
...@@ -1001,29 +1010,27 @@ pub fn openElfDebugInfo(...@@ -1001,29 +1010,27 @@ pub fn openElfDebugInfo(
1001 return di;1010 return di;
1002}1011}
10031012
1004fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DwarfInfo {1013fn openSelfDebugInfoPosix(allocator: *mem.Allocator) !DwarfInfo {
1005 const S = struct {1014 const S = struct {
1006 var self_exe_file: os.File = undefined;1015 var self_exe_file: File = undefined;
1007 var self_exe_mmap_seekable: io.SliceSeekableInStream = undefined;1016 var self_exe_mmap_seekable: io.SliceSeekableInStream = undefined;
1008 };1017 };
10091018
1010 S.self_exe_file = try os.openSelfExe();1019 S.self_exe_file = try fs.openSelfExe();
1011 errdefer S.self_exe_file.close();1020 errdefer S.self_exe_file.close();
10121021
1013 const self_exe_mmap_len = try S.self_exe_file.getEndPos();1022 const self_exe_mmap_len = mem.alignForward(try S.self_exe_file.getEndPos(), mem.page_size);
1014 const self_exe_mmap = os.posix.mmap(1023 const self_exe_mmap = try os.mmap(
1015 null,1024 null,
1016 self_exe_mmap_len,1025 self_exe_mmap_len,
1017 os.posix.PROT_READ,1026 os.PROT_READ,
1018 os.posix.MAP_SHARED,1027 os.MAP_SHARED,
1019 S.self_exe_file.handle,1028 S.self_exe_file.handle,
1020 0,1029 0,
1021 );1030 );
1022 if (self_exe_mmap == os.posix.MAP_FAILED) return error.OutOfMemory;1031 errdefer os.munmap(self_exe_mmap);
1023 errdefer assert(os.posix.munmap(self_exe_mmap, self_exe_mmap_len) == 0);
10241032
1025 const file_mmap_slice = @intToPtr([*]const u8, self_exe_mmap)[0..self_exe_mmap_len];1033 S.self_exe_mmap_seekable = io.SliceSeekableInStream.init(self_exe_mmap);
1026 S.self_exe_mmap_seekable = io.SliceSeekableInStream.init(file_mmap_slice);
10271034
1028 return openElfDebugInfo(1035 return openElfDebugInfo(
1029 allocator,1036 allocator,
...@@ -1112,11 +1119,11 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {...@@ -1112,11 +1119,11 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
1112}1119}
11131120
1114fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void {1121fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void {
1115 var f = try os.File.openRead(line_info.file_name);1122 var f = try File.openRead(line_info.file_name);
1116 defer f.close();1123 defer f.close();
1117 // TODO fstat and make sure that the file has the correct size1124 // TODO fstat and make sure that the file has the correct size
11181125
1119 var buf: [os.page_size]u8 = undefined;1126 var buf: [mem.page_size]u8 = undefined;
1120 var line: usize = 1;1127 var line: usize = 1;
1121 var column: usize = 1;1128 var column: usize = 1;
1122 var abs_index: usize = 0;1129 var abs_index: usize = 0;
...@@ -1195,7 +1202,7 @@ pub const DwarfInfo = struct {...@@ -1195,7 +1202,7 @@ pub const DwarfInfo = struct {
1195};1202};
11961203
1197pub const DebugInfo = switch (builtin.os) {1204pub const DebugInfo = switch (builtin.os) {
1198 builtin.Os.macosx, builtin.Os.ios => struct {1205 .macosx, .ios, .watchos, .tvos => struct {
1199 symbols: []const MachoSymbol,1206 symbols: []const MachoSymbol,
1200 strings: []const u8,1207 strings: []const u8,
1201 ofiles: OFileTable,1208 ofiles: OFileTable,
...@@ -1211,13 +1218,13 @@ pub const DebugInfo = switch (builtin.os) {...@@ -1211,13 +1218,13 @@ pub const DebugInfo = switch (builtin.os) {
1211 return self.ofiles.allocator;1218 return self.ofiles.allocator;
1212 }1219 }
1213 },1220 },
1214 builtin.Os.uefi, builtin.Os.windows => struct {1221 .uefi, .windows => struct {
1215 pdb: pdb.Pdb,1222 pdb: pdb.Pdb,
1216 coff: *coff.Coff,1223 coff: *coff.Coff,
1217 sect_contribs: []pdb.SectionContribEntry,1224 sect_contribs: []pdb.SectionContribEntry,
1218 modules: []Module,1225 modules: []Module,
1219 },1226 },
1220 builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => DwarfInfo,1227 .linux, .freebsd, .netbsd => DwarfInfo,
1221 else => @compileError("Unsupported OS"),1228 else => @compileError("Unsupported OS"),
1222};1229};
12231230
...@@ -1411,7 +1418,7 @@ const LineNumberProgram = struct {...@@ -1411,7 +1418,7 @@ const LineNumberProgram = struct {
1411 return error.InvalidDebugInfo;1418 return error.InvalidDebugInfo;
1412 } else1419 } else
1413 self.include_dirs[file_entry.dir_index];1420 self.include_dirs[file_entry.dir_index];
1414 const file_name = try os.path.join(self.file_entries.allocator, [][]const u8{ dir_name, file_entry.file_name });1421 const file_name = try fs.path.join(self.file_entries.allocator, [][]const u8{ dir_name, file_entry.file_name });
1415 errdefer self.file_entries.allocator.free(file_name);1422 errdefer self.file_entries.allocator.free(file_name);
1416 return LineInfo{1423 return LineInfo{
1417 .line = if (self.prev_line >= 0) @intCast(u64, self.prev_line) else 0,1424 .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...@@ -1938,7 +1945,7 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr
1938 },1945 },
1939 else => {1946 else => {
1940 const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;1947 const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
1941 try di.dwarf_seekable_stream.seekForward(fwd_amt);1948 try di.dwarf_seekable_stream.seekBy(fwd_amt);
1942 },1949 },
1943 }1950 }
1944 } else if (opcode >= opcode_base) {1951 } else if (opcode >= opcode_base) {
...@@ -1990,7 +1997,7 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr...@@ -1990,7 +1997,7 @@ fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_addr
1990 else => {1997 else => {
1991 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;1998 if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
1992 const len_bytes = standard_opcode_lengths[opcode - 1];1999 const len_bytes = standard_opcode_lengths[opcode - 1];
1993 try di.dwarf_seekable_stream.seekForward(len_bytes);2000 try di.dwarf_seekable_stream.seekBy(len_bytes);
1994 },2001 },
1995 }2002 }
1996 }2003 }
std/dynamic_library.zig+25-41
...@@ -1,21 +1,17 @@...@@ -1,21 +1,17 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const Os = builtin.Os;
32
4const std = @import("std.zig");3const std = @import("std.zig");
5const mem = std.mem;4const mem = std.mem;
6const cstr = std.cstr;
7const os = std.os;5const os = std.os;
8const assert = std.debug.assert;6const assert = std.debug.assert;
9const testing = std.testing;7const testing = std.testing;
10const elf = std.elf;8const elf = std.elf;
11const linux = os.linux;9const windows = std.os.windows;
12const windows = os.windows;
13const win_util = @import("os/windows/util.zig");
14const maxInt = std.math.maxInt;10const maxInt = std.math.maxInt;
1511
16pub const DynLib = switch (builtin.os) {12pub const DynLib = switch (builtin.os) {
17 Os.linux => LinuxDynLib,13 .linux => LinuxDynLib,
18 Os.windows => WindowsDynLib,14 .windows => WindowsDynLib,
19 else => void,15 else => void,
20};16};
2117
...@@ -105,39 +101,35 @@ pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator {...@@ -105,39 +101,35 @@ pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator {
105pub const LinuxDynLib = struct {101pub const LinuxDynLib = struct {
106 elf_lib: ElfLib,102 elf_lib: ElfLib,
107 fd: i32,103 fd: i32,
108 map_addr: usize,104 memory: []align(mem.page_size) u8,
109 map_size: usize,
110105
111 /// Trusts the file106 /// Trusts the file
112 pub fn open(allocator: *mem.Allocator, path: []const u8) !DynLib {107 pub fn open(allocator: *mem.Allocator, path: []const u8) !DynLib {
113 const fd = try std.os.posixOpen(path, 0, linux.O_RDONLY | linux.O_CLOEXEC);108 const fd = try os.open(path, 0, os.O_RDONLY | os.O_CLOEXEC);
114 errdefer std.os.close(fd);109 errdefer os.close(fd);
115110
116 const size = @intCast(usize, (try std.os.posixFStat(fd)).size);111 const size = @intCast(usize, (try os.fstat(fd)).size);
117112
118 const addr = linux.mmap(113 const bytes = try os.mmap(
119 null,114 null,
120 size,115 size,
121 linux.PROT_READ | linux.PROT_EXEC,116 os.PROT_READ | os.PROT_EXEC,
122 linux.MAP_PRIVATE | linux.MAP_LOCKED,117 os.MAP_PRIVATE | os.MAP_LOCKED,
123 fd,118 fd,
124 0,119 0,
125 );120 );
126 errdefer _ = linux.munmap(addr, size);121 errdefer os.munmap(bytes);
127
128 const bytes = @intToPtr([*]align(std.os.page_size) u8, addr)[0..size];
129122
130 return DynLib{123 return DynLib{
131 .elf_lib = try ElfLib.init(bytes),124 .elf_lib = try ElfLib.init(bytes),
132 .fd = fd,125 .fd = fd,
133 .map_addr = addr,126 .memory = bytes,
134 .map_size = size,
135 };127 };
136 }128 }
137129
138 pub fn close(self: *DynLib) void {130 pub fn close(self: *DynLib) void {
139 _ = linux.munmap(self.map_addr, self.map_size);131 os.munmap(self.memory);
140 std.os.close(self.fd);132 os.close(self.fd);
141 self.* = undefined;133 self.* = undefined;
142 }134 }
143135
...@@ -149,7 +141,7 @@ pub const LinuxDynLib = struct {...@@ -149,7 +141,7 @@ pub const LinuxDynLib = struct {
149pub const ElfLib = struct {141pub const ElfLib = struct {
150 strings: [*]u8,142 strings: [*]u8,
151 syms: [*]elf.Sym,143 syms: [*]elf.Sym,
152 hashtab: [*]linux.Elf_Symndx,144 hashtab: [*]os.Elf_Symndx,
153 versym: ?[*]u16,145 versym: ?[*]u16,
154 verdef: ?*elf.Verdef,146 verdef: ?*elf.Verdef,
155 base: usize,147 base: usize,
...@@ -184,7 +176,7 @@ pub const ElfLib = struct {...@@ -184,7 +176,7 @@ pub const ElfLib = struct {
184176
185 var maybe_strings: ?[*]u8 = null;177 var maybe_strings: ?[*]u8 = null;
186 var maybe_syms: ?[*]elf.Sym = null;178 var maybe_syms: ?[*]elf.Sym = null;
187 var maybe_hashtab: ?[*]linux.Elf_Symndx = null;179 var maybe_hashtab: ?[*]os.Elf_Symndx = null;
188 var maybe_versym: ?[*]u16 = null;180 var maybe_versym: ?[*]u16 = null;
189 var maybe_verdef: ?*elf.Verdef = null;181 var maybe_verdef: ?*elf.Verdef = null;
190182
...@@ -195,7 +187,7 @@ pub const ElfLib = struct {...@@ -195,7 +187,7 @@ pub const ElfLib = struct {
195 switch (dynv[i]) {187 switch (dynv[i]) {
196 elf.DT_STRTAB => maybe_strings = @intToPtr([*]u8, p),188 elf.DT_STRTAB => maybe_strings = @intToPtr([*]u8, p),
197 elf.DT_SYMTAB => maybe_syms = @intToPtr([*]elf.Sym, p),189 elf.DT_SYMTAB => maybe_syms = @intToPtr([*]elf.Sym, p),
198 elf.DT_HASH => maybe_hashtab = @intToPtr([*]linux.Elf_Symndx, p),190 elf.DT_HASH => maybe_hashtab = @intToPtr([*]os.Elf_Symndx, p),
199 elf.DT_VERSYM => maybe_versym = @intToPtr([*]u16, p),191 elf.DT_VERSYM => maybe_versym = @intToPtr([*]u16, p),
200 elf.DT_VERDEF => maybe_verdef = @intToPtr(*elf.Verdef, p),192 elf.DT_VERDEF => maybe_verdef = @intToPtr(*elf.Verdef, p),
201 else => {},193 else => {},
...@@ -225,7 +217,7 @@ pub const ElfLib = struct {...@@ -225,7 +217,7 @@ pub const ElfLib = struct {
225 if (0 == (u32(1) << @intCast(u5, self.syms[i].st_info & 0xf) & OK_TYPES)) continue;217 if (0 == (u32(1) << @intCast(u5, self.syms[i].st_info & 0xf) & OK_TYPES)) continue;
226 if (0 == (u32(1) << @intCast(u5, self.syms[i].st_info >> 4) & OK_BINDS)) continue;218 if (0 == (u32(1) << @intCast(u5, self.syms[i].st_info >> 4) & OK_BINDS)) continue;
227 if (0 == self.syms[i].st_shndx) continue;219 if (0 == self.syms[i].st_shndx) continue;
228 if (!mem.eql(u8, name, cstr.toSliceConst(self.strings + self.syms[i].st_name))) continue;220 if (!mem.eql(u8, name, mem.toSliceConst(u8, self.strings + self.syms[i].st_name))) continue;
229 if (maybe_versym) |versym| {221 if (maybe_versym) |versym| {
230 if (!checkver(self.verdef.?, versym[i], vername, self.strings))222 if (!checkver(self.verdef.?, versym[i], vername, self.strings))
231 continue;223 continue;
...@@ -248,7 +240,7 @@ fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [...@@ -248,7 +240,7 @@ fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [
248 def = @intToPtr(*elf.Verdef, @ptrToInt(def) + def.vd_next);240 def = @intToPtr(*elf.Verdef, @ptrToInt(def) + def.vd_next);
249 }241 }
250 const aux = @intToPtr(*elf.Verdaux, @ptrToInt(def) + def.vd_aux);242 const aux = @intToPtr(*elf.Verdaux, @ptrToInt(def) + def.vd_aux);
251 return mem.eql(u8, vername, cstr.toSliceConst(strings + aux.vda_name));243 return mem.eql(u8, vername, mem.toSliceConst(u8, strings + aux.vda_name));
252}244}
253245
254pub const WindowsDynLib = struct {246pub const WindowsDynLib = struct {
...@@ -256,36 +248,28 @@ pub const WindowsDynLib = struct {...@@ -256,36 +248,28 @@ pub const WindowsDynLib = struct {
256 dll: windows.HMODULE,248 dll: windows.HMODULE,
257249
258 pub fn open(allocator: *mem.Allocator, path: []const u8) !WindowsDynLib {250 pub fn open(allocator: *mem.Allocator, path: []const u8) !WindowsDynLib {
259 const wpath = try win_util.sliceToPrefixedFileW(path);251 const wpath = try windows.sliceToPrefixedFileW(path);
260252
261 return WindowsDynLib{253 return WindowsDynLib{
262 .allocator = allocator,254 .allocator = allocator,
263 .dll = windows.LoadLibraryW(&wpath) orelse {255 .dll = try windows.LoadLibraryW(&wpath),
264 const err = windows.GetLastError();
265 switch (err) {
266 windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
267 windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
268 windows.ERROR.MOD_NOT_FOUND => return error.FileNotFound,
269 else => return os.unexpectedErrorWindows(err),
270 }
271 },
272 };256 };
273 }257 }
274258
275 pub fn close(self: *WindowsDynLib) void {259 pub fn close(self: *WindowsDynLib) void {
276 assert(windows.FreeLibrary(self.dll) != 0);260 windows.FreeLibrary(self.dll);
277 self.* = undefined;261 self.* = undefined;
278 }262 }
279263
280 pub fn lookup(self: *WindowsDynLib, name: []const u8) ?usize {264 pub fn lookup(self: *WindowsDynLib, name: []const u8) ?usize {
281 return @ptrToInt(windows.GetProcAddress(self.dll, name.ptr));265 return @ptrToInt(windows.kernel32.GetProcAddress(self.dll, name.ptr));
282 }266 }
283};267};
284268
285test "dynamic_library" {269test "dynamic_library" {
286 const libname = switch (builtin.os) {270 const libname = switch (builtin.os) {
287 Os.linux => "invalid_so.so",271 .linux => "invalid_so.so",
288 Os.windows => "invalid_dll.dll",272 .windows => "invalid_dll.dll",
289 else => return,273 else => return,
290 };274 };
291275
std/elf.zig+5-4
...@@ -6,6 +6,7 @@ const math = std.math;...@@ -6,6 +6,7 @@ const math = std.math;
6const mem = std.mem;6const mem = std.mem;
7const debug = std.debug;7const debug = std.debug;
8const InStream = std.stream.InStream;8const InStream = std.stream.InStream;
9const File = std.fs.File;
910
10pub const AT_NULL = 0;11pub const AT_NULL = 0;
11pub const AT_IGNORE = 1;12pub const AT_IGNORE = 1;
...@@ -367,7 +368,7 @@ pub const Elf = struct {...@@ -367,7 +368,7 @@ pub const Elf = struct {
367 string_section: *SectionHeader,368 string_section: *SectionHeader,
368 section_headers: []SectionHeader,369 section_headers: []SectionHeader,
369 allocator: *mem.Allocator,370 allocator: *mem.Allocator,
370 prealloc_file: os.File,371 prealloc_file: File,
371372
372 /// Call close when done.373 /// Call close when done.
373 pub fn openPath(elf: *Elf, allocator: *mem.Allocator, path: []const u8) !void {374 pub fn openPath(elf: *Elf, allocator: *mem.Allocator, path: []const u8) !void {
...@@ -375,7 +376,7 @@ pub const Elf = struct {...@@ -375,7 +376,7 @@ pub const Elf = struct {
375 }376 }
376377
377 /// Call close when done.378 /// Call close when done.
378 pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: os.File) !void {379 pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: File) !void {
379 @compileError("TODO implement");380 @compileError("TODO implement");
380 }381 }
381382
...@@ -410,7 +411,7 @@ pub const Elf = struct {...@@ -410,7 +411,7 @@ pub const Elf = struct {
410 if (version_byte != 1) return error.InvalidFormat;411 if (version_byte != 1) return error.InvalidFormat;
411412
412 // skip over padding413 // skip over padding
413 try seekable_stream.seekForward(9);414 try seekable_stream.seekBy(9);
414415
415 elf.file_type = switch (try in.readInt(u16, elf.endian)) {416 elf.file_type = switch (try in.readInt(u16, elf.endian)) {
416 1 => FileType.Relocatable,417 1 => FileType.Relocatable,
...@@ -447,7 +448,7 @@ pub const Elf = struct {...@@ -447,7 +448,7 @@ pub const Elf = struct {
447 }448 }
448449
449 // skip over flags450 // skip over flags
450 try seekable_stream.seekForward(4);451 try seekable_stream.seekBy(4);
451452
452 const header_size = try in.readInt(u16, elf.endian);453 const header_size = try in.readInt(u16, elf.endian);
453 if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) {454 if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) {
std/event/fs.zig+110-114
...@@ -5,9 +5,10 @@ const assert = std.debug.assert;...@@ -5,9 +5,10 @@ const assert = std.debug.assert;
5const testing = std.testing;5const testing = std.testing;
6const os = std.os;6const os = std.os;
7const mem = std.mem;7const mem = std.mem;
8const posix = os.posix;
9const windows = os.windows;8const windows = os.windows;
10const Loop = event.Loop;9const Loop = event.Loop;
10const fd_t = os.fd_t;
11const File = std.fs.File;
1112
12pub const RequestNode = std.atomic.Queue(Request).Node;13pub const RequestNode = std.atomic.Queue(Request).Node;
1314
...@@ -30,53 +31,53 @@ pub const Request = struct {...@@ -30,53 +31,53 @@ pub const Request = struct {
30 End, // special - means the fs thread should exit31 End, // special - means the fs thread should exit
3132
32 pub const PWriteV = struct {33 pub const PWriteV = struct {
33 fd: os.FileHandle,34 fd: fd_t,
34 iov: []const os.posix.iovec_const,35 iov: []const os.iovec_const,
35 offset: usize,36 offset: usize,
36 result: Error!void,37 result: Error!void,
3738
38 pub const Error = os.PosixWriteError;39 pub const Error = os.WriteError;
39 };40 };
4041
41 pub const PReadV = struct {42 pub const PReadV = struct {
42 fd: os.FileHandle,43 fd: fd_t,
43 iov: []const os.posix.iovec,44 iov: []const os.iovec,
44 offset: usize,45 offset: usize,
45 result: Error!usize,46 result: Error!usize,
4647
47 pub const Error = os.PosixReadError;48 pub const Error = os.ReadError;
48 };49 };
4950
50 pub const Open = struct {51 pub const Open = struct {
51 /// must be null terminated. TODO https://github.com/ziglang/zig/issues/26552 /// must be null terminated. TODO https://github.com/ziglang/zig/issues/265
52 path: []const u8,53 path: []const u8,
53 flags: u32,54 flags: u32,
54 mode: os.File.Mode,55 mode: File.Mode,
55 result: Error!os.FileHandle,56 result: Error!fd_t,
5657
57 pub const Error = os.File.OpenError;58 pub const Error = File.OpenError;
58 };59 };
5960
60 pub const WriteFile = struct {61 pub const WriteFile = struct {
61 /// must be null terminated. TODO https://github.com/ziglang/zig/issues/26562 /// must be null terminated. TODO https://github.com/ziglang/zig/issues/265
62 path: []const u8,63 path: []const u8,
63 contents: []const u8,64 contents: []const u8,
64 mode: os.File.Mode,65 mode: File.Mode,
65 result: Error!void,66 result: Error!void,
6667
67 pub const Error = os.File.OpenError || os.File.WriteError;68 pub const Error = File.OpenError || File.WriteError;
68 };69 };
6970
70 pub const Close = struct {71 pub const Close = struct {
71 fd: os.FileHandle,72 fd: fd_t,
72 };73 };
73 };74 };
74};75};
7576
76pub const PWriteVError = error{OutOfMemory} || os.File.WriteError;77pub const PWriteVError = error{OutOfMemory} || File.WriteError;
7778
78/// data - just the inner references - must live until pwritev promise completes.79/// data - just the inner references - must live until pwritev promise completes.
79pub async fn pwritev(loop: *Loop, fd: os.FileHandle, data: []const []const u8, offset: usize) PWriteVError!void {80pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: usize) PWriteVError!void {
80 // workaround for https://github.com/ziglang/zig/issues/119481 // workaround for https://github.com/ziglang/zig/issues/1194
81 suspend {82 suspend {
82 resume @handle();83 resume @handle();
...@@ -87,11 +88,11 @@ pub async fn pwritev(loop: *Loop, fd: os.FileHandle, data: []const []const u8, o...@@ -87,11 +88,11 @@ pub async fn pwritev(loop: *Loop, fd: os.FileHandle, data: []const []const u8, o
87 builtin.Os.freebsd,88 builtin.Os.freebsd,
88 builtin.Os.netbsd,89 builtin.Os.netbsd,
89 => {90 => {
90 const iovecs = try loop.allocator.alloc(os.posix.iovec_const, data.len);91 const iovecs = try loop.allocator.alloc(os.iovec_const, data.len);
91 defer loop.allocator.free(iovecs);92 defer loop.allocator.free(iovecs);
9293
93 for (data) |buf, i| {94 for (data) |buf, i| {
94 iovecs[i] = os.posix.iovec_const{95 iovecs[i] = os.iovec_const{
95 .iov_base = buf.ptr,96 .iov_base = buf.ptr,
96 .iov_len = buf.len,97 .iov_len = buf.len,
97 };98 };
...@@ -109,7 +110,7 @@ pub async fn pwritev(loop: *Loop, fd: os.FileHandle, data: []const []const u8, o...@@ -109,7 +110,7 @@ pub async fn pwritev(loop: *Loop, fd: os.FileHandle, data: []const []const u8, o
109}110}
110111
111/// data must outlive the returned promise112/// data must outlive the returned promise
112pub async fn pwritevWindows(loop: *Loop, fd: os.FileHandle, data: []const []const u8, offset: usize) os.WindowsWriteError!void {113pub async fn pwritevWindows(loop: *Loop, fd: fd_t, data: []const []const u8, offset: usize) os.WindowsWriteError!void {
113 if (data.len == 0) return;114 if (data.len == 0) return;
114 if (data.len == 1) return await (async pwriteWindows(loop, fd, data[0], offset) catch unreachable);115 if (data.len == 1) return await (async pwriteWindows(loop, fd, data[0], offset) catch unreachable);
115116
...@@ -121,7 +122,7 @@ pub async fn pwritevWindows(loop: *Loop, fd: os.FileHandle, data: []const []cons...@@ -121,7 +122,7 @@ pub async fn pwritevWindows(loop: *Loop, fd: os.FileHandle, data: []const []cons
121 }122 }
122}123}
123124
124pub async fn pwriteWindows(loop: *Loop, fd: os.FileHandle, data: []const u8, offset: u64) os.WindowsWriteError!void {125pub async fn pwriteWindows(loop: *Loop, fd: fd_t, data: []const u8, offset: u64) os.WindowsWriteError!void {
125 // workaround for https://github.com/ziglang/zig/issues/1194126 // workaround for https://github.com/ziglang/zig/issues/1194
126 suspend {127 suspend {
127 resume @handle();128 resume @handle();
...@@ -146,33 +147,32 @@ pub async fn pwriteWindows(loop: *Loop, fd: os.FileHandle, data: []const u8, off...@@ -146,33 +147,32 @@ pub async fn pwriteWindows(loop: *Loop, fd: os.FileHandle, data: []const u8, off
146 errdefer loop.finishOneEvent();147 errdefer loop.finishOneEvent();
147148
148 errdefer {149 errdefer {
149 _ = windows.CancelIoEx(fd, &resume_node.base.overlapped);150 _ = windows.kernel32.CancelIoEx(fd, &resume_node.base.overlapped);
150 }151 }
151 suspend {152 suspend {
152 _ = windows.WriteFile(fd, data.ptr, @intCast(windows.DWORD, data.len), null, &resume_node.base.overlapped);153 _ = windows.kernel32.WriteFile(fd, data.ptr, @intCast(windows.DWORD, data.len), null, &resume_node.base.overlapped);
153 }154 }
154 var bytes_transferred: windows.DWORD = undefined;155 var bytes_transferred: windows.DWORD = undefined;
155 if (windows.GetOverlappedResult(fd, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {156 if (windows.kernel32.GetOverlappedResult(fd, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {
156 const err = windows.GetLastError();157 switch (windows.kernel32.GetLastError()) {
157 return switch (err) {
158 windows.ERROR.IO_PENDING => unreachable,158 windows.ERROR.IO_PENDING => unreachable,
159 windows.ERROR.INVALID_USER_BUFFER => error.SystemResources,159 windows.ERROR.INVALID_USER_BUFFER => return error.SystemResources,
160 windows.ERROR.NOT_ENOUGH_MEMORY => error.SystemResources,160 windows.ERROR.NOT_ENOUGH_MEMORY => return error.SystemResources,
161 windows.ERROR.OPERATION_ABORTED => error.OperationAborted,161 windows.ERROR.OPERATION_ABORTED => return error.OperationAborted,
162 windows.ERROR.NOT_ENOUGH_QUOTA => error.SystemResources,162 windows.ERROR.NOT_ENOUGH_QUOTA => return error.SystemResources,
163 windows.ERROR.BROKEN_PIPE => error.BrokenPipe,163 windows.ERROR.BROKEN_PIPE => return error.BrokenPipe,
164 else => os.unexpectedErrorWindows(err),164 else => |err| return windows.unexpectedError(err),
165 };165 }
166 }166 }
167}167}
168168
169/// iovecs must live until pwritev promise completes.169/// iovecs must live until pwritev promise completes.
170pub async fn pwritevPosix(170pub async fn pwritevPosix(
171 loop: *Loop,171 loop: *Loop,
172 fd: os.FileHandle,172 fd: fd_t,
173 iovecs: []const posix.iovec_const,173 iovecs: []const os.iovec_const,
174 offset: usize,174 offset: usize,
175) os.PosixWriteError!void {175) os.WriteError!void {
176 // workaround for https://github.com/ziglang/zig/issues/1194176 // workaround for https://github.com/ziglang/zig/issues/1194
177 suspend {177 suspend {
178 resume @handle();178 resume @handle();
...@@ -209,10 +209,10 @@ pub async fn pwritevPosix(...@@ -209,10 +209,10 @@ pub async fn pwritevPosix(
209 return req_node.data.msg.PWriteV.result;209 return req_node.data.msg.PWriteV.result;
210}210}
211211
212pub const PReadVError = error{OutOfMemory} || os.File.ReadError;212pub const PReadVError = error{OutOfMemory} || File.ReadError;
213213
214/// data - just the inner references - must live until preadv promise completes.214/// data - just the inner references - must live until preadv promise completes.
215pub async fn preadv(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset: usize) PReadVError!usize {215pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PReadVError!usize {
216 // workaround for https://github.com/ziglang/zig/issues/1194216 // workaround for https://github.com/ziglang/zig/issues/1194
217 suspend {217 suspend {
218 resume @handle();218 resume @handle();
...@@ -225,11 +225,11 @@ pub async fn preadv(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset:...@@ -225,11 +225,11 @@ pub async fn preadv(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset:
225 builtin.Os.freebsd,225 builtin.Os.freebsd,
226 builtin.Os.netbsd,226 builtin.Os.netbsd,
227 => {227 => {
228 const iovecs = try loop.allocator.alloc(os.posix.iovec, data.len);228 const iovecs = try loop.allocator.alloc(os.iovec, data.len);
229 defer loop.allocator.free(iovecs);229 defer loop.allocator.free(iovecs);
230230
231 for (data) |buf, i| {231 for (data) |buf, i| {
232 iovecs[i] = os.posix.iovec{232 iovecs[i] = os.iovec{
233 .iov_base = buf.ptr,233 .iov_base = buf.ptr,
234 .iov_len = buf.len,234 .iov_len = buf.len,
235 };235 };
...@@ -247,7 +247,7 @@ pub async fn preadv(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset:...@@ -247,7 +247,7 @@ pub async fn preadv(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset:
247}247}
248248
249/// data must outlive the returned promise249/// data must outlive the returned promise
250pub async fn preadvWindows(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset: u64) os.WindowsReadError!usize {250pub async fn preadvWindows(loop: *Loop, fd: fd_t, data: []const []u8, offset: u64) !usize {
251 assert(data.len != 0);251 assert(data.len != 0);
252 if (data.len == 1) return await (async preadWindows(loop, fd, data[0], offset) catch unreachable);252 if (data.len == 1) return await (async preadWindows(loop, fd, data[0], offset) catch unreachable);
253253
...@@ -271,7 +271,7 @@ pub async fn preadvWindows(loop: *Loop, fd: os.FileHandle, data: []const []u8, o...@@ -271,7 +271,7 @@ pub async fn preadvWindows(loop: *Loop, fd: os.FileHandle, data: []const []u8, o
271 }271 }
272}272}
273273
274pub async fn preadWindows(loop: *Loop, fd: os.FileHandle, data: []u8, offset: u64) !usize {274pub async fn preadWindows(loop: *Loop, fd: fd_t, data: []u8, offset: u64) !usize {
275 // workaround for https://github.com/ziglang/zig/issues/1194275 // workaround for https://github.com/ziglang/zig/issues/1194
276 suspend {276 suspend {
277 resume @handle();277 resume @handle();
...@@ -291,25 +291,24 @@ pub async fn preadWindows(loop: *Loop, fd: os.FileHandle, data: []u8, offset: u6...@@ -291,25 +291,24 @@ pub async fn preadWindows(loop: *Loop, fd: os.FileHandle, data: []u8, offset: u6
291 },291 },
292 };292 };
293 // TODO only call create io completion port once per fd293 // TODO only call create io completion port once per fd
294 _ = windows.CreateIoCompletionPort(fd, loop.os_data.io_port, undefined, undefined);294 _ = windows.CreateIoCompletionPort(fd, loop.os_data.io_port, undefined, undefined) catch undefined;
295 loop.beginOneEvent();295 loop.beginOneEvent();
296 errdefer loop.finishOneEvent();296 errdefer loop.finishOneEvent();
297297
298 errdefer {298 errdefer {
299 _ = windows.CancelIoEx(fd, &resume_node.base.overlapped);299 _ = windows.kernel32.CancelIoEx(fd, &resume_node.base.overlapped);
300 }300 }
301 suspend {301 suspend {
302 _ = windows.ReadFile(fd, data.ptr, @intCast(windows.DWORD, data.len), null, &resume_node.base.overlapped);302 _ = windows.kernel32.ReadFile(fd, data.ptr, @intCast(windows.DWORD, data.len), null, &resume_node.base.overlapped);
303 }303 }
304 var bytes_transferred: windows.DWORD = undefined;304 var bytes_transferred: windows.DWORD = undefined;
305 if (windows.GetOverlappedResult(fd, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {305 if (windows.kernel32.GetOverlappedResult(fd, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {
306 const err = windows.GetLastError();306 switch (windows.kernel32.GetLastError()) {
307 switch (err) {
308 windows.ERROR.IO_PENDING => unreachable,307 windows.ERROR.IO_PENDING => unreachable,
309 windows.ERROR.OPERATION_ABORTED => return error.OperationAborted,308 windows.ERROR.OPERATION_ABORTED => return error.OperationAborted,
310 windows.ERROR.BROKEN_PIPE => return error.BrokenPipe,309 windows.ERROR.BROKEN_PIPE => return error.BrokenPipe,
311 windows.ERROR.HANDLE_EOF => return usize(bytes_transferred),310 windows.ERROR.HANDLE_EOF => return usize(bytes_transferred),
312 else => return os.unexpectedErrorWindows(err),311 else => |err| return windows.unexpectedError(err),
313 }312 }
314 }313 }
315 return usize(bytes_transferred);314 return usize(bytes_transferred);
...@@ -318,10 +317,10 @@ pub async fn preadWindows(loop: *Loop, fd: os.FileHandle, data: []u8, offset: u6...@@ -318,10 +317,10 @@ pub async fn preadWindows(loop: *Loop, fd: os.FileHandle, data: []u8, offset: u6
318/// iovecs must live until preadv promise completes317/// iovecs must live until preadv promise completes
319pub async fn preadvPosix(318pub async fn preadvPosix(
320 loop: *Loop,319 loop: *Loop,
321 fd: os.FileHandle,320 fd: fd_t,
322 iovecs: []const posix.iovec,321 iovecs: []const os.iovec,
323 offset: usize,322 offset: usize,
324) os.PosixReadError!usize {323) os.ReadError!usize {
325 // workaround for https://github.com/ziglang/zig/issues/1194324 // workaround for https://github.com/ziglang/zig/issues/1194
326 suspend {325 suspend {
327 resume @handle();326 resume @handle();
...@@ -362,8 +361,8 @@ pub async fn openPosix(...@@ -362,8 +361,8 @@ pub async fn openPosix(
362 loop: *Loop,361 loop: *Loop,
363 path: []const u8,362 path: []const u8,
364 flags: u32,363 flags: u32,
365 mode: os.File.Mode,364 mode: File.Mode,
366) os.File.OpenError!os.FileHandle {365) File.OpenError!fd_t {
367 // workaround for https://github.com/ziglang/zig/issues/1194366 // workaround for https://github.com/ziglang/zig/issues/1194
368 suspend {367 suspend {
369 resume @handle();368 resume @handle();
...@@ -402,19 +401,21 @@ pub async fn openPosix(...@@ -402,19 +401,21 @@ pub async fn openPosix(
402 return req_node.data.msg.Open.result;401 return req_node.data.msg.Open.result;
403}402}
404403
405pub async fn openRead(loop: *Loop, path: []const u8) os.File.OpenError!os.FileHandle {404pub async fn openRead(loop: *Loop, path: []const u8) File.OpenError!fd_t {
406 switch (builtin.os) {405 switch (builtin.os) {
407 builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {406 builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {
408 const flags = posix.O_LARGEFILE | posix.O_RDONLY | posix.O_CLOEXEC;407 const flags = os.O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC;
409 return await (async openPosix(loop, path, flags, os.File.default_mode) catch unreachable);408 return await (async openPosix(loop, path, flags, File.default_mode) catch unreachable);
410 },409 },
411410
412 builtin.Os.windows => return os.windowsOpen(411 builtin.Os.windows => return windows.CreateFile(
413 path,412 path,
414 windows.GENERIC_READ,413 windows.GENERIC_READ,
415 windows.FILE_SHARE_READ,414 windows.FILE_SHARE_READ,
415 null,
416 windows.OPEN_EXISTING,416 windows.OPEN_EXISTING,
417 windows.FILE_ATTRIBUTE_NORMAL | windows.FILE_FLAG_OVERLAPPED,417 windows.FILE_ATTRIBUTE_NORMAL | windows.FILE_FLAG_OVERLAPPED,
418 null,
418 ),419 ),
419420
420 else => @compileError("Unsupported OS"),421 else => @compileError("Unsupported OS"),
...@@ -423,27 +424,29 @@ pub async fn openRead(loop: *Loop, path: []const u8) os.File.OpenError!os.FileHa...@@ -423,27 +424,29 @@ pub async fn openRead(loop: *Loop, path: []const u8) os.File.OpenError!os.FileHa
423424
424/// Creates if does not exist. Truncates the file if it exists.425/// Creates if does not exist. Truncates the file if it exists.
425/// Uses the default mode.426/// Uses the default mode.
426pub async fn openWrite(loop: *Loop, path: []const u8) os.File.OpenError!os.FileHandle {427pub async fn openWrite(loop: *Loop, path: []const u8) File.OpenError!fd_t {
427 return await (async openWriteMode(loop, path, os.File.default_mode) catch unreachable);428 return await (async openWriteMode(loop, path, File.default_mode) catch unreachable);
428}429}
429430
430/// Creates if does not exist. Truncates the file if it exists.431/// Creates if does not exist. Truncates the file if it exists.
431pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: os.File.Mode) os.File.OpenError!os.FileHandle {432pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: File.Mode) File.OpenError!fd_t {
432 switch (builtin.os) {433 switch (builtin.os) {
433 builtin.Os.macosx,434 builtin.Os.macosx,
434 builtin.Os.linux,435 builtin.Os.linux,
435 builtin.Os.freebsd,436 builtin.Os.freebsd,
436 builtin.Os.netbsd,437 builtin.Os.netbsd,
437 => {438 => {
438 const flags = posix.O_LARGEFILE | posix.O_WRONLY | posix.O_CREAT | posix.O_CLOEXEC | posix.O_TRUNC;439 const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_TRUNC;
439 return await (async openPosix(loop, path, flags, os.File.default_mode) catch unreachable);440 return await (async openPosix(loop, path, flags, File.default_mode) catch unreachable);
440 },441 },
441 builtin.Os.windows => return os.windowsOpen(442 builtin.Os.windows => return windows.CreateFile(
442 path,443 path,
443 windows.GENERIC_WRITE,444 windows.GENERIC_WRITE,
444 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,445 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
446 null,
445 windows.CREATE_ALWAYS,447 windows.CREATE_ALWAYS,
446 windows.FILE_ATTRIBUTE_NORMAL | windows.FILE_FLAG_OVERLAPPED,448 windows.FILE_ATTRIBUTE_NORMAL | windows.FILE_FLAG_OVERLAPPED,
449 null,
447 ),450 ),
448 else => @compileError("Unsupported OS"),451 else => @compileError("Unsupported OS"),
449 }452 }
...@@ -453,20 +456,22 @@ pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: os.File.Mode) os...@@ -453,20 +456,22 @@ pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: os.File.Mode) os
453pub async fn openReadWrite(456pub async fn openReadWrite(
454 loop: *Loop,457 loop: *Loop,
455 path: []const u8,458 path: []const u8,
456 mode: os.File.Mode,459 mode: File.Mode,
457) os.File.OpenError!os.FileHandle {460) File.OpenError!fd_t {
458 switch (builtin.os) {461 switch (builtin.os) {
459 builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {462 builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {
460 const flags = posix.O_LARGEFILE | posix.O_RDWR | posix.O_CREAT | posix.O_CLOEXEC;463 const flags = os.O_LARGEFILE | os.O_RDWR | os.O_CREAT | os.O_CLOEXEC;
461 return await (async openPosix(loop, path, flags, mode) catch unreachable);464 return await (async openPosix(loop, path, flags, mode) catch unreachable);
462 },465 },
463466
464 builtin.Os.windows => return os.windowsOpen(467 builtin.Os.windows => return windows.CreateFile(
465 path,468 path,
466 windows.GENERIC_WRITE | windows.GENERIC_READ,469 windows.GENERIC_WRITE | windows.GENERIC_READ,
467 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,470 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
471 null,
468 windows.OPEN_ALWAYS,472 windows.OPEN_ALWAYS,
469 windows.FILE_ATTRIBUTE_NORMAL | windows.FILE_FLAG_OVERLAPPED,473 windows.FILE_ATTRIBUTE_NORMAL | windows.FILE_FLAG_OVERLAPPED,
474 null,
470 ),475 ),
471476
472 else => @compileError("Unsupported OS"),477 else => @compileError("Unsupported OS"),
...@@ -487,7 +492,7 @@ pub const CloseOperation = struct {...@@ -487,7 +492,7 @@ pub const CloseOperation = struct {
487 builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => OsDataPosix,492 builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => OsDataPosix,
488493
489 builtin.Os.windows => struct {494 builtin.Os.windows => struct {
490 handle: ?os.FileHandle,495 handle: ?fd_t,
491 },496 },
492497
493 else => @compileError("Unsupported OS"),498 else => @compileError("Unsupported OS"),
...@@ -551,7 +556,7 @@ pub const CloseOperation = struct {...@@ -551,7 +556,7 @@ pub const CloseOperation = struct {
551 }556 }
552 }557 }
553558
554 pub fn setHandle(self: *CloseOperation, handle: os.FileHandle) void {559 pub fn setHandle(self: *CloseOperation, handle: fd_t) void {
555 switch (builtin.os) {560 switch (builtin.os) {
556 builtin.Os.linux,561 builtin.Os.linux,
557 builtin.Os.macosx,562 builtin.Os.macosx,
...@@ -585,7 +590,7 @@ pub const CloseOperation = struct {...@@ -585,7 +590,7 @@ pub const CloseOperation = struct {
585 }590 }
586 }591 }
587592
588 pub fn getHandle(self: *CloseOperation) os.FileHandle {593 pub fn getHandle(self: *CloseOperation) fd_t {
589 switch (builtin.os) {594 switch (builtin.os) {
590 builtin.Os.linux,595 builtin.Os.linux,
591 builtin.Os.macosx,596 builtin.Os.macosx,
...@@ -606,11 +611,11 @@ pub const CloseOperation = struct {...@@ -606,11 +611,11 @@ pub const CloseOperation = struct {
606/// contents must remain alive until writeFile completes.611/// contents must remain alive until writeFile completes.
607/// TODO make this atomic or provide writeFileAtomic and rename this one to writeFileTruncate612/// TODO make this atomic or provide writeFileAtomic and rename this one to writeFileTruncate
608pub async fn writeFile(loop: *Loop, path: []const u8, contents: []const u8) !void {613pub async fn writeFile(loop: *Loop, path: []const u8, contents: []const u8) !void {
609 return await (async writeFileMode(loop, path, contents, os.File.default_mode) catch unreachable);614 return await (async writeFileMode(loop, path, contents, File.default_mode) catch unreachable);
610}615}
611616
612/// contents must remain alive until writeFile completes.617/// contents must remain alive until writeFile completes.
613pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8, mode: os.File.Mode) !void {618pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8, mode: File.Mode) !void {
614 switch (builtin.os) {619 switch (builtin.os) {
615 builtin.Os.linux,620 builtin.Os.linux,
616 builtin.Os.macosx,621 builtin.Os.macosx,
...@@ -623,19 +628,21 @@ pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8,...@@ -623,19 +628,21 @@ pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8,
623}628}
624629
625async fn writeFileWindows(loop: *Loop, path: []const u8, contents: []const u8) !void {630async fn writeFileWindows(loop: *Loop, path: []const u8, contents: []const u8) !void {
626 const handle = try os.windowsOpen(631 const handle = try windows.CreateFile(
627 path,632 path,
628 windows.GENERIC_WRITE,633 windows.GENERIC_WRITE,
629 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,634 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
635 null,
630 windows.CREATE_ALWAYS,636 windows.CREATE_ALWAYS,
631 windows.FILE_ATTRIBUTE_NORMAL | windows.FILE_FLAG_OVERLAPPED,637 windows.FILE_ATTRIBUTE_NORMAL | windows.FILE_FLAG_OVERLAPPED,
638 null,
632 );639 );
633 defer os.close(handle);640 defer os.close(handle);
634641
635 try await (async pwriteWindows(loop, handle, contents, 0) catch unreachable);642 try await (async pwriteWindows(loop, handle, contents, 0) catch unreachable);
636}643}
637644
638async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8, mode: os.File.Mode) !void {645async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8, mode: File.Mode) !void {
639 // workaround for https://github.com/ziglang/zig/issues/1194646 // workaround for https://github.com/ziglang/zig/issues/1194
640 suspend {647 suspend {
641 resume @handle();648 resume @handle();
...@@ -689,7 +696,7 @@ pub async fn readFile(loop: *Loop, file_path: []const u8, max_size: usize) ![]u8...@@ -689,7 +696,7 @@ pub async fn readFile(loop: *Loop, file_path: []const u8, max_size: usize) ![]u8
689 defer list.deinit();696 defer list.deinit();
690697
691 while (true) {698 while (true) {
692 try list.ensureCapacity(list.len + os.page_size);699 try list.ensureCapacity(list.len + mem.page_size);
693 const buf = list.items[list.len..];700 const buf = list.items[list.len..];
694 const buf_array = [][]u8{buf};701 const buf_array = [][]u8{buf};
695 const amt = try await (async preadv(loop, fd, buf_array, list.len) catch unreachable);702 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 {...@@ -787,7 +794,7 @@ pub fn Watch(comptime V: type) type {
787794
788 switch (builtin.os) {795 switch (builtin.os) {
789 builtin.Os.linux => {796 builtin.Os.linux => {
790 const inotify_fd = try os.linuxINotifyInit1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC);797 const inotify_fd = try os.inotify_init1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC);
791 errdefer os.close(inotify_fd);798 errdefer os.close(inotify_fd);
792799
793 var result: *Self = undefined;800 var result: *Self = undefined;
...@@ -880,7 +887,7 @@ pub fn Watch(comptime V: type) type {...@@ -880,7 +887,7 @@ pub fn Watch(comptime V: type) type {
880 }887 }
881888
882 async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V {889 async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V {
883 const resolved_path = try os.path.resolve(self.channel.loop.allocator, [][]const u8{file_path});890 const resolved_path = try std.fs.path.resolve(self.channel.loop.allocator, [][]const u8{file_path});
884 var resolved_path_consumed = false;891 var resolved_path_consumed = false;
885 defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);892 defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);
886893
...@@ -888,10 +895,7 @@ pub fn Watch(comptime V: type) type {...@@ -888,10 +895,7 @@ pub fn Watch(comptime V: type) type {
888 var close_op_consumed = false;895 var close_op_consumed = false;
889 defer if (!close_op_consumed) close_op.finish();896 defer if (!close_op_consumed) close_op.finish();
890897
891 const flags = switch (builtin.os) {898 const flags = if (os.darwin.is_the_target) os.O_SYMLINK | os.O_EVTONLY else 0;
892 builtin.Os.macosx => posix.O_SYMLINK | posix.O_EVTONLY,
893 else => 0,
894 };
895 const mode = 0;899 const mode = 0;
896 const fd = try await (async openPosix(self.channel.loop, resolved_path, flags, mode) catch unreachable);900 const fd = try await (async openPosix(self.channel.loop, resolved_path, flags, mode) catch unreachable);
897 close_op.setHandle(fd);901 close_op.setHandle(fd);
...@@ -943,16 +947,16 @@ pub fn Watch(comptime V: type) type {...@@ -943,16 +947,16 @@ pub fn Watch(comptime V: type) type {
943 while (true) {947 while (true) {
944 if (await (async self.channel.loop.bsdWaitKev(948 if (await (async self.channel.loop.bsdWaitKev(
945 @intCast(usize, close_op.getHandle()),949 @intCast(usize, close_op.getHandle()),
946 posix.EVFILT_VNODE,950 os.EVFILT_VNODE,
947 posix.NOTE_WRITE | posix.NOTE_DELETE,951 os.NOTE_WRITE | os.NOTE_DELETE,
948 ) catch unreachable)) |kev| {952 ) catch unreachable)) |kev| {
949 // TODO handle EV_ERROR953 // TODO handle EV_ERROR
950 if (kev.fflags & posix.NOTE_DELETE != 0) {954 if (kev.fflags & os.NOTE_DELETE != 0) {
951 await (async self.channel.put(Self.Event{955 await (async self.channel.put(Self.Event{
952 .id = Event.Id.Delete,956 .id = Event.Id.Delete,
953 .data = value_copy,957 .data = value_copy,
954 }) catch unreachable);958 }) catch unreachable);
955 } else if (kev.fflags & posix.NOTE_WRITE != 0) {959 } else if (kev.fflags & os.NOTE_WRITE != 0) {
956 await (async self.channel.put(Self.Event{960 await (async self.channel.put(Self.Event{
957 .id = Event.Id.CloseWrite,961 .id = Event.Id.CloseWrite,
958 .data = value_copy,962 .data = value_copy,
...@@ -961,6 +965,7 @@ pub fn Watch(comptime V: type) type {...@@ -961,6 +965,7 @@ pub fn Watch(comptime V: type) type {
961 } else |err| switch (err) {965 } else |err| switch (err) {
962 error.EventNotFound => unreachable,966 error.EventNotFound => unreachable,
963 error.ProcessNotFound => unreachable,967 error.ProcessNotFound => unreachable,
968 error.Overflow => unreachable,
964 error.AccessDenied, error.SystemResources => |casted_err| {969 error.AccessDenied, error.SystemResources => |casted_err| {
965 await (async self.channel.put(casted_err) catch unreachable);970 await (async self.channel.put(casted_err) catch unreachable);
966 },971 },
...@@ -971,17 +976,17 @@ pub fn Watch(comptime V: type) type {...@@ -971,17 +976,17 @@ pub fn Watch(comptime V: type) type {
971 async fn addFileLinux(self: *Self, file_path: []const u8, value: V) !?V {976 async fn addFileLinux(self: *Self, file_path: []const u8, value: V) !?V {
972 const value_copy = value;977 const value_copy = value;
973978
974 const dirname = os.path.dirname(file_path) orelse ".";979 const dirname = std.fs.path.dirname(file_path) orelse ".";
975 const dirname_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, dirname);980 const dirname_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, dirname);
976 var dirname_with_null_consumed = false;981 var dirname_with_null_consumed = false;
977 defer if (!dirname_with_null_consumed) self.channel.loop.allocator.free(dirname_with_null);982 defer if (!dirname_with_null_consumed) self.channel.loop.allocator.free(dirname_with_null);
978983
979 const basename = os.path.basename(file_path);984 const basename = std.fs.path.basename(file_path);
980 const basename_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, basename);985 const basename_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, basename);
981 var basename_with_null_consumed = false;986 var basename_with_null_consumed = false;
982 defer if (!basename_with_null_consumed) self.channel.loop.allocator.free(basename_with_null);987 defer if (!basename_with_null_consumed) self.channel.loop.allocator.free(basename_with_null);
983988
984 const wd = try os.linuxINotifyAddWatchC(989 const wd = try os.inotify_add_watchC(
985 self.os_data.inotify_fd,990 self.os_data.inotify_fd,
986 dirname_with_null.ptr,991 dirname_with_null.ptr,
987 os.linux.IN_CLOSE_WRITE | os.linux.IN_ONLYDIR | os.linux.IN_EXCL_UNLINK,992 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 {...@@ -1017,7 +1022,7 @@ pub fn Watch(comptime V: type) type {
1017 const value_copy = value;1022 const value_copy = value;
1018 // TODO we might need to convert dirname and basename to canonical file paths ("short"?)1023 // TODO we might need to convert dirname and basename to canonical file paths ("short"?)
10191024
1020 const dirname = try std.mem.dupe(self.channel.loop.allocator, u8, os.path.dirname(file_path) orelse ".");1025 const dirname = try std.mem.dupe(self.channel.loop.allocator, u8, std.fs.path.dirname(file_path) orelse ".");
1021 var dirname_consumed = false;1026 var dirname_consumed = false;
1022 defer if (!dirname_consumed) self.channel.loop.allocator.free(dirname);1027 defer if (!dirname_consumed) self.channel.loop.allocator.free(dirname);
10231028
...@@ -1025,13 +1030,13 @@ pub fn Watch(comptime V: type) type {...@@ -1025,13 +1030,13 @@ pub fn Watch(comptime V: type) type {
1025 defer self.channel.loop.allocator.free(dirname_utf16le);1030 defer self.channel.loop.allocator.free(dirname_utf16le);
10261031
1027 // TODO https://github.com/ziglang/zig/issues/2651032 // TODO https://github.com/ziglang/zig/issues/265
1028 const basename = os.path.basename(file_path);1033 const basename = std.fs.path.basename(file_path);
1029 const basename_utf16le_null = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, basename);1034 const basename_utf16le_null = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, basename);
1030 var basename_utf16le_null_consumed = false;1035 var basename_utf16le_null_consumed = false;
1031 defer if (!basename_utf16le_null_consumed) self.channel.loop.allocator.free(basename_utf16le_null);1036 defer if (!basename_utf16le_null_consumed) self.channel.loop.allocator.free(basename_utf16le_null);
1032 const basename_utf16le_no_null = basename_utf16le_null[0 .. basename_utf16le_null.len - 1];1037 const basename_utf16le_no_null = basename_utf16le_null[0 .. basename_utf16le_null.len - 1];
10331038
1034 const dir_handle = windows.CreateFileW(1039 const dir_handle = try windows.CreateFileW(
1035 dirname_utf16le.ptr,1040 dirname_utf16le.ptr,
1036 windows.FILE_LIST_DIRECTORY,1041 windows.FILE_LIST_DIRECTORY,
1037 windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE | windows.FILE_SHARE_WRITE,1042 windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE | windows.FILE_SHARE_WRITE,
...@@ -1040,16 +1045,8 @@ pub fn Watch(comptime V: type) type {...@@ -1040,16 +1045,8 @@ pub fn Watch(comptime V: type) type {
1040 windows.FILE_FLAG_BACKUP_SEMANTICS | windows.FILE_FLAG_OVERLAPPED,1045 windows.FILE_FLAG_BACKUP_SEMANTICS | windows.FILE_FLAG_OVERLAPPED,
1041 null,1046 null,
1042 );1047 );
1043 if (dir_handle == windows.INVALID_HANDLE_VALUE) {
1044 const err = windows.GetLastError();
1045 switch (err) {
1046 windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
1047 windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
1048 else => return os.unexpectedErrorWindows(err),
1049 }
1050 }
1051 var dir_handle_consumed = false;1048 var dir_handle_consumed = false;
1052 defer if (!dir_handle_consumed) os.close(dir_handle);1049 defer if (!dir_handle_consumed) windows.CloseHandle(dir_handle);
10531050
1054 const held = await (async self.os_data.table_lock.acquire() catch unreachable);1051 const held = await (async self.os_data.table_lock.acquire() catch unreachable);
1055 defer held.release();1052 defer held.release();
...@@ -1128,7 +1125,7 @@ pub fn Watch(comptime V: type) type {...@@ -1128,7 +1125,7 @@ pub fn Watch(comptime V: type) type {
1128 var event_buf: [4096]u8 align(@alignOf(windows.FILE_NOTIFY_INFORMATION)) = undefined;1125 var event_buf: [4096]u8 align(@alignOf(windows.FILE_NOTIFY_INFORMATION)) = undefined;
11291126
1130 // TODO handle this error not in the channel but in the setup1127 // TODO handle this error not in the channel but in the setup
1131 _ = os.windowsCreateIoCompletionPort(1128 _ = windows.CreateIoCompletionPort(
1132 dir_handle,1129 dir_handle,
1133 self.channel.loop.os_data.io_port,1130 self.channel.loop.os_data.io_port,
1134 undefined,1131 undefined,
...@@ -1144,10 +1141,10 @@ pub fn Watch(comptime V: type) type {...@@ -1144,10 +1141,10 @@ pub fn Watch(comptime V: type) type {
1144 self.channel.loop.beginOneEvent();1141 self.channel.loop.beginOneEvent();
1145 errdefer self.channel.loop.finishOneEvent();1142 errdefer self.channel.loop.finishOneEvent();
1146 errdefer {1143 errdefer {
1147 _ = windows.CancelIoEx(dir_handle, &resume_node.base.overlapped);1144 _ = windows.kernel32.CancelIoEx(dir_handle, &resume_node.base.overlapped);
1148 }1145 }
1149 suspend {1146 suspend {
1150 _ = windows.ReadDirectoryChangesW(1147 _ = windows.kernel32.ReadDirectoryChangesW(
1151 dir_handle,1148 dir_handle,
1152 &event_buf,1149 &event_buf,
1153 @intCast(windows.DWORD, event_buf.len),1150 @intCast(windows.DWORD, event_buf.len),
...@@ -1163,10 +1160,9 @@ pub fn Watch(comptime V: type) type {...@@ -1163,10 +1160,9 @@ pub fn Watch(comptime V: type) type {
1163 }1160 }
1164 }1161 }
1165 var bytes_transferred: windows.DWORD = undefined;1162 var bytes_transferred: windows.DWORD = undefined;
1166 if (windows.GetOverlappedResult(dir_handle, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {1163 if (windows.kernel32.GetOverlappedResult(dir_handle, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {
1167 const errno = windows.GetLastError();1164 const err = switch (windows.kernel32.GetLastError()) {
1168 const err = switch (errno) {1165 else => |err| windows.unexpectedError(err),
1169 else => os.unexpectedErrorWindows(errno),
1170 };1166 };
1171 await (async self.channel.put(err) catch unreachable);1167 await (async self.channel.put(err) catch unreachable);
1172 } else {1168 } else {
...@@ -1261,7 +1257,7 @@ pub fn Watch(comptime V: type) type {...@@ -1261,7 +1257,7 @@ pub fn Watch(comptime V: type) type {
1261 ev = @ptrCast(*os.linux.inotify_event, ptr);1257 ev = @ptrCast(*os.linux.inotify_event, ptr);
1262 if (ev.mask & os.linux.IN_CLOSE_WRITE == os.linux.IN_CLOSE_WRITE) {1258 if (ev.mask & os.linux.IN_CLOSE_WRITE == os.linux.IN_CLOSE_WRITE) {
1263 const basename_ptr = ptr + @sizeOf(os.linux.inotify_event);1259 const basename_ptr = ptr + @sizeOf(os.linux.inotify_event);
1264 const basename_with_null = basename_ptr[0 .. std.cstr.len(basename_ptr) + 1];1260 const basename_with_null = basename_ptr[0 .. std.mem.len(u8, basename_ptr) + 1];
1265 const user_value = blk: {1261 const user_value = blk: {
1266 const held = await (async watch.os_data.table_lock.acquire() catch unreachable);1262 const held = await (async watch.os_data.table_lock.acquire() catch unreachable);
1267 defer held.release();1263 defer held.release();
...@@ -1340,7 +1336,7 @@ async fn testFsWatchCantFail(loop: *Loop, result: *(anyerror!void)) void {...@@ -1340,7 +1336,7 @@ async fn testFsWatchCantFail(loop: *Loop, result: *(anyerror!void)) void {
1340}1336}
13411337
1342async fn testFsWatch(loop: *Loop) !void {1338async fn testFsWatch(loop: *Loop) !void {
1343 const file_path = try os.path.join(loop.allocator, [][]const u8{ test_tmp_dir, "file.txt" });1339 const file_path = try std.fs.path.join(loop.allocator, [][]const u8{ test_tmp_dir, "file.txt" });
1344 defer loop.allocator.free(file_path);1340 defer loop.allocator.free(file_path);
13451341
1346 const contents =1342 const contents =
...@@ -1366,7 +1362,7 @@ async fn testFsWatch(loop: *Loop) !void {...@@ -1366,7 +1362,7 @@ async fn testFsWatch(loop: *Loop) !void {
1366 defer if (!ev_consumed) cancel ev;1362 defer if (!ev_consumed) cancel ev;
13671363
1368 // overwrite line 21364 // overwrite line 2
1369 const fd = try await try async openReadWrite(loop, file_path, os.File.default_mode);1365 const fd = try await try async openReadWrite(loop, file_path, File.default_mode);
1370 {1366 {
1371 defer os.close(fd);1367 defer os.close(fd);
13721368
...@@ -1388,15 +1384,15 @@ async fn testFsWatch(loop: *Loop) !void {...@@ -1388,15 +1384,15 @@ async fn testFsWatch(loop: *Loop) !void {
1388}1384}
13891385
1390pub const OutStream = struct {1386pub const OutStream = struct {
1391 fd: os.FileHandle,1387 fd: fd_t,
1392 stream: Stream,1388 stream: Stream,
1393 loop: *Loop,1389 loop: *Loop,
1394 offset: usize,1390 offset: usize,
13951391
1396 pub const Error = os.File.WriteError;1392 pub const Error = File.WriteError;
1397 pub const Stream = event.io.OutStream(Error);1393 pub const Stream = event.io.OutStream(Error);
13981394
1399 pub fn init(loop: *Loop, fd: os.FileHandle, offset: usize) OutStream {1395 pub fn init(loop: *Loop, fd: fd_t, offset: usize) OutStream {
1400 return OutStream{1396 return OutStream{
1401 .fd = fd,1397 .fd = fd,
1402 .loop = loop,1398 .loop = loop,
...@@ -1414,7 +1410,7 @@ pub const OutStream = struct {...@@ -1414,7 +1410,7 @@ pub const OutStream = struct {
1414};1410};
14151411
1416pub const InStream = struct {1412pub const InStream = struct {
1417 fd: os.FileHandle,1413 fd: fd_t,
1418 stream: Stream,1414 stream: Stream,
1419 loop: *Loop,1415 loop: *Loop,
1420 offset: usize,1416 offset: usize,
...@@ -1422,7 +1418,7 @@ pub const InStream = struct {...@@ -1422,7 +1418,7 @@ pub const InStream = struct {
1422 pub const Error = PReadVError; // TODO make this not have OutOfMemory1418 pub const Error = PReadVError; // TODO make this not have OutOfMemory
1423 pub const Stream = event.io.InStream(Error);1419 pub const Stream = event.io.InStream(Error);
14241420
1425 pub fn init(loop: *Loop, fd: os.FileHandle, offset: usize) InStream {1421 pub fn init(loop: *Loop, fd: fd_t, offset: usize) InStream {
1426 return InStream{1422 return InStream{
1427 .fd = fd,1423 .fd = fd,
1428 .loop = loop,1424 .loop = loop,
std/event/group.zig+1-1
...@@ -155,7 +155,7 @@ async fn testGroup(loop: *Loop) void {...@@ -155,7 +155,7 @@ async fn testGroup(loop: *Loop) void {
155}155}
156156
157async fn sleepALittle(count: *usize) void {157async fn sleepALittle(count: *usize) void {
158 std.os.time.sleep(1 * std.os.time.millisecond);158 std.time.sleep(1 * std.time.millisecond);
159 _ = @atomicRmw(usize, count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);159 _ = @atomicRmw(usize, count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
160}160}
161161
std/event/loop.zig+134-134
...@@ -7,9 +7,9 @@ const AtomicRmwOp = builtin.AtomicRmwOp;...@@ -7,9 +7,9 @@ const AtomicRmwOp = builtin.AtomicRmwOp;
7const AtomicOrder = builtin.AtomicOrder;7const AtomicOrder = builtin.AtomicOrder;
8const fs = std.event.fs;8const fs = std.event.fs;
9const os = std.os;9const os = std.os;
10const posix = os.posix;
11const windows = os.windows;10const windows = os.windows;
12const maxInt = std.math.maxInt;11const maxInt = std.math.maxInt;
12const Thread = std.Thread;
1313
14pub const Loop = struct {14pub const Loop = struct {
15 allocator: *mem.Allocator,15 allocator: *mem.Allocator,
...@@ -17,7 +17,7 @@ pub const Loop = struct {...@@ -17,7 +17,7 @@ pub const Loop = struct {
17 os_data: OsData,17 os_data: OsData,
18 final_resume_node: ResumeNode,18 final_resume_node: ResumeNode,
19 pending_event_count: usize,19 pending_event_count: usize,
20 extra_threads: []*os.Thread,20 extra_threads: []*Thread,
2121
22 // pre-allocated eventfds. all permanently active.22 // pre-allocated eventfds. all permanently active.
23 // this is how we send promises to be resumed on other threads.23 // this is how we send promises to be resumed on other threads.
...@@ -32,7 +32,7 @@ pub const Loop = struct {...@@ -32,7 +32,7 @@ pub const Loop = struct {
32 overlapped: Overlapped,32 overlapped: Overlapped,
3333
34 pub const overlapped_init = switch (builtin.os) {34 pub const overlapped_init = switch (builtin.os) {
35 builtin.Os.windows => windows.OVERLAPPED{35 .windows => windows.OVERLAPPED{
36 .Internal = 0,36 .Internal = 0,
37 .InternalHigh = 0,37 .InternalHigh = 0,
38 .Offset = 0,38 .Offset = 0,
...@@ -50,13 +50,13 @@ pub const Loop = struct {...@@ -50,13 +50,13 @@ pub const Loop = struct {
50 };50 };
5151
52 pub const EventFd = switch (builtin.os) {52 pub const EventFd = switch (builtin.os) {
53 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => KEventFd,53 .macosx, .freebsd, .netbsd => KEventFd,
54 builtin.Os.linux => struct {54 .linux => struct {
55 base: ResumeNode,55 base: ResumeNode,
56 epoll_op: u32,56 epoll_op: u32,
57 eventfd: i32,57 eventfd: i32,
58 },58 },
59 builtin.Os.windows => struct {59 .windows => struct {
60 base: ResumeNode,60 base: ResumeNode,
61 completion_key: usize,61 completion_key: usize,
62 },62 },
...@@ -65,15 +65,15 @@ pub const Loop = struct {...@@ -65,15 +65,15 @@ pub const Loop = struct {
6565
66 const KEventFd = struct {66 const KEventFd = struct {
67 base: ResumeNode,67 base: ResumeNode,
68 kevent: posix.Kevent,68 kevent: os.Kevent,
69 };69 };
7070
71 pub const Basic = switch (builtin.os) {71 pub const Basic = switch (builtin.os) {
72 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => KEventBasic,72 .macosx, .freebsd, .netbsd => KEventBasic,
73 builtin.Os.linux => struct {73 .linux => struct {
74 base: ResumeNode,74 base: ResumeNode,
75 },75 },
76 builtin.Os.windows => struct {76 .windows => struct {
77 base: ResumeNode,77 base: ResumeNode,
78 },78 },
79 else => @compileError("unsupported OS"),79 else => @compileError("unsupported OS"),
...@@ -81,7 +81,7 @@ pub const Loop = struct {...@@ -81,7 +81,7 @@ pub const Loop = struct {
8181
82 const KEventBasic = struct {82 const KEventBasic = struct {
83 base: ResumeNode,83 base: ResumeNode,
84 kev: posix.Kevent,84 kev: os.Kevent,
85 };85 };
86 };86 };
8787
...@@ -99,7 +99,7 @@ pub const Loop = struct {...@@ -99,7 +99,7 @@ pub const Loop = struct {
99 /// have the correct pointer value.99 /// have the correct pointer value.
100 pub fn initMultiThreaded(self: *Loop, allocator: *mem.Allocator) !void {100 pub fn initMultiThreaded(self: *Loop, allocator: *mem.Allocator) !void {
101 if (builtin.single_threaded) @compileError("initMultiThreaded unavailable when building in single-threaded mode");101 if (builtin.single_threaded) @compileError("initMultiThreaded unavailable when building in single-threaded mode");
102 const core_count = try os.cpuCount(allocator);102 const core_count = try Thread.cpuCount();
103 return self.initInternal(allocator, core_count);103 return self.initInternal(allocator, core_count);
104 }104 }
105105
...@@ -127,7 +127,7 @@ pub const Loop = struct {...@@ -127,7 +127,7 @@ pub const Loop = struct {
127 );127 );
128 errdefer self.allocator.free(self.eventfd_resume_nodes);128 errdefer self.allocator.free(self.eventfd_resume_nodes);
129129
130 self.extra_threads = try self.allocator.alloc(*os.Thread, extra_thread_count);130 self.extra_threads = try self.allocator.alloc(*Thread, extra_thread_count);
131 errdefer self.allocator.free(self.extra_threads);131 errdefer self.allocator.free(self.extra_threads);
132132
133 try self.initOsData(extra_thread_count);133 try self.initOsData(extra_thread_count);
...@@ -139,15 +139,15 @@ pub const Loop = struct {...@@ -139,15 +139,15 @@ pub const Loop = struct {
139 self.allocator.free(self.extra_threads);139 self.allocator.free(self.extra_threads);
140 }140 }
141141
142 const InitOsDataError = os.LinuxEpollCreateError || mem.Allocator.Error || os.LinuxEventFdError ||142 const InitOsDataError = os.EpollCreateError || mem.Allocator.Error || os.EventFdError ||
143 os.SpawnThreadError || os.LinuxEpollCtlError || os.BsdKEventError ||143 Thread.SpawnError || os.EpollCtlError || os.KEventError ||
144 os.WindowsCreateIoCompletionPortError;144 windows.CreateIoCompletionPortError;
145145
146 const wakeup_bytes = []u8{0x1} ** 8;146 const wakeup_bytes = []u8{0x1} ** 8;
147147
148 fn initOsData(self: *Loop, extra_thread_count: usize) InitOsDataError!void {148 fn initOsData(self: *Loop, extra_thread_count: usize) InitOsDataError!void {
149 switch (builtin.os) {149 switch (builtin.os) {
150 builtin.Os.linux => {150 .linux => {
151 self.os_data.fs_queue = std.atomic.Queue(fs.Request).init();151 self.os_data.fs_queue = std.atomic.Queue(fs.Request).init();
152 self.os_data.fs_queue_item = 0;152 self.os_data.fs_queue_item = 0;
153 // we need another thread for the file system because Linux does not have an async153 // we need another thread for the file system because Linux does not have an async
...@@ -172,32 +172,32 @@ pub const Loop = struct {...@@ -172,32 +172,32 @@ pub const Loop = struct {
172 .handle = undefined,172 .handle = undefined,
173 .overlapped = ResumeNode.overlapped_init,173 .overlapped = ResumeNode.overlapped_init,
174 },174 },
175 .eventfd = try os.linuxEventFd(1, posix.EFD_CLOEXEC | posix.EFD_NONBLOCK),175 .eventfd = try os.eventfd(1, os.EFD_CLOEXEC | os.EFD_NONBLOCK),
176 .epoll_op = posix.EPOLL_CTL_ADD,176 .epoll_op = os.EPOLL_CTL_ADD,
177 },177 },
178 .next = undefined,178 .next = undefined,
179 };179 };
180 self.available_eventfd_resume_nodes.push(eventfd_node);180 self.available_eventfd_resume_nodes.push(eventfd_node);
181 }181 }
182182
183 self.os_data.epollfd = try os.linuxEpollCreate(posix.EPOLL_CLOEXEC);183 self.os_data.epollfd = try os.epoll_create1(os.EPOLL_CLOEXEC);
184 errdefer os.close(self.os_data.epollfd);184 errdefer os.close(self.os_data.epollfd);
185185
186 self.os_data.final_eventfd = try os.linuxEventFd(0, posix.EFD_CLOEXEC | posix.EFD_NONBLOCK);186 self.os_data.final_eventfd = try os.eventfd(0, os.EFD_CLOEXEC | os.EFD_NONBLOCK);
187 errdefer os.close(self.os_data.final_eventfd);187 errdefer os.close(self.os_data.final_eventfd);
188188
189 self.os_data.final_eventfd_event = posix.epoll_event{189 self.os_data.final_eventfd_event = os.epoll_event{
190 .events = posix.EPOLLIN,190 .events = os.EPOLLIN,
191 .data = posix.epoll_data{ .ptr = @ptrToInt(&self.final_resume_node) },191 .data = os.epoll_data{ .ptr = @ptrToInt(&self.final_resume_node) },
192 };192 };
193 try os.linuxEpollCtl(193 try os.epoll_ctl(
194 self.os_data.epollfd,194 self.os_data.epollfd,
195 posix.EPOLL_CTL_ADD,195 os.EPOLL_CTL_ADD,
196 self.os_data.final_eventfd,196 self.os_data.final_eventfd,
197 &self.os_data.final_eventfd_event,197 &self.os_data.final_eventfd_event,
198 );198 );
199199
200 self.os_data.fs_thread = try os.spawnThread(self, posixFsRun);200 self.os_data.fs_thread = try Thread.spawn(self, posixFsRun);
201 errdefer {201 errdefer {
202 self.posixFsRequest(&self.os_data.fs_end_request);202 self.posixFsRequest(&self.os_data.fs_end_request);
203 self.os_data.fs_thread.wait();203 self.os_data.fs_thread.wait();
...@@ -211,21 +211,21 @@ pub const Loop = struct {...@@ -211,21 +211,21 @@ pub const Loop = struct {
211 var extra_thread_index: usize = 0;211 var extra_thread_index: usize = 0;
212 errdefer {212 errdefer {
213 // writing 8 bytes to an eventfd cannot fail213 // writing 8 bytes to an eventfd cannot fail
214 os.posixWrite(self.os_data.final_eventfd, wakeup_bytes) catch unreachable;214 os.write(self.os_data.final_eventfd, wakeup_bytes) catch unreachable;
215 while (extra_thread_index != 0) {215 while (extra_thread_index != 0) {
216 extra_thread_index -= 1;216 extra_thread_index -= 1;
217 self.extra_threads[extra_thread_index].wait();217 self.extra_threads[extra_thread_index].wait();
218 }218 }
219 }219 }
220 while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {220 while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
221 self.extra_threads[extra_thread_index] = try os.spawnThread(self, workerRun);221 self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun);
222 }222 }
223 },223 },
224 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {224 .macosx, .freebsd, .netbsd => {
225 self.os_data.kqfd = try os.bsdKQueue();225 self.os_data.kqfd = try os.kqueue();
226 errdefer os.close(self.os_data.kqfd);226 errdefer os.close(self.os_data.kqfd);
227227
228 self.os_data.fs_kqfd = try os.bsdKQueue();228 self.os_data.fs_kqfd = try os.kqueue();
229 errdefer os.close(self.os_data.fs_kqfd);229 errdefer os.close(self.os_data.fs_kqfd);
230230
231 self.os_data.fs_queue = std.atomic.Queue(fs.Request).init();231 self.os_data.fs_queue = std.atomic.Queue(fs.Request).init();
...@@ -240,7 +240,7 @@ pub const Loop = struct {...@@ -240,7 +240,7 @@ pub const Loop = struct {
240 },240 },
241 };241 };
242242
243 const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];243 const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
244244
245 for (self.eventfd_resume_nodes) |*eventfd_node, i| {245 for (self.eventfd_resume_nodes) |*eventfd_node, i| {
246 eventfd_node.* = std.atomic.Stack(ResumeNode.EventFd).Node{246 eventfd_node.* = std.atomic.Stack(ResumeNode.EventFd).Node{
...@@ -251,10 +251,10 @@ pub const Loop = struct {...@@ -251,10 +251,10 @@ pub const Loop = struct {
251 .overlapped = ResumeNode.overlapped_init,251 .overlapped = ResumeNode.overlapped_init,
252 },252 },
253 // this one is for sending events253 // this one is for sending events
254 .kevent = posix.Kevent{254 .kevent = os.Kevent{
255 .ident = i,255 .ident = i,
256 .filter = posix.EVFILT_USER,256 .filter = os.EVFILT_USER,
257 .flags = posix.EV_CLEAR | posix.EV_ADD | posix.EV_DISABLE,257 .flags = os.EV_CLEAR | os.EV_ADD | os.EV_DISABLE,
258 .fflags = 0,258 .fflags = 0,
259 .data = 0,259 .data = 0,
260 .udata = @ptrToInt(&eventfd_node.data.base),260 .udata = @ptrToInt(&eventfd_node.data.base),
...@@ -263,46 +263,46 @@ pub const Loop = struct {...@@ -263,46 +263,46 @@ pub const Loop = struct {
263 .next = undefined,263 .next = undefined,
264 };264 };
265 self.available_eventfd_resume_nodes.push(eventfd_node);265 self.available_eventfd_resume_nodes.push(eventfd_node);
266 const kevent_array = (*const [1]posix.Kevent)(&eventfd_node.data.kevent);266 const kevent_array = (*const [1]os.Kevent)(&eventfd_node.data.kevent);
267 _ = try os.bsdKEvent(self.os_data.kqfd, kevent_array, empty_kevs, null);267 _ = try os.kevent(self.os_data.kqfd, kevent_array, empty_kevs, null);
268 eventfd_node.data.kevent.flags = posix.EV_CLEAR | posix.EV_ENABLE;268 eventfd_node.data.kevent.flags = os.EV_CLEAR | os.EV_ENABLE;
269 eventfd_node.data.kevent.fflags = posix.NOTE_TRIGGER;269 eventfd_node.data.kevent.fflags = os.NOTE_TRIGGER;
270 }270 }
271271
272 // Pre-add so that we cannot get error.SystemResources272 // Pre-add so that we cannot get error.SystemResources
273 // later when we try to activate it.273 // later when we try to activate it.
274 self.os_data.final_kevent = posix.Kevent{274 self.os_data.final_kevent = os.Kevent{
275 .ident = extra_thread_count,275 .ident = extra_thread_count,
276 .filter = posix.EVFILT_USER,276 .filter = os.EVFILT_USER,
277 .flags = posix.EV_ADD | posix.EV_DISABLE,277 .flags = os.EV_ADD | os.EV_DISABLE,
278 .fflags = 0,278 .fflags = 0,
279 .data = 0,279 .data = 0,
280 .udata = @ptrToInt(&self.final_resume_node),280 .udata = @ptrToInt(&self.final_resume_node),
281 };281 };
282 const final_kev_arr = (*const [1]posix.Kevent)(&self.os_data.final_kevent);282 const final_kev_arr = (*const [1]os.Kevent)(&self.os_data.final_kevent);
283 _ = try os.bsdKEvent(self.os_data.kqfd, final_kev_arr, empty_kevs, null);283 _ = try os.kevent(self.os_data.kqfd, final_kev_arr, empty_kevs, null);
284 self.os_data.final_kevent.flags = posix.EV_ENABLE;284 self.os_data.final_kevent.flags = os.EV_ENABLE;
285 self.os_data.final_kevent.fflags = posix.NOTE_TRIGGER;285 self.os_data.final_kevent.fflags = os.NOTE_TRIGGER;
286286
287 self.os_data.fs_kevent_wake = posix.Kevent{287 self.os_data.fs_kevent_wake = os.Kevent{
288 .ident = 0,288 .ident = 0,
289 .filter = posix.EVFILT_USER,289 .filter = os.EVFILT_USER,
290 .flags = posix.EV_ADD | posix.EV_ENABLE,290 .flags = os.EV_ADD | os.EV_ENABLE,
291 .fflags = posix.NOTE_TRIGGER,291 .fflags = os.NOTE_TRIGGER,
292 .data = 0,292 .data = 0,
293 .udata = undefined,293 .udata = undefined,
294 };294 };
295295
296 self.os_data.fs_kevent_wait = posix.Kevent{296 self.os_data.fs_kevent_wait = os.Kevent{
297 .ident = 0,297 .ident = 0,
298 .filter = posix.EVFILT_USER,298 .filter = os.EVFILT_USER,
299 .flags = posix.EV_ADD | posix.EV_CLEAR,299 .flags = os.EV_ADD | os.EV_CLEAR,
300 .fflags = 0,300 .fflags = 0,
301 .data = 0,301 .data = 0,
302 .udata = undefined,302 .udata = undefined,
303 };303 };
304304
305 self.os_data.fs_thread = try os.spawnThread(self, posixFsRun);305 self.os_data.fs_thread = try Thread.spawn(self, posixFsRun);
306 errdefer {306 errdefer {
307 self.posixFsRequest(&self.os_data.fs_end_request);307 self.posixFsRequest(&self.os_data.fs_end_request);
308 self.os_data.fs_thread.wait();308 self.os_data.fs_thread.wait();
...@@ -315,24 +315,24 @@ pub const Loop = struct {...@@ -315,24 +315,24 @@ pub const Loop = struct {
315315
316 var extra_thread_index: usize = 0;316 var extra_thread_index: usize = 0;
317 errdefer {317 errdefer {
318 _ = os.bsdKEvent(self.os_data.kqfd, final_kev_arr, empty_kevs, null) catch unreachable;318 _ = os.kevent(self.os_data.kqfd, final_kev_arr, empty_kevs, null) catch unreachable;
319 while (extra_thread_index != 0) {319 while (extra_thread_index != 0) {
320 extra_thread_index -= 1;320 extra_thread_index -= 1;
321 self.extra_threads[extra_thread_index].wait();321 self.extra_threads[extra_thread_index].wait();
322 }322 }
323 }323 }
324 while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {324 while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
325 self.extra_threads[extra_thread_index] = try os.spawnThread(self, workerRun);325 self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun);
326 }326 }
327 },327 },
328 builtin.Os.windows => {328 .windows => {
329 self.os_data.io_port = try os.windowsCreateIoCompletionPort(329 self.os_data.io_port = try windows.CreateIoCompletionPort(
330 windows.INVALID_HANDLE_VALUE,330 windows.INVALID_HANDLE_VALUE,
331 null,331 null,
332 undefined,332 undefined,
333 maxInt(windows.DWORD),333 maxInt(windows.DWORD),
334 );334 );
335 errdefer os.close(self.os_data.io_port);335 errdefer windows.CloseHandle(self.os_data.io_port);
336336
337 for (self.eventfd_resume_nodes) |*eventfd_node, i| {337 for (self.eventfd_resume_nodes) |*eventfd_node, i| {
338 eventfd_node.* = std.atomic.Stack(ResumeNode.EventFd).Node{338 eventfd_node.* = std.atomic.Stack(ResumeNode.EventFd).Node{
...@@ -361,7 +361,7 @@ pub const Loop = struct {...@@ -361,7 +361,7 @@ pub const Loop = struct {
361 while (i < extra_thread_index) : (i += 1) {361 while (i < extra_thread_index) : (i += 1) {
362 while (true) {362 while (true) {
363 const overlapped = &self.final_resume_node.overlapped;363 const overlapped = &self.final_resume_node.overlapped;
364 os.windowsPostQueuedCompletionStatus(self.os_data.io_port, undefined, undefined, overlapped) catch continue;364 windows.PostQueuedCompletionStatus(self.os_data.io_port, undefined, undefined, overlapped) catch continue;
365 break;365 break;
366 }366 }
367 }367 }
...@@ -371,7 +371,7 @@ pub const Loop = struct {...@@ -371,7 +371,7 @@ pub const Loop = struct {
371 }371 }
372 }372 }
373 while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {373 while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
374 self.extra_threads[extra_thread_index] = try os.spawnThread(self, workerRun);374 self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun);
375 }375 }
376 },376 },
377 else => {},377 else => {},
...@@ -380,18 +380,18 @@ pub const Loop = struct {...@@ -380,18 +380,18 @@ pub const Loop = struct {
380380
381 fn deinitOsData(self: *Loop) void {381 fn deinitOsData(self: *Loop) void {
382 switch (builtin.os) {382 switch (builtin.os) {
383 builtin.Os.linux => {383 .linux => {
384 os.close(self.os_data.final_eventfd);384 os.close(self.os_data.final_eventfd);
385 while (self.available_eventfd_resume_nodes.pop()) |node| os.close(node.data.eventfd);385 while (self.available_eventfd_resume_nodes.pop()) |node| os.close(node.data.eventfd);
386 os.close(self.os_data.epollfd);386 os.close(self.os_data.epollfd);
387 self.allocator.free(self.eventfd_resume_nodes);387 self.allocator.free(self.eventfd_resume_nodes);
388 },388 },
389 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {389 .macosx, .freebsd, .netbsd => {
390 os.close(self.os_data.kqfd);390 os.close(self.os_data.kqfd);
391 os.close(self.os_data.fs_kqfd);391 os.close(self.os_data.fs_kqfd);
392 },392 },
393 builtin.Os.windows => {393 .windows => {
394 os.close(self.os_data.io_port);394 windows.CloseHandle(self.os_data.io_port);
395 },395 },
396 else => {},396 else => {},
397 }397 }
...@@ -400,28 +400,28 @@ pub const Loop = struct {...@@ -400,28 +400,28 @@ pub const Loop = struct {
400 /// resume_node must live longer than the promise that it holds a reference to.400 /// resume_node must live longer than the promise that it holds a reference to.
401 /// flags must contain EPOLLET401 /// flags must contain EPOLLET
402 pub fn linuxAddFd(self: *Loop, fd: i32, resume_node: *ResumeNode, flags: u32) !void {402 pub fn linuxAddFd(self: *Loop, fd: i32, resume_node: *ResumeNode, flags: u32) !void {
403 assert(flags & posix.EPOLLET == posix.EPOLLET);403 assert(flags & os.EPOLLET == os.EPOLLET);
404 self.beginOneEvent();404 self.beginOneEvent();
405 errdefer self.finishOneEvent();405 errdefer self.finishOneEvent();
406 try self.linuxModFd(406 try self.linuxModFd(
407 fd,407 fd,
408 posix.EPOLL_CTL_ADD,408 os.EPOLL_CTL_ADD,
409 flags,409 flags,
410 resume_node,410 resume_node,
411 );411 );
412 }412 }
413413
414 pub fn linuxModFd(self: *Loop, fd: i32, op: u32, flags: u32, resume_node: *ResumeNode) !void {414 pub fn linuxModFd(self: *Loop, fd: i32, op: u32, flags: u32, resume_node: *ResumeNode) !void {
415 assert(flags & posix.EPOLLET == posix.EPOLLET);415 assert(flags & os.EPOLLET == os.EPOLLET);
416 var ev = os.linux.epoll_event{416 var ev = os.linux.epoll_event{
417 .events = flags,417 .events = flags,
418 .data = os.linux.epoll_data{ .ptr = @ptrToInt(resume_node) },418 .data = os.linux.epoll_data{ .ptr = @ptrToInt(resume_node) },
419 };419 };
420 try os.linuxEpollCtl(self.os_data.epollfd, op, fd, &ev);420 try os.epoll_ctl(self.os_data.epollfd, op, fd, &ev);
421 }421 }
422422
423 pub fn linuxRemoveFd(self: *Loop, fd: i32) void {423 pub fn linuxRemoveFd(self: *Loop, fd: i32) void {
424 os.linuxEpollCtl(self.os_data.epollfd, os.linux.EPOLL_CTL_DEL, fd, undefined) catch {};424 os.epoll_ctl(self.os_data.epollfd, os.linux.EPOLL_CTL_DEL, fd, undefined) catch {};
425 self.finishOneEvent();425 self.finishOneEvent();
426 }426 }
427427
...@@ -440,7 +440,7 @@ pub const Loop = struct {...@@ -440,7 +440,7 @@ pub const Loop = struct {
440 }440 }
441 }441 }
442442
443 pub async fn bsdWaitKev(self: *Loop, ident: usize, filter: i16, fflags: u32) !posix.Kevent {443 pub async fn bsdWaitKev(self: *Loop, ident: usize, filter: i16, fflags: u32) !os.Kevent {
444 // TODO #1194444 // TODO #1194
445 suspend {445 suspend {
446 resume @handle();446 resume @handle();
...@@ -464,31 +464,31 @@ pub const Loop = struct {...@@ -464,31 +464,31 @@ pub const Loop = struct {
464 pub fn bsdAddKev(self: *Loop, resume_node: *ResumeNode.Basic, ident: usize, filter: i16, fflags: u32) !void {464 pub fn bsdAddKev(self: *Loop, resume_node: *ResumeNode.Basic, ident: usize, filter: i16, fflags: u32) !void {
465 self.beginOneEvent();465 self.beginOneEvent();
466 errdefer self.finishOneEvent();466 errdefer self.finishOneEvent();
467 var kev = posix.Kevent{467 var kev = os.Kevent{
468 .ident = ident,468 .ident = ident,
469 .filter = filter,469 .filter = filter,
470 .flags = posix.EV_ADD | posix.EV_ENABLE | posix.EV_CLEAR,470 .flags = os.EV_ADD | os.EV_ENABLE | os.EV_CLEAR,
471 .fflags = fflags,471 .fflags = fflags,
472 .data = 0,472 .data = 0,
473 .udata = @ptrToInt(&resume_node.base),473 .udata = @ptrToInt(&resume_node.base),
474 };474 };
475 const kevent_array = (*const [1]posix.Kevent)(&kev);475 const kevent_array = (*const [1]os.Kevent)(&kev);
476 const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];476 const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
477 _ = try os.bsdKEvent(self.os_data.kqfd, kevent_array, empty_kevs, null);477 _ = try os.kevent(self.os_data.kqfd, kevent_array, empty_kevs, null);
478 }478 }
479479
480 pub fn bsdRemoveKev(self: *Loop, ident: usize, filter: i16) void {480 pub fn bsdRemoveKev(self: *Loop, ident: usize, filter: i16) void {
481 var kev = posix.Kevent{481 var kev = os.Kevent{
482 .ident = ident,482 .ident = ident,
483 .filter = filter,483 .filter = filter,
484 .flags = posix.EV_DELETE,484 .flags = os.EV_DELETE,
485 .fflags = 0,485 .fflags = 0,
486 .data = 0,486 .data = 0,
487 .udata = 0,487 .udata = 0,
488 };488 };
489 const kevent_array = (*const [1]posix.Kevent)(&kev);489 const kevent_array = (*const [1]os.Kevent)(&kev);
490 const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];490 const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
491 _ = os.bsdKEvent(self.os_data.kqfd, kevent_array, empty_kevs, null) catch undefined;491 _ = os.kevent(self.os_data.kqfd, kevent_array, empty_kevs, null) catch undefined;
492 self.finishOneEvent();492 self.finishOneEvent();
493 }493 }
494494
...@@ -501,18 +501,18 @@ pub const Loop = struct {...@@ -501,18 +501,18 @@ pub const Loop = struct {
501 const eventfd_node = &resume_stack_node.data;501 const eventfd_node = &resume_stack_node.data;
502 eventfd_node.base.handle = next_tick_node.data;502 eventfd_node.base.handle = next_tick_node.data;
503 switch (builtin.os) {503 switch (builtin.os) {
504 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {504 .macosx, .freebsd, .netbsd => {
505 const kevent_array = (*const [1]posix.Kevent)(&eventfd_node.kevent);505 const kevent_array = (*const [1]os.Kevent)(&eventfd_node.kevent);
506 const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];506 const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
507 _ = os.bsdKEvent(self.os_data.kqfd, kevent_array, empty_kevs, null) catch {507 _ = os.kevent(self.os_data.kqfd, kevent_array, empty_kevs, null) catch {
508 self.next_tick_queue.unget(next_tick_node);508 self.next_tick_queue.unget(next_tick_node);
509 self.available_eventfd_resume_nodes.push(resume_stack_node);509 self.available_eventfd_resume_nodes.push(resume_stack_node);
510 return;510 return;
511 };511 };
512 },512 },
513 builtin.Os.linux => {513 .linux => {
514 // the pending count is already accounted for514 // the pending count is already accounted for
515 const epoll_events = posix.EPOLLONESHOT | os.linux.EPOLLIN | os.linux.EPOLLOUT |515 const epoll_events = os.EPOLLONESHOT | os.linux.EPOLLIN | os.linux.EPOLLOUT |
516 os.linux.EPOLLET;516 os.linux.EPOLLET;
517 self.linuxModFd(517 self.linuxModFd(
518 eventfd_node.eventfd,518 eventfd_node.eventfd,
...@@ -525,8 +525,8 @@ pub const Loop = struct {...@@ -525,8 +525,8 @@ pub const Loop = struct {
525 return;525 return;
526 };526 };
527 },527 },
528 builtin.Os.windows => {528 .windows => {
529 os.windowsPostQueuedCompletionStatus(529 windows.PostQueuedCompletionStatus(
530 self.os_data.io_port,530 self.os_data.io_port,
531 undefined,531 undefined,
532 undefined,532 undefined,
...@@ -623,26 +623,26 @@ pub const Loop = struct {...@@ -623,26 +623,26 @@ pub const Loop = struct {
623 if (prev == 1) {623 if (prev == 1) {
624 // cause all the threads to stop624 // cause all the threads to stop
625 switch (builtin.os) {625 switch (builtin.os) {
626 builtin.Os.linux => {626 .linux => {
627 self.posixFsRequest(&self.os_data.fs_end_request);627 self.posixFsRequest(&self.os_data.fs_end_request);
628 // writing 8 bytes to an eventfd cannot fail628 // writing 8 bytes to an eventfd cannot fail
629 os.posixWrite(self.os_data.final_eventfd, wakeup_bytes) catch unreachable;629 os.write(self.os_data.final_eventfd, wakeup_bytes) catch unreachable;
630 return;630 return;
631 },631 },
632 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {632 .macosx, .freebsd, .netbsd => {
633 self.posixFsRequest(&self.os_data.fs_end_request);633 self.posixFsRequest(&self.os_data.fs_end_request);
634 const final_kevent = (*const [1]posix.Kevent)(&self.os_data.final_kevent);634 const final_kevent = (*const [1]os.Kevent)(&self.os_data.final_kevent);
635 const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];635 const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
636 // cannot fail because we already added it and this just enables it636 // cannot fail because we already added it and this just enables it
637 _ = os.bsdKEvent(self.os_data.kqfd, final_kevent, empty_kevs, null) catch unreachable;637 _ = os.kevent(self.os_data.kqfd, final_kevent, empty_kevs, null) catch unreachable;
638 return;638 return;
639 },639 },
640 builtin.Os.windows => {640 .windows => {
641 var i: usize = 0;641 var i: usize = 0;
642 while (i < self.extra_threads.len + 1) : (i += 1) {642 while (i < self.extra_threads.len + 1) : (i += 1) {
643 while (true) {643 while (true) {
644 const overlapped = &self.final_resume_node.overlapped;644 const overlapped = &self.final_resume_node.overlapped;
645 os.windowsPostQueuedCompletionStatus(self.os_data.io_port, undefined, undefined, overlapped) catch continue;645 windows.PostQueuedCompletionStatus(self.os_data.io_port, undefined, undefined, overlapped) catch continue;
646 break;646 break;
647 }647 }
648 }648 }
...@@ -663,10 +663,10 @@ pub const Loop = struct {...@@ -663,10 +663,10 @@ pub const Loop = struct {
663 }663 }
664664
665 switch (builtin.os) {665 switch (builtin.os) {
666 builtin.Os.linux => {666 .linux => {
667 // only process 1 event so we don't steal from other threads667 // only process 1 event so we don't steal from other threads
668 var events: [1]os.linux.epoll_event = undefined;668 var events: [1]os.linux.epoll_event = undefined;
669 const count = os.linuxEpollWait(self.os_data.epollfd, events[0..], -1);669 const count = os.epoll_wait(self.os_data.epollfd, events[0..], -1);
670 for (events[0..count]) |ev| {670 for (events[0..count]) |ev| {
671 const resume_node = @intToPtr(*ResumeNode, ev.data.ptr);671 const resume_node = @intToPtr(*ResumeNode, ev.data.ptr);
672 const handle = resume_node.handle;672 const handle = resume_node.handle;
...@@ -676,7 +676,7 @@ pub const Loop = struct {...@@ -676,7 +676,7 @@ pub const Loop = struct {
676 ResumeNode.Id.Stop => return,676 ResumeNode.Id.Stop => return,
677 ResumeNode.Id.EventFd => {677 ResumeNode.Id.EventFd => {
678 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);678 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);
679 event_fd_node.epoll_op = posix.EPOLL_CTL_MOD;679 event_fd_node.epoll_op = os.EPOLL_CTL_MOD;
680 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);680 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);
681 self.available_eventfd_resume_nodes.push(stack_node);681 self.available_eventfd_resume_nodes.push(stack_node);
682 },682 },
...@@ -687,10 +687,10 @@ pub const Loop = struct {...@@ -687,10 +687,10 @@ pub const Loop = struct {
687 }687 }
688 }688 }
689 },689 },
690 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {690 .macosx, .freebsd, .netbsd => {
691 var eventlist: [1]posix.Kevent = undefined;691 var eventlist: [1]os.Kevent = undefined;
692 const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];692 const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
693 const count = os.bsdKEvent(self.os_data.kqfd, empty_kevs, eventlist[0..], null) catch unreachable;693 const count = os.kevent(self.os_data.kqfd, empty_kevs, eventlist[0..], null) catch unreachable;
694 for (eventlist[0..count]) |ev| {694 for (eventlist[0..count]) |ev| {
695 const resume_node = @intToPtr(*ResumeNode, ev.udata);695 const resume_node = @intToPtr(*ResumeNode, ev.udata);
696 const handle = resume_node.handle;696 const handle = resume_node.handle;
...@@ -713,16 +713,16 @@ pub const Loop = struct {...@@ -713,16 +713,16 @@ pub const Loop = struct {
713 }713 }
714 }714 }
715 },715 },
716 builtin.Os.windows => {716 .windows => {
717 var completion_key: usize = undefined;717 var completion_key: usize = undefined;
718 const overlapped = while (true) {718 const overlapped = while (true) {
719 var nbytes: windows.DWORD = undefined;719 var nbytes: windows.DWORD = undefined;
720 var overlapped: ?*windows.OVERLAPPED = undefined;720 var overlapped: ?*windows.OVERLAPPED = undefined;
721 switch (os.windowsGetQueuedCompletionStatus(self.os_data.io_port, &nbytes, &completion_key, &overlapped, windows.INFINITE)) {721 switch (windows.GetQueuedCompletionStatus(self.os_data.io_port, &nbytes, &completion_key, &overlapped, windows.INFINITE)) {
722 os.WindowsWaitResult.Aborted => return,722 .Aborted => return,
723 os.WindowsWaitResult.Normal => {},723 .Normal => {},
724 os.WindowsWaitResult.EOF => {},724 .EOF => {},
725 os.WindowsWaitResult.Cancelled => continue,725 .Cancelled => continue,
726 }726 }
727 if (overlapped) |o| break o;727 if (overlapped) |o| break o;
728 } else unreachable; // TODO else unreachable should not be necessary728 } else unreachable; // TODO else unreachable should not be necessary
...@@ -751,16 +751,16 @@ pub const Loop = struct {...@@ -751,16 +751,16 @@ pub const Loop = struct {
751 self.os_data.fs_queue.put(request_node);751 self.os_data.fs_queue.put(request_node);
752 switch (builtin.os) {752 switch (builtin.os) {
753 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {753 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
754 const fs_kevs = (*const [1]posix.Kevent)(&self.os_data.fs_kevent_wake);754 const fs_kevs = (*const [1]os.Kevent)(&self.os_data.fs_kevent_wake);
755 const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];755 const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
756 _ = os.bsdKEvent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable;756 _ = os.kevent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable;
757 },757 },
758 builtin.Os.linux => {758 builtin.Os.linux => {
759 _ = @atomicRmw(i32, &self.os_data.fs_queue_item, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);759 _ = @atomicRmw(i32, &self.os_data.fs_queue_item, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
760 const rc = os.linux.futex_wake(&self.os_data.fs_queue_item, os.linux.FUTEX_WAKE, 1);760 const rc = os.linux.futex_wake(&self.os_data.fs_queue_item, os.linux.FUTEX_WAKE, 1);
761 switch (os.linux.getErrno(rc)) {761 switch (os.linux.getErrno(rc)) {
762 0 => {},762 0 => {},
763 posix.EINVAL => unreachable,763 os.EINVAL => unreachable,
764 else => unreachable,764 else => unreachable,
765 }765 }
766 },766 },
...@@ -783,24 +783,24 @@ pub const Loop = struct {...@@ -783,24 +783,24 @@ pub const Loop = struct {
783 switch (node.data.msg) {783 switch (node.data.msg) {
784 @TagType(fs.Request.Msg).End => return,784 @TagType(fs.Request.Msg).End => return,
785 @TagType(fs.Request.Msg).PWriteV => |*msg| {785 @TagType(fs.Request.Msg).PWriteV => |*msg| {
786 msg.result = os.posix_pwritev(msg.fd, msg.iov.ptr, msg.iov.len, msg.offset);786 msg.result = os.pwritev(msg.fd, msg.iov, msg.offset);
787 },787 },
788 @TagType(fs.Request.Msg).PReadV => |*msg| {788 @TagType(fs.Request.Msg).PReadV => |*msg| {
789 msg.result = os.posix_preadv(msg.fd, msg.iov.ptr, msg.iov.len, msg.offset);789 msg.result = os.preadv(msg.fd, msg.iov, msg.offset);
790 },790 },
791 @TagType(fs.Request.Msg).Open => |*msg| {791 @TagType(fs.Request.Msg).Open => |*msg| {
792 msg.result = os.posixOpenC(msg.path.ptr, msg.flags, msg.mode);792 msg.result = os.openC(msg.path.ptr, msg.flags, msg.mode);
793 },793 },
794 @TagType(fs.Request.Msg).Close => |*msg| os.close(msg.fd),794 @TagType(fs.Request.Msg).Close => |*msg| os.close(msg.fd),
795 @TagType(fs.Request.Msg).WriteFile => |*msg| blk: {795 @TagType(fs.Request.Msg).WriteFile => |*msg| blk: {
796 const flags = posix.O_LARGEFILE | posix.O_WRONLY | posix.O_CREAT |796 const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT |
797 posix.O_CLOEXEC | posix.O_TRUNC;797 os.O_CLOEXEC | os.O_TRUNC;
798 const fd = os.posixOpenC(msg.path.ptr, flags, msg.mode) catch |err| {798 const fd = os.openC(msg.path.ptr, flags, msg.mode) catch |err| {
799 msg.result = err;799 msg.result = err;
800 break :blk;800 break :blk;
801 };801 };
802 defer os.close(fd);802 defer os.close(fd);
803 msg.result = os.posixWrite(fd, msg.contents);803 msg.result = os.write(fd, msg.contents);
804 },804 },
805 }805 }
806 switch (node.data.finish) {806 switch (node.data.finish) {
...@@ -816,14 +816,14 @@ pub const Loop = struct {...@@ -816,14 +816,14 @@ pub const Loop = struct {
816 builtin.Os.linux => {816 builtin.Os.linux => {
817 const rc = os.linux.futex_wait(&self.os_data.fs_queue_item, os.linux.FUTEX_WAIT, 0, null);817 const rc = os.linux.futex_wait(&self.os_data.fs_queue_item, os.linux.FUTEX_WAIT, 0, null);
818 switch (os.linux.getErrno(rc)) {818 switch (os.linux.getErrno(rc)) {
819 0, posix.EINTR, posix.EAGAIN => continue,819 0, os.EINTR, os.EAGAIN => continue,
820 else => unreachable,820 else => unreachable,
821 }821 }
822 },822 },
823 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {823 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
824 const fs_kevs = (*const [1]posix.Kevent)(&self.os_data.fs_kevent_wait);824 const fs_kevs = (*const [1]os.Kevent)(&self.os_data.fs_kevent_wait);
825 var out_kevs: [1]posix.Kevent = undefined;825 var out_kevs: [1]os.Kevent = undefined;
826 _ = os.bsdKEvent(self.os_data.fs_kqfd, fs_kevs, out_kevs[0..], null) catch unreachable;826 _ = os.kevent(self.os_data.fs_kqfd, fs_kevs, out_kevs[0..], null) catch unreachable;
827 },827 },
828 else => @compileError("Unsupported OS"),828 else => @compileError("Unsupported OS"),
829 }829 }
...@@ -831,9 +831,9 @@ pub const Loop = struct {...@@ -831,9 +831,9 @@ pub const Loop = struct {
831 }831 }
832832
833 const OsData = switch (builtin.os) {833 const OsData = switch (builtin.os) {
834 builtin.Os.linux => LinuxOsData,834 .linux => LinuxOsData,
835 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => KEventData,835 .macosx, .freebsd, .netbsd => KEventData,
836 builtin.Os.windows => struct {836 .windows => struct {
837 io_port: windows.HANDLE,837 io_port: windows.HANDLE,
838 extra_thread_count: usize,838 extra_thread_count: usize,
839 },839 },
...@@ -842,10 +842,10 @@ pub const Loop = struct {...@@ -842,10 +842,10 @@ pub const Loop = struct {
842842
843 const KEventData = struct {843 const KEventData = struct {
844 kqfd: i32,844 kqfd: i32,
845 final_kevent: posix.Kevent,845 final_kevent: os.Kevent,
846 fs_kevent_wake: posix.Kevent,846 fs_kevent_wake: os.Kevent,
847 fs_kevent_wait: posix.Kevent,847 fs_kevent_wait: os.Kevent,
848 fs_thread: *os.Thread,848 fs_thread: *Thread,
849 fs_kqfd: i32,849 fs_kqfd: i32,
850 fs_queue: std.atomic.Queue(fs.Request),850 fs_queue: std.atomic.Queue(fs.Request),
851 fs_end_request: fs.RequestNode,851 fs_end_request: fs.RequestNode,
...@@ -855,7 +855,7 @@ pub const Loop = struct {...@@ -855,7 +855,7 @@ pub const Loop = struct {
855 epollfd: i32,855 epollfd: i32,
856 final_eventfd: i32,856 final_eventfd: i32,
857 final_eventfd_event: os.linux.epoll_event,857 final_eventfd_event: os.linux.epoll_event,
858 fs_thread: *os.Thread,858 fs_thread: *Thread,
859 fs_queue_item: i32,859 fs_queue_item: i32,
860 fs_queue: std.atomic.Queue(fs.Request),860 fs_queue: std.atomic.Queue(fs.Request),
861 fs_end_request: fs.RequestNode,861 fs_end_request: fs.RequestNode,
std/event/net.zig+81-87
...@@ -4,11 +4,12 @@ const testing = std.testing;...@@ -4,11 +4,12 @@ const testing = std.testing;
4const event = std.event;4const event = std.event;
5const mem = std.mem;5const mem = std.mem;
6const os = std.os;6const os = std.os;
7const posix = os.posix;
8const Loop = std.event.Loop;7const Loop = std.event.Loop;
8const File = std.fs.File;
9const fd_t = os.fd_t;
910
10pub const Server = struct {11pub const Server = struct {
11 handleRequestFn: async<*mem.Allocator> fn (*Server, *const std.net.Address, os.File) void,12 handleRequestFn: async<*mem.Allocator> fn (*Server, *const std.net.Address, File) void,
1213
13 loop: *Loop,14 loop: *Loop,
14 sockfd: ?i32,15 sockfd: ?i32,
...@@ -40,30 +41,33 @@ pub const Server = struct {...@@ -40,30 +41,33 @@ pub const Server = struct {
40 pub fn listen(41 pub fn listen(
41 self: *Server,42 self: *Server,
42 address: *const std.net.Address,43 address: *const std.net.Address,
43 handleRequestFn: async<*mem.Allocator> fn (*Server, *const std.net.Address, os.File) void,44 handleRequestFn: async<*mem.Allocator> fn (*Server, *const std.net.Address, File) void,
44 ) !void {45 ) !void {
45 self.handleRequestFn = handleRequestFn;46 self.handleRequestFn = handleRequestFn;
4647
47 const sockfd = try os.posixSocket(posix.AF_INET, posix.SOCK_STREAM | posix.SOCK_CLOEXEC | posix.SOCK_NONBLOCK, posix.PROTO_tcp);48 const sockfd = try os.socket(os.AF_INET, os.SOCK_STREAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK, os.PROTO_tcp);
48 errdefer os.close(sockfd);49 errdefer os.close(sockfd);
49 self.sockfd = sockfd;50 self.sockfd = sockfd;
5051
51 try os.posixBind(sockfd, &address.os_addr);52 try os.bind(sockfd, &address.os_addr);
52 try os.posixListen(sockfd, posix.SOMAXCONN);53 try os.listen(sockfd, os.SOMAXCONN);
53 self.listen_address = std.net.Address.initPosix(try os.posixGetSockName(sockfd));54 self.listen_address = std.net.Address.initPosix(try os.getsockname(sockfd));
5455
55 self.accept_coro = try async<self.loop.allocator> Server.handler(self);56 self.accept_coro = try async<self.loop.allocator> Server.handler(self);
56 errdefer cancel self.accept_coro.?;57 errdefer cancel self.accept_coro.?;
5758
58 self.listen_resume_node.handle = self.accept_coro.?;59 self.listen_resume_node.handle = self.accept_coro.?;
59 try self.loop.linuxAddFd(sockfd, &self.listen_resume_node, posix.EPOLLIN | posix.EPOLLOUT | posix.EPOLLET);60 try self.loop.linuxAddFd(sockfd, &self.listen_resume_node, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
60 errdefer self.loop.removeFd(sockfd);61 errdefer self.loop.removeFd(sockfd);
61 }62 }
6263
63 /// Stop listening64 /// Stop listening
64 pub fn close(self: *Server) void {65 pub fn close(self: *Server) void {
65 self.loop.linuxRemoveFd(self.sockfd.?);66 self.loop.linuxRemoveFd(self.sockfd.?);
66 os.close(self.sockfd.?);67 if (self.sockfd) |fd| {
68 os.close(fd);
69 self.sockfd = null;
70 }
67 }71 }
6872
69 pub fn deinit(self: *Server) void {73 pub fn deinit(self: *Server) void {
...@@ -75,13 +79,13 @@ pub const Server = struct {...@@ -75,13 +79,13 @@ pub const Server = struct {
75 while (true) {79 while (true) {
76 var accepted_addr: std.net.Address = undefined;80 var accepted_addr: std.net.Address = undefined;
77 // TODO just inline the following function here and don't expose it as posixAsyncAccept81 // TODO just inline the following function here and don't expose it as posixAsyncAccept
78 if (os.posixAsyncAccept(self.sockfd.?, &accepted_addr.os_addr, posix.SOCK_NONBLOCK | posix.SOCK_CLOEXEC)) |accepted_fd| {82 if (os.accept4_async(self.sockfd.?, &accepted_addr.os_addr, os.SOCK_NONBLOCK | os.SOCK_CLOEXEC)) |accepted_fd| {
79 if (accepted_fd == -1) {83 if (accepted_fd == -1) {
80 // would block84 // would block
81 suspend; // we will get resumed by epoll_wait in the event loop85 suspend; // we will get resumed by epoll_wait in the event loop
82 continue;86 continue;
83 }87 }
84 var socket = os.File.openHandle(accepted_fd);88 var socket = File.openHandle(accepted_fd);
85 _ = async<self.loop.allocator> self.handleRequestFn(self, &accepted_addr, socket) catch |err| switch (err) {89 _ = async<self.loop.allocator> self.handleRequestFn(self, &accepted_addr, socket) catch |err| switch (err) {
86 error.OutOfMemory => {90 error.OutOfMemory => {
87 socket.close();91 socket.close();
...@@ -89,14 +93,7 @@ pub const Server = struct {...@@ -89,14 +93,7 @@ pub const Server = struct {
89 },93 },
90 };94 };
91 } else |err| switch (err) {95 } else |err| switch (err) {
92 error.ProcessFdQuotaExceeded => {96 error.ProcessFdQuotaExceeded => @panic("TODO handle this error"),
93 errdefer os.emfile_promise_queue.remove(&self.waiting_for_emfile_node);
94 suspend {
95 self.waiting_for_emfile_node = PromiseNode.init(@handle());
96 os.emfile_promise_queue.append(&self.waiting_for_emfile_node);
97 }
98 continue;
99 },
100 error.ConnectionAborted => continue,97 error.ConnectionAborted => continue,
10198
102 error.FileDescriptorNotASocket => unreachable,99 error.FileDescriptorNotASocket => unreachable,
...@@ -111,24 +108,24 @@ pub const Server = struct {...@@ -111,24 +108,24 @@ pub const Server = struct {
111};108};
112109
113pub async fn connectUnixSocket(loop: *Loop, path: []const u8) !i32 {110pub async fn connectUnixSocket(loop: *Loop, path: []const u8) !i32 {
114 const sockfd = try os.posixSocket(111 const sockfd = try os.socket(
115 posix.AF_UNIX,112 os.AF_UNIX,
116 posix.SOCK_STREAM | posix.SOCK_CLOEXEC | posix.SOCK_NONBLOCK,113 os.SOCK_STREAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK,
117 0,114 0,
118 );115 );
119 errdefer os.close(sockfd);116 errdefer os.close(sockfd);
120117
121 var sock_addr = posix.sockaddr_un{118 var sock_addr = os.sockaddr_un{
122 .family = posix.AF_UNIX,119 .family = os.AF_UNIX,
123 .path = undefined,120 .path = undefined,
124 };121 };
125122
126 if (path.len > @typeOf(sock_addr.path).len) return error.NameTooLong;123 if (path.len > @typeOf(sock_addr.path).len) return error.NameTooLong;
127 mem.copy(u8, sock_addr.path[0..], path);124 mem.copy(u8, sock_addr.path[0..], path);
128 const size = @intCast(u32, @sizeOf(posix.sa_family_t) + path.len);125 const size = @intCast(u32, @sizeOf(os.sa_family_t) + path.len);
129 try os.posixConnectAsync(sockfd, &sock_addr, size);126 try os.connect_async(sockfd, &sock_addr, size);
130 try await try async loop.linuxWaitFd(sockfd, posix.EPOLLIN | posix.EPOLLOUT | posix.EPOLLET);127 try await try async loop.linuxWaitFd(sockfd, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
131 try os.posixGetSockOptConnectError(sockfd);128 try os.getsockoptError(sockfd);
132129
133 return sockfd;130 return sockfd;
134}131}
...@@ -146,51 +143,49 @@ pub const ReadError = error{...@@ -146,51 +143,49 @@ pub const ReadError = error{
146};143};
147144
148/// returns number of bytes read. 0 means EOF.145/// returns number of bytes read. 0 means EOF.
149pub async fn read(loop: *std.event.Loop, fd: os.FileHandle, buffer: []u8) ReadError!usize {146pub async fn read(loop: *std.event.Loop, fd: fd_t, buffer: []u8) ReadError!usize {
150 const iov = posix.iovec{147 const iov = os.iovec{
151 .iov_base = buffer.ptr,148 .iov_base = buffer.ptr,
152 .iov_len = buffer.len,149 .iov_len = buffer.len,
153 };150 };
154 const iovs: *const [1]posix.iovec = &iov;151 const iovs: *const [1]os.iovec = &iov;
155 return await (async readvPosix(loop, fd, iovs, 1) catch unreachable);152 return await (async readvPosix(loop, fd, iovs, 1) catch unreachable);
156}153}
157154
158pub const WriteError = error{};155pub const WriteError = error{};
159156
160pub async fn write(loop: *std.event.Loop, fd: os.FileHandle, buffer: []const u8) WriteError!void {157pub async fn write(loop: *std.event.Loop, fd: fd_t, buffer: []const u8) WriteError!void {
161 const iov = posix.iovec_const{158 const iov = os.iovec_const{
162 .iov_base = buffer.ptr,159 .iov_base = buffer.ptr,
163 .iov_len = buffer.len,160 .iov_len = buffer.len,
164 };161 };
165 const iovs: *const [1]posix.iovec_const = &iov;162 const iovs: *const [1]os.iovec_const = &iov;
166 return await (async writevPosix(loop, fd, iovs, 1) catch unreachable);163 return await (async writevPosix(loop, fd, iovs, 1) catch unreachable);
167}164}
168165
169pub async fn writevPosix(loop: *Loop, fd: i32, iov: [*]const posix.iovec_const, count: usize) !void {166pub async fn writevPosix(loop: *Loop, fd: i32, iov: [*]const os.iovec_const, count: usize) !void {
170 while (true) {167 while (true) {
171 switch (builtin.os) {168 switch (builtin.os) {
172 builtin.Os.macosx, builtin.Os.linux => {169 .macosx, .linux => {
173 const rc = posix.writev(fd, iov, count);170 switch (os.errno(os.system.writev(fd, iov, count))) {
174 const err = posix.getErrno(rc);
175 switch (err) {
176 0 => return,171 0 => return,
177 posix.EINTR => continue,172 os.EINTR => continue,
178 posix.ESPIPE => unreachable,173 os.ESPIPE => unreachable,
179 posix.EINVAL => unreachable,174 os.EINVAL => unreachable,
180 posix.EFAULT => unreachable,175 os.EFAULT => unreachable,
181 posix.EAGAIN => {176 os.EAGAIN => {
182 try await (async loop.linuxWaitFd(fd, posix.EPOLLET | posix.EPOLLOUT) catch unreachable);177 try await (async loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLOUT) catch unreachable);
183 continue;178 continue;
184 },179 },
185 posix.EBADF => unreachable, // always a race condition180 os.EBADF => unreachable, // always a race condition
186 posix.EDESTADDRREQ => unreachable, // connect was never called181 os.EDESTADDRREQ => unreachable, // connect was never called
187 posix.EDQUOT => unreachable,182 os.EDQUOT => unreachable,
188 posix.EFBIG => unreachable,183 os.EFBIG => unreachable,
189 posix.EIO => return error.InputOutput,184 os.EIO => return error.InputOutput,
190 posix.ENOSPC => unreachable,185 os.ENOSPC => unreachable,
191 posix.EPERM => return error.AccessDenied,186 os.EPERM => return error.AccessDenied,
192 posix.EPIPE => unreachable,187 os.EPIPE => unreachable,
193 else => return os.unexpectedErrorPosix(err),188 else => |err| return os.unexpectedErrno(err),
194 }189 }
195 },190 },
196 else => @compileError("Unsupported OS"),191 else => @compileError("Unsupported OS"),
...@@ -199,27 +194,26 @@ pub async fn writevPosix(loop: *Loop, fd: i32, iov: [*]const posix.iovec_const,...@@ -199,27 +194,26 @@ pub async fn writevPosix(loop: *Loop, fd: i32, iov: [*]const posix.iovec_const,
199}194}
200195
201/// returns number of bytes read. 0 means EOF.196/// returns number of bytes read. 0 means EOF.
202pub async fn readvPosix(loop: *std.event.Loop, fd: i32, iov: [*]posix.iovec, count: usize) !usize {197pub async fn readvPosix(loop: *std.event.Loop, fd: i32, iov: [*]os.iovec, count: usize) !usize {
203 while (true) {198 while (true) {
204 switch (builtin.os) {199 switch (builtin.os) {
205 builtin.Os.linux, builtin.Os.freebsd, builtin.Os.macosx => {200 builtin.Os.linux, builtin.Os.freebsd, builtin.Os.macosx => {
206 const rc = posix.readv(fd, iov, count);201 const rc = os.system.readv(fd, iov, count);
207 const err = posix.getErrno(rc);202 switch (os.errno(rc)) {
208 switch (err) {
209 0 => return rc,203 0 => return rc,
210 posix.EINTR => continue,204 os.EINTR => continue,
211 posix.EINVAL => unreachable,205 os.EINVAL => unreachable,
212 posix.EFAULT => unreachable,206 os.EFAULT => unreachable,
213 posix.EAGAIN => {207 os.EAGAIN => {
214 try await (async loop.linuxWaitFd(fd, posix.EPOLLET | posix.EPOLLIN) catch unreachable);208 try await (async loop.linuxWaitFd(fd, os.EPOLLET | os.EPOLLIN) catch unreachable);
215 continue;209 continue;
216 },210 },
217 posix.EBADF => unreachable, // always a race condition211 os.EBADF => unreachable, // always a race condition
218 posix.EIO => return error.InputOutput,212 os.EIO => return error.InputOutput,
219 posix.EISDIR => unreachable,213 os.EISDIR => unreachable,
220 posix.ENOBUFS => return error.SystemResources,214 os.ENOBUFS => return error.SystemResources,
221 posix.ENOMEM => return error.SystemResources,215 os.ENOMEM => return error.SystemResources,
222 else => return os.unexpectedErrorPosix(err),216 else => |err| return os.unexpectedErrno(err),
223 }217 }
224 },218 },
225 else => @compileError("Unsupported OS"),219 else => @compileError("Unsupported OS"),
...@@ -227,12 +221,12 @@ pub async fn readvPosix(loop: *std.event.Loop, fd: i32, iov: [*]posix.iovec, cou...@@ -227,12 +221,12 @@ pub async fn readvPosix(loop: *std.event.Loop, fd: i32, iov: [*]posix.iovec, cou
227 }221 }
228}222}
229223
230pub async fn writev(loop: *Loop, fd: os.FileHandle, data: []const []const u8) !void {224pub async fn writev(loop: *Loop, fd: fd_t, data: []const []const u8) !void {
231 const iovecs = try loop.allocator.alloc(os.posix.iovec_const, data.len);225 const iovecs = try loop.allocator.alloc(os.iovec_const, data.len);
232 defer loop.allocator.free(iovecs);226 defer loop.allocator.free(iovecs);
233227
234 for (data) |buf, i| {228 for (data) |buf, i| {
235 iovecs[i] = os.posix.iovec_const{229 iovecs[i] = os.iovec_const{
236 .iov_base = buf.ptr,230 .iov_base = buf.ptr,
237 .iov_len = buf.len,231 .iov_len = buf.len,
238 };232 };
...@@ -241,12 +235,12 @@ pub async fn writev(loop: *Loop, fd: os.FileHandle, data: []const []const u8) !v...@@ -241,12 +235,12 @@ pub async fn writev(loop: *Loop, fd: os.FileHandle, data: []const []const u8) !v
241 return await (async writevPosix(loop, fd, iovecs.ptr, data.len) catch unreachable);235 return await (async writevPosix(loop, fd, iovecs.ptr, data.len) catch unreachable);
242}236}
243237
244pub async fn readv(loop: *Loop, fd: os.FileHandle, data: []const []u8) !usize {238pub async fn readv(loop: *Loop, fd: fd_t, data: []const []u8) !usize {
245 const iovecs = try loop.allocator.alloc(os.posix.iovec, data.len);239 const iovecs = try loop.allocator.alloc(os.iovec, data.len);
246 defer loop.allocator.free(iovecs);240 defer loop.allocator.free(iovecs);
247241
248 for (data) |buf, i| {242 for (data) |buf, i| {
249 iovecs[i] = os.posix.iovec{243 iovecs[i] = os.iovec{
250 .iov_base = buf.ptr,244 .iov_base = buf.ptr,
251 .iov_len = buf.len,245 .iov_len = buf.len,
252 };246 };
...@@ -255,17 +249,17 @@ pub async fn readv(loop: *Loop, fd: os.FileHandle, data: []const []u8) !usize {...@@ -255,17 +249,17 @@ pub async fn readv(loop: *Loop, fd: os.FileHandle, data: []const []u8) !usize {
255 return await (async readvPosix(loop, fd, iovecs.ptr, data.len) catch unreachable);249 return await (async readvPosix(loop, fd, iovecs.ptr, data.len) catch unreachable);
256}250}
257251
258pub async fn connect(loop: *Loop, _address: *const std.net.Address) !os.File {252pub async fn connect(loop: *Loop, _address: *const std.net.Address) !File {
259 var address = _address.*; // TODO https://github.com/ziglang/zig/issues/1592253 var address = _address.*; // TODO https://github.com/ziglang/zig/issues/1592
260254
261 const sockfd = try os.posixSocket(posix.AF_INET, posix.SOCK_STREAM | posix.SOCK_CLOEXEC | posix.SOCK_NONBLOCK, posix.PROTO_tcp);255 const sockfd = try os.socket(os.AF_INET, os.SOCK_STREAM | os.SOCK_CLOEXEC | os.SOCK_NONBLOCK, os.PROTO_tcp);
262 errdefer os.close(sockfd);256 errdefer os.close(sockfd);
263257
264 try os.posixConnectAsync(sockfd, &address.os_addr, @sizeOf(posix.sockaddr_in));258 try os.connect_async(sockfd, &address.os_addr, @sizeOf(os.sockaddr_in));
265 try await try async loop.linuxWaitFd(sockfd, posix.EPOLLIN | posix.EPOLLOUT | posix.EPOLLET);259 try await try async loop.linuxWaitFd(sockfd, os.EPOLLIN | os.EPOLLOUT | os.EPOLLET);
266 try os.posixGetSockOptConnectError(sockfd);260 try os.getsockoptError(sockfd);
267261
268 return os.File.openHandle(sockfd);262 return File.openHandle(sockfd);
269}263}
270264
271test "listen on a port, send bytes, receive bytes" {265test "listen on a port, send bytes, receive bytes" {
...@@ -281,7 +275,7 @@ test "listen on a port, send bytes, receive bytes" {...@@ -281,7 +275,7 @@ test "listen on a port, send bytes, receive bytes" {
281 tcp_server: Server,275 tcp_server: Server,
282276
283 const Self = @This();277 const Self = @This();
284 async<*mem.Allocator> fn handler(tcp_server: *Server, _addr: *const std.net.Address, _socket: os.File) void {278 async<*mem.Allocator> fn handler(tcp_server: *Server, _addr: *const std.net.Address, _socket: File) void {
285 const self = @fieldParentPtr(Self, "tcp_server", tcp_server);279 const self = @fieldParentPtr(Self, "tcp_server", tcp_server);
286 var socket = _socket; // TODO https://github.com/ziglang/zig/issues/1592280 var socket = _socket; // TODO https://github.com/ziglang/zig/issues/1592
287 defer socket.close();281 defer socket.close();
...@@ -294,7 +288,7 @@ test "listen on a port, send bytes, receive bytes" {...@@ -294,7 +288,7 @@ test "listen on a port, send bytes, receive bytes" {
294 cancel @handle();288 cancel @handle();
295 }289 }
296 }290 }
297 async fn errorableHandler(self: *Self, _addr: *const std.net.Address, _socket: os.File) !void {291 async fn errorableHandler(self: *Self, _addr: *const std.net.Address, _socket: File) !void {
298 const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/1592292 const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/1592
299 var socket = _socket; // TODO https://github.com/ziglang/zig/issues/1592293 var socket = _socket; // TODO https://github.com/ziglang/zig/issues/1592
300294
...@@ -331,14 +325,14 @@ async fn doAsyncTest(loop: *Loop, address: *const std.net.Address, server: *Serv...@@ -331,14 +325,14 @@ async fn doAsyncTest(loop: *Loop, address: *const std.net.Address, server: *Serv
331}325}
332326
333pub const OutStream = struct {327pub const OutStream = struct {
334 fd: os.FileHandle,328 fd: fd_t,
335 stream: Stream,329 stream: Stream,
336 loop: *Loop,330 loop: *Loop,
337331
338 pub const Error = WriteError;332 pub const Error = WriteError;
339 pub const Stream = event.io.OutStream(Error);333 pub const Stream = event.io.OutStream(Error);
340334
341 pub fn init(loop: *Loop, fd: os.FileHandle) OutStream {335 pub fn init(loop: *Loop, fd: fd_t) OutStream {
342 return OutStream{336 return OutStream{
343 .fd = fd,337 .fd = fd,
344 .loop = loop,338 .loop = loop,
...@@ -353,14 +347,14 @@ pub const OutStream = struct {...@@ -353,14 +347,14 @@ pub const OutStream = struct {
353};347};
354348
355pub const InStream = struct {349pub const InStream = struct {
356 fd: os.FileHandle,350 fd: fd_t,
357 stream: Stream,351 stream: Stream,
358 loop: *Loop,352 loop: *Loop,
359353
360 pub const Error = ReadError;354 pub const Error = ReadError;
361 pub const Stream = event.io.InStream(Error);355 pub const Stream = event.io.InStream(Error);
362356
363 pub fn init(loop: *Loop, fd: os.FileHandle) InStream {357 pub fn init(loop: *Loop, fd: fd_t) InStream {
364 return InStream{358 return InStream{
365 .fd = fd,359 .fd = fd,
366 .loop = loop,360 .loop = loop,
std/event/rwlock.zig+2-2
...@@ -271,7 +271,7 @@ async fn writeRunner(lock: *RwLock) void {...@@ -271,7 +271,7 @@ async fn writeRunner(lock: *RwLock) void {
271271
272 var i: usize = 0;272 var i: usize = 0;
273 while (i < shared_test_data.len) : (i += 1) {273 while (i < shared_test_data.len) : (i += 1) {
274 std.os.time.sleep(100 * std.os.time.microsecond);274 std.time.sleep(100 * std.time.microsecond);
275 const lock_promise = async lock.acquireWrite() catch @panic("out of memory");275 const lock_promise = async lock.acquireWrite() catch @panic("out of memory");
276 const handle = await lock_promise;276 const handle = await lock_promise;
277 defer handle.release();277 defer handle.release();
...@@ -286,7 +286,7 @@ async fn writeRunner(lock: *RwLock) void {...@@ -286,7 +286,7 @@ async fn writeRunner(lock: *RwLock) void {
286286
287async fn readRunner(lock: *RwLock) void {287async fn readRunner(lock: *RwLock) void {
288 suspend; // resumed by onNextTick288 suspend; // resumed by onNextTick
289 std.os.time.sleep(1);289 std.time.sleep(1);
290290
291 var i: usize = 0;291 var i: usize = 0;
292 while (i < shared_test_data.len) : (i += 1) {292 while (i < shared_test_data.len) : (i += 1) {
std/fmt.zig+1-1
...@@ -226,7 +226,7 @@ pub fn formatType(...@@ -226,7 +226,7 @@ pub fn formatType(
226 builtin.TypeInfo.Pointer.Size.Many => {226 builtin.TypeInfo.Pointer.Size.Many => {
227 if (ptr_info.child == u8) {227 if (ptr_info.child == u8) {
228 if (fmt.len > 0 and fmt[0] == 's') {228 if (fmt.len > 0 and fmt[0] == 's') {
229 const len = std.cstr.len(value);229 const len = mem.len(u8, value);
230 return formatText(value[0..len], fmt, context, Errors, output);230 return formatText(value[0..len], fmt, context, Errors, output);
231 }231 }
232 }232 }
std/fs.zig created+808
...@@ -0,0 +1,808 @@
1const builtin = @import("builtin");
2const std = @import("std.zig");
3const os = std.os;
4const mem = std.mem;
5const base64 = std.base64;
6const crypto = std.crypto;
7const Allocator = std.mem.Allocator;
8const assert = std.debug.assert;
9
10pub const path = @import("fs/path.zig");
11pub const File = @import("fs/file.zig").File;
12
13pub const symLink = os.symlink;
14pub const symLinkC = os.symlinkC;
15pub const deleteFile = os.unlink;
16pub const deleteFileC = os.unlinkC;
17pub const rename = os.rename;
18pub const renameC = os.renameC;
19pub const renameW = os.renameW;
20pub const realpath = os.realpath;
21pub const realpathC = os.realpathC;
22pub const realpathW = os.realpathW;
23
24pub const getAppDataDir = @import("fs/get_app_data_dir.zig").getAppDataDir;
25pub const GetAppDataDirError = @import("fs/get_app_data_dir.zig").GetAppDataDirError;
26
27/// This represents the maximum size of a UTF-8 encoded file path.
28/// All file system operations which return a path are guaranteed to
29/// fit into a UTF-8 encoded array of this length.
30/// path being too long if it is this 0long
31pub const MAX_PATH_BYTES = switch (builtin.os) {
32 .linux, .macosx, .ios, .freebsd, .netbsd => os.PATH_MAX,
33 // Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
34 // If it would require 4 UTF-8 bytes, then there would be a surrogate
35 // pair in the UTF-16LE, and we (over)account 3 bytes for it that way.
36 // +1 for the null byte at the end, which can be encoded in 1 byte.
37 .windows => os.windows.PATH_MAX_WIDE * 3 + 1,
38 else => @compileError("Unsupported OS"),
39};
40
41// here we replace the standard +/ with -_ so that it can be used in a file name
42const b64_fs_encoder = base64.Base64Encoder.init("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", base64.standard_pad_char);
43
44/// TODO remove the allocator requirement from this API
45pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) !void {
46 if (symLink(existing_path, new_path)) {
47 return;
48 } else |err| switch (err) {
49 error.PathAlreadyExists => {},
50 else => return err, // TODO zig should know this set does not include PathAlreadyExists
51 }
52
53 const dirname = path.dirname(new_path) orelse ".";
54
55 var rand_buf: [12]u8 = undefined;
56 const tmp_path = try allocator.alloc(u8, dirname.len + 1 + base64.Base64Encoder.calcSize(rand_buf.len));
57 defer allocator.free(tmp_path);
58 mem.copy(u8, tmp_path[0..], dirname);
59 tmp_path[dirname.len] = path.sep;
60 while (true) {
61 try crypto.randomBytes(rand_buf[0..]);
62 b64_fs_encoder.encode(tmp_path[dirname.len + 1 ..], rand_buf);
63
64 if (symLink(existing_path, tmp_path)) {
65 return rename(tmp_path, new_path);
66 } else |err| switch (err) {
67 error.PathAlreadyExists => continue,
68 else => return err, // TODO zig should know this set does not include PathAlreadyExists
69 }
70 }
71}
72
73/// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is
74/// merged and readily available,
75/// there is a possibility of power loss or application termination leaving temporary files present
76/// in the same directory as dest_path.
77/// Destination file will have the same mode as the source file.
78pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void {
79 var in_file = try File.openRead(source_path);
80 defer in_file.close();
81
82 const mode = try in_file.mode();
83 const in_stream = &in_file.inStream().stream;
84
85 var atomic_file = try AtomicFile.init(dest_path, mode);
86 defer atomic_file.deinit();
87
88 var buf: [mem.page_size]u8 = undefined;
89 while (true) {
90 const amt = try in_stream.readFull(buf[0..]);
91 try atomic_file.file.write(buf[0..amt]);
92 if (amt != buf.len) {
93 return atomic_file.finish();
94 }
95 }
96}
97
98/// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is
99/// merged and readily available,
100/// there is a possibility of power loss or application termination leaving temporary files present
101pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void {
102 var in_file = try File.openRead(source_path);
103 defer in_file.close();
104
105 var atomic_file = try AtomicFile.init(dest_path, mode);
106 defer atomic_file.deinit();
107
108 var buf: [mem.page_size]u8 = undefined;
109 while (true) {
110 const amt = try in_file.read(buf[0..]);
111 try atomic_file.file.write(buf[0..amt]);
112 if (amt != buf.len) {
113 return atomic_file.finish();
114 }
115 }
116}
117
118pub const AtomicFile = struct {
119 file: File,
120 tmp_path_buf: [MAX_PATH_BYTES]u8,
121 dest_path: []const u8,
122 finished: bool,
123
124 const InitError = File.OpenError;
125
126 /// dest_path must remain valid for the lifetime of AtomicFile
127 /// call finish to atomically replace dest_path with contents
128 /// TODO once we have null terminated pointers, use the
129 /// openWriteNoClobberN function
130 pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile {
131 const dirname = path.dirname(dest_path);
132 var rand_buf: [12]u8 = undefined;
133 const dirname_component_len = if (dirname) |d| d.len + 1 else 0;
134 const encoded_rand_len = comptime base64.Base64Encoder.calcSize(rand_buf.len);
135 const tmp_path_len = dirname_component_len + encoded_rand_len;
136 var tmp_path_buf: [MAX_PATH_BYTES]u8 = undefined;
137 if (tmp_path_len >= tmp_path_buf.len) return error.NameTooLong;
138
139 if (dirname) |dir| {
140 mem.copy(u8, tmp_path_buf[0..], dir);
141 tmp_path_buf[dir.len] = path.sep;
142 }
143
144 tmp_path_buf[tmp_path_len] = 0;
145
146 while (true) {
147 try crypto.randomBytes(rand_buf[0..]);
148 b64_fs_encoder.encode(tmp_path_buf[dirname_component_len..tmp_path_len], rand_buf);
149
150 const file = File.openWriteNoClobberC(&tmp_path_buf, mode) catch |err| switch (err) {
151 error.PathAlreadyExists => continue,
152 // TODO zig should figure out that this error set does not include PathAlreadyExists since
153 // it is handled in the above switch
154 else => return err,
155 };
156
157 return AtomicFile{
158 .file = file,
159 .tmp_path_buf = tmp_path_buf,
160 .dest_path = dest_path,
161 .finished = false,
162 };
163 }
164 }
165
166 /// always call deinit, even after successful finish()
167 pub fn deinit(self: *AtomicFile) void {
168 if (!self.finished) {
169 self.file.close();
170 deleteFileC(&self.tmp_path_buf) catch {};
171 self.finished = true;
172 }
173 }
174
175 pub fn finish(self: *AtomicFile) !void {
176 assert(!self.finished);
177 self.file.close();
178 self.finished = true;
179 if (os.windows.is_the_target) {
180 const dest_path_w = try os.windows.sliceToPrefixedFileW(self.dest_path);
181 const tmp_path_w = try os.windows.cStrToPrefixedFileW(&self.tmp_path_buf);
182 return os.renameW(&tmp_path_w, &dest_path_w);
183 }
184 const dest_path_c = try os.toPosixPath(self.dest_path);
185 return os.renameC(&self.tmp_path_buf, &dest_path_c);
186 }
187};
188
189const default_new_dir_mode = 0o755;
190
191/// Create a new directory.
192pub fn makeDir(dir_path: []const u8) !void {
193 return os.mkdir(dir_path, default_new_dir_mode);
194}
195
196/// Same as `makeDir` except the parameter is a null-terminated UTF8-encoded string.
197pub fn makeDirC(dir_path: [*]const u8) !void {
198 return os.mkdirC(dir_path, default_new_dir_mode);
199}
200
201/// Same as `makeDir` except the parameter is a null-terminated UTF16LE-encoded string.
202pub fn makeDirW(dir_path: [*]const u16) !void {
203 return os.mkdirW(dir_path, default_new_dir_mode);
204}
205
206/// Calls makeDir recursively to make an entire path. Returns success if the path
207/// already exists and is a directory.
208/// This function is not atomic, and if it returns an error, the file system may
209/// have been modified regardless.
210/// TODO determine if we can remove the allocator requirement from this function
211pub fn makePath(allocator: *Allocator, full_path: []const u8) !void {
212 const resolved_path = try path.resolve(allocator, [][]const u8{full_path});
213 defer allocator.free(resolved_path);
214
215 var end_index: usize = resolved_path.len;
216 while (true) {
217 makeDir(resolved_path[0..end_index]) catch |err| switch (err) {
218 error.PathAlreadyExists => {
219 // TODO stat the file and return an error if it's not a directory
220 // this is important because otherwise a dangling symlink
221 // could cause an infinite loop
222 if (end_index == resolved_path.len) return;
223 },
224 error.FileNotFound => {
225 // march end_index backward until next path component
226 while (true) {
227 end_index -= 1;
228 if (path.isSep(resolved_path[end_index])) break;
229 }
230 continue;
231 },
232 else => return err,
233 };
234 if (end_index == resolved_path.len) return;
235 // march end_index forward until next path component
236 while (true) {
237 end_index += 1;
238 if (end_index == resolved_path.len or path.isSep(resolved_path[end_index])) break;
239 }
240 }
241}
242
243/// Returns `error.DirNotEmpty` if the directory is not empty.
244/// To delete a directory recursively, see `deleteTree`.
245pub fn deleteDir(dir_path: []const u8) !void {
246 return os.rmdir(dir_path);
247}
248
249/// Same as `deleteDir` except the parameter is a null-terminated UTF8-encoded string.
250pub fn deleteDirC(dir_path: [*]const u8) !void {
251 return os.rmdirC(dir_path);
252}
253
254/// Same as `deleteDir` except the parameter is a null-terminated UTF16LE-encoded string.
255pub fn deleteDirW(dir_path: [*]const u16) !void {
256 return os.rmdirW(dir_path);
257}
258
259/// Whether ::full_path describes a symlink, file, or directory, this function
260/// removes it. If it cannot be removed because it is a non-empty directory,
261/// this function recursively removes its entries and then tries again.
262const DeleteTreeError = error{
263 OutOfMemory,
264 AccessDenied,
265 FileTooBig,
266 IsDir,
267 SymLinkLoop,
268 ProcessFdQuotaExceeded,
269 NameTooLong,
270 SystemFdQuotaExceeded,
271 NoDevice,
272 SystemResources,
273 NoSpaceLeft,
274 PathAlreadyExists,
275 ReadOnlyFileSystem,
276 NotDir,
277 FileNotFound,
278 FileSystem,
279 FileBusy,
280 DirNotEmpty,
281 DeviceBusy,
282
283 /// On Windows, file paths must be valid Unicode.
284 InvalidUtf8,
285
286 /// On Windows, file paths cannot contain these characters:
287 /// '/', '*', '?', '"', '<', '>', '|'
288 BadPathName,
289
290 Unexpected,
291};
292
293/// TODO determine if we can remove the allocator requirement
294pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!void {
295 start_over: while (true) {
296 var got_access_denied = false;
297 // First, try deleting the item as a file. This way we don't follow sym links.
298 if (deleteFile(full_path)) {
299 return;
300 } else |err| switch (err) {
301 error.FileNotFound => return,
302 error.IsDir => {},
303 error.AccessDenied => got_access_denied = true,
304
305 error.InvalidUtf8,
306 error.SymLinkLoop,
307 error.NameTooLong,
308 error.SystemResources,
309 error.ReadOnlyFileSystem,
310 error.NotDir,
311 error.FileSystem,
312 error.FileBusy,
313 error.BadPathName,
314 error.Unexpected,
315 => return err,
316 }
317 {
318 var dir = Dir.open(allocator, full_path) catch |err| switch (err) {
319 error.NotDir => {
320 if (got_access_denied) {
321 return error.AccessDenied;
322 }
323 continue :start_over;
324 },
325
326 error.OutOfMemory,
327 error.AccessDenied,
328 error.FileTooBig,
329 error.IsDir,
330 error.SymLinkLoop,
331 error.ProcessFdQuotaExceeded,
332 error.NameTooLong,
333 error.SystemFdQuotaExceeded,
334 error.NoDevice,
335 error.FileNotFound,
336 error.SystemResources,
337 error.NoSpaceLeft,
338 error.PathAlreadyExists,
339 error.Unexpected,
340 error.InvalidUtf8,
341 error.BadPathName,
342 error.DeviceBusy,
343 => return err,
344 };
345 defer dir.close();
346
347 var full_entry_buf = std.ArrayList(u8).init(allocator);
348 defer full_entry_buf.deinit();
349
350 while (try dir.next()) |entry| {
351 try full_entry_buf.resize(full_path.len + entry.name.len + 1);
352 const full_entry_path = full_entry_buf.toSlice();
353 mem.copy(u8, full_entry_path, full_path);
354 full_entry_path[full_path.len] = path.sep;
355 mem.copy(u8, full_entry_path[full_path.len + 1 ..], entry.name);
356
357 try deleteTree(allocator, full_entry_path);
358 }
359 }
360 return deleteDir(full_path);
361 }
362}
363
364pub const Dir = struct {
365 handle: Handle,
366 allocator: *Allocator,
367
368 pub const Handle = switch (builtin.os) {
369 .macosx, .ios, .freebsd, .netbsd => struct {
370 fd: i32,
371 seek: i64,
372 buf: []u8,
373 index: usize,
374 end_index: usize,
375 },
376 .linux => struct {
377 fd: i32,
378 buf: []u8,
379 index: usize,
380 end_index: usize,
381 },
382 .windows => struct {
383 handle: os.windows.HANDLE,
384 find_file_data: os.windows.WIN32_FIND_DATAW,
385 first: bool,
386 name_data: [256]u8,
387 },
388 else => @compileError("unimplemented"),
389 };
390
391 pub const Entry = struct {
392 name: []const u8,
393 kind: Kind,
394
395 pub const Kind = enum {
396 BlockDevice,
397 CharacterDevice,
398 Directory,
399 NamedPipe,
400 SymLink,
401 File,
402 UnixDomainSocket,
403 Whiteout,
404 Unknown,
405 };
406 };
407
408 pub const OpenError = error{
409 FileNotFound,
410 NotDir,
411 AccessDenied,
412 FileTooBig,
413 IsDir,
414 SymLinkLoop,
415 ProcessFdQuotaExceeded,
416 NameTooLong,
417 SystemFdQuotaExceeded,
418 NoDevice,
419 SystemResources,
420 NoSpaceLeft,
421 PathAlreadyExists,
422 OutOfMemory,
423 InvalidUtf8,
424 BadPathName,
425 DeviceBusy,
426
427 Unexpected,
428 };
429
430 /// TODO remove the allocator requirement from this API
431 pub fn open(allocator: *Allocator, dir_path: []const u8) OpenError!Dir {
432 return Dir{
433 .allocator = allocator,
434 .handle = switch (builtin.os) {
435 .windows => blk: {
436 var find_file_data: os.windows.WIN32_FIND_DATAW = undefined;
437 const handle = try os.windows.FindFirstFile(dir_path, &find_file_data);
438 break :blk Handle{
439 .handle = handle,
440 .find_file_data = find_file_data, // TODO guaranteed copy elision
441 .first = true,
442 .name_data = undefined,
443 };
444 },
445 .macosx, .ios, .freebsd, .netbsd => Handle{
446 .fd = try os.open(dir_path, os.O_RDONLY | os.O_NONBLOCK | os.O_DIRECTORY | os.O_CLOEXEC, 0),
447 .seek = 0,
448 .index = 0,
449 .end_index = 0,
450 .buf = []u8{},
451 },
452 .linux => Handle{
453 .fd = try os.open(dir_path, os.O_RDONLY | os.O_DIRECTORY | os.O_CLOEXEC, 0),
454 .index = 0,
455 .end_index = 0,
456 .buf = []u8{},
457 },
458 else => @compileError("unimplemented"),
459 },
460 };
461 }
462
463 pub fn close(self: *Dir) void {
464 if (os.windows.is_the_target) {
465 return os.windows.FindClose(self.handle.handle);
466 }
467 self.allocator.free(self.handle.buf);
468 os.close(self.handle.fd);
469 }
470
471 /// Memory such as file names referenced in this returned entry becomes invalid
472 /// with subsequent calls to next, as well as when this `Dir` is deinitialized.
473 pub fn next(self: *Dir) !?Entry {
474 switch (builtin.os) {
475 .linux => return self.nextLinux(),
476 .macosx, .ios => return self.nextDarwin(),
477 .windows => return self.nextWindows(),
478 .freebsd => return self.nextBsd(),
479 .netbsd => return self.nextBsd(),
480 else => @compileError("unimplemented"),
481 }
482 }
483
484 fn nextDarwin(self: *Dir) !?Entry {
485 start_over: while (true) {
486 if (self.handle.index >= self.handle.end_index) {
487 if (self.handle.buf.len == 0) {
488 self.handle.buf = try self.allocator.alloc(u8, mem.page_size);
489 }
490
491 while (true) {
492 const rc = os.system.__getdirentries64(
493 self.handle.fd,
494 self.handle.buf.ptr,
495 self.handle.buf.len,
496 &self.handle.seek,
497 );
498 if (rc == 0) return null;
499 if (rc < 0) {
500 switch (os.errno(rc)) {
501 os.EBADF => unreachable,
502 os.EFAULT => unreachable,
503 os.ENOTDIR => unreachable,
504 os.EINVAL => {
505 self.handle.buf = try self.allocator.realloc(self.handle.buf, self.handle.buf.len * 2);
506 continue;
507 },
508 else => |err| return os.unexpectedErrno(err),
509 }
510 }
511 self.handle.index = 0;
512 self.handle.end_index = @intCast(usize, rc);
513 break;
514 }
515 }
516 const darwin_entry = @ptrCast(*align(1) os.dirent, &self.handle.buf[self.handle.index]);
517 const next_index = self.handle.index + darwin_entry.d_reclen;
518 self.handle.index = next_index;
519
520 const name = @ptrCast([*]u8, &darwin_entry.d_name)[0..darwin_entry.d_namlen];
521
522 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
523 continue :start_over;
524 }
525
526 const entry_kind = switch (darwin_entry.d_type) {
527 os.DT_BLK => Entry.Kind.BlockDevice,
528 os.DT_CHR => Entry.Kind.CharacterDevice,
529 os.DT_DIR => Entry.Kind.Directory,
530 os.DT_FIFO => Entry.Kind.NamedPipe,
531 os.DT_LNK => Entry.Kind.SymLink,
532 os.DT_REG => Entry.Kind.File,
533 os.DT_SOCK => Entry.Kind.UnixDomainSocket,
534 os.DT_WHT => Entry.Kind.Whiteout,
535 else => Entry.Kind.Unknown,
536 };
537 return Entry{
538 .name = name,
539 .kind = entry_kind,
540 };
541 }
542 }
543
544 fn nextWindows(self: *Dir) !?Entry {
545 while (true) {
546 if (self.handle.first) {
547 self.handle.first = false;
548 } else {
549 if (!try os.windows.FindNextFile(self.handle.handle, &self.handle.find_file_data))
550 return null;
551 }
552 const name_utf16le = mem.toSlice(u16, self.handle.find_file_data.cFileName[0..].ptr);
553 if (mem.eql(u16, name_utf16le, []u16{'.'}) or mem.eql(u16, name_utf16le, []u16{ '.', '.' }))
554 continue;
555 // Trust that Windows gives us valid UTF-16LE
556 const name_utf8_len = std.unicode.utf16leToUtf8(self.handle.name_data[0..], name_utf16le) catch unreachable;
557 const name_utf8 = self.handle.name_data[0..name_utf8_len];
558 const kind = blk: {
559 const attrs = self.handle.find_file_data.dwFileAttributes;
560 if (attrs & os.windows.FILE_ATTRIBUTE_DIRECTORY != 0) break :blk Entry.Kind.Directory;
561 if (attrs & os.windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) break :blk Entry.Kind.SymLink;
562 if (attrs & os.windows.FILE_ATTRIBUTE_NORMAL != 0) break :blk Entry.Kind.File;
563 break :blk Entry.Kind.Unknown;
564 };
565 return Entry{
566 .name = name_utf8,
567 .kind = kind,
568 };
569 }
570 }
571
572 fn nextLinux(self: *Dir) !?Entry {
573 start_over: while (true) {
574 if (self.handle.index >= self.handle.end_index) {
575 if (self.handle.buf.len == 0) {
576 self.handle.buf = try self.allocator.alloc(u8, mem.page_size);
577 }
578
579 while (true) {
580 const rc = os.linux.getdents64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len);
581 switch (os.linux.getErrno(rc)) {
582 0 => {},
583 os.EBADF => unreachable,
584 os.EFAULT => unreachable,
585 os.ENOTDIR => unreachable,
586 os.EINVAL => {
587 self.handle.buf = try self.allocator.realloc(self.handle.buf, self.handle.buf.len * 2);
588 continue;
589 },
590 else => |err| return os.unexpectedErrno(err),
591 }
592 if (rc == 0) return null;
593 self.handle.index = 0;
594 self.handle.end_index = rc;
595 break;
596 }
597 }
598 const linux_entry = @ptrCast(*align(1) os.dirent64, &self.handle.buf[self.handle.index]);
599 const next_index = self.handle.index + linux_entry.d_reclen;
600 self.handle.index = next_index;
601
602 const name = mem.toSlice(u8, @ptrCast([*]u8, &linux_entry.d_name));
603
604 // skip . and .. entries
605 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
606 continue :start_over;
607 }
608
609 const entry_kind = switch (linux_entry.d_type) {
610 os.DT_BLK => Entry.Kind.BlockDevice,
611 os.DT_CHR => Entry.Kind.CharacterDevice,
612 os.DT_DIR => Entry.Kind.Directory,
613 os.DT_FIFO => Entry.Kind.NamedPipe,
614 os.DT_LNK => Entry.Kind.SymLink,
615 os.DT_REG => Entry.Kind.File,
616 os.DT_SOCK => Entry.Kind.UnixDomainSocket,
617 else => Entry.Kind.Unknown,
618 };
619 return Entry{
620 .name = name,
621 .kind = entry_kind,
622 };
623 }
624 }
625
626 fn nextBsd(self: *Dir) !?Entry {
627 start_over: while (true) {
628 if (self.handle.index >= self.handle.end_index) {
629 if (self.handle.buf.len == 0) {
630 self.handle.buf = try self.allocator.alloc(u8, mem.page_size);
631 }
632
633 while (true) {
634 const rc = os.system.getdirentries(
635 self.handle.fd,
636 self.handle.buf.ptr,
637 self.handle.buf.len,
638 &self.handle.seek,
639 );
640 switch (os.errno(rc)) {
641 0 => {},
642 os.EBADF => unreachable,
643 os.EFAULT => unreachable,
644 os.ENOTDIR => unreachable,
645 os.EINVAL => {
646 self.handle.buf = try self.allocator.realloc(self.handle.buf, self.handle.buf.len * 2);
647 continue;
648 },
649 else => |err| return os.unexpectedErrno(err),
650 }
651 if (rc == 0) return null;
652 self.handle.index = 0;
653 self.handle.end_index = @intCast(usize, rc);
654 break;
655 }
656 }
657 const freebsd_entry = @ptrCast(*align(1) os.dirent, &self.handle.buf[self.handle.index]);
658 const next_index = self.handle.index + freebsd_entry.d_reclen;
659 self.handle.index = next_index;
660
661 const name = @ptrCast([*]u8, &freebsd_entry.d_name)[0..freebsd_entry.d_namlen];
662
663 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
664 continue :start_over;
665 }
666
667 const entry_kind = switch (freebsd_entry.d_type) {
668 os.DT_BLK => Entry.Kind.BlockDevice,
669 os.DT_CHR => Entry.Kind.CharacterDevice,
670 os.DT_DIR => Entry.Kind.Directory,
671 os.DT_FIFO => Entry.Kind.NamedPipe,
672 os.DT_LNK => Entry.Kind.SymLink,
673 os.DT_REG => Entry.Kind.File,
674 os.DT_SOCK => Entry.Kind.UnixDomainSocket,
675 os.DT_WHT => Entry.Kind.Whiteout,
676 else => Entry.Kind.Unknown,
677 };
678 return Entry{
679 .name = name,
680 .kind = entry_kind,
681 };
682 }
683 }
684};
685
686/// Read value of a symbolic link.
687/// The return value is a slice of buffer, from index `0`.
688pub fn readLink(pathname: []const u8, buffer: *[os.PATH_MAX]u8) ![]u8 {
689 return os.readlink(pathname, buffer);
690}
691
692/// Same as `readLink`, except the `pathname` parameter is null-terminated.
693pub fn readLinkC(pathname: [*]const u8, buffer: *[os.PATH_MAX]u8) ![]u8 {
694 return os.readlinkC(pathname, buffer);
695}
696
697pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfExePathError;
698
699pub fn openSelfExe() OpenSelfExeError!File {
700 if (os.linux.is_the_target) {
701 return File.openReadC(c"/proc/self/exe");
702 }
703 if (os.windows.is_the_target) {
704 var buf: [os.windows.PATH_MAX_WIDE]u16 = undefined;
705 const wide_slice = try selfExePathW(&buf);
706 return File.openReadW(wide_slice.ptr);
707 }
708 var buf: [MAX_PATH_BYTES]u8 = undefined;
709 const self_exe_path = try selfExePath(&buf);
710 buf[self_exe_path.len] = 0;
711 return File.openReadC(self_exe_path.ptr);
712}
713
714test "openSelfExe" {
715 switch (builtin.os) {
716 .linux, .macosx, .ios, .windows, .freebsd => (try openSelfExe()).close(),
717 else => return error.SkipZigTest, // Unsupported OS.
718 }
719}
720
721pub const SelfExePathError = os.ReadLinkError || os.SysCtlError;
722
723/// Get the path to the current executable.
724/// If you only need the directory, use selfExeDirPath.
725/// If you only want an open file handle, use openSelfExe.
726/// This function may return an error if the current executable
727/// was deleted after spawning.
728/// Returned value is a slice of out_buffer.
729///
730/// On Linux, depends on procfs being mounted. If the currently executing binary has
731/// been deleted, the file path looks something like `/a/b/c/exe (deleted)`.
732/// TODO make the return type of this a null terminated pointer
733pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]u8 {
734 if (os.darwin.is_the_target) {
735 var u32_len: u32 = out_buffer.len;
736 const rc = std.c._NSGetExecutablePath(out_buffer, &u32_len);
737 if (rc != 0) return error.NameTooLong;
738 return mem.toSlice(u8, out_buffer);
739 }
740 switch (builtin.os) {
741 .linux => return os.readlinkC(c"/proc/self/exe", out_buffer),
742 .freebsd => {
743 var mib = [4]c_int{ os.CTL_KERN, os.KERN_PROC, os.KERN_PROC_PATHNAME, -1 };
744 var out_len: usize = out_buffer.len;
745 try os.sysctl(&mib, out_buffer, &out_len, null, 0);
746 // TODO could this slice from 0 to out_len instead?
747 return mem.toSlice(u8, out_buffer);
748 },
749 .netbsd => {
750 var mib = [4]c_int{ os.CTL_KERN, os.KERN_PROC_ARGS, -1, os.KERN_PROC_PATHNAME };
751 var out_len: usize = out_buffer.len;
752 try os.sysctl(&mib, out_buffer, &out_len, null, 0);
753 // TODO could this slice from 0 to out_len instead?
754 return mem.toSlice(u8, out_buffer);
755 },
756 .windows => {
757 var utf16le_buf: [os.windows.PATH_MAX_WIDE]u16 = undefined;
758 const utf16le_slice = try selfExePathW(&utf16le_buf);
759 // Trust that Windows gives us valid UTF-16LE.
760 const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
761 return out_buffer[0..end_index];
762 },
763 else => @compileError("std.fs.selfExePath not supported for this target"),
764 }
765}
766
767/// Same as `selfExePath` except the result is UTF16LE-encoded.
768pub fn selfExePathW(out_buffer: *[os.windows.PATH_MAX_WIDE]u16) SelfExePathError![]u16 {
769 return os.windows.GetModuleFileNameW(null, out_buffer, out_buffer.len);
770}
771
772/// `selfExeDirPath` except allocates the result on the heap.
773/// Caller owns returned memory.
774pub fn selfExeDirPathAlloc(allocator: *Allocator) ![]u8 {
775 var buf: [MAX_PATH_BYTES]u8 = undefined;
776 return mem.dupe(allocator, u8, try selfExeDirPath(&buf));
777}
778
779/// Get the directory path that contains the current executable.
780/// Returned value is a slice of out_buffer.
781pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const u8 {
782 if (os.linux.is_the_target) {
783 // If the currently executing binary has been deleted,
784 // the file path looks something like `/a/b/c/exe (deleted)`
785 // This path cannot be opened, but it's valid for determining the directory
786 // the executable was in when it was run.
787 const full_exe_path = try os.readlinkC(c"/proc/self/exe", out_buffer);
788 // Assume that /proc/self/exe has an absolute path, and therefore dirname
789 // will not return null.
790 return path.dirname(full_exe_path).?;
791 }
792 const self_exe_path = try selfExePath(out_buffer);
793 // Assume that the OS APIs return absolute paths, and therefore dirname
794 // will not return null.
795 return path.dirname(self_exe_path).?;
796}
797
798/// `realpath`, except caller must free the returned memory.
799pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 {
800 var buf: [MAX_PATH_BYTES]u8 = undefined;
801 return mem.dupe(allocator, u8, try os.realpath(pathname, &buf));
802}
803
804test "" {
805 _ = @import("fs/path.zig");
806 _ = @import("fs/file.zig");
807 _ = @import("fs/get_app_data_dir.zig");
808}
std/fs/file.zig created+319
...@@ -0,0 +1,319 @@
1const std = @import("../std.zig");
2const builtin = @import("builtin");
3const os = std.os;
4const io = std.io;
5const mem = std.mem;
6const math = std.math;
7const assert = std.debug.assert;
8const windows = os.windows;
9const Os = builtin.Os;
10const maxInt = std.math.maxInt;
11
12pub const File = struct {
13 /// The OS-specific file descriptor or file handle.
14 handle: os.fd_t,
15
16 pub const Mode = switch (builtin.os) {
17 Os.windows => void,
18 else => u32,
19 };
20
21 pub const default_mode = switch (builtin.os) {
22 Os.windows => {},
23 else => 0o666,
24 };
25
26 pub const OpenError = windows.CreateFileError || os.OpenError;
27
28 /// Call close to clean up.
29 pub fn openRead(path: []const u8) OpenError!File {
30 if (windows.is_the_target) {
31 const path_w = try windows.sliceToPrefixedFileW(path);
32 return openReadW(&path_w);
33 }
34 const path_c = try os.toPosixPath(path);
35 return openReadC(&path_c);
36 }
37
38 /// `openRead` except with a null terminated path
39 pub fn openReadC(path: [*]const u8) OpenError!File {
40 if (windows.is_the_target) {
41 const path_w = try windows.cStrToPrefixedFileW(path);
42 return openReadW(&path_w);
43 }
44 const flags = os.O_LARGEFILE | os.O_RDONLY;
45 const fd = try os.openC(path, flags, 0);
46 return openHandle(fd);
47 }
48
49 /// `openRead` except with a null terminated UTF16LE encoded path
50 pub fn openReadW(path_w: [*]const u16) OpenError!File {
51 const handle = try windows.CreateFileW(
52 path_w,
53 windows.GENERIC_READ,
54 windows.FILE_SHARE_READ,
55 null,
56 windows.OPEN_EXISTING,
57 windows.FILE_ATTRIBUTE_NORMAL,
58 null,
59 );
60 return openHandle(handle);
61 }
62
63 /// Calls `openWriteMode` with `default_mode` for the mode.
64 pub fn openWrite(path: []const u8) OpenError!File {
65 return openWriteMode(path, default_mode);
66 }
67
68 /// If the path does not exist it will be created.
69 /// If a file already exists in the destination it will be truncated.
70 /// Call close to clean up.
71 pub fn openWriteMode(path: []const u8, file_mode: Mode) OpenError!File {
72 if (windows.is_the_target) {
73 const path_w = try windows.sliceToPrefixedFileW(path);
74 return openWriteModeW(&path_w, file_mode);
75 }
76 const path_c = try os.toPosixPath(path);
77 return openWriteModeC(&path_c, file_mode);
78 }
79
80 /// Same as `openWriteMode` except `path` is null-terminated.
81 pub fn openWriteModeC(path: [*]const u8, file_mode: Mode) OpenError!File {
82 if (windows.is_the_target) {
83 const path_w = try windows.cStrToPrefixedFileW(path);
84 return openWriteModeW(&path_w, file_mode);
85 }
86 const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_TRUNC;
87 const fd = try os.openC(path, flags, file_mode);
88 return openHandle(fd);
89 }
90
91 /// Same as `openWriteMode` except `path` is null-terminated and UTF16LE encoded
92 pub fn openWriteModeW(path_w: [*]const u16, file_mode: Mode) OpenError!File {
93 const handle = try windows.CreateFileW(
94 path_w,
95 windows.GENERIC_WRITE,
96 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
97 null,
98 windows.CREATE_ALWAYS,
99 windows.FILE_ATTRIBUTE_NORMAL,
100 null,
101 );
102 return openHandle(handle);
103 }
104
105 /// If the path does not exist it will be created.
106 /// If a file already exists in the destination this returns OpenError.PathAlreadyExists
107 /// Call close to clean up.
108 pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File {
109 if (windows.is_the_target) {
110 const path_w = try windows.sliceToPrefixedFileW(path);
111 return openWriteNoClobberW(&path_w, file_mode);
112 }
113 const path_c = try os.toPosixPath(path);
114 return openWriteNoClobberC(&path_c, file_mode);
115 }
116
117 pub fn openWriteNoClobberC(path: [*]const u8, file_mode: Mode) OpenError!File {
118 if (windows.is_the_target) {
119 const path_w = try windows.cStrToPrefixedFileW(path);
120 return openWriteNoClobberW(&path_w, file_mode);
121 }
122 const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_EXCL;
123 const fd = try os.openC(path, flags, file_mode);
124 return openHandle(fd);
125 }
126
127 pub fn openWriteNoClobberW(path_w: [*]const u16, file_mode: Mode) OpenError!File {
128 const handle = try windows.CreateFileW(
129 path_w,
130 windows.GENERIC_WRITE,
131 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
132 null,
133 windows.CREATE_NEW,
134 windows.FILE_ATTRIBUTE_NORMAL,
135 null,
136 );
137 return openHandle(handle);
138 }
139
140 pub fn openHandle(handle: os.fd_t) File {
141 return File{ .handle = handle };
142 }
143
144 /// Test for the existence of `path`.
145 /// `path` is UTF8-encoded.
146 /// In general it is recommended to avoid this function. For example,
147 /// instead of testing if a file exists and then opening it, just
148 /// open it and handle the error for file not found.
149 pub fn access(path: []const u8) !void {
150 return os.access(path, os.F_OK);
151 }
152
153 /// Same as `access` except the parameter is null-terminated.
154 pub fn accessC(path: [*]const u8) !void {
155 return os.accessC(path, os.F_OK);
156 }
157
158 /// Same as `access` except the parameter is null-terminated UTF16LE-encoded.
159 pub fn accessW(path: [*]const u16) !void {
160 return os.accessW(path, os.F_OK);
161 }
162
163 /// Upon success, the stream is in an uninitialized state. To continue using it,
164 /// you must use the open() function.
165 pub fn close(self: File) void {
166 return os.close(self.handle);
167 }
168
169 /// Test whether the file refers to a terminal.
170 /// See also `supportsAnsiEscapeCodes`.
171 pub fn isTty(self: File) bool {
172 return os.isatty(self.handle);
173 }
174
175 /// Test whether ANSI escape codes will be treated as such.
176 pub fn supportsAnsiEscapeCodes(self: File) bool {
177 if (windows.is_the_target) {
178 return os.isCygwinPty(self.handle);
179 }
180 return self.isTty();
181 }
182
183 pub const SeekError = os.SeekError;
184
185 /// Repositions read/write file offset relative to the current offset.
186 pub fn seekBy(self: File, offset: i64) SeekError!void {
187 return os.lseek_CUR(self.handle, offset);
188 }
189
190 /// Repositions read/write file offset relative to the end.
191 pub fn seekFromEnd(self: File, offset: i64) SeekError!void {
192 return os.lseek_END(self.handle, offset);
193 }
194
195 /// Repositions read/write file offset relative to the beginning.
196 pub fn seekTo(self: File, offset: u64) SeekError!void {
197 return os.lseek_SET(self.handle, offset);
198 }
199
200 pub const GetPosError = os.SeekError || os.FStatError;
201
202 pub fn getPos(self: File) GetPosError!u64 {
203 return os.lseek_CUR_get(self.handle);
204 }
205
206 pub fn getEndPos(self: File) GetPosError!u64 {
207 if (windows.is_the_target) {
208 return windows.GetFileSizeEx(self.handle);
209 }
210 const stat = try os.fstat(self.handle);
211 return @bitCast(u64, stat.size);
212 }
213
214 pub const ModeError = os.FStatError;
215
216 pub fn mode(self: File) ModeError!Mode {
217 if (windows.is_the_target) {
218 return {};
219 }
220 const stat = try os.fstat(self.handle);
221 // TODO: we should be able to cast u16 to ModeError!u32, making this
222 // explicit cast not necessary
223 return Mode(stat.mode);
224 }
225
226 pub const ReadError = os.ReadError;
227
228 pub fn read(self: File, buffer: []u8) ReadError!usize {
229 return os.read(self.handle, buffer);
230 }
231
232 pub const WriteError = os.WriteError;
233
234 pub fn write(self: File, bytes: []const u8) WriteError!void {
235 return os.write(self.handle, bytes);
236 }
237
238 pub fn inStream(file: File) InStream {
239 return InStream{
240 .file = file,
241 .stream = InStream.Stream{ .readFn = InStream.readFn },
242 };
243 }
244
245 pub fn outStream(file: File) OutStream {
246 return OutStream{
247 .file = file,
248 .stream = OutStream.Stream{ .writeFn = OutStream.writeFn },
249 };
250 }
251
252 pub fn seekableStream(file: File) SeekableStream {
253 return SeekableStream{
254 .file = file,
255 .stream = SeekableStream.Stream{
256 .seekToFn = SeekableStream.seekToFn,
257 .seekByFn = SeekableStream.seekByFn,
258 .getPosFn = SeekableStream.getPosFn,
259 .getEndPosFn = SeekableStream.getEndPosFn,
260 },
261 };
262 }
263
264 /// Implementation of io.InStream trait for File
265 pub const InStream = struct {
266 file: File,
267 stream: Stream,
268
269 pub const Error = ReadError;
270 pub const Stream = io.InStream(Error);
271
272 fn readFn(in_stream: *Stream, buffer: []u8) Error!usize {
273 const self = @fieldParentPtr(InStream, "stream", in_stream);
274 return self.file.read(buffer);
275 }
276 };
277
278 /// Implementation of io.OutStream trait for File
279 pub const OutStream = struct {
280 file: File,
281 stream: Stream,
282
283 pub const Error = WriteError;
284 pub const Stream = io.OutStream(Error);
285
286 fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void {
287 const self = @fieldParentPtr(OutStream, "stream", out_stream);
288 return self.file.write(bytes);
289 }
290 };
291
292 /// Implementation of io.SeekableStream trait for File
293 pub const SeekableStream = struct {
294 file: File,
295 stream: Stream,
296
297 pub const Stream = io.SeekableStream(SeekError, GetPosError);
298
299 pub fn seekToFn(seekable_stream: *Stream, pos: u64) SeekError!void {
300 const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
301 return self.file.seekTo(pos);
302 }
303
304 pub fn seekByFn(seekable_stream: *Stream, amt: i64) SeekError!void {
305 const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
306 return self.file.seekBy(amt);
307 }
308
309 pub fn getEndPosFn(seekable_stream: *Stream) GetPosError!u64 {
310 const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
311 return self.file.getEndPos();
312 }
313
314 pub fn getPosFn(seekable_stream: *Stream) GetPosError!u64 {
315 const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
316 return self.file.getPos();
317 }
318 };
319};
std/fs/get_app_data_dir.zig created+70
...@@ -0,0 +1,70 @@
1const std = @import("../std.zig");
2const builtin = @import("builtin");
3const unicode = std.unicode;
4const mem = std.mem;
5const fs = std.fs;
6const os = std.os;
7
8pub const GetAppDataDirError = error{
9 OutOfMemory,
10 AppDataDirUnavailable,
11};
12
13/// Caller owns returned memory.
14/// TODO determine if we can remove the allocator requirement
15pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataDirError![]u8 {
16 switch (builtin.os) {
17 .windows => {
18 var dir_path_ptr: [*]u16 = undefined;
19 switch (os.windows.shell32.SHGetKnownFolderPath(
20 &os.windows.FOLDERID_LocalAppData,
21 os.windows.KF_FLAG_CREATE,
22 null,
23 &dir_path_ptr,
24 )) {
25 os.windows.S_OK => {
26 defer os.windows.ole32.CoTaskMemFree(@ptrCast(*c_void, dir_path_ptr));
27 const global_dir = unicode.utf16leToUtf8Alloc(allocator, utf16lePtrSlice(dir_path_ptr)) catch |err| switch (err) {
28 error.UnexpectedSecondSurrogateHalf => return error.AppDataDirUnavailable,
29 error.ExpectedSecondSurrogateHalf => return error.AppDataDirUnavailable,
30 error.DanglingSurrogateHalf => return error.AppDataDirUnavailable,
31 error.OutOfMemory => return error.OutOfMemory,
32 };
33 defer allocator.free(global_dir);
34 return fs.path.join(allocator, [][]const u8{ global_dir, appname });
35 },
36 os.windows.E_OUTOFMEMORY => return error.OutOfMemory,
37 else => return error.AppDataDirUnavailable,
38 }
39 },
40 .macosx => {
41 const home_dir = os.getenv("HOME") orelse {
42 // TODO look in /etc/passwd
43 return error.AppDataDirUnavailable;
44 };
45 return fs.path.join(allocator, [][]const u8{ home_dir, "Library", "Application Support", appname });
46 },
47 .linux, .freebsd, .netbsd => {
48 const home_dir = os.getenv("HOME") orelse {
49 // TODO look in /etc/passwd
50 return error.AppDataDirUnavailable;
51 };
52 return fs.path.join(allocator, [][]const u8{ home_dir, ".local", "share", appname });
53 },
54 else => @compileError("Unsupported OS"),
55 }
56}
57
58fn utf16lePtrSlice(ptr: [*]const u16) []const u16 {
59 var index: usize = 0;
60 while (ptr[index] != 0) : (index += 1) {}
61 return ptr[0..index];
62}
63
64test "getAppDataDir" {
65 var buf: [512]u8 = undefined;
66 const allocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
67
68 // We can't actually validate the result
69 _ = getAppDataDir(allocator, "zig") catch return;
70}
std/fs/path.zig created+1136
...@@ -0,0 +1,1136 @@
1const builtin = @import("builtin");
2const std = @import("../std.zig");
3const debug = std.debug;
4const assert = debug.assert;
5const testing = std.testing;
6const mem = std.mem;
7const fmt = std.fmt;
8const Allocator = mem.Allocator;
9const math = std.math;
10const windows = std.os.windows;
11const fs = std.fs;
12const process = std.process;
13
14pub const sep_windows = '\\';
15pub const sep_posix = '/';
16pub const sep = if (windows.is_the_target) sep_windows else sep_posix;
17
18pub const sep_str = [1]u8{sep};
19
20pub const delimiter_windows = ';';
21pub const delimiter_posix = ':';
22pub const delimiter = if (windows.is_the_target) delimiter_windows else delimiter_posix;
23
24pub fn isSep(byte: u8) bool {
25 if (windows.is_the_target) {
26 return byte == '/' or byte == '\\';
27 } else {
28 return byte == '/';
29 }
30}
31
32/// This is different from mem.join in that the separator will not be repeated if
33/// it is found at the end or beginning of a pair of consecutive paths.
34fn joinSep(allocator: *Allocator, separator: u8, paths: []const []const u8) ![]u8 {
35 if (paths.len == 0) return (([*]u8)(undefined))[0..0];
36
37 const total_len = blk: {
38 var sum: usize = paths[0].len;
39 var i: usize = 1;
40 while (i < paths.len) : (i += 1) {
41 const prev_path = paths[i - 1];
42 const this_path = paths[i];
43 const prev_sep = (prev_path.len != 0 and prev_path[prev_path.len - 1] == separator);
44 const this_sep = (this_path.len != 0 and this_path[0] == separator);
45 sum += @boolToInt(!prev_sep and !this_sep);
46 sum += if (prev_sep and this_sep) this_path.len - 1 else this_path.len;
47 }
48 break :blk sum;
49 };
50
51 const buf = try allocator.alloc(u8, total_len);
52 errdefer allocator.free(buf);
53
54 mem.copy(u8, buf, paths[0]);
55 var buf_index: usize = paths[0].len;
56 var i: usize = 1;
57 while (i < paths.len) : (i += 1) {
58 const prev_path = paths[i - 1];
59 const this_path = paths[i];
60 const prev_sep = (prev_path.len != 0 and prev_path[prev_path.len - 1] == separator);
61 const this_sep = (this_path.len != 0 and this_path[0] == separator);
62 if (!prev_sep and !this_sep) {
63 buf[buf_index] = separator;
64 buf_index += 1;
65 }
66 const adjusted_path = if (prev_sep and this_sep) this_path[1..] else this_path;
67 mem.copy(u8, buf[buf_index..], adjusted_path);
68 buf_index += adjusted_path.len;
69 }
70
71 // No need for shrink since buf is exactly the correct size.
72 return buf;
73}
74
75pub const join = if (windows.is_the_target) joinWindows else joinPosix;
76
77/// Naively combines a series of paths with the native path seperator.
78/// Allocates memory for the result, which must be freed by the caller.
79pub fn joinWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
80 return joinSep(allocator, sep_windows, paths);
81}
82
83/// Naively combines a series of paths with the native path seperator.
84/// Allocates memory for the result, which must be freed by the caller.
85pub fn joinPosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
86 return joinSep(allocator, sep_posix, paths);
87}
88
89fn testJoinWindows(paths: []const []const u8, expected: []const u8) void {
90 var buf: [1024]u8 = undefined;
91 const a = &std.heap.FixedBufferAllocator.init(&buf).allocator;
92 const actual = joinWindows(a, paths) catch @panic("fail");
93 testing.expectEqualSlices(u8, expected, actual);
94}
95
96fn testJoinPosix(paths: []const []const u8, expected: []const u8) void {
97 var buf: [1024]u8 = undefined;
98 const a = &std.heap.FixedBufferAllocator.init(&buf).allocator;
99 const actual = joinPosix(a, paths) catch @panic("fail");
100 testing.expectEqualSlices(u8, expected, actual);
101}
102
103test "join" {
104 testJoinWindows([][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c");
105 testJoinWindows([][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c");
106 testJoinWindows([][]const u8{ "c:\\a\\b\\", "c" }, "c:\\a\\b\\c");
107
108 testJoinWindows([][]const u8{ "c:\\", "a", "b\\", "c" }, "c:\\a\\b\\c");
109 testJoinWindows([][]const u8{ "c:\\a\\", "b\\", "c" }, "c:\\a\\b\\c");
110
111 testJoinWindows(
112 [][]const u8{ "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std", "io.zig" },
113 "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig",
114 );
115
116 testJoinPosix([][]const u8{ "/a/b", "c" }, "/a/b/c");
117 testJoinPosix([][]const u8{ "/a/b/", "c" }, "/a/b/c");
118
119 testJoinPosix([][]const u8{ "/", "a", "b/", "c" }, "/a/b/c");
120 testJoinPosix([][]const u8{ "/a/", "b/", "c" }, "/a/b/c");
121
122 testJoinPosix(
123 [][]const u8{ "/home/andy/dev/zig/build/lib/zig/std", "io.zig" },
124 "/home/andy/dev/zig/build/lib/zig/std/io.zig",
125 );
126
127 testJoinPosix([][]const u8{ "a", "/c" }, "a/c");
128 testJoinPosix([][]const u8{ "a/", "/c" }, "a/c");
129}
130
131pub fn isAbsolute(path: []const u8) bool {
132 if (windows.is_the_target) {
133 return isAbsoluteWindows(path);
134 } else {
135 return isAbsolutePosix(path);
136 }
137}
138
139pub fn isAbsoluteWindows(path: []const u8) bool {
140 if (path[0] == '/')
141 return true;
142
143 if (path[0] == '\\') {
144 return true;
145 }
146 if (path.len < 3) {
147 return false;
148 }
149 if (path[1] == ':') {
150 if (path[2] == '/')
151 return true;
152 if (path[2] == '\\')
153 return true;
154 }
155 return false;
156}
157
158pub fn isAbsolutePosix(path: []const u8) bool {
159 return path[0] == sep_posix;
160}
161
162test "isAbsoluteWindows" {
163 testIsAbsoluteWindows("/", true);
164 testIsAbsoluteWindows("//", true);
165 testIsAbsoluteWindows("//server", true);
166 testIsAbsoluteWindows("//server/file", true);
167 testIsAbsoluteWindows("\\\\server\\file", true);
168 testIsAbsoluteWindows("\\\\server", true);
169 testIsAbsoluteWindows("\\\\", true);
170 testIsAbsoluteWindows("c", false);
171 testIsAbsoluteWindows("c:", false);
172 testIsAbsoluteWindows("c:\\", true);
173 testIsAbsoluteWindows("c:/", true);
174 testIsAbsoluteWindows("c://", true);
175 testIsAbsoluteWindows("C:/Users/", true);
176 testIsAbsoluteWindows("C:\\Users\\", true);
177 testIsAbsoluteWindows("C:cwd/another", false);
178 testIsAbsoluteWindows("C:cwd\\another", false);
179 testIsAbsoluteWindows("directory/directory", false);
180 testIsAbsoluteWindows("directory\\directory", false);
181 testIsAbsoluteWindows("/usr/local", true);
182}
183
184test "isAbsolutePosix" {
185 testIsAbsolutePosix("/home/foo", true);
186 testIsAbsolutePosix("/home/foo/..", true);
187 testIsAbsolutePosix("bar/", false);
188 testIsAbsolutePosix("./baz", false);
189}
190
191fn testIsAbsoluteWindows(path: []const u8, expected_result: bool) void {
192 testing.expectEqual(expected_result, isAbsoluteWindows(path));
193}
194
195fn testIsAbsolutePosix(path: []const u8, expected_result: bool) void {
196 testing.expectEqual(expected_result, isAbsolutePosix(path));
197}
198
199pub const WindowsPath = struct {
200 is_abs: bool,
201 kind: Kind,
202 disk_designator: []const u8,
203
204 pub const Kind = enum {
205 None,
206 Drive,
207 NetworkShare,
208 };
209};
210
211pub fn windowsParsePath(path: []const u8) WindowsPath {
212 if (path.len >= 2 and path[1] == ':') {
213 return WindowsPath{
214 .is_abs = isAbsoluteWindows(path),
215 .kind = WindowsPath.Kind.Drive,
216 .disk_designator = path[0..2],
217 };
218 }
219 if (path.len >= 1 and (path[0] == '/' or path[0] == '\\') and
220 (path.len == 1 or (path[1] != '/' and path[1] != '\\')))
221 {
222 return WindowsPath{
223 .is_abs = true,
224 .kind = WindowsPath.Kind.None,
225 .disk_designator = path[0..0],
226 };
227 }
228 const relative_path = WindowsPath{
229 .kind = WindowsPath.Kind.None,
230 .disk_designator = []u8{},
231 .is_abs = false,
232 };
233 if (path.len < "//a/b".len) {
234 return relative_path;
235 }
236
237 // TODO when I combined these together with `inline for` the compiler crashed
238 {
239 const this_sep = '/';
240 const two_sep = []u8{ this_sep, this_sep };
241 if (mem.startsWith(u8, path, two_sep)) {
242 if (path[2] == this_sep) {
243 return relative_path;
244 }
245
246 var it = mem.tokenize(path, []u8{this_sep});
247 _ = (it.next() orelse return relative_path);
248 _ = (it.next() orelse return relative_path);
249 return WindowsPath{
250 .is_abs = isAbsoluteWindows(path),
251 .kind = WindowsPath.Kind.NetworkShare,
252 .disk_designator = path[0..it.index],
253 };
254 }
255 }
256 {
257 const this_sep = '\\';
258 const two_sep = []u8{ this_sep, this_sep };
259 if (mem.startsWith(u8, path, two_sep)) {
260 if (path[2] == this_sep) {
261 return relative_path;
262 }
263
264 var it = mem.tokenize(path, []u8{this_sep});
265 _ = (it.next() orelse return relative_path);
266 _ = (it.next() orelse return relative_path);
267 return WindowsPath{
268 .is_abs = isAbsoluteWindows(path),
269 .kind = WindowsPath.Kind.NetworkShare,
270 .disk_designator = path[0..it.index],
271 };
272 }
273 }
274 return relative_path;
275}
276
277test "windowsParsePath" {
278 {
279 const parsed = windowsParsePath("//a/b");
280 testing.expect(parsed.is_abs);
281 testing.expect(parsed.kind == WindowsPath.Kind.NetworkShare);
282 testing.expect(mem.eql(u8, parsed.disk_designator, "//a/b"));
283 }
284 {
285 const parsed = windowsParsePath("\\\\a\\b");
286 testing.expect(parsed.is_abs);
287 testing.expect(parsed.kind == WindowsPath.Kind.NetworkShare);
288 testing.expect(mem.eql(u8, parsed.disk_designator, "\\\\a\\b"));
289 }
290 {
291 const parsed = windowsParsePath("\\\\a\\");
292 testing.expect(!parsed.is_abs);
293 testing.expect(parsed.kind == WindowsPath.Kind.None);
294 testing.expect(mem.eql(u8, parsed.disk_designator, ""));
295 }
296 {
297 const parsed = windowsParsePath("/usr/local");
298 testing.expect(parsed.is_abs);
299 testing.expect(parsed.kind == WindowsPath.Kind.None);
300 testing.expect(mem.eql(u8, parsed.disk_designator, ""));
301 }
302 {
303 const parsed = windowsParsePath("c:../");
304 testing.expect(!parsed.is_abs);
305 testing.expect(parsed.kind == WindowsPath.Kind.Drive);
306 testing.expect(mem.eql(u8, parsed.disk_designator, "c:"));
307 }
308}
309
310pub fn diskDesignator(path: []const u8) []const u8 {
311 if (windows.is_the_target) {
312 return diskDesignatorWindows(path);
313 } else {
314 return "";
315 }
316}
317
318pub fn diskDesignatorWindows(path: []const u8) []const u8 {
319 return windowsParsePath(path).disk_designator;
320}
321
322fn networkShareServersEql(ns1: []const u8, ns2: []const u8) bool {
323 const sep1 = ns1[0];
324 const sep2 = ns2[0];
325
326 var it1 = mem.tokenize(ns1, []u8{sep1});
327 var it2 = mem.tokenize(ns2, []u8{sep2});
328
329 // TODO ASCII is wrong, we actually need full unicode support to compare paths.
330 return asciiEqlIgnoreCase(it1.next().?, it2.next().?);
331}
332
333fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8) bool {
334 switch (kind) {
335 WindowsPath.Kind.None => {
336 assert(p1.len == 0);
337 assert(p2.len == 0);
338 return true;
339 },
340 WindowsPath.Kind.Drive => {
341 return asciiUpper(p1[0]) == asciiUpper(p2[0]);
342 },
343 WindowsPath.Kind.NetworkShare => {
344 const sep1 = p1[0];
345 const sep2 = p2[0];
346
347 var it1 = mem.tokenize(p1, []u8{sep1});
348 var it2 = mem.tokenize(p2, []u8{sep2});
349
350 // TODO ASCII is wrong, we actually need full unicode support to compare paths.
351 return asciiEqlIgnoreCase(it1.next().?, it2.next().?) and asciiEqlIgnoreCase(it1.next().?, it2.next().?);
352 },
353 }
354}
355
356fn asciiUpper(byte: u8) u8 {
357 return switch (byte) {
358 'a'...'z' => 'A' + (byte - 'a'),
359 else => byte,
360 };
361}
362
363fn asciiEqlIgnoreCase(s1: []const u8, s2: []const u8) bool {
364 if (s1.len != s2.len)
365 return false;
366 var i: usize = 0;
367 while (i < s1.len) : (i += 1) {
368 if (asciiUpper(s1[i]) != asciiUpper(s2[i]))
369 return false;
370 }
371 return true;
372}
373
374/// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`.
375pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 {
376 if (windows.is_the_target) {
377 return resolveWindows(allocator, paths);
378 } else {
379 return resolvePosix(allocator, paths);
380 }
381}
382
383/// This function is like a series of `cd` statements executed one after another.
384/// It resolves "." and "..".
385/// The result does not have a trailing path separator.
386/// If all paths are relative it uses the current working directory as a starting point.
387/// Each drive has its own current working directory.
388/// Path separators are canonicalized to '\\' and drives are canonicalized to capital letters.
389/// Note: all usage of this function should be audited due to the existence of symlinks.
390/// Without performing actual syscalls, resolving `..` could be incorrect.
391pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
392 if (paths.len == 0) {
393 assert(windows.is_the_target); // resolveWindows called on non windows can't use getCwd
394 return process.getCwdAlloc(allocator);
395 }
396
397 // determine which disk designator we will result with, if any
398 var result_drive_buf = "_:";
399 var result_disk_designator: []const u8 = "";
400 var have_drive_kind = WindowsPath.Kind.None;
401 var have_abs_path = false;
402 var first_index: usize = 0;
403 var max_size: usize = 0;
404 for (paths) |p, i| {
405 const parsed = windowsParsePath(p);
406 if (parsed.is_abs) {
407 have_abs_path = true;
408 first_index = i;
409 max_size = result_disk_designator.len;
410 }
411 switch (parsed.kind) {
412 WindowsPath.Kind.Drive => {
413 result_drive_buf[0] = asciiUpper(parsed.disk_designator[0]);
414 result_disk_designator = result_drive_buf[0..];
415 have_drive_kind = WindowsPath.Kind.Drive;
416 },
417 WindowsPath.Kind.NetworkShare => {
418 result_disk_designator = parsed.disk_designator;
419 have_drive_kind = WindowsPath.Kind.NetworkShare;
420 },
421 WindowsPath.Kind.None => {},
422 }
423 max_size += p.len + 1;
424 }
425
426 // if we will result with a disk designator, loop again to determine
427 // which is the last time the disk designator is absolutely specified, if any
428 // and count up the max bytes for paths related to this disk designator
429 if (have_drive_kind != WindowsPath.Kind.None) {
430 have_abs_path = false;
431 first_index = 0;
432 max_size = result_disk_designator.len;
433 var correct_disk_designator = false;
434
435 for (paths) |p, i| {
436 const parsed = windowsParsePath(p);
437 if (parsed.kind != WindowsPath.Kind.None) {
438 if (parsed.kind == have_drive_kind) {
439 correct_disk_designator = compareDiskDesignators(have_drive_kind, result_disk_designator, parsed.disk_designator);
440 } else {
441 continue;
442 }
443 }
444 if (!correct_disk_designator) {
445 continue;
446 }
447 if (parsed.is_abs) {
448 first_index = i;
449 max_size = result_disk_designator.len;
450 have_abs_path = true;
451 }
452 max_size += p.len + 1;
453 }
454 }
455
456 // Allocate result and fill in the disk designator, calling getCwd if we have to.
457 var result: []u8 = undefined;
458 var result_index: usize = 0;
459
460 if (have_abs_path) {
461 switch (have_drive_kind) {
462 WindowsPath.Kind.Drive => {
463 result = try allocator.alloc(u8, max_size);
464
465 mem.copy(u8, result, result_disk_designator);
466 result_index += result_disk_designator.len;
467 },
468 WindowsPath.Kind.NetworkShare => {
469 result = try allocator.alloc(u8, max_size);
470 var it = mem.tokenize(paths[first_index], "/\\");
471 const server_name = it.next().?;
472 const other_name = it.next().?;
473
474 result[result_index] = '\\';
475 result_index += 1;
476 result[result_index] = '\\';
477 result_index += 1;
478 mem.copy(u8, result[result_index..], server_name);
479 result_index += server_name.len;
480 result[result_index] = '\\';
481 result_index += 1;
482 mem.copy(u8, result[result_index..], other_name);
483 result_index += other_name.len;
484
485 result_disk_designator = result[0..result_index];
486 },
487 WindowsPath.Kind.None => {
488 assert(windows.is_the_target); // resolveWindows called on non windows can't use getCwd
489 const cwd = try process.getCwdAlloc(allocator);
490 defer allocator.free(cwd);
491 const parsed_cwd = windowsParsePath(cwd);
492 result = try allocator.alloc(u8, max_size + parsed_cwd.disk_designator.len + 1);
493 mem.copy(u8, result, parsed_cwd.disk_designator);
494 result_index += parsed_cwd.disk_designator.len;
495 result_disk_designator = result[0..parsed_cwd.disk_designator.len];
496 if (parsed_cwd.kind == WindowsPath.Kind.Drive) {
497 result[0] = asciiUpper(result[0]);
498 }
499 have_drive_kind = parsed_cwd.kind;
500 },
501 }
502 } else {
503 assert(windows.is_the_target); // resolveWindows called on non windows can't use getCwd
504 // TODO call get cwd for the result_disk_designator instead of the global one
505 const cwd = try process.getCwdAlloc(allocator);
506 defer allocator.free(cwd);
507
508 result = try allocator.alloc(u8, max_size + cwd.len + 1);
509
510 mem.copy(u8, result, cwd);
511 result_index += cwd.len;
512 const parsed_cwd = windowsParsePath(result[0..result_index]);
513 result_disk_designator = parsed_cwd.disk_designator;
514 if (parsed_cwd.kind == WindowsPath.Kind.Drive) {
515 result[0] = asciiUpper(result[0]);
516 }
517 have_drive_kind = parsed_cwd.kind;
518 }
519 errdefer allocator.free(result);
520
521 // Now we know the disk designator to use, if any, and what kind it is. And our result
522 // is big enough to append all the paths to.
523 var correct_disk_designator = true;
524 for (paths[first_index..]) |p, i| {
525 const parsed = windowsParsePath(p);
526
527 if (parsed.kind != WindowsPath.Kind.None) {
528 if (parsed.kind == have_drive_kind) {
529 correct_disk_designator = compareDiskDesignators(have_drive_kind, result_disk_designator, parsed.disk_designator);
530 } else {
531 continue;
532 }
533 }
534 if (!correct_disk_designator) {
535 continue;
536 }
537 var it = mem.tokenize(p[parsed.disk_designator.len..], "/\\");
538 while (it.next()) |component| {
539 if (mem.eql(u8, component, ".")) {
540 continue;
541 } else if (mem.eql(u8, component, "..")) {
542 while (true) {
543 if (result_index == 0 or result_index == result_disk_designator.len)
544 break;
545 result_index -= 1;
546 if (result[result_index] == '\\' or result[result_index] == '/')
547 break;
548 }
549 } else {
550 result[result_index] = sep_windows;
551 result_index += 1;
552 mem.copy(u8, result[result_index..], component);
553 result_index += component.len;
554 }
555 }
556 }
557
558 if (result_index == result_disk_designator.len) {
559 result[result_index] = '\\';
560 result_index += 1;
561 }
562
563 return allocator.shrink(result, result_index);
564}
565
566/// This function is like a series of `cd` statements executed one after another.
567/// It resolves "." and "..".
568/// The result does not have a trailing path separator.
569/// If all paths are relative it uses the current working directory as a starting point.
570/// Note: all usage of this function should be audited due to the existence of symlinks.
571/// Without performing actual syscalls, resolving `..` could be incorrect.
572pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
573 if (paths.len == 0) {
574 assert(!windows.is_the_target); // resolvePosix called on windows can't use getCwd
575 return process.getCwdAlloc(allocator);
576 }
577
578 var first_index: usize = 0;
579 var have_abs = false;
580 var max_size: usize = 0;
581 for (paths) |p, i| {
582 if (isAbsolutePosix(p)) {
583 first_index = i;
584 have_abs = true;
585 max_size = 0;
586 }
587 max_size += p.len + 1;
588 }
589
590 var result: []u8 = undefined;
591 var result_index: usize = 0;
592
593 if (have_abs) {
594 result = try allocator.alloc(u8, max_size);
595 } else {
596 assert(!windows.is_the_target); // resolvePosix called on windows can't use getCwd
597 const cwd = try process.getCwdAlloc(allocator);
598 defer allocator.free(cwd);
599 result = try allocator.alloc(u8, max_size + cwd.len + 1);
600 mem.copy(u8, result, cwd);
601 result_index += cwd.len;
602 }
603 errdefer allocator.free(result);
604
605 for (paths[first_index..]) |p, i| {
606 var it = mem.tokenize(p, "/");
607 while (it.next()) |component| {
608 if (mem.eql(u8, component, ".")) {
609 continue;
610 } else if (mem.eql(u8, component, "..")) {
611 while (true) {
612 if (result_index == 0)
613 break;
614 result_index -= 1;
615 if (result[result_index] == '/')
616 break;
617 }
618 } else {
619 result[result_index] = '/';
620 result_index += 1;
621 mem.copy(u8, result[result_index..], component);
622 result_index += component.len;
623 }
624 }
625 }
626
627 if (result_index == 0) {
628 result[0] = '/';
629 result_index += 1;
630 }
631
632 return allocator.shrink(result, result_index);
633}
634
635test "resolve" {
636 const cwd = try process.getCwdAlloc(debug.global_allocator);
637 if (windows.is_the_target) {
638 if (windowsParsePath(cwd).kind == WindowsPath.Kind.Drive) {
639 cwd[0] = asciiUpper(cwd[0]);
640 }
641 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{"."}), cwd));
642 } else {
643 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "a/b/c/", "../../.." }), cwd));
644 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{"."}), cwd));
645 }
646}
647
648test "resolveWindows" {
649 if (windows.is_the_target) {
650 const cwd = try process.getCwdAlloc(debug.global_allocator);
651 const parsed_cwd = windowsParsePath(cwd);
652 {
653 const result = testResolveWindows([][]const u8{ "/usr/local", "lib\\zig\\std\\array_list.zig" });
654 const expected = try join(debug.global_allocator, [][]const u8{
655 parsed_cwd.disk_designator,
656 "usr\\local\\lib\\zig\\std\\array_list.zig",
657 });
658 if (parsed_cwd.kind == WindowsPath.Kind.Drive) {
659 expected[0] = asciiUpper(parsed_cwd.disk_designator[0]);
660 }
661 testing.expect(mem.eql(u8, result, expected));
662 }
663 {
664 const result = testResolveWindows([][]const u8{ "usr/local", "lib\\zig" });
665 const expected = try join(debug.global_allocator, [][]const u8{
666 cwd,
667 "usr\\local\\lib\\zig",
668 });
669 if (parsed_cwd.kind == WindowsPath.Kind.Drive) {
670 expected[0] = asciiUpper(parsed_cwd.disk_designator[0]);
671 }
672 testing.expect(mem.eql(u8, result, expected));
673 }
674 }
675
676 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:\\a\\b\\c", "/hi", "ok" }), "C:\\hi\\ok"));
677 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/blah\\blah", "d:/games", "c:../a" }), "C:\\blah\\a"));
678 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/blah\\blah", "d:/games", "C:../a" }), "C:\\blah\\a"));
679 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/ignore", "d:\\a/b\\c/d", "\\e.exe" }), "D:\\e.exe"));
680 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/ignore", "c:/some/file" }), "C:\\some\\file"));
681 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "d:/ignore", "d:some/dir//" }), "D:\\ignore\\some\\dir"));
682 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "//server/share", "..", "relative\\" }), "\\\\server\\share\\relative"));
683 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//" }), "C:\\"));
684 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//dir" }), "C:\\dir"));
685 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//server/share" }), "\\\\server\\share\\"));
686 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//server//share" }), "\\\\server\\share\\"));
687 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "///some//dir" }), "C:\\some\\dir"));
688 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "C:\\foo\\tmp.3\\", "..\\tmp.3\\cycles\\root.js" }), "C:\\foo\\tmp.3\\cycles\\root.js"));
689}
690
691test "resolvePosix" {
692 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b", "c" }), "/a/b/c"));
693 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b", "c", "//d", "e///" }), "/d/e"));
694 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b/c", "..", "../" }), "/a"));
695 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/", "..", ".." }), "/"));
696 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{"/a/b/c/"}), "/a/b/c"));
697
698 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/var/lib", "../", "file/" }), "/var/file"));
699 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/var/lib", "/../", "file/" }), "/file"));
700 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/some/dir", ".", "/absolute/" }), "/absolute"));
701 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/foo/tmp.3/", "../tmp.3/cycles/root.js" }), "/foo/tmp.3/cycles/root.js"));
702}
703
704fn testResolveWindows(paths: []const []const u8) []u8 {
705 return resolveWindows(debug.global_allocator, paths) catch unreachable;
706}
707
708fn testResolvePosix(paths: []const []const u8) []u8 {
709 return resolvePosix(debug.global_allocator, paths) catch unreachable;
710}
711
712/// If the path is a file in the current directory (no directory component)
713/// then returns null
714pub fn dirname(path: []const u8) ?[]const u8 {
715 if (windows.is_the_target) {
716 return dirnameWindows(path);
717 } else {
718 return dirnamePosix(path);
719 }
720}
721
722pub fn dirnameWindows(path: []const u8) ?[]const u8 {
723 if (path.len == 0)
724 return null;
725
726 const root_slice = diskDesignatorWindows(path);
727 if (path.len == root_slice.len)
728 return path;
729
730 const have_root_slash = path.len > root_slice.len and (path[root_slice.len] == '/' or path[root_slice.len] == '\\');
731
732 var end_index: usize = path.len - 1;
733
734 while ((path[end_index] == '/' or path[end_index] == '\\') and end_index > root_slice.len) {
735 if (end_index == 0)
736 return null;
737 end_index -= 1;
738 }
739
740 while (path[end_index] != '/' and path[end_index] != '\\' and end_index > root_slice.len) {
741 if (end_index == 0)
742 return null;
743 end_index -= 1;
744 }
745
746 if (have_root_slash and end_index == root_slice.len) {
747 end_index += 1;
748 }
749
750 if (end_index == 0)
751 return null;
752
753 return path[0..end_index];
754}
755
756pub fn dirnamePosix(path: []const u8) ?[]const u8 {
757 if (path.len == 0)
758 return null;
759
760 var end_index: usize = path.len - 1;
761 while (path[end_index] == '/') {
762 if (end_index == 0)
763 return path[0..1];
764 end_index -= 1;
765 }
766
767 while (path[end_index] != '/') {
768 if (end_index == 0)
769 return null;
770 end_index -= 1;
771 }
772
773 if (end_index == 0 and path[end_index] == '/')
774 return path[0..1];
775
776 if (end_index == 0)
777 return null;
778
779 return path[0..end_index];
780}
781
782test "dirnamePosix" {
783 testDirnamePosix("/a/b/c", "/a/b");
784 testDirnamePosix("/a/b/c///", "/a/b");
785 testDirnamePosix("/a", "/");
786 testDirnamePosix("/", "/");
787 testDirnamePosix("////", "/");
788 testDirnamePosix("", null);
789 testDirnamePosix("a", null);
790 testDirnamePosix("a/", null);
791 testDirnamePosix("a//", null);
792}
793
794test "dirnameWindows" {
795 testDirnameWindows("c:\\", "c:\\");
796 testDirnameWindows("c:\\foo", "c:\\");
797 testDirnameWindows("c:\\foo\\", "c:\\");
798 testDirnameWindows("c:\\foo\\bar", "c:\\foo");
799 testDirnameWindows("c:\\foo\\bar\\", "c:\\foo");
800 testDirnameWindows("c:\\foo\\bar\\baz", "c:\\foo\\bar");
801 testDirnameWindows("\\", "\\");
802 testDirnameWindows("\\foo", "\\");
803 testDirnameWindows("\\foo\\", "\\");
804 testDirnameWindows("\\foo\\bar", "\\foo");
805 testDirnameWindows("\\foo\\bar\\", "\\foo");
806 testDirnameWindows("\\foo\\bar\\baz", "\\foo\\bar");
807 testDirnameWindows("c:", "c:");
808 testDirnameWindows("c:foo", "c:");
809 testDirnameWindows("c:foo\\", "c:");
810 testDirnameWindows("c:foo\\bar", "c:foo");
811 testDirnameWindows("c:foo\\bar\\", "c:foo");
812 testDirnameWindows("c:foo\\bar\\baz", "c:foo\\bar");
813 testDirnameWindows("file:stream", null);
814 testDirnameWindows("dir\\file:stream", "dir");
815 testDirnameWindows("\\\\unc\\share", "\\\\unc\\share");
816 testDirnameWindows("\\\\unc\\share\\foo", "\\\\unc\\share\\");
817 testDirnameWindows("\\\\unc\\share\\foo\\", "\\\\unc\\share\\");
818 testDirnameWindows("\\\\unc\\share\\foo\\bar", "\\\\unc\\share\\foo");
819 testDirnameWindows("\\\\unc\\share\\foo\\bar\\", "\\\\unc\\share\\foo");
820 testDirnameWindows("\\\\unc\\share\\foo\\bar\\baz", "\\\\unc\\share\\foo\\bar");
821 testDirnameWindows("/a/b/", "/a");
822 testDirnameWindows("/a/b", "/a");
823 testDirnameWindows("/a", "/");
824 testDirnameWindows("", null);
825 testDirnameWindows("/", "/");
826 testDirnameWindows("////", "/");
827 testDirnameWindows("foo", null);
828}
829
830fn testDirnamePosix(input: []const u8, expected_output: ?[]const u8) void {
831 if (dirnamePosix(input)) |output| {
832 testing.expect(mem.eql(u8, output, expected_output.?));
833 } else {
834 testing.expect(expected_output == null);
835 }
836}
837
838fn testDirnameWindows(input: []const u8, expected_output: ?[]const u8) void {
839 if (dirnameWindows(input)) |output| {
840 testing.expect(mem.eql(u8, output, expected_output.?));
841 } else {
842 testing.expect(expected_output == null);
843 }
844}
845
846pub fn basename(path: []const u8) []const u8 {
847 if (windows.is_the_target) {
848 return basenameWindows(path);
849 } else {
850 return basenamePosix(path);
851 }
852}
853
854pub fn basenamePosix(path: []const u8) []const u8 {
855 if (path.len == 0)
856 return []u8{};
857
858 var end_index: usize = path.len - 1;
859 while (path[end_index] == '/') {
860 if (end_index == 0)
861 return []u8{};
862 end_index -= 1;
863 }
864 var start_index: usize = end_index;
865 end_index += 1;
866 while (path[start_index] != '/') {
867 if (start_index == 0)
868 return path[0..end_index];
869 start_index -= 1;
870 }
871
872 return path[start_index + 1 .. end_index];
873}
874
875pub fn basenameWindows(path: []const u8) []const u8 {
876 if (path.len == 0)
877 return []u8{};
878
879 var end_index: usize = path.len - 1;
880 while (true) {
881 const byte = path[end_index];
882 if (byte == '/' or byte == '\\') {
883 if (end_index == 0)
884 return []u8{};
885 end_index -= 1;
886 continue;
887 }
888 if (byte == ':' and end_index == 1) {
889 return []u8{};
890 }
891 break;
892 }
893
894 var start_index: usize = end_index;
895 end_index += 1;
896 while (path[start_index] != '/' and path[start_index] != '\\' and
897 !(path[start_index] == ':' and start_index == 1))
898 {
899 if (start_index == 0)
900 return path[0..end_index];
901 start_index -= 1;
902 }
903
904 return path[start_index + 1 .. end_index];
905}
906
907test "basename" {
908 testBasename("", "");
909 testBasename("/", "");
910 testBasename("/dir/basename.ext", "basename.ext");
911 testBasename("/basename.ext", "basename.ext");
912 testBasename("basename.ext", "basename.ext");
913 testBasename("basename.ext/", "basename.ext");
914 testBasename("basename.ext//", "basename.ext");
915 testBasename("/aaa/bbb", "bbb");
916 testBasename("/aaa/", "aaa");
917 testBasename("/aaa/b", "b");
918 testBasename("/a/b", "b");
919 testBasename("//a", "a");
920
921 testBasenamePosix("\\dir\\basename.ext", "\\dir\\basename.ext");
922 testBasenamePosix("\\basename.ext", "\\basename.ext");
923 testBasenamePosix("basename.ext", "basename.ext");
924 testBasenamePosix("basename.ext\\", "basename.ext\\");
925 testBasenamePosix("basename.ext\\\\", "basename.ext\\\\");
926 testBasenamePosix("foo", "foo");
927
928 testBasenameWindows("\\dir\\basename.ext", "basename.ext");
929 testBasenameWindows("\\basename.ext", "basename.ext");
930 testBasenameWindows("basename.ext", "basename.ext");
931 testBasenameWindows("basename.ext\\", "basename.ext");
932 testBasenameWindows("basename.ext\\\\", "basename.ext");
933 testBasenameWindows("foo", "foo");
934 testBasenameWindows("C:", "");
935 testBasenameWindows("C:.", ".");
936 testBasenameWindows("C:\\", "");
937 testBasenameWindows("C:\\dir\\base.ext", "base.ext");
938 testBasenameWindows("C:\\basename.ext", "basename.ext");
939 testBasenameWindows("C:basename.ext", "basename.ext");
940 testBasenameWindows("C:basename.ext\\", "basename.ext");
941 testBasenameWindows("C:basename.ext\\\\", "basename.ext");
942 testBasenameWindows("C:foo", "foo");
943 testBasenameWindows("file:stream", "file:stream");
944}
945
946fn testBasename(input: []const u8, expected_output: []const u8) void {
947 testing.expectEqualSlices(u8, expected_output, basename(input));
948}
949
950fn testBasenamePosix(input: []const u8, expected_output: []const u8) void {
951 testing.expectEqualSlices(u8, expected_output, basenamePosix(input));
952}
953
954fn testBasenameWindows(input: []const u8, expected_output: []const u8) void {
955 testing.expectEqualSlices(u8, expected_output, basenameWindows(input));
956}
957
958/// Returns the relative path from `from` to `to`. If `from` and `to` each
959/// resolve to the same path (after calling `resolve` on each), a zero-length
960/// string is returned.
961/// On Windows this canonicalizes the drive to a capital letter and paths to `\\`.
962pub fn relative(allocator: *Allocator, from: []const u8, to: []const u8) ![]u8 {
963 if (windows.is_the_target) {
964 return relativeWindows(allocator, from, to);
965 } else {
966 return relativePosix(allocator, from, to);
967 }
968}
969
970pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8) ![]u8 {
971 const resolved_from = try resolveWindows(allocator, [][]const u8{from});
972 defer allocator.free(resolved_from);
973
974 var clean_up_resolved_to = true;
975 const resolved_to = try resolveWindows(allocator, [][]const u8{to});
976 defer if (clean_up_resolved_to) allocator.free(resolved_to);
977
978 const parsed_from = windowsParsePath(resolved_from);
979 const parsed_to = windowsParsePath(resolved_to);
980 const result_is_to = x: {
981 if (parsed_from.kind != parsed_to.kind) {
982 break :x true;
983 } else switch (parsed_from.kind) {
984 WindowsPath.Kind.NetworkShare => {
985 break :x !networkShareServersEql(parsed_to.disk_designator, parsed_from.disk_designator);
986 },
987 WindowsPath.Kind.Drive => {
988 break :x asciiUpper(parsed_from.disk_designator[0]) != asciiUpper(parsed_to.disk_designator[0]);
989 },
990 else => unreachable,
991 }
992 };
993
994 if (result_is_to) {
995 clean_up_resolved_to = false;
996 return resolved_to;
997 }
998
999 var from_it = mem.tokenize(resolved_from, "/\\");
1000 var to_it = mem.tokenize(resolved_to, "/\\");
1001 while (true) {
1002 const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest());
1003 const to_rest = to_it.rest();
1004 if (to_it.next()) |to_component| {
1005 // TODO ASCII is wrong, we actually need full unicode support to compare paths.
1006 if (asciiEqlIgnoreCase(from_component, to_component))
1007 continue;
1008 }
1009 var up_count: usize = 1;
1010 while (from_it.next()) |_| {
1011 up_count += 1;
1012 }
1013 const up_index_end = up_count * "..\\".len;
1014 const result = try allocator.alloc(u8, up_index_end + to_rest.len);
1015 errdefer allocator.free(result);
1016
1017 var result_index: usize = 0;
1018 while (result_index < up_index_end) {
1019 result[result_index] = '.';
1020 result_index += 1;
1021 result[result_index] = '.';
1022 result_index += 1;
1023 result[result_index] = '\\';
1024 result_index += 1;
1025 }
1026 // shave off the trailing slash
1027 result_index -= 1;
1028
1029 var rest_it = mem.tokenize(to_rest, "/\\");
1030 while (rest_it.next()) |to_component| {
1031 result[result_index] = '\\';
1032 result_index += 1;
1033 mem.copy(u8, result[result_index..], to_component);
1034 result_index += to_component.len;
1035 }
1036
1037 return result[0..result_index];
1038 }
1039
1040 return []u8{};
1041}
1042
1043pub fn relativePosix(allocator: *Allocator, from: []const u8, to: []const u8) ![]u8 {
1044 const resolved_from = try resolvePosix(allocator, [][]const u8{from});
1045 defer allocator.free(resolved_from);
1046
1047 const resolved_to = try resolvePosix(allocator, [][]const u8{to});
1048 defer allocator.free(resolved_to);
1049
1050 var from_it = mem.tokenize(resolved_from, "/");
1051 var to_it = mem.tokenize(resolved_to, "/");
1052 while (true) {
1053 const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest());
1054 const to_rest = to_it.rest();
1055 if (to_it.next()) |to_component| {
1056 if (mem.eql(u8, from_component, to_component))
1057 continue;
1058 }
1059 var up_count: usize = 1;
1060 while (from_it.next()) |_| {
1061 up_count += 1;
1062 }
1063 const up_index_end = up_count * "../".len;
1064 const result = try allocator.alloc(u8, up_index_end + to_rest.len);
1065 errdefer allocator.free(result);
1066
1067 var result_index: usize = 0;
1068 while (result_index < up_index_end) {
1069 result[result_index] = '.';
1070 result_index += 1;
1071 result[result_index] = '.';
1072 result_index += 1;
1073 result[result_index] = '/';
1074 result_index += 1;
1075 }
1076 if (to_rest.len == 0) {
1077 // shave off the trailing slash
1078 return result[0 .. result_index - 1];
1079 }
1080
1081 mem.copy(u8, result[result_index..], to_rest);
1082 return result;
1083 }
1084
1085 return []u8{};
1086}
1087
1088test "relative" {
1089 testRelativeWindows("c:/blah\\blah", "d:/games", "D:\\games");
1090 testRelativeWindows("c:/aaaa/bbbb", "c:/aaaa", "..");
1091 testRelativeWindows("c:/aaaa/bbbb", "c:/cccc", "..\\..\\cccc");
1092 testRelativeWindows("c:/aaaa/bbbb", "c:/aaaa/bbbb", "");
1093 testRelativeWindows("c:/aaaa/bbbb", "c:/aaaa/cccc", "..\\cccc");
1094 testRelativeWindows("c:/aaaa/", "c:/aaaa/cccc", "cccc");
1095 testRelativeWindows("c:/", "c:\\aaaa\\bbbb", "aaaa\\bbbb");
1096 testRelativeWindows("c:/aaaa/bbbb", "d:\\", "D:\\");
1097 testRelativeWindows("c:/AaAa/bbbb", "c:/aaaa/bbbb", "");
1098 testRelativeWindows("c:/aaaaa/", "c:/aaaa/cccc", "..\\aaaa\\cccc");
1099 testRelativeWindows("C:\\foo\\bar\\baz\\quux", "C:\\", "..\\..\\..\\..");
1100 testRelativeWindows("C:\\foo\\test", "C:\\foo\\test\\bar\\package.json", "bar\\package.json");
1101 testRelativeWindows("C:\\foo\\bar\\baz-quux", "C:\\foo\\bar\\baz", "..\\baz");
1102 testRelativeWindows("C:\\foo\\bar\\baz", "C:\\foo\\bar\\baz-quux", "..\\baz-quux");
1103 testRelativeWindows("\\\\foo\\bar", "\\\\foo\\bar\\baz", "baz");
1104 testRelativeWindows("\\\\foo\\bar\\baz", "\\\\foo\\bar", "..");
1105 testRelativeWindows("\\\\foo\\bar\\baz-quux", "\\\\foo\\bar\\baz", "..\\baz");
1106 testRelativeWindows("\\\\foo\\bar\\baz", "\\\\foo\\bar\\baz-quux", "..\\baz-quux");
1107 testRelativeWindows("C:\\baz-quux", "C:\\baz", "..\\baz");
1108 testRelativeWindows("C:\\baz", "C:\\baz-quux", "..\\baz-quux");
1109 testRelativeWindows("\\\\foo\\baz-quux", "\\\\foo\\baz", "..\\baz");
1110 testRelativeWindows("\\\\foo\\baz", "\\\\foo\\baz-quux", "..\\baz-quux");
1111 testRelativeWindows("C:\\baz", "\\\\foo\\bar\\baz", "\\\\foo\\bar\\baz");
1112 testRelativeWindows("\\\\foo\\bar\\baz", "C:\\baz", "C:\\baz");
1113
1114 testRelativePosix("/var/lib", "/var", "..");
1115 testRelativePosix("/var/lib", "/bin", "../../bin");
1116 testRelativePosix("/var/lib", "/var/lib", "");
1117 testRelativePosix("/var/lib", "/var/apache", "../apache");
1118 testRelativePosix("/var/", "/var/lib", "lib");
1119 testRelativePosix("/", "/var/lib", "var/lib");
1120 testRelativePosix("/foo/test", "/foo/test/bar/package.json", "bar/package.json");
1121 testRelativePosix("/Users/a/web/b/test/mails", "/Users/a/web/b", "../..");
1122 testRelativePosix("/foo/bar/baz-quux", "/foo/bar/baz", "../baz");
1123 testRelativePosix("/foo/bar/baz", "/foo/bar/baz-quux", "../baz-quux");
1124 testRelativePosix("/baz-quux", "/baz", "../baz");
1125 testRelativePosix("/baz", "/baz-quux", "../baz-quux");
1126}
1127
1128fn testRelativePosix(from: []const u8, to: []const u8, expected_output: []const u8) void {
1129 const result = relativePosix(debug.global_allocator, from, to) catch unreachable;
1130 testing.expectEqualSlices(u8, expected_output, result);
1131}
1132
1133fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []const u8) void {
1134 const result = relativeWindows(debug.global_allocator, from, to) catch unreachable;
1135 testing.expectEqualSlices(u8, expected_output, result);
1136}
std/heap.zig+182-189
...@@ -5,7 +5,6 @@ const testing = std.testing;...@@ -5,7 +5,6 @@ const testing = std.testing;
5const mem = std.mem;5const mem = std.mem;
6const os = std.os;6const os = std.os;
7const builtin = @import("builtin");7const builtin = @import("builtin");
8const Os = builtin.Os;
9const c = std.c;8const c = std.c;
10const maxInt = std.math.maxInt;9const maxInt = std.math.maxInt;
1110
...@@ -51,201 +50,195 @@ pub const DirectAllocator = struct {...@@ -51,201 +50,195 @@ pub const DirectAllocator = struct {
51 if (n == 0)50 if (n == 0)
52 return (([*]u8)(undefined))[0..0];51 return (([*]u8)(undefined))[0..0];
5352
54 switch (builtin.os) {53 if (os.windows.is_the_target) {
55 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {54 const w = os.windows;
56 const p = os.posix;55
57 const alloc_size = if (alignment <= os.page_size) n else n + alignment;56 // Although officially it's at least aligned to page boundary,
58 const addr = p.mmap(null, alloc_size, p.PROT_READ | p.PROT_WRITE, p.MAP_PRIVATE | p.MAP_ANONYMOUS, -1, 0);57 // Windows is known to reserve pages on a 64K boundary. It's
59 if (addr == p.MAP_FAILED) return error.OutOfMemory;58 // even more likely that the requested alignment is <= 64K than
60 if (alloc_size == n) return @intToPtr([*]u8, addr)[0..n];59 // 4K, so we're just allocating blindly and hoping for the best.
6160 // see https://devblogs.microsoft.com/oldnewthing/?p=42223
62 const aligned_addr = mem.alignForward(addr, alignment);61 const addr = w.VirtualAlloc(
6362 null,
64 // Unmap the extra bytes that were only requested in order to guarantee63 n,
65 // that the range of memory we were provided had a proper alignment in64 w.MEM_COMMIT | w.MEM_RESERVE,
66 // it somewhere. The extra bytes could be at the beginning, or end, or both.65 w.PAGE_READWRITE,
67 const unused_start_len = aligned_addr - addr;66 ) catch return error.OutOfMemory;
68 if (unused_start_len != 0) {67
69 const err = p.munmap(addr, unused_start_len);68 // If the allocation is sufficiently aligned, use it.
70 assert(p.getErrno(err) == 0);69 if (@ptrToInt(addr) & (alignment - 1) == 0) {
71 }70 return @ptrCast([*]u8, addr)[0..n];
72 const aligned_end_addr = std.mem.alignForward(aligned_addr + n, os.page_size);71 }
73 const unused_end_len = addr + alloc_size - aligned_end_addr;
74 if (unused_end_len != 0) {
75 const err = p.munmap(aligned_end_addr, unused_end_len);
76 assert(p.getErrno(err) == 0);
77 }
7872
79 return @intToPtr([*]u8, aligned_addr)[0..n];73 // If it wasn't, actually do an explicitely aligned allocation.
80 },74 w.VirtualFree(addr, 0, w.MEM_RELEASE);
81 .windows => {75 const alloc_size = n + alignment;
82 const w = os.windows;76
8377 const final_addr = while (true) {
84 // Although officially it's at least aligned to page boundary,78 // Reserve a range of memory large enough to find a sufficiently
85 // Windows is known to reserve pages on a 64K boundary. It's79 // aligned address.
86 // even more likely that the requested alignment is <= 64K than80 const reserved_addr = w.VirtualAlloc(
87 // 4K, so we're just allocating blindly and hoping for the best.
88 // see https://devblogs.microsoft.com/oldnewthing/?p=42223
89 const addr = w.VirtualAlloc(
90 null,81 null,
82 alloc_size,
83 w.MEM_RESERVE,
84 w.PAGE_NOACCESS,
85 ) catch return error.OutOfMemory;
86 const aligned_addr = mem.alignForward(@ptrToInt(reserved_addr), alignment);
87
88 // Release the reserved pages (not actually used).
89 w.VirtualFree(reserved_addr, 0, w.MEM_RELEASE);
90
91 // At this point, it is possible that another thread has
92 // obtained some memory space that will cause the next
93 // VirtualAlloc call to fail. To handle this, we will retry
94 // until it succeeds.
95 const ptr = w.VirtualAlloc(
96 @intToPtr(*c_void, aligned_addr),
91 n,97 n,
92 w.MEM_COMMIT | w.MEM_RESERVE,98 w.MEM_COMMIT | w.MEM_RESERVE,
93 w.PAGE_READWRITE,99 w.PAGE_READWRITE,
94 ) orelse return error.OutOfMemory;100 ) catch continue;
95101
96 // If the allocation is sufficiently aligned, use it.102 return @ptrCast([*]u8, ptr)[0..n];
97 if (@ptrToInt(addr) & (alignment - 1) == 0) {103 };
98 return @ptrCast([*]u8, addr)[0..n];
99 }
100104
101 // If it wasn't, actually do an explicitely aligned allocation.105 return @ptrCast([*]u8, final_addr)[0..n];
102 if (w.VirtualFree(addr, 0, w.MEM_RELEASE) == 0) unreachable;
103 const alloc_size = n + alignment;
104
105 const final_addr = while (true) {
106 // Reserve a range of memory large enough to find a sufficiently
107 // aligned address.
108 const reserved_addr = w.VirtualAlloc(
109 null,
110 alloc_size,
111 w.MEM_RESERVE,
112 w.PAGE_NOACCESS,
113 ) orelse return error.OutOfMemory;
114 const aligned_addr = mem.alignForward(@ptrToInt(reserved_addr), alignment);
115
116 // Release the reserved pages (not actually used).
117 if (w.VirtualFree(reserved_addr, 0, w.MEM_RELEASE) == 0) unreachable;
118
119 // At this point, it is possible that another thread has
120 // obtained some memory space that will cause the next
121 // VirtualAlloc call to fail. To handle this, we will retry
122 // until it succeeds.
123 if (w.VirtualAlloc(
124 @intToPtr(*c_void, aligned_addr),
125 n,
126 w.MEM_COMMIT | w.MEM_RESERVE,
127 w.PAGE_READWRITE,
128 )) |ptr| break ptr;
129 } else unreachable; // TODO else unreachable should not be necessary
130
131 return @ptrCast([*]u8, final_addr)[0..n];
132 },
133 else => @compileError("Unsupported OS"),
134 }106 }
107
108 const alloc_size = if (alignment <= mem.page_size) n else n + alignment;
109 const slice = os.mmap(
110 null,
111 mem.alignForward(alloc_size, mem.page_size),
112 os.PROT_READ | os.PROT_WRITE,
113 os.MAP_PRIVATE | os.MAP_ANONYMOUS,
114 -1,
115 0,
116 ) catch return error.OutOfMemory;
117 if (alloc_size == n) return slice[0..n];
118
119 const aligned_addr = mem.alignForward(@ptrToInt(slice.ptr), alignment);
120
121 // Unmap the extra bytes that were only requested in order to guarantee
122 // that the range of memory we were provided had a proper alignment in
123 // it somewhere. The extra bytes could be at the beginning, or end, or both.
124 const unused_start_len = aligned_addr - @ptrToInt(slice.ptr);
125 if (unused_start_len != 0) {
126 os.munmap(slice[0..unused_start_len]);
127 }
128 const aligned_end_addr = mem.alignForward(aligned_addr + n, mem.page_size);
129 const unused_end_len = @ptrToInt(slice.ptr) + slice.len - aligned_end_addr;
130 if (unused_end_len != 0) {
131 os.munmap(@intToPtr([*]align(mem.page_size) u8, aligned_end_addr)[0..unused_end_len]);
132 }
133
134 return @intToPtr([*]u8, aligned_addr)[0..n];
135 }135 }
136136
137 fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {137 fn shrink(allocator: *Allocator, old_mem_unaligned: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {
138 switch (builtin.os) {138 const old_mem = @alignCast(mem.page_size, old_mem_unaligned);
139 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {139 if (os.windows.is_the_target) {
140 const w = os.windows;
141 if (new_size == 0) {
142 // From the docs:
143 // "If the dwFreeType parameter is MEM_RELEASE, this parameter
144 // must be 0 (zero). The function frees the entire region that
145 // is reserved in the initial allocation call to VirtualAlloc."
146 // So we can only use MEM_RELEASE when actually releasing the
147 // whole allocation.
148 w.VirtualFree(old_mem.ptr, 0, w.MEM_RELEASE);
149 } else {
140 const base_addr = @ptrToInt(old_mem.ptr);150 const base_addr = @ptrToInt(old_mem.ptr);
141 const old_addr_end = base_addr + old_mem.len;151 const old_addr_end = base_addr + old_mem.len;
142 const new_addr_end = base_addr + new_size;152 const new_addr_end = base_addr + new_size;
143 const new_addr_end_rounded = mem.alignForward(new_addr_end, os.page_size);153 const new_addr_end_rounded = mem.alignForward(new_addr_end, mem.page_size);
144 if (old_addr_end > new_addr_end_rounded) {154 if (old_addr_end > new_addr_end_rounded) {
145 _ = os.posix.munmap(new_addr_end_rounded, old_addr_end - new_addr_end_rounded);155 // For shrinking that is not releasing, we will only
146 }156 // decommit the pages not needed anymore.
147 return old_mem[0..new_size];157 w.VirtualFree(
148 },158 @intToPtr(*c_void, new_addr_end_rounded),
149 .windows => {159 old_addr_end - new_addr_end_rounded,
150 const w = os.windows;160 w.MEM_DECOMMIT,
151 if (new_size == 0) {161 );
152 // From the docs:
153 // "If the dwFreeType parameter is MEM_RELEASE, this parameter
154 // must be 0 (zero). The function frees the entire region that
155 // is reserved in the initial allocation call to VirtualAlloc."
156 // So we can only use MEM_RELEASE when actually releasing the
157 // whole allocation.
158 if (w.VirtualFree(old_mem.ptr, 0, w.MEM_RELEASE) == 0) unreachable;
159 } else {
160 const base_addr = @ptrToInt(old_mem.ptr);
161 const old_addr_end = base_addr + old_mem.len;
162 const new_addr_end = base_addr + new_size;
163 const new_addr_end_rounded = mem.alignForward(new_addr_end, os.page_size);
164 if (old_addr_end > new_addr_end_rounded) {
165 // For shrinking that is not releasing, we will only
166 // decommit the pages not needed anymore.
167 if (w.VirtualFree(
168 @intToPtr(*c_void, new_addr_end_rounded),
169 old_addr_end - new_addr_end_rounded,
170 w.MEM_DECOMMIT,
171 ) == 0) unreachable;
172 }
173 }162 }
174 return old_mem[0..new_size];163 }
175 },164 return old_mem[0..new_size];
176 else => @compileError("Unsupported OS"),165 }
166 const base_addr = @ptrToInt(old_mem.ptr);
167 const old_addr_end = base_addr + old_mem.len;
168 const new_addr_end = base_addr + new_size;
169 const new_addr_end_rounded = mem.alignForward(new_addr_end, mem.page_size);
170 if (old_addr_end > new_addr_end_rounded) {
171 const ptr = @intToPtr([*]align(mem.page_size) u8, new_addr_end_rounded);
172 os.munmap(ptr[0 .. old_addr_end - new_addr_end_rounded]);
177 }173 }
174 return old_mem[0..new_size];
178 }175 }
179176
180 fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {177 fn realloc(allocator: *Allocator, old_mem_unaligned: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {
181 switch (builtin.os) {178 const old_mem = @alignCast(mem.page_size, old_mem_unaligned);
182 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {179 if (os.windows.is_the_target) {
183 if (new_size <= old_mem.len and new_align <= old_align) {180 if (old_mem.len == 0) {
184 return shrink(allocator, old_mem, old_align, new_size, new_align);181 return alloc(allocator, new_size, new_align);
185 }182 }
186 const result = try alloc(allocator, new_size, new_align);
187 if (old_mem.len != 0) {
188 @memcpy(result.ptr, old_mem.ptr, std.math.min(old_mem.len, result.len));
189 _ = os.posix.munmap(@ptrToInt(old_mem.ptr), old_mem.len);
190 }
191 return result;
192 },
193 .windows => {
194 if (old_mem.len == 0) {
195 return alloc(allocator, new_size, new_align);
196 }
197
198 if (new_size <= old_mem.len and new_align <= old_align) {
199 return shrink(allocator, old_mem, old_align, new_size, new_align);
200 }
201
202 const w = os.windows;
203 const base_addr = @ptrToInt(old_mem.ptr);
204183
205 if (new_align > old_align and base_addr & (new_align - 1) != 0) {184 if (new_size <= old_mem.len and new_align <= old_align) {
206 // Current allocation doesn't satisfy the new alignment.185 return shrink(allocator, old_mem, old_align, new_size, new_align);
207 // For now we'll do a new one no matter what, but maybe186 }
208 // there is something smarter to do instead.
209 const result = try alloc(allocator, new_size, new_align);
210 assert(old_mem.len != 0);
211 @memcpy(result.ptr, old_mem.ptr, std.math.min(old_mem.len, result.len));
212 if (w.VirtualFree(old_mem.ptr, 0, w.MEM_RELEASE) == 0) unreachable;
213187
214 return result;188 const w = os.windows;
215 }189 const base_addr = @ptrToInt(old_mem.ptr);
216190
217 const old_addr_end = base_addr + old_mem.len;191 if (new_align > old_align and base_addr & (new_align - 1) != 0) {
218 const old_addr_end_rounded = mem.alignForward(old_addr_end, os.page_size);192 // Current allocation doesn't satisfy the new alignment.
219 const new_addr_end = base_addr + new_size;193 // For now we'll do a new one no matter what, but maybe
220 const new_addr_end_rounded = mem.alignForward(new_addr_end, os.page_size);194 // there is something smarter to do instead.
221 if (new_addr_end_rounded == old_addr_end_rounded) {195 const result = try alloc(allocator, new_size, new_align);
222 // The reallocation fits in the already allocated pages.196 assert(old_mem.len != 0);
223 return @ptrCast([*]u8, old_mem.ptr)[0..new_size];197 @memcpy(result.ptr, old_mem.ptr, std.math.min(old_mem.len, result.len));
224 }198 w.VirtualFree(old_mem.ptr, 0, w.MEM_RELEASE);
225 assert(new_addr_end_rounded > old_addr_end_rounded);
226199
227 // We need to commit new pages.200 return result;
228 const additional_size = new_addr_end - old_addr_end_rounded;201 }
229 const realloc_addr = w.VirtualAlloc(
230 @intToPtr(*c_void, old_addr_end_rounded),
231 additional_size,
232 w.MEM_COMMIT | w.MEM_RESERVE,
233 w.PAGE_READWRITE,
234 ) orelse {
235 // Committing new pages at the end of the existing allocation
236 // failed, we need to try a new one.
237 const new_alloc_mem = try alloc(allocator, new_size, new_align);
238 @memcpy(new_alloc_mem.ptr, old_mem.ptr, old_mem.len);
239 if (w.VirtualFree(old_mem.ptr, 0, w.MEM_RELEASE) == 0) unreachable;
240
241 return new_alloc_mem;
242 };
243202
244 assert(@ptrToInt(realloc_addr) == old_addr_end_rounded);203 const old_addr_end = base_addr + old_mem.len;
204 const old_addr_end_rounded = mem.alignForward(old_addr_end, mem.page_size);
205 const new_addr_end = base_addr + new_size;
206 const new_addr_end_rounded = mem.alignForward(new_addr_end, mem.page_size);
207 if (new_addr_end_rounded == old_addr_end_rounded) {
208 // The reallocation fits in the already allocated pages.
245 return @ptrCast([*]u8, old_mem.ptr)[0..new_size];209 return @ptrCast([*]u8, old_mem.ptr)[0..new_size];
246 },210 }
247 else => @compileError("Unsupported OS"),211 assert(new_addr_end_rounded > old_addr_end_rounded);
212
213 // We need to commit new pages.
214 const additional_size = new_addr_end - old_addr_end_rounded;
215 const realloc_addr = w.kernel32.VirtualAlloc(
216 @intToPtr(*c_void, old_addr_end_rounded),
217 additional_size,
218 w.MEM_COMMIT | w.MEM_RESERVE,
219 w.PAGE_READWRITE,
220 ) orelse {
221 // Committing new pages at the end of the existing allocation
222 // failed, we need to try a new one.
223 const new_alloc_mem = try alloc(allocator, new_size, new_align);
224 @memcpy(new_alloc_mem.ptr, old_mem.ptr, old_mem.len);
225 w.VirtualFree(old_mem.ptr, 0, w.MEM_RELEASE);
226
227 return new_alloc_mem;
228 };
229
230 assert(@ptrToInt(realloc_addr) == old_addr_end_rounded);
231 return @ptrCast([*]u8, old_mem.ptr)[0..new_size];
232 }
233 if (new_size <= old_mem.len and new_align <= old_align) {
234 return shrink(allocator, old_mem, old_align, new_size, new_align);
248 }235 }
236 const result = try alloc(allocator, new_size, new_align);
237 if (old_mem.len != 0) {
238 @memcpy(result.ptr, old_mem.ptr, std.math.min(old_mem.len, result.len));
239 os.munmap(old_mem);
240 }
241 return result;
249 }242 }
250};243};
251244
...@@ -268,7 +261,7 @@ pub const HeapAllocator = switch (builtin.os) {...@@ -268,7 +261,7 @@ pub const HeapAllocator = switch (builtin.os) {
268261
269 pub fn deinit(self: *HeapAllocator) void {262 pub fn deinit(self: *HeapAllocator) void {
270 if (self.heap_handle) |heap_handle| {263 if (self.heap_handle) |heap_handle| {
271 _ = os.windows.HeapDestroy(heap_handle);264 os.windows.HeapDestroy(heap_handle);
272 }265 }
273 }266 }
274267
...@@ -281,12 +274,12 @@ pub const HeapAllocator = switch (builtin.os) {...@@ -281,12 +274,12 @@ pub const HeapAllocator = switch (builtin.os) {
281 const optional_heap_handle = @atomicLoad(?HeapHandle, &self.heap_handle, builtin.AtomicOrder.SeqCst);274 const optional_heap_handle = @atomicLoad(?HeapHandle, &self.heap_handle, builtin.AtomicOrder.SeqCst);
282 const heap_handle = optional_heap_handle orelse blk: {275 const heap_handle = optional_heap_handle orelse blk: {
283 const options = if (builtin.single_threaded) os.windows.HEAP_NO_SERIALIZE else 0;276 const options = if (builtin.single_threaded) os.windows.HEAP_NO_SERIALIZE else 0;
284 const hh = os.windows.HeapCreate(options, amt, 0) orelse return error.OutOfMemory;277 const hh = os.windows.kernel32.HeapCreate(options, amt, 0) orelse return error.OutOfMemory;
285 const other_hh = @cmpxchgStrong(?HeapHandle, &self.heap_handle, null, hh, builtin.AtomicOrder.SeqCst, builtin.AtomicOrder.SeqCst) orelse break :blk hh;278 const other_hh = @cmpxchgStrong(?HeapHandle, &self.heap_handle, null, hh, builtin.AtomicOrder.SeqCst, builtin.AtomicOrder.SeqCst) orelse break :blk hh;
286 _ = os.windows.HeapDestroy(hh);279 os.windows.HeapDestroy(hh);
287 break :blk other_hh.?; // can't be null because of the cmpxchg280 break :blk other_hh.?; // can't be null because of the cmpxchg
288 };281 };
289 const ptr = os.windows.HeapAlloc(heap_handle, 0, amt) orelse return error.OutOfMemory;282 const ptr = os.windows.kernel32.HeapAlloc(heap_handle, 0, amt) orelse return error.OutOfMemory;
290 const root_addr = @ptrToInt(ptr);283 const root_addr = @ptrToInt(ptr);
291 const adjusted_addr = mem.alignForward(root_addr, alignment);284 const adjusted_addr = mem.alignForward(root_addr, alignment);
292 const record_addr = adjusted_addr + n;285 const record_addr = adjusted_addr + n;
...@@ -316,12 +309,12 @@ pub const HeapAllocator = switch (builtin.os) {...@@ -316,12 +309,12 @@ pub const HeapAllocator = switch (builtin.os) {
316 const old_ptr = @intToPtr(*c_void, root_addr);309 const old_ptr = @intToPtr(*c_void, root_addr);
317310
318 if (new_size == 0) {311 if (new_size == 0) {
319 if (os.windows.HeapFree(self.heap_handle.?, 0, old_ptr) == 0) unreachable;312 os.windows.HeapFree(self.heap_handle.?, 0, old_ptr);
320 return old_mem[0..0];313 return old_mem[0..0];
321 }314 }
322315
323 const amt = new_size + new_align + @sizeOf(usize);316 const amt = new_size + new_align + @sizeOf(usize);
324 const new_ptr = os.windows.HeapReAlloc(317 const new_ptr = os.windows.kernel32.HeapReAlloc(
325 self.heap_handle.?,318 self.heap_handle.?,
326 0,319 0,
327 old_ptr,320 old_ptr,
...@@ -386,7 +379,7 @@ pub const ArenaAllocator = struct {...@@ -386,7 +379,7 @@ pub const ArenaAllocator = struct {
386 var len = prev_len;379 var len = prev_len;
387 while (true) {380 while (true) {
388 len += len / 2;381 len += len / 2;
389 len += os.page_size - @rem(len, os.page_size);382 len += mem.page_size - @rem(len, mem.page_size);
390 if (len >= actual_min_size) break;383 if (len >= actual_min_size) break;
391 }384 }
392 const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);385 const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);
...@@ -532,11 +525,11 @@ const WasmAllocator = struct {...@@ -532,11 +525,11 @@ const WasmAllocator = struct {
532 const adjusted_index = self.end_index + (adjusted_addr - addr);525 const adjusted_index = self.end_index + (adjusted_addr - addr);
533 const new_end_index = adjusted_index + size;526 const new_end_index = adjusted_index + size;
534527
535 if (new_end_index > self.num_pages * os.page_size) {528 if (new_end_index > self.num_pages * mem.page_size) {
536 const required_memory = new_end_index - (self.num_pages * os.page_size);529 const required_memory = new_end_index - (self.num_pages * mem.page_size);
537530
538 var num_pages: usize = required_memory / os.page_size;531 var num_pages: usize = required_memory / mem.page_size;
539 if (required_memory % os.page_size != 0) {532 if (required_memory % mem.page_size != 0) {
540 num_pages += 1;533 num_pages += 1;
541 }534 }
542535
...@@ -565,14 +558,14 @@ const WasmAllocator = struct {...@@ -565,14 +558,14 @@ const WasmAllocator = struct {
565558
566 // Initialize start_ptr at the first realloc559 // Initialize start_ptr at the first realloc
567 if (self.num_pages == 0) {560 if (self.num_pages == 0) {
568 self.start_ptr = @intToPtr([*]u8, @intCast(usize, @"llvm.wasm.memory.size.i32"(0)) * os.page_size);561 self.start_ptr = @intToPtr([*]u8, @intCast(usize, @"llvm.wasm.memory.size.i32"(0)) * mem.page_size);
569 }562 }
570563
571 if (is_last_item(allocator, old_mem, new_align)) {564 if (is_last_item(allocator, old_mem, new_align)) {
572 const start_index = self.end_index - old_mem.len;565 const start_index = self.end_index - old_mem.len;
573 const new_end_index = start_index + new_size;566 const new_end_index = start_index + new_size;
574567
575 if (new_end_index > self.num_pages * os.page_size) {568 if (new_end_index > self.num_pages * mem.page_size) {
576 _ = try alloc(allocator, new_end_index - self.end_index, new_align);569 _ = try alloc(allocator, new_end_index - self.end_index, new_align);
577 }570 }
578 const result = self.start_ptr[start_index..new_end_index];571 const result = self.start_ptr[start_index..new_end_index];
...@@ -888,10 +881,10 @@ fn testAllocatorAligned(allocator: *mem.Allocator, comptime alignment: u29) !voi...@@ -888,10 +881,10 @@ fn testAllocatorAligned(allocator: *mem.Allocator, comptime alignment: u29) !voi
888fn testAllocatorLargeAlignment(allocator: *mem.Allocator) mem.Allocator.Error!void {881fn testAllocatorLargeAlignment(allocator: *mem.Allocator) mem.Allocator.Error!void {
889 //Maybe a platform's page_size is actually the same as or882 //Maybe a platform's page_size is actually the same as or
890 // very near usize?883 // very near usize?
891 if (os.page_size << 2 > maxInt(usize)) return;884 if (mem.page_size << 2 > maxInt(usize)) return;
892885
893 const USizeShift = @IntType(false, std.math.log2(usize.bit_count));886 const USizeShift = @IntType(false, std.math.log2(usize.bit_count));
894 const large_align = u29(os.page_size << 2);887 const large_align = u29(mem.page_size << 2);
895888
896 var align_mask: usize = undefined;889 var align_mask: usize = undefined;
897 _ = @shlWithOverflow(usize, ~usize(0), USizeShift(@ctz(u29, large_align)), &align_mask);890 _ = @shlWithOverflow(usize, ~usize(0), USizeShift(@ctz(u29, large_align)), &align_mask);
...@@ -918,7 +911,7 @@ fn testAllocatorAlignedShrink(allocator: *mem.Allocator) mem.Allocator.Error!voi...@@ -918,7 +911,7 @@ fn testAllocatorAlignedShrink(allocator: *mem.Allocator) mem.Allocator.Error!voi
918 var debug_buffer: [1000]u8 = undefined;911 var debug_buffer: [1000]u8 = undefined;
919 const debug_allocator = &FixedBufferAllocator.init(&debug_buffer).allocator;912 const debug_allocator = &FixedBufferAllocator.init(&debug_buffer).allocator;
920913
921 const alloc_size = os.page_size * 2 + 50;914 const alloc_size = mem.page_size * 2 + 50;
922 var slice = try allocator.alignedAlloc(u8, 16, alloc_size);915 var slice = try allocator.alignedAlloc(u8, 16, alloc_size);
923 defer allocator.free(slice);916 defer allocator.free(slice);
924917
...@@ -927,7 +920,7 @@ fn testAllocatorAlignedShrink(allocator: *mem.Allocator) mem.Allocator.Error!voi...@@ -927,7 +920,7 @@ fn testAllocatorAlignedShrink(allocator: *mem.Allocator) mem.Allocator.Error!voi
927 // which is 16 pages, hence the 32. This test may require to increase920 // which is 16 pages, hence the 32. This test may require to increase
928 // the size of the allocations feeding the `allocator` parameter if they921 // the size of the allocations feeding the `allocator` parameter if they
929 // fail, because of this high over-alignment we want to have.922 // fail, because of this high over-alignment we want to have.
930 while (@ptrToInt(slice.ptr) == mem.alignForward(@ptrToInt(slice.ptr), os.page_size * 32)) {923 while (@ptrToInt(slice.ptr) == mem.alignForward(@ptrToInt(slice.ptr), mem.page_size * 32)) {
931 try stuff_to_free.append(slice);924 try stuff_to_free.append(slice);
932 slice = try allocator.alignedAlloc(u8, 16, alloc_size);925 slice = try allocator.alignedAlloc(u8, 16, alloc_size);
933 }926 }
...@@ -938,7 +931,7 @@ fn testAllocatorAlignedShrink(allocator: *mem.Allocator) mem.Allocator.Error!voi...@@ -938,7 +931,7 @@ fn testAllocatorAlignedShrink(allocator: *mem.Allocator) mem.Allocator.Error!voi
938 slice[60] = 0x34;931 slice[60] = 0x34;
939932
940 // realloc to a smaller size but with a larger alignment933 // realloc to a smaller size but with a larger alignment
941 slice = try allocator.alignedRealloc(slice, os.page_size * 32, alloc_size / 2);934 slice = try allocator.alignedRealloc(slice, mem.page_size * 32, alloc_size / 2);
942 testing.expect(slice[0] == 0x12);935 testing.expect(slice[0] == 0x12);
943 testing.expect(slice[60] == 0x34);936 testing.expect(slice[60] == 0x34);
944}937}
std/io.zig+30-24
...@@ -1,38 +1,44 @@...@@ -1,38 +1,44 @@
1const std = @import("std.zig");1const std = @import("std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const Os = builtin.Os;
4const c = std.c;3const c = std.c;
54
6const math = std.math;5const math = std.math;
7const debug = std.debug;6const debug = std.debug;
8const assert = debug.assert;7const assert = debug.assert;
9const os = std.os;8const os = std.os;
9const fs = std.fs;
10const mem = std.mem;10const mem = std.mem;
11const meta = std.meta;11const meta = std.meta;
12const trait = meta.trait;12const trait = meta.trait;
13const Buffer = std.Buffer;13const Buffer = std.Buffer;
14const fmt = std.fmt;14const fmt = std.fmt;
15const File = std.os.File;15const File = std.fs.File;
16const testing = std.testing;16const testing = std.testing;
1717
18const is_posix = builtin.os != builtin.Os.windows;18pub const GetStdIoError = os.windows.GetStdHandleError;
19const is_windows = builtin.os == builtin.Os.windows;
2019
21const GetStdIoErrs = os.WindowsGetStdHandleErrs;20pub fn getStdOut() GetStdIoError!File {
2221 if (os.windows.is_the_target) {
23pub fn getStdErr() GetStdIoErrs!File {22 const handle = try os.windows.GetStdHandle(os.windows.STD_OUTPUT_HANDLE);
24 const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_ERROR_HANDLE) else if (is_posix) os.posix.STDERR_FILENO else unreachable;23 return File.openHandle(handle);
25 return File.openHandle(handle);24 }
25 return File.openHandle(os.STDOUT_FILENO);
26}26}
2727
28pub fn getStdOut() GetStdIoErrs!File {28pub fn getStdErr() GetStdIoError!File {
29 const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_OUTPUT_HANDLE) else if (is_posix) os.posix.STDOUT_FILENO else unreachable;29 if (os.windows.is_the_target) {
30 return File.openHandle(handle);30 const handle = try os.windows.GetStdHandle(os.windows.STD_ERROR_HANDLE);
31 return File.openHandle(handle);
32 }
33 return File.openHandle(os.STDERR_FILENO);
31}34}
3235
33pub fn getStdIn() GetStdIoErrs!File {36pub fn getStdIn() GetStdIoError!File {
34 const handle = if (is_windows) try os.windowsGetStdHandle(os.windows.STD_INPUT_HANDLE) else if (is_posix) os.posix.STDIN_FILENO else unreachable;37 if (os.windows.is_the_target) {
35 return File.openHandle(handle);38 const handle = try os.windows.GetStdHandle(os.windows.STD_INPUT_HANDLE);
39 return File.openHandle(handle);
40 }
41 return File.openHandle(os.STDIN_FILENO);
36}42}
3743
38pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;44pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
...@@ -66,7 +72,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -66,7 +72,7 @@ pub fn InStream(comptime ReadError: type) type {
66 return;72 return;
67 }73 }
6874
69 const new_buf_size = math.min(max_size, actual_buf_len + os.page_size);75 const new_buf_size = math.min(max_size, actual_buf_len + mem.page_size);
70 if (new_buf_size == actual_buf_len) return error.StreamTooLong;76 if (new_buf_size == actual_buf_len) return error.StreamTooLong;
71 try buffer.resize(new_buf_size);77 try buffer.resize(new_buf_size);
72 }78 }
...@@ -301,7 +307,7 @@ pub fn readFileAllocAligned(allocator: *mem.Allocator, path: []const u8, comptim...@@ -301,7 +307,7 @@ pub fn readFileAllocAligned(allocator: *mem.Allocator, path: []const u8, comptim
301}307}
302308
303pub fn BufferedInStream(comptime Error: type) type {309pub fn BufferedInStream(comptime Error: type) type {
304 return BufferedInStreamCustom(os.page_size, Error);310 return BufferedInStreamCustom(mem.page_size, Error);
305}311}
306312
307pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) type {313pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) type {
...@@ -774,7 +780,7 @@ test "io.CountingOutStream" {...@@ -774,7 +780,7 @@ test "io.CountingOutStream" {
774}780}
775781
776pub fn BufferedOutStream(comptime Error: type) type {782pub fn BufferedOutStream(comptime Error: type) type {
777 return BufferedOutStreamCustom(os.page_size, Error);783 return BufferedOutStreamCustom(mem.page_size, Error);
778}784}
779785
780pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamError: type) type {786pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamError: type) type {
...@@ -979,9 +985,9 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {...@@ -979,9 +985,9 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type {
979}985}
980986
981pub const BufferedAtomicFile = struct {987pub const BufferedAtomicFile = struct {
982 atomic_file: os.AtomicFile,988 atomic_file: fs.AtomicFile,
983 file_stream: os.File.OutStream,989 file_stream: File.OutStream,
984 buffered_stream: BufferedOutStream(os.File.WriteError),990 buffered_stream: BufferedOutStream(File.WriteError),
985 allocator: *mem.Allocator,991 allocator: *mem.Allocator,
986992
987 pub fn create(allocator: *mem.Allocator, dest_path: []const u8) !*BufferedAtomicFile {993 pub fn create(allocator: *mem.Allocator, dest_path: []const u8) !*BufferedAtomicFile {
...@@ -995,11 +1001,11 @@ pub const BufferedAtomicFile = struct {...@@ -995,11 +1001,11 @@ pub const BufferedAtomicFile = struct {
995 };1001 };
996 errdefer allocator.destroy(self);1002 errdefer allocator.destroy(self);
9971003
998 self.atomic_file = try os.AtomicFile.init(dest_path, os.File.default_mode);1004 self.atomic_file = try fs.AtomicFile.init(dest_path, File.default_mode);
999 errdefer self.atomic_file.deinit();1005 errdefer self.atomic_file.deinit();
10001006
1001 self.file_stream = self.atomic_file.file.outStream();1007 self.file_stream = self.atomic_file.file.outStream();
1002 self.buffered_stream = BufferedOutStream(os.File.WriteError).init(&self.file_stream.stream);1008 self.buffered_stream = BufferedOutStream(File.WriteError).init(&self.file_stream.stream);
1003 return self;1009 return self;
1004 }1010 }
10051011
...@@ -1014,7 +1020,7 @@ pub const BufferedAtomicFile = struct {...@@ -1014,7 +1020,7 @@ pub const BufferedAtomicFile = struct {
1014 try self.atomic_file.finish();1020 try self.atomic_file.finish();
1015 }1021 }
10161022
1017 pub fn stream(self: *BufferedAtomicFile) *OutStream(os.File.WriteError) {1023 pub fn stream(self: *BufferedAtomicFile) *OutStream(File.WriteError) {
1018 return &self.buffered_stream.stream;1024 return &self.buffered_stream.stream;
1019 }1025 }
1020};1026};
std/io/c_out_stream.zig+17-22
...@@ -1,13 +1,13 @@...@@ -1,13 +1,13 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const os = std.os;
2const OutStream = std.io.OutStream;3const OutStream = std.io.OutStream;
3const builtin = @import("builtin");4const builtin = @import("builtin");
4const posix = std.os.posix;
55
6/// TODO make std.os.FILE use *FILE when linking libc and this just becomes6/// TODO make a proposal to make `std.fs.File` use *FILE when linking libc and this just becomes
7/// std.io.FileOutStream because std.os.File.write would do this when linking7/// std.io.FileOutStream because std.fs.File.write would do this when linking
8/// libc.8/// libc.
9pub const COutStream = struct {9pub const COutStream = struct {
10 pub const Error = std.os.File.WriteError;10 pub const Error = std.fs.File.WriteError;
11 pub const Stream = OutStream(Error);11 pub const Stream = OutStream(Error);
1212
13 stream: Stream,13 stream: Stream,
...@@ -24,25 +24,20 @@ pub const COutStream = struct {...@@ -24,25 +24,20 @@ pub const COutStream = struct {
24 const self = @fieldParentPtr(COutStream, "stream", out_stream);24 const self = @fieldParentPtr(COutStream, "stream", out_stream);
25 const amt_written = std.c.fwrite(bytes.ptr, 1, bytes.len, self.c_file);25 const amt_written = std.c.fwrite(bytes.ptr, 1, bytes.len, self.c_file);
26 if (amt_written == bytes.len) return;26 if (amt_written == bytes.len) return;
27 // TODO errno on windows. should we have a posix layer for windows?27 switch (std.c._errno().*) {
28 if (builtin.os == .windows) {
29 return error.InputOutput;
30 }
31 const errno = std.c._errno().*;
32 switch (errno) {
33 0 => unreachable,28 0 => unreachable,
34 posix.EINVAL => unreachable,29 os.EINVAL => unreachable,
35 posix.EFAULT => unreachable,30 os.EFAULT => unreachable,
36 posix.EAGAIN => unreachable, // this is a blocking API31 os.EAGAIN => unreachable, // this is a blocking API
37 posix.EBADF => unreachable, // always a race condition32 os.EBADF => unreachable, // always a race condition
38 posix.EDESTADDRREQ => unreachable, // connect was never called33 os.EDESTADDRREQ => unreachable, // connect was never called
39 posix.EDQUOT => return error.DiskQuota,34 os.EDQUOT => return error.DiskQuota,
40 posix.EFBIG => return error.FileTooBig,35 os.EFBIG => return error.FileTooBig,
41 posix.EIO => return error.InputOutput,36 os.EIO => return error.InputOutput,
42 posix.ENOSPC => return error.NoSpaceLeft,37 os.ENOSPC => return error.NoSpaceLeft,
43 posix.EPERM => return error.AccessDenied,38 os.EPERM => return error.AccessDenied,
44 posix.EPIPE => return error.BrokenPipe,39 os.EPIPE => return error.BrokenPipe,
45 else => return std.os.unexpectedErrorPosix(@intCast(usize, errno)),40 else => |err| return os.unexpectedErrno(@intCast(usize, err)),
46 }41 }
47 }42 }
48};43};
std/io/seekable_stream.zig+5-5
...@@ -8,7 +8,7 @@ pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType...@@ -8,7 +8,7 @@ pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType
8 pub const GetSeekPosError = GetSeekPosErrorType;8 pub const GetSeekPosError = GetSeekPosErrorType;
99
10 seekToFn: fn (self: *Self, pos: u64) SeekError!void,10 seekToFn: fn (self: *Self, pos: u64) SeekError!void,
11 seekForwardFn: fn (self: *Self, pos: i64) SeekError!void,11 seekByFn: fn (self: *Self, pos: i64) SeekError!void,
1212
13 getPosFn: fn (self: *Self) GetSeekPosError!u64,13 getPosFn: fn (self: *Self) GetSeekPosError!u64,
14 getEndPosFn: fn (self: *Self) GetSeekPosError!u64,14 getEndPosFn: fn (self: *Self) GetSeekPosError!u64,
...@@ -17,8 +17,8 @@ pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType...@@ -17,8 +17,8 @@ pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType
17 return self.seekToFn(self, pos);17 return self.seekToFn(self, pos);
18 }18 }
1919
20 pub fn seekForward(self: *Self, amt: i64) SeekError!void {20 pub fn seekBy(self: *Self, amt: i64) SeekError!void {
21 return self.seekForwardFn(self, amt);21 return self.seekByFn(self, amt);
22 }22 }
2323
24 pub fn getEndPos(self: *Self) GetSeekPosError!u64 {24 pub fn getEndPos(self: *Self) GetSeekPosError!u64 {
...@@ -52,7 +52,7 @@ pub const SliceSeekableInStream = struct {...@@ -52,7 +52,7 @@ pub const SliceSeekableInStream = struct {
52 .stream = Stream{ .readFn = readFn },52 .stream = Stream{ .readFn = readFn },
53 .seekable_stream = SeekableInStream{53 .seekable_stream = SeekableInStream{
54 .seekToFn = seekToFn,54 .seekToFn = seekToFn,
55 .seekForwardFn = seekForwardFn,55 .seekByFn = seekByFn,
56 .getEndPosFn = getEndPosFn,56 .getEndPosFn = getEndPosFn,
57 .getPosFn = getPosFn,57 .getPosFn = getPosFn,
58 },58 },
...@@ -77,7 +77,7 @@ pub const SliceSeekableInStream = struct {...@@ -77,7 +77,7 @@ pub const SliceSeekableInStream = struct {
77 self.pos = usize_pos;77 self.pos = usize_pos;
78 }78 }
7979
80 fn seekForwardFn(in_stream: *SeekableInStream, amt: i64) SeekError!void {80 fn seekByFn(in_stream: *SeekableInStream, amt: i64) SeekError!void {
81 const self = @fieldParentPtr(Self, "seekable_stream", in_stream);81 const self = @fieldParentPtr(Self, "seekable_stream", in_stream);
8282
83 if (amt < 0) {83 if (amt < 0) {
std/io/test.zig+16-15
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
1const std = @import("../std.zig");2const std = @import("../std.zig");
2const io = std.io;3const io = std.io;
3const meta = std.meta;4const meta = std.meta;
...@@ -6,8 +7,8 @@ const DefaultPrng = std.rand.DefaultPrng;...@@ -6,8 +7,8 @@ const DefaultPrng = std.rand.DefaultPrng;
6const expect = std.testing.expect;7const expect = std.testing.expect;
7const expectError = std.testing.expectError;8const expectError = std.testing.expectError;
8const mem = std.mem;9const mem = std.mem;
9const os = std.os;10const fs = std.fs;
10const builtin = @import("builtin");11const File = std.fs.File;
1112
12test "write a file, read it, then delete it" {13test "write a file, read it, then delete it" {
13 var raw_bytes: [200 * 1024]u8 = undefined;14 var raw_bytes: [200 * 1024]u8 = undefined;
...@@ -18,11 +19,11 @@ test "write a file, read it, then delete it" {...@@ -18,11 +19,11 @@ test "write a file, read it, then delete it" {
18 prng.random.bytes(data[0..]);19 prng.random.bytes(data[0..]);
19 const tmp_file_name = "temp_test_file.txt";20 const tmp_file_name = "temp_test_file.txt";
20 {21 {
21 var file = try os.File.openWrite(tmp_file_name);22 var file = try File.openWrite(tmp_file_name);
22 defer file.close();23 defer file.close();
2324
24 var file_out_stream = file.outStream();25 var file_out_stream = file.outStream();
25 var buf_stream = io.BufferedOutStream(os.File.WriteError).init(&file_out_stream.stream);26 var buf_stream = io.BufferedOutStream(File.WriteError).init(&file_out_stream.stream);
26 const st = &buf_stream.stream;27 const st = &buf_stream.stream;
27 try st.print("begin");28 try st.print("begin");
28 try st.write(data[0..]);29 try st.write(data[0..]);
...@@ -32,15 +33,15 @@ test "write a file, read it, then delete it" {...@@ -32,15 +33,15 @@ test "write a file, read it, then delete it" {
3233
33 {34 {
34 // make sure openWriteNoClobber doesn't harm the file35 // make sure openWriteNoClobber doesn't harm the file
35 if (os.File.openWriteNoClobber(tmp_file_name, os.File.default_mode)) |file| {36 if (File.openWriteNoClobber(tmp_file_name, File.default_mode)) |file| {
36 unreachable;37 unreachable;
37 } else |err| {38 } else |err| {
38 std.debug.assert(err == os.File.OpenError.PathAlreadyExists);39 std.debug.assert(err == File.OpenError.PathAlreadyExists);
39 }40 }
40 }41 }
4142
42 {43 {
43 var file = try os.File.openRead(tmp_file_name);44 var file = try File.openRead(tmp_file_name);
44 defer file.close();45 defer file.close();
4546
46 const file_size = try file.getEndPos();47 const file_size = try file.getEndPos();
...@@ -48,7 +49,7 @@ test "write a file, read it, then delete it" {...@@ -48,7 +49,7 @@ test "write a file, read it, then delete it" {
48 expect(file_size == expected_file_size);49 expect(file_size == expected_file_size);
4950
50 var file_in_stream = file.inStream();51 var file_in_stream = file.inStream();
51 var buf_stream = io.BufferedInStream(os.File.ReadError).init(&file_in_stream.stream);52 var buf_stream = io.BufferedInStream(File.ReadError).init(&file_in_stream.stream);
52 const st = &buf_stream.stream;53 const st = &buf_stream.stream;
53 const contents = try st.readAllAlloc(allocator, 2 * 1024);54 const contents = try st.readAllAlloc(allocator, 2 * 1024);
54 defer allocator.free(contents);55 defer allocator.free(contents);
...@@ -57,7 +58,7 @@ test "write a file, read it, then delete it" {...@@ -57,7 +58,7 @@ test "write a file, read it, then delete it" {
57 expect(mem.eql(u8, contents["begin".len .. contents.len - "end".len], data));58 expect(mem.eql(u8, contents["begin".len .. contents.len - "end".len], data));
58 expect(mem.eql(u8, contents[contents.len - "end".len ..], "end"));59 expect(mem.eql(u8, contents[contents.len - "end".len ..], "end"));
59 }60 }
60 try os.deleteFile(tmp_file_name);61 try fs.deleteFile(tmp_file_name);
61}62}
6263
63test "BufferOutStream" {64test "BufferOutStream" {
...@@ -273,12 +274,12 @@ test "BitOutStream" {...@@ -273,12 +274,12 @@ test "BitOutStream" {
273test "BitStreams with File Stream" {274test "BitStreams with File Stream" {
274 const tmp_file_name = "temp_test_file.txt";275 const tmp_file_name = "temp_test_file.txt";
275 {276 {
276 var file = try os.File.openWrite(tmp_file_name);277 var file = try File.openWrite(tmp_file_name);
277 defer file.close();278 defer file.close();
278279
279 var file_out = file.outStream();280 var file_out = file.outStream();
280 var file_out_stream = &file_out.stream;281 var file_out_stream = &file_out.stream;
281 const OutError = os.File.WriteError;282 const OutError = File.WriteError;
282 var bit_stream = io.BitOutStream(builtin.endian, OutError).init(file_out_stream);283 var bit_stream = io.BitOutStream(builtin.endian, OutError).init(file_out_stream);
283284
284 try bit_stream.writeBits(u2(1), 1);285 try bit_stream.writeBits(u2(1), 1);
...@@ -290,12 +291,12 @@ test "BitStreams with File Stream" {...@@ -290,12 +291,12 @@ test "BitStreams with File Stream" {
290 try bit_stream.flushBits();291 try bit_stream.flushBits();
291 }292 }
292 {293 {
293 var file = try os.File.openRead(tmp_file_name);294 var file = try File.openRead(tmp_file_name);
294 defer file.close();295 defer file.close();
295296
296 var file_in = file.inStream();297 var file_in = file.inStream();
297 var file_in_stream = &file_in.stream;298 var file_in_stream = &file_in.stream;
298 const InError = os.File.ReadError;299 const InError = File.ReadError;
299 var bit_stream = io.BitInStream(builtin.endian, InError).init(file_in_stream);300 var bit_stream = io.BitInStream(builtin.endian, InError).init(file_in_stream);
300301
301 var out_bits: usize = undefined;302 var out_bits: usize = undefined;
...@@ -315,7 +316,7 @@ test "BitStreams with File Stream" {...@@ -315,7 +316,7 @@ test "BitStreams with File Stream" {
315316
316 expectError(error.EndOfStream, bit_stream.readBitsNoEof(u1, 1));317 expectError(error.EndOfStream, bit_stream.readBitsNoEof(u1, 1));
317 }318 }
318 try os.deleteFile(tmp_file_name);319 try fs.deleteFile(tmp_file_name);
319}320}
320321
321fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void {322fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void {
...@@ -595,7 +596,7 @@ test "c out stream" {...@@ -595,7 +596,7 @@ test "c out stream" {
595596
596 const filename = c"tmp_io_test_file.txt";597 const filename = c"tmp_io_test_file.txt";
597 const out_file = std.c.fopen(filename, c"w") orelse return error.UnableToOpenTestFile;598 const out_file = std.c.fopen(filename, c"w") orelse return error.UnableToOpenTestFile;
598 defer std.os.deleteFileC(filename) catch {};599 defer fs.deleteFileC(filename) catch {};
599600
600 const out_stream = &io.COutStream.init(out_file).stream;601 const out_stream = &io.COutStream.init(out_file).stream;
601 try out_stream.print("hi: {}\n", i32(123));602 try out_stream.print("hi: {}\n", i32(123));
std/mem.zig+55-23
...@@ -8,6 +8,11 @@ const meta = std.meta;...@@ -8,6 +8,11 @@ const meta = std.meta;
8const trait = meta.trait;8const trait = meta.trait;
9const testing = std.testing;9const testing = std.testing;
1010
11pub const page_size = switch (builtin.arch) {
12 .wasm32, .wasm64 => 64 * 1024,
13 else => 4 * 1024,
14};
15
11pub const Allocator = struct {16pub const Allocator = struct {
12 pub const Error = error{OutOfMemory};17 pub const Error = error{OutOfMemory};
1318
...@@ -580,14 +585,14 @@ pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian)...@@ -580,14 +585,14 @@ pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian)
580test "comptime read/write int" {585test "comptime read/write int" {
581 comptime {586 comptime {
582 var bytes: [2]u8 = undefined;587 var bytes: [2]u8 = undefined;
583 std.mem.writeIntLittle(u16, &bytes, 0x1234);588 writeIntLittle(u16, &bytes, 0x1234);
584 const result = std.mem.readIntBig(u16, &bytes);589 const result = readIntBig(u16, &bytes);
585 testing.expect(result == 0x3412);590 testing.expect(result == 0x3412);
586 }591 }
587 comptime {592 comptime {
588 var bytes: [2]u8 = undefined;593 var bytes: [2]u8 = undefined;
589 std.mem.writeIntBig(u16, &bytes, 0x1234);594 writeIntBig(u16, &bytes, 0x1234);
590 const result = std.mem.readIntLittle(u16, &bytes);595 const result = readIntLittle(u16, &bytes);
591 testing.expect(result == 0x3412);596 testing.expect(result == 0x3412);
592 }597 }
593}598}
...@@ -1048,7 +1053,7 @@ fn testReadIntImpl() void {...@@ -1048,7 +1053,7 @@ fn testReadIntImpl() void {
1048 }1053 }
1049}1054}
10501055
1051test "std.mem.writeIntSlice" {1056test "writeIntSlice" {
1052 testWriteIntImpl();1057 testWriteIntImpl();
1053 comptime testWriteIntImpl();1058 comptime testWriteIntImpl();
1054}1059}
...@@ -1179,7 +1184,7 @@ pub fn reverse(comptime T: type, items: []T) void {...@@ -1179,7 +1184,7 @@ pub fn reverse(comptime T: type, items: []T) void {
1179 }1184 }
1180}1185}
11811186
1182test "std.mem.reverse" {1187test "reverse" {
1183 var arr = []i32{1188 var arr = []i32{
1184 5,1189 5,
1185 3,1190 3,
...@@ -1206,7 +1211,7 @@ pub fn rotate(comptime T: type, items: []T, amount: usize) void {...@@ -1206,7 +1211,7 @@ pub fn rotate(comptime T: type, items: []T, amount: usize) void {
1206 reverse(T, items);1211 reverse(T, items);
1207}1212}
12081213
1209test "std.mem.rotate" {1214test "rotate" {
1210 var arr = []i32{1215 var arr = []i32{
1211 5,1216 5,
1212 3,1217 3,
...@@ -1291,14 +1296,14 @@ pub fn asBytes(ptr: var) AsBytesReturnType(@typeOf(ptr)) {...@@ -1291,14 +1296,14 @@ pub fn asBytes(ptr: var) AsBytesReturnType(@typeOf(ptr)) {
1291 return @ptrCast(AsBytesReturnType(P), ptr);1296 return @ptrCast(AsBytesReturnType(P), ptr);
1292}1297}
12931298
1294test "std.mem.asBytes" {1299test "asBytes" {
1295 const deadbeef = u32(0xDEADBEEF);1300 const deadbeef = u32(0xDEADBEEF);
1296 const deadbeef_bytes = switch (builtin.endian) {1301 const deadbeef_bytes = switch (builtin.endian) {
1297 builtin.Endian.Big => "\xDE\xAD\xBE\xEF",1302 builtin.Endian.Big => "\xDE\xAD\xBE\xEF",
1298 builtin.Endian.Little => "\xEF\xBE\xAD\xDE",1303 builtin.Endian.Little => "\xEF\xBE\xAD\xDE",
1299 };1304 };
13001305
1301 testing.expect(std.mem.eql(u8, asBytes(&deadbeef), deadbeef_bytes));1306 testing.expect(eql(u8, asBytes(&deadbeef), deadbeef_bytes));
13021307
1303 var codeface = u32(0xC0DEFACE);1308 var codeface = u32(0xC0DEFACE);
1304 for (asBytes(&codeface).*) |*b|1309 for (asBytes(&codeface).*) |*b|
...@@ -1318,7 +1323,7 @@ test "std.mem.asBytes" {...@@ -1318,7 +1323,7 @@ test "std.mem.asBytes" {
1318 .c = 0xDE,1323 .c = 0xDE,
1319 .d = 0xA1,1324 .d = 0xA1,
1320 };1325 };
1321 testing.expect(std.mem.eql(u8, asBytes(&inst), "\xBE\xEF\xDE\xA1"));1326 testing.expect(eql(u8, asBytes(&inst), "\xBE\xEF\xDE\xA1"));
1322}1327}
13231328
1324///Given any value, returns a copy of its bytes in an array.1329///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 {...@@ -1326,17 +1331,17 @@ pub fn toBytes(value: var) [@sizeOf(@typeOf(value))]u8 {
1326 return asBytes(&value).*;1331 return asBytes(&value).*;
1327}1332}
13281333
1329test "std.mem.toBytes" {1334test "toBytes" {
1330 var my_bytes = toBytes(u32(0x12345678));1335 var my_bytes = toBytes(u32(0x12345678));
1331 switch (builtin.endian) {1336 switch (builtin.endian) {
1332 builtin.Endian.Big => testing.expect(std.mem.eql(u8, my_bytes, "\x12\x34\x56\x78")),1337 builtin.Endian.Big => testing.expect(eql(u8, my_bytes, "\x12\x34\x56\x78")),
1333 builtin.Endian.Little => testing.expect(std.mem.eql(u8, my_bytes, "\x78\x56\x34\x12")),1338 builtin.Endian.Little => testing.expect(eql(u8, my_bytes, "\x78\x56\x34\x12")),
1334 }1339 }
13351340
1336 my_bytes[0] = '\x99';1341 my_bytes[0] = '\x99';
1337 switch (builtin.endian) {1342 switch (builtin.endian) {
1338 builtin.Endian.Big => testing.expect(std.mem.eql(u8, my_bytes, "\x99\x34\x56\x78")),1343 builtin.Endian.Big => testing.expect(eql(u8, my_bytes, "\x99\x34\x56\x78")),
1339 builtin.Endian.Little => testing.expect(std.mem.eql(u8, my_bytes, "\x99\x56\x34\x12")),1344 builtin.Endian.Little => testing.expect(eql(u8, my_bytes, "\x99\x56\x34\x12")),
1340 }1345 }
1341}1346}
13421347
...@@ -1358,7 +1363,7 @@ pub fn bytesAsValue(comptime T: type, bytes: var) BytesAsValueReturnType(T, @typ...@@ -1358,7 +1363,7 @@ pub fn bytesAsValue(comptime T: type, bytes: var) BytesAsValueReturnType(T, @typ
1358 return @ptrCast(BytesAsValueReturnType(T, @typeOf(bytes)), bytes);1363 return @ptrCast(BytesAsValueReturnType(T, @typeOf(bytes)), bytes);
1359}1364}
13601365
1361test "std.mem.bytesAsValue" {1366test "bytesAsValue" {
1362 const deadbeef = u32(0xDEADBEEF);1367 const deadbeef = u32(0xDEADBEEF);
1363 const deadbeef_bytes = switch (builtin.endian) {1368 const deadbeef_bytes = switch (builtin.endian) {
1364 builtin.Endian.Big => "\xDE\xAD\xBE\xEF",1369 builtin.Endian.Big => "\xDE\xAD\xBE\xEF",
...@@ -1400,7 +1405,7 @@ test "std.mem.bytesAsValue" {...@@ -1400,7 +1405,7 @@ test "std.mem.bytesAsValue" {
1400pub fn bytesToValue(comptime T: type, bytes: var) T {1405pub fn bytesToValue(comptime T: type, bytes: var) T {
1401 return bytesAsValue(T, &bytes).*;1406 return bytesAsValue(T, &bytes).*;
1402}1407}
1403test "std.mem.bytesToValue" {1408test "bytesToValue" {
1404 const deadbeef_bytes = switch (builtin.endian) {1409 const deadbeef_bytes = switch (builtin.endian) {
1405 builtin.Endian.Big => "\xDE\xAD\xBE\xEF",1410 builtin.Endian.Big => "\xDE\xAD\xBE\xEF",
1406 builtin.Endian.Little => "\xEF\xBE\xAD\xDE",1411 builtin.Endian.Little => "\xEF\xBE\xAD\xDE",
...@@ -1425,25 +1430,25 @@ pub fn subArrayPtr(ptr: var, comptime start: usize, comptime length: usize) SubA...@@ -1425,25 +1430,25 @@ pub fn subArrayPtr(ptr: var, comptime start: usize, comptime length: usize) SubA
1425 return @ptrCast(ReturnType, &ptr[start]);1430 return @ptrCast(ReturnType, &ptr[start]);
1426}1431}
14271432
1428test "std.mem.subArrayPtr" {1433test "subArrayPtr" {
1429 const a1 = "abcdef";1434 const a1 = "abcdef";
1430 const sub1 = subArrayPtr(&a1, 2, 3);1435 const sub1 = subArrayPtr(&a1, 2, 3);
1431 testing.expect(std.mem.eql(u8, sub1.*, "cde"));1436 testing.expect(eql(u8, sub1.*, "cde"));
14321437
1433 var a2 = "abcdef";1438 var a2 = "abcdef";
1434 var sub2 = subArrayPtr(&a2, 2, 3);1439 var sub2 = subArrayPtr(&a2, 2, 3);
14351440
1436 testing.expect(std.mem.eql(u8, sub2, "cde"));1441 testing.expect(eql(u8, sub2, "cde"));
1437 sub2[1] = 'X';1442 sub2[1] = 'X';
1438 testing.expect(std.mem.eql(u8, a2, "abcXef"));1443 testing.expect(eql(u8, a2, "abcXef"));
1439}1444}
14401445
1441/// Round an address up to the nearest aligned address1446/// Round an address up to the nearest aligned address
1442pub fn alignForward(addr: usize, alignment: usize) usize {1447pub fn alignForward(addr: usize, alignment: usize) usize {
1443 return (addr + alignment - 1) & ~(alignment - 1);1448 return alignBackward(addr + (alignment - 1), alignment);
1444}1449}
14451450
1446test "std.mem.alignForward" {1451test "alignForward" {
1447 testing.expect(alignForward(1, 1) == 1);1452 testing.expect(alignForward(1, 1) == 1);
1448 testing.expect(alignForward(2, 1) == 2);1453 testing.expect(alignForward(2, 1) == 2);
1449 testing.expect(alignForward(1, 2) == 2);1454 testing.expect(alignForward(1, 2) == 2);
...@@ -1457,3 +1462,30 @@ test "std.mem.alignForward" {...@@ -1457,3 +1462,30 @@ test "std.mem.alignForward" {
1457 testing.expect(alignForward(16, 8) == 16);1462 testing.expect(alignForward(16, 8) == 16);
1458 testing.expect(alignForward(17, 8) == 24);1463 testing.expect(alignForward(17, 8) == 24);
1459}1464}
1465
1466pub fn alignBackward(addr: usize, alignment: usize) usize {
1467 // 000010000 // example addr
1468 // 000001111 // subtract 1
1469 // 111110000 // binary not
1470 return addr & ~(alignment - 1);
1471}
1472
1473pub fn isAligned(addr: usize, alignment: usize) bool {
1474 return alignBackward(addr, alignment) == addr;
1475}
1476
1477test "isAligned" {
1478 testing.expect(isAligned(0, 4));
1479 testing.expect(isAligned(1, 1));
1480 testing.expect(isAligned(2, 1));
1481 testing.expect(isAligned(2, 2));
1482 testing.expect(!isAligned(2, 4));
1483 testing.expect(isAligned(3, 1));
1484 testing.expect(!isAligned(3, 2));
1485 testing.expect(!isAligned(3, 4));
1486 testing.expect(isAligned(4, 4));
1487 testing.expect(isAligned(4, 2));
1488 testing.expect(isAligned(4, 1));
1489 testing.expect(!isAligned(4, 8));
1490 testing.expect(!isAligned(4, 16));
1491}
std/mutex.zig+2-2
...@@ -152,9 +152,9 @@ test "std.Mutex" {...@@ -152,9 +152,9 @@ test "std.Mutex" {
152 testing.expect(context.data == TestContext.incr_count);152 testing.expect(context.data == TestContext.incr_count);
153 } else {153 } else {
154 const thread_count = 10;154 const thread_count = 10;
155 var threads: [thread_count]*std.os.Thread = undefined;155 var threads: [thread_count]*std.Thread = undefined;
156 for (threads) |*t| {156 for (threads) |*t| {
157 t.* = try std.os.spawnThread(&context, worker);157 t.* = try std.Thread.spawn(&context, worker);
158 }158 }
159 for (threads) |t|159 for (threads) |t|
160 t.wait();160 t.wait();
std/net.zig+12-12
...@@ -2,8 +2,8 @@ const std = @import("std.zig");...@@ -2,8 +2,8 @@ const std = @import("std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const net = @This();4const net = @This();
5const posix = std.os.posix;
6const mem = std.mem;5const mem = std.mem;
6const os = std.os;
77
8pub const TmpWinAddr = struct {8pub const TmpWinAddr = struct {
9 family: u8,9 family: u8,
...@@ -12,7 +12,7 @@ pub const TmpWinAddr = struct {...@@ -12,7 +12,7 @@ pub const TmpWinAddr = struct {
1212
13pub const OsAddress = switch (builtin.os) {13pub const OsAddress = switch (builtin.os) {
14 builtin.Os.windows => TmpWinAddr,14 builtin.Os.windows => TmpWinAddr,
15 else => posix.sockaddr,15 else => os.sockaddr,
16};16};
1717
18pub const Address = struct {18pub const Address = struct {
...@@ -20,9 +20,9 @@ pub const Address = struct {...@@ -20,9 +20,9 @@ pub const Address = struct {
2020
21 pub fn initIp4(ip4: u32, _port: u16) Address {21 pub fn initIp4(ip4: u32, _port: u16) Address {
22 return Address{22 return Address{
23 .os_addr = posix.sockaddr{23 .os_addr = os.sockaddr{
24 .in = posix.sockaddr_in{24 .in = os.sockaddr_in{
25 .family = posix.AF_INET,25 .family = os.AF_INET,
26 .port = mem.nativeToBig(u16, _port),26 .port = mem.nativeToBig(u16, _port),
27 .addr = ip4,27 .addr = ip4,
28 .zero = []u8{0} ** 8,28 .zero = []u8{0} ** 8,
...@@ -33,10 +33,10 @@ pub const Address = struct {...@@ -33,10 +33,10 @@ pub const Address = struct {
3333
34 pub fn initIp6(ip6: *const Ip6Addr, _port: u16) Address {34 pub fn initIp6(ip6: *const Ip6Addr, _port: u16) Address {
35 return Address{35 return Address{
36 .family = posix.AF_INET6,36 .family = os.AF_INET6,
37 .os_addr = posix.sockaddr{37 .os_addr = os.sockaddr{
38 .in6 = posix.sockaddr_in6{38 .in6 = os.sockaddr_in6{
39 .family = posix.AF_INET6,39 .family = os.AF_INET6,
40 .port = mem.nativeToBig(u16, _port),40 .port = mem.nativeToBig(u16, _port),
41 .flowinfo = 0,41 .flowinfo = 0,
42 .addr = ip6.addr,42 .addr = ip6.addr,
...@@ -50,18 +50,18 @@ pub const Address = struct {...@@ -50,18 +50,18 @@ pub const Address = struct {
50 return mem.bigToNative(u16, self.os_addr.in.port);50 return mem.bigToNative(u16, self.os_addr.in.port);
51 }51 }
5252
53 pub fn initPosix(addr: posix.sockaddr) Address {53 pub fn initPosix(addr: os.sockaddr) Address {
54 return Address{ .os_addr = addr };54 return Address{ .os_addr = addr };
55 }55 }
5656
57 pub fn format(self: *const Address, out_stream: var) !void {57 pub fn format(self: *const Address, out_stream: var) !void {
58 switch (self.os_addr.in.family) {58 switch (self.os_addr.in.family) {
59 posix.AF_INET => {59 os.AF_INET => {
60 const native_endian_port = mem.bigToNative(u16, self.os_addr.in.port);60 const native_endian_port = mem.bigToNative(u16, self.os_addr.in.port);
61 const bytes = ([]const u8)((*self.os_addr.in.addr)[0..1]);61 const bytes = ([]const u8)((*self.os_addr.in.addr)[0..1]);
62 try out_stream.print("{}.{}.{}.{}:{}", bytes[0], bytes[1], bytes[2], bytes[3], native_endian_port);62 try out_stream.print("{}.{}.{}.{}:{}", bytes[0], bytes[1], bytes[2], bytes[3], native_endian_port);
63 },63 },
64 posix.AF_INET6 => {64 os.AF_INET6 => {
65 const native_endian_port = mem.bigToNative(u16, self.os_addr.in6.port);65 const native_endian_port = mem.bigToNative(u16, self.os_addr.in6.port);
66 try out_stream.print("[TODO render ip6 address]:{}", native_endian_port);66 try out_stream.print("[TODO render ip6 address]:{}", native_endian_port);
67 },67 },
std/os.zig+1891-2972
...@@ -1,495 +1,484 @@...@@ -1,495 +1,484 @@
1// This file contains thin wrappers around OS-specific APIs, with these
2// specific goals in mind:
3// * Convert "errno"-style error codes into Zig errors.
4// * When null-terminated byte buffers are required, provide APIs which accept
5// slices as well as APIs which accept null-terminated byte buffers. Same goes
6// for UTF-16LE encoding.
7// * Where operating systems share APIs, e.g. POSIX, these thin wrappers provide
8// cross platform abstracting.
9// * When there exists a corresponding libc function and linking libc, the libc
10// implementation is used. Exceptions are made for known buggy areas of libc.
11// On Linux libc can be side-stepped by using `std.os.linux` directly.
12// * For Windows, this file represents the API that libc would provide for
13// Windows. For thin wrappers around Windows-specific APIs, see `std.os.windows`.
14// Note: The Zig standard library does not support POSIX thread cancellation, and
15// in general EINTR is handled by trying again.
16
1const std = @import("std.zig");17const std = @import("std.zig");
2const builtin = @import("builtin");18const builtin = @import("builtin");
3const Os = builtin.Os;19const assert = std.debug.assert;
4const is_windows = builtin.os == Os.windows;20const math = std.math;
5const is_posix = switch (builtin.os) {21const mem = std.mem;
6 builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => true,22const MAX_PATH_BYTES = std.fs.MAX_PATH_BYTES;
7 else => false,
8};
9const os = @This();
1023
11comptime {24comptime {
12 assert(@import("std") == std); // You have to run the std lib tests with --override-std-dir25 assert(@import("std") == std); // std lib tests require --override-std-dir
13}
14
15test "std.os" {
16 _ = @import("os/child_process.zig");
17 _ = @import("os/darwin.zig");
18 _ = @import("os/darwin/errno.zig");
19 _ = @import("os/get_user_id.zig");
20 _ = @import("os/linux.zig");
21 _ = @import("os/path.zig");
22 _ = @import("os/test.zig");
23 _ = @import("os/time.zig");
24 _ = @import("os/windows.zig");
25 _ = @import("os/uefi.zig");
26 _ = @import("os/wasi.zig");
27 _ = @import("os/get_app_data_dir.zig");
28}26}
2927
30pub const windows = @import("os/windows.zig");
31pub const darwin = @import("os/darwin.zig");28pub const darwin = @import("os/darwin.zig");
32pub const linux = @import("os/linux.zig");
33pub const freebsd = @import("os/freebsd.zig");29pub const freebsd = @import("os/freebsd.zig");
30pub const linux = @import("os/linux.zig");
34pub const netbsd = @import("os/netbsd.zig");31pub const netbsd = @import("os/netbsd.zig");
35pub const zen = @import("os/zen.zig");
36pub const uefi = @import("os/uefi.zig");32pub const uefi = @import("os/uefi.zig");
37pub const wasi = @import("os/wasi.zig");33pub const wasi = @import("os/wasi.zig");
34pub const windows = @import("os/windows.zig");
35pub const zen = @import("os/zen.zig");
3836
39pub const posix = switch (builtin.os) {37/// When linking libc, this is the C API. Otherwise, it is the OS-specific system interface.
40 Os.linux => linux,38pub const system = if (builtin.link_libc) std.c else switch (builtin.os) {
41 Os.macosx, Os.ios => darwin,39 .macosx, .ios, .watchos, .tvos => darwin,
42 Os.freebsd => freebsd,40 .freebsd => freebsd,
43 Os.netbsd => netbsd,41 .linux => linux,
44 Os.zen => zen,42 .netbsd => netbsd,
45 Os.wasi => wasi,43 .wasi => wasi,
46 else => @compileError("Unsupported OS"),44 .windows => windows,
47};45 .zen => zen,
4846 else => struct {},
49pub const net = @import("net.zig");
50
51pub const ChildProcess = @import("os/child_process.zig").ChildProcess;
52pub const path = @import("os/path.zig");
53pub const File = @import("os/file.zig").File;
54pub const time = @import("os/time.zig");
55
56pub const page_size = switch (builtin.arch) {
57 .wasm32, .wasm64 => 64 * 1024,
58 else => 4 * 1024,
59};
60
61pub const MAX_PATH_BYTES = switch (builtin.os) {
62 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => posix.PATH_MAX,
63 // Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
64 // If it would require 4 UTF-8 bytes, then there would be a surrogate
65 // pair in the UTF-16LE, and we (over)account 3 bytes for it that way.
66 // +1 for the null byte at the end, which can be encoded in 1 byte.
67 Os.windows => windows_util.PATH_MAX_WIDE * 3 + 1,
68 else => @compileError("Unsupported OS"),
69};47};
7048
71pub const UserInfo = @import("os/get_user_id.zig").UserInfo;49pub use @import("os/bits.zig");
72pub const getUserInfo = @import("os/get_user_id.zig").getUserInfo;
7350
74const windows_util = @import("os/windows/util.zig");51/// See also `getenv`. Populated by startup code before main().
75pub const windowsWaitSingle = windows_util.windowsWaitSingle;52pub var environ: [][*]u8 = undefined;
76pub const windowsWrite = windows_util.windowsWrite;
77pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty;
78pub const windowsOpen = windows_util.windowsOpen;
79pub const windowsOpenW = windows_util.windowsOpenW;
80pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
8153
82pub const WindowsCreateIoCompletionPortError = windows_util.WindowsCreateIoCompletionPortError;54/// Populated by startup code before main().
83pub const windowsCreateIoCompletionPort = windows_util.windowsCreateIoCompletionPort;55/// Not available on Windows. See `std.process.args`
56/// for obtaining the process arguments.
57pub var argv: [][*]u8 = undefined;
8458
85pub const WindowsPostQueuedCompletionStatusError = windows_util.WindowsPostQueuedCompletionStatusError;59/// To obtain errno, call this function with the return value of the
86pub const windowsPostQueuedCompletionStatus = windows_util.windowsPostQueuedCompletionStatus;60/// system function call. For some systems this will obtain the value directly
8761/// from the return code; for others it will use a thread-local errno variable.
88pub const WindowsWaitResult = windows_util.WindowsWaitResult;62/// Therefore, this function only returns a well-defined value when it is called
89pub const windowsGetQueuedCompletionStatus = windows_util.windowsGetQueuedCompletionStatus;63/// directly after the system function call which one wants to learn the errno
9064/// value of.
91pub const WindowsWaitError = windows_util.WaitError;65pub const errno = system.getErrno;
92pub const WindowsOpenError = windows_util.OpenError;
93pub const WindowsWriteError = windows_util.WriteError;
94pub const WindowsReadError = windows_util.ReadError;
95
96pub const FileHandle = if (is_windows) windows.HANDLE else i32;
97
98pub const getAppDataDir = @import("os/get_app_data_dir.zig").getAppDataDir;
99pub const GetAppDataDirError = @import("os/get_app_data_dir.zig").GetAppDataDirError;
100
101const debug = std.debug;
102const assert = debug.assert;
103const testing = std.testing;
104
105const c = std.c;
106
107const mem = std.mem;
108const Allocator = mem.Allocator;
10966
110const BufMap = std.BufMap;67/// Closes the file descriptor.
111const cstr = std.cstr;68/// This function is not capable of returning any indication of failure. An
69/// application which wants to ensure writes have succeeded before closing
70/// must call `fsync` before `close`.
71/// Note: The Zig standard library does not support POSIX thread cancellation.
72pub fn close(fd: fd_t) void {
73 if (windows.is_the_target) {
74 return windows.CloseHandle(fd);
75 }
76 if (wasi.is_the_target) {
77 _ = wasi.fd_close(fd);
78 }
79 if (darwin.is_the_target) {
80 // This avoids the EINTR problem.
81 switch (darwin.getErrno(darwin.@"close$NOCANCEL"(fd))) {
82 EBADF => unreachable, // Always a race condition.
83 else => return,
84 }
85 }
86 switch (errno(system.close(fd))) {
87 EBADF => unreachable, // Always a race condition.
88 EINTR => return, // This is still a success. See https://github.com/ziglang/zig/issues/2425
89 else => return,
90 }
91}
11292
113const io = std.io;93pub const GetRandomError = OpenError;
114const base64 = std.base64;
115const ArrayList = std.ArrayList;
116const Buffer = std.Buffer;
117const math = std.math;
11894
119/// Fills `buf` with random bytes. If linking against libc, this calls the95/// Obtain a series of random bytes. These bytes can be used to seed user-space
96/// random number generators or for cryptographic purposes.
97/// When linking against libc, this calls the
120/// appropriate OS-specific library call. Otherwise it uses the zig standard98/// appropriate OS-specific library call. Otherwise it uses the zig standard
121/// library implementation.99/// library implementation.
122pub fn getRandomBytes(buf: []u8) !void {100pub fn getrandom(buf: []u8) GetRandomError!void {
123 switch (builtin.os) {101 if (windows.is_the_target) {
124 Os.linux => while (true) {102 return windows.RtlGenRandom(buf);
125 // TODO check libc version and potentially call c.getrandom.103 }
126 // See #397104 if (linux.is_the_target) {
127 const errno = posix.getErrno(posix.getrandom(buf.ptr, buf.len, 0));105 while (true) {
128 switch (errno) {106 // Bypass libc because it's missing on even relatively new versions.
107 switch (linux.getErrno(linux.getrandom(buf.ptr, buf.len, 0))) {
129 0 => return,108 0 => return,
130 posix.EINVAL => unreachable,109 EINVAL => unreachable,
131 posix.EFAULT => unreachable,110 EFAULT => unreachable,
132 posix.EINTR => continue,111 EINTR => continue,
133 posix.ENOSYS => return getRandomBytesDevURandom(buf),112 ENOSYS => return getRandomBytesDevURandom(buf),
134 else => return unexpectedErrorPosix(errno),113 else => |err| return unexpectedErrno(err),
135 }
136 },
137 Os.macosx, Os.ios, Os.freebsd, Os.netbsd => return getRandomBytesDevURandom(buf),
138 Os.windows => {
139 // Call RtlGenRandom() instead of CryptGetRandom() on Windows
140 // https://github.com/rust-lang-nursery/rand/issues/111
141 // https://bugzilla.mozilla.org/show_bug.cgi?id=504270
142 if (windows.RtlGenRandom(buf.ptr, buf.len) == 0) {
143 const err = windows.GetLastError();
144 return switch (err) {
145 else => unexpectedErrorWindows(err),
146 };
147 }
148 },
149 Os.wasi => {
150 const random_get_result = os.wasi.random_get(buf.ptr, buf.len);
151 if (random_get_result != os.wasi.ESUCCESS) {
152 return error.Unknown;
153 }
154 },
155 Os.zen => {
156 const randomness = []u8{ 42, 1, 7, 12, 22, 17, 99, 16, 26, 87, 41, 45 };
157 var i: usize = 0;
158 while (i < buf.len) : (i += 1) {
159 if (i > randomness.len) return error.Unknown;
160 buf[i] = randomness[i];
161 }114 }
162 },115 }
163 else => @compileError("Unsupported OS"),116 }
117 if (wasi.is_the_target) {
118 switch (wasi.random_get(buf.ptr, buf.len)) {
119 0 => return,
120 else => |err| return unexpectedErrno(err),
121 }
164 }122 }
123 return getRandomBytesDevURandom(buf);
165}124}
166125
167fn getRandomBytesDevURandom(buf: []u8) !void {126fn getRandomBytesDevURandom(buf: []u8) !void {
168 const fd = try posixOpenC(c"/dev/urandom", posix.O_RDONLY | posix.O_CLOEXEC, 0);127 const fd = try openC(c"/dev/urandom", O_RDONLY | O_CLOEXEC, 0);
169 defer close(fd);128 defer close(fd);
170129
171 const stream = &File.openHandle(fd).inStream().stream;130 const stream = &std.fs.File.openHandle(fd).inStream().stream;
172 stream.readNoEof(buf) catch |err| switch (err) {131 stream.readNoEof(buf) catch return error.Unexpected;
173 error.EndOfStream => unreachable,
174 error.OperationAborted => unreachable,
175 error.BrokenPipe => unreachable,
176 error.Unexpected => return error.Unexpected,
177 error.InputOutput => return error.Unexpected,
178 error.SystemResources => return error.Unexpected,
179 error.IsDir => unreachable,
180 };
181}
182
183test "os.getRandomBytes" {
184 var buf_a: [50]u8 = undefined;
185 var buf_b: [50]u8 = undefined;
186 // Call Twice
187 try getRandomBytes(buf_a[0..]);
188 try getRandomBytes(buf_b[0..]);
189
190 // Check if random (not 100% conclusive)
191 testing.expect(!mem.eql(u8, buf_a, buf_b));
192}132}
193133
194/// Raises a signal in the current kernel thread, ending its execution.134/// Causes abnormal process termination.
195/// If linking against libc, this calls the abort() libc function. Otherwise135/// If linking against libc, this calls the abort() libc function. Otherwise
196/// it uses the zig standard library implementation.136/// it raises SIGABRT followed by SIGKILL and finally lo
197pub fn abort() noreturn {137pub fn abort() noreturn {
198 @setCold(true);138 @setCold(true);
199 if (builtin.link_libc) {139 if (builtin.link_libc) {
200 c.abort();140 system.abort();
201 }141 }
202 switch (builtin.os) {142 if (windows.is_the_target) {
203 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {143 if (builtin.mode == .Debug) {
204 _ = posix.raise(posix.SIGABRT);144 @breakpoint();
205 _ = posix.raise(posix.SIGKILL);145 }
206 while (true) {}146 windows.kernel32.ExitProcess(3);
207 },
208 Os.windows => {
209 if (builtin.mode == builtin.Mode.Debug) {
210 @breakpoint();
211 }
212 windows.ExitProcess(3);
213 },
214 Os.wasi => {
215 _ = wasi.proc_raise(wasi.SIGABRT);
216 // TODO: Is SIGKILL even necessary?
217 _ = wasi.proc_raise(wasi.SIGKILL);
218 while (true) {}
219 },
220 Os.uefi => {
221 // TODO there's gotta be a better thing to do here than loop forever
222 while (true) {}
223 },
224 else => @compileError("Unsupported OS"),
225 }147 }
148 if (builtin.os == .uefi) {
149 // TODO there must be a better thing to do here than loop forever
150 while (true) {}
151 }
152
153 raise(SIGABRT) catch {};
154
155 // TODO the rest of the implementation of abort() from musl libc here
156
157 raise(SIGKILL) catch {};
158 exit(127);
226}159}
227160
228/// Exits the program cleanly with the specified status code.161pub const RaiseError = error{Unexpected};
229pub fn exit(status: u8) noreturn {162
230 @setCold(true);163pub fn raise(sig: u8) RaiseError!void {
231 if (builtin.link_libc) {164 if (builtin.link_libc) {
232 c.exit(status);165 switch (errno(system.raise(sig))) {
233 }166 0 => return,
234 switch (builtin.os) {167 else => |err| return unexpectedErrno(err),
235 Os.linux => {168 }
236 if (builtin.single_threaded) {
237 linux.exit(status);
238 } else {
239 linux.exit_group(status);
240 }
241 },
242 Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
243 posix.exit(status);
244 },
245 Os.windows => {
246 windows.ExitProcess(status);
247 },
248 Os.wasi => {
249 wasi.proc_exit(status);
250 },
251 else => @compileError("Unsupported OS"),
252 }169 }
253}
254170
255/// When a file descriptor is closed on linux, it pops the first171 if (wasi.is_the_target) {
256/// node from this queue and resumes it.172 switch (wasi.proc_raise(SIGABRT)) {
257/// Async functions which get the EMFILE error code can suspend,173 0 => return,
258/// putting their coroutine handle into this list.174 else => |err| return unexpectedErrno(err),
259/// TODO make this an atomic linked list175 }
260pub var emfile_promise_queue = std.LinkedList(promise).init();176 }
261177
262/// Closes the file handle. Keeps trying if it gets interrupted by a signal.178 if (linux.is_the_target) {
263pub fn close(handle: FileHandle) void {179 var set: linux.sigset_t = undefined;
264 if (is_windows) {180 linux.blockAppSignals(&set);
265 windows_util.windowsClose(handle);181 const tid = linux.syscall0(linux.SYS_gettid);
266 } else {182 const rc = linux.syscall2(linux.SYS_tkill, tid, sig);
267 while (true) {183 linux.restoreSignals(&set);
268 const err = posix.getErrno(posix.close(handle));184 switch (errno(rc)) {
269 switch (err) {185 0 => return,
270 posix.EINTR => continue,186 else => |err| return unexpectedErrno(err),
271 else => {
272 if (emfile_promise_queue.popFirst()) |p| resume p.data;
273 return;
274 },
275 }
276 }187 }
277 }188 }
189
190 @compileError("std.os.raise unimplemented for this target");
191}
192
193pub const KillError = error{
194 PermissionDenied,
195 Unexpected,
196};
197
198pub fn kill(pid: pid_t, sig: u8) KillError!void {
199 switch (errno(system.kill(pid, sig))) {
200 0 => return,
201 EINVAL => unreachable, // invalid signal
202 EPERM => return error.PermissionDenied,
203 ESRCH => unreachable, // always a race condition
204 else => |err| return unexpectedErrno(err),
205 }
278}206}
279207
280pub const PosixReadError = error{208/// Exits the program cleanly with the specified status code.
209pub fn exit(status: u8) noreturn {
210 if (builtin.link_libc) {
211 system.exit(status);
212 }
213 if (windows.is_the_target) {
214 windows.kernel32.ExitProcess(status);
215 }
216 if (wasi.is_the_target) {
217 wasi.proc_exit(status);
218 }
219 if (linux.is_the_target and !builtin.single_threaded) {
220 linux.exit_group(status);
221 }
222 system.exit(status);
223}
224
225pub const ReadError = error{
281 InputOutput,226 InputOutput,
282 SystemResources,227 SystemResources,
283 IsDir,228 IsDir,
229 OperationAborted,
230 BrokenPipe,
284 Unexpected,231 Unexpected,
285};232};
286233
287/// Returns the number of bytes that were read, which can be less than234/// Returns the number of bytes that were read, which can be less than
288/// buf.len. If 0 bytes were read, that means EOF.235/// buf.len. If 0 bytes were read, that means EOF.
289pub fn posixRead(fd: i32, buf: []u8) PosixReadError!usize {236/// This function is for blocking file descriptors only. For non-blocking, see
237/// `readAsync`.
238pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
239 if (windows.is_the_target) {
240 return windows.ReadFile(fd, buf);
241 }
242
243 if (wasi.is_the_target and !builtin.link_libc) {
244 const iovs = [1]iovec{iovec{
245 .iov_base = buf.ptr,
246 .iov_len = buf.len,
247 }};
248
249 var nread: usize = undefined;
250 switch (wasi.fd_read(fd, &iovs, iovs.len, &nread)) {
251 0 => return nread,
252 else => |err| return unexpectedErrno(err),
253 }
254 }
255
290 // Linux can return EINVAL when read amount is > 0x7ffff000256 // Linux can return EINVAL when read amount is > 0x7ffff000
291 // See https://github.com/ziglang/zig/pull/743#issuecomment-363158274257 // See https://github.com/ziglang/zig/pull/743#issuecomment-363158274
258 // TODO audit this. Shawn Landden says that this is not actually true.
259 // if this logic should stay, move it to std.os.linux
292 const max_buf_len = 0x7ffff000;260 const max_buf_len = 0x7ffff000;
293261
294 var index: usize = 0;262 var index: usize = 0;
295 while (index < buf.len) {263 while (index < buf.len) {
296 const want_to_read = math.min(buf.len - index, usize(max_buf_len));264 const want_to_read = math.min(buf.len - index, usize(max_buf_len));
297 const rc = posix.read(fd, buf.ptr + index, want_to_read);265 const rc = system.read(fd, buf.ptr + index, want_to_read);
298 const err = posix.getErrno(rc);266 switch (errno(rc)) {
299 switch (err) {
300 0 => {267 0 => {
301 index += rc;268 const amt_read = @intCast(usize, rc);
302 if (rc == want_to_read) continue;269 index += amt_read;
270 if (amt_read == want_to_read) continue;
303 // Read returned less than buf.len.271 // Read returned less than buf.len.
304 return index;272 return index;
305 },273 },
306 posix.EINTR => continue,274 EINTR => continue,
307 posix.EINVAL => unreachable,275 EINVAL => unreachable,
308 posix.EFAULT => unreachable,276 EFAULT => unreachable,
309 posix.EAGAIN => unreachable,277 EAGAIN => unreachable, // This function is for blocking reads.
310 posix.EBADF => unreachable, // always a race condition278 EBADF => unreachable, // Always a race condition.
311 posix.EIO => return error.InputOutput,279 EIO => return error.InputOutput,
312 posix.EISDIR => return error.IsDir,280 EISDIR => return error.IsDir,
313 posix.ENOBUFS => return error.SystemResources,281 ENOBUFS => return error.SystemResources,
314 posix.ENOMEM => return error.SystemResources,282 ENOMEM => return error.SystemResources,
315 else => return unexpectedErrorPosix(err),283 else => |err| return unexpectedErrno(err),
316 }284 }
317 }285 }
318 return index;286 return index;
319}287}
320288
321/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.289/// Number of bytes read is returned. Upon reading end-of-file, zero is returned.
322pub fn posix_preadv(fd: i32, iov: [*]const posix.iovec, count: usize, offset: u64) PosixReadError!usize {290/// This function is for blocking file descriptors only. For non-blocking, see
323 switch (builtin.os) {291/// `preadvAsync`.
324 builtin.Os.macosx => {292pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) ReadError!usize {
325 // Darwin does not have preadv but it does have pread.293 if (darwin.is_the_target) {
326 var off: usize = 0;294 // Darwin does not have preadv but it does have pread.
327 var iov_i: usize = 0;295 var off: usize = 0;
328 var inner_off: usize = 0;296 var iov_i: usize = 0;
329 while (true) {297 var inner_off: usize = 0;
330 const v = iov[iov_i];298 while (true) {
331 const rc = darwin.pread(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);299 const v = iov[iov_i];
332 const err = darwin.getErrno(rc);300 const rc = darwin.pread(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
333 switch (err) {301 const err = darwin.getErrno(rc);
334 0 => {
335 off += rc;
336 inner_off += rc;
337 if (inner_off == v.iov_len) {
338 iov_i += 1;
339 inner_off = 0;
340 if (iov_i == count) {
341 return off;
342 }
343 }
344 if (rc == 0) return off; // EOF
345 continue;
346 },
347 posix.EINTR => continue,
348 posix.EINVAL => unreachable,
349 posix.EFAULT => unreachable,
350 posix.ESPIPE => unreachable, // fd is not seekable
351 posix.EAGAIN => unreachable, // this function is not for non blocking
352 posix.EBADF => unreachable, // always a race condition
353 posix.EIO => return error.InputOutput,
354 posix.EISDIR => return error.IsDir,
355 posix.ENOBUFS => return error.SystemResources,
356 posix.ENOMEM => return error.SystemResources,
357 else => return unexpectedErrorPosix(err),
358 }
359 }
360 },
361 builtin.Os.linux, builtin.Os.freebsd, Os.netbsd => while (true) {
362 const rc = posix.preadv(fd, iov, count, offset);
363 const err = posix.getErrno(rc);
364 switch (err) {302 switch (err) {
365 0 => return rc,303 0 => {
366 posix.EINTR => continue,304 const amt_read = @bitCast(usize, rc);
367 posix.EINVAL => unreachable,305 off += amt_read;
368 posix.EFAULT => unreachable,306 inner_off += amt_read;
369 posix.EAGAIN => unreachable, // don't call this function for non blocking307 if (inner_off == v.iov_len) {
370 posix.EBADF => unreachable, // always a race condition308 iov_i += 1;
371 posix.EIO => return error.InputOutput,309 inner_off = 0;
372 posix.EISDIR => return error.IsDir,310 if (iov_i == iov.len) {
373 posix.ENOBUFS => return error.SystemResources,311 return off;
374 posix.ENOMEM => return error.SystemResources,312 }
375 else => return unexpectedErrorPosix(err),313 }
314 if (rc == 0) return off; // EOF
315 continue;
316 },
317 EINTR => continue,
318 EINVAL => unreachable,
319 EFAULT => unreachable,
320 ESPIPE => unreachable, // fd is not seekable
321 EAGAIN => unreachable, // This function is for blocking reads.
322 EBADF => unreachable, // always a race condition
323 EIO => return error.InputOutput,
324 EISDIR => return error.IsDir,
325 ENOBUFS => return error.SystemResources,
326 ENOMEM => return error.SystemResources,
327 else => return unexpectedErrno(err),
376 }328 }
377 },329 }
378 else => @compileError("Unsupported OS"),330 }
331 while (true) {
332 // TODO handle the case when iov_len is too large and get rid of this @intCast
333 const rc = system.preadv(fd, iov.ptr, @intCast(u32, iov.len), offset);
334 switch (errno(rc)) {
335 0 => return @bitCast(usize, rc),
336 EINTR => continue,
337 EINVAL => unreachable,
338 EFAULT => unreachable,
339 EAGAIN => unreachable, // This function is for blocking reads.
340 EBADF => unreachable, // always a race condition
341 EIO => return error.InputOutput,
342 EISDIR => return error.IsDir,
343 ENOBUFS => return error.SystemResources,
344 ENOMEM => return error.SystemResources,
345 else => |err| return unexpectedErrno(err),
346 }
379 }347 }
380}348}
381349
382pub const PosixWriteError = error{350pub const WriteError = error{
383 DiskQuota,351 DiskQuota,
384 FileTooBig,352 FileTooBig,
385 InputOutput,353 InputOutput,
386 NoSpaceLeft,354 NoSpaceLeft,
387 AccessDenied,355 AccessDenied,
388 BrokenPipe,356 BrokenPipe,
389357 SystemResources,
390 /// See https://github.com/ziglang/zig/issues/1396358 OperationAborted,
391 Unexpected,359 Unexpected,
392};360};
393361
394/// Calls POSIX write, and keeps trying if it gets interrupted.362/// Write to a file descriptor. Keeps trying if it gets interrupted.
395pub fn posixWrite(fd: i32, bytes: []const u8) PosixWriteError!void {363/// This function is for blocking file descriptors only. For non-blocking, see
364/// `writeAsync`.
365pub fn write(fd: fd_t, bytes: []const u8) WriteError!void {
366 if (windows.is_the_target) {
367 return windows.WriteFile(fd, bytes);
368 }
369
370 if (wasi.is_the_target and !builtin.link_libc) {
371 const ciovs = [1]iovec_const{iovec_const{
372 .iov_base = bytes.ptr,
373 .iov_len = bytes.len,
374 }};
375 var nwritten: usize = undefined;
376 switch (wasi.fd_write(fd, &ciovs, ciovs.len, &nwritten)) {
377 0 => return,
378 else => |err| return unexpectedErrno(err),
379 }
380 }
381
396 // Linux can return EINVAL when write amount is > 0x7ffff000382 // Linux can return EINVAL when write amount is > 0x7ffff000
397 // See https://github.com/ziglang/zig/pull/743#issuecomment-363165856383 // See https://github.com/ziglang/zig/pull/743#issuecomment-363165856
384 // TODO audit this. Shawn Landden says that this is not actually true.
385 // if this logic should stay, move it to std.os.linux
398 const max_bytes_len = 0x7ffff000;386 const max_bytes_len = 0x7ffff000;
399387
400 var index: usize = 0;388 var index: usize = 0;
401 while (index < bytes.len) {389 while (index < bytes.len) {
402 const amt_to_write = math.min(bytes.len - index, usize(max_bytes_len));390 const amt_to_write = math.min(bytes.len - index, usize(max_bytes_len));
403 const rc = posix.write(fd, bytes.ptr + index, amt_to_write);391 const rc = system.write(fd, bytes.ptr + index, amt_to_write);
404 const write_err = posix.getErrno(rc);392 switch (errno(rc)) {
405 switch (write_err) {
406 0 => {393 0 => {
407 index += rc;394 index += @intCast(usize, rc);
408 continue;395 continue;
409 },396 },
410 posix.EINTR => continue,397 EINTR => continue,
411 posix.EINVAL => unreachable,398 EINVAL => unreachable,
412 posix.EFAULT => unreachable,399 EFAULT => unreachable,
413 posix.EAGAIN => unreachable, // use posixAsyncWrite for non-blocking400 EAGAIN => unreachable, // This function is for blocking writes.
414 posix.EBADF => unreachable, // always a race condition401 EBADF => unreachable, // Always a race condition.
415 posix.EDESTADDRREQ => unreachable, // connect was never called402 EDESTADDRREQ => unreachable, // `connect` was never called.
416 posix.EDQUOT => return PosixWriteError.DiskQuota,403 EDQUOT => return error.DiskQuota,
417 posix.EFBIG => return PosixWriteError.FileTooBig,404 EFBIG => return error.FileTooBig,
418 posix.EIO => return PosixWriteError.InputOutput,405 EIO => return error.InputOutput,
419 posix.ENOSPC => return PosixWriteError.NoSpaceLeft,406 ENOSPC => return error.NoSpaceLeft,
420 posix.EPERM => return PosixWriteError.AccessDenied,407 EPERM => return error.AccessDenied,
421 posix.EPIPE => return PosixWriteError.BrokenPipe,408 EPIPE => return error.BrokenPipe,
422 else => return unexpectedErrorPosix(write_err),409 else => |err| return unexpectedErrno(err),
410 }
411 }
412}
413
414/// Write multiple buffers to a file descriptor. Keeps trying if it gets interrupted.
415/// This function is for blocking file descriptors only. For non-blocking, see
416/// `pwritevAsync`.
417pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) WriteError!void {
418 if (darwin.is_the_target) {
419 // Darwin does not have pwritev but it does have pwrite.
420 var off: usize = 0;
421 var iov_i: usize = 0;
422 var inner_off: usize = 0;
423 while (true) {
424 const v = iov[iov_i];
425 const rc = darwin.pwrite(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);
426 const err = darwin.getErrno(rc);
427 switch (err) {
428 0 => {
429 const amt_written = @bitCast(usize, rc);
430 off += amt_written;
431 inner_off += amt_written;
432 if (inner_off == v.iov_len) {
433 iov_i += 1;
434 inner_off = 0;
435 if (iov_i == iov.len) {
436 return;
437 }
438 }
439 continue;
440 },
441 EINTR => continue,
442 ESPIPE => unreachable, // `fd` is not seekable.
443 EINVAL => unreachable,
444 EFAULT => unreachable,
445 EAGAIN => unreachable, // This function is for blocking writes.
446 EBADF => unreachable, // Always a race condition.
447 EDESTADDRREQ => unreachable, // `connect` was never called.
448 EDQUOT => return error.DiskQuota,
449 EFBIG => return error.FileTooBig,
450 EIO => return error.InputOutput,
451 ENOSPC => return error.NoSpaceLeft,
452 EPERM => return error.AccessDenied,
453 EPIPE => return error.BrokenPipe,
454 else => return unexpectedErrno(err),
455 }
423 }456 }
424 }457 }
425}
426458
427pub fn posix_pwritev(fd: i32, iov: [*]const posix.iovec_const, count: usize, offset: u64) PosixWriteError!void {459 while (true) {
428 switch (builtin.os) {460 // TODO handle the case when iov_len is too large and get rid of this @intCast
429 builtin.Os.macosx => {461 const rc = system.pwritev(fd, iov.ptr, @intCast(u32, iov.len), offset);
430 // Darwin does not have pwritev but it does have pwrite.462 switch (errno(rc)) {
431 var off: usize = 0;463 0 => return,
432 var iov_i: usize = 0;464 EINTR => continue,
433 var inner_off: usize = 0;465 EINVAL => unreachable,
434 while (true) {466 EFAULT => unreachable,
435 const v = iov[iov_i];467 EAGAIN => unreachable, // This function is for blocking writes.
436 const rc = darwin.pwrite(fd, v.iov_base + inner_off, v.iov_len - inner_off, offset + off);468 EBADF => unreachable, // Always a race condition.
437 const err = darwin.getErrno(rc);469 EDESTADDRREQ => unreachable, // `connect` was never called.
438 switch (err) {470 EDQUOT => return error.DiskQuota,
439 0 => {471 EFBIG => return error.FileTooBig,
440 off += rc;472 EIO => return error.InputOutput,
441 inner_off += rc;473 ENOSPC => return error.NoSpaceLeft,
442 if (inner_off == v.iov_len) {474 EPERM => return error.AccessDenied,
443 iov_i += 1;475 EPIPE => return error.BrokenPipe,
444 inner_off = 0;476 else => |err| return unexpectedErrno(err),
445 if (iov_i == count) {477 }
446 return;
447 }
448 }
449 continue;
450 },
451 posix.EINTR => continue,
452 posix.ESPIPE => unreachable, // fd is not seekable
453 posix.EINVAL => unreachable,
454 posix.EFAULT => unreachable,
455 posix.EAGAIN => unreachable, // use posixAsyncPWriteV for non-blocking
456 posix.EBADF => unreachable, // always a race condition
457 posix.EDESTADDRREQ => unreachable, // connect was never called
458 posix.EDQUOT => return PosixWriteError.DiskQuota,
459 posix.EFBIG => return PosixWriteError.FileTooBig,
460 posix.EIO => return PosixWriteError.InputOutput,
461 posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
462 posix.EPERM => return PosixWriteError.AccessDenied,
463 posix.EPIPE => return PosixWriteError.BrokenPipe,
464 else => return unexpectedErrorPosix(err),
465 }
466 }
467 },
468 builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => while (true) {
469 const rc = posix.pwritev(fd, iov, count, offset);
470 const err = posix.getErrno(rc);
471 switch (err) {
472 0 => return,
473 posix.EINTR => continue,
474 posix.EINVAL => unreachable,
475 posix.EFAULT => unreachable,
476 posix.EAGAIN => unreachable, // use posixAsyncPWriteV for non-blocking
477 posix.EBADF => unreachable, // always a race condition
478 posix.EDESTADDRREQ => unreachable, // connect was never called
479 posix.EDQUOT => return PosixWriteError.DiskQuota,
480 posix.EFBIG => return PosixWriteError.FileTooBig,
481 posix.EIO => return PosixWriteError.InputOutput,
482 posix.ENOSPC => return PosixWriteError.NoSpaceLeft,
483 posix.EPERM => return PosixWriteError.AccessDenied,
484 posix.EPIPE => return PosixWriteError.BrokenPipe,
485 else => return unexpectedErrorPosix(err),
486 }
487 },
488 else => @compileError("Unsupported OS"),
489 }478 }
490}479}
491480
492pub const PosixOpenError = error{481pub const OpenError = error{
493 AccessDenied,482 AccessDenied,
494 FileTooBig,483 FileTooBig,
495 IsDir,484 IsDir,
...@@ -504,106 +493,60 @@ pub const PosixOpenError = error{...@@ -504,106 +493,60 @@ pub const PosixOpenError = error{
504 NotDir,493 NotDir,
505 PathAlreadyExists,494 PathAlreadyExists,
506 DeviceBusy,495 DeviceBusy,
507
508 /// See https://github.com/ziglang/zig/issues/1396
509 Unexpected,496 Unexpected,
510};497};
511498
512/// ::file_path needs to be copied in memory to add a null terminating byte.499/// Open and possibly create a file. Keeps trying if it gets interrupted.
513/// Calls POSIX open, keeps trying if it gets interrupted, and translates500/// `file_path` needs to be copied in memory to add a null terminating byte.
514/// the return value into zig errors.501/// See also `openC`.
515pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize) PosixOpenError!i32 {502pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!fd_t {
516 const file_path_c = try toPosixPath(file_path);503 const file_path_c = try toPosixPath(file_path);
517 return posixOpenC(&file_path_c, flags, perm);504 return openC(&file_path_c, flags, perm);
518}505}
519506
520// TODO https://github.com/ziglang/zig/issues/265507/// Open and possibly create a file. Keeps trying if it gets interrupted.
521pub fn posixOpenC(file_path: [*]const u8, flags: u32, perm: usize) !i32 {508/// See also `open`.
509/// TODO https://github.com/ziglang/zig/issues/265
510pub fn openC(file_path: [*]const u8, flags: u32, perm: usize) OpenError!fd_t {
522 while (true) {511 while (true) {
523 const result = posix.open(file_path, flags, perm);512 const rc = system.open(file_path, flags, perm);
524 const err = posix.getErrno(result);513 switch (errno(rc)) {
525 if (err > 0) {514 0 => return @intCast(fd_t, rc),
526 switch (err) {515 EINTR => continue,
527 posix.EINTR => continue,516
528517 EFAULT => unreachable,
529 posix.EFAULT => unreachable,518 EINVAL => unreachable,
530 posix.EINVAL => unreachable,519 EACCES => return error.AccessDenied,
531 posix.EACCES => return PosixOpenError.AccessDenied,520 EFBIG => return error.FileTooBig,
532 posix.EFBIG, posix.EOVERFLOW => return PosixOpenError.FileTooBig,521 EOVERFLOW => return error.FileTooBig,
533 posix.EISDIR => return PosixOpenError.IsDir,522 EISDIR => return error.IsDir,
534 posix.ELOOP => return PosixOpenError.SymLinkLoop,523 ELOOP => return error.SymLinkLoop,
535 posix.EMFILE => return PosixOpenError.ProcessFdQuotaExceeded,524 EMFILE => return error.ProcessFdQuotaExceeded,
536 posix.ENAMETOOLONG => return PosixOpenError.NameTooLong,525 ENAMETOOLONG => return error.NameTooLong,
537 posix.ENFILE => return PosixOpenError.SystemFdQuotaExceeded,526 ENFILE => return error.SystemFdQuotaExceeded,
538 posix.ENODEV => return PosixOpenError.NoDevice,527 ENODEV => return error.NoDevice,
539 posix.ENOENT => return PosixOpenError.FileNotFound,528 ENOENT => return error.FileNotFound,
540 posix.ENOMEM => return PosixOpenError.SystemResources,529 ENOMEM => return error.SystemResources,
541 posix.ENOSPC => return PosixOpenError.NoSpaceLeft,530 ENOSPC => return error.NoSpaceLeft,
542 posix.ENOTDIR => return PosixOpenError.NotDir,531 ENOTDIR => return error.NotDir,
543 posix.EPERM => return PosixOpenError.AccessDenied,532 EPERM => return error.AccessDenied,
544 posix.EEXIST => return PosixOpenError.PathAlreadyExists,533 EEXIST => return error.PathAlreadyExists,
545 posix.EBUSY => return PosixOpenError.DeviceBusy,534 EBUSY => return error.DeviceBusy,
546 else => return unexpectedErrorPosix(err),535 else => |err| return unexpectedErrno(err),
547 }536 }
548 }537 }
549 return @intCast(i32, result);538}
550 }539
551}540pub fn dup2(old_fd: fd_t, new_fd: fd_t) !void {
552
553/// Used to convert a slice to a null terminated slice on the stack.
554/// TODO well defined copy elision
555pub fn toPosixPath(file_path: []const u8) ![posix.PATH_MAX]u8 {
556 var path_with_null: [posix.PATH_MAX]u8 = undefined;
557 if (file_path.len >= posix.PATH_MAX) return error.NameTooLong;
558 mem.copy(u8, path_with_null[0..], file_path);
559 path_with_null[file_path.len] = 0;
560 return path_with_null;
561}
562
563pub fn posixDup2(old_fd: i32, new_fd: i32) !void {
564 while (true) {541 while (true) {
565 const err = posix.getErrno(posix.dup2(old_fd, new_fd));542 switch (errno(system.dup2(old_fd, new_fd))) {
566 if (err > 0) {543 0 => return,
567 return switch (err) {544 EBUSY, EINTR => continue,
568 posix.EBUSY, posix.EINTR => continue,545 EMFILE => return error.ProcessFdQuotaExceeded,
569 posix.EMFILE => error.ProcessFdQuotaExceeded,546 EINVAL => unreachable,
570 posix.EINVAL => unreachable,547 else => |err| return unexpectedErrno(err),
571 else => unexpectedErrorPosix(err),
572 };
573 }
574 return;
575 }
576}
577
578pub fn createNullDelimitedEnvMap(allocator: *Allocator, env_map: *const BufMap) ![]?[*]u8 {
579 const envp_count = env_map.count();
580 const envp_buf = try allocator.alloc(?[*]u8, envp_count + 1);
581 mem.set(?[*]u8, envp_buf, null);
582 errdefer freeNullDelimitedEnvMap(allocator, envp_buf);
583 {
584 var it = env_map.iterator();
585 var i: usize = 0;
586 while (it.next()) |pair| : (i += 1) {
587 const env_buf = try allocator.alloc(u8, pair.key.len + pair.value.len + 2);
588 @memcpy(env_buf.ptr, pair.key.ptr, pair.key.len);
589 env_buf[pair.key.len] = '=';
590 @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len);
591 env_buf[env_buf.len - 1] = 0;
592
593 envp_buf[i] = env_buf.ptr;
594 }548 }
595 assert(i == envp_count);
596 }
597 assert(envp_buf[envp_count] == null);
598 return envp_buf;
599}
600
601pub fn freeNullDelimitedEnvMap(allocator: *Allocator, envp_buf: []?[*]u8) void {
602 for (envp_buf) |env| {
603 const env_buf = if (env) |ptr| ptr[0 .. cstr.len(ptr) + 1] else break;
604 allocator.free(env_buf);
605 }549 }
606 allocator.free(envp_buf);
607}550}
608551
609/// This function must allocate memory to add a null terminating bytes on path and each arg.552/// 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 {...@@ -611,34 +554,35 @@ pub fn freeNullDelimitedEnvMap(allocator: *Allocator, envp_buf: []?[*]u8) void {
611/// pointers after the args and after the environment variables.554/// pointers after the args and after the environment variables.
612/// `argv[0]` is the executable path.555/// `argv[0]` is the executable path.
613/// This function also uses the PATH environment variable to get the full path to the executable.556/// This function also uses the PATH environment variable to get the full path to the executable.
614pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator: *Allocator) !void {557/// TODO provide execveC which does not take an allocator
615 const argv_buf = try allocator.alloc(?[*]u8, argv.len + 1);558pub fn execve(allocator: *mem.Allocator, argv_slice: []const []const u8, env_map: *const std.BufMap) !void {
559 const argv_buf = try allocator.alloc(?[*]u8, argv_slice.len + 1);
616 mem.set(?[*]u8, argv_buf, null);560 mem.set(?[*]u8, argv_buf, null);
617 defer {561 defer {
618 for (argv_buf) |arg| {562 for (argv_buf) |arg| {
619 const arg_buf = if (arg) |ptr| cstr.toSlice(ptr) else break;563 const arg_buf = if (arg) |ptr| mem.toSlice(u8, ptr) else break;
620 allocator.free(arg_buf);564 allocator.free(arg_buf);
621 }565 }
622 allocator.free(argv_buf);566 allocator.free(argv_buf);
623 }567 }
624 for (argv) |arg, i| {568 for (argv_slice) |arg, i| {
625 const arg_buf = try allocator.alloc(u8, arg.len + 1);569 const arg_buf = try allocator.alloc(u8, arg.len + 1);
626 @memcpy(arg_buf.ptr, arg.ptr, arg.len);570 @memcpy(arg_buf.ptr, arg.ptr, arg.len);
627 arg_buf[arg.len] = 0;571 arg_buf[arg.len] = 0;
628572
629 argv_buf[i] = arg_buf.ptr;573 argv_buf[i] = arg_buf.ptr;
630 }574 }
631 argv_buf[argv.len] = null;575 argv_buf[argv_slice.len] = null;
632576
633 const envp_buf = try createNullDelimitedEnvMap(allocator, env_map);577 const envp_buf = try createNullDelimitedEnvMap(allocator, env_map);
634 defer freeNullDelimitedEnvMap(allocator, envp_buf);578 defer freeNullDelimitedEnvMap(allocator, envp_buf);
635579
636 const exe_path = argv[0];580 const exe_path = argv_slice[0];
637 if (mem.indexOfScalar(u8, exe_path, '/') != null) {581 if (mem.indexOfScalar(u8, exe_path, '/') != null) {
638 return posixExecveErrnoToErr(posix.getErrno(posix.execve(argv_buf[0].?, argv_buf.ptr, envp_buf.ptr)));582 return execveErrnoToErr(errno(system.execve(argv_buf[0].?, argv_buf.ptr, envp_buf.ptr)));
639 }583 }
640584
641 const PATH = getEnvPosix("PATH") orelse "/usr/local/bin:/bin/:/usr/bin";585 const PATH = getenv("PATH") orelse "/usr/local/bin:/bin/:/usr/bin";
642 // PATH.len because it is >= the largest search_path586 // PATH.len because it is >= the largest search_path
643 // +1 for the / to join the search path and exe_path587 // +1 for the / to join the search path and exe_path
644 // +1 for the null terminating byte588 // +1 for the null terminating byte
...@@ -652,21 +596,52 @@ pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator:...@@ -652,21 +596,52 @@ pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator:
652 path_buf[search_path.len] = '/';596 path_buf[search_path.len] = '/';
653 mem.copy(u8, path_buf[search_path.len + 1 ..], exe_path);597 mem.copy(u8, path_buf[search_path.len + 1 ..], exe_path);
654 path_buf[search_path.len + exe_path.len + 1] = 0;598 path_buf[search_path.len + exe_path.len + 1] = 0;
655 err = posix.getErrno(posix.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr));599 err = errno(system.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr));
656 assert(err > 0);600 assert(err > 0);
657 if (err == posix.EACCES) {601 if (err == EACCES) {
658 seen_eacces = true;602 seen_eacces = true;
659 } else if (err != posix.ENOENT) {603 } else if (err != ENOENT) {
660 return posixExecveErrnoToErr(err);604 return execveErrnoToErr(err);
661 }605 }
662 }606 }
663 if (seen_eacces) {607 if (seen_eacces) {
664 err = posix.EACCES;608 err = EACCES;
609 }
610 return execveErrnoToErr(err);
611}
612
613pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.BufMap) ![]?[*]u8 {
614 const envp_count = env_map.count();
615 const envp_buf = try allocator.alloc(?[*]u8, envp_count + 1);
616 mem.set(?[*]u8, envp_buf, null);
617 errdefer freeNullDelimitedEnvMap(allocator, envp_buf);
618 {
619 var it = env_map.iterator();
620 var i: usize = 0;
621 while (it.next()) |pair| : (i += 1) {
622 const env_buf = try allocator.alloc(u8, pair.key.len + pair.value.len + 2);
623 @memcpy(env_buf.ptr, pair.key.ptr, pair.key.len);
624 env_buf[pair.key.len] = '=';
625 @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len);
626 env_buf[env_buf.len - 1] = 0;
627
628 envp_buf[i] = env_buf.ptr;
629 }
630 assert(i == envp_count);
631 }
632 assert(envp_buf[envp_count] == null);
633 return envp_buf;
634}
635
636pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*]u8) void {
637 for (envp_buf) |env| {
638 const env_buf = if (env) |ptr| ptr[0 .. mem.len(u8, ptr) + 1] else break;
639 allocator.free(env_buf);
665 }640 }
666 return posixExecveErrnoToErr(err);641 allocator.free(envp_buf);
667}642}
668643
669pub const PosixExecveError = error{644pub const ExecveError = error{
670 SystemResources,645 SystemResources,
671 AccessDenied,646 AccessDenied,
672 InvalidExe,647 InvalidExe,
...@@ -675,1840 +650,599 @@ pub const PosixExecveError = error{...@@ -675,1840 +650,599 @@ pub const PosixExecveError = error{
675 FileNotFound,650 FileNotFound,
676 NotDir,651 NotDir,
677 FileBusy,652 FileBusy,
653 ProcessFdQuotaExceeded,
654 SystemFdQuotaExceeded,
655 NameTooLong,
678656
679 /// See https://github.com/ziglang/zig/issues/1396
680 Unexpected,657 Unexpected,
681};658};
682659
683fn posixExecveErrnoToErr(err: usize) PosixExecveError {660fn execveErrnoToErr(err: usize) ExecveError {
684 assert(err > 0);661 assert(err > 0);
685 switch (err) {662 switch (err) {
686 posix.EFAULT => unreachable,663 EFAULT => unreachable,
687 posix.E2BIG => return error.SystemResources,664 E2BIG => return error.SystemResources,
688 posix.EMFILE => return error.SystemResources,665 EMFILE => return error.ProcessFdQuotaExceeded,
689 posix.ENAMETOOLONG => return error.SystemResources,666 ENAMETOOLONG => return error.NameTooLong,
690 posix.ENFILE => return error.SystemResources,667 ENFILE => return error.SystemFdQuotaExceeded,
691 posix.ENOMEM => return error.SystemResources,668 ENOMEM => return error.SystemResources,
692 posix.EACCES => return error.AccessDenied,669 EACCES => return error.AccessDenied,
693 posix.EPERM => return error.AccessDenied,670 EPERM => return error.AccessDenied,
694 posix.EINVAL => return error.InvalidExe,671 EINVAL => return error.InvalidExe,
695 posix.ENOEXEC => return error.InvalidExe,672 ENOEXEC => return error.InvalidExe,
696 posix.EIO => return error.FileSystem,673 EIO => return error.FileSystem,
697 posix.ELOOP => return error.FileSystem,674 ELOOP => return error.FileSystem,
698 posix.EISDIR => return error.IsDir,675 EISDIR => return error.IsDir,
699 posix.ENOENT => return error.FileNotFound,676 ENOENT => return error.FileNotFound,
700 posix.ENOTDIR => return error.NotDir,677 ENOTDIR => return error.NotDir,
701 posix.ETXTBSY => return error.FileBusy,678 ETXTBSY => return error.FileBusy,
702 else => return unexpectedErrorPosix(err),679 else => return unexpectedErrno(err),
703 }680 }
704}681}
705682
706pub var linux_elf_aux_maybe: ?[*]std.elf.Auxv = null;683/// Get an environment variable.
707pub var posix_environ_raw: [][*]u8 = undefined;684/// See also `getenvC`.
708685/// TODO make this go through libc when we have it
709/// See std.elf for the constants.686pub fn getenv(key: []const u8) ?[]const u8 {
710pub fn linuxGetAuxVal(index: usize) usize {687 for (environ) |ptr| {
711 if (builtin.link_libc) {688 var line_i: usize = 0;
712 return usize(std.c.getauxval(index));689 while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
713 } else if (linux_elf_aux_maybe) |auxv| {690 const this_key = ptr[0..line_i];
714 var i: usize = 0;691 if (!mem.eql(u8, key, this_key)) continue;
715 while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) {692
716 if (auxv[i].a_type == index)693 var end_i: usize = line_i;
717 return auxv[i].a_un.a_val;694 while (ptr[end_i] != 0) : (end_i += 1) {}
718 }695 const this_value = ptr[line_i + 1 .. end_i];
696
697 return this_value;
719 }698 }
720 return 0;699 return null;
721}700}
722701
723pub fn getBaseAddress() usize {702/// Get an environment variable with a null-terminated name.
724 switch (builtin.os) {703/// See also `getenv`.
725 builtin.Os.linux => {704/// TODO https://github.com/ziglang/zig/issues/265
726 const base = linuxGetAuxVal(std.elf.AT_BASE);705pub fn getenvC(key: [*]const u8) ?[]const u8 {
727 if (base != 0) {706 if (builtin.link_libc) {
728 return base;707 const value = system.getenv(key) orelse return null;
729 }708 return mem.toSliceConst(u8, value);
730 const phdr = linuxGetAuxVal(std.elf.AT_PHDR);
731 return phdr - @sizeOf(std.elf.Ehdr);
732 },
733 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {
734 return @ptrToInt(&std.c._mh_execute_header);
735 },
736 builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)),
737 else => @compileError("Unsupported OS"),
738 }709 }
710 return getenv(mem.toSliceConst(u8, key));
739}711}
740712
741/// Caller must free result when done.713pub const GetCwdError = error{
742/// TODO make this go through libc when we have it714 NameTooLong,
743pub fn getEnvMap(allocator: *Allocator) !BufMap {715 CurrentWorkingDirectoryUnlinked,
744 var result = BufMap.init(allocator);716 Unexpected,
745 errdefer result.deinit();717};
746
747 if (is_windows) {
748 const ptr = windows.GetEnvironmentStringsW() orelse return error.OutOfMemory;
749 defer assert(windows.FreeEnvironmentStringsW(ptr) != 0);
750
751 var i: usize = 0;
752 while (true) {
753 if (ptr[i] == 0) return result;
754
755 const key_start = i;
756
757 while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
758 const key_w = ptr[key_start..i];
759 const key = try std.unicode.utf16leToUtf8Alloc(allocator, key_w);
760 errdefer allocator.free(key);
761718
762 if (ptr[i] == '=') i += 1;719/// The result is a slice of out_buffer, indexed from 0.
720pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 {
721 if (windows.is_the_target) {
722 return windows.GetCurrentDirectory(out_buffer);
723 }
763724
764 const value_start = i;725 const err = if (builtin.link_libc) blk: {
765 while (ptr[i] != 0) : (i += 1) {}726 break :blk if (std.c.getcwd(out_buffer.ptr, out_buffer.len)) |_| 0 else std.c._errno().*;
766 const value_w = ptr[value_start..i];727 } else blk: {
767 const value = try std.unicode.utf16leToUtf8Alloc(allocator, value_w);728 break :blk errno(system.getcwd(out_buffer.ptr, out_buffer.len));
768 errdefer allocator.free(value);729 };
730 switch (err) {
731 0 => return mem.toSlice(u8, out_buffer.ptr),
732 EFAULT => unreachable,
733 EINVAL => unreachable,
734 ENOENT => return error.CurrentWorkingDirectoryUnlinked,
735 ERANGE => return error.NameTooLong,
736 else => return unexpectedErrno(@intCast(usize, err)),
737 }
738}
769739
770 i += 1; // skip over null byte740pub const SymLinkError = error{
771741 AccessDenied,
772 try result.setMove(key, value);742 DiskQuota,
773 }743 PathAlreadyExists,
774 } else if (builtin.os == Os.wasi) {744 FileSystem,
775 var environ_count: usize = undefined;745 SymLinkLoop,
776 var environ_buf_size: usize = undefined;746 FileNotFound,
777747 SystemResources,
778 const environ_sizes_get_ret = std.os.wasi.environ_sizes_get(&environ_count, &environ_buf_size);748 NoSpaceLeft,
779 if (environ_sizes_get_ret != os.wasi.ESUCCESS) {749 ReadOnlyFileSystem,
780 return unexpectedErrorPosix(environ_sizes_get_ret);750 NotDir,
781 }751 NameTooLong,
782
783 // TODO: Verify that the documentation is incorrect
784 // https://github.com/WebAssembly/WASI/issues/27
785 var environ = try allocator.alloc(?[*]u8, environ_count + 1);
786 defer allocator.free(environ);
787 var environ_buf = try std.heap.wasm_allocator.alloc(u8, environ_buf_size);
788 defer allocator.free(environ_buf);
789
790 const environ_get_ret = std.os.wasi.environ_get(environ.ptr, environ_buf.ptr);
791 if (environ_get_ret != os.wasi.ESUCCESS) {
792 return unexpectedErrorPosix(environ_get_ret);
793 }
794
795 for (environ) |env| {
796 if (env) |ptr| {
797 const pair = mem.toSlice(u8, ptr);
798 var parts = mem.separate(pair, "=");
799 const key = parts.next().?;
800 const value = parts.next().?;
801 try result.set(key, value);
802 }
803 }
804 return result;
805 } else {
806 for (posix_environ_raw) |ptr| {
807 var line_i: usize = 0;
808 while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
809 const key = ptr[0..line_i];
810
811 var end_i: usize = line_i;
812 while (ptr[end_i] != 0) : (end_i += 1) {}
813 const value = ptr[line_i + 1 .. end_i];
814
815 try result.set(key, value);
816 }
817 return result;
818 }
819}
820
821test "os.getEnvMap" {
822 var env = try getEnvMap(std.debug.global_allocator);
823 defer env.deinit();
824}
825
826/// TODO make this go through libc when we have it
827pub fn getEnvPosix(key: []const u8) ?[]const u8 {
828 for (posix_environ_raw) |ptr| {
829 var line_i: usize = 0;
830 while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
831 const this_key = ptr[0..line_i];
832 if (!mem.eql(u8, key, this_key)) continue;
833
834 var end_i: usize = line_i;
835 while (ptr[end_i] != 0) : (end_i += 1) {}
836 const this_value = ptr[line_i + 1 .. end_i];
837
838 return this_value;
839 }
840 return null;
841}
842
843pub const GetEnvVarOwnedError = error{
844 OutOfMemory,
845 EnvironmentVariableNotFound,
846
847 /// See https://github.com/ziglang/zig/issues/1774
848 InvalidUtf8,752 InvalidUtf8,
753 BadPathName,
754 Unexpected,
849};755};
850756
851/// Caller must free returned memory.757/// Creates a symbolic link named `sym_link_path` which contains the string `target_path`.
852/// TODO make this go through libc when we have it758/// A symbolic link (also known as a soft link) may point to an existing file or to a nonexistent
853pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 {759/// one; the latter case is known as a dangling link.
854 if (is_windows) {760/// If `sym_link_path` exists, it will not be overwritten.
855 const key_with_null = try std.unicode.utf8ToUtf16LeWithNull(allocator, key);761/// See also `symlinkC` and `symlinkW`.
856 defer allocator.free(key_with_null);762pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!void {
857763 if (windows.is_the_target) {
858 var buf = try allocator.alloc(u16, 256);764 const target_path_w = try windows.sliceToPrefixedFileW(target_path);
859 defer allocator.free(buf);765 const sym_link_path_w = try windows.sliceToPrefixedFileW(sym_link_path);
860766 return windows.CreateSymbolicLinkW(&sym_link_path_w, &target_path_w, 0);
861 while (true) {
862 const windows_buf_len = math.cast(windows.DWORD, buf.len) catch return error.OutOfMemory;
863 const result = windows.GetEnvironmentVariableW(key_with_null.ptr, buf.ptr, windows_buf_len);
864
865 if (result == 0) {
866 const err = windows.GetLastError();
867 return switch (err) {
868 windows.ERROR.ENVVAR_NOT_FOUND => error.EnvironmentVariableNotFound,
869 else => {
870 unexpectedErrorWindows(err) catch {};
871 return error.EnvironmentVariableNotFound;
872 },
873 };
874 }
875
876 if (result > buf.len) {
877 buf = try allocator.realloc(buf, result);
878 continue;
879 }
880
881 return std.unicode.utf16leToUtf8Alloc(allocator, buf) catch |err| switch (err) {
882 error.DanglingSurrogateHalf => return error.InvalidUtf8,
883 error.ExpectedSecondSurrogateHalf => return error.InvalidUtf8,
884 error.UnexpectedSecondSurrogateHalf => return error.InvalidUtf8,
885 error.OutOfMemory => return error.OutOfMemory,
886 };
887 }
888 } else {767 } else {
889 const result = getEnvPosix(key) orelse return error.EnvironmentVariableNotFound;768 const target_path_c = try toPosixPath(target_path);
890 return mem.dupe(allocator, u8, result);769 const sym_link_path_c = try toPosixPath(sym_link_path);
770 return symlinkC(&target_path_c, &sym_link_path_c);
891 }771 }
892}772}
893773
894test "os.getEnvVarOwned" {774/// This is the same as `symlink` except the parameters are null-terminated pointers.
895 var ga = debug.global_allocator;775/// See also `symlink`.
896 testing.expectError(error.EnvironmentVariableNotFound, getEnvVarOwned(ga, "BADENV"));776pub fn symlinkC(target_path: [*]const u8, sym_link_path: [*]const u8) SymLinkError!void {
897}777 if (windows.is_the_target) {
898778 const target_path_w = try windows.cStrToPrefixedFileW(target_path);
899/// Caller must free the returned memory.779 const sym_link_path_w = try windows.cStrToPrefixedFileW(sym_link_path);
900pub fn getCwdAlloc(allocator: *Allocator) ![]u8 {780 return windows.CreateSymbolicLinkW(&sym_link_path_w, &target_path_w, 0);
901 var buf: [MAX_PATH_BYTES]u8 = undefined;
902 return mem.dupe(allocator, u8, try getCwd(&buf));
903}
904
905pub const GetCwdError = error{Unexpected};
906
907/// The result is a slice of out_buffer.
908pub fn getCwd(out_buffer: *[MAX_PATH_BYTES]u8) GetCwdError![]u8 {
909 switch (builtin.os) {
910 Os.windows => {
911 var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
912 const casted_len = @intCast(windows.DWORD, utf16le_buf.len); // TODO shouldn't need this cast
913 const casted_ptr = ([*]u16)(&utf16le_buf); // TODO shouldn't need this cast
914 const result = windows.GetCurrentDirectoryW(casted_len, casted_ptr);
915 if (result == 0) {
916 const err = windows.GetLastError();
917 switch (err) {
918 else => return unexpectedErrorWindows(err),
919 }
920 }
921 assert(result <= utf16le_buf.len);
922 const utf16le_slice = utf16le_buf[0..result];
923 // Trust that Windows gives us valid UTF-16LE.
924 const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
925 return out_buffer[0..end_index];
926 },
927 else => {
928 const err = posix.getErrno(posix.getcwd(out_buffer, out_buffer.len));
929 switch (err) {
930 0 => return cstr.toSlice(out_buffer),
931 posix.ERANGE => unreachable,
932 else => return unexpectedErrorPosix(err),
933 }
934 },
935 }781 }
936}782 switch (errno(system.symlink(target_path, sym_link_path))) {
783 0 => return,
784 EFAULT => unreachable,
785 EINVAL => unreachable,
786 EACCES => return error.AccessDenied,
787 EPERM => return error.AccessDenied,
788 EDQUOT => return error.DiskQuota,
789 EEXIST => return error.PathAlreadyExists,
790 EIO => return error.FileSystem,
791 ELOOP => return error.SymLinkLoop,
792 ENAMETOOLONG => return error.NameTooLong,
793 ENOENT => return error.FileNotFound,
794 ENOTDIR => return error.NotDir,
795 ENOMEM => return error.SystemResources,
796 ENOSPC => return error.NoSpaceLeft,
797 EROFS => return error.ReadOnlyFileSystem,
798 else => |err| return unexpectedErrno(err),
799 }
800}
801
802pub fn symlinkat(target_path: []const u8, newdirfd: fd_t, sym_link_path: []const u8) SymLinkError!void {
803 const target_path_c = try toPosixPath(target_path);
804 const sym_link_path_c = try toPosixPath(sym_link_path);
805 return symlinkatC(target_path_c, newdirfd, sym_link_path_c);
806}
807
808pub fn symlinkatC(target_path: [*]const u8, newdirfd: fd_t, sym_link_path: [*]const u8) SymLinkError!void {
809 switch (errno(system.symlinkat(target_path, newdirfd, sym_link_path))) {
810 0 => return,
811 EFAULT => unreachable,
812 EINVAL => unreachable,
813 EACCES => return error.AccessDenied,
814 EPERM => return error.AccessDenied,
815 EDQUOT => return error.DiskQuota,
816 EEXIST => return error.PathAlreadyExists,
817 EIO => return error.FileSystem,
818 ELOOP => return error.SymLinkLoop,
819 ENAMETOOLONG => return error.NameTooLong,
820 ENOENT => return error.FileNotFound,
821 ENOTDIR => return error.NotDir,
822 ENOMEM => return error.SystemResources,
823 ENOSPC => return error.NoSpaceLeft,
824 EROFS => return error.ReadOnlyFileSystem,
825 else => |err| return unexpectedErrno(err),
826 }
827}
828
829pub const UnlinkError = error{
830 FileNotFound,
831 AccessDenied,
832 FileBusy,
833 FileSystem,
834 IsDir,
835 SymLinkLoop,
836 NameTooLong,
837 NotDir,
838 SystemResources,
839 ReadOnlyFileSystem,
840 Unexpected,
937841
938test "os.getCwd" {842 /// On Windows, file paths must be valid Unicode.
939 // at least call it so it gets compiled843 InvalidUtf8,
940 _ = getCwdAlloc(debug.global_allocator) catch undefined;
941 var buf: [MAX_PATH_BYTES]u8 = undefined;
942 _ = getCwd(&buf) catch undefined;
943}
944844
945pub const SymLinkError = PosixSymLinkError || WindowsSymLinkError;845 /// On Windows, file paths cannot contain these characters:
846 /// '/', '*', '?', '"', '<', '>', '|'
847 BadPathName,
848};
946849
947/// TODO add a symLinkC variant850/// Delete a name and possibly the file it refers to.
948pub fn symLink(existing_path: []const u8, new_path: []const u8) SymLinkError!void {851/// See also `unlinkC`.
949 if (is_windows) {852pub fn unlink(file_path: []const u8) UnlinkError!void {
950 return symLinkWindows(existing_path, new_path);853 if (windows.is_the_target) {
854 const file_path_w = try windows.sliceToPrefixedFileW(file_path);
855 return windows.DeleteFileW(&file_path_w);
951 } else {856 } else {
952 return symLinkPosix(existing_path, new_path);857 const file_path_c = try toPosixPath(file_path);
858 return unlinkC(&file_path_c);
953 }859 }
954}860}
955861
956pub const WindowsSymLinkError = error{862/// Same as `unlink` except the parameter is a null terminated UTF8-encoded string.
863pub fn unlinkC(file_path: [*]const u8) UnlinkError!void {
864 if (windows.is_the_target) {
865 const file_path_w = try windows.cStrToPrefixedFileW(file_path);
866 return windows.DeleteFileW(&file_path_w);
867 }
868 switch (errno(system.unlink(file_path))) {
869 0 => return,
870 EACCES => return error.AccessDenied,
871 EPERM => return error.AccessDenied,
872 EBUSY => return error.FileBusy,
873 EFAULT => unreachable,
874 EINVAL => unreachable,
875 EIO => return error.FileSystem,
876 EISDIR => return error.IsDir,
877 ELOOP => return error.SymLinkLoop,
878 ENAMETOOLONG => return error.NameTooLong,
879 ENOENT => return error.FileNotFound,
880 ENOTDIR => return error.NotDir,
881 ENOMEM => return error.SystemResources,
882 EROFS => return error.ReadOnlyFileSystem,
883 else => |err| return unexpectedErrno(err),
884 }
885}
886
887const RenameError = error{
888 AccessDenied,
889 FileBusy,
890 DiskQuota,
891 IsDir,
892 SymLinkLoop,
893 LinkQuotaExceeded,
957 NameTooLong,894 NameTooLong,
895 FileNotFound,
896 NotDir,
897 SystemResources,
898 NoSpaceLeft,
899 PathAlreadyExists,
900 ReadOnlyFileSystem,
901 RenameAcrossMountPoints,
958 InvalidUtf8,902 InvalidUtf8,
959 BadPathName,903 BadPathName,
960
961 /// See https://github.com/ziglang/zig/issues/1396
962 Unexpected,904 Unexpected,
963};905};
964906
965pub fn symLinkW(existing_path_w: [*]const u16, new_path_w: [*]const u16) WindowsSymLinkError!void {907/// Change the name or location of a file.
966 if (windows.CreateSymbolicLinkW(existing_path_w, new_path_w, 0) == 0) {908pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void {
967 const err = windows.GetLastError();909 if (windows.is_the_target) {
968 switch (err) {910 const old_path_w = try windows.sliceToPrefixedFileW(old_path);
969 else => return unexpectedErrorWindows(err),911 const new_path_w = try windows.sliceToPrefixedFileW(new_path);
970 }912 return renameW(&old_path_w, &new_path_w);
913 } else {
914 const old_path_c = try toPosixPath(old_path);
915 const new_path_c = try toPosixPath(new_path);
916 return renameC(&old_path_c, &new_path_c);
971 }917 }
972}918}
973919
974pub fn symLinkWindows(existing_path: []const u8, new_path: []const u8) WindowsSymLinkError!void {920/// Same as `rename` except the parameters are null-terminated byte arrays.
975 const existing_path_w = try windows_util.sliceToPrefixedFileW(existing_path);921pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) RenameError!void {
976 const new_path_w = try windows_util.sliceToPrefixedFileW(new_path);922 if (windows.is_the_target) {
977 return symLinkW(&existing_path_w, &new_path_w);923 const old_path_w = try windows.cStrToPrefixedFileW(old_path);
924 const new_path_w = try windows.cStrToPrefixedFileW(new_path);
925 return renameW(&old_path_w, &new_path_w);
926 }
927 switch (errno(system.rename(old_path, new_path))) {
928 0 => return,
929 EACCES => return error.AccessDenied,
930 EPERM => return error.AccessDenied,
931 EBUSY => return error.FileBusy,
932 EDQUOT => return error.DiskQuota,
933 EFAULT => unreachable,
934 EINVAL => unreachable,
935 EISDIR => return error.IsDir,
936 ELOOP => return error.SymLinkLoop,
937 EMLINK => return error.LinkQuotaExceeded,
938 ENAMETOOLONG => return error.NameTooLong,
939 ENOENT => return error.FileNotFound,
940 ENOTDIR => return error.NotDir,
941 ENOMEM => return error.SystemResources,
942 ENOSPC => return error.NoSpaceLeft,
943 EEXIST => return error.PathAlreadyExists,
944 ENOTEMPTY => return error.PathAlreadyExists,
945 EROFS => return error.ReadOnlyFileSystem,
946 EXDEV => return error.RenameAcrossMountPoints,
947 else => |err| return unexpectedErrno(err),
948 }
949}
950
951/// Same as `rename` except the parameters are null-terminated UTF16LE encoded byte arrays.
952/// Assumes target is Windows.
953pub fn renameW(old_path: [*]const u16, new_path: [*]const u16) RenameError!void {
954 const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH;
955 return windows.MoveFileExW(old_path, new_path, flags);
978}956}
979957
980pub const PosixSymLinkError = error{958pub const MakeDirError = error{
981 AccessDenied,959 AccessDenied,
982 DiskQuota,960 DiskQuota,
983 PathAlreadyExists,961 PathAlreadyExists,
984 FileSystem,
985 SymLinkLoop,962 SymLinkLoop,
963 LinkQuotaExceeded,
986 NameTooLong,964 NameTooLong,
987 FileNotFound,965 FileNotFound,
988 SystemResources,966 SystemResources,
989 NoSpaceLeft,967 NoSpaceLeft,
990 ReadOnlyFileSystem,
991 NotDir,968 NotDir,
992969 ReadOnlyFileSystem,
993 /// See https://github.com/ziglang/zig/issues/1396970 InvalidUtf8,
971 BadPathName,
994 Unexpected,972 Unexpected,
995};973};
996974
997pub fn symLinkPosixC(existing_path: [*]const u8, new_path: [*]const u8) PosixSymLinkError!void {975/// Create a directory.
998 const err = posix.getErrno(posix.symlink(existing_path, new_path));976/// `mode` is ignored on Windows.
999 switch (err) {977pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void {
1000 0 => return,978 if (windows.is_the_target) {
1001 posix.EFAULT => unreachable,979 const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);
1002 posix.EINVAL => unreachable,980 return windows.CreateDirectoryW(&dir_path_w, null);
1003 posix.EACCES => return error.AccessDenied,981 } else {
1004 posix.EPERM => return error.AccessDenied,982 const dir_path_c = try toPosixPath(dir_path);
1005 posix.EDQUOT => return error.DiskQuota,983 return mkdirC(&dir_path_c, mode);
1006 posix.EEXIST => return error.PathAlreadyExists,
1007 posix.EIO => return error.FileSystem,
1008 posix.ELOOP => return error.SymLinkLoop,
1009 posix.ENAMETOOLONG => return error.NameTooLong,
1010 posix.ENOENT => return error.FileNotFound,
1011 posix.ENOTDIR => return error.NotDir,
1012 posix.ENOMEM => return error.SystemResources,
1013 posix.ENOSPC => return error.NoSpaceLeft,
1014 posix.EROFS => return error.ReadOnlyFileSystem,
1015 else => return unexpectedErrorPosix(err),
1016 }
1017}
1018
1019pub fn symLinkPosix(existing_path: []const u8, new_path: []const u8) PosixSymLinkError!void {
1020 const existing_path_c = try toPosixPath(existing_path);
1021 const new_path_c = try toPosixPath(new_path);
1022 return symLinkPosixC(&existing_path_c, &new_path_c);
1023}
1024
1025// here we replace the standard +/ with -_ so that it can be used in a file name
1026const b64_fs_encoder = base64.Base64Encoder.init("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", base64.standard_pad_char);
1027
1028/// TODO remove the allocator requirement from this API
1029pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) !void {
1030 if (symLink(existing_path, new_path)) {
1031 return;
1032 } else |err| switch (err) {
1033 error.PathAlreadyExists => {},
1034 else => return err, // TODO zig should know this set does not include PathAlreadyExists
1035 }984 }
985}
1036986
1037 const dirname = os.path.dirname(new_path) orelse ".";987/// Same as `mkdir` but the parameter is a null-terminated UTF8-encoded string.
1038988pub fn mkdirC(dir_path: [*]const u8, mode: u32) MakeDirError!void {
1039 var rand_buf: [12]u8 = undefined;989 if (windows.is_the_target) {
1040 const tmp_path = try allocator.alloc(u8, dirname.len + 1 + base64.Base64Encoder.calcSize(rand_buf.len));990 const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
1041 defer allocator.free(tmp_path);991 return windows.CreateDirectoryW(&dir_path_w, null);
1042 mem.copy(u8, tmp_path[0..], dirname);992 }
1043 tmp_path[dirname.len] = os.path.sep;993 switch (errno(system.mkdir(dir_path, mode))) {
1044 while (true) {994 0 => return,
1045 try getRandomBytes(rand_buf[0..]);995 EACCES => return error.AccessDenied,
1046 b64_fs_encoder.encode(tmp_path[dirname.len + 1 ..], rand_buf);996 EPERM => return error.AccessDenied,
1047997 EDQUOT => return error.DiskQuota,
1048 if (symLink(existing_path, tmp_path)) {998 EEXIST => return error.PathAlreadyExists,
1049 return rename(tmp_path, new_path);999 EFAULT => unreachable,
1050 } else |err| switch (err) {1000 ELOOP => return error.SymLinkLoop,
1051 error.PathAlreadyExists => continue,1001 EMLINK => return error.LinkQuotaExceeded,
1052 else => return err, // TODO zig should know this set does not include PathAlreadyExists1002 ENAMETOOLONG => return error.NameTooLong,
1053 }1003 ENOENT => return error.FileNotFound,
1004 ENOMEM => return error.SystemResources,
1005 ENOSPC => return error.NoSpaceLeft,
1006 ENOTDIR => return error.NotDir,
1007 EROFS => return error.ReadOnlyFileSystem,
1008 else => |err| return unexpectedErrno(err),
1054 }1009 }
1055}1010}
10561011
1057pub const DeleteFileError = error{1012pub const DeleteDirError = error{
1058 FileNotFound,
1059 AccessDenied,1013 AccessDenied,
1060 FileBusy,1014 FileBusy,
1061 FileSystem,
1062 IsDir,
1063 SymLinkLoop,1015 SymLinkLoop,
1064 NameTooLong,1016 NameTooLong,
1065 NotDir,1017 FileNotFound,
1066 SystemResources,1018 SystemResources,
1019 NotDir,
1020 DirNotEmpty,
1067 ReadOnlyFileSystem,1021 ReadOnlyFileSystem,
1068
1069 /// On Windows, file paths must be valid Unicode.
1070 InvalidUtf8,1022 InvalidUtf8,
1071
1072 /// On Windows, file paths cannot contain these characters:
1073 /// '/', '*', '?', '"', '<', '>', '|'
1074 BadPathName,1023 BadPathName,
1075
1076 /// See https://github.com/ziglang/zig/issues/1396
1077 Unexpected,1024 Unexpected,
1078};1025};
10791026
1080pub fn deleteFile(file_path: []const u8) DeleteFileError!void {1027/// Deletes an empty directory.
1081 if (builtin.os == Os.windows) {1028pub fn rmdir(dir_path: []const u8) DeleteDirError!void {
1082 const file_path_w = try windows_util.sliceToPrefixedFileW(file_path);1029 if (windows.is_the_target) {
1083 return deleteFileW(&file_path_w);1030 const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);
1031 return windows.RemoveDirectoryW(&dir_path_w);
1084 } else {1032 } else {
1085 const file_path_c = try toPosixPath(file_path);1033 const dir_path_c = try toPosixPath(dir_path);
1086 return deleteFileC(&file_path_c);1034 return rmdirC(&dir_path_c);
1087 }1035 }
1088}1036}
10891037
1090pub fn deleteFileW(file_path: [*]const u16) DeleteFileError!void {1038/// Same as `rmdir` except the parameter is null-terminated.
1091 if (windows.DeleteFileW(file_path) == 0) {1039pub fn rmdirC(dir_path: [*]const u8) DeleteDirError!void {
1092 const err = windows.GetLastError();1040 if (windows.is_the_target) {
1093 switch (err) {1041 const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
1094 windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,1042 return windows.RemoveDirectoryW(&dir_path_w);
1095 windows.ERROR.ACCESS_DENIED => return error.AccessDenied,
1096 windows.ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
1097 windows.ERROR.INVALID_PARAMETER => return error.NameTooLong,
1098 else => return unexpectedErrorWindows(err),
1099 }
1100 }1043 }
1101}1044 switch (errno(system.rmdir(dir_path))) {
1045 0 => return,
1046 EACCES => return error.AccessDenied,
1047 EPERM => return error.AccessDenied,
1048 EBUSY => return error.FileBusy,
1049 EFAULT => unreachable,
1050 EINVAL => unreachable,
1051 ELOOP => return error.SymLinkLoop,
1052 ENAMETOOLONG => return error.NameTooLong,
1053 ENOENT => return error.FileNotFound,
1054 ENOMEM => return error.SystemResources,
1055 ENOTDIR => return error.NotDir,
1056 EEXIST => return error.DirNotEmpty,
1057 ENOTEMPTY => return error.DirNotEmpty,
1058 EROFS => return error.ReadOnlyFileSystem,
1059 else => |err| return unexpectedErrno(err),
1060 }
1061}
1062
1063pub const ChangeCurDirError = error{
1064 AccessDenied,
1065 FileSystem,
1066 SymLinkLoop,
1067 NameTooLong,
1068 FileNotFound,
1069 SystemResources,
1070 NotDir,
1071 Unexpected,
1072};
11021073
1103pub fn deleteFileC(file_path: [*]const u8) DeleteFileError!void {1074/// Changes the current working directory of the calling process.
1104 if (is_windows) {1075/// `dir_path` is recommended to be a UTF-8 encoded string.
1105 const file_path_w = try windows_util.cStrToPrefixedFileW(file_path);1076pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
1106 return deleteFileW(&file_path_w);1077 if (windows.is_the_target) {
1078 const dir_path_w = try windows.sliceToPrefixedFileW(dir_path);
1079 @compileError("TODO implement chdir for Windows");
1107 } else {1080 } else {
1108 const err = posix.getErrno(posix.unlink(file_path));1081 const dir_path_c = try toPosixPath(dir_path);
1109 switch (err) {1082 return chdirC(&dir_path_c);
1110 0 => return,
1111 posix.EACCES => return error.AccessDenied,
1112 posix.EPERM => return error.AccessDenied,
1113 posix.EBUSY => return error.FileBusy,
1114 posix.EFAULT => unreachable,
1115 posix.EINVAL => unreachable,
1116 posix.EIO => return error.FileSystem,
1117 posix.EISDIR => return error.IsDir,
1118 posix.ELOOP => return error.SymLinkLoop,
1119 posix.ENAMETOOLONG => return error.NameTooLong,
1120 posix.ENOENT => return error.FileNotFound,
1121 posix.ENOTDIR => return error.NotDir,
1122 posix.ENOMEM => return error.SystemResources,
1123 posix.EROFS => return error.ReadOnlyFileSystem,
1124 else => return unexpectedErrorPosix(err),
1125 }
1126 }1083 }
1127}1084}
11281085
1129/// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is1086/// Same as `chdir` except the parameter is null-terminated.
1130/// merged and readily available,1087pub fn chdirC(dir_path: [*]const u8) ChangeCurDirError!void {
1131/// there is a possibility of power loss or application termination leaving temporary files present1088 if (windows.is_the_target) {
1132/// in the same directory as dest_path.1089 const dir_path_w = try windows.cStrToPrefixedFileW(dir_path);
1133/// Destination file will have the same mode as the source file.1090 @compileError("TODO implement chdir for Windows");
1134pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void {1091 }
1135 var in_file = try os.File.openRead(source_path);1092 switch (errno(system.chdir(dir_path))) {
1136 defer in_file.close();1093 0 => return,
11371094 EACCES => return error.AccessDenied,
1138 const mode = try in_file.mode();1095 EFAULT => unreachable,
1139 const in_stream = &in_file.inStream().stream;1096 EIO => return error.FileSystem,
11401097 ELOOP => return error.SymLinkLoop,
1141 var atomic_file = try AtomicFile.init(dest_path, mode);1098 ENAMETOOLONG => return error.NameTooLong,
1142 defer atomic_file.deinit();1099 ENOENT => return error.FileNotFound,
11431100 ENOMEM => return error.SystemResources,
1144 var buf: [page_size]u8 = undefined;1101 ENOTDIR => return error.NotDir,
1145 while (true) {1102 else => |err| return unexpectedErrno(err),
1146 const amt = try in_stream.readFull(buf[0..]);
1147 try atomic_file.file.write(buf[0..amt]);
1148 if (amt != buf.len) {
1149 return atomic_file.finish();
1150 }
1151 }1103 }
1152}1104}
11531105
1154/// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is1106pub const ReadLinkError = error{
1155/// merged and readily available,1107 AccessDenied,
1156/// there is a possibility of power loss or application termination leaving temporary files present1108 FileSystem,
1157pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void {1109 SymLinkLoop,
1158 var in_file = try os.File.openRead(source_path);1110 NameTooLong,
1159 defer in_file.close();1111 FileNotFound,
11601112 SystemResources,
1161 var atomic_file = try AtomicFile.init(dest_path, mode);1113 NotDir,
1162 defer atomic_file.deinit();1114 Unexpected,
1115};
11631116
1164 var buf: [page_size]u8 = undefined;1117/// Read value of a symbolic link.
1165 while (true) {1118/// The return value is a slice of `out_buffer` from index 0.
1166 const amt = try in_file.read(buf[0..]);1119pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 {
1167 try atomic_file.file.write(buf[0..amt]);1120 if (windows.is_the_target) {
1168 if (amt != buf.len) {1121 const file_path_w = try windows.sliceToPrefixedFileW(file_path);
1169 return atomic_file.finish();1122 @compileError("TODO implement readlink for Windows");
1170 }1123 } else {
1124 const file_path_c = try toPosixPath(file_path);
1125 return readlinkC(&file_path_c, out_buffer);
1171 }1126 }
1172}1127}
11731128
1174pub const AtomicFile = struct {1129/// Same as `readlink` except `file_path` is null-terminated.
1175 file: os.File,1130pub fn readlinkC(file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 {
1176 tmp_path_buf: [MAX_PATH_BYTES]u8,1131 if (windows.is_the_target) {
1177 dest_path: []const u8,1132 const file_path_w = try windows.cStrToPrefixedFileW(file_path);
1178 finished: bool,1133 @compileError("TODO implement readlink for Windows");
1179
1180 const InitError = os.File.OpenError;
1181
1182 /// dest_path must remain valid for the lifetime of AtomicFile
1183 /// call finish to atomically replace dest_path with contents
1184 /// TODO once we have null terminated pointers, use the
1185 /// openWriteNoClobberN function
1186 pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile {
1187 const dirname = os.path.dirname(dest_path);
1188 var rand_buf: [12]u8 = undefined;
1189 const dirname_component_len = if (dirname) |d| d.len + 1 else 0;
1190 const encoded_rand_len = comptime base64.Base64Encoder.calcSize(rand_buf.len);
1191 const tmp_path_len = dirname_component_len + encoded_rand_len;
1192 var tmp_path_buf: [MAX_PATH_BYTES]u8 = undefined;
1193 if (tmp_path_len >= tmp_path_buf.len) return error.NameTooLong;
1194
1195 if (dirname) |dir| {
1196 mem.copy(u8, tmp_path_buf[0..], dir);
1197 tmp_path_buf[dir.len] = os.path.sep;
1198 }
1199
1200 tmp_path_buf[tmp_path_len] = 0;
1201
1202 while (true) {
1203 try getRandomBytes(rand_buf[0..]);
1204 b64_fs_encoder.encode(tmp_path_buf[dirname_component_len..tmp_path_len], rand_buf);
1205
1206 const file = os.File.openWriteNoClobberC(&tmp_path_buf, mode) catch |err| switch (err) {
1207 error.PathAlreadyExists => continue,
1208 // TODO zig should figure out that this error set does not include PathAlreadyExists since
1209 // it is handled in the above switch
1210 else => return err,
1211 };
1212
1213 return AtomicFile{
1214 .file = file,
1215 .tmp_path_buf = tmp_path_buf,
1216 .dest_path = dest_path,
1217 .finished = false,
1218 };
1219 }
1220 }1134 }
12211135 const rc = system.readlink(file_path, out_buffer.ptr, out_buffer.len);
1222 /// always call deinit, even after successful finish()1136 switch (errno(rc)) {
1223 pub fn deinit(self: *AtomicFile) void {1137 0 => return out_buffer[0..@bitCast(usize, rc)],
1224 if (!self.finished) {1138 EACCES => return error.AccessDenied,
1225 self.file.close();1139 EFAULT => unreachable,
1226 deleteFileC(&self.tmp_path_buf) catch {};1140 EINVAL => unreachable,
1227 self.finished = true;1141 EIO => return error.FileSystem,
1228 }1142 ELOOP => return error.SymLinkLoop,
1143 ENAMETOOLONG => return error.NameTooLong,
1144 ENOENT => return error.FileNotFound,
1145 ENOMEM => return error.SystemResources,
1146 ENOTDIR => return error.NotDir,
1147 else => |err| return unexpectedErrno(err),
1229 }1148 }
1149}
12301150
1231 pub fn finish(self: *AtomicFile) !void {1151pub const SetIdError = error{
1232 assert(!self.finished);1152 ResourceLimitReached,
1233 self.file.close();1153 InvalidUserId,
1234 self.finished = true;1154 PermissionDenied,
1235 if (is_posix) {1155 Unexpected,
1236 const dest_path_c = try toPosixPath(self.dest_path);
1237 return renameC(&self.tmp_path_buf, &dest_path_c);
1238 } else if (is_windows) {
1239 const dest_path_w = try windows_util.sliceToPrefixedFileW(self.dest_path);
1240 const tmp_path_w = try windows_util.cStrToPrefixedFileW(&self.tmp_path_buf);
1241 return renameW(&tmp_path_w, &dest_path_w);
1242 } else {
1243 @compileError("Unsupported OS");
1244 }
1245 }
1246};1156};
12471157
1248pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) !void {1158pub fn setuid(uid: u32) SetIdError!void {
1249 if (is_windows) {1159 switch (errno(system.setuid(uid))) {
1250 const old_path_w = try windows_util.cStrToPrefixedFileW(old_path);1160 0 => return,
1251 const new_path_w = try windows_util.cStrToPrefixedFileW(new_path);1161 EAGAIN => return error.ResourceLimitReached,
1252 return renameW(&old_path_w, &new_path_w);1162 EINVAL => return error.InvalidUserId,
1253 } else {1163 EPERM => return error.PermissionDenied,
1254 const err = posix.getErrno(posix.rename(old_path, new_path));1164 else => |err| return unexpectedErrno(err),
1255 switch (err) {
1256 0 => return,
1257 posix.EACCES => return error.AccessDenied,
1258 posix.EPERM => return error.AccessDenied,
1259 posix.EBUSY => return error.FileBusy,
1260 posix.EDQUOT => return error.DiskQuota,
1261 posix.EFAULT => unreachable,
1262 posix.EINVAL => unreachable,
1263 posix.EISDIR => return error.IsDir,
1264 posix.ELOOP => return error.SymLinkLoop,
1265 posix.EMLINK => return error.LinkQuotaExceeded,
1266 posix.ENAMETOOLONG => return error.NameTooLong,
1267 posix.ENOENT => return error.FileNotFound,
1268 posix.ENOTDIR => return error.NotDir,
1269 posix.ENOMEM => return error.SystemResources,
1270 posix.ENOSPC => return error.NoSpaceLeft,
1271 posix.EEXIST => return error.PathAlreadyExists,
1272 posix.ENOTEMPTY => return error.PathAlreadyExists,
1273 posix.EROFS => return error.ReadOnlyFileSystem,
1274 posix.EXDEV => return error.RenameAcrossMountPoints,
1275 else => return unexpectedErrorPosix(err),
1276 }
1277 }1165 }
1278}1166}
12791167
1280pub fn renameW(old_path: [*]const u16, new_path: [*]const u16) !void {1168pub fn setreuid(ruid: u32, euid: u32) SetIdError!void {
1281 const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH;1169 switch (errno(system.setreuid(ruid, euid))) {
1282 if (windows.MoveFileExW(old_path, new_path, flags) == 0) {1170 0 => return,
1283 const err = windows.GetLastError();1171 EAGAIN => return error.ResourceLimitReached,
1284 switch (err) {1172 EINVAL => return error.InvalidUserId,
1285 else => return unexpectedErrorWindows(err),1173 EPERM => return error.PermissionDenied,
1286 }1174 else => |err| return unexpectedErrno(err),
1287 }1175 }
1288}1176}
12891177
1290pub fn rename(old_path: []const u8, new_path: []const u8) !void {1178pub fn setgid(gid: u32) SetIdError!void {
1291 if (is_windows) {1179 switch (errno(system.setgid(gid))) {
1292 const old_path_w = try windows_util.sliceToPrefixedFileW(old_path);1180 0 => return,
1293 const new_path_w = try windows_util.sliceToPrefixedFileW(new_path);1181 EAGAIN => return error.ResourceLimitReached,
1294 return renameW(&old_path_w, &new_path_w);1182 EINVAL => return error.InvalidUserId,
1295 } else {1183 EPERM => return error.PermissionDenied,
1296 const old_path_c = try toPosixPath(old_path);1184 else => |err| return unexpectedErrno(err),
1297 const new_path_c = try toPosixPath(new_path);
1298 return renameC(&old_path_c, &new_path_c);
1299 }1185 }
1300}1186}
13011187
1302pub fn makeDir(dir_path: []const u8) !void {1188pub fn setregid(rgid: u32, egid: u32) SetIdError!void {
1303 if (is_windows) {1189 switch (errno(system.setregid(rgid, egid))) {
1304 return makeDirWindows(dir_path);1190 0 => return,
1305 } else {1191 EAGAIN => return error.ResourceLimitReached,
1306 return makeDirPosix(dir_path);1192 EINVAL => return error.InvalidUserId,
1193 EPERM => return error.PermissionDenied,
1194 else => |err| return unexpectedErrno(err),
1307 }1195 }
1308}1196}
13091197
1310pub fn makeDirWindows(dir_path: []const u8) !void {1198/// Test whether a file descriptor refers to a terminal.
1311 const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path);1199pub fn isatty(handle: fd_t) bool {
1200 if (windows.is_the_target) {
1201 if (isCygwinPty(handle))
1202 return true;
13121203
1313 if (windows.CreateDirectoryW(&dir_path_w, null) == 0) {1204 var out: windows.DWORD = undefined;
1314 const err = windows.GetLastError();1205 return windows.kernel32.GetConsoleMode(handle, &out) != 0;
1315 return switch (err) {
1316 windows.ERROR.ALREADY_EXISTS => error.PathAlreadyExists,
1317 windows.ERROR.PATH_NOT_FOUND => error.FileNotFound,
1318 else => unexpectedErrorWindows(err),
1319 };
1320 }1206 }
1321}1207 if (builtin.link_libc) {
13221208 return system.isatty(handle) != 0;
1323pub fn makeDirPosixC(dir_path: [*]const u8) !void {
1324 const err = posix.getErrno(posix.mkdir(dir_path, 0o755));
1325 switch (err) {
1326 0 => return,
1327 posix.EACCES => return error.AccessDenied,
1328 posix.EPERM => return error.AccessDenied,
1329 posix.EDQUOT => return error.DiskQuota,
1330 posix.EEXIST => return error.PathAlreadyExists,
1331 posix.EFAULT => unreachable,
1332 posix.ELOOP => return error.SymLinkLoop,
1333 posix.EMLINK => return error.LinkQuotaExceeded,
1334 posix.ENAMETOOLONG => return error.NameTooLong,
1335 posix.ENOENT => return error.FileNotFound,
1336 posix.ENOMEM => return error.SystemResources,
1337 posix.ENOSPC => return error.NoSpaceLeft,
1338 posix.ENOTDIR => return error.NotDir,
1339 posix.EROFS => return error.ReadOnlyFileSystem,
1340 else => return unexpectedErrorPosix(err),
1341 }
1342}
1343
1344pub fn makeDirPosix(dir_path: []const u8) !void {
1345 const dir_path_c = try toPosixPath(dir_path);
1346 return makeDirPosixC(&dir_path_c);
1347}
1348
1349/// Calls makeDir recursively to make an entire path. Returns success if the path
1350/// already exists and is a directory.
1351/// TODO determine if we can remove the allocator requirement from this function
1352pub fn makePath(allocator: *Allocator, full_path: []const u8) !void {
1353 const resolved_path = try path.resolve(allocator, [][]const u8{full_path});
1354 defer allocator.free(resolved_path);
1355
1356 var end_index: usize = resolved_path.len;
1357 while (true) {
1358 makeDir(resolved_path[0..end_index]) catch |err| switch (err) {
1359 error.PathAlreadyExists => {
1360 // TODO stat the file and return an error if it's not a directory
1361 // this is important because otherwise a dangling symlink
1362 // could cause an infinite loop
1363 if (end_index == resolved_path.len) return;
1364 },
1365 error.FileNotFound => {
1366 // march end_index backward until next path component
1367 while (true) {
1368 end_index -= 1;
1369 if (os.path.isSep(resolved_path[end_index])) break;
1370 }
1371 continue;
1372 },
1373 else => return err,
1374 };
1375 if (end_index == resolved_path.len) return;
1376 // march end_index forward until next path component
1377 while (true) {
1378 end_index += 1;
1379 if (end_index == resolved_path.len or os.path.isSep(resolved_path[end_index])) break;
1380 }
1381 }1209 }
1210 if (wasi.is_the_target) {
1211 @compileError("TODO implement std.os.isatty for WASI");
1212 }
1213 if (linux.is_the_target) {
1214 var wsz: linux.winsize = undefined;
1215 return linux.syscall3(linux.SYS_ioctl, @bitCast(usize, isize(handle)), linux.TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
1216 }
1217 unreachable;
1382}1218}
13831219
1384pub const DeleteDirError = error{1220pub fn isCygwinPty(handle: fd_t) bool {
1385 AccessDenied,1221 if (!windows.is_the_target) return false;
1386 FileBusy,
1387 SymLinkLoop,
1388 NameTooLong,
1389 FileNotFound,
1390 SystemResources,
1391 NotDir,
1392 DirNotEmpty,
1393 ReadOnlyFileSystem,
1394 InvalidUtf8,
1395 BadPathName,
13961222
1397 /// See https://github.com/ziglang/zig/issues/13961223 const size = @sizeOf(windows.FILE_NAME_INFO);
1398 Unexpected,1224 var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = []u8{0} ** (size + windows.MAX_PATH);
1399};
14001225
1401pub fn deleteDirC(dir_path: [*]const u8) DeleteDirError!void {1226 if (windows.kernel32.GetFileInformationByHandleEx(
1402 switch (builtin.os) {1227 handle,
1403 Os.windows => {1228 windows.FileNameInfo,
1404 const dir_path_w = try windows_util.cStrToPrefixedFileW(dir_path);1229 @ptrCast(*c_void, &name_info_bytes),
1405 return deleteDirW(&dir_path_w);1230 name_info_bytes.len,
1406 },1231 ) == 0) {
1407 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {1232 return false;
1408 const err = posix.getErrno(posix.rmdir(dir_path));
1409 switch (err) {
1410 0 => return,
1411 posix.EACCES => return error.AccessDenied,
1412 posix.EPERM => return error.AccessDenied,
1413 posix.EBUSY => return error.FileBusy,
1414 posix.EFAULT => unreachable,
1415 posix.EINVAL => unreachable,
1416 posix.ELOOP => return error.SymLinkLoop,
1417 posix.ENAMETOOLONG => return error.NameTooLong,
1418 posix.ENOENT => return error.FileNotFound,
1419 posix.ENOMEM => return error.SystemResources,
1420 posix.ENOTDIR => return error.NotDir,
1421 posix.EEXIST => return error.DirNotEmpty,
1422 posix.ENOTEMPTY => return error.DirNotEmpty,
1423 posix.EROFS => return error.ReadOnlyFileSystem,
1424 else => return unexpectedErrorPosix(err),
1425 }
1426 },
1427 else => @compileError("unimplemented"),
1428 }1233 }
1429}
14301234
1431pub fn deleteDirW(dir_path_w: [*]const u16) DeleteDirError!void {1235 const name_info = @ptrCast(*const windows.FILE_NAME_INFO, &name_info_bytes[0]);
1432 if (windows.RemoveDirectoryW(dir_path_w) == 0) {1236 const name_bytes = name_info_bytes[size .. size + usize(name_info.FileNameLength)];
1433 const err = windows.GetLastError();1237 const name_wide = @bytesToSlice(u16, name_bytes);
1434 switch (err) {1238 return mem.indexOf(u16, name_wide, []u16{ 'm', 's', 'y', 's', '-' }) != null or
1435 windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,1239 mem.indexOf(u16, name_wide, []u16{ '-', 'p', 't', 'y' }) != null;
1436 windows.ERROR.DIR_NOT_EMPTY => return error.DirNotEmpty,
1437 else => return unexpectedErrorWindows(err),
1438 }
1439 }
1440}1240}
14411241
1442/// Returns ::error.DirNotEmpty if the directory is not empty.1242pub const SocketError = error{
1443/// To delete a directory recursively, see ::deleteTree1243 /// Permission to create a socket of the specified type and/or
1444pub fn deleteDir(dir_path: []const u8) DeleteDirError!void {1244 /// pro‐tocol is denied.
1445 switch (builtin.os) {1245 PermissionDenied,
1446 Os.windows => {
1447 const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path);
1448 return deleteDirW(&dir_path_w);
1449 },
1450 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
1451 const dir_path_c = try toPosixPath(dir_path);
1452 return deleteDirC(&dir_path_c);
1453 },
1454 else => @compileError("unimplemented"),
1455 }
1456}
1457
1458/// Whether ::full_path describes a symlink, file, or directory, this function
1459/// removes it. If it cannot be removed because it is a non-empty directory,
1460/// this function recursively removes its entries and then tries again.
1461const DeleteTreeError = error{
1462 OutOfMemory,
1463 AccessDenied,
1464 FileTooBig,
1465 IsDir,
1466 SymLinkLoop,
1467 ProcessFdQuotaExceeded,
1468 NameTooLong,
1469 SystemFdQuotaExceeded,
1470 NoDevice,
1471 SystemResources,
1472 NoSpaceLeft,
1473 PathAlreadyExists,
1474 ReadOnlyFileSystem,
1475 NotDir,
1476 FileNotFound,
1477 FileSystem,
1478 FileBusy,
1479 DirNotEmpty,
1480 DeviceBusy,
1481
1482 /// On Windows, file paths must be valid Unicode.
1483 InvalidUtf8,
1484
1485 /// On Windows, file paths cannot contain these characters:
1486 /// '/', '*', '?', '"', '<', '>', '|'
1487 BadPathName,
1488
1489 /// See https://github.com/ziglang/zig/issues/1396
1490 Unexpected,
1491};
1492
1493/// TODO determine if we can remove the allocator requirement
1494pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!void {
1495 start_over: while (true) {
1496 var got_access_denied = false;
1497 // First, try deleting the item as a file. This way we don't follow sym links.
1498 if (deleteFile(full_path)) {
1499 return;
1500 } else |err| switch (err) {
1501 error.FileNotFound => return,
1502 error.IsDir => {},
1503 error.AccessDenied => got_access_denied = true,
1504
1505 error.InvalidUtf8,
1506 error.SymLinkLoop,
1507 error.NameTooLong,
1508 error.SystemResources,
1509 error.ReadOnlyFileSystem,
1510 error.NotDir,
1511 error.FileSystem,
1512 error.FileBusy,
1513 error.BadPathName,
1514 error.Unexpected,
1515 => return err,
1516 }
1517 {
1518 var dir = Dir.open(allocator, full_path) catch |err| switch (err) {
1519 error.NotDir => {
1520 if (got_access_denied) {
1521 return error.AccessDenied;
1522 }
1523 continue :start_over;
1524 },
1525
1526 error.OutOfMemory,
1527 error.AccessDenied,
1528 error.FileTooBig,
1529 error.IsDir,
1530 error.SymLinkLoop,
1531 error.ProcessFdQuotaExceeded,
1532 error.NameTooLong,
1533 error.SystemFdQuotaExceeded,
1534 error.NoDevice,
1535 error.FileNotFound,
1536 error.SystemResources,
1537 error.NoSpaceLeft,
1538 error.PathAlreadyExists,
1539 error.Unexpected,
1540 error.InvalidUtf8,
1541 error.BadPathName,
1542 error.DeviceBusy,
1543 => return err,
1544 };
1545 defer dir.close();
1546
1547 var full_entry_buf = ArrayList(u8).init(allocator);
1548 defer full_entry_buf.deinit();
1549
1550 while (try dir.next()) |entry| {
1551 try full_entry_buf.resize(full_path.len + entry.name.len + 1);
1552 const full_entry_path = full_entry_buf.toSlice();
1553 mem.copy(u8, full_entry_path, full_path);
1554 full_entry_path[full_path.len] = path.sep;
1555 mem.copy(u8, full_entry_path[full_path.len + 1 ..], entry.name);
1556
1557 try deleteTree(allocator, full_entry_path);
1558 }
1559 }
1560 return deleteDir(full_path);
1561 }
1562}
1563
1564pub const Dir = struct {
1565 handle: Handle,
1566 allocator: *Allocator,
1567
1568 pub const Handle = switch (builtin.os) {
1569 Os.macosx, Os.ios, Os.freebsd, Os.netbsd => struct {
1570 fd: i32,
1571 seek: i64,
1572 buf: []u8,
1573 index: usize,
1574 end_index: usize,
1575 },
1576 Os.linux => struct {
1577 fd: i32,
1578 buf: []u8,
1579 index: usize,
1580 end_index: usize,
1581 },
1582 Os.windows => struct {
1583 handle: windows.HANDLE,
1584 find_file_data: windows.WIN32_FIND_DATAW,
1585 first: bool,
1586 name_data: [256]u8,
1587 },
1588 else => @compileError("unimplemented"),
1589 };
1590
1591 pub const Entry = struct {
1592 name: []const u8,
1593 kind: Kind,
1594
1595 pub const Kind = enum {
1596 BlockDevice,
1597 CharacterDevice,
1598 Directory,
1599 NamedPipe,
1600 SymLink,
1601 File,
1602 UnixDomainSocket,
1603 Whiteout,
1604 Unknown,
1605 };
1606 };
1607
1608 pub const OpenError = error{
1609 FileNotFound,
1610 NotDir,
1611 AccessDenied,
1612 FileTooBig,
1613 IsDir,
1614 SymLinkLoop,
1615 ProcessFdQuotaExceeded,
1616 NameTooLong,
1617 SystemFdQuotaExceeded,
1618 NoDevice,
1619 SystemResources,
1620 NoSpaceLeft,
1621 PathAlreadyExists,
1622 OutOfMemory,
1623 InvalidUtf8,
1624 BadPathName,
1625 DeviceBusy,
1626
1627 /// See https://github.com/ziglang/zig/issues/1396
1628 Unexpected,
1629 };
1630
1631 /// TODO remove the allocator requirement from this API
1632 pub fn open(allocator: *Allocator, dir_path: []const u8) OpenError!Dir {
1633 return Dir{
1634 .allocator = allocator,
1635 .handle = switch (builtin.os) {
1636 Os.windows => blk: {
1637 var find_file_data: windows.WIN32_FIND_DATAW = undefined;
1638 const handle = try windows_util.windowsFindFirstFile(dir_path, &find_file_data);
1639 break :blk Handle{
1640 .handle = handle,
1641 .find_file_data = find_file_data, // TODO guaranteed copy elision
1642 .first = true,
1643 .name_data = undefined,
1644 };
1645 },
1646 Os.macosx, Os.ios, Os.freebsd, Os.netbsd => Handle{
1647 .fd = try posixOpen(
1648 dir_path,
1649 posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC,
1650 0,
1651 ),
1652 .seek = 0,
1653 .index = 0,
1654 .end_index = 0,
1655 .buf = []u8{},
1656 },
1657 Os.linux => Handle{
1658 .fd = try posixOpen(
1659 dir_path,
1660 posix.O_RDONLY | posix.O_DIRECTORY | posix.O_CLOEXEC,
1661 0,
1662 ),
1663 .index = 0,
1664 .end_index = 0,
1665 .buf = []u8{},
1666 },
1667 else => @compileError("unimplemented"),
1668 },
1669 };
1670 }
1671
1672 pub fn close(self: *Dir) void {
1673 switch (builtin.os) {
1674 Os.windows => {
1675 _ = windows.FindClose(self.handle.handle);
1676 },
1677 Os.macosx, Os.ios, Os.linux, Os.freebsd, Os.netbsd => {
1678 self.allocator.free(self.handle.buf);
1679 os.close(self.handle.fd);
1680 },
1681 else => @compileError("unimplemented"),
1682 }
1683 }
1684
1685 /// Memory such as file names referenced in this returned entry becomes invalid
1686 /// with subsequent calls to next, as well as when this `Dir` is deinitialized.
1687 pub fn next(self: *Dir) !?Entry {
1688 switch (builtin.os) {
1689 Os.linux => return self.nextLinux(),
1690 Os.macosx, Os.ios => return self.nextDarwin(),
1691 Os.windows => return self.nextWindows(),
1692 Os.freebsd => return self.nextFreebsd(),
1693 Os.netbsd => return self.nextFreebsd(),
1694 else => @compileError("unimplemented"),
1695 }
1696 }
1697
1698 fn nextDarwin(self: *Dir) !?Entry {
1699 start_over: while (true) {
1700 if (self.handle.index >= self.handle.end_index) {
1701 if (self.handle.buf.len == 0) {
1702 self.handle.buf = try self.allocator.alloc(u8, page_size);
1703 }
1704
1705 while (true) {
1706 const result = posix.getdirentries64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len, &self.handle.seek);
1707 const err = posix.getErrno(result);
1708 if (err > 0) {
1709 switch (err) {
1710 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
1711 posix.EINVAL => {
1712 self.handle.buf = try self.allocator.realloc(self.handle.buf, self.handle.buf.len * 2);
1713 continue;
1714 },
1715 else => return unexpectedErrorPosix(err),
1716 }
1717 }
1718 if (result == 0) return null;
1719 self.handle.index = 0;
1720 self.handle.end_index = result;
1721 break;
1722 }
1723 }
1724 const darwin_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]);
1725 const next_index = self.handle.index + darwin_entry.d_reclen;
1726 self.handle.index = next_index;
1727
1728 const name = @ptrCast([*]u8, &darwin_entry.d_name)[0..darwin_entry.d_namlen];
1729
1730 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
1731 continue :start_over;
1732 }
1733
1734 const entry_kind = switch (darwin_entry.d_type) {
1735 posix.DT_BLK => Entry.Kind.BlockDevice,
1736 posix.DT_CHR => Entry.Kind.CharacterDevice,
1737 posix.DT_DIR => Entry.Kind.Directory,
1738 posix.DT_FIFO => Entry.Kind.NamedPipe,
1739 posix.DT_LNK => Entry.Kind.SymLink,
1740 posix.DT_REG => Entry.Kind.File,
1741 posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
1742 posix.DT_WHT => Entry.Kind.Whiteout,
1743 else => Entry.Kind.Unknown,
1744 };
1745 return Entry{
1746 .name = name,
1747 .kind = entry_kind,
1748 };
1749 }
1750 }
1751
1752 fn nextWindows(self: *Dir) !?Entry {
1753 while (true) {
1754 if (self.handle.first) {
1755 self.handle.first = false;
1756 } else {
1757 if (!try windows_util.windowsFindNextFile(self.handle.handle, &self.handle.find_file_data))
1758 return null;
1759 }
1760 const name_utf16le = mem.toSlice(u16, self.handle.find_file_data.cFileName[0..].ptr);
1761 if (mem.eql(u16, name_utf16le, []u16{'.'}) or mem.eql(u16, name_utf16le, []u16{ '.', '.' }))
1762 continue;
1763 // Trust that Windows gives us valid UTF-16LE
1764 const name_utf8_len = std.unicode.utf16leToUtf8(self.handle.name_data[0..], name_utf16le) catch unreachable;
1765 const name_utf8 = self.handle.name_data[0..name_utf8_len];
1766 const kind = blk: {
1767 const attrs = self.handle.find_file_data.dwFileAttributes;
1768 if (attrs & windows.FILE_ATTRIBUTE_DIRECTORY != 0) break :blk Entry.Kind.Directory;
1769 if (attrs & windows.FILE_ATTRIBUTE_REPARSE_POINT != 0) break :blk Entry.Kind.SymLink;
1770 if (attrs & windows.FILE_ATTRIBUTE_NORMAL != 0) break :blk Entry.Kind.File;
1771 break :blk Entry.Kind.Unknown;
1772 };
1773 return Entry{
1774 .name = name_utf8,
1775 .kind = kind,
1776 };
1777 }
1778 }
1779
1780 fn nextLinux(self: *Dir) !?Entry {
1781 start_over: while (true) {
1782 if (self.handle.index >= self.handle.end_index) {
1783 if (self.handle.buf.len == 0) {
1784 self.handle.buf = try self.allocator.alloc(u8, page_size);
1785 }
1786
1787 while (true) {
1788 const result = posix.getdents64(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len);
1789 const err = posix.getErrno(result);
1790 if (err > 0) {
1791 switch (err) {
1792 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
1793 posix.EINVAL => {
1794 self.handle.buf = try self.allocator.realloc(self.handle.buf, self.handle.buf.len * 2);
1795 continue;
1796 },
1797 else => return unexpectedErrorPosix(err),
1798 }
1799 }
1800 if (result == 0) return null;
1801 self.handle.index = 0;
1802 self.handle.end_index = result;
1803 break;
1804 }
1805 }
1806 const linux_entry = @ptrCast(*align(1) posix.dirent64, &self.handle.buf[self.handle.index]);
1807 const next_index = self.handle.index + linux_entry.d_reclen;
1808 self.handle.index = next_index;
1809
1810 const name = cstr.toSlice(@ptrCast([*]u8, &linux_entry.d_name));
1811
1812 // skip . and .. entries
1813 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
1814 continue :start_over;
1815 }
1816
1817 const entry_kind = switch (linux_entry.d_type) {
1818 posix.DT_BLK => Entry.Kind.BlockDevice,
1819 posix.DT_CHR => Entry.Kind.CharacterDevice,
1820 posix.DT_DIR => Entry.Kind.Directory,
1821 posix.DT_FIFO => Entry.Kind.NamedPipe,
1822 posix.DT_LNK => Entry.Kind.SymLink,
1823 posix.DT_REG => Entry.Kind.File,
1824 posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
1825 else => Entry.Kind.Unknown,
1826 };
1827 return Entry{
1828 .name = name,
1829 .kind = entry_kind,
1830 };
1831 }
1832 }
1833
1834 fn nextFreebsd(self: *Dir) !?Entry {
1835 start_over: while (true) {
1836 if (self.handle.index >= self.handle.end_index) {
1837 if (self.handle.buf.len == 0) {
1838 self.handle.buf = try self.allocator.alloc(u8, page_size);
1839 }
1840
1841 while (true) {
1842 const result = posix.getdirentries(self.handle.fd, self.handle.buf.ptr, self.handle.buf.len, &self.handle.seek);
1843 const err = posix.getErrno(result);
1844 if (err > 0) {
1845 switch (err) {
1846 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
1847 posix.EINVAL => {
1848 self.handle.buf = try self.allocator.realloc(self.handle.buf, self.handle.buf.len * 2);
1849 continue;
1850 },
1851 else => return unexpectedErrorPosix(err),
1852 }
1853 }
1854 if (result == 0) return null;
1855 self.handle.index = 0;
1856 self.handle.end_index = result;
1857 break;
1858 }
1859 }
1860 const freebsd_entry = @ptrCast(*align(1) posix.dirent, &self.handle.buf[self.handle.index]);
1861 const next_index = self.handle.index + freebsd_entry.d_reclen;
1862 self.handle.index = next_index;
1863
1864 const name = @ptrCast([*]u8, &freebsd_entry.d_name)[0..freebsd_entry.d_namlen];
1865
1866 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
1867 continue :start_over;
1868 }
1869
1870 const entry_kind = switch (freebsd_entry.d_type) {
1871 posix.DT_BLK => Entry.Kind.BlockDevice,
1872 posix.DT_CHR => Entry.Kind.CharacterDevice,
1873 posix.DT_DIR => Entry.Kind.Directory,
1874 posix.DT_FIFO => Entry.Kind.NamedPipe,
1875 posix.DT_LNK => Entry.Kind.SymLink,
1876 posix.DT_REG => Entry.Kind.File,
1877 posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
1878 posix.DT_WHT => Entry.Kind.Whiteout,
1879 else => Entry.Kind.Unknown,
1880 };
1881 return Entry{
1882 .name = name,
1883 .kind = entry_kind,
1884 };
1885 }
1886 }
1887};
1888
1889pub fn changeCurDir(dir_path: []const u8) !void {
1890 const dir_path_c = try toPosixPath(dir_path);
1891 const err = posix.getErrno(posix.chdir(&dir_path_c));
1892 switch (err) {
1893 0 => return,
1894 posix.EACCES => return error.AccessDenied,
1895 posix.EFAULT => unreachable,
1896 posix.EIO => return error.FileSystem,
1897 posix.ELOOP => return error.SymLinkLoop,
1898 posix.ENAMETOOLONG => return error.NameTooLong,
1899 posix.ENOENT => return error.FileNotFound,
1900 posix.ENOMEM => return error.SystemResources,
1901 posix.ENOTDIR => return error.NotDir,
1902 else => return unexpectedErrorPosix(err),
1903 }
1904}
1905
1906/// Read value of a symbolic link.
1907/// The return value is a slice of out_buffer.
1908pub fn readLinkC(out_buffer: *[posix.PATH_MAX]u8, pathname: [*]const u8) ![]u8 {
1909 const rc = posix.readlink(pathname, out_buffer, out_buffer.len);
1910 const err = posix.getErrno(rc);
1911 switch (err) {
1912 0 => return out_buffer[0..rc],
1913 posix.EACCES => return error.AccessDenied,
1914 posix.EFAULT => unreachable,
1915 posix.EINVAL => unreachable,
1916 posix.EIO => return error.FileSystem,
1917 posix.ELOOP => return error.SymLinkLoop,
1918 posix.ENAMETOOLONG => unreachable, // out_buffer is at least PATH_MAX
1919 posix.ENOENT => return error.FileNotFound,
1920 posix.ENOMEM => return error.SystemResources,
1921 posix.ENOTDIR => return error.NotDir,
1922 else => return unexpectedErrorPosix(err),
1923 }
1924}
1925
1926/// Read value of a symbolic link.
1927/// The return value is a slice of out_buffer.
1928pub fn readLink(out_buffer: *[posix.PATH_MAX]u8, file_path: []const u8) ![]u8 {
1929 const file_path_c = try toPosixPath(file_path);
1930 return readLinkC(out_buffer, &file_path_c);
1931}
1932
1933pub fn posix_setuid(uid: u32) !void {
1934 const err = posix.getErrno(posix.setuid(uid));
1935 if (err == 0) return;
1936 return switch (err) {
1937 posix.EAGAIN => error.ResourceLimitReached,
1938 posix.EINVAL => error.InvalidUserId,
1939 posix.EPERM => error.PermissionDenied,
1940 else => unexpectedErrorPosix(err),
1941 };
1942}
1943
1944pub fn posix_setreuid(ruid: u32, euid: u32) !void {
1945 const err = posix.getErrno(posix.setreuid(ruid, euid));
1946 if (err == 0) return;
1947 return switch (err) {
1948 posix.EAGAIN => error.ResourceLimitReached,
1949 posix.EINVAL => error.InvalidUserId,
1950 posix.EPERM => error.PermissionDenied,
1951 else => unexpectedErrorPosix(err),
1952 };
1953}
1954
1955pub fn posix_setgid(gid: u32) !void {
1956 const err = posix.getErrno(posix.setgid(gid));
1957 if (err == 0) return;
1958 return switch (err) {
1959 posix.EAGAIN => error.ResourceLimitReached,
1960 posix.EINVAL => error.InvalidUserId,
1961 posix.EPERM => error.PermissionDenied,
1962 else => unexpectedErrorPosix(err),
1963 };
1964}
1965
1966pub fn posix_setregid(rgid: u32, egid: u32) !void {
1967 const err = posix.getErrno(posix.setregid(rgid, egid));
1968 if (err == 0) return;
1969 return switch (err) {
1970 posix.EAGAIN => error.ResourceLimitReached,
1971 posix.EINVAL => error.InvalidUserId,
1972 posix.EPERM => error.PermissionDenied,
1973 else => unexpectedErrorPosix(err),
1974 };
1975}
1976
1977pub const WindowsGetStdHandleErrs = error{
1978 NoStdHandles,
1979
1980 /// See https://github.com/ziglang/zig/issues/1396
1981 Unexpected,
1982};
1983
1984pub fn windowsGetStdHandle(handle_id: windows.DWORD) WindowsGetStdHandleErrs!windows.HANDLE {
1985 if (windows.GetStdHandle(handle_id)) |handle| {
1986 if (handle == windows.INVALID_HANDLE_VALUE) {
1987 const err = windows.GetLastError();
1988 return switch (err) {
1989 else => os.unexpectedErrorWindows(err),
1990 };
1991 }
1992 return handle;
1993 } else {
1994 return error.NoStdHandles;
1995 }
1996}
1997
1998pub const ArgIteratorPosix = struct {
1999 index: usize,
2000 count: usize,
2001
2002 pub fn init() ArgIteratorPosix {
2003 return ArgIteratorPosix{
2004 .index = 0,
2005 .count = raw.len,
2006 };
2007 }
2008
2009 pub fn next(self: *ArgIteratorPosix) ?[]const u8 {
2010 if (self.index == self.count) return null;
2011
2012 const s = raw[self.index];
2013 self.index += 1;
2014 return cstr.toSlice(s);
2015 }
2016
2017 pub fn skip(self: *ArgIteratorPosix) bool {
2018 if (self.index == self.count) return false;
2019
2020 self.index += 1;
2021 return true;
2022 }
2023
2024 /// This is marked as public but actually it's only meant to be used
2025 /// internally by zig's startup code.
2026 pub var raw: [][*]u8 = undefined;
2027};
2028
2029pub const ArgIteratorWindows = struct {
2030 index: usize,
2031 cmd_line: [*]const u8,
2032 in_quote: bool,
2033 quote_count: usize,
2034 seen_quote_count: usize,
2035
2036 pub const NextError = error{OutOfMemory};
2037
2038 pub fn init() ArgIteratorWindows {
2039 return initWithCmdLine(windows.GetCommandLineA());
2040 }
2041
2042 pub fn initWithCmdLine(cmd_line: [*]const u8) ArgIteratorWindows {
2043 return ArgIteratorWindows{
2044 .index = 0,
2045 .cmd_line = cmd_line,
2046 .in_quote = false,
2047 .quote_count = countQuotes(cmd_line),
2048 .seen_quote_count = 0,
2049 };
2050 }
2051
2052 /// You must free the returned memory when done.
2053 pub fn next(self: *ArgIteratorWindows, allocator: *Allocator) ?(NextError![]u8) {
2054 // march forward over whitespace
2055 while (true) : (self.index += 1) {
2056 const byte = self.cmd_line[self.index];
2057 switch (byte) {
2058 0 => return null,
2059 ' ', '\t' => continue,
2060 else => break,
2061 }
2062 }
2063
2064 return self.internalNext(allocator);
2065 }
2066
2067 pub fn skip(self: *ArgIteratorWindows) bool {
2068 // march forward over whitespace
2069 while (true) : (self.index += 1) {
2070 const byte = self.cmd_line[self.index];
2071 switch (byte) {
2072 0 => return false,
2073 ' ', '\t' => continue,
2074 else => break,
2075 }
2076 }
2077
2078 var backslash_count: usize = 0;
2079 while (true) : (self.index += 1) {
2080 const byte = self.cmd_line[self.index];
2081 switch (byte) {
2082 0 => return true,
2083 '"' => {
2084 const quote_is_real = backslash_count % 2 == 0;
2085 if (quote_is_real) {
2086 self.seen_quote_count += 1;
2087 }
2088 },
2089 '\\' => {
2090 backslash_count += 1;
2091 },
2092 ' ', '\t' => {
2093 if (self.seen_quote_count % 2 == 0 or self.seen_quote_count == self.quote_count) {
2094 return true;
2095 }
2096 backslash_count = 0;
2097 },
2098 else => {
2099 backslash_count = 0;
2100 continue;
2101 },
2102 }
2103 }
2104 }
2105
2106 fn internalNext(self: *ArgIteratorWindows, allocator: *Allocator) NextError![]u8 {
2107 var buf = try Buffer.initSize(allocator, 0);
2108 defer buf.deinit();
2109
2110 var backslash_count: usize = 0;
2111 while (true) : (self.index += 1) {
2112 const byte = self.cmd_line[self.index];
2113 switch (byte) {
2114 0 => return buf.toOwnedSlice(),
2115 '"' => {
2116 const quote_is_real = backslash_count % 2 == 0;
2117 try self.emitBackslashes(&buf, backslash_count / 2);
2118 backslash_count = 0;
2119
2120 if (quote_is_real) {
2121 self.seen_quote_count += 1;
2122 if (self.seen_quote_count == self.quote_count and self.seen_quote_count % 2 == 1) {
2123 try buf.appendByte('"');
2124 }
2125 } else {
2126 try buf.appendByte('"');
2127 }
2128 },
2129 '\\' => {
2130 backslash_count += 1;
2131 },
2132 ' ', '\t' => {
2133 try self.emitBackslashes(&buf, backslash_count);
2134 backslash_count = 0;
2135 if (self.seen_quote_count % 2 == 1 and self.seen_quote_count != self.quote_count) {
2136 try buf.appendByte(byte);
2137 } else {
2138 return buf.toOwnedSlice();
2139 }
2140 },
2141 else => {
2142 try self.emitBackslashes(&buf, backslash_count);
2143 backslash_count = 0;
2144 try buf.appendByte(byte);
2145 },
2146 }
2147 }
2148 }
2149
2150 fn emitBackslashes(self: *ArgIteratorWindows, buf: *Buffer, emit_count: usize) !void {
2151 var i: usize = 0;
2152 while (i < emit_count) : (i += 1) {
2153 try buf.appendByte('\\');
2154 }
2155 }
2156
2157 fn countQuotes(cmd_line: [*]const u8) usize {
2158 var result: usize = 0;
2159 var backslash_count: usize = 0;
2160 var index: usize = 0;
2161 while (true) : (index += 1) {
2162 const byte = cmd_line[index];
2163 switch (byte) {
2164 0 => return result,
2165 '\\' => backslash_count += 1,
2166 '"' => {
2167 result += 1 - (backslash_count % 2);
2168 backslash_count = 0;
2169 },
2170 else => {
2171 backslash_count = 0;
2172 },
2173 }
2174 }
2175 }
2176};
2177
2178pub const ArgIterator = struct {
2179 const InnerType = if (builtin.os == Os.windows) ArgIteratorWindows else ArgIteratorPosix;
2180
2181 inner: InnerType,
2182
2183 pub fn init() ArgIterator {
2184 if (builtin.os == Os.wasi) {
2185 // TODO: Figure out a compatible interface accomodating WASI
2186 @compileError("ArgIterator is not yet supported in WASI. Use argsAlloc and argsFree instead.");
2187 }
2188
2189 return ArgIterator{ .inner = InnerType.init() };
2190 }
2191
2192 pub const NextError = ArgIteratorWindows.NextError;
2193
2194 /// You must free the returned memory when done.
2195 pub fn next(self: *ArgIterator, allocator: *Allocator) ?(NextError![]u8) {
2196 if (builtin.os == Os.windows) {
2197 return self.inner.next(allocator);
2198 } else {
2199 return mem.dupe(allocator, u8, self.inner.next() orelse return null);
2200 }
2201 }
2202
2203 /// If you only are targeting posix you can call this and not need an allocator.
2204 pub fn nextPosix(self: *ArgIterator) ?[]const u8 {
2205 return self.inner.next();
2206 }
2207
2208 /// Parse past 1 argument without capturing it.
2209 /// Returns `true` if skipped an arg, `false` if we are at the end.
2210 pub fn skip(self: *ArgIterator) bool {
2211 return self.inner.skip();
2212 }
2213};
2214
2215pub fn args() ArgIterator {
2216 return ArgIterator.init();
2217}
2218
2219/// Caller must call argsFree on result.
2220pub fn argsAlloc(allocator: *mem.Allocator) ![]const []u8 {
2221 if (builtin.os == Os.wasi) {
2222 var count: usize = undefined;
2223 var buf_size: usize = undefined;
2224
2225 const args_sizes_get_ret = os.wasi.args_sizes_get(&count, &buf_size);
2226 if (args_sizes_get_ret != os.wasi.ESUCCESS) {
2227 return unexpectedErrorPosix(args_sizes_get_ret);
2228 }
2229
2230 var argv = try allocator.alloc([*]u8, count);
2231 defer allocator.free(argv);
2232
2233 var argv_buf = try allocator.alloc(u8, buf_size);
2234 const args_get_ret = os.wasi.args_get(argv.ptr, argv_buf.ptr);
2235 if (args_get_ret != os.wasi.ESUCCESS) {
2236 return unexpectedErrorPosix(args_get_ret);
2237 }
2238
2239 var result_slice = try allocator.alloc([]u8, count);
2240
2241 var i: usize = 0;
2242 while (i < count) : (i += 1) {
2243 result_slice[i] = mem.toSlice(u8, argv[i]);
2244 }
2245
2246 return result_slice;
2247 }
2248
2249 // TODO refactor to only make 1 allocation.
2250 var it = args();
2251 var contents = try Buffer.initSize(allocator, 0);
2252 defer contents.deinit();
2253
2254 var slice_list = ArrayList(usize).init(allocator);
2255 defer slice_list.deinit();
2256
2257 while (it.next(allocator)) |arg_or_err| {
2258 const arg = try arg_or_err;
2259 defer allocator.free(arg);
2260 try contents.append(arg);
2261 try slice_list.append(arg.len);
2262 }
2263
2264 const contents_slice = contents.toSliceConst();
2265 const slice_sizes = slice_list.toSliceConst();
2266 const slice_list_bytes = try math.mul(usize, @sizeOf([]u8), slice_sizes.len);
2267 const total_bytes = try math.add(usize, slice_list_bytes, contents_slice.len);
2268 const buf = try allocator.alignedAlloc(u8, @alignOf([]u8), total_bytes);
2269 errdefer allocator.free(buf);
2270
2271 const result_slice_list = @bytesToSlice([]u8, buf[0..slice_list_bytes]);
2272 const result_contents = buf[slice_list_bytes..];
2273 mem.copy(u8, result_contents, contents_slice);
2274
2275 var contents_index: usize = 0;
2276 for (slice_sizes) |len, i| {
2277 const new_index = contents_index + len;
2278 result_slice_list[i] = result_contents[contents_index..new_index];
2279 contents_index = new_index;
2280 }
2281
2282 return result_slice_list;
2283}
2284
2285pub fn argsFree(allocator: *mem.Allocator, args_alloc: []const []u8) void {
2286 if (builtin.os == Os.wasi) {
2287 const last_item = args_alloc[args_alloc.len - 1];
2288 const last_byte_addr = @ptrToInt(last_item.ptr) + last_item.len + 1; // null terminated
2289 const first_item_ptr = args_alloc[0].ptr;
2290 const len = last_byte_addr - @ptrToInt(first_item_ptr);
2291 allocator.free(first_item_ptr[0..len]);
2292
2293 return allocator.free(args_alloc);
2294 }
2295
2296 var total_bytes: usize = 0;
2297 for (args_alloc) |arg| {
2298 total_bytes += @sizeOf([]u8) + arg.len;
2299 }
2300 const unaligned_allocated_buf = @ptrCast([*]const u8, args_alloc.ptr)[0..total_bytes];
2301 const aligned_allocated_buf = @alignCast(@alignOf([]u8), unaligned_allocated_buf);
2302 return allocator.free(aligned_allocated_buf);
2303}
2304
2305test "windows arg parsing" {
2306 testWindowsCmdLine(c"a b\tc d", [][]const u8{ "a", "b", "c", "d" });
2307 testWindowsCmdLine(c"\"abc\" d e", [][]const u8{ "abc", "d", "e" });
2308 testWindowsCmdLine(c"a\\\\\\b d\"e f\"g h", [][]const u8{ "a\\\\\\b", "de fg", "h" });
2309 testWindowsCmdLine(c"a\\\\\\\"b c d", [][]const u8{ "a\\\"b", "c", "d" });
2310 testWindowsCmdLine(c"a\\\\\\\\\"b c\" d e", [][]const u8{ "a\\\\b c", "d", "e" });
2311 testWindowsCmdLine(c"a b\tc \"d f", [][]const u8{ "a", "b", "c", "\"d", "f" });
2312
2313 testWindowsCmdLine(c"\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", [][]const u8{
2314 ".\\..\\zig-cache\\build",
2315 "bin\\zig.exe",
2316 ".\\..",
2317 ".\\..\\zig-cache",
2318 "--help",
2319 });
2320}
2321
2322fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []const u8) void {
2323 var it = ArgIteratorWindows.initWithCmdLine(input_cmd_line);
2324 for (expected_args) |expected_arg| {
2325 const arg = it.next(debug.global_allocator).? catch unreachable;
2326 testing.expectEqualSlices(u8, expected_arg, arg);
2327 }
2328 testing.expect(it.next(debug.global_allocator) == null);
2329}
2330
2331// TODO make this a build variable that you can set
2332const unexpected_error_tracing = false;
2333const UnexpectedError = error{
2334 /// The Operating System returned an undocumented error code.
2335 Unexpected,
2336};
2337
2338/// Call this when you made a syscall or something that sets errno
2339/// and you get an unexpected error.
2340pub fn unexpectedErrorPosix(errno: usize) UnexpectedError {
2341 if (unexpected_error_tracing) {
2342 debug.warn("unexpected errno: {}\n", errno);
2343 debug.dumpCurrentStackTrace(null);
2344 }
2345 return error.Unexpected;
2346}
2347
2348/// Call this when you made a windows DLL call or something that does SetLastError
2349/// and you get an unexpected error.
2350pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
2351 if (unexpected_error_tracing) {
2352 debug.warn("unexpected GetLastError(): {}\n", err);
2353 @breakpoint();
2354 debug.dumpCurrentStackTrace(null);
2355 }
2356 return error.Unexpected;
2357}
2358
2359pub fn openSelfExe() !os.File {
2360 switch (builtin.os) {
2361 Os.linux => return os.File.openReadC(c"/proc/self/exe"),
2362 Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
2363 var buf: [MAX_PATH_BYTES]u8 = undefined;
2364 const self_exe_path = try selfExePath(&buf);
2365 buf[self_exe_path.len] = 0;
2366 return os.File.openReadC(self_exe_path.ptr);
2367 },
2368 Os.windows => {
2369 var buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
2370 const wide_slice = try selfExePathW(&buf);
2371 return os.File.openReadW(wide_slice.ptr);
2372 },
2373 else => @compileError("Unsupported OS"),
2374 }
2375}
2376
2377test "openSelfExe" {
2378 switch (builtin.os) {
2379 Os.linux, Os.macosx, Os.ios, Os.windows, Os.freebsd => (try openSelfExe()).close(),
2380 else => return error.SkipZigTest, // Unsupported OS.
2381 }
2382}
2383
2384pub fn selfExePathW(out_buffer: *[windows_util.PATH_MAX_WIDE]u16) ![]u16 {
2385 const casted_len = @intCast(windows.DWORD, out_buffer.len); // TODO shouldn't need this cast
2386 const rc = windows.GetModuleFileNameW(null, out_buffer, casted_len);
2387 assert(rc <= out_buffer.len);
2388 if (rc == 0) {
2389 const err = windows.GetLastError();
2390 switch (err) {
2391 else => return unexpectedErrorWindows(err),
2392 }
2393 }
2394 return out_buffer[0..rc];
2395}
2396
2397/// Get the path to the current executable.
2398/// If you only need the directory, use selfExeDirPath.
2399/// If you only want an open file handle, use openSelfExe.
2400/// This function may return an error if the current executable
2401/// was deleted after spawning.
2402/// Returned value is a slice of out_buffer.
2403///
2404/// On Linux, depends on procfs being mounted. If the currently executing binary has
2405/// been deleted, the file path looks something like `/a/b/c/exe (deleted)`.
2406/// TODO make the return type of this a null terminated pointer
2407pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
2408 switch (builtin.os) {
2409 Os.linux => return readLink(out_buffer, "/proc/self/exe"),
2410 Os.freebsd => {
2411 var mib = [4]c_int{ posix.CTL_KERN, posix.KERN_PROC, posix.KERN_PROC_PATHNAME, -1 };
2412 var out_len: usize = out_buffer.len;
2413 const err = posix.getErrno(posix.sysctl(&mib, 4, out_buffer, &out_len, null, 0));
2414
2415 if (err == 0) return mem.toSlice(u8, out_buffer);
2416
2417 return switch (err) {
2418 posix.EFAULT => error.BadAdress,
2419 posix.EPERM => error.PermissionDenied,
2420 else => unexpectedErrorPosix(err),
2421 };
2422 },
2423 Os.netbsd => {
2424 var mib = [4]c_int{ posix.CTL_KERN, posix.KERN_PROC_ARGS, -1, posix.KERN_PROC_PATHNAME };
2425 var out_len: usize = out_buffer.len;
2426 const err = posix.getErrno(posix.sysctl(&mib, 4, out_buffer, &out_len, null, 0));
2427
2428 if (err == 0) return mem.toSlice(u8, out_buffer);
2429
2430 return switch (err) {
2431 posix.EFAULT => error.BadAdress,
2432 posix.EPERM => error.PermissionDenied,
2433 else => unexpectedErrorPosix(err),
2434 };
2435 },
2436 Os.windows => {
2437 var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
2438 const utf16le_slice = try selfExePathW(&utf16le_buf);
2439 // Trust that Windows gives us valid UTF-16LE.
2440 const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice) catch unreachable;
2441 return out_buffer[0..end_index];
2442 },
2443 Os.macosx, Os.ios => {
2444 var u32_len: u32 = @intCast(u32, out_buffer.len); // TODO shouldn't need this cast
2445 const rc = c._NSGetExecutablePath(out_buffer, &u32_len);
2446 if (rc != 0) return error.NameTooLong;
2447 return mem.toSlice(u8, out_buffer);
2448 },
2449 else => @compileError("Unsupported OS"),
2450 }
2451}
2452
2453/// `selfExeDirPath` except allocates the result on the heap.
2454/// Caller owns returned memory.
2455pub fn selfExeDirPathAlloc(allocator: *Allocator) ![]u8 {
2456 var buf: [MAX_PATH_BYTES]u8 = undefined;
2457 return mem.dupe(allocator, u8, try selfExeDirPath(&buf));
2458}
2459
2460/// Get the directory path that contains the current executable.
2461/// Returned value is a slice of out_buffer.
2462pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) ![]const u8 {
2463 switch (builtin.os) {
2464 Os.linux => {
2465 // If the currently executing binary has been deleted,
2466 // the file path looks something like `/a/b/c/exe (deleted)`
2467 // This path cannot be opened, but it's valid for determining the directory
2468 // the executable was in when it was run.
2469 const full_exe_path = try readLinkC(out_buffer, c"/proc/self/exe");
2470 // Assume that /proc/self/exe has an absolute path, and therefore dirname
2471 // will not return null.
2472 return path.dirname(full_exe_path).?;
2473 },
2474 Os.windows, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
2475 const self_exe_path = try selfExePath(out_buffer);
2476 // Assume that the OS APIs return absolute paths, and therefore dirname
2477 // will not return null.
2478 return path.dirname(self_exe_path).?;
2479 },
2480 else => @compileError("Unsupported OS"),
2481 }
2482}
2483
2484pub fn isTty(handle: FileHandle) bool {
2485 if (is_windows) {
2486 return windows_util.windowsIsTty(handle);
2487 } else {
2488 if (builtin.link_libc) {
2489 return c.isatty(handle) != 0;
2490 } else {
2491 return posix.isatty(handle);
2492 }
2493 }
2494}
2495
2496pub fn supportsAnsiEscapeCodes(handle: FileHandle) bool {
2497 if (is_windows) {
2498 return windows_util.windowsIsCygwinPty(handle);
2499 } else {
2500 if (builtin.link_libc) {
2501 return c.isatty(handle) != 0;
2502 } else {
2503 return posix.isatty(handle);
2504 }
2505 }
2506}
2507
2508pub const PosixSocketError = error{
2509 /// Permission to create a socket of the specified type and/or
2510 /// pro‐tocol is denied.
2511 PermissionDenied,
25121246
2513 /// The implementation does not support the specified address family.1247 /// The implementation does not support the specified address family.
2514 AddressFamilyNotSupported,1248 AddressFamilyNotSupported,
...@@ -2528,25 +1262,26 @@ pub const PosixSocketError = error{...@@ -2528,25 +1262,26 @@ pub const PosixSocketError = error{
25281262
2529 /// The protocol type or the specified protocol is not supported within this domain.1263 /// The protocol type or the specified protocol is not supported within this domain.
2530 ProtocolNotSupported,1264 ProtocolNotSupported,
1265
1266 Unexpected,
2531};1267};
25321268
2533pub fn posixSocket(domain: u32, socket_type: u32, protocol: u32) !i32 {1269pub fn socket(domain: u32, socket_type: u32, protocol: u32) SocketError!i32 {
2534 const rc = posix.socket(domain, socket_type, protocol);1270 const rc = system.socket(domain, socket_type, protocol);
2535 const err = posix.getErrno(rc);1271 switch (errno(rc)) {
2536 switch (err) {
2537 0 => return @intCast(i32, rc),1272 0 => return @intCast(i32, rc),
2538 posix.EACCES => return PosixSocketError.PermissionDenied,1273 EACCES => return error.PermissionDenied,
2539 posix.EAFNOSUPPORT => return PosixSocketError.AddressFamilyNotSupported,1274 EAFNOSUPPORT => return error.AddressFamilyNotSupported,
2540 posix.EINVAL => return PosixSocketError.ProtocolFamilyNotAvailable,1275 EINVAL => return error.ProtocolFamilyNotAvailable,
2541 posix.EMFILE => return PosixSocketError.ProcessFdQuotaExceeded,1276 EMFILE => return error.ProcessFdQuotaExceeded,
2542 posix.ENFILE => return PosixSocketError.SystemFdQuotaExceeded,1277 ENFILE => return error.SystemFdQuotaExceeded,
2543 posix.ENOBUFS, posix.ENOMEM => return PosixSocketError.SystemResources,1278 ENOBUFS, ENOMEM => return error.SystemResources,
2544 posix.EPROTONOSUPPORT => return PosixSocketError.ProtocolNotSupported,1279 EPROTONOSUPPORT => return error.ProtocolNotSupported,
2545 else => return unexpectedErrorPosix(err),1280 else => |err| return unexpectedErrno(err),
2546 }1281 }
2547}1282}
25481283
2549pub const PosixBindError = error{1284pub const BindError = error{
2550 /// The address is protected, and the user is not the superuser.1285 /// The address is protected, and the user is not the superuser.
2551 /// For UNIX domain sockets: Search permission is denied on a component1286 /// For UNIX domain sockets: Search permission is denied on a component
2552 /// of the path prefix.1287 /// of the path prefix.
...@@ -2580,34 +1315,32 @@ pub const PosixBindError = error{...@@ -2580,34 +1315,32 @@ pub const PosixBindError = error{
2580 /// The socket inode would reside on a read-only filesystem.1315 /// The socket inode would reside on a read-only filesystem.
2581 ReadOnlyFileSystem,1316 ReadOnlyFileSystem,
25821317
2583 /// See https://github.com/ziglang/zig/issues/1396
2584 Unexpected,1318 Unexpected,
2585};1319};
25861320
2587/// addr is `&const T` where T is one of the sockaddr1321/// addr is `*const T` where T is one of the sockaddr
2588pub fn posixBind(fd: i32, addr: *const posix.sockaddr) PosixBindError!void {1322pub fn bind(fd: i32, addr: *const sockaddr) BindError!void {
2589 const rc = posix.bind(fd, addr, @sizeOf(posix.sockaddr));1323 const rc = system.bind(fd, addr, @sizeOf(sockaddr));
2590 const err = posix.getErrno(rc);1324 switch (errno(rc)) {
2591 switch (err) {
2592 0 => return,1325 0 => return,
2593 posix.EACCES => return PosixBindError.AccessDenied,1326 EACCES => return error.AccessDenied,
2594 posix.EADDRINUSE => return PosixBindError.AddressInUse,1327 EADDRINUSE => return error.AddressInUse,
2595 posix.EBADF => unreachable, // always a race condition if this error is returned1328 EBADF => unreachable, // always a race condition if this error is returned
2596 posix.EINVAL => unreachable,1329 EINVAL => unreachable,
2597 posix.ENOTSOCK => unreachable,1330 ENOTSOCK => unreachable,
2598 posix.EADDRNOTAVAIL => return PosixBindError.AddressNotAvailable,1331 EADDRNOTAVAIL => return error.AddressNotAvailable,
2599 posix.EFAULT => unreachable,1332 EFAULT => unreachable,
2600 posix.ELOOP => return PosixBindError.SymLinkLoop,1333 ELOOP => return error.SymLinkLoop,
2601 posix.ENAMETOOLONG => return PosixBindError.NameTooLong,1334 ENAMETOOLONG => return error.NameTooLong,
2602 posix.ENOENT => return PosixBindError.FileNotFound,1335 ENOENT => return error.FileNotFound,
2603 posix.ENOMEM => return PosixBindError.SystemResources,1336 ENOMEM => return error.SystemResources,
2604 posix.ENOTDIR => return PosixBindError.NotDir,1337 ENOTDIR => return error.NotDir,
2605 posix.EROFS => return PosixBindError.ReadOnlyFileSystem,1338 EROFS => return error.ReadOnlyFileSystem,
2606 else => return unexpectedErrorPosix(err),1339 else => |err| return unexpectedErrno(err),
2607 }1340 }
2608}1341}
26091342
2610const PosixListenError = error{1343const ListenError = error{
2611 /// Another socket is already listening on the same port.1344 /// Another socket is already listening on the same port.
2612 /// For Internet domain sockets, the socket referred to by sockfd had not previously1345 /// For Internet domain sockets, the socket referred to by sockfd had not previously
2613 /// been bound to an address and, upon attempting to bind it to an ephemeral port, it1346 /// been bound to an address and, upon attempting to bind it to an ephemeral port, it
...@@ -2621,24 +1354,22 @@ const PosixListenError = error{...@@ -2621,24 +1354,22 @@ const PosixListenError = error{
2621 /// The socket is not of a type that supports the listen() operation.1354 /// The socket is not of a type that supports the listen() operation.
2622 OperationNotSupported,1355 OperationNotSupported,
26231356
2624 /// See https://github.com/ziglang/zig/issues/1396
2625 Unexpected,1357 Unexpected,
2626};1358};
26271359
2628pub fn posixListen(sockfd: i32, backlog: u32) PosixListenError!void {1360pub fn listen(sockfd: i32, backlog: u32) ListenError!void {
2629 const rc = posix.listen(sockfd, backlog);1361 const rc = system.listen(sockfd, backlog);
2630 const err = posix.getErrno(rc);1362 switch (errno(rc)) {
2631 switch (err) {
2632 0 => return,1363 0 => return,
2633 posix.EADDRINUSE => return PosixListenError.AddressInUse,1364 EADDRINUSE => return error.AddressInUse,
2634 posix.EBADF => unreachable,1365 EBADF => unreachable,
2635 posix.ENOTSOCK => return PosixListenError.FileDescriptorNotASocket,1366 ENOTSOCK => return error.FileDescriptorNotASocket,
2636 posix.EOPNOTSUPP => return PosixListenError.OperationNotSupported,1367 EOPNOTSUPP => return error.OperationNotSupported,
2637 else => return unexpectedErrorPosix(err),1368 else => |err| return unexpectedErrno(err),
2638 }1369 }
2639}1370}
26401371
2641pub const PosixAcceptError = error{1372pub const AcceptError = error{
2642 ConnectionAborted,1373 ConnectionAborted,
26431374
2644 /// The per-process limit on the number of open file descriptors has been reached.1375 /// The per-process limit on the number of open file descriptors has been reached.
...@@ -2662,66 +1393,66 @@ pub const PosixAcceptError = error{...@@ -2662,66 +1393,66 @@ pub const PosixAcceptError = error{
2662 /// Firewall rules forbid connection.1393 /// Firewall rules forbid connection.
2663 BlockedByFirewall,1394 BlockedByFirewall,
26641395
2665 /// See https://github.com/ziglang/zig/issues/1396
2666 Unexpected,1396 Unexpected,
2667};1397};
26681398
2669pub fn posixAccept(fd: i32, addr: *posix.sockaddr, flags: u32) PosixAcceptError!i32 {1399/// Accept a connection on a socket. `fd` must be opened in blocking mode.
1400/// See also `accept4_async`.
1401pub fn accept4(fd: i32, addr: *sockaddr, flags: u32) AcceptError!i32 {
2670 while (true) {1402 while (true) {
2671 var sockaddr_size = u32(@sizeOf(posix.sockaddr));1403 var sockaddr_size = u32(@sizeOf(sockaddr));
2672 const rc = posix.accept4(fd, addr, &sockaddr_size, flags);1404 const rc = system.accept4(fd, addr, &sockaddr_size, flags);
2673 const err = posix.getErrno(rc);1405 switch (errno(rc)) {
2674 switch (err) {
2675 0 => return @intCast(i32, rc),1406 0 => return @intCast(i32, rc),
2676 posix.EINTR => continue,1407 EINTR => continue,
2677 else => return unexpectedErrorPosix(err),1408 else => |err| return unexpectedErrno(err),
26781409
2679 posix.EAGAIN => unreachable, // use posixAsyncAccept for non-blocking1410 EAGAIN => unreachable, // This function is for blocking only.
2680 posix.EBADF => unreachable, // always a race condition1411 EBADF => unreachable, // always a race condition
2681 posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted,1412 ECONNABORTED => return error.ConnectionAborted,
2682 posix.EFAULT => unreachable,1413 EFAULT => unreachable,
2683 posix.EINVAL => unreachable,1414 EINVAL => unreachable,
2684 posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,1415 EMFILE => return error.ProcessFdQuotaExceeded,
2685 posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,1416 ENFILE => return error.SystemFdQuotaExceeded,
2686 posix.ENOBUFS => return PosixAcceptError.SystemResources,1417 ENOBUFS => return error.SystemResources,
2687 posix.ENOMEM => return PosixAcceptError.SystemResources,1418 ENOMEM => return error.SystemResources,
2688 posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,1419 ENOTSOCK => return error.FileDescriptorNotASocket,
2689 posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,1420 EOPNOTSUPP => return error.OperationNotSupported,
2690 posix.EPROTO => return PosixAcceptError.ProtocolFailure,1421 EPROTO => return error.ProtocolFailure,
2691 posix.EPERM => return PosixAcceptError.BlockedByFirewall,1422 EPERM => return error.BlockedByFirewall,
2692 }1423 }
2693 }1424 }
2694}1425}
26951426
1427/// This is the same as `accept4` except `fd` is expected to be non-blocking.
2696/// Returns -1 if would block.1428/// Returns -1 if would block.
2697pub fn posixAsyncAccept(fd: i32, addr: *posix.sockaddr, flags: u32) PosixAcceptError!i32 {1429pub fn accept4_async(fd: i32, addr: *sockaddr, flags: u32) AcceptError!i32 {
2698 while (true) {1430 while (true) {
2699 var sockaddr_size = u32(@sizeOf(posix.sockaddr));1431 var sockaddr_size = u32(@sizeOf(sockaddr));
2700 const rc = posix.accept4(fd, addr, &sockaddr_size, flags);1432 const rc = system.accept4(fd, addr, &sockaddr_size, flags);
2701 const err = posix.getErrno(rc);1433 switch (errno(rc)) {
2702 switch (err) {
2703 0 => return @intCast(i32, rc),1434 0 => return @intCast(i32, rc),
2704 posix.EINTR => continue,1435 EINTR => continue,
2705 else => return unexpectedErrorPosix(err),1436 else => |err| return unexpectedErrno(err),
27061437
2707 posix.EAGAIN => return -1,1438 EAGAIN => return -1,
2708 posix.EBADF => unreachable, // always a race condition1439 EBADF => unreachable, // always a race condition
2709 posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted,1440 ECONNABORTED => return error.ConnectionAborted,
2710 posix.EFAULT => unreachable,1441 EFAULT => unreachable,
2711 posix.EINVAL => unreachable,1442 EINVAL => unreachable,
2712 posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,1443 EMFILE => return error.ProcessFdQuotaExceeded,
2713 posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,1444 ENFILE => return error.SystemFdQuotaExceeded,
2714 posix.ENOBUFS => return PosixAcceptError.SystemResources,1445 ENOBUFS => return error.SystemResources,
2715 posix.ENOMEM => return PosixAcceptError.SystemResources,1446 ENOMEM => return error.SystemResources,
2716 posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,1447 ENOTSOCK => return error.FileDescriptorNotASocket,
2717 posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,1448 EOPNOTSUPP => return error.OperationNotSupported,
2718 posix.EPROTO => return PosixAcceptError.ProtocolFailure,1449 EPROTO => return error.ProtocolFailure,
2719 posix.EPERM => return PosixAcceptError.BlockedByFirewall,1450 EPERM => return error.BlockedByFirewall,
2720 }1451 }
2721 }1452 }
2722}1453}
27231454
2724pub const LinuxEpollCreateError = error{1455pub const EpollCreateError = error{
2725 /// The per-user limit on the number of epoll instances imposed by1456 /// The per-user limit on the number of epoll instances imposed by
2726 /// /proc/sys/fs/epoll/max_user_instances was encountered. See epoll(7) for further1457 /// /proc/sys/fs/epoll/max_user_instances was encountered. See epoll(7) for further
2727 /// details.1458 /// details.
...@@ -2734,25 +1465,23 @@ pub const LinuxEpollCreateError = error{...@@ -2734,25 +1465,23 @@ pub const LinuxEpollCreateError = error{
2734 /// There was insufficient memory to create the kernel object.1465 /// There was insufficient memory to create the kernel object.
2735 SystemResources,1466 SystemResources,
27361467
2737 /// See https://github.com/ziglang/zig/issues/1396
2738 Unexpected,1468 Unexpected,
2739};1469};
27401470
2741pub fn linuxEpollCreate(flags: u32) LinuxEpollCreateError!i32 {1471pub fn epoll_create1(flags: u32) EpollCreateError!i32 {
2742 const rc = posix.epoll_create1(flags);1472 const rc = system.epoll_create1(flags);
2743 const err = posix.getErrno(rc);1473 switch (errno(rc)) {
2744 switch (err) {
2745 0 => return @intCast(i32, rc),1474 0 => return @intCast(i32, rc),
2746 else => return unexpectedErrorPosix(err),1475 else => |err| return unexpectedErrno(err),
27471476
2748 posix.EINVAL => unreachable,1477 EINVAL => unreachable,
2749 posix.EMFILE => return LinuxEpollCreateError.ProcessFdQuotaExceeded,1478 EMFILE => return error.ProcessFdQuotaExceeded,
2750 posix.ENFILE => return LinuxEpollCreateError.SystemFdQuotaExceeded,1479 ENFILE => return error.SystemFdQuotaExceeded,
2751 posix.ENOMEM => return LinuxEpollCreateError.SystemResources,1480 ENOMEM => return error.SystemResources,
2752 }1481 }
2753}1482}
27541483
2755pub const LinuxEpollCtlError = error{1484pub const EpollCtlError = error{
2756 /// op was EPOLL_CTL_ADD, and the supplied file descriptor fd is already registered1485 /// op was EPOLL_CTL_ADD, and the supplied file descriptor fd is already registered
2757 /// with this epoll instance.1486 /// with this epoll instance.
2758 FileDescriptorAlreadyPresentInSet,1487 FileDescriptorAlreadyPresentInSet,
...@@ -2777,752 +1506,942 @@ pub const LinuxEpollCtlError = error{...@@ -2777,752 +1506,942 @@ pub const LinuxEpollCtlError = error{
2777 /// for example, a regular file or a directory.1506 /// for example, a regular file or a directory.
2778 FileDescriptorIncompatibleWithEpoll,1507 FileDescriptorIncompatibleWithEpoll,
27791508
2780 /// See https://github.com/ziglang/zig/issues/1396
2781 Unexpected,1509 Unexpected,
2782};1510};
27831511
2784pub fn linuxEpollCtl(epfd: i32, op: u32, fd: i32, event: *linux.epoll_event) LinuxEpollCtlError!void {1512pub fn epoll_ctl(epfd: i32, op: u32, fd: i32, event: *epoll_event) EpollCtlError!void {
2785 const rc = posix.epoll_ctl(epfd, op, fd, event);1513 const rc = system.epoll_ctl(epfd, op, fd, event);
2786 const err = posix.getErrno(rc);1514 switch (errno(rc)) {
2787 switch (err) {1515 0 => return,
2788 0 => return,1516 else => |err| return unexpectedErrno(err),
2789 else => return unexpectedErrorPosix(err),1517
1518 EBADF => unreachable, // always a race condition if this happens
1519 EEXIST => return error.FileDescriptorAlreadyPresentInSet,
1520 EINVAL => unreachable,
1521 ELOOP => return error.OperationCausesCircularLoop,
1522 ENOENT => return error.FileDescriptorNotRegistered,
1523 ENOMEM => return error.SystemResources,
1524 ENOSPC => return error.UserResourceLimitReached,
1525 EPERM => return error.FileDescriptorIncompatibleWithEpoll,
1526 }
1527}
1528
1529/// Waits for an I/O event on an epoll file descriptor.
1530/// Returns the number of file descriptors ready for the requested I/O,
1531/// or zero if no file descriptor became ready during the requested timeout milliseconds.
1532pub fn epoll_wait(epfd: i32, events: []epoll_event, timeout: i32) usize {
1533 while (true) {
1534 // TODO get rid of the @intCast
1535 const rc = system.epoll_wait(epfd, events.ptr, @intCast(u32, events.len), timeout);
1536 switch (errno(rc)) {
1537 0 => return @intCast(usize, rc),
1538 EINTR => continue,
1539 EBADF => unreachable,
1540 EFAULT => unreachable,
1541 EINVAL => unreachable,
1542 else => unreachable,
1543 }
1544 }
1545}
1546
1547pub const EventFdError = error{
1548 SystemResources,
1549 ProcessFdQuotaExceeded,
1550 SystemFdQuotaExceeded,
1551 Unexpected,
1552};
1553
1554pub fn eventfd(initval: u32, flags: u32) EventFdError!i32 {
1555 const rc = system.eventfd(initval, flags);
1556 switch (errno(rc)) {
1557 0 => return @intCast(i32, rc),
1558 else => |err| return unexpectedErrno(err),
1559
1560 EINVAL => unreachable, // invalid parameters
1561 EMFILE => return error.ProcessFdQuotaExceeded,
1562 ENFILE => return error.SystemFdQuotaExceeded,
1563 ENODEV => return error.SystemResources,
1564 ENOMEM => return error.SystemResources,
1565 }
1566}
1567
1568pub const GetSockNameError = error{
1569 /// Insufficient resources were available in the system to perform the operation.
1570 SystemResources,
1571
1572 Unexpected,
1573};
1574
1575pub fn getsockname(sockfd: i32) GetSockNameError!sockaddr {
1576 var addr: sockaddr = undefined;
1577 var addrlen: socklen_t = @sizeOf(sockaddr);
1578 switch (errno(system.getsockname(sockfd, &addr, &addrlen))) {
1579 0 => return addr,
1580 else => |err| return unexpectedErrno(err),
1581
1582 EBADF => unreachable, // always a race condition
1583 EFAULT => unreachable,
1584 EINVAL => unreachable, // invalid parameters
1585 ENOTSOCK => unreachable,
1586 ENOBUFS => return error.SystemResources,
1587 }
1588}
1589
1590pub const ConnectError = error{
1591 /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket
1592 /// file, or search permission is denied for one of the directories in the path prefix.
1593 /// or
1594 /// The user tried to connect to a broadcast address without having the socket broadcast flag enabled or
1595 /// the connection request failed because of a local firewall rule.
1596 PermissionDenied,
1597
1598 /// Local address is already in use.
1599 AddressInUse,
1600
1601 /// (Internet domain sockets) The socket referred to by sockfd had not previously been bound to an
1602 /// address and, upon attempting to bind it to an ephemeral port, it was determined that all port numbers
1603 /// in the ephemeral port range are currently in use. See the discussion of
1604 /// /proc/sys/net/ipv4/ip_local_port_range in ip(7).
1605 AddressNotAvailable,
1606
1607 /// The passed address didn't have the correct address family in its sa_family field.
1608 AddressFamilyNotSupported,
1609
1610 /// Insufficient entries in the routing cache.
1611 SystemResources,
1612
1613 /// A connect() on a stream socket found no one listening on the remote address.
1614 ConnectionRefused,
1615
1616 /// Network is unreachable.
1617 NetworkUnreachable,
1618
1619 /// Timeout while attempting connection. The server may be too busy to accept new connections. Note
1620 /// that for IP sockets the timeout may be very long when syncookies are enabled on the server.
1621 ConnectionTimedOut,
1622
1623 Unexpected,
1624};
1625
1626/// Initiate a connection on a socket.
1627/// This is for blocking file descriptors only.
1628/// For non-blocking, see `connect_async`.
1629pub fn connect(sockfd: i32, sock_addr: *sockaddr, len: socklen_t) ConnectError!void {
1630 while (true) {
1631 switch (errno(system.connect(sockfd, sock_addr, @sizeOf(sockaddr)))) {
1632 0 => return,
1633 EACCES => return error.PermissionDenied,
1634 EPERM => return error.PermissionDenied,
1635 EADDRINUSE => return error.AddressInUse,
1636 EADDRNOTAVAIL => return error.AddressNotAvailable,
1637 EAFNOSUPPORT => return error.AddressFamilyNotSupported,
1638 EAGAIN => return error.SystemResources,
1639 EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
1640 EBADF => unreachable, // sockfd is not a valid open file descriptor.
1641 ECONNREFUSED => return error.ConnectionRefused,
1642 EFAULT => unreachable, // The socket structure address is outside the user's address space.
1643 EINPROGRESS => unreachable, // The socket is nonblocking and the connection cannot be completed immediately.
1644 EINTR => continue,
1645 EISCONN => unreachable, // The socket is already connected.
1646 ENETUNREACH => return error.NetworkUnreachable,
1647 ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
1648 EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
1649 ETIMEDOUT => return error.ConnectionTimedOut,
1650 else => |err| return unexpectedErrno(err),
1651 }
1652 }
1653}
1654
1655/// Same as `connect` except it is for blocking socket file descriptors.
1656/// It expects to receive EINPROGRESS`.
1657pub fn connect_async(sockfd: i32, sock_addr: *sockaddr, len: socklen_t) ConnectError!void {
1658 while (true) {
1659 switch (errno(system.connect(sockfd, sock_addr, @sizeOf(sockaddr)))) {
1660 EINTR => continue,
1661 0, EINPROGRESS => return,
1662 EACCES => return error.PermissionDenied,
1663 EPERM => return error.PermissionDenied,
1664 EADDRINUSE => return error.AddressInUse,
1665 EADDRNOTAVAIL => return error.AddressNotAvailable,
1666 EAFNOSUPPORT => return error.AddressFamilyNotSupported,
1667 EAGAIN => return error.SystemResources,
1668 EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
1669 EBADF => unreachable, // sockfd is not a valid open file descriptor.
1670 ECONNREFUSED => return error.ConnectionRefused,
1671 EFAULT => unreachable, // The socket structure address is outside the user's address space.
1672 EISCONN => unreachable, // The socket is already connected.
1673 ENETUNREACH => return error.NetworkUnreachable,
1674 ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
1675 EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
1676 ETIMEDOUT => return error.ConnectionTimedOut,
1677 else => |err| return unexpectedErrno(err),
1678 }
1679 }
1680}
1681
1682pub fn getsockoptError(sockfd: i32) ConnectError!void {
1683 var err_code: u32 = undefined;
1684 var size: u32 = @sizeOf(u32);
1685 const rc = system.getsockopt(sockfd, SOL_SOCKET, SO_ERROR, @ptrCast([*]u8, &err_code), &size);
1686 assert(size == 4);
1687 switch (errno(rc)) {
1688 0 => switch (err_code) {
1689 0 => return,
1690 EACCES => return error.PermissionDenied,
1691 EPERM => return error.PermissionDenied,
1692 EADDRINUSE => return error.AddressInUse,
1693 EADDRNOTAVAIL => return error.AddressNotAvailable,
1694 EAFNOSUPPORT => return error.AddressFamilyNotSupported,
1695 EAGAIN => return error.SystemResources,
1696 EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
1697 EBADF => unreachable, // sockfd is not a valid open file descriptor.
1698 ECONNREFUSED => return error.ConnectionRefused,
1699 EFAULT => unreachable, // The socket structure address is outside the user's address space.
1700 EISCONN => unreachable, // The socket is already connected.
1701 ENETUNREACH => return error.NetworkUnreachable,
1702 ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
1703 EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
1704 ETIMEDOUT => return error.ConnectionTimedOut,
1705 else => |err| return unexpectedErrno(err),
1706 },
1707 EBADF => unreachable, // The argument sockfd is not a valid file descriptor.
1708 EFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space.
1709 EINVAL => unreachable,
1710 ENOPROTOOPT => unreachable, // The option is unknown at the level indicated.
1711 ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
1712 else => |err| return unexpectedErrno(err),
1713 }
1714}
1715
1716pub fn waitpid(pid: i32, flags: u32) u32 {
1717 // TODO allow implicit pointer cast from *u32 to *c_uint ?
1718 const Status = if (builtin.link_libc) c_uint else u32;
1719 var status: Status = undefined;
1720 while (true) {
1721 switch (errno(system.waitpid(pid, &status, flags))) {
1722 0 => return @bitCast(u32, status),
1723 EINTR => continue,
1724 ECHILD => unreachable, // The process specified does not exist. It would be a race condition to handle this error.
1725 EINVAL => unreachable, // The options argument was invalid
1726 else => unreachable,
1727 }
1728 }
1729}
1730
1731pub const FStatError = error{
1732 SystemResources,
1733 Unexpected,
1734};
1735
1736pub fn fstat(fd: fd_t) FStatError!Stat {
1737 var stat: Stat = undefined;
1738 if (darwin.is_the_target) {
1739 switch (darwin.getErrno(darwin.@"fstat$INODE64"(fd, &stat))) {
1740 0 => return stat,
1741 EBADF => unreachable, // Always a race condition.
1742 ENOMEM => return error.SystemResources,
1743 else => |err| return unexpectedErrno(err),
1744 }
1745 }
1746
1747 switch (errno(system.fstat(fd, &stat))) {
1748 0 => return stat,
1749 EBADF => unreachable, // Always a race condition.
1750 ENOMEM => return error.SystemResources,
1751 else => |err| return unexpectedErrno(err),
1752 }
1753}
1754
1755pub const KQueueError = error{
1756 /// The per-process limit on the number of open file descriptors has been reached.
1757 ProcessFdQuotaExceeded,
1758
1759 /// The system-wide limit on the total number of open files has been reached.
1760 SystemFdQuotaExceeded,
1761
1762 Unexpected,
1763};
1764
1765pub fn kqueue() KQueueError!i32 {
1766 const rc = system.kqueue();
1767 switch (errno(rc)) {
1768 0 => return @intCast(i32, rc),
1769 EMFILE => return error.ProcessFdQuotaExceeded,
1770 ENFILE => return error.SystemFdQuotaExceeded,
1771 else => |err| return unexpectedErrno(err),
1772 }
1773}
1774
1775pub const KEventError = error{
1776 /// The process does not have permission to register a filter.
1777 AccessDenied,
1778
1779 /// The event could not be found to be modified or deleted.
1780 EventNotFound,
1781
1782 /// No memory was available to register the event.
1783 SystemResources,
1784
1785 /// The specified process to attach to does not exist.
1786 ProcessNotFound,
1787
1788 /// changelist or eventlist had too many items on it.
1789 /// TODO remove this possibility
1790 Overflow,
1791};
1792
1793pub fn kevent(
1794 kq: i32,
1795 changelist: []const Kevent,
1796 eventlist: []Kevent,
1797 timeout: ?*const timespec,
1798) KEventError!usize {
1799 while (true) {
1800 const rc = system.kevent(
1801 kq,
1802 changelist.ptr,
1803 try math.cast(c_int, changelist.len),
1804 eventlist.ptr,
1805 try math.cast(c_int, eventlist.len),
1806 timeout,
1807 );
1808 switch (errno(rc)) {
1809 0 => return @intCast(usize, rc),
1810 EACCES => return error.AccessDenied,
1811 EFAULT => unreachable,
1812 EBADF => unreachable, // Always a race condition.
1813 EINTR => continue,
1814 EINVAL => unreachable,
1815 ENOENT => return error.EventNotFound,
1816 ENOMEM => return error.SystemResources,
1817 ESRCH => return error.ProcessNotFound,
1818 else => unreachable,
1819 }
1820 }
1821}
1822
1823pub const INotifyInitError = error{
1824 ProcessFdQuotaExceeded,
1825 SystemFdQuotaExceeded,
1826 SystemResources,
1827 Unexpected,
1828};
1829
1830/// initialize an inotify instance
1831pub fn inotify_init1(flags: u32) INotifyInitError!i32 {
1832 const rc = system.inotify_init1(flags);
1833 switch (errno(rc)) {
1834 0 => return @intCast(i32, rc),
1835 EINVAL => unreachable,
1836 EMFILE => return error.ProcessFdQuotaExceeded,
1837 ENFILE => return error.SystemFdQuotaExceeded,
1838 ENOMEM => return error.SystemResources,
1839 else => |err| return unexpectedErrno(err),
1840 }
1841}
1842
1843pub const INotifyAddWatchError = error{
1844 AccessDenied,
1845 NameTooLong,
1846 FileNotFound,
1847 SystemResources,
1848 UserResourceLimitReached,
1849 Unexpected,
1850};
1851
1852/// add a watch to an initialized inotify instance
1853pub fn inotify_add_watch(inotify_fd: i32, pathname: []const u8, mask: u32) INotifyAddWatchError!i32 {
1854 const pathname_c = try toPosixPath(pathname);
1855 return inotify_add_watchC(inotify_fd, &pathname_c, mask);
1856}
27901857
2791 posix.EBADF => unreachable, // always a race condition if this happens1858/// Same as `inotify_add_watch` except pathname is null-terminated.
2792 posix.EEXIST => return LinuxEpollCtlError.FileDescriptorAlreadyPresentInSet,1859pub fn inotify_add_watchC(inotify_fd: i32, pathname: [*]const u8, mask: u32) INotifyAddWatchError!i32 {
2793 posix.EINVAL => unreachable,1860 const rc = system.inotify_add_watch(inotify_fd, pathname, mask);
2794 posix.ELOOP => return LinuxEpollCtlError.OperationCausesCircularLoop,1861 switch (errno(rc)) {
2795 posix.ENOENT => return LinuxEpollCtlError.FileDescriptorNotRegistered,1862 0 => return @intCast(i32, rc),
2796 posix.ENOMEM => return LinuxEpollCtlError.SystemResources,1863 EACCES => return error.AccessDenied,
2797 posix.ENOSPC => return LinuxEpollCtlError.UserResourceLimitReached,1864 EBADF => unreachable,
2798 posix.EPERM => return LinuxEpollCtlError.FileDescriptorIncompatibleWithEpoll,1865 EFAULT => unreachable,
1866 EINVAL => unreachable,
1867 ENAMETOOLONG => return error.NameTooLong,
1868 ENOENT => return error.FileNotFound,
1869 ENOMEM => return error.SystemResources,
1870 ENOSPC => return error.UserResourceLimitReached,
1871 else => |err| return unexpectedErrno(err),
2799 }1872 }
2800}1873}
28011874
2802pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usize {1875/// remove an existing watch from an inotify instance
2803 while (true) {1876pub fn inotify_rm_watch(inotify_fd: i32, wd: i32) void {
2804 const rc = posix.epoll_wait(epfd, events.ptr, @intCast(u32, events.len), timeout);1877 switch (errno(system.inotify_rm_watch(inotify_fd, wd))) {
2805 const err = posix.getErrno(rc);1878 0 => return,
2806 switch (err) {1879 EBADF => unreachable,
2807 0 => return rc,1880 EINVAL => unreachable,
2808 posix.EINTR => continue,1881 else => unreachable,
2809 posix.EBADF => unreachable,
2810 posix.EFAULT => unreachable,
2811 posix.EINVAL => unreachable,
2812 else => unreachable,
2813 }
2814 }1882 }
2815}1883}
28161884
2817pub const LinuxEventFdError = error{1885pub const MProtectError = error{
2818 InvalidFlagValue,1886 AccessDenied,
2819 SystemResources,1887 OutOfMemory,
2820 ProcessFdQuotaExceeded,
2821 SystemFdQuotaExceeded,
2822
2823 /// See https://github.com/ziglang/zig/issues/1396
2824 Unexpected,1888 Unexpected,
2825};1889};
28261890
2827pub fn linuxEventFd(initval: u32, flags: u32) LinuxEventFdError!i32 {1891/// `memory.len` must be page-aligned.
2828 const rc = posix.eventfd(initval, flags);1892pub fn mprotect(memory: [*]align(mem.page_size) u8, protection: u32) MProtectError!void {
2829 const err = posix.getErrno(rc);1893 assert(mem.isAligned(memory.len, mem.page_size));
2830 switch (err) {1894 switch (errno(system.mprotect(memory.ptr, memory.len, protection))) {
2831 0 => return @intCast(i32, rc),1895 0 => return,
2832 else => return unexpectedErrorPosix(err),1896 EINVAL => unreachable,
28331897 EACCES => return error.AccessDenied,
2834 posix.EINVAL => return LinuxEventFdError.InvalidFlagValue,1898 ENOMEM => return error.OutOfMemory,
2835 posix.EMFILE => return LinuxEventFdError.ProcessFdQuotaExceeded,1899 else => return unexpectedErrno(err),
2836 posix.ENFILE => return LinuxEventFdError.SystemFdQuotaExceeded,
2837 posix.ENODEV => return LinuxEventFdError.SystemResources,
2838 posix.ENOMEM => return LinuxEventFdError.SystemResources,
2839 }1900 }
2840}1901}
28411902
2842pub const PosixGetSockNameError = error{1903pub const ForkError = error{
2843 /// Insufficient resources were available in the system to perform the operation.
2844 SystemResources,1904 SystemResources,
2845
2846 /// See https://github.com/ziglang/zig/issues/1396
2847 Unexpected,1905 Unexpected,
2848};1906};
28491907
2850pub fn posixGetSockName(sockfd: i32) PosixGetSockNameError!posix.sockaddr {1908pub fn fork() ForkError!pid_t {
2851 var addr: posix.sockaddr = undefined;1909 const rc = system.fork();
2852 var addrlen: posix.socklen_t = @sizeOf(posix.sockaddr);1910 switch (errno(rc)) {
2853 const rc = posix.getsockname(sockfd, &addr, &addrlen);1911 0 => return @intCast(pid_t, rc),
2854 const err = posix.getErrno(rc);1912 EAGAIN => return error.SystemResources,
2855 switch (err) {1913 ENOMEM => return error.SystemResources,
2856 0 => return addr,1914 else => |err| return unexpectedErrno(err),
2857 else => return unexpectedErrorPosix(err),
2858
2859 posix.EBADF => unreachable,
2860 posix.EFAULT => unreachable,
2861 posix.EINVAL => unreachable,
2862 posix.ENOTSOCK => unreachable,
2863 posix.ENOBUFS => return PosixGetSockNameError.SystemResources,
2864 }1915 }
2865}1916}
28661917
2867pub const PosixConnectError = error{1918pub const MMapError = error{
2868 /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket1919 /// The underlying filesystem of the specified file does not support memory mapping.
2869 /// file, or search permission is denied for one of the directories in the path prefix.1920 MemoryMappingNotSupported,
2870 /// or
2871 /// The user tried to connect to a broadcast address without having the socket broadcast flag enabled or
2872 /// the connection request failed because of a local firewall rule.
2873 PermissionDenied,
28741921
2875 /// Local address is already in use.1922 /// A file descriptor refers to a non-regular file. Or a file mapping was requested,
2876 AddressInUse,1923 /// but the file descriptor is not open for reading. Or `MAP_SHARED` was requested
1924 /// and `PROT_WRITE` is set, but the file descriptor is not open in `O_RDWR` mode.
1925 /// Or `PROT_WRITE` is set, but the file is append-only.
1926 AccessDenied,
28771927
2878 /// (Internet domain sockets) The socket referred to by sockfd had not previously been bound to an1928 /// The `prot` argument asks for `PROT_EXEC` but the mapped area belongs to a file on
2879 /// address and, upon attempting to bind it to an ephemeral port, it was determined that all port numbers1929 /// a filesystem that was mounted no-exec.
2880 /// in the ephemeral port range are currently in use. See the discussion of1930 PermissionDenied,
2881 /// /proc/sys/net/ipv4/ip_local_port_range in ip(7).1931 LockedMemoryLimitExceeded,
2882 AddressNotAvailable,1932 OutOfMemory,
1933 Unexpected,
1934};
28831935
2884 /// The passed address didn't have the correct address family in its sa_family field.1936/// Map files or devices into memory.
2885 AddressFamilyNotSupported,1937/// Use of a mapped region can result in these signals:
1938/// `length` must be page-aligned.
1939/// * SIGSEGV - Attempted write into a region mapped as read-only.
1940/// * SIGBUS - Attempted access to a portion of the buffer that does not correspond to the file
1941pub fn mmap(
1942 ptr: ?[*]align(mem.page_size) u8,
1943 length: usize,
1944 prot: u32,
1945 flags: u32,
1946 fd: fd_t,
1947 offset: isize,
1948) MMapError![]align(mem.page_size) u8 {
1949 assert(mem.isAligned(length, mem.page_size));
1950 const err = if (builtin.link_libc) blk: {
1951 const rc = std.c.mmap(ptr, length, prot, flags, fd, offset);
1952 if (rc != MAP_FAILED) return @ptrCast([*]align(mem.page_size) u8, @alignCast(mem.page_size, rc))[0..length];
1953 break :blk @intCast(usize, system._errno().*);
1954 } else blk: {
1955 const rc = system.mmap(ptr, length, prot, flags, fd, offset);
1956 const err = errno(rc);
1957 if (err == 0) return @intToPtr([*]align(mem.page_size) u8, rc)[0..length];
1958 break :blk err;
1959 };
1960 switch (err) {
1961 ETXTBSY => return error.AccessDenied,
1962 EACCES => return error.AccessDenied,
1963 EPERM => return error.PermissionDenied,
1964 EAGAIN => return error.LockedMemoryLimitExceeded,
1965 EBADF => unreachable, // Always a race condition.
1966 EOVERFLOW => unreachable, // The number of pages used for length + offset would overflow.
1967 ENODEV => return error.MemoryMappingNotSupported,
1968 EINVAL => unreachable, // Invalid parameters to mmap()
1969 ENOMEM => return error.OutOfMemory,
1970 else => return unexpectedErrno(err),
1971 }
1972}
1973
1974/// Deletes the mappings for the specified address range, causing
1975/// further references to addresses within the range to generate invalid memory references.
1976/// Note that while POSIX allows unmapping a region in the middle of an existing mapping,
1977/// Zig's munmap function does not, for two reasons:
1978/// * It violates the Zig principle that resource deallocation must succeed.
1979/// * The Windows function, VirtualFree, has this restriction.
1980pub fn munmap(memory: []align(mem.page_size) u8) void {
1981 switch (errno(system.munmap(memory.ptr, memory.len))) {
1982 0 => return,
1983 EINVAL => unreachable, // Invalid parameters.
1984 ENOMEM => unreachable, // Attempted to unmap a region in the middle of an existing mapping.
1985 else => unreachable,
1986 }
1987}
28861988
2887 /// Insufficient entries in the routing cache.1989pub const AccessError = error{
1990 PermissionDenied,
1991 FileNotFound,
1992 NameTooLong,
1993 InputOutput,
2888 SystemResources,1994 SystemResources,
1995 BadPathName,
28891996
2890 /// A connect() on a stream socket found no one listening on the remote address.1997 /// On Windows, file paths must be valid Unicode.
2891 ConnectionRefused,1998 InvalidUtf8,
2892
2893 /// Network is unreachable.
2894 NetworkUnreachable,
2895
2896 /// Timeout while attempting connection. The server may be too busy to accept new connections. Note
2897 /// that for IP sockets the timeout may be very long when syncookies are enabled on the server.
2898 ConnectionTimedOut,
28991999
2900 /// See https://github.com/ziglang/zig/issues/1396
2901 Unexpected,2000 Unexpected,
2902};2001};
29032002
2904pub fn posixConnect(sockfd: i32, sockaddr: *const posix.sockaddr) PosixConnectError!void {2003/// check user's permissions for a file
2905 while (true) {2004/// TODO currently this assumes `mode` is `F_OK` on Windows.
2906 const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));2005pub fn access(path: []const u8, mode: u32) AccessError!void {
2907 const err = posix.getErrno(rc);2006 if (windows.is_the_target) {
2908 switch (err) {2007 const path_w = try windows.sliceToPrefixedFileW(path);
2909 0 => return,2008 _ = try windows.GetFileAttributesW(&path_w);
2910 else => return unexpectedErrorPosix(err),2009 return;
2911
2912 posix.EACCES => return PosixConnectError.PermissionDenied,
2913 posix.EPERM => return PosixConnectError.PermissionDenied,
2914 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2915 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2916 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2917 posix.EAGAIN => return PosixConnectError.SystemResources,
2918 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2919 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2920 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2921 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2922 posix.EINPROGRESS => unreachable, // The socket is nonblocking and the connection cannot be completed immediately.
2923 posix.EINTR => continue,
2924 posix.EISCONN => unreachable, // The socket is already connected.
2925 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2926 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2927 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2928 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2929 }
2930 }2010 }
2011 const path_c = try toPosixPath(path);
2012 return accessC(&path_c, mode);
2931}2013}
29322014
2933/// Same as posixConnect except it is for blocking socket file descriptors.2015/// Same as `access` except `path` is null-terminated.
2934/// It expects to receive EINPROGRESS.2016pub fn accessC(path: [*]const u8, mode: u32) AccessError!void {
2935pub fn posixConnectAsync(sockfd: i32, sockaddr: *const c_void, len: u32) PosixConnectError!void {2017 if (windows.is_the_target) {
2936 while (true) {2018 const path_w = try windows.cStrToPrefixedFileW(path);
2937 const rc = posix.connect(sockfd, sockaddr, len);2019 _ = try windows.GetFileAttributesW(&path_w);
2938 const err = posix.getErrno(rc);2020 return;
2939 switch (err) {
2940 0, posix.EINPROGRESS => return,
2941 else => return unexpectedErrorPosix(err),
2942
2943 posix.EACCES => return PosixConnectError.PermissionDenied,
2944 posix.EPERM => return PosixConnectError.PermissionDenied,
2945 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2946 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2947 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2948 posix.EAGAIN => return PosixConnectError.SystemResources,
2949 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2950 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2951 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2952 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2953 posix.EINTR => continue,
2954 posix.EISCONN => unreachable, // The socket is already connected.
2955 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2956 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2957 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2958 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2959 }
2960 }2021 }
2961}2022 switch (errno(system.access(path, mode))) {
2023 0 => return,
2024 EACCES => return error.PermissionDenied,
2025 EROFS => return error.PermissionDenied,
2026 ELOOP => return error.PermissionDenied,
2027 ETXTBSY => return error.PermissionDenied,
2028 ENOTDIR => return error.FileNotFound,
2029 ENOENT => return error.FileNotFound,
29622030
2963pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void {2031 ENAMETOOLONG => return error.NameTooLong,
2964 var err_code: i32 = undefined;2032 EINVAL => unreachable,
2965 var size: u32 = @sizeOf(i32);2033 EFAULT => unreachable,
2966 const rc = posix.getsockopt(sockfd, posix.SOL_SOCKET, posix.SO_ERROR, @ptrCast([*]u8, &err_code), &size);2034 EIO => return error.InputOutput,
2967 assert(size == 4);2035 ENOMEM => return error.SystemResources,
2968 const err = posix.getErrno(rc);2036 else => |err| return unexpectedErrno(err),
2969 switch (err) {
2970 0 => switch (err_code) {
2971 0 => return,
2972 else => return unexpectedErrorPosix(err),
2973
2974 posix.EACCES => return PosixConnectError.PermissionDenied,
2975 posix.EPERM => return PosixConnectError.PermissionDenied,
2976 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2977 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2978 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2979 posix.EAGAIN => return PosixConnectError.SystemResources,
2980 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2981 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2982 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2983 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2984 posix.EISCONN => unreachable, // The socket is already connected.
2985 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2986 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2987 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2988 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2989 },
2990 else => return unexpectedErrorPosix(err),
2991 posix.EBADF => unreachable, // The argument sockfd is not a valid file descriptor.
2992 posix.EFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space.
2993 posix.EINVAL => unreachable,
2994 posix.ENOPROTOOPT => unreachable, // The option is unknown at the level indicated.
2995 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2996 }2037 }
2997}2038}
29982039
2999pub const Thread = struct {2040pub const PipeError = error{
3000 data: Data,2041 SystemFdQuotaExceeded,
30012042 ProcessFdQuotaExceeded,
3002 pub const use_pthreads = is_posix and builtin.link_libc;2043 Unexpected,
30032044};
3004 /// Represents a kernel thread handle.
3005 /// May be an integer or a pointer depending on the platform.
3006 /// On Linux and POSIX, this is the same as Id.
3007 pub const Handle = if (use_pthreads)
3008 c.pthread_t
3009 else switch (builtin.os) {
3010 builtin.Os.linux => i32,
3011 builtin.Os.windows => windows.HANDLE,
3012 else => @compileError("Unsupported OS"),
3013 };
3014
3015 /// Represents a unique ID per thread.
3016 /// May be an integer or pointer depending on the platform.
3017 /// On Linux and POSIX, this is the same as Handle.
3018 pub const Id = switch (builtin.os) {
3019 builtin.Os.windows => windows.DWORD,
3020 else => Handle,
3021 };
30222045
3023 pub const Data = if (use_pthreads)2046/// Creates a unidirectional data channel that can be used for interprocess communication.
3024 struct {2047pub fn pipe() PipeError![2]fd_t {
3025 handle: Thread.Handle,2048 var fds: [2]fd_t = undefined;
3026 mmap_addr: usize,2049 switch (errno(system.pipe(&fds))) {
3027 mmap_len: usize,2050 0 => return fds,
3028 }2051 EINVAL => unreachable, // Invalid parameters to pipe()
3029 else switch (builtin.os) {2052 EFAULT => unreachable, // Invalid fds pointer
3030 builtin.Os.linux => struct {2053 ENFILE => return error.SystemFdQuotaExceeded,
3031 handle: Thread.Handle,2054 EMFILE => return error.ProcessFdQuotaExceeded,
3032 mmap_addr: usize,2055 else => |err| return unexpectedErrno(err),
3033 mmap_len: usize,2056 }
3034 },2057}
3035 builtin.Os.windows => struct {
3036 handle: Thread.Handle,
3037 alloc_start: *c_void,
3038 heap_handle: windows.HANDLE,
3039 },
3040 else => @compileError("Unsupported OS"),
3041 };
30422058
3043 /// Returns the ID of the calling thread.2059pub fn pipe2(flags: u32) PipeError![2]fd_t {
3044 /// Makes a syscall every time the function is called.2060 var fds: [2]fd_t = undefined;
3045 /// On Linux and POSIX, this Id is the same as a Handle.2061 switch (errno(system.pipe2(&fds, flags))) {
3046 pub fn getCurrentId() Id {2062 0 => return fds,
3047 if (use_pthreads) {2063 EINVAL => unreachable, // Invalid flags
3048 return c.pthread_self();2064 EFAULT => unreachable, // Invalid fds pointer
3049 } else2065 ENFILE => return error.SystemFdQuotaExceeded,
3050 return switch (builtin.os) {2066 EMFILE => return error.ProcessFdQuotaExceeded,
3051 builtin.Os.linux => linux.gettid(),2067 else => |err| return unexpectedErrno(err),
3052 builtin.Os.windows => windows.GetCurrentThreadId(),
3053 else => @compileError("Unsupported OS"),
3054 };
3055 }
3056
3057 /// Returns the handle of this thread.
3058 /// On Linux and POSIX, this is the same as Id.
3059 /// On Linux, it is possible that the thread spawned with `spawnThread`
3060 /// finishes executing entirely before the clone syscall completes. In this
3061 /// case, this function will return 0 rather than the no-longer-existing thread's
3062 /// pid.
3063 pub fn handle(self: Thread) Handle {
3064 return self.data.handle;
3065 }
3066
3067 pub fn wait(self: *const Thread) void {
3068 if (use_pthreads) {
3069 const err = c.pthread_join(self.data.handle, null);
3070 switch (err) {
3071 0 => {},
3072 posix.EINVAL => unreachable,
3073 posix.ESRCH => unreachable,
3074 posix.EDEADLK => unreachable,
3075 else => unreachable,
3076 }
3077 assert(posix.munmap(self.data.mmap_addr, self.data.mmap_len) == 0);
3078 } else switch (builtin.os) {
3079 builtin.Os.linux => {
3080 while (true) {
3081 const pid_value = @atomicLoad(i32, &self.data.handle, .SeqCst);
3082 if (pid_value == 0) break;
3083 const rc = linux.futex_wait(&self.data.handle, linux.FUTEX_WAIT, pid_value, null);
3084 switch (linux.getErrno(rc)) {
3085 0 => continue,
3086 posix.EINTR => continue,
3087 posix.EAGAIN => continue,
3088 else => unreachable,
3089 }
3090 }
3091 assert(posix.munmap(self.data.mmap_addr, self.data.mmap_len) == 0);
3092 },
3093 builtin.Os.windows => {
3094 assert(windows.WaitForSingleObject(self.data.handle, windows.INFINITE) == windows.WAIT_OBJECT_0);
3095 assert(windows.CloseHandle(self.data.handle) != 0);
3096 assert(windows.HeapFree(self.data.heap_handle, 0, self.data.alloc_start) != 0);
3097 },
3098 else => @compileError("Unsupported OS"),
3099 }
3100 }2068 }
3101};2069}
31022070
3103pub const SpawnThreadError = error{2071pub const SysCtlError = error{
3104 /// A system-imposed limit on the number of threads was encountered.2072 PermissionDenied,
3105 /// There are a number of limits that may trigger this error:
3106 /// * the RLIMIT_NPROC soft resource limit (set via setrlimit(2)),
3107 /// which limits the number of processes and threads for a real
3108 /// user ID, was reached;
3109 /// * the kernel's system-wide limit on the number of processes and
3110 /// threads, /proc/sys/kernel/threads-max, was reached (see
3111 /// proc(5));
3112 /// * the maximum number of PIDs, /proc/sys/kernel/pid_max, was
3113 /// reached (see proc(5)); or
3114 /// * the PID limit (pids.max) imposed by the cgroup "process num‐
3115 /// ber" (PIDs) controller was reached.
3116 ThreadQuotaExceeded,
3117
3118 /// The kernel cannot allocate sufficient memory to allocate a task structure
3119 /// for the child, or to copy those parts of the caller's context that need to
3120 /// be copied.
3121 SystemResources,2073 SystemResources,
31222074 NameTooLong,
3123 /// Not enough userland memory to spawn the thread.
3124 OutOfMemory,
3125
3126 /// See https://github.com/ziglang/zig/issues/1396
3127 Unexpected,2075 Unexpected,
3128};2076};
31292077
3130/// caller must call wait on the returned thread2078pub fn sysctl(
3131/// fn startFn(@typeOf(context)) T2079 name: []const c_int,
3132/// where T is u8, noreturn, void, or !void2080 oldp: ?*c_void,
3133/// caller must call wait on the returned thread2081 oldlenp: ?*usize,
3134pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread {2082 newp: ?*c_void,
3135 if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode");2083 newlen: usize,
3136 // TODO compile-time call graph analysis to determine stack upper bound2084) SysCtlError!void {
3137 // https://github.com/ziglang/zig/issues/1572085 const name_len = math.cast(c_uint, name.len) catch return error.NameTooLong;
3138 const default_stack_size = 8 * 1024 * 1024;2086 switch (errno(system.sysctl(name.ptr, name_len, oldp, oldlenp, newp, newlen))) {
31392087 0 => return,
3140 const Context = @typeOf(context);2088 EFAULT => unreachable,
3141 comptime assert(@ArgType(@typeOf(startFn), 0) == Context);2089 EPERM => return error.PermissionDenied,
31422090 ENOMEM => return error.SystemResources,
3143 if (builtin.os == builtin.Os.windows) {2091 else => |err| return unexpectedErrno(err),
3144 const WinThread = struct {
3145 const OuterContext = struct {
3146 thread: Thread,
3147 inner: Context,
3148 };
3149 extern fn threadMain(raw_arg: windows.LPVOID) windows.DWORD {
3150 const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*;
3151 switch (@typeId(@typeOf(startFn).ReturnType)) {
3152 builtin.TypeId.Int => {
3153 return startFn(arg);
3154 },
3155 builtin.TypeId.Void => {
3156 startFn(arg);
3157 return 0;
3158 },
3159 else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"),
3160 }
3161 }
3162 };
3163
3164 const heap_handle = windows.GetProcessHeap() orelse return SpawnThreadError.OutOfMemory;
3165 const byte_count = @alignOf(WinThread.OuterContext) + @sizeOf(WinThread.OuterContext);
3166 const bytes_ptr = windows.HeapAlloc(heap_handle, 0, byte_count) orelse return SpawnThreadError.OutOfMemory;
3167 errdefer assert(windows.HeapFree(heap_handle, 0, bytes_ptr) != 0);
3168 const bytes = @ptrCast([*]u8, bytes_ptr)[0..byte_count];
3169 const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext) catch unreachable;
3170 outer_context.* = WinThread.OuterContext{
3171 .thread = Thread{
3172 .data = Thread.Data{
3173 .heap_handle = heap_handle,
3174 .alloc_start = bytes_ptr,
3175 .handle = undefined,
3176 },
3177 },
3178 .inner = context,
3179 };
3180
3181 const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner);
3182 outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse {
3183 const err = windows.GetLastError();
3184 return switch (err) {
3185 else => os.unexpectedErrorWindows(err),
3186 };
3187 };
3188 return &outer_context.thread;
3189 }
3190
3191 const MainFuncs = struct {
3192 extern fn linuxThreadMain(ctx_addr: usize) u8 {
3193 const arg = if (@sizeOf(Context) == 0) {} else @intToPtr(*const Context, ctx_addr).*;
3194
3195 switch (@typeId(@typeOf(startFn).ReturnType)) {
3196 builtin.TypeId.Int => {
3197 return startFn(arg);
3198 },
3199 builtin.TypeId.Void => {
3200 startFn(arg);
3201 return 0;
3202 },
3203 else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"),
3204 }
3205 }
3206 extern fn posixThreadMain(ctx: ?*c_void) ?*c_void {
3207 if (@sizeOf(Context) == 0) {
3208 _ = startFn({});
3209 return null;
3210 } else {
3211 _ = startFn(@ptrCast(*const Context, @alignCast(@alignOf(Context), ctx)).*);
3212 return null;
3213 }
3214 }
3215 };
3216
3217 const MAP_GROWSDOWN = if (builtin.os == builtin.Os.linux) linux.MAP_GROWSDOWN else 0;
3218
3219 var stack_end_offset: usize = undefined;
3220 var thread_start_offset: usize = undefined;
3221 var context_start_offset: usize = undefined;
3222 var tls_start_offset: usize = undefined;
3223 const mmap_len = blk: {
3224 // First in memory will be the stack, which grows downwards.
3225 var l: usize = mem.alignForward(default_stack_size, os.page_size);
3226 stack_end_offset = l;
3227 // Above the stack, so that it can be in the same mmap call, put the Thread object.
3228 l = mem.alignForward(l, @alignOf(Thread));
3229 thread_start_offset = l;
3230 l += @sizeOf(Thread);
3231 // Next, the Context object.
3232 if (@sizeOf(Context) != 0) {
3233 l = mem.alignForward(l, @alignOf(Context));
3234 context_start_offset = l;
3235 l += @sizeOf(Context);
3236 }
3237 // Finally, the Thread Local Storage, if any.
3238 if (!Thread.use_pthreads) {
3239 if (linux.tls.tls_image) |tls_img| {
3240 l = mem.alignForward(l, @alignOf(usize));
3241 tls_start_offset = l;
3242 l += tls_img.alloc_size;
3243 }
3244 }
3245 break :blk l;
3246 };
3247 const mmap_addr = posix.mmap(null, mmap_len, posix.PROT_READ | posix.PROT_WRITE, posix.MAP_PRIVATE | posix.MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0);
3248 if (mmap_addr == posix.MAP_FAILED) return error.OutOfMemory;
3249 errdefer assert(posix.munmap(mmap_addr, mmap_len) == 0);
3250
3251 const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(*Thread, mmap_addr + thread_start_offset));
3252 thread_ptr.data.mmap_addr = mmap_addr;
3253 thread_ptr.data.mmap_len = mmap_len;
3254
3255 var arg: usize = undefined;
3256 if (@sizeOf(Context) != 0) {
3257 arg = mmap_addr + context_start_offset;
3258 const context_ptr = @alignCast(@alignOf(Context), @intToPtr(*Context, arg));
3259 context_ptr.* = context;
3260 }
3261
3262 if (Thread.use_pthreads) {
3263 // use pthreads
3264 var attr: c.pthread_attr_t = undefined;
3265 if (c.pthread_attr_init(&attr) != 0) return SpawnThreadError.SystemResources;
3266 defer assert(c.pthread_attr_destroy(&attr) == 0);
3267
3268 assert(c.pthread_attr_setstack(&attr, @intToPtr(*c_void, mmap_addr), stack_end_offset) == 0);
3269
3270 const err = c.pthread_create(&thread_ptr.data.handle, &attr, MainFuncs.posixThreadMain, @intToPtr(*c_void, arg));
3271 switch (err) {
3272 0 => return thread_ptr,
3273 posix.EAGAIN => return SpawnThreadError.SystemResources,
3274 posix.EPERM => unreachable,
3275 posix.EINVAL => unreachable,
3276 else => return unexpectedErrorPosix(@intCast(usize, err)),
3277 }
3278 } else if (builtin.os == builtin.Os.linux) {
3279 var flags: u32 = posix.CLONE_VM | posix.CLONE_FS | posix.CLONE_FILES | posix.CLONE_SIGHAND |
3280 posix.CLONE_THREAD | posix.CLONE_SYSVSEM | posix.CLONE_PARENT_SETTID | posix.CLONE_CHILD_CLEARTID |
3281 posix.CLONE_DETACHED;
3282 var newtls: usize = undefined;
3283 if (linux.tls.tls_image) |tls_img| {
3284 newtls = linux.tls.copyTLS(mmap_addr + tls_start_offset);
3285 flags |= posix.CLONE_SETTLS;
3286 }
3287 const rc = posix.clone(MainFuncs.linuxThreadMain, mmap_addr + stack_end_offset, flags, arg, &thread_ptr.data.handle, newtls, &thread_ptr.data.handle);
3288 const err = posix.getErrno(rc);
3289 switch (err) {
3290 0 => return thread_ptr,
3291 posix.EAGAIN => return SpawnThreadError.ThreadQuotaExceeded,
3292 posix.EINVAL => unreachable,
3293 posix.ENOMEM => return SpawnThreadError.SystemResources,
3294 posix.ENOSPC => unreachable,
3295 posix.EPERM => unreachable,
3296 posix.EUSERS => unreachable,
3297 else => return unexpectedErrorPosix(err),
3298 }
3299 } else {
3300 @compileError("Unsupported OS");
3301 }2092 }
3302}2093}
33032094
3304pub fn posixWait(pid: i32) i32 {2095pub fn sysctlbynameC(
3305 var status: i32 = undefined;2096 name: [*]const u8,
3306 while (true) {2097 oldp: ?*c_void,
3307 const err = posix.getErrno(posix.waitpid(pid, &status, 0));2098 oldlenp: ?*usize,
3308 switch (err) {2099 newp: ?*c_void,
3309 0 => return status,2100 newlen: usize,
3310 posix.EINTR => continue,2101) SysCtlError!void {
3311 posix.ECHILD => unreachable, // The process specified does not exist. It would be a race condition to handle this error.2102 switch (errno(system.sysctlbyname(name, oldp, oldlenp, newp, newlen))) {
3312 posix.EINVAL => unreachable, // The options argument was invalid2103 0 => return,
3313 else => unreachable,2104 EFAULT => unreachable,
3314 }2105 EPERM => return error.PermissionDenied,
2106 ENOMEM => return error.SystemResources,
2107 else => |err| return unexpectedErrno(err),
3315 }2108 }
3316}2109}
33172110
3318pub fn posixFStat(fd: i32) !posix.Stat {2111pub fn gettimeofday(tv: ?*timeval, tz: ?*timezone) void {
3319 var stat: posix.Stat = undefined;2112 switch (errno(system.gettimeofday(tv, tz))) {
3320 const err = posix.getErrno(posix.fstat(fd, &stat));2113 0 => return,
3321 if (err > 0) {2114 EINVAL => unreachable,
3322 return switch (err) {2115 else => unreachable,
3323 // We do not make this an error code because if you get EBADF it's always a bug,
3324 // since the fd could have been reused.
3325 posix.EBADF => unreachable,
3326 posix.ENOMEM => error.SystemResources,
3327 else => os.unexpectedErrorPosix(err),
3328 };
3329 }2116 }
3330
3331 return stat;
3332}2117}
33332118
3334pub const CpuCountError = error{2119pub const SeekError = error{
3335 OutOfMemory,2120 Unseekable,
3336 PermissionDenied,
3337
3338 /// See https://github.com/ziglang/zig/issues/1396
3339 Unexpected,2121 Unexpected,
3340};2122};
33412123
3342pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {2124/// Repositions read/write file offset relative to the beginning.
3343 switch (builtin.os) {2125pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {
3344 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {2126 if (linux.is_the_target and !builtin.link_libc and @sizeOf(usize) == 4) {
3345 var count: c_int = undefined;2127 switch (errno(system.llseek(fd, offset, null, SEEK_SET))) {
3346 var count_len: usize = @sizeOf(c_int);2128 0 => return,
3347 const rc = posix.sysctlbyname(switch (builtin.os) {2129 EBADF => unreachable, // always a race condition
3348 builtin.Os.macosx => c"hw.logicalcpu",2130 EINVAL => return error.Unseekable,
3349 else => c"hw.ncpu",2131 EOVERFLOW => return error.Unseekable,
3350 }, @ptrCast(*c_void, &count), &count_len, null, 0);2132 ESPIPE => return error.Unseekable,
3351 const err = posix.getErrno(rc);2133 ENXIO => return error.Unseekable,
3352 switch (err) {2134 else => |err| return unexpectedErrno(err),
3353 0 => return @intCast(usize, count),2135 }
3354 posix.EFAULT => unreachable,2136 }
3355 posix.EINVAL => unreachable,2137 if (windows.is_the_target) {
3356 posix.ENOMEM => return CpuCountError.OutOfMemory,2138 return windows.SetFilePointerEx_BEGIN(fd, offset);
3357 posix.ENOTDIR => unreachable,2139 }
3358 posix.EISDIR => unreachable,2140 const ipos = @bitCast(i64, offset); // the OS treats this as unsigned
3359 posix.ENOENT => unreachable,2141 switch (errno(system.lseek(fd, ipos, SEEK_SET))) {
3360 posix.EPERM => unreachable,2142 0 => return,
3361 else => return os.unexpectedErrorPosix(err),2143 EBADF => unreachable, // always a race condition
3362 }2144 EINVAL => return error.Unseekable,
3363 },2145 EOVERFLOW => return error.Unseekable,
3364 builtin.Os.linux => {2146 ESPIPE => return error.Unseekable,
3365 const usize_count = 16;2147 ENXIO => return error.Unseekable,
3366 const allocator = std.heap.stackFallback(usize_count * @sizeOf(usize), fallback_allocator).get();2148 else => |err| return unexpectedErrno(err),
3367
3368 var set = try allocator.alloc(usize, usize_count);
3369 defer allocator.free(set);
3370
3371 while (true) {
3372 const rc = posix.sched_getaffinity(0, set);
3373 const err = posix.getErrno(rc);
3374 switch (err) {
3375 0 => {
3376 if (rc < set.len * @sizeOf(usize)) {
3377 const result = set[0 .. rc / @sizeOf(usize)];
3378 var sum: usize = 0;
3379 for (result) |x| {
3380 sum += @popCount(usize, x);
3381 }
3382 return sum;
3383 } else {
3384 set = try allocator.realloc(set, set.len * 2);
3385 continue;
3386 }
3387 },
3388 posix.EFAULT => unreachable,
3389 posix.EINVAL => unreachable,
3390 posix.EPERM => return CpuCountError.PermissionDenied,
3391 posix.ESRCH => unreachable,
3392 else => return os.unexpectedErrorPosix(err),
3393 }
3394 }
3395 },
3396 builtin.Os.windows => {
3397 var system_info: windows.SYSTEM_INFO = undefined;
3398 windows.GetSystemInfo(&system_info);
3399 return @intCast(usize, system_info.dwNumberOfProcessors);
3400 },
3401 else => @compileError("unsupported OS"),
3402 }2149 }
3403}2150}
34042151
3405pub const BsdKQueueError = error{2152/// Repositions read/write file offset relative to the current offset.
3406 /// The per-process limit on the number of open file descriptors has been reached.2153pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {
3407 ProcessFdQuotaExceeded,2154 if (linux.is_the_target and !builtin.link_libc and @sizeOf(usize) == 4) {
34082155 switch (errno(system.llseek(fd, @bitCast(u64, offset), null, SEEK_CUR))) {
3409 /// The system-wide limit on the total number of open files has been reached.2156 0 => return,
3410 SystemFdQuotaExceeded,2157 EBADF => unreachable, // always a race condition
2158 EINVAL => return error.Unseekable,
2159 EOVERFLOW => return error.Unseekable,
2160 ESPIPE => return error.Unseekable,
2161 ENXIO => return error.Unseekable,
2162 else => |err| return unexpectedErrno(err),
2163 }
2164 }
2165 if (windows.is_the_target) {
2166 return windows.SetFilePointerEx_CURRENT(fd, offset);
2167 }
2168 switch (errno(system.lseek(fd, offset, SEEK_CUR))) {
2169 0 => return,
2170 EBADF => unreachable, // always a race condition
2171 EINVAL => return error.Unseekable,
2172 EOVERFLOW => return error.Unseekable,
2173 ESPIPE => return error.Unseekable,
2174 ENXIO => return error.Unseekable,
2175 else => |err| return unexpectedErrno(err),
2176 }
2177}
34112178
3412 /// See https://github.com/ziglang/zig/issues/13962179/// Repositions read/write file offset relative to the end.
3413 Unexpected,2180pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {
3414};2181 if (linux.is_the_target and !builtin.link_libc and @sizeOf(usize) == 4) {
2182 switch (errno(system.llseek(fd, @bitCast(u64, offset), null, SEEK_END))) {
2183 EBADF => unreachable, // always a race condition
2184 EINVAL => return error.Unseekable,
2185 EOVERFLOW => return error.Unseekable,
2186 ESPIPE => return error.Unseekable,
2187 ENXIO => return error.Unseekable,
2188 else => |err| return unexpectedErrno(err),
2189 }
2190 }
2191 if (windows.is_the_target) {
2192 return windows.SetFilePointerEx_END(fd, offset);
2193 }
2194 switch (errno(system.lseek(fd, offset, SEEK_END))) {
2195 0 => return,
2196 EBADF => unreachable, // always a race condition
2197 EINVAL => return error.Unseekable,
2198 EOVERFLOW => return error.Unseekable,
2199 ESPIPE => return error.Unseekable,
2200 ENXIO => return error.Unseekable,
2201 else => |err| return unexpectedErrno(err),
2202 }
2203}
34152204
3416pub fn bsdKQueue() BsdKQueueError!i32 {2205/// Returns the read/write file offset relative to the beginning.
3417 const rc = posix.kqueue();2206pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {
3418 const err = posix.getErrno(rc);2207 if (linux.is_the_target and !builtin.link_libc and @sizeOf(usize) == 4) {
3419 switch (err) {2208 var result: u64 = undefined;
3420 0 => return @intCast(i32, rc),2209 switch (errno(system.llseek(fd, 0, &result, SEEK_CUR))) {
3421 posix.EMFILE => return BsdKQueueError.ProcessFdQuotaExceeded,2210 0 => return result,
3422 posix.ENFILE => return BsdKQueueError.SystemFdQuotaExceeded,2211 EBADF => unreachable, // always a race condition
3423 else => return unexpectedErrorPosix(err),2212 EINVAL => return error.Unseekable,
2213 EOVERFLOW => return error.Unseekable,
2214 ESPIPE => return error.Unseekable,
2215 ENXIO => return error.Unseekable,
2216 else => |err| return unexpectedErrno(err),
2217 }
2218 }
2219 if (windows.is_the_target) {
2220 return windows.SetFilePointerEx_CURRENT_get(fd);
2221 }
2222 const rc = system.lseek(fd, 0, SEEK_CUR);
2223 switch (errno(rc)) {
2224 0 => return @bitCast(u64, rc),
2225 EBADF => unreachable, // always a race condition
2226 EINVAL => return error.Unseekable,
2227 EOVERFLOW => return error.Unseekable,
2228 ESPIPE => return error.Unseekable,
2229 ENXIO => return error.Unseekable,
2230 else => |err| return unexpectedErrno(err),
3424 }2231 }
3425}2232}
34262233
3427pub const BsdKEventError = error{2234pub const RealPathError = error{
3428 /// The process does not have permission to register a filter.2235 FileNotFound,
3429 AccessDenied,2236 AccessDenied,
2237 NameTooLong,
2238 NotSupported,
2239 NotDir,
2240 SymLinkLoop,
2241 InputOutput,
2242 FileTooBig,
2243 IsDir,
2244 ProcessFdQuotaExceeded,
2245 SystemFdQuotaExceeded,
2246 NoDevice,
2247 SystemResources,
2248 NoSpaceLeft,
2249 FileSystem,
2250 BadPathName,
2251 DeviceBusy,
34302252
3431 /// The event could not be found to be modified or deleted.2253 SharingViolation,
3432 EventNotFound,2254 PipeBusy,
34332255
3434 /// No memory was available to register the event.2256 /// On Windows, file paths must be valid Unicode.
3435 SystemResources,2257 InvalidUtf8,
34362258
3437 /// The specified process to attach to does not exist.2259 PathAlreadyExists,
3438 ProcessNotFound,2260
2261 Unexpected,
3439};2262};
34402263
3441pub fn bsdKEvent(2264/// Return the canonicalized absolute pathname.
3442 kq: i32,2265/// Expands all symbolic links and resolves references to `.`, `..`, and
3443 changelist: []const posix.Kevent,2266/// extra `/` characters in `pathname`.
3444 eventlist: []posix.Kevent,2267/// The return value is a slice of `out_buffer`, but not necessarily from the beginning.
3445 timeout: ?*const posix.timespec,2268/// See also `realpathC` and `realpathW`.
3446) BsdKEventError!usize {2269pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
2270 if (windows.is_the_target) {
2271 const pathname_w = try windows.sliceToPrefixedFileW(pathname);
2272 return realpathW(&pathname_w, out_buffer);
2273 }
2274 const pathname_c = try toPosixPath(pathname);
2275 return realpathC(&pathname_c, out_buffer);
2276}
2277
2278/// Same as `realpath` except `pathname` is null-terminated.
2279pub fn realpathC(pathname: [*]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
2280 if (windows.is_the_target) {
2281 const pathname_w = try windows.cStrToPrefixedFileW(pathname);
2282 return realpathW(&pathname_w, out_buffer);
2283 }
2284 if (linux.is_the_target and !builtin.link_libc) {
2285 const fd = try openC(pathname, linux.O_PATH | linux.O_NONBLOCK | linux.O_CLOEXEC, 0);
2286 defer close(fd);
2287
2288 var procfs_buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined;
2289 const proc_path = std.fmt.bufPrint(procfs_buf[0..], "/proc/self/fd/{}\x00", fd) catch unreachable;
2290
2291 return readlinkC(proc_path.ptr, out_buffer);
2292 }
2293 const result_path = std.c.realpath(pathname, out_buffer) orelse switch (std.c._errno().*) {
2294 EINVAL => unreachable,
2295 EBADF => unreachable,
2296 EFAULT => unreachable,
2297 EACCES => return error.AccessDenied,
2298 ENOENT => return error.FileNotFound,
2299 ENOTSUP => return error.NotSupported,
2300 ENOTDIR => return error.NotDir,
2301 ENAMETOOLONG => return error.NameTooLong,
2302 ELOOP => return error.SymLinkLoop,
2303 EIO => return error.InputOutput,
2304 else => |err| return unexpectedErrno(@intCast(usize, err)),
2305 };
2306 return mem.toSlice(u8, result_path);
2307}
2308
2309/// Same as `realpath` except `pathname` is null-terminated and UTF16LE-encoded.
2310pub fn realpathW(pathname: [*]const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
2311 const h_file = try windows.CreateFileW(
2312 pathname,
2313 windows.GENERIC_READ,
2314 windows.FILE_SHARE_READ,
2315 null,
2316 windows.OPEN_EXISTING,
2317 windows.FILE_ATTRIBUTE_NORMAL,
2318 null,
2319 );
2320 defer windows.CloseHandle(h_file);
2321
2322 var wide_buf: [windows.PATH_MAX_WIDE]u16 = undefined;
2323 const wide_len = try windows.GetFinalPathNameByHandleW(h_file, &wide_buf, wide_buf.len, windows.VOLUME_NAME_DOS);
2324 assert(wide_len <= wide_buf.len);
2325 const wide_slice = wide_buf[0..wide_len];
2326
2327 // Windows returns \\?\ prepended to the path.
2328 // We strip it to make this function consistent across platforms.
2329 const prefix = []u16{ '\\', '\\', '?', '\\' };
2330 const start_index = if (mem.startsWith(u16, wide_slice, prefix)) prefix.len else 0;
2331
2332 // Trust that Windows gives us valid UTF-16LE.
2333 const end_index = std.unicode.utf16leToUtf8(out_buffer, wide_slice[start_index..]) catch unreachable;
2334 return out_buffer[0..end_index];
2335}
2336
2337/// Spurious wakeups are possible and no precision of timing is guaranteed.
2338pub fn nanosleep(seconds: u64, nanoseconds: u64) void {
2339 var req = timespec{
2340 .tv_sec = math.cast(isize, seconds) catch math.maxInt(isize),
2341 .tv_nsec = math.cast(isize, nanoseconds) catch math.maxInt(isize),
2342 };
2343 var rem: timespec = undefined;
3447 while (true) {2344 while (true) {
3448 const rc = posix.kevent(kq, changelist, eventlist, timeout);2345 switch (errno(system.nanosleep(&req, &rem))) {
3449 const err = posix.getErrno(rc);2346 EFAULT => unreachable,
3450 switch (err) {2347 EINVAL => {
3451 0 => return rc,2348 // Sometimes Darwin returns EINVAL for no reason.
3452 posix.EACCES => return BsdKEventError.AccessDenied,2349 // We treat it as a spurious wakeup.
3453 posix.EFAULT => unreachable,2350 return;
3454 posix.EBADF => unreachable,2351 },
3455 posix.EINTR => continue,2352 EINTR => {
3456 posix.EINVAL => unreachable,2353 req = rem;
3457 posix.ENOENT => return BsdKEventError.EventNotFound,2354 continue;
3458 posix.ENOMEM => return BsdKEventError.SystemResources,2355 },
3459 posix.ESRCH => return BsdKEventError.ProcessNotFound,2356 // This prong handles success as well as unexpected errors.
3460 else => unreachable,2357 else => return,
3461 }2358 }
3462 }2359 }
3463}2360}
34642361
3465pub fn linuxINotifyInit1(flags: u32) !i32 {2362pub const ClockGetTimeError = error{
3466 const rc = linux.inotify_init1(flags);2363 UnsupportedClock,
3467 const err = posix.getErrno(rc);2364 Unexpected,
3468 switch (err) {2365};
3469 0 => return @intCast(i32, rc),2366
3470 posix.EINVAL => unreachable,2367pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void {
3471 posix.EMFILE => return error.ProcessFdQuotaExceeded,2368 switch (errno(system.clock_gettime(clk_id, tp))) {
3472 posix.ENFILE => return error.SystemFdQuotaExceeded,2369 0 => return,
3473 posix.ENOMEM => return error.SystemResources,2370 EFAULT => unreachable,
3474 else => return unexpectedErrorPosix(err),2371 EINVAL => return error.UnsupportedClock,
2372 else => |err| return unexpectedErrno(err),
3475 }2373 }
3476}2374}
34772375
3478pub fn linuxINotifyAddWatchC(inotify_fd: i32, pathname: [*]const u8, mask: u32) !i32 {2376pub fn clock_getres(clk_id: i32, res: *timespec) ClockGetTimeError!void {
3479 const rc = linux.inotify_add_watch(inotify_fd, pathname, mask);2377 switch (errno(system.clock_getres(clk_id, res))) {
3480 const err = posix.getErrno(rc);2378 0 => return,
3481 switch (err) {2379 EFAULT => unreachable,
3482 0 => return @intCast(i32, rc),2380 EINVAL => return error.UnsupportedClock,
3483 posix.EACCES => return error.AccessDenied,2381 else => |err| return unexpectedErrno(err),
3484 posix.EBADF => unreachable,
3485 posix.EFAULT => unreachable,
3486 posix.EINVAL => unreachable,
3487 posix.ENAMETOOLONG => return error.NameTooLong,
3488 posix.ENOENT => return error.FileNotFound,
3489 posix.ENOMEM => return error.SystemResources,
3490 posix.ENOSPC => return error.UserResourceLimitReached,
3491 else => return unexpectedErrorPosix(err),
3492 }2382 }
3493}2383}
34942384
3495pub fn linuxINotifyRmWatch(inotify_fd: i32, wd: i32) !void {2385pub const SchedGetAffinityError = error{
3496 const rc = linux.inotify_rm_watch(inotify_fd, wd);2386 PermissionDenied,
3497 const err = posix.getErrno(rc);2387 Unexpected,
3498 switch (err) {2388};
3499 0 => return rc,2389
3500 posix.EBADF => unreachable,2390pub fn sched_getaffinity(pid: pid_t) SchedGetAffinityError!cpu_set_t {
3501 posix.EINVAL => unreachable,2391 var set: cpu_set_t = undefined;
3502 else => unreachable,2392 switch (errno(system.sched_getaffinity(pid, @sizeOf(cpu_set_t), &set))) {
2393 0 => return set,
2394 EFAULT => unreachable,
2395 EINVAL => unreachable,
2396 ESRCH => unreachable,
2397 EPERM => return error.PermissionDenied,
2398 else => |err| return unexpectedErrno(err),
3503 }2399 }
3504}2400}
35052401
3506pub const MProtectError = error{2402/// Used to convert a slice to a null terminated slice on the stack.
3507 AccessDenied,2403/// TODO https://github.com/ziglang/zig/issues/287
3508 OutOfMemory,2404pub fn toPosixPath(file_path: []const u8) ![PATH_MAX]u8 {
2405 var path_with_null: [PATH_MAX]u8 = undefined;
2406 // >= rather than > to make room for the null byte
2407 if (file_path.len >= PATH_MAX) return error.NameTooLong;
2408 mem.copy(u8, &path_with_null, file_path);
2409 path_with_null[file_path.len] = 0;
2410 return path_with_null;
2411}
2412
2413/// Whether or not error.Unexpected will print its value and a stack trace.
2414/// if this happens the fix is to add the error code to the corresponding
2415/// switch expression, possibly introduce a new error in the error set, and
2416/// send a patch to Zig.
2417pub const unexpected_error_tracing = builtin.mode == .Debug;
2418
2419pub const UnexpectedError = error{
2420 /// The Operating System returned an undocumented error code.
2421 /// This error is in theory not possible, but it would be better
2422 /// to handle this error than to invoke undefined behavior.
3509 Unexpected,2423 Unexpected,
3510};2424};
35112425
3512/// address and length must be page-aligned2426/// Call this when you made a syscall or something that sets errno
3513pub fn posixMProtect(address: usize, length: usize, protection: u32) MProtectError!void {2427/// and you get an unexpected error.
3514 const negative_page_size = @bitCast(usize, -isize(page_size));2428pub fn unexpectedErrno(err: usize) UnexpectedError {
3515 const aligned_address = address & negative_page_size;2429 if (unexpected_error_tracing) {
3516 const aligned_end = (address + length + page_size - 1) & negative_page_size;2430 std.debug.warn("unexpected errno: {}\n", err);
3517 assert(address == aligned_address);2431 std.debug.dumpCurrentStackTrace(null);
3518 assert(length == aligned_end - aligned_address);
3519 const rc = posix.mprotect(address, length, protection);
3520 const err = posix.getErrno(rc);
3521 switch (err) {
3522 0 => return,
3523 posix.EINVAL => unreachable,
3524 posix.EACCES => return error.AccessDenied,
3525 posix.ENOMEM => return error.OutOfMemory,
3526 else => return unexpectedErrorPosix(err),
3527 }2432 }
2433 return error.Unexpected;
2434}
2435
2436test "" {
2437 _ = @import("os/darwin.zig");
2438 _ = @import("os/freebsd.zig");
2439 _ = @import("os/linux.zig");
2440 _ = @import("os/netbsd.zig");
2441 _ = @import("os/uefi.zig");
2442 _ = @import("os/wasi.zig");
2443 _ = @import("os/windows.zig");
2444 _ = @import("os/zen.zig");
2445
2446 _ = @import("os/test.zig");
3528}2447}
std/os/bits.zig created+27
...@@ -0,0 +1,27 @@
1// Platform-dependent types and values that are used along with OS-specific APIs.
2// These are imported into `std.c`, `std.os`, and `std.os.linux`.
3
4const builtin = @import("builtin");
5
6pub use switch (builtin.os) {
7 .macosx, .ios, .tvos, .watchos => @import("bits/darwin.zig"),
8 .freebsd => @import("bits/freebsd.zig"),
9 .linux => @import("bits/linux.zig"),
10 .netbsd => @import("bits/netbsd.zig"),
11 .wasi => @import("bits/wasi.zig"),
12 .windows => @import("bits/windows.zig"),
13 else => struct {},
14};
15
16pub const pthread_t = *@OpaqueType();
17pub const FILE = @OpaqueType();
18
19pub const iovec = extern struct {
20 iov_base: [*]u8,
21 iov_len: usize,
22};
23
24pub const iovec_const = extern struct {
25 iov_base: [*]const u8,
26 iov_len: usize,
27};
std/os/bits/darwin.zig created+1080
...@@ -0,0 +1,1080 @@
1const std = @import("../../std.zig");
2const assert = std.debug.assert;
3const maxInt = std.math.maxInt;
4
5pub const fd_t = c_int;
6pub const pid_t = c_int;
7
8pub const in_port_t = u16;
9pub const sa_family_t = u8;
10pub const socklen_t = u32;
11pub const sockaddr = extern union {
12 in: sockaddr_in,
13 in6: sockaddr_in6,
14};
15pub const sockaddr_in = extern struct {
16 len: u8,
17 family: sa_family_t,
18 port: in_port_t,
19 addr: u32,
20 zero: [8]u8,
21};
22pub const sockaddr_in6 = extern struct {
23 len: u8,
24 family: sa_family_t,
25 port: in_port_t,
26 flowinfo: u32,
27 addr: [16]u8,
28 scope_id: u32,
29};
30
31pub const timeval = extern struct {
32 tv_sec: c_long,
33 tv_usec: i32,
34};
35
36pub const timezone = extern struct {
37 tz_minuteswest: i32,
38 tz_dsttime: i32,
39};
40
41pub const mach_timebase_info_data = extern struct {
42 numer: u32,
43 denom: u32,
44};
45
46/// Renamed to Stat to not conflict with the stat function.
47pub const Stat = extern struct {
48 dev: i32,
49 mode: u16,
50 nlink: u16,
51 ino: u64,
52 uid: u32,
53 gid: u32,
54 rdev: i32,
55 atime: usize,
56 atimensec: usize,
57 mtime: usize,
58 mtimensec: usize,
59 ctime: usize,
60 ctimensec: usize,
61 birthtime: usize,
62 birthtimensec: usize,
63 size: i64,
64 blocks: i64,
65 blksize: i32,
66 flags: u32,
67 gen: u32,
68 lspare: i32,
69 qspare: [2]i64,
70};
71
72pub const timespec = extern struct {
73 tv_sec: isize,
74 tv_nsec: isize,
75};
76
77pub const sigset_t = u32;
78pub const empty_sigset = sigset_t(0);
79
80/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.
81pub const Sigaction = extern struct {
82 handler: extern fn (c_int) void,
83 sa_mask: sigset_t,
84 sa_flags: c_int,
85};
86
87pub const dirent = extern struct {
88 d_ino: usize,
89 d_seekoff: usize,
90 d_reclen: u16,
91 d_namlen: u16,
92 d_type: u8,
93 d_name: u8, // field address is address of first byte of name
94};
95
96pub const pthread_attr_t = extern struct {
97 __sig: c_long,
98 __opaque: [56]u8,
99};
100
101/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
102pub const Kevent = extern struct {
103 ident: usize,
104 filter: i16,
105 flags: u16,
106 fflags: u32,
107 data: isize,
108 udata: usize,
109};
110
111// sys/types.h on macos uses #pragma pack(4) so these checks are
112// to make sure the struct is laid out the same. These values were
113// produced from C code using the offsetof macro.
114comptime {
115 assert(@byteOffsetOf(Kevent, "ident") == 0);
116 assert(@byteOffsetOf(Kevent, "filter") == 8);
117 assert(@byteOffsetOf(Kevent, "flags") == 10);
118 assert(@byteOffsetOf(Kevent, "fflags") == 12);
119 assert(@byteOffsetOf(Kevent, "data") == 16);
120 assert(@byteOffsetOf(Kevent, "udata") == 24);
121}
122
123pub const kevent64_s = extern struct {
124 ident: u64,
125 filter: i16,
126 flags: u16,
127 fflags: u32,
128 data: i64,
129 udata: u64,
130 ext: [2]u64,
131};
132
133// sys/types.h on macos uses #pragma pack() so these checks are
134// to make sure the struct is laid out the same. These values were
135// produced from C code using the offsetof macro.
136comptime {
137 assert(@byteOffsetOf(kevent64_s, "ident") == 0);
138 assert(@byteOffsetOf(kevent64_s, "filter") == 8);
139 assert(@byteOffsetOf(kevent64_s, "flags") == 10);
140 assert(@byteOffsetOf(kevent64_s, "fflags") == 12);
141 assert(@byteOffsetOf(kevent64_s, "data") == 16);
142 assert(@byteOffsetOf(kevent64_s, "udata") == 24);
143 assert(@byteOffsetOf(kevent64_s, "ext") == 32);
144}
145
146pub const mach_port_t = c_uint;
147pub const clock_serv_t = mach_port_t;
148pub const clock_res_t = c_int;
149pub const mach_port_name_t = natural_t;
150pub const natural_t = c_uint;
151pub const mach_timespec_t = extern struct {
152 tv_sec: c_uint,
153 tv_nsec: clock_res_t,
154};
155pub const kern_return_t = c_int;
156pub const host_t = mach_port_t;
157pub const CALENDAR_CLOCK = 1;
158
159pub const PATH_MAX = 1024;
160
161pub const STDIN_FILENO = 0;
162pub const STDOUT_FILENO = 1;
163pub const STDERR_FILENO = 2;
164
165/// [MC2] no permissions
166pub const PROT_NONE = 0x00;
167
168/// [MC2] pages can be read
169pub const PROT_READ = 0x01;
170
171/// [MC2] pages can be written
172pub const PROT_WRITE = 0x02;
173
174/// [MC2] pages can be executed
175pub const PROT_EXEC = 0x04;
176
177/// allocated from memory, swap space
178pub const MAP_ANONYMOUS = 0x1000;
179
180/// map from file (default)
181pub const MAP_FILE = 0x0000;
182
183/// interpret addr exactly
184pub const MAP_FIXED = 0x0010;
185
186/// region may contain semaphores
187pub const MAP_HASSEMAPHORE = 0x0200;
188
189/// changes are private
190pub const MAP_PRIVATE = 0x0002;
191
192/// share changes
193pub const MAP_SHARED = 0x0001;
194
195/// don't cache pages for this mapping
196pub const MAP_NOCACHE = 0x0400;
197
198/// don't reserve needed swap area
199pub const MAP_NORESERVE = 0x0040;
200pub const MAP_FAILED = @intToPtr(*c_void, maxInt(usize));
201
202/// [XSI] no hang in wait/no child to reap
203pub const WNOHANG = 0x00000001;
204
205/// [XSI] notify on stop, untraced child
206pub const WUNTRACED = 0x00000002;
207
208/// take signal on signal stack
209pub const SA_ONSTACK = 0x0001;
210
211/// restart system on signal return
212pub const SA_RESTART = 0x0002;
213
214/// reset to SIG_DFL when taking signal
215pub const SA_RESETHAND = 0x0004;
216
217/// do not generate SIGCHLD on child stop
218pub const SA_NOCLDSTOP = 0x0008;
219
220/// don't mask the signal we're delivering
221pub const SA_NODEFER = 0x0010;
222
223/// don't keep zombies around
224pub const SA_NOCLDWAIT = 0x0020;
225
226/// signal handler with SA_SIGINFO args
227pub const SA_SIGINFO = 0x0040;
228
229/// do not bounce off kernel's sigtramp
230pub const SA_USERTRAMP = 0x0100;
231
232/// signal handler with SA_SIGINFO args with 64bit regs information
233pub const SA_64REGSET = 0x0200;
234
235pub const O_LARGEFILE = 0x0000;
236pub const O_PATH = 0x0000;
237
238pub const F_OK = 0;
239pub const X_OK = 1;
240pub const W_OK = 2;
241pub const R_OK = 4;
242
243/// open for reading only
244pub const O_RDONLY = 0x0000;
245
246/// open for writing only
247pub const O_WRONLY = 0x0001;
248
249/// open for reading and writing
250pub const O_RDWR = 0x0002;
251
252/// do not block on open or for data to become available
253pub const O_NONBLOCK = 0x0004;
254
255/// append on each write
256pub const O_APPEND = 0x0008;
257
258/// create file if it does not exist
259pub const O_CREAT = 0x0200;
260
261/// truncate size to 0
262pub const O_TRUNC = 0x0400;
263
264/// error if O_CREAT and the file exists
265pub const O_EXCL = 0x0800;
266
267/// atomically obtain a shared lock
268pub const O_SHLOCK = 0x0010;
269
270/// atomically obtain an exclusive lock
271pub const O_EXLOCK = 0x0020;
272
273/// do not follow symlinks
274pub const O_NOFOLLOW = 0x0100;
275
276/// allow open of symlinks
277pub const O_SYMLINK = 0x200000;
278
279/// descriptor requested for event notifications only
280pub const O_EVTONLY = 0x8000;
281
282/// mark as close-on-exec
283pub const O_CLOEXEC = 0x1000000;
284
285pub const O_ACCMODE = 3;
286pub const O_ALERT = 536870912;
287pub const O_ASYNC = 64;
288pub const O_DIRECTORY = 1048576;
289pub const O_DP_GETRAWENCRYPTED = 1;
290pub const O_DP_GETRAWUNENCRYPTED = 2;
291pub const O_DSYNC = 4194304;
292pub const O_FSYNC = O_SYNC;
293pub const O_NOCTTY = 131072;
294pub const O_POPUP = 2147483648;
295pub const O_SYNC = 128;
296
297pub const SEEK_SET = 0x0;
298pub const SEEK_CUR = 0x1;
299pub const SEEK_END = 0x2;
300
301pub const DT_UNKNOWN = 0;
302pub const DT_FIFO = 1;
303pub const DT_CHR = 2;
304pub const DT_DIR = 4;
305pub const DT_BLK = 6;
306pub const DT_REG = 8;
307pub const DT_LNK = 10;
308pub const DT_SOCK = 12;
309pub const DT_WHT = 14;
310
311/// block specified signal set
312pub const SIG_BLOCK = 1;
313
314/// unblock specified signal set
315pub const SIG_UNBLOCK = 2;
316
317/// set specified signal set
318pub const SIG_SETMASK = 3;
319
320/// hangup
321pub const SIGHUP = 1;
322
323/// interrupt
324pub const SIGINT = 2;
325
326/// quit
327pub const SIGQUIT = 3;
328
329/// illegal instruction (not reset when caught)
330pub const SIGILL = 4;
331
332/// trace trap (not reset when caught)
333pub const SIGTRAP = 5;
334
335/// abort()
336pub const SIGABRT = 6;
337
338/// pollable event ([XSR] generated, not supported)
339pub const SIGPOLL = 7;
340
341/// compatibility
342pub const SIGIOT = SIGABRT;
343
344/// EMT instruction
345pub const SIGEMT = 7;
346
347/// floating point exception
348pub const SIGFPE = 8;
349
350/// kill (cannot be caught or ignored)
351pub const SIGKILL = 9;
352
353/// bus error
354pub const SIGBUS = 10;
355
356/// segmentation violation
357pub const SIGSEGV = 11;
358
359/// bad argument to system call
360pub const SIGSYS = 12;
361
362/// write on a pipe with no one to read it
363pub const SIGPIPE = 13;
364
365/// alarm clock
366pub const SIGALRM = 14;
367
368/// software termination signal from kill
369pub const SIGTERM = 15;
370
371/// urgent condition on IO channel
372pub const SIGURG = 16;
373
374/// sendable stop signal not from tty
375pub const SIGSTOP = 17;
376
377/// stop signal from tty
378pub const SIGTSTP = 18;
379
380/// continue a stopped process
381pub const SIGCONT = 19;
382
383/// to parent on child stop or exit
384pub const SIGCHLD = 20;
385
386/// to readers pgrp upon background tty read
387pub const SIGTTIN = 21;
388
389/// like TTIN for output if (tp->t_local&LTOSTOP)
390pub const SIGTTOU = 22;
391
392/// input/output possible signal
393pub const SIGIO = 23;
394
395/// exceeded CPU time limit
396pub const SIGXCPU = 24;
397
398/// exceeded file size limit
399pub const SIGXFSZ = 25;
400
401/// virtual time alarm
402pub const SIGVTALRM = 26;
403
404/// profiling time alarm
405pub const SIGPROF = 27;
406
407/// window size changes
408pub const SIGWINCH = 28;
409
410/// information request
411pub const SIGINFO = 29;
412
413/// user defined signal 1
414pub const SIGUSR1 = 30;
415
416/// user defined signal 2
417pub const SIGUSR2 = 31;
418
419/// no flag value
420pub const KEVENT_FLAG_NONE = 0x000;
421
422/// immediate timeout
423pub const KEVENT_FLAG_IMMEDIATE = 0x001;
424
425/// output events only include change
426pub const KEVENT_FLAG_ERROR_EVENTS = 0x002;
427
428/// add event to kq (implies enable)
429pub const EV_ADD = 0x0001;
430
431/// delete event from kq
432pub const EV_DELETE = 0x0002;
433
434/// enable event
435pub const EV_ENABLE = 0x0004;
436
437/// disable event (not reported)
438pub const EV_DISABLE = 0x0008;
439
440/// only report one occurrence
441pub const EV_ONESHOT = 0x0010;
442
443/// clear event state after reporting
444pub const EV_CLEAR = 0x0020;
445
446/// force immediate event output
447/// ... with or without EV_ERROR
448/// ... use KEVENT_FLAG_ERROR_EVENTS
449/// on syscalls supporting flags
450pub const EV_RECEIPT = 0x0040;
451
452/// disable event after reporting
453pub const EV_DISPATCH = 0x0080;
454
455/// unique kevent per udata value
456pub const EV_UDATA_SPECIFIC = 0x0100;
457
458/// ... in combination with EV_DELETE
459/// will defer delete until udata-specific
460/// event enabled. EINPROGRESS will be
461/// returned to indicate the deferral
462pub const EV_DISPATCH2 = EV_DISPATCH | EV_UDATA_SPECIFIC;
463
464/// report that source has vanished
465/// ... only valid with EV_DISPATCH2
466pub const EV_VANISHED = 0x0200;
467
468/// reserved by system
469pub const EV_SYSFLAGS = 0xF000;
470
471/// filter-specific flag
472pub const EV_FLAG0 = 0x1000;
473
474/// filter-specific flag
475pub const EV_FLAG1 = 0x2000;
476
477/// EOF detected
478pub const EV_EOF = 0x8000;
479
480/// error, data contains errno
481pub const EV_ERROR = 0x4000;
482
483pub const EV_POLL = EV_FLAG0;
484pub const EV_OOBAND = EV_FLAG1;
485
486pub const EVFILT_READ = -1;
487pub const EVFILT_WRITE = -2;
488
489/// attached to aio requests
490pub const EVFILT_AIO = -3;
491
492/// attached to vnodes
493pub const EVFILT_VNODE = -4;
494
495/// attached to struct proc
496pub const EVFILT_PROC = -5;
497
498/// attached to struct proc
499pub const EVFILT_SIGNAL = -6;
500
501/// timers
502pub const EVFILT_TIMER = -7;
503
504/// Mach portsets
505pub const EVFILT_MACHPORT = -8;
506
507/// Filesystem events
508pub const EVFILT_FS = -9;
509
510/// User events
511pub const EVFILT_USER = -10;
512
513/// Virtual memory events
514pub const EVFILT_VM = -12;
515
516/// Exception events
517pub const EVFILT_EXCEPT = -15;
518
519pub const EVFILT_SYSCOUNT = 17;
520
521/// On input, NOTE_TRIGGER causes the event to be triggered for output.
522pub const NOTE_TRIGGER = 0x01000000;
523
524/// ignore input fflags
525pub const NOTE_FFNOP = 0x00000000;
526
527/// and fflags
528pub const NOTE_FFAND = 0x40000000;
529
530/// or fflags
531pub const NOTE_FFOR = 0x80000000;
532
533/// copy fflags
534pub const NOTE_FFCOPY = 0xc0000000;
535
536/// mask for operations
537pub const NOTE_FFCTRLMASK = 0xc0000000;
538pub const NOTE_FFLAGSMASK = 0x00ffffff;
539
540/// low water mark
541pub const NOTE_LOWAT = 0x00000001;
542
543/// OOB data
544pub const NOTE_OOB = 0x00000002;
545
546/// vnode was removed
547pub const NOTE_DELETE = 0x00000001;
548
549/// data contents changed
550pub const NOTE_WRITE = 0x00000002;
551
552/// size increased
553pub const NOTE_EXTEND = 0x00000004;
554
555/// attributes changed
556pub const NOTE_ATTRIB = 0x00000008;
557
558/// link count changed
559pub const NOTE_LINK = 0x00000010;
560
561/// vnode was renamed
562pub const NOTE_RENAME = 0x00000020;
563
564/// vnode access was revoked
565pub const NOTE_REVOKE = 0x00000040;
566
567/// No specific vnode event: to test for EVFILT_READ activation
568pub const NOTE_NONE = 0x00000080;
569
570/// vnode was unlocked by flock(2)
571pub const NOTE_FUNLOCK = 0x00000100;
572
573/// process exited
574pub const NOTE_EXIT = 0x80000000;
575
576/// process forked
577pub const NOTE_FORK = 0x40000000;
578
579/// process exec'd
580pub const NOTE_EXEC = 0x20000000;
581
582/// shared with EVFILT_SIGNAL
583pub const NOTE_SIGNAL = 0x08000000;
584
585/// exit status to be returned, valid for child process only
586pub const NOTE_EXITSTATUS = 0x04000000;
587
588/// provide details on reasons for exit
589pub const NOTE_EXIT_DETAIL = 0x02000000;
590
591/// mask for signal & exit status
592pub const NOTE_PDATAMASK = 0x000fffff;
593pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK);
594
595pub const NOTE_EXIT_DETAIL_MASK = 0x00070000;
596pub const NOTE_EXIT_DECRYPTFAIL = 0x00010000;
597pub const NOTE_EXIT_MEMORY = 0x00020000;
598pub const NOTE_EXIT_CSERROR = 0x00040000;
599
600/// will react on memory pressure
601pub const NOTE_VM_PRESSURE = 0x80000000;
602
603/// will quit on memory pressure, possibly after cleaning up dirty state
604pub const NOTE_VM_PRESSURE_TERMINATE = 0x40000000;
605
606/// will quit immediately on memory pressure
607pub const NOTE_VM_PRESSURE_SUDDEN_TERMINATE = 0x20000000;
608
609/// there was an error
610pub const NOTE_VM_ERROR = 0x10000000;
611
612/// data is seconds
613pub const NOTE_SECONDS = 0x00000001;
614
615/// data is microseconds
616pub const NOTE_USECONDS = 0x00000002;
617
618/// data is nanoseconds
619pub const NOTE_NSECONDS = 0x00000004;
620
621/// absolute timeout
622pub const NOTE_ABSOLUTE = 0x00000008;
623
624/// ext[1] holds leeway for power aware timers
625pub const NOTE_LEEWAY = 0x00000010;
626
627/// system does minimal timer coalescing
628pub const NOTE_CRITICAL = 0x00000020;
629
630/// system does maximum timer coalescing
631pub const NOTE_BACKGROUND = 0x00000040;
632pub const NOTE_MACH_CONTINUOUS_TIME = 0x00000080;
633
634/// data is mach absolute time units
635pub const NOTE_MACHTIME = 0x00000100;
636
637pub const AF_UNSPEC = 0;
638pub const AF_LOCAL = 1;
639pub const AF_UNIX = AF_LOCAL;
640pub const AF_INET = 2;
641pub const AF_SYS_CONTROL = 2;
642pub const AF_IMPLINK = 3;
643pub const AF_PUP = 4;
644pub const AF_CHAOS = 5;
645pub const AF_NS = 6;
646pub const AF_ISO = 7;
647pub const AF_OSI = AF_ISO;
648pub const AF_ECMA = 8;
649pub const AF_DATAKIT = 9;
650pub const AF_CCITT = 10;
651pub const AF_SNA = 11;
652pub const AF_DECnet = 12;
653pub const AF_DLI = 13;
654pub const AF_LAT = 14;
655pub const AF_HYLINK = 15;
656pub const AF_APPLETALK = 16;
657pub const AF_ROUTE = 17;
658pub const AF_LINK = 18;
659pub const AF_XTP = 19;
660pub const AF_COIP = 20;
661pub const AF_CNT = 21;
662pub const AF_RTIP = 22;
663pub const AF_IPX = 23;
664pub const AF_SIP = 24;
665pub const AF_PIP = 25;
666pub const AF_ISDN = 28;
667pub const AF_E164 = AF_ISDN;
668pub const AF_KEY = 29;
669pub const AF_INET6 = 30;
670pub const AF_NATM = 31;
671pub const AF_SYSTEM = 32;
672pub const AF_NETBIOS = 33;
673pub const AF_PPP = 34;
674pub const AF_MAX = 40;
675
676pub const PF_UNSPEC = AF_UNSPEC;
677pub const PF_LOCAL = AF_LOCAL;
678pub const PF_UNIX = PF_LOCAL;
679pub const PF_INET = AF_INET;
680pub const PF_IMPLINK = AF_IMPLINK;
681pub const PF_PUP = AF_PUP;
682pub const PF_CHAOS = AF_CHAOS;
683pub const PF_NS = AF_NS;
684pub const PF_ISO = AF_ISO;
685pub const PF_OSI = AF_ISO;
686pub const PF_ECMA = AF_ECMA;
687pub const PF_DATAKIT = AF_DATAKIT;
688pub const PF_CCITT = AF_CCITT;
689pub const PF_SNA = AF_SNA;
690pub const PF_DECnet = AF_DECnet;
691pub const PF_DLI = AF_DLI;
692pub const PF_LAT = AF_LAT;
693pub const PF_HYLINK = AF_HYLINK;
694pub const PF_APPLETALK = AF_APPLETALK;
695pub const PF_ROUTE = AF_ROUTE;
696pub const PF_LINK = AF_LINK;
697pub const PF_XTP = AF_XTP;
698pub const PF_COIP = AF_COIP;
699pub const PF_CNT = AF_CNT;
700pub const PF_SIP = AF_SIP;
701pub const PF_IPX = AF_IPX;
702pub const PF_RTIP = AF_RTIP;
703pub const PF_PIP = AF_PIP;
704pub const PF_ISDN = AF_ISDN;
705pub const PF_KEY = AF_KEY;
706pub const PF_INET6 = AF_INET6;
707pub const PF_NATM = AF_NATM;
708pub const PF_SYSTEM = AF_SYSTEM;
709pub const PF_NETBIOS = AF_NETBIOS;
710pub const PF_PPP = AF_PPP;
711pub const PF_MAX = AF_MAX;
712
713pub const SYSPROTO_EVENT = 1;
714pub const SYSPROTO_CONTROL = 2;
715
716pub const SOCK_STREAM = 1;
717pub const SOCK_DGRAM = 2;
718pub const SOCK_RAW = 3;
719pub const SOCK_RDM = 4;
720pub const SOCK_SEQPACKET = 5;
721pub const SOCK_MAXADDRLEN = 255;
722
723pub const IPPROTO_ICMP = 1;
724pub const IPPROTO_ICMPV6 = 58;
725pub const IPPROTO_TCP = 6;
726pub const IPPROTO_UDP = 17;
727pub const IPPROTO_IP = 0;
728pub const IPPROTO_IPV6 = 41;
729
730fn wstatus(x: u32) u32 {
731 return x & 0o177;
732}
733const wstopped = 0o177;
734pub fn WEXITSTATUS(x: u32) u32 {
735 return x >> 8;
736}
737pub fn WTERMSIG(x: u32) u32 {
738 return wstatus(x);
739}
740pub fn WSTOPSIG(x: u32) u32 {
741 return x >> 8;
742}
743pub fn WIFEXITED(x: u32) bool {
744 return wstatus(x) == 0;
745}
746pub fn WIFSTOPPED(x: u32) bool {
747 return wstatus(x) == wstopped and WSTOPSIG(x) != 0x13;
748}
749pub fn WIFSIGNALED(x: u32) bool {
750 return wstatus(x) != wstopped and wstatus(x) != 0;
751}
752
753/// Operation not permitted
754pub const EPERM = 1;
755
756/// No such file or directory
757pub const ENOENT = 2;
758
759/// No such process
760pub const ESRCH = 3;
761
762/// Interrupted system call
763pub const EINTR = 4;
764
765/// Input/output error
766pub const EIO = 5;
767
768/// Device not configured
769pub const ENXIO = 6;
770
771/// Argument list too long
772pub const E2BIG = 7;
773
774/// Exec format error
775pub const ENOEXEC = 8;
776
777/// Bad file descriptor
778pub const EBADF = 9;
779
780/// No child processes
781pub const ECHILD = 10;
782
783/// Resource deadlock avoided
784pub const EDEADLK = 11;
785
786/// Cannot allocate memory
787pub const ENOMEM = 12;
788
789/// Permission denied
790pub const EACCES = 13;
791
792/// Bad address
793pub const EFAULT = 14;
794
795/// Block device required
796pub const ENOTBLK = 15;
797
798/// Device / Resource busy
799pub const EBUSY = 16;
800
801/// File exists
802pub const EEXIST = 17;
803
804/// Cross-device link
805pub const EXDEV = 18;
806
807/// Operation not supported by device
808pub const ENODEV = 19;
809
810/// Not a directory
811pub const ENOTDIR = 20;
812
813/// Is a directory
814pub const EISDIR = 21;
815
816/// Invalid argument
817pub const EINVAL = 22;
818
819/// Too many open files in system
820pub const ENFILE = 23;
821
822/// Too many open files
823pub const EMFILE = 24;
824
825/// Inappropriate ioctl for device
826pub const ENOTTY = 25;
827
828/// Text file busy
829pub const ETXTBSY = 26;
830
831/// File too large
832pub const EFBIG = 27;
833
834/// No space left on device
835pub const ENOSPC = 28;
836
837/// Illegal seek
838pub const ESPIPE = 29;
839
840/// Read-only file system
841pub const EROFS = 30;
842
843/// Too many links
844pub const EMLINK = 31;
845/// Broken pipe
846
847// math software
848pub const EPIPE = 32;
849
850/// Numerical argument out of domain
851pub const EDOM = 33;
852/// Result too large
853
854// non-blocking and interrupt i/o
855pub const ERANGE = 34;
856
857/// Resource temporarily unavailable
858pub const EAGAIN = 35;
859
860/// Operation would block
861pub const EWOULDBLOCK = EAGAIN;
862
863/// Operation now in progress
864pub const EINPROGRESS = 36;
865/// Operation already in progress
866
867// ipc/network software -- argument errors
868pub const EALREADY = 37;
869
870/// Socket operation on non-socket
871pub const ENOTSOCK = 38;
872
873/// Destination address required
874pub const EDESTADDRREQ = 39;
875
876/// Message too long
877pub const EMSGSIZE = 40;
878
879/// Protocol wrong type for socket
880pub const EPROTOTYPE = 41;
881
882/// Protocol not available
883pub const ENOPROTOOPT = 42;
884
885/// Protocol not supported
886pub const EPROTONOSUPPORT = 43;
887
888/// Socket type not supported
889pub const ESOCKTNOSUPPORT = 44;
890
891/// Operation not supported
892pub const ENOTSUP = 45;
893
894/// Protocol family not supported
895pub const EPFNOSUPPORT = 46;
896
897/// Address family not supported by protocol family
898pub const EAFNOSUPPORT = 47;
899
900/// Address already in use
901pub const EADDRINUSE = 48;
902/// Can't assign requested address
903
904// ipc/network software -- operational errors
905pub const EADDRNOTAVAIL = 49;
906
907/// Network is down
908pub const ENETDOWN = 50;
909
910/// Network is unreachable
911pub const ENETUNREACH = 51;
912
913/// Network dropped connection on reset
914pub const ENETRESET = 52;
915
916/// Software caused connection abort
917pub const ECONNABORTED = 53;
918
919/// Connection reset by peer
920pub const ECONNRESET = 54;
921
922/// No buffer space available
923pub const ENOBUFS = 55;
924
925/// Socket is already connected
926pub const EISCONN = 56;
927
928/// Socket is not connected
929pub const ENOTCONN = 57;
930
931/// Can't send after socket shutdown
932pub const ESHUTDOWN = 58;
933
934/// Too many references: can't splice
935pub const ETOOMANYREFS = 59;
936
937/// Operation timed out
938pub const ETIMEDOUT = 60;
939
940/// Connection refused
941pub const ECONNREFUSED = 61;
942
943/// Too many levels of symbolic links
944pub const ELOOP = 62;
945
946/// File name too long
947pub const ENAMETOOLONG = 63;
948
949/// Host is down
950pub const EHOSTDOWN = 64;
951
952/// No route to host
953pub const EHOSTUNREACH = 65;
954/// Directory not empty
955
956// quotas & mush
957pub const ENOTEMPTY = 66;
958
959/// Too many processes
960pub const EPROCLIM = 67;
961
962/// Too many users
963pub const EUSERS = 68;
964/// Disc quota exceeded
965
966// Network File System
967pub const EDQUOT = 69;
968
969/// Stale NFS file handle
970pub const ESTALE = 70;
971
972/// Too many levels of remote in path
973pub const EREMOTE = 71;
974
975/// RPC struct is bad
976pub const EBADRPC = 72;
977
978/// RPC version wrong
979pub const ERPCMISMATCH = 73;
980
981/// RPC prog. not avail
982pub const EPROGUNAVAIL = 74;
983
984/// Program version wrong
985pub const EPROGMISMATCH = 75;
986
987/// Bad procedure for program
988pub const EPROCUNAVAIL = 76;
989
990/// No locks available
991pub const ENOLCK = 77;
992
993/// Function not implemented
994pub const ENOSYS = 78;
995
996/// Inappropriate file type or format
997pub const EFTYPE = 79;
998
999/// Authentication error
1000pub const EAUTH = 80;
1001/// Need authenticator
1002
1003// Intelligent device errors
1004pub const ENEEDAUTH = 81;
1005
1006/// Device power is off
1007pub const EPWROFF = 82;
1008
1009/// Device error, e.g. paper out
1010pub const EDEVERR = 83;
1011/// Value too large to be stored in data type
1012
1013// Program loading errors
1014pub const EOVERFLOW = 84;
1015
1016/// Bad executable
1017pub const EBADEXEC = 85;
1018
1019/// Bad CPU type in executable
1020pub const EBADARCH = 86;
1021
1022/// Shared library version mismatch
1023pub const ESHLIBVERS = 87;
1024
1025/// Malformed Macho file
1026pub const EBADMACHO = 88;
1027
1028/// Operation canceled
1029pub const ECANCELED = 89;
1030
1031/// Identifier removed
1032pub const EIDRM = 90;
1033
1034/// No message of desired type
1035pub const ENOMSG = 91;
1036
1037/// Illegal byte sequence
1038pub const EILSEQ = 92;
1039
1040/// Attribute not found
1041pub const ENOATTR = 93;
1042
1043/// Bad message
1044pub const EBADMSG = 94;
1045
1046/// Reserved
1047pub const EMULTIHOP = 95;
1048
1049/// No message available on STREAM
1050pub const ENODATA = 96;
1051
1052/// Reserved
1053pub const ENOLINK = 97;
1054
1055/// No STREAM resources
1056pub const ENOSR = 98;
1057
1058/// Not a STREAM
1059pub const ENOSTR = 99;
1060
1061/// Protocol error
1062pub const EPROTO = 100;
1063
1064/// STREAM ioctl timeout
1065pub const ETIME = 101;
1066
1067/// No such policy registered
1068pub const ENOPOLICY = 103;
1069
1070/// State not recoverable
1071pub const ENOTRECOVERABLE = 104;
1072
1073/// Previous owner died
1074pub const EOWNERDEAD = 105;
1075
1076/// Interface output queue is full
1077pub const EQFULL = 106;
1078
1079/// Must be equal largest errno
1080pub const ELAST = 106;
std/os/bits/freebsd.zig created+837
...@@ -0,0 +1,837 @@
1const std = @import("../../std.zig");
2const maxInt = std.math.maxInt;
3
4pub const fd_t = c_int;
5pub const pid_t = c_int;
6
7/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
8pub const Kevent = extern struct {
9 ident: usize,
10 filter: i16,
11 flags: u16,
12 fflags: u32,
13 data: i64,
14 udata: usize,
15 // TODO ext
16};
17
18pub const pthread_attr_t = extern struct {
19 __size: [56]u8,
20 __align: c_long,
21};
22
23pub const msghdr = extern struct {
24 /// optional address
25 msg_name: ?*sockaddr,
26
27 /// size of address
28 msg_namelen: socklen_t,
29
30 /// scatter/gather array
31 msg_iov: [*]iovec,
32
33 /// # elements in msg_iov
34 msg_iovlen: i32,
35
36 /// ancillary data
37 msg_control: ?*c_void,
38
39 /// ancillary data buffer len
40 msg_controllen: socklen_t,
41
42 /// flags on received message
43 msg_flags: i32,
44};
45
46pub const msghdr_const = extern struct {
47 /// optional address
48 msg_name: ?*const sockaddr,
49
50 /// size of address
51 msg_namelen: socklen_t,
52
53 /// scatter/gather array
54 msg_iov: [*]iovec_const,
55
56 /// # elements in msg_iov
57 msg_iovlen: i32,
58
59 /// ancillary data
60 msg_control: ?*c_void,
61
62 /// ancillary data buffer len
63 msg_controllen: socklen_t,
64
65 /// flags on received message
66 msg_flags: i32,
67};
68
69pub const Stat = extern struct {
70 dev: u64,
71 ino: u64,
72 nlink: usize,
73
74 mode: u16,
75 __pad0: u16,
76 uid: u32,
77 gid: u32,
78 __pad1: u32,
79 rdev: u64,
80
81 atim: timespec,
82 mtim: timespec,
83 ctim: timespec,
84 birthtim: timespec,
85
86 size: i64,
87 blocks: i64,
88 blksize: isize,
89 flags: u32,
90 gen: u64,
91 __spare: [10]u64,
92};
93
94pub const timespec = extern struct {
95 tv_sec: isize,
96 tv_nsec: isize,
97};
98
99pub const dirent = extern struct {
100 d_fileno: usize,
101 d_off: i64,
102 d_reclen: u16,
103 d_type: u8,
104 d_pad0: u8,
105 d_namlen: u16,
106 d_pad1: u16,
107 d_name: [256]u8,
108};
109
110pub const in_port_t = u16;
111pub const sa_family_t = u16;
112
113pub const sockaddr = extern union {
114 in: sockaddr_in,
115 in6: sockaddr_in6,
116};
117
118pub const sockaddr_in = extern struct {
119 len: u8,
120 family: sa_family_t,
121 port: in_port_t,
122 addr: [16]u8,
123 zero: [8]u8,
124};
125
126pub const sockaddr_in6 = extern struct {
127 len: u8,
128 family: sa_family_t,
129 port: in_port_t,
130 flowinfo: u32,
131 addr: [16]u8,
132 scope_id: u32,
133};
134
135pub const CTL_KERN = 1;
136pub const CTL_DEBUG = 5;
137
138pub const KERN_PROC = 14; // struct: process entries
139pub const KERN_PROC_PATHNAME = 12; // path to executable
140
141pub const PATH_MAX = 1024;
142
143pub const STDIN_FILENO = 0;
144pub const STDOUT_FILENO = 1;
145pub const STDERR_FILENO = 2;
146
147pub const PROT_NONE = 0;
148pub const PROT_READ = 1;
149pub const PROT_WRITE = 2;
150pub const PROT_EXEC = 4;
151
152pub const CLOCK_REALTIME = 0;
153pub const CLOCK_VIRTUAL = 1;
154pub const CLOCK_PROF = 2;
155pub const CLOCK_MONOTONIC = 4;
156pub const CLOCK_UPTIME = 5;
157pub const CLOCK_UPTIME_PRECISE = 7;
158pub const CLOCK_UPTIME_FAST = 8;
159pub const CLOCK_REALTIME_PRECISE = 9;
160pub const CLOCK_REALTIME_FAST = 10;
161pub const CLOCK_MONOTONIC_PRECISE = 11;
162pub const CLOCK_MONOTONIC_FAST = 12;
163pub const CLOCK_SECOND = 13;
164pub const CLOCK_THREAD_CPUTIME_ID = 14;
165pub const CLOCK_PROCESS_CPUTIME_ID = 15;
166
167pub const MAP_FAILED = @intToPtr(*c_void, maxInt(usize));
168pub const MAP_SHARED = 0x0001;
169pub const MAP_PRIVATE = 0x0002;
170pub const MAP_FIXED = 0x0010;
171pub const MAP_STACK = 0x0400;
172pub const MAP_NOSYNC = 0x0800;
173pub const MAP_ANON = 0x1000;
174pub const MAP_ANONYMOUS = MAP_ANON;
175pub const MAP_FILE = 0;
176pub const MAP_NORESERVE = 0;
177
178pub const MAP_GUARD = 0x00002000;
179pub const MAP_EXCL = 0x00004000;
180pub const MAP_NOCORE = 0x00020000;
181pub const MAP_PREFAULT_READ = 0x00040000;
182pub const MAP_32BIT = 0x00080000;
183
184pub const WNOHANG = 1;
185pub const WUNTRACED = 2;
186pub const WSTOPPED = WUNTRACED;
187pub const WCONTINUED = 4;
188pub const WNOWAIT = 8;
189pub const WEXITED = 16;
190pub const WTRAPPED = 32;
191
192pub const SA_ONSTACK = 0x0001;
193pub const SA_RESTART = 0x0002;
194pub const SA_RESETHAND = 0x0004;
195pub const SA_NOCLDSTOP = 0x0008;
196pub const SA_NODEFER = 0x0010;
197pub const SA_NOCLDWAIT = 0x0020;
198pub const SA_SIGINFO = 0x0040;
199
200pub const SIGHUP = 1;
201pub const SIGINT = 2;
202pub const SIGQUIT = 3;
203pub const SIGILL = 4;
204pub const SIGTRAP = 5;
205pub const SIGABRT = 6;
206pub const SIGIOT = SIGABRT;
207pub const SIGEMT = 7;
208pub const SIGFPE = 8;
209pub const SIGKILL = 9;
210pub const SIGBUS = 10;
211pub const SIGSEGV = 11;
212pub const SIGSYS = 12;
213pub const SIGPIPE = 13;
214pub const SIGALRM = 14;
215pub const SIGTERM = 15;
216pub const SIGURG = 16;
217pub const SIGSTOP = 17;
218pub const SIGTSTP = 18;
219pub const SIGCONT = 19;
220pub const SIGCHLD = 20;
221pub const SIGTTIN = 21;
222pub const SIGTTOU = 22;
223pub const SIGIO = 23;
224pub const SIGXCPU = 24;
225pub const SIGXFSZ = 25;
226pub const SIGVTALRM = 26;
227pub const SIGPROF = 27;
228pub const SIGWINCH = 28;
229pub const SIGINFO = 29;
230pub const SIGUSR1 = 30;
231pub const SIGUSR2 = 31;
232pub const SIGTHR = 32;
233pub const SIGLWP = SIGTHR;
234pub const SIGLIBRT = 33;
235
236pub const SIGRTMIN = 65;
237pub const SIGRTMAX = 126;
238
239// access function
240pub const F_OK = 0; // test for existence of file
241pub const X_OK = 1; // test for execute or search permission
242pub const W_OK = 2; // test for write permission
243pub const R_OK = 4; // test for read permission
244
245pub const O_RDONLY = 0x0000;
246pub const O_WRONLY = 0x0001;
247pub const O_RDWR = 0x0002;
248pub const O_ACCMODE = 0x0003;
249
250pub const O_CREAT = 0x0200;
251pub const O_EXCL = 0x0800;
252pub const O_NOCTTY = 0x8000;
253pub const O_TRUNC = 0x0400;
254pub const O_APPEND = 0x0008;
255pub const O_NONBLOCK = 0x0004;
256pub const O_DSYNC = 0o10000;
257pub const O_SYNC = 0x0080;
258pub const O_RSYNC = 0o4010000;
259pub const O_DIRECTORY = 0o200000;
260pub const O_NOFOLLOW = 0x0100;
261pub const O_CLOEXEC = 0x00100000;
262
263pub const O_ASYNC = 0x0040;
264pub const O_DIRECT = 0x00010000;
265pub const O_LARGEFILE = 0;
266pub const O_NOATIME = 0o1000000;
267pub const O_PATH = 0o10000000;
268pub const O_TMPFILE = 0o20200000;
269pub const O_NDELAY = O_NONBLOCK;
270
271pub const F_DUPFD = 0;
272pub const F_GETFD = 1;
273pub const F_SETFD = 2;
274pub const F_GETFL = 3;
275pub const F_SETFL = 4;
276
277pub const F_SETOWN = 8;
278pub const F_GETOWN = 9;
279pub const F_SETSIG = 10;
280pub const F_GETSIG = 11;
281
282pub const F_GETLK = 5;
283pub const F_SETLK = 6;
284pub const F_SETLKW = 7;
285
286pub const F_SETOWN_EX = 15;
287pub const F_GETOWN_EX = 16;
288
289pub const F_GETOWNER_UIDS = 17;
290
291pub const SEEK_SET = 0;
292pub const SEEK_CUR = 1;
293pub const SEEK_END = 2;
294
295pub const SIG_BLOCK = 1;
296pub const SIG_UNBLOCK = 2;
297pub const SIG_SETMASK = 3;
298
299pub const SOCK_STREAM = 1;
300pub const SOCK_DGRAM = 2;
301pub const SOCK_RAW = 3;
302pub const SOCK_RDM = 4;
303pub const SOCK_SEQPACKET = 5;
304
305pub const SOCK_CLOEXEC = 0x10000000;
306pub const SOCK_NONBLOCK = 0x20000000;
307
308pub const PROTO_ip = 0o000;
309pub const PROTO_icmp = 0o001;
310pub const PROTO_igmp = 0o002;
311pub const PROTO_ggp = 0o003;
312pub const PROTO_ipencap = 0o004;
313pub const PROTO_st = 0o005;
314pub const PROTO_tcp = 0o006;
315pub const PROTO_egp = 0o010;
316pub const PROTO_pup = 0o014;
317pub const PROTO_udp = 0o021;
318pub const PROTO_hmp = 0o024;
319pub const PROTO_xns_idp = 0o026;
320pub const PROTO_rdp = 0o033;
321pub const PROTO_iso_tp4 = 0o035;
322pub const PROTO_xtp = 0o044;
323pub const PROTO_ddp = 0o045;
324pub const PROTO_idpr_cmtp = 0o046;
325pub const PROTO_ipv6 = 0o051;
326pub const PROTO_ipv6_route = 0o053;
327pub const PROTO_ipv6_frag = 0o054;
328pub const PROTO_idrp = 0o055;
329pub const PROTO_rsvp = 0o056;
330pub const PROTO_gre = 0o057;
331pub const PROTO_esp = 0o062;
332pub const PROTO_ah = 0o063;
333pub const PROTO_skip = 0o071;
334pub const PROTO_ipv6_icmp = 0o072;
335pub const PROTO_ipv6_nonxt = 0o073;
336pub const PROTO_ipv6_opts = 0o074;
337pub const PROTO_rspf = 0o111;
338pub const PROTO_vmtp = 0o121;
339pub const PROTO_ospf = 0o131;
340pub const PROTO_ipip = 0o136;
341pub const PROTO_encap = 0o142;
342pub const PROTO_pim = 0o147;
343pub const PROTO_raw = 0o377;
344
345pub const PF_UNSPEC = 0;
346pub const PF_LOCAL = 1;
347pub const PF_UNIX = PF_LOCAL;
348pub const PF_FILE = PF_LOCAL;
349pub const PF_INET = 2;
350pub const PF_AX25 = 3;
351pub const PF_IPX = 4;
352pub const PF_APPLETALK = 5;
353pub const PF_NETROM = 6;
354pub const PF_BRIDGE = 7;
355pub const PF_ATMPVC = 8;
356pub const PF_X25 = 9;
357pub const PF_INET6 = 10;
358pub const PF_ROSE = 11;
359pub const PF_DECnet = 12;
360pub const PF_NETBEUI = 13;
361pub const PF_SECURITY = 14;
362pub const PF_KEY = 15;
363pub const PF_NETLINK = 16;
364pub const PF_ROUTE = PF_NETLINK;
365pub const PF_PACKET = 17;
366pub const PF_ASH = 18;
367pub const PF_ECONET = 19;
368pub const PF_ATMSVC = 20;
369pub const PF_RDS = 21;
370pub const PF_SNA = 22;
371pub const PF_IRDA = 23;
372pub const PF_PPPOX = 24;
373pub const PF_WANPIPE = 25;
374pub const PF_LLC = 26;
375pub const PF_IB = 27;
376pub const PF_MPLS = 28;
377pub const PF_CAN = 29;
378pub const PF_TIPC = 30;
379pub const PF_BLUETOOTH = 31;
380pub const PF_IUCV = 32;
381pub const PF_RXRPC = 33;
382pub const PF_ISDN = 34;
383pub const PF_PHONET = 35;
384pub const PF_IEEE802154 = 36;
385pub const PF_CAIF = 37;
386pub const PF_ALG = 38;
387pub const PF_NFC = 39;
388pub const PF_VSOCK = 40;
389pub const PF_MAX = 41;
390
391pub const AF_UNSPEC = PF_UNSPEC;
392pub const AF_LOCAL = PF_LOCAL;
393pub const AF_UNIX = AF_LOCAL;
394pub const AF_FILE = AF_LOCAL;
395pub const AF_INET = PF_INET;
396pub const AF_AX25 = PF_AX25;
397pub const AF_IPX = PF_IPX;
398pub const AF_APPLETALK = PF_APPLETALK;
399pub const AF_NETROM = PF_NETROM;
400pub const AF_BRIDGE = PF_BRIDGE;
401pub const AF_ATMPVC = PF_ATMPVC;
402pub const AF_X25 = PF_X25;
403pub const AF_INET6 = PF_INET6;
404pub const AF_ROSE = PF_ROSE;
405pub const AF_DECnet = PF_DECnet;
406pub const AF_NETBEUI = PF_NETBEUI;
407pub const AF_SECURITY = PF_SECURITY;
408pub const AF_KEY = PF_KEY;
409pub const AF_NETLINK = PF_NETLINK;
410pub const AF_ROUTE = PF_ROUTE;
411pub const AF_PACKET = PF_PACKET;
412pub const AF_ASH = PF_ASH;
413pub const AF_ECONET = PF_ECONET;
414pub const AF_ATMSVC = PF_ATMSVC;
415pub const AF_RDS = PF_RDS;
416pub const AF_SNA = PF_SNA;
417pub const AF_IRDA = PF_IRDA;
418pub const AF_PPPOX = PF_PPPOX;
419pub const AF_WANPIPE = PF_WANPIPE;
420pub const AF_LLC = PF_LLC;
421pub const AF_IB = PF_IB;
422pub const AF_MPLS = PF_MPLS;
423pub const AF_CAN = PF_CAN;
424pub const AF_TIPC = PF_TIPC;
425pub const AF_BLUETOOTH = PF_BLUETOOTH;
426pub const AF_IUCV = PF_IUCV;
427pub const AF_RXRPC = PF_RXRPC;
428pub const AF_ISDN = PF_ISDN;
429pub const AF_PHONET = PF_PHONET;
430pub const AF_IEEE802154 = PF_IEEE802154;
431pub const AF_CAIF = PF_CAIF;
432pub const AF_ALG = PF_ALG;
433pub const AF_NFC = PF_NFC;
434pub const AF_VSOCK = PF_VSOCK;
435pub const AF_MAX = PF_MAX;
436
437pub const DT_UNKNOWN = 0;
438pub const DT_FIFO = 1;
439pub const DT_CHR = 2;
440pub const DT_DIR = 4;
441pub const DT_BLK = 6;
442pub const DT_REG = 8;
443pub const DT_LNK = 10;
444pub const DT_SOCK = 12;
445pub const DT_WHT = 14;
446
447/// add event to kq (implies enable)
448pub const EV_ADD = 0x0001;
449
450/// delete event from kq
451pub const EV_DELETE = 0x0002;
452
453/// enable event
454pub const EV_ENABLE = 0x0004;
455
456/// disable event (not reported)
457pub const EV_DISABLE = 0x0008;
458
459/// only report one occurrence
460pub const EV_ONESHOT = 0x0010;
461
462/// clear event state after reporting
463pub const EV_CLEAR = 0x0020;
464
465/// force immediate event output
466/// ... with or without EV_ERROR
467/// ... use KEVENT_FLAG_ERROR_EVENTS
468/// on syscalls supporting flags
469pub const EV_RECEIPT = 0x0040;
470
471/// disable event after reporting
472pub const EV_DISPATCH = 0x0080;
473
474pub const EVFILT_READ = -1;
475pub const EVFILT_WRITE = -2;
476
477/// attached to aio requests
478pub const EVFILT_AIO = -3;
479
480/// attached to vnodes
481pub const EVFILT_VNODE = -4;
482
483/// attached to struct proc
484pub const EVFILT_PROC = -5;
485
486/// attached to struct proc
487pub const EVFILT_SIGNAL = -6;
488
489/// timers
490pub const EVFILT_TIMER = -7;
491
492/// Process descriptors
493pub const EVFILT_PROCDESC = -8;
494
495/// Filesystem events
496pub const EVFILT_FS = -9;
497
498pub const EVFILT_LIO = -10;
499
500/// User events
501pub const EVFILT_USER = -11;
502
503/// Sendfile events
504pub const EVFILT_SENDFILE = -12;
505
506pub const EVFILT_EMPTY = -13;
507
508/// On input, NOTE_TRIGGER causes the event to be triggered for output.
509pub const NOTE_TRIGGER = 0x01000000;
510
511/// ignore input fflags
512pub const NOTE_FFNOP = 0x00000000;
513
514/// and fflags
515pub const NOTE_FFAND = 0x40000000;
516
517/// or fflags
518pub const NOTE_FFOR = 0x80000000;
519
520/// copy fflags
521pub const NOTE_FFCOPY = 0xc0000000;
522
523/// mask for operations
524pub const NOTE_FFCTRLMASK = 0xc0000000;
525pub const NOTE_FFLAGSMASK = 0x00ffffff;
526
527/// low water mark
528pub const NOTE_LOWAT = 0x00000001;
529
530/// behave like poll()
531pub const NOTE_FILE_POLL = 0x00000002;
532
533/// vnode was removed
534pub const NOTE_DELETE = 0x00000001;
535
536/// data contents changed
537pub const NOTE_WRITE = 0x00000002;
538
539/// size increased
540pub const NOTE_EXTEND = 0x00000004;
541
542/// attributes changed
543pub const NOTE_ATTRIB = 0x00000008;
544
545/// link count changed
546pub const NOTE_LINK = 0x00000010;
547
548/// vnode was renamed
549pub const NOTE_RENAME = 0x00000020;
550
551/// vnode access was revoked
552pub const NOTE_REVOKE = 0x00000040;
553
554/// vnode was opened
555pub const NOTE_OPEN = 0x00000080;
556
557/// file closed, fd did not allow write
558pub const NOTE_CLOSE = 0x00000100;
559
560/// file closed, fd did allow write
561pub const NOTE_CLOSE_WRITE = 0x00000200;
562
563/// file was read
564pub const NOTE_READ = 0x00000400;
565
566/// process exited
567pub const NOTE_EXIT = 0x80000000;
568
569/// process forked
570pub const NOTE_FORK = 0x40000000;
571
572/// process exec'd
573pub const NOTE_EXEC = 0x20000000;
574
575/// mask for signal & exit status
576pub const NOTE_PDATAMASK = 0x000fffff;
577pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK);
578
579/// data is seconds
580pub const NOTE_SECONDS = 0x00000001;
581
582/// data is milliseconds
583pub const NOTE_MSECONDS = 0x00000002;
584
585/// data is microseconds
586pub const NOTE_USECONDS = 0x00000004;
587
588/// data is nanoseconds
589pub const NOTE_NSECONDS = 0x00000008;
590
591/// timeout is absolute
592pub const NOTE_ABSTIME = 0x00000010;
593
594pub const TCGETS = 0x5401;
595pub const TCSETS = 0x5402;
596pub const TCSETSW = 0x5403;
597pub const TCSETSF = 0x5404;
598pub const TCGETA = 0x5405;
599pub const TCSETA = 0x5406;
600pub const TCSETAW = 0x5407;
601pub const TCSETAF = 0x5408;
602pub const TCSBRK = 0x5409;
603pub const TCXONC = 0x540A;
604pub const TCFLSH = 0x540B;
605pub const TIOCEXCL = 0x540C;
606pub const TIOCNXCL = 0x540D;
607pub const TIOCSCTTY = 0x540E;
608pub const TIOCGPGRP = 0x540F;
609pub const TIOCSPGRP = 0x5410;
610pub const TIOCOUTQ = 0x5411;
611pub const TIOCSTI = 0x5412;
612pub const TIOCGWINSZ = 0x5413;
613pub const TIOCSWINSZ = 0x5414;
614pub const TIOCMGET = 0x5415;
615pub const TIOCMBIS = 0x5416;
616pub const TIOCMBIC = 0x5417;
617pub const TIOCMSET = 0x5418;
618pub const TIOCGSOFTCAR = 0x5419;
619pub const TIOCSSOFTCAR = 0x541A;
620pub const FIONREAD = 0x541B;
621pub const TIOCINQ = FIONREAD;
622pub const TIOCLINUX = 0x541C;
623pub const TIOCCONS = 0x541D;
624pub const TIOCGSERIAL = 0x541E;
625pub const TIOCSSERIAL = 0x541F;
626pub const TIOCPKT = 0x5420;
627pub const FIONBIO = 0x5421;
628pub const TIOCNOTTY = 0x5422;
629pub const TIOCSETD = 0x5423;
630pub const TIOCGETD = 0x5424;
631pub const TCSBRKP = 0x5425;
632pub const TIOCSBRK = 0x5427;
633pub const TIOCCBRK = 0x5428;
634pub const TIOCGSID = 0x5429;
635pub const TIOCGRS485 = 0x542E;
636pub const TIOCSRS485 = 0x542F;
637pub const TIOCGPTN = 0x80045430;
638pub const TIOCSPTLCK = 0x40045431;
639pub const TIOCGDEV = 0x80045432;
640pub const TCGETX = 0x5432;
641pub const TCSETX = 0x5433;
642pub const TCSETXF = 0x5434;
643pub const TCSETXW = 0x5435;
644pub const TIOCSIG = 0x40045436;
645pub const TIOCVHANGUP = 0x5437;
646pub const TIOCGPKT = 0x80045438;
647pub const TIOCGPTLCK = 0x80045439;
648pub const TIOCGEXCL = 0x80045440;
649
650pub fn WEXITSTATUS(s: u32) u32 {
651 return (s & 0xff00) >> 8;
652}
653pub fn WTERMSIG(s: u32) u32 {
654 return s & 0x7f;
655}
656pub fn WSTOPSIG(s: u32) u32 {
657 return WEXITSTATUS(s);
658}
659pub fn WIFEXITED(s: u32) bool {
660 return WTERMSIG(s) == 0;
661}
662pub fn WIFSTOPPED(s: u32) bool {
663 return @intCast(u16, (((s & 0xffff) *% 0x10001) >> 8)) > 0x7f00;
664}
665pub fn WIFSIGNALED(s: u32) bool {
666 return (s & 0xffff) -% 1 < 0xff;
667}
668
669pub const winsize = extern struct {
670 ws_row: u16,
671 ws_col: u16,
672 ws_xpixel: u16,
673 ws_ypixel: u16,
674};
675
676const NSIG = 32;
677
678pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
679pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
680pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
681
682/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
683pub const Sigaction = extern struct {
684 /// signal handler
685 __sigaction_u: extern union {
686 __sa_handler: extern fn (i32) void,
687 __sa_sigaction: extern fn (i32, *__siginfo, usize) void,
688 },
689
690 /// see signal options
691 sa_flags: u32,
692
693 /// signal mask to apply
694 sa_mask: sigset_t,
695};
696
697pub const _SIG_WORDS = 4;
698pub const _SIG_MAXSIG = 128;
699
700pub inline fn _SIG_IDX(sig: usize) usize {
701 return sig - 1;
702}
703pub inline fn _SIG_WORD(sig: usize) usize {
704 return_SIG_IDX(sig) >> 5;
705}
706pub inline fn _SIG_BIT(sig: usize) usize {
707 return 1 << (_SIG_IDX(sig) & 31);
708}
709pub inline fn _SIG_VALID(sig: usize) usize {
710 return sig <= _SIG_MAXSIG and sig > 0;
711}
712
713pub const sigset_t = extern struct {
714 __bits: [_SIG_WORDS]u32,
715};
716
717pub const EPERM = 1; // Operation not permitted
718pub const ENOENT = 2; // No such file or directory
719pub const ESRCH = 3; // No such process
720pub const EINTR = 4; // Interrupted system call
721pub const EIO = 5; // Input/output error
722pub const ENXIO = 6; // Device not configured
723pub const E2BIG = 7; // Argument list too long
724pub const ENOEXEC = 8; // Exec format error
725pub const EBADF = 9; // Bad file descriptor
726pub const ECHILD = 10; // No child processes
727pub const EDEADLK = 11; // Resource deadlock avoided
728// 11 was EAGAIN
729pub const ENOMEM = 12; // Cannot allocate memory
730pub const EACCES = 13; // Permission denied
731pub const EFAULT = 14; // Bad address
732pub const ENOTBLK = 15; // Block device required
733pub const EBUSY = 16; // Device busy
734pub const EEXIST = 17; // File exists
735pub const EXDEV = 18; // Cross-device link
736pub const ENODEV = 19; // Operation not supported by device
737pub const ENOTDIR = 20; // Not a directory
738pub const EISDIR = 21; // Is a directory
739pub const EINVAL = 22; // Invalid argument
740pub const ENFILE = 23; // Too many open files in system
741pub const EMFILE = 24; // Too many open files
742pub const ENOTTY = 25; // Inappropriate ioctl for device
743pub const ETXTBSY = 26; // Text file busy
744pub const EFBIG = 27; // File too large
745pub const ENOSPC = 28; // No space left on device
746pub const ESPIPE = 29; // Illegal seek
747pub const EROFS = 30; // Read-only filesystem
748pub const EMLINK = 31; // Too many links
749pub const EPIPE = 32; // Broken pipe
750
751// math software
752pub const EDOM = 33; // Numerical argument out of domain
753pub const ERANGE = 34; // Result too large
754
755// non-blocking and interrupt i/o
756pub const EAGAIN = 35; // Resource temporarily unavailable
757pub const EWOULDBLOCK = EAGAIN; // Operation would block
758pub const EINPROGRESS = 36; // Operation now in progress
759pub const EALREADY = 37; // Operation already in progress
760
761// ipc/network software -- argument errors
762pub const ENOTSOCK = 38; // Socket operation on non-socket
763pub const EDESTADDRREQ = 39; // Destination address required
764pub const EMSGSIZE = 40; // Message too long
765pub const EPROTOTYPE = 41; // Protocol wrong type for socket
766pub const ENOPROTOOPT = 42; // Protocol not available
767pub const EPROTONOSUPPORT = 43; // Protocol not supported
768pub const ESOCKTNOSUPPORT = 44; // Socket type not supported
769pub const EOPNOTSUPP = 45; // Operation not supported
770pub const ENOTSUP = EOPNOTSUPP; // Operation not supported
771pub const EPFNOSUPPORT = 46; // Protocol family not supported
772pub const EAFNOSUPPORT = 47; // Address family not supported by protocol family
773pub const EADDRINUSE = 48; // Address already in use
774pub const EADDRNOTAVAIL = 49; // Can't assign requested address
775
776// ipc/network software -- operational errors
777pub const ENETDOWN = 50; // Network is down
778pub const ENETUNREACH = 51; // Network is unreachable
779pub const ENETRESET = 52; // Network dropped connection on reset
780pub const ECONNABORTED = 53; // Software caused connection abort
781pub const ECONNRESET = 54; // Connection reset by peer
782pub const ENOBUFS = 55; // No buffer space available
783pub const EISCONN = 56; // Socket is already connected
784pub const ENOTCONN = 57; // Socket is not connected
785pub const ESHUTDOWN = 58; // Can't send after socket shutdown
786pub const ETOOMANYREFS = 59; // Too many references: can't splice
787pub const ETIMEDOUT = 60; // Operation timed out
788pub const ECONNREFUSED = 61; // Connection refused
789
790pub const ELOOP = 62; // Too many levels of symbolic links
791pub const ENAMETOOLONG = 63; // File name too long
792
793// should be rearranged
794pub const EHOSTDOWN = 64; // Host is down
795pub const EHOSTUNREACH = 65; // No route to host
796pub const ENOTEMPTY = 66; // Directory not empty
797
798// quotas & mush
799pub const EPROCLIM = 67; // Too many processes
800pub const EUSERS = 68; // Too many users
801pub const EDQUOT = 69; // Disc quota exceeded
802
803// Network File System
804pub const ESTALE = 70; // Stale NFS file handle
805pub const EREMOTE = 71; // Too many levels of remote in path
806pub const EBADRPC = 72; // RPC struct is bad
807pub const ERPCMISMATCH = 73; // RPC version wrong
808pub const EPROGUNAVAIL = 74; // RPC prog. not avail
809pub const EPROGMISMATCH = 75; // Program version wrong
810pub const EPROCUNAVAIL = 76; // Bad procedure for program
811
812pub const ENOLCK = 77; // No locks available
813pub const ENOSYS = 78; // Function not implemented
814
815pub const EFTYPE = 79; // Inappropriate file type or format
816pub const EAUTH = 80; // Authentication error
817pub const ENEEDAUTH = 81; // Need authenticator
818pub const EIDRM = 82; // Identifier removed
819pub const ENOMSG = 83; // No message of desired type
820pub const EOVERFLOW = 84; // Value too large to be stored in data type
821pub const ECANCELED = 85; // Operation canceled
822pub const EILSEQ = 86; // Illegal byte sequence
823pub const ENOATTR = 87; // Attribute not found
824
825pub const EDOOFUS = 88; // Programming error
826
827pub const EBADMSG = 89; // Bad message
828pub const EMULTIHOP = 90; // Multihop attempted
829pub const ENOLINK = 91; // Link has been severed
830pub const EPROTO = 92; // Protocol error
831
832pub const ENOTCAPABLE = 93; // Capabilities insufficient
833pub const ECAPMODE = 94; // Not permitted in capability mode
834pub const ENOTRECOVERABLE = 95; // State not recoverable
835pub const EOWNERDEAD = 96; // Previous owner died
836
837pub const ELAST = 96; // Must be equal largest errno
std/os/bits/linux.zig created+931
...@@ -0,0 +1,931 @@
1const builtin = @import("builtin");
2const std = @import("../../std.zig");
3const maxInt = std.math.maxInt;
4use @import("../bits.zig");
5
6pub use @import("linux/errno.zig");
7pub use switch (builtin.arch) {
8 .x86_64 => @import("linux/x86_64.zig"),
9 .aarch64 => @import("linux/arm64.zig"),
10 else => struct {},
11};
12
13pub const pid_t = i32;
14pub const fd_t = i32;
15
16pub const PATH_MAX = 4096;
17pub const IOV_MAX = 1024;
18
19pub const STDIN_FILENO = 0;
20pub const STDOUT_FILENO = 1;
21pub const STDERR_FILENO = 2;
22
23pub const FUTEX_WAIT = 0;
24pub const FUTEX_WAKE = 1;
25pub const FUTEX_FD = 2;
26pub const FUTEX_REQUEUE = 3;
27pub const FUTEX_CMP_REQUEUE = 4;
28pub const FUTEX_WAKE_OP = 5;
29pub const FUTEX_LOCK_PI = 6;
30pub const FUTEX_UNLOCK_PI = 7;
31pub const FUTEX_TRYLOCK_PI = 8;
32pub const FUTEX_WAIT_BITSET = 9;
33
34pub const FUTEX_PRIVATE_FLAG = 128;
35
36pub const FUTEX_CLOCK_REALTIME = 256;
37
38pub const PROT_NONE = 0;
39pub const PROT_READ = 1;
40pub const PROT_WRITE = 2;
41pub const PROT_EXEC = 4;
42pub const PROT_GROWSDOWN = 0x01000000;
43pub const PROT_GROWSUP = 0x02000000;
44
45pub const MAP_FAILED = @intToPtr(*c_void, maxInt(usize));
46pub const MAP_SHARED = 0x01;
47pub const MAP_PRIVATE = 0x02;
48pub const MAP_TYPE = 0x0f;
49pub const MAP_FIXED = 0x10;
50pub const MAP_ANONYMOUS = 0x20;
51pub const MAP_NORESERVE = 0x4000;
52pub const MAP_GROWSDOWN = 0x0100;
53pub const MAP_DENYWRITE = 0x0800;
54pub const MAP_EXECUTABLE = 0x1000;
55pub const MAP_LOCKED = 0x2000;
56pub const MAP_POPULATE = 0x8000;
57pub const MAP_NONBLOCK = 0x10000;
58pub const MAP_STACK = 0x20000;
59pub const MAP_HUGETLB = 0x40000;
60pub const MAP_FILE = 0;
61
62pub const F_OK = 0;
63pub const X_OK = 1;
64pub const W_OK = 2;
65pub const R_OK = 4;
66
67pub const WNOHANG = 1;
68pub const WUNTRACED = 2;
69pub const WSTOPPED = 2;
70pub const WEXITED = 4;
71pub const WCONTINUED = 8;
72pub const WNOWAIT = 0x1000000;
73
74pub const SA_NOCLDSTOP = 1;
75pub const SA_NOCLDWAIT = 2;
76pub const SA_SIGINFO = 4;
77pub const SA_ONSTACK = 0x08000000;
78pub const SA_RESTART = 0x10000000;
79pub const SA_NODEFER = 0x40000000;
80pub const SA_RESETHAND = 0x80000000;
81pub const SA_RESTORER = 0x04000000;
82
83pub const SIGHUP = 1;
84pub const SIGINT = 2;
85pub const SIGQUIT = 3;
86pub const SIGILL = 4;
87pub const SIGTRAP = 5;
88pub const SIGABRT = 6;
89pub const SIGIOT = SIGABRT;
90pub const SIGBUS = 7;
91pub const SIGFPE = 8;
92pub const SIGKILL = 9;
93pub const SIGUSR1 = 10;
94pub const SIGSEGV = 11;
95pub const SIGUSR2 = 12;
96pub const SIGPIPE = 13;
97pub const SIGALRM = 14;
98pub const SIGTERM = 15;
99pub const SIGSTKFLT = 16;
100pub const SIGCHLD = 17;
101pub const SIGCONT = 18;
102pub const SIGSTOP = 19;
103pub const SIGTSTP = 20;
104pub const SIGTTIN = 21;
105pub const SIGTTOU = 22;
106pub const SIGURG = 23;
107pub const SIGXCPU = 24;
108pub const SIGXFSZ = 25;
109pub const SIGVTALRM = 26;
110pub const SIGPROF = 27;
111pub const SIGWINCH = 28;
112pub const SIGIO = 29;
113pub const SIGPOLL = 29;
114pub const SIGPWR = 30;
115pub const SIGSYS = 31;
116pub const SIGUNUSED = SIGSYS;
117
118pub const O_RDONLY = 0o0;
119pub const O_WRONLY = 0o1;
120pub const O_RDWR = 0o2;
121
122pub const SEEK_SET = 0;
123pub const SEEK_CUR = 1;
124pub const SEEK_END = 2;
125
126pub const SIG_BLOCK = 0;
127pub const SIG_UNBLOCK = 1;
128pub const SIG_SETMASK = 2;
129
130pub const PROTO_ip = 0o000;
131pub const PROTO_icmp = 0o001;
132pub const PROTO_igmp = 0o002;
133pub const PROTO_ggp = 0o003;
134pub const PROTO_ipencap = 0o004;
135pub const PROTO_st = 0o005;
136pub const PROTO_tcp = 0o006;
137pub const PROTO_egp = 0o010;
138pub const PROTO_pup = 0o014;
139pub const PROTO_udp = 0o021;
140pub const PROTO_hmp = 0o024;
141pub const PROTO_xns_idp = 0o026;
142pub const PROTO_rdp = 0o033;
143pub const PROTO_iso_tp4 = 0o035;
144pub const PROTO_xtp = 0o044;
145pub const PROTO_ddp = 0o045;
146pub const PROTO_idpr_cmtp = 0o046;
147pub const PROTO_ipv6 = 0o051;
148pub const PROTO_ipv6_route = 0o053;
149pub const PROTO_ipv6_frag = 0o054;
150pub const PROTO_idrp = 0o055;
151pub const PROTO_rsvp = 0o056;
152pub const PROTO_gre = 0o057;
153pub const PROTO_esp = 0o062;
154pub const PROTO_ah = 0o063;
155pub const PROTO_skip = 0o071;
156pub const PROTO_ipv6_icmp = 0o072;
157pub const PROTO_ipv6_nonxt = 0o073;
158pub const PROTO_ipv6_opts = 0o074;
159pub const PROTO_rspf = 0o111;
160pub const PROTO_vmtp = 0o121;
161pub const PROTO_ospf = 0o131;
162pub const PROTO_ipip = 0o136;
163pub const PROTO_encap = 0o142;
164pub const PROTO_pim = 0o147;
165pub const PROTO_raw = 0o377;
166
167pub const SHUT_RD = 0;
168pub const SHUT_WR = 1;
169pub const SHUT_RDWR = 2;
170
171pub const SOCK_STREAM = 1;
172pub const SOCK_DGRAM = 2;
173pub const SOCK_RAW = 3;
174pub const SOCK_RDM = 4;
175pub const SOCK_SEQPACKET = 5;
176pub const SOCK_DCCP = 6;
177pub const SOCK_PACKET = 10;
178pub const SOCK_CLOEXEC = 0o2000000;
179pub const SOCK_NONBLOCK = 0o4000;
180
181pub const PF_UNSPEC = 0;
182pub const PF_LOCAL = 1;
183pub const PF_UNIX = PF_LOCAL;
184pub const PF_FILE = PF_LOCAL;
185pub const PF_INET = 2;
186pub const PF_AX25 = 3;
187pub const PF_IPX = 4;
188pub const PF_APPLETALK = 5;
189pub const PF_NETROM = 6;
190pub const PF_BRIDGE = 7;
191pub const PF_ATMPVC = 8;
192pub const PF_X25 = 9;
193pub const PF_INET6 = 10;
194pub const PF_ROSE = 11;
195pub const PF_DECnet = 12;
196pub const PF_NETBEUI = 13;
197pub const PF_SECURITY = 14;
198pub const PF_KEY = 15;
199pub const PF_NETLINK = 16;
200pub const PF_ROUTE = PF_NETLINK;
201pub const PF_PACKET = 17;
202pub const PF_ASH = 18;
203pub const PF_ECONET = 19;
204pub const PF_ATMSVC = 20;
205pub const PF_RDS = 21;
206pub const PF_SNA = 22;
207pub const PF_IRDA = 23;
208pub const PF_PPPOX = 24;
209pub const PF_WANPIPE = 25;
210pub const PF_LLC = 26;
211pub const PF_IB = 27;
212pub const PF_MPLS = 28;
213pub const PF_CAN = 29;
214pub const PF_TIPC = 30;
215pub const PF_BLUETOOTH = 31;
216pub const PF_IUCV = 32;
217pub const PF_RXRPC = 33;
218pub const PF_ISDN = 34;
219pub const PF_PHONET = 35;
220pub const PF_IEEE802154 = 36;
221pub const PF_CAIF = 37;
222pub const PF_ALG = 38;
223pub const PF_NFC = 39;
224pub const PF_VSOCK = 40;
225pub const PF_KCM = 41;
226pub const PF_QIPCRTR = 42;
227pub const PF_SMC = 43;
228pub const PF_MAX = 44;
229
230pub const AF_UNSPEC = PF_UNSPEC;
231pub const AF_LOCAL = PF_LOCAL;
232pub const AF_UNIX = AF_LOCAL;
233pub const AF_FILE = AF_LOCAL;
234pub const AF_INET = PF_INET;
235pub const AF_AX25 = PF_AX25;
236pub const AF_IPX = PF_IPX;
237pub const AF_APPLETALK = PF_APPLETALK;
238pub const AF_NETROM = PF_NETROM;
239pub const AF_BRIDGE = PF_BRIDGE;
240pub const AF_ATMPVC = PF_ATMPVC;
241pub const AF_X25 = PF_X25;
242pub const AF_INET6 = PF_INET6;
243pub const AF_ROSE = PF_ROSE;
244pub const AF_DECnet = PF_DECnet;
245pub const AF_NETBEUI = PF_NETBEUI;
246pub const AF_SECURITY = PF_SECURITY;
247pub const AF_KEY = PF_KEY;
248pub const AF_NETLINK = PF_NETLINK;
249pub const AF_ROUTE = PF_ROUTE;
250pub const AF_PACKET = PF_PACKET;
251pub const AF_ASH = PF_ASH;
252pub const AF_ECONET = PF_ECONET;
253pub const AF_ATMSVC = PF_ATMSVC;
254pub const AF_RDS = PF_RDS;
255pub const AF_SNA = PF_SNA;
256pub const AF_IRDA = PF_IRDA;
257pub const AF_PPPOX = PF_PPPOX;
258pub const AF_WANPIPE = PF_WANPIPE;
259pub const AF_LLC = PF_LLC;
260pub const AF_IB = PF_IB;
261pub const AF_MPLS = PF_MPLS;
262pub const AF_CAN = PF_CAN;
263pub const AF_TIPC = PF_TIPC;
264pub const AF_BLUETOOTH = PF_BLUETOOTH;
265pub const AF_IUCV = PF_IUCV;
266pub const AF_RXRPC = PF_RXRPC;
267pub const AF_ISDN = PF_ISDN;
268pub const AF_PHONET = PF_PHONET;
269pub const AF_IEEE802154 = PF_IEEE802154;
270pub const AF_CAIF = PF_CAIF;
271pub const AF_ALG = PF_ALG;
272pub const AF_NFC = PF_NFC;
273pub const AF_VSOCK = PF_VSOCK;
274pub const AF_KCM = PF_KCM;
275pub const AF_QIPCRTR = PF_QIPCRTR;
276pub const AF_SMC = PF_SMC;
277pub const AF_MAX = PF_MAX;
278
279pub const SO_DEBUG = 1;
280pub const SO_REUSEADDR = 2;
281pub const SO_TYPE = 3;
282pub const SO_ERROR = 4;
283pub const SO_DONTROUTE = 5;
284pub const SO_BROADCAST = 6;
285pub const SO_SNDBUF = 7;
286pub const SO_RCVBUF = 8;
287pub const SO_KEEPALIVE = 9;
288pub const SO_OOBINLINE = 10;
289pub const SO_NO_CHECK = 11;
290pub const SO_PRIORITY = 12;
291pub const SO_LINGER = 13;
292pub const SO_BSDCOMPAT = 14;
293pub const SO_REUSEPORT = 15;
294pub const SO_PASSCRED = 16;
295pub const SO_PEERCRED = 17;
296pub const SO_RCVLOWAT = 18;
297pub const SO_SNDLOWAT = 19;
298pub const SO_RCVTIMEO = 20;
299pub const SO_SNDTIMEO = 21;
300pub const SO_ACCEPTCONN = 30;
301pub const SO_SNDBUFFORCE = 32;
302pub const SO_RCVBUFFORCE = 33;
303pub const SO_PROTOCOL = 38;
304pub const SO_DOMAIN = 39;
305
306pub const SO_SECURITY_AUTHENTICATION = 22;
307pub const SO_SECURITY_ENCRYPTION_TRANSPORT = 23;
308pub const SO_SECURITY_ENCRYPTION_NETWORK = 24;
309
310pub const SO_BINDTODEVICE = 25;
311
312pub const SO_ATTACH_FILTER = 26;
313pub const SO_DETACH_FILTER = 27;
314pub const SO_GET_FILTER = SO_ATTACH_FILTER;
315
316pub const SO_PEERNAME = 28;
317pub const SO_TIMESTAMP = 29;
318pub const SCM_TIMESTAMP = SO_TIMESTAMP;
319
320pub const SO_PEERSEC = 31;
321pub const SO_PASSSEC = 34;
322pub const SO_TIMESTAMPNS = 35;
323pub const SCM_TIMESTAMPNS = SO_TIMESTAMPNS;
324pub const SO_MARK = 36;
325pub const SO_TIMESTAMPING = 37;
326pub const SCM_TIMESTAMPING = SO_TIMESTAMPING;
327pub const SO_RXQ_OVFL = 40;
328pub const SO_WIFI_STATUS = 41;
329pub const SCM_WIFI_STATUS = SO_WIFI_STATUS;
330pub const SO_PEEK_OFF = 42;
331pub const SO_NOFCS = 43;
332pub const SO_LOCK_FILTER = 44;
333pub const SO_SELECT_ERR_QUEUE = 45;
334pub const SO_BUSY_POLL = 46;
335pub const SO_MAX_PACING_RATE = 47;
336pub const SO_BPF_EXTENSIONS = 48;
337pub const SO_INCOMING_CPU = 49;
338pub const SO_ATTACH_BPF = 50;
339pub const SO_DETACH_BPF = SO_DETACH_FILTER;
340pub const SO_ATTACH_REUSEPORT_CBPF = 51;
341pub const SO_ATTACH_REUSEPORT_EBPF = 52;
342pub const SO_CNX_ADVICE = 53;
343pub const SCM_TIMESTAMPING_OPT_STATS = 54;
344pub const SO_MEMINFO = 55;
345pub const SO_INCOMING_NAPI_ID = 56;
346pub const SO_COOKIE = 57;
347pub const SCM_TIMESTAMPING_PKTINFO = 58;
348pub const SO_PEERGROUPS = 59;
349pub const SO_ZEROCOPY = 60;
350
351pub const SOL_SOCKET = 1;
352
353pub const SOL_IP = 0;
354pub const SOL_IPV6 = 41;
355pub const SOL_ICMPV6 = 58;
356
357pub const SOL_RAW = 255;
358pub const SOL_DECNET = 261;
359pub const SOL_X25 = 262;
360pub const SOL_PACKET = 263;
361pub const SOL_ATM = 264;
362pub const SOL_AAL = 265;
363pub const SOL_IRDA = 266;
364pub const SOL_NETBEUI = 267;
365pub const SOL_LLC = 268;
366pub const SOL_DCCP = 269;
367pub const SOL_NETLINK = 270;
368pub const SOL_TIPC = 271;
369pub const SOL_RXRPC = 272;
370pub const SOL_PPPOL2TP = 273;
371pub const SOL_BLUETOOTH = 274;
372pub const SOL_PNPIPE = 275;
373pub const SOL_RDS = 276;
374pub const SOL_IUCV = 277;
375pub const SOL_CAIF = 278;
376pub const SOL_ALG = 279;
377pub const SOL_NFC = 280;
378pub const SOL_KCM = 281;
379pub const SOL_TLS = 282;
380
381pub const SOMAXCONN = 128;
382
383pub const MSG_OOB = 0x0001;
384pub const MSG_PEEK = 0x0002;
385pub const MSG_DONTROUTE = 0x0004;
386pub const MSG_CTRUNC = 0x0008;
387pub const MSG_PROXY = 0x0010;
388pub const MSG_TRUNC = 0x0020;
389pub const MSG_DONTWAIT = 0x0040;
390pub const MSG_EOR = 0x0080;
391pub const MSG_WAITALL = 0x0100;
392pub const MSG_FIN = 0x0200;
393pub const MSG_SYN = 0x0400;
394pub const MSG_CONFIRM = 0x0800;
395pub const MSG_RST = 0x1000;
396pub const MSG_ERRQUEUE = 0x2000;
397pub const MSG_NOSIGNAL = 0x4000;
398pub const MSG_MORE = 0x8000;
399pub const MSG_WAITFORONE = 0x10000;
400pub const MSG_BATCH = 0x40000;
401pub const MSG_ZEROCOPY = 0x4000000;
402pub const MSG_FASTOPEN = 0x20000000;
403pub const MSG_CMSG_CLOEXEC = 0x40000000;
404
405pub const DT_UNKNOWN = 0;
406pub const DT_FIFO = 1;
407pub const DT_CHR = 2;
408pub const DT_DIR = 4;
409pub const DT_BLK = 6;
410pub const DT_REG = 8;
411pub const DT_LNK = 10;
412pub const DT_SOCK = 12;
413pub const DT_WHT = 14;
414
415pub const TCGETS = 0x5401;
416pub const TCSETS = 0x5402;
417pub const TCSETSW = 0x5403;
418pub const TCSETSF = 0x5404;
419pub const TCGETA = 0x5405;
420pub const TCSETA = 0x5406;
421pub const TCSETAW = 0x5407;
422pub const TCSETAF = 0x5408;
423pub const TCSBRK = 0x5409;
424pub const TCXONC = 0x540A;
425pub const TCFLSH = 0x540B;
426pub const TIOCEXCL = 0x540C;
427pub const TIOCNXCL = 0x540D;
428pub const TIOCSCTTY = 0x540E;
429pub const TIOCGPGRP = 0x540F;
430pub const TIOCSPGRP = 0x5410;
431pub const TIOCOUTQ = 0x5411;
432pub const TIOCSTI = 0x5412;
433pub const TIOCGWINSZ = 0x5413;
434pub const TIOCSWINSZ = 0x5414;
435pub const TIOCMGET = 0x5415;
436pub const TIOCMBIS = 0x5416;
437pub const TIOCMBIC = 0x5417;
438pub const TIOCMSET = 0x5418;
439pub const TIOCGSOFTCAR = 0x5419;
440pub const TIOCSSOFTCAR = 0x541A;
441pub const FIONREAD = 0x541B;
442pub const TIOCINQ = FIONREAD;
443pub const TIOCLINUX = 0x541C;
444pub const TIOCCONS = 0x541D;
445pub const TIOCGSERIAL = 0x541E;
446pub const TIOCSSERIAL = 0x541F;
447pub const TIOCPKT = 0x5420;
448pub const FIONBIO = 0x5421;
449pub const TIOCNOTTY = 0x5422;
450pub const TIOCSETD = 0x5423;
451pub const TIOCGETD = 0x5424;
452pub const TCSBRKP = 0x5425;
453pub const TIOCSBRK = 0x5427;
454pub const TIOCCBRK = 0x5428;
455pub const TIOCGSID = 0x5429;
456pub const TIOCGRS485 = 0x542E;
457pub const TIOCSRS485 = 0x542F;
458pub const TIOCGPTN = 0x80045430;
459pub const TIOCSPTLCK = 0x40045431;
460pub const TIOCGDEV = 0x80045432;
461pub const TCGETX = 0x5432;
462pub const TCSETX = 0x5433;
463pub const TCSETXF = 0x5434;
464pub const TCSETXW = 0x5435;
465pub const TIOCSIG = 0x40045436;
466pub const TIOCVHANGUP = 0x5437;
467pub const TIOCGPKT = 0x80045438;
468pub const TIOCGPTLCK = 0x80045439;
469pub const TIOCGEXCL = 0x80045440;
470
471pub const EPOLL_CLOEXEC = O_CLOEXEC;
472
473pub const EPOLL_CTL_ADD = 1;
474pub const EPOLL_CTL_DEL = 2;
475pub const EPOLL_CTL_MOD = 3;
476
477pub const EPOLLIN = 0x001;
478pub const EPOLLPRI = 0x002;
479pub const EPOLLOUT = 0x004;
480pub const EPOLLRDNORM = 0x040;
481pub const EPOLLRDBAND = 0x080;
482pub const EPOLLWRNORM = 0x100;
483pub const EPOLLWRBAND = 0x200;
484pub const EPOLLMSG = 0x400;
485pub const EPOLLERR = 0x008;
486pub const EPOLLHUP = 0x010;
487pub const EPOLLRDHUP = 0x2000;
488pub const EPOLLEXCLUSIVE = (u32(1) << 28);
489pub const EPOLLWAKEUP = (u32(1) << 29);
490pub const EPOLLONESHOT = (u32(1) << 30);
491pub const EPOLLET = (u32(1) << 31);
492
493pub const CLOCK_REALTIME = 0;
494pub const CLOCK_MONOTONIC = 1;
495pub const CLOCK_PROCESS_CPUTIME_ID = 2;
496pub const CLOCK_THREAD_CPUTIME_ID = 3;
497pub const CLOCK_MONOTONIC_RAW = 4;
498pub const CLOCK_REALTIME_COARSE = 5;
499pub const CLOCK_MONOTONIC_COARSE = 6;
500pub const CLOCK_BOOTTIME = 7;
501pub const CLOCK_REALTIME_ALARM = 8;
502pub const CLOCK_BOOTTIME_ALARM = 9;
503pub const CLOCK_SGI_CYCLE = 10;
504pub const CLOCK_TAI = 11;
505
506pub const CSIGNAL = 0x000000ff;
507pub const CLONE_VM = 0x00000100;
508pub const CLONE_FS = 0x00000200;
509pub const CLONE_FILES = 0x00000400;
510pub const CLONE_SIGHAND = 0x00000800;
511pub const CLONE_PTRACE = 0x00002000;
512pub const CLONE_VFORK = 0x00004000;
513pub const CLONE_PARENT = 0x00008000;
514pub const CLONE_THREAD = 0x00010000;
515pub const CLONE_NEWNS = 0x00020000;
516pub const CLONE_SYSVSEM = 0x00040000;
517pub const CLONE_SETTLS = 0x00080000;
518pub const CLONE_PARENT_SETTID = 0x00100000;
519pub const CLONE_CHILD_CLEARTID = 0x00200000;
520pub const CLONE_DETACHED = 0x00400000;
521pub const CLONE_UNTRACED = 0x00800000;
522pub const CLONE_CHILD_SETTID = 0x01000000;
523pub const CLONE_NEWCGROUP = 0x02000000;
524pub const CLONE_NEWUTS = 0x04000000;
525pub const CLONE_NEWIPC = 0x08000000;
526pub const CLONE_NEWUSER = 0x10000000;
527pub const CLONE_NEWPID = 0x20000000;
528pub const CLONE_NEWNET = 0x40000000;
529pub const CLONE_IO = 0x80000000;
530
531pub const EFD_SEMAPHORE = 1;
532pub const EFD_CLOEXEC = O_CLOEXEC;
533pub const EFD_NONBLOCK = O_NONBLOCK;
534
535pub const MS_RDONLY = 1;
536pub const MS_NOSUID = 2;
537pub const MS_NODEV = 4;
538pub const MS_NOEXEC = 8;
539pub const MS_SYNCHRONOUS = 16;
540pub const MS_REMOUNT = 32;
541pub const MS_MANDLOCK = 64;
542pub const MS_DIRSYNC = 128;
543pub const MS_NOATIME = 1024;
544pub const MS_NODIRATIME = 2048;
545pub const MS_BIND = 4096;
546pub const MS_MOVE = 8192;
547pub const MS_REC = 16384;
548pub const MS_SILENT = 32768;
549pub const MS_POSIXACL = (1 << 16);
550pub const MS_UNBINDABLE = (1 << 17);
551pub const MS_PRIVATE = (1 << 18);
552pub const MS_SLAVE = (1 << 19);
553pub const MS_SHARED = (1 << 20);
554pub const MS_RELATIME = (1 << 21);
555pub const MS_KERNMOUNT = (1 << 22);
556pub const MS_I_VERSION = (1 << 23);
557pub const MS_STRICTATIME = (1 << 24);
558pub const MS_LAZYTIME = (1 << 25);
559pub const MS_NOREMOTELOCK = (1 << 27);
560pub const MS_NOSEC = (1 << 28);
561pub const MS_BORN = (1 << 29);
562pub const MS_ACTIVE = (1 << 30);
563pub const MS_NOUSER = (1 << 31);
564
565pub const MS_RMT_MASK = (MS_RDONLY | MS_SYNCHRONOUS | MS_MANDLOCK | MS_I_VERSION | MS_LAZYTIME);
566
567pub const MS_MGC_VAL = 0xc0ed0000;
568pub const MS_MGC_MSK = 0xffff0000;
569
570pub const MNT_FORCE = 1;
571pub const MNT_DETACH = 2;
572pub const MNT_EXPIRE = 4;
573pub const UMOUNT_NOFOLLOW = 8;
574
575pub const IN_CLOEXEC = O_CLOEXEC;
576pub const IN_NONBLOCK = O_NONBLOCK;
577
578pub const IN_ACCESS = 0x00000001;
579pub const IN_MODIFY = 0x00000002;
580pub const IN_ATTRIB = 0x00000004;
581pub const IN_CLOSE_WRITE = 0x00000008;
582pub const IN_CLOSE_NOWRITE = 0x00000010;
583pub const IN_CLOSE = IN_CLOSE_WRITE | IN_CLOSE_NOWRITE;
584pub const IN_OPEN = 0x00000020;
585pub const IN_MOVED_FROM = 0x00000040;
586pub const IN_MOVED_TO = 0x00000080;
587pub const IN_MOVE = IN_MOVED_FROM | IN_MOVED_TO;
588pub const IN_CREATE = 0x00000100;
589pub const IN_DELETE = 0x00000200;
590pub const IN_DELETE_SELF = 0x00000400;
591pub const IN_MOVE_SELF = 0x00000800;
592pub const IN_ALL_EVENTS = 0x00000fff;
593
594pub const IN_UNMOUNT = 0x00002000;
595pub const IN_Q_OVERFLOW = 0x00004000;
596pub const IN_IGNORED = 0x00008000;
597
598pub const IN_ONLYDIR = 0x01000000;
599pub const IN_DONT_FOLLOW = 0x02000000;
600pub const IN_EXCL_UNLINK = 0x04000000;
601pub const IN_MASK_ADD = 0x20000000;
602
603pub const IN_ISDIR = 0x40000000;
604pub const IN_ONESHOT = 0x80000000;
605
606pub const S_IFMT = 0o170000;
607
608pub const S_IFDIR = 0o040000;
609pub const S_IFCHR = 0o020000;
610pub const S_IFBLK = 0o060000;
611pub const S_IFREG = 0o100000;
612pub const S_IFIFO = 0o010000;
613pub const S_IFLNK = 0o120000;
614pub const S_IFSOCK = 0o140000;
615
616pub const S_ISUID = 0o4000;
617pub const S_ISGID = 0o2000;
618pub const S_ISVTX = 0o1000;
619pub const S_IRUSR = 0o400;
620pub const S_IWUSR = 0o200;
621pub const S_IXUSR = 0o100;
622pub const S_IRWXU = 0o700;
623pub const S_IRGRP = 0o040;
624pub const S_IWGRP = 0o020;
625pub const S_IXGRP = 0o010;
626pub const S_IRWXG = 0o070;
627pub const S_IROTH = 0o004;
628pub const S_IWOTH = 0o002;
629pub const S_IXOTH = 0o001;
630pub const S_IRWXO = 0o007;
631
632pub fn S_ISREG(m: u32) bool {
633 return m & S_IFMT == S_IFREG;
634}
635
636pub fn S_ISDIR(m: u32) bool {
637 return m & S_IFMT == S_IFDIR;
638}
639
640pub fn S_ISCHR(m: u32) bool {
641 return m & S_IFMT == S_IFCHR;
642}
643
644pub fn S_ISBLK(m: u32) bool {
645 return m & S_IFMT == S_IFBLK;
646}
647
648pub fn S_ISFIFO(m: u32) bool {
649 return m & S_IFMT == S_IFIFO;
650}
651
652pub fn S_ISLNK(m: u32) bool {
653 return m & S_IFMT == S_IFLNK;
654}
655
656pub fn S_ISSOCK(m: u32) bool {
657 return m & S_IFMT == S_IFSOCK;
658}
659
660pub const TFD_NONBLOCK = O_NONBLOCK;
661pub const TFD_CLOEXEC = O_CLOEXEC;
662
663pub const TFD_TIMER_ABSTIME = 1;
664pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1);
665
666pub fn WEXITSTATUS(s: u32) u32 {
667 return (s & 0xff00) >> 8;
668}
669pub fn WTERMSIG(s: u32) u32 {
670 return s & 0x7f;
671}
672pub fn WSTOPSIG(s: u32) u32 {
673 return WEXITSTATUS(s);
674}
675pub fn WIFEXITED(s: u32) bool {
676 return WTERMSIG(s) == 0;
677}
678pub fn WIFSTOPPED(s: u32) bool {
679 return @intCast(u16, ((s & 0xffff) *% 0x10001) >> 8) > 0x7f00;
680}
681pub fn WIFSIGNALED(s: u32) bool {
682 return (s & 0xffff) -% 1 < 0xff;
683}
684
685pub const winsize = extern struct {
686 ws_row: u16,
687 ws_col: u16,
688 ws_xpixel: u16,
689 ws_ypixel: u16,
690};
691
692pub const NSIG = 65;
693pub const sigset_t = [128 / @sizeOf(usize)]usize;
694pub const all_mask = []u32{ 0xffffffff, 0xffffffff };
695pub const app_mask = []u32{ 0xfffffffc, 0x7fffffff };
696
697pub const k_sigaction = extern struct {
698 handler: extern fn (i32) void,
699 flags: usize,
700 restorer: extern fn () void,
701 mask: [2]u32,
702};
703
704/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
705pub const Sigaction = struct {
706 handler: extern fn (i32) void,
707 mask: sigset_t,
708 flags: u32,
709};
710
711pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
712pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
713pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
714pub const empty_sigset = []usize{0} ** sigset_t.len;
715
716pub const in_port_t = u16;
717pub const sa_family_t = u16;
718pub const socklen_t = u32;
719
720/// This intentionally only has ip4 and ip6
721pub const sockaddr = extern union {
722 in: sockaddr_in,
723 in6: sockaddr_in6,
724};
725
726pub const sockaddr_in = extern struct {
727 family: sa_family_t,
728 port: in_port_t,
729 addr: u32,
730 zero: [8]u8,
731};
732
733pub const sockaddr_in6 = extern struct {
734 family: sa_family_t,
735 port: in_port_t,
736 flowinfo: u32,
737 addr: [16]u8,
738 scope_id: u32,
739};
740
741pub const sockaddr_un = extern struct {
742 family: sa_family_t,
743 path: [108]u8,
744};
745
746pub const mmsghdr = extern struct {
747 msg_hdr: msghdr,
748 msg_len: u32,
749};
750
751pub const mmsghdr_const = extern struct {
752 msg_hdr: msghdr_const,
753 msg_len: u32,
754};
755
756pub const epoll_data = extern union {
757 ptr: usize,
758 fd: i32,
759 @"u32": u32,
760 @"u64": u64,
761};
762
763// On x86_64 the structure is packed so that it matches the definition of its
764// 32bit counterpart
765pub const epoll_event = if (builtin.arch != .x86_64)
766 extern struct {
767 events: u32,
768 data: epoll_data,
769 }
770else
771 packed struct {
772 events: u32,
773 data: epoll_data,
774 };
775
776pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330;
777pub const _LINUX_CAPABILITY_U32S_1 = 1;
778
779pub const _LINUX_CAPABILITY_VERSION_2 = 0x20071026;
780pub const _LINUX_CAPABILITY_U32S_2 = 2;
781
782pub const _LINUX_CAPABILITY_VERSION_3 = 0x20080522;
783pub const _LINUX_CAPABILITY_U32S_3 = 2;
784
785pub const VFS_CAP_REVISION_MASK = 0xFF000000;
786pub const VFS_CAP_REVISION_SHIFT = 24;
787pub const VFS_CAP_FLAGS_MASK = ~VFS_CAP_REVISION_MASK;
788pub const VFS_CAP_FLAGS_EFFECTIVE = 0x000001;
789
790pub const VFS_CAP_REVISION_1 = 0x01000000;
791pub const VFS_CAP_U32_1 = 1;
792pub const XATTR_CAPS_SZ_1 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_1);
793
794pub const VFS_CAP_REVISION_2 = 0x02000000;
795pub const VFS_CAP_U32_2 = 2;
796pub const XATTR_CAPS_SZ_2 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_2);
797
798pub const XATTR_CAPS_SZ = XATTR_CAPS_SZ_2;
799pub const VFS_CAP_U32 = VFS_CAP_U32_2;
800pub const VFS_CAP_REVISION = VFS_CAP_REVISION_2;
801
802pub const vfs_cap_data = extern struct {
803 //all of these are mandated as little endian
804 //when on disk.
805 const Data = struct {
806 permitted: u32,
807 inheritable: u32,
808 };
809
810 magic_etc: u32,
811 data: [VFS_CAP_U32]Data,
812};
813
814pub const CAP_CHOWN = 0;
815pub const CAP_DAC_OVERRIDE = 1;
816pub const CAP_DAC_READ_SEARCH = 2;
817pub const CAP_FOWNER = 3;
818pub const CAP_FSETID = 4;
819pub const CAP_KILL = 5;
820pub const CAP_SETGID = 6;
821pub const CAP_SETUID = 7;
822pub const CAP_SETPCAP = 8;
823pub const CAP_LINUX_IMMUTABLE = 9;
824pub const CAP_NET_BIND_SERVICE = 10;
825pub const CAP_NET_BROADCAST = 11;
826pub const CAP_NET_ADMIN = 12;
827pub const CAP_NET_RAW = 13;
828pub const CAP_IPC_LOCK = 14;
829pub const CAP_IPC_OWNER = 15;
830pub const CAP_SYS_MODULE = 16;
831pub const CAP_SYS_RAWIO = 17;
832pub const CAP_SYS_CHROOT = 18;
833pub const CAP_SYS_PTRACE = 19;
834pub const CAP_SYS_PACCT = 20;
835pub const CAP_SYS_ADMIN = 21;
836pub const CAP_SYS_BOOT = 22;
837pub const CAP_SYS_NICE = 23;
838pub const CAP_SYS_RESOURCE = 24;
839pub const CAP_SYS_TIME = 25;
840pub const CAP_SYS_TTY_CONFIG = 26;
841pub const CAP_MKNOD = 27;
842pub const CAP_LEASE = 28;
843pub const CAP_AUDIT_WRITE = 29;
844pub const CAP_AUDIT_CONTROL = 30;
845pub const CAP_SETFCAP = 31;
846pub const CAP_MAC_OVERRIDE = 32;
847pub const CAP_MAC_ADMIN = 33;
848pub const CAP_SYSLOG = 34;
849pub const CAP_WAKE_ALARM = 35;
850pub const CAP_BLOCK_SUSPEND = 36;
851pub const CAP_AUDIT_READ = 37;
852pub const CAP_LAST_CAP = CAP_AUDIT_READ;
853
854pub fn cap_valid(u8: x) bool {
855 return x >= 0 and x <= CAP_LAST_CAP;
856}
857
858pub fn CAP_TO_MASK(cap: u8) u32 {
859 return u32(1) << u5(cap & 31);
860}
861
862pub fn CAP_TO_INDEX(cap: u8) u8 {
863 return cap >> 5;
864}
865
866pub const cap_t = extern struct {
867 hdrp: *cap_user_header_t,
868 datap: *cap_user_data_t,
869};
870
871pub const cap_user_header_t = extern struct {
872 version: u32,
873 pid: usize,
874};
875
876pub const cap_user_data_t = extern struct {
877 effective: u32,
878 permitted: u32,
879 inheritable: u32,
880};
881
882pub const inotify_event = extern struct {
883 wd: i32,
884 mask: u32,
885 cookie: u32,
886 len: u32,
887 //name: [?]u8,
888};
889
890pub const dirent64 = extern struct {
891 d_ino: u64,
892 d_off: u64,
893 d_reclen: u16,
894 d_type: u8,
895 d_name: u8, // field address is the address of first byte of name https://github.com/ziglang/zig/issues/173
896};
897
898pub const dl_phdr_info = extern struct {
899 dlpi_addr: usize,
900 dlpi_name: ?[*]const u8,
901 dlpi_phdr: [*]std.elf.Phdr,
902 dlpi_phnum: u16,
903};
904
905pub const pthread_attr_t = extern struct {
906 __size: [56]u8,
907 __align: c_long,
908};
909
910pub const CPU_SETSIZE = 128;
911pub const cpu_set_t = [CPU_SETSIZE / @sizeOf(usize)]usize;
912pub const cpu_count_t = @IntType(false, std.math.log2(CPU_SETSIZE * 8));
913
914pub fn CPU_COUNT(set: cpu_set_t) cpu_count_t {
915 var sum: cpu_count_t = 0;
916 for (set) |x| {
917 sum += @popCount(usize, x);
918 }
919 return sum;
920}
921
922// TODO port these over
923//#define CPU_SET(i, set) CPU_SET_S(i,sizeof(cpu_set_t),set)
924//#define CPU_CLR(i, set) CPU_CLR_S(i,sizeof(cpu_set_t),set)
925//#define CPU_ISSET(i, set) CPU_ISSET_S(i,sizeof(cpu_set_t),set)
926//#define CPU_AND(d,s1,s2) CPU_AND_S(sizeof(cpu_set_t),d,s1,s2)
927//#define CPU_OR(d,s1,s2) CPU_OR_S(sizeof(cpu_set_t),d,s1,s2)
928//#define CPU_XOR(d,s1,s2) CPU_XOR_S(sizeof(cpu_set_t),d,s1,s2)
929//#define CPU_COUNT(set) CPU_COUNT_S(sizeof(cpu_set_t),set)
930//#define CPU_ZERO(set) CPU_ZERO_S(sizeof(cpu_set_t),set)
931//#define CPU_EQUAL(s1,s2) CPU_EQUAL_S(sizeof(cpu_set_t),s1,s2)
std/os/bits/linux/arm64.zig created+405
...@@ -0,0 +1,405 @@
1// arm64-specific declarations that are intended to be imported into the POSIX namespace.
2// This does include Linux-only APIs.
3
4const std = @import("../../std.zig");
5const linux = std.os.linux;
6const socklen_t = linux.socklen_t;
7const iovec = linux.iovec;
8const iovec_const = linux.iovec_const;
9
10pub const SYS_io_setup = 0;
11pub const SYS_io_destroy = 1;
12pub const SYS_io_submit = 2;
13pub const SYS_io_cancel = 3;
14pub const SYS_io_getevents = 4;
15pub const SYS_setxattr = 5;
16pub const SYS_lsetxattr = 6;
17pub const SYS_fsetxattr = 7;
18pub const SYS_getxattr = 8;
19pub const SYS_lgetxattr = 9;
20pub const SYS_fgetxattr = 10;
21pub const SYS_listxattr = 11;
22pub const SYS_llistxattr = 12;
23pub const SYS_flistxattr = 13;
24pub const SYS_removexattr = 14;
25pub const SYS_lremovexattr = 15;
26pub const SYS_fremovexattr = 16;
27pub const SYS_getcwd = 17;
28pub const SYS_lookup_dcookie = 18;
29pub const SYS_eventfd2 = 19;
30pub const SYS_epoll_create1 = 20;
31pub const SYS_epoll_ctl = 21;
32pub const SYS_epoll_pwait = 22;
33pub const SYS_dup = 23;
34pub const SYS_dup3 = 24;
35pub const SYS_fcntl = 25;
36pub const SYS_inotify_init1 = 26;
37pub const SYS_inotify_add_watch = 27;
38pub const SYS_inotify_rm_watch = 28;
39pub const SYS_ioctl = 29;
40pub const SYS_ioprio_set = 30;
41pub const SYS_ioprio_get = 31;
42pub const SYS_flock = 32;
43pub const SYS_mknodat = 33;
44pub const SYS_mkdirat = 34;
45pub const SYS_unlinkat = 35;
46pub const SYS_symlinkat = 36;
47pub const SYS_linkat = 37;
48pub const SYS_renameat = 38;
49pub const SYS_umount2 = 39;
50pub const SYS_mount = 40;
51pub const SYS_pivot_root = 41;
52pub const SYS_nfsservctl = 42;
53pub const SYS_statfs = 43;
54pub const SYS_fstatfs = 44;
55pub const SYS_truncate = 45;
56pub const SYS_ftruncate = 46;
57pub const SYS_fallocate = 47;
58pub const SYS_faccessat = 48;
59pub const SYS_chdir = 49;
60pub const SYS_fchdir = 50;
61pub const SYS_chroot = 51;
62pub const SYS_fchmod = 52;
63pub const SYS_fchmodat = 53;
64pub const SYS_fchownat = 54;
65pub const SYS_fchown = 55;
66pub const SYS_openat = 56;
67pub const SYS_close = 57;
68pub const SYS_vhangup = 58;
69pub const SYS_pipe2 = 59;
70pub const SYS_quotactl = 60;
71pub const SYS_getdents64 = 61;
72pub const SYS_lseek = 62;
73pub const SYS_read = 63;
74pub const SYS_write = 64;
75pub const SYS_readv = 65;
76pub const SYS_writev = 66;
77pub const SYS_pread64 = 67;
78pub const SYS_pwrite64 = 68;
79pub const SYS_preadv = 69;
80pub const SYS_pwritev = 70;
81pub const SYS_pselect6 = 72;
82pub const SYS_ppoll = 73;
83pub const SYS_signalfd4 = 74;
84pub const SYS_vmsplice = 75;
85pub const SYS_splice = 76;
86pub const SYS_tee = 77;
87pub const SYS_readlinkat = 78;
88pub const SYS_fstatat = 79;
89pub const SYS_fstat = 80;
90pub const SYS_sync = 81;
91pub const SYS_fsync = 82;
92pub const SYS_fdatasync = 83;
93pub const SYS_sync_file_range2 = 84;
94pub const SYS_sync_file_range = 84;
95pub const SYS_timerfd_create = 85;
96pub const SYS_timerfd_settime = 86;
97pub const SYS_timerfd_gettime = 87;
98pub const SYS_utimensat = 88;
99pub const SYS_acct = 89;
100pub const SYS_capget = 90;
101pub const SYS_capset = 91;
102pub const SYS_personality = 92;
103pub const SYS_exit = 93;
104pub const SYS_exit_group = 94;
105pub const SYS_waitid = 95;
106pub const SYS_set_tid_address = 96;
107pub const SYS_unshare = 97;
108pub const SYS_futex = 98;
109pub const SYS_set_robust_list = 99;
110pub const SYS_get_robust_list = 100;
111pub const SYS_nanosleep = 101;
112pub const SYS_getitimer = 102;
113pub const SYS_setitimer = 103;
114pub const SYS_kexec_load = 104;
115pub const SYS_init_module = 105;
116pub const SYS_delete_module = 106;
117pub const SYS_timer_create = 107;
118pub const SYS_timer_gettime = 108;
119pub const SYS_timer_getoverrun = 109;
120pub const SYS_timer_settime = 110;
121pub const SYS_timer_delete = 111;
122pub const SYS_clock_settime = 112;
123pub const SYS_clock_gettime = 113;
124pub const SYS_clock_getres = 114;
125pub const SYS_clock_nanosleep = 115;
126pub const SYS_syslog = 116;
127pub const SYS_ptrace = 117;
128pub const SYS_sched_setparam = 118;
129pub const SYS_sched_setscheduler = 119;
130pub const SYS_sched_getscheduler = 120;
131pub const SYS_sched_getparam = 121;
132pub const SYS_sched_setaffinity = 122;
133pub const SYS_sched_getaffinity = 123;
134pub const SYS_sched_yield = 124;
135pub const SYS_sched_get_priority_max = 125;
136pub const SYS_sched_get_priority_min = 126;
137pub const SYS_sched_rr_get_interval = 127;
138pub const SYS_restart_syscall = 128;
139pub const SYS_kill = 129;
140pub const SYS_tkill = 130;
141pub const SYS_tgkill = 131;
142pub const SYS_sigaltstack = 132;
143pub const SYS_rt_sigsuspend = 133;
144pub const SYS_rt_sigaction = 134;
145pub const SYS_rt_sigprocmask = 135;
146pub const SYS_rt_sigpending = 136;
147pub const SYS_rt_sigtimedwait = 137;
148pub const SYS_rt_sigqueueinfo = 138;
149pub const SYS_rt_sigreturn = 139;
150pub const SYS_setpriority = 140;
151pub const SYS_getpriority = 141;
152pub const SYS_reboot = 142;
153pub const SYS_setregid = 143;
154pub const SYS_setgid = 144;
155pub const SYS_setreuid = 145;
156pub const SYS_setuid = 146;
157pub const SYS_setresuid = 147;
158pub const SYS_getresuid = 148;
159pub const SYS_setresgid = 149;
160pub const SYS_getresgid = 150;
161pub const SYS_setfsuid = 151;
162pub const SYS_setfsgid = 152;
163pub const SYS_times = 153;
164pub const SYS_setpgid = 154;
165pub const SYS_getpgid = 155;
166pub const SYS_getsid = 156;
167pub const SYS_setsid = 157;
168pub const SYS_getgroups = 158;
169pub const SYS_setgroups = 159;
170pub const SYS_uname = 160;
171pub const SYS_sethostname = 161;
172pub const SYS_setdomainname = 162;
173pub const SYS_getrlimit = 163;
174pub const SYS_setrlimit = 164;
175pub const SYS_getrusage = 165;
176pub const SYS_umask = 166;
177pub const SYS_prctl = 167;
178pub const SYS_getcpu = 168;
179pub const SYS_gettimeofday = 169;
180pub const SYS_settimeofday = 170;
181pub const SYS_adjtimex = 171;
182pub const SYS_getpid = 172;
183pub const SYS_getppid = 173;
184pub const SYS_getuid = 174;
185pub const SYS_geteuid = 175;
186pub const SYS_getgid = 176;
187pub const SYS_getegid = 177;
188pub const SYS_gettid = 178;
189pub const SYS_sysinfo = 179;
190pub const SYS_mq_open = 180;
191pub const SYS_mq_unlink = 181;
192pub const SYS_mq_timedsend = 182;
193pub const SYS_mq_timedreceive = 183;
194pub const SYS_mq_notify = 184;
195pub const SYS_mq_getsetattr = 185;
196pub const SYS_msgget = 186;
197pub const SYS_msgctl = 187;
198pub const SYS_msgrcv = 188;
199pub const SYS_msgsnd = 189;
200pub const SYS_semget = 190;
201pub const SYS_semctl = 191;
202pub const SYS_semtimedop = 192;
203pub const SYS_semop = 193;
204pub const SYS_shmget = 194;
205pub const SYS_shmctl = 195;
206pub const SYS_shmat = 196;
207pub const SYS_shmdt = 197;
208pub const SYS_socket = 198;
209pub const SYS_socketpair = 199;
210pub const SYS_bind = 200;
211pub const SYS_listen = 201;
212pub const SYS_accept = 202;
213pub const SYS_connect = 203;
214pub const SYS_getsockname = 204;
215pub const SYS_getpeername = 205;
216pub const SYS_sendto = 206;
217pub const SYS_recvfrom = 207;
218pub const SYS_setsockopt = 208;
219pub const SYS_getsockopt = 209;
220pub const SYS_shutdown = 210;
221pub const SYS_sendmsg = 211;
222pub const SYS_recvmsg = 212;
223pub const SYS_readahead = 213;
224pub const SYS_brk = 214;
225pub const SYS_munmap = 215;
226pub const SYS_mremap = 216;
227pub const SYS_add_key = 217;
228pub const SYS_request_key = 218;
229pub const SYS_keyctl = 219;
230pub const SYS_clone = 220;
231pub const SYS_execve = 221;
232pub const SYS_mmap = 222;
233pub const SYS_fadvise64 = 223;
234pub const SYS_swapon = 224;
235pub const SYS_swapoff = 225;
236pub const SYS_mprotect = 226;
237pub const SYS_msync = 227;
238pub const SYS_mlock = 228;
239pub const SYS_munlock = 229;
240pub const SYS_mlockall = 230;
241pub const SYS_munlockall = 231;
242pub const SYS_mincore = 232;
243pub const SYS_madvise = 233;
244pub const SYS_remap_file_pages = 234;
245pub const SYS_mbind = 235;
246pub const SYS_get_mempolicy = 236;
247pub const SYS_set_mempolicy = 237;
248pub const SYS_migrate_pages = 238;
249pub const SYS_move_pages = 239;
250pub const SYS_rt_tgsigqueueinfo = 240;
251pub const SYS_perf_event_open = 241;
252pub const SYS_accept4 = 242;
253pub const SYS_recvmmsg = 243;
254pub const SYS_arch_specific_syscall = 244;
255pub const SYS_wait4 = 260;
256pub const SYS_prlimit64 = 261;
257pub const SYS_fanotify_init = 262;
258pub const SYS_fanotify_mark = 263;
259pub const SYS_clock_adjtime = 266;
260pub const SYS_syncfs = 267;
261pub const SYS_setns = 268;
262pub const SYS_sendmmsg = 269;
263pub const SYS_process_vm_readv = 270;
264pub const SYS_process_vm_writev = 271;
265pub const SYS_kcmp = 272;
266pub const SYS_finit_module = 273;
267pub const SYS_sched_setattr = 274;
268pub const SYS_sched_getattr = 275;
269pub const SYS_renameat2 = 276;
270pub const SYS_seccomp = 277;
271pub const SYS_getrandom = 278;
272pub const SYS_memfd_create = 279;
273pub const SYS_bpf = 280;
274pub const SYS_execveat = 281;
275pub const SYS_userfaultfd = 282;
276pub const SYS_membarrier = 283;
277pub const SYS_mlock2 = 284;
278pub const SYS_copy_file_range = 285;
279pub const SYS_preadv2 = 286;
280pub const SYS_pwritev2 = 287;
281pub const SYS_pkey_mprotect = 288;
282pub const SYS_pkey_alloc = 289;
283pub const SYS_pkey_free = 290;
284pub const SYS_statx = 291;
285pub const SYS_io_pgetevents = 292;
286pub const SYS_rseq = 293;
287pub const SYS_kexec_file_load = 294;
288pub const SYS_pidfd_send_signal = 424;
289pub const SYS_io_uring_setup = 425;
290pub const SYS_io_uring_enter = 426;
291pub const SYS_io_uring_register = 427;
292
293pub const O_CREAT = 0o100;
294pub const O_EXCL = 0o200;
295pub const O_NOCTTY = 0o400;
296pub const O_TRUNC = 0o1000;
297pub const O_APPEND = 0o2000;
298pub const O_NONBLOCK = 0o4000;
299pub const O_DSYNC = 0o10000;
300pub const O_SYNC = 0o4010000;
301pub const O_RSYNC = 0o4010000;
302pub const O_DIRECTORY = 0o200000;
303pub const O_NOFOLLOW = 0o400000;
304pub const O_CLOEXEC = 0o2000000;
305
306pub const O_ASYNC = 0o20000;
307pub const O_DIRECT = 0o40000;
308pub const O_LARGEFILE = 0;
309pub const O_NOATIME = 0o1000000;
310pub const O_PATH = 0o10000000;
311pub const O_TMPFILE = 0o20200000;
312pub const O_NDELAY = O_NONBLOCK;
313
314pub const F_DUPFD = 0;
315pub const F_GETFD = 1;
316pub const F_SETFD = 2;
317pub const F_GETFL = 3;
318pub const F_SETFL = 4;
319
320pub const F_SETOWN = 8;
321pub const F_GETOWN = 9;
322pub const F_SETSIG = 10;
323pub const F_GETSIG = 11;
324
325pub const F_GETLK = 5;
326pub const F_SETLK = 6;
327pub const F_SETLKW = 7;
328
329pub const F_SETOWN_EX = 15;
330pub const F_GETOWN_EX = 16;
331
332pub const F_GETOWNER_UIDS = 17;
333
334pub const AT_FDCWD = -100;
335pub const AT_SYMLINK_NOFOLLOW = 0x100;
336pub const AT_REMOVEDIR = 0x200;
337pub const AT_SYMLINK_FOLLOW = 0x400;
338pub const AT_NO_AUTOMOUNT = 0x800;
339pub const AT_EMPTY_PATH = 0x1000;
340
341pub const VDSO_USEFUL = true;
342pub const VDSO_CGT_SYM = "__kernel_clock_gettime";
343pub const VDSO_CGT_VER = "LINUX_2.6.39";
344
345pub const msghdr = extern struct {
346 msg_name: ?*sockaddr,
347 msg_namelen: socklen_t,
348 msg_iov: [*]iovec,
349 msg_iovlen: i32,
350 __pad1: i32,
351 msg_control: ?*c_void,
352 msg_controllen: socklen_t,
353 __pad2: socklen_t,
354 msg_flags: i32,
355};
356
357pub const msghdr_const = extern struct {
358 msg_name: ?*const sockaddr,
359 msg_namelen: socklen_t,
360 msg_iov: [*]iovec_const,
361 msg_iovlen: i32,
362 __pad1: i32,
363 msg_control: ?*c_void,
364 msg_controllen: socklen_t,
365 __pad2: socklen_t,
366 msg_flags: i32,
367};
368
369/// Renamed to Stat to not conflict with the stat function.
370pub const Stat = extern struct {
371 dev: u64,
372 ino: u64,
373 nlink: usize,
374
375 mode: u32,
376 uid: u32,
377 gid: u32,
378 __pad0: u32,
379 rdev: u64,
380 size: i64,
381 blksize: isize,
382 blocks: i64,
383
384 atim: timespec,
385 mtim: timespec,
386 ctim: timespec,
387 __unused: [3]isize,
388};
389
390pub const timespec = extern struct {
391 tv_sec: isize,
392 tv_nsec: isize,
393};
394
395pub const timeval = extern struct {
396 tv_sec: isize,
397 tv_usec: isize,
398};
399
400pub const timezone = extern struct {
401 tz_minuteswest: i32,
402 tz_dsttime: i32,
403};
404
405pub const Elf_Symndx = u32;
std/os/bits/linux/errno.zig created+428
...@@ -0,0 +1,428 @@
1/// Operation not permitted
2pub const EPERM = 1;
3
4/// No such file or directory
5pub const ENOENT = 2;
6
7/// No such process
8pub const ESRCH = 3;
9
10/// Interrupted system call
11pub const EINTR = 4;
12
13/// I/O error
14pub const EIO = 5;
15
16/// No such device or address
17pub const ENXIO = 6;
18
19/// Arg list too long
20pub const E2BIG = 7;
21
22/// Exec format error
23pub const ENOEXEC = 8;
24
25/// Bad file number
26pub const EBADF = 9;
27
28/// No child processes
29pub const ECHILD = 10;
30
31/// Try again
32pub const EAGAIN = 11;
33
34/// Out of memory
35pub const ENOMEM = 12;
36
37/// Permission denied
38pub const EACCES = 13;
39
40/// Bad address
41pub const EFAULT = 14;
42
43/// Block device required
44pub const ENOTBLK = 15;
45
46/// Device or resource busy
47pub const EBUSY = 16;
48
49/// File exists
50pub const EEXIST = 17;
51
52/// Cross-device link
53pub const EXDEV = 18;
54
55/// No such device
56pub const ENODEV = 19;
57
58/// Not a directory
59pub const ENOTDIR = 20;
60
61/// Is a directory
62pub const EISDIR = 21;
63
64/// Invalid argument
65pub const EINVAL = 22;
66
67/// File table overflow
68pub const ENFILE = 23;
69
70/// Too many open files
71pub const EMFILE = 24;
72
73/// Not a typewriter
74pub const ENOTTY = 25;
75
76/// Text file busy
77pub const ETXTBSY = 26;
78
79/// File too large
80pub const EFBIG = 27;
81
82/// No space left on device
83pub const ENOSPC = 28;
84
85/// Illegal seek
86pub const ESPIPE = 29;
87
88/// Read-only file system
89pub const EROFS = 30;
90
91/// Too many links
92pub const EMLINK = 31;
93
94/// Broken pipe
95pub const EPIPE = 32;
96
97/// Math argument out of domain of func
98pub const EDOM = 33;
99
100/// Math result not representable
101pub const ERANGE = 34;
102
103/// Resource deadlock would occur
104pub const EDEADLK = 35;
105
106/// File name too long
107pub const ENAMETOOLONG = 36;
108
109/// No record locks available
110pub const ENOLCK = 37;
111
112/// Function not implemented
113pub const ENOSYS = 38;
114
115/// Directory not empty
116pub const ENOTEMPTY = 39;
117
118/// Too many symbolic links encountered
119pub const ELOOP = 40;
120
121/// Operation would block
122pub const EWOULDBLOCK = EAGAIN;
123
124/// No message of desired type
125pub const ENOMSG = 42;
126
127/// Identifier removed
128pub const EIDRM = 43;
129
130/// Channel number out of range
131pub const ECHRNG = 44;
132
133/// Level 2 not synchronized
134pub const EL2NSYNC = 45;
135
136/// Level 3 halted
137pub const EL3HLT = 46;
138
139/// Level 3 reset
140pub const EL3RST = 47;
141
142/// Link number out of range
143pub const ELNRNG = 48;
144
145/// Protocol driver not attached
146pub const EUNATCH = 49;
147
148/// No CSI structure available
149pub const ENOCSI = 50;
150
151/// Level 2 halted
152pub const EL2HLT = 51;
153
154/// Invalid exchange
155pub const EBADE = 52;
156
157/// Invalid request descriptor
158pub const EBADR = 53;
159
160/// Exchange full
161pub const EXFULL = 54;
162
163/// No anode
164pub const ENOANO = 55;
165
166/// Invalid request code
167pub const EBADRQC = 56;
168
169/// Invalid slot
170pub const EBADSLT = 57;
171
172/// Bad font file format
173pub const EBFONT = 59;
174
175/// Device not a stream
176pub const ENOSTR = 60;
177
178/// No data available
179pub const ENODATA = 61;
180
181/// Timer expired
182pub const ETIME = 62;
183
184/// Out of streams resources
185pub const ENOSR = 63;
186
187/// Machine is not on the network
188pub const ENONET = 64;
189
190/// Package not installed
191pub const ENOPKG = 65;
192
193/// Object is remote
194pub const EREMOTE = 66;
195
196/// Link has been severed
197pub const ENOLINK = 67;
198
199/// Advertise error
200pub const EADV = 68;
201
202/// Srmount error
203pub const ESRMNT = 69;
204
205/// Communication error on send
206pub const ECOMM = 70;
207
208/// Protocol error
209pub const EPROTO = 71;
210
211/// Multihop attempted
212pub const EMULTIHOP = 72;
213
214/// RFS specific error
215pub const EDOTDOT = 73;
216
217/// Not a data message
218pub const EBADMSG = 74;
219
220/// Value too large for defined data type
221pub const EOVERFLOW = 75;
222
223/// Name not unique on network
224pub const ENOTUNIQ = 76;
225
226/// File descriptor in bad state
227pub const EBADFD = 77;
228
229/// Remote address changed
230pub const EREMCHG = 78;
231
232/// Can not access a needed shared library
233pub const ELIBACC = 79;
234
235/// Accessing a corrupted shared library
236pub const ELIBBAD = 80;
237
238/// .lib section in a.out corrupted
239pub const ELIBSCN = 81;
240
241/// Attempting to link in too many shared libraries
242pub const ELIBMAX = 82;
243
244/// Cannot exec a shared library directly
245pub const ELIBEXEC = 83;
246
247/// Illegal byte sequence
248pub const EILSEQ = 84;
249
250/// Interrupted system call should be restarted
251pub const ERESTART = 85;
252
253/// Streams pipe error
254pub const ESTRPIPE = 86;
255
256/// Too many users
257pub const EUSERS = 87;
258
259/// Socket operation on non-socket
260pub const ENOTSOCK = 88;
261
262/// Destination address required
263pub const EDESTADDRREQ = 89;
264
265/// Message too long
266pub const EMSGSIZE = 90;
267
268/// Protocol wrong type for socket
269pub const EPROTOTYPE = 91;
270
271/// Protocol not available
272pub const ENOPROTOOPT = 92;
273
274/// Protocol not supported
275pub const EPROTONOSUPPORT = 93;
276
277/// Socket type not supported
278pub const ESOCKTNOSUPPORT = 94;
279
280/// Operation not supported on transport endpoint
281pub const EOPNOTSUPP = 95;
282pub const ENOTSUP = EOPNOTSUPP;
283
284/// Protocol family not supported
285pub const EPFNOSUPPORT = 96;
286
287/// Address family not supported by protocol
288pub const EAFNOSUPPORT = 97;
289
290/// Address already in use
291pub const EADDRINUSE = 98;
292
293/// Cannot assign requested address
294pub const EADDRNOTAVAIL = 99;
295
296/// Network is down
297pub const ENETDOWN = 100;
298
299/// Network is unreachable
300pub const ENETUNREACH = 101;
301
302/// Network dropped connection because of reset
303pub const ENETRESET = 102;
304
305/// Software caused connection abort
306pub const ECONNABORTED = 103;
307
308/// Connection reset by peer
309pub const ECONNRESET = 104;
310
311/// No buffer space available
312pub const ENOBUFS = 105;
313
314/// Transport endpoint is already connected
315pub const EISCONN = 106;
316
317/// Transport endpoint is not connected
318pub const ENOTCONN = 107;
319
320/// Cannot send after transport endpoint shutdown
321pub const ESHUTDOWN = 108;
322
323/// Too many references: cannot splice
324pub const ETOOMANYREFS = 109;
325
326/// Connection timed out
327pub const ETIMEDOUT = 110;
328
329/// Connection refused
330pub const ECONNREFUSED = 111;
331
332/// Host is down
333pub const EHOSTDOWN = 112;
334
335/// No route to host
336pub const EHOSTUNREACH = 113;
337
338/// Operation already in progress
339pub const EALREADY = 114;
340
341/// Operation now in progress
342pub const EINPROGRESS = 115;
343
344/// Stale NFS file handle
345pub const ESTALE = 116;
346
347/// Structure needs cleaning
348pub const EUCLEAN = 117;
349
350/// Not a XENIX named type file
351pub const ENOTNAM = 118;
352
353/// No XENIX semaphores available
354pub const ENAVAIL = 119;
355
356/// Is a named type file
357pub const EISNAM = 120;
358
359/// Remote I/O error
360pub const EREMOTEIO = 121;
361
362/// Quota exceeded
363pub const EDQUOT = 122;
364
365/// No medium found
366pub const ENOMEDIUM = 123;
367
368/// Wrong medium type
369pub const EMEDIUMTYPE = 124;
370
371// nameserver query return codes
372
373/// DNS server returned answer with no data
374pub const ENSROK = 0;
375
376/// DNS server returned answer with no data
377pub const ENSRNODATA = 160;
378
379/// DNS server claims query was misformatted
380pub const ENSRFORMERR = 161;
381
382/// DNS server returned general failure
383pub const ENSRSERVFAIL = 162;
384
385/// Domain name not found
386pub const ENSRNOTFOUND = 163;
387
388/// DNS server does not implement requested operation
389pub const ENSRNOTIMP = 164;
390
391/// DNS server refused query
392pub const ENSRREFUSED = 165;
393
394/// Misformatted DNS query
395pub const ENSRBADQUERY = 166;
396
397/// Misformatted domain name
398pub const ENSRBADNAME = 167;
399
400/// Unsupported address family
401pub const ENSRBADFAMILY = 168;
402
403/// Misformatted DNS reply
404pub const ENSRBADRESP = 169;
405
406/// Could not contact DNS servers
407pub const ENSRCONNREFUSED = 170;
408
409/// Timeout while contacting DNS servers
410pub const ENSRTIMEOUT = 171;
411
412/// End of file
413pub const ENSROF = 172;
414
415/// Error reading file
416pub const ENSRFILE = 173;
417
418/// Out of memory
419pub const ENSRNOMEM = 174;
420
421/// Application terminated lookup
422pub const ENSRDESTRUCTION = 175;
423
424/// Domain name is too long
425pub const ENSRQUERYDOMAINTOOLONG = 176;
426
427/// Domain name is too long
428pub const ENSRCNAMELOOP = 177;
std/os/bits/linux/x86_64.zig created+470
...@@ -0,0 +1,470 @@
1// x86-64-specific declarations that are intended to be imported into the POSIX namespace.
2const std = @import("../../../std.zig");
3
4const linux = std.os.linux;
5const sockaddr = linux.sockaddr;
6const socklen_t = linux.socklen_t;
7const iovec = linux.iovec;
8const iovec_const = linux.iovec_const;
9
10pub const SYS_read = 0;
11pub const SYS_write = 1;
12pub const SYS_open = 2;
13pub const SYS_close = 3;
14pub const SYS_stat = 4;
15pub const SYS_fstat = 5;
16pub const SYS_lstat = 6;
17pub const SYS_poll = 7;
18pub const SYS_lseek = 8;
19pub const SYS_mmap = 9;
20pub const SYS_mprotect = 10;
21pub const SYS_munmap = 11;
22pub const SYS_brk = 12;
23pub const SYS_rt_sigaction = 13;
24pub const SYS_rt_sigprocmask = 14;
25pub const SYS_rt_sigreturn = 15;
26pub const SYS_ioctl = 16;
27pub const SYS_pread = 17;
28pub const SYS_pwrite = 18;
29pub const SYS_readv = 19;
30pub const SYS_writev = 20;
31pub const SYS_access = 21;
32pub const SYS_pipe = 22;
33pub const SYS_select = 23;
34pub const SYS_sched_yield = 24;
35pub const SYS_mremap = 25;
36pub const SYS_msync = 26;
37pub const SYS_mincore = 27;
38pub const SYS_madvise = 28;
39pub const SYS_shmget = 29;
40pub const SYS_shmat = 30;
41pub const SYS_shmctl = 31;
42pub const SYS_dup = 32;
43pub const SYS_dup2 = 33;
44pub const SYS_pause = 34;
45pub const SYS_nanosleep = 35;
46pub const SYS_getitimer = 36;
47pub const SYS_alarm = 37;
48pub const SYS_setitimer = 38;
49pub const SYS_getpid = 39;
50pub const SYS_sendfile = 40;
51pub const SYS_socket = 41;
52pub const SYS_connect = 42;
53pub const SYS_accept = 43;
54pub const SYS_sendto = 44;
55pub const SYS_recvfrom = 45;
56pub const SYS_sendmsg = 46;
57pub const SYS_recvmsg = 47;
58pub const SYS_shutdown = 48;
59pub const SYS_bind = 49;
60pub const SYS_listen = 50;
61pub const SYS_getsockname = 51;
62pub const SYS_getpeername = 52;
63pub const SYS_socketpair = 53;
64pub const SYS_setsockopt = 54;
65pub const SYS_getsockopt = 55;
66pub const SYS_clone = 56;
67pub const SYS_fork = 57;
68pub const SYS_vfork = 58;
69pub const SYS_execve = 59;
70pub const SYS_exit = 60;
71pub const SYS_wait4 = 61;
72pub const SYS_kill = 62;
73pub const SYS_uname = 63;
74pub const SYS_semget = 64;
75pub const SYS_semop = 65;
76pub const SYS_semctl = 66;
77pub const SYS_shmdt = 67;
78pub const SYS_msgget = 68;
79pub const SYS_msgsnd = 69;
80pub const SYS_msgrcv = 70;
81pub const SYS_msgctl = 71;
82pub const SYS_fcntl = 72;
83pub const SYS_flock = 73;
84pub const SYS_fsync = 74;
85pub const SYS_fdatasync = 75;
86pub const SYS_truncate = 76;
87pub const SYS_ftruncate = 77;
88pub const SYS_getdents = 78;
89pub const SYS_getcwd = 79;
90pub const SYS_chdir = 80;
91pub const SYS_fchdir = 81;
92pub const SYS_rename = 82;
93pub const SYS_mkdir = 83;
94pub const SYS_rmdir = 84;
95pub const SYS_creat = 85;
96pub const SYS_link = 86;
97pub const SYS_unlink = 87;
98pub const SYS_symlink = 88;
99pub const SYS_readlink = 89;
100pub const SYS_chmod = 90;
101pub const SYS_fchmod = 91;
102pub const SYS_chown = 92;
103pub const SYS_fchown = 93;
104pub const SYS_lchown = 94;
105pub const SYS_umask = 95;
106pub const SYS_gettimeofday = 96;
107pub const SYS_getrlimit = 97;
108pub const SYS_getrusage = 98;
109pub const SYS_sysinfo = 99;
110pub const SYS_times = 100;
111pub const SYS_ptrace = 101;
112pub const SYS_getuid = 102;
113pub const SYS_syslog = 103;
114pub const SYS_getgid = 104;
115pub const SYS_setuid = 105;
116pub const SYS_setgid = 106;
117pub const SYS_geteuid = 107;
118pub const SYS_getegid = 108;
119pub const SYS_setpgid = 109;
120pub const SYS_getppid = 110;
121pub const SYS_getpgrp = 111;
122pub const SYS_setsid = 112;
123pub const SYS_setreuid = 113;
124pub const SYS_setregid = 114;
125pub const SYS_getgroups = 115;
126pub const SYS_setgroups = 116;
127pub const SYS_setresuid = 117;
128pub const SYS_getresuid = 118;
129pub const SYS_setresgid = 119;
130pub const SYS_getresgid = 120;
131pub const SYS_getpgid = 121;
132pub const SYS_setfsuid = 122;
133pub const SYS_setfsgid = 123;
134pub const SYS_getsid = 124;
135pub const SYS_capget = 125;
136pub const SYS_capset = 126;
137pub const SYS_rt_sigpending = 127;
138pub const SYS_rt_sigtimedwait = 128;
139pub const SYS_rt_sigqueueinfo = 129;
140pub const SYS_rt_sigsuspend = 130;
141pub const SYS_sigaltstack = 131;
142pub const SYS_utime = 132;
143pub const SYS_mknod = 133;
144pub const SYS_uselib = 134;
145pub const SYS_personality = 135;
146pub const SYS_ustat = 136;
147pub const SYS_statfs = 137;
148pub const SYS_fstatfs = 138;
149pub const SYS_sysfs = 139;
150pub const SYS_getpriority = 140;
151pub const SYS_setpriority = 141;
152pub const SYS_sched_setparam = 142;
153pub const SYS_sched_getparam = 143;
154pub const SYS_sched_setscheduler = 144;
155pub const SYS_sched_getscheduler = 145;
156pub const SYS_sched_get_priority_max = 146;
157pub const SYS_sched_get_priority_min = 147;
158pub const SYS_sched_rr_get_interval = 148;
159pub const SYS_mlock = 149;
160pub const SYS_munlock = 150;
161pub const SYS_mlockall = 151;
162pub const SYS_munlockall = 152;
163pub const SYS_vhangup = 153;
164pub const SYS_modify_ldt = 154;
165pub const SYS_pivot_root = 155;
166pub const SYS__sysctl = 156;
167pub const SYS_prctl = 157;
168pub const SYS_arch_prctl = 158;
169pub const SYS_adjtimex = 159;
170pub const SYS_setrlimit = 160;
171pub const SYS_chroot = 161;
172pub const SYS_sync = 162;
173pub const SYS_acct = 163;
174pub const SYS_settimeofday = 164;
175pub const SYS_mount = 165;
176pub const SYS_umount2 = 166;
177pub const SYS_swapon = 167;
178pub const SYS_swapoff = 168;
179pub const SYS_reboot = 169;
180pub const SYS_sethostname = 170;
181pub const SYS_setdomainname = 171;
182pub const SYS_iopl = 172;
183pub const SYS_ioperm = 173;
184pub const SYS_create_module = 174;
185pub const SYS_init_module = 175;
186pub const SYS_delete_module = 176;
187pub const SYS_get_kernel_syms = 177;
188pub const SYS_query_module = 178;
189pub const SYS_quotactl = 179;
190pub const SYS_nfsservctl = 180;
191pub const SYS_getpmsg = 181;
192pub const SYS_putpmsg = 182;
193pub const SYS_afs_syscall = 183;
194pub const SYS_tuxcall = 184;
195pub const SYS_security = 185;
196pub const SYS_gettid = 186;
197pub const SYS_readahead = 187;
198pub const SYS_setxattr = 188;
199pub const SYS_lsetxattr = 189;
200pub const SYS_fsetxattr = 190;
201pub const SYS_getxattr = 191;
202pub const SYS_lgetxattr = 192;
203pub const SYS_fgetxattr = 193;
204pub const SYS_listxattr = 194;
205pub const SYS_llistxattr = 195;
206pub const SYS_flistxattr = 196;
207pub const SYS_removexattr = 197;
208pub const SYS_lremovexattr = 198;
209pub const SYS_fremovexattr = 199;
210pub const SYS_tkill = 200;
211pub const SYS_time = 201;
212pub const SYS_futex = 202;
213pub const SYS_sched_setaffinity = 203;
214pub const SYS_sched_getaffinity = 204;
215pub const SYS_set_thread_area = 205;
216pub const SYS_io_setup = 206;
217pub const SYS_io_destroy = 207;
218pub const SYS_io_getevents = 208;
219pub const SYS_io_submit = 209;
220pub const SYS_io_cancel = 210;
221pub const SYS_get_thread_area = 211;
222pub const SYS_lookup_dcookie = 212;
223pub const SYS_epoll_create = 213;
224pub const SYS_epoll_ctl_old = 214;
225pub const SYS_epoll_wait_old = 215;
226pub const SYS_remap_file_pages = 216;
227pub const SYS_getdents64 = 217;
228pub const SYS_set_tid_address = 218;
229pub const SYS_restart_syscall = 219;
230pub const SYS_semtimedop = 220;
231pub const SYS_fadvise64 = 221;
232pub const SYS_timer_create = 222;
233pub const SYS_timer_settime = 223;
234pub const SYS_timer_gettime = 224;
235pub const SYS_timer_getoverrun = 225;
236pub const SYS_timer_delete = 226;
237pub const SYS_clock_settime = 227;
238pub const SYS_clock_gettime = 228;
239pub const SYS_clock_getres = 229;
240pub const SYS_clock_nanosleep = 230;
241pub const SYS_exit_group = 231;
242pub const SYS_epoll_wait = 232;
243pub const SYS_epoll_ctl = 233;
244pub const SYS_tgkill = 234;
245pub const SYS_utimes = 235;
246pub const SYS_vserver = 236;
247pub const SYS_mbind = 237;
248pub const SYS_set_mempolicy = 238;
249pub const SYS_get_mempolicy = 239;
250pub const SYS_mq_open = 240;
251pub const SYS_mq_unlink = 241;
252pub const SYS_mq_timedsend = 242;
253pub const SYS_mq_timedreceive = 243;
254pub const SYS_mq_notify = 244;
255pub const SYS_mq_getsetattr = 245;
256pub const SYS_kexec_load = 246;
257pub const SYS_waitid = 247;
258pub const SYS_add_key = 248;
259pub const SYS_request_key = 249;
260pub const SYS_keyctl = 250;
261pub const SYS_ioprio_set = 251;
262pub const SYS_ioprio_get = 252;
263pub const SYS_inotify_init = 253;
264pub const SYS_inotify_add_watch = 254;
265pub const SYS_inotify_rm_watch = 255;
266pub const SYS_migrate_pages = 256;
267pub const SYS_openat = 257;
268pub const SYS_mkdirat = 258;
269pub const SYS_mknodat = 259;
270pub const SYS_fchownat = 260;
271pub const SYS_futimesat = 261;
272pub const SYS_newfstatat = 262;
273pub const SYS_fstatat = 262;
274pub const SYS_unlinkat = 263;
275pub const SYS_renameat = 264;
276pub const SYS_linkat = 265;
277pub const SYS_symlinkat = 266;
278pub const SYS_readlinkat = 267;
279pub const SYS_fchmodat = 268;
280pub const SYS_faccessat = 269;
281pub const SYS_pselect6 = 270;
282pub const SYS_ppoll = 271;
283pub const SYS_unshare = 272;
284pub const SYS_set_robust_list = 273;
285pub const SYS_get_robust_list = 274;
286pub const SYS_splice = 275;
287pub const SYS_tee = 276;
288pub const SYS_sync_file_range = 277;
289pub const SYS_vmsplice = 278;
290pub const SYS_move_pages = 279;
291pub const SYS_utimensat = 280;
292pub const SYS_epoll_pwait = 281;
293pub const SYS_signalfd = 282;
294pub const SYS_timerfd_create = 283;
295pub const SYS_eventfd = 284;
296pub const SYS_fallocate = 285;
297pub const SYS_timerfd_settime = 286;
298pub const SYS_timerfd_gettime = 287;
299pub const SYS_accept4 = 288;
300pub const SYS_signalfd4 = 289;
301pub const SYS_eventfd2 = 290;
302pub const SYS_epoll_create1 = 291;
303pub const SYS_dup3 = 292;
304pub const SYS_pipe2 = 293;
305pub const SYS_inotify_init1 = 294;
306pub const SYS_preadv = 295;
307pub const SYS_pwritev = 296;
308pub const SYS_rt_tgsigqueueinfo = 297;
309pub const SYS_perf_event_open = 298;
310pub const SYS_recvmmsg = 299;
311pub const SYS_fanotify_init = 300;
312pub const SYS_fanotify_mark = 301;
313pub const SYS_prlimit64 = 302;
314pub const SYS_name_to_handle_at = 303;
315pub const SYS_open_by_handle_at = 304;
316pub const SYS_clock_adjtime = 305;
317pub const SYS_syncfs = 306;
318pub const SYS_sendmmsg = 307;
319pub const SYS_setns = 308;
320pub const SYS_getcpu = 309;
321pub const SYS_process_vm_readv = 310;
322pub const SYS_process_vm_writev = 311;
323pub const SYS_kcmp = 312;
324pub const SYS_finit_module = 313;
325pub const SYS_sched_setattr = 314;
326pub const SYS_sched_getattr = 315;
327pub const SYS_renameat2 = 316;
328pub const SYS_seccomp = 317;
329pub const SYS_getrandom = 318;
330pub const SYS_memfd_create = 319;
331pub const SYS_kexec_file_load = 320;
332pub const SYS_bpf = 321;
333pub const SYS_execveat = 322;
334pub const SYS_userfaultfd = 323;
335pub const SYS_membarrier = 324;
336pub const SYS_mlock2 = 325;
337pub const SYS_copy_file_range = 326;
338pub const SYS_preadv2 = 327;
339pub const SYS_pwritev2 = 328;
340pub const SYS_pkey_mprotect = 329;
341pub const SYS_pkey_alloc = 330;
342pub const SYS_pkey_free = 331;
343pub const SYS_statx = 332;
344pub const SYS_io_pgetevents = 333;
345pub const SYS_rseq = 334;
346pub const SYS_pidfd_send_signal = 424;
347pub const SYS_io_uring_setup = 425;
348pub const SYS_io_uring_enter = 426;
349pub const SYS_io_uring_register = 427;
350
351pub const O_CREAT = 0o100;
352pub const O_EXCL = 0o200;
353pub const O_NOCTTY = 0o400;
354pub const O_TRUNC = 0o1000;
355pub const O_APPEND = 0o2000;
356pub const O_NONBLOCK = 0o4000;
357pub const O_DSYNC = 0o10000;
358pub const O_SYNC = 0o4010000;
359pub const O_RSYNC = 0o4010000;
360pub const O_DIRECTORY = 0o200000;
361pub const O_NOFOLLOW = 0o400000;
362pub const O_CLOEXEC = 0o2000000;
363
364pub const O_ASYNC = 0o20000;
365pub const O_DIRECT = 0o40000;
366pub const O_LARGEFILE = 0;
367pub const O_NOATIME = 0o1000000;
368pub const O_PATH = 0o10000000;
369pub const O_TMPFILE = 0o20200000;
370pub const O_NDELAY = O_NONBLOCK;
371
372pub const F_DUPFD = 0;
373pub const F_GETFD = 1;
374pub const F_SETFD = 2;
375pub const F_GETFL = 3;
376pub const F_SETFL = 4;
377
378pub const F_SETOWN = 8;
379pub const F_GETOWN = 9;
380pub const F_SETSIG = 10;
381pub const F_GETSIG = 11;
382
383pub const F_GETLK = 5;
384pub const F_SETLK = 6;
385pub const F_SETLKW = 7;
386
387pub const F_SETOWN_EX = 15;
388pub const F_GETOWN_EX = 16;
389
390pub const F_GETOWNER_UIDS = 17;
391
392pub const AT_FDCWD = -100;
393pub const AT_SYMLINK_NOFOLLOW = 0x100;
394pub const AT_REMOVEDIR = 0x200;
395pub const AT_SYMLINK_FOLLOW = 0x400;
396pub const AT_NO_AUTOMOUNT = 0x800;
397pub const AT_EMPTY_PATH = 0x1000;
398
399pub const VDSO_USEFUL = true;
400pub const VDSO_CGT_SYM = "__vdso_clock_gettime";
401pub const VDSO_CGT_VER = "LINUX_2.6";
402pub const VDSO_GETCPU_SYM = "__vdso_getcpu";
403pub const VDSO_GETCPU_VER = "LINUX_2.6";
404
405pub const ARCH_SET_GS = 0x1001;
406pub const ARCH_SET_FS = 0x1002;
407pub const ARCH_GET_FS = 0x1003;
408pub const ARCH_GET_GS = 0x1004;
409
410pub const msghdr = extern struct {
411 msg_name: ?*sockaddr,
412 msg_namelen: socklen_t,
413 msg_iov: [*]iovec,
414 msg_iovlen: i32,
415 __pad1: i32,
416 msg_control: ?*c_void,
417 msg_controllen: socklen_t,
418 __pad2: socklen_t,
419 msg_flags: i32,
420};
421
422pub const msghdr_const = extern struct {
423 msg_name: ?*const sockaddr,
424 msg_namelen: socklen_t,
425 msg_iov: [*]iovec_const,
426 msg_iovlen: i32,
427 __pad1: i32,
428 msg_control: ?*c_void,
429 msg_controllen: socklen_t,
430 __pad2: socklen_t,
431 msg_flags: i32,
432};
433
434/// Renamed to Stat to not conflict with the stat function.
435pub const Stat = extern struct {
436 dev: u64,
437 ino: u64,
438 nlink: usize,
439
440 mode: u32,
441 uid: u32,
442 gid: u32,
443 __pad0: u32,
444 rdev: u64,
445 size: i64,
446 blksize: isize,
447 blocks: i64,
448
449 atim: timespec,
450 mtim: timespec,
451 ctim: timespec,
452 __unused: [3]isize,
453};
454
455pub const timespec = extern struct {
456 tv_sec: isize,
457 tv_nsec: isize,
458};
459
460pub const timeval = extern struct {
461 tv_sec: isize,
462 tv_usec: isize,
463};
464
465pub const timezone = extern struct {
466 tz_minuteswest: i32,
467 tz_dsttime: i32,
468};
469
470pub const Elf_Symndx = u32;
std/os/bits/netbsd.zig created+725
...@@ -0,0 +1,725 @@
1const std = @import("../../std.zig");
2const maxInt = std.math.maxInt;
3
4pub const fd_t = c_int;
5pub const pid_t = c_int;
6
7/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
8pub const Kevent = extern struct {
9 ident: usize,
10 filter: i32,
11 flags: u32,
12 fflags: u32,
13 data: i64,
14 udata: usize,
15};
16
17pub const pthread_attr_t = extern struct {
18 pta_magic: u32,
19 pta_flags: c_int,
20 pta_private: *c_void,
21};
22
23pub const msghdr = extern struct {
24 /// optional address
25 msg_name: ?*sockaddr,
26
27 /// size of address
28 msg_namelen: socklen_t,
29
30 /// scatter/gather array
31 msg_iov: [*]iovec,
32
33 /// # elements in msg_iov
34 msg_iovlen: i32,
35
36 /// ancillary data
37 msg_control: ?*c_void,
38
39 /// ancillary data buffer len
40 msg_controllen: socklen_t,
41
42 /// flags on received message
43 msg_flags: i32,
44};
45
46pub const msghdr_const = extern struct {
47 /// optional address
48 msg_name: ?*const sockaddr,
49
50 /// size of address
51 msg_namelen: socklen_t,
52
53 /// scatter/gather array
54 msg_iov: [*]iovec_const,
55
56 /// # elements in msg_iov
57 msg_iovlen: i32,
58
59 /// ancillary data
60 msg_control: ?*c_void,
61
62 /// ancillary data buffer len
63 msg_controllen: socklen_t,
64
65 /// flags on received message
66 msg_flags: i32,
67};
68
69pub const Stat = extern struct {
70 dev: u64,
71 mode: u32,
72 ino: u64,
73 nlink: usize,
74
75 uid: u32,
76 gid: u32,
77 rdev: u64,
78
79 atim: timespec,
80 mtim: timespec,
81 ctim: timespec,
82 birthtim: timespec,
83
84 size: i64,
85 blocks: i64,
86 blksize: isize,
87 flags: u32,
88 gen: u32,
89 __spare: [2]u32,
90};
91
92pub const timespec = extern struct {
93 tv_sec: i64,
94 tv_nsec: isize,
95};
96
97pub const dirent = extern struct {
98 d_fileno: u64,
99 d_reclen: u16,
100 d_namlen: u16,
101 d_type: u8,
102 d_off: i64,
103 d_name: [512]u8,
104};
105
106pub const in_port_t = u16;
107pub const sa_family_t = u8;
108
109pub const sockaddr = extern union {
110 in: sockaddr_in,
111 in6: sockaddr_in6,
112};
113
114pub const sockaddr_in = extern struct {
115 len: u8,
116 family: sa_family_t,
117 port: in_port_t,
118 addr: u32,
119 zero: [8]u8,
120};
121
122pub const sockaddr_in6 = extern struct {
123 len: u8,
124 family: sa_family_t,
125 port: in_port_t,
126 flowinfo: u32,
127 addr: [16]u8,
128 scope_id: u32,
129};
130
131pub const CTL_KERN = 1;
132pub const CTL_DEBUG = 5;
133
134pub const KERN_PROC_ARGS = 48; // struct: process argv/env
135pub const KERN_PROC_PATHNAME = 5; // path to executable
136
137pub const PATH_MAX = 1024;
138
139pub const STDIN_FILENO = 0;
140pub const STDOUT_FILENO = 1;
141pub const STDERR_FILENO = 2;
142
143pub const PROT_NONE = 0;
144pub const PROT_READ = 1;
145pub const PROT_WRITE = 2;
146pub const PROT_EXEC = 4;
147
148pub const CLOCK_REALTIME = 0;
149pub const CLOCK_VIRTUAL = 1;
150pub const CLOCK_PROF = 2;
151pub const CLOCK_MONOTONIC = 3;
152pub const CLOCK_THREAD_CPUTIME_ID = 0x20000000;
153pub const CLOCK_PROCESS_CPUTIME_ID = 0x40000000;
154
155pub const MAP_FAILED = @intToPtr(*c_void, maxInt(usize));
156pub const MAP_SHARED = 0x0001;
157pub const MAP_PRIVATE = 0x0002;
158pub const MAP_REMAPDUP = 0x0004;
159pub const MAP_FIXED = 0x0010;
160pub const MAP_RENAME = 0x0020;
161pub const MAP_NORESERVE = 0x0040;
162pub const MAP_INHERIT = 0x0080;
163pub const MAP_HASSEMAPHORE = 0x0200;
164pub const MAP_TRYFIXED = 0x0400;
165pub const MAP_WIRED = 0x0800;
166
167pub const MAP_FILE = 0x0000;
168pub const MAP_NOSYNC = 0x0800;
169pub const MAP_ANON = 0x1000;
170pub const MAP_ANONYMOUS = MAP_ANON;
171pub const MAP_STACK = 0x2000;
172
173pub const WNOHANG = 0x00000001;
174pub const WUNTRACED = 0x00000002;
175pub const WSTOPPED = WUNTRACED;
176pub const WCONTINUED = 0x00000010;
177pub const WNOWAIT = 0x00010000;
178pub const WEXITED = 0x00000020;
179pub const WTRAPPED = 0x00000040;
180
181pub const SA_ONSTACK = 0x0001;
182pub const SA_RESTART = 0x0002;
183pub const SA_RESETHAND = 0x0004;
184pub const SA_NOCLDSTOP = 0x0008;
185pub const SA_NODEFER = 0x0010;
186pub const SA_NOCLDWAIT = 0x0020;
187pub const SA_SIGINFO = 0x0040;
188
189pub const SIGHUP = 1;
190pub const SIGINT = 2;
191pub const SIGQUIT = 3;
192pub const SIGILL = 4;
193pub const SIGTRAP = 5;
194pub const SIGABRT = 6;
195pub const SIGIOT = SIGABRT;
196pub const SIGEMT = 7;
197pub const SIGFPE = 8;
198pub const SIGKILL = 9;
199pub const SIGBUS = 10;
200pub const SIGSEGV = 11;
201pub const SIGSYS = 12;
202pub const SIGPIPE = 13;
203pub const SIGALRM = 14;
204pub const SIGTERM = 15;
205pub const SIGURG = 16;
206pub const SIGSTOP = 17;
207pub const SIGTSTP = 18;
208pub const SIGCONT = 19;
209pub const SIGCHLD = 20;
210pub const SIGTTIN = 21;
211pub const SIGTTOU = 22;
212pub const SIGIO = 23;
213pub const SIGXCPU = 24;
214pub const SIGXFSZ = 25;
215pub const SIGVTALRM = 26;
216pub const SIGPROF = 27;
217pub const SIGWINCH = 28;
218pub const SIGINFO = 29;
219pub const SIGUSR1 = 30;
220pub const SIGUSR2 = 31;
221pub const SIGPWR = 32;
222
223pub const SIGRTMIN = 33;
224pub const SIGRTMAX = 63;
225
226// access function
227pub const F_OK = 0; // test for existence of file
228pub const X_OK = 1; // test for execute or search permission
229pub const W_OK = 2; // test for write permission
230pub const R_OK = 4; // test for read permission
231
232pub const O_RDONLY = 0x0000;
233pub const O_WRONLY = 0x0001;
234pub const O_RDWR = 0x0002;
235pub const O_ACCMODE = 0x0003;
236
237pub const O_CREAT = 0x0200;
238pub const O_EXCL = 0x0800;
239pub const O_NOCTTY = 0x8000;
240pub const O_TRUNC = 0x0400;
241pub const O_APPEND = 0x0008;
242pub const O_NONBLOCK = 0x0004;
243pub const O_DSYNC = 0x00010000;
244pub const O_SYNC = 0x0080;
245pub const O_RSYNC = 0x00020000;
246pub const O_DIRECTORY = 0x00080000;
247pub const O_NOFOLLOW = 0x00000100;
248pub const O_CLOEXEC = 0x00400000;
249
250pub const O_ASYNC = 0x0040;
251pub const O_DIRECT = 0x00080000;
252pub const O_LARGEFILE = 0;
253pub const O_NOATIME = 0;
254pub const O_PATH = 0;
255pub const O_TMPFILE = 0;
256pub const O_NDELAY = O_NONBLOCK;
257
258pub const F_DUPFD = 0;
259pub const F_GETFD = 1;
260pub const F_SETFD = 2;
261pub const F_GETFL = 3;
262pub const F_SETFL = 4;
263
264pub const F_GETOWN = 5;
265pub const F_SETOWN = 6;
266
267pub const F_GETLK = 7;
268pub const F_SETLK = 8;
269pub const F_SETLKW = 9;
270
271pub const SEEK_SET = 0;
272pub const SEEK_CUR = 1;
273pub const SEEK_END = 2;
274
275pub const SIG_BLOCK = 1;
276pub const SIG_UNBLOCK = 2;
277pub const SIG_SETMASK = 3;
278
279pub const SOCK_STREAM = 1;
280pub const SOCK_DGRAM = 2;
281pub const SOCK_RAW = 3;
282pub const SOCK_RDM = 4;
283pub const SOCK_SEQPACKET = 5;
284
285pub const SOCK_CLOEXEC = 0x10000000;
286pub const SOCK_NONBLOCK = 0x20000000;
287
288pub const PROTO_ip = 0;
289pub const PROTO_icmp = 1;
290pub const PROTO_igmp = 2;
291pub const PROTO_ggp = 3;
292pub const PROTO_ipencap = 4;
293pub const PROTO_tcp = 6;
294pub const PROTO_egp = 8;
295pub const PROTO_pup = 12;
296pub const PROTO_udp = 17;
297pub const PROTO_xns_idp = 22;
298pub const PROTO_iso_tp4 = 29;
299pub const PROTO_ipv6 = 41;
300pub const PROTO_ipv6_route = 43;
301pub const PROTO_ipv6_frag = 44;
302pub const PROTO_rsvp = 46;
303pub const PROTO_gre = 47;
304pub const PROTO_esp = 50;
305pub const PROTO_ah = 51;
306pub const PROTO_ipv6_icmp = 58;
307pub const PROTO_ipv6_nonxt = 59;
308pub const PROTO_ipv6_opts = 60;
309pub const PROTO_encap = 98;
310pub const PROTO_pim = 103;
311pub const PROTO_raw = 255;
312
313pub const PF_UNSPEC = 0;
314pub const PF_LOCAL = 1;
315pub const PF_UNIX = PF_LOCAL;
316pub const PF_FILE = PF_LOCAL;
317pub const PF_INET = 2;
318pub const PF_APPLETALK = 16;
319pub const PF_INET6 = 24;
320pub const PF_DECnet = 12;
321pub const PF_KEY = 29;
322pub const PF_ROUTE = 34;
323pub const PF_SNA = 11;
324pub const PF_MPLS = 33;
325pub const PF_CAN = 35;
326pub const PF_BLUETOOTH = 31;
327pub const PF_ISDN = 26;
328pub const PF_MAX = 37;
329
330pub const AF_UNSPEC = PF_UNSPEC;
331pub const AF_LOCAL = PF_LOCAL;
332pub const AF_UNIX = AF_LOCAL;
333pub const AF_FILE = AF_LOCAL;
334pub const AF_INET = PF_INET;
335pub const AF_APPLETALK = PF_APPLETALK;
336pub const AF_INET6 = PF_INET6;
337pub const AF_KEY = PF_KEY;
338pub const AF_ROUTE = PF_ROUTE;
339pub const AF_SNA = PF_SNA;
340pub const AF_MPLS = PF_MPLS;
341pub const AF_CAN = PF_CAN;
342pub const AF_BLUETOOTH = PF_BLUETOOTH;
343pub const AF_ISDN = PF_ISDN;
344pub const AF_MAX = PF_MAX;
345
346pub const DT_UNKNOWN = 0;
347pub const DT_FIFO = 1;
348pub const DT_CHR = 2;
349pub const DT_DIR = 4;
350pub const DT_BLK = 6;
351pub const DT_REG = 8;
352pub const DT_LNK = 10;
353pub const DT_SOCK = 12;
354pub const DT_WHT = 14;
355
356/// add event to kq (implies enable)
357pub const EV_ADD = 0x0001;
358
359/// delete event from kq
360pub const EV_DELETE = 0x0002;
361
362/// enable event
363pub const EV_ENABLE = 0x0004;
364
365/// disable event (not reported)
366pub const EV_DISABLE = 0x0008;
367
368/// only report one occurrence
369pub const EV_ONESHOT = 0x0010;
370
371/// clear event state after reporting
372pub const EV_CLEAR = 0x0020;
373
374/// force immediate event output
375/// ... with or without EV_ERROR
376/// ... use KEVENT_FLAG_ERROR_EVENTS
377/// on syscalls supporting flags
378pub const EV_RECEIPT = 0x0040;
379
380/// disable event after reporting
381pub const EV_DISPATCH = 0x0080;
382
383pub const EVFILT_READ = 0;
384pub const EVFILT_WRITE = 1;
385
386/// attached to aio requests
387pub const EVFILT_AIO = 2;
388
389/// attached to vnodes
390pub const EVFILT_VNODE = 3;
391
392/// attached to struct proc
393pub const EVFILT_PROC = 4;
394
395/// attached to struct proc
396pub const EVFILT_SIGNAL = 5;
397
398/// timers
399pub const EVFILT_TIMER = 6;
400
401/// Filesystem events
402pub const EVFILT_FS = 7;
403
404/// On input, NOTE_TRIGGER causes the event to be triggered for output.
405pub const NOTE_TRIGGER = 0x08000000;
406
407/// low water mark
408pub const NOTE_LOWAT = 0x00000001;
409
410/// vnode was removed
411pub const NOTE_DELETE = 0x00000001;
412
413/// data contents changed
414pub const NOTE_WRITE = 0x00000002;
415
416/// size increased
417pub const NOTE_EXTEND = 0x00000004;
418
419/// attributes changed
420pub const NOTE_ATTRIB = 0x00000008;
421
422/// link count changed
423pub const NOTE_LINK = 0x00000010;
424
425/// vnode was renamed
426pub const NOTE_RENAME = 0x00000020;
427
428/// vnode access was revoked
429pub const NOTE_REVOKE = 0x00000040;
430
431/// process exited
432pub const NOTE_EXIT = 0x80000000;
433
434/// process forked
435pub const NOTE_FORK = 0x40000000;
436
437/// process exec'd
438pub const NOTE_EXEC = 0x20000000;
439
440/// mask for signal & exit status
441pub const NOTE_PDATAMASK = 0x000fffff;
442pub const NOTE_PCTRLMASK = 0xf0000000;
443
444pub const TIOCCBRK = 0x2000747a;
445pub const TIOCCDTR = 0x20007478;
446pub const TIOCCONS = 0x80047462;
447pub const TIOCDCDTIMESTAMP = 0x40107458;
448pub const TIOCDRAIN = 0x2000745e;
449pub const TIOCEXCL = 0x2000740d;
450pub const TIOCEXT = 0x80047460;
451pub const TIOCFLAG_CDTRCTS = 0x10;
452pub const TIOCFLAG_CLOCAL = 0x2;
453pub const TIOCFLAG_CRTSCTS = 0x4;
454pub const TIOCFLAG_MDMBUF = 0x8;
455pub const TIOCFLAG_SOFTCAR = 0x1;
456pub const TIOCFLUSH = 0x80047410;
457pub const TIOCGETA = 0x402c7413;
458pub const TIOCGETD = 0x4004741a;
459pub const TIOCGFLAGS = 0x4004745d;
460pub const TIOCGLINED = 0x40207442;
461pub const TIOCGPGRP = 0x40047477;
462pub const TIOCGQSIZE = 0x40047481;
463pub const TIOCGRANTPT = 0x20007447;
464pub const TIOCGSID = 0x40047463;
465pub const TIOCGSIZE = 0x40087468;
466pub const TIOCGWINSZ = 0x40087468;
467pub const TIOCMBIC = 0x8004746b;
468pub const TIOCMBIS = 0x8004746c;
469pub const TIOCMGET = 0x4004746a;
470pub const TIOCMSET = 0x8004746d;
471pub const TIOCM_CAR = 0x40;
472pub const TIOCM_CD = 0x40;
473pub const TIOCM_CTS = 0x20;
474pub const TIOCM_DSR = 0x100;
475pub const TIOCM_DTR = 0x2;
476pub const TIOCM_LE = 0x1;
477pub const TIOCM_RI = 0x80;
478pub const TIOCM_RNG = 0x80;
479pub const TIOCM_RTS = 0x4;
480pub const TIOCM_SR = 0x10;
481pub const TIOCM_ST = 0x8;
482pub const TIOCNOTTY = 0x20007471;
483pub const TIOCNXCL = 0x2000740e;
484pub const TIOCOUTQ = 0x40047473;
485pub const TIOCPKT = 0x80047470;
486pub const TIOCPKT_DATA = 0x0;
487pub const TIOCPKT_DOSTOP = 0x20;
488pub const TIOCPKT_FLUSHREAD = 0x1;
489pub const TIOCPKT_FLUSHWRITE = 0x2;
490pub const TIOCPKT_IOCTL = 0x40;
491pub const TIOCPKT_NOSTOP = 0x10;
492pub const TIOCPKT_START = 0x8;
493pub const TIOCPKT_STOP = 0x4;
494pub const TIOCPTMGET = 0x40287446;
495pub const TIOCPTSNAME = 0x40287448;
496pub const TIOCRCVFRAME = 0x80087445;
497pub const TIOCREMOTE = 0x80047469;
498pub const TIOCSBRK = 0x2000747b;
499pub const TIOCSCTTY = 0x20007461;
500pub const TIOCSDTR = 0x20007479;
501pub const TIOCSETA = 0x802c7414;
502pub const TIOCSETAF = 0x802c7416;
503pub const TIOCSETAW = 0x802c7415;
504pub const TIOCSETD = 0x8004741b;
505pub const TIOCSFLAGS = 0x8004745c;
506pub const TIOCSIG = 0x2000745f;
507pub const TIOCSLINED = 0x80207443;
508pub const TIOCSPGRP = 0x80047476;
509pub const TIOCSQSIZE = 0x80047480;
510pub const TIOCSSIZE = 0x80087467;
511pub const TIOCSTART = 0x2000746e;
512pub const TIOCSTAT = 0x80047465;
513pub const TIOCSTI = 0x80017472;
514pub const TIOCSTOP = 0x2000746f;
515pub const TIOCSWINSZ = 0x80087467;
516pub const TIOCUCNTL = 0x80047466;
517pub const TIOCXMTFRAME = 0x80087444;
518
519pub fn WEXITSTATUS(s: u32) u32 {
520 return (s >> 8) & 0xff;
521}
522pub fn WTERMSIG(s: u32) u32 {
523 return s & 0x7f;
524}
525pub fn WSTOPSIG(s: u32) u32 {
526 return WEXITSTATUS(s);
527}
528pub fn WIFEXITED(s: u32) bool {
529 return WTERMSIG(s) == 0;
530}
531
532pub fn WIFCONTINUED(s: u32) bool {
533 return ((s & 0x7f) == 0xffff);
534}
535
536pub fn WIFSTOPPED(s: u32) bool {
537 return ((s & 0x7f != 0x7f) and !WIFCONTINUED(s));
538}
539
540pub fn WIFSIGNALED(s: u32) bool {
541 return !WIFSTOPPED(s) and !WIFCONTINUED(s) and !WIFEXITED(s);
542}
543
544pub const winsize = extern struct {
545 ws_row: u16,
546 ws_col: u16,
547 ws_xpixel: u16,
548 ws_ypixel: u16,
549};
550
551const NSIG = 32;
552
553pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
554pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
555pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
556
557/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
558pub const Sigaction = extern struct {
559 /// signal handler
560 __sigaction_u: extern union {
561 __sa_handler: extern fn (i32) void,
562 __sa_sigaction: extern fn (i32, *__siginfo, usize) void,
563 },
564
565 /// see signal options
566 sa_flags: u32,
567
568 /// signal mask to apply
569 sa_mask: sigset_t,
570};
571
572pub const _SIG_WORDS = 4;
573pub const _SIG_MAXSIG = 128;
574
575pub inline fn _SIG_IDX(sig: usize) usize {
576 return sig - 1;
577}
578pub inline fn _SIG_WORD(sig: usize) usize {
579 return_SIG_IDX(sig) >> 5;
580}
581pub inline fn _SIG_BIT(sig: usize) usize {
582 return 1 << (_SIG_IDX(sig) & 31);
583}
584pub inline fn _SIG_VALID(sig: usize) usize {
585 return sig <= _SIG_MAXSIG and sig > 0;
586}
587
588pub const sigset_t = extern struct {
589 __bits: [_SIG_WORDS]u32,
590};
591
592pub const EPERM = 1; // Operation not permitted
593pub const ENOENT = 2; // No such file or directory
594pub const ESRCH = 3; // No such process
595pub const EINTR = 4; // Interrupted system call
596pub const EIO = 5; // Input/output error
597pub const ENXIO = 6; // Device not configured
598pub const E2BIG = 7; // Argument list too long
599pub const ENOEXEC = 8; // Exec format error
600pub const EBADF = 9; // Bad file descriptor
601pub const ECHILD = 10; // No child processes
602pub const EDEADLK = 11; // Resource deadlock avoided
603// 11 was EAGAIN
604pub const ENOMEM = 12; // Cannot allocate memory
605pub const EACCES = 13; // Permission denied
606pub const EFAULT = 14; // Bad address
607pub const ENOTBLK = 15; // Block device required
608pub const EBUSY = 16; // Device busy
609pub const EEXIST = 17; // File exists
610pub const EXDEV = 18; // Cross-device link
611pub const ENODEV = 19; // Operation not supported by device
612pub const ENOTDIR = 20; // Not a directory
613pub const EISDIR = 21; // Is a directory
614pub const EINVAL = 22; // Invalid argument
615pub const ENFILE = 23; // Too many open files in system
616pub const EMFILE = 24; // Too many open files
617pub const ENOTTY = 25; // Inappropriate ioctl for device
618pub const ETXTBSY = 26; // Text file busy
619pub const EFBIG = 27; // File too large
620pub const ENOSPC = 28; // No space left on device
621pub const ESPIPE = 29; // Illegal seek
622pub const EROFS = 30; // Read-only file system
623pub const EMLINK = 31; // Too many links
624pub const EPIPE = 32; // Broken pipe
625
626// math software
627pub const EDOM = 33; // Numerical argument out of domain
628pub const ERANGE = 34; // Result too large or too small
629
630// non-blocking and interrupt i/o
631pub const EAGAIN = 35; // Resource temporarily unavailable
632pub const EWOULDBLOCK = EAGAIN; // Operation would block
633pub const EINPROGRESS = 36; // Operation now in progress
634pub const EALREADY = 37; // Operation already in progress
635
636// ipc/network software -- argument errors
637pub const ENOTSOCK = 38; // Socket operation on non-socket
638pub const EDESTADDRREQ = 39; // Destination address required
639pub const EMSGSIZE = 40; // Message too long
640pub const EPROTOTYPE = 41; // Protocol wrong type for socket
641pub const ENOPROTOOPT = 42; // Protocol option not available
642pub const EPROTONOSUPPORT = 43; // Protocol not supported
643pub const ESOCKTNOSUPPORT = 44; // Socket type not supported
644pub const EOPNOTSUPP = 45; // Operation not supported
645pub const EPFNOSUPPORT = 46; // Protocol family not supported
646pub const EAFNOSUPPORT = 47; // Address family not supported by protocol family
647pub const EADDRINUSE = 48; // Address already in use
648pub const EADDRNOTAVAIL = 49; // Can't assign requested address
649
650// ipc/network software -- operational errors
651pub const ENETDOWN = 50; // Network is down
652pub const ENETUNREACH = 51; // Network is unreachable
653pub const ENETRESET = 52; // Network dropped connection on reset
654pub const ECONNABORTED = 53; // Software caused connection abort
655pub const ECONNRESET = 54; // Connection reset by peer
656pub const ENOBUFS = 55; // No buffer space available
657pub const EISCONN = 56; // Socket is already connected
658pub const ENOTCONN = 57; // Socket is not connected
659pub const ESHUTDOWN = 58; // Can't send after socket shutdown
660pub const ETOOMANYREFS = 59; // Too many references: can't splice
661pub const ETIMEDOUT = 60; // Operation timed out
662pub const ECONNREFUSED = 61; // Connection refused
663
664pub const ELOOP = 62; // Too many levels of symbolic links
665pub const ENAMETOOLONG = 63; // File name too long
666
667// should be rearranged
668pub const EHOSTDOWN = 64; // Host is down
669pub const EHOSTUNREACH = 65; // No route to host
670pub const ENOTEMPTY = 66; // Directory not empty
671
672// quotas & mush
673pub const EPROCLIM = 67; // Too many processes
674pub const EUSERS = 68; // Too many users
675pub const EDQUOT = 69; // Disc quota exceeded
676
677// Network File System
678pub const ESTALE = 70; // Stale NFS file handle
679pub const EREMOTE = 71; // Too many levels of remote in path
680pub const EBADRPC = 72; // RPC struct is bad
681pub const ERPCMISMATCH = 73; // RPC version wrong
682pub const EPROGUNAVAIL = 74; // RPC prog. not avail
683pub const EPROGMISMATCH = 75; // Program version wrong
684pub const EPROCUNAVAIL = 76; // Bad procedure for program
685
686pub const ENOLCK = 77; // No locks available
687pub const ENOSYS = 78; // Function not implemented
688
689pub const EFTYPE = 79; // Inappropriate file type or format
690pub const EAUTH = 80; // Authentication error
691pub const ENEEDAUTH = 81; // Need authenticator
692
693// SystemV IPC
694pub const EIDRM = 82; // Identifier removed
695pub const ENOMSG = 83; // No message of desired type
696pub const EOVERFLOW = 84; // Value too large to be stored in data type
697
698// Wide/multibyte-character handling, ISO/IEC 9899/AMD1:1995
699pub const EILSEQ = 85; // Illegal byte sequence
700
701// From IEEE Std 1003.1-2001
702// Base, Realtime, Threads or Thread Priority Scheduling option errors
703pub const ENOTSUP = 86; // Not supported
704
705// Realtime option errors
706pub const ECANCELED = 87; // Operation canceled
707
708// Realtime, XSI STREAMS option errors
709pub const EBADMSG = 88; // Bad or Corrupt message
710
711// XSI STREAMS option errors
712pub const ENODATA = 89; // No message available
713pub const ENOSR = 90; // No STREAM resources
714pub const ENOSTR = 91; // Not a STREAM
715pub const ETIME = 92; // STREAM ioctl timeout
716
717// File system extended attribute errors
718pub const ENOATTR = 93; // Attribute not found
719
720// Realtime, XSI STREAMS option errors
721pub const EMULTIHOP = 94; // Multihop attempted
722pub const ENOLINK = 95; // Link has been severed
723pub const EPROTO = 96; // Protocol error
724
725pub const ELAST = 96; // Must equal largest errno
std/os/bits/wasi.zig created+307
...@@ -0,0 +1,307 @@
1pub const STDIN_FILENO = 0;
2pub const STDOUT_FILENO = 1;
3pub const STDERR_FILENO = 2;
4
5pub const advice_t = u8;
6pub const ADVICE_NORMAL: advice_t = 0;
7pub const ADVICE_SEQUENTIAL: advice_t = 1;
8pub const ADVICE_RANDOM: advice_t = 2;
9pub const ADVICE_WILLNEED: advice_t = 3;
10pub const ADVICE_DONTNEED: advice_t = 4;
11pub const ADVICE_NOREUSE: advice_t = 5;
12
13pub const clockid_t = u32;
14pub const CLOCK_REALTIME: clockid_t = 0;
15pub const CLOCK_MONOTONIC: clockid_t = 1;
16pub const CLOCK_PROCESS_CPUTIME_ID: clockid_t = 2;
17pub const CLOCK_THREAD_CPUTIME_ID: clockid_t = 3;
18
19pub const device_t = u64;
20
21pub const dircookie_t = u64;
22pub const DIRCOOKIE_START: dircookie_t = 0;
23
24pub const dirent_t = extern struct {
25 d_next: dircookie_t,
26 d_ino: inode_t,
27 d_namlen: u32,
28 d_type: filetype_t,
29};
30
31pub const errno_t = u16;
32pub const ESUCCESS: errno_t = 0;
33pub const E2BIG: errno_t = 1;
34pub const EACCES: errno_t = 2;
35pub const EADDRINUSE: errno_t = 3;
36pub const EADDRNOTAVAIL: errno_t = 4;
37pub const EAFNOSUPPORT: errno_t = 5;
38pub const EAGAIN: errno_t = 6;
39pub const EALREADY: errno_t = 7;
40pub const EBADF: errno_t = 8;
41pub const EBADMSG: errno_t = 9;
42pub const EBUSY: errno_t = 10;
43pub const ECANCELED: errno_t = 11;
44pub const ECHILD: errno_t = 12;
45pub const ECONNABORTED: errno_t = 13;
46pub const ECONNREFUSED: errno_t = 14;
47pub const ECONNRESET: errno_t = 15;
48pub const EDEADLK: errno_t = 16;
49pub const EDESTADDRREQ: errno_t = 17;
50pub const EDOM: errno_t = 18;
51pub const EDQUOT: errno_t = 19;
52pub const EEXIST: errno_t = 20;
53pub const EFAULT: errno_t = 21;
54pub const EFBIG: errno_t = 22;
55pub const EHOSTUNREACH: errno_t = 23;
56pub const EIDRM: errno_t = 24;
57pub const EILSEQ: errno_t = 25;
58pub const EINPROGRESS: errno_t = 26;
59pub const EINTR: errno_t = 27;
60pub const EINVAL: errno_t = 28;
61pub const EIO: errno_t = 29;
62pub const EISCONN: errno_t = 30;
63pub const EISDIR: errno_t = 31;
64pub const ELOOP: errno_t = 32;
65pub const EMFILE: errno_t = 33;
66pub const EMLINK: errno_t = 34;
67pub const EMSGSIZE: errno_t = 35;
68pub const EMULTIHOP: errno_t = 36;
69pub const ENAMETOOLONG: errno_t = 37;
70pub const ENETDOWN: errno_t = 38;
71pub const ENETRESET: errno_t = 39;
72pub const ENETUNREACH: errno_t = 40;
73pub const ENFILE: errno_t = 41;
74pub const ENOBUFS: errno_t = 42;
75pub const ENODEV: errno_t = 43;
76pub const ENOENT: errno_t = 44;
77pub const ENOEXEC: errno_t = 45;
78pub const ENOLCK: errno_t = 46;
79pub const ENOLINK: errno_t = 47;
80pub const ENOMEM: errno_t = 48;
81pub const ENOMSG: errno_t = 49;
82pub const ENOPROTOOPT: errno_t = 50;
83pub const ENOSPC: errno_t = 51;
84pub const ENOSYS: errno_t = 52;
85pub const ENOTCONN: errno_t = 53;
86pub const ENOTDIR: errno_t = 54;
87pub const ENOTEMPTY: errno_t = 55;
88pub const ENOTRECOVERABLE: errno_t = 56;
89pub const ENOTSOCK: errno_t = 57;
90pub const ENOTSUP: errno_t = 58;
91pub const ENOTTY: errno_t = 59;
92pub const ENXIO: errno_t = 60;
93pub const EOVERFLOW: errno_t = 61;
94pub const EOWNERDEAD: errno_t = 62;
95pub const EPERM: errno_t = 63;
96pub const EPIPE: errno_t = 64;
97pub const EPROTO: errno_t = 65;
98pub const EPROTONOSUPPORT: errno_t = 66;
99pub const EPROTOTYPE: errno_t = 67;
100pub const ERANGE: errno_t = 68;
101pub const EROFS: errno_t = 69;
102pub const ESPIPE: errno_t = 70;
103pub const ESRCH: errno_t = 71;
104pub const ESTALE: errno_t = 72;
105pub const ETIMEDOUT: errno_t = 73;
106pub const ETXTBSY: errno_t = 74;
107pub const EXDEV: errno_t = 75;
108pub const ENOTCAPABLE: errno_t = 76;
109
110pub const event_t = extern struct {
111 userdata: userdata_t,
112 @"error": errno_t,
113 @"type": eventtype_t,
114 u: extern union {
115 fd_readwrite: extern struct {
116 nbytes: filesize_t,
117 flags: eventrwflags_t,
118 },
119 },
120};
121
122pub const eventrwflags_t = u16;
123pub const EVENT_FD_READWRITE_HANGUP: eventrwflags_t = 0x0001;
124
125pub const eventtype_t = u8;
126pub const EVENTTYPE_CLOCK: eventtype_t = 0;
127pub const EVENTTYPE_FD_READ: eventtype_t = 1;
128pub const EVENTTYPE_FD_WRITE: eventtype_t = 2;
129
130pub const exitcode_t = u32;
131
132pub const fd_t = u32;
133
134pub const fdflags_t = u16;
135pub const FDFLAG_APPEND: fdflags_t = 0x0001;
136pub const FDFLAG_DSYNC: fdflags_t = 0x0002;
137pub const FDFLAG_NONBLOCK: fdflags_t = 0x0004;
138pub const FDFLAG_RSYNC: fdflags_t = 0x0008;
139pub const FDFLAG_SYNC: fdflags_t = 0x0010;
140
141const fdstat_t = extern struct {
142 fs_filetype: filetype_t,
143 fs_flags: fdflags_t,
144 fs_rights_base: rights_t,
145 fs_rights_inheriting: rights_t,
146};
147
148pub const filedelta_t = i64;
149
150pub const filesize_t = u64;
151
152pub const filestat_t = extern struct {
153 st_dev: device_t,
154 st_ino: inode_t,
155 st_filetype: filetype_t,
156 st_nlink: linkcount_t,
157 st_size: filesize_t,
158 st_atim: timestamp_t,
159 st_mtim: timestamp_t,
160 st_ctim: timestamp_t,
161};
162
163pub const filetype_t = u8;
164pub const FILETYPE_UNKNOWN: filetype_t = 0;
165pub const FILETYPE_BLOCK_DEVICE: filetype_t = 1;
166pub const FILETYPE_CHARACTER_DEVICE: filetype_t = 2;
167pub const FILETYPE_DIRECTORY: filetype_t = 3;
168pub const FILETYPE_REGULAR_FILE: filetype_t = 4;
169pub const FILETYPE_SOCKET_DGRAM: filetype_t = 5;
170pub const FILETYPE_SOCKET_STREAM: filetype_t = 6;
171pub const FILETYPE_SYMBOLIC_LINK: filetype_t = 7;
172
173pub const fstflags_t = u16;
174pub const FILESTAT_SET_ATIM: fstflags_t = 0x0001;
175pub const FILESTAT_SET_ATIM_NOW: fstflags_t = 0x0002;
176pub const FILESTAT_SET_MTIM: fstflags_t = 0x0004;
177pub const FILESTAT_SET_MTIM_NOW: fstflags_t = 0x0008;
178
179pub const inode_t = u64;
180
181pub const linkcount_t = u32;
182
183pub const lookupflags_t = u32;
184pub const LOOKUP_SYMLINK_FOLLOW: lookupflags_t = 0x00000001;
185
186pub const oflags_t = u16;
187pub const O_CREAT: oflags_t = 0x0001;
188pub const O_DIRECTORY: oflags_t = 0x0002;
189pub const O_EXCL: oflags_t = 0x0004;
190pub const O_TRUNC: oflags_t = 0x0008;
191
192pub const preopentype_t = u8;
193pub const PREOPENTYPE_DIR: preopentype_t = 0;
194
195pub const prestat_t = extern struct {
196 pr_type: preopentype_t,
197 u: extern union {
198 dir: extern struct {
199 pr_name_len: usize,
200 },
201 },
202};
203
204pub const riflags_t = u16;
205pub const SOCK_RECV_PEEK: riflags_t = 0x0001;
206pub const SOCK_RECV_WAITALL: riflags_t = 0x0002;
207
208pub const rights_t = u64;
209pub const RIGHT_FD_DATASYNC: rights_t = 0x0000000000000001;
210pub const RIGHT_FD_READ: rights_t = 0x0000000000000002;
211pub const RIGHT_FD_SEEK: rights_t = 0x0000000000000004;
212pub const RIGHT_FD_FDSTAT_SET_FLAGS: rights_t = 0x0000000000000008;
213pub const RIGHT_FD_SYNC: rights_t = 0x0000000000000010;
214pub const RIGHT_FD_TELL: rights_t = 0x0000000000000020;
215pub const RIGHT_FD_WRITE: rights_t = 0x0000000000000040;
216pub const RIGHT_FD_ADVISE: rights_t = 0x0000000000000080;
217pub const RIGHT_FD_ALLOCATE: rights_t = 0x0000000000000100;
218pub const RIGHT_PATH_CREATE_DIRECTORY: rights_t = 0x0000000000000200;
219pub const RIGHT_PATH_CREATE_FILE: rights_t = 0x0000000000000400;
220pub const RIGHT_PATH_LINK_SOURCE: rights_t = 0x0000000000000800;
221pub const RIGHT_PATH_LINK_TARGET: rights_t = 0x0000000000001000;
222pub const RIGHT_PATH_OPEN: rights_t = 0x0000000000002000;
223pub const RIGHT_FD_READDIR: rights_t = 0x0000000000004000;
224pub const RIGHT_PATH_READLINK: rights_t = 0x0000000000008000;
225pub const RIGHT_PATH_RENAME_SOURCE: rights_t = 0x0000000000010000;
226pub const RIGHT_PATH_RENAME_TARGET: rights_t = 0x0000000000020000;
227pub const RIGHT_PATH_FILESTAT_GET: rights_t = 0x0000000000040000;
228pub const RIGHT_PATH_FILESTAT_SET_SIZE: rights_t = 0x0000000000080000;
229pub const RIGHT_PATH_FILESTAT_SET_TIMES: rights_t = 0x0000000000100000;
230pub const RIGHT_FD_FILESTAT_GET: rights_t = 0x0000000000200000;
231pub const RIGHT_FD_FILESTAT_SET_SIZE: rights_t = 0x0000000000400000;
232pub const RIGHT_FD_FILESTAT_SET_TIMES: rights_t = 0x0000000000800000;
233pub const RIGHT_PATH_SYMLINK: rights_t = 0x0000000001000000;
234pub const RIGHT_PATH_REMOVE_DIRECTORY: rights_t = 0x0000000002000000;
235pub const RIGHT_PATH_UNLINK_FILE: rights_t = 0x0000000004000000;
236pub const RIGHT_POLL_FD_READWRITE: rights_t = 0x0000000008000000;
237pub const RIGHT_SOCK_SHUTDOWN: rights_t = 0x0000000010000000;
238
239pub const roflags_t = u16;
240pub const SOCK_RECV_DATA_TRUNCATED: roflags_t = 0x0001;
241
242pub const sdflags_t = u8;
243pub const SHUT_RD: sdflags_t = 0x01;
244pub const SHUT_WR: sdflags_t = 0x02;
245
246pub const siflags_t = u16;
247
248pub const signal_t = u8;
249pub const SIGHUP: signal_t = 1;
250pub const SIGINT: signal_t = 2;
251pub const SIGQUIT: signal_t = 3;
252pub const SIGILL: signal_t = 4;
253pub const SIGTRAP: signal_t = 5;
254pub const SIGABRT: signal_t = 6;
255pub const SIGBUS: signal_t = 7;
256pub const SIGFPE: signal_t = 8;
257pub const SIGKILL: signal_t = 9;
258pub const SIGUSR1: signal_t = 10;
259pub const SIGSEGV: signal_t = 11;
260pub const SIGUSR2: signal_t = 12;
261pub const SIGPIPE: signal_t = 13;
262pub const SIGALRM: signal_t = 14;
263pub const SIGTERM: signal_t = 15;
264pub const SIGCHLD: signal_t = 16;
265pub const SIGCONT: signal_t = 17;
266pub const SIGSTOP: signal_t = 18;
267pub const SIGTSTP: signal_t = 19;
268pub const SIGTTIN: signal_t = 20;
269pub const SIGTTOU: signal_t = 21;
270pub const SIGURG: signal_t = 22;
271pub const SIGXCPU: signal_t = 23;
272pub const SIGXFSZ: signal_t = 24;
273pub const SIGVTALRM: signal_t = 25;
274pub const SIGPROF: signal_t = 26;
275pub const SIGWINCH: signal_t = 27;
276pub const SIGPOLL: signal_t = 28;
277pub const SIGPWR: signal_t = 29;
278pub const SIGSYS: signal_t = 30;
279
280pub const subclockflags_t = u16;
281pub const SUBSCRIPTION_CLOCK_ABSTIME: subclockflags_t = 0x0001;
282
283pub const subscription_t = extern struct {
284 userdata: userdata_t,
285 @"type": eventtype_t,
286 u: extern union {
287 clock: extern struct {
288 identifier: userdata_t,
289 clock_id: clockid_t,
290 timeout: timestamp_t,
291 precision: timestamp_t,
292 flags: subclockflags_t,
293 },
294 fd_readwrite: extern struct {
295 fd: fd_t,
296 },
297 },
298};
299
300pub const timestamp_t = u64;
301
302pub const userdata_t = u64;
303
304pub const whence_t = u8;
305pub const WHENCE_CUR: whence_t = 0;
306pub const WHENCE_END: whence_t = 1;
307pub const WHENCE_SET: whence_t = 2;
std/os/bits/windows.zig created+167
...@@ -0,0 +1,167 @@
1// The reference for these types and values is Microsoft Windows's ucrt (Universal C RunTime).
2
3use @import("../windows/bits.zig");
4
5pub const fd_t = HANDLE;
6pub const pid_t = HANDLE;
7
8pub const PATH_MAX = 260;
9
10pub const time_t = c_longlong;
11
12pub const timespec = extern struct {
13 tv_sec: time_t,
14 tv_nsec: c_long,
15};
16
17pub const sig_atomic_t = c_int;
18
19/// maximum signal number + 1
20pub const NSIG = 23;
21
22// Signal types
23
24/// interrupt
25pub const SIGINT = 2;
26
27/// illegal instruction - invalid function image
28pub const SIGILL = 4;
29
30/// floating point exception
31pub const SIGFPE = 8;
32
33/// segment violation
34pub const SIGSEGV = 11;
35
36/// Software termination signal from kill
37pub const SIGTERM = 15;
38
39/// Ctrl-Break sequence
40pub const SIGBREAK = 21;
41
42/// abnormal termination triggered by abort call
43pub const SIGABRT = 22;
44
45/// SIGABRT compatible with other platforms, same as SIGABRT
46pub const SIGABRT_COMPAT = 6;
47
48// Signal action codes
49
50/// default signal action
51pub const SIG_DFL = 0;
52
53/// ignore signal
54pub const SIG_IGN = 1;
55
56/// return current value
57pub const SIG_GET = 2;
58
59/// signal gets error
60pub const SIG_SGE = 3;
61
62/// acknowledge
63pub const SIG_ACK = 4;
64
65/// Signal error value (returned by signal call on error)
66pub const SIG_ERR = -1;
67
68pub const SEEK_SET = 0;
69pub const SEEK_CUR = 1;
70pub const SEEK_END = 2;
71
72pub const EPERM = 1;
73pub const ENOENT = 2;
74pub const ESRCH = 3;
75pub const EINTR = 4;
76pub const EIO = 5;
77pub const ENXIO = 6;
78pub const E2BIG = 7;
79pub const ENOEXEC = 8;
80pub const EBADF = 9;
81pub const ECHILD = 10;
82pub const EAGAIN = 11;
83pub const ENOMEM = 12;
84pub const EACCES = 13;
85pub const EFAULT = 14;
86pub const EBUSY = 16;
87pub const EEXIST = 17;
88pub const EXDEV = 18;
89pub const ENODEV = 19;
90pub const ENOTDIR = 20;
91pub const EISDIR = 21;
92pub const ENFILE = 23;
93pub const EMFILE = 24;
94pub const ENOTTY = 25;
95pub const EFBIG = 27;
96pub const ENOSPC = 28;
97pub const ESPIPE = 29;
98pub const EROFS = 30;
99pub const EMLINK = 31;
100pub const EPIPE = 32;
101pub const EDOM = 33;
102pub const EDEADLK = 36;
103pub const ENAMETOOLONG = 38;
104pub const ENOLCK = 39;
105pub const ENOSYS = 40;
106pub const ENOTEMPTY = 41;
107
108pub const EINVAL = 22;
109pub const ERANGE = 34;
110pub const EILSEQ = 42;
111pub const STRUNCATE = 80;
112
113// Support EDEADLOCK for compatibility with older Microsoft C versions
114pub const EDEADLOCK = EDEADLK;
115
116// POSIX Supplement
117pub const EADDRINUSE = 100;
118pub const EADDRNOTAVAIL = 101;
119pub const EAFNOSUPPORT = 102;
120pub const EALREADY = 103;
121pub const EBADMSG = 104;
122pub const ECANCELED = 105;
123pub const ECONNABORTED = 106;
124pub const ECONNREFUSED = 107;
125pub const ECONNRESET = 108;
126pub const EDESTADDRREQ = 109;
127pub const EHOSTUNREACH = 110;
128pub const EIDRM = 111;
129pub const EINPROGRESS = 112;
130pub const EISCONN = 113;
131pub const ELOOP = 114;
132pub const EMSGSIZE = 115;
133pub const ENETDOWN = 116;
134pub const ENETRESET = 117;
135pub const ENETUNREACH = 118;
136pub const ENOBUFS = 119;
137pub const ENODATA = 120;
138pub const ENOLINK = 121;
139pub const ENOMSG = 122;
140pub const ENOPROTOOPT = 123;
141pub const ENOSR = 124;
142pub const ENOSTR = 125;
143pub const ENOTCONN = 126;
144pub const ENOTRECOVERABLE = 127;
145pub const ENOTSOCK = 128;
146pub const ENOTSUP = 129;
147pub const EOPNOTSUPP = 130;
148pub const EOTHER = 131;
149pub const EOVERFLOW = 132;
150pub const EOWNERDEAD = 133;
151pub const EPROTO = 134;
152pub const EPROTONOSUPPORT = 135;
153pub const EPROTOTYPE = 136;
154pub const ETIME = 137;
155pub const ETIMEDOUT = 138;
156pub const ETXTBSY = 139;
157pub const EWOULDBLOCK = 140;
158pub const EDQUOT = 10069;
159
160pub const F_OK = 0;
161
162// These are workarounds for "use of undeclared identifier" compile errors
163// TODO make the compiler even more lazy. don't emit "use of undeclared identifier" errors
164// for if branches that aren't taken.
165pub const SIGKILL = @compileError("Windows libc does not have this");
166
167
std/os/child_process.zig deleted-819
...@@ -1,819 +0,0 @@
1const std = @import("../std.zig");
2const cstr = std.cstr;
3const unicode = std.unicode;
4const io = std.io;
5const os = std.os;
6const posix = os.posix;
7const windows = os.windows;
8const mem = std.mem;
9const debug = std.debug;
10const BufMap = std.BufMap;
11const Buffer = std.Buffer;
12const builtin = @import("builtin");
13const Os = builtin.Os;
14const LinkedList = std.LinkedList;
15const windows_util = @import("windows/util.zig");
16const maxInt = std.math.maxInt;
17
18const is_windows = builtin.os == Os.windows;
19
20pub const ChildProcess = struct {
21 pub pid: if (is_windows) void else i32,
22 pub handle: if (is_windows) windows.HANDLE else void,
23 pub thread_handle: if (is_windows) windows.HANDLE else void,
24
25 pub allocator: *mem.Allocator,
26
27 pub stdin: ?os.File,
28 pub stdout: ?os.File,
29 pub stderr: ?os.File,
30
31 pub term: ?(SpawnError!Term),
32
33 pub argv: []const []const u8,
34
35 /// Leave as null to use the current env map using the supplied allocator.
36 pub env_map: ?*const BufMap,
37
38 pub stdin_behavior: StdIo,
39 pub stdout_behavior: StdIo,
40 pub stderr_behavior: StdIo,
41
42 /// Set to change the user id when spawning the child process.
43 pub uid: if (is_windows) void else ?u32,
44
45 /// Set to change the group id when spawning the child process.
46 pub gid: if (is_windows) void else ?u32,
47
48 /// Set to change the current working directory when spawning the child process.
49 pub cwd: ?[]const u8,
50
51 err_pipe: if (is_windows) void else [2]i32,
52 llnode: if (is_windows) void else LinkedList(*ChildProcess).Node,
53
54 pub const SpawnError = error{
55 ProcessFdQuotaExceeded,
56 Unexpected,
57 NotDir,
58 SystemResources,
59 FileNotFound,
60 NameTooLong,
61 SymLinkLoop,
62 FileSystem,
63 OutOfMemory,
64 AccessDenied,
65 PermissionDenied,
66 InvalidUserId,
67 ResourceLimitReached,
68 InvalidExe,
69 IsDir,
70 FileBusy,
71 };
72
73 pub const Term = union(enum) {
74 Exited: i32,
75 Signal: i32,
76 Stopped: i32,
77 Unknown: i32,
78 };
79
80 pub const StdIo = enum {
81 Inherit,
82 Ignore,
83 Pipe,
84 Close,
85 };
86
87 /// First argument in argv is the executable.
88 /// On success must call deinit.
89 pub fn init(argv: []const []const u8, allocator: *mem.Allocator) !*ChildProcess {
90 const child = try allocator.create(ChildProcess);
91 child.* = ChildProcess{
92 .allocator = allocator,
93 .argv = argv,
94 .pid = undefined,
95 .handle = undefined,
96 .thread_handle = undefined,
97 .err_pipe = undefined,
98 .llnode = undefined,
99 .term = null,
100 .env_map = null,
101 .cwd = null,
102 .uid = if (is_windows) {} else
103 null,
104 .gid = if (is_windows) {} else
105 null,
106 .stdin = null,
107 .stdout = null,
108 .stderr = null,
109 .stdin_behavior = StdIo.Inherit,
110 .stdout_behavior = StdIo.Inherit,
111 .stderr_behavior = StdIo.Inherit,
112 };
113 errdefer allocator.destroy(child);
114 return child;
115 }
116
117 pub fn setUserName(self: *ChildProcess, name: []const u8) !void {
118 const user_info = try os.getUserInfo(name);
119 self.uid = user_info.uid;
120 self.gid = user_info.gid;
121 }
122
123 /// On success must call `kill` or `wait`.
124 pub fn spawn(self: *ChildProcess) !void {
125 if (is_windows) {
126 return self.spawnWindows();
127 } else {
128 return self.spawnPosix();
129 }
130 }
131
132 pub fn spawnAndWait(self: *ChildProcess) !Term {
133 try self.spawn();
134 return self.wait();
135 }
136
137 /// Forcibly terminates child process and then cleans up all resources.
138 pub fn kill(self: *ChildProcess) !Term {
139 if (is_windows) {
140 return self.killWindows(1);
141 } else {
142 return self.killPosix();
143 }
144 }
145
146 pub fn killWindows(self: *ChildProcess, exit_code: windows.UINT) !Term {
147 if (self.term) |term| {
148 self.cleanupStreams();
149 return term;
150 }
151
152 if (!windows.TerminateProcess(self.handle, exit_code)) {
153 const err = windows.GetLastError();
154 return switch (err) {
155 else => os.unexpectedErrorWindows(err),
156 };
157 }
158 try self.waitUnwrappedWindows();
159 return self.term.?;
160 }
161
162 pub fn killPosix(self: *ChildProcess) !Term {
163 if (self.term) |term| {
164 self.cleanupStreams();
165 return term;
166 }
167 const ret = posix.kill(self.pid, posix.SIGTERM);
168 const err = posix.getErrno(ret);
169 if (err > 0) {
170 return switch (err) {
171 posix.EINVAL => unreachable,
172 posix.EPERM => error.PermissionDenied,
173 posix.ESRCH => error.ProcessNotFound,
174 else => os.unexpectedErrorPosix(err),
175 };
176 }
177 self.waitUnwrapped();
178 return self.term.?;
179 }
180
181 /// Blocks until child process terminates and then cleans up all resources.
182 pub fn wait(self: *ChildProcess) !Term {
183 if (is_windows) {
184 return self.waitWindows();
185 } else {
186 return self.waitPosix();
187 }
188 }
189
190 pub const ExecResult = struct {
191 term: os.ChildProcess.Term,
192 stdout: []u8,
193 stderr: []u8,
194 };
195
196 /// Spawns a child process, waits for it, collecting stdout and stderr, and then returns.
197 /// If it succeeds, the caller owns result.stdout and result.stderr memory.
198 pub fn exec(allocator: *mem.Allocator, argv: []const []const u8, cwd: ?[]const u8, env_map: ?*const BufMap, max_output_size: usize) !ExecResult {
199 const child = try ChildProcess.init(argv, allocator);
200 defer child.deinit();
201
202 child.stdin_behavior = ChildProcess.StdIo.Ignore;
203 child.stdout_behavior = ChildProcess.StdIo.Pipe;
204 child.stderr_behavior = ChildProcess.StdIo.Pipe;
205 child.cwd = cwd;
206 child.env_map = env_map;
207
208 try child.spawn();
209
210 var stdout = Buffer.initNull(allocator);
211 var stderr = Buffer.initNull(allocator);
212 defer Buffer.deinit(&stdout);
213 defer Buffer.deinit(&stderr);
214
215 var stdout_file_in_stream = child.stdout.?.inStream();
216 var stderr_file_in_stream = child.stderr.?.inStream();
217
218 try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size);
219 try stderr_file_in_stream.stream.readAllBuffer(&stderr, max_output_size);
220
221 return ExecResult{
222 .term = try child.wait(),
223 .stdout = stdout.toOwnedSlice(),
224 .stderr = stderr.toOwnedSlice(),
225 };
226 }
227
228 fn waitWindows(self: *ChildProcess) !Term {
229 if (self.term) |term| {
230 self.cleanupStreams();
231 return term;
232 }
233
234 try self.waitUnwrappedWindows();
235 return self.term.?;
236 }
237
238 fn waitPosix(self: *ChildProcess) !Term {
239 if (self.term) |term| {
240 self.cleanupStreams();
241 return term;
242 }
243
244 self.waitUnwrapped();
245 return self.term.?;
246 }
247
248 pub fn deinit(self: *ChildProcess) void {
249 self.allocator.destroy(self);
250 }
251
252 fn waitUnwrappedWindows(self: *ChildProcess) !void {
253 const result = os.windowsWaitSingle(self.handle, windows.INFINITE);
254
255 self.term = (SpawnError!Term)(x: {
256 var exit_code: windows.DWORD = undefined;
257 if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) {
258 break :x Term{ .Unknown = 0 };
259 } else {
260 break :x Term{ .Exited = @bitCast(i32, exit_code) };
261 }
262 });
263
264 os.close(self.handle);
265 os.close(self.thread_handle);
266 self.cleanupStreams();
267 return result;
268 }
269
270 fn waitUnwrapped(self: *ChildProcess) void {
271 var status: i32 = undefined;
272 while (true) {
273 const err = posix.getErrno(posix.waitpid(self.pid, &status, 0));
274 if (err > 0) {
275 switch (err) {
276 posix.EINTR => continue,
277 else => unreachable,
278 }
279 }
280 self.cleanupStreams();
281 self.handleWaitResult(status);
282 return;
283 }
284 }
285
286 fn handleWaitResult(self: *ChildProcess, status: i32) void {
287 self.term = self.cleanupAfterWait(status);
288 }
289
290 fn cleanupStreams(self: *ChildProcess) void {
291 if (self.stdin) |*stdin| {
292 stdin.close();
293 self.stdin = null;
294 }
295 if (self.stdout) |*stdout| {
296 stdout.close();
297 self.stdout = null;
298 }
299 if (self.stderr) |*stderr| {
300 stderr.close();
301 self.stderr = null;
302 }
303 }
304
305 fn cleanupAfterWait(self: *ChildProcess, status: i32) !Term {
306 defer {
307 os.close(self.err_pipe[0]);
308 os.close(self.err_pipe[1]);
309 }
310
311 // Write maxInt(ErrInt) to the write end of the err_pipe. This is after
312 // waitpid, so this write is guaranteed to be after the child
313 // pid potentially wrote an error. This way we can do a blocking
314 // read on the error pipe and either get maxInt(ErrInt) (no error) or
315 // an error code.
316 try writeIntFd(self.err_pipe[1], maxInt(ErrInt));
317 const err_int = try readIntFd(self.err_pipe[0]);
318 // Here we potentially return the fork child's error
319 // from the parent pid.
320 if (err_int != maxInt(ErrInt)) {
321 return @errSetCast(SpawnError, @intToError(err_int));
322 }
323
324 return statusToTerm(status);
325 }
326
327 fn statusToTerm(status: i32) Term {
328 return if (posix.WIFEXITED(status))
329 Term{ .Exited = posix.WEXITSTATUS(status) }
330 else if (posix.WIFSIGNALED(status))
331 Term{ .Signal = posix.WTERMSIG(status) }
332 else if (posix.WIFSTOPPED(status))
333 Term{ .Stopped = posix.WSTOPSIG(status) }
334 else
335 Term{ .Unknown = status };
336 }
337
338 fn spawnPosix(self: *ChildProcess) !void {
339 const stdin_pipe = if (self.stdin_behavior == StdIo.Pipe) try makePipe() else undefined;
340 errdefer if (self.stdin_behavior == StdIo.Pipe) {
341 destroyPipe(stdin_pipe);
342 };
343
344 const stdout_pipe = if (self.stdout_behavior == StdIo.Pipe) try makePipe() else undefined;
345 errdefer if (self.stdout_behavior == StdIo.Pipe) {
346 destroyPipe(stdout_pipe);
347 };
348
349 const stderr_pipe = if (self.stderr_behavior == StdIo.Pipe) try makePipe() else undefined;
350 errdefer if (self.stderr_behavior == StdIo.Pipe) {
351 destroyPipe(stderr_pipe);
352 };
353
354 const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
355 const dev_null_fd = if (any_ignore) try os.posixOpenC(c"/dev/null", posix.O_RDWR, 0) else undefined;
356 defer {
357 if (any_ignore) os.close(dev_null_fd);
358 }
359
360 var env_map_owned: BufMap = undefined;
361 var we_own_env_map: bool = undefined;
362 const env_map = if (self.env_map) |env_map| x: {
363 we_own_env_map = false;
364 break :x env_map;
365 } else x: {
366 we_own_env_map = true;
367 env_map_owned = try os.getEnvMap(self.allocator);
368 break :x &env_map_owned;
369 };
370 defer {
371 if (we_own_env_map) env_map_owned.deinit();
372 }
373
374 // This pipe is used to communicate errors between the time of fork
375 // and execve from the child process to the parent process.
376 const err_pipe = try makePipe();
377 errdefer destroyPipe(err_pipe);
378
379 const pid_result = posix.fork();
380 const pid_err = posix.getErrno(pid_result);
381 if (pid_err > 0) {
382 return switch (pid_err) {
383 posix.EAGAIN, posix.ENOMEM, posix.ENOSYS => error.SystemResources,
384 else => os.unexpectedErrorPosix(pid_err),
385 };
386 }
387 if (pid_result == 0) {
388 // we are the child
389 setUpChildIo(self.stdin_behavior, stdin_pipe[0], posix.STDIN_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
390 setUpChildIo(self.stdout_behavior, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
391 setUpChildIo(self.stderr_behavior, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
392
393 if (self.stdin_behavior == StdIo.Pipe) {
394 os.close(stdin_pipe[0]);
395 os.close(stdin_pipe[1]);
396 }
397 if (self.stdout_behavior == StdIo.Pipe) {
398 os.close(stdout_pipe[0]);
399 os.close(stdout_pipe[1]);
400 }
401 if (self.stderr_behavior == StdIo.Pipe) {
402 os.close(stderr_pipe[0]);
403 os.close(stderr_pipe[1]);
404 }
405
406 if (self.cwd) |cwd| {
407 os.changeCurDir(cwd) catch |err| forkChildErrReport(err_pipe[1], err);
408 }
409
410 if (self.gid) |gid| {
411 os.posix_setregid(gid, gid) catch |err| forkChildErrReport(err_pipe[1], err);
412 }
413
414 if (self.uid) |uid| {
415 os.posix_setreuid(uid, uid) catch |err| forkChildErrReport(err_pipe[1], err);
416 }
417
418 os.posixExecve(self.argv, env_map, self.allocator) catch |err| forkChildErrReport(err_pipe[1], err);
419 }
420
421 // we are the parent
422 const pid = @intCast(i32, pid_result);
423 if (self.stdin_behavior == StdIo.Pipe) {
424 self.stdin = os.File.openHandle(stdin_pipe[1]);
425 } else {
426 self.stdin = null;
427 }
428 if (self.stdout_behavior == StdIo.Pipe) {
429 self.stdout = os.File.openHandle(stdout_pipe[0]);
430 } else {
431 self.stdout = null;
432 }
433 if (self.stderr_behavior == StdIo.Pipe) {
434 self.stderr = os.File.openHandle(stderr_pipe[0]);
435 } else {
436 self.stderr = null;
437 }
438
439 self.pid = pid;
440 self.err_pipe = err_pipe;
441 self.llnode = LinkedList(*ChildProcess).Node.init(self);
442 self.term = null;
443
444 if (self.stdin_behavior == StdIo.Pipe) {
445 os.close(stdin_pipe[0]);
446 }
447 if (self.stdout_behavior == StdIo.Pipe) {
448 os.close(stdout_pipe[1]);
449 }
450 if (self.stderr_behavior == StdIo.Pipe) {
451 os.close(stderr_pipe[1]);
452 }
453 }
454
455 fn spawnWindows(self: *ChildProcess) !void {
456 const saAttr = windows.SECURITY_ATTRIBUTES{
457 .nLength = @sizeOf(windows.SECURITY_ATTRIBUTES),
458 .bInheritHandle = windows.TRUE,
459 .lpSecurityDescriptor = null,
460 };
461
462 const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore);
463
464 const nul_handle = if (any_ignore) blk: {
465 break :blk try os.windowsOpen("NUL", windows.GENERIC_READ, windows.FILE_SHARE_READ, windows.OPEN_EXISTING, windows.FILE_ATTRIBUTE_NORMAL);
466 } else blk: {
467 break :blk undefined;
468 };
469 defer {
470 if (any_ignore) os.close(nul_handle);
471 }
472 if (any_ignore) {
473 try windowsSetHandleInfo(nul_handle, windows.HANDLE_FLAG_INHERIT, 0);
474 }
475
476 var g_hChildStd_IN_Rd: ?windows.HANDLE = null;
477 var g_hChildStd_IN_Wr: ?windows.HANDLE = null;
478 switch (self.stdin_behavior) {
479 StdIo.Pipe => {
480 try windowsMakePipeIn(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr);
481 },
482 StdIo.Ignore => {
483 g_hChildStd_IN_Rd = nul_handle;
484 },
485 StdIo.Inherit => {
486 g_hChildStd_IN_Rd = windows.GetStdHandle(windows.STD_INPUT_HANDLE);
487 },
488 StdIo.Close => {
489 g_hChildStd_IN_Rd = null;
490 },
491 }
492 errdefer if (self.stdin_behavior == StdIo.Pipe) {
493 windowsDestroyPipe(g_hChildStd_IN_Rd, g_hChildStd_IN_Wr);
494 };
495
496 var g_hChildStd_OUT_Rd: ?windows.HANDLE = null;
497 var g_hChildStd_OUT_Wr: ?windows.HANDLE = null;
498 switch (self.stdout_behavior) {
499 StdIo.Pipe => {
500 try windowsMakePipeOut(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr);
501 },
502 StdIo.Ignore => {
503 g_hChildStd_OUT_Wr = nul_handle;
504 },
505 StdIo.Inherit => {
506 g_hChildStd_OUT_Wr = windows.GetStdHandle(windows.STD_OUTPUT_HANDLE);
507 },
508 StdIo.Close => {
509 g_hChildStd_OUT_Wr = null;
510 },
511 }
512 errdefer if (self.stdin_behavior == StdIo.Pipe) {
513 windowsDestroyPipe(g_hChildStd_OUT_Rd, g_hChildStd_OUT_Wr);
514 };
515
516 var g_hChildStd_ERR_Rd: ?windows.HANDLE = null;
517 var g_hChildStd_ERR_Wr: ?windows.HANDLE = null;
518 switch (self.stderr_behavior) {
519 StdIo.Pipe => {
520 try windowsMakePipeOut(&g_hChildStd_ERR_Rd, &g_hChildStd_ERR_Wr, &saAttr);
521 },
522 StdIo.Ignore => {
523 g_hChildStd_ERR_Wr = nul_handle;
524 },
525 StdIo.Inherit => {
526 g_hChildStd_ERR_Wr = windows.GetStdHandle(windows.STD_ERROR_HANDLE);
527 },
528 StdIo.Close => {
529 g_hChildStd_ERR_Wr = null;
530 },
531 }
532 errdefer if (self.stdin_behavior == StdIo.Pipe) {
533 windowsDestroyPipe(g_hChildStd_ERR_Rd, g_hChildStd_ERR_Wr);
534 };
535
536 const cmd_line = try windowsCreateCommandLine(self.allocator, self.argv);
537 defer self.allocator.free(cmd_line);
538
539 var siStartInfo = windows.STARTUPINFOW{
540 .cb = @sizeOf(windows.STARTUPINFOW),
541 .hStdError = g_hChildStd_ERR_Wr,
542 .hStdOutput = g_hChildStd_OUT_Wr,
543 .hStdInput = g_hChildStd_IN_Rd,
544 .dwFlags = windows.STARTF_USESTDHANDLES,
545
546 .lpReserved = null,
547 .lpDesktop = null,
548 .lpTitle = null,
549 .dwX = 0,
550 .dwY = 0,
551 .dwXSize = 0,
552 .dwYSize = 0,
553 .dwXCountChars = 0,
554 .dwYCountChars = 0,
555 .dwFillAttribute = 0,
556 .wShowWindow = 0,
557 .cbReserved2 = 0,
558 .lpReserved2 = null,
559 };
560 var piProcInfo: windows.PROCESS_INFORMATION = undefined;
561
562 const cwd_slice = if (self.cwd) |cwd| try cstr.addNullByte(self.allocator, cwd) else null;
563 defer if (cwd_slice) |cwd| self.allocator.free(cwd);
564 const cwd_w = if (cwd_slice) |cwd| try unicode.utf8ToUtf16LeWithNull(self.allocator, cwd) else null;
565 defer if (cwd_w) |cwd| self.allocator.free(cwd);
566 const cwd_w_ptr = if (cwd_w) |cwd| cwd.ptr else null;
567
568 const maybe_envp_buf = if (self.env_map) |env_map| try os.createWindowsEnvBlock(self.allocator, env_map) else null;
569 defer if (maybe_envp_buf) |envp_buf| self.allocator.free(envp_buf);
570 const envp_ptr = if (maybe_envp_buf) |envp_buf| envp_buf.ptr else null;
571
572 // the cwd set in ChildProcess is in effect when choosing the executable path
573 // to match posix semantics
574 const app_name = x: {
575 if (self.cwd) |cwd| {
576 const resolved = try os.path.resolve(self.allocator, [][]const u8{ cwd, self.argv[0] });
577 defer self.allocator.free(resolved);
578 break :x try cstr.addNullByte(self.allocator, resolved);
579 } else {
580 break :x try cstr.addNullByte(self.allocator, self.argv[0]);
581 }
582 };
583 defer self.allocator.free(app_name);
584
585 const app_name_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, app_name);
586 defer self.allocator.free(app_name_w);
587
588 const cmd_line_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, cmd_line);
589 defer self.allocator.free(cmd_line_w);
590
591 windowsCreateProcess(app_name_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo) catch |no_path_err| {
592 if (no_path_err != error.FileNotFound) return no_path_err;
593
594 const PATH = try os.getEnvVarOwned(self.allocator, "PATH");
595 defer self.allocator.free(PATH);
596
597 var it = mem.tokenize(PATH, ";");
598 while (it.next()) |search_path| {
599 const joined_path = try os.path.join(self.allocator, [][]const u8{ search_path, app_name });
600 defer self.allocator.free(joined_path);
601
602 const joined_path_w = try unicode.utf8ToUtf16LeWithNull(self.allocator, joined_path);
603 defer self.allocator.free(joined_path_w);
604
605 if (windowsCreateProcess(joined_path_w.ptr, cmd_line_w.ptr, envp_ptr, cwd_w_ptr, &siStartInfo, &piProcInfo)) |_| {
606 break;
607 } else |err| if (err == error.FileNotFound) {
608 continue;
609 } else {
610 return err;
611 }
612 } else {
613 // Every other error would have been returned earlier.
614 return error.FileNotFound;
615 }
616 };
617
618 if (g_hChildStd_IN_Wr) |h| {
619 self.stdin = os.File.openHandle(h);
620 } else {
621 self.stdin = null;
622 }
623 if (g_hChildStd_OUT_Rd) |h| {
624 self.stdout = os.File.openHandle(h);
625 } else {
626 self.stdout = null;
627 }
628 if (g_hChildStd_ERR_Rd) |h| {
629 self.stderr = os.File.openHandle(h);
630 } else {
631 self.stderr = null;
632 }
633
634 self.handle = piProcInfo.hProcess;
635 self.thread_handle = piProcInfo.hThread;
636 self.term = null;
637
638 if (self.stdin_behavior == StdIo.Pipe) {
639 os.close(g_hChildStd_IN_Rd.?);
640 }
641 if (self.stderr_behavior == StdIo.Pipe) {
642 os.close(g_hChildStd_ERR_Wr.?);
643 }
644 if (self.stdout_behavior == StdIo.Pipe) {
645 os.close(g_hChildStd_OUT_Wr.?);
646 }
647 }
648
649 fn setUpChildIo(stdio: StdIo, pipe_fd: i32, std_fileno: i32, dev_null_fd: i32) !void {
650 switch (stdio) {
651 StdIo.Pipe => try os.posixDup2(pipe_fd, std_fileno),
652 StdIo.Close => os.close(std_fileno),
653 StdIo.Inherit => {},
654 StdIo.Ignore => try os.posixDup2(dev_null_fd, std_fileno),
655 }
656 }
657};
658
659fn windowsCreateProcess(app_name: [*]u16, cmd_line: [*]u16, envp_ptr: ?[*]u16, cwd_ptr: ?[*]u16, lpStartupInfo: *windows.STARTUPINFOW, lpProcessInformation: *windows.PROCESS_INFORMATION) !void {
660 // TODO the docs for environment pointer say:
661 // > A pointer to the environment block for the new process. If this parameter
662 // > is NULL, the new process uses the environment of the calling process.
663 // > ...
664 // > An environment block can contain either Unicode or ANSI characters. If
665 // > the environment block pointed to by lpEnvironment contains Unicode
666 // > characters, be sure that dwCreationFlags includes CREATE_UNICODE_ENVIRONMENT.
667 // > If this parameter is NULL and the environment block of the parent process
668 // > contains Unicode characters, you must also ensure that dwCreationFlags
669 // > includes CREATE_UNICODE_ENVIRONMENT.
670 // This seems to imply that we have to somehow know whether our process parent passed
671 // CREATE_UNICODE_ENVIRONMENT if we want to pass NULL for the environment parameter.
672 // Since we do not know this information that would imply that we must not pass NULL
673 // for the parameter.
674 // However this would imply that programs compiled with -DUNICODE could not pass
675 // environment variables to programs that were not, which seems unlikely.
676 // More investigation is needed.
677 if (windows.CreateProcessW(
678 app_name,
679 cmd_line,
680 null,
681 null,
682 windows.TRUE,
683 windows.CREATE_UNICODE_ENVIRONMENT,
684 @ptrCast(?*c_void, envp_ptr),
685 cwd_ptr,
686 lpStartupInfo,
687 lpProcessInformation,
688 ) == 0) {
689 const err = windows.GetLastError();
690 switch (err) {
691 windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
692 windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
693 windows.ERROR.INVALID_PARAMETER => unreachable,
694 windows.ERROR.INVALID_NAME => return error.InvalidName,
695 else => return os.unexpectedErrorWindows(err),
696 }
697 }
698}
699
700/// Caller must dealloc.
701/// Guarantees a null byte at result[result.len].
702fn windowsCreateCommandLine(allocator: *mem.Allocator, argv: []const []const u8) ![]u8 {
703 var buf = try Buffer.initSize(allocator, 0);
704 defer buf.deinit();
705
706 var buf_stream = &io.BufferOutStream.init(&buf).stream;
707
708 for (argv) |arg, arg_i| {
709 if (arg_i != 0) try buf.appendByte(' ');
710 if (mem.indexOfAny(u8, arg, " \t\n\"") == null) {
711 try buf.append(arg);
712 continue;
713 }
714 try buf.appendByte('"');
715 var backslash_count: usize = 0;
716 for (arg) |byte| {
717 switch (byte) {
718 '\\' => backslash_count += 1,
719 '"' => {
720 try buf_stream.writeByteNTimes('\\', backslash_count * 2 + 1);
721 try buf.appendByte('"');
722 backslash_count = 0;
723 },
724 else => {
725 try buf_stream.writeByteNTimes('\\', backslash_count);
726 try buf.appendByte(byte);
727 backslash_count = 0;
728 },
729 }
730 }
731 try buf_stream.writeByteNTimes('\\', backslash_count * 2);
732 try buf.appendByte('"');
733 }
734
735 return buf.toOwnedSlice();
736}
737
738fn windowsDestroyPipe(rd: ?windows.HANDLE, wr: ?windows.HANDLE) void {
739 if (rd) |h| os.close(h);
740 if (wr) |h| os.close(h);
741}
742
743// TODO: workaround for bug where the `const` from `&const` is dropped when the type is
744// a namespace field lookup
745const SECURITY_ATTRIBUTES = windows.SECURITY_ATTRIBUTES;
746
747fn windowsMakePipe(rd: *windows.HANDLE, wr: *windows.HANDLE, sattr: *const SECURITY_ATTRIBUTES) !void {
748 if (windows.CreatePipe(rd, wr, sattr, 0) == 0) {
749 const err = windows.GetLastError();
750 return switch (err) {
751 else => os.unexpectedErrorWindows(err),
752 };
753 }
754}
755
756fn windowsSetHandleInfo(h: windows.HANDLE, mask: windows.DWORD, flags: windows.DWORD) !void {
757 if (windows.SetHandleInformation(h, mask, flags) == 0) {
758 const err = windows.GetLastError();
759 return switch (err) {
760 else => os.unexpectedErrorWindows(err),
761 };
762 }
763}
764
765fn windowsMakePipeIn(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const SECURITY_ATTRIBUTES) !void {
766 var rd_h: windows.HANDLE = undefined;
767 var wr_h: windows.HANDLE = undefined;
768 try windowsMakePipe(&rd_h, &wr_h, sattr);
769 errdefer windowsDestroyPipe(rd_h, wr_h);
770 try windowsSetHandleInfo(wr_h, windows.HANDLE_FLAG_INHERIT, 0);
771 rd.* = rd_h;
772 wr.* = wr_h;
773}
774
775fn windowsMakePipeOut(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const SECURITY_ATTRIBUTES) !void {
776 var rd_h: windows.HANDLE = undefined;
777 var wr_h: windows.HANDLE = undefined;
778 try windowsMakePipe(&rd_h, &wr_h, sattr);
779 errdefer windowsDestroyPipe(rd_h, wr_h);
780 try windowsSetHandleInfo(rd_h, windows.HANDLE_FLAG_INHERIT, 0);
781 rd.* = rd_h;
782 wr.* = wr_h;
783}
784
785fn makePipe() ![2]i32 {
786 var fds: [2]i32 = undefined;
787 const err = posix.getErrno(posix.pipe(&fds));
788 if (err > 0) {
789 return switch (err) {
790 posix.EMFILE, posix.ENFILE => error.SystemResources,
791 else => os.unexpectedErrorPosix(err),
792 };
793 }
794 return fds;
795}
796
797fn destroyPipe(pipe: [2]i32) void {
798 os.close(pipe[0]);
799 os.close(pipe[1]);
800}
801
802// Child of fork calls this to report an error to the fork parent.
803// Then the child exits.
804fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {
805 writeIntFd(fd, ErrInt(@errorToInt(err))) catch {};
806 posix.exit(1);
807}
808
809const ErrInt = @IntType(false, @sizeOf(anyerror) * 8);
810
811fn writeIntFd(fd: i32, value: ErrInt) !void {
812 const stream = &os.File.openHandle(fd).outStream().stream;
813 stream.writeIntNative(ErrInt, value) catch return error.SystemResources;
814}
815
816fn readIntFd(fd: i32) !ErrInt {
817 const stream = &os.File.openHandle(fd).inStream().stream;
818 return stream.readIntNative(ErrInt) catch return error.SystemResources;
819}
std/os/darwin.zig+5-883
...@@ -1,885 +1,7 @@...@@ -1,885 +1,7 @@
1const builtin = @import("builtin");
1const std = @import("../std.zig");2const std = @import("../std.zig");
2const c = std.c;3pub const is_the_target = switch (builtin.os) {
3const assert = std.debug.assert;4 .macosx, .tvos, .watchos, .ios => true,
4const maxInt = std.math.maxInt;5 else => false,
5
6pub use @import("darwin/errno.zig");
7
8pub const PATH_MAX = 1024;
9
10pub const STDIN_FILENO = 0;
11pub const STDOUT_FILENO = 1;
12pub const STDERR_FILENO = 2;
13
14/// [MC2] no permissions
15pub const PROT_NONE = 0x00;
16
17/// [MC2] pages can be read
18pub const PROT_READ = 0x01;
19
20/// [MC2] pages can be written
21pub const PROT_WRITE = 0x02;
22
23/// [MC2] pages can be executed
24pub const PROT_EXEC = 0x04;
25
26/// allocated from memory, swap space
27pub const MAP_ANONYMOUS = 0x1000;
28
29/// map from file (default)
30pub const MAP_FILE = 0x0000;
31
32/// interpret addr exactly
33pub const MAP_FIXED = 0x0010;
34
35/// region may contain semaphores
36pub const MAP_HASSEMAPHORE = 0x0200;
37
38/// changes are private
39pub const MAP_PRIVATE = 0x0002;
40
41/// share changes
42pub const MAP_SHARED = 0x0001;
43
44/// don't cache pages for this mapping
45pub const MAP_NOCACHE = 0x0400;
46
47/// don't reserve needed swap area
48pub const MAP_NORESERVE = 0x0040;
49pub const MAP_FAILED = maxInt(usize);
50
51/// [XSI] no hang in wait/no child to reap
52pub const WNOHANG = 0x00000001;
53
54/// [XSI] notify on stop, untraced child
55pub const WUNTRACED = 0x00000002;
56
57/// take signal on signal stack
58pub const SA_ONSTACK = 0x0001;
59
60/// restart system on signal return
61pub const SA_RESTART = 0x0002;
62
63/// reset to SIG_DFL when taking signal
64pub const SA_RESETHAND = 0x0004;
65
66/// do not generate SIGCHLD on child stop
67pub const SA_NOCLDSTOP = 0x0008;
68
69/// don't mask the signal we're delivering
70pub const SA_NODEFER = 0x0010;
71
72/// don't keep zombies around
73pub const SA_NOCLDWAIT = 0x0020;
74
75/// signal handler with SA_SIGINFO args
76pub const SA_SIGINFO = 0x0040;
77
78/// do not bounce off kernel's sigtramp
79pub const SA_USERTRAMP = 0x0100;
80
81/// signal handler with SA_SIGINFO args with 64bit regs information
82pub const SA_64REGSET = 0x0200;
83
84pub const O_LARGEFILE = 0x0000;
85pub const O_PATH = 0x0000;
86
87pub const F_OK = 0;
88pub const X_OK = 1;
89pub const W_OK = 2;
90pub const R_OK = 4;
91
92/// open for reading only
93pub const O_RDONLY = 0x0000;
94
95/// open for writing only
96pub const O_WRONLY = 0x0001;
97
98/// open for reading and writing
99pub const O_RDWR = 0x0002;
100
101/// do not block on open or for data to become available
102pub const O_NONBLOCK = 0x0004;
103
104/// append on each write
105pub const O_APPEND = 0x0008;
106
107/// create file if it does not exist
108pub const O_CREAT = 0x0200;
109
110/// truncate size to 0
111pub const O_TRUNC = 0x0400;
112
113/// error if O_CREAT and the file exists
114pub const O_EXCL = 0x0800;
115
116/// atomically obtain a shared lock
117pub const O_SHLOCK = 0x0010;
118
119/// atomically obtain an exclusive lock
120pub const O_EXLOCK = 0x0020;
121
122/// do not follow symlinks
123pub const O_NOFOLLOW = 0x0100;
124
125/// allow open of symlinks
126pub const O_SYMLINK = 0x200000;
127
128/// descriptor requested for event notifications only
129pub const O_EVTONLY = 0x8000;
130
131/// mark as close-on-exec
132pub const O_CLOEXEC = 0x1000000;
133
134pub const O_ACCMODE = 3;
135pub const O_ALERT = 536870912;
136pub const O_ASYNC = 64;
137pub const O_DIRECTORY = 1048576;
138pub const O_DP_GETRAWENCRYPTED = 1;
139pub const O_DP_GETRAWUNENCRYPTED = 2;
140pub const O_DSYNC = 4194304;
141pub const O_FSYNC = O_SYNC;
142pub const O_NOCTTY = 131072;
143pub const O_POPUP = 2147483648;
144pub const O_SYNC = 128;
145
146pub const SEEK_SET = 0x0;
147pub const SEEK_CUR = 0x1;
148pub const SEEK_END = 0x2;
149
150pub const DT_UNKNOWN = 0;
151pub const DT_FIFO = 1;
152pub const DT_CHR = 2;
153pub const DT_DIR = 4;
154pub const DT_BLK = 6;
155pub const DT_REG = 8;
156pub const DT_LNK = 10;
157pub const DT_SOCK = 12;
158pub const DT_WHT = 14;
159
160/// block specified signal set
161pub const SIG_BLOCK = 1;
162
163/// unblock specified signal set
164pub const SIG_UNBLOCK = 2;
165
166/// set specified signal set
167pub const SIG_SETMASK = 3;
168
169/// hangup
170pub const SIGHUP = 1;
171
172/// interrupt
173pub const SIGINT = 2;
174
175/// quit
176pub const SIGQUIT = 3;
177
178/// illegal instruction (not reset when caught)
179pub const SIGILL = 4;
180
181/// trace trap (not reset when caught)
182pub const SIGTRAP = 5;
183
184/// abort()
185pub const SIGABRT = 6;
186
187/// pollable event ([XSR] generated, not supported)
188pub const SIGPOLL = 7;
189
190/// compatibility
191pub const SIGIOT = SIGABRT;
192
193/// EMT instruction
194pub const SIGEMT = 7;
195
196/// floating point exception
197pub const SIGFPE = 8;
198
199/// kill (cannot be caught or ignored)
200pub const SIGKILL = 9;
201
202/// bus error
203pub const SIGBUS = 10;
204
205/// segmentation violation
206pub const SIGSEGV = 11;
207
208/// bad argument to system call
209pub const SIGSYS = 12;
210
211/// write on a pipe with no one to read it
212pub const SIGPIPE = 13;
213
214/// alarm clock
215pub const SIGALRM = 14;
216
217/// software termination signal from kill
218pub const SIGTERM = 15;
219
220/// urgent condition on IO channel
221pub const SIGURG = 16;
222
223/// sendable stop signal not from tty
224pub const SIGSTOP = 17;
225
226/// stop signal from tty
227pub const SIGTSTP = 18;
228
229/// continue a stopped process
230pub const SIGCONT = 19;
231
232/// to parent on child stop or exit
233pub const SIGCHLD = 20;
234
235/// to readers pgrp upon background tty read
236pub const SIGTTIN = 21;
237
238/// like TTIN for output if (tp->t_local&LTOSTOP)
239pub const SIGTTOU = 22;
240
241/// input/output possible signal
242pub const SIGIO = 23;
243
244/// exceeded CPU time limit
245pub const SIGXCPU = 24;
246
247/// exceeded file size limit
248pub const SIGXFSZ = 25;
249
250/// virtual time alarm
251pub const SIGVTALRM = 26;
252
253/// profiling time alarm
254pub const SIGPROF = 27;
255
256/// window size changes
257pub const SIGWINCH = 28;
258
259/// information request
260pub const SIGINFO = 29;
261
262/// user defined signal 1
263pub const SIGUSR1 = 30;
264
265/// user defined signal 2
266pub const SIGUSR2 = 31;
267
268/// no flag value
269pub const KEVENT_FLAG_NONE = 0x000;
270
271/// immediate timeout
272pub const KEVENT_FLAG_IMMEDIATE = 0x001;
273
274/// output events only include change
275pub const KEVENT_FLAG_ERROR_EVENTS = 0x002;
276
277/// add event to kq (implies enable)
278pub const EV_ADD = 0x0001;
279
280/// delete event from kq
281pub const EV_DELETE = 0x0002;
282
283/// enable event
284pub const EV_ENABLE = 0x0004;
285
286/// disable event (not reported)
287pub const EV_DISABLE = 0x0008;
288
289/// only report one occurrence
290pub const EV_ONESHOT = 0x0010;
291
292/// clear event state after reporting
293pub const EV_CLEAR = 0x0020;
294
295/// force immediate event output
296/// ... with or without EV_ERROR
297/// ... use KEVENT_FLAG_ERROR_EVENTS
298/// on syscalls supporting flags
299pub const EV_RECEIPT = 0x0040;
300
301/// disable event after reporting
302pub const EV_DISPATCH = 0x0080;
303
304/// unique kevent per udata value
305pub const EV_UDATA_SPECIFIC = 0x0100;
306
307/// ... in combination with EV_DELETE
308/// will defer delete until udata-specific
309/// event enabled. EINPROGRESS will be
310/// returned to indicate the deferral
311pub const EV_DISPATCH2 = EV_DISPATCH | EV_UDATA_SPECIFIC;
312
313/// report that source has vanished
314/// ... only valid with EV_DISPATCH2
315pub const EV_VANISHED = 0x0200;
316
317/// reserved by system
318pub const EV_SYSFLAGS = 0xF000;
319
320/// filter-specific flag
321pub const EV_FLAG0 = 0x1000;
322
323/// filter-specific flag
324pub const EV_FLAG1 = 0x2000;
325
326/// EOF detected
327pub const EV_EOF = 0x8000;
328
329/// error, data contains errno
330pub const EV_ERROR = 0x4000;
331
332pub const EV_POLL = EV_FLAG0;
333pub const EV_OOBAND = EV_FLAG1;
334
335pub const EVFILT_READ = -1;
336pub const EVFILT_WRITE = -2;
337
338/// attached to aio requests
339pub const EVFILT_AIO = -3;
340
341/// attached to vnodes
342pub const EVFILT_VNODE = -4;
343
344/// attached to struct proc
345pub const EVFILT_PROC = -5;
346
347/// attached to struct proc
348pub const EVFILT_SIGNAL = -6;
349
350/// timers
351pub const EVFILT_TIMER = -7;
352
353/// Mach portsets
354pub const EVFILT_MACHPORT = -8;
355
356/// Filesystem events
357pub const EVFILT_FS = -9;
358
359/// User events
360pub const EVFILT_USER = -10;
361
362/// Virtual memory events
363pub const EVFILT_VM = -12;
364
365/// Exception events
366pub const EVFILT_EXCEPT = -15;
367
368pub const EVFILT_SYSCOUNT = 17;
369
370/// On input, NOTE_TRIGGER causes the event to be triggered for output.
371pub const NOTE_TRIGGER = 0x01000000;
372
373/// ignore input fflags
374pub const NOTE_FFNOP = 0x00000000;
375
376/// and fflags
377pub const NOTE_FFAND = 0x40000000;
378
379/// or fflags
380pub const NOTE_FFOR = 0x80000000;
381
382/// copy fflags
383pub const NOTE_FFCOPY = 0xc0000000;
384
385/// mask for operations
386pub const NOTE_FFCTRLMASK = 0xc0000000;
387pub const NOTE_FFLAGSMASK = 0x00ffffff;
388
389/// low water mark
390pub const NOTE_LOWAT = 0x00000001;
391
392/// OOB data
393pub const NOTE_OOB = 0x00000002;
394
395/// vnode was removed
396pub const NOTE_DELETE = 0x00000001;
397
398/// data contents changed
399pub const NOTE_WRITE = 0x00000002;
400
401/// size increased
402pub const NOTE_EXTEND = 0x00000004;
403
404/// attributes changed
405pub const NOTE_ATTRIB = 0x00000008;
406
407/// link count changed
408pub const NOTE_LINK = 0x00000010;
409
410/// vnode was renamed
411pub const NOTE_RENAME = 0x00000020;
412
413/// vnode access was revoked
414pub const NOTE_REVOKE = 0x00000040;
415
416/// No specific vnode event: to test for EVFILT_READ activation
417pub const NOTE_NONE = 0x00000080;
418
419/// vnode was unlocked by flock(2)
420pub const NOTE_FUNLOCK = 0x00000100;
421
422/// process exited
423pub const NOTE_EXIT = 0x80000000;
424
425/// process forked
426pub const NOTE_FORK = 0x40000000;
427
428/// process exec'd
429pub const NOTE_EXEC = 0x20000000;
430
431/// shared with EVFILT_SIGNAL
432pub const NOTE_SIGNAL = 0x08000000;
433
434/// exit status to be returned, valid for child process only
435pub const NOTE_EXITSTATUS = 0x04000000;
436
437/// provide details on reasons for exit
438pub const NOTE_EXIT_DETAIL = 0x02000000;
439
440/// mask for signal & exit status
441pub const NOTE_PDATAMASK = 0x000fffff;
442pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK);
443
444pub const NOTE_EXIT_DETAIL_MASK = 0x00070000;
445pub const NOTE_EXIT_DECRYPTFAIL = 0x00010000;
446pub const NOTE_EXIT_MEMORY = 0x00020000;
447pub const NOTE_EXIT_CSERROR = 0x00040000;
448
449/// will react on memory pressure
450pub const NOTE_VM_PRESSURE = 0x80000000;
451
452/// will quit on memory pressure, possibly after cleaning up dirty state
453pub const NOTE_VM_PRESSURE_TERMINATE = 0x40000000;
454
455/// will quit immediately on memory pressure
456pub const NOTE_VM_PRESSURE_SUDDEN_TERMINATE = 0x20000000;
457
458/// there was an error
459pub const NOTE_VM_ERROR = 0x10000000;
460
461/// data is seconds
462pub const NOTE_SECONDS = 0x00000001;
463
464/// data is microseconds
465pub const NOTE_USECONDS = 0x00000002;
466
467/// data is nanoseconds
468pub const NOTE_NSECONDS = 0x00000004;
469
470/// absolute timeout
471pub const NOTE_ABSOLUTE = 0x00000008;
472
473/// ext[1] holds leeway for power aware timers
474pub const NOTE_LEEWAY = 0x00000010;
475
476/// system does minimal timer coalescing
477pub const NOTE_CRITICAL = 0x00000020;
478
479/// system does maximum timer coalescing
480pub const NOTE_BACKGROUND = 0x00000040;
481pub const NOTE_MACH_CONTINUOUS_TIME = 0x00000080;
482
483/// data is mach absolute time units
484pub const NOTE_MACHTIME = 0x00000100;
485
486pub const AF_UNSPEC = 0;
487pub const AF_LOCAL = 1;
488pub const AF_UNIX = AF_LOCAL;
489pub const AF_INET = 2;
490pub const AF_SYS_CONTROL = 2;
491pub const AF_IMPLINK = 3;
492pub const AF_PUP = 4;
493pub const AF_CHAOS = 5;
494pub const AF_NS = 6;
495pub const AF_ISO = 7;
496pub const AF_OSI = AF_ISO;
497pub const AF_ECMA = 8;
498pub const AF_DATAKIT = 9;
499pub const AF_CCITT = 10;
500pub const AF_SNA = 11;
501pub const AF_DECnet = 12;
502pub const AF_DLI = 13;
503pub const AF_LAT = 14;
504pub const AF_HYLINK = 15;
505pub const AF_APPLETALK = 16;
506pub const AF_ROUTE = 17;
507pub const AF_LINK = 18;
508pub const AF_XTP = 19;
509pub const AF_COIP = 20;
510pub const AF_CNT = 21;
511pub const AF_RTIP = 22;
512pub const AF_IPX = 23;
513pub const AF_SIP = 24;
514pub const AF_PIP = 25;
515pub const AF_ISDN = 28;
516pub const AF_E164 = AF_ISDN;
517pub const AF_KEY = 29;
518pub const AF_INET6 = 30;
519pub const AF_NATM = 31;
520pub const AF_SYSTEM = 32;
521pub const AF_NETBIOS = 33;
522pub const AF_PPP = 34;
523pub const AF_MAX = 40;
524
525pub const PF_UNSPEC = AF_UNSPEC;
526pub const PF_LOCAL = AF_LOCAL;
527pub const PF_UNIX = PF_LOCAL;
528pub const PF_INET = AF_INET;
529pub const PF_IMPLINK = AF_IMPLINK;
530pub const PF_PUP = AF_PUP;
531pub const PF_CHAOS = AF_CHAOS;
532pub const PF_NS = AF_NS;
533pub const PF_ISO = AF_ISO;
534pub const PF_OSI = AF_ISO;
535pub const PF_ECMA = AF_ECMA;
536pub const PF_DATAKIT = AF_DATAKIT;
537pub const PF_CCITT = AF_CCITT;
538pub const PF_SNA = AF_SNA;
539pub const PF_DECnet = AF_DECnet;
540pub const PF_DLI = AF_DLI;
541pub const PF_LAT = AF_LAT;
542pub const PF_HYLINK = AF_HYLINK;
543pub const PF_APPLETALK = AF_APPLETALK;
544pub const PF_ROUTE = AF_ROUTE;
545pub const PF_LINK = AF_LINK;
546pub const PF_XTP = AF_XTP;
547pub const PF_COIP = AF_COIP;
548pub const PF_CNT = AF_CNT;
549pub const PF_SIP = AF_SIP;
550pub const PF_IPX = AF_IPX;
551pub const PF_RTIP = AF_RTIP;
552pub const PF_PIP = AF_PIP;
553pub const PF_ISDN = AF_ISDN;
554pub const PF_KEY = AF_KEY;
555pub const PF_INET6 = AF_INET6;
556pub const PF_NATM = AF_NATM;
557pub const PF_SYSTEM = AF_SYSTEM;
558pub const PF_NETBIOS = AF_NETBIOS;
559pub const PF_PPP = AF_PPP;
560pub const PF_MAX = AF_MAX;
561
562pub const SYSPROTO_EVENT = 1;
563pub const SYSPROTO_CONTROL = 2;
564
565pub const SOCK_STREAM = 1;
566pub const SOCK_DGRAM = 2;
567pub const SOCK_RAW = 3;
568pub const SOCK_RDM = 4;
569pub const SOCK_SEQPACKET = 5;
570pub const SOCK_MAXADDRLEN = 255;
571
572pub const IPPROTO_ICMP = 1;
573pub const IPPROTO_ICMPV6 = 58;
574pub const IPPROTO_TCP = 6;
575pub const IPPROTO_UDP = 17;
576pub const IPPROTO_IP = 0;
577pub const IPPROTO_IPV6 = 41;
578
579fn wstatus(x: i32) i32 {
580 return x & 0o177;
581}
582const wstopped = 0o177;
583pub fn WEXITSTATUS(x: i32) i32 {
584 return x >> 8;
585}
586pub fn WTERMSIG(x: i32) i32 {
587 return wstatus(x);
588}
589pub fn WSTOPSIG(x: i32) i32 {
590 return x >> 8;
591}
592pub fn WIFEXITED(x: i32) bool {
593 return wstatus(x) == 0;
594}
595pub fn WIFSTOPPED(x: i32) bool {
596 return wstatus(x) == wstopped and WSTOPSIG(x) != 0x13;
597}
598pub fn WIFSIGNALED(x: i32) bool {
599 return wstatus(x) != wstopped and wstatus(x) != 0;
600}
601
602/// Get the errno from a syscall return value, or 0 for no error.
603pub fn getErrno(r: usize) usize {
604 const signed_r = @bitCast(isize, r);
605 return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
606}
607
608pub fn close(fd: i32) usize {
609 return errnoWrap(c.close(fd));
610}
611
612pub fn abort() noreturn {
613 c.abort();
614}
615
616// bind(int socket, const struct sockaddr *address, socklen_t address_len)
617pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize {
618 return errnoWrap(c.bind(@bitCast(c_int, fd), addr, len));
619}
620
621pub fn exit(code: i32) noreturn {
622 c.exit(code);
623}
624
625pub fn isatty(fd: i32) bool {
626 return c.isatty(fd) != 0;
627}
628
629pub fn fstat(fd: i32, buf: *c.Stat) usize {
630 return errnoWrap(c.@"fstat$INODE64"(fd, buf));
631}
632
633pub fn lseek(fd: i32, offset: isize, whence: c_int) usize {
634 return errnoWrap(c.lseek(fd, offset, whence));
635}
636
637// TODO https://github.com/ziglang/zig/issues/265 on the whole file
638pub fn open(path: [*]const u8, flags: u32, mode: usize) usize {
639 return errnoWrap(c.open(path, @bitCast(c_int, flags), mode));
640}
641
642pub fn raise(sig: i32) usize {
643 return errnoWrap(c.raise(sig));
644}
645
646pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
647 return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte));
648}
649
650pub fn pread(fd: i32, buf: [*]u8, nbyte: usize, offset: u64) usize {
651 return errnoWrap(c.pread(fd, @ptrCast(*c_void, buf), nbyte, offset));
652}
653
654pub fn stat(noalias path: [*]const u8, noalias buf: *stat) usize {
655 return errnoWrap(c.stat(path, buf));
656}
657
658pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize {
659 return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte));
660}
661
662pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize {
663 return errnoWrap(c.pwrite(fd, @ptrCast(*const c_void, buf), nbyte, offset));
664}
665
666pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
667 const ptr_result = c.mmap(
668 @ptrCast(?*c_void, address),
669 length,
670 @bitCast(c_int, @intCast(c_uint, prot)),
671 @bitCast(c_int, c_uint(flags)),
672 fd,
673 offset,
674 );
675 const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
676 return errnoWrap(isize_result);
677}
678
679pub fn munmap(address: usize, length: usize) usize {
680 return errnoWrap(c.munmap(@intToPtr(?*c_void, address), length));
681}
682
683pub fn unlink(path: [*]const u8) usize {
684 return errnoWrap(c.unlink(path));
685}
686
687pub fn getcwd(buf: [*]u8, size: usize) usize {
688 return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
689}
690
691pub fn waitpid(pid: i32, status: *i32, options: u32) usize {
692 comptime assert(i32.bit_count == c_int.bit_count);
693 return errnoWrap(c.waitpid(pid, @ptrCast(*c_int, status), @bitCast(c_int, options)));
694}
695
696pub fn fork() usize {
697 return errnoWrap(c.fork());
698}
699
700pub fn access(path: [*]const u8, mode: u32) usize {
701 return errnoWrap(c.access(path, mode));
702}
703
704pub fn pipe(fds: *[2]i32) usize {
705 comptime assert(i32.bit_count == c_int.bit_count);
706 return errnoWrap(c.pipe(@ptrCast(*[2]c_int, fds)));
707}
708
709pub fn getdirentries64(fd: i32, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize {
710 return errnoWrap(@bitCast(isize, c.__getdirentries64(fd, buf_ptr, buf_len, basep)));
711}
712
713pub fn kqueue() usize {
714 return errnoWrap(c.kqueue());
715}
716
717pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize {
718 return errnoWrap(c.kevent(
719 kq,
720 changelist.ptr,
721 @intCast(c_int, changelist.len),
722 eventlist.ptr,
723 @intCast(c_int, eventlist.len),
724 timeout,
725 ));
726}
727
728pub fn kevent64(
729 kq: i32,
730 changelist: []const kevent64_s,
731 eventlist: []kevent64_s,
732 flags: u32,
733 timeout: ?*const timespec,
734) usize {
735 return errnoWrap(c.kevent64(kq, changelist.ptr, changelist.len, eventlist.ptr, eventlist.len, flags, timeout));
736}
737
738pub fn mkdir(path: [*]const u8, mode: u32) usize {
739 return errnoWrap(c.mkdir(path, mode));
740}
741
742pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
743 return errnoWrap(c.symlink(existing, new));
744}
745
746pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
747 return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen));
748}
749
750pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
751 return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen));
752}
753
754pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize {
755 return errnoWrap(c.sysctlnametomib(name, wibp, sizep));
756}
757
758pub fn rename(old: [*]const u8, new: [*]const u8) usize {
759 return errnoWrap(c.rename(old, new));
760}
761
762pub fn rmdir(path: [*]const u8) usize {
763 return errnoWrap(c.rmdir(path));
764}
765
766pub fn chdir(path: [*]const u8) usize {
767 return errnoWrap(c.chdir(path));
768}
769
770pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
771 return errnoWrap(c.execve(path, argv, envp));
772}
773
774pub fn dup2(old: i32, new: i32) usize {
775 return errnoWrap(c.dup2(old, new));
776}
777
778pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
779 return errnoWrap(c.readlink(path, buf_ptr, buf_len));
780}
781
782pub fn gettimeofday(tv: ?*timeval, tz: ?*timezone) usize {
783 return errnoWrap(c.gettimeofday(tv, tz));
784}
785
786pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
787 return errnoWrap(c.nanosleep(req, rem));
788}
789
790pub fn realpath(noalias filename: [*]const u8, noalias resolved_name: [*]u8) usize {
791 return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
792}
793
794pub fn setreuid(ruid: u32, euid: u32) usize {
795 return errnoWrap(c.setreuid(ruid, euid));
796}
797
798pub fn setregid(rgid: u32, egid: u32) usize {
799 return errnoWrap(c.setregid(rgid, egid));
800}
801
802pub fn sigprocmask(flags: u32, noalias set: *const sigset_t, noalias oldset: ?*sigset_t) usize {
803 return errnoWrap(c.sigprocmask(@bitCast(c_int, flags), set, oldset));
804}
805
806pub fn sigaction(sig: u5, noalias act: *const Sigaction, noalias oact: ?*Sigaction) usize {
807 assert(sig != SIGKILL);
808 assert(sig != SIGSTOP);
809 var cact = c.Sigaction{
810 .handler = @ptrCast(extern fn (c_int) void, act.handler),
811 .sa_flags = @bitCast(c_int, act.flags),
812 .sa_mask = act.mask,
813 };
814 var coact: c.Sigaction = undefined;
815 const result = errnoWrap(c.sigaction(sig, &cact, &coact));
816 if (result != 0) {
817 return result;
818 }
819 if (oact) |old| {
820 old.* = Sigaction{
821 .handler = @ptrCast(extern fn (i32) void, coact.handler),
822 .flags = @bitCast(u32, coact.sa_flags),
823 .mask = coact.sa_mask,
824 };
825 }
826 return result;
827}
828
829pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {
830 return errnoWrap(c.socket(@bitCast(c_int, domain), @bitCast(c_int, socket_type), @bitCast(c_int, protocol)));
831}
832
833pub const iovec = extern struct {
834 iov_base: [*]u8,
835 iov_len: usize,
836};6};
8377pub use std.c;
838pub const iovec_const = extern struct {
839 iov_base: [*]const u8,
840 iov_len: usize,
841};
842
843pub const sigset_t = c.sigset_t;
844pub const empty_sigset = sigset_t(0);
845
846pub const timespec = c.timespec;
847pub const Stat = c.Stat;
848pub const dirent = c.dirent;
849
850pub const in_port_t = c.in_port_t;
851pub const sa_family_t = c.sa_family_t;
852pub const socklen_t = c.socklen_t;
853
854pub const sockaddr = c.sockaddr;
855pub const sockaddr_in = c.sockaddr_in;
856pub const sockaddr_in6 = c.sockaddr_in6;
857
858/// Renamed from `kevent` to `Kevent` to avoid conflict with the syscall.
859pub const Kevent = c.Kevent;
860pub const kevent64_s = c.kevent64_s;
861
862/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
863pub const Sigaction = struct {
864 handler: extern fn (i32) void,
865 mask: sigset_t,
866 flags: u32,
867};
868
869pub fn sigaddset(set: *sigset_t, signo: u5) void {
870 set.* |= u32(1) << (signo - 1);
871}
872
873/// Takes the return value from a syscall and formats it back in the way
874/// that the kernel represents it to libc. Errno was a mistake, let's make
875/// it go away forever.
876fn errnoWrap(value: isize) usize {
877 return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
878}
879
880pub const timezone = c.timezone;
881pub const timeval = c.timeval;
882pub const mach_timebase_info_data = c.mach_timebase_info_data;
883
884pub const mach_absolute_time = c.mach_absolute_time;
885pub const mach_timebase_info = c.mach_timebase_info;
std/os/darwin/errno.zig deleted-328
...@@ -1,328 +0,0 @@
1/// Operation not permitted
2pub const EPERM = 1;
3
4/// No such file or directory
5pub const ENOENT = 2;
6
7/// No such process
8pub const ESRCH = 3;
9
10/// Interrupted system call
11pub const EINTR = 4;
12
13/// Input/output error
14pub const EIO = 5;
15
16/// Device not configured
17pub const ENXIO = 6;
18
19/// Argument list too long
20pub const E2BIG = 7;
21
22/// Exec format error
23pub const ENOEXEC = 8;
24
25/// Bad file descriptor
26pub const EBADF = 9;
27
28/// No child processes
29pub const ECHILD = 10;
30
31/// Resource deadlock avoided
32pub const EDEADLK = 11;
33
34/// Cannot allocate memory
35pub const ENOMEM = 12;
36
37/// Permission denied
38pub const EACCES = 13;
39
40/// Bad address
41pub const EFAULT = 14;
42
43/// Block device required
44pub const ENOTBLK = 15;
45
46/// Device / Resource busy
47pub const EBUSY = 16;
48
49/// File exists
50pub const EEXIST = 17;
51
52/// Cross-device link
53pub const EXDEV = 18;
54
55/// Operation not supported by device
56pub const ENODEV = 19;
57
58/// Not a directory
59pub const ENOTDIR = 20;
60
61/// Is a directory
62pub const EISDIR = 21;
63
64/// Invalid argument
65pub const EINVAL = 22;
66
67/// Too many open files in system
68pub const ENFILE = 23;
69
70/// Too many open files
71pub const EMFILE = 24;
72
73/// Inappropriate ioctl for device
74pub const ENOTTY = 25;
75
76/// Text file busy
77pub const ETXTBSY = 26;
78
79/// File too large
80pub const EFBIG = 27;
81
82/// No space left on device
83pub const ENOSPC = 28;
84
85/// Illegal seek
86pub const ESPIPE = 29;
87
88/// Read-only file system
89pub const EROFS = 30;
90
91/// Too many links
92pub const EMLINK = 31;
93/// Broken pipe
94
95// math software
96pub const EPIPE = 32;
97
98/// Numerical argument out of domain
99pub const EDOM = 33;
100/// Result too large
101
102// non-blocking and interrupt i/o
103pub const ERANGE = 34;
104
105/// Resource temporarily unavailable
106pub const EAGAIN = 35;
107
108/// Operation would block
109pub const EWOULDBLOCK = EAGAIN;
110
111/// Operation now in progress
112pub const EINPROGRESS = 36;
113/// Operation already in progress
114
115// ipc/network software -- argument errors
116pub const EALREADY = 37;
117
118/// Socket operation on non-socket
119pub const ENOTSOCK = 38;
120
121/// Destination address required
122pub const EDESTADDRREQ = 39;
123
124/// Message too long
125pub const EMSGSIZE = 40;
126
127/// Protocol wrong type for socket
128pub const EPROTOTYPE = 41;
129
130/// Protocol not available
131pub const ENOPROTOOPT = 42;
132
133/// Protocol not supported
134pub const EPROTONOSUPPORT = 43;
135
136/// Socket type not supported
137pub const ESOCKTNOSUPPORT = 44;
138
139/// Operation not supported
140pub const ENOTSUP = 45;
141
142/// Protocol family not supported
143pub const EPFNOSUPPORT = 46;
144
145/// Address family not supported by protocol family
146pub const EAFNOSUPPORT = 47;
147
148/// Address already in use
149pub const EADDRINUSE = 48;
150/// Can't assign requested address
151
152// ipc/network software -- operational errors
153pub const EADDRNOTAVAIL = 49;
154
155/// Network is down
156pub const ENETDOWN = 50;
157
158/// Network is unreachable
159pub const ENETUNREACH = 51;
160
161/// Network dropped connection on reset
162pub const ENETRESET = 52;
163
164/// Software caused connection abort
165pub const ECONNABORTED = 53;
166
167/// Connection reset by peer
168pub const ECONNRESET = 54;
169
170/// No buffer space available
171pub const ENOBUFS = 55;
172
173/// Socket is already connected
174pub const EISCONN = 56;
175
176/// Socket is not connected
177pub const ENOTCONN = 57;
178
179/// Can't send after socket shutdown
180pub const ESHUTDOWN = 58;
181
182/// Too many references: can't splice
183pub const ETOOMANYREFS = 59;
184
185/// Operation timed out
186pub const ETIMEDOUT = 60;
187
188/// Connection refused
189pub const ECONNREFUSED = 61;
190
191/// Too many levels of symbolic links
192pub const ELOOP = 62;
193
194/// File name too long
195pub const ENAMETOOLONG = 63;
196
197/// Host is down
198pub const EHOSTDOWN = 64;
199
200/// No route to host
201pub const EHOSTUNREACH = 65;
202/// Directory not empty
203
204// quotas & mush
205pub const ENOTEMPTY = 66;
206
207/// Too many processes
208pub const EPROCLIM = 67;
209
210/// Too many users
211pub const EUSERS = 68;
212/// Disc quota exceeded
213
214// Network File System
215pub const EDQUOT = 69;
216
217/// Stale NFS file handle
218pub const ESTALE = 70;
219
220/// Too many levels of remote in path
221pub const EREMOTE = 71;
222
223/// RPC struct is bad
224pub const EBADRPC = 72;
225
226/// RPC version wrong
227pub const ERPCMISMATCH = 73;
228
229/// RPC prog. not avail
230pub const EPROGUNAVAIL = 74;
231
232/// Program version wrong
233pub const EPROGMISMATCH = 75;
234
235/// Bad procedure for program
236pub const EPROCUNAVAIL = 76;
237
238/// No locks available
239pub const ENOLCK = 77;
240
241/// Function not implemented
242pub const ENOSYS = 78;
243
244/// Inappropriate file type or format
245pub const EFTYPE = 79;
246
247/// Authentication error
248pub const EAUTH = 80;
249/// Need authenticator
250
251// Intelligent device errors
252pub const ENEEDAUTH = 81;
253
254/// Device power is off
255pub const EPWROFF = 82;
256
257/// Device error, e.g. paper out
258pub const EDEVERR = 83;
259/// Value too large to be stored in data type
260
261// Program loading errors
262pub const EOVERFLOW = 84;
263
264/// Bad executable
265pub const EBADEXEC = 85;
266
267/// Bad CPU type in executable
268pub const EBADARCH = 86;
269
270/// Shared library version mismatch
271pub const ESHLIBVERS = 87;
272
273/// Malformed Macho file
274pub const EBADMACHO = 88;
275
276/// Operation canceled
277pub const ECANCELED = 89;
278
279/// Identifier removed
280pub const EIDRM = 90;
281
282/// No message of desired type
283pub const ENOMSG = 91;
284
285/// Illegal byte sequence
286pub const EILSEQ = 92;
287
288/// Attribute not found
289pub const ENOATTR = 93;
290
291/// Bad message
292pub const EBADMSG = 94;
293
294/// Reserved
295pub const EMULTIHOP = 95;
296
297/// No message available on STREAM
298pub const ENODATA = 96;
299
300/// Reserved
301pub const ENOLINK = 97;
302
303/// No STREAM resources
304pub const ENOSR = 98;
305
306/// Not a STREAM
307pub const ENOSTR = 99;
308
309/// Protocol error
310pub const EPROTO = 100;
311
312/// STREAM ioctl timeout
313pub const ETIME = 101;
314
315/// No such policy registered
316pub const ENOPOLICY = 103;
317
318/// State not recoverable
319pub const ENOTRECOVERABLE = 104;
320
321/// Previous owner died
322pub const EOWNERDEAD = 105;
323
324/// Interface output queue is full
325pub const EQFULL = 106;
326
327/// Must be equal largest errno
328pub const ELAST = 106;
std/os/epoch.zig deleted-26
...@@ -1,26 +0,0 @@
1/// Epoch reference times in terms of their difference from
2/// posix epoch in seconds.
3pub const posix = 0; //Jan 01, 1970 AD
4pub const dos = 315532800; //Jan 01, 1980 AD
5pub const ios = 978307200; //Jan 01, 2001 AD
6pub const openvms = -3506716800; //Nov 17, 1858 AD
7pub const zos = -2208988800; //Jan 01, 1900 AD
8pub const windows = -11644473600; //Jan 01, 1601 AD
9pub const amiga = 252460800; //Jan 01, 1978 AD
10pub const pickos = -63244800; //Dec 31, 1967 AD
11pub const gps = 315964800; //Jan 06, 1980 AD
12pub const clr = -62135769600; //Jan 01, 0001 AD
13
14pub const unix = posix;
15pub const android = posix;
16pub const os2 = dos;
17pub const bios = dos;
18pub const vfat = dos;
19pub const ntfs = windows;
20pub const ntp = zos;
21pub const jbase = pickos;
22pub const aros = amiga;
23pub const morphos = amiga;
24pub const brew = gps;
25pub const atsc = gps;
26pub const go = clr;
std/os/file.zig deleted-512
...@@ -1,512 +0,0 @@
1const std = @import("../std.zig");
2const builtin = @import("builtin");
3const os = std.os;
4const io = std.io;
5const mem = std.mem;
6const math = std.math;
7const assert = std.debug.assert;
8const posix = os.posix;
9const windows = os.windows;
10const Os = builtin.Os;
11const windows_util = @import("windows/util.zig");
12const maxInt = std.math.maxInt;
13
14const is_posix = builtin.os != builtin.Os.windows;
15const is_windows = builtin.os == builtin.Os.windows;
16
17pub const File = struct {
18 /// The OS-specific file descriptor or file handle.
19 handle: os.FileHandle,
20
21 pub const Mode = switch (builtin.os) {
22 Os.windows => void,
23 else => u32,
24 };
25
26 pub const default_mode = switch (builtin.os) {
27 Os.windows => {},
28 else => 0o666,
29 };
30
31 pub const OpenError = os.WindowsOpenError || os.PosixOpenError;
32
33 /// `openRead` except with a null terminated path
34 pub fn openReadC(path: [*]const u8) OpenError!File {
35 if (is_posix) {
36 const flags = posix.O_LARGEFILE | posix.O_RDONLY;
37 const fd = try os.posixOpenC(path, flags, 0);
38 return openHandle(fd);
39 }
40 if (is_windows) {
41 return openRead(mem.toSliceConst(u8, path));
42 }
43 @compileError("Unsupported OS");
44 }
45
46 /// Call close to clean up.
47 pub fn openRead(path: []const u8) OpenError!File {
48 if (is_posix) {
49 const path_c = try os.toPosixPath(path);
50 return openReadC(&path_c);
51 }
52 if (is_windows) {
53 const path_w = try windows_util.sliceToPrefixedFileW(path);
54 return openReadW(&path_w);
55 }
56 @compileError("Unsupported OS");
57 }
58
59 pub fn openReadW(path_w: [*]const u16) OpenError!File {
60 const handle = try os.windowsOpenW(
61 path_w,
62 windows.GENERIC_READ,
63 windows.FILE_SHARE_READ,
64 windows.OPEN_EXISTING,
65 windows.FILE_ATTRIBUTE_NORMAL,
66 );
67 return openHandle(handle);
68 }
69
70 /// Calls `openWriteMode` with os.File.default_mode for the mode.
71 pub fn openWrite(path: []const u8) OpenError!File {
72 return openWriteMode(path, os.File.default_mode);
73 }
74
75 /// If the path does not exist it will be created.
76 /// If a file already exists in the destination it will be truncated.
77 /// Call close to clean up.
78 pub fn openWriteMode(path: []const u8, file_mode: Mode) OpenError!File {
79 if (is_posix) {
80 const flags = posix.O_LARGEFILE | posix.O_WRONLY | posix.O_CREAT | posix.O_CLOEXEC | posix.O_TRUNC;
81 const fd = try os.posixOpen(path, flags, file_mode);
82 return openHandle(fd);
83 } else if (is_windows) {
84 const path_w = try windows_util.sliceToPrefixedFileW(path);
85 return openWriteModeW(&path_w, file_mode);
86 } else {
87 @compileError("TODO implement openWriteMode for this OS");
88 }
89 }
90
91 pub fn openWriteModeW(path_w: [*]const u16, file_mode: Mode) OpenError!File {
92 const handle = try os.windowsOpenW(
93 path_w,
94 windows.GENERIC_WRITE,
95 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
96 windows.CREATE_ALWAYS,
97 windows.FILE_ATTRIBUTE_NORMAL,
98 );
99 return openHandle(handle);
100 }
101
102 /// If the path does not exist it will be created.
103 /// If a file already exists in the destination this returns OpenError.PathAlreadyExists
104 /// Call close to clean up.
105 pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File {
106 if (is_posix) {
107 const path_c = try os.toPosixPath(path);
108 return openWriteNoClobberC(&path_c, file_mode);
109 } else if (is_windows) {
110 const path_w = try windows_util.sliceToPrefixedFileW(path);
111 return openWriteNoClobberW(&path_w, file_mode);
112 } else {
113 @compileError("TODO implement openWriteMode for this OS");
114 }
115 }
116
117 pub fn openWriteNoClobberC(path: [*]const u8, file_mode: Mode) OpenError!File {
118 if (is_posix) {
119 const flags = posix.O_LARGEFILE | posix.O_WRONLY | posix.O_CREAT | posix.O_CLOEXEC | posix.O_EXCL;
120 const fd = try os.posixOpenC(path, flags, file_mode);
121 return openHandle(fd);
122 } else if (is_windows) {
123 const path_w = try windows_util.cStrToPrefixedFileW(path);
124 return openWriteNoClobberW(&path_w, file_mode);
125 } else {
126 @compileError("TODO implement openWriteMode for this OS");
127 }
128 }
129
130 pub fn openWriteNoClobberW(path_w: [*]const u16, file_mode: Mode) OpenError!File {
131 const handle = try os.windowsOpenW(
132 path_w,
133 windows.GENERIC_WRITE,
134 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
135 windows.CREATE_NEW,
136 windows.FILE_ATTRIBUTE_NORMAL,
137 );
138 return openHandle(handle);
139 }
140
141 pub fn openHandle(handle: os.FileHandle) File {
142 return File{ .handle = handle };
143 }
144
145 pub const AccessError = error{
146 PermissionDenied,
147 FileNotFound,
148 NameTooLong,
149 InputOutput,
150 SystemResources,
151 BadPathName,
152
153 /// On Windows, file paths must be valid Unicode.
154 InvalidUtf8,
155
156 Unexpected,
157 };
158
159 /// Call from Windows-specific code if you already have a UTF-16LE encoded, null terminated string.
160 /// Otherwise use `access` or `accessC`.
161 pub fn accessW(path: [*]const u16) AccessError!void {
162 if (os.windows.GetFileAttributesW(path) != os.windows.INVALID_FILE_ATTRIBUTES) {
163 return;
164 }
165
166 const err = windows.GetLastError();
167 switch (err) {
168 windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
169 windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
170 windows.ERROR.ACCESS_DENIED => return error.PermissionDenied,
171 else => return os.unexpectedErrorWindows(err),
172 }
173 }
174
175 /// Call if you have a UTF-8 encoded, null-terminated string.
176 /// Otherwise use `access` or `accessW`.
177 pub fn accessC(path: [*]const u8) AccessError!void {
178 if (is_windows) {
179 const path_w = try windows_util.cStrToPrefixedFileW(path);
180 return accessW(&path_w);
181 }
182 if (is_posix) {
183 const result = posix.access(path, posix.F_OK);
184 const err = posix.getErrno(result);
185 switch (err) {
186 0 => return,
187 posix.EACCES => return error.PermissionDenied,
188 posix.EROFS => return error.PermissionDenied,
189 posix.ELOOP => return error.PermissionDenied,
190 posix.ETXTBSY => return error.PermissionDenied,
191 posix.ENOTDIR => return error.FileNotFound,
192 posix.ENOENT => return error.FileNotFound,
193
194 posix.ENAMETOOLONG => return error.NameTooLong,
195 posix.EINVAL => unreachable,
196 posix.EFAULT => unreachable,
197 posix.EIO => return error.InputOutput,
198 posix.ENOMEM => return error.SystemResources,
199 else => return os.unexpectedErrorPosix(err),
200 }
201 }
202 @compileError("Unsupported OS");
203 }
204
205 pub fn access(path: []const u8) AccessError!void {
206 if (is_windows) {
207 const path_w = try windows_util.sliceToPrefixedFileW(path);
208 return accessW(&path_w);
209 }
210 if (is_posix) {
211 var path_with_null: [posix.PATH_MAX]u8 = undefined;
212 if (path.len >= posix.PATH_MAX) return error.NameTooLong;
213 mem.copy(u8, path_with_null[0..], path);
214 path_with_null[path.len] = 0;
215 return accessC(&path_with_null);
216 }
217 @compileError("Unsupported OS");
218 }
219
220 /// Upon success, the stream is in an uninitialized state. To continue using it,
221 /// you must use the open() function.
222 pub fn close(self: File) void {
223 os.close(self.handle);
224 }
225
226 /// Calls `os.isTty` on `self.handle`.
227 pub fn isTty(self: File) bool {
228 return os.isTty(self.handle);
229 }
230
231 pub const SeekError = error{
232 /// TODO make this error impossible to get
233 Overflow,
234 Unseekable,
235 Unexpected,
236 };
237
238 pub fn seekForward(self: File, amount: i64) SeekError!void {
239 switch (builtin.os) {
240 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
241 const iamount = try math.cast(isize, amount);
242 const result = posix.lseek(self.handle, iamount, posix.SEEK_CUR);
243 const err = posix.getErrno(result);
244 if (err > 0) {
245 return switch (err) {
246 // We do not make this an error code because if you get EBADF it's always a bug,
247 // since the fd could have been reused.
248 posix.EBADF => unreachable,
249 posix.EINVAL => error.Unseekable,
250 posix.EOVERFLOW => error.Unseekable,
251 posix.ESPIPE => error.Unseekable,
252 posix.ENXIO => error.Unseekable,
253 else => os.unexpectedErrorPosix(err),
254 };
255 }
256 },
257 Os.windows => {
258 if (windows.SetFilePointerEx(self.handle, amount, null, windows.FILE_CURRENT) == 0) {
259 const err = windows.GetLastError();
260 return switch (err) {
261 windows.ERROR.INVALID_PARAMETER => unreachable,
262 else => os.unexpectedErrorWindows(err),
263 };
264 }
265 },
266 else => @compileError("unsupported OS"),
267 }
268 }
269
270 pub fn seekTo(self: File, pos: u64) SeekError!void {
271 switch (builtin.os) {
272 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
273 const ipos = try math.cast(isize, pos);
274 const result = posix.lseek(self.handle, ipos, posix.SEEK_SET);
275 const err = posix.getErrno(result);
276 if (err > 0) {
277 return switch (err) {
278 // We do not make this an error code because if you get EBADF it's always a bug,
279 // since the fd could have been reused.
280 posix.EBADF => unreachable,
281 posix.EINVAL => error.Unseekable,
282 posix.EOVERFLOW => error.Unseekable,
283 posix.ESPIPE => error.Unseekable,
284 posix.ENXIO => error.Unseekable,
285 else => os.unexpectedErrorPosix(err),
286 };
287 }
288 },
289 Os.windows => {
290 const ipos = try math.cast(isize, pos);
291 if (windows.SetFilePointerEx(self.handle, ipos, null, windows.FILE_BEGIN) == 0) {
292 const err = windows.GetLastError();
293 return switch (err) {
294 windows.ERROR.INVALID_PARAMETER => unreachable,
295 windows.ERROR.INVALID_HANDLE => unreachable,
296 else => os.unexpectedErrorWindows(err),
297 };
298 }
299 },
300 else => @compileError("unsupported OS: " ++ @tagName(builtin.os)),
301 }
302 }
303
304 pub const GetSeekPosError = error{
305 SystemResources,
306 Unseekable,
307 Unexpected,
308 };
309
310 pub fn getPos(self: File) GetSeekPosError!u64 {
311 switch (builtin.os) {
312 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
313 const result = posix.lseek(self.handle, 0, posix.SEEK_CUR);
314 const err = posix.getErrno(result);
315 if (err > 0) {
316 return switch (err) {
317 // We do not make this an error code because if you get EBADF it's always a bug,
318 // since the fd could have been reused.
319 posix.EBADF => unreachable,
320 posix.EINVAL => error.Unseekable,
321 posix.EOVERFLOW => error.Unseekable,
322 posix.ESPIPE => error.Unseekable,
323 posix.ENXIO => error.Unseekable,
324 else => os.unexpectedErrorPosix(err),
325 };
326 }
327 return u64(result);
328 },
329 Os.windows => {
330 var pos: windows.LARGE_INTEGER = undefined;
331 if (windows.SetFilePointerEx(self.handle, 0, &pos, windows.FILE_CURRENT) == 0) {
332 const err = windows.GetLastError();
333 return switch (err) {
334 windows.ERROR.INVALID_PARAMETER => unreachable,
335 else => os.unexpectedErrorWindows(err),
336 };
337 }
338
339 return @intCast(u64, pos);
340 },
341 else => @compileError("unsupported OS"),
342 }
343 }
344
345 pub fn getEndPos(self: File) GetSeekPosError!u64 {
346 if (is_posix) {
347 const stat = try os.posixFStat(self.handle);
348 return @intCast(u64, stat.size);
349 } else if (is_windows) {
350 var file_size: windows.LARGE_INTEGER = undefined;
351 if (windows.GetFileSizeEx(self.handle, &file_size) == 0) {
352 const err = windows.GetLastError();
353 return switch (err) {
354 else => os.unexpectedErrorWindows(err),
355 };
356 }
357 return @intCast(u64, file_size);
358 } else {
359 @compileError("TODO support getEndPos on this OS");
360 }
361 }
362
363 pub const ModeError = error{
364 SystemResources,
365 Unexpected,
366 };
367
368 pub fn mode(self: File) ModeError!Mode {
369 if (is_posix) {
370 var stat: posix.Stat = undefined;
371 const err = posix.getErrno(posix.fstat(self.handle, &stat));
372 if (err > 0) {
373 return switch (err) {
374 // We do not make this an error code because if you get EBADF it's always a bug,
375 // since the fd could have been reused.
376 posix.EBADF => unreachable,
377 posix.ENOMEM => error.SystemResources,
378 else => os.unexpectedErrorPosix(err),
379 };
380 }
381
382 // TODO: we should be able to cast u16 to ModeError!u32, making this
383 // explicit cast not necessary
384 return Mode(stat.mode);
385 } else if (is_windows) {
386 return {};
387 } else {
388 @compileError("TODO support file mode on this OS");
389 }
390 }
391
392 pub const ReadError = os.WindowsReadError || os.PosixReadError;
393
394 pub fn read(self: File, buffer: []u8) ReadError!usize {
395 if (is_posix) {
396 return os.posixRead(self.handle, buffer);
397 } else if (is_windows) {
398 var index: usize = 0;
399 while (index < buffer.len) {
400 const want_read_count = @intCast(windows.DWORD, math.min(windows.DWORD(maxInt(windows.DWORD)), buffer.len - index));
401 var amt_read: windows.DWORD = undefined;
402 if (windows.ReadFile(self.handle, buffer.ptr + index, want_read_count, &amt_read, null) == 0) {
403 const err = windows.GetLastError();
404 return switch (err) {
405 windows.ERROR.OPERATION_ABORTED => continue,
406 windows.ERROR.BROKEN_PIPE => return index,
407 else => os.unexpectedErrorWindows(err),
408 };
409 }
410 if (amt_read == 0) return index;
411 index += amt_read;
412 }
413 return index;
414 } else {
415 @compileError("Unsupported OS");
416 }
417 }
418
419 pub const WriteError = os.WindowsWriteError || os.PosixWriteError;
420
421 pub fn write(self: File, bytes: []const u8) WriteError!void {
422 if (is_posix) {
423 try os.posixWrite(self.handle, bytes);
424 } else if (is_windows) {
425 try os.windowsWrite(self.handle, bytes);
426 } else {
427 @compileError("Unsupported OS");
428 }
429 }
430
431 pub fn inStream(file: File) InStream {
432 return InStream{
433 .file = file,
434 .stream = InStream.Stream{ .readFn = InStream.readFn },
435 };
436 }
437
438 pub fn outStream(file: File) OutStream {
439 return OutStream{
440 .file = file,
441 .stream = OutStream.Stream{ .writeFn = OutStream.writeFn },
442 };
443 }
444
445 pub fn seekableStream(file: File) SeekableStream {
446 return SeekableStream{
447 .file = file,
448 .stream = SeekableStream.Stream{
449 .seekToFn = SeekableStream.seekToFn,
450 .seekForwardFn = SeekableStream.seekForwardFn,
451 .getPosFn = SeekableStream.getPosFn,
452 .getEndPosFn = SeekableStream.getEndPosFn,
453 },
454 };
455 }
456
457 /// Implementation of io.InStream trait for File
458 pub const InStream = struct {
459 file: File,
460 stream: Stream,
461
462 pub const Error = ReadError;
463 pub const Stream = io.InStream(Error);
464
465 fn readFn(in_stream: *Stream, buffer: []u8) Error!usize {
466 const self = @fieldParentPtr(InStream, "stream", in_stream);
467 return self.file.read(buffer);
468 }
469 };
470
471 /// Implementation of io.OutStream trait for File
472 pub const OutStream = struct {
473 file: File,
474 stream: Stream,
475
476 pub const Error = WriteError;
477 pub const Stream = io.OutStream(Error);
478
479 fn writeFn(out_stream: *Stream, bytes: []const u8) Error!void {
480 const self = @fieldParentPtr(OutStream, "stream", out_stream);
481 return self.file.write(bytes);
482 }
483 };
484
485 /// Implementation of io.SeekableStream trait for File
486 pub const SeekableStream = struct {
487 file: File,
488 stream: Stream,
489
490 pub const Stream = io.SeekableStream(SeekError, GetSeekPosError);
491
492 pub fn seekToFn(seekable_stream: *Stream, pos: u64) SeekError!void {
493 const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
494 return self.file.seekTo(pos);
495 }
496
497 pub fn seekForwardFn(seekable_stream: *Stream, amt: i64) SeekError!void {
498 const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
499 return self.file.seekForward(amt);
500 }
501
502 pub fn getEndPosFn(seekable_stream: *Stream) GetSeekPosError!u64 {
503 const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
504 return self.file.getEndPos();
505 }
506
507 pub fn getPosFn(seekable_stream: *Stream) GetSeekPosError!u64 {
508 const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
509 return self.file.getPos();
510 }
511 };
512};
std/os/freebsd.zig+3-844
...@@ -1,845 +1,4 @@...@@ -1,845 +1,4 @@
1const builtin = @import("builtin");
2
3pub use @import("freebsd/errno.zig");
4
5const std = @import("../std.zig");1const std = @import("../std.zig");
6const c = std.c;2const builtin = @import("builtin");
73pub const is_the_target = builtin.os == .freebsd;
8const assert = std.debug.assert;4pub use std.c;
9const maxInt = std.math.maxInt;
10pub const Kevent = c.Kevent;
11
12pub const CTL_KERN = 1;
13pub const CTL_DEBUG = 5;
14
15pub const KERN_PROC = 14; // struct: process entries
16pub const KERN_PROC_PATHNAME = 12; // path to executable
17
18pub const PATH_MAX = 1024;
19
20pub const STDIN_FILENO = 0;
21pub const STDOUT_FILENO = 1;
22pub const STDERR_FILENO = 2;
23
24pub const PROT_NONE = 0;
25pub const PROT_READ = 1;
26pub const PROT_WRITE = 2;
27pub const PROT_EXEC = 4;
28
29pub const CLOCK_REALTIME = 0;
30pub const CLOCK_VIRTUAL = 1;
31pub const CLOCK_PROF = 2;
32pub const CLOCK_MONOTONIC = 4;
33pub const CLOCK_UPTIME = 5;
34pub const CLOCK_UPTIME_PRECISE = 7;
35pub const CLOCK_UPTIME_FAST = 8;
36pub const CLOCK_REALTIME_PRECISE = 9;
37pub const CLOCK_REALTIME_FAST = 10;
38pub const CLOCK_MONOTONIC_PRECISE = 11;
39pub const CLOCK_MONOTONIC_FAST = 12;
40pub const CLOCK_SECOND = 13;
41pub const CLOCK_THREAD_CPUTIME_ID = 14;
42pub const CLOCK_PROCESS_CPUTIME_ID = 15;
43
44pub const MAP_FAILED = maxInt(usize);
45pub const MAP_SHARED = 0x0001;
46pub const MAP_PRIVATE = 0x0002;
47pub const MAP_FIXED = 0x0010;
48pub const MAP_STACK = 0x0400;
49pub const MAP_NOSYNC = 0x0800;
50pub const MAP_ANON = 0x1000;
51pub const MAP_ANONYMOUS = MAP_ANON;
52pub const MAP_FILE = 0;
53pub const MAP_NORESERVE = 0;
54
55pub const MAP_GUARD = 0x00002000;
56pub const MAP_EXCL = 0x00004000;
57pub const MAP_NOCORE = 0x00020000;
58pub const MAP_PREFAULT_READ = 0x00040000;
59pub const MAP_32BIT = 0x00080000;
60
61pub const WNOHANG = 1;
62pub const WUNTRACED = 2;
63pub const WSTOPPED = WUNTRACED;
64pub const WCONTINUED = 4;
65pub const WNOWAIT = 8;
66pub const WEXITED = 16;
67pub const WTRAPPED = 32;
68
69pub const SA_ONSTACK = 0x0001;
70pub const SA_RESTART = 0x0002;
71pub const SA_RESETHAND = 0x0004;
72pub const SA_NOCLDSTOP = 0x0008;
73pub const SA_NODEFER = 0x0010;
74pub const SA_NOCLDWAIT = 0x0020;
75pub const SA_SIGINFO = 0x0040;
76
77pub const SIGHUP = 1;
78pub const SIGINT = 2;
79pub const SIGQUIT = 3;
80pub const SIGILL = 4;
81pub const SIGTRAP = 5;
82pub const SIGABRT = 6;
83pub const SIGIOT = SIGABRT;
84pub const SIGEMT = 7;
85pub const SIGFPE = 8;
86pub const SIGKILL = 9;
87pub const SIGBUS = 10;
88pub const SIGSEGV = 11;
89pub const SIGSYS = 12;
90pub const SIGPIPE = 13;
91pub const SIGALRM = 14;
92pub const SIGTERM = 15;
93pub const SIGURG = 16;
94pub const SIGSTOP = 17;
95pub const SIGTSTP = 18;
96pub const SIGCONT = 19;
97pub const SIGCHLD = 20;
98pub const SIGTTIN = 21;
99pub const SIGTTOU = 22;
100pub const SIGIO = 23;
101pub const SIGXCPU = 24;
102pub const SIGXFSZ = 25;
103pub const SIGVTALRM = 26;
104pub const SIGPROF = 27;
105pub const SIGWINCH = 28;
106pub const SIGINFO = 29;
107pub const SIGUSR1 = 30;
108pub const SIGUSR2 = 31;
109pub const SIGTHR = 32;
110pub const SIGLWP = SIGTHR;
111pub const SIGLIBRT = 33;
112
113pub const SIGRTMIN = 65;
114pub const SIGRTMAX = 126;
115
116// access function
117pub const F_OK = 0; // test for existence of file
118pub const X_OK = 1; // test for execute or search permission
119pub const W_OK = 2; // test for write permission
120pub const R_OK = 4; // test for read permission
121
122pub const O_RDONLY = 0x0000;
123pub const O_WRONLY = 0x0001;
124pub const O_RDWR = 0x0002;
125pub const O_ACCMODE = 0x0003;
126
127pub const O_CREAT = 0x0200;
128pub const O_EXCL = 0x0800;
129pub const O_NOCTTY = 0x8000;
130pub const O_TRUNC = 0x0400;
131pub const O_APPEND = 0x0008;
132pub const O_NONBLOCK = 0x0004;
133pub const O_DSYNC = 0o10000;
134pub const O_SYNC = 0x0080;
135pub const O_RSYNC = 0o4010000;
136pub const O_DIRECTORY = 0o200000;
137pub const O_NOFOLLOW = 0x0100;
138pub const O_CLOEXEC = 0x00100000;
139
140pub const O_ASYNC = 0x0040;
141pub const O_DIRECT = 0x00010000;
142pub const O_LARGEFILE = 0;
143pub const O_NOATIME = 0o1000000;
144pub const O_PATH = 0o10000000;
145pub const O_TMPFILE = 0o20200000;
146pub const O_NDELAY = O_NONBLOCK;
147
148pub const F_DUPFD = 0;
149pub const F_GETFD = 1;
150pub const F_SETFD = 2;
151pub const F_GETFL = 3;
152pub const F_SETFL = 4;
153
154pub const F_SETOWN = 8;
155pub const F_GETOWN = 9;
156pub const F_SETSIG = 10;
157pub const F_GETSIG = 11;
158
159pub const F_GETLK = 5;
160pub const F_SETLK = 6;
161pub const F_SETLKW = 7;
162
163pub const F_SETOWN_EX = 15;
164pub const F_GETOWN_EX = 16;
165
166pub const F_GETOWNER_UIDS = 17;
167
168pub const SEEK_SET = 0;
169pub const SEEK_CUR = 1;
170pub const SEEK_END = 2;
171
172pub const SIG_BLOCK = 1;
173pub const SIG_UNBLOCK = 2;
174pub const SIG_SETMASK = 3;
175
176pub const SOCK_STREAM = 1;
177pub const SOCK_DGRAM = 2;
178pub const SOCK_RAW = 3;
179pub const SOCK_RDM = 4;
180pub const SOCK_SEQPACKET = 5;
181
182pub const SOCK_CLOEXEC = 0x10000000;
183pub const SOCK_NONBLOCK = 0x20000000;
184
185pub const PROTO_ip = 0o000;
186pub const PROTO_icmp = 0o001;
187pub const PROTO_igmp = 0o002;
188pub const PROTO_ggp = 0o003;
189pub const PROTO_ipencap = 0o004;
190pub const PROTO_st = 0o005;
191pub const PROTO_tcp = 0o006;
192pub const PROTO_egp = 0o010;
193pub const PROTO_pup = 0o014;
194pub const PROTO_udp = 0o021;
195pub const PROTO_hmp = 0o024;
196pub const PROTO_xns_idp = 0o026;
197pub const PROTO_rdp = 0o033;
198pub const PROTO_iso_tp4 = 0o035;
199pub const PROTO_xtp = 0o044;
200pub const PROTO_ddp = 0o045;
201pub const PROTO_idpr_cmtp = 0o046;
202pub const PROTO_ipv6 = 0o051;
203pub const PROTO_ipv6_route = 0o053;
204pub const PROTO_ipv6_frag = 0o054;
205pub const PROTO_idrp = 0o055;
206pub const PROTO_rsvp = 0o056;
207pub const PROTO_gre = 0o057;
208pub const PROTO_esp = 0o062;
209pub const PROTO_ah = 0o063;
210pub const PROTO_skip = 0o071;
211pub const PROTO_ipv6_icmp = 0o072;
212pub const PROTO_ipv6_nonxt = 0o073;
213pub const PROTO_ipv6_opts = 0o074;
214pub const PROTO_rspf = 0o111;
215pub const PROTO_vmtp = 0o121;
216pub const PROTO_ospf = 0o131;
217pub const PROTO_ipip = 0o136;
218pub const PROTO_encap = 0o142;
219pub const PROTO_pim = 0o147;
220pub const PROTO_raw = 0o377;
221
222pub const PF_UNSPEC = 0;
223pub const PF_LOCAL = 1;
224pub const PF_UNIX = PF_LOCAL;
225pub const PF_FILE = PF_LOCAL;
226pub const PF_INET = 2;
227pub const PF_AX25 = 3;
228pub const PF_IPX = 4;
229pub const PF_APPLETALK = 5;
230pub const PF_NETROM = 6;
231pub const PF_BRIDGE = 7;
232pub const PF_ATMPVC = 8;
233pub const PF_X25 = 9;
234pub const PF_INET6 = 10;
235pub const PF_ROSE = 11;
236pub const PF_DECnet = 12;
237pub const PF_NETBEUI = 13;
238pub const PF_SECURITY = 14;
239pub const PF_KEY = 15;
240pub const PF_NETLINK = 16;
241pub const PF_ROUTE = PF_NETLINK;
242pub const PF_PACKET = 17;
243pub const PF_ASH = 18;
244pub const PF_ECONET = 19;
245pub const PF_ATMSVC = 20;
246pub const PF_RDS = 21;
247pub const PF_SNA = 22;
248pub const PF_IRDA = 23;
249pub const PF_PPPOX = 24;
250pub const PF_WANPIPE = 25;
251pub const PF_LLC = 26;
252pub const PF_IB = 27;
253pub const PF_MPLS = 28;
254pub const PF_CAN = 29;
255pub const PF_TIPC = 30;
256pub const PF_BLUETOOTH = 31;
257pub const PF_IUCV = 32;
258pub const PF_RXRPC = 33;
259pub const PF_ISDN = 34;
260pub const PF_PHONET = 35;
261pub const PF_IEEE802154 = 36;
262pub const PF_CAIF = 37;
263pub const PF_ALG = 38;
264pub const PF_NFC = 39;
265pub const PF_VSOCK = 40;
266pub const PF_MAX = 41;
267
268pub const AF_UNSPEC = PF_UNSPEC;
269pub const AF_LOCAL = PF_LOCAL;
270pub const AF_UNIX = AF_LOCAL;
271pub const AF_FILE = AF_LOCAL;
272pub const AF_INET = PF_INET;
273pub const AF_AX25 = PF_AX25;
274pub const AF_IPX = PF_IPX;
275pub const AF_APPLETALK = PF_APPLETALK;
276pub const AF_NETROM = PF_NETROM;
277pub const AF_BRIDGE = PF_BRIDGE;
278pub const AF_ATMPVC = PF_ATMPVC;
279pub const AF_X25 = PF_X25;
280pub const AF_INET6 = PF_INET6;
281pub const AF_ROSE = PF_ROSE;
282pub const AF_DECnet = PF_DECnet;
283pub const AF_NETBEUI = PF_NETBEUI;
284pub const AF_SECURITY = PF_SECURITY;
285pub const AF_KEY = PF_KEY;
286pub const AF_NETLINK = PF_NETLINK;
287pub const AF_ROUTE = PF_ROUTE;
288pub const AF_PACKET = PF_PACKET;
289pub const AF_ASH = PF_ASH;
290pub const AF_ECONET = PF_ECONET;
291pub const AF_ATMSVC = PF_ATMSVC;
292pub const AF_RDS = PF_RDS;
293pub const AF_SNA = PF_SNA;
294pub const AF_IRDA = PF_IRDA;
295pub const AF_PPPOX = PF_PPPOX;
296pub const AF_WANPIPE = PF_WANPIPE;
297pub const AF_LLC = PF_LLC;
298pub const AF_IB = PF_IB;
299pub const AF_MPLS = PF_MPLS;
300pub const AF_CAN = PF_CAN;
301pub const AF_TIPC = PF_TIPC;
302pub const AF_BLUETOOTH = PF_BLUETOOTH;
303pub const AF_IUCV = PF_IUCV;
304pub const AF_RXRPC = PF_RXRPC;
305pub const AF_ISDN = PF_ISDN;
306pub const AF_PHONET = PF_PHONET;
307pub const AF_IEEE802154 = PF_IEEE802154;
308pub const AF_CAIF = PF_CAIF;
309pub const AF_ALG = PF_ALG;
310pub const AF_NFC = PF_NFC;
311pub const AF_VSOCK = PF_VSOCK;
312pub const AF_MAX = PF_MAX;
313
314pub const DT_UNKNOWN = 0;
315pub const DT_FIFO = 1;
316pub const DT_CHR = 2;
317pub const DT_DIR = 4;
318pub const DT_BLK = 6;
319pub const DT_REG = 8;
320pub const DT_LNK = 10;
321pub const DT_SOCK = 12;
322pub const DT_WHT = 14;
323
324/// add event to kq (implies enable)
325pub const EV_ADD = 0x0001;
326
327/// delete event from kq
328pub const EV_DELETE = 0x0002;
329
330/// enable event
331pub const EV_ENABLE = 0x0004;
332
333/// disable event (not reported)
334pub const EV_DISABLE = 0x0008;
335
336/// only report one occurrence
337pub const EV_ONESHOT = 0x0010;
338
339/// clear event state after reporting
340pub const EV_CLEAR = 0x0020;
341
342/// force immediate event output
343/// ... with or without EV_ERROR
344/// ... use KEVENT_FLAG_ERROR_EVENTS
345/// on syscalls supporting flags
346pub const EV_RECEIPT = 0x0040;
347
348/// disable event after reporting
349pub const EV_DISPATCH = 0x0080;
350
351pub const EVFILT_READ = -1;
352pub const EVFILT_WRITE = -2;
353
354/// attached to aio requests
355pub const EVFILT_AIO = -3;
356
357/// attached to vnodes
358pub const EVFILT_VNODE = -4;
359
360/// attached to struct proc
361pub const EVFILT_PROC = -5;
362
363/// attached to struct proc
364pub const EVFILT_SIGNAL = -6;
365
366/// timers
367pub const EVFILT_TIMER = -7;
368
369/// Process descriptors
370pub const EVFILT_PROCDESC = -8;
371
372/// Filesystem events
373pub const EVFILT_FS = -9;
374
375pub const EVFILT_LIO = -10;
376
377/// User events
378pub const EVFILT_USER = -11;
379
380/// Sendfile events
381pub const EVFILT_SENDFILE = -12;
382
383pub const EVFILT_EMPTY = -13;
384
385/// On input, NOTE_TRIGGER causes the event to be triggered for output.
386pub const NOTE_TRIGGER = 0x01000000;
387
388/// ignore input fflags
389pub const NOTE_FFNOP = 0x00000000;
390
391/// and fflags
392pub const NOTE_FFAND = 0x40000000;
393
394/// or fflags
395pub const NOTE_FFOR = 0x80000000;
396
397/// copy fflags
398pub const NOTE_FFCOPY = 0xc0000000;
399
400/// mask for operations
401pub const NOTE_FFCTRLMASK = 0xc0000000;
402pub const NOTE_FFLAGSMASK = 0x00ffffff;
403
404/// low water mark
405pub const NOTE_LOWAT = 0x00000001;
406
407/// behave like poll()
408pub const NOTE_FILE_POLL = 0x00000002;
409
410/// vnode was removed
411pub const NOTE_DELETE = 0x00000001;
412
413/// data contents changed
414pub const NOTE_WRITE = 0x00000002;
415
416/// size increased
417pub const NOTE_EXTEND = 0x00000004;
418
419/// attributes changed
420pub const NOTE_ATTRIB = 0x00000008;
421
422/// link count changed
423pub const NOTE_LINK = 0x00000010;
424
425/// vnode was renamed
426pub const NOTE_RENAME = 0x00000020;
427
428/// vnode access was revoked
429pub const NOTE_REVOKE = 0x00000040;
430
431/// vnode was opened
432pub const NOTE_OPEN = 0x00000080;
433
434/// file closed, fd did not allow write
435pub const NOTE_CLOSE = 0x00000100;
436
437/// file closed, fd did allow write
438pub const NOTE_CLOSE_WRITE = 0x00000200;
439
440/// file was read
441pub const NOTE_READ = 0x00000400;
442
443/// process exited
444pub const NOTE_EXIT = 0x80000000;
445
446/// process forked
447pub const NOTE_FORK = 0x40000000;
448
449/// process exec'd
450pub const NOTE_EXEC = 0x20000000;
451
452/// mask for signal & exit status
453pub const NOTE_PDATAMASK = 0x000fffff;
454pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK);
455
456/// data is seconds
457pub const NOTE_SECONDS = 0x00000001;
458
459/// data is milliseconds
460pub const NOTE_MSECONDS = 0x00000002;
461
462/// data is microseconds
463pub const NOTE_USECONDS = 0x00000004;
464
465/// data is nanoseconds
466pub const NOTE_NSECONDS = 0x00000008;
467
468/// timeout is absolute
469pub const NOTE_ABSTIME = 0x00000010;
470
471pub const TCGETS = 0x5401;
472pub const TCSETS = 0x5402;
473pub const TCSETSW = 0x5403;
474pub const TCSETSF = 0x5404;
475pub const TCGETA = 0x5405;
476pub const TCSETA = 0x5406;
477pub const TCSETAW = 0x5407;
478pub const TCSETAF = 0x5408;
479pub const TCSBRK = 0x5409;
480pub const TCXONC = 0x540A;
481pub const TCFLSH = 0x540B;
482pub const TIOCEXCL = 0x540C;
483pub const TIOCNXCL = 0x540D;
484pub const TIOCSCTTY = 0x540E;
485pub const TIOCGPGRP = 0x540F;
486pub const TIOCSPGRP = 0x5410;
487pub const TIOCOUTQ = 0x5411;
488pub const TIOCSTI = 0x5412;
489pub const TIOCGWINSZ = 0x5413;
490pub const TIOCSWINSZ = 0x5414;
491pub const TIOCMGET = 0x5415;
492pub const TIOCMBIS = 0x5416;
493pub const TIOCMBIC = 0x5417;
494pub const TIOCMSET = 0x5418;
495pub const TIOCGSOFTCAR = 0x5419;
496pub const TIOCSSOFTCAR = 0x541A;
497pub const FIONREAD = 0x541B;
498pub const TIOCINQ = FIONREAD;
499pub const TIOCLINUX = 0x541C;
500pub const TIOCCONS = 0x541D;
501pub const TIOCGSERIAL = 0x541E;
502pub const TIOCSSERIAL = 0x541F;
503pub const TIOCPKT = 0x5420;
504pub const FIONBIO = 0x5421;
505pub const TIOCNOTTY = 0x5422;
506pub const TIOCSETD = 0x5423;
507pub const TIOCGETD = 0x5424;
508pub const TCSBRKP = 0x5425;
509pub const TIOCSBRK = 0x5427;
510pub const TIOCCBRK = 0x5428;
511pub const TIOCGSID = 0x5429;
512pub const TIOCGRS485 = 0x542E;
513pub const TIOCSRS485 = 0x542F;
514pub const TIOCGPTN = 0x80045430;
515pub const TIOCSPTLCK = 0x40045431;
516pub const TIOCGDEV = 0x80045432;
517pub const TCGETX = 0x5432;
518pub const TCSETX = 0x5433;
519pub const TCSETXF = 0x5434;
520pub const TCSETXW = 0x5435;
521pub const TIOCSIG = 0x40045436;
522pub const TIOCVHANGUP = 0x5437;
523pub const TIOCGPKT = 0x80045438;
524pub const TIOCGPTLCK = 0x80045439;
525pub const TIOCGEXCL = 0x80045440;
526
527pub const sockaddr = c.sockaddr;
528pub const sockaddr_in = c.sockaddr_in;
529pub const sockaddr_in6 = c.sockaddr_in6;
530
531fn unsigned(s: i32) u32 {
532 return @bitCast(u32, s);
533}
534fn signed(s: u32) i32 {
535 return @bitCast(i32, s);
536}
537pub fn WEXITSTATUS(s: i32) i32 {
538 return signed((unsigned(s) & 0xff00) >> 8);
539}
540pub fn WTERMSIG(s: i32) i32 {
541 return signed(unsigned(s) & 0x7f);
542}
543pub fn WSTOPSIG(s: i32) i32 {
544 return WEXITSTATUS(s);
545}
546pub fn WIFEXITED(s: i32) bool {
547 return WTERMSIG(s) == 0;
548}
549pub fn WIFSTOPPED(s: i32) bool {
550 return @intCast(u16, (((unsigned(s) & 0xffff) *% 0x10001) >> 8)) > 0x7f00;
551}
552pub fn WIFSIGNALED(s: i32) bool {
553 return (unsigned(s) & 0xffff) -% 1 < 0xff;
554}
555
556pub const winsize = extern struct {
557 ws_row: u16,
558 ws_col: u16,
559 ws_xpixel: u16,
560 ws_ypixel: u16,
561};
562
563/// Get the errno from a syscall return value, or 0 for no error.
564pub fn getErrno(r: usize) usize {
565 const signed_r = @bitCast(isize, r);
566 return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
567}
568
569pub fn dup2(old: i32, new: i32) usize {
570 return errnoWrap(c.dup2(old, new));
571}
572
573pub fn chdir(path: [*]const u8) usize {
574 return errnoWrap(c.chdir(path));
575}
576
577pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
578 return errnoWrap(c.execve(path, argv, envp));
579}
580
581pub fn fork() usize {
582 return errnoWrap(c.fork());
583}
584
585pub fn access(path: [*]const u8, mode: u32) usize {
586 return errnoWrap(c.access(path, mode));
587}
588
589pub fn getcwd(buf: [*]u8, size: usize) usize {
590 return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
591}
592
593pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize {
594 return errnoWrap(@bitCast(isize, c.getdents(fd, drip, count)));
595}
596
597pub fn getdirentries(fd: i32, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize {
598 return errnoWrap(@bitCast(isize, c.getdirentries(fd, buf_ptr, buf_len, basep)));
599}
600
601pub fn realpath(noalias filename: [*]const u8, noalias resolved_name: [*]u8) usize {
602 return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
603}
604
605pub fn isatty(fd: i32) bool {
606 return c.isatty(fd) != 0;
607}
608
609pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
610 return errnoWrap(c.readlink(path, buf_ptr, buf_len));
611}
612
613pub fn mkdir(path: [*]const u8, mode: u32) usize {
614 return errnoWrap(c.mkdir(path, mode));
615}
616
617pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
618 const ptr_result = c.mmap(
619 @ptrCast(?*c_void, address),
620 length,
621 @bitCast(c_int, @intCast(c_uint, prot)),
622 @bitCast(c_int, c_uint(flags)),
623 fd,
624 offset,
625 );
626 const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
627 return errnoWrap(isize_result);
628}
629
630pub fn munmap(address: usize, length: usize) usize {
631 return errnoWrap(c.munmap(@intToPtr(?*c_void, address), length));
632}
633
634pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
635 return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte));
636}
637
638pub fn rmdir(path: [*]const u8) usize {
639 return errnoWrap(c.rmdir(path));
640}
641
642pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
643 return errnoWrap(c.symlink(existing, new));
644}
645
646pub fn pread(fd: i32, buf: [*]u8, nbyte: usize, offset: u64) usize {
647 return errnoWrap(c.pread(fd, @ptrCast(*c_void, buf), nbyte, offset));
648}
649
650pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: usize) usize {
651 return errnoWrap(c.preadv(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
652}
653
654pub fn pipe(fd: *[2]i32) usize {
655 return pipe2(fd, 0);
656}
657
658pub fn pipe2(fd: *[2]i32, flags: u32) usize {
659 comptime assert(i32.bit_count == c_int.bit_count);
660 return errnoWrap(c.pipe2(@ptrCast(*[2]c_int, fd), flags));
661}
662
663pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize {
664 return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte));
665}
666
667pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize {
668 return errnoWrap(c.pwrite(fd, @ptrCast(*const c_void, buf), nbyte, offset));
669}
670
671pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) usize {
672 return errnoWrap(c.pwritev(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
673}
674
675pub fn rename(old: [*]const u8, new: [*]const u8) usize {
676 return errnoWrap(c.rename(old, new));
677}
678
679pub fn open(path: [*]const u8, flags: u32, mode: usize) usize {
680 return errnoWrap(c.open(path, @bitCast(c_int, flags), mode));
681}
682
683pub fn create(path: [*]const u8, perm: usize) usize {
684 return arch.syscall2(SYS_creat, @ptrToInt(path), perm);
685}
686
687pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize {
688 return errnoWrap(c.openat(@bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode));
689}
690
691pub fn close(fd: i32) usize {
692 return errnoWrap(c.close(fd));
693}
694
695pub fn lseek(fd: i32, offset: isize, whence: c_int) usize {
696 return errnoWrap(c.lseek(fd, offset, whence));
697}
698
699pub fn exit(code: i32) noreturn {
700 c.exit(code);
701}
702
703pub fn kill(pid: i32, sig: i32) usize {
704 return errnoWrap(c.kill(pid, sig));
705}
706
707pub fn unlink(path: [*]const u8) usize {
708 return errnoWrap(c.unlink(path));
709}
710
711pub fn waitpid(pid: i32, status: *i32, options: u32) usize {
712 comptime assert(i32.bit_count == c_int.bit_count);
713 return errnoWrap(c.waitpid(pid, @ptrCast(*c_int, status), @bitCast(c_int, options)));
714}
715
716pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
717 return errnoWrap(c.nanosleep(req, rem));
718}
719
720pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
721 return errnoWrap(c.clock_gettime(clk_id, tp));
722}
723
724pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
725 return errnoWrap(c.clock_getres(clk_id, tp));
726}
727
728pub fn setuid(uid: u32) usize {
729 return errnoWrap(c.setuid(uid));
730}
731
732pub fn setgid(gid: u32) usize {
733 return errnoWrap(c.setgid(gid));
734}
735
736pub fn setreuid(ruid: u32, euid: u32) usize {
737 return errnoWrap(c.setreuid(ruid, euid));
738}
739
740pub fn setregid(rgid: u32, egid: u32) usize {
741 return errnoWrap(c.setregid(rgid, egid));
742}
743
744const NSIG = 32;
745
746pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
747pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
748pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
749
750/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
751pub const Sigaction = extern struct {
752 /// signal handler
753 __sigaction_u: extern union {
754 __sa_handler: extern fn (i32) void,
755 __sa_sigaction: extern fn (i32, *__siginfo, usize) void,
756 },
757
758 /// see signal options
759 sa_flags: u32,
760
761 /// signal mask to apply
762 sa_mask: sigset_t,
763};
764
765pub const _SIG_WORDS = 4;
766pub const _SIG_MAXSIG = 128;
767
768pub inline fn _SIG_IDX(sig: usize) usize {
769 return sig - 1;
770}
771pub inline fn _SIG_WORD(sig: usize) usize {
772 return_SIG_IDX(sig) >> 5;
773}
774pub inline fn _SIG_BIT(sig: usize) usize {
775 return 1 << (_SIG_IDX(sig) & 31);
776}
777pub inline fn _SIG_VALID(sig: usize) usize {
778 return sig <= _SIG_MAXSIG and sig > 0;
779}
780
781pub const sigset_t = extern struct {
782 __bits: [_SIG_WORDS]u32,
783};
784
785pub fn raise(sig: i32) usize {
786 return errnoWrap(c.raise(sig));
787}
788
789pub const Stat = c.Stat;
790pub const dirent = c.dirent;
791pub const timespec = c.timespec;
792
793pub fn fstat(fd: i32, buf: *c.Stat) usize {
794 return errnoWrap(c.fstat(fd, buf));
795}
796pub const iovec = extern struct {
797 iov_base: [*]u8,
798 iov_len: usize,
799};
800
801pub const iovec_const = extern struct {
802 iov_base: [*]const u8,
803 iov_len: usize,
804};
805
806// TODO avoid libc dependency
807pub fn kqueue() usize {
808 return errnoWrap(c.kqueue());
809}
810
811// TODO avoid libc dependency
812pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize {
813 return errnoWrap(c.kevent(
814 kq,
815 changelist.ptr,
816 @intCast(c_int, changelist.len),
817 eventlist.ptr,
818 @intCast(c_int, eventlist.len),
819 timeout,
820 ));
821}
822
823// TODO avoid libc dependency
824pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
825 return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen));
826}
827
828// TODO avoid libc dependency
829pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
830 return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen));
831}
832
833// TODO avoid libc dependency
834pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize {
835 return errnoWrap(c.sysctlnametomib(name, wibp, sizep));
836}
837
838// TODO avoid libc dependency
839
840/// Takes the return value from a syscall and formats it back in the way
841/// that the kernel represents it to libc. Errno was a mistake, let's make
842/// it go away forever.
843fn errnoWrap(value: isize) usize {
844 return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
845}
std/os/freebsd/errno.zig deleted-121
...@@ -1,121 +0,0 @@
1pub const EPERM = 1; // Operation not permitted
2pub const ENOENT = 2; // No such file or directory
3pub const ESRCH = 3; // No such process
4pub const EINTR = 4; // Interrupted system call
5pub const EIO = 5; // Input/output error
6pub const ENXIO = 6; // Device not configured
7pub const E2BIG = 7; // Argument list too long
8pub const ENOEXEC = 8; // Exec format error
9pub const EBADF = 9; // Bad file descriptor
10pub const ECHILD = 10; // No child processes
11pub const EDEADLK = 11; // Resource deadlock avoided
12// 11 was EAGAIN
13pub const ENOMEM = 12; // Cannot allocate memory
14pub const EACCES = 13; // Permission denied
15pub const EFAULT = 14; // Bad address
16pub const ENOTBLK = 15; // Block device required
17pub const EBUSY = 16; // Device busy
18pub const EEXIST = 17; // File exists
19pub const EXDEV = 18; // Cross-device link
20pub const ENODEV = 19; // Operation not supported by device
21pub const ENOTDIR = 20; // Not a directory
22pub const EISDIR = 21; // Is a directory
23pub const EINVAL = 22; // Invalid argument
24pub const ENFILE = 23; // Too many open files in system
25pub const EMFILE = 24; // Too many open files
26pub const ENOTTY = 25; // Inappropriate ioctl for device
27pub const ETXTBSY = 26; // Text file busy
28pub const EFBIG = 27; // File too large
29pub const ENOSPC = 28; // No space left on device
30pub const ESPIPE = 29; // Illegal seek
31pub const EROFS = 30; // Read-only filesystem
32pub const EMLINK = 31; // Too many links
33pub const EPIPE = 32; // Broken pipe
34
35// math software
36pub const EDOM = 33; // Numerical argument out of domain
37pub const ERANGE = 34; // Result too large
38
39// non-blocking and interrupt i/o
40pub const EAGAIN = 35; // Resource temporarily unavailable
41pub const EWOULDBLOCK = EAGAIN; // Operation would block
42pub const EINPROGRESS = 36; // Operation now in progress
43pub const EALREADY = 37; // Operation already in progress
44
45// ipc/network software -- argument errors
46pub const ENOTSOCK = 38; // Socket operation on non-socket
47pub const EDESTADDRREQ = 39; // Destination address required
48pub const EMSGSIZE = 40; // Message too long
49pub const EPROTOTYPE = 41; // Protocol wrong type for socket
50pub const ENOPROTOOPT = 42; // Protocol not available
51pub const EPROTONOSUPPORT = 43; // Protocol not supported
52pub const ESOCKTNOSUPPORT = 44; // Socket type not supported
53pub const EOPNOTSUPP = 45; // Operation not supported
54pub const ENOTSUP = EOPNOTSUPP; // Operation not supported
55pub const EPFNOSUPPORT = 46; // Protocol family not supported
56pub const EAFNOSUPPORT = 47; // Address family not supported by protocol family
57pub const EADDRINUSE = 48; // Address already in use
58pub const EADDRNOTAVAIL = 49; // Can't assign requested address
59
60// ipc/network software -- operational errors
61pub const ENETDOWN = 50; // Network is down
62pub const ENETUNREACH = 51; // Network is unreachable
63pub const ENETRESET = 52; // Network dropped connection on reset
64pub const ECONNABORTED = 53; // Software caused connection abort
65pub const ECONNRESET = 54; // Connection reset by peer
66pub const ENOBUFS = 55; // No buffer space available
67pub const EISCONN = 56; // Socket is already connected
68pub const ENOTCONN = 57; // Socket is not connected
69pub const ESHUTDOWN = 58; // Can't send after socket shutdown
70pub const ETOOMANYREFS = 59; // Too many references: can't splice
71pub const ETIMEDOUT = 60; // Operation timed out
72pub const ECONNREFUSED = 61; // Connection refused
73
74pub const ELOOP = 62; // Too many levels of symbolic links
75pub const ENAMETOOLONG = 63; // File name too long
76
77// should be rearranged
78pub const EHOSTDOWN = 64; // Host is down
79pub const EHOSTUNREACH = 65; // No route to host
80pub const ENOTEMPTY = 66; // Directory not empty
81
82// quotas & mush
83pub const EPROCLIM = 67; // Too many processes
84pub const EUSERS = 68; // Too many users
85pub const EDQUOT = 69; // Disc quota exceeded
86
87// Network File System
88pub const ESTALE = 70; // Stale NFS file handle
89pub const EREMOTE = 71; // Too many levels of remote in path
90pub const EBADRPC = 72; // RPC struct is bad
91pub const ERPCMISMATCH = 73; // RPC version wrong
92pub const EPROGUNAVAIL = 74; // RPC prog. not avail
93pub const EPROGMISMATCH = 75; // Program version wrong
94pub const EPROCUNAVAIL = 76; // Bad procedure for program
95
96pub const ENOLCK = 77; // No locks available
97pub const ENOSYS = 78; // Function not implemented
98
99pub const EFTYPE = 79; // Inappropriate file type or format
100pub const EAUTH = 80; // Authentication error
101pub const ENEEDAUTH = 81; // Need authenticator
102pub const EIDRM = 82; // Identifier removed
103pub const ENOMSG = 83; // No message of desired type
104pub const EOVERFLOW = 84; // Value too large to be stored in data type
105pub const ECANCELED = 85; // Operation canceled
106pub const EILSEQ = 86; // Illegal byte sequence
107pub const ENOATTR = 87; // Attribute not found
108
109pub const EDOOFUS = 88; // Programming error
110
111pub const EBADMSG = 89; // Bad message
112pub const EMULTIHOP = 90; // Multihop attempted
113pub const ENOLINK = 91; // Link has been severed
114pub const EPROTO = 92; // Protocol error
115
116pub const ENOTCAPABLE = 93; // Capabilities insufficient
117pub const ECAPMODE = 94; // Not permitted in capability mode
118pub const ENOTRECOVERABLE = 95; // State not recoverable
119pub const EOWNERDEAD = 96; // Previous owner died
120
121pub const ELAST = 96; // Must be equal largest errno
std/os/get_app_data_dir.zig deleted-69
...@@ -1,69 +0,0 @@
1const std = @import("../std.zig");
2const builtin = @import("builtin");
3const unicode = std.unicode;
4const mem = std.mem;
5const os = std.os;
6
7pub const GetAppDataDirError = error{
8 OutOfMemory,
9 AppDataDirUnavailable,
10};
11
12/// Caller owns returned memory.
13/// TODO determine if we can remove the allocator requirement
14pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataDirError![]u8 {
15 switch (builtin.os) {
16 builtin.Os.windows => {
17 var dir_path_ptr: [*]u16 = undefined;
18 switch (os.windows.SHGetKnownFolderPath(
19 &os.windows.FOLDERID_LocalAppData,
20 os.windows.KF_FLAG_CREATE,
21 null,
22 &dir_path_ptr,
23 )) {
24 os.windows.S_OK => {
25 defer os.windows.CoTaskMemFree(@ptrCast(*c_void, dir_path_ptr));
26 const global_dir = unicode.utf16leToUtf8Alloc(allocator, utf16lePtrSlice(dir_path_ptr)) catch |err| switch (err) {
27 error.UnexpectedSecondSurrogateHalf => return error.AppDataDirUnavailable,
28 error.ExpectedSecondSurrogateHalf => return error.AppDataDirUnavailable,
29 error.DanglingSurrogateHalf => return error.AppDataDirUnavailable,
30 error.OutOfMemory => return error.OutOfMemory,
31 };
32 defer allocator.free(global_dir);
33 return os.path.join(allocator, [][]const u8{ global_dir, appname });
34 },
35 os.windows.E_OUTOFMEMORY => return error.OutOfMemory,
36 else => return error.AppDataDirUnavailable,
37 }
38 },
39 builtin.Os.macosx => {
40 const home_dir = os.getEnvPosix("HOME") orelse {
41 // TODO look in /etc/passwd
42 return error.AppDataDirUnavailable;
43 };
44 return os.path.join(allocator, [][]const u8{ home_dir, "Library", "Application Support", appname });
45 },
46 builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {
47 const home_dir = os.getEnvPosix("HOME") orelse {
48 // TODO look in /etc/passwd
49 return error.AppDataDirUnavailable;
50 };
51 return os.path.join(allocator, [][]const u8{ home_dir, ".local", "share", appname });
52 },
53 else => @compileError("Unsupported OS"),
54 }
55}
56
57fn utf16lePtrSlice(ptr: [*]const u16) []const u16 {
58 var index: usize = 0;
59 while (ptr[index] != 0) : (index += 1) {}
60 return ptr[0..index];
61}
62
63test "std.os.getAppDataDir" {
64 var buf: [512]u8 = undefined;
65 const allocator = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
66
67 // We can't actually validate the result
68 _ = getAppDataDir(allocator, "zig") catch return;
69}
std/os/get_user_id.zig deleted-104
...@@ -1,104 +0,0 @@
1const builtin = @import("builtin");
2const Os = builtin.Os;
3const os = @import("../os.zig");
4const io = @import("../io.zig");
5
6pub const UserInfo = struct {
7 uid: u32,
8 gid: u32,
9};
10
11/// POSIX function which gets a uid from username.
12pub fn getUserInfo(name: []const u8) !UserInfo {
13 return switch (builtin.os) {
14 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => posixGetUserInfo(name),
15 else => @compileError("Unsupported OS"),
16 };
17}
18
19const State = enum {
20 Start,
21 WaitForNextLine,
22 SkipPassword,
23 ReadUserId,
24 ReadGroupId,
25};
26
27// TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else
28// like NIS, AD, etc. See `man nss` or look at an strace for `id myuser`.
29
30pub fn posixGetUserInfo(name: []const u8) !UserInfo {
31 var in_stream = try io.InStream.open("/etc/passwd", null);
32 defer in_stream.close();
33
34 var buf: [os.page_size]u8 = undefined;
35 var name_index: usize = 0;
36 var state = State.Start;
37 var uid: u32 = 0;
38 var gid: u32 = 0;
39
40 while (true) {
41 const amt_read = try in_stream.read(buf[0..]);
42 for (buf[0..amt_read]) |byte| {
43 switch (state) {
44 State.Start => switch (byte) {
45 ':' => {
46 state = if (name_index == name.len) State.SkipPassword else State.WaitForNextLine;
47 },
48 '\n' => return error.CorruptPasswordFile,
49 else => {
50 if (name_index == name.len or name[name_index] != byte) {
51 state = State.WaitForNextLine;
52 }
53 name_index += 1;
54 },
55 },
56 State.WaitForNextLine => switch (byte) {
57 '\n' => {
58 name_index = 0;
59 state = State.Start;
60 },
61 else => continue,
62 },
63 State.SkipPassword => switch (byte) {
64 '\n' => return error.CorruptPasswordFile,
65 ':' => {
66 state = State.ReadUserId;
67 },
68 else => continue,
69 },
70 State.ReadUserId => switch (byte) {
71 ':' => {
72 state = State.ReadGroupId;
73 },
74 '\n' => return error.CorruptPasswordFile,
75 else => {
76 const digit = switch (byte) {
77 '0'...'9' => byte - '0',
78 else => return error.CorruptPasswordFile,
79 };
80 if (@mulWithOverflow(u32, uid, 10, *uid)) return error.CorruptPasswordFile;
81 if (@addWithOverflow(u32, uid, digit, *uid)) return error.CorruptPasswordFile;
82 },
83 },
84 State.ReadGroupId => switch (byte) {
85 '\n', ':' => {
86 return UserInfo{
87 .uid = uid,
88 .gid = gid,
89 };
90 },
91 else => {
92 const digit = switch (byte) {
93 '0'...'9' => byte - '0',
94 else => return error.CorruptPasswordFile,
95 };
96 if (@mulWithOverflow(u32, gid, 10, *gid)) return error.CorruptPasswordFile;
97 if (@addWithOverflow(u32, gid, digit, *gid)) return error.CorruptPasswordFile;
98 },
99 },
100 }
101 }
102 if (amt_read < buf.len) return error.UserNotFound;
103 }
104}
std/os/linux.zig+159-955
...@@ -1,709 +1,61 @@...@@ -1,709 +1,61 @@
1// This file provides the system interface functions for Linux matching those
2// that are provided by libc, whether or not libc is linked. The following
3// abstractions are made:
4// * Work around kernel bugs and limitations. For example, see sendmmsg.
5// * Implement all the syscalls in the same way that libc functions will
6// provide `rename` when only the `renameat` syscall exists.
7// * Does not support POSIX thread cancellation.
1const std = @import("../std.zig");8const std = @import("../std.zig");
2const assert = std.debug.assert;
3const builtin = @import("builtin");9const builtin = @import("builtin");
10const assert = std.debug.assert;
4const maxInt = std.math.maxInt;11const maxInt = std.math.maxInt;
5const elf = std.elf;12const elf = std.elf;
6pub const tls = @import("linux/tls.zig");
7const vdso = @import("linux/vdso.zig");13const vdso = @import("linux/vdso.zig");
8const dl = @import("../dynamic_library.zig");14const dl = @import("../dynamic_library.zig");
15
16pub const is_the_target = builtin.os == .linux;
9pub use switch (builtin.arch) {17pub use switch (builtin.arch) {
10 builtin.Arch.x86_64 => @import("linux/x86_64.zig"),18 .x86_64 => @import("linux/x86_64.zig"),
11 builtin.Arch.i386 => @import("linux/i386.zig"),19 .aarch64 => @import("linux/arm64.zig"),
12 builtin.Arch.aarch64 => @import("linux/arm64.zig"),20 else => struct {},
13 else => @compileError("unsupported arch"),
14};21};
15pub use @import("linux/errno.zig");22pub use @import("bits.zig");
1623pub const tls = @import("linux/tls.zig");
17pub const PATH_MAX = 4096;
18pub const IOV_MAX = 1024;
19
20pub const STDIN_FILENO = 0;
21pub const STDOUT_FILENO = 1;
22pub const STDERR_FILENO = 2;
23
24pub const FUTEX_WAIT = 0;
25pub const FUTEX_WAKE = 1;
26pub const FUTEX_FD = 2;
27pub const FUTEX_REQUEUE = 3;
28pub const FUTEX_CMP_REQUEUE = 4;
29pub const FUTEX_WAKE_OP = 5;
30pub const FUTEX_LOCK_PI = 6;
31pub const FUTEX_UNLOCK_PI = 7;
32pub const FUTEX_TRYLOCK_PI = 8;
33pub const FUTEX_WAIT_BITSET = 9;
34
35pub const FUTEX_PRIVATE_FLAG = 128;
36
37pub const FUTEX_CLOCK_REALTIME = 256;
38
39pub const PROT_NONE = 0;
40pub const PROT_READ = 1;
41pub const PROT_WRITE = 2;
42pub const PROT_EXEC = 4;
43pub const PROT_GROWSDOWN = 0x01000000;
44pub const PROT_GROWSUP = 0x02000000;
45
46pub const MAP_FAILED = maxInt(usize);
47pub const MAP_SHARED = 0x01;
48pub const MAP_PRIVATE = 0x02;
49pub const MAP_TYPE = 0x0f;
50pub const MAP_FIXED = 0x10;
51pub const MAP_ANONYMOUS = 0x20;
52pub const MAP_NORESERVE = 0x4000;
53pub const MAP_GROWSDOWN = 0x0100;
54pub const MAP_DENYWRITE = 0x0800;
55pub const MAP_EXECUTABLE = 0x1000;
56pub const MAP_LOCKED = 0x2000;
57pub const MAP_POPULATE = 0x8000;
58pub const MAP_NONBLOCK = 0x10000;
59pub const MAP_STACK = 0x20000;
60pub const MAP_HUGETLB = 0x40000;
61pub const MAP_FILE = 0;
62
63pub const F_OK = 0;
64pub const X_OK = 1;
65pub const W_OK = 2;
66pub const R_OK = 4;
67
68pub const WNOHANG = 1;
69pub const WUNTRACED = 2;
70pub const WSTOPPED = 2;
71pub const WEXITED = 4;
72pub const WCONTINUED = 8;
73pub const WNOWAIT = 0x1000000;
74
75pub const SA_NOCLDSTOP = 1;
76pub const SA_NOCLDWAIT = 2;
77pub const SA_SIGINFO = 4;
78pub const SA_ONSTACK = 0x08000000;
79pub const SA_RESTART = 0x10000000;
80pub const SA_NODEFER = 0x40000000;
81pub const SA_RESETHAND = 0x80000000;
82pub const SA_RESTORER = 0x04000000;
83
84pub const SIGHUP = 1;
85pub const SIGINT = 2;
86pub const SIGQUIT = 3;
87pub const SIGILL = 4;
88pub const SIGTRAP = 5;
89pub const SIGABRT = 6;
90pub const SIGIOT = SIGABRT;
91pub const SIGBUS = 7;
92pub const SIGFPE = 8;
93pub const SIGKILL = 9;
94pub const SIGUSR1 = 10;
95pub const SIGSEGV = 11;
96pub const SIGUSR2 = 12;
97pub const SIGPIPE = 13;
98pub const SIGALRM = 14;
99pub const SIGTERM = 15;
100pub const SIGSTKFLT = 16;
101pub const SIGCHLD = 17;
102pub const SIGCONT = 18;
103pub const SIGSTOP = 19;
104pub const SIGTSTP = 20;
105pub const SIGTTIN = 21;
106pub const SIGTTOU = 22;
107pub const SIGURG = 23;
108pub const SIGXCPU = 24;
109pub const SIGXFSZ = 25;
110pub const SIGVTALRM = 26;
111pub const SIGPROF = 27;
112pub const SIGWINCH = 28;
113pub const SIGIO = 29;
114pub const SIGPOLL = 29;
115pub const SIGPWR = 30;
116pub const SIGSYS = 31;
117pub const SIGUNUSED = SIGSYS;
118
119pub const O_RDONLY = 0o0;
120pub const O_WRONLY = 0o1;
121pub const O_RDWR = 0o2;
122
123pub const SEEK_SET = 0;
124pub const SEEK_CUR = 1;
125pub const SEEK_END = 2;
126
127pub const SIG_BLOCK = 0;
128pub const SIG_UNBLOCK = 1;
129pub const SIG_SETMASK = 2;
130
131pub const PROTO_ip = 0o000;
132pub const PROTO_icmp = 0o001;
133pub const PROTO_igmp = 0o002;
134pub const PROTO_ggp = 0o003;
135pub const PROTO_ipencap = 0o004;
136pub const PROTO_st = 0o005;
137pub const PROTO_tcp = 0o006;
138pub const PROTO_egp = 0o010;
139pub const PROTO_pup = 0o014;
140pub const PROTO_udp = 0o021;
141pub const PROTO_hmp = 0o024;
142pub const PROTO_xns_idp = 0o026;
143pub const PROTO_rdp = 0o033;
144pub const PROTO_iso_tp4 = 0o035;
145pub const PROTO_xtp = 0o044;
146pub const PROTO_ddp = 0o045;
147pub const PROTO_idpr_cmtp = 0o046;
148pub const PROTO_ipv6 = 0o051;
149pub const PROTO_ipv6_route = 0o053;
150pub const PROTO_ipv6_frag = 0o054;
151pub const PROTO_idrp = 0o055;
152pub const PROTO_rsvp = 0o056;
153pub const PROTO_gre = 0o057;
154pub const PROTO_esp = 0o062;
155pub const PROTO_ah = 0o063;
156pub const PROTO_skip = 0o071;
157pub const PROTO_ipv6_icmp = 0o072;
158pub const PROTO_ipv6_nonxt = 0o073;
159pub const PROTO_ipv6_opts = 0o074;
160pub const PROTO_rspf = 0o111;
161pub const PROTO_vmtp = 0o121;
162pub const PROTO_ospf = 0o131;
163pub const PROTO_ipip = 0o136;
164pub const PROTO_encap = 0o142;
165pub const PROTO_pim = 0o147;
166pub const PROTO_raw = 0o377;
167
168pub const SHUT_RD = 0;
169pub const SHUT_WR = 1;
170pub const SHUT_RDWR = 2;
171
172pub const SOCK_STREAM = 1;
173pub const SOCK_DGRAM = 2;
174pub const SOCK_RAW = 3;
175pub const SOCK_RDM = 4;
176pub const SOCK_SEQPACKET = 5;
177pub const SOCK_DCCP = 6;
178pub const SOCK_PACKET = 10;
179pub const SOCK_CLOEXEC = 0o2000000;
180pub const SOCK_NONBLOCK = 0o4000;
181
182pub const PF_UNSPEC = 0;
183pub const PF_LOCAL = 1;
184pub const PF_UNIX = PF_LOCAL;
185pub const PF_FILE = PF_LOCAL;
186pub const PF_INET = 2;
187pub const PF_AX25 = 3;
188pub const PF_IPX = 4;
189pub const PF_APPLETALK = 5;
190pub const PF_NETROM = 6;
191pub const PF_BRIDGE = 7;
192pub const PF_ATMPVC = 8;
193pub const PF_X25 = 9;
194pub const PF_INET6 = 10;
195pub const PF_ROSE = 11;
196pub const PF_DECnet = 12;
197pub const PF_NETBEUI = 13;
198pub const PF_SECURITY = 14;
199pub const PF_KEY = 15;
200pub const PF_NETLINK = 16;
201pub const PF_ROUTE = PF_NETLINK;
202pub const PF_PACKET = 17;
203pub const PF_ASH = 18;
204pub const PF_ECONET = 19;
205pub const PF_ATMSVC = 20;
206pub const PF_RDS = 21;
207pub const PF_SNA = 22;
208pub const PF_IRDA = 23;
209pub const PF_PPPOX = 24;
210pub const PF_WANPIPE = 25;
211pub const PF_LLC = 26;
212pub const PF_IB = 27;
213pub const PF_MPLS = 28;
214pub const PF_CAN = 29;
215pub const PF_TIPC = 30;
216pub const PF_BLUETOOTH = 31;
217pub const PF_IUCV = 32;
218pub const PF_RXRPC = 33;
219pub const PF_ISDN = 34;
220pub const PF_PHONET = 35;
221pub const PF_IEEE802154 = 36;
222pub const PF_CAIF = 37;
223pub const PF_ALG = 38;
224pub const PF_NFC = 39;
225pub const PF_VSOCK = 40;
226pub const PF_KCM = 41;
227pub const PF_QIPCRTR = 42;
228pub const PF_SMC = 43;
229pub const PF_MAX = 44;
230
231pub const AF_UNSPEC = PF_UNSPEC;
232pub const AF_LOCAL = PF_LOCAL;
233pub const AF_UNIX = AF_LOCAL;
234pub const AF_FILE = AF_LOCAL;
235pub const AF_INET = PF_INET;
236pub const AF_AX25 = PF_AX25;
237pub const AF_IPX = PF_IPX;
238pub const AF_APPLETALK = PF_APPLETALK;
239pub const AF_NETROM = PF_NETROM;
240pub const AF_BRIDGE = PF_BRIDGE;
241pub const AF_ATMPVC = PF_ATMPVC;
242pub const AF_X25 = PF_X25;
243pub const AF_INET6 = PF_INET6;
244pub const AF_ROSE = PF_ROSE;
245pub const AF_DECnet = PF_DECnet;
246pub const AF_NETBEUI = PF_NETBEUI;
247pub const AF_SECURITY = PF_SECURITY;
248pub const AF_KEY = PF_KEY;
249pub const AF_NETLINK = PF_NETLINK;
250pub const AF_ROUTE = PF_ROUTE;
251pub const AF_PACKET = PF_PACKET;
252pub const AF_ASH = PF_ASH;
253pub const AF_ECONET = PF_ECONET;
254pub const AF_ATMSVC = PF_ATMSVC;
255pub const AF_RDS = PF_RDS;
256pub const AF_SNA = PF_SNA;
257pub const AF_IRDA = PF_IRDA;
258pub const AF_PPPOX = PF_PPPOX;
259pub const AF_WANPIPE = PF_WANPIPE;
260pub const AF_LLC = PF_LLC;
261pub const AF_IB = PF_IB;
262pub const AF_MPLS = PF_MPLS;
263pub const AF_CAN = PF_CAN;
264pub const AF_TIPC = PF_TIPC;
265pub const AF_BLUETOOTH = PF_BLUETOOTH;
266pub const AF_IUCV = PF_IUCV;
267pub const AF_RXRPC = PF_RXRPC;
268pub const AF_ISDN = PF_ISDN;
269pub const AF_PHONET = PF_PHONET;
270pub const AF_IEEE802154 = PF_IEEE802154;
271pub const AF_CAIF = PF_CAIF;
272pub const AF_ALG = PF_ALG;
273pub const AF_NFC = PF_NFC;
274pub const AF_VSOCK = PF_VSOCK;
275pub const AF_KCM = PF_KCM;
276pub const AF_QIPCRTR = PF_QIPCRTR;
277pub const AF_SMC = PF_SMC;
278pub const AF_MAX = PF_MAX;
279
280pub const SO_DEBUG = 1;
281pub const SO_REUSEADDR = 2;
282pub const SO_TYPE = 3;
283pub const SO_ERROR = 4;
284pub const SO_DONTROUTE = 5;
285pub const SO_BROADCAST = 6;
286pub const SO_SNDBUF = 7;
287pub const SO_RCVBUF = 8;
288pub const SO_KEEPALIVE = 9;
289pub const SO_OOBINLINE = 10;
290pub const SO_NO_CHECK = 11;
291pub const SO_PRIORITY = 12;
292pub const SO_LINGER = 13;
293pub const SO_BSDCOMPAT = 14;
294pub const SO_REUSEPORT = 15;
295pub const SO_PASSCRED = 16;
296pub const SO_PEERCRED = 17;
297pub const SO_RCVLOWAT = 18;
298pub const SO_SNDLOWAT = 19;
299pub const SO_RCVTIMEO = 20;
300pub const SO_SNDTIMEO = 21;
301pub const SO_ACCEPTCONN = 30;
302pub const SO_SNDBUFFORCE = 32;
303pub const SO_RCVBUFFORCE = 33;
304pub const SO_PROTOCOL = 38;
305pub const SO_DOMAIN = 39;
306
307pub const SO_SECURITY_AUTHENTICATION = 22;
308pub const SO_SECURITY_ENCRYPTION_TRANSPORT = 23;
309pub const SO_SECURITY_ENCRYPTION_NETWORK = 24;
310
311pub const SO_BINDTODEVICE = 25;
312
313pub const SO_ATTACH_FILTER = 26;
314pub const SO_DETACH_FILTER = 27;
315pub const SO_GET_FILTER = SO_ATTACH_FILTER;
316
317pub const SO_PEERNAME = 28;
318pub const SO_TIMESTAMP = 29;
319pub const SCM_TIMESTAMP = SO_TIMESTAMP;
320
321pub const SO_PEERSEC = 31;
322pub const SO_PASSSEC = 34;
323pub const SO_TIMESTAMPNS = 35;
324pub const SCM_TIMESTAMPNS = SO_TIMESTAMPNS;
325pub const SO_MARK = 36;
326pub const SO_TIMESTAMPING = 37;
327pub const SCM_TIMESTAMPING = SO_TIMESTAMPING;
328pub const SO_RXQ_OVFL = 40;
329pub const SO_WIFI_STATUS = 41;
330pub const SCM_WIFI_STATUS = SO_WIFI_STATUS;
331pub const SO_PEEK_OFF = 42;
332pub const SO_NOFCS = 43;
333pub const SO_LOCK_FILTER = 44;
334pub const SO_SELECT_ERR_QUEUE = 45;
335pub const SO_BUSY_POLL = 46;
336pub const SO_MAX_PACING_RATE = 47;
337pub const SO_BPF_EXTENSIONS = 48;
338pub const SO_INCOMING_CPU = 49;
339pub const SO_ATTACH_BPF = 50;
340pub const SO_DETACH_BPF = SO_DETACH_FILTER;
341pub const SO_ATTACH_REUSEPORT_CBPF = 51;
342pub const SO_ATTACH_REUSEPORT_EBPF = 52;
343pub const SO_CNX_ADVICE = 53;
344pub const SCM_TIMESTAMPING_OPT_STATS = 54;
345pub const SO_MEMINFO = 55;
346pub const SO_INCOMING_NAPI_ID = 56;
347pub const SO_COOKIE = 57;
348pub const SCM_TIMESTAMPING_PKTINFO = 58;
349pub const SO_PEERGROUPS = 59;
350pub const SO_ZEROCOPY = 60;
351
352pub const SOL_SOCKET = 1;
353
354pub const SOL_IP = 0;
355pub const SOL_IPV6 = 41;
356pub const SOL_ICMPV6 = 58;
357
358pub const SOL_RAW = 255;
359pub const SOL_DECNET = 261;
360pub const SOL_X25 = 262;
361pub const SOL_PACKET = 263;
362pub const SOL_ATM = 264;
363pub const SOL_AAL = 265;
364pub const SOL_IRDA = 266;
365pub const SOL_NETBEUI = 267;
366pub const SOL_LLC = 268;
367pub const SOL_DCCP = 269;
368pub const SOL_NETLINK = 270;
369pub const SOL_TIPC = 271;
370pub const SOL_RXRPC = 272;
371pub const SOL_PPPOL2TP = 273;
372pub const SOL_BLUETOOTH = 274;
373pub const SOL_PNPIPE = 275;
374pub const SOL_RDS = 276;
375pub const SOL_IUCV = 277;
376pub const SOL_CAIF = 278;
377pub const SOL_ALG = 279;
378pub const SOL_NFC = 280;
379pub const SOL_KCM = 281;
380pub const SOL_TLS = 282;
381
382pub const SOMAXCONN = 128;
383
384pub const MSG_OOB = 0x0001;
385pub const MSG_PEEK = 0x0002;
386pub const MSG_DONTROUTE = 0x0004;
387pub const MSG_CTRUNC = 0x0008;
388pub const MSG_PROXY = 0x0010;
389pub const MSG_TRUNC = 0x0020;
390pub const MSG_DONTWAIT = 0x0040;
391pub const MSG_EOR = 0x0080;
392pub const MSG_WAITALL = 0x0100;
393pub const MSG_FIN = 0x0200;
394pub const MSG_SYN = 0x0400;
395pub const MSG_CONFIRM = 0x0800;
396pub const MSG_RST = 0x1000;
397pub const MSG_ERRQUEUE = 0x2000;
398pub const MSG_NOSIGNAL = 0x4000;
399pub const MSG_MORE = 0x8000;
400pub const MSG_WAITFORONE = 0x10000;
401pub const MSG_BATCH = 0x40000;
402pub const MSG_ZEROCOPY = 0x4000000;
403pub const MSG_FASTOPEN = 0x20000000;
404pub const MSG_CMSG_CLOEXEC = 0x40000000;
405
406pub const DT_UNKNOWN = 0;
407pub const DT_FIFO = 1;
408pub const DT_CHR = 2;
409pub const DT_DIR = 4;
410pub const DT_BLK = 6;
411pub const DT_REG = 8;
412pub const DT_LNK = 10;
413pub const DT_SOCK = 12;
414pub const DT_WHT = 14;
415
416pub const TCGETS = 0x5401;
417pub const TCSETS = 0x5402;
418pub const TCSETSW = 0x5403;
419pub const TCSETSF = 0x5404;
420pub const TCGETA = 0x5405;
421pub const TCSETA = 0x5406;
422pub const TCSETAW = 0x5407;
423pub const TCSETAF = 0x5408;
424pub const TCSBRK = 0x5409;
425pub const TCXONC = 0x540A;
426pub const TCFLSH = 0x540B;
427pub const TIOCEXCL = 0x540C;
428pub const TIOCNXCL = 0x540D;
429pub const TIOCSCTTY = 0x540E;
430pub const TIOCGPGRP = 0x540F;
431pub const TIOCSPGRP = 0x5410;
432pub const TIOCOUTQ = 0x5411;
433pub const TIOCSTI = 0x5412;
434pub const TIOCGWINSZ = 0x5413;
435pub const TIOCSWINSZ = 0x5414;
436pub const TIOCMGET = 0x5415;
437pub const TIOCMBIS = 0x5416;
438pub const TIOCMBIC = 0x5417;
439pub const TIOCMSET = 0x5418;
440pub const TIOCGSOFTCAR = 0x5419;
441pub const TIOCSSOFTCAR = 0x541A;
442pub const FIONREAD = 0x541B;
443pub const TIOCINQ = FIONREAD;
444pub const TIOCLINUX = 0x541C;
445pub const TIOCCONS = 0x541D;
446pub const TIOCGSERIAL = 0x541E;
447pub const TIOCSSERIAL = 0x541F;
448pub const TIOCPKT = 0x5420;
449pub const FIONBIO = 0x5421;
450pub const TIOCNOTTY = 0x5422;
451pub const TIOCSETD = 0x5423;
452pub const TIOCGETD = 0x5424;
453pub const TCSBRKP = 0x5425;
454pub const TIOCSBRK = 0x5427;
455pub const TIOCCBRK = 0x5428;
456pub const TIOCGSID = 0x5429;
457pub const TIOCGRS485 = 0x542E;
458pub const TIOCSRS485 = 0x542F;
459pub const TIOCGPTN = 0x80045430;
460pub const TIOCSPTLCK = 0x40045431;
461pub const TIOCGDEV = 0x80045432;
462pub const TCGETX = 0x5432;
463pub const TCSETX = 0x5433;
464pub const TCSETXF = 0x5434;
465pub const TCSETXW = 0x5435;
466pub const TIOCSIG = 0x40045436;
467pub const TIOCVHANGUP = 0x5437;
468pub const TIOCGPKT = 0x80045438;
469pub const TIOCGPTLCK = 0x80045439;
470pub const TIOCGEXCL = 0x80045440;
471
472pub const EPOLL_CLOEXEC = O_CLOEXEC;
473
474pub const EPOLL_CTL_ADD = 1;
475pub const EPOLL_CTL_DEL = 2;
476pub const EPOLL_CTL_MOD = 3;
477
478pub const EPOLLIN = 0x001;
479pub const EPOLLPRI = 0x002;
480pub const EPOLLOUT = 0x004;
481pub const EPOLLRDNORM = 0x040;
482pub const EPOLLRDBAND = 0x080;
483pub const EPOLLWRNORM = 0x100;
484pub const EPOLLWRBAND = 0x200;
485pub const EPOLLMSG = 0x400;
486pub const EPOLLERR = 0x008;
487pub const EPOLLHUP = 0x010;
488pub const EPOLLRDHUP = 0x2000;
489pub const EPOLLEXCLUSIVE = (u32(1) << 28);
490pub const EPOLLWAKEUP = (u32(1) << 29);
491pub const EPOLLONESHOT = (u32(1) << 30);
492pub const EPOLLET = (u32(1) << 31);
493
494pub const CLOCK_REALTIME = 0;
495pub const CLOCK_MONOTONIC = 1;
496pub const CLOCK_PROCESS_CPUTIME_ID = 2;
497pub const CLOCK_THREAD_CPUTIME_ID = 3;
498pub const CLOCK_MONOTONIC_RAW = 4;
499pub const CLOCK_REALTIME_COARSE = 5;
500pub const CLOCK_MONOTONIC_COARSE = 6;
501pub const CLOCK_BOOTTIME = 7;
502pub const CLOCK_REALTIME_ALARM = 8;
503pub const CLOCK_BOOTTIME_ALARM = 9;
504pub const CLOCK_SGI_CYCLE = 10;
505pub const CLOCK_TAI = 11;
506
507pub const CSIGNAL = 0x000000ff;
508pub const CLONE_VM = 0x00000100;
509pub const CLONE_FS = 0x00000200;
510pub const CLONE_FILES = 0x00000400;
511pub const CLONE_SIGHAND = 0x00000800;
512pub const CLONE_PTRACE = 0x00002000;
513pub const CLONE_VFORK = 0x00004000;
514pub const CLONE_PARENT = 0x00008000;
515pub const CLONE_THREAD = 0x00010000;
516pub const CLONE_NEWNS = 0x00020000;
517pub const CLONE_SYSVSEM = 0x00040000;
518pub const CLONE_SETTLS = 0x00080000;
519pub const CLONE_PARENT_SETTID = 0x00100000;
520pub const CLONE_CHILD_CLEARTID = 0x00200000;
521pub const CLONE_DETACHED = 0x00400000;
522pub const CLONE_UNTRACED = 0x00800000;
523pub const CLONE_CHILD_SETTID = 0x01000000;
524pub const CLONE_NEWCGROUP = 0x02000000;
525pub const CLONE_NEWUTS = 0x04000000;
526pub const CLONE_NEWIPC = 0x08000000;
527pub const CLONE_NEWUSER = 0x10000000;
528pub const CLONE_NEWPID = 0x20000000;
529pub const CLONE_NEWNET = 0x40000000;
530pub const CLONE_IO = 0x80000000;
531
532pub const EFD_SEMAPHORE = 1;
533pub const EFD_CLOEXEC = O_CLOEXEC;
534pub const EFD_NONBLOCK = O_NONBLOCK;
535
536pub const MS_RDONLY = 1;
537pub const MS_NOSUID = 2;
538pub const MS_NODEV = 4;
539pub const MS_NOEXEC = 8;
540pub const MS_SYNCHRONOUS = 16;
541pub const MS_REMOUNT = 32;
542pub const MS_MANDLOCK = 64;
543pub const MS_DIRSYNC = 128;
544pub const MS_NOATIME = 1024;
545pub const MS_NODIRATIME = 2048;
546pub const MS_BIND = 4096;
547pub const MS_MOVE = 8192;
548pub const MS_REC = 16384;
549pub const MS_SILENT = 32768;
550pub const MS_POSIXACL = (1 << 16);
551pub const MS_UNBINDABLE = (1 << 17);
552pub const MS_PRIVATE = (1 << 18);
553pub const MS_SLAVE = (1 << 19);
554pub const MS_SHARED = (1 << 20);
555pub const MS_RELATIME = (1 << 21);
556pub const MS_KERNMOUNT = (1 << 22);
557pub const MS_I_VERSION = (1 << 23);
558pub const MS_STRICTATIME = (1 << 24);
559pub const MS_LAZYTIME = (1 << 25);
560pub const MS_NOREMOTELOCK = (1 << 27);
561pub const MS_NOSEC = (1 << 28);
562pub const MS_BORN = (1 << 29);
563pub const MS_ACTIVE = (1 << 30);
564pub const MS_NOUSER = (1 << 31);
565
566pub const MS_RMT_MASK = (MS_RDONLY | MS_SYNCHRONOUS | MS_MANDLOCK | MS_I_VERSION | MS_LAZYTIME);
567
568pub const MS_MGC_VAL = 0xc0ed0000;
569pub const MS_MGC_MSK = 0xffff0000;
570
571pub const MNT_FORCE = 1;
572pub const MNT_DETACH = 2;
573pub const MNT_EXPIRE = 4;
574pub const UMOUNT_NOFOLLOW = 8;
575
576pub const IN_CLOEXEC = O_CLOEXEC;
577pub const IN_NONBLOCK = O_NONBLOCK;
578
579pub const IN_ACCESS = 0x00000001;
580pub const IN_MODIFY = 0x00000002;
581pub const IN_ATTRIB = 0x00000004;
582pub const IN_CLOSE_WRITE = 0x00000008;
583pub const IN_CLOSE_NOWRITE = 0x00000010;
584pub const IN_CLOSE = IN_CLOSE_WRITE | IN_CLOSE_NOWRITE;
585pub const IN_OPEN = 0x00000020;
586pub const IN_MOVED_FROM = 0x00000040;
587pub const IN_MOVED_TO = 0x00000080;
588pub const IN_MOVE = IN_MOVED_FROM | IN_MOVED_TO;
589pub const IN_CREATE = 0x00000100;
590pub const IN_DELETE = 0x00000200;
591pub const IN_DELETE_SELF = 0x00000400;
592pub const IN_MOVE_SELF = 0x00000800;
593pub const IN_ALL_EVENTS = 0x00000fff;
594
595pub const IN_UNMOUNT = 0x00002000;
596pub const IN_Q_OVERFLOW = 0x00004000;
597pub const IN_IGNORED = 0x00008000;
598
599pub const IN_ONLYDIR = 0x01000000;
600pub const IN_DONT_FOLLOW = 0x02000000;
601pub const IN_EXCL_UNLINK = 0x04000000;
602pub const IN_MASK_ADD = 0x20000000;
603
604pub const IN_ISDIR = 0x40000000;
605pub const IN_ONESHOT = 0x80000000;
606
607pub const S_IFMT = 0o170000;
608
609pub const S_IFDIR = 0o040000;
610pub const S_IFCHR = 0o020000;
611pub const S_IFBLK = 0o060000;
612pub const S_IFREG = 0o100000;
613pub const S_IFIFO = 0o010000;
614pub const S_IFLNK = 0o120000;
615pub const S_IFSOCK = 0o140000;
616
617pub const S_ISUID = 0o4000;
618pub const S_ISGID = 0o2000;
619pub const S_ISVTX = 0o1000;
620pub const S_IRUSR = 0o400;
621pub const S_IWUSR = 0o200;
622pub const S_IXUSR = 0o100;
623pub const S_IRWXU = 0o700;
624pub const S_IRGRP = 0o040;
625pub const S_IWGRP = 0o020;
626pub const S_IXGRP = 0o010;
627pub const S_IRWXG = 0o070;
628pub const S_IROTH = 0o004;
629pub const S_IWOTH = 0o002;
630pub const S_IXOTH = 0o001;
631pub const S_IRWXO = 0o007;
632
633pub fn S_ISREG(m: u32) bool {
634 return m & S_IFMT == S_IFREG;
635}
636
637pub fn S_ISDIR(m: u32) bool {
638 return m & S_IFMT == S_IFDIR;
639}
640
641pub fn S_ISCHR(m: u32) bool {
642 return m & S_IFMT == S_IFCHR;
643}
644
645pub fn S_ISBLK(m: u32) bool {
646 return m & S_IFMT == S_IFBLK;
647}
648
649pub fn S_ISFIFO(m: u32) bool {
650 return m & S_IFMT == S_IFIFO;
651}
652
653pub fn S_ISLNK(m: u32) bool {
654 return m & S_IFMT == S_IFLNK;
655}
656
657pub fn S_ISSOCK(m: u32) bool {
658 return m & S_IFMT == S_IFSOCK;
659}
660
661pub const TFD_NONBLOCK = O_NONBLOCK;
662pub const TFD_CLOEXEC = O_CLOEXEC;
66324
664pub const TFD_TIMER_ABSTIME = 1;25/// Set by startup code, used by `getauxval`.
665pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1);26pub var elf_aux_maybe: ?[*]std.elf.Auxv = null;
66627
667fn unsigned(s: i32) u32 {28/// See `std.elf` for the constants.
668 return @bitCast(u32, s);29pub fn getauxval(index: usize) usize {
669}30 const auxv = elf_aux_maybe orelse return 0;
670fn signed(s: u32) i32 {31 var i: usize = 0;
671 return @bitCast(i32, s);32 while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) {
672}33 if (auxv[i].a_type == index)
673pub fn WEXITSTATUS(s: i32) i32 {34 return auxv[i].a_un.a_val;
674 return signed((unsigned(s) & 0xff00) >> 8);35 }
675}36 return 0;
676pub fn WTERMSIG(s: i32) i32 {
677 return signed(unsigned(s) & 0x7f);
678}
679pub fn WSTOPSIG(s: i32) i32 {
680 return WEXITSTATUS(s);
681}
682pub fn WIFEXITED(s: i32) bool {
683 return WTERMSIG(s) == 0;
684}
685pub fn WIFSTOPPED(s: i32) bool {
686 return @intCast(u16, ((unsigned(s) & 0xffff) *% 0x10001) >> 8) > 0x7f00;
687}
688pub fn WIFSIGNALED(s: i32) bool {
689 return (unsigned(s) & 0xffff) -% 1 < 0xff;
690}37}
69138
692pub const winsize = extern struct {
693 ws_row: u16,
694 ws_col: u16,
695 ws_xpixel: u16,
696 ws_ypixel: u16,
697};
698
699/// Get the errno from a syscall return value, or 0 for no error.39/// Get the errno from a syscall return value, or 0 for no error.
700pub fn getErrno(r: usize) usize {40pub fn getErrno(r: usize) u12 {
701 const signed_r = @bitCast(isize, r);41 const signed_r = @bitCast(isize, r);
702 return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;42 return if (signed_r > -4096 and signed_r < 0) @intCast(u12, -signed_r) else 0;
703}43}
70444
705pub fn dup2(old: i32, new: i32) usize {45pub fn dup2(old: i32, new: i32) usize {
706 return dup3(old, new, 0);46 if (@hasDecl(@This(), "SYS_dup2")) {
47 return syscall2(SYS_dup2, @bitCast(usize, isize(old)), @bitCast(usize, isize(new)));
48 } else {
49 if (old == new) {
50 if (std.debug.runtime_safety) {
51 const rc = syscall2(SYS_fcntl, @bitCast(usize, isize(old)), F_GETFD);
52 if (@bitCast(isize, rc) < 0) return rc;
53 }
54 return @intCast(usize, old);
55 } else {
56 return syscall3(SYS_dup3, @bitCast(usize, isize(old)), @bitCast(usize, isize(new)), 0);
57 }
58 }
707}59}
70860
709pub fn dup3(old: i32, new: i32, flags: u32) usize {61pub 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 ?[*...@@ -726,7 +78,11 @@ pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*
726}78}
72779
728pub fn fork() usize {80pub fn fork() usize {
729 return clone2(SIGCHLD, 0);81 if (@hasDecl(@This(), "SYS_fork")) {
82 return syscall0(SYS_fork);
83 } else {
84 return syscall2(SYS_clone, SIGCHLD, 0);
85 }
730}86}
73187
732/// This must be inline, and inline call the syscall function, because if the88/// 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 {...@@ -750,6 +106,10 @@ pub fn getcwd(buf: [*]u8, size: usize) usize {
750 return syscall2(SYS_getcwd, @ptrToInt(buf), size);106 return syscall2(SYS_getcwd, @ptrToInt(buf), size);
751}107}
752108
109pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize {
110 return syscall3(SYS_getdents, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count);
111}
112
753pub fn getdents64(fd: i32, dirp: [*]u8, count: usize) usize {113pub fn getdents64(fd: i32, dirp: [*]u8, count: usize) usize {
754 return syscall3(SYS_getdents64, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count);114 return syscall3(SYS_getdents64, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count);
755}115}
...@@ -766,14 +126,13 @@ pub fn inotify_rm_watch(fd: i32, wd: i32) usize {...@@ -766,14 +126,13 @@ pub fn inotify_rm_watch(fd: i32, wd: i32) usize {
766 return syscall2(SYS_inotify_rm_watch, @bitCast(usize, isize(fd)), @bitCast(usize, isize(wd)));126 return syscall2(SYS_inotify_rm_watch, @bitCast(usize, isize(fd)), @bitCast(usize, isize(wd)));
767}127}
768128
769pub fn isatty(fd: i32) bool {
770 var wsz: winsize = undefined;
771 return syscall3(SYS_ioctl, @bitCast(usize, isize(fd)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
772}
773
774// TODO https://github.com/ziglang/zig/issues/265129// TODO https://github.com/ziglang/zig/issues/265
775pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {130pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
776 return readlinkat(AT_FDCWD, path, buf_ptr, buf_len);131 if (@hasDecl(@This(), "SYS_readlink")) {
132 return syscall3(SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);
133 } else {
134 return syscall4(SYS_readlinkat, AT_FDCWD, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);
135 }
777}136}
778137
779// TODO https://github.com/ziglang/zig/issues/265138// 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,...@@ -783,7 +142,11 @@ pub fn readlinkat(dirfd: i32, noalias path: [*]const u8, noalias buf_ptr: [*]u8,
783142
784// TODO https://github.com/ziglang/zig/issues/265143// TODO https://github.com/ziglang/zig/issues/265
785pub fn mkdir(path: [*]const u8, mode: u32) usize {144pub fn mkdir(path: [*]const u8, mode: u32) usize {
786 return mkdirat(AT_FDCWD, path, mode);145 if (@hasDecl(@This(), "SYS_mkdir")) {
146 return syscall2(SYS_mkdir, @ptrToInt(path), mode);
147 } else {
148 return syscall3(SYS_mkdirat, AT_FDCWD, @ptrToInt(path), mode);
149 }
787}150}
788151
789// TODO https://github.com/ziglang/zig/issues/265152// 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...@@ -810,12 +173,12 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, of
810 return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @bitCast(usize, isize(fd)), @bitCast(usize, offset));173 return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @bitCast(usize, isize(fd)), @bitCast(usize, offset));
811}174}
812175
813pub fn mprotect(address: usize, length: usize, protection: usize) usize {176pub fn mprotect(address: [*]const u8, length: usize, protection: usize) usize {
814 return syscall3(SYS_mprotect, address, length, protection);177 return syscall3(SYS_mprotect, @ptrToInt(address), length, protection);
815}178}
816179
817pub fn munmap(address: usize, length: usize) usize {180pub fn munmap(address: [*]const u8, length: usize) usize {
818 return syscall2(SYS_munmap, address, length);181 return syscall2(SYS_munmap, @ptrToInt(address), length);
819}182}
820183
821pub fn read(fd: i32, buf: [*]u8, count: usize) usize {184pub 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...@@ -840,12 +203,20 @@ pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) us
840203
841// TODO https://github.com/ziglang/zig/issues/265204// TODO https://github.com/ziglang/zig/issues/265
842pub fn rmdir(path: [*]const u8) usize {205pub fn rmdir(path: [*]const u8) usize {
843 return unlinkat(AT_FDCWD, path, AT_REMOVEDIR);206 if (@hasDecl(@This(), "SYS_rmdir")) {
207 return syscall1(SYS_rmdir, @ptrToInt(path));
208 } else {
209 return syscall3(SYS_unlinkat, AT_FDCWD, @ptrToInt(path), AT_REMOVEDIR);
210 }
844}211}
845212
846// TODO https://github.com/ziglang/zig/issues/265213// TODO https://github.com/ziglang/zig/issues/265
847pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {214pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
848 return symlinkat(existing, AT_FDCWD, new);215 if (@hasDecl(@This(), "SYS_symlink")) {
216 return syscall2(SYS_symlink, @ptrToInt(existing), @ptrToInt(new));
217 } else {
218 return syscall3(SYS_symlinkat, @ptrToInt(existing), AT_FDCWD, @ptrToInt(new));
219 }
849}220}
850221
851// TODO https://github.com/ziglang/zig/issues/265222// TODO https://github.com/ziglang/zig/issues/265
...@@ -860,15 +231,20 @@ pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize {...@@ -860,15 +231,20 @@ pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize {
860231
861// TODO https://github.com/ziglang/zig/issues/265232// TODO https://github.com/ziglang/zig/issues/265
862pub fn access(path: [*]const u8, mode: u32) usize {233pub fn access(path: [*]const u8, mode: u32) usize {
863 return faccessat(AT_FDCWD, path, mode);234 return syscall2(SYS_access, @ptrToInt(path), mode);
864}235}
865236
237// TODO https://github.com/ziglang/zig/issues/265
866pub fn faccessat(dirfd: i32, path: [*]const u8, mode: u32) usize {238pub fn faccessat(dirfd: i32, path: [*]const u8, mode: u32) usize {
867 return syscall3(SYS_faccessat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode);239 return syscall3(SYS_faccessat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode);
868}240}
869241
870pub fn pipe(fd: *[2]i32) usize {242pub fn pipe(fd: *[2]i32) usize {
871 return pipe2(fd, 0);243 if (@hasDecl(@This(), "SYS_pipe")) {
244 return syscall1(SYS_pipe, @ptrToInt(fd));
245 } else {
246 return syscall2(SYS_pipe2, @ptrToInt(fd), 0);
247 }
872}248}
873249
874pub fn pipe2(fd: *[2]i32, flags: u32) usize {250pub 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 {...@@ -885,17 +261,51 @@ pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize {
885261
886// TODO https://github.com/ziglang/zig/issues/265262// TODO https://github.com/ziglang/zig/issues/265
887pub fn rename(old: [*]const u8, new: [*]const u8) usize {263pub fn rename(old: [*]const u8, new: [*]const u8) usize {
888 return renameat2(AT_FDCWD, old, AT_FDCWD, new, 0);264 if (@hasDecl(@This(), "SYS_rename")) {
265 return syscall2(SYS_rename, @ptrToInt(old), @ptrToInt(new));
266 } else if (@hasDecl(@This(), "SYS_renameat")) {
267 return syscall4(SYS_renameat, AT_FDCWD, @ptrToInt(old), AT_FDCWD, @ptrToInt(new));
268 } else {
269 return syscall5(SYS_renameat2, AT_FDCWD, @ptrToInt(old), AT_FDCWD, @ptrToInt(new), 0);
270 }
271}
272
273pub fn renameat(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const u8) usize {
274 if (@hasDecl(@This(), "SYS_renameat")) {
275 return syscall4(
276 SYS_renameat,
277 @bitCast(usize, isize(oldfd)),
278 @ptrToInt(old),
279 @bitCast(usize, isize(newfd)),
280 @ptrToInt(new),
281 );
282 } else {
283 return syscall5(
284 SYS_renameat2,
285 @bitCast(usize, isize(oldfd)),
286 @ptrToInt(old),
287 @bitCast(usize, isize(newfd)),
288 @ptrToInt(new),
289 0,
290 );
291 }
889}292}
890293
891// TODO https://github.com/ziglang/zig/issues/265294// TODO https://github.com/ziglang/zig/issues/265
892pub fn renameat2(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const u8, flags: u32) usize {295pub fn renameat2(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const u8, flags: u32) usize {
893 return syscall5(SYS_renameat2, @bitCast(usize, isize(oldfd)), @ptrToInt(oldpath), @bitCast(usize, isize(newfd)), @ptrToInt(newpath), flags);296 return syscall5(
297 SYS_renameat2,
298 @bitCast(usize, isize(oldfd)),
299 @ptrToInt(oldpath),
300 @bitCast(usize, isize(newfd)),
301 @ptrToInt(newpath),
302 flags,
303 );
894}304}
895305
896// TODO https://github.com/ziglang/zig/issues/265306// TODO https://github.com/ziglang/zig/issues/265
897pub fn open(path: [*]const u8, flags: u32, perm: usize) usize {307pub fn open(path: [*]const u8, flags: u32, perm: usize) usize {
898 return openat(AT_FDCWD, path, flags, perm);308 return syscall3(SYS_open, @ptrToInt(path), flags, perm);
899}309}
900310
901// TODO https://github.com/ziglang/zig/issues/265311// TODO https://github.com/ziglang/zig/issues/265
...@@ -923,8 +333,21 @@ pub fn close(fd: i32) usize {...@@ -923,8 +333,21 @@ pub fn close(fd: i32) usize {
923 return syscall1(SYS_close, @bitCast(usize, isize(fd)));333 return syscall1(SYS_close, @bitCast(usize, isize(fd)));
924}334}
925335
926pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize {336/// Can only be called on 32 bit systems. For 64 bit see `lseek`.
927 return syscall3(SYS_lseek, @bitCast(usize, isize(fd)), @bitCast(usize, offset), ref_pos);337pub fn llseek(fd: i32, offset: u64, result: ?*u64, whence: usize) usize {
338 return syscall5(
339 SYS__llseek,
340 @bitCast(usize, isize(fd)),
341 @truncate(usize, offset >> 32),
342 @truncate(usize, offset),
343 @ptrToInt(result),
344 whence,
345 );
346}
347
348/// Can only be called on 64 bit systems. For 32 bit see `llseek`.
349pub fn lseek(fd: i32, offset: i64, whence: usize) usize {
350 return syscall3(SYS_lseek, @bitCast(usize, isize(fd)), @bitCast(usize, offset), whence);
928}351}
929352
930pub fn exit(status: i32) noreturn {353pub fn exit(status: i32) noreturn {
...@@ -947,7 +370,11 @@ pub fn kill(pid: i32, sig: i32) usize {...@@ -947,7 +370,11 @@ pub fn kill(pid: i32, sig: i32) usize {
947370
948// TODO https://github.com/ziglang/zig/issues/265371// TODO https://github.com/ziglang/zig/issues/265
949pub fn unlink(path: [*]const u8) usize {372pub fn unlink(path: [*]const u8) usize {
950 return unlinkat(AT_FDCWD, path, 0);373 if (@hasDecl(@This(), "SYS_unlink")) {
374 return syscall1(SYS_unlink, @ptrToInt(path));
375 } else {
376 return syscall3(SYS_unlinkat, AT_FDCWD, @ptrToInt(path), 0);
377 }
951}378}
952379
953// TODO https://github.com/ziglang/zig/issues/265380// TODO https://github.com/ziglang/zig/issues/265
...@@ -955,8 +382,8 @@ pub fn unlinkat(dirfd: i32, path: [*]const u8, flags: u32) usize {...@@ -955,8 +382,8 @@ pub fn unlinkat(dirfd: i32, path: [*]const u8, flags: u32) usize {
955 return syscall3(SYS_unlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags);382 return syscall3(SYS_unlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags);
956}383}
957384
958pub fn waitpid(pid: i32, status: *i32, options: i32) usize {385pub fn waitpid(pid: i32, status: *u32, flags: u32) usize {
959 return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0);386 return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), flags, 0);
960}387}
961388
962var vdso_clock_gettime = @ptrCast(?*const c_void, init_vdso_clock_gettime);389var 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...@@ -1113,48 +540,15 @@ pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigacti
1113 return 0;540 return 0;
1114}541}
1115542
1116const NSIG = 65;543pub fn blockAllSignals(set: *sigset_t) void {
1117const sigset_t = [128 / @sizeOf(usize)]usize;
1118const all_mask = []u32{ 0xffffffff, 0xffffffff };
1119const app_mask = []u32{ 0xfffffffc, 0x7fffffff };
1120
1121const k_sigaction = extern struct {
1122 handler: extern fn (i32) void,
1123 flags: usize,
1124 restorer: extern fn () void,
1125 mask: [2]u32,
1126};
1127
1128/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
1129pub const Sigaction = struct {
1130 handler: extern fn (i32) void,
1131 mask: sigset_t,
1132 flags: u32,
1133};
1134
1135pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
1136pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
1137pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
1138pub const empty_sigset = []usize{0} ** sigset_t.len;
1139
1140pub fn raise(sig: i32) usize {
1141 var set: sigset_t = undefined;
1142 blockAppSignals(&set);
1143 const tid = syscall0(SYS_gettid);
1144 const ret = syscall2(SYS_tkill, tid, @bitCast(usize, isize(sig)));
1145 restoreSignals(&set);
1146 return ret;
1147}
1148
1149fn blockAllSignals(set: *sigset_t) void {
1150 _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG / 8);544 _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG / 8);
1151}545}
1152546
1153fn blockAppSignals(set: *sigset_t) void {547pub fn blockAppSignals(set: *sigset_t) void {
1154 _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG / 8);548 _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG / 8);
1155}549}
1156550
1157fn restoreSignals(set: *sigset_t) void {551pub fn restoreSignals(set: *sigset_t) void {
1158 _ = syscall4(SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG / 8);552 _ = syscall4(SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG / 8);
1159}553}
1160554
...@@ -1168,56 +562,6 @@ pub fn sigismember(set: *const sigset_t, sig: u6) bool {...@@ -1168,56 +562,6 @@ pub fn sigismember(set: *const sigset_t, sig: u6) bool {
1168 return ((set.*)[@intCast(usize, s) / usize.bit_count] & (@intCast(usize, 1) << (s & (usize.bit_count - 1)))) != 0;562 return ((set.*)[@intCast(usize, s) / usize.bit_count] & (@intCast(usize, 1) << (s & (usize.bit_count - 1)))) != 0;
1169}563}
1170564
1171pub const in_port_t = u16;
1172pub const sa_family_t = u16;
1173pub const socklen_t = u32;
1174
1175/// This intentionally only has ip4 and ip6
1176pub const sockaddr = extern union {
1177 in: sockaddr_in,
1178 in6: sockaddr_in6,
1179};
1180
1181pub const sockaddr_in = extern struct {
1182 family: sa_family_t,
1183 port: in_port_t,
1184 addr: u32,
1185 zero: [8]u8,
1186};
1187
1188pub const sockaddr_in6 = extern struct {
1189 family: sa_family_t,
1190 port: in_port_t,
1191 flowinfo: u32,
1192 addr: [16]u8,
1193 scope_id: u32,
1194};
1195
1196pub const sockaddr_un = extern struct {
1197 family: sa_family_t,
1198 path: [108]u8,
1199};
1200
1201pub const iovec = extern struct {
1202 iov_base: [*]u8,
1203 iov_len: usize,
1204};
1205
1206pub const iovec_const = extern struct {
1207 iov_base: [*]const u8,
1208 iov_len: usize,
1209};
1210
1211pub const mmsghdr = extern struct {
1212 msg_hdr: msghdr,
1213 msg_len: u32,
1214};
1215
1216pub const mmsghdr_const = extern struct {
1217 msg_hdr: msghdr_const,
1218 msg_len: u32,
1219};
1220
1221pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {565pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
1222 return syscall3(SYS_getsockname, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len));566 return syscall3(SYS_getsockname, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len));
1223}567}
...@@ -1328,12 +672,12 @@ pub fn fstat(fd: i32, stat_buf: *Stat) usize {...@@ -1328,12 +672,12 @@ pub fn fstat(fd: i32, stat_buf: *Stat) usize {
1328672
1329// TODO https://github.com/ziglang/zig/issues/265673// TODO https://github.com/ziglang/zig/issues/265
1330pub fn stat(pathname: [*]const u8, statbuf: *Stat) usize {674pub fn stat(pathname: [*]const u8, statbuf: *Stat) usize {
1331 return fstatat(AT_FDCWD, pathname, statbuf, AT_NO_AUTOMOUNT);675 return syscall2(SYS_stat, @ptrToInt(pathname), @ptrToInt(statbuf));
1332}676}
1333677
1334// TODO https://github.com/ziglang/zig/issues/265678// TODO https://github.com/ziglang/zig/issues/265
1335pub fn lstat(pathname: [*]const u8, statbuf: *Stat) usize {679pub fn lstat(pathname: [*]const u8, statbuf: *Stat) usize {
1336 return fstatat(AF_FDCWD, pathname, statbuf, AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT);680 return syscall2(SYS_lstat, @ptrToInt(pathname), @ptrToInt(statbuf));
1337}681}
1338682
1339// TODO https://github.com/ziglang/zig/issues/265683// TODO https://github.com/ziglang/zig/issues/265
...@@ -1400,30 +744,13 @@ pub fn fremovexattr(fd: usize, name: [*]const u8) usize {...@@ -1400,30 +744,13 @@ pub fn fremovexattr(fd: usize, name: [*]const u8) usize {
1400 return syscall2(SYS_fremovexattr, fd, @ptrToInt(name));744 return syscall2(SYS_fremovexattr, fd, @ptrToInt(name));
1401}745}
1402746
1403pub fn sched_getaffinity(pid: i32, set: []usize) usize {747pub fn sched_getaffinity(pid: i32, size: usize, set: *cpu_set_t) usize {
1404 return syscall3(SYS_sched_getaffinity, @bitCast(usize, isize(pid)), set.len * @sizeOf(usize), @ptrToInt(set.ptr));748 const rc = syscall3(SYS_sched_getaffinity, @bitCast(usize, isize(pid)), size, @ptrToInt(set));
749 if (@bitCast(isize, rc) < 0) return rc;
750 if (rc < size) @memset(@ptrCast([*]u8, set) + rc, 0, size - rc);
751 return 0;
1405}752}
1406753
1407pub const epoll_data = extern union {
1408 ptr: usize,
1409 fd: i32,
1410 @"u32": u32,
1411 @"u64": u64,
1412};
1413
1414// On x86_64 the structure is packed so that it matches the definition of its
1415// 32bit counterpart
1416pub const epoll_event = if (builtin.arch != .x86_64)
1417 extern struct {
1418 events: u32,
1419 data: epoll_data,
1420 }
1421else
1422 packed struct {
1423 events: u32,
1424 data: epoll_data,
1425 };
1426
1427pub fn epoll_create() usize {754pub fn epoll_create() usize {
1428 return epoll_create1(0);755 return epoll_create1(0);
1429}756}
...@@ -1437,7 +764,13 @@ pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: *epoll_event) usize {...@@ -1437,7 +764,13 @@ pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: *epoll_event) usize {
1437}764}
1438765
1439pub fn epoll_wait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32) usize {766pub fn epoll_wait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32) usize {
1440 return epoll_pwait(epoll_fd, events, maxevents, timeout, null);767 return syscall4(
768 SYS_epoll_wait,
769 @bitCast(usize, isize(epoll_fd)),
770 @ptrToInt(events),
771 maxevents,
772 @bitCast(usize, isize(timeout)),
773 );
1441}774}
1442775
1443pub fn epoll_pwait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32, sigmask: ?*sigset_t) usize {776pub 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...@@ -1473,112 +806,6 @@ pub fn timerfd_settime(fd: i32, flags: u32, new_value: *const itimerspec, old_va
1473 return syscall4(SYS_timerfd_settime, @bitCast(usize, isize(fd)), flags, @ptrToInt(new_value), @ptrToInt(old_value));806 return syscall4(SYS_timerfd_settime, @bitCast(usize, isize(fd)), flags, @ptrToInt(new_value), @ptrToInt(old_value));
1474}807}
1475808
1476pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330;
1477pub const _LINUX_CAPABILITY_U32S_1 = 1;
1478
1479pub const _LINUX_CAPABILITY_VERSION_2 = 0x20071026;
1480pub const _LINUX_CAPABILITY_U32S_2 = 2;
1481
1482pub const _LINUX_CAPABILITY_VERSION_3 = 0x20080522;
1483pub const _LINUX_CAPABILITY_U32S_3 = 2;
1484
1485pub const VFS_CAP_REVISION_MASK = 0xFF000000;
1486pub const VFS_CAP_REVISION_SHIFT = 24;
1487pub const VFS_CAP_FLAGS_MASK = ~VFS_CAP_REVISION_MASK;
1488pub const VFS_CAP_FLAGS_EFFECTIVE = 0x000001;
1489
1490pub const VFS_CAP_REVISION_1 = 0x01000000;
1491pub const VFS_CAP_U32_1 = 1;
1492pub const XATTR_CAPS_SZ_1 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_1);
1493
1494pub const VFS_CAP_REVISION_2 = 0x02000000;
1495pub const VFS_CAP_U32_2 = 2;
1496pub const XATTR_CAPS_SZ_2 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_2);
1497
1498pub const XATTR_CAPS_SZ = XATTR_CAPS_SZ_2;
1499pub const VFS_CAP_U32 = VFS_CAP_U32_2;
1500pub const VFS_CAP_REVISION = VFS_CAP_REVISION_2;
1501
1502pub const vfs_cap_data = extern struct {
1503 //all of these are mandated as little endian
1504 //when on disk.
1505 const Data = struct {
1506 permitted: u32,
1507 inheritable: u32,
1508 };
1509
1510 magic_etc: u32,
1511 data: [VFS_CAP_U32]Data,
1512};
1513
1514pub const CAP_CHOWN = 0;
1515pub const CAP_DAC_OVERRIDE = 1;
1516pub const CAP_DAC_READ_SEARCH = 2;
1517pub const CAP_FOWNER = 3;
1518pub const CAP_FSETID = 4;
1519pub const CAP_KILL = 5;
1520pub const CAP_SETGID = 6;
1521pub const CAP_SETUID = 7;
1522pub const CAP_SETPCAP = 8;
1523pub const CAP_LINUX_IMMUTABLE = 9;
1524pub const CAP_NET_BIND_SERVICE = 10;
1525pub const CAP_NET_BROADCAST = 11;
1526pub const CAP_NET_ADMIN = 12;
1527pub const CAP_NET_RAW = 13;
1528pub const CAP_IPC_LOCK = 14;
1529pub const CAP_IPC_OWNER = 15;
1530pub const CAP_SYS_MODULE = 16;
1531pub const CAP_SYS_RAWIO = 17;
1532pub const CAP_SYS_CHROOT = 18;
1533pub const CAP_SYS_PTRACE = 19;
1534pub const CAP_SYS_PACCT = 20;
1535pub const CAP_SYS_ADMIN = 21;
1536pub const CAP_SYS_BOOT = 22;
1537pub const CAP_SYS_NICE = 23;
1538pub const CAP_SYS_RESOURCE = 24;
1539pub const CAP_SYS_TIME = 25;
1540pub const CAP_SYS_TTY_CONFIG = 26;
1541pub const CAP_MKNOD = 27;
1542pub const CAP_LEASE = 28;
1543pub const CAP_AUDIT_WRITE = 29;
1544pub const CAP_AUDIT_CONTROL = 30;
1545pub const CAP_SETFCAP = 31;
1546pub const CAP_MAC_OVERRIDE = 32;
1547pub const CAP_MAC_ADMIN = 33;
1548pub const CAP_SYSLOG = 34;
1549pub const CAP_WAKE_ALARM = 35;
1550pub const CAP_BLOCK_SUSPEND = 36;
1551pub const CAP_AUDIT_READ = 37;
1552pub const CAP_LAST_CAP = CAP_AUDIT_READ;
1553
1554pub fn cap_valid(u8: x) bool {
1555 return x >= 0 and x <= CAP_LAST_CAP;
1556}
1557
1558pub fn CAP_TO_MASK(cap: u8) u32 {
1559 return u32(1) << u5(cap & 31);
1560}
1561
1562pub fn CAP_TO_INDEX(cap: u8) u8 {
1563 return cap >> 5;
1564}
1565
1566pub const cap_t = extern struct {
1567 hdrp: *cap_user_header_t,
1568 datap: *cap_user_data_t,
1569};
1570
1571pub const cap_user_header_t = extern struct {
1572 version: u32,
1573 pid: usize,
1574};
1575
1576pub const cap_user_data_t = extern struct {
1577 effective: u32,
1578 permitted: u32,
1579 inheritable: u32,
1580};
1581
1582pub fn unshare(flags: usize) usize {809pub fn unshare(flags: usize) usize {
1583 return syscall1(SYS_unshare, flags);810 return syscall1(SYS_unshare, flags);
1584}811}
...@@ -1591,29 +818,6 @@ pub fn capset(hdrp: *cap_user_header_t, datap: *const cap_user_data_t) usize {...@@ -1591,29 +818,6 @@ pub fn capset(hdrp: *cap_user_header_t, datap: *const cap_user_data_t) usize {
1591 return syscall2(SYS_capset, @ptrToInt(hdrp), @ptrToInt(datap));818 return syscall2(SYS_capset, @ptrToInt(hdrp), @ptrToInt(datap));
1592}819}
1593820
1594pub const inotify_event = extern struct {
1595 wd: i32,
1596 mask: u32,
1597 cookie: u32,
1598 len: u32,
1599 //name: [?]u8,
1600};
1601
1602pub const dirent64 = extern struct {
1603 d_ino: u64,
1604 d_off: u64,
1605 d_reclen: u16,
1606 d_type: u8,
1607 d_name: u8, // field address is the address of first byte of name https://github.com/ziglang/zig/issues/173
1608};
1609
1610pub const dl_phdr_info = extern struct {
1611 dlpi_addr: usize,
1612 dlpi_name: ?[*]const u8,
1613 dlpi_phdr: [*]elf.Phdr,
1614 dlpi_phnum: u16,
1615};
1616
1617// XXX: This should be weak821// XXX: This should be weak
1618extern const __ehdr_start: elf.Ehdr = undefined;822extern const __ehdr_start: elf.Ehdr = undefined;
1619823
...@@ -1671,8 +875,8 @@ pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_inf...@@ -1671,8 +875,8 @@ pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_inf
1671 return last_r;875 return last_r;
1672}876}
1673877
1674test "import" {878test "" {
1675 if (builtin.os == builtin.Os.linux) {879 if (is_the_target) {
1676 _ = @import("linux/test.zig");880 _ = @import("linux/test.zig");
1677 }881 }
1678}882}
std/os/linux/arm64.zig-403
...@@ -1,344 +1,3 @@...@@ -1,344 +1,3 @@
1const std = @import("../../std.zig");
2const linux = std.os.linux;
3const socklen_t = linux.socklen_t;
4const iovec = linux.iovec;
5const iovec_const = linux.iovec_const;
6
7pub const SYS_io_setup = 0;
8pub const SYS_io_destroy = 1;
9pub const SYS_io_submit = 2;
10pub const SYS_io_cancel = 3;
11pub const SYS_io_getevents = 4;
12pub const SYS_setxattr = 5;
13pub const SYS_lsetxattr = 6;
14pub const SYS_fsetxattr = 7;
15pub const SYS_getxattr = 8;
16pub const SYS_lgetxattr = 9;
17pub const SYS_fgetxattr = 10;
18pub const SYS_listxattr = 11;
19pub const SYS_llistxattr = 12;
20pub const SYS_flistxattr = 13;
21pub const SYS_removexattr = 14;
22pub const SYS_lremovexattr = 15;
23pub const SYS_fremovexattr = 16;
24pub const SYS_getcwd = 17;
25pub const SYS_lookup_dcookie = 18;
26pub const SYS_eventfd2 = 19;
27pub const SYS_epoll_create1 = 20;
28pub const SYS_epoll_ctl = 21;
29pub const SYS_epoll_pwait = 22;
30pub const SYS_dup = 23;
31pub const SYS_dup3 = 24;
32pub const SYS_fcntl = 25;
33pub const SYS_inotify_init1 = 26;
34pub const SYS_inotify_add_watch = 27;
35pub const SYS_inotify_rm_watch = 28;
36pub const SYS_ioctl = 29;
37pub const SYS_ioprio_set = 30;
38pub const SYS_ioprio_get = 31;
39pub const SYS_flock = 32;
40pub const SYS_mknodat = 33;
41pub const SYS_mkdirat = 34;
42pub const SYS_unlinkat = 35;
43pub const SYS_symlinkat = 36;
44pub const SYS_linkat = 37;
45pub const SYS_renameat = 38;
46pub const SYS_umount2 = 39;
47pub const SYS_mount = 40;
48pub const SYS_pivot_root = 41;
49pub const SYS_nfsservctl = 42;
50pub const SYS_statfs = 43;
51pub const SYS_fstatfs = 44;
52pub const SYS_truncate = 45;
53pub const SYS_ftruncate = 46;
54pub const SYS_fallocate = 47;
55pub const SYS_faccessat = 48;
56pub const SYS_chdir = 49;
57pub const SYS_fchdir = 50;
58pub const SYS_chroot = 51;
59pub const SYS_fchmod = 52;
60pub const SYS_fchmodat = 53;
61pub const SYS_fchownat = 54;
62pub const SYS_fchown = 55;
63pub const SYS_openat = 56;
64pub const SYS_close = 57;
65pub const SYS_vhangup = 58;
66pub const SYS_pipe2 = 59;
67pub const SYS_quotactl = 60;
68pub const SYS_getdents64 = 61;
69pub const SYS_lseek = 62;
70pub const SYS_read = 63;
71pub const SYS_write = 64;
72pub const SYS_readv = 65;
73pub const SYS_writev = 66;
74pub const SYS_pread64 = 67;
75pub const SYS_pwrite64 = 68;
76pub const SYS_preadv = 69;
77pub const SYS_pwritev = 70;
78pub const SYS_pselect6 = 72;
79pub const SYS_ppoll = 73;
80pub const SYS_signalfd4 = 74;
81pub const SYS_vmsplice = 75;
82pub const SYS_splice = 76;
83pub const SYS_tee = 77;
84pub const SYS_readlinkat = 78;
85pub const SYS_fstatat = 79;
86pub const SYS_fstat = 80;
87pub const SYS_sync = 81;
88pub const SYS_fsync = 82;
89pub const SYS_fdatasync = 83;
90pub const SYS_sync_file_range2 = 84;
91pub const SYS_sync_file_range = 84;
92pub const SYS_timerfd_create = 85;
93pub const SYS_timerfd_settime = 86;
94pub const SYS_timerfd_gettime = 87;
95pub const SYS_utimensat = 88;
96pub const SYS_acct = 89;
97pub const SYS_capget = 90;
98pub const SYS_capset = 91;
99pub const SYS_personality = 92;
100pub const SYS_exit = 93;
101pub const SYS_exit_group = 94;
102pub const SYS_waitid = 95;
103pub const SYS_set_tid_address = 96;
104pub const SYS_unshare = 97;
105pub const SYS_futex = 98;
106pub const SYS_set_robust_list = 99;
107pub const SYS_get_robust_list = 100;
108pub const SYS_nanosleep = 101;
109pub const SYS_getitimer = 102;
110pub const SYS_setitimer = 103;
111pub const SYS_kexec_load = 104;
112pub const SYS_init_module = 105;
113pub const SYS_delete_module = 106;
114pub const SYS_timer_create = 107;
115pub const SYS_timer_gettime = 108;
116pub const SYS_timer_getoverrun = 109;
117pub const SYS_timer_settime = 110;
118pub const SYS_timer_delete = 111;
119pub const SYS_clock_settime = 112;
120pub const SYS_clock_gettime = 113;
121pub const SYS_clock_getres = 114;
122pub const SYS_clock_nanosleep = 115;
123pub const SYS_syslog = 116;
124pub const SYS_ptrace = 117;
125pub const SYS_sched_setparam = 118;
126pub const SYS_sched_setscheduler = 119;
127pub const SYS_sched_getscheduler = 120;
128pub const SYS_sched_getparam = 121;
129pub const SYS_sched_setaffinity = 122;
130pub const SYS_sched_getaffinity = 123;
131pub const SYS_sched_yield = 124;
132pub const SYS_sched_get_priority_max = 125;
133pub const SYS_sched_get_priority_min = 126;
134pub const SYS_sched_rr_get_interval = 127;
135pub const SYS_restart_syscall = 128;
136pub const SYS_kill = 129;
137pub const SYS_tkill = 130;
138pub const SYS_tgkill = 131;
139pub const SYS_sigaltstack = 132;
140pub const SYS_rt_sigsuspend = 133;
141pub const SYS_rt_sigaction = 134;
142pub const SYS_rt_sigprocmask = 135;
143pub const SYS_rt_sigpending = 136;
144pub const SYS_rt_sigtimedwait = 137;
145pub const SYS_rt_sigqueueinfo = 138;
146pub const SYS_rt_sigreturn = 139;
147pub const SYS_setpriority = 140;
148pub const SYS_getpriority = 141;
149pub const SYS_reboot = 142;
150pub const SYS_setregid = 143;
151pub const SYS_setgid = 144;
152pub const SYS_setreuid = 145;
153pub const SYS_setuid = 146;
154pub const SYS_setresuid = 147;
155pub const SYS_getresuid = 148;
156pub const SYS_setresgid = 149;
157pub const SYS_getresgid = 150;
158pub const SYS_setfsuid = 151;
159pub const SYS_setfsgid = 152;
160pub const SYS_times = 153;
161pub const SYS_setpgid = 154;
162pub const SYS_getpgid = 155;
163pub const SYS_getsid = 156;
164pub const SYS_setsid = 157;
165pub const SYS_getgroups = 158;
166pub const SYS_setgroups = 159;
167pub const SYS_uname = 160;
168pub const SYS_sethostname = 161;
169pub const SYS_setdomainname = 162;
170pub const SYS_getrlimit = 163;
171pub const SYS_setrlimit = 164;
172pub const SYS_getrusage = 165;
173pub const SYS_umask = 166;
174pub const SYS_prctl = 167;
175pub const SYS_getcpu = 168;
176pub const SYS_gettimeofday = 169;
177pub const SYS_settimeofday = 170;
178pub const SYS_adjtimex = 171;
179pub const SYS_getpid = 172;
180pub const SYS_getppid = 173;
181pub const SYS_getuid = 174;
182pub const SYS_geteuid = 175;
183pub const SYS_getgid = 176;
184pub const SYS_getegid = 177;
185pub const SYS_gettid = 178;
186pub const SYS_sysinfo = 179;
187pub const SYS_mq_open = 180;
188pub const SYS_mq_unlink = 181;
189pub const SYS_mq_timedsend = 182;
190pub const SYS_mq_timedreceive = 183;
191pub const SYS_mq_notify = 184;
192pub const SYS_mq_getsetattr = 185;
193pub const SYS_msgget = 186;
194pub const SYS_msgctl = 187;
195pub const SYS_msgrcv = 188;
196pub const SYS_msgsnd = 189;
197pub const SYS_semget = 190;
198pub const SYS_semctl = 191;
199pub const SYS_semtimedop = 192;
200pub const SYS_semop = 193;
201pub const SYS_shmget = 194;
202pub const SYS_shmctl = 195;
203pub const SYS_shmat = 196;
204pub const SYS_shmdt = 197;
205pub const SYS_socket = 198;
206pub const SYS_socketpair = 199;
207pub const SYS_bind = 200;
208pub const SYS_listen = 201;
209pub const SYS_accept = 202;
210pub const SYS_connect = 203;
211pub const SYS_getsockname = 204;
212pub const SYS_getpeername = 205;
213pub const SYS_sendto = 206;
214pub const SYS_recvfrom = 207;
215pub const SYS_setsockopt = 208;
216pub const SYS_getsockopt = 209;
217pub const SYS_shutdown = 210;
218pub const SYS_sendmsg = 211;
219pub const SYS_recvmsg = 212;
220pub const SYS_readahead = 213;
221pub const SYS_brk = 214;
222pub const SYS_munmap = 215;
223pub const SYS_mremap = 216;
224pub const SYS_add_key = 217;
225pub const SYS_request_key = 218;
226pub const SYS_keyctl = 219;
227pub const SYS_clone = 220;
228pub const SYS_execve = 221;
229pub const SYS_mmap = 222;
230pub const SYS_fadvise64 = 223;
231pub const SYS_swapon = 224;
232pub const SYS_swapoff = 225;
233pub const SYS_mprotect = 226;
234pub const SYS_msync = 227;
235pub const SYS_mlock = 228;
236pub const SYS_munlock = 229;
237pub const SYS_mlockall = 230;
238pub const SYS_munlockall = 231;
239pub const SYS_mincore = 232;
240pub const SYS_madvise = 233;
241pub const SYS_remap_file_pages = 234;
242pub const SYS_mbind = 235;
243pub const SYS_get_mempolicy = 236;
244pub const SYS_set_mempolicy = 237;
245pub const SYS_migrate_pages = 238;
246pub const SYS_move_pages = 239;
247pub const SYS_rt_tgsigqueueinfo = 240;
248pub const SYS_perf_event_open = 241;
249pub const SYS_accept4 = 242;
250pub const SYS_recvmmsg = 243;
251pub const SYS_arch_specific_syscall = 244;
252pub const SYS_wait4 = 260;
253pub const SYS_prlimit64 = 261;
254pub const SYS_fanotify_init = 262;
255pub const SYS_fanotify_mark = 263;
256pub const SYS_clock_adjtime = 266;
257pub const SYS_syncfs = 267;
258pub const SYS_setns = 268;
259pub const SYS_sendmmsg = 269;
260pub const SYS_process_vm_readv = 270;
261pub const SYS_process_vm_writev = 271;
262pub const SYS_kcmp = 272;
263pub const SYS_finit_module = 273;
264pub const SYS_sched_setattr = 274;
265pub const SYS_sched_getattr = 275;
266pub const SYS_renameat2 = 276;
267pub const SYS_seccomp = 277;
268pub const SYS_getrandom = 278;
269pub const SYS_memfd_create = 279;
270pub const SYS_bpf = 280;
271pub const SYS_execveat = 281;
272pub const SYS_userfaultfd = 282;
273pub const SYS_membarrier = 283;
274pub const SYS_mlock2 = 284;
275pub const SYS_copy_file_range = 285;
276pub const SYS_preadv2 = 286;
277pub const SYS_pwritev2 = 287;
278pub const SYS_pkey_mprotect = 288;
279pub const SYS_pkey_alloc = 289;
280pub const SYS_pkey_free = 290;
281pub const SYS_statx = 291;
282pub const SYS_io_pgetevents = 292;
283pub const SYS_rseq = 293;
284pub const SYS_kexec_file_load = 294;
285pub const SYS_pidfd_send_signal = 424;
286pub const SYS_io_uring_setup = 425;
287pub const SYS_io_uring_enter = 426;
288pub const SYS_io_uring_register = 427;
289
290pub const O_CREAT = 0o100;
291pub const O_EXCL = 0o200;
292pub const O_NOCTTY = 0o400;
293pub const O_TRUNC = 0o1000;
294pub const O_APPEND = 0o2000;
295pub const O_NONBLOCK = 0o4000;
296pub const O_DSYNC = 0o10000;
297pub const O_SYNC = 0o4010000;
298pub const O_RSYNC = 0o4010000;
299pub const O_DIRECTORY = 0o200000;
300pub const O_NOFOLLOW = 0o400000;
301pub const O_CLOEXEC = 0o2000000;
302
303pub const O_ASYNC = 0o20000;
304pub const O_DIRECT = 0o40000;
305pub const O_LARGEFILE = 0;
306pub const O_NOATIME = 0o1000000;
307pub const O_PATH = 0o10000000;
308pub const O_TMPFILE = 0o20200000;
309pub const O_NDELAY = O_NONBLOCK;
310
311pub const F_DUPFD = 0;
312pub const F_GETFD = 1;
313pub const F_SETFD = 2;
314pub const F_GETFL = 3;
315pub const F_SETFL = 4;
316
317pub const F_SETOWN = 8;
318pub const F_GETOWN = 9;
319pub const F_SETSIG = 10;
320pub const F_GETSIG = 11;
321
322pub const F_GETLK = 5;
323pub const F_SETLK = 6;
324pub const F_SETLKW = 7;
325
326pub const F_SETOWN_EX = 15;
327pub const F_GETOWN_EX = 16;
328
329pub const F_GETOWNER_UIDS = 17;
330
331pub const AT_FDCWD = -100;
332pub const AT_SYMLINK_NOFOLLOW = 0x100;
333pub const AT_REMOVEDIR = 0x200;
334pub const AT_SYMLINK_FOLLOW = 0x400;
335pub const AT_NO_AUTOMOUNT = 0x800;
336pub const AT_EMPTY_PATH = 0x1000;
337
338pub const VDSO_USEFUL = true;
339pub const VDSO_CGT_SYM = "__kernel_clock_gettime";
340pub const VDSO_CGT_VER = "LINUX_2.6.39";
341
342pub fn syscall0(number: usize) usize {1pub fn syscall0(number: usize) usize {
343 return asm volatile ("svc #0"2 return asm volatile ("svc #0"
344 : [ret] "={x0}" (-> usize)3 : [ret] "={x0}" (-> usize)
...@@ -419,65 +78,3 @@ pub fn syscall6(...@@ -419,65 +78,3 @@ pub fn syscall6(
41978
420/// This matches the libc clone function.79/// This matches the libc clone function.
421pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;80pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
422
423pub const msghdr = extern struct {
424 msg_name: ?*sockaddr,
425 msg_namelen: socklen_t,
426 msg_iov: [*]iovec,
427 msg_iovlen: i32,
428 __pad1: i32,
429 msg_control: ?*c_void,
430 msg_controllen: socklen_t,
431 __pad2: socklen_t,
432 msg_flags: i32,
433};
434
435pub const msghdr_const = extern struct {
436 msg_name: ?*const sockaddr,
437 msg_namelen: socklen_t,
438 msg_iov: [*]iovec_const,
439 msg_iovlen: i32,
440 __pad1: i32,
441 msg_control: ?*c_void,
442 msg_controllen: socklen_t,
443 __pad2: socklen_t,
444 msg_flags: i32,
445};
446
447/// Renamed to Stat to not conflict with the stat function.
448pub const Stat = extern struct {
449 dev: u64,
450 ino: u64,
451 nlink: usize,
452
453 mode: u32,
454 uid: u32,
455 gid: u32,
456 __pad0: u32,
457 rdev: u64,
458 size: i64,
459 blksize: isize,
460 blocks: i64,
461
462 atim: timespec,
463 mtim: timespec,
464 ctim: timespec,
465 __unused: [3]isize,
466};
467
468pub const timespec = extern struct {
469 tv_sec: isize,
470 tv_nsec: isize,
471};
472
473pub const timeval = extern struct {
474 tv_sec: isize,
475 tv_usec: isize,
476};
477
478pub const timezone = extern struct {
479 tz_minuteswest: i32,
480 tz_dsttime: i32,
481};
482
483pub const Elf_Symndx = u32;
std/os/linux/errno.zig deleted-427
...@@ -1,427 +0,0 @@
1/// Operation not permitted
2pub const EPERM = 1;
3
4/// No such file or directory
5pub const ENOENT = 2;
6
7/// No such process
8pub const ESRCH = 3;
9
10/// Interrupted system call
11pub const EINTR = 4;
12
13/// I/O error
14pub const EIO = 5;
15
16/// No such device or address
17pub const ENXIO = 6;
18
19/// Arg list too long
20pub const E2BIG = 7;
21
22/// Exec format error
23pub const ENOEXEC = 8;
24
25/// Bad file number
26pub const EBADF = 9;
27
28/// No child processes
29pub const ECHILD = 10;
30
31/// Try again
32pub const EAGAIN = 11;
33
34/// Out of memory
35pub const ENOMEM = 12;
36
37/// Permission denied
38pub const EACCES = 13;
39
40/// Bad address
41pub const EFAULT = 14;
42
43/// Block device required
44pub const ENOTBLK = 15;
45
46/// Device or resource busy
47pub const EBUSY = 16;
48
49/// File exists
50pub const EEXIST = 17;
51
52/// Cross-device link
53pub const EXDEV = 18;
54
55/// No such device
56pub const ENODEV = 19;
57
58/// Not a directory
59pub const ENOTDIR = 20;
60
61/// Is a directory
62pub const EISDIR = 21;
63
64/// Invalid argument
65pub const EINVAL = 22;
66
67/// File table overflow
68pub const ENFILE = 23;
69
70/// Too many open files
71pub const EMFILE = 24;
72
73/// Not a typewriter
74pub const ENOTTY = 25;
75
76/// Text file busy
77pub const ETXTBSY = 26;
78
79/// File too large
80pub const EFBIG = 27;
81
82/// No space left on device
83pub const ENOSPC = 28;
84
85/// Illegal seek
86pub const ESPIPE = 29;
87
88/// Read-only file system
89pub const EROFS = 30;
90
91/// Too many links
92pub const EMLINK = 31;
93
94/// Broken pipe
95pub const EPIPE = 32;
96
97/// Math argument out of domain of func
98pub const EDOM = 33;
99
100/// Math result not representable
101pub const ERANGE = 34;
102
103/// Resource deadlock would occur
104pub const EDEADLK = 35;
105
106/// File name too long
107pub const ENAMETOOLONG = 36;
108
109/// No record locks available
110pub const ENOLCK = 37;
111
112/// Function not implemented
113pub const ENOSYS = 38;
114
115/// Directory not empty
116pub const ENOTEMPTY = 39;
117
118/// Too many symbolic links encountered
119pub const ELOOP = 40;
120
121/// Operation would block
122pub const EWOULDBLOCK = EAGAIN;
123
124/// No message of desired type
125pub const ENOMSG = 42;
126
127/// Identifier removed
128pub const EIDRM = 43;
129
130/// Channel number out of range
131pub const ECHRNG = 44;
132
133/// Level 2 not synchronized
134pub const EL2NSYNC = 45;
135
136/// Level 3 halted
137pub const EL3HLT = 46;
138
139/// Level 3 reset
140pub const EL3RST = 47;
141
142/// Link number out of range
143pub const ELNRNG = 48;
144
145/// Protocol driver not attached
146pub const EUNATCH = 49;
147
148/// No CSI structure available
149pub const ENOCSI = 50;
150
151/// Level 2 halted
152pub const EL2HLT = 51;
153
154/// Invalid exchange
155pub const EBADE = 52;
156
157/// Invalid request descriptor
158pub const EBADR = 53;
159
160/// Exchange full
161pub const EXFULL = 54;
162
163/// No anode
164pub const ENOANO = 55;
165
166/// Invalid request code
167pub const EBADRQC = 56;
168
169/// Invalid slot
170pub const EBADSLT = 57;
171
172/// Bad font file format
173pub const EBFONT = 59;
174
175/// Device not a stream
176pub const ENOSTR = 60;
177
178/// No data available
179pub const ENODATA = 61;
180
181/// Timer expired
182pub const ETIME = 62;
183
184/// Out of streams resources
185pub const ENOSR = 63;
186
187/// Machine is not on the network
188pub const ENONET = 64;
189
190/// Package not installed
191pub const ENOPKG = 65;
192
193/// Object is remote
194pub const EREMOTE = 66;
195
196/// Link has been severed
197pub const ENOLINK = 67;
198
199/// Advertise error
200pub const EADV = 68;
201
202/// Srmount error
203pub const ESRMNT = 69;
204
205/// Communication error on send
206pub const ECOMM = 70;
207
208/// Protocol error
209pub const EPROTO = 71;
210
211/// Multihop attempted
212pub const EMULTIHOP = 72;
213
214/// RFS specific error
215pub const EDOTDOT = 73;
216
217/// Not a data message
218pub const EBADMSG = 74;
219
220/// Value too large for defined data type
221pub const EOVERFLOW = 75;
222
223/// Name not unique on network
224pub const ENOTUNIQ = 76;
225
226/// File descriptor in bad state
227pub const EBADFD = 77;
228
229/// Remote address changed
230pub const EREMCHG = 78;
231
232/// Can not access a needed shared library
233pub const ELIBACC = 79;
234
235/// Accessing a corrupted shared library
236pub const ELIBBAD = 80;
237
238/// .lib section in a.out corrupted
239pub const ELIBSCN = 81;
240
241/// Attempting to link in too many shared libraries
242pub const ELIBMAX = 82;
243
244/// Cannot exec a shared library directly
245pub const ELIBEXEC = 83;
246
247/// Illegal byte sequence
248pub const EILSEQ = 84;
249
250/// Interrupted system call should be restarted
251pub const ERESTART = 85;
252
253/// Streams pipe error
254pub const ESTRPIPE = 86;
255
256/// Too many users
257pub const EUSERS = 87;
258
259/// Socket operation on non-socket
260pub const ENOTSOCK = 88;
261
262/// Destination address required
263pub const EDESTADDRREQ = 89;
264
265/// Message too long
266pub const EMSGSIZE = 90;
267
268/// Protocol wrong type for socket
269pub const EPROTOTYPE = 91;
270
271/// Protocol not available
272pub const ENOPROTOOPT = 92;
273
274/// Protocol not supported
275pub const EPROTONOSUPPORT = 93;
276
277/// Socket type not supported
278pub const ESOCKTNOSUPPORT = 94;
279
280/// Operation not supported on transport endpoint
281pub const EOPNOTSUPP = 95;
282
283/// Protocol family not supported
284pub const EPFNOSUPPORT = 96;
285
286/// Address family not supported by protocol
287pub const EAFNOSUPPORT = 97;
288
289/// Address already in use
290pub const EADDRINUSE = 98;
291
292/// Cannot assign requested address
293pub const EADDRNOTAVAIL = 99;
294
295/// Network is down
296pub const ENETDOWN = 100;
297
298/// Network is unreachable
299pub const ENETUNREACH = 101;
300
301/// Network dropped connection because of reset
302pub const ENETRESET = 102;
303
304/// Software caused connection abort
305pub const ECONNABORTED = 103;
306
307/// Connection reset by peer
308pub const ECONNRESET = 104;
309
310/// No buffer space available
311pub const ENOBUFS = 105;
312
313/// Transport endpoint is already connected
314pub const EISCONN = 106;
315
316/// Transport endpoint is not connected
317pub const ENOTCONN = 107;
318
319/// Cannot send after transport endpoint shutdown
320pub const ESHUTDOWN = 108;
321
322/// Too many references: cannot splice
323pub const ETOOMANYREFS = 109;
324
325/// Connection timed out
326pub const ETIMEDOUT = 110;
327
328/// Connection refused
329pub const ECONNREFUSED = 111;
330
331/// Host is down
332pub const EHOSTDOWN = 112;
333
334/// No route to host
335pub const EHOSTUNREACH = 113;
336
337/// Operation already in progress
338pub const EALREADY = 114;
339
340/// Operation now in progress
341pub const EINPROGRESS = 115;
342
343/// Stale NFS file handle
344pub const ESTALE = 116;
345
346/// Structure needs cleaning
347pub const EUCLEAN = 117;
348
349/// Not a XENIX named type file
350pub const ENOTNAM = 118;
351
352/// No XENIX semaphores available
353pub const ENAVAIL = 119;
354
355/// Is a named type file
356pub const EISNAM = 120;
357
358/// Remote I/O error
359pub const EREMOTEIO = 121;
360
361/// Quota exceeded
362pub const EDQUOT = 122;
363
364/// No medium found
365pub const ENOMEDIUM = 123;
366
367/// Wrong medium type
368pub const EMEDIUMTYPE = 124;
369
370// nameserver query return codes
371
372/// DNS server returned answer with no data
373pub const ENSROK = 0;
374
375/// DNS server returned answer with no data
376pub const ENSRNODATA = 160;
377
378/// DNS server claims query was misformatted
379pub const ENSRFORMERR = 161;
380
381/// DNS server returned general failure
382pub const ENSRSERVFAIL = 162;
383
384/// Domain name not found
385pub const ENSRNOTFOUND = 163;
386
387/// DNS server does not implement requested operation
388pub const ENSRNOTIMP = 164;
389
390/// DNS server refused query
391pub const ENSRREFUSED = 165;
392
393/// Misformatted DNS query
394pub const ENSRBADQUERY = 166;
395
396/// Misformatted domain name
397pub const ENSRBADNAME = 167;
398
399/// Unsupported address family
400pub const ENSRBADFAMILY = 168;
401
402/// Misformatted DNS reply
403pub const ENSRBADRESP = 169;
404
405/// Could not contact DNS servers
406pub const ENSRCONNREFUSED = 170;
407
408/// Timeout while contacting DNS servers
409pub const ENSRTIMEOUT = 171;
410
411/// End of file
412pub const ENSROF = 172;
413
414/// Error reading file
415pub const ENSRFILE = 173;
416
417/// Out of memory
418pub const ENSRNOMEM = 174;
419
420/// Application terminated lookup
421pub const ENSRDESTRUCTION = 175;
422
423/// Domain name is too long
424pub const ENSRQUERYDOMAINTOOLONG = 176;
425
426/// Domain name is too long
427pub const ENSRCNAMELOOP = 177;
std/os/linux/test.zig+1-1
...@@ -11,7 +11,7 @@ test "getpid" {...@@ -11,7 +11,7 @@ test "getpid" {
1111
12test "timer" {12test "timer" {
13 const epoll_fd = linux.epoll_create();13 const epoll_fd = linux.epoll_create();
14 var err = linux.getErrno(epoll_fd);14 var err: usize = linux.getErrno(epoll_fd);
15 expect(err == 0);15 expect(err == 0);
1616
17 const timer_fd = linux.timerfd_create(linux.CLOCK_MONOTONIC, 0);17 const timer_fd = linux.timerfd_create(linux.CLOCK_MONOTONIC, 0);
std/os/linux/tls.zig+11-6
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const os = std.os;
2const mem = std.mem;3const mem = std.mem;
3const posix = std.os.posix;
4const elf = std.elf;4const elf = std.elf;
5const builtin = @import("builtin");5const builtin = @import("builtin");
6const assert = std.debug.assert;6const assert = std.debug.assert;
...@@ -126,7 +126,7 @@ pub fn initTLS() void {...@@ -126,7 +126,7 @@ pub fn initTLS() void {
126 var tls_phdr: ?*elf.Phdr = null;126 var tls_phdr: ?*elf.Phdr = null;
127 var img_base: usize = 0;127 var img_base: usize = 0;
128128
129 const auxv = std.os.linux_elf_aux_maybe.?;129 const auxv = std.os.linux.elf_aux_maybe.?;
130 var at_phent: usize = undefined;130 var at_phent: usize = undefined;
131 var at_phnum: usize = undefined;131 var at_phnum: usize = undefined;
132 var at_phdr: usize = undefined;132 var at_phdr: usize = undefined;
...@@ -237,9 +237,14 @@ pub fn allocateTLS(size: usize) usize {...@@ -237,9 +237,14 @@ pub fn allocateTLS(size: usize) usize {
237 return @ptrToInt(&main_thread_tls_buffer);237 return @ptrToInt(&main_thread_tls_buffer);
238 }238 }
239239
240 const addr = posix.mmap(null, size, posix.PROT_READ | posix.PROT_WRITE, posix.MAP_PRIVATE | posix.MAP_ANONYMOUS, -1, 0);240 const slice = os.mmap(
241 null,
242 size,
243 os.PROT_READ | os.PROT_WRITE,
244 os.MAP_PRIVATE | os.MAP_ANONYMOUS,
245 -1,
246 0,
247 ) catch @panic("out of memory");
241248
242 if (posix.getErrno(addr) != 0) @panic("out of memory");249 return @ptrToInt(slice.ptr);
243
244 return addr;
245}250}
std/os/linux/vdso.zig+3-4
...@@ -1,12 +1,11 @@...@@ -1,12 +1,11 @@
1const std = @import("../../std.zig");1const std = @import("../../std.zig");
2const elf = std.elf;2const elf = std.elf;
3const linux = std.os.linux;3const linux = std.os.linux;
4const cstr = std.cstr;
5const mem = std.mem;4const mem = std.mem;
6const maxInt = std.math.maxInt;5const maxInt = std.math.maxInt;
76
8pub fn lookup(vername: []const u8, name: []const u8) usize {7pub fn lookup(vername: []const u8, name: []const u8) usize {
9 const vdso_addr = std.os.linuxGetAuxVal(std.elf.AT_SYSINFO_EHDR);8 const vdso_addr = std.os.system.getauxval(std.elf.AT_SYSINFO_EHDR);
10 if (vdso_addr == 0) return 0;9 if (vdso_addr == 0) return 0;
1110
12 const eh = @intToPtr(*elf.Ehdr, vdso_addr);11 const eh = @intToPtr(*elf.Ehdr, vdso_addr);
...@@ -66,7 +65,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {...@@ -66,7 +65,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize {
66 if (0 == (u32(1) << @intCast(u5, syms[i].st_info & 0xf) & OK_TYPES)) continue;65 if (0 == (u32(1) << @intCast(u5, syms[i].st_info & 0xf) & OK_TYPES)) continue;
67 if (0 == (u32(1) << @intCast(u5, syms[i].st_info >> 4) & OK_BINDS)) continue;66 if (0 == (u32(1) << @intCast(u5, syms[i].st_info >> 4) & OK_BINDS)) continue;
68 if (0 == syms[i].st_shndx) continue;67 if (0 == syms[i].st_shndx) continue;
69 if (!mem.eql(u8, name, cstr.toSliceConst(strings + syms[i].st_name))) continue;68 if (!mem.eql(u8, name, mem.toSliceConst(u8, strings + syms[i].st_name))) continue;
70 if (maybe_versym) |versym| {69 if (maybe_versym) |versym| {
71 if (!checkver(maybe_verdef.?, versym[i], vername, strings))70 if (!checkver(maybe_verdef.?, versym[i], vername, strings))
72 continue;71 continue;
...@@ -88,5 +87,5 @@ fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [...@@ -88,5 +87,5 @@ fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [
88 def = @intToPtr(*elf.Verdef, @ptrToInt(def) + def.vd_next);87 def = @intToPtr(*elf.Verdef, @ptrToInt(def) + def.vd_next);
89 }88 }
90 const aux = @intToPtr(*elf.Verdaux, @ptrToInt(def) + def.vd_aux);89 const aux = @intToPtr(*elf.Verdaux, @ptrToInt(def) + def.vd_aux);
91 return mem.eql(u8, vername, cstr.toSliceConst(strings + aux.vda_name));90 return mem.eql(u8, vername, mem.toSliceConst(u8, strings + aux.vda_name));
92}91}
std/os/linux/x86_64.zig+1-469
...@@ -1,410 +1,4 @@...@@ -1,410 +1,4 @@
1const std = @import("../../std.zig");1use @import("../bits.zig");
2const linux = std.os.linux;
3const sockaddr = linux.sockaddr;
4const socklen_t = linux.socklen_t;
5const iovec = linux.iovec;
6const iovec_const = linux.iovec_const;
7
8pub const SYS_read = 0;
9pub const SYS_write = 1;
10pub const SYS_open = 2;
11pub const SYS_close = 3;
12pub const SYS_stat = 4;
13pub const SYS_fstat = 5;
14pub const SYS_lstat = 6;
15pub const SYS_poll = 7;
16pub const SYS_lseek = 8;
17pub const SYS_mmap = 9;
18pub const SYS_mprotect = 10;
19pub const SYS_munmap = 11;
20pub const SYS_brk = 12;
21pub const SYS_rt_sigaction = 13;
22pub const SYS_rt_sigprocmask = 14;
23pub const SYS_rt_sigreturn = 15;
24pub const SYS_ioctl = 16;
25pub const SYS_pread = 17;
26pub const SYS_pwrite = 18;
27pub const SYS_readv = 19;
28pub const SYS_writev = 20;
29pub const SYS_access = 21;
30pub const SYS_pipe = 22;
31pub const SYS_select = 23;
32pub const SYS_sched_yield = 24;
33pub const SYS_mremap = 25;
34pub const SYS_msync = 26;
35pub const SYS_mincore = 27;
36pub const SYS_madvise = 28;
37pub const SYS_shmget = 29;
38pub const SYS_shmat = 30;
39pub const SYS_shmctl = 31;
40pub const SYS_dup = 32;
41pub const SYS_dup2 = 33;
42pub const SYS_pause = 34;
43pub const SYS_nanosleep = 35;
44pub const SYS_getitimer = 36;
45pub const SYS_alarm = 37;
46pub const SYS_setitimer = 38;
47pub const SYS_getpid = 39;
48pub const SYS_sendfile = 40;
49pub const SYS_socket = 41;
50pub const SYS_connect = 42;
51pub const SYS_accept = 43;
52pub const SYS_sendto = 44;
53pub const SYS_recvfrom = 45;
54pub const SYS_sendmsg = 46;
55pub const SYS_recvmsg = 47;
56pub const SYS_shutdown = 48;
57pub const SYS_bind = 49;
58pub const SYS_listen = 50;
59pub const SYS_getsockname = 51;
60pub const SYS_getpeername = 52;
61pub const SYS_socketpair = 53;
62pub const SYS_setsockopt = 54;
63pub const SYS_getsockopt = 55;
64pub const SYS_clone = 56;
65pub const SYS_fork = 57;
66pub const SYS_vfork = 58;
67pub const SYS_execve = 59;
68pub const SYS_exit = 60;
69pub const SYS_wait4 = 61;
70pub const SYS_kill = 62;
71pub const SYS_uname = 63;
72pub const SYS_semget = 64;
73pub const SYS_semop = 65;
74pub const SYS_semctl = 66;
75pub const SYS_shmdt = 67;
76pub const SYS_msgget = 68;
77pub const SYS_msgsnd = 69;
78pub const SYS_msgrcv = 70;
79pub const SYS_msgctl = 71;
80pub const SYS_fcntl = 72;
81pub const SYS_flock = 73;
82pub const SYS_fsync = 74;
83pub const SYS_fdatasync = 75;
84pub const SYS_truncate = 76;
85pub const SYS_ftruncate = 77;
86pub const SYS_getdents = 78;
87pub const SYS_getcwd = 79;
88pub const SYS_chdir = 80;
89pub const SYS_fchdir = 81;
90pub const SYS_rename = 82;
91pub const SYS_mkdir = 83;
92pub const SYS_rmdir = 84;
93pub const SYS_creat = 85;
94pub const SYS_link = 86;
95pub const SYS_unlink = 87;
96pub const SYS_symlink = 88;
97pub const SYS_readlink = 89;
98pub const SYS_chmod = 90;
99pub const SYS_fchmod = 91;
100pub const SYS_chown = 92;
101pub const SYS_fchown = 93;
102pub const SYS_lchown = 94;
103pub const SYS_umask = 95;
104pub const SYS_gettimeofday = 96;
105pub const SYS_getrlimit = 97;
106pub const SYS_getrusage = 98;
107pub const SYS_sysinfo = 99;
108pub const SYS_times = 100;
109pub const SYS_ptrace = 101;
110pub const SYS_getuid = 102;
111pub const SYS_syslog = 103;
112pub const SYS_getgid = 104;
113pub const SYS_setuid = 105;
114pub const SYS_setgid = 106;
115pub const SYS_geteuid = 107;
116pub const SYS_getegid = 108;
117pub const SYS_setpgid = 109;
118pub const SYS_getppid = 110;
119pub const SYS_getpgrp = 111;
120pub const SYS_setsid = 112;
121pub const SYS_setreuid = 113;
122pub const SYS_setregid = 114;
123pub const SYS_getgroups = 115;
124pub const SYS_setgroups = 116;
125pub const SYS_setresuid = 117;
126pub const SYS_getresuid = 118;
127pub const SYS_setresgid = 119;
128pub const SYS_getresgid = 120;
129pub const SYS_getpgid = 121;
130pub const SYS_setfsuid = 122;
131pub const SYS_setfsgid = 123;
132pub const SYS_getsid = 124;
133pub const SYS_capget = 125;
134pub const SYS_capset = 126;
135pub const SYS_rt_sigpending = 127;
136pub const SYS_rt_sigtimedwait = 128;
137pub const SYS_rt_sigqueueinfo = 129;
138pub const SYS_rt_sigsuspend = 130;
139pub const SYS_sigaltstack = 131;
140pub const SYS_utime = 132;
141pub const SYS_mknod = 133;
142pub const SYS_uselib = 134;
143pub const SYS_personality = 135;
144pub const SYS_ustat = 136;
145pub const SYS_statfs = 137;
146pub const SYS_fstatfs = 138;
147pub const SYS_sysfs = 139;
148pub const SYS_getpriority = 140;
149pub const SYS_setpriority = 141;
150pub const SYS_sched_setparam = 142;
151pub const SYS_sched_getparam = 143;
152pub const SYS_sched_setscheduler = 144;
153pub const SYS_sched_getscheduler = 145;
154pub const SYS_sched_get_priority_max = 146;
155pub const SYS_sched_get_priority_min = 147;
156pub const SYS_sched_rr_get_interval = 148;
157pub const SYS_mlock = 149;
158pub const SYS_munlock = 150;
159pub const SYS_mlockall = 151;
160pub const SYS_munlockall = 152;
161pub const SYS_vhangup = 153;
162pub const SYS_modify_ldt = 154;
163pub const SYS_pivot_root = 155;
164pub const SYS__sysctl = 156;
165pub const SYS_prctl = 157;
166pub const SYS_arch_prctl = 158;
167pub const SYS_adjtimex = 159;
168pub const SYS_setrlimit = 160;
169pub const SYS_chroot = 161;
170pub const SYS_sync = 162;
171pub const SYS_acct = 163;
172pub const SYS_settimeofday = 164;
173pub const SYS_mount = 165;
174pub const SYS_umount2 = 166;
175pub const SYS_swapon = 167;
176pub const SYS_swapoff = 168;
177pub const SYS_reboot = 169;
178pub const SYS_sethostname = 170;
179pub const SYS_setdomainname = 171;
180pub const SYS_iopl = 172;
181pub const SYS_ioperm = 173;
182pub const SYS_create_module = 174;
183pub const SYS_init_module = 175;
184pub const SYS_delete_module = 176;
185pub const SYS_get_kernel_syms = 177;
186pub const SYS_query_module = 178;
187pub const SYS_quotactl = 179;
188pub const SYS_nfsservctl = 180;
189pub const SYS_getpmsg = 181;
190pub const SYS_putpmsg = 182;
191pub const SYS_afs_syscall = 183;
192pub const SYS_tuxcall = 184;
193pub const SYS_security = 185;
194pub const SYS_gettid = 186;
195pub const SYS_readahead = 187;
196pub const SYS_setxattr = 188;
197pub const SYS_lsetxattr = 189;
198pub const SYS_fsetxattr = 190;
199pub const SYS_getxattr = 191;
200pub const SYS_lgetxattr = 192;
201pub const SYS_fgetxattr = 193;
202pub const SYS_listxattr = 194;
203pub const SYS_llistxattr = 195;
204pub const SYS_flistxattr = 196;
205pub const SYS_removexattr = 197;
206pub const SYS_lremovexattr = 198;
207pub const SYS_fremovexattr = 199;
208pub const SYS_tkill = 200;
209pub const SYS_time = 201;
210pub const SYS_futex = 202;
211pub const SYS_sched_setaffinity = 203;
212pub const SYS_sched_getaffinity = 204;
213pub const SYS_set_thread_area = 205;
214pub const SYS_io_setup = 206;
215pub const SYS_io_destroy = 207;
216pub const SYS_io_getevents = 208;
217pub const SYS_io_submit = 209;
218pub const SYS_io_cancel = 210;
219pub const SYS_get_thread_area = 211;
220pub const SYS_lookup_dcookie = 212;
221pub const SYS_epoll_create = 213;
222pub const SYS_epoll_ctl_old = 214;
223pub const SYS_epoll_wait_old = 215;
224pub const SYS_remap_file_pages = 216;
225pub const SYS_getdents64 = 217;
226pub const SYS_set_tid_address = 218;
227pub const SYS_restart_syscall = 219;
228pub const SYS_semtimedop = 220;
229pub const SYS_fadvise64 = 221;
230pub const SYS_timer_create = 222;
231pub const SYS_timer_settime = 223;
232pub const SYS_timer_gettime = 224;
233pub const SYS_timer_getoverrun = 225;
234pub const SYS_timer_delete = 226;
235pub const SYS_clock_settime = 227;
236pub const SYS_clock_gettime = 228;
237pub const SYS_clock_getres = 229;
238pub const SYS_clock_nanosleep = 230;
239pub const SYS_exit_group = 231;
240pub const SYS_epoll_wait = 232;
241pub const SYS_epoll_ctl = 233;
242pub const SYS_tgkill = 234;
243pub const SYS_utimes = 235;
244pub const SYS_vserver = 236;
245pub const SYS_mbind = 237;
246pub const SYS_set_mempolicy = 238;
247pub const SYS_get_mempolicy = 239;
248pub const SYS_mq_open = 240;
249pub const SYS_mq_unlink = 241;
250pub const SYS_mq_timedsend = 242;
251pub const SYS_mq_timedreceive = 243;
252pub const SYS_mq_notify = 244;
253pub const SYS_mq_getsetattr = 245;
254pub const SYS_kexec_load = 246;
255pub const SYS_waitid = 247;
256pub const SYS_add_key = 248;
257pub const SYS_request_key = 249;
258pub const SYS_keyctl = 250;
259pub const SYS_ioprio_set = 251;
260pub const SYS_ioprio_get = 252;
261pub const SYS_inotify_init = 253;
262pub const SYS_inotify_add_watch = 254;
263pub const SYS_inotify_rm_watch = 255;
264pub const SYS_migrate_pages = 256;
265pub const SYS_openat = 257;
266pub const SYS_mkdirat = 258;
267pub const SYS_mknodat = 259;
268pub const SYS_fchownat = 260;
269pub const SYS_futimesat = 261;
270pub const SYS_newfstatat = 262;
271// https://github.com/ziglang/zig/issues/1439
272pub const SYS_fstatat = 262;
273pub const SYS_unlinkat = 263;
274pub const SYS_renameat = 264;
275pub const SYS_linkat = 265;
276pub const SYS_symlinkat = 266;
277pub const SYS_readlinkat = 267;
278pub const SYS_fchmodat = 268;
279pub const SYS_faccessat = 269;
280pub const SYS_pselect6 = 270;
281pub const SYS_ppoll = 271;
282pub const SYS_unshare = 272;
283pub const SYS_set_robust_list = 273;
284pub const SYS_get_robust_list = 274;
285pub const SYS_splice = 275;
286pub const SYS_tee = 276;
287pub const SYS_sync_file_range = 277;
288pub const SYS_vmsplice = 278;
289pub const SYS_move_pages = 279;
290pub const SYS_utimensat = 280;
291pub const SYS_epoll_pwait = 281;
292pub const SYS_signalfd = 282;
293pub const SYS_timerfd_create = 283;
294pub const SYS_eventfd = 284;
295pub const SYS_fallocate = 285;
296pub const SYS_timerfd_settime = 286;
297pub const SYS_timerfd_gettime = 287;
298pub const SYS_accept4 = 288;
299pub const SYS_signalfd4 = 289;
300pub const SYS_eventfd2 = 290;
301pub const SYS_epoll_create1 = 291;
302pub const SYS_dup3 = 292;
303pub const SYS_pipe2 = 293;
304pub const SYS_inotify_init1 = 294;
305pub const SYS_preadv = 295;
306pub const SYS_pwritev = 296;
307pub const SYS_rt_tgsigqueueinfo = 297;
308pub const SYS_perf_event_open = 298;
309pub const SYS_recvmmsg = 299;
310pub const SYS_fanotify_init = 300;
311pub const SYS_fanotify_mark = 301;
312pub const SYS_prlimit64 = 302;
313pub const SYS_name_to_handle_at = 303;
314pub const SYS_open_by_handle_at = 304;
315pub const SYS_clock_adjtime = 305;
316pub const SYS_syncfs = 306;
317pub const SYS_sendmmsg = 307;
318pub const SYS_setns = 308;
319pub const SYS_getcpu = 309;
320pub const SYS_process_vm_readv = 310;
321pub const SYS_process_vm_writev = 311;
322pub const SYS_kcmp = 312;
323pub const SYS_finit_module = 313;
324pub const SYS_sched_setattr = 314;
325pub const SYS_sched_getattr = 315;
326pub const SYS_renameat2 = 316;
327pub const SYS_seccomp = 317;
328pub const SYS_getrandom = 318;
329pub const SYS_memfd_create = 319;
330pub const SYS_kexec_file_load = 320;
331pub const SYS_bpf = 321;
332pub const SYS_execveat = 322;
333pub const SYS_userfaultfd = 323;
334pub const SYS_membarrier = 324;
335pub const SYS_mlock2 = 325;
336pub const SYS_copy_file_range = 326;
337pub const SYS_preadv2 = 327;
338pub const SYS_pwritev2 = 328;
339pub const SYS_pkey_mprotect = 329;
340pub const SYS_pkey_alloc = 330;
341pub const SYS_pkey_free = 331;
342pub const SYS_statx = 332;
343pub const SYS_io_pgetevents = 333;
344pub const SYS_rseq = 334;
345pub const SYS_pidfd_send_signal = 424;
346pub const SYS_io_uring_setup = 425;
347pub const SYS_io_uring_enter = 426;
348pub const SYS_io_uring_register = 427;
349
350pub const O_CREAT = 0o100;
351pub const O_EXCL = 0o200;
352pub const O_NOCTTY = 0o400;
353pub const O_TRUNC = 0o1000;
354pub const O_APPEND = 0o2000;
355pub const O_NONBLOCK = 0o4000;
356pub const O_DSYNC = 0o10000;
357pub const O_SYNC = 0o4010000;
358pub const O_RSYNC = 0o4010000;
359pub const O_DIRECTORY = 0o200000;
360pub const O_NOFOLLOW = 0o400000;
361pub const O_CLOEXEC = 0o2000000;
362
363pub const O_ASYNC = 0o20000;
364pub const O_DIRECT = 0o40000;
365pub const O_LARGEFILE = 0;
366pub const O_NOATIME = 0o1000000;
367pub const O_PATH = 0o10000000;
368pub const O_TMPFILE = 0o20200000;
369pub const O_NDELAY = O_NONBLOCK;
370
371pub const F_DUPFD = 0;
372pub const F_GETFD = 1;
373pub const F_SETFD = 2;
374pub const F_GETFL = 3;
375pub const F_SETFL = 4;
376
377pub const F_SETOWN = 8;
378pub const F_GETOWN = 9;
379pub const F_SETSIG = 10;
380pub const F_GETSIG = 11;
381
382pub const F_GETLK = 5;
383pub const F_SETLK = 6;
384pub const F_SETLKW = 7;
385
386pub const F_SETOWN_EX = 15;
387pub const F_GETOWN_EX = 16;
388
389pub const F_GETOWNER_UIDS = 17;
390
391pub const AT_FDCWD = -100;
392pub const AT_SYMLINK_NOFOLLOW = 0x100;
393pub const AT_REMOVEDIR = 0x200;
394pub const AT_SYMLINK_FOLLOW = 0x400;
395pub const AT_NO_AUTOMOUNT = 0x800;
396pub const AT_EMPTY_PATH = 0x1000;
397
398pub const VDSO_USEFUL = true;
399pub const VDSO_CGT_SYM = "__vdso_clock_gettime";
400pub const VDSO_CGT_VER = "LINUX_2.6";
401pub const VDSO_GETCPU_SYM = "__vdso_getcpu";
402pub const VDSO_GETCPU_VER = "LINUX_2.6";
403
404pub const ARCH_SET_GS = 0x1001;
405pub const ARCH_SET_FS = 0x1002;
406pub const ARCH_GET_FS = 0x1003;
407pub const ARCH_GET_GS = 0x1004;
4082
409pub fn syscall0(number: usize) usize {3pub fn syscall0(number: usize) usize {
410 return asm volatile ("syscall"4 return asm volatile ("syscall"
...@@ -501,65 +95,3 @@ pub nakedcc fn restore_rt() void {...@@ -501,65 +95,3 @@ pub nakedcc fn restore_rt() void {
501 : "rcx", "r11"95 : "rcx", "r11"
502 );96 );
503}97}
504
505pub const msghdr = extern struct {
506 msg_name: ?*sockaddr,
507 msg_namelen: socklen_t,
508 msg_iov: [*]iovec,
509 msg_iovlen: i32,
510 __pad1: i32,
511 msg_control: ?*c_void,
512 msg_controllen: socklen_t,
513 __pad2: socklen_t,
514 msg_flags: i32,
515};
516
517pub const msghdr_const = extern struct {
518 msg_name: ?*const sockaddr,
519 msg_namelen: socklen_t,
520 msg_iov: [*]iovec_const,
521 msg_iovlen: i32,
522 __pad1: i32,
523 msg_control: ?*c_void,
524 msg_controllen: socklen_t,
525 __pad2: socklen_t,
526 msg_flags: i32,
527};
528
529/// Renamed to Stat to not conflict with the stat function.
530pub const Stat = extern struct {
531 dev: u64,
532 ino: u64,
533 nlink: usize,
534
535 mode: u32,
536 uid: u32,
537 gid: u32,
538 __pad0: u32,
539 rdev: u64,
540 size: i64,
541 blksize: isize,
542 blocks: i64,
543
544 atim: timespec,
545 mtim: timespec,
546 ctim: timespec,
547 __unused: [3]isize,
548};
549
550pub const timespec = extern struct {
551 tv_sec: isize,
552 tv_nsec: isize,
553};
554
555pub const timeval = extern struct {
556 tv_sec: isize,
557 tv_usec: isize,
558};
559
560pub const timezone = extern struct {
561 tz_minuteswest: i32,
562 tz_dsttime: i32,
563};
564
565pub const Elf_Symndx = u32;
std/os/netbsd.zig+2-722
...@@ -1,724 +1,4 @@...@@ -1,724 +1,4 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2
3pub use @import("netbsd/errno.zig");
4
5const std = @import("../std.zig");2const std = @import("../std.zig");
6const c = std.c;3pub const is_the_target = builtin.os == .netbsd;
74pub use std.c;
8const assert = std.debug.assert;
9const maxInt = std.math.maxInt;
10pub const Kevent = c.Kevent;
11
12pub const CTL_KERN = 1;
13pub const CTL_DEBUG = 5;
14
15pub const KERN_PROC_ARGS = 48; // struct: process argv/env
16pub const KERN_PROC_PATHNAME = 5; // path to executable
17
18pub const PATH_MAX = 1024;
19
20pub const STDIN_FILENO = 0;
21pub const STDOUT_FILENO = 1;
22pub const STDERR_FILENO = 2;
23
24pub const PROT_NONE = 0;
25pub const PROT_READ = 1;
26pub const PROT_WRITE = 2;
27pub const PROT_EXEC = 4;
28
29pub const CLOCK_REALTIME = 0;
30pub const CLOCK_VIRTUAL = 1;
31pub const CLOCK_PROF = 2;
32pub const CLOCK_MONOTONIC = 3;
33pub const CLOCK_THREAD_CPUTIME_ID = 0x20000000;
34pub const CLOCK_PROCESS_CPUTIME_ID = 0x40000000;
35
36pub const MAP_FAILED = maxInt(usize);
37pub const MAP_SHARED = 0x0001;
38pub const MAP_PRIVATE = 0x0002;
39pub const MAP_REMAPDUP = 0x0004;
40pub const MAP_FIXED = 0x0010;
41pub const MAP_RENAME = 0x0020;
42pub const MAP_NORESERVE = 0x0040;
43pub const MAP_INHERIT = 0x0080;
44pub const MAP_HASSEMAPHORE = 0x0200;
45pub const MAP_TRYFIXED = 0x0400;
46pub const MAP_WIRED = 0x0800;
47
48pub const MAP_FILE = 0x0000;
49pub const MAP_NOSYNC = 0x0800;
50pub const MAP_ANON = 0x1000;
51pub const MAP_ANONYMOUS = MAP_ANON;
52pub const MAP_STACK = 0x2000;
53
54pub const WNOHANG = 0x00000001;
55pub const WUNTRACED = 0x00000002;
56pub const WSTOPPED = WUNTRACED;
57pub const WCONTINUED = 0x00000010;
58pub const WNOWAIT = 0x00010000;
59pub const WEXITED = 0x00000020;
60pub const WTRAPPED = 0x00000040;
61
62pub const SA_ONSTACK = 0x0001;
63pub const SA_RESTART = 0x0002;
64pub const SA_RESETHAND = 0x0004;
65pub const SA_NOCLDSTOP = 0x0008;
66pub const SA_NODEFER = 0x0010;
67pub const SA_NOCLDWAIT = 0x0020;
68pub const SA_SIGINFO = 0x0040;
69
70pub const SIGHUP = 1;
71pub const SIGINT = 2;
72pub const SIGQUIT = 3;
73pub const SIGILL = 4;
74pub const SIGTRAP = 5;
75pub const SIGABRT = 6;
76pub const SIGIOT = SIGABRT;
77pub const SIGEMT = 7;
78pub const SIGFPE = 8;
79pub const SIGKILL = 9;
80pub const SIGBUS = 10;
81pub const SIGSEGV = 11;
82pub const SIGSYS = 12;
83pub const SIGPIPE = 13;
84pub const SIGALRM = 14;
85pub const SIGTERM = 15;
86pub const SIGURG = 16;
87pub const SIGSTOP = 17;
88pub const SIGTSTP = 18;
89pub const SIGCONT = 19;
90pub const SIGCHLD = 20;
91pub const SIGTTIN = 21;
92pub const SIGTTOU = 22;
93pub const SIGIO = 23;
94pub const SIGXCPU = 24;
95pub const SIGXFSZ = 25;
96pub const SIGVTALRM = 26;
97pub const SIGPROF = 27;
98pub const SIGWINCH = 28;
99pub const SIGINFO = 29;
100pub const SIGUSR1 = 30;
101pub const SIGUSR2 = 31;
102pub const SIGPWR = 32;
103
104pub const SIGRTMIN = 33;
105pub const SIGRTMAX = 63;
106
107// access function
108pub const F_OK = 0; // test for existence of file
109pub const X_OK = 1; // test for execute or search permission
110pub const W_OK = 2; // test for write permission
111pub const R_OK = 4; // test for read permission
112
113pub const O_RDONLY = 0x0000;
114pub const O_WRONLY = 0x0001;
115pub const O_RDWR = 0x0002;
116pub const O_ACCMODE = 0x0003;
117
118pub const O_CREAT = 0x0200;
119pub const O_EXCL = 0x0800;
120pub const O_NOCTTY = 0x8000;
121pub const O_TRUNC = 0x0400;
122pub const O_APPEND = 0x0008;
123pub const O_NONBLOCK = 0x0004;
124pub const O_DSYNC = 0x00010000;
125pub const O_SYNC = 0x0080;
126pub const O_RSYNC = 0x00020000;
127pub const O_DIRECTORY = 0x00080000;
128pub const O_NOFOLLOW = 0x00000100;
129pub const O_CLOEXEC = 0x00400000;
130
131pub const O_ASYNC = 0x0040;
132pub const O_DIRECT = 0x00080000;
133pub const O_LARGEFILE = 0;
134pub const O_NOATIME = 0;
135pub const O_PATH = 0;
136pub const O_TMPFILE = 0;
137pub const O_NDELAY = O_NONBLOCK;
138
139pub const F_DUPFD = 0;
140pub const F_GETFD = 1;
141pub const F_SETFD = 2;
142pub const F_GETFL = 3;
143pub const F_SETFL = 4;
144
145pub const F_GETOWN = 5;
146pub const F_SETOWN = 6;
147
148pub const F_GETLK = 7;
149pub const F_SETLK = 8;
150pub const F_SETLKW = 9;
151
152pub const SEEK_SET = 0;
153pub const SEEK_CUR = 1;
154pub const SEEK_END = 2;
155
156pub const SIG_BLOCK = 1;
157pub const SIG_UNBLOCK = 2;
158pub const SIG_SETMASK = 3;
159
160pub const SOCK_STREAM = 1;
161pub const SOCK_DGRAM = 2;
162pub const SOCK_RAW = 3;
163pub const SOCK_RDM = 4;
164pub const SOCK_SEQPACKET = 5;
165
166pub const SOCK_CLOEXEC = 0x10000000;
167pub const SOCK_NONBLOCK = 0x20000000;
168
169pub const PROTO_ip = 0;
170pub const PROTO_icmp = 1;
171pub const PROTO_igmp = 2;
172pub const PROTO_ggp = 3;
173pub const PROTO_ipencap = 4;
174pub const PROTO_tcp = 6;
175pub const PROTO_egp = 8;
176pub const PROTO_pup = 12;
177pub const PROTO_udp = 17;
178pub const PROTO_xns_idp = 22;
179pub const PROTO_iso_tp4 = 29;
180pub const PROTO_ipv6 = 41;
181pub const PROTO_ipv6_route = 43;
182pub const PROTO_ipv6_frag = 44;
183pub const PROTO_rsvp = 46;
184pub const PROTO_gre = 47;
185pub const PROTO_esp = 50;
186pub const PROTO_ah = 51;
187pub const PROTO_ipv6_icmp = 58;
188pub const PROTO_ipv6_nonxt = 59;
189pub const PROTO_ipv6_opts = 60;
190pub const PROTO_encap = 98;
191pub const PROTO_pim = 103;
192pub const PROTO_raw = 255;
193
194pub const PF_UNSPEC = 0;
195pub const PF_LOCAL = 1;
196pub const PF_UNIX = PF_LOCAL;
197pub const PF_FILE = PF_LOCAL;
198pub const PF_INET = 2;
199pub const PF_APPLETALK = 16;
200pub const PF_INET6 = 24;
201pub const PF_DECnet = 12;
202pub const PF_KEY = 29;
203pub const PF_ROUTE = 34;
204pub const PF_SNA = 11;
205pub const PF_MPLS = 33;
206pub const PF_CAN = 35;
207pub const PF_BLUETOOTH = 31;
208pub const PF_ISDN = 26;
209pub const PF_MAX = 37;
210
211pub const AF_UNSPEC = PF_UNSPEC;
212pub const AF_LOCAL = PF_LOCAL;
213pub const AF_UNIX = AF_LOCAL;
214pub const AF_FILE = AF_LOCAL;
215pub const AF_INET = PF_INET;
216pub const AF_APPLETALK = PF_APPLETALK;
217pub const AF_INET6 = PF_INET6;
218pub const AF_KEY = PF_KEY;
219pub const AF_ROUTE = PF_ROUTE;
220pub const AF_SNA = PF_SNA;
221pub const AF_MPLS = PF_MPLS;
222pub const AF_CAN = PF_CAN;
223pub const AF_BLUETOOTH = PF_BLUETOOTH;
224pub const AF_ISDN = PF_ISDN;
225pub const AF_MAX = PF_MAX;
226
227pub const DT_UNKNOWN = 0;
228pub const DT_FIFO = 1;
229pub const DT_CHR = 2;
230pub const DT_DIR = 4;
231pub const DT_BLK = 6;
232pub const DT_REG = 8;
233pub const DT_LNK = 10;
234pub const DT_SOCK = 12;
235pub const DT_WHT = 14;
236
237/// add event to kq (implies enable)
238pub const EV_ADD = 0x0001;
239
240/// delete event from kq
241pub const EV_DELETE = 0x0002;
242
243/// enable event
244pub const EV_ENABLE = 0x0004;
245
246/// disable event (not reported)
247pub const EV_DISABLE = 0x0008;
248
249/// only report one occurrence
250pub const EV_ONESHOT = 0x0010;
251
252/// clear event state after reporting
253pub const EV_CLEAR = 0x0020;
254
255/// force immediate event output
256/// ... with or without EV_ERROR
257/// ... use KEVENT_FLAG_ERROR_EVENTS
258/// on syscalls supporting flags
259pub const EV_RECEIPT = 0x0040;
260
261/// disable event after reporting
262pub const EV_DISPATCH = 0x0080;
263
264pub const EVFILT_READ = 0;
265pub const EVFILT_WRITE = 1;
266
267/// attached to aio requests
268pub const EVFILT_AIO = 2;
269
270/// attached to vnodes
271pub const EVFILT_VNODE = 3;
272
273/// attached to struct proc
274pub const EVFILT_PROC = 4;
275
276/// attached to struct proc
277pub const EVFILT_SIGNAL = 5;
278
279/// timers
280pub const EVFILT_TIMER = 6;
281
282/// Filesystem events
283pub const EVFILT_FS = 7;
284
285/// On input, NOTE_TRIGGER causes the event to be triggered for output.
286pub const NOTE_TRIGGER = 0x08000000;
287
288/// low water mark
289pub const NOTE_LOWAT = 0x00000001;
290
291/// vnode was removed
292pub const NOTE_DELETE = 0x00000001;
293
294/// data contents changed
295pub const NOTE_WRITE = 0x00000002;
296
297/// size increased
298pub const NOTE_EXTEND = 0x00000004;
299
300/// attributes changed
301pub const NOTE_ATTRIB = 0x00000008;
302
303/// link count changed
304pub const NOTE_LINK = 0x00000010;
305
306/// vnode was renamed
307pub const NOTE_RENAME = 0x00000020;
308
309/// vnode access was revoked
310pub const NOTE_REVOKE = 0x00000040;
311
312/// process exited
313pub const NOTE_EXIT = 0x80000000;
314
315/// process forked
316pub const NOTE_FORK = 0x40000000;
317
318/// process exec'd
319pub const NOTE_EXEC = 0x20000000;
320
321/// mask for signal & exit status
322pub const NOTE_PDATAMASK = 0x000fffff;
323pub const NOTE_PCTRLMASK = 0xf0000000;
324
325pub const TIOCCBRK = 0x2000747a;
326pub const TIOCCDTR = 0x20007478;
327pub const TIOCCONS = 0x80047462;
328pub const TIOCDCDTIMESTAMP = 0x40107458;
329pub const TIOCDRAIN = 0x2000745e;
330pub const TIOCEXCL = 0x2000740d;
331pub const TIOCEXT = 0x80047460;
332pub const TIOCFLAG_CDTRCTS = 0x10;
333pub const TIOCFLAG_CLOCAL = 0x2;
334pub const TIOCFLAG_CRTSCTS = 0x4;
335pub const TIOCFLAG_MDMBUF = 0x8;
336pub const TIOCFLAG_SOFTCAR = 0x1;
337pub const TIOCFLUSH = 0x80047410;
338pub const TIOCGETA = 0x402c7413;
339pub const TIOCGETD = 0x4004741a;
340pub const TIOCGFLAGS = 0x4004745d;
341pub const TIOCGLINED = 0x40207442;
342pub const TIOCGPGRP = 0x40047477;
343pub const TIOCGQSIZE = 0x40047481;
344pub const TIOCGRANTPT = 0x20007447;
345pub const TIOCGSID = 0x40047463;
346pub const TIOCGSIZE = 0x40087468;
347pub const TIOCGWINSZ = 0x40087468;
348pub const TIOCMBIC = 0x8004746b;
349pub const TIOCMBIS = 0x8004746c;
350pub const TIOCMGET = 0x4004746a;
351pub const TIOCMSET = 0x8004746d;
352pub const TIOCM_CAR = 0x40;
353pub const TIOCM_CD = 0x40;
354pub const TIOCM_CTS = 0x20;
355pub const TIOCM_DSR = 0x100;
356pub const TIOCM_DTR = 0x2;
357pub const TIOCM_LE = 0x1;
358pub const TIOCM_RI = 0x80;
359pub const TIOCM_RNG = 0x80;
360pub const TIOCM_RTS = 0x4;
361pub const TIOCM_SR = 0x10;
362pub const TIOCM_ST = 0x8;
363pub const TIOCNOTTY = 0x20007471;
364pub const TIOCNXCL = 0x2000740e;
365pub const TIOCOUTQ = 0x40047473;
366pub const TIOCPKT = 0x80047470;
367pub const TIOCPKT_DATA = 0x0;
368pub const TIOCPKT_DOSTOP = 0x20;
369pub const TIOCPKT_FLUSHREAD = 0x1;
370pub const TIOCPKT_FLUSHWRITE = 0x2;
371pub const TIOCPKT_IOCTL = 0x40;
372pub const TIOCPKT_NOSTOP = 0x10;
373pub const TIOCPKT_START = 0x8;
374pub const TIOCPKT_STOP = 0x4;
375pub const TIOCPTMGET = 0x40287446;
376pub const TIOCPTSNAME = 0x40287448;
377pub const TIOCRCVFRAME = 0x80087445;
378pub const TIOCREMOTE = 0x80047469;
379pub const TIOCSBRK = 0x2000747b;
380pub const TIOCSCTTY = 0x20007461;
381pub const TIOCSDTR = 0x20007479;
382pub const TIOCSETA = 0x802c7414;
383pub const TIOCSETAF = 0x802c7416;
384pub const TIOCSETAW = 0x802c7415;
385pub const TIOCSETD = 0x8004741b;
386pub const TIOCSFLAGS = 0x8004745c;
387pub const TIOCSIG = 0x2000745f;
388pub const TIOCSLINED = 0x80207443;
389pub const TIOCSPGRP = 0x80047476;
390pub const TIOCSQSIZE = 0x80047480;
391pub const TIOCSSIZE = 0x80087467;
392pub const TIOCSTART = 0x2000746e;
393pub const TIOCSTAT = 0x80047465;
394pub const TIOCSTI = 0x80017472;
395pub const TIOCSTOP = 0x2000746f;
396pub const TIOCSWINSZ = 0x80087467;
397pub const TIOCUCNTL = 0x80047466;
398pub const TIOCXMTFRAME = 0x80087444;
399
400pub const sockaddr = c.sockaddr;
401pub const sockaddr_in = c.sockaddr_in;
402pub const sockaddr_in6 = c.sockaddr_in6;
403
404fn unsigned(s: i32) u32 {
405 return @bitCast(u32, s);
406}
407fn signed(s: u32) i32 {
408 return @bitCast(i32, s);
409}
410pub fn WEXITSTATUS(s: i32) i32 {
411 return signed((unsigned(s) >> 8) & 0xff);
412}
413pub fn WTERMSIG(s: i32) i32 {
414 return signed(unsigned(s) & 0x7f);
415}
416pub fn WSTOPSIG(s: i32) i32 {
417 return WEXITSTATUS(s);
418}
419pub fn WIFEXITED(s: i32) bool {
420 return WTERMSIG(s) == 0;
421}
422
423pub fn WIFCONTINUED(s: i32) bool {
424 return ((s & 0x7f) == 0xffff);
425}
426
427pub fn WIFSTOPPED(s: i32) bool {
428 return ((s & 0x7f != 0x7f) and !WIFCONTINUED(s));
429}
430
431pub fn WIFSIGNALED(s: i32) bool {
432 return !WIFSTOPPED(s) and !WIFCONTINUED(s) and !WIFEXITED(s);
433}
434
435pub const winsize = extern struct {
436 ws_row: u16,
437 ws_col: u16,
438 ws_xpixel: u16,
439 ws_ypixel: u16,
440};
441
442/// Get the errno from a syscall return value, or 0 for no error.
443pub fn getErrno(r: usize) usize {
444 const signed_r = @bitCast(isize, r);
445 return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
446}
447
448pub fn dup2(old: i32, new: i32) usize {
449 return errnoWrap(c.dup2(old, new));
450}
451
452pub fn chdir(path: [*]const u8) usize {
453 return errnoWrap(c.chdir(path));
454}
455
456pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
457 return errnoWrap(c.execve(path, argv, envp));
458}
459
460pub fn fork() usize {
461 return errnoWrap(c.fork());
462}
463
464pub fn access(path: [*]const u8, mode: u32) usize {
465 return errnoWrap(c.access(path, mode));
466}
467
468pub fn getcwd(buf: [*]u8, size: usize) usize {
469 return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
470}
471
472pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize {
473 return errnoWrap(@bitCast(isize, c.getdents(fd, drip, count)));
474}
475
476pub fn getdirentries(fd: i32, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize {
477 return errnoWrap(@bitCast(isize, c.getdirentries(fd, buf_ptr, buf_len, basep)));
478}
479
480pub fn realpath(noalias filename: [*]const u8, noalias resolved_name: [*]u8) usize {
481 return if (c.realpath(filename, resolved_name) == null) @bitCast(usize, -isize(c._errno().*)) else 0;
482}
483
484pub fn isatty(fd: i32) bool {
485 return c.isatty(fd) != 0;
486}
487
488pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
489 return errnoWrap(c.readlink(path, buf_ptr, buf_len));
490}
491
492pub fn mkdir(path: [*]const u8, mode: u32) usize {
493 return errnoWrap(c.mkdir(path, mode));
494}
495
496pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
497 const ptr_result = c.mmap(
498 @ptrCast(?*c_void, address),
499 length,
500 @bitCast(c_int, @intCast(c_uint, prot)),
501 @bitCast(c_int, c_uint(flags)),
502 fd,
503 offset,
504 );
505 const isize_result = @bitCast(isize, @ptrToInt(ptr_result));
506 return errnoWrap(isize_result);
507}
508
509pub fn munmap(address: usize, length: usize) usize {
510 return errnoWrap(c.munmap(@intToPtr(*c_void, address), length));
511}
512
513pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {
514 return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte));
515}
516
517pub fn rmdir(path: [*]const u8) usize {
518 return errnoWrap(c.rmdir(path));
519}
520
521pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
522 return errnoWrap(c.symlink(existing, new));
523}
524
525pub fn pread(fd: i32, buf: [*]u8, nbyte: usize, offset: u64) usize {
526 return errnoWrap(c.pread(fd, @ptrCast(*c_void, buf), nbyte, offset));
527}
528
529pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: usize) usize {
530 return errnoWrap(c.preadv(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
531}
532
533pub fn pipe(fd: *[2]i32) usize {
534 return pipe2(fd, 0);
535}
536
537pub fn pipe2(fd: *[2]i32, flags: u32) usize {
538 comptime assert(i32.bit_count == c_int.bit_count);
539 return errnoWrap(c.pipe2(@ptrCast(*[2]c_int, fd), flags));
540}
541
542pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize {
543 return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte));
544}
545
546pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize {
547 return errnoWrap(c.pwrite(fd, @ptrCast(*const c_void, buf), nbyte, offset));
548}
549
550pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) usize {
551 return errnoWrap(c.pwritev(fd, @ptrCast(*const c_void, iov), @intCast(c_int, count), offset));
552}
553
554pub fn rename(old: [*]const u8, new: [*]const u8) usize {
555 return errnoWrap(c.rename(old, new));
556}
557
558pub fn open(path: [*]const u8, flags: u32, mode: usize) usize {
559 return errnoWrap(c.open(path, @bitCast(c_int, flags), mode));
560}
561
562pub fn create(path: [*]const u8, perm: usize) usize {
563 return arch.syscall2(SYS_creat, @ptrToInt(path), perm);
564}
565
566pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize {
567 return errnoWrap(c.openat(@bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode));
568}
569
570pub fn close(fd: i32) usize {
571 return errnoWrap(c.close(fd));
572}
573
574pub fn lseek(fd: i32, offset: isize, whence: c_int) usize {
575 return errnoWrap(c.lseek(fd, offset, whence));
576}
577
578pub fn exit(code: i32) noreturn {
579 c.exit(code);
580}
581
582pub fn kill(pid: i32, sig: i32) usize {
583 return errnoWrap(c.kill(pid, sig));
584}
585
586pub fn unlink(path: [*]const u8) usize {
587 return errnoWrap(c.unlink(path));
588}
589
590pub fn waitpid(pid: i32, status: *i32, options: u32) usize {
591 comptime assert(i32.bit_count == c_int.bit_count);
592 return errnoWrap(c.waitpid(pid, @ptrCast(*c_int, status), @bitCast(c_int, options)));
593}
594
595pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
596 return errnoWrap(c.nanosleep(req, rem));
597}
598
599pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
600 return errnoWrap(c.clock_gettime(clk_id, tp));
601}
602
603pub fn clock_getres(clk_id: i32, tp: *timespec) usize {
604 return errnoWrap(c.clock_getres(clk_id, tp));
605}
606
607pub fn setuid(uid: u32) usize {
608 return errnoWrap(c.setuid(uid));
609}
610
611pub fn setgid(gid: u32) usize {
612 return errnoWrap(c.setgid(gid));
613}
614
615pub fn setreuid(ruid: u32, euid: u32) usize {
616 return errnoWrap(c.setreuid(ruid, euid));
617}
618
619pub fn setregid(rgid: u32, egid: u32) usize {
620 return errnoWrap(c.setregid(rgid, egid));
621}
622
623const NSIG = 32;
624
625pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
626pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
627pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
628
629/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
630pub const Sigaction = extern struct {
631 /// signal handler
632 __sigaction_u: extern union {
633 __sa_handler: extern fn (i32) void,
634 __sa_sigaction: extern fn (i32, *__siginfo, usize) void,
635 },
636
637 /// see signal options
638 sa_flags: u32,
639
640 /// signal mask to apply
641 sa_mask: sigset_t,
642};
643
644pub const _SIG_WORDS = 4;
645pub const _SIG_MAXSIG = 128;
646
647pub inline fn _SIG_IDX(sig: usize) usize {
648 return sig - 1;
649}
650pub inline fn _SIG_WORD(sig: usize) usize {
651 return_SIG_IDX(sig) >> 5;
652}
653pub inline fn _SIG_BIT(sig: usize) usize {
654 return 1 << (_SIG_IDX(sig) & 31);
655}
656pub inline fn _SIG_VALID(sig: usize) usize {
657 return sig <= _SIG_MAXSIG and sig > 0;
658}
659
660pub const sigset_t = extern struct {
661 __bits: [_SIG_WORDS]u32,
662};
663
664pub fn raise(sig: i32) usize {
665 return errnoWrap(c.raise(sig));
666}
667
668pub const Stat = c.Stat;
669pub const dirent = c.dirent;
670pub const timespec = c.timespec;
671
672pub fn fstat(fd: i32, buf: *c.Stat) usize {
673 return errnoWrap(c.fstat(fd, buf));
674}
675pub const iovec = extern struct {
676 iov_base: [*]u8,
677 iov_len: usize,
678};
679
680pub const iovec_const = extern struct {
681 iov_base: [*]const u8,
682 iov_len: usize,
683};
684
685// TODO avoid libc dependency
686pub fn kqueue() usize {
687 return errnoWrap(c.kqueue());
688}
689
690// TODO avoid libc dependency
691pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize {
692 return errnoWrap(c.kevent(
693 kq,
694 changelist.ptr,
695 @intCast(c_int, changelist.len),
696 eventlist.ptr,
697 @intCast(c_int, eventlist.len),
698 timeout,
699 ));
700}
701
702// TODO avoid libc dependency
703pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
704 return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen));
705}
706
707// TODO avoid libc dependency
708pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
709 return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen));
710}
711
712// TODO avoid libc dependency
713pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize {
714 return errnoWrap(c.sysctlnametomib(name, wibp, sizep));
715}
716
717// TODO avoid libc dependency
718
719/// Takes the return value from a syscall and formats it back in the way
720/// that the kernel represents it to libc. Errno was a mistake, let's make
721/// it go away forever.
722fn errnoWrap(value: isize) usize {
723 return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
724}
std/os/netbsd/errno.zig deleted-134
...@@ -1,134 +0,0 @@
1pub const EPERM = 1; // Operation not permitted
2pub const ENOENT = 2; // No such file or directory
3pub const ESRCH = 3; // No such process
4pub const EINTR = 4; // Interrupted system call
5pub const EIO = 5; // Input/output error
6pub const ENXIO = 6; // Device not configured
7pub const E2BIG = 7; // Argument list too long
8pub const ENOEXEC = 8; // Exec format error
9pub const EBADF = 9; // Bad file descriptor
10pub const ECHILD = 10; // No child processes
11pub const EDEADLK = 11; // Resource deadlock avoided
12// 11 was EAGAIN
13pub const ENOMEM = 12; // Cannot allocate memory
14pub const EACCES = 13; // Permission denied
15pub const EFAULT = 14; // Bad address
16pub const ENOTBLK = 15; // Block device required
17pub const EBUSY = 16; // Device busy
18pub const EEXIST = 17; // File exists
19pub const EXDEV = 18; // Cross-device link
20pub const ENODEV = 19; // Operation not supported by device
21pub const ENOTDIR = 20; // Not a directory
22pub const EISDIR = 21; // Is a directory
23pub const EINVAL = 22; // Invalid argument
24pub const ENFILE = 23; // Too many open files in system
25pub const EMFILE = 24; // Too many open files
26pub const ENOTTY = 25; // Inappropriate ioctl for device
27pub const ETXTBSY = 26; // Text file busy
28pub const EFBIG = 27; // File too large
29pub const ENOSPC = 28; // No space left on device
30pub const ESPIPE = 29; // Illegal seek
31pub const EROFS = 30; // Read-only file system
32pub const EMLINK = 31; // Too many links
33pub const EPIPE = 32; // Broken pipe
34
35// math software
36pub const EDOM = 33; // Numerical argument out of domain
37pub const ERANGE = 34; // Result too large or too small
38
39// non-blocking and interrupt i/o
40pub const EAGAIN = 35; // Resource temporarily unavailable
41pub const EWOULDBLOCK = EAGAIN; // Operation would block
42pub const EINPROGRESS = 36; // Operation now in progress
43pub const EALREADY = 37; // Operation already in progress
44
45// ipc/network software -- argument errors
46pub const ENOTSOCK = 38; // Socket operation on non-socket
47pub const EDESTADDRREQ = 39; // Destination address required
48pub const EMSGSIZE = 40; // Message too long
49pub const EPROTOTYPE = 41; // Protocol wrong type for socket
50pub const ENOPROTOOPT = 42; // Protocol option not available
51pub const EPROTONOSUPPORT = 43; // Protocol not supported
52pub const ESOCKTNOSUPPORT = 44; // Socket type not supported
53pub const EOPNOTSUPP = 45; // Operation not supported
54pub const EPFNOSUPPORT = 46; // Protocol family not supported
55pub const EAFNOSUPPORT = 47; // Address family not supported by protocol family
56pub const EADDRINUSE = 48; // Address already in use
57pub const EADDRNOTAVAIL = 49; // Can't assign requested address
58
59// ipc/network software -- operational errors
60pub const ENETDOWN = 50; // Network is down
61pub const ENETUNREACH = 51; // Network is unreachable
62pub const ENETRESET = 52; // Network dropped connection on reset
63pub const ECONNABORTED = 53; // Software caused connection abort
64pub const ECONNRESET = 54; // Connection reset by peer
65pub const ENOBUFS = 55; // No buffer space available
66pub const EISCONN = 56; // Socket is already connected
67pub const ENOTCONN = 57; // Socket is not connected
68pub const ESHUTDOWN = 58; // Can't send after socket shutdown
69pub const ETOOMANYREFS = 59; // Too many references: can't splice
70pub const ETIMEDOUT = 60; // Operation timed out
71pub const ECONNREFUSED = 61; // Connection refused
72
73pub const ELOOP = 62; // Too many levels of symbolic links
74pub const ENAMETOOLONG = 63; // File name too long
75
76// should be rearranged
77pub const EHOSTDOWN = 64; // Host is down
78pub const EHOSTUNREACH = 65; // No route to host
79pub const ENOTEMPTY = 66; // Directory not empty
80
81// quotas & mush
82pub const EPROCLIM = 67; // Too many processes
83pub const EUSERS = 68; // Too many users
84pub const EDQUOT = 69; // Disc quota exceeded
85
86// Network File System
87pub const ESTALE = 70; // Stale NFS file handle
88pub const EREMOTE = 71; // Too many levels of remote in path
89pub const EBADRPC = 72; // RPC struct is bad
90pub const ERPCMISMATCH = 73; // RPC version wrong
91pub const EPROGUNAVAIL = 74; // RPC prog. not avail
92pub const EPROGMISMATCH = 75; // Program version wrong
93pub const EPROCUNAVAIL = 76; // Bad procedure for program
94
95pub const ENOLCK = 77; // No locks available
96pub const ENOSYS = 78; // Function not implemented
97
98pub const EFTYPE = 79; // Inappropriate file type or format
99pub const EAUTH = 80; // Authentication error
100pub const ENEEDAUTH = 81; // Need authenticator
101
102// SystemV IPC
103pub const EIDRM = 82; // Identifier removed
104pub const ENOMSG = 83; // No message of desired type
105pub const EOVERFLOW = 84; // Value too large to be stored in data type
106
107// Wide/multibyte-character handling, ISO/IEC 9899/AMD1:1995
108pub const EILSEQ = 85; // Illegal byte sequence
109
110// From IEEE Std 1003.1-2001
111// Base, Realtime, Threads or Thread Priority Scheduling option errors
112pub const ENOTSUP = 86; // Not supported
113
114// Realtime option errors
115pub const ECANCELED = 87; // Operation canceled
116
117// Realtime, XSI STREAMS option errors
118pub const EBADMSG = 88; // Bad or Corrupt message
119
120// XSI STREAMS option errors
121pub const ENODATA = 89; // No message available
122pub const ENOSR = 90; // No STREAM resources
123pub const ENOSTR = 91; // Not a STREAM
124pub const ETIME = 92; // STREAM ioctl timeout
125
126// File system extended attribute errors
127pub const ENOATTR = 93; // Attribute not found
128
129// Realtime, XSI STREAMS option errors
130pub const EMULTIHOP = 94; // Multihop attempted
131pub const ENOLINK = 95; // Link has been severed
132pub const EPROTO = 96; // Protocol error
133
134pub const ELAST = 96; // Must equal largest errno
std/os/path.zig deleted-1288
...@@ -1,1288 +0,0 @@
1const std = @import("../std.zig");
2const builtin = @import("builtin");
3const Os = builtin.Os;
4const debug = std.debug;
5const assert = debug.assert;
6const testing = std.testing;
7const mem = std.mem;
8const fmt = std.fmt;
9const Allocator = mem.Allocator;
10const os = std.os;
11const math = std.math;
12const posix = os.posix;
13const windows = os.windows;
14const cstr = std.cstr;
15const windows_util = @import("windows/util.zig");
16
17pub const sep_windows = '\\';
18pub const sep_posix = '/';
19pub const sep = if (is_windows) sep_windows else sep_posix;
20
21pub const sep_str = [1]u8{sep};
22
23pub const delimiter_windows = ';';
24pub const delimiter_posix = ':';
25pub const delimiter = if (is_windows) delimiter_windows else delimiter_posix;
26
27const is_windows = builtin.os == builtin.Os.windows;
28
29pub fn isSep(byte: u8) bool {
30 if (is_windows) {
31 return byte == '/' or byte == '\\';
32 } else {
33 return byte == '/';
34 }
35}
36
37/// This is different from mem.join in that the separator will not be repeated if
38/// it is found at the end or beginning of a pair of consecutive paths.
39fn joinSep(allocator: *Allocator, separator: u8, paths: []const []const u8) ![]u8 {
40 if (paths.len == 0) return (([*]u8)(undefined))[0..0];
41
42 const total_len = blk: {
43 var sum: usize = paths[0].len;
44 var i: usize = 1;
45 while (i < paths.len) : (i += 1) {
46 const prev_path = paths[i - 1];
47 const this_path = paths[i];
48 const prev_sep = (prev_path.len != 0 and prev_path[prev_path.len - 1] == separator);
49 const this_sep = (this_path.len != 0 and this_path[0] == separator);
50 sum += @boolToInt(!prev_sep and !this_sep);
51 sum += if (prev_sep and this_sep) this_path.len - 1 else this_path.len;
52 }
53 break :blk sum;
54 };
55
56 const buf = try allocator.alloc(u8, total_len);
57 errdefer allocator.free(buf);
58
59 mem.copy(u8, buf, paths[0]);
60 var buf_index: usize = paths[0].len;
61 var i: usize = 1;
62 while (i < paths.len) : (i += 1) {
63 const prev_path = paths[i - 1];
64 const this_path = paths[i];
65 const prev_sep = (prev_path.len != 0 and prev_path[prev_path.len - 1] == separator);
66 const this_sep = (this_path.len != 0 and this_path[0] == separator);
67 if (!prev_sep and !this_sep) {
68 buf[buf_index] = separator;
69 buf_index += 1;
70 }
71 const adjusted_path = if (prev_sep and this_sep) this_path[1..] else this_path;
72 mem.copy(u8, buf[buf_index..], adjusted_path);
73 buf_index += adjusted_path.len;
74 }
75
76 // No need for shrink since buf is exactly the correct size.
77 return buf;
78}
79
80pub const join = if (is_windows) joinWindows else joinPosix;
81
82/// Naively combines a series of paths with the native path seperator.
83/// Allocates memory for the result, which must be freed by the caller.
84pub fn joinWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
85 return joinSep(allocator, sep_windows, paths);
86}
87
88/// Naively combines a series of paths with the native path seperator.
89/// Allocates memory for the result, which must be freed by the caller.
90pub fn joinPosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
91 return joinSep(allocator, sep_posix, paths);
92}
93
94fn testJoinWindows(paths: []const []const u8, expected: []const u8) void {
95 var buf: [1024]u8 = undefined;
96 const a = &std.heap.FixedBufferAllocator.init(&buf).allocator;
97 const actual = joinWindows(a, paths) catch @panic("fail");
98 testing.expectEqualSlices(u8, expected, actual);
99}
100
101fn testJoinPosix(paths: []const []const u8, expected: []const u8) void {
102 var buf: [1024]u8 = undefined;
103 const a = &std.heap.FixedBufferAllocator.init(&buf).allocator;
104 const actual = joinPosix(a, paths) catch @panic("fail");
105 testing.expectEqualSlices(u8, expected, actual);
106}
107
108test "os.path.join" {
109 testJoinWindows([][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c");
110 testJoinWindows([][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c");
111 testJoinWindows([][]const u8{ "c:\\a\\b\\", "c" }, "c:\\a\\b\\c");
112
113 testJoinWindows([][]const u8{ "c:\\", "a", "b\\", "c" }, "c:\\a\\b\\c");
114 testJoinWindows([][]const u8{ "c:\\a\\", "b\\", "c" }, "c:\\a\\b\\c");
115
116 testJoinWindows(
117 [][]const u8{ "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std", "io.zig" },
118 "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig",
119 );
120
121 testJoinPosix([][]const u8{ "/a/b", "c" }, "/a/b/c");
122 testJoinPosix([][]const u8{ "/a/b/", "c" }, "/a/b/c");
123
124 testJoinPosix([][]const u8{ "/", "a", "b/", "c" }, "/a/b/c");
125 testJoinPosix([][]const u8{ "/a/", "b/", "c" }, "/a/b/c");
126
127 testJoinPosix(
128 [][]const u8{ "/home/andy/dev/zig/build/lib/zig/std", "io.zig" },
129 "/home/andy/dev/zig/build/lib/zig/std/io.zig",
130 );
131
132 testJoinPosix([][]const u8{ "a", "/c" }, "a/c");
133 testJoinPosix([][]const u8{ "a/", "/c" }, "a/c");
134}
135
136pub fn isAbsolute(path: []const u8) bool {
137 if (is_windows) {
138 return isAbsoluteWindows(path);
139 } else {
140 return isAbsolutePosix(path);
141 }
142}
143
144pub fn isAbsoluteWindows(path: []const u8) bool {
145 if (path[0] == '/')
146 return true;
147
148 if (path[0] == '\\') {
149 return true;
150 }
151 if (path.len < 3) {
152 return false;
153 }
154 if (path[1] == ':') {
155 if (path[2] == '/')
156 return true;
157 if (path[2] == '\\')
158 return true;
159 }
160 return false;
161}
162
163pub fn isAbsolutePosix(path: []const u8) bool {
164 return path[0] == sep_posix;
165}
166
167test "os.path.isAbsoluteWindows" {
168 testIsAbsoluteWindows("/", true);
169 testIsAbsoluteWindows("//", true);
170 testIsAbsoluteWindows("//server", true);
171 testIsAbsoluteWindows("//server/file", true);
172 testIsAbsoluteWindows("\\\\server\\file", true);
173 testIsAbsoluteWindows("\\\\server", true);
174 testIsAbsoluteWindows("\\\\", true);
175 testIsAbsoluteWindows("c", false);
176 testIsAbsoluteWindows("c:", false);
177 testIsAbsoluteWindows("c:\\", true);
178 testIsAbsoluteWindows("c:/", true);
179 testIsAbsoluteWindows("c://", true);
180 testIsAbsoluteWindows("C:/Users/", true);
181 testIsAbsoluteWindows("C:\\Users\\", true);
182 testIsAbsoluteWindows("C:cwd/another", false);
183 testIsAbsoluteWindows("C:cwd\\another", false);
184 testIsAbsoluteWindows("directory/directory", false);
185 testIsAbsoluteWindows("directory\\directory", false);
186 testIsAbsoluteWindows("/usr/local", true);
187}
188
189test "os.path.isAbsolutePosix" {
190 testIsAbsolutePosix("/home/foo", true);
191 testIsAbsolutePosix("/home/foo/..", true);
192 testIsAbsolutePosix("bar/", false);
193 testIsAbsolutePosix("./baz", false);
194}
195
196fn testIsAbsoluteWindows(path: []const u8, expected_result: bool) void {
197 testing.expectEqual(expected_result, isAbsoluteWindows(path));
198}
199
200fn testIsAbsolutePosix(path: []const u8, expected_result: bool) void {
201 testing.expectEqual(expected_result, isAbsolutePosix(path));
202}
203
204pub const WindowsPath = struct {
205 is_abs: bool,
206 kind: Kind,
207 disk_designator: []const u8,
208
209 pub const Kind = enum {
210 None,
211 Drive,
212 NetworkShare,
213 };
214};
215
216pub fn windowsParsePath(path: []const u8) WindowsPath {
217 if (path.len >= 2 and path[1] == ':') {
218 return WindowsPath{
219 .is_abs = isAbsoluteWindows(path),
220 .kind = WindowsPath.Kind.Drive,
221 .disk_designator = path[0..2],
222 };
223 }
224 if (path.len >= 1 and (path[0] == '/' or path[0] == '\\') and
225 (path.len == 1 or (path[1] != '/' and path[1] != '\\')))
226 {
227 return WindowsPath{
228 .is_abs = true,
229 .kind = WindowsPath.Kind.None,
230 .disk_designator = path[0..0],
231 };
232 }
233 const relative_path = WindowsPath{
234 .kind = WindowsPath.Kind.None,
235 .disk_designator = []u8{},
236 .is_abs = false,
237 };
238 if (path.len < "//a/b".len) {
239 return relative_path;
240 }
241
242 // TODO when I combined these together with `inline for` the compiler crashed
243 {
244 const this_sep = '/';
245 const two_sep = []u8{ this_sep, this_sep };
246 if (mem.startsWith(u8, path, two_sep)) {
247 if (path[2] == this_sep) {
248 return relative_path;
249 }
250
251 var it = mem.tokenize(path, []u8{this_sep});
252 _ = (it.next() orelse return relative_path);
253 _ = (it.next() orelse return relative_path);
254 return WindowsPath{
255 .is_abs = isAbsoluteWindows(path),
256 .kind = WindowsPath.Kind.NetworkShare,
257 .disk_designator = path[0..it.index],
258 };
259 }
260 }
261 {
262 const this_sep = '\\';
263 const two_sep = []u8{ this_sep, this_sep };
264 if (mem.startsWith(u8, path, two_sep)) {
265 if (path[2] == this_sep) {
266 return relative_path;
267 }
268
269 var it = mem.tokenize(path, []u8{this_sep});
270 _ = (it.next() orelse return relative_path);
271 _ = (it.next() orelse return relative_path);
272 return WindowsPath{
273 .is_abs = isAbsoluteWindows(path),
274 .kind = WindowsPath.Kind.NetworkShare,
275 .disk_designator = path[0..it.index],
276 };
277 }
278 }
279 return relative_path;
280}
281
282test "os.path.windowsParsePath" {
283 {
284 const parsed = windowsParsePath("//a/b");
285 testing.expect(parsed.is_abs);
286 testing.expect(parsed.kind == WindowsPath.Kind.NetworkShare);
287 testing.expect(mem.eql(u8, parsed.disk_designator, "//a/b"));
288 }
289 {
290 const parsed = windowsParsePath("\\\\a\\b");
291 testing.expect(parsed.is_abs);
292 testing.expect(parsed.kind == WindowsPath.Kind.NetworkShare);
293 testing.expect(mem.eql(u8, parsed.disk_designator, "\\\\a\\b"));
294 }
295 {
296 const parsed = windowsParsePath("\\\\a\\");
297 testing.expect(!parsed.is_abs);
298 testing.expect(parsed.kind == WindowsPath.Kind.None);
299 testing.expect(mem.eql(u8, parsed.disk_designator, ""));
300 }
301 {
302 const parsed = windowsParsePath("/usr/local");
303 testing.expect(parsed.is_abs);
304 testing.expect(parsed.kind == WindowsPath.Kind.None);
305 testing.expect(mem.eql(u8, parsed.disk_designator, ""));
306 }
307 {
308 const parsed = windowsParsePath("c:../");
309 testing.expect(!parsed.is_abs);
310 testing.expect(parsed.kind == WindowsPath.Kind.Drive);
311 testing.expect(mem.eql(u8, parsed.disk_designator, "c:"));
312 }
313}
314
315pub fn diskDesignator(path: []const u8) []const u8 {
316 if (is_windows) {
317 return diskDesignatorWindows(path);
318 } else {
319 return "";
320 }
321}
322
323pub fn diskDesignatorWindows(path: []const u8) []const u8 {
324 return windowsParsePath(path).disk_designator;
325}
326
327fn networkShareServersEql(ns1: []const u8, ns2: []const u8) bool {
328 const sep1 = ns1[0];
329 const sep2 = ns2[0];
330
331 var it1 = mem.tokenize(ns1, []u8{sep1});
332 var it2 = mem.tokenize(ns2, []u8{sep2});
333
334 // TODO ASCII is wrong, we actually need full unicode support to compare paths.
335 return asciiEqlIgnoreCase(it1.next().?, it2.next().?);
336}
337
338fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8) bool {
339 switch (kind) {
340 WindowsPath.Kind.None => {
341 assert(p1.len == 0);
342 assert(p2.len == 0);
343 return true;
344 },
345 WindowsPath.Kind.Drive => {
346 return asciiUpper(p1[0]) == asciiUpper(p2[0]);
347 },
348 WindowsPath.Kind.NetworkShare => {
349 const sep1 = p1[0];
350 const sep2 = p2[0];
351
352 var it1 = mem.tokenize(p1, []u8{sep1});
353 var it2 = mem.tokenize(p2, []u8{sep2});
354
355 // TODO ASCII is wrong, we actually need full unicode support to compare paths.
356 return asciiEqlIgnoreCase(it1.next().?, it2.next().?) and asciiEqlIgnoreCase(it1.next().?, it2.next().?);
357 },
358 }
359}
360
361fn asciiUpper(byte: u8) u8 {
362 return switch (byte) {
363 'a'...'z' => 'A' + (byte - 'a'),
364 else => byte,
365 };
366}
367
368fn asciiEqlIgnoreCase(s1: []const u8, s2: []const u8) bool {
369 if (s1.len != s2.len)
370 return false;
371 var i: usize = 0;
372 while (i < s1.len) : (i += 1) {
373 if (asciiUpper(s1[i]) != asciiUpper(s2[i]))
374 return false;
375 }
376 return true;
377}
378
379/// On Windows, this calls `resolveWindows` and on POSIX it calls `resolvePosix`.
380pub fn resolve(allocator: *Allocator, paths: []const []const u8) ![]u8 {
381 if (is_windows) {
382 return resolveWindows(allocator, paths);
383 } else {
384 return resolvePosix(allocator, paths);
385 }
386}
387
388/// This function is like a series of `cd` statements executed one after another.
389/// It resolves "." and "..".
390/// The result does not have a trailing path separator.
391/// If all paths are relative it uses the current working directory as a starting point.
392/// Each drive has its own current working directory.
393/// Path separators are canonicalized to '\\' and drives are canonicalized to capital letters.
394/// Note: all usage of this function should be audited due to the existence of symlinks.
395/// Without performing actual syscalls, resolving `..` could be incorrect.
396pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 {
397 if (paths.len == 0) {
398 assert(is_windows); // resolveWindows called on non windows can't use getCwd
399 return os.getCwdAlloc(allocator);
400 }
401
402 // determine which disk designator we will result with, if any
403 var result_drive_buf = "_:";
404 var result_disk_designator: []const u8 = "";
405 var have_drive_kind = WindowsPath.Kind.None;
406 var have_abs_path = false;
407 var first_index: usize = 0;
408 var max_size: usize = 0;
409 for (paths) |p, i| {
410 const parsed = windowsParsePath(p);
411 if (parsed.is_abs) {
412 have_abs_path = true;
413 first_index = i;
414 max_size = result_disk_designator.len;
415 }
416 switch (parsed.kind) {
417 WindowsPath.Kind.Drive => {
418 result_drive_buf[0] = asciiUpper(parsed.disk_designator[0]);
419 result_disk_designator = result_drive_buf[0..];
420 have_drive_kind = WindowsPath.Kind.Drive;
421 },
422 WindowsPath.Kind.NetworkShare => {
423 result_disk_designator = parsed.disk_designator;
424 have_drive_kind = WindowsPath.Kind.NetworkShare;
425 },
426 WindowsPath.Kind.None => {},
427 }
428 max_size += p.len + 1;
429 }
430
431 // if we will result with a disk designator, loop again to determine
432 // which is the last time the disk designator is absolutely specified, if any
433 // and count up the max bytes for paths related to this disk designator
434 if (have_drive_kind != WindowsPath.Kind.None) {
435 have_abs_path = false;
436 first_index = 0;
437 max_size = result_disk_designator.len;
438 var correct_disk_designator = false;
439
440 for (paths) |p, i| {
441 const parsed = windowsParsePath(p);
442 if (parsed.kind != WindowsPath.Kind.None) {
443 if (parsed.kind == have_drive_kind) {
444 correct_disk_designator = compareDiskDesignators(have_drive_kind, result_disk_designator, parsed.disk_designator);
445 } else {
446 continue;
447 }
448 }
449 if (!correct_disk_designator) {
450 continue;
451 }
452 if (parsed.is_abs) {
453 first_index = i;
454 max_size = result_disk_designator.len;
455 have_abs_path = true;
456 }
457 max_size += p.len + 1;
458 }
459 }
460
461 // Allocate result and fill in the disk designator, calling getCwd if we have to.
462 var result: []u8 = undefined;
463 var result_index: usize = 0;
464
465 if (have_abs_path) {
466 switch (have_drive_kind) {
467 WindowsPath.Kind.Drive => {
468 result = try allocator.alloc(u8, max_size);
469
470 mem.copy(u8, result, result_disk_designator);
471 result_index += result_disk_designator.len;
472 },
473 WindowsPath.Kind.NetworkShare => {
474 result = try allocator.alloc(u8, max_size);
475 var it = mem.tokenize(paths[first_index], "/\\");
476 const server_name = it.next().?;
477 const other_name = it.next().?;
478
479 result[result_index] = '\\';
480 result_index += 1;
481 result[result_index] = '\\';
482 result_index += 1;
483 mem.copy(u8, result[result_index..], server_name);
484 result_index += server_name.len;
485 result[result_index] = '\\';
486 result_index += 1;
487 mem.copy(u8, result[result_index..], other_name);
488 result_index += other_name.len;
489
490 result_disk_designator = result[0..result_index];
491 },
492 WindowsPath.Kind.None => {
493 assert(is_windows); // resolveWindows called on non windows can't use getCwd
494 const cwd = try os.getCwdAlloc(allocator);
495 defer allocator.free(cwd);
496 const parsed_cwd = windowsParsePath(cwd);
497 result = try allocator.alloc(u8, max_size + parsed_cwd.disk_designator.len + 1);
498 mem.copy(u8, result, parsed_cwd.disk_designator);
499 result_index += parsed_cwd.disk_designator.len;
500 result_disk_designator = result[0..parsed_cwd.disk_designator.len];
501 if (parsed_cwd.kind == WindowsPath.Kind.Drive) {
502 result[0] = asciiUpper(result[0]);
503 }
504 have_drive_kind = parsed_cwd.kind;
505 },
506 }
507 } else {
508 assert(is_windows); // resolveWindows called on non windows can't use getCwd
509 // TODO call get cwd for the result_disk_designator instead of the global one
510 const cwd = try os.getCwdAlloc(allocator);
511 defer allocator.free(cwd);
512
513 result = try allocator.alloc(u8, max_size + cwd.len + 1);
514
515 mem.copy(u8, result, cwd);
516 result_index += cwd.len;
517 const parsed_cwd = windowsParsePath(result[0..result_index]);
518 result_disk_designator = parsed_cwd.disk_designator;
519 if (parsed_cwd.kind == WindowsPath.Kind.Drive) {
520 result[0] = asciiUpper(result[0]);
521 }
522 have_drive_kind = parsed_cwd.kind;
523 }
524 errdefer allocator.free(result);
525
526 // Now we know the disk designator to use, if any, and what kind it is. And our result
527 // is big enough to append all the paths to.
528 var correct_disk_designator = true;
529 for (paths[first_index..]) |p, i| {
530 const parsed = windowsParsePath(p);
531
532 if (parsed.kind != WindowsPath.Kind.None) {
533 if (parsed.kind == have_drive_kind) {
534 correct_disk_designator = compareDiskDesignators(have_drive_kind, result_disk_designator, parsed.disk_designator);
535 } else {
536 continue;
537 }
538 }
539 if (!correct_disk_designator) {
540 continue;
541 }
542 var it = mem.tokenize(p[parsed.disk_designator.len..], "/\\");
543 while (it.next()) |component| {
544 if (mem.eql(u8, component, ".")) {
545 continue;
546 } else if (mem.eql(u8, component, "..")) {
547 while (true) {
548 if (result_index == 0 or result_index == result_disk_designator.len)
549 break;
550 result_index -= 1;
551 if (result[result_index] == '\\' or result[result_index] == '/')
552 break;
553 }
554 } else {
555 result[result_index] = sep_windows;
556 result_index += 1;
557 mem.copy(u8, result[result_index..], component);
558 result_index += component.len;
559 }
560 }
561 }
562
563 if (result_index == result_disk_designator.len) {
564 result[result_index] = '\\';
565 result_index += 1;
566 }
567
568 return allocator.shrink(result, result_index);
569}
570
571/// This function is like a series of `cd` statements executed one after another.
572/// It resolves "." and "..".
573/// The result does not have a trailing path separator.
574/// If all paths are relative it uses the current working directory as a starting point.
575/// Note: all usage of this function should be audited due to the existence of symlinks.
576/// Without performing actual syscalls, resolving `..` could be incorrect.
577pub fn resolvePosix(allocator: *Allocator, paths: []const []const u8) ![]u8 {
578 if (paths.len == 0) {
579 assert(!is_windows); // resolvePosix called on windows can't use getCwd
580 return os.getCwdAlloc(allocator);
581 }
582
583 var first_index: usize = 0;
584 var have_abs = false;
585 var max_size: usize = 0;
586 for (paths) |p, i| {
587 if (isAbsolutePosix(p)) {
588 first_index = i;
589 have_abs = true;
590 max_size = 0;
591 }
592 max_size += p.len + 1;
593 }
594
595 var result: []u8 = undefined;
596 var result_index: usize = 0;
597
598 if (have_abs) {
599 result = try allocator.alloc(u8, max_size);
600 } else {
601 assert(!is_windows); // resolvePosix called on windows can't use getCwd
602 const cwd = try os.getCwdAlloc(allocator);
603 defer allocator.free(cwd);
604 result = try allocator.alloc(u8, max_size + cwd.len + 1);
605 mem.copy(u8, result, cwd);
606 result_index += cwd.len;
607 }
608 errdefer allocator.free(result);
609
610 for (paths[first_index..]) |p, i| {
611 var it = mem.tokenize(p, "/");
612 while (it.next()) |component| {
613 if (mem.eql(u8, component, ".")) {
614 continue;
615 } else if (mem.eql(u8, component, "..")) {
616 while (true) {
617 if (result_index == 0)
618 break;
619 result_index -= 1;
620 if (result[result_index] == '/')
621 break;
622 }
623 } else {
624 result[result_index] = '/';
625 result_index += 1;
626 mem.copy(u8, result[result_index..], component);
627 result_index += component.len;
628 }
629 }
630 }
631
632 if (result_index == 0) {
633 result[0] = '/';
634 result_index += 1;
635 }
636
637 return allocator.shrink(result, result_index);
638}
639
640test "os.path.resolve" {
641 const cwd = try os.getCwdAlloc(debug.global_allocator);
642 if (is_windows) {
643 if (windowsParsePath(cwd).kind == WindowsPath.Kind.Drive) {
644 cwd[0] = asciiUpper(cwd[0]);
645 }
646 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{"."}), cwd));
647 } else {
648 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "a/b/c/", "../../.." }), cwd));
649 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{"."}), cwd));
650 }
651}
652
653test "os.path.resolveWindows" {
654 if (is_windows) {
655 const cwd = try os.getCwdAlloc(debug.global_allocator);
656 const parsed_cwd = windowsParsePath(cwd);
657 {
658 const result = testResolveWindows([][]const u8{ "/usr/local", "lib\\zig\\std\\array_list.zig" });
659 const expected = try join(debug.global_allocator, [][]const u8{
660 parsed_cwd.disk_designator,
661 "usr\\local\\lib\\zig\\std\\array_list.zig",
662 });
663 if (parsed_cwd.kind == WindowsPath.Kind.Drive) {
664 expected[0] = asciiUpper(parsed_cwd.disk_designator[0]);
665 }
666 testing.expect(mem.eql(u8, result, expected));
667 }
668 {
669 const result = testResolveWindows([][]const u8{ "usr/local", "lib\\zig" });
670 const expected = try join(debug.global_allocator, [][]const u8{
671 cwd,
672 "usr\\local\\lib\\zig",
673 });
674 if (parsed_cwd.kind == WindowsPath.Kind.Drive) {
675 expected[0] = asciiUpper(parsed_cwd.disk_designator[0]);
676 }
677 testing.expect(mem.eql(u8, result, expected));
678 }
679 }
680
681 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:\\a\\b\\c", "/hi", "ok" }), "C:\\hi\\ok"));
682 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/blah\\blah", "d:/games", "c:../a" }), "C:\\blah\\a"));
683 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/blah\\blah", "d:/games", "C:../a" }), "C:\\blah\\a"));
684 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/ignore", "d:\\a/b\\c/d", "\\e.exe" }), "D:\\e.exe"));
685 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/ignore", "c:/some/file" }), "C:\\some\\file"));
686 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "d:/ignore", "d:some/dir//" }), "D:\\ignore\\some\\dir"));
687 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "//server/share", "..", "relative\\" }), "\\\\server\\share\\relative"));
688 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//" }), "C:\\"));
689 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//dir" }), "C:\\dir"));
690 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//server/share" }), "\\\\server\\share\\"));
691 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "//server//share" }), "\\\\server\\share\\"));
692 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "c:/", "///some//dir" }), "C:\\some\\dir"));
693 testing.expect(mem.eql(u8, testResolveWindows([][]const u8{ "C:\\foo\\tmp.3\\", "..\\tmp.3\\cycles\\root.js" }), "C:\\foo\\tmp.3\\cycles\\root.js"));
694}
695
696test "os.path.resolvePosix" {
697 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b", "c" }), "/a/b/c"));
698 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b", "c", "//d", "e///" }), "/d/e"));
699 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/a/b/c", "..", "../" }), "/a"));
700 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/", "..", ".." }), "/"));
701 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{"/a/b/c/"}), "/a/b/c"));
702
703 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/var/lib", "../", "file/" }), "/var/file"));
704 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/var/lib", "/../", "file/" }), "/file"));
705 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/some/dir", ".", "/absolute/" }), "/absolute"));
706 testing.expect(mem.eql(u8, testResolvePosix([][]const u8{ "/foo/tmp.3/", "../tmp.3/cycles/root.js" }), "/foo/tmp.3/cycles/root.js"));
707}
708
709fn testResolveWindows(paths: []const []const u8) []u8 {
710 return resolveWindows(debug.global_allocator, paths) catch unreachable;
711}
712
713fn testResolvePosix(paths: []const []const u8) []u8 {
714 return resolvePosix(debug.global_allocator, paths) catch unreachable;
715}
716
717/// If the path is a file in the current directory (no directory component)
718/// then returns null
719pub fn dirname(path: []const u8) ?[]const u8 {
720 if (is_windows) {
721 return dirnameWindows(path);
722 } else {
723 return dirnamePosix(path);
724 }
725}
726
727pub fn dirnameWindows(path: []const u8) ?[]const u8 {
728 if (path.len == 0)
729 return null;
730
731 const root_slice = diskDesignatorWindows(path);
732 if (path.len == root_slice.len)
733 return path;
734
735 const have_root_slash = path.len > root_slice.len and (path[root_slice.len] == '/' or path[root_slice.len] == '\\');
736
737 var end_index: usize = path.len - 1;
738
739 while ((path[end_index] == '/' or path[end_index] == '\\') and end_index > root_slice.len) {
740 if (end_index == 0)
741 return null;
742 end_index -= 1;
743 }
744
745 while (path[end_index] != '/' and path[end_index] != '\\' and end_index > root_slice.len) {
746 if (end_index == 0)
747 return null;
748 end_index -= 1;
749 }
750
751 if (have_root_slash and end_index == root_slice.len) {
752 end_index += 1;
753 }
754
755 if (end_index == 0)
756 return null;
757
758 return path[0..end_index];
759}
760
761pub fn dirnamePosix(path: []const u8) ?[]const u8 {
762 if (path.len == 0)
763 return null;
764
765 var end_index: usize = path.len - 1;
766 while (path[end_index] == '/') {
767 if (end_index == 0)
768 return path[0..1];
769 end_index -= 1;
770 }
771
772 while (path[end_index] != '/') {
773 if (end_index == 0)
774 return null;
775 end_index -= 1;
776 }
777
778 if (end_index == 0 and path[end_index] == '/')
779 return path[0..1];
780
781 if (end_index == 0)
782 return null;
783
784 return path[0..end_index];
785}
786
787test "os.path.dirnamePosix" {
788 testDirnamePosix("/a/b/c", "/a/b");
789 testDirnamePosix("/a/b/c///", "/a/b");
790 testDirnamePosix("/a", "/");
791 testDirnamePosix("/", "/");
792 testDirnamePosix("////", "/");
793 testDirnamePosix("", null);
794 testDirnamePosix("a", null);
795 testDirnamePosix("a/", null);
796 testDirnamePosix("a//", null);
797}
798
799test "os.path.dirnameWindows" {
800 testDirnameWindows("c:\\", "c:\\");
801 testDirnameWindows("c:\\foo", "c:\\");
802 testDirnameWindows("c:\\foo\\", "c:\\");
803 testDirnameWindows("c:\\foo\\bar", "c:\\foo");
804 testDirnameWindows("c:\\foo\\bar\\", "c:\\foo");
805 testDirnameWindows("c:\\foo\\bar\\baz", "c:\\foo\\bar");
806 testDirnameWindows("\\", "\\");
807 testDirnameWindows("\\foo", "\\");
808 testDirnameWindows("\\foo\\", "\\");
809 testDirnameWindows("\\foo\\bar", "\\foo");
810 testDirnameWindows("\\foo\\bar\\", "\\foo");
811 testDirnameWindows("\\foo\\bar\\baz", "\\foo\\bar");
812 testDirnameWindows("c:", "c:");
813 testDirnameWindows("c:foo", "c:");
814 testDirnameWindows("c:foo\\", "c:");
815 testDirnameWindows("c:foo\\bar", "c:foo");
816 testDirnameWindows("c:foo\\bar\\", "c:foo");
817 testDirnameWindows("c:foo\\bar\\baz", "c:foo\\bar");
818 testDirnameWindows("file:stream", null);
819 testDirnameWindows("dir\\file:stream", "dir");
820 testDirnameWindows("\\\\unc\\share", "\\\\unc\\share");
821 testDirnameWindows("\\\\unc\\share\\foo", "\\\\unc\\share\\");
822 testDirnameWindows("\\\\unc\\share\\foo\\", "\\\\unc\\share\\");
823 testDirnameWindows("\\\\unc\\share\\foo\\bar", "\\\\unc\\share\\foo");
824 testDirnameWindows("\\\\unc\\share\\foo\\bar\\", "\\\\unc\\share\\foo");
825 testDirnameWindows("\\\\unc\\share\\foo\\bar\\baz", "\\\\unc\\share\\foo\\bar");
826 testDirnameWindows("/a/b/", "/a");
827 testDirnameWindows("/a/b", "/a");
828 testDirnameWindows("/a", "/");
829 testDirnameWindows("", null);
830 testDirnameWindows("/", "/");
831 testDirnameWindows("////", "/");
832 testDirnameWindows("foo", null);
833}
834
835fn testDirnamePosix(input: []const u8, expected_output: ?[]const u8) void {
836 if (dirnamePosix(input)) |output| {
837 testing.expect(mem.eql(u8, output, expected_output.?));
838 } else {
839 testing.expect(expected_output == null);
840 }
841}
842
843fn testDirnameWindows(input: []const u8, expected_output: ?[]const u8) void {
844 if (dirnameWindows(input)) |output| {
845 testing.expect(mem.eql(u8, output, expected_output.?));
846 } else {
847 testing.expect(expected_output == null);
848 }
849}
850
851pub fn basename(path: []const u8) []const u8 {
852 if (is_windows) {
853 return basenameWindows(path);
854 } else {
855 return basenamePosix(path);
856 }
857}
858
859pub fn basenamePosix(path: []const u8) []const u8 {
860 if (path.len == 0)
861 return []u8{};
862
863 var end_index: usize = path.len - 1;
864 while (path[end_index] == '/') {
865 if (end_index == 0)
866 return []u8{};
867 end_index -= 1;
868 }
869 var start_index: usize = end_index;
870 end_index += 1;
871 while (path[start_index] != '/') {
872 if (start_index == 0)
873 return path[0..end_index];
874 start_index -= 1;
875 }
876
877 return path[start_index + 1 .. end_index];
878}
879
880pub fn basenameWindows(path: []const u8) []const u8 {
881 if (path.len == 0)
882 return []u8{};
883
884 var end_index: usize = path.len - 1;
885 while (true) {
886 const byte = path[end_index];
887 if (byte == '/' or byte == '\\') {
888 if (end_index == 0)
889 return []u8{};
890 end_index -= 1;
891 continue;
892 }
893 if (byte == ':' and end_index == 1) {
894 return []u8{};
895 }
896 break;
897 }
898
899 var start_index: usize = end_index;
900 end_index += 1;
901 while (path[start_index] != '/' and path[start_index] != '\\' and
902 !(path[start_index] == ':' and start_index == 1))
903 {
904 if (start_index == 0)
905 return path[0..end_index];
906 start_index -= 1;
907 }
908
909 return path[start_index + 1 .. end_index];
910}
911
912test "os.path.basename" {
913 testBasename("", "");
914 testBasename("/", "");
915 testBasename("/dir/basename.ext", "basename.ext");
916 testBasename("/basename.ext", "basename.ext");
917 testBasename("basename.ext", "basename.ext");
918 testBasename("basename.ext/", "basename.ext");
919 testBasename("basename.ext//", "basename.ext");
920 testBasename("/aaa/bbb", "bbb");
921 testBasename("/aaa/", "aaa");
922 testBasename("/aaa/b", "b");
923 testBasename("/a/b", "b");
924 testBasename("//a", "a");
925
926 testBasenamePosix("\\dir\\basename.ext", "\\dir\\basename.ext");
927 testBasenamePosix("\\basename.ext", "\\basename.ext");
928 testBasenamePosix("basename.ext", "basename.ext");
929 testBasenamePosix("basename.ext\\", "basename.ext\\");
930 testBasenamePosix("basename.ext\\\\", "basename.ext\\\\");
931 testBasenamePosix("foo", "foo");
932
933 testBasenameWindows("\\dir\\basename.ext", "basename.ext");
934 testBasenameWindows("\\basename.ext", "basename.ext");
935 testBasenameWindows("basename.ext", "basename.ext");
936 testBasenameWindows("basename.ext\\", "basename.ext");
937 testBasenameWindows("basename.ext\\\\", "basename.ext");
938 testBasenameWindows("foo", "foo");
939 testBasenameWindows("C:", "");
940 testBasenameWindows("C:.", ".");
941 testBasenameWindows("C:\\", "");
942 testBasenameWindows("C:\\dir\\base.ext", "base.ext");
943 testBasenameWindows("C:\\basename.ext", "basename.ext");
944 testBasenameWindows("C:basename.ext", "basename.ext");
945 testBasenameWindows("C:basename.ext\\", "basename.ext");
946 testBasenameWindows("C:basename.ext\\\\", "basename.ext");
947 testBasenameWindows("C:foo", "foo");
948 testBasenameWindows("file:stream", "file:stream");
949}
950
951fn testBasename(input: []const u8, expected_output: []const u8) void {
952 testing.expectEqualSlices(u8, expected_output, basename(input));
953}
954
955fn testBasenamePosix(input: []const u8, expected_output: []const u8) void {
956 testing.expectEqualSlices(u8, expected_output, basenamePosix(input));
957}
958
959fn testBasenameWindows(input: []const u8, expected_output: []const u8) void {
960 testing.expectEqualSlices(u8, expected_output, basenameWindows(input));
961}
962
963/// Returns the relative path from `from` to `to`. If `from` and `to` each
964/// resolve to the same path (after calling `resolve` on each), a zero-length
965/// string is returned.
966/// On Windows this canonicalizes the drive to a capital letter and paths to `\\`.
967pub fn relative(allocator: *Allocator, from: []const u8, to: []const u8) ![]u8 {
968 if (is_windows) {
969 return relativeWindows(allocator, from, to);
970 } else {
971 return relativePosix(allocator, from, to);
972 }
973}
974
975pub fn relativeWindows(allocator: *Allocator, from: []const u8, to: []const u8) ![]u8 {
976 const resolved_from = try resolveWindows(allocator, [][]const u8{from});
977 defer allocator.free(resolved_from);
978
979 var clean_up_resolved_to = true;
980 const resolved_to = try resolveWindows(allocator, [][]const u8{to});
981 defer if (clean_up_resolved_to) allocator.free(resolved_to);
982
983 const parsed_from = windowsParsePath(resolved_from);
984 const parsed_to = windowsParsePath(resolved_to);
985 const result_is_to = x: {
986 if (parsed_from.kind != parsed_to.kind) {
987 break :x true;
988 } else switch (parsed_from.kind) {
989 WindowsPath.Kind.NetworkShare => {
990 break :x !networkShareServersEql(parsed_to.disk_designator, parsed_from.disk_designator);
991 },
992 WindowsPath.Kind.Drive => {
993 break :x asciiUpper(parsed_from.disk_designator[0]) != asciiUpper(parsed_to.disk_designator[0]);
994 },
995 else => unreachable,
996 }
997 };
998
999 if (result_is_to) {
1000 clean_up_resolved_to = false;
1001 return resolved_to;
1002 }
1003
1004 var from_it = mem.tokenize(resolved_from, "/\\");
1005 var to_it = mem.tokenize(resolved_to, "/\\");
1006 while (true) {
1007 const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest());
1008 const to_rest = to_it.rest();
1009 if (to_it.next()) |to_component| {
1010 // TODO ASCII is wrong, we actually need full unicode support to compare paths.
1011 if (asciiEqlIgnoreCase(from_component, to_component))
1012 continue;
1013 }
1014 var up_count: usize = 1;
1015 while (from_it.next()) |_| {
1016 up_count += 1;
1017 }
1018 const up_index_end = up_count * "..\\".len;
1019 const result = try allocator.alloc(u8, up_index_end + to_rest.len);
1020 errdefer allocator.free(result);
1021
1022 var result_index: usize = 0;
1023 while (result_index < up_index_end) {
1024 result[result_index] = '.';
1025 result_index += 1;
1026 result[result_index] = '.';
1027 result_index += 1;
1028 result[result_index] = '\\';
1029 result_index += 1;
1030 }
1031 // shave off the trailing slash
1032 result_index -= 1;
1033
1034 var rest_it = mem.tokenize(to_rest, "/\\");
1035 while (rest_it.next()) |to_component| {
1036 result[result_index] = '\\';
1037 result_index += 1;
1038 mem.copy(u8, result[result_index..], to_component);
1039 result_index += to_component.len;
1040 }
1041
1042 return result[0..result_index];
1043 }
1044
1045 return []u8{};
1046}
1047
1048pub fn relativePosix(allocator: *Allocator, from: []const u8, to: []const u8) ![]u8 {
1049 const resolved_from = try resolvePosix(allocator, [][]const u8{from});
1050 defer allocator.free(resolved_from);
1051
1052 const resolved_to = try resolvePosix(allocator, [][]const u8{to});
1053 defer allocator.free(resolved_to);
1054
1055 var from_it = mem.tokenize(resolved_from, "/");
1056 var to_it = mem.tokenize(resolved_to, "/");
1057 while (true) {
1058 const from_component = from_it.next() orelse return mem.dupe(allocator, u8, to_it.rest());
1059 const to_rest = to_it.rest();
1060 if (to_it.next()) |to_component| {
1061 if (mem.eql(u8, from_component, to_component))
1062 continue;
1063 }
1064 var up_count: usize = 1;
1065 while (from_it.next()) |_| {
1066 up_count += 1;
1067 }
1068 const up_index_end = up_count * "../".len;
1069 const result = try allocator.alloc(u8, up_index_end + to_rest.len);
1070 errdefer allocator.free(result);
1071
1072 var result_index: usize = 0;
1073 while (result_index < up_index_end) {
1074 result[result_index] = '.';
1075 result_index += 1;
1076 result[result_index] = '.';
1077 result_index += 1;
1078 result[result_index] = '/';
1079 result_index += 1;
1080 }
1081 if (to_rest.len == 0) {
1082 // shave off the trailing slash
1083 return result[0 .. result_index - 1];
1084 }
1085
1086 mem.copy(u8, result[result_index..], to_rest);
1087 return result;
1088 }
1089
1090 return []u8{};
1091}
1092
1093test "os.path.relative" {
1094 testRelativeWindows("c:/blah\\blah", "d:/games", "D:\\games");
1095 testRelativeWindows("c:/aaaa/bbbb", "c:/aaaa", "..");
1096 testRelativeWindows("c:/aaaa/bbbb", "c:/cccc", "..\\..\\cccc");
1097 testRelativeWindows("c:/aaaa/bbbb", "c:/aaaa/bbbb", "");
1098 testRelativeWindows("c:/aaaa/bbbb", "c:/aaaa/cccc", "..\\cccc");
1099 testRelativeWindows("c:/aaaa/", "c:/aaaa/cccc", "cccc");
1100 testRelativeWindows("c:/", "c:\\aaaa\\bbbb", "aaaa\\bbbb");
1101 testRelativeWindows("c:/aaaa/bbbb", "d:\\", "D:\\");
1102 testRelativeWindows("c:/AaAa/bbbb", "c:/aaaa/bbbb", "");
1103 testRelativeWindows("c:/aaaaa/", "c:/aaaa/cccc", "..\\aaaa\\cccc");
1104 testRelativeWindows("C:\\foo\\bar\\baz\\quux", "C:\\", "..\\..\\..\\..");
1105 testRelativeWindows("C:\\foo\\test", "C:\\foo\\test\\bar\\package.json", "bar\\package.json");
1106 testRelativeWindows("C:\\foo\\bar\\baz-quux", "C:\\foo\\bar\\baz", "..\\baz");
1107 testRelativeWindows("C:\\foo\\bar\\baz", "C:\\foo\\bar\\baz-quux", "..\\baz-quux");
1108 testRelativeWindows("\\\\foo\\bar", "\\\\foo\\bar\\baz", "baz");
1109 testRelativeWindows("\\\\foo\\bar\\baz", "\\\\foo\\bar", "..");
1110 testRelativeWindows("\\\\foo\\bar\\baz-quux", "\\\\foo\\bar\\baz", "..\\baz");
1111 testRelativeWindows("\\\\foo\\bar\\baz", "\\\\foo\\bar\\baz-quux", "..\\baz-quux");
1112 testRelativeWindows("C:\\baz-quux", "C:\\baz", "..\\baz");
1113 testRelativeWindows("C:\\baz", "C:\\baz-quux", "..\\baz-quux");
1114 testRelativeWindows("\\\\foo\\baz-quux", "\\\\foo\\baz", "..\\baz");
1115 testRelativeWindows("\\\\foo\\baz", "\\\\foo\\baz-quux", "..\\baz-quux");
1116 testRelativeWindows("C:\\baz", "\\\\foo\\bar\\baz", "\\\\foo\\bar\\baz");
1117 testRelativeWindows("\\\\foo\\bar\\baz", "C:\\baz", "C:\\baz");
1118
1119 testRelativePosix("/var/lib", "/var", "..");
1120 testRelativePosix("/var/lib", "/bin", "../../bin");
1121 testRelativePosix("/var/lib", "/var/lib", "");
1122 testRelativePosix("/var/lib", "/var/apache", "../apache");
1123 testRelativePosix("/var/", "/var/lib", "lib");
1124 testRelativePosix("/", "/var/lib", "var/lib");
1125 testRelativePosix("/foo/test", "/foo/test/bar/package.json", "bar/package.json");
1126 testRelativePosix("/Users/a/web/b/test/mails", "/Users/a/web/b", "../..");
1127 testRelativePosix("/foo/bar/baz-quux", "/foo/bar/baz", "../baz");
1128 testRelativePosix("/foo/bar/baz", "/foo/bar/baz-quux", "../baz-quux");
1129 testRelativePosix("/baz-quux", "/baz", "../baz");
1130 testRelativePosix("/baz", "/baz-quux", "../baz-quux");
1131}
1132
1133fn testRelativePosix(from: []const u8, to: []const u8, expected_output: []const u8) void {
1134 const result = relativePosix(debug.global_allocator, from, to) catch unreachable;
1135 testing.expectEqualSlices(u8, expected_output, result);
1136}
1137
1138fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []const u8) void {
1139 const result = relativeWindows(debug.global_allocator, from, to) catch unreachable;
1140 testing.expectEqualSlices(u8, expected_output, result);
1141}
1142
1143pub const RealError = error{
1144 FileNotFound,
1145 AccessDenied,
1146 NameTooLong,
1147 NotSupported,
1148 NotDir,
1149 SymLinkLoop,
1150 InputOutput,
1151 FileTooBig,
1152 IsDir,
1153 ProcessFdQuotaExceeded,
1154 SystemFdQuotaExceeded,
1155 NoDevice,
1156 SystemResources,
1157 NoSpaceLeft,
1158 FileSystem,
1159 BadPathName,
1160 DeviceBusy,
1161
1162 /// On Windows, file paths must be valid Unicode.
1163 InvalidUtf8,
1164
1165 /// TODO remove this possibility
1166 PathAlreadyExists,
1167
1168 /// TODO remove this possibility
1169 Unexpected,
1170};
1171
1172/// Call from Windows-specific code if you already have a UTF-16LE encoded, null terminated string.
1173/// Otherwise use `real` or `realC`.
1174pub fn realW(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: [*]const u16) RealError![]u8 {
1175 const h_file = windows.CreateFileW(
1176 pathname,
1177 windows.GENERIC_READ,
1178 windows.FILE_SHARE_READ,
1179 null,
1180 windows.OPEN_EXISTING,
1181 windows.FILE_ATTRIBUTE_NORMAL,
1182 null,
1183 );
1184 if (h_file == windows.INVALID_HANDLE_VALUE) {
1185 const err = windows.GetLastError();
1186 switch (err) {
1187 windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
1188 windows.ERROR.ACCESS_DENIED => return error.AccessDenied,
1189 windows.ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
1190 else => return os.unexpectedErrorWindows(err),
1191 }
1192 }
1193 defer os.close(h_file);
1194 var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
1195 const casted_len = @intCast(windows.DWORD, utf16le_buf.len); // TODO shouldn't need this cast
1196 const result = windows.GetFinalPathNameByHandleW(h_file, &utf16le_buf, casted_len, windows.VOLUME_NAME_DOS);
1197 assert(result <= utf16le_buf.len);
1198 if (result == 0) {
1199 const err = windows.GetLastError();
1200 switch (err) {
1201 windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
1202 windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
1203 windows.ERROR.NOT_ENOUGH_MEMORY => return error.SystemResources,
1204 windows.ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
1205 windows.ERROR.INVALID_PARAMETER => unreachable,
1206 else => return os.unexpectedErrorWindows(err),
1207 }
1208 }
1209 const utf16le_slice = utf16le_buf[0..result];
1210
1211 // windows returns \\?\ prepended to the path
1212 // we strip it because nobody wants \\?\ prepended to their path
1213 const prefix = []u16{ '\\', '\\', '?', '\\' };
1214 const start_index = if (mem.startsWith(u16, utf16le_slice, prefix)) prefix.len else 0;
1215
1216 // Trust that Windows gives us valid UTF-16LE.
1217 const end_index = std.unicode.utf16leToUtf8(out_buffer, utf16le_slice[start_index..]) catch unreachable;
1218 return out_buffer[0..end_index];
1219}
1220
1221/// See `real`
1222/// Use this when you have a null terminated pointer path.
1223pub fn realC(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: [*]const u8) RealError![]u8 {
1224 switch (builtin.os) {
1225 Os.windows => {
1226 const pathname_w = try windows_util.cStrToPrefixedFileW(pathname);
1227 return realW(out_buffer, pathname_w);
1228 },
1229 Os.freebsd, Os.netbsd, Os.macosx, Os.ios => {
1230 // TODO instead of calling the libc function here, port the implementation to Zig
1231 const err = posix.getErrno(posix.realpath(pathname, out_buffer));
1232 switch (err) {
1233 0 => return mem.toSlice(u8, out_buffer),
1234 posix.EINVAL => unreachable,
1235 posix.EBADF => unreachable,
1236 posix.EFAULT => unreachable,
1237 posix.EACCES => return error.AccessDenied,
1238 posix.ENOENT => return error.FileNotFound,
1239 posix.ENOTSUP => return error.NotSupported,
1240 posix.ENOTDIR => return error.NotDir,
1241 posix.ENAMETOOLONG => return error.NameTooLong,
1242 posix.ELOOP => return error.SymLinkLoop,
1243 posix.EIO => return error.InputOutput,
1244 else => return os.unexpectedErrorPosix(err),
1245 }
1246 },
1247 Os.linux => {
1248 const fd = try os.posixOpenC(pathname, posix.O_PATH | posix.O_NONBLOCK | posix.O_CLOEXEC, 0);
1249 defer os.close(fd);
1250
1251 var buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined;
1252 const proc_path = fmt.bufPrint(buf[0..], "/proc/self/fd/{}\x00", fd) catch unreachable;
1253
1254 return os.readLinkC(out_buffer, proc_path.ptr);
1255 },
1256 else => @compileError("TODO implement os.path.real for " ++ @tagName(builtin.os)),
1257 }
1258}
1259
1260/// Return the canonicalized absolute pathname.
1261/// Expands all symbolic links and resolves references to `.`, `..`, and
1262/// extra `/` characters in ::pathname.
1263/// The return value is a slice of out_buffer, and not necessarily from the beginning.
1264pub fn real(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: []const u8) RealError![]u8 {
1265 switch (builtin.os) {
1266 Os.windows => {
1267 const pathname_w = try windows_util.sliceToPrefixedFileW(pathname);
1268 return realW(out_buffer, &pathname_w);
1269 },
1270 Os.macosx, Os.ios, Os.linux, Os.freebsd, Os.netbsd => {
1271 const pathname_c = try os.toPosixPath(pathname);
1272 return realC(out_buffer, &pathname_c);
1273 },
1274 else => @compileError("Unsupported OS"),
1275 }
1276}
1277
1278/// `real`, except caller must free the returned memory.
1279pub fn realAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 {
1280 var buf: [os.MAX_PATH_BYTES]u8 = undefined;
1281 return mem.dupe(allocator, u8, try real(&buf, pathname));
1282}
1283
1284test "os.path.real" {
1285 // at least call it so it gets compiled
1286 var buf: [os.MAX_PATH_BYTES]u8 = undefined;
1287 testing.expectError(error.FileNotFound, real(&buf, "definitely_bogus_does_not_exist1234"));
1288}
std/os/test.zig+55-33
...@@ -1,8 +1,12 @@...@@ -1,8 +1,12 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const os = std.os;2const os = std.os;
3const testing = std.testing;
3const expect = std.testing.expect;4const expect = std.testing.expect;
4const io = std.io;5const io = std.io;
6const fs = std.fs;
5const mem = std.mem;7const mem = std.mem;
8const File = std.fs.File;
9const Thread = std.Thread;
610
7const a = std.debug.global_allocator;11const a = std.debug.global_allocator;
812
...@@ -11,11 +15,11 @@ const AtomicRmwOp = builtin.AtomicRmwOp;...@@ -11,11 +15,11 @@ const AtomicRmwOp = builtin.AtomicRmwOp;
11const AtomicOrder = builtin.AtomicOrder;15const AtomicOrder = builtin.AtomicOrder;
1216
13test "makePath, put some files in it, deleteTree" {17test "makePath, put some files in it, deleteTree" {
14 try os.makePath(a, "os_test_tmp" ++ os.path.sep_str ++ "b" ++ os.path.sep_str ++ "c");18 try fs.makePath(a, "os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c");
15 try io.writeFile("os_test_tmp" ++ os.path.sep_str ++ "b" ++ os.path.sep_str ++ "c" ++ os.path.sep_str ++ "file.txt", "nonsense");19 try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c" ++ fs.path.sep_str ++ "file.txt", "nonsense");
16 try io.writeFile("os_test_tmp" ++ os.path.sep_str ++ "b" ++ os.path.sep_str ++ "file2.txt", "blah");20 try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "file2.txt", "blah");
17 try os.deleteTree(a, "os_test_tmp");21 try fs.deleteTree(a, "os_test_tmp");
18 if (os.Dir.open(a, "os_test_tmp")) |dir| {22 if (fs.Dir.open(a, "os_test_tmp")) |dir| {
19 @panic("expected error");23 @panic("expected error");
20 } else |err| {24 } else |err| {
21 expect(err == error.FileNotFound);25 expect(err == error.FileNotFound);
...@@ -23,40 +27,37 @@ test "makePath, put some files in it, deleteTree" {...@@ -23,40 +27,37 @@ test "makePath, put some files in it, deleteTree" {
23}27}
2428
25test "access file" {29test "access file" {
26 try os.makePath(a, "os_test_tmp");30 try fs.makePath(a, "os_test_tmp");
27 if (os.File.access("os_test_tmp" ++ os.path.sep_str ++ "file.txt")) |ok| {31 if (File.access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt")) |ok| {
28 @panic("expected error");32 @panic("expected error");
29 } else |err| {33 } else |err| {
30 expect(err == error.FileNotFound);34 expect(err == error.FileNotFound);
31 }35 }
3236
33 try io.writeFile("os_test_tmp" ++ os.path.sep_str ++ "file.txt", "");37 try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", "");
34 try os.File.access("os_test_tmp" ++ os.path.sep_str ++ "file.txt");38 try os.access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", os.F_OK);
35 try os.deleteTree(a, "os_test_tmp");39 try fs.deleteTree(a, "os_test_tmp");
36}40}
3741
38fn testThreadIdFn(thread_id: *os.Thread.Id) void {42fn testThreadIdFn(thread_id: *Thread.Id) void {
39 thread_id.* = os.Thread.getCurrentId();43 thread_id.* = Thread.getCurrentId();
40}44}
4145
42test "std.os.Thread.getCurrentId" {46test "std.Thread.getCurrentId" {
43 if (builtin.single_threaded) return error.SkipZigTest;47 if (builtin.single_threaded) return error.SkipZigTest;
4448
45 var thread_current_id: os.Thread.Id = undefined;49 var thread_current_id: Thread.Id = undefined;
46 const thread = try os.spawnThread(&thread_current_id, testThreadIdFn);50 const thread = try Thread.spawn(&thread_current_id, testThreadIdFn);
47 const thread_id = thread.handle();51 const thread_id = thread.handle();
48 thread.wait();52 thread.wait();
49 if (os.Thread.use_pthreads) {53 if (Thread.use_pthreads) {
50 expect(thread_current_id == thread_id);54 expect(thread_current_id == thread_id);
55 } else if (os.windows.is_the_target) {
56 expect(Thread.getCurrentId() != thread_current_id);
51 } else {57 } else {
52 switch (builtin.os) {58 // If the thread completes very quickly, then thread_id can be 0. See the
53 builtin.Os.windows => expect(os.Thread.getCurrentId() != thread_current_id),59 // documentation comments for `std.Thread.handle`.
54 else => {60 expect(thread_id == 0 or thread_current_id == thread_id);
55 // If the thread completes very quickly, then thread_id can be 0. See the
56 // documentation comments for `std.os.Thread.handle`.
57 expect(thread_id == 0 or thread_current_id == thread_id);
58 },
59 }
60 }61 }
61}62}
6263
...@@ -65,10 +66,10 @@ test "spawn threads" {...@@ -65,10 +66,10 @@ test "spawn threads" {
6566
66 var shared_ctx: i32 = 1;67 var shared_ctx: i32 = 1;
6768
68 const thread1 = try std.os.spawnThread({}, start1);69 const thread1 = try Thread.spawn({}, start1);
69 const thread2 = try std.os.spawnThread(&shared_ctx, start2);70 const thread2 = try Thread.spawn(&shared_ctx, start2);
70 const thread3 = try std.os.spawnThread(&shared_ctx, start2);71 const thread3 = try Thread.spawn(&shared_ctx, start2);
71 const thread4 = try std.os.spawnThread(&shared_ctx, start2);72 const thread4 = try Thread.spawn(&shared_ctx, start2);
7273
73 thread1.wait();74 thread1.wait();
74 thread2.wait();75 thread2.wait();
...@@ -88,7 +89,7 @@ fn start2(ctx: *i32) u8 {...@@ -88,7 +89,7 @@ fn start2(ctx: *i32) u8 {
88}89}
8990
90test "cpu count" {91test "cpu count" {
91 const cpu_count = try std.os.cpuCount(a);92 const cpu_count = try Thread.cpuCount();
92 expect(cpu_count >= 1);93 expect(cpu_count >= 1);
93}94}
9495
...@@ -101,7 +102,7 @@ test "AtomicFile" {...@@ -101,7 +102,7 @@ test "AtomicFile" {
101 \\ this is a test file102 \\ this is a test file
102 ;103 ;
103 {104 {
104 var af = try os.AtomicFile.init(test_out_file, os.File.default_mode);105 var af = try fs.AtomicFile.init(test_out_file, File.default_mode);
105 defer af.deinit();106 defer af.deinit();
106 try af.file.write(test_content);107 try af.file.write(test_content);
107 try af.finish();108 try af.finish();
...@@ -109,13 +110,13 @@ test "AtomicFile" {...@@ -109,13 +110,13 @@ test "AtomicFile" {
109 const content = try io.readFileAlloc(allocator, test_out_file);110 const content = try io.readFileAlloc(allocator, test_out_file);
110 expect(mem.eql(u8, content, test_content));111 expect(mem.eql(u8, content, test_content));
111112
112 try os.deleteFile(test_out_file);113 try fs.deleteFile(test_out_file);
113}114}
114115
115test "thread local storage" {116test "thread local storage" {
116 if (builtin.single_threaded) return error.SkipZigTest;117 if (builtin.single_threaded) return error.SkipZigTest;
117 const thread1 = try std.os.spawnThread({}, testTls);118 const thread1 = try Thread.spawn({}, testTls);
118 const thread2 = try std.os.spawnThread({}, testTls);119 const thread2 = try Thread.spawn({}, testTls);
119 testTls({});120 testTls({});
120 thread1.wait();121 thread1.wait();
121 thread2.wait();122 thread2.wait();
...@@ -127,3 +128,24 @@ fn testTls(context: void) void {...@@ -127,3 +128,24 @@ fn testTls(context: void) void {
127 x += 1;128 x += 1;
128 if (x != 1235) @panic("bad end value");129 if (x != 1235) @panic("bad end value");
129}130}
131
132test "getrandom" {
133 var buf_a: [50]u8 = undefined;
134 var buf_b: [50]u8 = undefined;
135 try os.getrandom(&buf_a);
136 try os.getrandom(&buf_b);
137 // If this test fails the chance is significantly higher that there is a bug than
138 // that two sets of 50 bytes were equal.
139 expect(!mem.eql(u8, buf_a, buf_b));
140}
141
142test "getcwd" {
143 // at least call it so it gets compiled
144 var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
145 _ = os.getcwd(&buf) catch undefined;
146}
147
148test "realpath" {
149 var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
150 testing.expectError(error.FileNotFound, fs.realpath("definitely_bogus_does_not_exist1234", &buf));
151}
std/os/time.zig deleted-307
...@@ -1,307 +0,0 @@
1const std = @import("../std.zig");
2const builtin = @import("builtin");
3const Os = builtin.Os;
4const debug = std.debug;
5const testing = std.testing;
6const math = std.math;
7
8const windows = std.os.windows;
9const linux = std.os.linux;
10const darwin = std.os.darwin;
11const wasi = std.os.wasi;
12const posix = std.os.posix;
13
14pub const epoch = @import("epoch.zig");
15
16/// Spurious wakeups are possible and no precision of timing is guaranteed.
17pub fn sleep(nanoseconds: u64) void {
18 switch (builtin.os) {
19 Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => {
20 const s = nanoseconds / ns_per_s;
21 const ns = nanoseconds % ns_per_s;
22 posixSleep(s, ns);
23 },
24 Os.windows => {
25 const ns_per_ms = ns_per_s / ms_per_s;
26 const milliseconds = nanoseconds / ns_per_ms;
27 const ms_that_will_fit = std.math.cast(windows.DWORD, milliseconds) catch std.math.maxInt(windows.DWORD);
28 windows.Sleep(ms_that_will_fit);
29 },
30 else => @compileError("Unsupported OS"),
31 }
32}
33
34/// Spurious wakeups are possible and no precision of timing is guaranteed.
35pub fn posixSleep(seconds: u64, nanoseconds: u64) void {
36 var req = posix.timespec{
37 .tv_sec = std.math.cast(isize, seconds) catch std.math.maxInt(isize),
38 .tv_nsec = std.math.cast(isize, nanoseconds) catch std.math.maxInt(isize),
39 };
40 var rem: posix.timespec = undefined;
41 while (true) {
42 const ret_val = posix.nanosleep(&req, &rem);
43 const err = posix.getErrno(ret_val);
44 switch (err) {
45 posix.EFAULT => unreachable,
46 posix.EINVAL => {
47 // Sometimes Darwin returns EINVAL for no reason.
48 // We treat it as a spurious wakeup.
49 return;
50 },
51 posix.EINTR => {
52 req = rem;
53 continue;
54 },
55 // This prong handles success as well as unexpected errors.
56 else => return,
57 }
58 }
59}
60
61/// Get the posix timestamp, UTC, in seconds
62pub fn timestamp() u64 {
63 return @divFloor(milliTimestamp(), ms_per_s);
64}
65
66/// Get the posix timestamp, UTC, in milliseconds
67pub const milliTimestamp = switch (builtin.os) {
68 Os.windows => milliTimestampWindows,
69 Os.linux, Os.freebsd, Os.netbsd => milliTimestampPosix,
70 Os.macosx, Os.ios => milliTimestampDarwin,
71 Os.wasi => milliTimestampWasi,
72 else => @compileError("Unsupported OS"),
73};
74
75fn milliTimestampWasi() u64 {
76 var ns: wasi.timestamp_t = undefined;
77
78 // TODO: Verify that precision is ignored
79 const err = wasi.clock_time_get(wasi.CLOCK_REALTIME, 1, &ns);
80 debug.assert(err == wasi.ESUCCESS);
81
82 const ns_per_ms = 1000;
83 return @divFloor(ns, ns_per_ms);
84}
85
86fn milliTimestampWindows() u64 {
87 //FileTime has a granularity of 100 nanoseconds
88 // and uses the NTFS/Windows epoch
89 var ft: windows.FILETIME = undefined;
90 windows.GetSystemTimeAsFileTime(&ft);
91 const hns_per_ms = (ns_per_s / 100) / ms_per_s;
92 const epoch_adj = epoch.windows * ms_per_s;
93
94 const ft64 = (u64(ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
95 return @divFloor(ft64, hns_per_ms) - -epoch_adj;
96}
97
98fn milliTimestampDarwin() u64 {
99 var tv: darwin.timeval = undefined;
100 var err = darwin.gettimeofday(&tv, null);
101 debug.assert(err == 0);
102 const sec_ms = tv.tv_sec * ms_per_s;
103 const usec_ms = @divFloor(tv.tv_usec, us_per_s / ms_per_s);
104 return @intCast(u64, sec_ms + usec_ms);
105}
106
107fn milliTimestampPosix() u64 {
108 //From what I can tell there's no reason clock_gettime
109 // should ever fail for us with CLOCK_REALTIME,
110 // seccomp aside.
111 var ts: posix.timespec = undefined;
112 const err = posix.clock_gettime(posix.CLOCK_REALTIME, &ts);
113 debug.assert(err == 0);
114 const sec_ms = @intCast(u64, ts.tv_sec) * ms_per_s;
115 const nsec_ms = @divFloor(@intCast(u64, ts.tv_nsec), ns_per_s / ms_per_s);
116 return sec_ms + nsec_ms;
117}
118
119/// Multiples of a base unit (nanoseconds)
120pub const nanosecond = 1;
121pub const microsecond = 1000 * nanosecond;
122pub const millisecond = 1000 * microsecond;
123pub const second = 1000 * millisecond;
124pub const minute = 60 * second;
125pub const hour = 60 * minute;
126
127/// Divisions of a second
128pub const ns_per_s = 1000000000;
129pub const us_per_s = 1000000;
130pub const ms_per_s = 1000;
131pub const cs_per_s = 100;
132
133/// Common time divisions
134pub const s_per_min = 60;
135pub const s_per_hour = s_per_min * 60;
136pub const s_per_day = s_per_hour * 24;
137pub const s_per_week = s_per_day * 7;
138
139/// A monotonic high-performance timer.
140/// Timer.start() must be called to initialize the struct, which captures
141/// the counter frequency on windows and darwin, records the resolution,
142/// and gives the user an opportunity to check for the existnece of
143/// monotonic clocks without forcing them to check for error on each read.
144/// .resolution is in nanoseconds on all platforms but .start_time's meaning
145/// depends on the OS. On Windows and Darwin it is a hardware counter
146/// value that requires calculation to convert to a meaninful unit.
147pub const Timer = struct {
148
149 //if we used resolution's value when performing the
150 // performance counter calc on windows/darwin, it would
151 // be less precise
152 frequency: switch (builtin.os) {
153 Os.windows => u64,
154 Os.macosx, Os.ios => darwin.mach_timebase_info_data,
155 else => void,
156 },
157 resolution: u64,
158 start_time: u64,
159
160 //At some point we may change our minds on RAW, but for now we're
161 // sticking with posix standard MONOTONIC. For more information, see:
162 // https://github.com/ziglang/zig/pull/933
163 //
164 //const monotonic_clock_id = switch(builtin.os) {
165 // Os.linux => linux.CLOCK_MONOTONIC_RAW,
166 // else => posix.CLOCK_MONOTONIC,
167 //};
168 const monotonic_clock_id = posix.CLOCK_MONOTONIC;
169 /// Initialize the timer structure.
170 //This gives us an opportunity to grab the counter frequency in windows.
171 //On Windows: QueryPerformanceCounter will succeed on anything >= XP/2000.
172 //On Posix: CLOCK_MONOTONIC will only fail if the monotonic counter is not
173 // supported, or if the timespec pointer is out of bounds, which should be
174 // impossible here barring cosmic rays or other such occurrences of
175 // incredibly bad luck.
176 //On Darwin: This cannot fail, as far as I am able to tell.
177 const TimerError = error{
178 TimerUnsupported,
179 Unexpected,
180 };
181 pub fn start() TimerError!Timer {
182 var self: Timer = undefined;
183
184 switch (builtin.os) {
185 Os.windows => {
186 var freq: i64 = undefined;
187 var err = windows.QueryPerformanceFrequency(&freq);
188 if (err == windows.FALSE) return error.TimerUnsupported;
189 self.frequency = @intCast(u64, freq);
190 self.resolution = @divFloor(ns_per_s, self.frequency);
191
192 var start_time: i64 = undefined;
193 err = windows.QueryPerformanceCounter(&start_time);
194 debug.assert(err != windows.FALSE);
195 self.start_time = @intCast(u64, start_time);
196 },
197 Os.linux, Os.freebsd, Os.netbsd => {
198 //On Linux, seccomp can do arbitrary things to our ability to call
199 // syscalls, including return any errno value it wants and
200 // inconsistently throwing errors. Since we can't account for
201 // abuses of seccomp in a reasonable way, we'll assume that if
202 // seccomp is going to block us it will at least do so consistently
203 var ts: posix.timespec = undefined;
204 var result = posix.clock_getres(monotonic_clock_id, &ts);
205 var errno = posix.getErrno(result);
206 switch (errno) {
207 0 => {},
208 posix.EINVAL => return error.TimerUnsupported,
209 else => return std.os.unexpectedErrorPosix(errno),
210 }
211 self.resolution = @intCast(u64, ts.tv_sec) * u64(ns_per_s) + @intCast(u64, ts.tv_nsec);
212
213 result = posix.clock_gettime(monotonic_clock_id, &ts);
214 errno = posix.getErrno(result);
215 if (errno != 0) return std.os.unexpectedErrorPosix(errno);
216 self.start_time = @intCast(u64, ts.tv_sec) * u64(ns_per_s) + @intCast(u64, ts.tv_nsec);
217 },
218 Os.macosx, Os.ios => {
219 darwin.mach_timebase_info(&self.frequency);
220 self.resolution = @divFloor(self.frequency.numer, self.frequency.denom);
221 self.start_time = darwin.mach_absolute_time();
222 },
223 else => @compileError("Unsupported OS"),
224 }
225 return self;
226 }
227
228 /// Reads the timer value since start or the last reset in nanoseconds
229 pub fn read(self: *Timer) u64 {
230 var clock = clockNative() - self.start_time;
231 return switch (builtin.os) {
232 Os.windows => @divFloor(clock * ns_per_s, self.frequency),
233 Os.linux, Os.freebsd, Os.netbsd => clock,
234 Os.macosx, Os.ios => @divFloor(clock * self.frequency.numer, self.frequency.denom),
235 else => @compileError("Unsupported OS"),
236 };
237 }
238
239 /// Resets the timer value to 0/now.
240 pub fn reset(self: *Timer) void {
241 self.start_time = clockNative();
242 }
243
244 /// Returns the current value of the timer in nanoseconds, then resets it
245 pub fn lap(self: *Timer) u64 {
246 var now = clockNative();
247 var lap_time = self.read();
248 self.start_time = now;
249 return lap_time;
250 }
251
252 const clockNative = switch (builtin.os) {
253 Os.windows => clockWindows,
254 Os.linux, Os.freebsd, Os.netbsd => clockLinux,
255 Os.macosx, Os.ios => clockDarwin,
256 else => @compileError("Unsupported OS"),
257 };
258
259 fn clockWindows() u64 {
260 var result: i64 = undefined;
261 var err = windows.QueryPerformanceCounter(&result);
262 debug.assert(err != windows.FALSE);
263 return @intCast(u64, result);
264 }
265
266 fn clockDarwin() u64 {
267 return darwin.mach_absolute_time();
268 }
269
270 fn clockLinux() u64 {
271 var ts: posix.timespec = undefined;
272 var result = posix.clock_gettime(monotonic_clock_id, &ts);
273 debug.assert(posix.getErrno(result) == 0);
274 return @intCast(u64, ts.tv_sec) * u64(ns_per_s) + @intCast(u64, ts.tv_nsec);
275 }
276};
277
278test "os.time.sleep" {
279 sleep(1);
280}
281
282test "os.time.timestamp" {
283 const ns_per_ms = (ns_per_s / ms_per_s);
284 const margin = 50;
285
286 const time_0 = milliTimestamp();
287 sleep(ns_per_ms);
288 const time_1 = milliTimestamp();
289 const interval = time_1 - time_0;
290 testing.expect(interval > 0 and interval < margin);
291}
292
293test "os.time.Timer" {
294 const ns_per_ms = (ns_per_s / ms_per_s);
295 const margin = ns_per_ms * 150;
296
297 var timer = try Timer.start();
298 sleep(10 * ns_per_ms);
299 const time_0 = timer.read();
300 testing.expect(time_0 > 0 and time_0 < margin);
301
302 const time_1 = timer.lap();
303 testing.expect(time_1 >= time_0);
304
305 timer.reset();
306 testing.expect(timer.read() < time_1);
307}
std/os/wasi.zig+71-33
...@@ -1,42 +1,80 @@...@@ -1,42 +1,80 @@
1pub use @import("wasi/core.zig");1// Based on https://github.com/CraneStation/wasi-sysroot/blob/wasi/libc-bottom-half/headers/public/wasi/core.h
2// and https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md
3const builtin = @import("builtin");
4const std = @import("std");
5const assert = std.debug.assert;
26
3pub const STDIN_FILENO = 0;7pub const is_the_target = builtin.os == .wasi;
4pub const STDOUT_FILENO = 1;8pub use @import("bits.zig");
5pub const STDERR_FILENO = 2;
69
7pub fn getErrno(r: usize) usize {10comptime {
8 const signed_r = @bitCast(isize, r);11 assert(@alignOf(i8) == 1);
9 return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;12 assert(@alignOf(u8) == 1);
13 assert(@alignOf(i16) == 2);
14 assert(@alignOf(u16) == 2);
15 assert(@alignOf(i32) == 4);
16 assert(@alignOf(u32) == 4);
17 assert(@alignOf(i64) == 8);
18 assert(@alignOf(u64) == 8);
10}19}
1120
12pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {21pub const iovec_t = iovec;
13 var nwritten: usize = undefined;22pub const ciovec_t = iovec_const;
1423
15 const ciovs = ciovec_t{24pub extern "wasi_unstable" fn args_get(argv: [*][*]u8, argv_buf: [*]u8) errno_t;
16 .buf = buf,25pub extern "wasi_unstable" fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t;
17 .buf_len = count,
18 };
1926
20 const err = fd_write(@bitCast(fd_t, isize(fd)), &ciovs, 1, &nwritten);27pub extern "wasi_unstable" fn clock_res_get(clock_id: clockid_t, resolution: *timestamp_t) errno_t;
21 if (err == ESUCCESS) {28pub extern "wasi_unstable" fn clock_time_get(clock_id: clockid_t, precision: timestamp_t, timestamp: *timestamp_t) errno_t;
22 return nwritten;
23 } else {
24 return @bitCast(usize, -isize(err));
25 }
26}
2729
28pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize {30pub extern "wasi_unstable" fn environ_get(environ: [*]?[*]u8, environ_buf: [*]u8) errno_t;
29 var nread: usize = undefined;31pub extern "wasi_unstable" fn environ_sizes_get(environ_count: *usize, environ_buf_size: *usize) errno_t;
3032
31 const iovs = iovec_t{33pub extern "wasi_unstable" fn fd_advise(fd: fd_t, offset: filesize_t, len: filesize_t, advice: advice_t) errno_t;
32 .buf = buf,34pub extern "wasi_unstable" fn fd_allocate(fd: fd_t, offset: filesize_t, len: filesize_t) errno_t;
33 .buf_len = nbyte,35pub extern "wasi_unstable" fn fd_close(fd: fd_t) errno_t;
34 };36pub extern "wasi_unstable" fn fd_datasync(fd: fd_t) errno_t;
37pub extern "wasi_unstable" fn fd_pread(fd: fd_t, iovs: [*]const iovec_t, iovs_len: usize, offset: filesize_t, nread: *usize) errno_t;
38pub extern "wasi_unstable" fn fd_pwrite(fd: fd_t, iovs: [*]const ciovec_t, iovs_len: usize, offset: filesize_t, nwritten: *usize) errno_t;
39pub extern "wasi_unstable" fn fd_read(fd: fd_t, iovs: [*]const iovec_t, iovs_len: usize, nread: *usize) errno_t;
40pub extern "wasi_unstable" fn fd_readdir(fd: fd_t, buf: [*]u8, buf_len: usize, cookie: dircookie_t, bufused: *usize) errno_t;
41pub extern "wasi_unstable" fn fd_renumber(from: fd_t, to: fd_t) errno_t;
42pub extern "wasi_unstable" fn fd_seek(fd: fd_t, offset: filedelta_t, whence: whence_t, newoffset: *filesize_t) errno_t;
43pub extern "wasi_unstable" fn fd_sync(fd: fd_t) errno_t;
44pub extern "wasi_unstable" fn fd_tell(fd: fd_t, newoffset: *filesize_t) errno_t;
45pub extern "wasi_unstable" fn fd_write(fd: fd_t, iovs: [*]const ciovec_t, iovs_len: usize, nwritten: *usize) errno_t;
3546
36 const err = fd_read(@bitCast(fd_t, isize(fd)), &iovs, 1, &nread);47pub extern "wasi_unstable" fn fd_fdstat_get(fd: fd_t, buf: *fdstat_t) errno_t;
37 if (err == ESUCCESS) {48pub extern "wasi_unstable" fn fd_fdstat_set_flags(fd: fd_t, flags: fdflags_t) errno_t;
38 return nread;49pub extern "wasi_unstable" fn fd_fdstat_set_rights(fd: fd_t, fs_rights_base: rights_t, fs_rights_inheriting: rights_t) errno_t;
39 } else {50
40 return @bitCast(usize, -isize(err));51pub extern "wasi_unstable" fn fd_filestat_get(fd: fd_t, buf: *filestat_t) errno_t;
41 }52pub extern "wasi_unstable" fn fd_filestat_set_size(fd: fd_t, st_size: filesize_t) errno_t;
42}53pub extern "wasi_unstable" fn fd_filestat_set_times(fd: fd_t, st_atim: timestamp_t, st_mtim: timestamp_t, fstflags: fstflags_t) errno_t;
54
55pub extern "wasi_unstable" fn fd_prestat_get(fd: fd_t, buf: *prestat_t) errno_t;
56pub extern "wasi_unstable" fn fd_prestat_dir_name(fd: fd_t, path: [*]u8, path_len: usize) errno_t;
57
58pub extern "wasi_unstable" fn path_create_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
59pub extern "wasi_unstable" fn path_filestat_get(fd: fd_t, flags: lookupflags_t, path: [*]const u8, path_len: usize, buf: *filestat_t) errno_t;
60pub 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;
61pub 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;
62pub 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;
63pub extern "wasi_unstable" fn path_readlink(fd: fd_t, path: [*]const u8, path_len: usize, buf: [*]u8, buf_len: usize, bufused: *usize) errno_t;
64pub extern "wasi_unstable" fn path_remove_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
65pub 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;
66pub 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;
67pub extern "wasi_unstable" fn path_unlink_file(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
68
69pub extern "wasi_unstable" fn poll_oneoff(in: *const subscription_t, out: *event_t, nsubscriptions: usize, nevents: *usize) errno_t;
70
71pub extern "wasi_unstable" fn proc_exit(rval: exitcode_t) noreturn;
72pub extern "wasi_unstable" fn proc_raise(sig: signal_t) errno_t;
73
74pub extern "wasi_unstable" fn random_get(buf: [*]u8, buf_len: usize) errno_t;
75
76pub extern "wasi_unstable" fn sched_yield() errno_t;
77
78pub 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;
79pub 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;
80pub extern "wasi_unstable" fn sock_shutdown(sock: fd_t, how: sdflags_t) errno_t;
std/os/wasi/core.zig deleted-374
...@@ -1,374 +0,0 @@
1// Based on https://github.com/CraneStation/wasi-sysroot/blob/wasi/libc-bottom-half/headers/public/wasi/core.h
2// and https://github.com/WebAssembly/WASI/blob/master/design/WASI-core.md
3
4pub const advice_t = u8;
5pub const ADVICE_NORMAL: advice_t = 0;
6pub const ADVICE_SEQUENTIAL: advice_t = 1;
7pub const ADVICE_RANDOM: advice_t = 2;
8pub const ADVICE_WILLNEED: advice_t = 3;
9pub const ADVICE_DONTNEED: advice_t = 4;
10pub const ADVICE_NOREUSE: advice_t = 5;
11
12pub const ciovec_t = extern struct {
13 buf: [*]const u8,
14 buf_len: usize,
15};
16
17pub const clockid_t = u32;
18pub const CLOCK_REALTIME: clockid_t = 0;
19pub const CLOCK_MONOTONIC: clockid_t = 1;
20pub const CLOCK_PROCESS_CPUTIME_ID: clockid_t = 2;
21pub const CLOCK_THREAD_CPUTIME_ID: clockid_t = 3;
22
23pub const device_t = u64;
24
25pub const dircookie_t = u64;
26pub const DIRCOOKIE_START: dircookie_t = 0;
27
28pub const dirent_t = extern struct {
29 d_next: dircookie_t,
30 d_ino: inode_t,
31 d_namlen: u32,
32 d_type: filetype_t,
33};
34
35pub const errno_t = u16;
36pub const ESUCCESS: errno_t = 0;
37pub const E2BIG: errno_t = 1;
38pub const EACCES: errno_t = 2;
39pub const EADDRINUSE: errno_t = 3;
40pub const EADDRNOTAVAIL: errno_t = 4;
41pub const EAFNOSUPPORT: errno_t = 5;
42pub const EAGAIN: errno_t = 6;
43pub const EALREADY: errno_t = 7;
44pub const EBADF: errno_t = 8;
45pub const EBADMSG: errno_t = 9;
46pub const EBUSY: errno_t = 10;
47pub const ECANCELED: errno_t = 11;
48pub const ECHILD: errno_t = 12;
49pub const ECONNABORTED: errno_t = 13;
50pub const ECONNREFUSED: errno_t = 14;
51pub const ECONNRESET: errno_t = 15;
52pub const EDEADLK: errno_t = 16;
53pub const EDESTADDRREQ: errno_t = 17;
54pub const EDOM: errno_t = 18;
55pub const EDQUOT: errno_t = 19;
56pub const EEXIST: errno_t = 20;
57pub const EFAULT: errno_t = 21;
58pub const EFBIG: errno_t = 22;
59pub const EHOSTUNREACH: errno_t = 23;
60pub const EIDRM: errno_t = 24;
61pub const EILSEQ: errno_t = 25;
62pub const EINPROGRESS: errno_t = 26;
63pub const EINTR: errno_t = 27;
64pub const EINVAL: errno_t = 28;
65pub const EIO: errno_t = 29;
66pub const EISCONN: errno_t = 30;
67pub const EISDIR: errno_t = 31;
68pub const ELOOP: errno_t = 32;
69pub const EMFILE: errno_t = 33;
70pub const EMLINK: errno_t = 34;
71pub const EMSGSIZE: errno_t = 35;
72pub const EMULTIHOP: errno_t = 36;
73pub const ENAMETOOLONG: errno_t = 37;
74pub const ENETDOWN: errno_t = 38;
75pub const ENETRESET: errno_t = 39;
76pub const ENETUNREACH: errno_t = 40;
77pub const ENFILE: errno_t = 41;
78pub const ENOBUFS: errno_t = 42;
79pub const ENODEV: errno_t = 43;
80pub const ENOENT: errno_t = 44;
81pub const ENOEXEC: errno_t = 45;
82pub const ENOLCK: errno_t = 46;
83pub const ENOLINK: errno_t = 47;
84pub const ENOMEM: errno_t = 48;
85pub const ENOMSG: errno_t = 49;
86pub const ENOPROTOOPT: errno_t = 50;
87pub const ENOSPC: errno_t = 51;
88pub const ENOSYS: errno_t = 52;
89pub const ENOTCONN: errno_t = 53;
90pub const ENOTDIR: errno_t = 54;
91pub const ENOTEMPTY: errno_t = 55;
92pub const ENOTRECOVERABLE: errno_t = 56;
93pub const ENOTSOCK: errno_t = 57;
94pub const ENOTSUP: errno_t = 58;
95pub const ENOTTY: errno_t = 59;
96pub const ENXIO: errno_t = 60;
97pub const EOVERFLOW: errno_t = 61;
98pub const EOWNERDEAD: errno_t = 62;
99pub const EPERM: errno_t = 63;
100pub const EPIPE: errno_t = 64;
101pub const EPROTO: errno_t = 65;
102pub const EPROTONOSUPPORT: errno_t = 66;
103pub const EPROTOTYPE: errno_t = 67;
104pub const ERANGE: errno_t = 68;
105pub const EROFS: errno_t = 69;
106pub const ESPIPE: errno_t = 70;
107pub const ESRCH: errno_t = 71;
108pub const ESTALE: errno_t = 72;
109pub const ETIMEDOUT: errno_t = 73;
110pub const ETXTBSY: errno_t = 74;
111pub const EXDEV: errno_t = 75;
112pub const ENOTCAPABLE: errno_t = 76;
113
114pub const event_t = extern struct {
115 userdata: userdata_t,
116 @"error": errno_t,
117 @"type": eventtype_t,
118 u: extern union {
119 fd_readwrite: extern struct {
120 nbytes: filesize_t,
121 flags: eventrwflags_t,
122 },
123 },
124};
125
126pub const eventrwflags_t = u16;
127pub const EVENT_FD_READWRITE_HANGUP: eventrwflags_t = 0x0001;
128
129pub const eventtype_t = u8;
130pub const EVENTTYPE_CLOCK: eventtype_t = 0;
131pub const EVENTTYPE_FD_READ: eventtype_t = 1;
132pub const EVENTTYPE_FD_WRITE: eventtype_t = 2;
133
134pub const exitcode_t = u32;
135
136pub const fd_t = u32;
137
138pub const fdflags_t = u16;
139pub const FDFLAG_APPEND: fdflags_t = 0x0001;
140pub const FDFLAG_DSYNC: fdflags_t = 0x0002;
141pub const FDFLAG_NONBLOCK: fdflags_t = 0x0004;
142pub const FDFLAG_RSYNC: fdflags_t = 0x0008;
143pub const FDFLAG_SYNC: fdflags_t = 0x0010;
144
145const fdstat_t = extern struct {
146 fs_filetype: filetype_t,
147 fs_flags: fdflags_t,
148 fs_rights_base: rights_t,
149 fs_rights_inheriting: rights_t,
150};
151
152pub const filedelta_t = i64;
153
154pub const filesize_t = u64;
155
156pub const filestat_t = extern struct {
157 st_dev: device_t,
158 st_ino: inode_t,
159 st_filetype: filetype_t,
160 st_nlink: linkcount_t,
161 st_size: filesize_t,
162 st_atim: timestamp_t,
163 st_mtim: timestamp_t,
164 st_ctim: timestamp_t,
165};
166
167pub const filetype_t = u8;
168pub const FILETYPE_UNKNOWN: filetype_t = 0;
169pub const FILETYPE_BLOCK_DEVICE: filetype_t = 1;
170pub const FILETYPE_CHARACTER_DEVICE: filetype_t = 2;
171pub const FILETYPE_DIRECTORY: filetype_t = 3;
172pub const FILETYPE_REGULAR_FILE: filetype_t = 4;
173pub const FILETYPE_SOCKET_DGRAM: filetype_t = 5;
174pub const FILETYPE_SOCKET_STREAM: filetype_t = 6;
175pub const FILETYPE_SYMBOLIC_LINK: filetype_t = 7;
176
177pub const fstflags_t = u16;
178pub const FILESTAT_SET_ATIM: fstflags_t = 0x0001;
179pub const FILESTAT_SET_ATIM_NOW: fstflags_t = 0x0002;
180pub const FILESTAT_SET_MTIM: fstflags_t = 0x0004;
181pub const FILESTAT_SET_MTIM_NOW: fstflags_t = 0x0008;
182
183pub const inode_t = u64;
184
185pub const iovec_t = extern struct {
186 buf: [*]u8,
187 buf_len: usize,
188};
189
190pub const linkcount_t = u32;
191
192pub const lookupflags_t = u32;
193pub const LOOKUP_SYMLINK_FOLLOW: lookupflags_t = 0x00000001;
194
195pub const oflags_t = u16;
196pub const O_CREAT: oflags_t = 0x0001;
197pub const O_DIRECTORY: oflags_t = 0x0002;
198pub const O_EXCL: oflags_t = 0x0004;
199pub const O_TRUNC: oflags_t = 0x0008;
200
201pub const preopentype_t = u8;
202pub const PREOPENTYPE_DIR: preopentype_t = 0;
203
204pub const prestat_t = extern struct {
205 pr_type: preopentype_t,
206 u: extern union {
207 dir: extern struct {
208 pr_name_len: usize,
209 },
210 },
211};
212
213pub const riflags_t = u16;
214pub const SOCK_RECV_PEEK: riflags_t = 0x0001;
215pub const SOCK_RECV_WAITALL: riflags_t = 0x0002;
216
217pub const rights_t = u64;
218pub const RIGHT_FD_DATASYNC: rights_t = 0x0000000000000001;
219pub const RIGHT_FD_READ: rights_t = 0x0000000000000002;
220pub const RIGHT_FD_SEEK: rights_t = 0x0000000000000004;
221pub const RIGHT_FD_FDSTAT_SET_FLAGS: rights_t = 0x0000000000000008;
222pub const RIGHT_FD_SYNC: rights_t = 0x0000000000000010;
223pub const RIGHT_FD_TELL: rights_t = 0x0000000000000020;
224pub const RIGHT_FD_WRITE: rights_t = 0x0000000000000040;
225pub const RIGHT_FD_ADVISE: rights_t = 0x0000000000000080;
226pub const RIGHT_FD_ALLOCATE: rights_t = 0x0000000000000100;
227pub const RIGHT_PATH_CREATE_DIRECTORY: rights_t = 0x0000000000000200;
228pub const RIGHT_PATH_CREATE_FILE: rights_t = 0x0000000000000400;
229pub const RIGHT_PATH_LINK_SOURCE: rights_t = 0x0000000000000800;
230pub const RIGHT_PATH_LINK_TARGET: rights_t = 0x0000000000001000;
231pub const RIGHT_PATH_OPEN: rights_t = 0x0000000000002000;
232pub const RIGHT_FD_READDIR: rights_t = 0x0000000000004000;
233pub const RIGHT_PATH_READLINK: rights_t = 0x0000000000008000;
234pub const RIGHT_PATH_RENAME_SOURCE: rights_t = 0x0000000000010000;
235pub const RIGHT_PATH_RENAME_TARGET: rights_t = 0x0000000000020000;
236pub const RIGHT_PATH_FILESTAT_GET: rights_t = 0x0000000000040000;
237pub const RIGHT_PATH_FILESTAT_SET_SIZE: rights_t = 0x0000000000080000;
238pub const RIGHT_PATH_FILESTAT_SET_TIMES: rights_t = 0x0000000000100000;
239pub const RIGHT_FD_FILESTAT_GET: rights_t = 0x0000000000200000;
240pub const RIGHT_FD_FILESTAT_SET_SIZE: rights_t = 0x0000000000400000;
241pub const RIGHT_FD_FILESTAT_SET_TIMES: rights_t = 0x0000000000800000;
242pub const RIGHT_PATH_SYMLINK: rights_t = 0x0000000001000000;
243pub const RIGHT_PATH_REMOVE_DIRECTORY: rights_t = 0x0000000002000000;
244pub const RIGHT_PATH_UNLINK_FILE: rights_t = 0x0000000004000000;
245pub const RIGHT_POLL_FD_READWRITE: rights_t = 0x0000000008000000;
246pub const RIGHT_SOCK_SHUTDOWN: rights_t = 0x0000000010000000;
247
248pub const roflags_t = u16;
249pub const SOCK_RECV_DATA_TRUNCATED: roflags_t = 0x0001;
250
251pub const sdflags_t = u8;
252pub const SHUT_RD: sdflags_t = 0x01;
253pub const SHUT_WR: sdflags_t = 0x02;
254
255pub const siflags_t = u16;
256
257pub const signal_t = u8;
258pub const SIGHUP: signal_t = 1;
259pub const SIGINT: signal_t = 2;
260pub const SIGQUIT: signal_t = 3;
261pub const SIGILL: signal_t = 4;
262pub const SIGTRAP: signal_t = 5;
263pub const SIGABRT: signal_t = 6;
264pub const SIGBUS: signal_t = 7;
265pub const SIGFPE: signal_t = 8;
266pub const SIGKILL: signal_t = 9;
267pub const SIGUSR1: signal_t = 10;
268pub const SIGSEGV: signal_t = 11;
269pub const SIGUSR2: signal_t = 12;
270pub const SIGPIPE: signal_t = 13;
271pub const SIGALRM: signal_t = 14;
272pub const SIGTERM: signal_t = 15;
273pub const SIGCHLD: signal_t = 16;
274pub const SIGCONT: signal_t = 17;
275pub const SIGSTOP: signal_t = 18;
276pub const SIGTSTP: signal_t = 19;
277pub const SIGTTIN: signal_t = 20;
278pub const SIGTTOU: signal_t = 21;
279pub const SIGURG: signal_t = 22;
280pub const SIGXCPU: signal_t = 23;
281pub const SIGXFSZ: signal_t = 24;
282pub const SIGVTALRM: signal_t = 25;
283pub const SIGPROF: signal_t = 26;
284pub const SIGWINCH: signal_t = 27;
285pub const SIGPOLL: signal_t = 28;
286pub const SIGPWR: signal_t = 29;
287pub const SIGSYS: signal_t = 30;
288
289pub const subclockflags_t = u16;
290pub const SUBSCRIPTION_CLOCK_ABSTIME: subclockflags_t = 0x0001;
291
292pub const subscription_t = extern struct {
293 userdata: userdata_t,
294 @"type": eventtype_t,
295 u: extern union {
296 clock: extern struct {
297 identifier: userdata_t,
298 clock_id: clockid_t,
299 timeout: timestamp_t,
300 precision: timestamp_t,
301 flags: subclockflags_t,
302 },
303 fd_readwrite: extern struct {
304 fd: fd_t,
305 },
306 },
307};
308
309pub const timestamp_t = u64;
310
311pub const userdata_t = u64;
312
313pub const whence_t = u8;
314pub const WHENCE_CUR: whence_t = 0;
315pub const WHENCE_END: whence_t = 1;
316pub const WHENCE_SET: whence_t = 2;
317
318pub extern "wasi_unstable" fn args_get(argv: [*][*]u8, argv_buf: [*]u8) errno_t;
319pub extern "wasi_unstable" fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t;
320
321pub extern "wasi_unstable" fn clock_res_get(clock_id: clockid_t, resolution: *timestamp_t) errno_t;
322pub extern "wasi_unstable" fn clock_time_get(clock_id: clockid_t, precision: timestamp_t, timestamp: *timestamp_t) errno_t;
323
324pub extern "wasi_unstable" fn environ_get(environ: [*]?[*]u8, environ_buf: [*]u8) errno_t;
325pub extern "wasi_unstable" fn environ_sizes_get(environ_count: *usize, environ_buf_size: *usize) errno_t;
326
327pub extern "wasi_unstable" fn fd_advise(fd: fd_t, offset: filesize_t, len: filesize_t, advice: advice_t) errno_t;
328pub extern "wasi_unstable" fn fd_allocate(fd: fd_t, offset: filesize_t, len: filesize_t) errno_t;
329pub extern "wasi_unstable" fn fd_close(fd: fd_t) errno_t;
330pub extern "wasi_unstable" fn fd_datasync(fd: fd_t) errno_t;
331pub extern "wasi_unstable" fn fd_pread(fd: fd_t, iovs: *const iovec_t, iovs_len: usize, offset: filesize_t, nread: *usize) errno_t;
332pub extern "wasi_unstable" fn fd_pwrite(fd: fd_t, iovs: *const ciovec_t, iovs_len: usize, offset: filesize_t, nwritten: *usize) errno_t;
333pub extern "wasi_unstable" fn fd_read(fd: fd_t, iovs: *const iovec_t, iovs_len: usize, nread: *usize) errno_t;
334pub extern "wasi_unstable" fn fd_readdir(fd: fd_t, buf: [*]u8, buf_len: usize, cookie: dircookie_t, bufused: *usize) errno_t;
335pub extern "wasi_unstable" fn fd_renumber(from: fd_t, to: fd_t) errno_t;
336pub extern "wasi_unstable" fn fd_seek(fd: fd_t, offset: filedelta_t, whence: whence_t, newoffset: *filesize_t) errno_t;
337pub extern "wasi_unstable" fn fd_sync(fd: fd_t) errno_t;
338pub extern "wasi_unstable" fn fd_tell(fd: fd_t, newoffset: *filesize_t) errno_t;
339pub extern "wasi_unstable" fn fd_write(fd: fd_t, iovs: *const ciovec_t, iovs_len: usize, nwritten: *usize) errno_t;
340
341pub extern "wasi_unstable" fn fd_fdstat_get(fd: fd_t, buf: *fdstat_t) errno_t;
342pub extern "wasi_unstable" fn fd_fdstat_set_flags(fd: fd_t, flags: fdflags_t) errno_t;
343pub extern "wasi_unstable" fn fd_fdstat_set_rights(fd: fd_t, fs_rights_base: rights_t, fs_rights_inheriting: rights_t) errno_t;
344
345pub extern "wasi_unstable" fn fd_filestat_get(fd: fd_t, buf: *filestat_t) errno_t;
346pub extern "wasi_unstable" fn fd_filestat_set_size(fd: fd_t, st_size: filesize_t) errno_t;
347pub extern "wasi_unstable" fn fd_filestat_set_times(fd: fd_t, st_atim: timestamp_t, st_mtim: timestamp_t, fstflags: fstflags_t) errno_t;
348
349pub extern "wasi_unstable" fn fd_prestat_get(fd: fd_t, buf: *prestat_t) errno_t;
350pub extern "wasi_unstable" fn fd_prestat_dir_name(fd: fd_t, path: [*]u8, path_len: usize) errno_t;
351
352pub extern "wasi_unstable" fn path_create_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
353pub extern "wasi_unstable" fn path_filestat_get(fd: fd_t, flags: lookupflags_t, path: [*]const u8, path_len: usize, buf: *filestat_t) errno_t;
354pub 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;
355pub 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;
356pub 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;
357pub extern "wasi_unstable" fn path_readlink(fd: fd_t, path: [*]const u8, path_len: usize, buf: [*]u8, buf_len: usize, bufused: *usize) errno_t;
358pub extern "wasi_unstable" fn path_remove_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
359pub 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;
360pub 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;
361pub extern "wasi_unstable" fn path_unlink_file(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
362
363pub extern "wasi_unstable" fn poll_oneoff(in: *const subscription_t, out: *event_t, nsubscriptions: usize, nevents: *usize) errno_t;
364
365pub extern "wasi_unstable" fn proc_exit(rval: exitcode_t) noreturn;
366pub extern "wasi_unstable" fn proc_raise(sig: signal_t) errno_t;
367
368pub extern "wasi_unstable" fn random_get(buf: [*]u8, buf_len: usize) errno_t;
369
370pub extern "wasi_unstable" fn sched_yield() errno_t;
371
372pub 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;
373pub 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;
374pub extern "wasi_unstable" fn sock_shutdown(sock: fd_t, how: sdflags_t) errno_t;
std/os/windows.zig+721-384
...@@ -1,430 +1,767 @@...@@ -1,430 +1,767 @@
1// This file contains thin wrappers around Windows-specific APIs, with these
2// specific goals in mind:
3// * Convert "errno"-style error codes into Zig errors.
4// * When null-terminated or UTF16LE byte buffers are required, provide APIs which accept
5// slices as well as APIs which accept null-terminated UTF16LE byte buffers.
6
7const builtin = @import("builtin");
1const std = @import("../std.zig");8const std = @import("../std.zig");
9const mem = std.mem;
2const assert = std.debug.assert;10const assert = std.debug.assert;
11const math = std.math;
3const maxInt = std.math.maxInt;12const maxInt = std.math.maxInt;
413
5pub use @import("windows/advapi32.zig");14pub const is_the_target = builtin.os == .windows;
6pub use @import("windows/kernel32.zig");15pub const advapi32 = @import("windows/advapi32.zig");
7pub use @import("windows/ntdll.zig");16pub const kernel32 = @import("windows/kernel32.zig");
8pub use @import("windows/ole32.zig");17pub const ntdll = @import("windows/ntdll.zig");
9pub use @import("windows/shell32.zig");18pub const ole32 = @import("windows/ole32.zig");
1019pub const shell32 = @import("windows/shell32.zig");
11test "import" {20
12 _ = @import("windows/util.zig");21pub use @import("windows/bits.zig");
13}22
1423pub const CreateFileError = error{
15pub const ERROR = @import("windows/error.zig");24 SharingViolation,
1625 PathAlreadyExists,
17pub const SHORT = c_short;26
18pub const BOOL = c_int;27 /// When any of the path components can not be found or the file component can not
19pub const BOOLEAN = BYTE;28 /// be found. Some operating systems distinguish between path components not found and
20pub const BYTE = u8;29 /// file components not found, but they are collapsed into FileNotFound to gain
21pub const CHAR = u8;30 /// consistency across operating systems.
22pub const DWORD = u32;31 FileNotFound,
23pub const FLOAT = f32;32
24pub const HANDLE = *c_void;33 AccessDenied,
25pub const HCRYPTPROV = ULONG_PTR;34 PipeBusy,
26pub const HINSTANCE = *@OpaqueType();35 NameTooLong,
27pub const HMODULE = *@OpaqueType();36
28pub const FARPROC = *@OpaqueType();37 /// On Windows, file paths must be valid Unicode.
29pub const INT = c_int;38 InvalidUtf8,
30pub const LPBYTE = *BYTE;39
31pub const LPCH = *CHAR;40 /// On Windows, file paths cannot contain these characters:
32pub const LPCSTR = [*]const CHAR;41 /// '/', '*', '?', '"', '<', '>', '|'
33pub const LPCTSTR = [*]const TCHAR;42 BadPathName,
34pub const LPCVOID = *const c_void;43
35pub const LPDWORD = *DWORD;44 Unexpected,
36pub const LPSTR = [*]CHAR;
37pub const LPTSTR = if (UNICODE) LPWSTR else LPSTR;
38pub const LPVOID = *c_void;
39pub const LPWSTR = [*]WCHAR;
40pub const LPCWSTR = [*]const WCHAR;
41pub const PVOID = *c_void;
42pub const PWSTR = [*]WCHAR;
43pub const SIZE_T = usize;
44pub const TCHAR = if (UNICODE) WCHAR else u8;
45pub const UINT = c_uint;
46pub const ULONG_PTR = usize;
47pub const DWORD_PTR = ULONG_PTR;
48pub const UNICODE = false;
49pub const WCHAR = u16;
50pub const WORD = u16;
51pub const LARGE_INTEGER = i64;
52pub const ULONG = u32;
53pub const LONG = i32;
54pub const ULONGLONG = u64;
55pub const LONGLONG = i64;
56
57pub const TRUE = 1;
58pub const FALSE = 0;
59
60/// The standard input device. Initially, this is the console input buffer, CONIN$.
61pub const STD_INPUT_HANDLE = maxInt(DWORD) - 10 + 1;
62
63/// The standard output device. Initially, this is the active console screen buffer, CONOUT$.
64pub const STD_OUTPUT_HANDLE = maxInt(DWORD) - 11 + 1;
65
66/// The standard error device. Initially, this is the active console screen buffer, CONOUT$.
67pub const STD_ERROR_HANDLE = maxInt(DWORD) - 12 + 1;
68
69pub const INVALID_HANDLE_VALUE = @intToPtr(HANDLE, maxInt(usize));
70
71pub const INVALID_FILE_ATTRIBUTES = DWORD(maxInt(DWORD));
72
73pub const OVERLAPPED = extern struct {
74 Internal: ULONG_PTR,
75 InternalHigh: ULONG_PTR,
76 Offset: DWORD,
77 OffsetHigh: DWORD,
78 hEvent: ?HANDLE,
79};
80pub const LPOVERLAPPED = *OVERLAPPED;
81
82pub const MAX_PATH = 260;
83
84// TODO issue #305
85pub const FILE_INFO_BY_HANDLE_CLASS = u32;
86pub const FileBasicInfo = 0;
87pub const FileStandardInfo = 1;
88pub const FileNameInfo = 2;
89pub const FileRenameInfo = 3;
90pub const FileDispositionInfo = 4;
91pub const FileAllocationInfo = 5;
92pub const FileEndOfFileInfo = 6;
93pub const FileStreamInfo = 7;
94pub const FileCompressionInfo = 8;
95pub const FileAttributeTagInfo = 9;
96pub const FileIdBothDirectoryInfo = 10;
97pub const FileIdBothDirectoryRestartInfo = 11;
98pub const FileIoPriorityHintInfo = 12;
99pub const FileRemoteProtocolInfo = 13;
100pub const FileFullDirectoryInfo = 14;
101pub const FileFullDirectoryRestartInfo = 15;
102pub const FileStorageInfo = 16;
103pub const FileAlignmentInfo = 17;
104pub const FileIdInfo = 18;
105pub const FileIdExtdDirectoryInfo = 19;
106pub const FileIdExtdDirectoryRestartInfo = 20;
107
108pub const FILE_NAME_INFO = extern struct {
109 FileNameLength: DWORD,
110 FileName: [1]WCHAR,
111};45};
11246
113/// Return the normalized drive name. This is the default.47pub fn CreateFile(
114pub const FILE_NAME_NORMALIZED = 0x0;48 file_path: []const u8,
49 desired_access: DWORD,
50 share_mode: DWORD,
51 lpSecurityAttributes: ?LPSECURITY_ATTRIBUTES,
52 creation_disposition: DWORD,
53 flags_and_attrs: DWORD,
54 hTemplateFile: ?HANDLE,
55) CreateFileError!HANDLE {
56 const file_path_w = try sliceToPrefixedFileW(file_path);
57 return CreateFileW(&file_path_w, desired_access, share_mode, lpSecurityAttributes, creation_disposition, flags_and_attrs, hTemplateFile);
58}
59
60pub fn CreateFileW(
61 file_path_w: [*]const u16,
62 desired_access: DWORD,
63 share_mode: DWORD,
64 lpSecurityAttributes: ?LPSECURITY_ATTRIBUTES,
65 creation_disposition: DWORD,
66 flags_and_attrs: DWORD,
67 hTemplateFile: ?HANDLE,
68) CreateFileError!HANDLE {
69 const result = kernel32.CreateFileW(file_path_w, desired_access, share_mode, lpSecurityAttributes, creation_disposition, flags_and_attrs, hTemplateFile);
70
71 if (result == INVALID_HANDLE_VALUE) {
72 switch (kernel32.GetLastError()) {
73 ERROR.SHARING_VIOLATION => return error.SharingViolation,
74 ERROR.ALREADY_EXISTS => return error.PathAlreadyExists,
75 ERROR.FILE_EXISTS => return error.PathAlreadyExists,
76 ERROR.FILE_NOT_FOUND => return error.FileNotFound,
77 ERROR.PATH_NOT_FOUND => return error.FileNotFound,
78 ERROR.ACCESS_DENIED => return error.AccessDenied,
79 ERROR.PIPE_BUSY => return error.PipeBusy,
80 ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
81 else => |err| return unexpectedError(err),
82 }
83 }
84
85 return result;
86}
87
88pub const CreatePipeError = error{Unexpected};
11589
116/// Return the opened file name (not normalized).90pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) CreatePipeError!void {
117pub const FILE_NAME_OPENED = 0x8;91 if (kernel32.CreatePipe(rd, wr, sattr, 0) == 0) {
92 switch (kernel32.GetLastError()) {
93 else => |err| return unexpectedError(err),
94 }
95 }
96}
11897
119/// Return the path with the drive letter. This is the default.98pub const SetHandleInformationError = error{Unexpected};
120pub const VOLUME_NAME_DOS = 0x0;
12199
122/// Return the path with a volume GUID path instead of the drive name.100pub fn SetHandleInformation(h: HANDLE, mask: DWORD, flags: DWORD) SetHandleInformationError!void {
123pub const VOLUME_NAME_GUID = 0x1;101 if (kernel32.SetHandleInformation(h, mask, flags) == 0) {
102 switch (kernel32.GetLastError()) {
103 else => |err| return unexpectedError(err),
104 }
105 }
106}
124107
125/// Return the path with no drive information.108pub const RtlGenRandomError = error{Unexpected};
126pub const VOLUME_NAME_NONE = 0x4;
127109
128/// Return the path with the volume device path.110/// Call RtlGenRandom() instead of CryptGetRandom() on Windows
129pub const VOLUME_NAME_NT = 0x2;111/// https://github.com/rust-lang-nursery/rand/issues/111
112/// https://bugzilla.mozilla.org/show_bug.cgi?id=504270
113pub fn RtlGenRandom(output: []u8) RtlGenRandomError!void {
114 if (advapi32.RtlGenRandom(output.ptr, output.len) == 0) {
115 switch (kernel32.GetLastError()) {
116 else => |err| return unexpectedError(err),
117 }
118 }
119}
130120
131pub const SECURITY_ATTRIBUTES = extern struct {121pub const WaitForSingleObjectError = error{
132 nLength: DWORD,122 WaitAbandoned,
133 lpSecurityDescriptor: ?*c_void,123 WaitTimeOut,
134 bInheritHandle: BOOL,124 Unexpected,
135};125};
136pub const PSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES;126
137pub const LPSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES;127pub fn WaitForSingleObject(handle: HANDLE, milliseconds: DWORD) WaitForSingleObjectError!void {
138128 switch (kernel32.WaitForSingleObject(handle, milliseconds)) {
139pub const GENERIC_READ = 0x80000000;129 WAIT_ABANDONED => return error.WaitAbandoned,
140pub const GENERIC_WRITE = 0x40000000;130 WAIT_OBJECT_0 => return,
141pub const GENERIC_EXECUTE = 0x20000000;131 WAIT_TIMEOUT => return error.WaitTimeOut,
142pub const GENERIC_ALL = 0x10000000;132 WAIT_FAILED => switch (kernel32.GetLastError()) {
143133 else => |err| return unexpectedError(err),
144pub const FILE_SHARE_DELETE = 0x00000004;134 },
145pub const FILE_SHARE_READ = 0x00000001;135 else => return error.Unexpected,
146pub const FILE_SHARE_WRITE = 0x00000002;136 }
147137}
148pub const CREATE_ALWAYS = 2;138
149pub const CREATE_NEW = 1;139pub const FindFirstFileError = error{
150pub const OPEN_ALWAYS = 4;140 FileNotFound,
151pub const OPEN_EXISTING = 3;141 InvalidUtf8,
152pub const TRUNCATE_EXISTING = 5;142 BadPathName,
153143 NameTooLong,
154pub const FILE_ATTRIBUTE_ARCHIVE = 0x20;144 Unexpected,
155pub const FILE_ATTRIBUTE_COMPRESSED = 0x800;
156pub const FILE_ATTRIBUTE_DEVICE = 0x40;
157pub const FILE_ATTRIBUTE_DIRECTORY = 0x10;
158pub const FILE_ATTRIBUTE_ENCRYPTED = 0x4000;
159pub const FILE_ATTRIBUTE_HIDDEN = 0x2;
160pub const FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x8000;
161pub const FILE_ATTRIBUTE_NORMAL = 0x80;
162pub const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000;
163pub const FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x20000;
164pub const FILE_ATTRIBUTE_OFFLINE = 0x1000;
165pub const FILE_ATTRIBUTE_READONLY = 0x1;
166pub const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x400000;
167pub const FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x40000;
168pub const FILE_ATTRIBUTE_REPARSE_POINT = 0x400;
169pub const FILE_ATTRIBUTE_SPARSE_FILE = 0x200;
170pub const FILE_ATTRIBUTE_SYSTEM = 0x4;
171pub const FILE_ATTRIBUTE_TEMPORARY = 0x100;
172pub const FILE_ATTRIBUTE_VIRTUAL = 0x10000;
173
174pub const PROCESS_INFORMATION = extern struct {
175 hProcess: HANDLE,
176 hThread: HANDLE,
177 dwProcessId: DWORD,
178 dwThreadId: DWORD,
179};145};
180146
181pub const STARTUPINFOW = extern struct {147pub fn FindFirstFile(dir_path: []const u8, find_file_data: *WIN32_FIND_DATAW) FindFirstFileError!HANDLE {
182 cb: DWORD,148 const dir_path_w = try sliceToPrefixedSuffixedFileW(dir_path, []u16{ '\\', '*', 0 });
183 lpReserved: ?LPWSTR,149 const handle = kernel32.FindFirstFileW(&dir_path_w, find_file_data);
184 lpDesktop: ?LPWSTR,150
185 lpTitle: ?LPWSTR,151 if (handle == INVALID_HANDLE_VALUE) {
186 dwX: DWORD,152 switch (kernel32.GetLastError()) {
187 dwY: DWORD,153 ERROR.FILE_NOT_FOUND => return error.FileNotFound,
188 dwXSize: DWORD,154 ERROR.PATH_NOT_FOUND => return error.FileNotFound,
189 dwYSize: DWORD,155 else => |err| return unexpectedError(err),
190 dwXCountChars: DWORD,156 }
191 dwYCountChars: DWORD,157 }
192 dwFillAttribute: DWORD,158
193 dwFlags: DWORD,159 return handle;
194 wShowWindow: WORD,160}
195 cbReserved2: WORD,161
196 lpReserved2: ?LPBYTE,162pub const FindNextFileError = error{Unexpected};
197 hStdInput: ?HANDLE,163
198 hStdOutput: ?HANDLE,164/// Returns `true` if there was another file, `false` otherwise.
199 hStdError: ?HANDLE,165pub fn FindNextFile(handle: HANDLE, find_file_data: *WIN32_FIND_DATAW) FindNextFileError!bool {
166 if (kernel32.FindNextFileW(handle, find_file_data) == 0) {
167 switch (kernel32.GetLastError()) {
168 ERROR.NO_MORE_FILES => return false,
169 else => |err| return unexpectedError(err),
170 }
171 }
172 return true;
173}
174
175pub const CreateIoCompletionPortError = error{Unexpected};
176
177pub fn CreateIoCompletionPort(
178 file_handle: HANDLE,
179 existing_completion_port: ?HANDLE,
180 completion_key: usize,
181 concurrent_thread_count: DWORD,
182) CreateIoCompletionPortError!HANDLE {
183 const handle = kernel32.CreateIoCompletionPort(file_handle, existing_completion_port, completion_key, concurrent_thread_count) orelse {
184 switch (kernel32.GetLastError()) {
185 ERROR.INVALID_PARAMETER => unreachable,
186 else => |err| return unexpectedError(err),
187 }
188 };
189 return handle;
190}
191
192pub const PostQueuedCompletionStatusError = error{Unexpected};
193
194pub fn PostQueuedCompletionStatus(
195 completion_port: HANDLE,
196 bytes_transferred_count: DWORD,
197 completion_key: usize,
198 lpOverlapped: ?*OVERLAPPED,
199) PostQueuedCompletionStatusError!void {
200 if (kernel32.PostQueuedCompletionStatus(completion_port, bytes_transferred_count, completion_key, lpOverlapped) == 0) {
201 switch (kernel32.GetLastError()) {
202 else => |err| return unexpectedError(err),
203 }
204 }
205}
206
207pub const GetQueuedCompletionStatusResult = enum {
208 Normal,
209 Aborted,
210 Cancelled,
211 EOF,
200};212};
201213
202pub const STARTF_FORCEONFEEDBACK = 0x00000040;214pub fn GetQueuedCompletionStatus(
203pub const STARTF_FORCEOFFFEEDBACK = 0x00000080;215 completion_port: HANDLE,
204pub const STARTF_PREVENTPINNING = 0x00002000;216 bytes_transferred_count: *DWORD,
205pub const STARTF_RUNFULLSCREEN = 0x00000020;217 lpCompletionKey: *usize,
206pub const STARTF_TITLEISAPPID = 0x00001000;218 lpOverlapped: *?*OVERLAPPED,
207pub const STARTF_TITLEISLINKNAME = 0x00000800;219 dwMilliseconds: DWORD,
208pub const STARTF_UNTRUSTEDSOURCE = 0x00008000;220) GetQueuedCompletionStatusResult {
209pub const STARTF_USECOUNTCHARS = 0x00000008;221 if (kernel32.GetQueuedCompletionStatus(
210pub const STARTF_USEFILLATTRIBUTE = 0x00000010;222 completion_port,
211pub const STARTF_USEHOTKEY = 0x00000200;223 bytes_transferred_count,
212pub const STARTF_USEPOSITION = 0x00000004;224 lpCompletionKey,
213pub const STARTF_USESHOWWINDOW = 0x00000001;225 lpOverlapped,
214pub const STARTF_USESIZE = 0x00000002;226 dwMilliseconds,
215pub const STARTF_USESTDHANDLES = 0x00000100;227 ) == FALSE) {
216228 switch (kernel32.GetLastError()) {
217pub const INFINITE = 4294967295;229 ERROR.ABANDONED_WAIT_0 => return GetQueuedCompletionStatusResult.Aborted,
218230 ERROR.OPERATION_ABORTED => return GetQueuedCompletionStatusResult.Cancelled,
219pub const WAIT_ABANDONED = 0x00000080;231 ERROR.HANDLE_EOF => return GetQueuedCompletionStatusResult.EOF,
220pub const WAIT_OBJECT_0 = 0x00000000;232 else => |err| {
221pub const WAIT_TIMEOUT = 0x00000102;233 if (std.debug.runtime_safety) {
222pub const WAIT_FAILED = 0xFFFFFFFF;234 std.debug.panic("unexpected error: {}\n", err);
223235 }
224pub const HANDLE_FLAG_INHERIT = 0x00000001;236 },
225pub const HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x00000002;237 }
226238 }
227pub const MOVEFILE_COPY_ALLOWED = 2;239 return GetQueuedCompletionStatusResult.Normal;
228pub const MOVEFILE_CREATE_HARDLINK = 16;240}
229pub const MOVEFILE_DELAY_UNTIL_REBOOT = 4;241
230pub const MOVEFILE_FAIL_IF_NOT_TRACKABLE = 32;242pub fn CloseHandle(hObject: HANDLE) void {
231pub const MOVEFILE_REPLACE_EXISTING = 1;243 assert(kernel32.CloseHandle(hObject) != 0);
232pub const MOVEFILE_WRITE_THROUGH = 8;244}
233245
234pub const FILE_BEGIN = 0;246pub fn FindClose(hFindFile: HANDLE) void {
235pub const FILE_CURRENT = 1;247 assert(kernel32.FindClose(hFindFile) != 0);
236pub const FILE_END = 2;248}
237249
238pub const HEAP_CREATE_ENABLE_EXECUTE = 0x00040000;250pub const ReadFileError = error{Unexpected};
239pub const HEAP_GENERATE_EXCEPTIONS = 0x00000004;251
240pub const HEAP_NO_SERIALIZE = 0x00000001;252pub fn ReadFile(in_hFile: HANDLE, buffer: []u8) ReadFileError!usize {
241253 var index: usize = 0;
242// AllocationType values254 while (index < buffer.len) {
243pub const MEM_COMMIT = 0x1000;255 const want_read_count = @intCast(DWORD, math.min(DWORD(maxInt(DWORD)), buffer.len - index));
244pub const MEM_RESERVE = 0x2000;256 var amt_read: DWORD = undefined;
245pub const MEM_RESET = 0x80000;257 if (kernel32.ReadFile(in_hFile, buffer.ptr + index, want_read_count, &amt_read, null) == 0) {
246pub const MEM_RESET_UNDO = 0x1000000;258 switch (kernel32.GetLastError()) {
247pub const MEM_LARGE_PAGES = 0x20000000;259 ERROR.OPERATION_ABORTED => continue,
248pub const MEM_PHYSICAL = 0x400000;260 ERROR.BROKEN_PIPE => return index,
249pub const MEM_TOP_DOWN = 0x100000;261 else => |err| return unexpectedError(err),
250pub const MEM_WRITE_WATCH = 0x200000;262 }
251263 }
252// Protect values264 if (amt_read == 0) return index;
253pub const PAGE_EXECUTE = 0x10;265 index += amt_read;
254pub const PAGE_EXECUTE_READ = 0x20;266 }
255pub const PAGE_EXECUTE_READWRITE = 0x40;267 return index;
256pub const PAGE_EXECUTE_WRITECOPY = 0x80;268}
257pub const PAGE_NOACCESS = 0x01;269
258pub const PAGE_READONLY = 0x02;270pub const WriteFileError = error{
259pub const PAGE_READWRITE = 0x04;271 SystemResources,
260pub const PAGE_WRITECOPY = 0x08;272 OperationAborted,
261pub const PAGE_TARGETS_INVALID = 0x40000000;273 BrokenPipe,
262pub const PAGE_TARGETS_NO_UPDATE = 0x40000000; // Same as PAGE_TARGETS_INVALID274 Unexpected,
263pub const PAGE_GUARD = 0x100;
264pub const PAGE_NOCACHE = 0x200;
265pub const PAGE_WRITECOMBINE = 0x400;
266
267// FreeType values
268pub const MEM_COALESCE_PLACEHOLDERS = 0x1;
269pub const MEM_RESERVE_PLACEHOLDERS = 0x2;
270pub const MEM_DECOMMIT = 0x4000;
271pub const MEM_RELEASE = 0x8000;
272
273pub const PTHREAD_START_ROUTINE = extern fn (LPVOID) DWORD;
274pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE;
275
276pub const WIN32_FIND_DATAW = extern struct {
277 dwFileAttributes: DWORD,
278 ftCreationTime: FILETIME,
279 ftLastAccessTime: FILETIME,
280 ftLastWriteTime: FILETIME,
281 nFileSizeHigh: DWORD,
282 nFileSizeLow: DWORD,
283 dwReserved0: DWORD,
284 dwReserved1: DWORD,
285 cFileName: [260]u16,
286 cAlternateFileName: [14]u16,
287};275};
288276
289pub const FILETIME = extern struct {277/// This function is for blocking file descriptors only. For non-blocking, see
290 dwLowDateTime: DWORD,278/// `WriteFileAsync`.
291 dwHighDateTime: DWORD,279pub fn WriteFile(handle: HANDLE, bytes: []const u8) WriteFileError!void {
280 var bytes_written: DWORD = undefined;
281 // TODO replace this @intCast with a loop that writes all the bytes
282 if (kernel32.WriteFile(handle, bytes.ptr, @intCast(u32, bytes.len), &bytes_written, null) == 0) {
283 switch (kernel32.GetLastError()) {
284 ERROR.INVALID_USER_BUFFER => return error.SystemResources,
285 ERROR.NOT_ENOUGH_MEMORY => return error.SystemResources,
286 ERROR.OPERATION_ABORTED => return error.OperationAborted,
287 ERROR.NOT_ENOUGH_QUOTA => return error.SystemResources,
288 ERROR.IO_PENDING => unreachable, // this function is for blocking files only
289 ERROR.BROKEN_PIPE => return error.BrokenPipe,
290 else => |err| return unexpectedError(err),
291 }
292 }
293}
294
295pub const GetCurrentDirectoryError = error{
296 NameTooLong,
297 Unexpected,
292};298};
293299
294pub const SYSTEM_INFO = extern struct {300/// The result is a slice of `buffer`, indexed from 0.
295 anon1: extern union {301pub fn GetCurrentDirectory(buffer: []u8) GetCurrentDirectoryError![]u8 {
296 dwOemId: DWORD,302 var utf16le_buf: [PATH_MAX_WIDE]u16 = undefined;
297 anon2: extern struct {303 const result = kernel32.GetCurrentDirectoryW(utf16le_buf.len, &utf16le_buf);
298 wProcessorArchitecture: WORD,304 if (result == 0) {
299 wReserved: WORD,305 switch (kernel32.GetLastError()) {
300 },306 else => |err| return unexpectedError(err),
301 },307 }
302 dwPageSize: DWORD,308 }
303 lpMinimumApplicationAddress: LPVOID,309 assert(result <= utf16le_buf.len);
304 lpMaximumApplicationAddress: LPVOID,310 const utf16le_slice = utf16le_buf[0..result];
305 dwActiveProcessorMask: DWORD_PTR,311 // Trust that Windows gives us valid UTF-16LE.
306 dwNumberOfProcessors: DWORD,312 var end_index: usize = 0;
307 dwProcessorType: DWORD,313 var it = std.unicode.Utf16LeIterator.init(utf16le_slice);
308 dwAllocationGranularity: DWORD,314 while (it.nextCodepoint() catch unreachable) |codepoint| {
309 wProcessorLevel: WORD,315 const seq_len = std.unicode.utf8CodepointSequenceLength(codepoint) catch unreachable;
310 wProcessorRevision: WORD,316 if (end_index + seq_len >= buffer.len)
317 return error.NameTooLong;
318 end_index += std.unicode.utf8Encode(codepoint, buffer[end_index..]) catch unreachable;
319 }
320 return buffer[0..end_index];
321}
322
323pub const CreateSymbolicLinkError = error{Unexpected};
324
325pub fn CreateSymbolicLink(
326 sym_link_path: []const u8,
327 target_path: []const u8,
328 flags: DWORD,
329) CreateSymbolicLinkError!void {
330 const sym_link_path_w = try sliceToPrefixedFileW(sym_link_path);
331 const target_path_w = try sliceToPrefixedFileW(target_path);
332 return CreateSymbolicLinkW(&sym_link_path_w, &target_path_w, flags);
333}
334
335pub fn CreateSymbolicLinkW(
336 sym_link_path: [*]const u16,
337 target_path: [*]const u16,
338 flags: DWORD,
339) CreateSymbolicLinkError!void {
340 if (kernel32.CreateSymbolicLinkW(sym_link_path, target_path, flags) == 0) {
341 switch (kernel32.GetLastError()) {
342 else => |err| return unexpectedError(err),
343 }
344 }
345}
346
347pub const DeleteFileError = error{
348 FileNotFound,
349 AccessDenied,
350 NameTooLong,
351 Unexpected,
311};352};
312353
313pub const HRESULT = c_long;354pub fn DeleteFile(filename: []const u8) DeleteFileError!void {
355 const filename_w = try sliceToPrefixedFileW(filename);
356 return DeleteFileW(&filename_w);
357}
314358
315pub const KNOWNFOLDERID = GUID;359pub fn DeleteFileW(filename: [*]const u16) DeleteFileError!void {
316pub const GUID = extern struct {360 if (kernel32.DeleteFileW(filename) == 0) {
317 Data1: c_ulong,361 switch (kernel32.GetLastError()) {
318 Data2: c_ushort,362 ERROR.FILE_NOT_FOUND => return error.FileNotFound,
319 Data3: c_ushort,363 ERROR.ACCESS_DENIED => return error.AccessDenied,
320 Data4: [8]u8,364 ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
365 ERROR.INVALID_PARAMETER => return error.NameTooLong,
366 else => |err| return unexpectedError(err),
367 }
368 }
369}
321370
322 pub fn parse(str: []const u8) GUID {371pub const MoveFileError = error{Unexpected};
323 var guid: GUID = undefined;
324 var index: usize = 0;
325 assert(str[index] == '{');
326 index += 1;
327372
328 guid.Data1 = std.fmt.parseUnsigned(c_ulong, str[index .. index + 8], 16) catch unreachable;373pub fn MoveFileEx(old_path: []const u8, new_path: []const u8, flags: DWORD) MoveFileError!void {
329 index += 8;374 const old_path_w = try sliceToPrefixedFileW(old_path);
375 const new_path_w = try sliceToPrefixedFileW(new_path);
376 return MoveFileExW(&old_path_w, &new_path_w, flags);
377}
330378
331 assert(str[index] == '-');379pub fn MoveFileExW(old_path: [*]const u16, new_path: [*]const u16, flags: DWORD) MoveFileError!void {
332 index += 1;380 if (kernel32.MoveFileExW(old_path, new_path, flags) == 0) {
381 switch (kernel32.GetLastError()) {
382 else => |err| return unexpectedError(err),
383 }
384 }
385}
333386
334 guid.Data2 = std.fmt.parseUnsigned(c_ushort, str[index .. index + 4], 16) catch unreachable;387pub const CreateDirectoryError = error{
335 index += 4;388 PathAlreadyExists,
389 FileNotFound,
390 Unexpected,
391};
336392
337 assert(str[index] == '-');393pub fn CreateDirectory(pathname: []const u8, attrs: ?*SECURITY_ATTRIBUTES) CreateDirectoryError!void {
338 index += 1;394 const pathname_w = try sliceToPrefixedFileW(pathname);
395 return CreateDirectoryW(&pathname_w, attrs);
396}
339397
340 guid.Data3 = std.fmt.parseUnsigned(c_ushort, str[index .. index + 4], 16) catch unreachable;398pub fn CreateDirectoryW(pathname: [*]const u16, attrs: ?*SECURITY_ATTRIBUTES) CreateDirectoryError!void {
341 index += 4;399 if (kernel32.CreateDirectoryW(pathname, attrs) == 0) {
400 switch (kernel32.GetLastError()) {
401 ERROR.ALREADY_EXISTS => return error.PathAlreadyExists,
402 ERROR.PATH_NOT_FOUND => return error.FileNotFound,
403 else => |err| return unexpectedError(err),
404 }
405 }
406}
342407
343 assert(str[index] == '-');408pub const RemoveDirectoryError = error{
344 index += 1;409 FileNotFound,
410 DirNotEmpty,
411 Unexpected,
412};
345413
346 guid.Data4[0] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;414pub fn RemoveDirectory(dir_path: []const u8) RemoveDirectoryError!void {
347 index += 2;415 const dir_path_w = try sliceToPrefixedFileW(dir_path);
348 guid.Data4[1] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;416 return RemoveDirectoryW(&dir_path_w);
349 index += 2;417}
350418
351 assert(str[index] == '-');419pub fn RemoveDirectoryW(dir_path_w: [*]const u16) RemoveDirectoryError!void {
352 index += 1;420 if (kernel32.RemoveDirectoryW(dir_path_w) == 0) {
421 switch (kernel32.GetLastError()) {
422 ERROR.PATH_NOT_FOUND => return error.FileNotFound,
423 ERROR.DIR_NOT_EMPTY => return error.DirNotEmpty,
424 else => |err| return unexpectedError(err),
425 }
426 }
427}
353428
354 var i: usize = 2;429pub const GetStdHandleError = error{
355 while (i < guid.Data4.len) : (i += 1) {430 NoStandardHandleAttached,
356 guid.Data4[i] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;431 Unexpected,
357 index += 2;432};
433
434pub fn GetStdHandle(handle_id: DWORD) GetStdHandleError!HANDLE {
435 const handle = kernel32.GetStdHandle(handle_id) orelse return error.NoStandardHandleAttached;
436 if (handle == INVALID_HANDLE_VALUE) {
437 switch (kernel32.GetLastError()) {
438 else => |err| return unexpectedError(err),
439 }
440 }
441 return handle;
442}
443
444pub const SetFilePointerError = error{Unexpected};
445
446/// The SetFilePointerEx function with the `dwMoveMethod` parameter set to `FILE_BEGIN`.
447pub fn SetFilePointerEx_BEGIN(handle: HANDLE, offset: u64) SetFilePointerError!void {
448 // "The starting point is zero or the beginning of the file. If [FILE_BEGIN]
449 // is specified, then the liDistanceToMove parameter is interpreted as an unsigned value."
450 // https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-setfilepointerex
451 const ipos = @bitCast(LARGE_INTEGER, offset);
452 if (kernel32.SetFilePointerEx(handle, ipos, null, FILE_BEGIN) == 0) {
453 switch (kernel32.GetLastError()) {
454 ERROR.INVALID_PARAMETER => unreachable,
455 ERROR.INVALID_HANDLE => unreachable,
456 else => |err| return unexpectedError(err),
457 }
458 }
459}
460
461/// The SetFilePointerEx function with the `dwMoveMethod` parameter set to `FILE_CURRENT`.
462pub fn SetFilePointerEx_CURRENT(handle: HANDLE, offset: i64) SetFilePointerError!void {
463 if (kernel32.SetFilePointerEx(handle, offset, null, FILE_CURRENT) == 0) {
464 switch (kernel32.GetLastError()) {
465 ERROR.INVALID_PARAMETER => unreachable,
466 ERROR.INVALID_HANDLE => unreachable,
467 else => |err| return unexpectedError(err),
468 }
469 }
470}
471
472/// The SetFilePointerEx function with the `dwMoveMethod` parameter set to `FILE_END`.
473pub fn SetFilePointerEx_END(handle: HANDLE, offset: i64) SetFilePointerError!void {
474 if (kernel32.SetFilePointerEx(handle, offset, null, FILE_END) == 0) {
475 switch (kernel32.GetLastError()) {
476 ERROR.INVALID_PARAMETER => unreachable,
477 ERROR.INVALID_HANDLE => unreachable,
478 else => |err| return unexpectedError(err),
358 }479 }
480 }
481}
359482
360 assert(str[index] == '}');483/// The SetFilePointerEx function with parameters to get the current offset.
361 index += 1;484pub fn SetFilePointerEx_CURRENT_get(handle: HANDLE) SetFilePointerError!u64 {
362 return guid;485 var result: LARGE_INTEGER = undefined;
486 if (kernel32.SetFilePointerEx(handle, 0, &result, FILE_CURRENT) == 0) {
487 switch (kernel32.GetLastError()) {
488 ERROR.INVALID_PARAMETER => unreachable,
489 ERROR.INVALID_HANDLE => unreachable,
490 else => |err| return unexpectedError(err),
491 }
363 }492 }
493 // Based on the docs for FILE_BEGIN, it seems that the returned signed integer
494 // should be interpreted as an unsigned integer.
495 return @bitCast(u64, result);
496}
497
498pub const GetFinalPathNameByHandleError = error{
499 FileNotFound,
500 SystemResources,
501 NameTooLong,
502 Unexpected,
364};503};
365504
366pub const FOLDERID_LocalAppData = GUID.parse("{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}");505pub fn GetFinalPathNameByHandleW(
367506 hFile: HANDLE,
368pub const KF_FLAG_DEFAULT = 0;507 buf_ptr: [*]u16,
369pub const KF_FLAG_NO_APPCONTAINER_REDIRECTION = 65536;508 buf_len: DWORD,
370pub const KF_FLAG_CREATE = 32768;509 flags: DWORD,
371pub const KF_FLAG_DONT_VERIFY = 16384;510) GetFinalPathNameByHandleError!DWORD {
372pub const KF_FLAG_DONT_UNEXPAND = 8192;511 const rc = kernel32.GetFinalPathNameByHandleW(hFile, buf_ptr, buf_len, flags);
373pub const KF_FLAG_NO_ALIAS = 4096;512 if (rc == 0) {
374pub const KF_FLAG_INIT = 2048;513 switch (kernel32.GetLastError()) {
375pub const KF_FLAG_DEFAULT_PATH = 1024;514 ERROR.FILE_NOT_FOUND => return error.FileNotFound,
376pub const KF_FLAG_NOT_PARENT_RELATIVE = 512;515 ERROR.PATH_NOT_FOUND => return error.FileNotFound,
377pub const KF_FLAG_SIMPLE_IDLIST = 256;516 ERROR.NOT_ENOUGH_MEMORY => return error.SystemResources,
378pub const KF_FLAG_ALIAS_ONLY = -2147483648;517 ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong,
379518 ERROR.INVALID_PARAMETER => unreachable,
380pub const S_OK = 0;519 else => |err| return unexpectedError(err),
381pub const E_NOTIMPL = @bitCast(c_long, c_ulong(0x80004001));520 }
382pub const E_NOINTERFACE = @bitCast(c_long, c_ulong(0x80004002));521 }
383pub const E_POINTER = @bitCast(c_long, c_ulong(0x80004003));522 return rc;
384pub const E_ABORT = @bitCast(c_long, c_ulong(0x80004004));523}
385pub const E_FAIL = @bitCast(c_long, c_ulong(0x80004005));524
386pub const E_UNEXPECTED = @bitCast(c_long, c_ulong(0x8000FFFF));525pub const GetFileSizeError = error{Unexpected};
387pub const E_ACCESSDENIED = @bitCast(c_long, c_ulong(0x80070005));526
388pub const E_HANDLE = @bitCast(c_long, c_ulong(0x80070006));527pub fn GetFileSizeEx(hFile: HANDLE) GetFileSizeError!u64 {
389pub const E_OUTOFMEMORY = @bitCast(c_long, c_ulong(0x8007000E));528 var file_size: LARGE_INTEGER = undefined;
390pub const E_INVALIDARG = @bitCast(c_long, c_ulong(0x80070057));529 if (kernel32.GetFileSizeEx(hFile, &file_size) == 0) {
391530 switch (kernel32.GetLastError()) {
392pub const FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;531 else => |err| return unexpectedError(err),
393pub const FILE_FLAG_DELETE_ON_CLOSE = 0x04000000;532 }
394pub const FILE_FLAG_NO_BUFFERING = 0x20000000;533 }
395pub const FILE_FLAG_OPEN_NO_RECALL = 0x00100000;534 return @bitCast(u64, file_size);
396pub const FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;535}
397pub const FILE_FLAG_OVERLAPPED = 0x40000000;536
398pub const FILE_FLAG_POSIX_SEMANTICS = 0x0100000;537pub const GetFileAttributesError = error{
399pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000;538 FileNotFound,
400pub const FILE_FLAG_SESSION_AWARE = 0x00800000;539 PermissionDenied,
401pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;540 Unexpected,
402pub const FILE_FLAG_WRITE_THROUGH = 0x80000000;541};
403542
404pub const SMALL_RECT = extern struct {543pub fn GetFileAttributes(filename: []const u8) GetFileAttributesError!DWORD {
405 Left: SHORT,544 const filename_w = try sliceToPrefixedFileW(filename);
406 Top: SHORT,545 return GetFileAttributesW(&filename_w);
407 Right: SHORT,546}
408 Bottom: SHORT,547
548pub fn GetFileAttributesW(lpFileName: [*]const u16) GetFileAttributesError!DWORD {
549 const rc = kernel32.GetFileAttributesW(lpFileName);
550 if (rc == INVALID_FILE_ATTRIBUTES) {
551 switch (kernel32.GetLastError()) {
552 ERROR.FILE_NOT_FOUND => return error.FileNotFound,
553 ERROR.PATH_NOT_FOUND => return error.FileNotFound,
554 ERROR.ACCESS_DENIED => return error.PermissionDenied,
555 else => |err| return unexpectedError(err),
556 }
557 }
558 return rc;
559}
560
561const GetModuleFileNameError = error{Unexpected};
562
563pub fn GetModuleFileNameW(hModule: ?HMODULE, buf_ptr: [*]u16, buf_len: DWORD) GetModuleFileNameError![]u16 {
564 const rc = kernel32.GetModuleFileNameW(hModule, buf_ptr, buf_len);
565 if (rc == 0) {
566 switch (kernel32.GetLastError()) {
567 else => |err| return unexpectedError(err),
568 }
569 }
570 return buf_ptr[0..rc];
571}
572
573pub const TerminateProcessError = error{Unexpected};
574
575pub fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) TerminateProcessError!void {
576 if (kernel32.TerminateProcess(hProcess, uExitCode) == 0) {
577 switch (kernel32.GetLastError()) {
578 else => |err| return unexpectedError(err),
579 }
580 }
581}
582
583pub const VirtualAllocError = error{Unexpected};
584
585pub fn VirtualAlloc(addr: ?LPVOID, size: usize, alloc_type: DWORD, flProtect: DWORD) VirtualAllocError!LPVOID {
586 return kernel32.VirtualAlloc(addr, size, alloc_type, flProtect) orelse {
587 switch (kernel32.GetLastError()) {
588 else => |err| return unexpectedError(err),
589 }
590 };
591}
592
593pub fn VirtualFree(lpAddress: ?LPVOID, dwSize: usize, dwFreeType: DWORD) void {
594 assert(kernel32.VirtualFree(lpAddress, dwSize, dwFreeType) != 0);
595}
596
597pub const SetConsoleTextAttributeError = error{Unexpected};
598
599pub fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) SetConsoleTextAttributeError!void {
600 if (kernel32.SetConsoleTextAttribute(hConsoleOutput, wAttributes) == 0) {
601 switch (kernel32.GetLastError()) {
602 else => |err| return unexpectedError(err),
603 }
604 }
605}
606
607pub const GetEnvironmentStringsError = error{OutOfMemory};
608
609pub fn GetEnvironmentStringsW() GetEnvironmentStringsError![*]u16 {
610 return kernel32.GetEnvironmentStringsW() orelse return error.OutOfMemory;
611}
612
613pub fn FreeEnvironmentStringsW(penv: [*]u16) void {
614 assert(kernel32.FreeEnvironmentStringsW(penv) != 0);
615}
616
617pub const GetEnvironmentVariableError = error{
618 EnvironmentVariableNotFound,
619 Unexpected,
409};620};
410621
411pub const COORD = extern struct {622pub fn GetEnvironmentVariableW(lpName: LPWSTR, lpBuffer: LPWSTR, nSize: DWORD) GetEnvironmentVariableError!DWORD {
412 X: SHORT,623 const rc = kernel32.GetEnvironmentVariableW(lpName, lpBuffer, nSize);
413 Y: SHORT,624 if (rc == 0) {
625 switch (kernel32.GetLastError()) {
626 ERROR.ENVVAR_NOT_FOUND => return error.EnvironmentVariableNotFound,
627 else => |err| return unexpectedError(err),
628 }
629 }
630 return rc;
631}
632
633pub const CreateProcessError = error{
634 FileNotFound,
635 InvalidName,
636 Unexpected,
414};637};
415638
416pub const CREATE_UNICODE_ENVIRONMENT = 1024;639pub fn CreateProcessW(
640 lpApplicationName: ?LPWSTR,
641 lpCommandLine: LPWSTR,
642 lpProcessAttributes: ?*SECURITY_ATTRIBUTES,
643 lpThreadAttributes: ?*SECURITY_ATTRIBUTES,
644 bInheritHandles: BOOL,
645 dwCreationFlags: DWORD,
646 lpEnvironment: ?*c_void,
647 lpCurrentDirectory: ?LPWSTR,
648 lpStartupInfo: *STARTUPINFOW,
649 lpProcessInformation: *PROCESS_INFORMATION,
650) CreateProcessError!void {
651 if (kernel32.CreateProcessW(
652 lpApplicationName,
653 lpCommandLine,
654 lpProcessAttributes,
655 lpThreadAttributes,
656 bInheritHandles,
657 dwCreationFlags,
658 lpEnvironment,
659 lpCurrentDirectory,
660 lpStartupInfo,
661 lpProcessInformation,
662 ) == 0) {
663 switch (kernel32.GetLastError()) {
664 ERROR.FILE_NOT_FOUND => return error.FileNotFound,
665 ERROR.PATH_NOT_FOUND => return error.FileNotFound,
666 ERROR.INVALID_PARAMETER => unreachable,
667 ERROR.INVALID_NAME => return error.InvalidName,
668 else => |err| return unexpectedError(err),
669 }
670 }
671}
417672
418pub const TLS_OUT_OF_INDEXES = 4294967295;673pub const LoadLibraryError = error{
419pub const IMAGE_TLS_DIRECTORY = extern struct {674 FileNotFound,
420 StartAddressOfRawData: usize,675 Unexpected,
421 EndAddressOfRawData: usize,
422 AddressOfIndex: usize,
423 AddressOfCallBacks: usize,
424 SizeOfZeroFill: u32,
425 Characteristics: u32,
426};676};
427pub const IMAGE_TLS_DIRECTORY64 = IMAGE_TLS_DIRECTORY;
428pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY;
429677
430pub const PIMAGE_TLS_CALLBACK = ?extern fn (PVOID, DWORD, PVOID) void;678pub fn LoadLibraryW(lpLibFileName: [*]const u16) LoadLibraryError!HMODULE {
679 return kernel32.LoadLibraryW(lpLibFileName) orelse {
680 switch (kernel32.GetLastError()) {
681 ERROR.FILE_NOT_FOUND => return error.FileNotFound,
682 ERROR.PATH_NOT_FOUND => return error.FileNotFound,
683 ERROR.MOD_NOT_FOUND => return error.FileNotFound,
684 else => |err| return unexpectedError(err),
685 }
686 };
687}
688
689pub fn FreeLibrary(hModule: HMODULE) void {
690 assert(kernel32.FreeLibrary(hModule) != 0);
691}
692
693pub fn QueryPerformanceFrequency() u64 {
694 // "On systems that run Windows XP or later, the function will always succeed"
695 // https://docs.microsoft.com/en-us/windows/desktop/api/profileapi/nf-profileapi-queryperformancefrequency
696 var result: LARGE_INTEGER = undefined;
697 assert(kernel32.QueryPerformanceFrequency(&result) != 0);
698 // The kernel treats this integer as unsigned.
699 return @bitCast(u64, result);
700}
701
702pub fn QueryPerformanceCounter() u64 {
703 // "On systems that run Windows XP or later, the function will always succeed"
704 // https://docs.microsoft.com/en-us/windows/desktop/api/profileapi/nf-profileapi-queryperformancecounter
705 var result: LARGE_INTEGER = undefined;
706 assert(kernel32.QueryPerformanceCounter(&result) != 0);
707 // The kernel treats this integer as unsigned.
708 return @bitCast(u64, result);
709}
710
711pub fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter: ?*c_void, Context: ?*c_void) void {
712 assert(kernel32.InitOnceExecuteOnce(InitOnce, InitFn, Parameter, Context) != 0);
713}
714
715pub fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: *c_void) void {
716 assert(kernel32.HeapFree(hHeap, dwFlags, lpMem) != 0);
717}
718
719pub fn HeapDestroy(hHeap: HANDLE) void {
720 assert(kernel32.HeapDestroy(hHeap) != 0);
721}
722
723pub fn cStrToPrefixedFileW(s: [*]const u8) ![PATH_MAX_WIDE + 1]u16 {
724 return sliceToPrefixedFileW(mem.toSliceConst(u8, s));
725}
726
727pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 {
728 return sliceToPrefixedSuffixedFileW(s, []u16{0});
729}
730
731pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) ![PATH_MAX_WIDE + suffix.len]u16 {
732 // TODO well defined copy elision
733 var result: [PATH_MAX_WIDE + suffix.len]u16 = undefined;
734
735 // > File I/O functions in the Windows API convert "/" to "\" as part of
736 // > converting the name to an NT-style name, except when using the "\\?\"
737 // > prefix as detailed in the following sections.
738 // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
739 // Because we want the larger maximum path length for absolute paths, we
740 // disallow forward slashes in zig std lib file functions on Windows.
741 for (s) |byte| {
742 switch (byte) {
743 '/', '*', '?', '"', '<', '>', '|' => return error.BadPathName,
744 else => {},
745 }
746 }
747 const start_index = if (mem.startsWith(u8, s, "\\\\") or !std.fs.path.isAbsolute(s)) 0 else blk: {
748 const prefix = []u16{ '\\', '\\', '?', '\\' };
749 mem.copy(u16, result[0..], prefix);
750 break :blk prefix.len;
751 };
752 const end_index = start_index + try std.unicode.utf8ToUtf16Le(result[start_index..], s);
753 assert(end_index <= result.len);
754 if (end_index + suffix.len > result.len) return error.NameTooLong;
755 mem.copy(u16, result[end_index..], suffix);
756 return result;
757}
758
759/// Call this when you made a windows DLL call or something that does SetLastError
760/// and you get an unexpected error.
761pub fn unexpectedError(err: DWORD) std.os.UnexpectedError {
762 if (std.os.unexpected_error_tracing) {
763 std.debug.warn("unexpected GetLastError(): {}\n", err);
764 std.debug.dumpCurrentStackTrace(null);
765 }
766 return error.Unexpected;
767}
std/os/windows/advapi32.zig+1-12
...@@ -1,15 +1,4 @@...@@ -1,15 +1,4 @@
1use @import("../windows.zig");1use @import("bits.zig");
2
3pub const PROV_RSA_FULL = 1;
4
5pub const REGSAM = ACCESS_MASK;
6pub const ACCESS_MASK = DWORD;
7pub const PHKEY = *HKEY;
8pub const HKEY = *HKEY__;
9pub const HKEY__ = extern struct {
10 unused: c_int,
11};
12pub const LSTATUS = LONG;
132
14pub extern "advapi32" stdcallcc fn RegOpenKeyExW(3pub extern "advapi32" stdcallcc fn RegOpenKeyExW(
15 hKey: HKEY,4 hKey: HKEY,
std/os/windows/bits.zig created+527
...@@ -0,0 +1,527 @@
1// Platform-dependent types and values that are used along with OS-specific APIs.
2
3const builtin = @import("builtin");
4const std = @import("../../std.zig");
5const assert = std.debug.assert;
6const maxInt = std.math.maxInt;
7
8pub const ERROR = @import("error.zig");
9
10/// The standard input device. Initially, this is the console input buffer, CONIN$.
11pub const STD_INPUT_HANDLE = maxInt(DWORD) - 10 + 1;
12
13/// The standard output device. Initially, this is the active console screen buffer, CONOUT$.
14pub const STD_OUTPUT_HANDLE = maxInt(DWORD) - 11 + 1;
15
16/// The standard error device. Initially, this is the active console screen buffer, CONOUT$.
17pub const STD_ERROR_HANDLE = maxInt(DWORD) - 12 + 1;
18
19pub const SHORT = c_short;
20pub const BOOL = c_int;
21pub const BOOLEAN = BYTE;
22pub const BYTE = u8;
23pub const CHAR = u8;
24pub const DWORD = u32;
25pub const FLOAT = f32;
26pub const HANDLE = *c_void;
27pub const HCRYPTPROV = ULONG_PTR;
28pub const HINSTANCE = *@OpaqueType();
29pub const HMODULE = *@OpaqueType();
30pub const FARPROC = *@OpaqueType();
31pub const INT = c_int;
32pub const LPBYTE = *BYTE;
33pub const LPCH = *CHAR;
34pub const LPCSTR = [*]const CHAR;
35pub const LPCTSTR = [*]const TCHAR;
36pub const LPCVOID = *const c_void;
37pub const LPDWORD = *DWORD;
38pub const LPSTR = [*]CHAR;
39pub const LPTSTR = if (UNICODE) LPWSTR else LPSTR;
40pub const LPVOID = *c_void;
41pub const LPWSTR = [*]WCHAR;
42pub const LPCWSTR = [*]const WCHAR;
43pub const PVOID = *c_void;
44pub const PWSTR = [*]WCHAR;
45pub const SIZE_T = usize;
46pub const TCHAR = if (UNICODE) WCHAR else u8;
47pub const UINT = c_uint;
48pub const ULONG_PTR = usize;
49pub const DWORD_PTR = ULONG_PTR;
50pub const UNICODE = false;
51pub const WCHAR = u16;
52pub const WORD = u16;
53pub const LARGE_INTEGER = i64;
54pub const ULONG = u32;
55pub const LONG = i32;
56pub const ULONGLONG = u64;
57pub const LONGLONG = i64;
58
59pub const TRUE = 1;
60pub const FALSE = 0;
61
62pub const INVALID_HANDLE_VALUE = @intToPtr(HANDLE, maxInt(usize));
63
64pub const INVALID_FILE_ATTRIBUTES = DWORD(maxInt(DWORD));
65
66pub const OVERLAPPED = extern struct {
67 Internal: ULONG_PTR,
68 InternalHigh: ULONG_PTR,
69 Offset: DWORD,
70 OffsetHigh: DWORD,
71 hEvent: ?HANDLE,
72};
73pub const LPOVERLAPPED = *OVERLAPPED;
74
75pub const MAX_PATH = 260;
76
77// TODO issue #305
78pub const FILE_INFO_BY_HANDLE_CLASS = u32;
79pub const FileBasicInfo = 0;
80pub const FileStandardInfo = 1;
81pub const FileNameInfo = 2;
82pub const FileRenameInfo = 3;
83pub const FileDispositionInfo = 4;
84pub const FileAllocationInfo = 5;
85pub const FileEndOfFileInfo = 6;
86pub const FileStreamInfo = 7;
87pub const FileCompressionInfo = 8;
88pub const FileAttributeTagInfo = 9;
89pub const FileIdBothDirectoryInfo = 10;
90pub const FileIdBothDirectoryRestartInfo = 11;
91pub const FileIoPriorityHintInfo = 12;
92pub const FileRemoteProtocolInfo = 13;
93pub const FileFullDirectoryInfo = 14;
94pub const FileFullDirectoryRestartInfo = 15;
95pub const FileStorageInfo = 16;
96pub const FileAlignmentInfo = 17;
97pub const FileIdInfo = 18;
98pub const FileIdExtdDirectoryInfo = 19;
99pub const FileIdExtdDirectoryRestartInfo = 20;
100
101pub const FILE_NAME_INFO = extern struct {
102 FileNameLength: DWORD,
103 FileName: [1]WCHAR,
104};
105
106/// Return the normalized drive name. This is the default.
107pub const FILE_NAME_NORMALIZED = 0x0;
108
109/// Return the opened file name (not normalized).
110pub const FILE_NAME_OPENED = 0x8;
111
112/// Return the path with the drive letter. This is the default.
113pub const VOLUME_NAME_DOS = 0x0;
114
115/// Return the path with a volume GUID path instead of the drive name.
116pub const VOLUME_NAME_GUID = 0x1;
117
118/// Return the path with no drive information.
119pub const VOLUME_NAME_NONE = 0x4;
120
121/// Return the path with the volume device path.
122pub const VOLUME_NAME_NT = 0x2;
123
124pub const SECURITY_ATTRIBUTES = extern struct {
125 nLength: DWORD,
126 lpSecurityDescriptor: ?*c_void,
127 bInheritHandle: BOOL,
128};
129pub const PSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES;
130pub const LPSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES;
131
132pub const GENERIC_READ = 0x80000000;
133pub const GENERIC_WRITE = 0x40000000;
134pub const GENERIC_EXECUTE = 0x20000000;
135pub const GENERIC_ALL = 0x10000000;
136
137pub const FILE_SHARE_DELETE = 0x00000004;
138pub const FILE_SHARE_READ = 0x00000001;
139pub const FILE_SHARE_WRITE = 0x00000002;
140
141pub const CREATE_ALWAYS = 2;
142pub const CREATE_NEW = 1;
143pub const OPEN_ALWAYS = 4;
144pub const OPEN_EXISTING = 3;
145pub const TRUNCATE_EXISTING = 5;
146
147pub const FILE_ATTRIBUTE_ARCHIVE = 0x20;
148pub const FILE_ATTRIBUTE_COMPRESSED = 0x800;
149pub const FILE_ATTRIBUTE_DEVICE = 0x40;
150pub const FILE_ATTRIBUTE_DIRECTORY = 0x10;
151pub const FILE_ATTRIBUTE_ENCRYPTED = 0x4000;
152pub const FILE_ATTRIBUTE_HIDDEN = 0x2;
153pub const FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x8000;
154pub const FILE_ATTRIBUTE_NORMAL = 0x80;
155pub const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000;
156pub const FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x20000;
157pub const FILE_ATTRIBUTE_OFFLINE = 0x1000;
158pub const FILE_ATTRIBUTE_READONLY = 0x1;
159pub const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x400000;
160pub const FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x40000;
161pub const FILE_ATTRIBUTE_REPARSE_POINT = 0x400;
162pub const FILE_ATTRIBUTE_SPARSE_FILE = 0x200;
163pub const FILE_ATTRIBUTE_SYSTEM = 0x4;
164pub const FILE_ATTRIBUTE_TEMPORARY = 0x100;
165pub const FILE_ATTRIBUTE_VIRTUAL = 0x10000;
166
167pub const PROCESS_INFORMATION = extern struct {
168 hProcess: HANDLE,
169 hThread: HANDLE,
170 dwProcessId: DWORD,
171 dwThreadId: DWORD,
172};
173
174pub const STARTUPINFOW = extern struct {
175 cb: DWORD,
176 lpReserved: ?LPWSTR,
177 lpDesktop: ?LPWSTR,
178 lpTitle: ?LPWSTR,
179 dwX: DWORD,
180 dwY: DWORD,
181 dwXSize: DWORD,
182 dwYSize: DWORD,
183 dwXCountChars: DWORD,
184 dwYCountChars: DWORD,
185 dwFillAttribute: DWORD,
186 dwFlags: DWORD,
187 wShowWindow: WORD,
188 cbReserved2: WORD,
189 lpReserved2: ?LPBYTE,
190 hStdInput: ?HANDLE,
191 hStdOutput: ?HANDLE,
192 hStdError: ?HANDLE,
193};
194
195pub const STARTF_FORCEONFEEDBACK = 0x00000040;
196pub const STARTF_FORCEOFFFEEDBACK = 0x00000080;
197pub const STARTF_PREVENTPINNING = 0x00002000;
198pub const STARTF_RUNFULLSCREEN = 0x00000020;
199pub const STARTF_TITLEISAPPID = 0x00001000;
200pub const STARTF_TITLEISLINKNAME = 0x00000800;
201pub const STARTF_UNTRUSTEDSOURCE = 0x00008000;
202pub const STARTF_USECOUNTCHARS = 0x00000008;
203pub const STARTF_USEFILLATTRIBUTE = 0x00000010;
204pub const STARTF_USEHOTKEY = 0x00000200;
205pub const STARTF_USEPOSITION = 0x00000004;
206pub const STARTF_USESHOWWINDOW = 0x00000001;
207pub const STARTF_USESIZE = 0x00000002;
208pub const STARTF_USESTDHANDLES = 0x00000100;
209
210pub const INFINITE = 4294967295;
211
212pub const WAIT_ABANDONED = 0x00000080;
213pub const WAIT_OBJECT_0 = 0x00000000;
214pub const WAIT_TIMEOUT = 0x00000102;
215pub const WAIT_FAILED = 0xFFFFFFFF;
216
217pub const HANDLE_FLAG_INHERIT = 0x00000001;
218pub const HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x00000002;
219
220pub const MOVEFILE_COPY_ALLOWED = 2;
221pub const MOVEFILE_CREATE_HARDLINK = 16;
222pub const MOVEFILE_DELAY_UNTIL_REBOOT = 4;
223pub const MOVEFILE_FAIL_IF_NOT_TRACKABLE = 32;
224pub const MOVEFILE_REPLACE_EXISTING = 1;
225pub const MOVEFILE_WRITE_THROUGH = 8;
226
227pub const FILE_BEGIN = 0;
228pub const FILE_CURRENT = 1;
229pub const FILE_END = 2;
230
231pub const HEAP_CREATE_ENABLE_EXECUTE = 0x00040000;
232pub const HEAP_GENERATE_EXCEPTIONS = 0x00000004;
233pub const HEAP_NO_SERIALIZE = 0x00000001;
234
235// AllocationType values
236pub const MEM_COMMIT = 0x1000;
237pub const MEM_RESERVE = 0x2000;
238pub const MEM_RESET = 0x80000;
239pub const MEM_RESET_UNDO = 0x1000000;
240pub const MEM_LARGE_PAGES = 0x20000000;
241pub const MEM_PHYSICAL = 0x400000;
242pub const MEM_TOP_DOWN = 0x100000;
243pub const MEM_WRITE_WATCH = 0x200000;
244
245// Protect values
246pub const PAGE_EXECUTE = 0x10;
247pub const PAGE_EXECUTE_READ = 0x20;
248pub const PAGE_EXECUTE_READWRITE = 0x40;
249pub const PAGE_EXECUTE_WRITECOPY = 0x80;
250pub const PAGE_NOACCESS = 0x01;
251pub const PAGE_READONLY = 0x02;
252pub const PAGE_READWRITE = 0x04;
253pub const PAGE_WRITECOPY = 0x08;
254pub const PAGE_TARGETS_INVALID = 0x40000000;
255pub const PAGE_TARGETS_NO_UPDATE = 0x40000000; // Same as PAGE_TARGETS_INVALID
256pub const PAGE_GUARD = 0x100;
257pub const PAGE_NOCACHE = 0x200;
258pub const PAGE_WRITECOMBINE = 0x400;
259
260// FreeType values
261pub const MEM_COALESCE_PLACEHOLDERS = 0x1;
262pub const MEM_RESERVE_PLACEHOLDERS = 0x2;
263pub const MEM_DECOMMIT = 0x4000;
264pub const MEM_RELEASE = 0x8000;
265
266pub const PTHREAD_START_ROUTINE = extern fn (LPVOID) DWORD;
267pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE;
268
269pub const WIN32_FIND_DATAW = extern struct {
270 dwFileAttributes: DWORD,
271 ftCreationTime: FILETIME,
272 ftLastAccessTime: FILETIME,
273 ftLastWriteTime: FILETIME,
274 nFileSizeHigh: DWORD,
275 nFileSizeLow: DWORD,
276 dwReserved0: DWORD,
277 dwReserved1: DWORD,
278 cFileName: [260]u16,
279 cAlternateFileName: [14]u16,
280};
281
282pub const FILETIME = extern struct {
283 dwLowDateTime: DWORD,
284 dwHighDateTime: DWORD,
285};
286
287pub const SYSTEM_INFO = extern struct {
288 anon1: extern union {
289 dwOemId: DWORD,
290 anon2: extern struct {
291 wProcessorArchitecture: WORD,
292 wReserved: WORD,
293 },
294 },
295 dwPageSize: DWORD,
296 lpMinimumApplicationAddress: LPVOID,
297 lpMaximumApplicationAddress: LPVOID,
298 dwActiveProcessorMask: DWORD_PTR,
299 dwNumberOfProcessors: DWORD,
300 dwProcessorType: DWORD,
301 dwAllocationGranularity: DWORD,
302 wProcessorLevel: WORD,
303 wProcessorRevision: WORD,
304};
305
306pub const HRESULT = c_long;
307
308pub const KNOWNFOLDERID = GUID;
309pub const GUID = extern struct {
310 Data1: c_ulong,
311 Data2: c_ushort,
312 Data3: c_ushort,
313 Data4: [8]u8,
314
315 pub fn parse(str: []const u8) GUID {
316 var guid: GUID = undefined;
317 var index: usize = 0;
318 assert(str[index] == '{');
319 index += 1;
320
321 guid.Data1 = std.fmt.parseUnsigned(c_ulong, str[index .. index + 8], 16) catch unreachable;
322 index += 8;
323
324 assert(str[index] == '-');
325 index += 1;
326
327 guid.Data2 = std.fmt.parseUnsigned(c_ushort, str[index .. index + 4], 16) catch unreachable;
328 index += 4;
329
330 assert(str[index] == '-');
331 index += 1;
332
333 guid.Data3 = std.fmt.parseUnsigned(c_ushort, str[index .. index + 4], 16) catch unreachable;
334 index += 4;
335
336 assert(str[index] == '-');
337 index += 1;
338
339 guid.Data4[0] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
340 index += 2;
341 guid.Data4[1] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
342 index += 2;
343
344 assert(str[index] == '-');
345 index += 1;
346
347 var i: usize = 2;
348 while (i < guid.Data4.len) : (i += 1) {
349 guid.Data4[i] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable;
350 index += 2;
351 }
352
353 assert(str[index] == '}');
354 index += 1;
355 return guid;
356 }
357};
358
359pub const FOLDERID_LocalAppData = GUID.parse("{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}");
360
361pub const KF_FLAG_DEFAULT = 0;
362pub const KF_FLAG_NO_APPCONTAINER_REDIRECTION = 65536;
363pub const KF_FLAG_CREATE = 32768;
364pub const KF_FLAG_DONT_VERIFY = 16384;
365pub const KF_FLAG_DONT_UNEXPAND = 8192;
366pub const KF_FLAG_NO_ALIAS = 4096;
367pub const KF_FLAG_INIT = 2048;
368pub const KF_FLAG_DEFAULT_PATH = 1024;
369pub const KF_FLAG_NOT_PARENT_RELATIVE = 512;
370pub const KF_FLAG_SIMPLE_IDLIST = 256;
371pub const KF_FLAG_ALIAS_ONLY = -2147483648;
372
373pub const S_OK = 0;
374pub const E_NOTIMPL = @bitCast(c_long, c_ulong(0x80004001));
375pub const E_NOINTERFACE = @bitCast(c_long, c_ulong(0x80004002));
376pub const E_POINTER = @bitCast(c_long, c_ulong(0x80004003));
377pub const E_ABORT = @bitCast(c_long, c_ulong(0x80004004));
378pub const E_FAIL = @bitCast(c_long, c_ulong(0x80004005));
379pub const E_UNEXPECTED = @bitCast(c_long, c_ulong(0x8000FFFF));
380pub const E_ACCESSDENIED = @bitCast(c_long, c_ulong(0x80070005));
381pub const E_HANDLE = @bitCast(c_long, c_ulong(0x80070006));
382pub const E_OUTOFMEMORY = @bitCast(c_long, c_ulong(0x8007000E));
383pub const E_INVALIDARG = @bitCast(c_long, c_ulong(0x80070057));
384
385pub const FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
386pub const FILE_FLAG_DELETE_ON_CLOSE = 0x04000000;
387pub const FILE_FLAG_NO_BUFFERING = 0x20000000;
388pub const FILE_FLAG_OPEN_NO_RECALL = 0x00100000;
389pub const FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;
390pub const FILE_FLAG_OVERLAPPED = 0x40000000;
391pub const FILE_FLAG_POSIX_SEMANTICS = 0x0100000;
392pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000;
393pub const FILE_FLAG_SESSION_AWARE = 0x00800000;
394pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000;
395pub const FILE_FLAG_WRITE_THROUGH = 0x80000000;
396
397pub const SMALL_RECT = extern struct {
398 Left: SHORT,
399 Top: SHORT,
400 Right: SHORT,
401 Bottom: SHORT,
402};
403
404pub const COORD = extern struct {
405 X: SHORT,
406 Y: SHORT,
407};
408
409pub const CREATE_UNICODE_ENVIRONMENT = 1024;
410
411pub const TLS_OUT_OF_INDEXES = 4294967295;
412pub const IMAGE_TLS_DIRECTORY = extern struct {
413 StartAddressOfRawData: usize,
414 EndAddressOfRawData: usize,
415 AddressOfIndex: usize,
416 AddressOfCallBacks: usize,
417 SizeOfZeroFill: u32,
418 Characteristics: u32,
419};
420pub const IMAGE_TLS_DIRECTORY64 = IMAGE_TLS_DIRECTORY;
421pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY;
422
423pub const PIMAGE_TLS_CALLBACK = ?extern fn (PVOID, DWORD, PVOID) void;
424
425pub const PROV_RSA_FULL = 1;
426
427pub const REGSAM = ACCESS_MASK;
428pub const ACCESS_MASK = DWORD;
429pub const PHKEY = *HKEY;
430pub const HKEY = *HKEY__;
431pub const HKEY__ = extern struct {
432 unused: c_int,
433};
434pub const LSTATUS = LONG;
435
436pub const FILE_NOTIFY_INFORMATION = extern struct {
437 NextEntryOffset: DWORD,
438 Action: DWORD,
439 FileNameLength: DWORD,
440 FileName: [1]WCHAR,
441};
442
443pub const FILE_ACTION_ADDED = 0x00000001;
444pub const FILE_ACTION_REMOVED = 0x00000002;
445pub const FILE_ACTION_MODIFIED = 0x00000003;
446pub const FILE_ACTION_RENAMED_OLD_NAME = 0x00000004;
447pub const FILE_ACTION_RENAMED_NEW_NAME = 0x00000005;
448
449pub const LPOVERLAPPED_COMPLETION_ROUTINE = ?extern fn (DWORD, DWORD, *OVERLAPPED) void;
450
451pub const FILE_LIST_DIRECTORY = 1;
452
453pub const FILE_NOTIFY_CHANGE_CREATION = 64;
454pub const FILE_NOTIFY_CHANGE_SIZE = 8;
455pub const FILE_NOTIFY_CHANGE_SECURITY = 256;
456pub const FILE_NOTIFY_CHANGE_LAST_ACCESS = 32;
457pub const FILE_NOTIFY_CHANGE_LAST_WRITE = 16;
458pub const FILE_NOTIFY_CHANGE_DIR_NAME = 2;
459pub const FILE_NOTIFY_CHANGE_FILE_NAME = 1;
460pub const FILE_NOTIFY_CHANGE_ATTRIBUTES = 4;
461
462pub const CONSOLE_SCREEN_BUFFER_INFO = extern struct {
463 dwSize: COORD,
464 dwCursorPosition: COORD,
465 wAttributes: WORD,
466 srWindow: SMALL_RECT,
467 dwMaximumWindowSize: COORD,
468};
469
470pub const FOREGROUND_BLUE = 1;
471pub const FOREGROUND_GREEN = 2;
472pub const FOREGROUND_RED = 4;
473pub const FOREGROUND_INTENSITY = 8;
474
475pub const LIST_ENTRY = extern struct {
476 Flink: *LIST_ENTRY,
477 Blink: *LIST_ENTRY,
478};
479
480pub const RTL_CRITICAL_SECTION_DEBUG = extern struct {
481 Type: WORD,
482 CreatorBackTraceIndex: WORD,
483 CriticalSection: *RTL_CRITICAL_SECTION,
484 ProcessLocksList: LIST_ENTRY,
485 EntryCount: DWORD,
486 ContentionCount: DWORD,
487 Flags: DWORD,
488 CreatorBackTraceIndexHigh: WORD,
489 SpareWORD: WORD,
490};
491
492pub const RTL_CRITICAL_SECTION = extern struct {
493 DebugInfo: *RTL_CRITICAL_SECTION_DEBUG,
494 LockCount: LONG,
495 RecursionCount: LONG,
496 OwningThread: HANDLE,
497 LockSemaphore: HANDLE,
498 SpinCount: ULONG_PTR,
499};
500
501pub const CRITICAL_SECTION = RTL_CRITICAL_SECTION;
502pub const INIT_ONCE = RTL_RUN_ONCE;
503pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE_INIT;
504pub const INIT_ONCE_FN = extern fn (InitOnce: *INIT_ONCE, Parameter: ?*c_void, Context: ?*c_void) BOOL;
505
506pub const RTL_RUN_ONCE = extern struct {
507 Ptr: ?*c_void,
508};
509
510pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE{ .Ptr = null };
511
512pub const COINIT_APARTMENTTHREADED = COINIT.COINIT_APARTMENTTHREADED;
513pub const COINIT_MULTITHREADED = COINIT.COINIT_MULTITHREADED;
514pub const COINIT_DISABLE_OLE1DDE = COINIT.COINIT_DISABLE_OLE1DDE;
515pub const COINIT_SPEED_OVER_MEMORY = COINIT.COINIT_SPEED_OVER_MEMORY;
516pub const COINIT = extern enum {
517 COINIT_APARTMENTTHREADED = 2,
518 COINIT_MULTITHREADED = 0,
519 COINIT_DISABLE_OLE1DDE = 4,
520 COINIT_SPEED_OVER_MEMORY = 8,
521};
522
523/// > The maximum path of 32,767 characters is approximate, because the "\\?\"
524/// > prefix may be expanded to a longer string by the system at run time, and
525/// > this expansion applies to the total length.
526/// from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
527pub const PATH_MAX_WIDE = 32767;
std/os/windows/kernel32.zig+1-78
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1use @import("../windows.zig");1use @import("bits.zig");
22
3pub extern "kernel32" stdcallcc fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) BOOL;3pub extern "kernel32" stdcallcc fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) BOOL;
44
...@@ -189,86 +189,9 @@ pub extern "kernel32" stdcallcc fn GetProcAddress(hModule: HMODULE, lpProcName:...@@ -189,86 +189,9 @@ pub extern "kernel32" stdcallcc fn GetProcAddress(hModule: HMODULE, lpProcName:
189189
190pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) BOOL;190pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) BOOL;
191191
192pub const FILE_NOTIFY_INFORMATION = extern struct {
193 NextEntryOffset: DWORD,
194 Action: DWORD,
195 FileNameLength: DWORD,
196 FileName: [1]WCHAR,
197};
198
199pub const FILE_ACTION_ADDED = 0x00000001;
200pub const FILE_ACTION_REMOVED = 0x00000002;
201pub const FILE_ACTION_MODIFIED = 0x00000003;
202pub const FILE_ACTION_RENAMED_OLD_NAME = 0x00000004;
203pub const FILE_ACTION_RENAMED_NEW_NAME = 0x00000005;
204
205pub const LPOVERLAPPED_COMPLETION_ROUTINE = ?extern fn (DWORD, DWORD, *OVERLAPPED) void;
206
207pub const FILE_LIST_DIRECTORY = 1;
208
209pub const FILE_NOTIFY_CHANGE_CREATION = 64;
210pub const FILE_NOTIFY_CHANGE_SIZE = 8;
211pub const FILE_NOTIFY_CHANGE_SECURITY = 256;
212pub const FILE_NOTIFY_CHANGE_LAST_ACCESS = 32;
213pub const FILE_NOTIFY_CHANGE_LAST_WRITE = 16;
214pub const FILE_NOTIFY_CHANGE_DIR_NAME = 2;
215pub const FILE_NOTIFY_CHANGE_FILE_NAME = 1;
216pub const FILE_NOTIFY_CHANGE_ATTRIBUTES = 4;
217
218pub const CONSOLE_SCREEN_BUFFER_INFO = extern struct {
219 dwSize: COORD,
220 dwCursorPosition: COORD,
221 wAttributes: WORD,
222 srWindow: SMALL_RECT,
223 dwMaximumWindowSize: COORD,
224};
225
226pub const FOREGROUND_BLUE = 1;
227pub const FOREGROUND_GREEN = 2;
228pub const FOREGROUND_RED = 4;
229pub const FOREGROUND_INTENSITY = 8;
230
231pub extern "kernel32" stdcallcc fn InitializeCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void;192pub extern "kernel32" stdcallcc fn InitializeCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void;
232pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void;193pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void;
233pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void;194pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void;
234pub extern "kernel32" stdcallcc fn DeleteCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void;195pub extern "kernel32" stdcallcc fn DeleteCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void;
235196
236pub const LIST_ENTRY = extern struct {
237 Flink: *LIST_ENTRY,
238 Blink: *LIST_ENTRY,
239};
240
241pub const RTL_CRITICAL_SECTION_DEBUG = extern struct {
242 Type: WORD,
243 CreatorBackTraceIndex: WORD,
244 CriticalSection: *RTL_CRITICAL_SECTION,
245 ProcessLocksList: LIST_ENTRY,
246 EntryCount: DWORD,
247 ContentionCount: DWORD,
248 Flags: DWORD,
249 CreatorBackTraceIndexHigh: WORD,
250 SpareWORD: WORD,
251};
252
253pub const RTL_CRITICAL_SECTION = extern struct {
254 DebugInfo: *RTL_CRITICAL_SECTION_DEBUG,
255 LockCount: LONG,
256 RecursionCount: LONG,
257 OwningThread: HANDLE,
258 LockSemaphore: HANDLE,
259 SpinCount: ULONG_PTR,
260};
261
262pub const CRITICAL_SECTION = RTL_CRITICAL_SECTION;
263pub const INIT_ONCE = RTL_RUN_ONCE;
264pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE_INIT;
265
266pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter: ?*c_void, Context: ?*c_void) BOOL;197pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter: ?*c_void, Context: ?*c_void) BOOL;
267
268pub const INIT_ONCE_FN = extern fn (InitOnce: *INIT_ONCE, Parameter: ?*c_void, Context: ?*c_void) BOOL;
269
270pub const RTL_RUN_ONCE = extern struct {
271 Ptr: ?*c_void,
272};
273
274pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE{ .Ptr = null };
std/os/windows/ntdll.zig+1-1
...@@ -1,3 +1,3 @@...@@ -1,3 +1,3 @@
1use @import("../windows.zig");1use @import("bits.zig");
22
3pub extern "NtDll" stdcallcc fn RtlCaptureStackBackTrace(FramesToSkip: DWORD, FramesToCapture: DWORD, BackTrace: **c_void, BackTraceHash: ?*DWORD) WORD;3pub extern "NtDll" stdcallcc fn RtlCaptureStackBackTrace(FramesToSkip: DWORD, FramesToCapture: DWORD, BackTrace: **c_void, BackTraceHash: ?*DWORD) WORD;
std/os/windows/ole32.zig+1-12
...@@ -1,17 +1,6 @@...@@ -1,17 +1,6 @@
1use @import("../windows.zig");1use @import("bits.zig");
22
3pub extern "ole32" stdcallcc fn CoTaskMemFree(pv: LPVOID) void;3pub extern "ole32" stdcallcc fn CoTaskMemFree(pv: LPVOID) void;
4pub extern "ole32" stdcallcc fn CoUninitialize() void;4pub extern "ole32" stdcallcc fn CoUninitialize() void;
5pub extern "ole32" stdcallcc fn CoGetCurrentProcess() DWORD;5pub extern "ole32" stdcallcc fn CoGetCurrentProcess() DWORD;
6pub extern "ole32" stdcallcc fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) HRESULT;6pub extern "ole32" stdcallcc fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) HRESULT;
7
8pub const COINIT_APARTMENTTHREADED = COINIT.COINIT_APARTMENTTHREADED;
9pub const COINIT_MULTITHREADED = COINIT.COINIT_MULTITHREADED;
10pub const COINIT_DISABLE_OLE1DDE = COINIT.COINIT_DISABLE_OLE1DDE;
11pub const COINIT_SPEED_OVER_MEMORY = COINIT.COINIT_SPEED_OVER_MEMORY;
12pub const COINIT = extern enum {
13 COINIT_APARTMENTTHREADED = 2,
14 COINIT_MULTITHREADED = 0,
15 COINIT_DISABLE_OLE1DDE = 4,
16 COINIT_SPEED_OVER_MEMORY = 8,
17};
std/os/windows/shell32.zig+1-1
...@@ -1,3 +1,3 @@...@@ -1,3 +1,3 @@
1use @import("../windows.zig");1use @import("bits.zig");
22
3pub extern "shell32" stdcallcc fn SHGetKnownFolderPath(rfid: *const KNOWNFOLDERID, dwFlags: DWORD, hToken: ?HANDLE, ppszPath: *[*]WCHAR) HRESULT;3pub extern "shell32" stdcallcc fn SHGetKnownFolderPath(rfid: *const KNOWNFOLDERID, dwFlags: DWORD, hToken: ?HANDLE, ppszPath: *[*]WCHAR) HRESULT;
std/os/windows/util.zig deleted-316
...@@ -1,316 +0,0 @@
1const std = @import("../../std.zig");
2const builtin = @import("builtin");
3const os = std.os;
4const unicode = std.unicode;
5const windows = std.os.windows;
6const assert = std.debug.assert;
7const mem = std.mem;
8const BufMap = std.BufMap;
9const cstr = std.cstr;
10
11// > The maximum path of 32,767 characters is approximate, because the "\\?\"
12// > prefix may be expanded to a longer string by the system at run time, and
13// > this expansion applies to the total length.
14// from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
15pub const PATH_MAX_WIDE = 32767;
16
17pub const WaitError = error{
18 WaitAbandoned,
19 WaitTimeOut,
20
21 /// See https://github.com/ziglang/zig/issues/1396
22 Unexpected,
23};
24
25pub fn windowsWaitSingle(handle: windows.HANDLE, milliseconds: windows.DWORD) WaitError!void {
26 const result = windows.WaitForSingleObject(handle, milliseconds);
27 return switch (result) {
28 windows.WAIT_ABANDONED => error.WaitAbandoned,
29 windows.WAIT_OBJECT_0 => {},
30 windows.WAIT_TIMEOUT => error.WaitTimeOut,
31 windows.WAIT_FAILED => x: {
32 const err = windows.GetLastError();
33 break :x switch (err) {
34 else => os.unexpectedErrorWindows(err),
35 };
36 },
37 else => error.Unexpected,
38 };
39}
40
41pub fn windowsClose(handle: windows.HANDLE) void {
42 assert(windows.CloseHandle(handle) != 0);
43}
44
45pub const ReadError = error{
46 OperationAborted,
47 BrokenPipe,
48 Unexpected,
49};
50
51pub const WriteError = error{
52 SystemResources,
53 OperationAborted,
54 BrokenPipe,
55
56 /// See https://github.com/ziglang/zig/issues/1396
57 Unexpected,
58};
59
60pub fn windowsWrite(handle: windows.HANDLE, bytes: []const u8) WriteError!void {
61 var bytes_written: windows.DWORD = undefined;
62 if (windows.WriteFile(handle, bytes.ptr, @intCast(u32, bytes.len), &bytes_written, null) == 0) {
63 const err = windows.GetLastError();
64 return switch (err) {
65 windows.ERROR.INVALID_USER_BUFFER => WriteError.SystemResources,
66 windows.ERROR.NOT_ENOUGH_MEMORY => WriteError.SystemResources,
67 windows.ERROR.OPERATION_ABORTED => WriteError.OperationAborted,
68 windows.ERROR.NOT_ENOUGH_QUOTA => WriteError.SystemResources,
69 windows.ERROR.IO_PENDING => unreachable,
70 windows.ERROR.BROKEN_PIPE => WriteError.BrokenPipe,
71 else => os.unexpectedErrorWindows(err),
72 };
73 }
74}
75
76pub fn windowsIsTty(handle: windows.HANDLE) bool {
77 if (windowsIsCygwinPty(handle))
78 return true;
79
80 var out: windows.DWORD = undefined;
81 return windows.GetConsoleMode(handle, &out) != 0;
82}
83
84pub fn windowsIsCygwinPty(handle: windows.HANDLE) bool {
85 const size = @sizeOf(windows.FILE_NAME_INFO);
86 var name_info_bytes align(@alignOf(windows.FILE_NAME_INFO)) = []u8{0} ** (size + windows.MAX_PATH);
87
88 if (windows.GetFileInformationByHandleEx(
89 handle,
90 windows.FileNameInfo,
91 @ptrCast(*c_void, &name_info_bytes[0]),
92 @intCast(u32, name_info_bytes.len),
93 ) == 0) {
94 return false;
95 }
96
97 const name_info = @ptrCast(*const windows.FILE_NAME_INFO, &name_info_bytes[0]);
98 const name_bytes = name_info_bytes[size .. size + usize(name_info.FileNameLength)];
99 const name_wide = @bytesToSlice(u16, name_bytes);
100 return mem.indexOf(u16, name_wide, []u16{ 'm', 's', 'y', 's', '-' }) != null or
101 mem.indexOf(u16, name_wide, []u16{ '-', 'p', 't', 'y' }) != null;
102}
103
104pub const OpenError = error{
105 SharingViolation,
106 PathAlreadyExists,
107
108 /// When any of the path components can not be found or the file component can not
109 /// be found. Some operating systems distinguish between path components not found and
110 /// file components not found, but they are collapsed into FileNotFound to gain
111 /// consistency across operating systems.
112 FileNotFound,
113
114 AccessDenied,
115 PipeBusy,
116 NameTooLong,
117
118 /// On Windows, file paths must be valid Unicode.
119 InvalidUtf8,
120
121 /// On Windows, file paths cannot contain these characters:
122 /// '/', '*', '?', '"', '<', '>', '|'
123 BadPathName,
124
125 /// See https://github.com/ziglang/zig/issues/1396
126 Unexpected,
127};
128
129pub fn windowsOpenW(
130 file_path_w: [*]const u16,
131 desired_access: windows.DWORD,
132 share_mode: windows.DWORD,
133 creation_disposition: windows.DWORD,
134 flags_and_attrs: windows.DWORD,
135) OpenError!windows.HANDLE {
136 const result = windows.CreateFileW(file_path_w, desired_access, share_mode, null, creation_disposition, flags_and_attrs, null);
137
138 if (result == windows.INVALID_HANDLE_VALUE) {
139 const err = windows.GetLastError();
140 switch (err) {
141 windows.ERROR.SHARING_VIOLATION => return OpenError.SharingViolation,
142 windows.ERROR.ALREADY_EXISTS => return OpenError.PathAlreadyExists,
143 windows.ERROR.FILE_EXISTS => return OpenError.PathAlreadyExists,
144 windows.ERROR.FILE_NOT_FOUND => return OpenError.FileNotFound,
145 windows.ERROR.PATH_NOT_FOUND => return OpenError.FileNotFound,
146 windows.ERROR.ACCESS_DENIED => return OpenError.AccessDenied,
147 windows.ERROR.PIPE_BUSY => return OpenError.PipeBusy,
148 else => return os.unexpectedErrorWindows(err),
149 }
150 }
151
152 return result;
153}
154
155pub fn windowsOpen(
156 file_path: []const u8,
157 desired_access: windows.DWORD,
158 share_mode: windows.DWORD,
159 creation_disposition: windows.DWORD,
160 flags_and_attrs: windows.DWORD,
161) OpenError!windows.HANDLE {
162 const file_path_w = try sliceToPrefixedFileW(file_path);
163 return windowsOpenW(&file_path_w, desired_access, share_mode, creation_disposition, flags_and_attrs);
164}
165
166/// Caller must free result.
167pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u16 {
168 // count bytes needed
169 const max_chars_needed = x: {
170 var max_chars_needed: usize = 4; // 4 for the final 4 null bytes
171 var it = env_map.iterator();
172 while (it.next()) |pair| {
173 // +1 for '='
174 // +1 for null byte
175 max_chars_needed += pair.key.len + pair.value.len + 2;
176 }
177 break :x max_chars_needed;
178 };
179 const result = try allocator.alloc(u16, max_chars_needed);
180 errdefer allocator.free(result);
181
182 var it = env_map.iterator();
183 var i: usize = 0;
184 while (it.next()) |pair| {
185 i += try unicode.utf8ToUtf16Le(result[i..], pair.key);
186 result[i] = '=';
187 i += 1;
188 i += try unicode.utf8ToUtf16Le(result[i..], pair.value);
189 result[i] = 0;
190 i += 1;
191 }
192 result[i] = 0;
193 i += 1;
194 result[i] = 0;
195 i += 1;
196 result[i] = 0;
197 i += 1;
198 result[i] = 0;
199 i += 1;
200 return allocator.shrink(result, i);
201}
202
203pub fn windowsFindFirstFile(
204 dir_path: []const u8,
205 find_file_data: *windows.WIN32_FIND_DATAW,
206) !windows.HANDLE {
207 const dir_path_w = try sliceToPrefixedSuffixedFileW(dir_path, []u16{ '\\', '*', 0 });
208 const handle = windows.FindFirstFileW(&dir_path_w, find_file_data);
209
210 if (handle == windows.INVALID_HANDLE_VALUE) {
211 const err = windows.GetLastError();
212 switch (err) {
213 windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound,
214 windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound,
215 else => return os.unexpectedErrorWindows(err),
216 }
217 }
218
219 return handle;
220}
221
222/// Returns `true` if there was another file, `false` otherwise.
223pub fn windowsFindNextFile(handle: windows.HANDLE, find_file_data: *windows.WIN32_FIND_DATAW) !bool {
224 if (windows.FindNextFileW(handle, find_file_data) == 0) {
225 const err = windows.GetLastError();
226 return switch (err) {
227 windows.ERROR.NO_MORE_FILES => false,
228 else => os.unexpectedErrorWindows(err),
229 };
230 }
231 return true;
232}
233
234pub const WindowsCreateIoCompletionPortError = error{Unexpected};
235
236pub fn windowsCreateIoCompletionPort(file_handle: windows.HANDLE, existing_completion_port: ?windows.HANDLE, completion_key: usize, concurrent_thread_count: windows.DWORD) !windows.HANDLE {
237 const handle = windows.CreateIoCompletionPort(file_handle, existing_completion_port, completion_key, concurrent_thread_count) orelse {
238 const err = windows.GetLastError();
239 switch (err) {
240 windows.ERROR.INVALID_PARAMETER => unreachable,
241 else => return os.unexpectedErrorWindows(err),
242 }
243 };
244 return handle;
245}
246
247pub const WindowsPostQueuedCompletionStatusError = error{Unexpected};
248
249pub fn windowsPostQueuedCompletionStatus(completion_port: windows.HANDLE, bytes_transferred_count: windows.DWORD, completion_key: usize, lpOverlapped: ?*windows.OVERLAPPED) WindowsPostQueuedCompletionStatusError!void {
250 if (windows.PostQueuedCompletionStatus(completion_port, bytes_transferred_count, completion_key, lpOverlapped) == 0) {
251 const err = windows.GetLastError();
252 switch (err) {
253 else => return os.unexpectedErrorWindows(err),
254 }
255 }
256}
257
258pub const WindowsWaitResult = enum {
259 Normal,
260 Aborted,
261 Cancelled,
262 EOF,
263};
264
265pub fn windowsGetQueuedCompletionStatus(completion_port: windows.HANDLE, bytes_transferred_count: *windows.DWORD, lpCompletionKey: *usize, lpOverlapped: *?*windows.OVERLAPPED, dwMilliseconds: windows.DWORD) WindowsWaitResult {
266 if (windows.GetQueuedCompletionStatus(completion_port, bytes_transferred_count, lpCompletionKey, lpOverlapped, dwMilliseconds) == windows.FALSE) {
267 const err = windows.GetLastError();
268 switch (err) {
269 windows.ERROR.ABANDONED_WAIT_0 => return WindowsWaitResult.Aborted,
270 windows.ERROR.OPERATION_ABORTED => return WindowsWaitResult.Cancelled,
271 windows.ERROR.HANDLE_EOF => return WindowsWaitResult.EOF,
272 else => {
273 if (std.debug.runtime_safety) {
274 std.debug.panic("unexpected error: {}\n", err);
275 }
276 },
277 }
278 }
279 return WindowsWaitResult.Normal;
280}
281
282pub fn cStrToPrefixedFileW(s: [*]const u8) ![PATH_MAX_WIDE + 1]u16 {
283 return sliceToPrefixedFileW(mem.toSliceConst(u8, s));
284}
285
286pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 {
287 return sliceToPrefixedSuffixedFileW(s, []u16{0});
288}
289
290pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) ![PATH_MAX_WIDE + suffix.len]u16 {
291 // TODO well defined copy elision
292 var result: [PATH_MAX_WIDE + suffix.len]u16 = undefined;
293
294 // > File I/O functions in the Windows API convert "/" to "\" as part of
295 // > converting the name to an NT-style name, except when using the "\\?\"
296 // > prefix as detailed in the following sections.
297 // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation
298 // Because we want the larger maximum path length for absolute paths, we
299 // disallow forward slashes in zig std lib file functions on Windows.
300 for (s) |byte| {
301 switch (byte) {
302 '/', '*', '?', '"', '<', '>', '|' => return error.BadPathName,
303 else => {},
304 }
305 }
306 const start_index = if (mem.startsWith(u8, s, "\\\\") or !os.path.isAbsolute(s)) 0 else blk: {
307 const prefix = []u16{ '\\', '\\', '?', '\\' };
308 mem.copy(u16, result[0..], prefix);
309 break :blk prefix.len;
310 };
311 const end_index = start_index + try std.unicode.utf8ToUtf16Le(result[start_index..], s);
312 assert(end_index <= result.len);
313 if (end_index + suffix.len > result.len) return error.NameTooLong;
314 mem.copy(u16, result[end_index..], suffix);
315 return result;
316}
std/os/zen.zig+1-1
...@@ -80,7 +80,7 @@ pub const STDOUT_FILENO = 1;...@@ -80,7 +80,7 @@ pub const STDOUT_FILENO = 1;
80pub const STDERR_FILENO = 2;80pub const STDERR_FILENO = 2;
8181
82// FIXME: let's borrow Linux's error numbers for now.82// FIXME: let's borrow Linux's error numbers for now.
83use @import("linux/errno.zig");83use @import("bits/linux/errno.zig");
84// Get the errno from a syscall return value, or 0 for no error.84// Get the errno from a syscall return value, or 0 for no error.
85pub fn getErrno(r: usize) usize {85pub fn getErrno(r: usize) usize {
86 const signed_r = @bitCast(isize, r);86 const signed_r = @bitCast(isize, r);
std/packed_int_array.zig+3-3
...@@ -619,7 +619,7 @@ test "PackedIntArray at end of available memory" {...@@ -619,7 +619,7 @@ test "PackedIntArray at end of available memory" {
619 const PackedArray = PackedIntArray(u3, 8);619 const PackedArray = PackedIntArray(u3, 8);
620620
621 const Padded = struct {621 const Padded = struct {
622 _: [std.os.page_size - @sizeOf(PackedArray)]u8,622 _: [std.mem.page_size - @sizeOf(PackedArray)]u8,
623 p: PackedArray,623 p: PackedArray,
624 };624 };
625625
...@@ -641,9 +641,9 @@ test "PackedIntSlice at end of available memory" {...@@ -641,9 +641,9 @@ test "PackedIntSlice at end of available memory" {
641 var da = std.heap.DirectAllocator.init();641 var da = std.heap.DirectAllocator.init();
642 const allocator = &da.allocator;642 const allocator = &da.allocator;
643643
644 var page = try allocator.alloc(u8, std.os.page_size);644 var page = try allocator.alloc(u8, std.mem.page_size);
645 defer allocator.free(page);645 defer allocator.free(page);
646646
647 var p = PackedSlice.init(page[std.os.page_size - 2 ..], 1);647 var p = PackedSlice.init(page[std.mem.page_size - 2 ..], 1);
648 p.set(0, std.math.maxInt(u11));648 p.set(0, std.math.maxInt(u11));
649}649}
std/pdb.zig+8-8
...@@ -6,6 +6,7 @@ const mem = std.mem;...@@ -6,6 +6,7 @@ const mem = std.mem;
6const os = std.os;6const os = std.os;
7const warn = std.debug.warn;7const warn = std.debug.warn;
8const coff = std.coff;8const coff = std.coff;
9const File = std.fs.File;
910
10const ArrayList = std.ArrayList;11const ArrayList = std.ArrayList;
1112
...@@ -459,7 +460,7 @@ pub const PDBStringTableHeader = packed struct {...@@ -459,7 +460,7 @@ pub const PDBStringTableHeader = packed struct {
459};460};
460461
461pub const Pdb = struct {462pub const Pdb = struct {
462 in_file: os.File,463 in_file: File,
463 allocator: *mem.Allocator,464 allocator: *mem.Allocator,
464 coff: *coff.Coff,465 coff: *coff.Coff,
465 string_table: *MsfStream,466 string_table: *MsfStream,
...@@ -468,7 +469,7 @@ pub const Pdb = struct {...@@ -468,7 +469,7 @@ pub const Pdb = struct {
468 msf: Msf,469 msf: Msf,
469470
470 pub fn openFile(self: *Pdb, coff_ptr: *coff.Coff, file_name: []u8) !void {471 pub fn openFile(self: *Pdb, coff_ptr: *coff.Coff, file_name: []u8) !void {
471 self.in_file = try os.File.openRead(file_name);472 self.in_file = try File.openRead(file_name);
472 self.allocator = coff_ptr.allocator;473 self.allocator = coff_ptr.allocator;
473 self.coff = coff_ptr;474 self.coff = coff_ptr;
474475
...@@ -492,7 +493,7 @@ const Msf = struct {...@@ -492,7 +493,7 @@ const Msf = struct {
492 directory: MsfStream,493 directory: MsfStream,
493 streams: []MsfStream,494 streams: []MsfStream,
494495
495 fn openFile(self: *Msf, allocator: *mem.Allocator, file: os.File) !void {496 fn openFile(self: *Msf, allocator: *mem.Allocator, file: File) !void {
496 var file_stream = file.inStream();497 var file_stream = file.inStream();
497 const in = &file_stream.stream;498 const in = &file_stream.stream;
498499
...@@ -587,7 +588,7 @@ const SuperBlock = packed struct {...@@ -587,7 +588,7 @@ const SuperBlock = packed struct {
587};588};
588589
589const MsfStream = struct {590const MsfStream = struct {
590 in_file: os.File,591 in_file: File,
591 pos: u64,592 pos: u64,
592 blocks: []u32,593 blocks: []u32,
593 block_size: u32,594 block_size: u32,
...@@ -598,7 +599,7 @@ const MsfStream = struct {...@@ -598,7 +599,7 @@ const MsfStream = struct {
598 pub const Error = @typeOf(read).ReturnType.ErrorSet;599 pub const Error = @typeOf(read).ReturnType.ErrorSet;
599 pub const Stream = io.InStream(Error);600 pub const Stream = io.InStream(Error);
600601
601 fn init(block_size: u32, block_count: u32, pos: u64, file: os.File, allocator: *mem.Allocator) !MsfStream {602 fn init(block_size: u32, block_count: u32, pos: u64, file: File, allocator: *mem.Allocator) !MsfStream {
602 var stream = MsfStream{603 var stream = MsfStream{
603 .in_file = file,604 .in_file = file,
604 .pos = 0,605 .pos = 0,
...@@ -660,9 +661,8 @@ const MsfStream = struct {...@@ -660,9 +661,8 @@ const MsfStream = struct {
660 return size;661 return size;
661 }662 }
662663
663 // XXX: The `len` parameter should be signed664 fn seekBy(self: *MsfStream, len: i64) !void {
664 fn seekForward(self: *MsfStream, len: u64) !void {665 self.pos = @intCast(u64, @intCast(i64, self.pos) + len);
665 self.pos += len;
666 if (self.pos >= self.blocks.len * self.block_size)666 if (self.pos >= self.blocks.len * self.block_size)
667 return error.EOF;667 return error.EOF;
668 }668 }
std/process.zig created+617
...@@ -0,0 +1,617 @@
1const builtin = @import("builtin");
2const std = @import("std.zig");
3const os = std.os;
4const fs = std.fs;
5const BufMap = std.BufMap;
6const Buffer = std.Buffer;
7const mem = std.mem;
8const math = std.math;
9const Allocator = mem.Allocator;
10const assert = std.debug.assert;
11const testing = std.testing;
12
13pub const abort = os.abort;
14pub const exit = os.exit;
15pub const changeCurDir = os.chdir;
16pub const changeCurDirC = os.chdirC;
17
18/// The result is a slice of `out_buffer`, from index `0`.
19pub fn getCwd(out_buffer: *[fs.MAX_PATH_BYTES]u8) ![]u8 {
20 return os.getcwd(out_buffer);
21}
22
23/// Caller must free the returned memory.
24pub fn getCwdAlloc(allocator: *Allocator) ![]u8 {
25 var buf: [fs.MAX_PATH_BYTES]u8 = undefined;
26 return mem.dupe(allocator, u8, try os.getcwd(&buf));
27}
28
29test "getCwdAlloc" {
30 // at least call it so it gets compiled
31 var buf: [1000]u8 = undefined;
32 const allocator = &std.heap.FixedBufferAllocator.init(&buf).allocator;
33 _ = getCwdAlloc(allocator) catch undefined;
34}
35
36/// Caller must free result when done.
37/// TODO make this go through libc when we have it
38pub fn getEnvMap(allocator: *Allocator) !BufMap {
39 var result = BufMap.init(allocator);
40 errdefer result.deinit();
41
42 if (os.windows.is_the_target) {
43 const ptr = try os.windows.GetEnvironmentStringsW();
44 defer os.windows.FreeEnvironmentStringsW(ptr);
45
46 var i: usize = 0;
47 while (true) {
48 if (ptr[i] == 0) return result;
49
50 const key_start = i;
51
52 while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
53 const key_w = ptr[key_start..i];
54 const key = try std.unicode.utf16leToUtf8Alloc(allocator, key_w);
55 errdefer allocator.free(key);
56
57 if (ptr[i] == '=') i += 1;
58
59 const value_start = i;
60 while (ptr[i] != 0) : (i += 1) {}
61 const value_w = ptr[value_start..i];
62 const value = try std.unicode.utf16leToUtf8Alloc(allocator, value_w);
63 errdefer allocator.free(value);
64
65 i += 1; // skip over null byte
66
67 try result.setMove(key, value);
68 }
69 } else if (builtin.os == .wasi) {
70 var environ_count: usize = undefined;
71 var environ_buf_size: usize = undefined;
72
73 const environ_sizes_get_ret = os.wasi.environ_sizes_get(&environ_count, &environ_buf_size);
74 if (environ_sizes_get_ret != os.wasi.ESUCCESS) {
75 return os.unexpectedErrno(environ_sizes_get_ret);
76 }
77
78 // TODO: Verify that the documentation is incorrect
79 // https://github.com/WebAssembly/WASI/issues/27
80 var environ = try allocator.alloc(?[*]u8, environ_count + 1);
81 defer allocator.free(environ);
82 var environ_buf = try std.heap.wasm_allocator.alloc(u8, environ_buf_size);
83 defer allocator.free(environ_buf);
84
85 const environ_get_ret = os.wasi.environ_get(environ.ptr, environ_buf.ptr);
86 if (environ_get_ret != os.wasi.ESUCCESS) {
87 return os.unexpectedErrno(environ_get_ret);
88 }
89
90 for (environ) |env| {
91 if (env) |ptr| {
92 const pair = mem.toSlice(u8, ptr);
93 var parts = mem.separate(pair, "=");
94 const key = parts.next().?;
95 const value = parts.next().?;
96 try result.set(key, value);
97 }
98 }
99 return result;
100 } else {
101 for (os.environ) |ptr| {
102 var line_i: usize = 0;
103 while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
104 const key = ptr[0..line_i];
105
106 var end_i: usize = line_i;
107 while (ptr[end_i] != 0) : (end_i += 1) {}
108 const value = ptr[line_i + 1 .. end_i];
109
110 try result.set(key, value);
111 }
112 return result;
113 }
114}
115
116test "os.getEnvMap" {
117 var env = try getEnvMap(std.debug.global_allocator);
118 defer env.deinit();
119}
120
121pub const GetEnvVarOwnedError = error{
122 OutOfMemory,
123 EnvironmentVariableNotFound,
124
125 /// See https://github.com/ziglang/zig/issues/1774
126 InvalidUtf8,
127};
128
129/// Caller must free returned memory.
130/// TODO make this go through libc when we have it
131pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 {
132 if (os.windows.is_the_target) {
133 const key_with_null = try std.unicode.utf8ToUtf16LeWithNull(allocator, key);
134 defer allocator.free(key_with_null);
135
136 var buf = try allocator.alloc(u16, 256);
137 defer allocator.free(buf);
138
139 while (true) {
140 const windows_buf_len = math.cast(os.windows.DWORD, buf.len) catch return error.OutOfMemory;
141 const result = os.windows.GetEnvironmentVariableW(
142 key_with_null.ptr,
143 buf.ptr,
144 windows_buf_len,
145 ) catch |err| switch (err) {
146 error.Unexpected => return error.EnvironmentVariableNotFound,
147 else => |e| return e,
148 };
149
150 if (result > buf.len) {
151 buf = try allocator.realloc(buf, result);
152 continue;
153 }
154
155 return std.unicode.utf16leToUtf8Alloc(allocator, buf) catch |err| switch (err) {
156 error.DanglingSurrogateHalf => return error.InvalidUtf8,
157 error.ExpectedSecondSurrogateHalf => return error.InvalidUtf8,
158 error.UnexpectedSecondSurrogateHalf => return error.InvalidUtf8,
159 else => |e| return e,
160 };
161 }
162 } else {
163 const result = os.getenv(key) orelse return error.EnvironmentVariableNotFound;
164 return mem.dupe(allocator, u8, result);
165 }
166}
167
168test "os.getEnvVarOwned" {
169 var ga = std.debug.global_allocator;
170 testing.expectError(error.EnvironmentVariableNotFound, getEnvVarOwned(ga, "BADENV"));
171}
172
173pub const ArgIteratorPosix = struct {
174 index: usize,
175 count: usize,
176
177 pub fn init() ArgIteratorPosix {
178 return ArgIteratorPosix{
179 .index = 0,
180 .count = os.argv.len,
181 };
182 }
183
184 pub fn next(self: *ArgIteratorPosix) ?[]const u8 {
185 if (self.index == self.count) return null;
186
187 const s = os.argv[self.index];
188 self.index += 1;
189 return mem.toSlice(u8, s);
190 }
191
192 pub fn skip(self: *ArgIteratorPosix) bool {
193 if (self.index == self.count) return false;
194
195 self.index += 1;
196 return true;
197 }
198};
199
200pub const ArgIteratorWindows = struct {
201 index: usize,
202 cmd_line: [*]const u8,
203 in_quote: bool,
204 quote_count: usize,
205 seen_quote_count: usize,
206
207 pub const NextError = error{OutOfMemory};
208
209 pub fn init() ArgIteratorWindows {
210 return initWithCmdLine(os.windows.kernel32.GetCommandLineA());
211 }
212
213 pub fn initWithCmdLine(cmd_line: [*]const u8) ArgIteratorWindows {
214 return ArgIteratorWindows{
215 .index = 0,
216 .cmd_line = cmd_line,
217 .in_quote = false,
218 .quote_count = countQuotes(cmd_line),
219 .seen_quote_count = 0,
220 };
221 }
222
223 /// You must free the returned memory when done.
224 pub fn next(self: *ArgIteratorWindows, allocator: *Allocator) ?(NextError![]u8) {
225 // march forward over whitespace
226 while (true) : (self.index += 1) {
227 const byte = self.cmd_line[self.index];
228 switch (byte) {
229 0 => return null,
230 ' ', '\t' => continue,
231 else => break,
232 }
233 }
234
235 return self.internalNext(allocator);
236 }
237
238 pub fn skip(self: *ArgIteratorWindows) bool {
239 // march forward over whitespace
240 while (true) : (self.index += 1) {
241 const byte = self.cmd_line[self.index];
242 switch (byte) {
243 0 => return false,
244 ' ', '\t' => continue,
245 else => break,
246 }
247 }
248
249 var backslash_count: usize = 0;
250 while (true) : (self.index += 1) {
251 const byte = self.cmd_line[self.index];
252 switch (byte) {
253 0 => return true,
254 '"' => {
255 const quote_is_real = backslash_count % 2 == 0;
256 if (quote_is_real) {
257 self.seen_quote_count += 1;
258 }
259 },
260 '\\' => {
261 backslash_count += 1;
262 },
263 ' ', '\t' => {
264 if (self.seen_quote_count % 2 == 0 or self.seen_quote_count == self.quote_count) {
265 return true;
266 }
267 backslash_count = 0;
268 },
269 else => {
270 backslash_count = 0;
271 continue;
272 },
273 }
274 }
275 }
276
277 fn internalNext(self: *ArgIteratorWindows, allocator: *Allocator) NextError![]u8 {
278 var buf = try Buffer.initSize(allocator, 0);
279 defer buf.deinit();
280
281 var backslash_count: usize = 0;
282 while (true) : (self.index += 1) {
283 const byte = self.cmd_line[self.index];
284 switch (byte) {
285 0 => return buf.toOwnedSlice(),
286 '"' => {
287 const quote_is_real = backslash_count % 2 == 0;
288 try self.emitBackslashes(&buf, backslash_count / 2);
289 backslash_count = 0;
290
291 if (quote_is_real) {
292 self.seen_quote_count += 1;
293 if (self.seen_quote_count == self.quote_count and self.seen_quote_count % 2 == 1) {
294 try buf.appendByte('"');
295 }
296 } else {
297 try buf.appendByte('"');
298 }
299 },
300 '\\' => {
301 backslash_count += 1;
302 },
303 ' ', '\t' => {
304 try self.emitBackslashes(&buf, backslash_count);
305 backslash_count = 0;
306 if (self.seen_quote_count % 2 == 1 and self.seen_quote_count != self.quote_count) {
307 try buf.appendByte(byte);
308 } else {
309 return buf.toOwnedSlice();
310 }
311 },
312 else => {
313 try self.emitBackslashes(&buf, backslash_count);
314 backslash_count = 0;
315 try buf.appendByte(byte);
316 },
317 }
318 }
319 }
320
321 fn emitBackslashes(self: *ArgIteratorWindows, buf: *Buffer, emit_count: usize) !void {
322 var i: usize = 0;
323 while (i < emit_count) : (i += 1) {
324 try buf.appendByte('\\');
325 }
326 }
327
328 fn countQuotes(cmd_line: [*]const u8) usize {
329 var result: usize = 0;
330 var backslash_count: usize = 0;
331 var index: usize = 0;
332 while (true) : (index += 1) {
333 const byte = cmd_line[index];
334 switch (byte) {
335 0 => return result,
336 '\\' => backslash_count += 1,
337 '"' => {
338 result += 1 - (backslash_count % 2);
339 backslash_count = 0;
340 },
341 else => {
342 backslash_count = 0;
343 },
344 }
345 }
346 }
347};
348
349pub const ArgIterator = struct {
350 const InnerType = if (builtin.os == .windows) ArgIteratorWindows else ArgIteratorPosix;
351
352 inner: InnerType,
353
354 pub fn init() ArgIterator {
355 if (builtin.os == .wasi) {
356 // TODO: Figure out a compatible interface accomodating WASI
357 @compileError("ArgIterator is not yet supported in WASI. Use argsAlloc and argsFree instead.");
358 }
359
360 return ArgIterator{ .inner = InnerType.init() };
361 }
362
363 pub const NextError = ArgIteratorWindows.NextError;
364
365 /// You must free the returned memory when done.
366 pub fn next(self: *ArgIterator, allocator: *Allocator) ?(NextError![]u8) {
367 if (builtin.os == .windows) {
368 return self.inner.next(allocator);
369 } else {
370 return mem.dupe(allocator, u8, self.inner.next() orelse return null);
371 }
372 }
373
374 /// If you only are targeting posix you can call this and not need an allocator.
375 pub fn nextPosix(self: *ArgIterator) ?[]const u8 {
376 return self.inner.next();
377 }
378
379 /// Parse past 1 argument without capturing it.
380 /// Returns `true` if skipped an arg, `false` if we are at the end.
381 pub fn skip(self: *ArgIterator) bool {
382 return self.inner.skip();
383 }
384};
385
386pub fn args() ArgIterator {
387 return ArgIterator.init();
388}
389
390/// Caller must call argsFree on result.
391pub fn argsAlloc(allocator: *mem.Allocator) ![]const []u8 {
392 if (builtin.os == .wasi) {
393 var count: usize = undefined;
394 var buf_size: usize = undefined;
395
396 const args_sizes_get_ret = os.wasi.args_sizes_get(&count, &buf_size);
397 if (args_sizes_get_ret != os.wasi.ESUCCESS) {
398 return os.unexpectedErrno(args_sizes_get_ret);
399 }
400
401 var argv = try allocator.alloc([*]u8, count);
402 defer allocator.free(argv);
403
404 var argv_buf = try allocator.alloc(u8, buf_size);
405 const args_get_ret = os.wasi.args_get(argv.ptr, argv_buf.ptr);
406 if (args_get_ret != os.wasi.ESUCCESS) {
407 return os.unexpectedErrno(args_get_ret);
408 }
409
410 var result_slice = try allocator.alloc([]u8, count);
411
412 var i: usize = 0;
413 while (i < count) : (i += 1) {
414 result_slice[i] = mem.toSlice(u8, argv[i]);
415 }
416
417 return result_slice;
418 }
419
420 // TODO refactor to only make 1 allocation.
421 var it = args();
422 var contents = try Buffer.initSize(allocator, 0);
423 defer contents.deinit();
424
425 var slice_list = std.ArrayList(usize).init(allocator);
426 defer slice_list.deinit();
427
428 while (it.next(allocator)) |arg_or_err| {
429 const arg = try arg_or_err;
430 defer allocator.free(arg);
431 try contents.append(arg);
432 try slice_list.append(arg.len);
433 }
434
435 const contents_slice = contents.toSliceConst();
436 const slice_sizes = slice_list.toSliceConst();
437 const slice_list_bytes = try math.mul(usize, @sizeOf([]u8), slice_sizes.len);
438 const total_bytes = try math.add(usize, slice_list_bytes, contents_slice.len);
439 const buf = try allocator.alignedAlloc(u8, @alignOf([]u8), total_bytes);
440 errdefer allocator.free(buf);
441
442 const result_slice_list = @bytesToSlice([]u8, buf[0..slice_list_bytes]);
443 const result_contents = buf[slice_list_bytes..];
444 mem.copy(u8, result_contents, contents_slice);
445
446 var contents_index: usize = 0;
447 for (slice_sizes) |len, i| {
448 const new_index = contents_index + len;
449 result_slice_list[i] = result_contents[contents_index..new_index];
450 contents_index = new_index;
451 }
452
453 return result_slice_list;
454}
455
456pub fn argsFree(allocator: *mem.Allocator, args_alloc: []const []u8) void {
457 if (builtin.os == .wasi) {
458 const last_item = args_alloc[args_alloc.len - 1];
459 const last_byte_addr = @ptrToInt(last_item.ptr) + last_item.len + 1; // null terminated
460 const first_item_ptr = args_alloc[0].ptr;
461 const len = last_byte_addr - @ptrToInt(first_item_ptr);
462 allocator.free(first_item_ptr[0..len]);
463
464 return allocator.free(args_alloc);
465 }
466
467 var total_bytes: usize = 0;
468 for (args_alloc) |arg| {
469 total_bytes += @sizeOf([]u8) + arg.len;
470 }
471 const unaligned_allocated_buf = @ptrCast([*]const u8, args_alloc.ptr)[0..total_bytes];
472 const aligned_allocated_buf = @alignCast(@alignOf([]u8), unaligned_allocated_buf);
473 return allocator.free(aligned_allocated_buf);
474}
475
476test "windows arg parsing" {
477 testWindowsCmdLine(c"a b\tc d", [][]const u8{ "a", "b", "c", "d" });
478 testWindowsCmdLine(c"\"abc\" d e", [][]const u8{ "abc", "d", "e" });
479 testWindowsCmdLine(c"a\\\\\\b d\"e f\"g h", [][]const u8{ "a\\\\\\b", "de fg", "h" });
480 testWindowsCmdLine(c"a\\\\\\\"b c d", [][]const u8{ "a\\\"b", "c", "d" });
481 testWindowsCmdLine(c"a\\\\\\\\\"b c\" d e", [][]const u8{ "a\\\\b c", "d", "e" });
482 testWindowsCmdLine(c"a b\tc \"d f", [][]const u8{ "a", "b", "c", "\"d", "f" });
483
484 testWindowsCmdLine(c"\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", [][]const u8{
485 ".\\..\\zig-cache\\build",
486 "bin\\zig.exe",
487 ".\\..",
488 ".\\..\\zig-cache",
489 "--help",
490 });
491}
492
493fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []const u8) void {
494 var it = ArgIteratorWindows.initWithCmdLine(input_cmd_line);
495 for (expected_args) |expected_arg| {
496 const arg = it.next(std.debug.global_allocator).? catch unreachable;
497 testing.expectEqualSlices(u8, expected_arg, arg);
498 }
499 testing.expect(it.next(std.debug.global_allocator) == null);
500}
501
502pub const UserInfo = struct {
503 uid: u32,
504 gid: u32,
505};
506
507/// POSIX function which gets a uid from username.
508pub fn getUserInfo(name: []const u8) !UserInfo {
509 return switch (builtin.os) {
510 .linux, .macosx, .watchos, .tvos, .ios, .freebsd, .netbsd => posixGetUserInfo(name),
511 else => @compileError("Unsupported OS"),
512 };
513}
514
515/// TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else
516/// like NIS, AD, etc. See `man nss` or look at an strace for `id myuser`.
517pub fn posixGetUserInfo(name: []const u8) !UserInfo {
518 var in_stream = try io.InStream.open("/etc/passwd", null);
519 defer in_stream.close();
520
521 const State = enum {
522 Start,
523 WaitForNextLine,
524 SkipPassword,
525 ReadUserId,
526 ReadGroupId,
527 };
528
529 var buf: [std.mem.page_size]u8 = undefined;
530 var name_index: usize = 0;
531 var state = State.Start;
532 var uid: u32 = 0;
533 var gid: u32 = 0;
534
535 while (true) {
536 const amt_read = try in_stream.read(buf[0..]);
537 for (buf[0..amt_read]) |byte| {
538 switch (state) {
539 .Start => switch (byte) {
540 ':' => {
541 state = if (name_index == name.len) State.SkipPassword else State.WaitForNextLine;
542 },
543 '\n' => return error.CorruptPasswordFile,
544 else => {
545 if (name_index == name.len or name[name_index] != byte) {
546 state = .WaitForNextLine;
547 }
548 name_index += 1;
549 },
550 },
551 .WaitForNextLine => switch (byte) {
552 '\n' => {
553 name_index = 0;
554 state = .Start;
555 },
556 else => continue,
557 },
558 .SkipPassword => switch (byte) {
559 '\n' => return error.CorruptPasswordFile,
560 ':' => {
561 state = .ReadUserId;
562 },
563 else => continue,
564 },
565 .ReadUserId => switch (byte) {
566 ':' => {
567 state = .ReadGroupId;
568 },
569 '\n' => return error.CorruptPasswordFile,
570 else => {
571 const digit = switch (byte) {
572 '0'...'9' => byte - '0',
573 else => return error.CorruptPasswordFile,
574 };
575 if (@mulWithOverflow(u32, uid, 10, *uid)) return error.CorruptPasswordFile;
576 if (@addWithOverflow(u32, uid, digit, *uid)) return error.CorruptPasswordFile;
577 },
578 },
579 .ReadGroupId => switch (byte) {
580 '\n', ':' => {
581 return UserInfo{
582 .uid = uid,
583 .gid = gid,
584 };
585 },
586 else => {
587 const digit = switch (byte) {
588 '0'...'9' => byte - '0',
589 else => return error.CorruptPasswordFile,
590 };
591 if (@mulWithOverflow(u32, gid, 10, *gid)) return error.CorruptPasswordFile;
592 if (@addWithOverflow(u32, gid, digit, *gid)) return error.CorruptPasswordFile;
593 },
594 },
595 }
596 }
597 if (amt_read < buf.len) return error.UserNotFound;
598 }
599}
600
601pub fn getBaseAddress() usize {
602 switch (builtin.os) {
603 .linux => {
604 const base = os.system.getauxval(std.elf.AT_BASE);
605 if (base != 0) {
606 return base;
607 }
608 const phdr = os.system.getauxval(std.elf.AT_PHDR);
609 return phdr - @sizeOf(std.elf.Ehdr);
610 },
611 .macosx, .freebsd, .netbsd => {
612 return @ptrToInt(&std.c._mh_execute_header);
613 },
614 .windows => return @ptrToInt(os.windows.kernel32.GetModuleHandleW(null)),
615 else => @compileError("Unsupported OS"),
616 }
617}
std/rand.zig+3-3
...@@ -1,10 +1,10 @@...@@ -1,10 +1,10 @@
1// The engines provided here should be initialized from an external source. For now, getRandomBytes1// The engines provided here should be initialized from an external source. For now, randomBytes
2// from the os package is the most suitable. Be sure to use a CSPRNG when required, otherwise using2// from the crypto package is the most suitable. Be sure to use a CSPRNG when required, otherwise using
3// a normal PRNG will be faster and use substantially less stack space.3// a normal PRNG will be faster and use substantially less stack space.
4//4//
5// ```5// ```
6// var buf: [8]u8 = undefined;6// var buf: [8]u8 = undefined;
7// try std.os.getRandomBytes(buf[0..]);7// try std.crypto.randomBytes(buf[0..]);
8// const seed = mem.readIntSliceLittle(u64, buf[0..8]);8// const seed = mem.readIntSliceLittle(u64, buf[0..8]);
9//9//
10// var r = DefaultPrng.init(seed);10// var r = DefaultPrng.init(seed);
std/special/bootstrap.zig+6-6
...@@ -62,7 +62,7 @@ extern fn WinMainCRTStartup() noreturn {...@@ -62,7 +62,7 @@ extern fn WinMainCRTStartup() noreturn {
62 if (!builtin.single_threaded) {62 if (!builtin.single_threaded) {
63 _ = @import("bootstrap_windows_tls.zig");63 _ = @import("bootstrap_windows_tls.zig");
64 }64 }
65 std.os.windows.ExitProcess(callMain());65 std.os.windows.kernel32.ExitProcess(callMain());
66}66}
6767
68// TODO https://github.com/ziglang/zig/issues/26568// TODO https://github.com/ziglang/zig/issues/265
...@@ -78,10 +78,10 @@ fn posixCallMainAndExit() noreturn {...@@ -78,10 +78,10 @@ fn posixCallMainAndExit() noreturn {
78 while (envp_optional[envp_count]) |_| : (envp_count += 1) {}78 while (envp_optional[envp_count]) |_| : (envp_count += 1) {}
79 const envp = @ptrCast([*][*]u8, envp_optional)[0..envp_count];79 const envp = @ptrCast([*][*]u8, envp_optional)[0..envp_count];
8080
81 if (builtin.os == builtin.Os.linux) {81 if (builtin.os == .linux) {
82 // Find the beginning of the auxiliary vector82 // Find the beginning of the auxiliary vector
83 const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1);83 const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1);
84 std.os.linux_elf_aux_maybe = auxv;84 std.os.linux.elf_aux_maybe = auxv;
85 // Initialize the TLS area85 // Initialize the TLS area
86 std.os.linux.tls.initTLS();86 std.os.linux.tls.initTLS();
8787
...@@ -92,14 +92,14 @@ fn posixCallMainAndExit() noreturn {...@@ -92,14 +92,14 @@ fn posixCallMainAndExit() noreturn {
92 }92 }
93 }93 }
9494
95 std.os.posix.exit(callMainWithArgs(argc, argv, envp));95 std.os.exit(callMainWithArgs(argc, argv, envp));
96}96}
9797
98// This is marked inline because for some reason LLVM in release mode fails to inline it,98// This is marked inline because for some reason LLVM in release mode fails to inline it,
99// and we want fewer call frames in stack traces.99// and we want fewer call frames in stack traces.
100inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 {100inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 {
101 std.os.ArgIteratorPosix.raw = argv[0..argc];101 std.os.argv = argv[0..argc];
102 std.os.posix_environ_raw = envp;102 std.os.environ = envp;
103 return callMain();103 return callMain();
104}104}
105105
std/special/build_runner.zig+7-6
...@@ -3,14 +3,15 @@ const std = @import("std");...@@ -3,14 +3,15 @@ const std = @import("std");
3const builtin = @import("builtin");3const builtin = @import("builtin");
4const io = std.io;4const io = std.io;
5const fmt = std.fmt;5const fmt = std.fmt;
6const os = std.os;
7const Builder = std.build.Builder;6const Builder = std.build.Builder;
8const mem = std.mem;7const mem = std.mem;
8const process = std.process;
9const ArrayList = std.ArrayList;9const ArrayList = std.ArrayList;
10const warn = std.debug.warn;10const warn = std.debug.warn;
11const File = std.fs.File;
1112
12pub fn main() !void {13pub fn main() !void {
13 var arg_it = os.args();14 var arg_it = process.args();
1415
15 // Here we use an ArenaAllocator backed by a DirectAllocator because a build is a short-lived,16 // Here we use an ArenaAllocator backed by a DirectAllocator because a build is a short-lived,
16 // one shot program. We don't need to waste time freeing memory and finding places to squish17 // 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 {...@@ -48,14 +49,14 @@ pub fn main() !void {
48 var prefix: ?[]const u8 = null;49 var prefix: ?[]const u8 = null;
4950
50 var stderr_file = io.getStdErr();51 var stderr_file = io.getStdErr();
51 var stderr_file_stream: os.File.OutStream = undefined;52 var stderr_file_stream: File.OutStream = undefined;
52 var stderr_stream = if (stderr_file) |f| x: {53 var stderr_stream = if (stderr_file) |f| x: {
53 stderr_file_stream = f.outStream();54 stderr_file_stream = f.outStream();
54 break :x &stderr_file_stream.stream;55 break :x &stderr_file_stream.stream;
55 } else |err| err;56 } else |err| err;
5657
57 var stdout_file = io.getStdOut();58 var stdout_file = io.getStdOut();
58 var stdout_file_stream: os.File.OutStream = undefined;59 var stdout_file_stream: File.OutStream = undefined;
59 var stdout_stream = if (stdout_file) |f| x: {60 var stdout_stream = if (stdout_file) |f| x: {
60 stdout_file_stream = f.outStream();61 stdout_file_stream = f.outStream();
61 break :x &stdout_file_stream.stream;62 break :x &stdout_file_stream.stream;
...@@ -138,7 +139,7 @@ pub fn main() !void {...@@ -138,7 +139,7 @@ pub fn main() !void {
138 error.InvalidStepName => {139 error.InvalidStepName => {
139 return usageAndErr(&builder, true, try stderr_stream);140 return usageAndErr(&builder, true, try stderr_stream);
140 },141 },
141 error.UncleanExit => os.exit(1),142 error.UncleanExit => process.exit(1),
142 else => return err,143 else => return err,
143 }144 }
144 };145 };
...@@ -214,7 +215,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {...@@ -214,7 +215,7 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {
214215
215fn usageAndErr(builder: *Builder, already_ran_build: bool, out_stream: var) void {216fn usageAndErr(builder: *Builder, already_ran_build: bool, out_stream: var) void {
216 usage(builder, already_ran_build, out_stream) catch {};217 usage(builder, already_ran_build, out_stream) catch {};
217 os.exit(1);218 process.exit(1);
218}219}
219220
220const UnwrapArgError = error{OutOfMemory};221const UnwrapArgError = error{OutOfMemory};
std/statically_initialized_mutex.zig+8-8
...@@ -23,7 +23,7 @@ pub const StaticallyInitializedMutex = switch (builtin.os) {...@@ -23,7 +23,7 @@ pub const StaticallyInitializedMutex = switch (builtin.os) {
23 mutex: *StaticallyInitializedMutex,23 mutex: *StaticallyInitializedMutex,
2424
25 pub fn release(self: Held) void {25 pub fn release(self: Held) void {
26 windows.LeaveCriticalSection(&self.mutex.lock);26 windows.kernel32.LeaveCriticalSection(&self.mutex.lock);
27 }27 }
28 };28 };
2929
...@@ -40,20 +40,20 @@ pub const StaticallyInitializedMutex = switch (builtin.os) {...@@ -40,20 +40,20 @@ pub const StaticallyInitializedMutex = switch (builtin.os) {
40 Context: ?*c_void,40 Context: ?*c_void,
41 ) windows.BOOL {41 ) windows.BOOL {
42 const lock = @ptrCast(*windows.CRITICAL_SECTION, @alignCast(@alignOf(windows.CRITICAL_SECTION), Parameter));42 const lock = @ptrCast(*windows.CRITICAL_SECTION, @alignCast(@alignOf(windows.CRITICAL_SECTION), Parameter));
43 windows.InitializeCriticalSection(lock);43 windows.kernel32.InitializeCriticalSection(lock);
44 return windows.TRUE;44 return windows.TRUE;
45 }45 }
4646
47 /// TODO: once https://github.com/ziglang/zig/issues/287 is solved and std.Mutex has a better47 /// TODO: once https://github.com/ziglang/zig/issues/287 is solved and std.Mutex has a better
48 /// implementation of a runtime initialized mutex, remove this function.48 /// implementation of a runtime initialized mutex, remove this function.
49 pub fn deinit(self: *StaticallyInitializedMutex) void {49 pub fn deinit(self: *StaticallyInitializedMutex) void {
50 assert(windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, &self.lock, null) != 0);50 windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, &self.lock, null);
51 windows.DeleteCriticalSection(&self.lock);51 windows.kernel32.DeleteCriticalSection(&self.lock);
52 }52 }
5353
54 pub fn acquire(self: *StaticallyInitializedMutex) Held {54 pub fn acquire(self: *StaticallyInitializedMutex) Held {
55 assert(windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, &self.lock, null) != 0);55 windows.InitOnceExecuteOnce(&self.init_once, initCriticalSection, &self.lock, null);
56 windows.EnterCriticalSection(&self.lock);56 windows.kernel32.EnterCriticalSection(&self.lock);
57 return Held{ .mutex = self };57 return Held{ .mutex = self };
58 }58 }
59 },59 },
...@@ -96,9 +96,9 @@ test "std.StaticallyInitializedMutex" {...@@ -96,9 +96,9 @@ test "std.StaticallyInitializedMutex" {
96 expect(context.data == TestContext.incr_count);96 expect(context.data == TestContext.incr_count);
97 } else {97 } else {
98 const thread_count = 10;98 const thread_count = 10;
99 var threads: [thread_count]*std.os.Thread = undefined;99 var threads: [thread_count]*std.Thread = undefined;
100 for (threads) |*t| {100 for (threads) |*t| {
101 t.* = try std.os.spawnThread(&context, TestContext.worker);101 t.* = try std.Thread.spawn(&context, TestContext.worker);
102 }102 }
103 for (threads) |t|103 for (threads) |t|
104 t.wait();104 t.wait();
std/std.zig+10
...@@ -17,6 +17,8 @@ pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;...@@ -17,6 +17,8 @@ pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
17pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex;17pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex;
18pub const SegmentedList = @import("segmented_list.zig").SegmentedList;18pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
19pub const SpinLock = @import("spinlock.zig").SpinLock;19pub const SpinLock = @import("spinlock.zig").SpinLock;
20pub const ChildProcess = @import("child_process.zig").ChildProcess;
21pub const Thread = @import("thread.zig").Thread;
2022
21pub const atomic = @import("atomic.zig");23pub const atomic = @import("atomic.zig");
22pub const base64 = @import("base64.zig");24pub const base64 = @import("base64.zig");
...@@ -30,6 +32,7 @@ pub const dwarf = @import("dwarf.zig");...@@ -30,6 +32,7 @@ pub const dwarf = @import("dwarf.zig");
30pub const elf = @import("elf.zig");32pub const elf = @import("elf.zig");
31pub const event = @import("event.zig");33pub const event = @import("event.zig");
32pub const fmt = @import("fmt.zig");34pub const fmt = @import("fmt.zig");
35pub const fs = @import("fs.zig");
33pub const hash = @import("hash.zig");36pub const hash = @import("hash.zig");
34pub const hash_map = @import("hash_map.zig");37pub const hash_map = @import("hash_map.zig");
35pub const heap = @import("heap.zig");38pub const heap = @import("heap.zig");
...@@ -43,11 +46,13 @@ pub const meta = @import("meta.zig");...@@ -43,11 +46,13 @@ pub const meta = @import("meta.zig");
43pub const net = @import("net.zig");46pub const net = @import("net.zig");
44pub const os = @import("os.zig");47pub const os = @import("os.zig");
45pub const pdb = @import("pdb.zig");48pub const pdb = @import("pdb.zig");
49pub const process = @import("process.zig");
46pub const rand = @import("rand.zig");50pub const rand = @import("rand.zig");
47pub const rb = @import("rb.zig");51pub const rb = @import("rb.zig");
48pub const sort = @import("sort.zig");52pub const sort = @import("sort.zig");
49pub const ascii = @import("ascii.zig");53pub const ascii = @import("ascii.zig");
50pub const testing = @import("testing.zig");54pub const testing = @import("testing.zig");
55pub const time = @import("time.zig");
51pub const unicode = @import("unicode.zig");56pub const unicode = @import("unicode.zig");
52pub const valgrind = @import("valgrind.zig");57pub const valgrind = @import("valgrind.zig");
53pub const zig = @import("zig.zig");58pub const zig = @import("zig.zig");
...@@ -65,6 +70,7 @@ test "std" {...@@ -65,6 +70,7 @@ test "std" {
65 _ = @import("statically_initialized_mutex.zig");70 _ = @import("statically_initialized_mutex.zig");
66 _ = @import("segmented_list.zig");71 _ = @import("segmented_list.zig");
67 _ = @import("spinlock.zig");72 _ = @import("spinlock.zig");
73 _ = @import("child_process.zig");
6874
69 _ = @import("ascii.zig");75 _ = @import("ascii.zig");
70 _ = @import("base64.zig");76 _ = @import("base64.zig");
...@@ -79,6 +85,7 @@ test "std" {...@@ -79,6 +85,7 @@ test "std" {
79 _ = @import("elf.zig");85 _ = @import("elf.zig");
80 _ = @import("event.zig");86 _ = @import("event.zig");
81 _ = @import("fmt.zig");87 _ = @import("fmt.zig");
88 _ = @import("fs.zig");
82 _ = @import("hash.zig");89 _ = @import("hash.zig");
83 _ = @import("heap.zig");90 _ = @import("heap.zig");
84 _ = @import("io.zig");91 _ = @import("io.zig");
...@@ -91,11 +98,14 @@ test "std" {...@@ -91,11 +98,14 @@ test "std" {
91 _ = @import("net.zig");98 _ = @import("net.zig");
92 _ = @import("os.zig");99 _ = @import("os.zig");
93 _ = @import("pdb.zig");100 _ = @import("pdb.zig");
101 _ = @import("process.zig");
94 _ = @import("packed_int_array.zig");102 _ = @import("packed_int_array.zig");
95 _ = @import("priority_queue.zig");103 _ = @import("priority_queue.zig");
96 _ = @import("rand.zig");104 _ = @import("rand.zig");
97 _ = @import("sort.zig");105 _ = @import("sort.zig");
98 _ = @import("testing.zig");106 _ = @import("testing.zig");
107 _ = @import("thread.zig");
108 _ = @import("time.zig");
99 _ = @import("unicode.zig");109 _ = @import("unicode.zig");
100 _ = @import("valgrind.zig");110 _ = @import("valgrind.zig");
101 _ = @import("zig.zig");111 _ = @import("zig.zig");
std/thread.zig created+349
...@@ -0,0 +1,349 @@
1const builtin = @import("builtin");
2const std = @import("std.zig");
3const os = std.os;
4const mem = std.mem;
5const windows = std.os.windows;
6const c = std.c;
7const assert = std.debug.assert;
8
9pub const Thread = struct {
10 data: Data,
11
12 pub const use_pthreads = !windows.is_the_target and builtin.link_libc;
13
14 /// Represents a kernel thread handle.
15 /// May be an integer or a pointer depending on the platform.
16 /// On Linux and POSIX, this is the same as Id.
17 pub const Handle = if (use_pthreads)
18 c.pthread_t
19 else switch (builtin.os) {
20 .linux => i32,
21 .windows => windows.HANDLE,
22 else => @compileError("Unsupported OS"),
23 };
24
25 /// Represents a unique ID per thread.
26 /// May be an integer or pointer depending on the platform.
27 /// On Linux and POSIX, this is the same as Handle.
28 pub const Id = switch (builtin.os) {
29 .windows => windows.DWORD,
30 else => Handle,
31 };
32
33 pub const Data = if (use_pthreads)
34 struct {
35 handle: Thread.Handle,
36 memory: []align(mem.page_size) u8,
37 }
38 else switch (builtin.os) {
39 .linux => struct {
40 handle: Thread.Handle,
41 memory: []align(mem.page_size) u8,
42 },
43 .windows => struct {
44 handle: Thread.Handle,
45 alloc_start: *c_void,
46 heap_handle: windows.HANDLE,
47 },
48 else => @compileError("Unsupported OS"),
49 };
50
51 /// Returns the ID of the calling thread.
52 /// Makes a syscall every time the function is called.
53 /// On Linux and POSIX, this Id is the same as a Handle.
54 pub fn getCurrentId() Id {
55 if (use_pthreads) {
56 return c.pthread_self();
57 } else
58 return switch (builtin.os) {
59 .linux => os.linux.gettid(),
60 .windows => windows.kernel32.GetCurrentThreadId(),
61 else => @compileError("Unsupported OS"),
62 };
63 }
64
65 /// Returns the handle of this thread.
66 /// On Linux and POSIX, this is the same as Id.
67 /// On Linux, it is possible that the thread spawned with `spawn`
68 /// finishes executing entirely before the clone syscall completes. In this
69 /// case, this function will return 0 rather than the no-longer-existing thread's
70 /// pid.
71 pub fn handle(self: Thread) Handle {
72 return self.data.handle;
73 }
74
75 pub fn wait(self: *const Thread) void {
76 if (use_pthreads) {
77 const err = c.pthread_join(self.data.handle, null);
78 switch (err) {
79 0 => {},
80 os.EINVAL => unreachable,
81 os.ESRCH => unreachable,
82 os.EDEADLK => unreachable,
83 else => unreachable,
84 }
85 os.munmap(self.data.memory);
86 } else switch (builtin.os) {
87 .linux => {
88 while (true) {
89 const pid_value = @atomicLoad(i32, &self.data.handle, .SeqCst);
90 if (pid_value == 0) break;
91 const rc = os.linux.futex_wait(&self.data.handle, os.linux.FUTEX_WAIT, pid_value, null);
92 switch (os.linux.getErrno(rc)) {
93 0 => continue,
94 os.EINTR => continue,
95 os.EAGAIN => continue,
96 else => unreachable,
97 }
98 }
99 os.munmap(self.data.memory);
100 },
101 .windows => {
102 windows.WaitForSingleObject(self.data.handle, windows.INFINITE) catch unreachable;
103 windows.CloseHandle(self.data.handle);
104 windows.HeapFree(self.data.heap_handle, 0, self.data.alloc_start);
105 },
106 else => @compileError("Unsupported OS"),
107 }
108 }
109
110 pub const SpawnError = error{
111 /// A system-imposed limit on the number of threads was encountered.
112 /// There are a number of limits that may trigger this error:
113 /// * the RLIMIT_NPROC soft resource limit (set via setrlimit(2)),
114 /// which limits the number of processes and threads for a real
115 /// user ID, was reached;
116 /// * the kernel's system-wide limit on the number of processes and
117 /// threads, /proc/sys/kernel/threads-max, was reached (see
118 /// proc(5));
119 /// * the maximum number of PIDs, /proc/sys/kernel/pid_max, was
120 /// reached (see proc(5)); or
121 /// * the PID limit (pids.max) imposed by the cgroup "process num‐
122 /// ber" (PIDs) controller was reached.
123 ThreadQuotaExceeded,
124
125 /// The kernel cannot allocate sufficient memory to allocate a task structure
126 /// for the child, or to copy those parts of the caller's context that need to
127 /// be copied.
128 SystemResources,
129
130 /// Not enough userland memory to spawn the thread.
131 OutOfMemory,
132
133 /// `mlockall` is enabled, and the memory needed to spawn the thread
134 /// would exceed the limit.
135 LockedMemoryLimitExceeded,
136
137 Unexpected,
138 };
139
140 /// caller must call wait on the returned thread
141 /// fn startFn(@typeOf(context)) T
142 /// where T is u8, noreturn, void, or !void
143 /// caller must call wait on the returned thread
144 pub fn spawn(context: var, comptime startFn: var) SpawnError!*Thread {
145 if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode");
146 // TODO compile-time call graph analysis to determine stack upper bound
147 // https://github.com/ziglang/zig/issues/157
148 const default_stack_size = 8 * 1024 * 1024;
149
150 const Context = @typeOf(context);
151 comptime assert(@ArgType(@typeOf(startFn), 0) == Context);
152
153 if (builtin.os == builtin.Os.windows) {
154 const WinThread = struct {
155 const OuterContext = struct {
156 thread: Thread,
157 inner: Context,
158 };
159 extern fn threadMain(raw_arg: windows.LPVOID) windows.DWORD {
160 const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*;
161 switch (@typeId(@typeOf(startFn).ReturnType)) {
162 .Int => {
163 return startFn(arg);
164 },
165 .Void => {
166 startFn(arg);
167 return 0;
168 },
169 else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"),
170 }
171 }
172 };
173
174 const heap_handle = windows.kernel32.GetProcessHeap() orelse return error.OutOfMemory;
175 const byte_count = @alignOf(WinThread.OuterContext) + @sizeOf(WinThread.OuterContext);
176 const bytes_ptr = windows.kernel32.HeapAlloc(heap_handle, 0, byte_count) orelse return error.OutOfMemory;
177 errdefer assert(windows.kernel32.HeapFree(heap_handle, 0, bytes_ptr) != 0);
178 const bytes = @ptrCast([*]u8, bytes_ptr)[0..byte_count];
179 const outer_context = std.heap.FixedBufferAllocator.init(bytes).allocator.create(WinThread.OuterContext) catch unreachable;
180 outer_context.* = WinThread.OuterContext{
181 .thread = Thread{
182 .data = Thread.Data{
183 .heap_handle = heap_handle,
184 .alloc_start = bytes_ptr,
185 .handle = undefined,
186 },
187 },
188 .inner = context,
189 };
190
191 const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner);
192 outer_context.thread.data.handle = windows.kernel32.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse {
193 switch (windows.kernel32.GetLastError()) {
194 else => |err| return windows.unexpectedError(err),
195 }
196 };
197 return &outer_context.thread;
198 }
199
200 const MainFuncs = struct {
201 extern fn linuxThreadMain(ctx_addr: usize) u8 {
202 const arg = if (@sizeOf(Context) == 0) {} else @intToPtr(*const Context, ctx_addr).*;
203
204 switch (@typeId(@typeOf(startFn).ReturnType)) {
205 .Int => {
206 return startFn(arg);
207 },
208 .Void => {
209 startFn(arg);
210 return 0;
211 },
212 else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"),
213 }
214 }
215 extern fn posixThreadMain(ctx: ?*c_void) ?*c_void {
216 if (@sizeOf(Context) == 0) {
217 _ = startFn({});
218 return null;
219 } else {
220 _ = startFn(@ptrCast(*const Context, @alignCast(@alignOf(Context), ctx)).*);
221 return null;
222 }
223 }
224 };
225
226 const MAP_GROWSDOWN = if (os.linux.is_the_target) os.linux.MAP_GROWSDOWN else 0;
227
228 var stack_end_offset: usize = undefined;
229 var thread_start_offset: usize = undefined;
230 var context_start_offset: usize = undefined;
231 var tls_start_offset: usize = undefined;
232 const mmap_len = blk: {
233 // First in memory will be the stack, which grows downwards.
234 var l: usize = mem.alignForward(default_stack_size, mem.page_size);
235 stack_end_offset = l;
236 // Above the stack, so that it can be in the same mmap call, put the Thread object.
237 l = mem.alignForward(l, @alignOf(Thread));
238 thread_start_offset = l;
239 l += @sizeOf(Thread);
240 // Next, the Context object.
241 if (@sizeOf(Context) != 0) {
242 l = mem.alignForward(l, @alignOf(Context));
243 context_start_offset = l;
244 l += @sizeOf(Context);
245 }
246 // Finally, the Thread Local Storage, if any.
247 if (!Thread.use_pthreads) {
248 if (os.linux.tls.tls_image) |tls_img| {
249 l = mem.alignForward(l, @alignOf(usize));
250 tls_start_offset = l;
251 l += tls_img.alloc_size;
252 }
253 }
254 break :blk l;
255 };
256 const mmap_slice = os.mmap(
257 null,
258 mem.alignForward(mmap_len, mem.page_size),
259 os.PROT_READ | os.PROT_WRITE,
260 os.MAP_PRIVATE | os.MAP_ANONYMOUS | MAP_GROWSDOWN,
261 -1,
262 0,
263 ) catch |err| switch (err) {
264 error.MemoryMappingNotSupported => unreachable, // no file descriptor
265 error.AccessDenied => unreachable, // no file descriptor
266 error.PermissionDenied => unreachable, // no file descriptor
267 else => |e| return e,
268 };
269 errdefer os.munmap(mmap_slice);
270 const mmap_addr = @ptrToInt(mmap_slice.ptr);
271
272 const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(*Thread, mmap_addr + thread_start_offset));
273 thread_ptr.data.memory = mmap_slice;
274
275 var arg: usize = undefined;
276 if (@sizeOf(Context) != 0) {
277 arg = mmap_addr + context_start_offset;
278 const context_ptr = @alignCast(@alignOf(Context), @intToPtr(*Context, arg));
279 context_ptr.* = context;
280 }
281
282 if (Thread.use_pthreads) {
283 // use pthreads
284 var attr: c.pthread_attr_t = undefined;
285 if (c.pthread_attr_init(&attr) != 0) return error.SystemResources;
286 defer assert(c.pthread_attr_destroy(&attr) == 0);
287
288 assert(c.pthread_attr_setstack(&attr, mmap_slice.ptr, stack_end_offset) == 0);
289
290 const err = c.pthread_create(&thread_ptr.data.handle, &attr, MainFuncs.posixThreadMain, @intToPtr(*c_void, arg));
291 switch (err) {
292 0 => return thread_ptr,
293 os.EAGAIN => return error.SystemResources,
294 os.EPERM => unreachable,
295 os.EINVAL => unreachable,
296 else => return os.unexpectedErrno(@intCast(usize, err)),
297 }
298 } else if (os.linux.is_the_target) {
299 var flags: u32 = os.CLONE_VM | os.CLONE_FS | os.CLONE_FILES | os.CLONE_SIGHAND |
300 os.CLONE_THREAD | os.CLONE_SYSVSEM | os.CLONE_PARENT_SETTID | os.CLONE_CHILD_CLEARTID |
301 os.CLONE_DETACHED;
302 var newtls: usize = undefined;
303 if (os.linux.tls.tls_image) |tls_img| {
304 newtls = os.linux.tls.copyTLS(mmap_addr + tls_start_offset);
305 flags |= os.CLONE_SETTLS;
306 }
307 const rc = os.linux.clone(MainFuncs.linuxThreadMain, mmap_addr + stack_end_offset, flags, arg, &thread_ptr.data.handle, newtls, &thread_ptr.data.handle);
308 switch (os.errno(rc)) {
309 0 => return thread_ptr,
310 os.EAGAIN => return error.ThreadQuotaExceeded,
311 os.EINVAL => unreachable,
312 os.ENOMEM => return error.SystemResources,
313 os.ENOSPC => unreachable,
314 os.EPERM => unreachable,
315 os.EUSERS => unreachable,
316 else => |err| return os.unexpectedErrno(err),
317 }
318 } else {
319 @compileError("Unsupported OS");
320 }
321 }
322
323 pub const CpuCountError = error{
324 OutOfMemory,
325 PermissionDenied,
326 SystemResources,
327 Unexpected,
328 };
329
330 pub fn cpuCount() CpuCountError!usize {
331 if (os.linux.is_the_target) {
332 const cpu_set = try os.sched_getaffinity(0);
333 return usize(os.CPU_COUNT(cpu_set)); // TODO should not need this usize cast
334 }
335 if (os.windows.is_the_target) {
336 var system_info: windows.SYSTEM_INFO = undefined;
337 windows.kernel32.GetSystemInfo(&system_info);
338 return @intCast(usize, system_info.dwNumberOfProcessors);
339 }
340 var count: c_int = undefined;
341 var count_len: usize = @sizeOf(c_int);
342 const name = if (os.darwin.is_the_target) c"hw.logicalcpu" else c"hw.ncpu";
343 os.sysctlbynameC(name, &count, &count_len, null, 0) catch |err| switch (err) {
344 error.NameTooLong => unreachable,
345 else => |e| return e,
346 };
347 return @intCast(usize, count);
348 }
349};
std/time.zig created+221
...@@ -0,0 +1,221 @@
1const builtin = @import("builtin");
2const std = @import("std.zig");
3const assert = std.debug.assert;
4const testing = std.testing;
5const os = std.os;
6const math = std.math;
7
8pub const epoch = @import("time/epoch.zig");
9
10/// Spurious wakeups are possible and no precision of timing is guaranteed.
11pub fn sleep(nanoseconds: u64) void {
12 if (os.windows.is_the_target) {
13 const ns_per_ms = ns_per_s / ms_per_s;
14 const big_ms_from_ns = nanoseconds / ns_per_ms;
15 const ms = math.cast(os.windows.DWORD, big_ms_from_ns) catch math.maxInt(os.windows.DWORD);
16 os.windows.kernel32.Sleep(ms);
17 return;
18 }
19 const s = nanoseconds / ns_per_s;
20 const ns = nanoseconds % ns_per_s;
21 std.os.nanosleep(s, ns);
22}
23
24/// Get the posix timestamp, UTC, in seconds
25/// TODO audit this function. is it possible to return an error?
26pub fn timestamp() u64 {
27 return @divFloor(milliTimestamp(), ms_per_s);
28}
29
30/// Get the posix timestamp, UTC, in milliseconds
31/// TODO audit this function. is it possible to return an error?
32pub fn milliTimestamp() u64 {
33 if (os.windows.is_the_target) {
34 //FileTime has a granularity of 100 nanoseconds
35 // and uses the NTFS/Windows epoch
36 var ft: os.windows.FILETIME = undefined;
37 os.windows.kernel32.GetSystemTimeAsFileTime(&ft);
38 const hns_per_ms = (ns_per_s / 100) / ms_per_s;
39 const epoch_adj = epoch.windows * ms_per_s;
40
41 const ft64 = (u64(ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
42 return @divFloor(ft64, hns_per_ms) - -epoch_adj;
43 }
44 if (os.wasi.is_the_target and !builtin.link_libc) {
45 var ns: os.wasi.timestamp_t = undefined;
46
47 // TODO: Verify that precision is ignored
48 const err = os.wasi.clock_time_get(os.wasi.CLOCK_REALTIME, 1, &ns);
49 assert(err == os.wasi.ESUCCESS);
50
51 const ns_per_ms = 1000;
52 return @divFloor(ns, ns_per_ms);
53 }
54 if (os.darwin.is_the_target) {
55 var tv: os.darwin.timeval = undefined;
56 var err = os.darwin.gettimeofday(&tv, null);
57 assert(err == 0);
58 const sec_ms = tv.tv_sec * ms_per_s;
59 const usec_ms = @divFloor(tv.tv_usec, us_per_s / ms_per_s);
60 return @intCast(u64, sec_ms + usec_ms);
61 }
62 var ts: os.timespec = undefined;
63 //From what I can tell there's no reason clock_gettime
64 // should ever fail for us with CLOCK_REALTIME,
65 // seccomp aside.
66 os.clock_gettime(os.CLOCK_REALTIME, &ts) catch unreachable;
67 const sec_ms = @intCast(u64, ts.tv_sec) * ms_per_s;
68 const nsec_ms = @divFloor(@intCast(u64, ts.tv_nsec), ns_per_s / ms_per_s);
69 return sec_ms + nsec_ms;
70}
71
72/// Multiples of a base unit (nanoseconds)
73pub const nanosecond = 1;
74pub const microsecond = 1000 * nanosecond;
75pub const millisecond = 1000 * microsecond;
76pub const second = 1000 * millisecond;
77pub const minute = 60 * second;
78pub const hour = 60 * minute;
79
80/// Divisions of a second
81pub const ns_per_s = 1000000000;
82pub const us_per_s = 1000000;
83pub const ms_per_s = 1000;
84pub const cs_per_s = 100;
85
86/// Common time divisions
87pub const s_per_min = 60;
88pub const s_per_hour = s_per_min * 60;
89pub const s_per_day = s_per_hour * 24;
90pub const s_per_week = s_per_day * 7;
91
92/// A monotonic high-performance timer.
93/// Timer.start() must be called to initialize the struct, which captures
94/// the counter frequency on windows and darwin, records the resolution,
95/// and gives the user an opportunity to check for the existnece of
96/// monotonic clocks without forcing them to check for error on each read.
97/// .resolution is in nanoseconds on all platforms but .start_time's meaning
98/// depends on the OS. On Windows and Darwin it is a hardware counter
99/// value that requires calculation to convert to a meaninful unit.
100pub const Timer = struct {
101 ///if we used resolution's value when performing the
102 /// performance counter calc on windows/darwin, it would
103 /// be less precise
104 frequency: switch (builtin.os) {
105 .windows => u64,
106 .macosx, .ios, .tvos, .watchos => os.darwin.mach_timebase_info_data,
107 else => void,
108 },
109 resolution: u64,
110 start_time: u64,
111
112 const Error = error{TimerUnsupported};
113
114 ///At some point we may change our minds on RAW, but for now we're
115 /// sticking with posix standard MONOTONIC. For more information, see:
116 /// https://github.com/ziglang/zig/pull/933
117 const monotonic_clock_id = os.CLOCK_MONOTONIC;
118 /// Initialize the timer structure.
119 //This gives us an opportunity to grab the counter frequency in windows.
120 //On Windows: QueryPerformanceCounter will succeed on anything >= XP/2000.
121 //On Posix: CLOCK_MONOTONIC will only fail if the monotonic counter is not
122 // supported, or if the timespec pointer is out of bounds, which should be
123 // impossible here barring cosmic rays or other such occurrences of
124 // incredibly bad luck.
125 //On Darwin: This cannot fail, as far as I am able to tell.
126 pub fn start() Error!Timer {
127 var self: Timer = undefined;
128
129 if (os.windows.is_the_target) {
130 self.frequency = os.windows.QueryPerformanceFrequency();
131 self.resolution = @divFloor(ns_per_s, self.frequency);
132 self.start_time = os.windows.QueryPerformanceCounter();
133 } else if (os.darwin.is_the_target) {
134 os.darwin.mach_timebase_info(&self.frequency);
135 self.resolution = @divFloor(self.frequency.numer, self.frequency.denom);
136 self.start_time = os.darwin.mach_absolute_time();
137 } else {
138 //On Linux, seccomp can do arbitrary things to our ability to call
139 // syscalls, including return any errno value it wants and
140 // inconsistently throwing errors. Since we can't account for
141 // abuses of seccomp in a reasonable way, we'll assume that if
142 // seccomp is going to block us it will at least do so consistently
143 var ts: os.timespec = undefined;
144 os.clock_getres(monotonic_clock_id, &ts) catch return error.TimerUnsupported;
145 self.resolution = @intCast(u64, ts.tv_sec) * u64(ns_per_s) + @intCast(u64, ts.tv_nsec);
146
147 os.clock_gettime(monotonic_clock_id, &ts) catch return error.TimerUnsupported;
148 self.start_time = @intCast(u64, ts.tv_sec) * u64(ns_per_s) + @intCast(u64, ts.tv_nsec);
149 }
150
151 return self;
152 }
153
154 /// Reads the timer value since start or the last reset in nanoseconds
155 pub fn read(self: *Timer) u64 {
156 var clock = clockNative() - self.start_time;
157 if (os.windows.is_the_target) {
158 return @divFloor(clock * ns_per_s, self.frequency);
159 }
160 if (os.darwin.is_the_target) {
161 return @divFloor(clock * self.frequency.numer, self.frequency.denom);
162 }
163 return clock;
164 }
165
166 /// Resets the timer value to 0/now.
167 pub fn reset(self: *Timer) void {
168 self.start_time = clockNative();
169 }
170
171 /// Returns the current value of the timer in nanoseconds, then resets it
172 pub fn lap(self: *Timer) u64 {
173 var now = clockNative();
174 var lap_time = self.read();
175 self.start_time = now;
176 return lap_time;
177 }
178
179 fn clockNative() u64 {
180 if (os.windows.is_the_target) {
181 return os.windows.QueryPerformanceCounter();
182 }
183 if (os.darwin.is_the_target) {
184 return os.darwin.mach_absolute_time();
185 }
186 var ts: os.timespec = undefined;
187 os.clock_gettime(monotonic_clock_id, &ts) catch unreachable;
188 return @intCast(u64, ts.tv_sec) * u64(ns_per_s) + @intCast(u64, ts.tv_nsec);
189 }
190};
191
192test "sleep" {
193 sleep(1);
194}
195
196test "timestamp" {
197 const ns_per_ms = (ns_per_s / ms_per_s);
198 const margin = 50;
199
200 const time_0 = milliTimestamp();
201 sleep(ns_per_ms);
202 const time_1 = milliTimestamp();
203 const interval = time_1 - time_0;
204 testing.expect(interval > 0 and interval < margin);
205}
206
207test "Timer" {
208 const ns_per_ms = (ns_per_s / ms_per_s);
209 const margin = ns_per_ms * 150;
210
211 var timer = try Timer.start();
212 sleep(10 * ns_per_ms);
213 const time_0 = timer.read();
214 testing.expect(time_0 > 0 and time_0 < margin);
215
216 const time_1 = timer.lap();
217 testing.expect(time_1 >= time_0);
218
219 timer.reset();
220 testing.expect(timer.read() < time_1);
221}
std/time/epoch.zig created+26
...@@ -0,0 +1,26 @@
1/// Epoch reference times in terms of their difference from
2/// posix epoch in seconds.
3pub const posix = 0; //Jan 01, 1970 AD
4pub const dos = 315532800; //Jan 01, 1980 AD
5pub const ios = 978307200; //Jan 01, 2001 AD
6pub const openvms = -3506716800; //Nov 17, 1858 AD
7pub const zos = -2208988800; //Jan 01, 1900 AD
8pub const windows = -11644473600; //Jan 01, 1601 AD
9pub const amiga = 252460800; //Jan 01, 1978 AD
10pub const pickos = -63244800; //Dec 31, 1967 AD
11pub const gps = 315964800; //Jan 06, 1980 AD
12pub const clr = -62135769600; //Jan 01, 0001 AD
13
14pub const unix = posix;
15pub const android = posix;
16pub const os2 = dos;
17pub const bios = dos;
18pub const vfat = dos;
19pub const ntfs = windows;
20pub const ntp = zos;
21pub const jbase = pickos;
22pub const aros = amiga;
23pub const morphos = amiga;
24pub const brew = gps;
25pub const atsc = gps;
26pub const go = clr;
std/zig/bench.zig+2-2
...@@ -10,7 +10,7 @@ var fixed_buffer_mem: [10 * 1024 * 1024]u8 = undefined;...@@ -10,7 +10,7 @@ var fixed_buffer_mem: [10 * 1024 * 1024]u8 = undefined;
1010
11pub fn main() !void {11pub fn main() !void {
12 var i: usize = 0;12 var i: usize = 0;
13 var timer = try std.os.time.Timer.start();13 var timer = try std.time.Timer.start();
14 const start = timer.lap();14 const start = timer.lap();
15 const iterations = 100;15 const iterations = 100;
16 var memory_used: usize = 0;16 var memory_used: usize = 0;
...@@ -19,7 +19,7 @@ pub fn main() !void {...@@ -19,7 +19,7 @@ pub fn main() !void {
19 }19 }
20 const end = timer.read();20 const end = timer.read();
21 memory_used /= iterations;21 memory_used /= iterations;
22 const elapsed_s = @intToFloat(f64, end - start) / std.os.time.ns_per_s;22 const elapsed_s = @intToFloat(f64, end - start) / std.time.ns_per_s;
23 const bytes_per_sec = @intToFloat(f64, source.len * iterations) / elapsed_s;23 const bytes_per_sec = @intToFloat(f64, source.len * iterations) / elapsed_s;
24 const mb_per_sec = bytes_per_sec / (1024 * 1024);24 const mb_per_sec = bytes_per_sec / (1024 * 1024);
2525
test/cli.zig+21-19
...@@ -1,7 +1,9 @@...@@ -1,7 +1,9 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const os = std.os;
4const testing = std.testing;3const testing = std.testing;
4const process = std.process;
5const fs = std.fs;
6const ChildProcess = std.ChildProcess;
57
6var a: *std.mem.Allocator = undefined;8var a: *std.mem.Allocator = undefined;
79
...@@ -12,7 +14,7 @@ pub fn main() !void {...@@ -12,7 +14,7 @@ pub fn main() !void {
12 var arena = std.heap.ArenaAllocator.init(&direct_allocator.allocator);14 var arena = std.heap.ArenaAllocator.init(&direct_allocator.allocator);
13 defer arena.deinit();15 defer arena.deinit();
1416
15 var arg_it = os.args();17 var arg_it = process.args();
1618
17 // skip my own exe name19 // skip my own exe name
18 _ = arg_it.skip();20 _ = arg_it.skip();
...@@ -27,9 +29,9 @@ pub fn main() !void {...@@ -27,9 +29,9 @@ pub fn main() !void {
27 std.debug.warn("Expected second argument to be cache root directory path\n");29 std.debug.warn("Expected second argument to be cache root directory path\n");
28 return error.InvalidArgs;30 return error.InvalidArgs;
29 });31 });
30 const zig_exe = try os.path.resolve(a, [][]const u8{zig_exe_rel});32 const zig_exe = try fs.path.resolve(a, [][]const u8{zig_exe_rel});
3133
32 const dir_path = try os.path.join(a, [][]const u8{ cache_root, "clitest" });34 const dir_path = try fs.path.join(a, [][]const u8{ cache_root, "clitest" });
33 const TestFn = fn ([]const u8, []const u8) anyerror!void;35 const TestFn = fn ([]const u8, []const u8) anyerror!void;
34 const test_fns = []TestFn{36 const test_fns = []TestFn{
35 testZigInitLib,37 testZigInitLib,
...@@ -37,8 +39,8 @@ pub fn main() !void {...@@ -37,8 +39,8 @@ pub fn main() !void {
37 testGodboltApi,39 testGodboltApi,
38 };40 };
39 for (test_fns) |testFn| {41 for (test_fns) |testFn| {
40 try os.deleteTree(a, dir_path);42 try fs.deleteTree(a, dir_path);
41 try os.makeDir(dir_path);43 try fs.makeDir(dir_path);
42 try testFn(zig_exe, dir_path);44 try testFn(zig_exe, dir_path);
43 }45 }
44}46}
...@@ -58,15 +60,15 @@ fn printCmd(cwd: []const u8, argv: []const []const u8) void {...@@ -58,15 +60,15 @@ fn printCmd(cwd: []const u8, argv: []const []const u8) void {
58 std.debug.warn("\n");60 std.debug.warn("\n");
59}61}
6062
61fn exec(cwd: []const u8, argv: []const []const u8) !os.ChildProcess.ExecResult {63fn exec(cwd: []const u8, argv: []const []const u8) !ChildProcess.ExecResult {
62 const max_output_size = 100 * 1024;64 const max_output_size = 100 * 1024;
63 const result = os.ChildProcess.exec(a, argv, cwd, null, max_output_size) catch |err| {65 const result = ChildProcess.exec(a, argv, cwd, null, max_output_size) catch |err| {
64 std.debug.warn("The following command failed:\n");66 std.debug.warn("The following command failed:\n");
65 printCmd(cwd, argv);67 printCmd(cwd, argv);
66 return err;68 return err;
67 };69 };
68 switch (result.term) {70 switch (result.term) {
69 os.ChildProcess.Term.Exited => |code| {71 .Exited => |code| {
70 if (code != 0) {72 if (code != 0) {
71 std.debug.warn("The following command exited with error code {}:\n", code);73 std.debug.warn("The following command exited with error code {}:\n", code);
72 printCmd(cwd, argv);74 printCmd(cwd, argv);
...@@ -97,10 +99,10 @@ fn testZigInitExe(zig_exe: []const u8, dir_path: []const u8) !void {...@@ -97,10 +99,10 @@ fn testZigInitExe(zig_exe: []const u8, dir_path: []const u8) !void {
97}99}
98100
99fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void {101fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void {
100 if (builtin.os != builtin.Os.linux or builtin.arch != builtin.Arch.x86_64) return;102 if (builtin.os != .linux or builtin.arch != .x86_64) return;
101103
102 const example_zig_path = try os.path.join(a, [][]const u8{ dir_path, "example.zig" });104 const example_zig_path = try fs.path.join(a, [][]const u8{ dir_path, "example.zig" });
103 const example_s_path = try os.path.join(a, [][]const u8{ dir_path, "example.s" });105 const example_s_path = try fs.path.join(a, [][]const u8{ dir_path, "example.s" });
104106
105 try std.io.writeFile(example_zig_path,107 try std.io.writeFile(example_zig_path,
106 \\// Type your code here, or load an example.108 \\// Type your code here, or load an example.
...@@ -114,13 +116,13 @@ fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void {...@@ -114,13 +116,13 @@ fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void {
114 );116 );
115117
116 const args = [][]const u8{118 const args = [][]const u8{
117 zig_exe, "build-obj",119 zig_exe, "build-obj",
118 "--cache-dir", dir_path,120 "--cache-dir", dir_path,
119 "--name", "example",121 "--name", "example",
120 "--output-dir", dir_path,122 "--output-dir", dir_path,
121 "--emit", "asm",123 "--emit", "asm",
122 "-mllvm", "--x86-asm-syntax=intel",124 "-mllvm", "--x86-asm-syntax=intel",
123 "--strip", "--release-fast",125 "--strip", "--release-fast",
124 example_zig_path, "--disable-gen-h",126 example_zig_path, "--disable-gen-h",
125 };127 };
126 _ = try exec(dir_path, args);128 _ = try exec(dir_path, args);
test/compare_output.zig+3-3
...@@ -377,7 +377,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -377,7 +377,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
377 \\ stdout.print("before\n") catch unreachable;377 \\ stdout.print("before\n") catch unreachable;
378 \\ defer stdout.print("defer1\n") catch unreachable;378 \\ defer stdout.print("defer1\n") catch unreachable;
379 \\ defer stdout.print("defer2\n") catch unreachable;379 \\ defer stdout.print("defer2\n") catch unreachable;
380 \\ var args_it = @import("std").os.args();380 \\ var args_it = @import("std").process.args();
381 \\ if (args_it.skip() and !args_it.skip()) return;381 \\ if (args_it.skip() and !args_it.skip()) return;
382 \\ defer stdout.print("defer3\n") catch unreachable;382 \\ defer stdout.print("defer3\n") catch unreachable;
383 \\ stdout.print("after\n") catch unreachable;383 \\ stdout.print("after\n") catch unreachable;
...@@ -444,7 +444,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -444,7 +444,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
444 \\const allocator = std.debug.global_allocator;444 \\const allocator = std.debug.global_allocator;
445 \\445 \\
446 \\pub fn main() !void {446 \\pub fn main() !void {
447 \\ var args_it = os.args();447 \\ var args_it = std.process.args();
448 \\ var stdout_file = try io.getStdOut();448 \\ var stdout_file = try io.getStdOut();
449 \\ var stdout_adapter = stdout_file.outStream();449 \\ var stdout_adapter = stdout_file.outStream();
450 \\ const stdout = &stdout_adapter.stream;450 \\ const stdout = &stdout_adapter.stream;
...@@ -485,7 +485,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -485,7 +485,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
485 \\const allocator = std.debug.global_allocator;485 \\const allocator = std.debug.global_allocator;
486 \\486 \\
487 \\pub fn main() !void {487 \\pub fn main() !void {
488 \\ var args_it = os.args();488 \\ var args_it = std.process.args();
489 \\ var stdout_file = try io.getStdOut();489 \\ var stdout_file = try io.getStdOut();
490 \\ var stdout_adapter = stdout_file.outStream();490 \\ var stdout_adapter = stdout_file.outStream();
491 \\ const stdout = &stdout_adapter.stream;491 \\ const stdout = &stdout_adapter.stream;
test/compile_errors.zig+9
...@@ -2,6 +2,15 @@ const tests = @import("tests.zig");...@@ -2,6 +2,15 @@ const tests = @import("tests.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4pub fn addCases(cases: *tests.CompileErrorContext) void {4pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.add(
6 "@hasDecl with non-container",
7 \\export fn entry() void {
8 \\ _ = @hasDecl(i32, "hi");
9 \\}
10 ,
11 "tmp.zig:2:18: error: expected struct, enum, or union; found 'i32'",
12 );
13
5 cases.add(14 cases.add(
6 "field access of slices",15 "field access of slices",
7 \\export fn entry() void {16 \\export fn entry() void {
test/stage1/behavior.zig+1
...@@ -53,6 +53,7 @@ comptime {...@@ -53,6 +53,7 @@ comptime {
53 _ = @import("behavior/fn_in_struct_in_comptime.zig");53 _ = @import("behavior/fn_in_struct_in_comptime.zig");
54 _ = @import("behavior/for.zig");54 _ = @import("behavior/for.zig");
55 _ = @import("behavior/generics.zig");55 _ = @import("behavior/generics.zig");
56 _ = @import("behavior/hasdecl.zig");
56 _ = @import("behavior/if.zig");57 _ = @import("behavior/if.zig");
57 _ = @import("behavior/import.zig");58 _ = @import("behavior/import.zig");
58 _ = @import("behavior/incomplete_struct_param_tld.zig");59 _ = @import("behavior/incomplete_struct_param_tld.zig");
test/stage1/behavior/cast.zig+1-1
...@@ -318,7 +318,7 @@ fn testCastPtrOfArrayToSliceAndPtr() void {...@@ -318,7 +318,7 @@ fn testCastPtrOfArrayToSliceAndPtr() void {
318test "cast *[1][*]const u8 to [*]const ?[*]const u8" {318test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
319 const window_name = [1][*]const u8{c"window name"};319 const window_name = [1][*]const u8{c"window name"};
320 const x: [*]const ?[*]const u8 = &window_name;320 const x: [*]const ?[*]const u8 = &window_name;
321 expect(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name"));321 expect(mem.eql(u8, std.mem.toSliceConst(u8, x[0].?), "window name"));
322}322}
323323
324test "@intCast comptime_int" {324test "@intCast comptime_int" {
test/stage1/behavior/hasdecl.zig created+21
...@@ -0,0 +1,21 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
4const Foo = @import("hasdecl/foo.zig");
5
6const Bar = struct {
7 nope: i32,
8
9 const hi = 1;
10 pub var blah = "xxx";
11};
12
13test "@hasDecl" {
14 expect(@hasDecl(Foo, "public_thing"));
15 expect(!@hasDecl(Foo, "private_thing"));
16 expect(!@hasDecl(Foo, "no_thing"));
17
18 expect(@hasDecl(Bar, "hi"));
19 expect(@hasDecl(Bar, "blah"));
20 expect(!@hasDecl(Bar, "nope"));
21}
test/stage1/behavior/hasdecl/foo.zig created+2
...@@ -0,0 +1,2 @@
1pub const public_thing = 42;
2const private_thing = 666;
test/stage1/behavior/misc.zig+2-3
...@@ -2,7 +2,6 @@ const std = @import("std");...@@ -2,7 +2,6 @@ const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
3const expectEqualSlices = std.testing.expectEqualSlices;3const expectEqualSlices = std.testing.expectEqualSlices;
4const mem = std.mem;4const mem = std.mem;
5const cstr = std.cstr;
6const builtin = @import("builtin");5const builtin = @import("builtin");
7const maxInt = std.math.maxInt;6const maxInt = std.math.maxInt;
87
...@@ -210,7 +209,7 @@ test "multiline C string" {...@@ -210,7 +209,7 @@ test "multiline C string" {
210 c\\three209 c\\three
211 ;210 ;
212 const s2 = c"one\ntwo)\nthree";211 const s2 = c"one\ntwo)\nthree";
213 expect(cstr.cmp(s1, s2) == 0);212 expect(std.cstr.cmp(s1, s2) == 0);
214}213}
215214
216test "type equality" {215test "type equality" {
...@@ -363,7 +362,7 @@ test "C string concatenation" {...@@ -363,7 +362,7 @@ test "C string concatenation" {
363 const a = c"OK" ++ c" IT " ++ c"WORKED";362 const a = c"OK" ++ c" IT " ++ c"WORKED";
364 const b = c"OK IT WORKED";363 const b = c"OK IT WORKED";
365364
366 const len = cstr.len(b);365 const len = mem.len(u8, b);
367 const len_with_null = len + 1;366 const len_with_null = len + 1;
368 {367 {
369 var i: u32 = 0;368 var i: u32 = 0;
test/stage1/behavior/ptrcast.zig+8
...@@ -58,3 +58,11 @@ test "comptime ptrcast keeps larger alignment" {...@@ -58,3 +58,11 @@ test "comptime ptrcast keeps larger alignment" {
58 std.debug.assert(@typeOf(p) == [*]align(@alignOf(u32)) const u8);58 std.debug.assert(@typeOf(p) == [*]align(@alignOf(u32)) const u8);
59 }59 }
60}60}
61
62test "implicit optional pointer to optional c_void pointer" {
63 var buf: [4]u8 = "aoeu";
64 var x: ?[*]u8 = &buf;
65 var y: ?*c_void = x;
66 var z = @ptrCast(*[4]u8, y);
67 expect(std.mem.eql(u8, z, "aoeu"));
68}
test/standalone/empty_env/main.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn main() void {3pub fn main() void {
4 const env_map = std.os.getEnvMap(std.debug.global_allocator) catch @panic("unable to get env map");4 const env_map = std.process.getEnvMap(std.debug.global_allocator) catch @panic("unable to get env map");
5 std.testing.expect(env_map.count() == 0);5 std.testing.expect(env_map.count() == 0);
6}6}
test/tests.zig+45-47
...@@ -2,11 +2,9 @@ const std = @import("std");...@@ -2,11 +2,9 @@ const std = @import("std");
2const debug = std.debug;2const debug = std.debug;
3const warn = debug.warn;3const warn = debug.warn;
4const build = std.build;4const build = std.build;
5const os = std.os;
6const StdIo = os.ChildProcess.StdIo;
7const Term = os.ChildProcess.Term;
8const Buffer = std.Buffer;5const Buffer = std.Buffer;
9const io = std.io;6const io = std.io;
7const fs = std.fs;
10const mem = std.mem;8const mem = std.mem;
11const fmt = std.fmt;9const fmt = std.fmt;
12const ArrayList = std.ArrayList;10const ArrayList = std.ArrayList;
...@@ -30,19 +28,19 @@ const TestTarget = struct {...@@ -30,19 +28,19 @@ const TestTarget = struct {
3028
31const test_targets = []TestTarget{29const test_targets = []TestTarget{
32 TestTarget{30 TestTarget{
33 .os = builtin.Os.linux,31 .os = .linux,
34 .arch = builtin.Arch.x86_64,32 .arch = .x86_64,
35 .abi = builtin.Abi.gnu,33 .abi = .gnu,
36 },34 },
37 TestTarget{35 TestTarget{
38 .os = builtin.Os.macosx,36 .os = .macosx,
39 .arch = builtin.Arch.x86_64,37 .arch = .x86_64,
40 .abi = builtin.Abi.gnu,38 .abi = .gnu,
41 },39 },
42 TestTarget{40 TestTarget{
43 .os = builtin.Os.windows,41 .os = .windows,
44 .arch = builtin.Arch.x86_64,42 .arch = .x86_64,
45 .abi = builtin.Abi.msvc,43 .abi = .msvc,
46 },44 },
47};45};
4846
...@@ -114,7 +112,7 @@ pub fn addCliTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const M...@@ -114,7 +112,7 @@ pub fn addCliTests(b: *build.Builder, test_filter: ?[]const u8, modes: []const M
114 const exe = b.addExecutable("test-cli", "test/cli.zig");112 const exe = b.addExecutable("test-cli", "test/cli.zig");
115 const run_cmd = exe.run();113 const run_cmd = exe.run();
116 run_cmd.addArgs([][]const u8{114 run_cmd.addArgs([][]const u8{
117 os.path.realAlloc(b.allocator, b.zig_exe) catch unreachable,115 fs.realpathAlloc(b.allocator, b.zig_exe) catch unreachable,
118 b.pathFromRoot(b.cache_root),116 b.pathFromRoot(b.cache_root),
119 });117 });
120118
...@@ -301,12 +299,12 @@ pub const CompareOutputContext = struct {...@@ -301,12 +299,12 @@ pub const CompareOutputContext = struct {
301299
302 warn("Test {}/{} {}...", self.test_index + 1, self.context.test_index, self.name);300 warn("Test {}/{} {}...", self.test_index + 1, self.context.test_index, self.name);
303301
304 const child = os.ChildProcess.init(args.toSliceConst(), b.allocator) catch unreachable;302 const child = std.ChildProcess.init(args.toSliceConst(), b.allocator) catch unreachable;
305 defer child.deinit();303 defer child.deinit();
306304
307 child.stdin_behavior = StdIo.Ignore;305 child.stdin_behavior = .Ignore;
308 child.stdout_behavior = StdIo.Pipe;306 child.stdout_behavior = .Pipe;
309 child.stderr_behavior = StdIo.Pipe;307 child.stderr_behavior = .Pipe;
310 child.env_map = b.env_map;308 child.env_map = b.env_map;
311309
312 child.spawn() catch |err| debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));310 child.spawn() catch |err| debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));
...@@ -324,7 +322,7 @@ pub const CompareOutputContext = struct {...@@ -324,7 +322,7 @@ pub const CompareOutputContext = struct {
324 debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));322 debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));
325 };323 };
326 switch (term) {324 switch (term) {
327 Term.Exited => |code| {325 .Exited => |code| {
328 if (code != 0) {326 if (code != 0) {
329 warn("Process {} exited with error code {}\n", full_exe_path, code);327 warn("Process {} exited with error code {}\n", full_exe_path, code);
330 printInvocation(args.toSliceConst());328 printInvocation(args.toSliceConst());
...@@ -383,27 +381,27 @@ pub const CompareOutputContext = struct {...@@ -383,27 +381,27 @@ pub const CompareOutputContext = struct {
383381
384 warn("Test {}/{} {}...", self.test_index + 1, self.context.test_index, self.name);382 warn("Test {}/{} {}...", self.test_index + 1, self.context.test_index, self.name);
385383
386 const child = os.ChildProcess.init([][]const u8{full_exe_path}, b.allocator) catch unreachable;384 const child = std.ChildProcess.init([][]const u8{full_exe_path}, b.allocator) catch unreachable;
387 defer child.deinit();385 defer child.deinit();
388386
389 child.env_map = b.env_map;387 child.env_map = b.env_map;
390 child.stdin_behavior = StdIo.Ignore;388 child.stdin_behavior = .Ignore;
391 child.stdout_behavior = StdIo.Ignore;389 child.stdout_behavior = .Ignore;
392 child.stderr_behavior = StdIo.Ignore;390 child.stderr_behavior = .Ignore;
393391
394 const term = child.spawnAndWait() catch |err| {392 const term = child.spawnAndWait() catch |err| {
395 debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));393 debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));
396 };394 };
397395
398 const expected_exit_code: i32 = 126;396 const expected_exit_code: u32 = 126;
399 switch (term) {397 switch (term) {
400 Term.Exited => |code| {398 .Exited => |code| {
401 if (code != expected_exit_code) {399 if (code != expected_exit_code) {
402 warn("\nProgram expected to exit with code {} " ++ "but exited with code {}\n", expected_exit_code, code);400 warn("\nProgram expected to exit with code {} " ++ "but exited with code {}\n", expected_exit_code, code);
403 return error.TestFailed;401 return error.TestFailed;
404 }402 }
405 },403 },
406 Term.Signal => |sig| {404 .Signal => |sig| {
407 warn("\nProgram expected to exit with code {} " ++ "but instead signaled {}\n", expected_exit_code, sig);405 warn("\nProgram expected to exit with code {} " ++ "but instead signaled {}\n", expected_exit_code, sig);
408 return error.TestFailed;406 return error.TestFailed;
409 },407 },
...@@ -459,7 +457,7 @@ pub const CompareOutputContext = struct {...@@ -459,7 +457,7 @@ pub const CompareOutputContext = struct {
459 pub fn addCase(self: *CompareOutputContext, case: TestCase) void {457 pub fn addCase(self: *CompareOutputContext, case: TestCase) void {
460 const b = self.b;458 const b = self.b;
461459
462 const root_src = os.path.join(460 const root_src = fs.path.join(
463 b.allocator,461 b.allocator,
464 [][]const u8{ b.cache_root, case.sources.items[0].filename },462 [][]const u8{ b.cache_root, case.sources.items[0].filename },
465 ) catch unreachable;463 ) catch unreachable;
...@@ -475,7 +473,7 @@ pub const CompareOutputContext = struct {...@@ -475,7 +473,7 @@ pub const CompareOutputContext = struct {
475 exe.addAssemblyFile(root_src);473 exe.addAssemblyFile(root_src);
476474
477 for (case.sources.toSliceConst()) |src_file| {475 for (case.sources.toSliceConst()) |src_file| {
478 const expanded_src_path = os.path.join(476 const expanded_src_path = fs.path.join(
479 b.allocator,477 b.allocator,
480 [][]const u8{ b.cache_root, src_file.filename },478 [][]const u8{ b.cache_root, src_file.filename },
481 ) catch unreachable;479 ) catch unreachable;
...@@ -507,7 +505,7 @@ pub const CompareOutputContext = struct {...@@ -507,7 +505,7 @@ pub const CompareOutputContext = struct {
507 }505 }
508506
509 for (case.sources.toSliceConst()) |src_file| {507 for (case.sources.toSliceConst()) |src_file| {
510 const expanded_src_path = os.path.join(508 const expanded_src_path = fs.path.join(
511 b.allocator,509 b.allocator,
512 [][]const u8{ b.cache_root, src_file.filename },510 [][]const u8{ b.cache_root, src_file.filename },
513 ) catch unreachable;511 ) catch unreachable;
...@@ -538,7 +536,7 @@ pub const CompareOutputContext = struct {...@@ -538,7 +536,7 @@ pub const CompareOutputContext = struct {
538 }536 }
539537
540 for (case.sources.toSliceConst()) |src_file| {538 for (case.sources.toSliceConst()) |src_file| {
541 const expanded_src_path = os.path.join(539 const expanded_src_path = fs.path.join(
542 b.allocator,540 b.allocator,
543 [][]const u8{ b.cache_root, src_file.filename },541 [][]const u8{ b.cache_root, src_file.filename },
544 ) catch unreachable;542 ) catch unreachable;
...@@ -633,7 +631,7 @@ pub const CompileErrorContext = struct {...@@ -633,7 +631,7 @@ pub const CompileErrorContext = struct {
633 const self = @fieldParentPtr(CompileCmpOutputStep, "step", step);631 const self = @fieldParentPtr(CompileCmpOutputStep, "step", step);
634 const b = self.context.b;632 const b = self.context.b;
635633
636 const root_src = os.path.join(634 const root_src = fs.path.join(
637 b.allocator,635 b.allocator,
638 [][]const u8{ b.cache_root, self.case.sources.items[0].filename },636 [][]const u8{ b.cache_root, self.case.sources.items[0].filename },
639 ) catch unreachable;637 ) catch unreachable;
...@@ -669,13 +667,13 @@ pub const CompileErrorContext = struct {...@@ -669,13 +667,13 @@ pub const CompileErrorContext = struct {
669 printInvocation(zig_args.toSliceConst());667 printInvocation(zig_args.toSliceConst());
670 }668 }
671669
672 const child = os.ChildProcess.init(zig_args.toSliceConst(), b.allocator) catch unreachable;670 const child = std.ChildProcess.init(zig_args.toSliceConst(), b.allocator) catch unreachable;
673 defer child.deinit();671 defer child.deinit();
674672
675 child.env_map = b.env_map;673 child.env_map = b.env_map;
676 child.stdin_behavior = StdIo.Ignore;674 child.stdin_behavior = .Ignore;
677 child.stdout_behavior = StdIo.Pipe;675 child.stdout_behavior = .Pipe;
678 child.stderr_behavior = StdIo.Pipe;676 child.stderr_behavior = .Pipe;
679677
680 child.spawn() catch |err| debug.panic("Unable to spawn {}: {}\n", zig_args.items[0], @errorName(err));678 child.spawn() catch |err| debug.panic("Unable to spawn {}: {}\n", zig_args.items[0], @errorName(err));
681679
...@@ -692,7 +690,7 @@ pub const CompileErrorContext = struct {...@@ -692,7 +690,7 @@ pub const CompileErrorContext = struct {
692 debug.panic("Unable to spawn {}: {}\n", zig_args.items[0], @errorName(err));690 debug.panic("Unable to spawn {}: {}\n", zig_args.items[0], @errorName(err));
693 };691 };
694 switch (term) {692 switch (term) {
695 Term.Exited => |code| {693 .Exited => |code| {
696 if (code == 0) {694 if (code == 0) {
697 printInvocation(zig_args.toSliceConst());695 printInvocation(zig_args.toSliceConst());
698 return error.CompilationIncorrectlySucceeded;696 return error.CompilationIncorrectlySucceeded;
...@@ -823,7 +821,7 @@ pub const CompileErrorContext = struct {...@@ -823,7 +821,7 @@ pub const CompileErrorContext = struct {
823 self.step.dependOn(&compile_and_cmp_errors.step);821 self.step.dependOn(&compile_and_cmp_errors.step);
824822
825 for (case.sources.toSliceConst()) |src_file| {823 for (case.sources.toSliceConst()) |src_file| {
826 const expanded_src_path = os.path.join(824 const expanded_src_path = fs.path.join(
827 b.allocator,825 b.allocator,
828 [][]const u8{ b.cache_root, src_file.filename },826 [][]const u8{ b.cache_root, src_file.filename },
829 ) catch unreachable;827 ) catch unreachable;
...@@ -858,7 +856,7 @@ pub const BuildExamplesContext = struct {...@@ -858,7 +856,7 @@ pub const BuildExamplesContext = struct {
858 }856 }
859857
860 var zig_args = ArrayList([]const u8).init(b.allocator);858 var zig_args = ArrayList([]const u8).init(b.allocator);
861 const rel_zig_exe = os.path.relative(b.allocator, b.build_root, b.zig_exe) catch unreachable;859 const rel_zig_exe = fs.path.relative(b.allocator, b.build_root, b.zig_exe) catch unreachable;
862 zig_args.append(rel_zig_exe) catch unreachable;860 zig_args.append(rel_zig_exe) catch unreachable;
863 zig_args.append("build") catch unreachable;861 zig_args.append("build") catch unreachable;
864862
...@@ -958,7 +956,7 @@ pub const TranslateCContext = struct {...@@ -958,7 +956,7 @@ pub const TranslateCContext = struct {
958 const self = @fieldParentPtr(TranslateCCmpOutputStep, "step", step);956 const self = @fieldParentPtr(TranslateCCmpOutputStep, "step", step);
959 const b = self.context.b;957 const b = self.context.b;
960958
961 const root_src = os.path.join(959 const root_src = fs.path.join(
962 b.allocator,960 b.allocator,
963 [][]const u8{ b.cache_root, self.case.sources.items[0].filename },961 [][]const u8{ b.cache_root, self.case.sources.items[0].filename },
964 ) catch unreachable;962 ) catch unreachable;
...@@ -976,13 +974,13 @@ pub const TranslateCContext = struct {...@@ -976,13 +974,13 @@ pub const TranslateCContext = struct {
976 printInvocation(zig_args.toSliceConst());974 printInvocation(zig_args.toSliceConst());
977 }975 }
978976
979 const child = os.ChildProcess.init(zig_args.toSliceConst(), b.allocator) catch unreachable;977 const child = std.ChildProcess.init(zig_args.toSliceConst(), b.allocator) catch unreachable;
980 defer child.deinit();978 defer child.deinit();
981979
982 child.env_map = b.env_map;980 child.env_map = b.env_map;
983 child.stdin_behavior = StdIo.Ignore;981 child.stdin_behavior = .Ignore;
984 child.stdout_behavior = StdIo.Pipe;982 child.stdout_behavior = .Pipe;
985 child.stderr_behavior = StdIo.Pipe;983 child.stderr_behavior = .Pipe;
986984
987 child.spawn() catch |err| debug.panic("Unable to spawn {}: {}\n", zig_args.toSliceConst()[0], @errorName(err));985 child.spawn() catch |err| debug.panic("Unable to spawn {}: {}\n", zig_args.toSliceConst()[0], @errorName(err));
988986
...@@ -999,14 +997,14 @@ pub const TranslateCContext = struct {...@@ -999,14 +997,14 @@ pub const TranslateCContext = struct {
999 debug.panic("Unable to spawn {}: {}\n", zig_args.toSliceConst()[0], @errorName(err));997 debug.panic("Unable to spawn {}: {}\n", zig_args.toSliceConst()[0], @errorName(err));
1000 };998 };
1001 switch (term) {999 switch (term) {
1002 Term.Exited => |code| {1000 .Exited => |code| {
1003 if (code != 0) {1001 if (code != 0) {
1004 warn("Compilation failed with exit code {}\n", code);1002 warn("Compilation failed with exit code {}\n", code);
1005 printInvocation(zig_args.toSliceConst());1003 printInvocation(zig_args.toSliceConst());
1006 return error.TestFailed;1004 return error.TestFailed;
1007 }1005 }
1008 },1006 },
1009 Term.Signal => |code| {1007 .Signal => |code| {
1010 warn("Compilation failed with signal {}\n", code);1008 warn("Compilation failed with signal {}\n", code);
1011 printInvocation(zig_args.toSliceConst());1009 printInvocation(zig_args.toSliceConst());
1012 return error.TestFailed;1010 return error.TestFailed;
...@@ -1131,7 +1129,7 @@ pub const TranslateCContext = struct {...@@ -1131,7 +1129,7 @@ pub const TranslateCContext = struct {
1131 self.step.dependOn(&translate_c_and_cmp.step);1129 self.step.dependOn(&translate_c_and_cmp.step);
11321130
1133 for (case.sources.toSliceConst()) |src_file| {1131 for (case.sources.toSliceConst()) |src_file| {
1134 const expanded_src_path = os.path.join(1132 const expanded_src_path = fs.path.join(
1135 b.allocator,1133 b.allocator,
1136 [][]const u8{ b.cache_root, src_file.filename },1134 [][]const u8{ b.cache_root, src_file.filename },
1137 ) catch unreachable;1135 ) catch unreachable;
...@@ -1254,7 +1252,7 @@ pub const GenHContext = struct {...@@ -1254,7 +1252,7 @@ pub const GenHContext = struct {
12541252
1255 pub fn addCase(self: *GenHContext, case: *const TestCase) void {1253 pub fn addCase(self: *GenHContext, case: *const TestCase) void {
1256 const b = self.b;1254 const b = self.b;
1257 const root_src = os.path.join(1255 const root_src = fs.path.join(
1258 b.allocator,1256 b.allocator,
1259 [][]const u8{ b.cache_root, case.sources.items[0].filename },1257 [][]const u8{ b.cache_root, case.sources.items[0].filename },
1260 ) catch unreachable;1258 ) catch unreachable;
...@@ -1269,7 +1267,7 @@ pub const GenHContext = struct {...@@ -1269,7 +1267,7 @@ pub const GenHContext = struct {
1269 obj.setBuildMode(mode);1267 obj.setBuildMode(mode);
12701268
1271 for (case.sources.toSliceConst()) |src_file| {1269 for (case.sources.toSliceConst()) |src_file| {
1272 const expanded_src_path = os.path.join(1270 const expanded_src_path = fs.path.join(
1273 b.allocator,1271 b.allocator,
1274 [][]const u8{ b.cache_root, src_file.filename },1272 [][]const u8{ b.cache_root, src_file.filename },
1275 ) catch unreachable;1273 ) catch unreachable;