| author | |
| committer | |
| log | e1f3eec9cc05535b3f3b81f2fb7cd65dd4d1e841 |
| tree | 5f408ed68a686491eaf759f9cbba02beac829b38 |
| parent | 2aa1c5da5dded6b1b346c3a1b57443f2c459ebe9 |
| parent | 3fccc0747903f0726d6cc8ee73832cb62f1304bb |
| signature |
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) |
| 6707 | 6714 | ||
| 6708 | if(WIN32) | 6715 | if(WIN32) |
| 6709 | set(LIBUSERLAND "${CMAKE_BINARY_DIR}/userland.lib") | 6716 | set(LIBUSERLAND "${CMAKE_BINARY_DIR}/userland.lib") |
| 6710 | elseif(APPLE) | ||
| 6711 | set(LIBUSERLAND "${CMAKE_BINARY_DIR}/userland.o") | ||
| 6712 | else() | 6717 | else() |
| 6713 | set(LIBUSERLAND "${CMAKE_BINARY_DIR}/libuserland.a") | 6718 | set(LIBUSERLAND "${CMAKE_BINARY_DIR}/libuserland.a") |
| 6714 | endif() | 6719 | endif() |
build.zig+17-27| ... | @@ -2,28 +2,28 @@ const builtin = @import("builtin"); | ... | @@ -2,28 +2,28 @@ const builtin = @import("builtin"); |
| 2 | const std = @import("std"); | 2 | const std = @import("std"); |
| 3 | const Builder = std.build.Builder; | 3 | const Builder = std.build.Builder; |
| 4 | const tests = @import("test/tests.zig"); | 4 | const tests = @import("test/tests.zig"); |
| 5 | const os = std.os; | ||
| 6 | const BufMap = std.BufMap; | 5 | const BufMap = std.BufMap; |
| 7 | const warn = std.debug.warn; | 6 | const warn = std.debug.warn; |
| 8 | const mem = std.mem; | 7 | const mem = std.mem; |
| 9 | const ArrayList = std.ArrayList; | 8 | const ArrayList = std.ArrayList; |
| 10 | const Buffer = std.Buffer; | 9 | const Buffer = std.Buffer; |
| 11 | const io = std.io; | 10 | const io = std.io; |
| 11 | const fs = std.fs; | ||
| 12 | 12 | ||
| 13 | pub fn build(b: *Builder) !void { | 13 | pub fn build(b: *Builder) !void { |
| 14 | const mode = b.standardReleaseOptions(); | 14 | const mode = b.standardReleaseOptions(); |
| 15 | 15 | ||
| 16 | var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig"); | 16 | var docgen_exe = b.addExecutable("docgen", "doc/docgen.zig"); |
| 17 | 17 | ||
| 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 | else | 147 | 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 | } |
| 167 | 167 | ||
| 168 | fn fileExists(filename: []const u8) !bool { | 168 | fn 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 { |
| 177 | 175 | ||
| 178 | fn addCppLib(b: *Builder, lib_exe_obj: var, cmake_binary_dir: []const u8, lib_name: []const u8) void { | 176 | fn 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 { |
| 257 | pub fn installStdLib(b: *Builder, stdlib_files: []const u8) void { | 255 | pub 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 { |
| 269 | pub fn installCHeaders(b: *Builder, c_header_files: []const u8) void { | 267 | pub 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); |
| 317 | 315 | ||
| 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++.a | 318 | \\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 | }; |
| 386 | 384 | ||
| 387 | fn addLibUserlandStep(b: *Builder) void { | 385 | fn 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 @@ |
| 1 | const builtin = @import("builtin"); | 1 | const builtin = @import("builtin"); |
| 2 | const std = @import("std"); | 2 | const std = @import("std"); |
| 3 | const io = std.io; | 3 | const io = std.io; |
| 4 | const os = std.os; | 4 | const fs = std.fs; |
| 5 | const process = std.process; | ||
| 6 | const ChildProcess = std.ChildProcess; | ||
| 5 | const warn = std.debug.warn; | 7 | const warn = std.debug.warn; |
| 6 | const mem = std.mem; | 8 | const mem = std.mem; |
| 7 | const testing = std.testing; | 9 | const 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; |
| 11 | const exe_ext = std.build.Target(std.build.Target.Native).exeFileExt(); | 13 | const exe_ext = std.build.Target(std.build.Target.Native).exeFileExt(); |
| 12 | const obj_ext = std.build.Target(std.build.Target.Native).oFileExt(); | 14 | const obj_ext = std.build.Target(std.build.Target.Native).oFileExt(); |
| 13 | const tmp_dir_name = "docgen_tmp"; | 15 | const tmp_dir_name = "docgen_tmp"; |
| 14 | const test_out_path = tmp_dir_name ++ os.path.sep_str ++ "test" ++ exe_ext; | 16 | const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext; |
| 15 | 17 | ||
| 16 | pub fn main() !void { | 18 | pub 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 { |
| 22 | 24 | ||
| 23 | const allocator = &arena.allocator; | 25 | const allocator = &arena.allocator; |
| 24 | 26 | ||
| 25 | var args_it = os.args(); | 27 | var args_it = process.args(); |
| 26 | 28 | ||
| 27 | if (!args_it.skip()) @panic("expected self arg"); | 29 | if (!args_it.skip()) @panic("expected self arg"); |
| 28 | 30 | ||
| ... | @@ -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); |
| 37 | 39 | ||
| 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(); |
| 40 | 42 | ||
| 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(); |
| 43 | 45 | ||
| 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); |
| 47 | 49 | ||
| 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); |
| 50 | 52 | ||
| 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); |
| 53 | 55 | ||
| 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 {}; |
| 56 | 58 | ||
| 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) |
| 950 | fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var, zig_exe: []const u8) !void { | 952 | fn 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; |
| 952 | 954 | ||
| 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"); |
| 955 | 957 | ||
| 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") or | 1116 | if (mem.startsWith(u8, triple, "wasm32") or |
| 1115 | mem.startsWith(u8, triple, "x86_64-linux") and | 1117 | 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 execution | 1120 | // 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}; |
| 1125 | 1127 | ||
| 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 | } |
| 1276 | 1278 | ||
| 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(); |
| 1319 | 1321 | ||
| 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 | } |
| 1368 | 1370 | ||
| 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 | } |
| 1450 | 1452 | ||
| 1451 | fn exec(allocator: *mem.Allocator, env_map: *std.BufMap, args: []const []const u8) !os.ChildProcess.ExecResult { | 1453 | fn 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; |
| 796 | threadlocal var x: i32 = 1234; | 796 | threadlocal var x: i32 = 1234; |
| 797 | 797 | ||
| 798 | test "thread local storage" { | 798 | test "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; |
| 4531 | test "cast *[1][*]const u8 to [*]const ?[*]const u8" { | 4531 | test "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#} |
| 6736 | 6736 | ||
| 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#} | ||
| 6744 | const std = @import("std"); | ||
| 6745 | const assert = std.debug.assert; | ||
| 6746 | |||
| 6747 | const Foo = struct { | ||
| 6748 | nope: i32, | ||
| 6749 | |||
| 6750 | pub var blah = "xxx"; | ||
| 6751 | const hi = 1; | ||
| 6752 | }; | ||
| 6753 | |||
| 6754 | test "@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 { |
| 8980 | const std = @import("std"); | 9012 | const std = @import("std"); |
| 8981 | 9013 | ||
| 8982 | pub fn main() !void { | 9014 | pub 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); |
| 8985 | 9017 | ||
| 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 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const io = std.io; | 2 | const io = std.io; |
| 3 | const process = std.process; | ||
| 4 | const File = std.fs.File; | ||
| 3 | const mem = std.mem; | 5 | const mem = std.mem; |
| 4 | const os = std.os; | ||
| 5 | const warn = std.debug.warn; | 6 | const warn = std.debug.warn; |
| 6 | const allocator = std.debug.global_allocator; | 7 | const allocator = std.debug.global_allocator; |
| 7 | 8 | ||
| 8 | pub fn main() !void { | 9 | pub 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 | } |
| 43 | 44 | ||
| 44 | fn cat_file(stdout: *os.File, file: *os.File) !void { | 45 | fn cat_file(stdout: *File, file: *File) !void { |
| 45 | var buf: [1024 * 4]u8 = undefined; | 46 | var buf: [1024 * 4]u8 = undefined; |
| 46 | 47 | ||
| 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"); |
| 2 | const std = @import("std"); | 2 | const std = @import("std"); |
| 3 | const io = std.io; | 3 | const io = std.io; |
| 4 | const fmt = std.fmt; | 4 | const fmt = std.fmt; |
| 5 | const os = std.os; | ||
| 6 | 5 | ||
| 7 | pub fn main() !void { | 6 | pub 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"); |
| 12 | 11 | ||
| 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"; |
| 9 | 9 | ||
| 10 | export fn main(argc: c_int, argv: **u8) c_int { | 10 | export 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 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const os = std.os; | ||
| 3 | const io = std.io; | 2 | const io = std.io; |
| 4 | const mem = std.mem; | 3 | const mem = std.mem; |
| 5 | const Allocator = mem.Allocator; | 4 | const Allocator = mem.Allocator; |
| ... | @@ -54,7 +53,7 @@ pub const ZigCompiler = struct { | ... | @@ -54,7 +53,7 @@ pub const ZigCompiler = struct { |
| 54 | }; | 53 | }; |
| 55 | 54 | ||
| 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); |
| 59 | 58 | ||
| 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 | }; |
| 306 | 306 | ||
| 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" }); |
| 491 | 491 | ||
| 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(); |
| 530 | 530 | ||
| 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); |
| 534 | 534 | ||
| 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 { |
| 558 | 558 | ||
| 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 | } |
| 564 | 564 | ||
| ... | @@ -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.real | 973 | // 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); |
| 1198 | 1198 | ||
| 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); |
| 1201 | 1201 | ||
| 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); |
| 1219 | 1219 | ||
| 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 | } |
| 1224 | 1224 | ||
| ... | @@ -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 | } |
| 1385 | 1385 | ||
| 1386 | fn getZigDir(allocator: *mem.Allocator) ![]u8 { | 1386 | fn getZigDir(allocator: *mem.Allocator) ![]u8 { |
| 1387 | return os.getAppDataDir(allocator, "zig"); | 1387 | return std.fs.getAppDataDir(allocator, "zig"); |
| 1388 | } | 1388 | } |
| 1389 | 1389 | ||
| 1390 | async fn analyzeFnType( | 1390 | async fn analyzeFnType( |
src-self-hosted/errmsg.zig+5-4| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const mem = std.mem; | 2 | const mem = std.mem; |
| 3 | const os = std.os; | 3 | const fs = std.fs; |
| 4 | const process = std.process; | ||
| 4 | const Token = std.zig.Token; | 5 | const Token = std.zig.Token; |
| 5 | const ast = std.zig.ast; | 6 | const ast = std.zig.ast; |
| 6 | const TokenIndex = std.zig.ast.TokenIndex; | 7 | const 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(); |
| 241 | 242 | ||
| 242 | const cwd = try os.getCwdAlloc(allocator); | 243 | const cwd = try process.getCwdAlloc(allocator); |
| 243 | defer allocator.free(cwd); | 244 | defer allocator.free(cwd); |
| 244 | 245 | ||
| 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); |
| 247 | 248 | ||
| 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 | } |
| 278 | 279 | ||
| 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 @@ |
| 2 | 2 | ||
| 3 | const std = @import("std"); | 3 | const std = @import("std"); |
| 4 | const mem = std.mem; | 4 | const mem = std.mem; |
| 5 | const os = std.os; | 5 | const fs = std.fs; |
| 6 | 6 | ||
| 7 | const warn = std.debug.warn; | 7 | const warn = std.debug.warn; |
| 8 | 8 | ||
| 9 | /// Caller must free result | 9 | /// Caller must free result |
| 10 | pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 { | 10 | pub 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); |
| 13 | 13 | ||
| 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); |
| 16 | 16 | ||
| 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(); |
| 19 | 19 | ||
| 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) ![ |
| 22 | 22 | ||
| 23 | /// Caller must free result | 23 | /// Caller must free result |
| 24 | pub fn findZigLibDir(allocator: *mem.Allocator) ![]u8 { | 24 | pub 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); |
| 27 | 27 | ||
| 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 "."; |
| 31 | 31 | ||
| 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"); |
| 3 | const event = std.event; | 3 | const event = std.event; |
| 4 | const Target = @import("target.zig").Target; | 4 | const Target = @import("target.zig").Target; |
| 5 | const c = @import("c.zig"); | 5 | const c = @import("c.zig"); |
| 6 | const fs = std.fs; | ||
| 6 | 7 | ||
| 7 | /// See the render function implementation for documentation of the fields. | 8 | /// See the render function implementation for documentation of the fields. |
| 8 | pub const LibCInstallation = struct { | 9 | pub 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(); |
| 36 | 37 | ||
| ... | @@ -100,7 +101,7 @@ pub const LibCInstallation = struct { | ... | @@ -100,7 +101,7 @@ pub const LibCInstallation = struct { |
| 100 | } | 101 | } |
| 101 | } | 102 | } |
| 102 | 103 | ||
| 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)); |
| 149 | 150 | ||
| 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 | } |
| 182 | 183 | ||
| 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 loop | 193 | // 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 | } |
| 206 | 207 | ||
| 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); |
| 235 | 236 | ||
| 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); |
| 256 | 257 | ||
| 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 { |
| 391 | 392 | ||
| 392 | /// caller owns returned memory | 393 | /// caller owns returned memory |
| 393 | async fn ccPrintFileName(loop: *event.Loop, o_file: []const u8, want_dirname: bool) ![]u8 { | 394 | async 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 }; |
| 398 | 399 | ||
| 399 | // TODO This simulates evented I/O for the child process exec | 400 | // 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; |
| 425 | 426 | ||
| 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 | } |
| 460 | 461 | ||
| 461 | fn fileExists(path: []const u8) !bool { | 462 | fn 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 | } |
| 304 | 304 | ||
| 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"); |
| 308 | 308 | ||
| ... | @@ -311,7 +311,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void { | ... | @@ -311,7 +311,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void { |
| 311 | } | 311 | } |
| 312 | 312 | ||
| 313 | fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void { | 313 | fn 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"); |
| 4 | const event = std.event; | 4 | const event = std.event; |
| 5 | const os = std.os; | 5 | const os = std.os; |
| 6 | const io = std.io; | 6 | const io = std.io; |
| 7 | const fs = std.fs; | ||
| 7 | const mem = std.mem; | 8 | const mem = std.mem; |
| 9 | const process = std.process; | ||
| 8 | const Allocator = mem.Allocator; | 10 | const Allocator = mem.Allocator; |
| 9 | const ArrayList = std.ArrayList; | 11 | const ArrayList = std.ArrayList; |
| 10 | const Buffer = std.Buffer; | 12 | const Buffer = std.Buffer; |
| ... | @@ -20,9 +22,9 @@ const Target = @import("target.zig").Target; | ... | @@ -20,9 +22,9 @@ const Target = @import("target.zig").Target; |
| 20 | const errmsg = @import("errmsg.zig"); | 22 | const errmsg = @import("errmsg.zig"); |
| 21 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; | 23 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; |
| 22 | 24 | ||
| 23 | var stderr_file: os.File = undefined; | 25 | var stderr_file: fs.File = undefined; |
| 24 | var stderr: *io.OutStream(os.File.WriteError) = undefined; | 26 | var stderr: *io.OutStream(fs.File.WriteError) = undefined; |
| 25 | var stdout: *io.OutStream(os.File.WriteError) = undefined; | 27 | var stdout: *io.OutStream(fs.File.WriteError) = undefined; |
| 26 | 28 | ||
| 27 | pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB | 29 | pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB |
| 28 | 30 | ||
| ... | @@ -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; |
| 64 | 66 | ||
| 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 happen | 68 | // TODO I'm getting unreachable code here, which shouldn't happen |
| 67 | //defer os.argsFree(allocator, args); | 69 | //defer process.argsFree(allocator, args); |
| 68 | 70 | ||
| 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 | } |
| 74 | 76 | ||
| 75 | const commands = []Command{ | 77 | const commands = []Command{ |
| ... | @@ -125,7 +127,7 @@ pub fn main() !void { | ... | @@ -125,7 +127,7 @@ pub fn main() !void { |
| 125 | 127 | ||
| 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 | } |
| 130 | 132 | ||
| 131 | const usage_build_generic = | 133 | const 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 |
| 256 | 258 | ||
| 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 | } |
| 261 | 263 | ||
| 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 | } |
| 331 | 333 | ||
| 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 | } |
| 336 | 338 | ||
| 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 | }; |
| 346 | 348 | ||
| 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 | }; |
| 357 | 359 | ||
| ... | @@ -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 | } |
| 366 | 368 | ||
| 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 | } |
| 371 | 373 | ||
| 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); |
| 381 | 383 | ||
| 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); |
| 384 | 386 | ||
| 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 |
| 448 | 450 | ||
| 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 | } |
| 453 | 455 | ||
| 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 { |
| 478 | 480 | ||
| 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 | } |
| 557 | 559 | ||
| ... | @@ -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 | } |
| 571 | 573 | ||
| ... | @@ -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 { |
| 584 | 586 | ||
| 585 | async fn findLibCAsync(zig_compiler: *ZigCompiler) void { | 587 | async 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 | } |
| 592 | 594 | ||
| 593 | fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { | 595 | fn 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 { |
| 596 | 598 | ||
| 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 | } |
| 601 | 603 | ||
| 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 | } |
| 621 | 623 | ||
| 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 { |
| 627 | 629 | ||
| 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(); |
| 633 | 635 | ||
| ... | @@ -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 | } |
| 649 | 651 | ||
| 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 { |
| 653 | 655 | ||
| 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 | } |
| 658 | 660 | ||
| 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; | ||
| 704 | 707 | ||
| 705 | async fn asyncFmtMain( | 708 | async 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 | } |
| 731 | 734 | ||
| ... | @@ -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(); |
| 752 | 755 | ||
| 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 | } |
| 850 | 853 | ||
| 851 | fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void { | 854 | fn 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 | } |
| 854 | 857 | ||
| 855 | const args_test_spec = []Flag{Flag.Bool("--help")}; | 858 | const args_test_spec = []Flag{Flag.Bool("--help")}; |
| ... | @@ -891,7 +894,7 @@ const usage_internal = | ... | @@ -891,7 +894,7 @@ const usage_internal = |
| 891 | fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void { | 894 | fn 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 | } |
| 896 | 899 | ||
| 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 | } |
| 935 | 938 |
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. |
| 3 | 3 | ||
| 4 | const std = @import("std"); | ||
| 5 | const builtin = @import("builtin"); | 4 | const builtin = @import("builtin"); |
| 5 | const std = @import("std"); | ||
| 6 | const io = std.io; | ||
| 7 | const mem = std.mem; | ||
| 8 | const fs = std.fs; | ||
| 9 | const process = std.process; | ||
| 10 | const Allocator = mem.Allocator; | ||
| 11 | const ArrayList = std.ArrayList; | ||
| 12 | const Buffer = std.Buffer; | ||
| 13 | const arg = @import("arg.zig"); | ||
| 14 | const self_hosted_main = @import("main.zig"); | ||
| 15 | const Args = arg.Args; | ||
| 16 | const Flag = arg.Flag; | ||
| 17 | const errmsg = @import("errmsg.zig"); | ||
| 18 | |||
| 19 | var stderr_file: fs.File = undefined; | ||
| 20 | var stderr: *io.OutStream(fs.File.WriteError) = undefined; | ||
| 21 | var stdout: *io.OutStream(fs.File.WriteError) = undefined; | ||
| 6 | 22 | ||
| 7 | // ABI warning | 23 | // ABI warning |
| 8 | export fn stage2_zen(ptr: *[*]const u8, len: *usize) void { | 24 | export 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 { |
| 157 | 173 | ||
| 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 | } |
| 162 | 178 | ||
| 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 | } |
| 182 | 198 | ||
| 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 { |
| 188 | 204 | ||
| 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(); |
| 194 | 210 | ||
| ... | @@ -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 | } |
| 207 | 223 | ||
| 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 { |
| 211 | 227 | ||
| 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 | } |
| 216 | 232 | ||
| 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 | } |
| 233 | 249 | ||
| ... | @@ -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; |
| 254 | 270 | ||
| 255 | fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void { | 271 | fn 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(); |
| 266 | 282 | ||
| 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 | |||
| 381 | const os = std.os; | ||
| 382 | const io = std.io; | ||
| 383 | const mem = std.mem; | ||
| 384 | const Allocator = mem.Allocator; | ||
| 385 | const ArrayList = std.ArrayList; | ||
| 386 | const Buffer = std.Buffer; | ||
| 387 | |||
| 388 | const arg = @import("arg.zig"); | ||
| 389 | const self_hosted_main = @import("main.zig"); | ||
| 390 | const Args = arg.Args; | ||
| 391 | const Flag = arg.Flag; | ||
| 392 | const errmsg = @import("errmsg.zig"); | ||
| 393 | |||
| 394 | var stderr_file: os.File = undefined; | ||
| 395 | var stderr: *io.OutStream(os.File.WriteError) = undefined; | ||
| 396 | var 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); |
| 57 | 57 | ||
| 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 | } |
| 61 | 61 | ||
| 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 }); |
| 91 | 91 | ||
| 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 | } |
| 95 | 95 | ||
| 96 | // TODO async I/O | 96 | // 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 }); |
| 124 | 124 | ||
| 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 | } |
| 129 | 129 | ||
| 130 | // TODO async I/O | 130 | // 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 loop | 166 | // 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( |
| 152 | 152 | ||
| 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; | ||
| 156 | 155 | ||
| 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 | }; |
| 165 | 176 | ||
| 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); |
| 178 | 178 | ||
| 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 | }; |
| 1475 | 1476 | ||
| 1476 | struct BuiltinFnEntry { | 1477 | struct 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 | }; |
| 2301 | 2303 | ||
| 2302 | struct IrInstruction { | 2304 | struct IrInstruction { |
| ... | @@ -3503,6 +3505,13 @@ struct IrInstructionAssertNonNull { | ... | @@ -3503,6 +3505,13 @@ struct IrInstructionAssertNonNull { |
| 3503 | IrInstruction *target; | 3505 | IrInstruction *target; |
| 3504 | }; | 3506 | }; |
| 3505 | 3507 | ||
| 3508 | struct IrInstructionHasDecl { | ||
| 3509 | IrInstruction base; | ||
| 3510 | |||
| 3511 | IrInstruction *container; | ||
| 3512 | IrInstruction *name; | ||
| 3513 | }; | ||
| 3514 | |||
| 3506 | static const size_t slice_ptr_index = 0; | 3515 | static const size_t slice_ptr_index = 0; |
| 3507 | static const size_t slice_len_index = 1; | 3516 | static const size_t slice_len_index = 1; |
| 3508 | 3517 |
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(); |
| 5620 | 5621 | ||
| 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 | } |
| 7413 | 7415 | ||
| 7414 | static const char *bool_to_str(bool b) { | 7416 | static 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 | } |
| 1013 | 1013 | ||
| 1014 | static constexpr IrInstructionId ir_instruction_id(IrInstructionHasDecl *) { | ||
| 1015 | return IrInstructionIdHasDecl; | ||
| 1016 | } | ||
| 1017 | |||
| 1014 | template<typename T> | 1018 | template<typename T> |
| 1015 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { | 1019 | static 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 | } |
| 3016 | 3020 | ||
| 3021 | static 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 | |||
| 3017 | static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *scope_is_comptime, IrInstruction *is_comptime) { | 3034 | static 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 | } |
| 11491 | 11523 | ||
| 11524 | static 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 | |||
| 11492 | static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, | 11537 | static 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 |
| 11863 | 11908 | ||
| 11864 | // cast from *T and [*]T to *c_void and ?*c_void | 11909 | // cast from *T and [*]T to *c_void and ?*c_void |
| 11865 | // but don't do it if the actual type is a double pointer | 11910 | // 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 | } |
| 23175 | 23212 | ||
| 23213 | static 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 | |||
| 23176 | static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { | 23240 | static 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; |
| 23707 | 23774 | ||
| 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 | } |
| 1455 | 1455 | ||
| 1456 | static 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 | |||
| 1456 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | 1464 | static 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 | } |
| 777 | 777 | ||
| 778 | static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path, OutType child_out_type) { | 778 | static 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 | } |
| 197 | 197 | ||
| 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 fuzz | 223 | 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; |
| 240 | 240 | ||
| 241 | while (ctx.queue.get()) |node| { | 241 | while (ctx.queue.get()) |node| { |
| 242 | std.os.time.sleep(1); // let the os scheduler be our fuzz | 242 | 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 | } |
| 131 | 131 | ||
| 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 fuzz | 157 | 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; |
| 173 | 173 | ||
| 174 | while (ctx.stack.pop()) |node| { | 174 | while (ctx.stack.pop()) |node| { |
| 175 | std.os.time.sleep(1); // let the os scheduler be our fuzz | 175 | 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 | }; |
| 140 | 140 | ||
| 141 | test "simple Buffer" { | 141 | test "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())); |
| 151 | 149 | ||
| 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 @@ |
| 1 | const std = @import("std.zig"); | 1 | const std = @import("std.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const io = std.io; | 3 | const io = std.io; |
| 4 | const fs = std.fs; | ||
| 4 | const mem = std.mem; | 5 | const mem = std.mem; |
| 5 | const debug = std.debug; | 6 | const debug = std.debug; |
| 6 | const assert = debug.assert; | 7 | const assert = debug.assert; |
| ... | @@ -8,12 +9,11 @@ const warn = std.debug.warn; | ... | @@ -8,12 +9,11 @@ const warn = std.debug.warn; |
| 8 | const ArrayList = std.ArrayList; | 9 | const ArrayList = std.ArrayList; |
| 9 | const HashMap = std.HashMap; | 10 | const HashMap = std.HashMap; |
| 10 | const Allocator = mem.Allocator; | 11 | const Allocator = mem.Allocator; |
| 11 | const os = std.os; | 12 | const process = std.process; |
| 12 | const StdIo = os.ChildProcess.StdIo; | ||
| 13 | const Term = os.ChildProcess.Term; | ||
| 14 | const BufSet = std.BufSet; | 13 | const BufSet = std.BufSet; |
| 15 | const BufMap = std.BufMap; | 14 | const BufMap = std.BufMap; |
| 16 | const fmt_lib = std.fmt; | 15 | const fmt_lib = std.fmt; |
| 16 | const File = std.fs.File; | ||
| 17 | 17 | ||
| 18 | pub const FmtStep = @import("build/fmt.zig").FmtStep; | 18 | pub const FmtStep = @import("build/fmt.zig").FmtStep; |
| 19 | 19 | ||
| ... | @@ -95,11 +95,11 @@ pub const Builder = struct { | ... | @@ -95,11 +95,11 @@ pub const Builder = struct { |
| 95 | 95 | ||
| 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 { |
| 153 | 153 | ||
| 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 default | 155 | 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 | } |
| 159 | 159 | ||
| 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 | } |
| 291 | 291 | ||
| 292 | // TODO remove empty directories | 292 | // TODO remove empty directories |
| ... | @@ -325,7 +325,7 @@ pub const Builder = struct { | ... | @@ -325,7 +325,7 @@ pub const Builder = struct { |
| 325 | 325 | ||
| 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 | } |
| 603 | 603 | ||
| 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(); |
| 606 | 606 | ||
| 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 | }; |
| 614 | 614 | ||
| 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 | } |
| 631 | 631 | ||
| 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 { |
| 651 | 651 | ||
| 652 | ///::dest_rel_path is relative to prefix path or it can be an absolute path | 652 | ///::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 | } |
| 669 | 669 | ||
| 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 | } |
| 673 | 673 | ||
| 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 | } |
| 678 | 678 | ||
| 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 | } |
| 690 | 690 | ||
| 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 | } |
| 694 | 694 | ||
| 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); |
| 749 | 749 | ||
| 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(); |
| 753 | 753 | ||
| 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; |
| 757 | 757 | ||
| 758 | try child.spawn(); | 758 | try child.spawn(); |
| 759 | 759 | ||
| ... | @@ -765,7 +765,7 @@ pub const Builder = struct { | ... | @@ -765,7 +765,7 @@ pub const Builder = struct { |
| 765 | 765 | ||
| 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 | } |
| 847 | 847 | ||
| 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 | } |
| 858 | 858 | ||
| 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 | } |
| 865 | 865 | ||
| 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 | } |
| 872 | 872 | ||
| 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 | } |
| 879 | 879 | ||
| 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 | } |
| 886 | 886 | ||
| 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 | } |
| 893 | 893 | ||
| 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 | } |
| 900 | 900 | ||
| 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 { |
| 1064 | 1064 | ||
| 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); |
| 1366 | 1366 | ||
| 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 | } |
| 1391 | 1391 | ||
| 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 { |
| 1575 | 1575 | ||
| 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 | } |
| 1580 | 1580 | ||
| 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 | } |
| 1637 | 1637 | ||
| 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 | } |
| 1648 | 1648 | ||
| 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; |
| 1743 | 1743 | ||
| 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); |
| 1845 | 1845 | ||
| 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 | }; |
| 1887 | 1887 | ||
| 1888 | fn doAtomicSymLinks(allocator: *Allocator, output_path: []const u8, filename_major_only: []const u8, filename_name_only: []const u8) !void { | 1888 | fn 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.3 | 1891 | // 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.1 | 1900 | // 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 @@ |
| 1 | const builtin = @import("builtin"); | 1 | const builtin = @import("builtin"); |
| 2 | const Os = builtin.Os; | 2 | const std = @import("std"); |
| 3 | const page_size = std.mem.page_size; | ||
| 4 | |||
| 5 | pub use @import("os/bits.zig"); | ||
| 3 | 6 | ||
| 4 | pub use switch (builtin.os) { | 7 | pub 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 | }; |
| 12 | 15 | ||
| 16 | pub 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 file | 24 | // TODO https://github.com/ziglang/zig/issues/265 on this whole file |
| 14 | 25 | ||
| 15 | pub const FILE = @OpaqueType(); | ||
| 16 | pub extern "c" fn fopen(filename: [*]const u8, modes: [*]const u8) ?*FILE; | 26 | pub extern "c" fn fopen(filename: [*]const u8, modes: [*]const u8) ?*FILE; |
| 17 | pub extern "c" fn fclose(stream: *FILE) c_int; | 27 | pub extern "c" fn fclose(stream: *FILE) c_int; |
| 18 | pub extern "c" fn fwrite(ptr: [*]const u8, size_of_type: usize, item_count: usize, stream: *FILE) usize; | 28 | pub extern "c" fn fwrite(ptr: [*]const u8, size_of_type: usize, item_count: usize, stream: *FILE) usize; |
| ... | @@ -20,33 +30,38 @@ pub extern "c" fn fread(ptr: [*]u8, size_of_type: usize, item_count: usize, stre | ... | @@ -20,33 +30,38 @@ pub extern "c" fn fread(ptr: [*]u8, size_of_type: usize, item_count: usize, stre |
| 20 | 30 | ||
| 21 | pub extern "c" fn abort() noreturn; | 31 | pub extern "c" fn abort() noreturn; |
| 22 | pub extern "c" fn exit(code: c_int) noreturn; | 32 | pub extern "c" fn exit(code: c_int) noreturn; |
| 23 | pub extern "c" fn isatty(fd: c_int) c_int; | 33 | pub extern "c" fn isatty(fd: fd_t) c_int; |
| 24 | pub extern "c" fn close(fd: c_int) c_int; | 34 | pub extern "c" fn close(fd: fd_t) c_int; |
| 25 | pub extern "c" fn fstat(fd: c_int, buf: *Stat) c_int; | 35 | pub extern "c" fn @"close$NOCANCEL"(fd: fd_t) c_int; |
| 26 | pub extern "c" fn @"fstat$INODE64"(fd: c_int, buf: *Stat) c_int; | 36 | pub extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int; |
| 27 | pub extern "c" fn lseek(fd: c_int, offset: isize, whence: c_int) isize; | 37 | pub extern "c" fn @"fstat$INODE64"(fd: fd_t, buf: *Stat) c_int; |
| 28 | pub extern "c" fn open(path: [*]const u8, oflag: c_int, ...) c_int; | 38 | pub extern "c" fn lseek(fd: fd_t, offset: isize, whence: c_int) isize; |
| 39 | pub extern "c" fn open(path: [*]const u8, oflag: c_uint, ...) c_int; | ||
| 29 | pub extern "c" fn raise(sig: c_int) c_int; | 40 | pub extern "c" fn raise(sig: c_int) c_int; |
| 30 | pub extern "c" fn read(fd: c_int, buf: *c_void, nbyte: usize) isize; | 41 | pub extern "c" fn read(fd: fd_t, buf: [*]u8, nbyte: usize) isize; |
| 31 | pub extern "c" fn pread(fd: c_int, buf: *c_void, nbyte: usize, offset: u64) isize; | 42 | pub extern "c" fn pread(fd: fd_t, buf: [*]u8, nbyte: usize, offset: u64) isize; |
| 43 | pub extern "c" fn preadv(fd: c_int, iov: [*]const iovec, iovcnt: c_uint, offset: usize) isize; | ||
| 44 | pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: usize) isize; | ||
| 32 | pub extern "c" fn stat(noalias path: [*]const u8, noalias buf: *Stat) c_int; | 45 | pub extern "c" fn stat(noalias path: [*]const u8, noalias buf: *Stat) c_int; |
| 33 | pub extern "c" fn write(fd: c_int, buf: *const c_void, nbyte: usize) isize; | 46 | pub extern "c" fn write(fd: fd_t, buf: [*]const u8, nbyte: usize) isize; |
| 34 | pub extern "c" fn pwrite(fd: c_int, buf: *const c_void, nbyte: usize, offset: u64) isize; | 47 | pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: u64) isize; |
| 35 | pub extern "c" fn mmap(addr: ?*c_void, len: usize, prot: c_int, flags: c_int, fd: c_int, offset: isize) ?*c_void; | 48 | pub extern "c" fn mmap(addr: ?*align(page_size) c_void, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: isize) *c_void; |
| 36 | pub extern "c" fn munmap(addr: ?*c_void, len: usize) c_int; | 49 | pub extern "c" fn munmap(addr: *align(page_size) c_void, len: usize) c_int; |
| 50 | pub extern "c" fn mprotect(addr: *align(page_size) c_void, len: usize, prot: c_uint) c_int; | ||
| 37 | pub extern "c" fn unlink(path: [*]const u8) c_int; | 51 | pub extern "c" fn unlink(path: [*]const u8) c_int; |
| 38 | pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8; | 52 | pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8; |
| 39 | pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_int, options: c_int) c_int; | 53 | pub extern "c" fn waitpid(pid: c_int, stat_loc: *c_uint, options: c_uint) c_int; |
| 40 | pub extern "c" fn fork() c_int; | 54 | pub extern "c" fn fork() c_int; |
| 41 | pub extern "c" fn access(path: [*]const u8, mode: c_uint) c_int; | 55 | pub extern "c" fn access(path: [*]const u8, mode: c_uint) c_int; |
| 42 | pub extern "c" fn pipe(fds: *[2]c_int) c_int; | 56 | pub extern "c" fn pipe(fds: *[2]fd_t) c_int; |
| 57 | pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int; | ||
| 43 | pub extern "c" fn mkdir(path: [*]const u8, mode: c_uint) c_int; | 58 | pub extern "c" fn mkdir(path: [*]const u8, mode: c_uint) c_int; |
| 44 | pub extern "c" fn symlink(existing: [*]const u8, new: [*]const u8) c_int; | 59 | pub extern "c" fn symlink(existing: [*]const u8, new: [*]const u8) c_int; |
| 45 | pub extern "c" fn rename(old: [*]const u8, new: [*]const u8) c_int; | 60 | pub extern "c" fn rename(old: [*]const u8, new: [*]const u8) c_int; |
| 46 | pub extern "c" fn chdir(path: [*]const u8) c_int; | 61 | pub extern "c" fn chdir(path: [*]const u8) c_int; |
| 47 | pub extern "c" fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) c_int; | 62 | pub extern "c" fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) c_int; |
| 48 | pub extern "c" fn dup(fd: c_int) c_int; | 63 | pub extern "c" fn dup(fd: fd_t) c_int; |
| 49 | pub extern "c" fn dup2(old_fd: c_int, new_fd: c_int) c_int; | 64 | pub extern "c" fn dup2(old_fd: fd_t, new_fd: fd_t) c_int; |
| 50 | pub extern "c" fn readlink(noalias path: [*]const u8, noalias buf: [*]u8, bufsize: usize) isize; | 65 | pub extern "c" fn readlink(noalias path: [*]const u8, noalias buf: [*]u8, bufsize: usize) isize; |
| 51 | pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*]u8; | 66 | pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*]u8; |
| 52 | pub extern "c" fn sigprocmask(how: c_int, noalias set: *const sigset_t, noalias oset: ?*sigset_t) c_int; | 67 | pub extern "c" fn sigprocmask(how: c_int, noalias set: *const sigset_t, noalias oset: ?*sigset_t) c_int; |
| ... | @@ -56,6 +71,25 @@ pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int; | ... | @@ -56,6 +71,25 @@ pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int; |
| 56 | pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int; | 71 | pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int; |
| 57 | pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int; | 72 | pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int; |
| 58 | pub extern "c" fn rmdir(path: [*]const u8) c_int; | 73 | pub extern "c" fn rmdir(path: [*]const u8) c_int; |
| 74 | pub extern "c" fn getenv(name: [*]const u8) ?[*]u8; | ||
| 75 | pub extern "c" fn sysctl(name: [*]const c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int; | ||
| 76 | pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int; | ||
| 77 | pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int; | ||
| 78 | |||
| 79 | pub extern "c" fn bind(socket: fd_t, address: ?*const sockaddr, address_len: socklen_t) c_int; | ||
| 80 | pub extern "c" fn socket(domain: c_uint, sock_type: c_uint, protocol: c_uint) c_int; | ||
| 81 | pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int; | ||
| 82 | pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int; | ||
| 83 | pub extern "c" fn connect(sockfd: fd_t, sock_addr: *const sockaddr, addrlen: socklen_t) c_int; | ||
| 84 | pub extern "c" fn accept4(sockfd: fd_t, addr: *sockaddr, addrlen: *socklen_t, flags: c_uint) c_int; | ||
| 85 | pub extern "c" fn getsockopt(sockfd: fd_t, level: c_int, optname: c_int, optval: *c_void, optlen: *socklen_t) c_int; | ||
| 86 | pub extern "c" fn kill(pid: pid_t, sig: c_int) c_int; | ||
| 87 | pub extern "c" fn getdirentries(fd: fd_t, buf_ptr: [*]u8, nbytes: usize, basep: *i64) isize; | ||
| 88 | pub extern "c" fn openat(fd: c_int, path: [*]const u8, flags: c_int) c_int; | ||
| 89 | pub extern "c" fn setgid(ruid: c_uint, euid: c_uint) c_int; | ||
| 90 | pub extern "c" fn setuid(uid: c_uint) c_int; | ||
| 91 | pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int; | ||
| 92 | pub extern "c" fn clock_getres(clk_id: c_int, tp: *timespec) c_int; | ||
| 59 | 93 | ||
| 60 | pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?*c_void; | 94 | pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?*c_void; |
| 61 | pub extern "c" fn malloc(usize) ?*c_void; | 95 | pub 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; |
| 63 | pub extern "c" fn free(*c_void) void; | 97 | pub extern "c" fn free(*c_void) void; |
| 64 | pub extern "c" fn posix_memalign(memptr: **c_void, alignment: usize, size: usize) c_int; | 98 | pub extern "c" fn posix_memalign(memptr: **c_void, alignment: usize, size: usize) c_int; |
| 65 | 99 | ||
| 66 | pub extern "pthread" fn pthread_create(noalias newthread: *pthread_t, noalias attr: ?*const pthread_attr_t, start_routine: extern fn (?*c_void) ?*c_void, noalias arg: ?*c_void) c_int; | 100 | pub extern "c" fn pthread_create(noalias newthread: *pthread_t, noalias attr: ?*const pthread_attr_t, start_routine: extern fn (?*c_void) ?*c_void, noalias arg: ?*c_void) c_int; |
| 67 | pub extern "pthread" fn pthread_attr_init(attr: *pthread_attr_t) c_int; | 101 | pub extern "c" fn pthread_attr_init(attr: *pthread_attr_t) c_int; |
| 68 | pub extern "pthread" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int; | 102 | pub extern "c" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int; |
| 69 | pub extern "pthread" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int; | 103 | pub extern "c" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int; |
| 70 | pub extern "pthread" fn pthread_self() pthread_t; | 104 | pub extern "c" fn pthread_self() pthread_t; |
| 71 | pub extern "pthread" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int; | 105 | pub extern "c" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int; |
| 72 | 106 | ||
| 73 | pub const pthread_t = *@OpaqueType(); | 107 | pub extern "c" fn kqueue() c_int; |
| 108 | pub 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 @@ |
| 1 | const macho = @import("../macho.zig"); | 1 | const std = @import("../std.zig"); |
| 2 | const assert = std.debug.assert; | ||
| 3 | const builtin = @import("builtin"); | ||
| 4 | const macho = std.macho; | ||
| 5 | |||
| 6 | use @import("../os/bits.zig"); | ||
| 2 | 7 | ||
| 3 | extern "c" fn __error() *c_int; | 8 | extern "c" fn __error() *c_int; |
| 4 | pub extern "c" fn _NSGetExecutablePath(buf: [*]u8, bufsize: *u32) c_int; | 9 | pub extern "c" fn _NSGetExecutablePath(buf: [*]u8, bufsize: *u32) c_int; |
| 5 | pub extern "c" fn _dyld_get_image_header(image_index: u32) ?*mach_header; | 10 | pub extern "c" fn _dyld_get_image_header(image_index: u32) ?*mach_header; |
| 6 | 11 | ||
| 7 | pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: [*]u8, buf_len: usize, basep: *i64) usize; | 12 | pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: [*]u8, buf_len: usize, basep: *i64) isize; |
| 8 | 13 | ||
| 9 | pub extern "c" fn mach_absolute_time() u64; | 14 | pub extern "c" fn mach_absolute_time() u64; |
| 10 | pub extern "c" fn mach_timebase_info(tinfo: ?*mach_timebase_info_data) void; | 15 | pub extern "c" fn mach_timebase_info(tinfo: ?*mach_timebase_info_data) void; |
| 11 | 16 | ||
| 12 | pub extern "c" fn kqueue() c_int; | ||
| 13 | pub 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 | |||
| 22 | pub extern "c" fn kevent64( | 17 | pub 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; |
| 31 | 26 | ||
| 32 | pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int; | ||
| 33 | pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int; | ||
| 34 | pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int; | ||
| 35 | |||
| 36 | pub extern "c" fn bind(socket: c_int, address: ?*const sockaddr, address_len: socklen_t) c_int; | ||
| 37 | pub extern "c" fn socket(domain: c_int, type: c_int, protocol: c_int) c_int; | ||
| 38 | |||
| 39 | const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header; | 27 | const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header; |
| 40 | 28 | ||
| 41 | /// The value of the link editor defined symbol _MH_EXECUTE_SYM is the address | 29 | /// 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. |
| 49 | pub extern "c" var _mh_execute_header: mach_hdr = undefined; | 37 | pub extern "c" var _mh_execute_header: mach_hdr = undefined; |
| 50 | comptime { | 38 | comptime { |
| 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 | } |
| 53 | 43 | ||
| 54 | pub const mach_header_64 = macho.mach_header_64; | 44 | pub const mach_header_64 = macho.mach_header_64; |
| 55 | pub const mach_header = macho.mach_header; | 45 | pub const mach_header = macho.mach_header; |
| 56 | 46 | ||
| 57 | pub use @import("../os/darwin/errno.zig"); | ||
| 58 | |||
| 59 | pub const _errno = __error; | 47 | pub const _errno = __error; |
| 60 | 48 | ||
| 61 | pub const in_port_t = u16; | 49 | pub extern "c" fn mach_host_self() mach_port_t; |
| 62 | pub const sa_family_t = u8; | 50 | pub extern "c" fn clock_get_time(clock_serv: clock_serv_t, cur_time: *mach_timespec_t) kern_return_t; |
| 63 | pub const socklen_t = u32; | 51 | pub extern "c" fn host_get_clock_service(host: host_t, clock_id: clock_id_t, clock_serv: ?[*]clock_serv_t) kern_return_t; |
| 64 | pub const sockaddr = extern union { | 52 | pub 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 | }; | ||
| 68 | pub 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 | }; | ||
| 75 | pub 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 | |||
| 84 | pub const timeval = extern struct { | ||
| 85 | tv_sec: c_long, | ||
| 86 | tv_usec: i32, | ||
| 87 | }; | ||
| 88 | |||
| 89 | pub const timezone = extern struct { | ||
| 90 | tz_minuteswest: i32, | ||
| 91 | tz_dsttime: i32, | ||
| 92 | }; | ||
| 93 | |||
| 94 | pub 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. | ||
| 100 | pub 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 | }; | ||
| 124 | 53 | ||
| 125 | pub const timespec = extern struct { | 54 | pub fn sigaddset(set: *sigset_t, signo: u5) void { |
| 126 | tv_sec: isize, | 55 | set.* |= u32(1) << (signo - 1); |
| 127 | tv_nsec: isize, | ||
| 128 | }; | ||
| 129 | |||
| 130 | pub const sigset_t = u32; | ||
| 131 | |||
| 132 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name. | ||
| 133 | pub const Sigaction = extern struct { | ||
| 134 | handler: extern fn (c_int) void, | ||
| 135 | sa_mask: sigset_t, | ||
| 136 | sa_flags: c_int, | ||
| 137 | }; | ||
| 138 | |||
| 139 | pub 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 | |||
| 148 | pub 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. | ||
| 154 | pub 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. | ||
| 166 | const std = @import("../std.zig"); | ||
| 167 | const assert = std.debug.assert; | ||
| 168 | |||
| 169 | comptime { | ||
| 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 | |||
| 178 | pub 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 | |||
| 188 | pub const mach_port_t = c_uint; | ||
| 189 | pub const clock_serv_t = mach_port_t; | ||
| 190 | pub const clock_res_t = c_int; | ||
| 191 | pub const mach_port_name_t = natural_t; | ||
| 192 | pub const natural_t = c_uint; | ||
| 193 | pub const mach_timespec_t = extern struct { | ||
| 194 | tv_sec: c_uint, | ||
| 195 | tv_nsec: clock_res_t, | ||
| 196 | }; | ||
| 197 | pub const kern_return_t = c_int; | ||
| 198 | pub const host_t = mach_port_t; | ||
| 199 | pub const CALENDAR_CLOCK = 1; | ||
| 200 | |||
| 201 | pub extern fn mach_host_self() mach_port_t; | ||
| 202 | pub extern fn clock_get_time(clock_serv: clock_serv_t, cur_time: *mach_timespec_t) kern_return_t; | ||
| 203 | pub extern fn host_get_clock_service(host: host_t, clock_id: clock_id_t, clock_serv: ?[*]clock_serv_t) kern_return_t; | ||
| 204 | pub 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. | ||
| 209 | comptime { | ||
| 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 @@ |
| 1 | extern "c" fn __error() *c_int; | 1 | extern "c" fn __error() *c_int; |
| 2 | pub const _errno = __error; | 2 | pub const _errno = __error; |
| 3 | 3 | ||
| 4 | pub extern "c" fn kqueue() c_int; | ||
| 5 | pub 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; | ||
| 13 | pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int; | ||
| 14 | pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int; | ||
| 15 | pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int; | ||
| 16 | pub extern "c" fn getdirentries(fd: c_int, buf_ptr: [*]u8, nbytes: usize, basep: *i64) usize; | ||
| 17 | pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize; | 4 | pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize; |
| 18 | pub extern "c" fn pipe2(arg0: *[2]c_int, arg1: u32) c_int; | ||
| 19 | pub extern "c" fn preadv(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize; | ||
| 20 | pub extern "c" fn pwritev(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize; | ||
| 21 | pub extern "c" fn openat(fd: c_int, path: ?[*]const u8, flags: c_int) c_int; | ||
| 22 | pub extern "c" fn setgid(ruid: c_uint, euid: c_uint) c_int; | ||
| 23 | pub extern "c" fn setuid(uid: c_uint) c_int; | ||
| 24 | pub extern "c" fn kill(pid: c_int, sig: c_int) c_int; | ||
| 25 | pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int; | ||
| 26 | pub 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. | ||
| 29 | pub 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 | |||
| 39 | pub const pthread_attr_t = extern struct { | ||
| 40 | __size: [56]u8, | ||
| 41 | __align: c_long, | ||
| 42 | }; | ||
| 43 | |||
| 44 | pub 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 | |||
| 67 | pub 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 | |||
| 90 | pub 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 | |||
| 115 | pub const timespec = extern struct { | ||
| 116 | tv_sec: isize, | ||
| 117 | tv_nsec: isize, | ||
| 118 | }; | ||
| 119 | |||
| 120 | pub 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 | |||
| 131 | pub const in_port_t = u16; | ||
| 132 | pub const sa_family_t = u16; | ||
| 133 | |||
| 134 | pub const sockaddr = extern union { | ||
| 135 | in: sockaddr_in, | ||
| 136 | in6: sockaddr_in6, | ||
| 137 | }; | ||
| 138 | |||
| 139 | pub 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 | |||
| 147 | pub 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 @@ |
| 1 | const linux = @import("../os/linux.zig"); | 1 | const std = @import("../std.zig"); |
| 2 | pub use @import("../os/linux/errno.zig"); | 2 | use std.c; |
| 3 | 3 | ||
| 4 | pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) c_int; | ||
| 5 | extern "c" fn __errno_location() *c_int; | 4 | extern "c" fn __errno_location() *c_int; |
| 6 | pub const _errno = __errno_location; | 5 | pub const _errno = __errno_location; |
| 7 | 6 | ||
| 8 | pub const pthread_attr_t = extern struct { | 7 | pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) c_int; |
| 9 | __size: [56]u8, | 8 | pub extern "c" fn sched_getaffinity(pid: c_int, size: usize, set: *cpu_set_t) c_int; |
| 10 | __align: c_long, | 9 | pub extern "c" fn eventfd(initval: c_uint, flags: c_uint) c_int; |
| 11 | }; | 10 | pub extern "c" fn epoll_ctl(epfd: fd_t, op: c_uint, fd: fd_t, event: *epoll_event) c_int; |
| 11 | pub extern "c" fn epoll_create1(flags: c_uint) c_int; | ||
| 12 | pub extern "c" fn epoll_wait(epfd: fd_t, events: [*]epoll_event, maxevents: c_uint, timeout: c_int) c_int; | ||
| 13 | pub 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; | ||
| 20 | pub extern "c" fn inotify_init1(flags: c_uint) c_int; | ||
| 21 | pub extern "c" fn inotify_add_watch(fd: fd_t, pathname: [*]const u8, mask: u32) c_int; | ||
| 12 | 22 | ||
| 13 | /// See std.elf for constants for this | 23 | /// See std.elf for constants for this |
| 14 | pub extern fn getauxval(__type: c_ulong) c_ulong; | 24 | pub extern "c" fn getauxval(__type: c_ulong) c_ulong; |
| 15 | 25 | ||
| 16 | pub const dl_iterate_phdr_callback = extern fn (info: *linux.dl_phdr_info, size: usize, data: ?*c_void) c_int; | 26 | pub const dl_iterate_phdr_callback = extern fn (info: *dl_phdr_info, size: usize, data: ?*c_void) c_int; |
| 17 | pub extern fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int; | 27 | pub 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 @@ |
| 1 | extern "c" fn __errno() *c_int; | 1 | extern "c" fn __errno() *c_int; |
| 2 | pub const _errno = __errno; | 2 | pub const _errno = __errno; |
| 3 | 3 | ||
| 4 | pub extern "c" fn kqueue() c_int; | ||
| 5 | pub 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; | ||
| 13 | pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int; | ||
| 14 | pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int; | ||
| 15 | pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int; | ||
| 16 | pub extern "c" fn getdirentries(fd: c_int, buf_ptr: [*]u8, nbytes: usize, basep: *i64) usize; | ||
| 17 | pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize; | 4 | pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize; |
| 18 | pub extern "c" fn pipe2(arg0: *[2]c_int, arg1: u32) c_int; | ||
| 19 | pub extern "c" fn preadv(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize; | ||
| 20 | pub extern "c" fn pwritev(fd: c_int, iov: *const c_void, iovcnt: c_int, offset: usize) isize; | ||
| 21 | pub extern "c" fn openat(fd: c_int, path: ?[*]const u8, flags: c_int) c_int; | ||
| 22 | pub extern "c" fn setgid(ruid: c_uint, euid: c_uint) c_int; | ||
| 23 | pub extern "c" fn setuid(uid: c_uint) c_int; | ||
| 24 | pub extern "c" fn kill(pid: c_int, sig: c_int) c_int; | ||
| 25 | pub extern "c" fn clock_gettime(clk_id: c_int, tp: *timespec) c_int; | ||
| 26 | pub 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. | ||
| 29 | pub const Kevent = extern struct { | ||
| 30 | ident: usize, | ||
| 31 | filter: i32, | ||
| 32 | flags: u32, | ||
| 33 | fflags: u32, | ||
| 34 | data: i64, | ||
| 35 | udata: usize, | ||
| 36 | }; | ||
| 37 | |||
| 38 | pub const pthread_attr_t = extern struct { | ||
| 39 | pta_magic: u32, | ||
| 40 | pta_flags: c_int, | ||
| 41 | pta_private: *c_void, | ||
| 42 | }; | ||
| 43 | |||
| 44 | pub 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 | |||
| 67 | pub 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 | |||
| 90 | pub 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 | |||
| 113 | pub const timespec = extern struct { | ||
| 114 | tv_sec: i64, | ||
| 115 | tv_nsec: isize, | ||
| 116 | }; | ||
| 117 | |||
| 118 | pub 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 | |||
| 127 | pub const in_port_t = u16; | ||
| 128 | pub const sa_family_t = u8; | ||
| 129 | |||
| 130 | pub const sockaddr = extern union { | ||
| 131 | in: sockaddr_in, | ||
| 132 | in6: sockaddr_in6, | ||
| 133 | }; | ||
| 134 | |||
| 135 | pub 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 | |||
| 143 | pub 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 @@ | ||
| 1 | const std = @import("std.zig"); | ||
| 2 | const cstr = std.cstr; | ||
| 3 | const unicode = std.unicode; | ||
| 4 | const io = std.io; | ||
| 5 | const fs = std.fs; | ||
| 6 | const os = std.os; | ||
| 7 | const process = std.process; | ||
| 8 | const File = std.fs.File; | ||
| 9 | const windows = os.windows; | ||
| 10 | const mem = std.mem; | ||
| 11 | const debug = std.debug; | ||
| 12 | const BufMap = std.BufMap; | ||
| 13 | const Buffer = std.Buffer; | ||
| 14 | const builtin = @import("builtin"); | ||
| 15 | const Os = builtin.Os; | ||
| 16 | const LinkedList = std.LinkedList; | ||
| 17 | const maxInt = std.math.maxInt; | ||
| 18 | |||
| 19 | pub 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 | |||
| 609 | fn 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]. | ||
| 643 | fn 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 | |||
| 679 | fn windowsDestroyPipe(rd: ?windows.HANDLE, wr: ?windows.HANDLE) void { | ||
| 680 | if (rd) |h| os.close(h); | ||
| 681 | if (wr) |h| os.close(h); | ||
| 682 | } | ||
| 683 | |||
| 684 | fn 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 | |||
| 694 | fn 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 | |||
| 704 | fn 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. | ||
| 711 | fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn { | ||
| 712 | writeIntFd(fd, ErrInt(@errorToInt(err))) catch {}; | ||
| 713 | os.exit(1); | ||
| 714 | } | ||
| 715 | |||
| 716 | const ErrInt = @IntType(false, @sizeOf(anyerror) * 8); | ||
| 717 | |||
| 718 | fn 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 | |||
| 723 | fn 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. | ||
| 729 | pub 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"); |
| 3 | const io = std.io; | 3 | const io = std.io; |
| 4 | const mem = std.mem; | 4 | const mem = std.mem; |
| 5 | const os = std.os; | 5 | const os = std.os; |
| 6 | const File = std.fs.File; | ||
| 6 | 7 | ||
| 7 | const ArrayList = std.ArrayList; | 8 | const ArrayList = std.ArrayList; |
| 8 | 9 | ||
| ... | @@ -28,7 +29,7 @@ pub const CoffError = error{ | ... | @@ -28,7 +29,7 @@ pub const CoffError = error{ |
| 28 | }; | 29 | }; |
| 29 | 30 | ||
| 30 | pub const Coff = struct { | 31 | pub const Coff = struct { |
| 31 | in_file: os.File, | 32 | in_file: File, |
| 32 | allocator: *mem.Allocator, | 33 | allocator: *mem.Allocator, |
| 33 | 34 | ||
| 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 | } |
| 79 | 80 | ||
| 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 | } else | 92 | } else |
| 92 | return error.InvalidPEMagic; | 93 | return error.InvalidPEMagic; |
| 93 | 94 | ||
| 94 | try self.in_file.seekForward(skip_size); | 95 | try self.in_file.seekBy(skip_size); |
| 95 | 96 | ||
| 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; |
| 32 | pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305; | 32 | pub const Poly1305 = @import("crypto/poly1305.zig").Poly1305; |
| 33 | pub const X25519 = @import("crypto/x25519.zig").X25519; | 33 | pub const X25519 = @import("crypto/x25519.zig").X25519; |
| 34 | 34 | ||
| 35 | const std = @import("std.zig"); | ||
| 36 | pub const randomBytes = std.os.getrandom; | ||
| 37 | |||
| 35 | test "crypto" { | 38 | test "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 @@ |
| 1 | const builtin = @import("builtin"); | 1 | const builtin = @import("builtin"); |
| 2 | const std = @import("std"); | 2 | const std = @import("std"); |
| 3 | const time = std.os.time; | 3 | const time = std.time; |
| 4 | const Timer = time.Timer; | 4 | const Timer = time.Timer; |
| 5 | const crypto = @import("../crypto.zig"); | 5 | const crypto = @import("../crypto.zig"); |
| 6 | 6 |
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 | }; |
| 11 | 11 | ||
| 12 | /// Deprecated, use mem.len | ||
| 13 | pub fn len(ptr: [*]const u8) usize { | ||
| 14 | return mem.len(u8, ptr); | ||
| 15 | } | ||
| 16 | |||
| 17 | pub fn cmp(a: [*]const u8, b: [*]const u8) i8 { | 12 | pub 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 | } |
| 28 | 23 | ||
| 29 | /// Deprecated, use mem.toSliceConst | ||
| 30 | pub fn toSliceConst(str: [*]const u8) []const u8 { | ||
| 31 | return mem.toSliceConst(u8, str); | ||
| 32 | } | ||
| 33 | |||
| 34 | /// Deprecated, use mem.toSlice | ||
| 35 | pub fn toSlice(str: [*]u8) []u8 { | ||
| 36 | return mem.toSlice(u8, str); | ||
| 37 | } | ||
| 38 | |||
| 39 | test "cstr fns" { | 24 | test "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" { |
| 43 | 28 | ||
| 44 | fn testCStrFnsImpl() void { | 29 | fn 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 | } |
| 48 | 33 | ||
| 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; |
| 3 | const mem = std.mem; | 3 | const mem = std.mem; |
| 4 | const io = std.io; | 4 | const io = std.io; |
| 5 | const os = std.os; | 5 | const os = std.os; |
| 6 | const fs = std.fs; | ||
| 7 | const process = std.process; | ||
| 6 | const elf = std.elf; | 8 | const elf = std.elf; |
| 7 | const DW = std.dwarf; | 9 | const DW = std.dwarf; |
| 8 | const macho = std.macho; | 10 | const macho = std.macho; |
| 9 | const coff = std.coff; | 11 | const coff = std.coff; |
| 10 | const pdb = std.pdb; | 12 | const pdb = std.pdb; |
| 11 | const windows = os.windows; | ||
| 12 | const ArrayList = std.ArrayList; | 13 | const ArrayList = std.ArrayList; |
| 13 | const builtin = @import("builtin"); | 14 | const builtin = @import("builtin"); |
| 14 | const maxInt = std.math.maxInt; | 15 | const maxInt = std.math.maxInt; |
| 16 | const File = std.fs.File; | ||
| 17 | const windows = std.os.windows; | ||
| 15 | 18 | ||
| 16 | const leb = @import("debug/leb128.zig"); | 19 | const leb = @import("debug/leb128.zig"); |
| 17 | 20 | ||
| ... | @@ -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 |
| 19 | pub const failing_allocator = &FailingAllocator.init(global_allocator, 0).allocator; | 22 | pub const failing_allocator = &FailingAllocator.init(global_allocator, 0).allocator; |
| 20 | 23 | ||
| 21 | pub const runtime_safety = switch (builtin.mode) { | 24 | pub 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 | }; |
| 25 | 28 | ||
| 26 | const Module = struct { | 29 | const Module = struct { |
| ... | @@ -36,10 +39,10 @@ const Module = struct { | ... | @@ -36,10 +39,10 @@ const Module = struct { |
| 36 | 39 | ||
| 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. |
| 39 | var stderr_file: os.File = undefined; | 42 | var stderr_file: File = undefined; |
| 40 | var stderr_file_out_stream: os.File.OutStream = undefined; | 43 | var stderr_file_out_stream: File.OutStream = undefined; |
| 41 | 44 | ||
| 42 | var stderr_stream: ?*io.OutStream(os.File.WriteError) = null; | 45 | var stderr_stream: ?*io.OutStream(File.WriteError) = null; |
| 43 | var stderr_mutex = std.Mutex.init(); | 46 | var stderr_mutex = std.Mutex.init(); |
| 44 | pub fn warn(comptime fmt: []const u8, args: ...) void { | 47 | pub 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 | } |
| 50 | 53 | ||
| 51 | pub fn getStderrStream() !*io.OutStream(os.File.WriteError) { | 54 | pub 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 { |
| 75 | fn wantTtyColor() bool { | 78 | fn 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 | } |
| 80 | 83 | ||
| 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 awareness | 85 | /// TODO multithreaded awareness |
| 83 | pub fn dumpCurrentStackTrace(start_addr: ?usize) void { | 86 | pub 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 pointer | 106 | /// 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. |
| 101 | pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace) void { | 108 | pub 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 | } |
| 145 | 149 | ||
| ... | @@ -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 awareness | 151 | /// TODO multithreaded awareness |
| 148 | pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void { | 152 | pub 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 | }; |
| 260 | 268 | ||
| 261 | pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void { | 269 | pub 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 | } |
| 291 | 298 | ||
| 292 | pub fn printSourceAtAddress(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { | 299 | pub 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 | } |
| 300 | 308 | ||
| 301 | fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_address: usize, tty_color: bool) !void { | 309 | fn 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; |
| 305 | 313 | ||
| 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 |
| 330 | 338 | ||
| 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); |
| 334 | 342 | ||
| 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 { |
| 510 | 518 | ||
| 511 | /// TODO this is a special case hack right now. clean it up and maybe make it part of std.fmt | 519 | /// TODO this is a special case hack right now. clean it up and maybe make it part of std.fmt |
| 512 | fn setTtyColor(tty_color: TtyColor) void { | 520 | fn 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 error | 550 | // 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 | } |
| 546 | 554 | ||
| 547 | // TODO handle errors | 555 | // 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 | } |
| 634 | 642 | ||
| 635 | fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { | 643 | fn 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); |
| 638 | 646 | ||
| 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 | } |
| 717 | 725 | ||
| 718 | pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { | 726 | pub 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 | } |
| 721 | 729 | ||
| ... | @@ -775,16 +783,17 @@ pub const OpenSelfDebugInfoError = error{ | ... | @@ -775,16 +783,17 @@ pub const OpenSelfDebugInfoError = error{ |
| 775 | }; | 783 | }; |
| 776 | 784 | ||
| 777 | pub fn openSelfDebugInfo(allocator: *mem.Allocator) !DebugInfo { | 785 | pub 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 | } |
| 785 | 794 | ||
| 786 | fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { | 795 | fn 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(); |
| 789 | 798 | ||
| 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]; |
| 813 | 822 | ||
| 814 | const path = try os.path.resolve(allocator, [][]const u8{raw_path}); | 823 | const path = try fs.path.resolve(allocator, [][]const u8{raw_path}); |
| 815 | 824 | ||
| 816 | try di.pdb.openFile(di.coff, path); | 825 | try di.pdb.openFile(di.coff, path); |
| 817 | 826 | ||
| ... | @@ -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 | } |
| 899 | 908 | ||
| ... | @@ -1001,29 +1010,27 @@ pub fn openElfDebugInfo( | ... | @@ -1001,29 +1010,27 @@ pub fn openElfDebugInfo( |
| 1001 | return di; | 1010 | return di; |
| 1002 | } | 1011 | } |
| 1003 | 1012 | ||
| 1004 | fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DwarfInfo { | 1013 | fn 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 | }; |
| 1009 | 1018 | ||
| 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(); |
| 1012 | 1021 | ||
| 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); | ||
| 1024 | 1032 | ||
| 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); | ||
| 1027 | 1034 | ||
| 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 | } |
| 1113 | 1120 | ||
| 1114 | fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void { | 1121 | fn 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 size | 1124 | // TODO fstat and make sure that the file has the correct size |
| 1118 | 1125 | ||
| 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 | }; |
| 1196 | 1203 | ||
| 1197 | pub const DebugInfo = switch (builtin.os) { | 1204 | pub 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 | }; |
| 1223 | 1230 | ||
| ... | @@ -1411,7 +1418,7 @@ const LineNumberProgram = struct { | ... | @@ -1411,7 +1418,7 @@ const LineNumberProgram = struct { |
| 1411 | return error.InvalidDebugInfo; | 1418 | return error.InvalidDebugInfo; |
| 1412 | } else | 1419 | } 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 @@ |
| 1 | const builtin = @import("builtin"); | 1 | const builtin = @import("builtin"); |
| 2 | const Os = builtin.Os; | ||
| 3 | 2 | ||
| 4 | const std = @import("std.zig"); | 3 | const std = @import("std.zig"); |
| 5 | const mem = std.mem; | 4 | const mem = std.mem; |
| 6 | const cstr = std.cstr; | ||
| 7 | const os = std.os; | 5 | const os = std.os; |
| 8 | const assert = std.debug.assert; | 6 | const assert = std.debug.assert; |
| 9 | const testing = std.testing; | 7 | const testing = std.testing; |
| 10 | const elf = std.elf; | 8 | const elf = std.elf; |
| 11 | const linux = os.linux; | 9 | const windows = std.os.windows; |
| 12 | const windows = os.windows; | ||
| 13 | const win_util = @import("os/windows/util.zig"); | ||
| 14 | const maxInt = std.math.maxInt; | 10 | const maxInt = std.math.maxInt; |
| 15 | 11 | ||
| 16 | pub const DynLib = switch (builtin.os) { | 12 | pub 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 | }; |
| 21 | 17 | ||
| ... | @@ -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 { |
| 105 | pub const LinuxDynLib = struct { | 101 | pub 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, | ||
| 110 | 105 | ||
| 111 | /// Trusts the file | 106 | /// 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); |
| 115 | 110 | ||
| 116 | const size = @intCast(usize, (try std.os.posixFStat(fd)).size); | 111 | const size = @intCast(usize, (try os.fstat(fd)).size); |
| 117 | 112 | ||
| 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]; | ||
| 129 | 122 | ||
| 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 | } |
| 137 | 129 | ||
| 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 | } |
| 143 | 135 | ||
| ... | @@ -149,7 +141,7 @@ pub const LinuxDynLib = struct { | ... | @@ -149,7 +141,7 @@ pub const LinuxDynLib = struct { |
| 149 | pub const ElfLib = struct { | 141 | pub 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 { |
| 184 | 176 | ||
| 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; |
| 190 | 182 | ||
| ... | @@ -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 | } |
| 253 | 245 | ||
| 254 | pub const WindowsDynLib = struct { | 246 | pub 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, |
| 257 | 249 | ||
| 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); |
| 260 | 252 | ||
| 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 | } |
| 274 | 258 | ||
| 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 | } |
| 279 | 263 | ||
| 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 | }; |
| 284 | 268 | ||
| 285 | test "dynamic_library" { | 269 | test "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 | }; |
| 291 | 275 |
std/elf.zig+5-4| ... | @@ -6,6 +6,7 @@ const math = std.math; | ... | @@ -6,6 +6,7 @@ const math = std.math; |
| 6 | const mem = std.mem; | 6 | const mem = std.mem; |
| 7 | const debug = std.debug; | 7 | const debug = std.debug; |
| 8 | const InStream = std.stream.InStream; | 8 | const InStream = std.stream.InStream; |
| 9 | const File = std.fs.File; | ||
| 9 | 10 | ||
| 10 | pub const AT_NULL = 0; | 11 | pub const AT_NULL = 0; |
| 11 | pub const AT_IGNORE = 1; | 12 | pub 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, |
| 371 | 372 | ||
| 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 | } |
| 376 | 377 | ||
| 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 | } |
| 381 | 382 | ||
| ... | @@ -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; |
| 411 | 412 | ||
| 412 | // skip over padding | 413 | // skip over padding |
| 413 | try seekable_stream.seekForward(9); | 414 | try seekable_stream.seekBy(9); |
| 414 | 415 | ||
| 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 | } |
| 448 | 449 | ||
| 449 | // skip over flags | 450 | // skip over flags |
| 450 | try seekable_stream.seekForward(4); | 451 | try seekable_stream.seekBy(4); |
| 451 | 452 | ||
| 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; |
| 5 | const testing = std.testing; | 5 | const testing = std.testing; |
| 6 | const os = std.os; | 6 | const os = std.os; |
| 7 | const mem = std.mem; | 7 | const mem = std.mem; |
| 8 | const posix = os.posix; | ||
| 9 | const windows = os.windows; | 8 | const windows = os.windows; |
| 10 | const Loop = event.Loop; | 9 | const Loop = event.Loop; |
| 10 | const fd_t = os.fd_t; | ||
| 11 | const File = std.fs.File; | ||
| 11 | 12 | ||
| 12 | pub const RequestNode = std.atomic.Queue(Request).Node; | 13 | pub const RequestNode = std.atomic.Queue(Request).Node; |
| 13 | 14 | ||
| ... | @@ -30,53 +31,53 @@ pub const Request = struct { | ... | @@ -30,53 +31,53 @@ pub const Request = struct { |
| 30 | End, // special - means the fs thread should exit | 31 | End, // special - means the fs thread should exit |
| 31 | 32 | ||
| 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, |
| 37 | 38 | ||
| 38 | pub const Error = os.PosixWriteError; | 39 | pub const Error = os.WriteError; |
| 39 | }; | 40 | }; |
| 40 | 41 | ||
| 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, |
| 46 | 47 | ||
| 47 | pub const Error = os.PosixReadError; | 48 | pub const Error = os.ReadError; |
| 48 | }; | 49 | }; |
| 49 | 50 | ||
| 50 | pub const Open = struct { | 51 | pub const Open = struct { |
| 51 | /// must be null terminated. TODO https://github.com/ziglang/zig/issues/265 | 52 | /// 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, |
| 56 | 57 | ||
| 57 | pub const Error = os.File.OpenError; | 58 | pub const Error = File.OpenError; |
| 58 | }; | 59 | }; |
| 59 | 60 | ||
| 60 | pub const WriteFile = struct { | 61 | pub const WriteFile = struct { |
| 61 | /// must be null terminated. TODO https://github.com/ziglang/zig/issues/265 | 62 | /// 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, |
| 66 | 67 | ||
| 67 | pub const Error = os.File.OpenError || os.File.WriteError; | 68 | pub const Error = File.OpenError || File.WriteError; |
| 68 | }; | 69 | }; |
| 69 | 70 | ||
| 70 | pub const Close = struct { | 71 | pub const Close = struct { |
| 71 | fd: os.FileHandle, | 72 | fd: fd_t, |
| 72 | }; | 73 | }; |
| 73 | }; | 74 | }; |
| 74 | }; | 75 | }; |
| 75 | 76 | ||
| 76 | pub const PWriteVError = error{OutOfMemory} || os.File.WriteError; | 77 | pub const PWriteVError = error{OutOfMemory} || File.WriteError; |
| 77 | 78 | ||
| 78 | /// data - just the inner references - must live until pwritev promise completes. | 79 | /// data - just the inner references - must live until pwritev promise completes. |
| 79 | pub async fn pwritev(loop: *Loop, fd: os.FileHandle, data: []const []const u8, offset: usize) PWriteVError!void { | 80 | pub 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/1194 | 81 | // 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); |
| 92 | 93 | ||
| 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 | } |
| 110 | 111 | ||
| 111 | /// data must outlive the returned promise | 112 | /// data must outlive the returned promise |
| 112 | pub async fn pwritevWindows(loop: *Loop, fd: os.FileHandle, data: []const []const u8, offset: usize) os.WindowsWriteError!void { | 113 | pub 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); |
| 115 | 116 | ||
| ... | @@ -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 | } |
| 123 | 124 | ||
| 124 | pub async fn pwriteWindows(loop: *Loop, fd: os.FileHandle, data: []const u8, offset: u64) os.WindowsWriteError!void { | 125 | pub 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/1194 | 126 | // 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(); |
| 147 | 148 | ||
| 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 | } |
| 168 | 168 | ||
| 169 | /// iovecs must live until pwritev promise completes. | 169 | /// iovecs must live until pwritev promise completes. |
| 170 | pub async fn pwritevPosix( | 170 | pub 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/1194 | 176 | // 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 | } |
| 211 | 211 | ||
| 212 | pub const PReadVError = error{OutOfMemory} || os.File.ReadError; | 212 | pub const PReadVError = error{OutOfMemory} || File.ReadError; |
| 213 | 213 | ||
| 214 | /// data - just the inner references - must live until preadv promise completes. | 214 | /// data - just the inner references - must live until preadv promise completes. |
| 215 | pub async fn preadv(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset: usize) PReadVError!usize { | 215 | pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PReadVError!usize { |
| 216 | // workaround for https://github.com/ziglang/zig/issues/1194 | 216 | // 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); |
| 230 | 230 | ||
| 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 | } |
| 248 | 248 | ||
| 249 | /// data must outlive the returned promise | 249 | /// data must outlive the returned promise |
| 250 | pub async fn preadvWindows(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset: u64) os.WindowsReadError!usize { | 250 | pub 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); |
| 253 | 253 | ||
| ... | @@ -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 | } |
| 273 | 273 | ||
| 274 | pub async fn preadWindows(loop: *Loop, fd: os.FileHandle, data: []u8, offset: u64) !usize { | 274 | pub async fn preadWindows(loop: *Loop, fd: fd_t, data: []u8, offset: u64) !usize { |
| 275 | // workaround for https://github.com/ziglang/zig/issues/1194 | 275 | // 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 fd | 293 | // 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(); |
| 297 | 297 | ||
| 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 completes | 317 | /// iovecs must live until preadv promise completes |
| 319 | pub async fn preadvPosix( | 318 | pub 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/1194 | 324 | // 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/1194 | 366 | // 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 | } |
| 404 | 403 | ||
| 405 | pub async fn openRead(loop: *Loop, path: []const u8) os.File.OpenError!os.FileHandle { | 404 | pub 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 | }, |
| 411 | 410 | ||
| 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 | ), |
| 419 | 420 | ||
| 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 |
| 423 | 424 | ||
| 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. |
| 426 | pub async fn openWrite(loop: *Loop, path: []const u8) os.File.OpenError!os.FileHandle { | 427 | pub 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 | } |
| 429 | 430 | ||
| 430 | /// Creates if does not exist. Truncates the file if it exists. | 431 | /// Creates if does not exist. Truncates the file if it exists. |
| 431 | pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: os.File.Mode) os.File.OpenError!os.FileHandle { | 432 | pub 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 |
| 453 | pub async fn openReadWrite( | 456 | pub 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 | }, |
| 463 | 466 | ||
| 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 | ), |
| 471 | 476 | ||
| 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, |
| 488 | 493 | ||
| 489 | builtin.Os.windows => struct { | 494 | builtin.Os.windows => struct { |
| 490 | handle: ?os.FileHandle, | 495 | handle: ?fd_t, |
| 491 | }, | 496 | }, |
| 492 | 497 | ||
| 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 | } |
| 553 | 558 | ||
| 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 | } |
| 587 | 592 | ||
| 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 writeFileTruncate | 612 | /// TODO make this atomic or provide writeFileAtomic and rename this one to writeFileTruncate |
| 608 | pub async fn writeFile(loop: *Loop, path: []const u8, contents: []const u8) !void { | 613 | pub 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 | } |
| 611 | 616 | ||
| 612 | /// contents must remain alive until writeFile completes. | 617 | /// contents must remain alive until writeFile completes. |
| 613 | pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8, mode: os.File.Mode) !void { | 618 | pub 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 | } |
| 624 | 629 | ||
| 625 | async fn writeFileWindows(loop: *Loop, path: []const u8, contents: []const u8) !void { | 630 | async 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); |
| 634 | 641 | ||
| 635 | try await (async pwriteWindows(loop, handle, contents, 0) catch unreachable); | 642 | try await (async pwriteWindows(loop, handle, contents, 0) catch unreachable); |
| 636 | } | 643 | } |
| 637 | 644 | ||
| 638 | async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8, mode: os.File.Mode) !void { | 645 | async fn writeFileModeThread(loop: *Loop, path: []const u8, contents: []const u8, mode: File.Mode) !void { |
| 639 | // workaround for https://github.com/ziglang/zig/issues/1194 | 646 | // 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(); |
| 690 | 697 | ||
| 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 { |
| 787 | 794 | ||
| 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); |
| 792 | 799 | ||
| 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 | } |
| 881 | 888 | ||
| 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); |
| 886 | 893 | ||
| ... | @@ -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(); |
| 890 | 897 | ||
| 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_ERROR | 953 | // 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; |
| 973 | 978 | ||
| 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); |
| 978 | 983 | ||
| 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); |
| 983 | 988 | ||
| 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"?) |
| 1019 | 1024 | ||
| 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); |
| 1023 | 1028 | ||
| ... | @@ -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); |
| 1026 | 1031 | ||
| 1027 | // TODO https://github.com/ziglang/zig/issues/265 | 1032 | // 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]; |
| 1033 | 1038 | ||
| 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); |
| 1053 | 1050 | ||
| 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; |
| 1129 | 1126 | ||
| 1130 | // TODO handle this error not in the channel but in the setup | 1127 | // 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 | } |
| 1341 | 1337 | ||
| 1342 | async fn testFsWatch(loop: *Loop) !void { | 1338 | async 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); |
| 1345 | 1341 | ||
| 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; |
| 1367 | 1363 | ||
| 1368 | // overwrite line 2 | 1364 | // 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); |
| 1372 | 1368 | ||
| ... | @@ -1388,15 +1384,15 @@ async fn testFsWatch(loop: *Loop) !void { | ... | @@ -1388,15 +1384,15 @@ async fn testFsWatch(loop: *Loop) !void { |
| 1388 | } | 1384 | } |
| 1389 | 1385 | ||
| 1390 | pub const OutStream = struct { | 1386 | pub 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, |
| 1395 | 1391 | ||
| 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); |
| 1398 | 1394 | ||
| 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 | }; |
| 1415 | 1411 | ||
| 1416 | pub const InStream = struct { | 1412 | pub 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 OutOfMemory | 1418 | 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); |
| 1424 | 1420 | ||
| 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 | } |
| 156 | 156 | ||
| 157 | async fn sleepALittle(count: *usize) void { | 157 | async 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 | } |
| 161 | 161 |
std/event/loop.zig+134-134| ... | @@ -7,9 +7,9 @@ const AtomicRmwOp = builtin.AtomicRmwOp; | ... | @@ -7,9 +7,9 @@ const AtomicRmwOp = builtin.AtomicRmwOp; |
| 7 | const AtomicOrder = builtin.AtomicOrder; | 7 | const AtomicOrder = builtin.AtomicOrder; |
| 8 | const fs = std.event.fs; | 8 | const fs = std.event.fs; |
| 9 | const os = std.os; | 9 | const os = std.os; |
| 10 | const posix = os.posix; | ||
| 11 | const windows = os.windows; | 10 | const windows = os.windows; |
| 12 | const maxInt = std.math.maxInt; | 11 | const maxInt = std.math.maxInt; |
| 12 | const Thread = std.Thread; | ||
| 13 | 13 | ||
| 14 | pub const Loop = struct { | 14 | pub 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, |
| 21 | 21 | ||
| 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, |
| 33 | 33 | ||
| 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 | }; |
| 51 | 51 | ||
| 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 { |
| 65 | 65 | ||
| 66 | const KEventFd = struct { | 66 | const KEventFd = struct { |
| 67 | base: ResumeNode, | 67 | base: ResumeNode, |
| 68 | kevent: posix.Kevent, | 68 | kevent: os.Kevent, |
| 69 | }; | 69 | }; |
| 70 | 70 | ||
| 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 { |
| 81 | 81 | ||
| 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 | }; |
| 87 | 87 | ||
| ... | @@ -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 | } |
| 105 | 105 | ||
| ... | @@ -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); |
| 129 | 129 | ||
| 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); |
| 132 | 132 | ||
| 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 | } |
| 141 | 141 | ||
| 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; |
| 145 | 145 | ||
| 146 | const wakeup_bytes = []u8{0x1} ** 8; | 146 | const wakeup_bytes = []u8{0x1} ** 8; |
| 147 | 147 | ||
| 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 async | 153 | // 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 | } |
| 182 | 182 | ||
| 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); |
| 185 | 185 | ||
| 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); |
| 188 | 188 | ||
| 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 | ); |
| 199 | 199 | ||
| 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 fail | 213 | // 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); |
| 227 | 227 | ||
| 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); |
| 230 | 230 | ||
| 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 | }; |
| 242 | 242 | ||
| 243 | const empty_kevs = ([*]posix.Kevent)(undefined)[0..0]; | 243 | const empty_kevs = ([*]os.Kevent)(undefined)[0..0]; |
| 244 | 244 | ||
| 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 events | 253 | // 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 | } |
| 271 | 271 | ||
| 272 | // Pre-add so that we cannot get error.SystemResources | 272 | // 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; |
| 286 | 286 | ||
| 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 | }; |
| 295 | 295 | ||
| 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 | }; |
| 304 | 304 | ||
| 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 { |
| 315 | 315 | ||
| 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); |
| 336 | 336 | ||
| 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 { |
| 380 | 380 | ||
| 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 EPOLLET | 401 | /// 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 | } |
| 413 | 413 | ||
| 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 | } |
| 422 | 422 | ||
| 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 | } |
| 427 | 427 | ||
| ... | @@ -440,7 +440,7 @@ pub const Loop = struct { | ... | @@ -440,7 +440,7 @@ pub const Loop = struct { |
| 440 | } | 440 | } |
| 441 | } | 441 | } |
| 442 | 442 | ||
| 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 #1194 | 444 | // 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 | } |
| 479 | 479 | ||
| 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 | } |
| 494 | 494 | ||
| ... | @@ -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 for | 514 | // 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 stop | 624 | // 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 fail | 628 | // 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 it | 636 | // 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 | } |
| 664 | 664 | ||
| 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 threads | 667 | // 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 necessary | 728 | } 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 | } |
| 832 | 832 | ||
| 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 { |
| 842 | 842 | ||
| 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; |
| 4 | const event = std.event; | 4 | const event = std.event; |
| 5 | const mem = std.mem; | 5 | const mem = std.mem; |
| 6 | const os = std.os; | 6 | const os = std.os; |
| 7 | const posix = os.posix; | ||
| 8 | const Loop = std.event.Loop; | 7 | const Loop = std.event.Loop; |
| 8 | const File = std.fs.File; | ||
| 9 | const fd_t = os.fd_t; | ||
| 9 | 10 | ||
| 10 | pub const Server = struct { | 11 | pub 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, |
| 12 | 13 | ||
| 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; |
| 46 | 47 | ||
| 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; |
| 50 | 51 | ||
| 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)); |
| 54 | 55 | ||
| 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.?; |
| 57 | 58 | ||
| 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 | } |
| 62 | 63 | ||
| 63 | /// Stop listening | 64 | /// 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 | } |
| 68 | 72 | ||
| 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 posixAsyncAccept | 81 | // 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 block | 84 | // would block |
| 81 | suspend; // we will get resumed by epoll_wait in the event loop | 85 | 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, |
| 101 | 98 | ||
| 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 | }; |
| 112 | 109 | ||
| 113 | pub async fn connectUnixSocket(loop: *Loop, path: []const u8) !i32 { | 110 | pub 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); |
| 120 | 117 | ||
| 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 | }; |
| 125 | 122 | ||
| 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); |
| 132 | 129 | ||
| 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 | }; |
| 147 | 144 | ||
| 148 | /// returns number of bytes read. 0 means EOF. | 145 | /// returns number of bytes read. 0 means EOF. |
| 149 | pub async fn read(loop: *std.event.Loop, fd: os.FileHandle, buffer: []u8) ReadError!usize { | 146 | pub 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 | } |
| 157 | 154 | ||
| 158 | pub const WriteError = error{}; | 155 | pub const WriteError = error{}; |
| 159 | 156 | ||
| 160 | pub async fn write(loop: *std.event.Loop, fd: os.FileHandle, buffer: []const u8) WriteError!void { | 157 | pub 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 | } |
| 168 | 165 | ||
| 169 | pub async fn writevPosix(loop: *Loop, fd: i32, iov: [*]const posix.iovec_const, count: usize) !void { | 166 | pub 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 condition | 180 | os.EBADF => unreachable, // always a race condition |
| 186 | posix.EDESTADDRREQ => unreachable, // connect was never called | 181 | 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 | } |
| 200 | 195 | ||
| 201 | /// returns number of bytes read. 0 means EOF. | 196 | /// returns number of bytes read. 0 means EOF. |
| 202 | pub async fn readvPosix(loop: *std.event.Loop, fd: i32, iov: [*]posix.iovec, count: usize) !usize { | 197 | pub 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 condition | 211 | 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 | } |
| 229 | 223 | ||
| 230 | pub async fn writev(loop: *Loop, fd: os.FileHandle, data: []const []const u8) !void { | 224 | pub 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); |
| 233 | 227 | ||
| 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 | } |
| 243 | 237 | ||
| 244 | pub async fn readv(loop: *Loop, fd: os.FileHandle, data: []const []u8) !usize { | 238 | pub 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); |
| 247 | 241 | ||
| 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 | } |
| 257 | 251 | ||
| 258 | pub async fn connect(loop: *Loop, _address: *const std.net.Address) !os.File { | 252 | pub async fn connect(loop: *Loop, _address: *const std.net.Address) !File { |
| 259 | var address = _address.*; // TODO https://github.com/ziglang/zig/issues/1592 | 253 | var address = _address.*; // TODO https://github.com/ziglang/zig/issues/1592 |
| 260 | 254 | ||
| 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); |
| 263 | 257 | ||
| 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); |
| 267 | 261 | ||
| 268 | return os.File.openHandle(sockfd); | 262 | return File.openHandle(sockfd); |
| 269 | } | 263 | } |
| 270 | 264 | ||
| 271 | test "listen on a port, send bytes, receive bytes" { | 265 | test "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, |
| 282 | 276 | ||
| 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/1592 | 280 | 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/1592 | 292 | const addr = _addr.*; // TODO https://github.com/ziglang/zig/issues/1592 |
| 299 | var socket = _socket; // TODO https://github.com/ziglang/zig/issues/1592 | 293 | var socket = _socket; // TODO https://github.com/ziglang/zig/issues/1592 |
| 300 | 294 | ||
| ... | @@ -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 | } |
| 332 | 326 | ||
| 333 | pub const OutStream = struct { | 327 | pub const OutStream = struct { |
| 334 | fd: os.FileHandle, | 328 | fd: fd_t, |
| 335 | stream: Stream, | 329 | stream: Stream, |
| 336 | loop: *Loop, | 330 | loop: *Loop, |
| 337 | 331 | ||
| 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); |
| 340 | 334 | ||
| 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 | }; |
| 354 | 348 | ||
| 355 | pub const InStream = struct { | 349 | pub const InStream = struct { |
| 356 | fd: os.FileHandle, | 350 | fd: fd_t, |
| 357 | stream: Stream, | 351 | stream: Stream, |
| 358 | loop: *Loop, | 352 | loop: *Loop, |
| 359 | 353 | ||
| 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); |
| 362 | 356 | ||
| 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 { |
| 271 | 271 | ||
| 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 { |
| 286 | 286 | ||
| 287 | async fn readRunner(lock: *RwLock) void { | 287 | async fn readRunner(lock: *RwLock) void { |
| 288 | suspend; // resumed by onNextTick | 288 | suspend; // resumed by onNextTick |
| 289 | std.os.time.sleep(1); | 289 | std.time.sleep(1); |
| 290 | 290 | ||
| 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 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("std.zig"); | ||
| 3 | const os = std.os; | ||
| 4 | const mem = std.mem; | ||
| 5 | const base64 = std.base64; | ||
| 6 | const crypto = std.crypto; | ||
| 7 | const Allocator = std.mem.Allocator; | ||
| 8 | const assert = std.debug.assert; | ||
| 9 | |||
| 10 | pub const path = @import("fs/path.zig"); | ||
| 11 | pub const File = @import("fs/file.zig").File; | ||
| 12 | |||
| 13 | pub const symLink = os.symlink; | ||
| 14 | pub const symLinkC = os.symlinkC; | ||
| 15 | pub const deleteFile = os.unlink; | ||
| 16 | pub const deleteFileC = os.unlinkC; | ||
| 17 | pub const rename = os.rename; | ||
| 18 | pub const renameC = os.renameC; | ||
| 19 | pub const renameW = os.renameW; | ||
| 20 | pub const realpath = os.realpath; | ||
| 21 | pub const realpathC = os.realpathC; | ||
| 22 | pub const realpathW = os.realpathW; | ||
| 23 | |||
| 24 | pub const getAppDataDir = @import("fs/get_app_data_dir.zig").getAppDataDir; | ||
| 25 | pub 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 | ||
| 31 | pub 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 | ||
| 42 | const b64_fs_encoder = base64.Base64Encoder.init("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", base64.standard_pad_char); | ||
| 43 | |||
| 44 | /// TODO remove the allocator requirement from this API | ||
| 45 | pub 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. | ||
| 78 | pub 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 | ||
| 101 | pub 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 | |||
| 118 | pub 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 | |||
| 189 | const default_new_dir_mode = 0o755; | ||
| 190 | |||
| 191 | /// Create a new directory. | ||
| 192 | pub 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. | ||
| 197 | pub 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. | ||
| 202 | pub 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 | ||
| 211 | pub 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`. | ||
| 245 | pub 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. | ||
| 250 | pub 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. | ||
| 255 | pub 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. | ||
| 262 | const 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 | ||
| 294 | pub 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 | |||
| 364 | pub 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`. | ||
| 688 | pub 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. | ||
| 693 | pub fn readLinkC(pathname: [*]const u8, buffer: *[os.PATH_MAX]u8) ![]u8 { | ||
| 694 | return os.readlinkC(pathname, buffer); | ||
| 695 | } | ||
| 696 | |||
| 697 | pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfExePathError; | ||
| 698 | |||
| 699 | pub 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 | |||
| 714 | test "openSelfExe" { | ||
| 715 | switch (builtin.os) { | ||
| 716 | .linux, .macosx, .ios, .windows, .freebsd => (try openSelfExe()).close(), | ||
| 717 | else => return error.SkipZigTest, // Unsupported OS. | ||
| 718 | } | ||
| 719 | } | ||
| 720 | |||
| 721 | pub 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 | ||
| 733 | pub 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. | ||
| 768 | pub 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. | ||
| 774 | pub 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. | ||
| 781 | pub 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. | ||
| 799 | pub 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 | |||
| 804 | test "" { | ||
| 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 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const os = std.os; | ||
| 4 | const io = std.io; | ||
| 5 | const mem = std.mem; | ||
| 6 | const math = std.math; | ||
| 7 | const assert = std.debug.assert; | ||
| 8 | const windows = os.windows; | ||
| 9 | const Os = builtin.Os; | ||
| 10 | const maxInt = std.math.maxInt; | ||
| 11 | |||
| 12 | pub 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 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const unicode = std.unicode; | ||
| 4 | const mem = std.mem; | ||
| 5 | const fs = std.fs; | ||
| 6 | const os = std.os; | ||
| 7 | |||
| 8 | pub const GetAppDataDirError = error{ | ||
| 9 | OutOfMemory, | ||
| 10 | AppDataDirUnavailable, | ||
| 11 | }; | ||
| 12 | |||
| 13 | /// Caller owns returned memory. | ||
| 14 | /// TODO determine if we can remove the allocator requirement | ||
| 15 | pub 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 | |||
| 58 | fn 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 | |||
| 64 | test "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 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("../std.zig"); | ||
| 3 | const debug = std.debug; | ||
| 4 | const assert = debug.assert; | ||
| 5 | const testing = std.testing; | ||
| 6 | const mem = std.mem; | ||
| 7 | const fmt = std.fmt; | ||
| 8 | const Allocator = mem.Allocator; | ||
| 9 | const math = std.math; | ||
| 10 | const windows = std.os.windows; | ||
| 11 | const fs = std.fs; | ||
| 12 | const process = std.process; | ||
| 13 | |||
| 14 | pub const sep_windows = '\\'; | ||
| 15 | pub const sep_posix = '/'; | ||
| 16 | pub const sep = if (windows.is_the_target) sep_windows else sep_posix; | ||
| 17 | |||
| 18 | pub const sep_str = [1]u8{sep}; | ||
| 19 | |||
| 20 | pub const delimiter_windows = ';'; | ||
| 21 | pub const delimiter_posix = ':'; | ||
| 22 | pub const delimiter = if (windows.is_the_target) delimiter_windows else delimiter_posix; | ||
| 23 | |||
| 24 | pub 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. | ||
| 34 | fn 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 | |||
| 75 | pub 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. | ||
| 79 | pub 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. | ||
| 85 | pub fn joinPosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { | ||
| 86 | return joinSep(allocator, sep_posix, paths); | ||
| 87 | } | ||
| 88 | |||
| 89 | fn 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 | |||
| 96 | fn 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 | |||
| 103 | test "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 | |||
| 131 | pub 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 | |||
| 139 | pub 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 | |||
| 158 | pub fn isAbsolutePosix(path: []const u8) bool { | ||
| 159 | return path[0] == sep_posix; | ||
| 160 | } | ||
| 161 | |||
| 162 | test "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 | |||
| 184 | test "isAbsolutePosix" { | ||
| 185 | testIsAbsolutePosix("/home/foo", true); | ||
| 186 | testIsAbsolutePosix("/home/foo/..", true); | ||
| 187 | testIsAbsolutePosix("bar/", false); | ||
| 188 | testIsAbsolutePosix("./baz", false); | ||
| 189 | } | ||
| 190 | |||
| 191 | fn testIsAbsoluteWindows(path: []const u8, expected_result: bool) void { | ||
| 192 | testing.expectEqual(expected_result, isAbsoluteWindows(path)); | ||
| 193 | } | ||
| 194 | |||
| 195 | fn testIsAbsolutePosix(path: []const u8, expected_result: bool) void { | ||
| 196 | testing.expectEqual(expected_result, isAbsolutePosix(path)); | ||
| 197 | } | ||
| 198 | |||
| 199 | pub 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 | |||
| 211 | pub 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 | |||
| 277 | test "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 | |||
| 310 | pub fn diskDesignator(path: []const u8) []const u8 { | ||
| 311 | if (windows.is_the_target) { | ||
| 312 | return diskDesignatorWindows(path); | ||
| 313 | } else { | ||
| 314 | return ""; | ||
| 315 | } | ||
| 316 | } | ||
| 317 | |||
| 318 | pub fn diskDesignatorWindows(path: []const u8) []const u8 { | ||
| 319 | return windowsParsePath(path).disk_designator; | ||
| 320 | } | ||
| 321 | |||
| 322 | fn 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 | |||
| 333 | fn 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 | |||
| 356 | fn asciiUpper(byte: u8) u8 { | ||
| 357 | return switch (byte) { | ||
| 358 | 'a'...'z' => 'A' + (byte - 'a'), | ||
| 359 | else => byte, | ||
| 360 | }; | ||
| 361 | } | ||
| 362 | |||
| 363 | fn 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`. | ||
| 375 | pub 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. | ||
| 391 | pub 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. | ||
| 572 | pub 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 | |||
| 635 | test "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 | |||
| 648 | test "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 | |||
| 691 | test "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 | |||
| 704 | fn testResolveWindows(paths: []const []const u8) []u8 { | ||
| 705 | return resolveWindows(debug.global_allocator, paths) catch unreachable; | ||
| 706 | } | ||
| 707 | |||
| 708 | fn 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 | ||
| 714 | pub 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 | |||
| 722 | pub 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 | |||
| 756 | pub 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 | |||
| 782 | test "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 | |||
| 794 | test "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 | |||
| 830 | fn 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 | |||
| 838 | fn 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 | |||
| 846 | pub 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 | |||
| 854 | pub 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 | |||
| 875 | pub 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 | |||
| 907 | test "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 | |||
| 946 | fn testBasename(input: []const u8, expected_output: []const u8) void { | ||
| 947 | testing.expectEqualSlices(u8, expected_output, basename(input)); | ||
| 948 | } | ||
| 949 | |||
| 950 | fn testBasenamePosix(input: []const u8, expected_output: []const u8) void { | ||
| 951 | testing.expectEqualSlices(u8, expected_output, basenamePosix(input)); | ||
| 952 | } | ||
| 953 | |||
| 954 | fn 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 `\\`. | ||
| 962 | pub 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 | |||
| 970 | pub 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 | |||
| 1043 | pub 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 | |||
| 1088 | test "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 | |||
| 1128 | fn 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 | |||
| 1133 | fn 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; |
| 5 | const mem = std.mem; | 5 | const mem = std.mem; |
| 6 | const os = std.os; | 6 | const os = std.os; |
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const Os = builtin.Os; | ||
| 9 | const c = std.c; | 8 | const c = std.c; |
| 10 | const maxInt = std.math.maxInt; | 9 | const maxInt = std.math.maxInt; |
| 11 | 10 | ||
| ... | @@ -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]; |
| 53 | 52 | ||
| 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. |
| 61 | 60 | // see https://devblogs.microsoft.com/oldnewthing/?p=42223 | |
| 62 | const aligned_addr = mem.alignForward(addr, alignment); | 61 | const addr = w.VirtualAlloc( |
| 63 | 62 | null, | |
| 64 | // Unmap the extra bytes that were only requested in order to guarantee | 63 | n, |
| 65 | // that the range of memory we were provided had a proper alignment in | 64 | 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 | } | ||
| 78 | 72 | ||
| 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 | |
| 83 | 77 | 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's | 79 | // aligned address. |
| 86 | // even more likely that the requested alignment is <= 64K than | 80 | 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; |
| 95 | 101 | ||
| 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 | } | ||
| 100 | 104 | ||
| 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 | } |
| 136 | 136 | ||
| 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 | } |
| 179 | 176 | ||
| 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); | ||
| 204 | 183 | ||
| 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 maybe | 186 | } |
| 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; | ||
| 213 | 187 | ||
| 214 | return result; | 188 | const w = os.windows; |
| 215 | } | 189 | const base_addr = @ptrToInt(old_mem.ptr); |
| 216 | 190 | ||
| 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); | ||
| 226 | 199 | ||
| 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 | }; | ||
| 243 | 202 | ||
| 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 | }; |
| 251 | 244 | ||
| ... | @@ -268,7 +261,7 @@ pub const HeapAllocator = switch (builtin.os) { | ... | @@ -268,7 +261,7 @@ pub const HeapAllocator = switch (builtin.os) { |
| 268 | 261 | ||
| 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 | } |
| 274 | 267 | ||
| ... | @@ -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 cmpxchg | 280 | 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); |
| 317 | 310 | ||
| 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 | } |
| 322 | 315 | ||
| 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; |
| 534 | 527 | ||
| 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); |
| 537 | 530 | ||
| 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 | } |
| 542 | 535 | ||
| ... | @@ -565,14 +558,14 @@ const WasmAllocator = struct { | ... | @@ -565,14 +558,14 @@ const WasmAllocator = struct { |
| 565 | 558 | ||
| 566 | // Initialize start_ptr at the first realloc | 559 | // 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 | } |
| 570 | 563 | ||
| 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; |
| 574 | 567 | ||
| 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 |
| 888 | fn testAllocatorLargeAlignment(allocator: *mem.Allocator) mem.Allocator.Error!void { | 881 | fn testAllocatorLargeAlignment(allocator: *mem.Allocator) mem.Allocator.Error!void { |
| 889 | //Maybe a platform's page_size is actually the same as or | 882 | //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; |
| 892 | 885 | ||
| 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); |
| 895 | 888 | ||
| 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; |
| 920 | 913 | ||
| 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); |
| 924 | 917 | ||
| ... | @@ -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 increase | 920 | // which is 16 pages, hence the 32. This test may require to increase |
| 928 | // the size of the allocations feeding the `allocator` parameter if they | 921 | // 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; |
| 939 | 932 | ||
| 940 | // realloc to a smaller size but with a larger alignment | 933 | // 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 @@ |
| 1 | const std = @import("std.zig"); | 1 | const std = @import("std.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const Os = builtin.Os; | ||
| 4 | const c = std.c; | 3 | const c = std.c; |
| 5 | 4 | ||
| 6 | const math = std.math; | 5 | const math = std.math; |
| 7 | const debug = std.debug; | 6 | const debug = std.debug; |
| 8 | const assert = debug.assert; | 7 | const assert = debug.assert; |
| 9 | const os = std.os; | 8 | const os = std.os; |
| 9 | const fs = std.fs; | ||
| 10 | const mem = std.mem; | 10 | const mem = std.mem; |
| 11 | const meta = std.meta; | 11 | const meta = std.meta; |
| 12 | const trait = meta.trait; | 12 | const trait = meta.trait; |
| 13 | const Buffer = std.Buffer; | 13 | const Buffer = std.Buffer; |
| 14 | const fmt = std.fmt; | 14 | const fmt = std.fmt; |
| 15 | const File = std.os.File; | 15 | const File = std.fs.File; |
| 16 | const testing = std.testing; | 16 | const testing = std.testing; |
| 17 | 17 | ||
| 18 | const is_posix = builtin.os != builtin.Os.windows; | 18 | pub const GetStdIoError = os.windows.GetStdHandleError; |
| 19 | const is_windows = builtin.os == builtin.Os.windows; | ||
| 20 | 19 | ||
| 21 | const GetStdIoErrs = os.WindowsGetStdHandleErrs; | 20 | pub fn getStdOut() GetStdIoError!File { |
| 22 | 21 | if (os.windows.is_the_target) { | |
| 23 | pub 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 | } |
| 27 | 27 | ||
| 28 | pub fn getStdOut() GetStdIoErrs!File { | 28 | pub 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 | } |
| 32 | 35 | ||
| 33 | pub fn getStdIn() GetStdIoErrs!File { | 36 | pub 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 | } |
| 37 | 43 | ||
| 38 | pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream; | 44 | pub 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 | } |
| 68 | 74 | ||
| 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 | } |
| 302 | 308 | ||
| 303 | pub fn BufferedInStream(comptime Error: type) type { | 309 | pub fn BufferedInStream(comptime Error: type) type { |
| 304 | return BufferedInStreamCustom(os.page_size, Error); | 310 | return BufferedInStreamCustom(mem.page_size, Error); |
| 305 | } | 311 | } |
| 306 | 312 | ||
| 307 | pub fn BufferedInStreamCustom(comptime buffer_size: usize, comptime Error: type) type { | 313 | pub 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 | } |
| 775 | 781 | ||
| 776 | pub fn BufferedOutStream(comptime Error: type) type { | 782 | pub fn BufferedOutStream(comptime Error: type) type { |
| 777 | return BufferedOutStreamCustom(os.page_size, Error); | 783 | return BufferedOutStreamCustom(mem.page_size, Error); |
| 778 | } | 784 | } |
| 779 | 785 | ||
| 780 | pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamError: type) type { | 786 | pub fn BufferedOutStreamCustom(comptime buffer_size: usize, comptime OutStreamError: type) type { |
| ... | @@ -979,9 +985,9 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type { | ... | @@ -979,9 +985,9 @@ pub fn BitOutStream(endian: builtin.Endian, comptime Error: type) type { |
| 979 | } | 985 | } |
| 980 | 986 | ||
| 981 | pub const BufferedAtomicFile = struct { | 987 | pub 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, |
| 986 | 992 | ||
| 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); |
| 997 | 1003 | ||
| 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(); |
| 1000 | 1006 | ||
| 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 | } |
| 1005 | 1011 | ||
| ... | @@ -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 | } |
| 1016 | 1022 | ||
| 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 @@ |
| 1 | const std = @import("../std.zig"); | 1 | const std = @import("../std.zig"); |
| 2 | const os = std.os; | ||
| 2 | const OutStream = std.io.OutStream; | 3 | const OutStream = std.io.OutStream; |
| 3 | const builtin = @import("builtin"); | 4 | const builtin = @import("builtin"); |
| 4 | const posix = std.os.posix; | ||
| 5 | 5 | ||
| 6 | /// TODO make std.os.FILE use *FILE when linking libc and this just becomes | 6 | /// 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 linking | 7 | /// std.io.FileOutStream because std.fs.File.write would do this when linking |
| 8 | /// libc. | 8 | /// libc. |
| 9 | pub const COutStream = struct { | 9 | pub 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); |
| 12 | 12 | ||
| 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 API | 31 | os.EAGAIN => unreachable, // this is a blocking API |
| 37 | posix.EBADF => unreachable, // always a race condition | 32 | os.EBADF => unreachable, // always a race condition |
| 38 | posix.EDESTADDRREQ => unreachable, // connect was never called | 33 | 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; |
| 9 | 9 | ||
| 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, |
| 12 | 12 | ||
| 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 | } |
| 19 | 19 | ||
| 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 | } |
| 23 | 23 | ||
| 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 | } |
| 79 | 79 | ||
| 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); |
| 82 | 82 | ||
| 83 | if (amt < 0) { | 83 | if (amt < 0) { |
std/io/test.zig+16-15| ... | @@ -1,3 +1,4 @@ | ... | @@ -1,3 +1,4 @@ |
| 1 | const builtin = @import("builtin"); | ||
| 1 | const std = @import("../std.zig"); | 2 | const std = @import("../std.zig"); |
| 2 | const io = std.io; | 3 | const io = std.io; |
| 3 | const meta = std.meta; | 4 | const meta = std.meta; |
| ... | @@ -6,8 +7,8 @@ const DefaultPrng = std.rand.DefaultPrng; | ... | @@ -6,8 +7,8 @@ const DefaultPrng = std.rand.DefaultPrng; |
| 6 | const expect = std.testing.expect; | 7 | const expect = std.testing.expect; |
| 7 | const expectError = std.testing.expectError; | 8 | const expectError = std.testing.expectError; |
| 8 | const mem = std.mem; | 9 | const mem = std.mem; |
| 9 | const os = std.os; | 10 | const fs = std.fs; |
| 10 | const builtin = @import("builtin"); | 11 | const File = std.fs.File; |
| 11 | 12 | ||
| 12 | test "write a file, read it, then delete it" { | 13 | test "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(); |
| 23 | 24 | ||
| 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" { |
| 32 | 33 | ||
| 33 | { | 34 | { |
| 34 | // make sure openWriteNoClobber doesn't harm the file | 35 | // 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 | } |
| 41 | 42 | ||
| 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(); |
| 45 | 46 | ||
| 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); |
| 49 | 50 | ||
| 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 | } |
| 62 | 63 | ||
| 63 | test "BufferOutStream" { | 64 | test "BufferOutStream" { |
| ... | @@ -273,12 +274,12 @@ test "BitOutStream" { | ... | @@ -273,12 +274,12 @@ test "BitOutStream" { |
| 273 | test "BitStreams with File Stream" { | 274 | test "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(); |
| 278 | 279 | ||
| 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); |
| 283 | 284 | ||
| 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(); |
| 295 | 296 | ||
| 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); |
| 300 | 301 | ||
| 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" { |
| 315 | 316 | ||
| 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 | } |
| 320 | 321 | ||
| 321 | fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void { | 322 | fn 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" { |
| 595 | 596 | ||
| 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 {}; |
| 599 | 600 | ||
| 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; |
| 8 | const trait = meta.trait; | 8 | const trait = meta.trait; |
| 9 | const testing = std.testing; | 9 | const testing = std.testing; |
| 10 | 10 | ||
| 11 | pub const page_size = switch (builtin.arch) { | ||
| 12 | .wasm32, .wasm64 => 64 * 1024, | ||
| 13 | else => 4 * 1024, | ||
| 14 | }; | ||
| 15 | |||
| 11 | pub const Allocator = struct { | 16 | pub const Allocator = struct { |
| 12 | pub const Error = error{OutOfMemory}; | 17 | pub const Error = error{OutOfMemory}; |
| 13 | 18 | ||
| ... | @@ -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) |
| 580 | test "comptime read/write int" { | 585 | test "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 | } |
| 1050 | 1055 | ||
| 1051 | test "std.mem.writeIntSlice" { | 1056 | test "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 | } |
| 1181 | 1186 | ||
| 1182 | test "std.mem.reverse" { | 1187 | test "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 | } |
| 1208 | 1213 | ||
| 1209 | test "std.mem.rotate" { | 1214 | test "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 | } |
| 1293 | 1298 | ||
| 1294 | test "std.mem.asBytes" { | 1299 | test "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 | }; |
| 1300 | 1305 | ||
| 1301 | testing.expect(std.mem.eql(u8, asBytes(&deadbeef), deadbeef_bytes)); | 1306 | testing.expect(eql(u8, asBytes(&deadbeef), deadbeef_bytes)); |
| 1302 | 1307 | ||
| 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 | } |
| 1323 | 1328 | ||
| 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 | } |
| 1328 | 1333 | ||
| 1329 | test "std.mem.toBytes" { | 1334 | test "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 | } |
| 1335 | 1340 | ||
| 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 | } |
| 1342 | 1347 | ||
| ... | @@ -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 | } |
| 1360 | 1365 | ||
| 1361 | test "std.mem.bytesAsValue" { | 1366 | test "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" { |
| 1400 | pub fn bytesToValue(comptime T: type, bytes: var) T { | 1405 | pub fn bytesToValue(comptime T: type, bytes: var) T { |
| 1401 | return bytesAsValue(T, &bytes).*; | 1406 | return bytesAsValue(T, &bytes).*; |
| 1402 | } | 1407 | } |
| 1403 | test "std.mem.bytesToValue" { | 1408 | test "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 | } |
| 1427 | 1432 | ||
| 1428 | test "std.mem.subArrayPtr" { | 1433 | test "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")); |
| 1432 | 1437 | ||
| 1433 | var a2 = "abcdef"; | 1438 | var a2 = "abcdef"; |
| 1434 | var sub2 = subArrayPtr(&a2, 2, 3); | 1439 | var sub2 = subArrayPtr(&a2, 2, 3); |
| 1435 | 1440 | ||
| 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 | } |
| 1440 | 1445 | ||
| 1441 | /// Round an address up to the nearest aligned address | 1446 | /// Round an address up to the nearest aligned address |
| 1442 | pub fn alignForward(addr: usize, alignment: usize) usize { | 1447 | pub fn alignForward(addr: usize, alignment: usize) usize { |
| 1443 | return (addr + alignment - 1) & ~(alignment - 1); | 1448 | return alignBackward(addr + (alignment - 1), alignment); |
| 1444 | } | 1449 | } |
| 1445 | 1450 | ||
| 1446 | test "std.mem.alignForward" { | 1451 | test "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 | |||
| 1466 | pub 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 | |||
| 1473 | pub fn isAligned(addr: usize, alignment: usize) bool { | ||
| 1474 | return alignBackward(addr, alignment) == addr; | ||
| 1475 | } | ||
| 1476 | |||
| 1477 | test "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"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const assert = std.debug.assert; | 3 | const assert = std.debug.assert; |
| 4 | const net = @This(); | 4 | const net = @This(); |
| 5 | const posix = std.os.posix; | ||
| 6 | const mem = std.mem; | 5 | const mem = std.mem; |
| 6 | const os = std.os; | ||
| 7 | 7 | ||
| 8 | pub const TmpWinAddr = struct { | 8 | pub 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 { |
| 12 | 12 | ||
| 13 | pub const OsAddress = switch (builtin.os) { | 13 | pub 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 | }; |
| 17 | 17 | ||
| 18 | pub const Address = struct { | 18 | pub const Address = struct { |
| ... | @@ -20,9 +20,9 @@ pub const Address = struct { | ... | @@ -20,9 +20,9 @@ pub const Address = struct { |
| 20 | 20 | ||
| 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 { |
| 33 | 33 | ||
| 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 | } |
| 52 | 52 | ||
| 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 | } |
| 56 | 56 | ||
| 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 | |||
| 1 | const std = @import("std.zig"); | 17 | const std = @import("std.zig"); |
| 2 | const builtin = @import("builtin"); | 18 | const builtin = @import("builtin"); |
| 3 | const Os = builtin.Os; | 19 | const assert = std.debug.assert; |
| 4 | const is_windows = builtin.os == Os.windows; | 20 | const math = std.math; |
| 5 | const is_posix = switch (builtin.os) { | 21 | const mem = std.mem; |
| 6 | builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => true, | 22 | const MAX_PATH_BYTES = std.fs.MAX_PATH_BYTES; |
| 7 | else => false, | ||
| 8 | }; | ||
| 9 | const os = @This(); | ||
| 10 | 23 | ||
| 11 | comptime { | 24 | comptime { |
| 12 | assert(@import("std") == std); // You have to run the std lib tests with --override-std-dir | 25 | assert(@import("std") == std); // std lib tests require --override-std-dir |
| 13 | } | ||
| 14 | |||
| 15 | test "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 | } |
| 29 | 27 | ||
| 30 | pub const windows = @import("os/windows.zig"); | ||
| 31 | pub const darwin = @import("os/darwin.zig"); | 28 | pub const darwin = @import("os/darwin.zig"); |
| 32 | pub const linux = @import("os/linux.zig"); | ||
| 33 | pub const freebsd = @import("os/freebsd.zig"); | 29 | pub const freebsd = @import("os/freebsd.zig"); |
| 30 | pub const linux = @import("os/linux.zig"); | ||
| 34 | pub const netbsd = @import("os/netbsd.zig"); | 31 | pub const netbsd = @import("os/netbsd.zig"); |
| 35 | pub const zen = @import("os/zen.zig"); | ||
| 36 | pub const uefi = @import("os/uefi.zig"); | 32 | pub const uefi = @import("os/uefi.zig"); |
| 37 | pub const wasi = @import("os/wasi.zig"); | 33 | pub const wasi = @import("os/wasi.zig"); |
| 34 | pub const windows = @import("os/windows.zig"); | ||
| 35 | pub const zen = @import("os/zen.zig"); | ||
| 38 | 36 | ||
| 39 | pub 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, | 38 | pub 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, |
| 48 | 46 | else => struct {}, | |
| 49 | pub const net = @import("net.zig"); | ||
| 50 | |||
| 51 | pub const ChildProcess = @import("os/child_process.zig").ChildProcess; | ||
| 52 | pub const path = @import("os/path.zig"); | ||
| 53 | pub const File = @import("os/file.zig").File; | ||
| 54 | pub const time = @import("os/time.zig"); | ||
| 55 | |||
| 56 | pub const page_size = switch (builtin.arch) { | ||
| 57 | .wasm32, .wasm64 => 64 * 1024, | ||
| 58 | else => 4 * 1024, | ||
| 59 | }; | ||
| 60 | |||
| 61 | pub 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 | }; |
| 70 | 48 | ||
| 71 | pub const UserInfo = @import("os/get_user_id.zig").UserInfo; | 49 | pub use @import("os/bits.zig"); |
| 72 | pub const getUserInfo = @import("os/get_user_id.zig").getUserInfo; | ||
| 73 | 50 | ||
| 74 | const windows_util = @import("os/windows/util.zig"); | 51 | /// See also `getenv`. Populated by startup code before main(). |
| 75 | pub const windowsWaitSingle = windows_util.windowsWaitSingle; | 52 | pub var environ: [][*]u8 = undefined; |
| 76 | pub const windowsWrite = windows_util.windowsWrite; | ||
| 77 | pub const windowsIsCygwinPty = windows_util.windowsIsCygwinPty; | ||
| 78 | pub const windowsOpen = windows_util.windowsOpen; | ||
| 79 | pub const windowsOpenW = windows_util.windowsOpenW; | ||
| 80 | pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock; | ||
| 81 | 53 | ||
| 82 | pub const WindowsCreateIoCompletionPortError = windows_util.WindowsCreateIoCompletionPortError; | 54 | /// Populated by startup code before main(). |
| 83 | pub const windowsCreateIoCompletionPort = windows_util.windowsCreateIoCompletionPort; | 55 | /// Not available on Windows. See `std.process.args` |
| 56 | /// for obtaining the process arguments. | ||
| 57 | pub var argv: [][*]u8 = undefined; | ||
| 84 | 58 | ||
| 85 | pub const WindowsPostQueuedCompletionStatusError = windows_util.WindowsPostQueuedCompletionStatusError; | 59 | /// To obtain errno, call this function with the return value of the |
| 86 | pub const windowsPostQueuedCompletionStatus = windows_util.windowsPostQueuedCompletionStatus; | 60 | /// system function call. For some systems this will obtain the value directly |
| 87 | 61 | /// from the return code; for others it will use a thread-local errno variable. | |
| 88 | pub const WindowsWaitResult = windows_util.WindowsWaitResult; | 62 | /// Therefore, this function only returns a well-defined value when it is called |
| 89 | pub const windowsGetQueuedCompletionStatus = windows_util.windowsGetQueuedCompletionStatus; | 63 | /// directly after the system function call which one wants to learn the errno |
| 90 | 64 | /// value of. | |
| 91 | pub const WindowsWaitError = windows_util.WaitError; | 65 | pub const errno = system.getErrno; |
| 92 | pub const WindowsOpenError = windows_util.OpenError; | ||
| 93 | pub const WindowsWriteError = windows_util.WriteError; | ||
| 94 | pub const WindowsReadError = windows_util.ReadError; | ||
| 95 | |||
| 96 | pub const FileHandle = if (is_windows) windows.HANDLE else i32; | ||
| 97 | |||
| 98 | pub const getAppDataDir = @import("os/get_app_data_dir.zig").getAppDataDir; | ||
| 99 | pub const GetAppDataDirError = @import("os/get_app_data_dir.zig").GetAppDataDirError; | ||
| 100 | |||
| 101 | const debug = std.debug; | ||
| 102 | const assert = debug.assert; | ||
| 103 | const testing = std.testing; | ||
| 104 | |||
| 105 | const c = std.c; | ||
| 106 | |||
| 107 | const mem = std.mem; | ||
| 108 | const Allocator = mem.Allocator; | ||
| 109 | 66 | ||
| 110 | const BufMap = std.BufMap; | 67 | /// Closes the file descriptor. |
| 111 | const 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. | ||
| 72 | pub 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 | } | ||
| 112 | 92 | ||
| 113 | const io = std.io; | 93 | pub const GetRandomError = OpenError; |
| 114 | const base64 = std.base64; | ||
| 115 | const ArrayList = std.ArrayList; | ||
| 116 | const Buffer = std.Buffer; | ||
| 117 | const math = std.math; | ||
| 118 | 94 | ||
| 119 | /// Fills `buf` with random bytes. If linking against libc, this calls the | 95 | /// 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 standard | 98 | /// appropriate OS-specific library call. Otherwise it uses the zig standard |
| 121 | /// library implementation. | 99 | /// library implementation. |
| 122 | pub fn getRandomBytes(buf: []u8) !void { | 100 | pub 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 #397 | 104 | 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 | } |
| 166 | 125 | ||
| 167 | fn getRandomBytesDevURandom(buf: []u8) !void { | 126 | fn 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); |
| 170 | 129 | ||
| 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 | |||
| 183 | test "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 | } |
| 193 | 133 | ||
| 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. Otherwise | 135 | /// 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 |
| 197 | pub fn abort() noreturn { | 137 | pub 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 | } |
| 227 | 160 | ||
| 228 | /// Exits the program cleanly with the specified status code. | 161 | pub const RaiseError = error{Unexpected}; |
| 229 | pub fn exit(status: u8) noreturn { | 162 | |
| 230 | @setCold(true); | 163 | pub 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 | } | ||
| 254 | 170 | ||
| 255 | /// When a file descriptor is closed on linux, it pops the first | 171 | 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 list | 175 | } |
| 260 | pub var emfile_promise_queue = std.LinkedList(promise).init(); | 176 | } |
| 261 | 177 | ||
| 262 | /// Closes the file handle. Keeps trying if it gets interrupted by a signal. | 178 | if (linux.is_the_target) { |
| 263 | pub 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 | |||
| 193 | pub const KillError = error{ | ||
| 194 | PermissionDenied, | ||
| 195 | Unexpected, | ||
| 196 | }; | ||
| 197 | |||
| 198 | pub 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 | } |
| 279 | 207 | ||
| 280 | pub const PosixReadError = error{ | 208 | /// Exits the program cleanly with the specified status code. |
| 209 | pub 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 | |||
| 225 | pub 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 | }; |
| 286 | 233 | ||
| 287 | /// Returns the number of bytes that were read, which can be less than | 234 | /// 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. |
| 289 | pub fn posixRead(fd: i32, buf: []u8) PosixReadError!usize { | 236 | /// This function is for blocking file descriptors only. For non-blocking, see |
| 237 | /// `readAsync`. | ||
| 238 | pub 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 > 0x7ffff000 | 256 | // Linux can return EINVAL when read amount is > 0x7ffff000 |
| 291 | // See https://github.com/ziglang/zig/pull/743#issuecomment-363158274 | 257 | // 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; |
| 293 | 261 | ||
| 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 condition | 278 | 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 | } |
| 320 | 288 | ||
| 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. |
| 322 | pub 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 => { | 292 | pub 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 blocking | 307 | if (inner_off == v.iov_len) { |
| 370 | posix.EBADF => unreachable, // always a race condition | 308 | 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 | } |
| 381 | 349 | ||
| 382 | pub const PosixWriteError = error{ | 350 | pub 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, |
| 389 | 357 | SystemResources, | |
| 390 | /// See https://github.com/ziglang/zig/issues/1396 | 358 | OperationAborted, |
| 391 | Unexpected, | 359 | Unexpected, |
| 392 | }; | 360 | }; |
| 393 | 361 | ||
| 394 | /// Calls POSIX write, and keeps trying if it gets interrupted. | 362 | /// Write to a file descriptor. Keeps trying if it gets interrupted. |
| 395 | pub fn posixWrite(fd: i32, bytes: []const u8) PosixWriteError!void { | 363 | /// This function is for blocking file descriptors only. For non-blocking, see |
| 364 | /// `writeAsync`. | ||
| 365 | pub 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 > 0x7ffff000 | 382 | // Linux can return EINVAL when write amount is > 0x7ffff000 |
| 397 | // See https://github.com/ziglang/zig/pull/743#issuecomment-363165856 | 383 | // 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; |
| 399 | 387 | ||
| 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-blocking | 400 | EAGAIN => unreachable, // This function is for blocking writes. |
| 414 | posix.EBADF => unreachable, // always a race condition | 401 | EBADF => unreachable, // Always a race condition. |
| 415 | posix.EDESTADDRREQ => unreachable, // connect was never called | 402 | 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`. | ||
| 417 | pub 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 | } | ||
| 426 | 458 | ||
| 427 | pub 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 | } |
| 491 | 480 | ||
| 492 | pub const PosixOpenError = error{ | 481 | pub 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 | }; |
| 511 | 498 | ||
| 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 translates | 500 | /// `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`. |
| 515 | pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize) PosixOpenError!i32 { | 502 | pub 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 | } |
| 519 | 506 | ||
| 520 | // TODO https://github.com/ziglang/zig/issues/265 | 507 | /// Open and possibly create a file. Keeps trying if it gets interrupted. |
| 521 | pub fn posixOpenC(file_path: [*]const u8, flags: u32, perm: usize) !i32 { | 508 | /// See also `open`. |
| 509 | /// TODO https://github.com/ziglang/zig/issues/265 | ||
| 510 | pub 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 | |
| 528 | 517 | 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 | } | 540 | pub 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 | ||
| 555 | pub 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 | |||
| 563 | pub 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 | |||
| 578 | pub 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 | |||
| 601 | pub 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 | } |
| 608 | 551 | ||
| 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. |
| 614 | pub 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); | 558 | pub 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; |
| 628 | 572 | ||
| 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; |
| 632 | 576 | ||
| 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); |
| 635 | 579 | ||
| 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 | } |
| 640 | 584 | ||
| 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_path | 586 | // PATH.len because it is >= the largest search_path |
| 643 | // +1 for the / to join the search path and exe_path | 587 | // +1 for the / to join the search path and exe_path |
| 644 | // +1 for the null terminating byte | 588 | // +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 | |||
| 613 | pub 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 | |||
| 636 | pub 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 | } |
| 668 | 643 | ||
| 669 | pub const PosixExecveError = error{ | 644 | pub 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, | ||
| 678 | 656 | ||
| 679 | /// See https://github.com/ziglang/zig/issues/1396 | ||
| 680 | Unexpected, | 657 | Unexpected, |
| 681 | }; | 658 | }; |
| 682 | 659 | ||
| 683 | fn posixExecveErrnoToErr(err: usize) PosixExecveError { | 660 | fn 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 | } |
| 705 | 682 | ||
| 706 | pub var linux_elf_aux_maybe: ?[*]std.elf.Auxv = null; | 683 | /// Get an environment variable. |
| 707 | pub var posix_environ_raw: [][*]u8 = undefined; | 684 | /// See also `getenvC`. |
| 708 | 685 | /// TODO make this go through libc when we have it | |
| 709 | /// See std.elf for the constants. | 686 | pub fn getenv(key: []const u8) ?[]const u8 { |
| 710 | pub 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 | } |
| 722 | 701 | ||
| 723 | pub 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); | 705 | pub 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 | } |
| 740 | 712 | ||
| 741 | /// Caller must free result when done. | 713 | pub const GetCwdError = error{ |
| 742 | /// TODO make this go through libc when we have it | 714 | NameTooLong, |
| 743 | pub 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); | ||
| 761 | 718 | ||
| 762 | if (ptr[i] == '=') i += 1; | 719 | /// The result is a slice of out_buffer, indexed from 0. |
| 720 | pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 { | ||
| 721 | if (windows.is_the_target) { | ||
| 722 | return windows.GetCurrentDirectory(out_buffer); | ||
| 723 | } | ||
| 763 | 724 | ||
| 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 | } | ||
| 769 | 739 | ||
| 770 | i += 1; // skip over null byte | 740 | pub const SymLinkError = error{ |
| 771 | 741 | 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, |
| 777 | 747 | 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 | |||
| 821 | test "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 | ||
| 827 | pub 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 | |||
| 843 | pub 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 | }; |
| 850 | 756 | ||
| 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 it | 758 | /// A symbolic link (also known as a soft link) may point to an existing file or to a nonexistent |
| 853 | pub 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); | 762 | pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError!void { |
| 857 | 763 | 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); |
| 860 | 766 | 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 | } |
| 893 | 773 | ||
| 894 | test "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")); | 776 | pub fn symlinkC(target_path: [*]const u8, sym_link_path: [*]const u8) SymLinkError!void { |
| 897 | } | 777 | if (windows.is_the_target) { |
| 898 | 778 | 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); |
| 900 | pub 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 | |||
| 905 | pub const GetCwdError = error{Unexpected}; | ||
| 906 | |||
| 907 | /// The result is a slice of out_buffer. | ||
| 908 | pub 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 | |||
| 802 | pub 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 | |||
| 808 | pub 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 | |||
| 829 | pub 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, | ||
| 937 | 841 | ||
| 938 | test "os.getCwd" { | 842 | /// On Windows, file paths must be valid Unicode. |
| 939 | // at least call it so it gets compiled | 843 | InvalidUtf8, |
| 940 | _ = getCwdAlloc(debug.global_allocator) catch undefined; | ||
| 941 | var buf: [MAX_PATH_BYTES]u8 = undefined; | ||
| 942 | _ = getCwd(&buf) catch undefined; | ||
| 943 | } | ||
| 944 | 844 | ||
| 945 | pub const SymLinkError = PosixSymLinkError || WindowsSymLinkError; | 845 | /// On Windows, file paths cannot contain these characters: |
| 846 | /// '/', '*', '?', '"', '<', '>', '|' | ||
| 847 | BadPathName, | ||
| 848 | }; | ||
| 946 | 849 | ||
| 947 | /// TODO add a symLinkC variant | 850 | /// Delete a name and possibly the file it refers to. |
| 948 | pub fn symLink(existing_path: []const u8, new_path: []const u8) SymLinkError!void { | 851 | /// See also `unlinkC`. |
| 949 | if (is_windows) { | 852 | pub 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 | } |
| 955 | 861 | ||
| 956 | pub const WindowsSymLinkError = error{ | 862 | /// Same as `unlink` except the parameter is a null terminated UTF8-encoded string. |
| 863 | pub 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 | |||
| 887 | const 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 | }; |
| 964 | 906 | ||
| 965 | pub 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) { | 908 | pub 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 | } |
| 973 | 919 | ||
| 974 | pub 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); | 921 | pub 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. | ||
| 953 | pub 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 | } |
| 979 | 957 | ||
| 980 | pub const PosixSymLinkError = error{ | 958 | pub 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, |
| 992 | 969 | ReadOnlyFileSystem, | |
| 993 | /// See https://github.com/ziglang/zig/issues/1396 | 970 | InvalidUtf8, |
| 971 | BadPathName, | ||
| 994 | Unexpected, | 972 | Unexpected, |
| 995 | }; | 973 | }; |
| 996 | 974 | ||
| 997 | pub 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) { | 977 | pub 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 | |||
| 1019 | pub 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 | ||
| 1026 | const b64_fs_encoder = base64.Base64Encoder.init("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", base64.standard_pad_char); | ||
| 1027 | |||
| 1028 | /// TODO remove the allocator requirement from this API | ||
| 1029 | pub 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 | } | ||
| 1036 | 986 | ||
| 1037 | const dirname = os.path.dirname(new_path) orelse "."; | 987 | /// Same as `mkdir` but the parameter is a null-terminated UTF8-encoded string. |
| 1038 | 988 | pub 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, |
| 1047 | 997 | 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 PathAlreadyExists | 1002 | 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 | } |
| 1056 | 1011 | ||
| 1057 | pub const DeleteFileError = error{ | 1012 | pub 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 | }; |
| 1079 | 1026 | ||
| 1080 | pub fn deleteFile(file_path: []const u8) DeleteFileError!void { | 1027 | /// Deletes an empty directory. |
| 1081 | if (builtin.os == Os.windows) { | 1028 | pub 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 | } |
| 1089 | 1037 | ||
| 1090 | pub 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) { | 1039 | pub 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 | |||
| 1063 | pub const ChangeCurDirError = error{ | ||
| 1064 | AccessDenied, | ||
| 1065 | FileSystem, | ||
| 1066 | SymLinkLoop, | ||
| 1067 | NameTooLong, | ||
| 1068 | FileNotFound, | ||
| 1069 | SystemResources, | ||
| 1070 | NotDir, | ||
| 1071 | Unexpected, | ||
| 1072 | }; | ||
| 1102 | 1073 | ||
| 1103 | pub 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); | 1076 | pub 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 | } |
| 1128 | 1085 | ||
| 1129 | /// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is | 1086 | /// Same as `chdir` except the parameter is null-terminated. |
| 1130 | /// merged and readily available, | 1087 | pub fn chdirC(dir_path: [*]const u8) ChangeCurDirError!void { |
| 1131 | /// there is a possibility of power loss or application termination leaving temporary files present | 1088 | 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"); |
| 1134 | pub 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, |
| 1137 | 1094 | 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, |
| 1140 | 1097 | 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, |
| 1143 | 1100 | 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 | } |
| 1153 | 1105 | ||
| 1154 | /// Guaranteed to be atomic. However until https://patchwork.kernel.org/patch/9636735/ is | 1106 | pub const ReadLinkError = error{ |
| 1155 | /// merged and readily available, | 1107 | AccessDenied, |
| 1156 | /// there is a possibility of power loss or application termination leaving temporary files present | 1108 | FileSystem, |
| 1157 | pub 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, |
| 1160 | 1112 | SystemResources, | |
| 1161 | var atomic_file = try AtomicFile.init(dest_path, mode); | 1113 | NotDir, |
| 1162 | defer atomic_file.deinit(); | 1114 | Unexpected, |
| 1115 | }; | ||
| 1163 | 1116 | ||
| 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..]); | 1119 | pub 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 | } |
| 1173 | 1128 | ||
| 1174 | pub const AtomicFile = struct { | 1129 | /// Same as `readlink` except `file_path` is null-terminated. |
| 1175 | file: os.File, | 1130 | pub 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 | } |
| 1221 | 1135 | 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 | } | ||
| 1230 | 1150 | ||
| 1231 | pub fn finish(self: *AtomicFile) !void { | 1151 | pub 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 | }; |
| 1247 | 1157 | ||
| 1248 | pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) !void { | 1158 | pub 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 | } |
| 1279 | 1167 | ||
| 1280 | pub fn renameW(old_path: [*]const u16, new_path: [*]const u16) !void { | 1168 | pub 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 | } |
| 1289 | 1177 | ||
| 1290 | pub fn rename(old_path: []const u8, new_path: []const u8) !void { | 1178 | pub 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 | } |
| 1301 | 1187 | ||
| 1302 | pub fn makeDir(dir_path: []const u8) !void { | 1188 | pub 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 | } |
| 1309 | 1197 | ||
| 1310 | pub 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); | 1199 | pub fn isatty(handle: fd_t) bool { |
| 1200 | if (windows.is_the_target) { | ||
| 1201 | if (isCygwinPty(handle)) | ||
| 1202 | return true; | ||
| 1312 | 1203 | ||
| 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) { |
| 1322 | 1208 | return system.isatty(handle) != 0; | |
| 1323 | pub 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 | |||
| 1344 | pub 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 | ||
| 1352 | pub 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 | } |
| 1383 | 1219 | ||
| 1384 | pub const DeleteDirError = error{ | 1220 | pub 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, | ||
| 1396 | 1222 | ||
| 1397 | /// See https://github.com/ziglang/zig/issues/1396 | 1223 | 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 | }; | ||
| 1400 | 1225 | ||
| 1401 | pub 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 | } | ||
| 1430 | 1234 | ||
| 1431 | pub 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 | } |
| 1441 | 1241 | ||
| 1442 | /// Returns ::error.DirNotEmpty if the directory is not empty. | 1242 | pub const SocketError = error{ |
| 1443 | /// To delete a directory recursively, see ::deleteTree | 1243 | /// Permission to create a socket of the specified type and/or |
| 1444 | pub 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. | ||
| 1461 | const 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 | ||
| 1494 | pub 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 | |||
| 1564 | pub 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 | |||
| 1889 | pub 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. | ||
| 1908 | pub 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. | ||
| 1928 | pub 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 | |||
| 1933 | pub 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 | |||
| 1944 | pub 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 | |||
| 1955 | pub 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 | |||
| 1966 | pub 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 | |||
| 1977 | pub const WindowsGetStdHandleErrs = error{ | ||
| 1978 | NoStdHandles, | ||
| 1979 | |||
| 1980 | /// See https://github.com/ziglang/zig/issues/1396 | ||
| 1981 | Unexpected, | ||
| 1982 | }; | ||
| 1983 | |||
| 1984 | pub 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 | |||
| 1998 | pub 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 | |||
| 2029 | pub 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 | |||
| 2178 | pub 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 | |||
| 2215 | pub fn args() ArgIterator { | ||
| 2216 | return ArgIterator.init(); | ||
| 2217 | } | ||
| 2218 | |||
| 2219 | /// Caller must call argsFree on result. | ||
| 2220 | pub 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 | |||
| 2285 | pub 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 | |||
| 2305 | test "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 | |||
| 2322 | fn 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 | ||
| 2332 | const unexpected_error_tracing = false; | ||
| 2333 | const 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. | ||
| 2340 | pub 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. | ||
| 2350 | pub 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 | |||
| 2359 | pub 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 | |||
| 2377 | test "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 | |||
| 2384 | pub 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 | ||
| 2407 | pub 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. | ||
| 2455 | pub 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. | ||
| 2462 | pub 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 | |||
| 2484 | pub 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 | |||
| 2496 | pub 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 | |||
| 2508 | pub const PosixSocketError = error{ | ||
| 2509 | /// Permission to create a socket of the specified type and/or | ||
| 2510 | /// pro‐tocol is denied. | ||
| 2511 | PermissionDenied, | ||
| 2512 | 1246 | ||
| 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{ |
| 2528 | 1262 | ||
| 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 | }; |
| 2532 | 1268 | ||
| 2533 | pub fn posixSocket(domain: u32, socket_type: u32, protocol: u32) !i32 { | 1269 | pub 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 | } |
| 2548 | 1283 | ||
| 2549 | pub const PosixBindError = error{ | 1284 | pub 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 component | 1286 | /// 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, |
| 2582 | 1317 | ||
| 2583 | /// See https://github.com/ziglang/zig/issues/1396 | ||
| 2584 | Unexpected, | 1318 | Unexpected, |
| 2585 | }; | 1319 | }; |
| 2586 | 1320 | ||
| 2587 | /// addr is `&const T` where T is one of the sockaddr | 1321 | /// addr is `*const T` where T is one of the sockaddr |
| 2588 | pub fn posixBind(fd: i32, addr: *const posix.sockaddr) PosixBindError!void { | 1322 | pub 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 returned | 1328 | 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 | } |
| 2609 | 1342 | ||
| 2610 | const PosixListenError = error{ | 1343 | const 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 previously | 1345 | /// 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, it | 1346 | /// 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, |
| 2623 | 1356 | ||
| 2624 | /// See https://github.com/ziglang/zig/issues/1396 | ||
| 2625 | Unexpected, | 1357 | Unexpected, |
| 2626 | }; | 1358 | }; |
| 2627 | 1359 | ||
| 2628 | pub fn posixListen(sockfd: i32, backlog: u32) PosixListenError!void { | 1360 | pub 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 | } |
| 2640 | 1371 | ||
| 2641 | pub const PosixAcceptError = error{ | 1372 | pub const AcceptError = error{ |
| 2642 | ConnectionAborted, | 1373 | ConnectionAborted, |
| 2643 | 1374 | ||
| 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, |
| 2664 | 1395 | ||
| 2665 | /// See https://github.com/ziglang/zig/issues/1396 | ||
| 2666 | Unexpected, | 1396 | Unexpected, |
| 2667 | }; | 1397 | }; |
| 2668 | 1398 | ||
| 2669 | pub 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`. | ||
| 1401 | pub 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), |
| 2678 | 1409 | ||
| 2679 | posix.EAGAIN => unreachable, // use posixAsyncAccept for non-blocking | 1410 | EAGAIN => unreachable, // This function is for blocking only. |
| 2680 | posix.EBADF => unreachable, // always a race condition | 1411 | 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 | } |
| 2695 | 1426 | ||
| 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. |
| 2697 | pub fn posixAsyncAccept(fd: i32, addr: *posix.sockaddr, flags: u32) PosixAcceptError!i32 { | 1429 | pub 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), |
| 2706 | 1437 | ||
| 2707 | posix.EAGAIN => return -1, | 1438 | EAGAIN => return -1, |
| 2708 | posix.EBADF => unreachable, // always a race condition | 1439 | 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 | } |
| 2723 | 1454 | ||
| 2724 | pub const LinuxEpollCreateError = error{ | 1455 | pub const EpollCreateError = error{ |
| 2725 | /// The per-user limit on the number of epoll instances imposed by | 1456 | /// 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 further | 1457 | /// /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, |
| 2736 | 1467 | ||
| 2737 | /// See https://github.com/ziglang/zig/issues/1396 | ||
| 2738 | Unexpected, | 1468 | Unexpected, |
| 2739 | }; | 1469 | }; |
| 2740 | 1470 | ||
| 2741 | pub fn linuxEpollCreate(flags: u32) LinuxEpollCreateError!i32 { | 1471 | pub 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), |
| 2747 | 1476 | ||
| 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 | } |
| 2754 | 1483 | ||
| 2755 | pub const LinuxEpollCtlError = error{ | 1484 | pub const EpollCtlError = error{ |
| 2756 | /// op was EPOLL_CTL_ADD, and the supplied file descriptor fd is already registered | 1485 | /// 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, |
| 2779 | 1508 | ||
| 2780 | /// See https://github.com/ziglang/zig/issues/1396 | ||
| 2781 | Unexpected, | 1509 | Unexpected, |
| 2782 | }; | 1510 | }; |
| 2783 | 1511 | ||
| 2784 | pub fn linuxEpollCtl(epfd: i32, op: u32, fd: i32, event: *linux.epoll_event) LinuxEpollCtlError!void { | 1512 | pub 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. | ||
| 1532 | pub 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 | |||
| 1547 | pub const EventFdError = error{ | ||
| 1548 | SystemResources, | ||
| 1549 | ProcessFdQuotaExceeded, | ||
| 1550 | SystemFdQuotaExceeded, | ||
| 1551 | Unexpected, | ||
| 1552 | }; | ||
| 1553 | |||
| 1554 | pub 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 | |||
| 1568 | pub const GetSockNameError = error{ | ||
| 1569 | /// Insufficient resources were available in the system to perform the operation. | ||
| 1570 | SystemResources, | ||
| 1571 | |||
| 1572 | Unexpected, | ||
| 1573 | }; | ||
| 1574 | |||
| 1575 | pub 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 | |||
| 1590 | pub 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`. | ||
| 1629 | pub 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`. | ||
| 1657 | pub 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 | |||
| 1682 | pub 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 | |||
| 1716 | pub 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 | |||
| 1731 | pub const FStatError = error{ | ||
| 1732 | SystemResources, | ||
| 1733 | Unexpected, | ||
| 1734 | }; | ||
| 1735 | |||
| 1736 | pub 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 | |||
| 1755 | pub 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 | |||
| 1765 | pub 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 | |||
| 1775 | pub 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 | |||
| 1793 | pub 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 | |||
| 1823 | pub const INotifyInitError = error{ | ||
| 1824 | ProcessFdQuotaExceeded, | ||
| 1825 | SystemFdQuotaExceeded, | ||
| 1826 | SystemResources, | ||
| 1827 | Unexpected, | ||
| 1828 | }; | ||
| 1829 | |||
| 1830 | /// initialize an inotify instance | ||
| 1831 | pub 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 | |||
| 1843 | pub 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 | ||
| 1853 | pub 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 | } | ||
| 2790 | 1857 | ||
| 2791 | posix.EBADF => unreachable, // always a race condition if this happens | 1858 | /// Same as `inotify_add_watch` except pathname is null-terminated. |
| 2792 | posix.EEXIST => return LinuxEpollCtlError.FileDescriptorAlreadyPresentInSet, | 1859 | pub 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 | } |
| 2801 | 1874 | ||
| 2802 | pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usize { | 1875 | /// remove an existing watch from an inotify instance |
| 2803 | while (true) { | 1876 | pub 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 | } |
| 2816 | 1884 | ||
| 2817 | pub const LinuxEventFdError = error{ | 1885 | pub 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 | }; |
| 2826 | 1890 | ||
| 2827 | pub fn linuxEventFd(initval: u32, flags: u32) LinuxEventFdError!i32 { | 1891 | /// `memory.len` must be page-aligned. |
| 2828 | const rc = posix.eventfd(initval, flags); | 1892 | pub 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, |
| 2833 | 1897 | 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 | } |
| 2841 | 1902 | ||
| 2842 | pub const PosixGetSockNameError = error{ | 1903 | pub 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 | }; |
| 2849 | 1907 | ||
| 2850 | pub fn posixGetSockName(sockfd: i32) PosixGetSockNameError!posix.sockaddr { | 1908 | pub 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 | } |
| 2866 | 1917 | ||
| 2867 | pub const PosixConnectError = error{ | 1918 | pub const MMapError = error{ |
| 2868 | /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket | 1919 | /// 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, | ||
| 2874 | 1921 | ||
| 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, | ||
| 2877 | 1927 | ||
| 2878 | /// (Internet domain sockets) The socket referred to by sockfd had not previously been bound to an | 1928 | /// 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 numbers | 1929 | /// a filesystem that was mounted no-exec. |
| 2880 | /// in the ephemeral port range are currently in use. See the discussion of | 1930 | PermissionDenied, |
| 2881 | /// /proc/sys/net/ipv4/ip_local_port_range in ip(7). | 1931 | LockedMemoryLimitExceeded, |
| 2882 | AddressNotAvailable, | 1932 | OutOfMemory, |
| 1933 | Unexpected, | ||
| 1934 | }; | ||
| 2883 | 1935 | ||
| 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 | ||
| 1941 | pub 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. | ||
| 1980 | pub 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 | } | ||
| 2886 | 1988 | ||
| 2887 | /// Insufficient entries in the routing cache. | 1989 | pub const AccessError = error{ |
| 1990 | PermissionDenied, | ||
| 1991 | FileNotFound, | ||
| 1992 | NameTooLong, | ||
| 1993 | InputOutput, | ||
| 2888 | SystemResources, | 1994 | SystemResources, |
| 1995 | BadPathName, | ||
| 2889 | 1996 | ||
| 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, | ||
| 2899 | 1999 | ||
| 2900 | /// See https://github.com/ziglang/zig/issues/1396 | ||
| 2901 | Unexpected, | 2000 | Unexpected, |
| 2902 | }; | 2001 | }; |
| 2903 | 2002 | ||
| 2904 | pub 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)); | 2005 | pub 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 | } |
| 2932 | 2014 | ||
| 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. | 2016 | pub fn accessC(path: [*]const u8, mode: u32) AccessError!void { |
| 2935 | pub 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, | ||
| 2962 | 2030 | ||
| 2963 | pub 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 | } |
| 2998 | 2039 | ||
| 2999 | pub const Thread = struct { | 2040 | pub const PipeError = error{ |
| 3000 | data: Data, | 2041 | SystemFdQuotaExceeded, |
| 3001 | 2042 | ProcessFdQuotaExceeded, | |
| 3002 | pub const use_pthreads = is_posix and builtin.link_libc; | 2043 | Unexpected, |
| 3003 | 2044 | }; | |
| 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 | }; | ||
| 3022 | 2045 | ||
| 3023 | pub const Data = if (use_pthreads) | 2046 | /// Creates a unidirectional data channel that can be used for interprocess communication. |
| 3024 | struct { | 2047 | pub 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 | }; | ||
| 3042 | 2058 | ||
| 3043 | /// Returns the ID of the calling thread. | 2059 | pub 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 | } else | 2065 | 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 | } |
| 3102 | 2070 | ||
| 3103 | pub const SpawnThreadError = error{ | 2071 | pub 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, |
| 3122 | 2074 | 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 | }; |
| 3129 | 2077 | ||
| 3130 | /// caller must call wait on the returned thread | 2078 | pub fn sysctl( |
| 3131 | /// fn startFn(@typeOf(context)) T | 2079 | name: []const c_int, |
| 3132 | /// where T is u8, noreturn, void, or !void | 2080 | oldp: ?*c_void, |
| 3133 | /// caller must call wait on the returned thread | 2081 | oldlenp: ?*usize, |
| 3134 | pub 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 bound | 2084 | ) SysCtlError!void { |
| 3137 | // https://github.com/ziglang/zig/issues/157 | 2085 | 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))) { |
| 3139 | 2087 | 0 => return, | |
| 3140 | const Context = @typeOf(context); | 2088 | EFAULT => unreachable, |
| 3141 | comptime assert(@ArgType(@typeOf(startFn), 0) == Context); | 2089 | EPERM => return error.PermissionDenied, |
| 3142 | 2090 | 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 | } |
| 3303 | 2094 | ||
| 3304 | pub fn posixWait(pid: i32) i32 { | 2095 | pub 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 invalid | 2103 | 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 | } |
| 3317 | 2110 | ||
| 3318 | pub fn posixFStat(fd: i32) !posix.Stat { | 2111 | pub 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 | } |
| 3333 | 2118 | ||
| 3334 | pub const CpuCountError = error{ | 2119 | pub 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 | }; |
| 3341 | 2123 | ||
| 3342 | pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize { | 2124 | /// Repositions read/write file offset relative to the beginning. |
| 3343 | switch (builtin.os) { | 2125 | pub 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 | } |
| 3404 | 2151 | ||
| 3405 | pub 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. | 2153 | pub 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) { |
| 3408 | 2155 | 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 | } | ||
| 3411 | 2178 | ||
| 3412 | /// See https://github.com/ziglang/zig/issues/1396 | 2179 | /// Repositions read/write file offset relative to the end. |
| 3413 | Unexpected, | 2180 | pub 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 | } | ||
| 3415 | 2204 | ||
| 3416 | pub fn bsdKQueue() BsdKQueueError!i32 { | 2205 | /// Returns the read/write file offset relative to the beginning. |
| 3417 | const rc = posix.kqueue(); | 2206 | pub 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 | } |
| 3426 | 2233 | ||
| 3427 | pub const BsdKEventError = error{ | 2234 | pub 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, | ||
| 3430 | 2252 | ||
| 3431 | /// The event could not be found to be modified or deleted. | 2253 | SharingViolation, |
| 3432 | EventNotFound, | 2254 | PipeBusy, |
| 3433 | 2255 | ||
| 3434 | /// No memory was available to register the event. | 2256 | /// On Windows, file paths must be valid Unicode. |
| 3435 | SystemResources, | 2257 | InvalidUtf8, |
| 3436 | 2258 | ||
| 3437 | /// The specified process to attach to does not exist. | 2259 | PathAlreadyExists, |
| 3438 | ProcessNotFound, | 2260 | |
| 2261 | Unexpected, | ||
| 3439 | }; | 2262 | }; |
| 3440 | 2263 | ||
| 3441 | pub 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 { | 2269 | pub 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. | ||
| 2279 | pub 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. | ||
| 2310 | pub 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. | ||
| 2338 | pub 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 | } |
| 3464 | 2361 | ||
| 3465 | pub fn linuxINotifyInit1(flags: u32) !i32 { | 2362 | pub 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, | 2367 | pub 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 | } |
| 3477 | 2375 | ||
| 3478 | pub fn linuxINotifyAddWatchC(inotify_fd: i32, pathname: [*]const u8, mask: u32) !i32 { | 2376 | pub 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 | } |
| 3494 | 2384 | ||
| 3495 | pub fn linuxINotifyRmWatch(inotify_fd: i32, wd: i32) !void { | 2385 | pub 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, | 2390 | pub 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 | } |
| 3505 | 2401 | ||
| 3506 | pub 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, | 2404 | pub 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. | ||
| 2417 | pub const unexpected_error_tracing = builtin.mode == .Debug; | ||
| 2418 | |||
| 2419 | pub 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 | }; |
| 3511 | 2425 | ||
| 3512 | /// address and length must be page-aligned | 2426 | /// Call this when you made a syscall or something that sets errno |
| 3513 | pub 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)); | 2428 | pub 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 | |||
| 2436 | test "" { | ||
| 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 | |||
| 4 | const builtin = @import("builtin"); | ||
| 5 | |||
| 6 | pub 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 | |||
| 16 | pub const pthread_t = *@OpaqueType(); | ||
| 17 | pub const FILE = @OpaqueType(); | ||
| 18 | |||
| 19 | pub const iovec = extern struct { | ||
| 20 | iov_base: [*]u8, | ||
| 21 | iov_len: usize, | ||
| 22 | }; | ||
| 23 | |||
| 24 | pub 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 @@ | ||
| 1 | const std = @import("../../std.zig"); | ||
| 2 | const assert = std.debug.assert; | ||
| 3 | const maxInt = std.math.maxInt; | ||
| 4 | |||
| 5 | pub const fd_t = c_int; | ||
| 6 | pub const pid_t = c_int; | ||
| 7 | |||
| 8 | pub const in_port_t = u16; | ||
| 9 | pub const sa_family_t = u8; | ||
| 10 | pub const socklen_t = u32; | ||
| 11 | pub const sockaddr = extern union { | ||
| 12 | in: sockaddr_in, | ||
| 13 | in6: sockaddr_in6, | ||
| 14 | }; | ||
| 15 | pub 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 | }; | ||
| 22 | pub 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 | |||
| 31 | pub const timeval = extern struct { | ||
| 32 | tv_sec: c_long, | ||
| 33 | tv_usec: i32, | ||
| 34 | }; | ||
| 35 | |||
| 36 | pub const timezone = extern struct { | ||
| 37 | tz_minuteswest: i32, | ||
| 38 | tz_dsttime: i32, | ||
| 39 | }; | ||
| 40 | |||
| 41 | pub 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. | ||
| 47 | pub 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 | |||
| 72 | pub const timespec = extern struct { | ||
| 73 | tv_sec: isize, | ||
| 74 | tv_nsec: isize, | ||
| 75 | }; | ||
| 76 | |||
| 77 | pub const sigset_t = u32; | ||
| 78 | pub const empty_sigset = sigset_t(0); | ||
| 79 | |||
| 80 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name. | ||
| 81 | pub const Sigaction = extern struct { | ||
| 82 | handler: extern fn (c_int) void, | ||
| 83 | sa_mask: sigset_t, | ||
| 84 | sa_flags: c_int, | ||
| 85 | }; | ||
| 86 | |||
| 87 | pub 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 | |||
| 96 | pub 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. | ||
| 102 | pub 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. | ||
| 114 | comptime { | ||
| 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 | |||
| 123 | pub 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. | ||
| 136 | comptime { | ||
| 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 | |||
| 146 | pub const mach_port_t = c_uint; | ||
| 147 | pub const clock_serv_t = mach_port_t; | ||
| 148 | pub const clock_res_t = c_int; | ||
| 149 | pub const mach_port_name_t = natural_t; | ||
| 150 | pub const natural_t = c_uint; | ||
| 151 | pub const mach_timespec_t = extern struct { | ||
| 152 | tv_sec: c_uint, | ||
| 153 | tv_nsec: clock_res_t, | ||
| 154 | }; | ||
| 155 | pub const kern_return_t = c_int; | ||
| 156 | pub const host_t = mach_port_t; | ||
| 157 | pub const CALENDAR_CLOCK = 1; | ||
| 158 | |||
| 159 | pub const PATH_MAX = 1024; | ||
| 160 | |||
| 161 | pub const STDIN_FILENO = 0; | ||
| 162 | pub const STDOUT_FILENO = 1; | ||
| 163 | pub const STDERR_FILENO = 2; | ||
| 164 | |||
| 165 | /// [MC2] no permissions | ||
| 166 | pub const PROT_NONE = 0x00; | ||
| 167 | |||
| 168 | /// [MC2] pages can be read | ||
| 169 | pub const PROT_READ = 0x01; | ||
| 170 | |||
| 171 | /// [MC2] pages can be written | ||
| 172 | pub const PROT_WRITE = 0x02; | ||
| 173 | |||
| 174 | /// [MC2] pages can be executed | ||
| 175 | pub const PROT_EXEC = 0x04; | ||
| 176 | |||
| 177 | /// allocated from memory, swap space | ||
| 178 | pub const MAP_ANONYMOUS = 0x1000; | ||
| 179 | |||
| 180 | /// map from file (default) | ||
| 181 | pub const MAP_FILE = 0x0000; | ||
| 182 | |||
| 183 | /// interpret addr exactly | ||
| 184 | pub const MAP_FIXED = 0x0010; | ||
| 185 | |||
| 186 | /// region may contain semaphores | ||
| 187 | pub const MAP_HASSEMAPHORE = 0x0200; | ||
| 188 | |||
| 189 | /// changes are private | ||
| 190 | pub const MAP_PRIVATE = 0x0002; | ||
| 191 | |||
| 192 | /// share changes | ||
| 193 | pub const MAP_SHARED = 0x0001; | ||
| 194 | |||
| 195 | /// don't cache pages for this mapping | ||
| 196 | pub const MAP_NOCACHE = 0x0400; | ||
| 197 | |||
| 198 | /// don't reserve needed swap area | ||
| 199 | pub const MAP_NORESERVE = 0x0040; | ||
| 200 | pub const MAP_FAILED = @intToPtr(*c_void, maxInt(usize)); | ||
| 201 | |||
| 202 | /// [XSI] no hang in wait/no child to reap | ||
| 203 | pub const WNOHANG = 0x00000001; | ||
| 204 | |||
| 205 | /// [XSI] notify on stop, untraced child | ||
| 206 | pub const WUNTRACED = 0x00000002; | ||
| 207 | |||
| 208 | /// take signal on signal stack | ||
| 209 | pub const SA_ONSTACK = 0x0001; | ||
| 210 | |||
| 211 | /// restart system on signal return | ||
| 212 | pub const SA_RESTART = 0x0002; | ||
| 213 | |||
| 214 | /// reset to SIG_DFL when taking signal | ||
| 215 | pub const SA_RESETHAND = 0x0004; | ||
| 216 | |||
| 217 | /// do not generate SIGCHLD on child stop | ||
| 218 | pub const SA_NOCLDSTOP = 0x0008; | ||
| 219 | |||
| 220 | /// don't mask the signal we're delivering | ||
| 221 | pub const SA_NODEFER = 0x0010; | ||
| 222 | |||
| 223 | /// don't keep zombies around | ||
| 224 | pub const SA_NOCLDWAIT = 0x0020; | ||
| 225 | |||
| 226 | /// signal handler with SA_SIGINFO args | ||
| 227 | pub const SA_SIGINFO = 0x0040; | ||
| 228 | |||
| 229 | /// do not bounce off kernel's sigtramp | ||
| 230 | pub const SA_USERTRAMP = 0x0100; | ||
| 231 | |||
| 232 | /// signal handler with SA_SIGINFO args with 64bit regs information | ||
| 233 | pub const SA_64REGSET = 0x0200; | ||
| 234 | |||
| 235 | pub const O_LARGEFILE = 0x0000; | ||
| 236 | pub const O_PATH = 0x0000; | ||
| 237 | |||
| 238 | pub const F_OK = 0; | ||
| 239 | pub const X_OK = 1; | ||
| 240 | pub const W_OK = 2; | ||
| 241 | pub const R_OK = 4; | ||
| 242 | |||
| 243 | /// open for reading only | ||
| 244 | pub const O_RDONLY = 0x0000; | ||
| 245 | |||
| 246 | /// open for writing only | ||
| 247 | pub const O_WRONLY = 0x0001; | ||
| 248 | |||
| 249 | /// open for reading and writing | ||
| 250 | pub const O_RDWR = 0x0002; | ||
| 251 | |||
| 252 | /// do not block on open or for data to become available | ||
| 253 | pub const O_NONBLOCK = 0x0004; | ||
| 254 | |||
| 255 | /// append on each write | ||
| 256 | pub const O_APPEND = 0x0008; | ||
| 257 | |||
| 258 | /// create file if it does not exist | ||
| 259 | pub const O_CREAT = 0x0200; | ||
| 260 | |||
| 261 | /// truncate size to 0 | ||
| 262 | pub const O_TRUNC = 0x0400; | ||
| 263 | |||
| 264 | /// error if O_CREAT and the file exists | ||
| 265 | pub const O_EXCL = 0x0800; | ||
| 266 | |||
| 267 | /// atomically obtain a shared lock | ||
| 268 | pub const O_SHLOCK = 0x0010; | ||
| 269 | |||
| 270 | /// atomically obtain an exclusive lock | ||
| 271 | pub const O_EXLOCK = 0x0020; | ||
| 272 | |||
| 273 | /// do not follow symlinks | ||
| 274 | pub const O_NOFOLLOW = 0x0100; | ||
| 275 | |||
| 276 | /// allow open of symlinks | ||
| 277 | pub const O_SYMLINK = 0x200000; | ||
| 278 | |||
| 279 | /// descriptor requested for event notifications only | ||
| 280 | pub const O_EVTONLY = 0x8000; | ||
| 281 | |||
| 282 | /// mark as close-on-exec | ||
| 283 | pub const O_CLOEXEC = 0x1000000; | ||
| 284 | |||
| 285 | pub const O_ACCMODE = 3; | ||
| 286 | pub const O_ALERT = 536870912; | ||
| 287 | pub const O_ASYNC = 64; | ||
| 288 | pub const O_DIRECTORY = 1048576; | ||
| 289 | pub const O_DP_GETRAWENCRYPTED = 1; | ||
| 290 | pub const O_DP_GETRAWUNENCRYPTED = 2; | ||
| 291 | pub const O_DSYNC = 4194304; | ||
| 292 | pub const O_FSYNC = O_SYNC; | ||
| 293 | pub const O_NOCTTY = 131072; | ||
| 294 | pub const O_POPUP = 2147483648; | ||
| 295 | pub const O_SYNC = 128; | ||
| 296 | |||
| 297 | pub const SEEK_SET = 0x0; | ||
| 298 | pub const SEEK_CUR = 0x1; | ||
| 299 | pub const SEEK_END = 0x2; | ||
| 300 | |||
| 301 | pub const DT_UNKNOWN = 0; | ||
| 302 | pub const DT_FIFO = 1; | ||
| 303 | pub const DT_CHR = 2; | ||
| 304 | pub const DT_DIR = 4; | ||
| 305 | pub const DT_BLK = 6; | ||
| 306 | pub const DT_REG = 8; | ||
| 307 | pub const DT_LNK = 10; | ||
| 308 | pub const DT_SOCK = 12; | ||
| 309 | pub const DT_WHT = 14; | ||
| 310 | |||
| 311 | /// block specified signal set | ||
| 312 | pub const SIG_BLOCK = 1; | ||
| 313 | |||
| 314 | /// unblock specified signal set | ||
| 315 | pub const SIG_UNBLOCK = 2; | ||
| 316 | |||
| 317 | /// set specified signal set | ||
| 318 | pub const SIG_SETMASK = 3; | ||
| 319 | |||
| 320 | /// hangup | ||
| 321 | pub const SIGHUP = 1; | ||
| 322 | |||
| 323 | /// interrupt | ||
| 324 | pub const SIGINT = 2; | ||
| 325 | |||
| 326 | /// quit | ||
| 327 | pub const SIGQUIT = 3; | ||
| 328 | |||
| 329 | /// illegal instruction (not reset when caught) | ||
| 330 | pub const SIGILL = 4; | ||
| 331 | |||
| 332 | /// trace trap (not reset when caught) | ||
| 333 | pub const SIGTRAP = 5; | ||
| 334 | |||
| 335 | /// abort() | ||
| 336 | pub const SIGABRT = 6; | ||
| 337 | |||
| 338 | /// pollable event ([XSR] generated, not supported) | ||
| 339 | pub const SIGPOLL = 7; | ||
| 340 | |||
| 341 | /// compatibility | ||
| 342 | pub const SIGIOT = SIGABRT; | ||
| 343 | |||
| 344 | /// EMT instruction | ||
| 345 | pub const SIGEMT = 7; | ||
| 346 | |||
| 347 | /// floating point exception | ||
| 348 | pub const SIGFPE = 8; | ||
| 349 | |||
| 350 | /// kill (cannot be caught or ignored) | ||
| 351 | pub const SIGKILL = 9; | ||
| 352 | |||
| 353 | /// bus error | ||
| 354 | pub const SIGBUS = 10; | ||
| 355 | |||
| 356 | /// segmentation violation | ||
| 357 | pub const SIGSEGV = 11; | ||
| 358 | |||
| 359 | /// bad argument to system call | ||
| 360 | pub const SIGSYS = 12; | ||
| 361 | |||
| 362 | /// write on a pipe with no one to read it | ||
| 363 | pub const SIGPIPE = 13; | ||
| 364 | |||
| 365 | /// alarm clock | ||
| 366 | pub const SIGALRM = 14; | ||
| 367 | |||
| 368 | /// software termination signal from kill | ||
| 369 | pub const SIGTERM = 15; | ||
| 370 | |||
| 371 | /// urgent condition on IO channel | ||
| 372 | pub const SIGURG = 16; | ||
| 373 | |||
| 374 | /// sendable stop signal not from tty | ||
| 375 | pub const SIGSTOP = 17; | ||
| 376 | |||
| 377 | /// stop signal from tty | ||
| 378 | pub const SIGTSTP = 18; | ||
| 379 | |||
| 380 | /// continue a stopped process | ||
| 381 | pub const SIGCONT = 19; | ||
| 382 | |||
| 383 | /// to parent on child stop or exit | ||
| 384 | pub const SIGCHLD = 20; | ||
| 385 | |||
| 386 | /// to readers pgrp upon background tty read | ||
| 387 | pub const SIGTTIN = 21; | ||
| 388 | |||
| 389 | /// like TTIN for output if (tp->t_local&LTOSTOP) | ||
| 390 | pub const SIGTTOU = 22; | ||
| 391 | |||
| 392 | /// input/output possible signal | ||
| 393 | pub const SIGIO = 23; | ||
| 394 | |||
| 395 | /// exceeded CPU time limit | ||
| 396 | pub const SIGXCPU = 24; | ||
| 397 | |||
| 398 | /// exceeded file size limit | ||
| 399 | pub const SIGXFSZ = 25; | ||
| 400 | |||
| 401 | /// virtual time alarm | ||
| 402 | pub const SIGVTALRM = 26; | ||
| 403 | |||
| 404 | /// profiling time alarm | ||
| 405 | pub const SIGPROF = 27; | ||
| 406 | |||
| 407 | /// window size changes | ||
| 408 | pub const SIGWINCH = 28; | ||
| 409 | |||
| 410 | /// information request | ||
| 411 | pub const SIGINFO = 29; | ||
| 412 | |||
| 413 | /// user defined signal 1 | ||
| 414 | pub const SIGUSR1 = 30; | ||
| 415 | |||
| 416 | /// user defined signal 2 | ||
| 417 | pub const SIGUSR2 = 31; | ||
| 418 | |||
| 419 | /// no flag value | ||
| 420 | pub const KEVENT_FLAG_NONE = 0x000; | ||
| 421 | |||
| 422 | /// immediate timeout | ||
| 423 | pub const KEVENT_FLAG_IMMEDIATE = 0x001; | ||
| 424 | |||
| 425 | /// output events only include change | ||
| 426 | pub const KEVENT_FLAG_ERROR_EVENTS = 0x002; | ||
| 427 | |||
| 428 | /// add event to kq (implies enable) | ||
| 429 | pub const EV_ADD = 0x0001; | ||
| 430 | |||
| 431 | /// delete event from kq | ||
| 432 | pub const EV_DELETE = 0x0002; | ||
| 433 | |||
| 434 | /// enable event | ||
| 435 | pub const EV_ENABLE = 0x0004; | ||
| 436 | |||
| 437 | /// disable event (not reported) | ||
| 438 | pub const EV_DISABLE = 0x0008; | ||
| 439 | |||
| 440 | /// only report one occurrence | ||
| 441 | pub const EV_ONESHOT = 0x0010; | ||
| 442 | |||
| 443 | /// clear event state after reporting | ||
| 444 | pub 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 | ||
| 450 | pub const EV_RECEIPT = 0x0040; | ||
| 451 | |||
| 452 | /// disable event after reporting | ||
| 453 | pub const EV_DISPATCH = 0x0080; | ||
| 454 | |||
| 455 | /// unique kevent per udata value | ||
| 456 | pub 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 | ||
| 462 | pub const EV_DISPATCH2 = EV_DISPATCH | EV_UDATA_SPECIFIC; | ||
| 463 | |||
| 464 | /// report that source has vanished | ||
| 465 | /// ... only valid with EV_DISPATCH2 | ||
| 466 | pub const EV_VANISHED = 0x0200; | ||
| 467 | |||
| 468 | /// reserved by system | ||
| 469 | pub const EV_SYSFLAGS = 0xF000; | ||
| 470 | |||
| 471 | /// filter-specific flag | ||
| 472 | pub const EV_FLAG0 = 0x1000; | ||
| 473 | |||
| 474 | /// filter-specific flag | ||
| 475 | pub const EV_FLAG1 = 0x2000; | ||
| 476 | |||
| 477 | /// EOF detected | ||
| 478 | pub const EV_EOF = 0x8000; | ||
| 479 | |||
| 480 | /// error, data contains errno | ||
| 481 | pub const EV_ERROR = 0x4000; | ||
| 482 | |||
| 483 | pub const EV_POLL = EV_FLAG0; | ||
| 484 | pub const EV_OOBAND = EV_FLAG1; | ||
| 485 | |||
| 486 | pub const EVFILT_READ = -1; | ||
| 487 | pub const EVFILT_WRITE = -2; | ||
| 488 | |||
| 489 | /// attached to aio requests | ||
| 490 | pub const EVFILT_AIO = -3; | ||
| 491 | |||
| 492 | /// attached to vnodes | ||
| 493 | pub const EVFILT_VNODE = -4; | ||
| 494 | |||
| 495 | /// attached to struct proc | ||
| 496 | pub const EVFILT_PROC = -5; | ||
| 497 | |||
| 498 | /// attached to struct proc | ||
| 499 | pub const EVFILT_SIGNAL = -6; | ||
| 500 | |||
| 501 | /// timers | ||
| 502 | pub const EVFILT_TIMER = -7; | ||
| 503 | |||
| 504 | /// Mach portsets | ||
| 505 | pub const EVFILT_MACHPORT = -8; | ||
| 506 | |||
| 507 | /// Filesystem events | ||
| 508 | pub const EVFILT_FS = -9; | ||
| 509 | |||
| 510 | /// User events | ||
| 511 | pub const EVFILT_USER = -10; | ||
| 512 | |||
| 513 | /// Virtual memory events | ||
| 514 | pub const EVFILT_VM = -12; | ||
| 515 | |||
| 516 | /// Exception events | ||
| 517 | pub const EVFILT_EXCEPT = -15; | ||
| 518 | |||
| 519 | pub const EVFILT_SYSCOUNT = 17; | ||
| 520 | |||
| 521 | /// On input, NOTE_TRIGGER causes the event to be triggered for output. | ||
| 522 | pub const NOTE_TRIGGER = 0x01000000; | ||
| 523 | |||
| 524 | /// ignore input fflags | ||
| 525 | pub const NOTE_FFNOP = 0x00000000; | ||
| 526 | |||
| 527 | /// and fflags | ||
| 528 | pub const NOTE_FFAND = 0x40000000; | ||
| 529 | |||
| 530 | /// or fflags | ||
| 531 | pub const NOTE_FFOR = 0x80000000; | ||
| 532 | |||
| 533 | /// copy fflags | ||
| 534 | pub const NOTE_FFCOPY = 0xc0000000; | ||
| 535 | |||
| 536 | /// mask for operations | ||
| 537 | pub const NOTE_FFCTRLMASK = 0xc0000000; | ||
| 538 | pub const NOTE_FFLAGSMASK = 0x00ffffff; | ||
| 539 | |||
| 540 | /// low water mark | ||
| 541 | pub const NOTE_LOWAT = 0x00000001; | ||
| 542 | |||
| 543 | /// OOB data | ||
| 544 | pub const NOTE_OOB = 0x00000002; | ||
| 545 | |||
| 546 | /// vnode was removed | ||
| 547 | pub const NOTE_DELETE = 0x00000001; | ||
| 548 | |||
| 549 | /// data contents changed | ||
| 550 | pub const NOTE_WRITE = 0x00000002; | ||
| 551 | |||
| 552 | /// size increased | ||
| 553 | pub const NOTE_EXTEND = 0x00000004; | ||
| 554 | |||
| 555 | /// attributes changed | ||
| 556 | pub const NOTE_ATTRIB = 0x00000008; | ||
| 557 | |||
| 558 | /// link count changed | ||
| 559 | pub const NOTE_LINK = 0x00000010; | ||
| 560 | |||
| 561 | /// vnode was renamed | ||
| 562 | pub const NOTE_RENAME = 0x00000020; | ||
| 563 | |||
| 564 | /// vnode access was revoked | ||
| 565 | pub const NOTE_REVOKE = 0x00000040; | ||
| 566 | |||
| 567 | /// No specific vnode event: to test for EVFILT_READ activation | ||
| 568 | pub const NOTE_NONE = 0x00000080; | ||
| 569 | |||
| 570 | /// vnode was unlocked by flock(2) | ||
| 571 | pub const NOTE_FUNLOCK = 0x00000100; | ||
| 572 | |||
| 573 | /// process exited | ||
| 574 | pub const NOTE_EXIT = 0x80000000; | ||
| 575 | |||
| 576 | /// process forked | ||
| 577 | pub const NOTE_FORK = 0x40000000; | ||
| 578 | |||
| 579 | /// process exec'd | ||
| 580 | pub const NOTE_EXEC = 0x20000000; | ||
| 581 | |||
| 582 | /// shared with EVFILT_SIGNAL | ||
| 583 | pub const NOTE_SIGNAL = 0x08000000; | ||
| 584 | |||
| 585 | /// exit status to be returned, valid for child process only | ||
| 586 | pub const NOTE_EXITSTATUS = 0x04000000; | ||
| 587 | |||
| 588 | /// provide details on reasons for exit | ||
| 589 | pub const NOTE_EXIT_DETAIL = 0x02000000; | ||
| 590 | |||
| 591 | /// mask for signal & exit status | ||
| 592 | pub const NOTE_PDATAMASK = 0x000fffff; | ||
| 593 | pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK); | ||
| 594 | |||
| 595 | pub const NOTE_EXIT_DETAIL_MASK = 0x00070000; | ||
| 596 | pub const NOTE_EXIT_DECRYPTFAIL = 0x00010000; | ||
| 597 | pub const NOTE_EXIT_MEMORY = 0x00020000; | ||
| 598 | pub const NOTE_EXIT_CSERROR = 0x00040000; | ||
| 599 | |||
| 600 | /// will react on memory pressure | ||
| 601 | pub const NOTE_VM_PRESSURE = 0x80000000; | ||
| 602 | |||
| 603 | /// will quit on memory pressure, possibly after cleaning up dirty state | ||
| 604 | pub const NOTE_VM_PRESSURE_TERMINATE = 0x40000000; | ||
| 605 | |||
| 606 | /// will quit immediately on memory pressure | ||
| 607 | pub const NOTE_VM_PRESSURE_SUDDEN_TERMINATE = 0x20000000; | ||
| 608 | |||
| 609 | /// there was an error | ||
| 610 | pub const NOTE_VM_ERROR = 0x10000000; | ||
| 611 | |||
| 612 | /// data is seconds | ||
| 613 | pub const NOTE_SECONDS = 0x00000001; | ||
| 614 | |||
| 615 | /// data is microseconds | ||
| 616 | pub const NOTE_USECONDS = 0x00000002; | ||
| 617 | |||
| 618 | /// data is nanoseconds | ||
| 619 | pub const NOTE_NSECONDS = 0x00000004; | ||
| 620 | |||
| 621 | /// absolute timeout | ||
| 622 | pub const NOTE_ABSOLUTE = 0x00000008; | ||
| 623 | |||
| 624 | /// ext[1] holds leeway for power aware timers | ||
| 625 | pub const NOTE_LEEWAY = 0x00000010; | ||
| 626 | |||
| 627 | /// system does minimal timer coalescing | ||
| 628 | pub const NOTE_CRITICAL = 0x00000020; | ||
| 629 | |||
| 630 | /// system does maximum timer coalescing | ||
| 631 | pub const NOTE_BACKGROUND = 0x00000040; | ||
| 632 | pub const NOTE_MACH_CONTINUOUS_TIME = 0x00000080; | ||
| 633 | |||
| 634 | /// data is mach absolute time units | ||
| 635 | pub const NOTE_MACHTIME = 0x00000100; | ||
| 636 | |||
| 637 | pub const AF_UNSPEC = 0; | ||
| 638 | pub const AF_LOCAL = 1; | ||
| 639 | pub const AF_UNIX = AF_LOCAL; | ||
| 640 | pub const AF_INET = 2; | ||
| 641 | pub const AF_SYS_CONTROL = 2; | ||
| 642 | pub const AF_IMPLINK = 3; | ||
| 643 | pub const AF_PUP = 4; | ||
| 644 | pub const AF_CHAOS = 5; | ||
| 645 | pub const AF_NS = 6; | ||
| 646 | pub const AF_ISO = 7; | ||
| 647 | pub const AF_OSI = AF_ISO; | ||
| 648 | pub const AF_ECMA = 8; | ||
| 649 | pub const AF_DATAKIT = 9; | ||
| 650 | pub const AF_CCITT = 10; | ||
| 651 | pub const AF_SNA = 11; | ||
| 652 | pub const AF_DECnet = 12; | ||
| 653 | pub const AF_DLI = 13; | ||
| 654 | pub const AF_LAT = 14; | ||
| 655 | pub const AF_HYLINK = 15; | ||
| 656 | pub const AF_APPLETALK = 16; | ||
| 657 | pub const AF_ROUTE = 17; | ||
| 658 | pub const AF_LINK = 18; | ||
| 659 | pub const AF_XTP = 19; | ||
| 660 | pub const AF_COIP = 20; | ||
| 661 | pub const AF_CNT = 21; | ||
| 662 | pub const AF_RTIP = 22; | ||
| 663 | pub const AF_IPX = 23; | ||
| 664 | pub const AF_SIP = 24; | ||
| 665 | pub const AF_PIP = 25; | ||
| 666 | pub const AF_ISDN = 28; | ||
| 667 | pub const AF_E164 = AF_ISDN; | ||
| 668 | pub const AF_KEY = 29; | ||
| 669 | pub const AF_INET6 = 30; | ||
| 670 | pub const AF_NATM = 31; | ||
| 671 | pub const AF_SYSTEM = 32; | ||
| 672 | pub const AF_NETBIOS = 33; | ||
| 673 | pub const AF_PPP = 34; | ||
| 674 | pub const AF_MAX = 40; | ||
| 675 | |||
| 676 | pub const PF_UNSPEC = AF_UNSPEC; | ||
| 677 | pub const PF_LOCAL = AF_LOCAL; | ||
| 678 | pub const PF_UNIX = PF_LOCAL; | ||
| 679 | pub const PF_INET = AF_INET; | ||
| 680 | pub const PF_IMPLINK = AF_IMPLINK; | ||
| 681 | pub const PF_PUP = AF_PUP; | ||
| 682 | pub const PF_CHAOS = AF_CHAOS; | ||
| 683 | pub const PF_NS = AF_NS; | ||
| 684 | pub const PF_ISO = AF_ISO; | ||
| 685 | pub const PF_OSI = AF_ISO; | ||
| 686 | pub const PF_ECMA = AF_ECMA; | ||
| 687 | pub const PF_DATAKIT = AF_DATAKIT; | ||
| 688 | pub const PF_CCITT = AF_CCITT; | ||
| 689 | pub const PF_SNA = AF_SNA; | ||
| 690 | pub const PF_DECnet = AF_DECnet; | ||
| 691 | pub const PF_DLI = AF_DLI; | ||
| 692 | pub const PF_LAT = AF_LAT; | ||
| 693 | pub const PF_HYLINK = AF_HYLINK; | ||
| 694 | pub const PF_APPLETALK = AF_APPLETALK; | ||
| 695 | pub const PF_ROUTE = AF_ROUTE; | ||
| 696 | pub const PF_LINK = AF_LINK; | ||
| 697 | pub const PF_XTP = AF_XTP; | ||
| 698 | pub const PF_COIP = AF_COIP; | ||
| 699 | pub const PF_CNT = AF_CNT; | ||
| 700 | pub const PF_SIP = AF_SIP; | ||
| 701 | pub const PF_IPX = AF_IPX; | ||
| 702 | pub const PF_RTIP = AF_RTIP; | ||
| 703 | pub const PF_PIP = AF_PIP; | ||
| 704 | pub const PF_ISDN = AF_ISDN; | ||
| 705 | pub const PF_KEY = AF_KEY; | ||
| 706 | pub const PF_INET6 = AF_INET6; | ||
| 707 | pub const PF_NATM = AF_NATM; | ||
| 708 | pub const PF_SYSTEM = AF_SYSTEM; | ||
| 709 | pub const PF_NETBIOS = AF_NETBIOS; | ||
| 710 | pub const PF_PPP = AF_PPP; | ||
| 711 | pub const PF_MAX = AF_MAX; | ||
| 712 | |||
| 713 | pub const SYSPROTO_EVENT = 1; | ||
| 714 | pub const SYSPROTO_CONTROL = 2; | ||
| 715 | |||
| 716 | pub const SOCK_STREAM = 1; | ||
| 717 | pub const SOCK_DGRAM = 2; | ||
| 718 | pub const SOCK_RAW = 3; | ||
| 719 | pub const SOCK_RDM = 4; | ||
| 720 | pub const SOCK_SEQPACKET = 5; | ||
| 721 | pub const SOCK_MAXADDRLEN = 255; | ||
| 722 | |||
| 723 | pub const IPPROTO_ICMP = 1; | ||
| 724 | pub const IPPROTO_ICMPV6 = 58; | ||
| 725 | pub const IPPROTO_TCP = 6; | ||
| 726 | pub const IPPROTO_UDP = 17; | ||
| 727 | pub const IPPROTO_IP = 0; | ||
| 728 | pub const IPPROTO_IPV6 = 41; | ||
| 729 | |||
| 730 | fn wstatus(x: u32) u32 { | ||
| 731 | return x & 0o177; | ||
| 732 | } | ||
| 733 | const wstopped = 0o177; | ||
| 734 | pub fn WEXITSTATUS(x: u32) u32 { | ||
| 735 | return x >> 8; | ||
| 736 | } | ||
| 737 | pub fn WTERMSIG(x: u32) u32 { | ||
| 738 | return wstatus(x); | ||
| 739 | } | ||
| 740 | pub fn WSTOPSIG(x: u32) u32 { | ||
| 741 | return x >> 8; | ||
| 742 | } | ||
| 743 | pub fn WIFEXITED(x: u32) bool { | ||
| 744 | return wstatus(x) == 0; | ||
| 745 | } | ||
| 746 | pub fn WIFSTOPPED(x: u32) bool { | ||
| 747 | return wstatus(x) == wstopped and WSTOPSIG(x) != 0x13; | ||
| 748 | } | ||
| 749 | pub fn WIFSIGNALED(x: u32) bool { | ||
| 750 | return wstatus(x) != wstopped and wstatus(x) != 0; | ||
| 751 | } | ||
| 752 | |||
| 753 | /// Operation not permitted | ||
| 754 | pub const EPERM = 1; | ||
| 755 | |||
| 756 | /// No such file or directory | ||
| 757 | pub const ENOENT = 2; | ||
| 758 | |||
| 759 | /// No such process | ||
| 760 | pub const ESRCH = 3; | ||
| 761 | |||
| 762 | /// Interrupted system call | ||
| 763 | pub const EINTR = 4; | ||
| 764 | |||
| 765 | /// Input/output error | ||
| 766 | pub const EIO = 5; | ||
| 767 | |||
| 768 | /// Device not configured | ||
| 769 | pub const ENXIO = 6; | ||
| 770 | |||
| 771 | /// Argument list too long | ||
| 772 | pub const E2BIG = 7; | ||
| 773 | |||
| 774 | /// Exec format error | ||
| 775 | pub const ENOEXEC = 8; | ||
| 776 | |||
| 777 | /// Bad file descriptor | ||
| 778 | pub const EBADF = 9; | ||
| 779 | |||
| 780 | /// No child processes | ||
| 781 | pub const ECHILD = 10; | ||
| 782 | |||
| 783 | /// Resource deadlock avoided | ||
| 784 | pub const EDEADLK = 11; | ||
| 785 | |||
| 786 | /// Cannot allocate memory | ||
| 787 | pub const ENOMEM = 12; | ||
| 788 | |||
| 789 | /// Permission denied | ||
| 790 | pub const EACCES = 13; | ||
| 791 | |||
| 792 | /// Bad address | ||
| 793 | pub const EFAULT = 14; | ||
| 794 | |||
| 795 | /// Block device required | ||
| 796 | pub const ENOTBLK = 15; | ||
| 797 | |||
| 798 | /// Device / Resource busy | ||
| 799 | pub const EBUSY = 16; | ||
| 800 | |||
| 801 | /// File exists | ||
| 802 | pub const EEXIST = 17; | ||
| 803 | |||
| 804 | /// Cross-device link | ||
| 805 | pub const EXDEV = 18; | ||
| 806 | |||
| 807 | /// Operation not supported by device | ||
| 808 | pub const ENODEV = 19; | ||
| 809 | |||
| 810 | /// Not a directory | ||
| 811 | pub const ENOTDIR = 20; | ||
| 812 | |||
| 813 | /// Is a directory | ||
| 814 | pub const EISDIR = 21; | ||
| 815 | |||
| 816 | /// Invalid argument | ||
| 817 | pub const EINVAL = 22; | ||
| 818 | |||
| 819 | /// Too many open files in system | ||
| 820 | pub const ENFILE = 23; | ||
| 821 | |||
| 822 | /// Too many open files | ||
| 823 | pub const EMFILE = 24; | ||
| 824 | |||
| 825 | /// Inappropriate ioctl for device | ||
| 826 | pub const ENOTTY = 25; | ||
| 827 | |||
| 828 | /// Text file busy | ||
| 829 | pub const ETXTBSY = 26; | ||
| 830 | |||
| 831 | /// File too large | ||
| 832 | pub const EFBIG = 27; | ||
| 833 | |||
| 834 | /// No space left on device | ||
| 835 | pub const ENOSPC = 28; | ||
| 836 | |||
| 837 | /// Illegal seek | ||
| 838 | pub const ESPIPE = 29; | ||
| 839 | |||
| 840 | /// Read-only file system | ||
| 841 | pub const EROFS = 30; | ||
| 842 | |||
| 843 | /// Too many links | ||
| 844 | pub const EMLINK = 31; | ||
| 845 | /// Broken pipe | ||
| 846 | |||
| 847 | // math software | ||
| 848 | pub const EPIPE = 32; | ||
| 849 | |||
| 850 | /// Numerical argument out of domain | ||
| 851 | pub const EDOM = 33; | ||
| 852 | /// Result too large | ||
| 853 | |||
| 854 | // non-blocking and interrupt i/o | ||
| 855 | pub const ERANGE = 34; | ||
| 856 | |||
| 857 | /// Resource temporarily unavailable | ||
| 858 | pub const EAGAIN = 35; | ||
| 859 | |||
| 860 | /// Operation would block | ||
| 861 | pub const EWOULDBLOCK = EAGAIN; | ||
| 862 | |||
| 863 | /// Operation now in progress | ||
| 864 | pub const EINPROGRESS = 36; | ||
| 865 | /// Operation already in progress | ||
| 866 | |||
| 867 | // ipc/network software -- argument errors | ||
| 868 | pub const EALREADY = 37; | ||
| 869 | |||
| 870 | /// Socket operation on non-socket | ||
| 871 | pub const ENOTSOCK = 38; | ||
| 872 | |||
| 873 | /// Destination address required | ||
| 874 | pub const EDESTADDRREQ = 39; | ||
| 875 | |||
| 876 | /// Message too long | ||
| 877 | pub const EMSGSIZE = 40; | ||
| 878 | |||
| 879 | /// Protocol wrong type for socket | ||
| 880 | pub const EPROTOTYPE = 41; | ||
| 881 | |||
| 882 | /// Protocol not available | ||
| 883 | pub const ENOPROTOOPT = 42; | ||
| 884 | |||
| 885 | /// Protocol not supported | ||
| 886 | pub const EPROTONOSUPPORT = 43; | ||
| 887 | |||
| 888 | /// Socket type not supported | ||
| 889 | pub const ESOCKTNOSUPPORT = 44; | ||
| 890 | |||
| 891 | /// Operation not supported | ||
| 892 | pub const ENOTSUP = 45; | ||
| 893 | |||
| 894 | /// Protocol family not supported | ||
| 895 | pub const EPFNOSUPPORT = 46; | ||
| 896 | |||
| 897 | /// Address family not supported by protocol family | ||
| 898 | pub const EAFNOSUPPORT = 47; | ||
| 899 | |||
| 900 | /// Address already in use | ||
| 901 | pub const EADDRINUSE = 48; | ||
| 902 | /// Can't assign requested address | ||
| 903 | |||
| 904 | // ipc/network software -- operational errors | ||
| 905 | pub const EADDRNOTAVAIL = 49; | ||
| 906 | |||
| 907 | /// Network is down | ||
| 908 | pub const ENETDOWN = 50; | ||
| 909 | |||
| 910 | /// Network is unreachable | ||
| 911 | pub const ENETUNREACH = 51; | ||
| 912 | |||
| 913 | /// Network dropped connection on reset | ||
| 914 | pub const ENETRESET = 52; | ||
| 915 | |||
| 916 | /// Software caused connection abort | ||
| 917 | pub const ECONNABORTED = 53; | ||
| 918 | |||
| 919 | /// Connection reset by peer | ||
| 920 | pub const ECONNRESET = 54; | ||
| 921 | |||
| 922 | /// No buffer space available | ||
| 923 | pub const ENOBUFS = 55; | ||
| 924 | |||
| 925 | /// Socket is already connected | ||
| 926 | pub const EISCONN = 56; | ||
| 927 | |||
| 928 | /// Socket is not connected | ||
| 929 | pub const ENOTCONN = 57; | ||
| 930 | |||
| 931 | /// Can't send after socket shutdown | ||
| 932 | pub const ESHUTDOWN = 58; | ||
| 933 | |||
| 934 | /// Too many references: can't splice | ||
| 935 | pub const ETOOMANYREFS = 59; | ||
| 936 | |||
| 937 | /// Operation timed out | ||
| 938 | pub const ETIMEDOUT = 60; | ||
| 939 | |||
| 940 | /// Connection refused | ||
| 941 | pub const ECONNREFUSED = 61; | ||
| 942 | |||
| 943 | /// Too many levels of symbolic links | ||
| 944 | pub const ELOOP = 62; | ||
| 945 | |||
| 946 | /// File name too long | ||
| 947 | pub const ENAMETOOLONG = 63; | ||
| 948 | |||
| 949 | /// Host is down | ||
| 950 | pub const EHOSTDOWN = 64; | ||
| 951 | |||
| 952 | /// No route to host | ||
| 953 | pub const EHOSTUNREACH = 65; | ||
| 954 | /// Directory not empty | ||
| 955 | |||
| 956 | // quotas & mush | ||
| 957 | pub const ENOTEMPTY = 66; | ||
| 958 | |||
| 959 | /// Too many processes | ||
| 960 | pub const EPROCLIM = 67; | ||
| 961 | |||
| 962 | /// Too many users | ||
| 963 | pub const EUSERS = 68; | ||
| 964 | /// Disc quota exceeded | ||
| 965 | |||
| 966 | // Network File System | ||
| 967 | pub const EDQUOT = 69; | ||
| 968 | |||
| 969 | /// Stale NFS file handle | ||
| 970 | pub const ESTALE = 70; | ||
| 971 | |||
| 972 | /// Too many levels of remote in path | ||
| 973 | pub const EREMOTE = 71; | ||
| 974 | |||
| 975 | /// RPC struct is bad | ||
| 976 | pub const EBADRPC = 72; | ||
| 977 | |||
| 978 | /// RPC version wrong | ||
| 979 | pub const ERPCMISMATCH = 73; | ||
| 980 | |||
| 981 | /// RPC prog. not avail | ||
| 982 | pub const EPROGUNAVAIL = 74; | ||
| 983 | |||
| 984 | /// Program version wrong | ||
| 985 | pub const EPROGMISMATCH = 75; | ||
| 986 | |||
| 987 | /// Bad procedure for program | ||
| 988 | pub const EPROCUNAVAIL = 76; | ||
| 989 | |||
| 990 | /// No locks available | ||
| 991 | pub const ENOLCK = 77; | ||
| 992 | |||
| 993 | /// Function not implemented | ||
| 994 | pub const ENOSYS = 78; | ||
| 995 | |||
| 996 | /// Inappropriate file type or format | ||
| 997 | pub const EFTYPE = 79; | ||
| 998 | |||
| 999 | /// Authentication error | ||
| 1000 | pub const EAUTH = 80; | ||
| 1001 | /// Need authenticator | ||
| 1002 | |||
| 1003 | // Intelligent device errors | ||
| 1004 | pub const ENEEDAUTH = 81; | ||
| 1005 | |||
| 1006 | /// Device power is off | ||
| 1007 | pub const EPWROFF = 82; | ||
| 1008 | |||
| 1009 | /// Device error, e.g. paper out | ||
| 1010 | pub const EDEVERR = 83; | ||
| 1011 | /// Value too large to be stored in data type | ||
| 1012 | |||
| 1013 | // Program loading errors | ||
| 1014 | pub const EOVERFLOW = 84; | ||
| 1015 | |||
| 1016 | /// Bad executable | ||
| 1017 | pub const EBADEXEC = 85; | ||
| 1018 | |||
| 1019 | /// Bad CPU type in executable | ||
| 1020 | pub const EBADARCH = 86; | ||
| 1021 | |||
| 1022 | /// Shared library version mismatch | ||
| 1023 | pub const ESHLIBVERS = 87; | ||
| 1024 | |||
| 1025 | /// Malformed Macho file | ||
| 1026 | pub const EBADMACHO = 88; | ||
| 1027 | |||
| 1028 | /// Operation canceled | ||
| 1029 | pub const ECANCELED = 89; | ||
| 1030 | |||
| 1031 | /// Identifier removed | ||
| 1032 | pub const EIDRM = 90; | ||
| 1033 | |||
| 1034 | /// No message of desired type | ||
| 1035 | pub const ENOMSG = 91; | ||
| 1036 | |||
| 1037 | /// Illegal byte sequence | ||
| 1038 | pub const EILSEQ = 92; | ||
| 1039 | |||
| 1040 | /// Attribute not found | ||
| 1041 | pub const ENOATTR = 93; | ||
| 1042 | |||
| 1043 | /// Bad message | ||
| 1044 | pub const EBADMSG = 94; | ||
| 1045 | |||
| 1046 | /// Reserved | ||
| 1047 | pub const EMULTIHOP = 95; | ||
| 1048 | |||
| 1049 | /// No message available on STREAM | ||
| 1050 | pub const ENODATA = 96; | ||
| 1051 | |||
| 1052 | /// Reserved | ||
| 1053 | pub const ENOLINK = 97; | ||
| 1054 | |||
| 1055 | /// No STREAM resources | ||
| 1056 | pub const ENOSR = 98; | ||
| 1057 | |||
| 1058 | /// Not a STREAM | ||
| 1059 | pub const ENOSTR = 99; | ||
| 1060 | |||
| 1061 | /// Protocol error | ||
| 1062 | pub const EPROTO = 100; | ||
| 1063 | |||
| 1064 | /// STREAM ioctl timeout | ||
| 1065 | pub const ETIME = 101; | ||
| 1066 | |||
| 1067 | /// No such policy registered | ||
| 1068 | pub const ENOPOLICY = 103; | ||
| 1069 | |||
| 1070 | /// State not recoverable | ||
| 1071 | pub const ENOTRECOVERABLE = 104; | ||
| 1072 | |||
| 1073 | /// Previous owner died | ||
| 1074 | pub const EOWNERDEAD = 105; | ||
| 1075 | |||
| 1076 | /// Interface output queue is full | ||
| 1077 | pub const EQFULL = 106; | ||
| 1078 | |||
| 1079 | /// Must be equal largest errno | ||
| 1080 | pub const ELAST = 106; | ||
std/os/bits/freebsd.zig created+837| ... | @@ -0,0 +1,837 @@ | ||
| 1 | const std = @import("../../std.zig"); | ||
| 2 | const maxInt = std.math.maxInt; | ||
| 3 | |||
| 4 | pub const fd_t = c_int; | ||
| 5 | pub const pid_t = c_int; | ||
| 6 | |||
| 7 | /// Renamed from `kevent` to `Kevent` to avoid conflict with function name. | ||
| 8 | pub 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 | |||
| 18 | pub const pthread_attr_t = extern struct { | ||
| 19 | __size: [56]u8, | ||
| 20 | __align: c_long, | ||
| 21 | }; | ||
| 22 | |||
| 23 | pub 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 | |||
| 46 | pub 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 | |||
| 69 | pub 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 | |||
| 94 | pub const timespec = extern struct { | ||
| 95 | tv_sec: isize, | ||
| 96 | tv_nsec: isize, | ||
| 97 | }; | ||
| 98 | |||
| 99 | pub 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 | |||
| 110 | pub const in_port_t = u16; | ||
| 111 | pub const sa_family_t = u16; | ||
| 112 | |||
| 113 | pub const sockaddr = extern union { | ||
| 114 | in: sockaddr_in, | ||
| 115 | in6: sockaddr_in6, | ||
| 116 | }; | ||
| 117 | |||
| 118 | pub 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 | |||
| 126 | pub 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 | |||
| 135 | pub const CTL_KERN = 1; | ||
| 136 | pub const CTL_DEBUG = 5; | ||
| 137 | |||
| 138 | pub const KERN_PROC = 14; // struct: process entries | ||
| 139 | pub const KERN_PROC_PATHNAME = 12; // path to executable | ||
| 140 | |||
| 141 | pub const PATH_MAX = 1024; | ||
| 142 | |||
| 143 | pub const STDIN_FILENO = 0; | ||
| 144 | pub const STDOUT_FILENO = 1; | ||
| 145 | pub const STDERR_FILENO = 2; | ||
| 146 | |||
| 147 | pub const PROT_NONE = 0; | ||
| 148 | pub const PROT_READ = 1; | ||
| 149 | pub const PROT_WRITE = 2; | ||
| 150 | pub const PROT_EXEC = 4; | ||
| 151 | |||
| 152 | pub const CLOCK_REALTIME = 0; | ||
| 153 | pub const CLOCK_VIRTUAL = 1; | ||
| 154 | pub const CLOCK_PROF = 2; | ||
| 155 | pub const CLOCK_MONOTONIC = 4; | ||
| 156 | pub const CLOCK_UPTIME = 5; | ||
| 157 | pub const CLOCK_UPTIME_PRECISE = 7; | ||
| 158 | pub const CLOCK_UPTIME_FAST = 8; | ||
| 159 | pub const CLOCK_REALTIME_PRECISE = 9; | ||
| 160 | pub const CLOCK_REALTIME_FAST = 10; | ||
| 161 | pub const CLOCK_MONOTONIC_PRECISE = 11; | ||
| 162 | pub const CLOCK_MONOTONIC_FAST = 12; | ||
| 163 | pub const CLOCK_SECOND = 13; | ||
| 164 | pub const CLOCK_THREAD_CPUTIME_ID = 14; | ||
| 165 | pub const CLOCK_PROCESS_CPUTIME_ID = 15; | ||
| 166 | |||
| 167 | pub const MAP_FAILED = @intToPtr(*c_void, maxInt(usize)); | ||
| 168 | pub const MAP_SHARED = 0x0001; | ||
| 169 | pub const MAP_PRIVATE = 0x0002; | ||
| 170 | pub const MAP_FIXED = 0x0010; | ||
| 171 | pub const MAP_STACK = 0x0400; | ||
| 172 | pub const MAP_NOSYNC = 0x0800; | ||
| 173 | pub const MAP_ANON = 0x1000; | ||
| 174 | pub const MAP_ANONYMOUS = MAP_ANON; | ||
| 175 | pub const MAP_FILE = 0; | ||
| 176 | pub const MAP_NORESERVE = 0; | ||
| 177 | |||
| 178 | pub const MAP_GUARD = 0x00002000; | ||
| 179 | pub const MAP_EXCL = 0x00004000; | ||
| 180 | pub const MAP_NOCORE = 0x00020000; | ||
| 181 | pub const MAP_PREFAULT_READ = 0x00040000; | ||
| 182 | pub const MAP_32BIT = 0x00080000; | ||
| 183 | |||
| 184 | pub const WNOHANG = 1; | ||
| 185 | pub const WUNTRACED = 2; | ||
| 186 | pub const WSTOPPED = WUNTRACED; | ||
| 187 | pub const WCONTINUED = 4; | ||
| 188 | pub const WNOWAIT = 8; | ||
| 189 | pub const WEXITED = 16; | ||
| 190 | pub const WTRAPPED = 32; | ||
| 191 | |||
| 192 | pub const SA_ONSTACK = 0x0001; | ||
| 193 | pub const SA_RESTART = 0x0002; | ||
| 194 | pub const SA_RESETHAND = 0x0004; | ||
| 195 | pub const SA_NOCLDSTOP = 0x0008; | ||
| 196 | pub const SA_NODEFER = 0x0010; | ||
| 197 | pub const SA_NOCLDWAIT = 0x0020; | ||
| 198 | pub const SA_SIGINFO = 0x0040; | ||
| 199 | |||
| 200 | pub const SIGHUP = 1; | ||
| 201 | pub const SIGINT = 2; | ||
| 202 | pub const SIGQUIT = 3; | ||
| 203 | pub const SIGILL = 4; | ||
| 204 | pub const SIGTRAP = 5; | ||
| 205 | pub const SIGABRT = 6; | ||
| 206 | pub const SIGIOT = SIGABRT; | ||
| 207 | pub const SIGEMT = 7; | ||
| 208 | pub const SIGFPE = 8; | ||
| 209 | pub const SIGKILL = 9; | ||
| 210 | pub const SIGBUS = 10; | ||
| 211 | pub const SIGSEGV = 11; | ||
| 212 | pub const SIGSYS = 12; | ||
| 213 | pub const SIGPIPE = 13; | ||
| 214 | pub const SIGALRM = 14; | ||
| 215 | pub const SIGTERM = 15; | ||
| 216 | pub const SIGURG = 16; | ||
| 217 | pub const SIGSTOP = 17; | ||
| 218 | pub const SIGTSTP = 18; | ||
| 219 | pub const SIGCONT = 19; | ||
| 220 | pub const SIGCHLD = 20; | ||
| 221 | pub const SIGTTIN = 21; | ||
| 222 | pub const SIGTTOU = 22; | ||
| 223 | pub const SIGIO = 23; | ||
| 224 | pub const SIGXCPU = 24; | ||
| 225 | pub const SIGXFSZ = 25; | ||
| 226 | pub const SIGVTALRM = 26; | ||
| 227 | pub const SIGPROF = 27; | ||
| 228 | pub const SIGWINCH = 28; | ||
| 229 | pub const SIGINFO = 29; | ||
| 230 | pub const SIGUSR1 = 30; | ||
| 231 | pub const SIGUSR2 = 31; | ||
| 232 | pub const SIGTHR = 32; | ||
| 233 | pub const SIGLWP = SIGTHR; | ||
| 234 | pub const SIGLIBRT = 33; | ||
| 235 | |||
| 236 | pub const SIGRTMIN = 65; | ||
| 237 | pub const SIGRTMAX = 126; | ||
| 238 | |||
| 239 | // access function | ||
| 240 | pub const F_OK = 0; // test for existence of file | ||
| 241 | pub const X_OK = 1; // test for execute or search permission | ||
| 242 | pub const W_OK = 2; // test for write permission | ||
| 243 | pub const R_OK = 4; // test for read permission | ||
| 244 | |||
| 245 | pub const O_RDONLY = 0x0000; | ||
| 246 | pub const O_WRONLY = 0x0001; | ||
| 247 | pub const O_RDWR = 0x0002; | ||
| 248 | pub const O_ACCMODE = 0x0003; | ||
| 249 | |||
| 250 | pub const O_CREAT = 0x0200; | ||
| 251 | pub const O_EXCL = 0x0800; | ||
| 252 | pub const O_NOCTTY = 0x8000; | ||
| 253 | pub const O_TRUNC = 0x0400; | ||
| 254 | pub const O_APPEND = 0x0008; | ||
| 255 | pub const O_NONBLOCK = 0x0004; | ||
| 256 | pub const O_DSYNC = 0o10000; | ||
| 257 | pub const O_SYNC = 0x0080; | ||
| 258 | pub const O_RSYNC = 0o4010000; | ||
| 259 | pub const O_DIRECTORY = 0o200000; | ||
| 260 | pub const O_NOFOLLOW = 0x0100; | ||
| 261 | pub const O_CLOEXEC = 0x00100000; | ||
| 262 | |||
| 263 | pub const O_ASYNC = 0x0040; | ||
| 264 | pub const O_DIRECT = 0x00010000; | ||
| 265 | pub const O_LARGEFILE = 0; | ||
| 266 | pub const O_NOATIME = 0o1000000; | ||
| 267 | pub const O_PATH = 0o10000000; | ||
| 268 | pub const O_TMPFILE = 0o20200000; | ||
| 269 | pub const O_NDELAY = O_NONBLOCK; | ||
| 270 | |||
| 271 | pub const F_DUPFD = 0; | ||
| 272 | pub const F_GETFD = 1; | ||
| 273 | pub const F_SETFD = 2; | ||
| 274 | pub const F_GETFL = 3; | ||
| 275 | pub const F_SETFL = 4; | ||
| 276 | |||
| 277 | pub const F_SETOWN = 8; | ||
| 278 | pub const F_GETOWN = 9; | ||
| 279 | pub const F_SETSIG = 10; | ||
| 280 | pub const F_GETSIG = 11; | ||
| 281 | |||
| 282 | pub const F_GETLK = 5; | ||
| 283 | pub const F_SETLK = 6; | ||
| 284 | pub const F_SETLKW = 7; | ||
| 285 | |||
| 286 | pub const F_SETOWN_EX = 15; | ||
| 287 | pub const F_GETOWN_EX = 16; | ||
| 288 | |||
| 289 | pub const F_GETOWNER_UIDS = 17; | ||
| 290 | |||
| 291 | pub const SEEK_SET = 0; | ||
| 292 | pub const SEEK_CUR = 1; | ||
| 293 | pub const SEEK_END = 2; | ||
| 294 | |||
| 295 | pub const SIG_BLOCK = 1; | ||
| 296 | pub const SIG_UNBLOCK = 2; | ||
| 297 | pub const SIG_SETMASK = 3; | ||
| 298 | |||
| 299 | pub const SOCK_STREAM = 1; | ||
| 300 | pub const SOCK_DGRAM = 2; | ||
| 301 | pub const SOCK_RAW = 3; | ||
| 302 | pub const SOCK_RDM = 4; | ||
| 303 | pub const SOCK_SEQPACKET = 5; | ||
| 304 | |||
| 305 | pub const SOCK_CLOEXEC = 0x10000000; | ||
| 306 | pub const SOCK_NONBLOCK = 0x20000000; | ||
| 307 | |||
| 308 | pub const PROTO_ip = 0o000; | ||
| 309 | pub const PROTO_icmp = 0o001; | ||
| 310 | pub const PROTO_igmp = 0o002; | ||
| 311 | pub const PROTO_ggp = 0o003; | ||
| 312 | pub const PROTO_ipencap = 0o004; | ||
| 313 | pub const PROTO_st = 0o005; | ||
| 314 | pub const PROTO_tcp = 0o006; | ||
| 315 | pub const PROTO_egp = 0o010; | ||
| 316 | pub const PROTO_pup = 0o014; | ||
| 317 | pub const PROTO_udp = 0o021; | ||
| 318 | pub const PROTO_hmp = 0o024; | ||
| 319 | pub const PROTO_xns_idp = 0o026; | ||
| 320 | pub const PROTO_rdp = 0o033; | ||
| 321 | pub const PROTO_iso_tp4 = 0o035; | ||
| 322 | pub const PROTO_xtp = 0o044; | ||
| 323 | pub const PROTO_ddp = 0o045; | ||
| 324 | pub const PROTO_idpr_cmtp = 0o046; | ||
| 325 | pub const PROTO_ipv6 = 0o051; | ||
| 326 | pub const PROTO_ipv6_route = 0o053; | ||
| 327 | pub const PROTO_ipv6_frag = 0o054; | ||
| 328 | pub const PROTO_idrp = 0o055; | ||
| 329 | pub const PROTO_rsvp = 0o056; | ||
| 330 | pub const PROTO_gre = 0o057; | ||
| 331 | pub const PROTO_esp = 0o062; | ||
| 332 | pub const PROTO_ah = 0o063; | ||
| 333 | pub const PROTO_skip = 0o071; | ||
| 334 | pub const PROTO_ipv6_icmp = 0o072; | ||
| 335 | pub const PROTO_ipv6_nonxt = 0o073; | ||
| 336 | pub const PROTO_ipv6_opts = 0o074; | ||
| 337 | pub const PROTO_rspf = 0o111; | ||
| 338 | pub const PROTO_vmtp = 0o121; | ||
| 339 | pub const PROTO_ospf = 0o131; | ||
| 340 | pub const PROTO_ipip = 0o136; | ||
| 341 | pub const PROTO_encap = 0o142; | ||
| 342 | pub const PROTO_pim = 0o147; | ||
| 343 | pub const PROTO_raw = 0o377; | ||
| 344 | |||
| 345 | pub const PF_UNSPEC = 0; | ||
| 346 | pub const PF_LOCAL = 1; | ||
| 347 | pub const PF_UNIX = PF_LOCAL; | ||
| 348 | pub const PF_FILE = PF_LOCAL; | ||
| 349 | pub const PF_INET = 2; | ||
| 350 | pub const PF_AX25 = 3; | ||
| 351 | pub const PF_IPX = 4; | ||
| 352 | pub const PF_APPLETALK = 5; | ||
| 353 | pub const PF_NETROM = 6; | ||
| 354 | pub const PF_BRIDGE = 7; | ||
| 355 | pub const PF_ATMPVC = 8; | ||
| 356 | pub const PF_X25 = 9; | ||
| 357 | pub const PF_INET6 = 10; | ||
| 358 | pub const PF_ROSE = 11; | ||
| 359 | pub const PF_DECnet = 12; | ||
| 360 | pub const PF_NETBEUI = 13; | ||
| 361 | pub const PF_SECURITY = 14; | ||
| 362 | pub const PF_KEY = 15; | ||
| 363 | pub const PF_NETLINK = 16; | ||
| 364 | pub const PF_ROUTE = PF_NETLINK; | ||
| 365 | pub const PF_PACKET = 17; | ||
| 366 | pub const PF_ASH = 18; | ||
| 367 | pub const PF_ECONET = 19; | ||
| 368 | pub const PF_ATMSVC = 20; | ||
| 369 | pub const PF_RDS = 21; | ||
| 370 | pub const PF_SNA = 22; | ||
| 371 | pub const PF_IRDA = 23; | ||
| 372 | pub const PF_PPPOX = 24; | ||
| 373 | pub const PF_WANPIPE = 25; | ||
| 374 | pub const PF_LLC = 26; | ||
| 375 | pub const PF_IB = 27; | ||
| 376 | pub const PF_MPLS = 28; | ||
| 377 | pub const PF_CAN = 29; | ||
| 378 | pub const PF_TIPC = 30; | ||
| 379 | pub const PF_BLUETOOTH = 31; | ||
| 380 | pub const PF_IUCV = 32; | ||
| 381 | pub const PF_RXRPC = 33; | ||
| 382 | pub const PF_ISDN = 34; | ||
| 383 | pub const PF_PHONET = 35; | ||
| 384 | pub const PF_IEEE802154 = 36; | ||
| 385 | pub const PF_CAIF = 37; | ||
| 386 | pub const PF_ALG = 38; | ||
| 387 | pub const PF_NFC = 39; | ||
| 388 | pub const PF_VSOCK = 40; | ||
| 389 | pub const PF_MAX = 41; | ||
| 390 | |||
| 391 | pub const AF_UNSPEC = PF_UNSPEC; | ||
| 392 | pub const AF_LOCAL = PF_LOCAL; | ||
| 393 | pub const AF_UNIX = AF_LOCAL; | ||
| 394 | pub const AF_FILE = AF_LOCAL; | ||
| 395 | pub const AF_INET = PF_INET; | ||
| 396 | pub const AF_AX25 = PF_AX25; | ||
| 397 | pub const AF_IPX = PF_IPX; | ||
| 398 | pub const AF_APPLETALK = PF_APPLETALK; | ||
| 399 | pub const AF_NETROM = PF_NETROM; | ||
| 400 | pub const AF_BRIDGE = PF_BRIDGE; | ||
| 401 | pub const AF_ATMPVC = PF_ATMPVC; | ||
| 402 | pub const AF_X25 = PF_X25; | ||
| 403 | pub const AF_INET6 = PF_INET6; | ||
| 404 | pub const AF_ROSE = PF_ROSE; | ||
| 405 | pub const AF_DECnet = PF_DECnet; | ||
| 406 | pub const AF_NETBEUI = PF_NETBEUI; | ||
| 407 | pub const AF_SECURITY = PF_SECURITY; | ||
| 408 | pub const AF_KEY = PF_KEY; | ||
| 409 | pub const AF_NETLINK = PF_NETLINK; | ||
| 410 | pub const AF_ROUTE = PF_ROUTE; | ||
| 411 | pub const AF_PACKET = PF_PACKET; | ||
| 412 | pub const AF_ASH = PF_ASH; | ||
| 413 | pub const AF_ECONET = PF_ECONET; | ||
| 414 | pub const AF_ATMSVC = PF_ATMSVC; | ||
| 415 | pub const AF_RDS = PF_RDS; | ||
| 416 | pub const AF_SNA = PF_SNA; | ||
| 417 | pub const AF_IRDA = PF_IRDA; | ||
| 418 | pub const AF_PPPOX = PF_PPPOX; | ||
| 419 | pub const AF_WANPIPE = PF_WANPIPE; | ||
| 420 | pub const AF_LLC = PF_LLC; | ||
| 421 | pub const AF_IB = PF_IB; | ||
| 422 | pub const AF_MPLS = PF_MPLS; | ||
| 423 | pub const AF_CAN = PF_CAN; | ||
| 424 | pub const AF_TIPC = PF_TIPC; | ||
| 425 | pub const AF_BLUETOOTH = PF_BLUETOOTH; | ||
| 426 | pub const AF_IUCV = PF_IUCV; | ||
| 427 | pub const AF_RXRPC = PF_RXRPC; | ||
| 428 | pub const AF_ISDN = PF_ISDN; | ||
| 429 | pub const AF_PHONET = PF_PHONET; | ||
| 430 | pub const AF_IEEE802154 = PF_IEEE802154; | ||
| 431 | pub const AF_CAIF = PF_CAIF; | ||
| 432 | pub const AF_ALG = PF_ALG; | ||
| 433 | pub const AF_NFC = PF_NFC; | ||
| 434 | pub const AF_VSOCK = PF_VSOCK; | ||
| 435 | pub const AF_MAX = PF_MAX; | ||
| 436 | |||
| 437 | pub const DT_UNKNOWN = 0; | ||
| 438 | pub const DT_FIFO = 1; | ||
| 439 | pub const DT_CHR = 2; | ||
| 440 | pub const DT_DIR = 4; | ||
| 441 | pub const DT_BLK = 6; | ||
| 442 | pub const DT_REG = 8; | ||
| 443 | pub const DT_LNK = 10; | ||
| 444 | pub const DT_SOCK = 12; | ||
| 445 | pub const DT_WHT = 14; | ||
| 446 | |||
| 447 | /// add event to kq (implies enable) | ||
| 448 | pub const EV_ADD = 0x0001; | ||
| 449 | |||
| 450 | /// delete event from kq | ||
| 451 | pub const EV_DELETE = 0x0002; | ||
| 452 | |||
| 453 | /// enable event | ||
| 454 | pub const EV_ENABLE = 0x0004; | ||
| 455 | |||
| 456 | /// disable event (not reported) | ||
| 457 | pub const EV_DISABLE = 0x0008; | ||
| 458 | |||
| 459 | /// only report one occurrence | ||
| 460 | pub const EV_ONESHOT = 0x0010; | ||
| 461 | |||
| 462 | /// clear event state after reporting | ||
| 463 | pub 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 | ||
| 469 | pub const EV_RECEIPT = 0x0040; | ||
| 470 | |||
| 471 | /// disable event after reporting | ||
| 472 | pub const EV_DISPATCH = 0x0080; | ||
| 473 | |||
| 474 | pub const EVFILT_READ = -1; | ||
| 475 | pub const EVFILT_WRITE = -2; | ||
| 476 | |||
| 477 | /// attached to aio requests | ||
| 478 | pub const EVFILT_AIO = -3; | ||
| 479 | |||
| 480 | /// attached to vnodes | ||
| 481 | pub const EVFILT_VNODE = -4; | ||
| 482 | |||
| 483 | /// attached to struct proc | ||
| 484 | pub const EVFILT_PROC = -5; | ||
| 485 | |||
| 486 | /// attached to struct proc | ||
| 487 | pub const EVFILT_SIGNAL = -6; | ||
| 488 | |||
| 489 | /// timers | ||
| 490 | pub const EVFILT_TIMER = -7; | ||
| 491 | |||
| 492 | /// Process descriptors | ||
| 493 | pub const EVFILT_PROCDESC = -8; | ||
| 494 | |||
| 495 | /// Filesystem events | ||
| 496 | pub const EVFILT_FS = -9; | ||
| 497 | |||
| 498 | pub const EVFILT_LIO = -10; | ||
| 499 | |||
| 500 | /// User events | ||
| 501 | pub const EVFILT_USER = -11; | ||
| 502 | |||
| 503 | /// Sendfile events | ||
| 504 | pub const EVFILT_SENDFILE = -12; | ||
| 505 | |||
| 506 | pub const EVFILT_EMPTY = -13; | ||
| 507 | |||
| 508 | /// On input, NOTE_TRIGGER causes the event to be triggered for output. | ||
| 509 | pub const NOTE_TRIGGER = 0x01000000; | ||
| 510 | |||
| 511 | /// ignore input fflags | ||
| 512 | pub const NOTE_FFNOP = 0x00000000; | ||
| 513 | |||
| 514 | /// and fflags | ||
| 515 | pub const NOTE_FFAND = 0x40000000; | ||
| 516 | |||
| 517 | /// or fflags | ||
| 518 | pub const NOTE_FFOR = 0x80000000; | ||
| 519 | |||
| 520 | /// copy fflags | ||
| 521 | pub const NOTE_FFCOPY = 0xc0000000; | ||
| 522 | |||
| 523 | /// mask for operations | ||
| 524 | pub const NOTE_FFCTRLMASK = 0xc0000000; | ||
| 525 | pub const NOTE_FFLAGSMASK = 0x00ffffff; | ||
| 526 | |||
| 527 | /// low water mark | ||
| 528 | pub const NOTE_LOWAT = 0x00000001; | ||
| 529 | |||
| 530 | /// behave like poll() | ||
| 531 | pub const NOTE_FILE_POLL = 0x00000002; | ||
| 532 | |||
| 533 | /// vnode was removed | ||
| 534 | pub const NOTE_DELETE = 0x00000001; | ||
| 535 | |||
| 536 | /// data contents changed | ||
| 537 | pub const NOTE_WRITE = 0x00000002; | ||
| 538 | |||
| 539 | /// size increased | ||
| 540 | pub const NOTE_EXTEND = 0x00000004; | ||
| 541 | |||
| 542 | /// attributes changed | ||
| 543 | pub const NOTE_ATTRIB = 0x00000008; | ||
| 544 | |||
| 545 | /// link count changed | ||
| 546 | pub const NOTE_LINK = 0x00000010; | ||
| 547 | |||
| 548 | /// vnode was renamed | ||
| 549 | pub const NOTE_RENAME = 0x00000020; | ||
| 550 | |||
| 551 | /// vnode access was revoked | ||
| 552 | pub const NOTE_REVOKE = 0x00000040; | ||
| 553 | |||
| 554 | /// vnode was opened | ||
| 555 | pub const NOTE_OPEN = 0x00000080; | ||
| 556 | |||
| 557 | /// file closed, fd did not allow write | ||
| 558 | pub const NOTE_CLOSE = 0x00000100; | ||
| 559 | |||
| 560 | /// file closed, fd did allow write | ||
| 561 | pub const NOTE_CLOSE_WRITE = 0x00000200; | ||
| 562 | |||
| 563 | /// file was read | ||
| 564 | pub const NOTE_READ = 0x00000400; | ||
| 565 | |||
| 566 | /// process exited | ||
| 567 | pub const NOTE_EXIT = 0x80000000; | ||
| 568 | |||
| 569 | /// process forked | ||
| 570 | pub const NOTE_FORK = 0x40000000; | ||
| 571 | |||
| 572 | /// process exec'd | ||
| 573 | pub const NOTE_EXEC = 0x20000000; | ||
| 574 | |||
| 575 | /// mask for signal & exit status | ||
| 576 | pub const NOTE_PDATAMASK = 0x000fffff; | ||
| 577 | pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK); | ||
| 578 | |||
| 579 | /// data is seconds | ||
| 580 | pub const NOTE_SECONDS = 0x00000001; | ||
| 581 | |||
| 582 | /// data is milliseconds | ||
| 583 | pub const NOTE_MSECONDS = 0x00000002; | ||
| 584 | |||
| 585 | /// data is microseconds | ||
| 586 | pub const NOTE_USECONDS = 0x00000004; | ||
| 587 | |||
| 588 | /// data is nanoseconds | ||
| 589 | pub const NOTE_NSECONDS = 0x00000008; | ||
| 590 | |||
| 591 | /// timeout is absolute | ||
| 592 | pub const NOTE_ABSTIME = 0x00000010; | ||
| 593 | |||
| 594 | pub const TCGETS = 0x5401; | ||
| 595 | pub const TCSETS = 0x5402; | ||
| 596 | pub const TCSETSW = 0x5403; | ||
| 597 | pub const TCSETSF = 0x5404; | ||
| 598 | pub const TCGETA = 0x5405; | ||
| 599 | pub const TCSETA = 0x5406; | ||
| 600 | pub const TCSETAW = 0x5407; | ||
| 601 | pub const TCSETAF = 0x5408; | ||
| 602 | pub const TCSBRK = 0x5409; | ||
| 603 | pub const TCXONC = 0x540A; | ||
| 604 | pub const TCFLSH = 0x540B; | ||
| 605 | pub const TIOCEXCL = 0x540C; | ||
| 606 | pub const TIOCNXCL = 0x540D; | ||
| 607 | pub const TIOCSCTTY = 0x540E; | ||
| 608 | pub const TIOCGPGRP = 0x540F; | ||
| 609 | pub const TIOCSPGRP = 0x5410; | ||
| 610 | pub const TIOCOUTQ = 0x5411; | ||
| 611 | pub const TIOCSTI = 0x5412; | ||
| 612 | pub const TIOCGWINSZ = 0x5413; | ||
| 613 | pub const TIOCSWINSZ = 0x5414; | ||
| 614 | pub const TIOCMGET = 0x5415; | ||
| 615 | pub const TIOCMBIS = 0x5416; | ||
| 616 | pub const TIOCMBIC = 0x5417; | ||
| 617 | pub const TIOCMSET = 0x5418; | ||
| 618 | pub const TIOCGSOFTCAR = 0x5419; | ||
| 619 | pub const TIOCSSOFTCAR = 0x541A; | ||
| 620 | pub const FIONREAD = 0x541B; | ||
| 621 | pub const TIOCINQ = FIONREAD; | ||
| 622 | pub const TIOCLINUX = 0x541C; | ||
| 623 | pub const TIOCCONS = 0x541D; | ||
| 624 | pub const TIOCGSERIAL = 0x541E; | ||
| 625 | pub const TIOCSSERIAL = 0x541F; | ||
| 626 | pub const TIOCPKT = 0x5420; | ||
| 627 | pub const FIONBIO = 0x5421; | ||
| 628 | pub const TIOCNOTTY = 0x5422; | ||
| 629 | pub const TIOCSETD = 0x5423; | ||
| 630 | pub const TIOCGETD = 0x5424; | ||
| 631 | pub const TCSBRKP = 0x5425; | ||
| 632 | pub const TIOCSBRK = 0x5427; | ||
| 633 | pub const TIOCCBRK = 0x5428; | ||
| 634 | pub const TIOCGSID = 0x5429; | ||
| 635 | pub const TIOCGRS485 = 0x542E; | ||
| 636 | pub const TIOCSRS485 = 0x542F; | ||
| 637 | pub const TIOCGPTN = 0x80045430; | ||
| 638 | pub const TIOCSPTLCK = 0x40045431; | ||
| 639 | pub const TIOCGDEV = 0x80045432; | ||
| 640 | pub const TCGETX = 0x5432; | ||
| 641 | pub const TCSETX = 0x5433; | ||
| 642 | pub const TCSETXF = 0x5434; | ||
| 643 | pub const TCSETXW = 0x5435; | ||
| 644 | pub const TIOCSIG = 0x40045436; | ||
| 645 | pub const TIOCVHANGUP = 0x5437; | ||
| 646 | pub const TIOCGPKT = 0x80045438; | ||
| 647 | pub const TIOCGPTLCK = 0x80045439; | ||
| 648 | pub const TIOCGEXCL = 0x80045440; | ||
| 649 | |||
| 650 | pub fn WEXITSTATUS(s: u32) u32 { | ||
| 651 | return (s & 0xff00) >> 8; | ||
| 652 | } | ||
| 653 | pub fn WTERMSIG(s: u32) u32 { | ||
| 654 | return s & 0x7f; | ||
| 655 | } | ||
| 656 | pub fn WSTOPSIG(s: u32) u32 { | ||
| 657 | return WEXITSTATUS(s); | ||
| 658 | } | ||
| 659 | pub fn WIFEXITED(s: u32) bool { | ||
| 660 | return WTERMSIG(s) == 0; | ||
| 661 | } | ||
| 662 | pub fn WIFSTOPPED(s: u32) bool { | ||
| 663 | return @intCast(u16, (((s & 0xffff) *% 0x10001) >> 8)) > 0x7f00; | ||
| 664 | } | ||
| 665 | pub fn WIFSIGNALED(s: u32) bool { | ||
| 666 | return (s & 0xffff) -% 1 < 0xff; | ||
| 667 | } | ||
| 668 | |||
| 669 | pub const winsize = extern struct { | ||
| 670 | ws_row: u16, | ||
| 671 | ws_col: u16, | ||
| 672 | ws_xpixel: u16, | ||
| 673 | ws_ypixel: u16, | ||
| 674 | }; | ||
| 675 | |||
| 676 | const NSIG = 32; | ||
| 677 | |||
| 678 | pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize)); | ||
| 679 | pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0); | ||
| 680 | pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1); | ||
| 681 | |||
| 682 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. | ||
| 683 | pub 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 | |||
| 697 | pub const _SIG_WORDS = 4; | ||
| 698 | pub const _SIG_MAXSIG = 128; | ||
| 699 | |||
| 700 | pub inline fn _SIG_IDX(sig: usize) usize { | ||
| 701 | return sig - 1; | ||
| 702 | } | ||
| 703 | pub inline fn _SIG_WORD(sig: usize) usize { | ||
| 704 | return_SIG_IDX(sig) >> 5; | ||
| 705 | } | ||
| 706 | pub inline fn _SIG_BIT(sig: usize) usize { | ||
| 707 | return 1 << (_SIG_IDX(sig) & 31); | ||
| 708 | } | ||
| 709 | pub inline fn _SIG_VALID(sig: usize) usize { | ||
| 710 | return sig <= _SIG_MAXSIG and sig > 0; | ||
| 711 | } | ||
| 712 | |||
| 713 | pub const sigset_t = extern struct { | ||
| 714 | __bits: [_SIG_WORDS]u32, | ||
| 715 | }; | ||
| 716 | |||
| 717 | pub const EPERM = 1; // Operation not permitted | ||
| 718 | pub const ENOENT = 2; // No such file or directory | ||
| 719 | pub const ESRCH = 3; // No such process | ||
| 720 | pub const EINTR = 4; // Interrupted system call | ||
| 721 | pub const EIO = 5; // Input/output error | ||
| 722 | pub const ENXIO = 6; // Device not configured | ||
| 723 | pub const E2BIG = 7; // Argument list too long | ||
| 724 | pub const ENOEXEC = 8; // Exec format error | ||
| 725 | pub const EBADF = 9; // Bad file descriptor | ||
| 726 | pub const ECHILD = 10; // No child processes | ||
| 727 | pub const EDEADLK = 11; // Resource deadlock avoided | ||
| 728 | // 11 was EAGAIN | ||
| 729 | pub const ENOMEM = 12; // Cannot allocate memory | ||
| 730 | pub const EACCES = 13; // Permission denied | ||
| 731 | pub const EFAULT = 14; // Bad address | ||
| 732 | pub const ENOTBLK = 15; // Block device required | ||
| 733 | pub const EBUSY = 16; // Device busy | ||
| 734 | pub const EEXIST = 17; // File exists | ||
| 735 | pub const EXDEV = 18; // Cross-device link | ||
| 736 | pub const ENODEV = 19; // Operation not supported by device | ||
| 737 | pub const ENOTDIR = 20; // Not a directory | ||
| 738 | pub const EISDIR = 21; // Is a directory | ||
| 739 | pub const EINVAL = 22; // Invalid argument | ||
| 740 | pub const ENFILE = 23; // Too many open files in system | ||
| 741 | pub const EMFILE = 24; // Too many open files | ||
| 742 | pub const ENOTTY = 25; // Inappropriate ioctl for device | ||
| 743 | pub const ETXTBSY = 26; // Text file busy | ||
| 744 | pub const EFBIG = 27; // File too large | ||
| 745 | pub const ENOSPC = 28; // No space left on device | ||
| 746 | pub const ESPIPE = 29; // Illegal seek | ||
| 747 | pub const EROFS = 30; // Read-only filesystem | ||
| 748 | pub const EMLINK = 31; // Too many links | ||
| 749 | pub const EPIPE = 32; // Broken pipe | ||
| 750 | |||
| 751 | // math software | ||
| 752 | pub const EDOM = 33; // Numerical argument out of domain | ||
| 753 | pub const ERANGE = 34; // Result too large | ||
| 754 | |||
| 755 | // non-blocking and interrupt i/o | ||
| 756 | pub const EAGAIN = 35; // Resource temporarily unavailable | ||
| 757 | pub const EWOULDBLOCK = EAGAIN; // Operation would block | ||
| 758 | pub const EINPROGRESS = 36; // Operation now in progress | ||
| 759 | pub const EALREADY = 37; // Operation already in progress | ||
| 760 | |||
| 761 | // ipc/network software -- argument errors | ||
| 762 | pub const ENOTSOCK = 38; // Socket operation on non-socket | ||
| 763 | pub const EDESTADDRREQ = 39; // Destination address required | ||
| 764 | pub const EMSGSIZE = 40; // Message too long | ||
| 765 | pub const EPROTOTYPE = 41; // Protocol wrong type for socket | ||
| 766 | pub const ENOPROTOOPT = 42; // Protocol not available | ||
| 767 | pub const EPROTONOSUPPORT = 43; // Protocol not supported | ||
| 768 | pub const ESOCKTNOSUPPORT = 44; // Socket type not supported | ||
| 769 | pub const EOPNOTSUPP = 45; // Operation not supported | ||
| 770 | pub const ENOTSUP = EOPNOTSUPP; // Operation not supported | ||
| 771 | pub const EPFNOSUPPORT = 46; // Protocol family not supported | ||
| 772 | pub const EAFNOSUPPORT = 47; // Address family not supported by protocol family | ||
| 773 | pub const EADDRINUSE = 48; // Address already in use | ||
| 774 | pub const EADDRNOTAVAIL = 49; // Can't assign requested address | ||
| 775 | |||
| 776 | // ipc/network software -- operational errors | ||
| 777 | pub const ENETDOWN = 50; // Network is down | ||
| 778 | pub const ENETUNREACH = 51; // Network is unreachable | ||
| 779 | pub const ENETRESET = 52; // Network dropped connection on reset | ||
| 780 | pub const ECONNABORTED = 53; // Software caused connection abort | ||
| 781 | pub const ECONNRESET = 54; // Connection reset by peer | ||
| 782 | pub const ENOBUFS = 55; // No buffer space available | ||
| 783 | pub const EISCONN = 56; // Socket is already connected | ||
| 784 | pub const ENOTCONN = 57; // Socket is not connected | ||
| 785 | pub const ESHUTDOWN = 58; // Can't send after socket shutdown | ||
| 786 | pub const ETOOMANYREFS = 59; // Too many references: can't splice | ||
| 787 | pub const ETIMEDOUT = 60; // Operation timed out | ||
| 788 | pub const ECONNREFUSED = 61; // Connection refused | ||
| 789 | |||
| 790 | pub const ELOOP = 62; // Too many levels of symbolic links | ||
| 791 | pub const ENAMETOOLONG = 63; // File name too long | ||
| 792 | |||
| 793 | // should be rearranged | ||
| 794 | pub const EHOSTDOWN = 64; // Host is down | ||
| 795 | pub const EHOSTUNREACH = 65; // No route to host | ||
| 796 | pub const ENOTEMPTY = 66; // Directory not empty | ||
| 797 | |||
| 798 | // quotas & mush | ||
| 799 | pub const EPROCLIM = 67; // Too many processes | ||
| 800 | pub const EUSERS = 68; // Too many users | ||
| 801 | pub const EDQUOT = 69; // Disc quota exceeded | ||
| 802 | |||
| 803 | // Network File System | ||
| 804 | pub const ESTALE = 70; // Stale NFS file handle | ||
| 805 | pub const EREMOTE = 71; // Too many levels of remote in path | ||
| 806 | pub const EBADRPC = 72; // RPC struct is bad | ||
| 807 | pub const ERPCMISMATCH = 73; // RPC version wrong | ||
| 808 | pub const EPROGUNAVAIL = 74; // RPC prog. not avail | ||
| 809 | pub const EPROGMISMATCH = 75; // Program version wrong | ||
| 810 | pub const EPROCUNAVAIL = 76; // Bad procedure for program | ||
| 811 | |||
| 812 | pub const ENOLCK = 77; // No locks available | ||
| 813 | pub const ENOSYS = 78; // Function not implemented | ||
| 814 | |||
| 815 | pub const EFTYPE = 79; // Inappropriate file type or format | ||
| 816 | pub const EAUTH = 80; // Authentication error | ||
| 817 | pub const ENEEDAUTH = 81; // Need authenticator | ||
| 818 | pub const EIDRM = 82; // Identifier removed | ||
| 819 | pub const ENOMSG = 83; // No message of desired type | ||
| 820 | pub const EOVERFLOW = 84; // Value too large to be stored in data type | ||
| 821 | pub const ECANCELED = 85; // Operation canceled | ||
| 822 | pub const EILSEQ = 86; // Illegal byte sequence | ||
| 823 | pub const ENOATTR = 87; // Attribute not found | ||
| 824 | |||
| 825 | pub const EDOOFUS = 88; // Programming error | ||
| 826 | |||
| 827 | pub const EBADMSG = 89; // Bad message | ||
| 828 | pub const EMULTIHOP = 90; // Multihop attempted | ||
| 829 | pub const ENOLINK = 91; // Link has been severed | ||
| 830 | pub const EPROTO = 92; // Protocol error | ||
| 831 | |||
| 832 | pub const ENOTCAPABLE = 93; // Capabilities insufficient | ||
| 833 | pub const ECAPMODE = 94; // Not permitted in capability mode | ||
| 834 | pub const ENOTRECOVERABLE = 95; // State not recoverable | ||
| 835 | pub const EOWNERDEAD = 96; // Previous owner died | ||
| 836 | |||
| 837 | pub const ELAST = 96; // Must be equal largest errno | ||
std/os/bits/linux.zig created+931| ... | @@ -0,0 +1,931 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("../../std.zig"); | ||
| 3 | const maxInt = std.math.maxInt; | ||
| 4 | use @import("../bits.zig"); | ||
| 5 | |||
| 6 | pub use @import("linux/errno.zig"); | ||
| 7 | pub use switch (builtin.arch) { | ||
| 8 | .x86_64 => @import("linux/x86_64.zig"), | ||
| 9 | .aarch64 => @import("linux/arm64.zig"), | ||
| 10 | else => struct {}, | ||
| 11 | }; | ||
| 12 | |||
| 13 | pub const pid_t = i32; | ||
| 14 | pub const fd_t = i32; | ||
| 15 | |||
| 16 | pub const PATH_MAX = 4096; | ||
| 17 | pub const IOV_MAX = 1024; | ||
| 18 | |||
| 19 | pub const STDIN_FILENO = 0; | ||
| 20 | pub const STDOUT_FILENO = 1; | ||
| 21 | pub const STDERR_FILENO = 2; | ||
| 22 | |||
| 23 | pub const FUTEX_WAIT = 0; | ||
| 24 | pub const FUTEX_WAKE = 1; | ||
| 25 | pub const FUTEX_FD = 2; | ||
| 26 | pub const FUTEX_REQUEUE = 3; | ||
| 27 | pub const FUTEX_CMP_REQUEUE = 4; | ||
| 28 | pub const FUTEX_WAKE_OP = 5; | ||
| 29 | pub const FUTEX_LOCK_PI = 6; | ||
| 30 | pub const FUTEX_UNLOCK_PI = 7; | ||
| 31 | pub const FUTEX_TRYLOCK_PI = 8; | ||
| 32 | pub const FUTEX_WAIT_BITSET = 9; | ||
| 33 | |||
| 34 | pub const FUTEX_PRIVATE_FLAG = 128; | ||
| 35 | |||
| 36 | pub const FUTEX_CLOCK_REALTIME = 256; | ||
| 37 | |||
| 38 | pub const PROT_NONE = 0; | ||
| 39 | pub const PROT_READ = 1; | ||
| 40 | pub const PROT_WRITE = 2; | ||
| 41 | pub const PROT_EXEC = 4; | ||
| 42 | pub const PROT_GROWSDOWN = 0x01000000; | ||
| 43 | pub const PROT_GROWSUP = 0x02000000; | ||
| 44 | |||
| 45 | pub const MAP_FAILED = @intToPtr(*c_void, maxInt(usize)); | ||
| 46 | pub const MAP_SHARED = 0x01; | ||
| 47 | pub const MAP_PRIVATE = 0x02; | ||
| 48 | pub const MAP_TYPE = 0x0f; | ||
| 49 | pub const MAP_FIXED = 0x10; | ||
| 50 | pub const MAP_ANONYMOUS = 0x20; | ||
| 51 | pub const MAP_NORESERVE = 0x4000; | ||
| 52 | pub const MAP_GROWSDOWN = 0x0100; | ||
| 53 | pub const MAP_DENYWRITE = 0x0800; | ||
| 54 | pub const MAP_EXECUTABLE = 0x1000; | ||
| 55 | pub const MAP_LOCKED = 0x2000; | ||
| 56 | pub const MAP_POPULATE = 0x8000; | ||
| 57 | pub const MAP_NONBLOCK = 0x10000; | ||
| 58 | pub const MAP_STACK = 0x20000; | ||
| 59 | pub const MAP_HUGETLB = 0x40000; | ||
| 60 | pub const MAP_FILE = 0; | ||
| 61 | |||
| 62 | pub const F_OK = 0; | ||
| 63 | pub const X_OK = 1; | ||
| 64 | pub const W_OK = 2; | ||
| 65 | pub const R_OK = 4; | ||
| 66 | |||
| 67 | pub const WNOHANG = 1; | ||
| 68 | pub const WUNTRACED = 2; | ||
| 69 | pub const WSTOPPED = 2; | ||
| 70 | pub const WEXITED = 4; | ||
| 71 | pub const WCONTINUED = 8; | ||
| 72 | pub const WNOWAIT = 0x1000000; | ||
| 73 | |||
| 74 | pub const SA_NOCLDSTOP = 1; | ||
| 75 | pub const SA_NOCLDWAIT = 2; | ||
| 76 | pub const SA_SIGINFO = 4; | ||
| 77 | pub const SA_ONSTACK = 0x08000000; | ||
| 78 | pub const SA_RESTART = 0x10000000; | ||
| 79 | pub const SA_NODEFER = 0x40000000; | ||
| 80 | pub const SA_RESETHAND = 0x80000000; | ||
| 81 | pub const SA_RESTORER = 0x04000000; | ||
| 82 | |||
| 83 | pub const SIGHUP = 1; | ||
| 84 | pub const SIGINT = 2; | ||
| 85 | pub const SIGQUIT = 3; | ||
| 86 | pub const SIGILL = 4; | ||
| 87 | pub const SIGTRAP = 5; | ||
| 88 | pub const SIGABRT = 6; | ||
| 89 | pub const SIGIOT = SIGABRT; | ||
| 90 | pub const SIGBUS = 7; | ||
| 91 | pub const SIGFPE = 8; | ||
| 92 | pub const SIGKILL = 9; | ||
| 93 | pub const SIGUSR1 = 10; | ||
| 94 | pub const SIGSEGV = 11; | ||
| 95 | pub const SIGUSR2 = 12; | ||
| 96 | pub const SIGPIPE = 13; | ||
| 97 | pub const SIGALRM = 14; | ||
| 98 | pub const SIGTERM = 15; | ||
| 99 | pub const SIGSTKFLT = 16; | ||
| 100 | pub const SIGCHLD = 17; | ||
| 101 | pub const SIGCONT = 18; | ||
| 102 | pub const SIGSTOP = 19; | ||
| 103 | pub const SIGTSTP = 20; | ||
| 104 | pub const SIGTTIN = 21; | ||
| 105 | pub const SIGTTOU = 22; | ||
| 106 | pub const SIGURG = 23; | ||
| 107 | pub const SIGXCPU = 24; | ||
| 108 | pub const SIGXFSZ = 25; | ||
| 109 | pub const SIGVTALRM = 26; | ||
| 110 | pub const SIGPROF = 27; | ||
| 111 | pub const SIGWINCH = 28; | ||
| 112 | pub const SIGIO = 29; | ||
| 113 | pub const SIGPOLL = 29; | ||
| 114 | pub const SIGPWR = 30; | ||
| 115 | pub const SIGSYS = 31; | ||
| 116 | pub const SIGUNUSED = SIGSYS; | ||
| 117 | |||
| 118 | pub const O_RDONLY = 0o0; | ||
| 119 | pub const O_WRONLY = 0o1; | ||
| 120 | pub const O_RDWR = 0o2; | ||
| 121 | |||
| 122 | pub const SEEK_SET = 0; | ||
| 123 | pub const SEEK_CUR = 1; | ||
| 124 | pub const SEEK_END = 2; | ||
| 125 | |||
| 126 | pub const SIG_BLOCK = 0; | ||
| 127 | pub const SIG_UNBLOCK = 1; | ||
| 128 | pub const SIG_SETMASK = 2; | ||
| 129 | |||
| 130 | pub const PROTO_ip = 0o000; | ||
| 131 | pub const PROTO_icmp = 0o001; | ||
| 132 | pub const PROTO_igmp = 0o002; | ||
| 133 | pub const PROTO_ggp = 0o003; | ||
| 134 | pub const PROTO_ipencap = 0o004; | ||
| 135 | pub const PROTO_st = 0o005; | ||
| 136 | pub const PROTO_tcp = 0o006; | ||
| 137 | pub const PROTO_egp = 0o010; | ||
| 138 | pub const PROTO_pup = 0o014; | ||
| 139 | pub const PROTO_udp = 0o021; | ||
| 140 | pub const PROTO_hmp = 0o024; | ||
| 141 | pub const PROTO_xns_idp = 0o026; | ||
| 142 | pub const PROTO_rdp = 0o033; | ||
| 143 | pub const PROTO_iso_tp4 = 0o035; | ||
| 144 | pub const PROTO_xtp = 0o044; | ||
| 145 | pub const PROTO_ddp = 0o045; | ||
| 146 | pub const PROTO_idpr_cmtp = 0o046; | ||
| 147 | pub const PROTO_ipv6 = 0o051; | ||
| 148 | pub const PROTO_ipv6_route = 0o053; | ||
| 149 | pub const PROTO_ipv6_frag = 0o054; | ||
| 150 | pub const PROTO_idrp = 0o055; | ||
| 151 | pub const PROTO_rsvp = 0o056; | ||
| 152 | pub const PROTO_gre = 0o057; | ||
| 153 | pub const PROTO_esp = 0o062; | ||
| 154 | pub const PROTO_ah = 0o063; | ||
| 155 | pub const PROTO_skip = 0o071; | ||
| 156 | pub const PROTO_ipv6_icmp = 0o072; | ||
| 157 | pub const PROTO_ipv6_nonxt = 0o073; | ||
| 158 | pub const PROTO_ipv6_opts = 0o074; | ||
| 159 | pub const PROTO_rspf = 0o111; | ||
| 160 | pub const PROTO_vmtp = 0o121; | ||
| 161 | pub const PROTO_ospf = 0o131; | ||
| 162 | pub const PROTO_ipip = 0o136; | ||
| 163 | pub const PROTO_encap = 0o142; | ||
| 164 | pub const PROTO_pim = 0o147; | ||
| 165 | pub const PROTO_raw = 0o377; | ||
| 166 | |||
| 167 | pub const SHUT_RD = 0; | ||
| 168 | pub const SHUT_WR = 1; | ||
| 169 | pub const SHUT_RDWR = 2; | ||
| 170 | |||
| 171 | pub const SOCK_STREAM = 1; | ||
| 172 | pub const SOCK_DGRAM = 2; | ||
| 173 | pub const SOCK_RAW = 3; | ||
| 174 | pub const SOCK_RDM = 4; | ||
| 175 | pub const SOCK_SEQPACKET = 5; | ||
| 176 | pub const SOCK_DCCP = 6; | ||
| 177 | pub const SOCK_PACKET = 10; | ||
| 178 | pub const SOCK_CLOEXEC = 0o2000000; | ||
| 179 | pub const SOCK_NONBLOCK = 0o4000; | ||
| 180 | |||
| 181 | pub const PF_UNSPEC = 0; | ||
| 182 | pub const PF_LOCAL = 1; | ||
| 183 | pub const PF_UNIX = PF_LOCAL; | ||
| 184 | pub const PF_FILE = PF_LOCAL; | ||
| 185 | pub const PF_INET = 2; | ||
| 186 | pub const PF_AX25 = 3; | ||
| 187 | pub const PF_IPX = 4; | ||
| 188 | pub const PF_APPLETALK = 5; | ||
| 189 | pub const PF_NETROM = 6; | ||
| 190 | pub const PF_BRIDGE = 7; | ||
| 191 | pub const PF_ATMPVC = 8; | ||
| 192 | pub const PF_X25 = 9; | ||
| 193 | pub const PF_INET6 = 10; | ||
| 194 | pub const PF_ROSE = 11; | ||
| 195 | pub const PF_DECnet = 12; | ||
| 196 | pub const PF_NETBEUI = 13; | ||
| 197 | pub const PF_SECURITY = 14; | ||
| 198 | pub const PF_KEY = 15; | ||
| 199 | pub const PF_NETLINK = 16; | ||
| 200 | pub const PF_ROUTE = PF_NETLINK; | ||
| 201 | pub const PF_PACKET = 17; | ||
| 202 | pub const PF_ASH = 18; | ||
| 203 | pub const PF_ECONET = 19; | ||
| 204 | pub const PF_ATMSVC = 20; | ||
| 205 | pub const PF_RDS = 21; | ||
| 206 | pub const PF_SNA = 22; | ||
| 207 | pub const PF_IRDA = 23; | ||
| 208 | pub const PF_PPPOX = 24; | ||
| 209 | pub const PF_WANPIPE = 25; | ||
| 210 | pub const PF_LLC = 26; | ||
| 211 | pub const PF_IB = 27; | ||
| 212 | pub const PF_MPLS = 28; | ||
| 213 | pub const PF_CAN = 29; | ||
| 214 | pub const PF_TIPC = 30; | ||
| 215 | pub const PF_BLUETOOTH = 31; | ||
| 216 | pub const PF_IUCV = 32; | ||
| 217 | pub const PF_RXRPC = 33; | ||
| 218 | pub const PF_ISDN = 34; | ||
| 219 | pub const PF_PHONET = 35; | ||
| 220 | pub const PF_IEEE802154 = 36; | ||
| 221 | pub const PF_CAIF = 37; | ||
| 222 | pub const PF_ALG = 38; | ||
| 223 | pub const PF_NFC = 39; | ||
| 224 | pub const PF_VSOCK = 40; | ||
| 225 | pub const PF_KCM = 41; | ||
| 226 | pub const PF_QIPCRTR = 42; | ||
| 227 | pub const PF_SMC = 43; | ||
| 228 | pub const PF_MAX = 44; | ||
| 229 | |||
| 230 | pub const AF_UNSPEC = PF_UNSPEC; | ||
| 231 | pub const AF_LOCAL = PF_LOCAL; | ||
| 232 | pub const AF_UNIX = AF_LOCAL; | ||
| 233 | pub const AF_FILE = AF_LOCAL; | ||
| 234 | pub const AF_INET = PF_INET; | ||
| 235 | pub const AF_AX25 = PF_AX25; | ||
| 236 | pub const AF_IPX = PF_IPX; | ||
| 237 | pub const AF_APPLETALK = PF_APPLETALK; | ||
| 238 | pub const AF_NETROM = PF_NETROM; | ||
| 239 | pub const AF_BRIDGE = PF_BRIDGE; | ||
| 240 | pub const AF_ATMPVC = PF_ATMPVC; | ||
| 241 | pub const AF_X25 = PF_X25; | ||
| 242 | pub const AF_INET6 = PF_INET6; | ||
| 243 | pub const AF_ROSE = PF_ROSE; | ||
| 244 | pub const AF_DECnet = PF_DECnet; | ||
| 245 | pub const AF_NETBEUI = PF_NETBEUI; | ||
| 246 | pub const AF_SECURITY = PF_SECURITY; | ||
| 247 | pub const AF_KEY = PF_KEY; | ||
| 248 | pub const AF_NETLINK = PF_NETLINK; | ||
| 249 | pub const AF_ROUTE = PF_ROUTE; | ||
| 250 | pub const AF_PACKET = PF_PACKET; | ||
| 251 | pub const AF_ASH = PF_ASH; | ||
| 252 | pub const AF_ECONET = PF_ECONET; | ||
| 253 | pub const AF_ATMSVC = PF_ATMSVC; | ||
| 254 | pub const AF_RDS = PF_RDS; | ||
| 255 | pub const AF_SNA = PF_SNA; | ||
| 256 | pub const AF_IRDA = PF_IRDA; | ||
| 257 | pub const AF_PPPOX = PF_PPPOX; | ||
| 258 | pub const AF_WANPIPE = PF_WANPIPE; | ||
| 259 | pub const AF_LLC = PF_LLC; | ||
| 260 | pub const AF_IB = PF_IB; | ||
| 261 | pub const AF_MPLS = PF_MPLS; | ||
| 262 | pub const AF_CAN = PF_CAN; | ||
| 263 | pub const AF_TIPC = PF_TIPC; | ||
| 264 | pub const AF_BLUETOOTH = PF_BLUETOOTH; | ||
| 265 | pub const AF_IUCV = PF_IUCV; | ||
| 266 | pub const AF_RXRPC = PF_RXRPC; | ||
| 267 | pub const AF_ISDN = PF_ISDN; | ||
| 268 | pub const AF_PHONET = PF_PHONET; | ||
| 269 | pub const AF_IEEE802154 = PF_IEEE802154; | ||
| 270 | pub const AF_CAIF = PF_CAIF; | ||
| 271 | pub const AF_ALG = PF_ALG; | ||
| 272 | pub const AF_NFC = PF_NFC; | ||
| 273 | pub const AF_VSOCK = PF_VSOCK; | ||
| 274 | pub const AF_KCM = PF_KCM; | ||
| 275 | pub const AF_QIPCRTR = PF_QIPCRTR; | ||
| 276 | pub const AF_SMC = PF_SMC; | ||
| 277 | pub const AF_MAX = PF_MAX; | ||
| 278 | |||
| 279 | pub const SO_DEBUG = 1; | ||
| 280 | pub const SO_REUSEADDR = 2; | ||
| 281 | pub const SO_TYPE = 3; | ||
| 282 | pub const SO_ERROR = 4; | ||
| 283 | pub const SO_DONTROUTE = 5; | ||
| 284 | pub const SO_BROADCAST = 6; | ||
| 285 | pub const SO_SNDBUF = 7; | ||
| 286 | pub const SO_RCVBUF = 8; | ||
| 287 | pub const SO_KEEPALIVE = 9; | ||
| 288 | pub const SO_OOBINLINE = 10; | ||
| 289 | pub const SO_NO_CHECK = 11; | ||
| 290 | pub const SO_PRIORITY = 12; | ||
| 291 | pub const SO_LINGER = 13; | ||
| 292 | pub const SO_BSDCOMPAT = 14; | ||
| 293 | pub const SO_REUSEPORT = 15; | ||
| 294 | pub const SO_PASSCRED = 16; | ||
| 295 | pub const SO_PEERCRED = 17; | ||
| 296 | pub const SO_RCVLOWAT = 18; | ||
| 297 | pub const SO_SNDLOWAT = 19; | ||
| 298 | pub const SO_RCVTIMEO = 20; | ||
| 299 | pub const SO_SNDTIMEO = 21; | ||
| 300 | pub const SO_ACCEPTCONN = 30; | ||
| 301 | pub const SO_SNDBUFFORCE = 32; | ||
| 302 | pub const SO_RCVBUFFORCE = 33; | ||
| 303 | pub const SO_PROTOCOL = 38; | ||
| 304 | pub const SO_DOMAIN = 39; | ||
| 305 | |||
| 306 | pub const SO_SECURITY_AUTHENTICATION = 22; | ||
| 307 | pub const SO_SECURITY_ENCRYPTION_TRANSPORT = 23; | ||
| 308 | pub const SO_SECURITY_ENCRYPTION_NETWORK = 24; | ||
| 309 | |||
| 310 | pub const SO_BINDTODEVICE = 25; | ||
| 311 | |||
| 312 | pub const SO_ATTACH_FILTER = 26; | ||
| 313 | pub const SO_DETACH_FILTER = 27; | ||
| 314 | pub const SO_GET_FILTER = SO_ATTACH_FILTER; | ||
| 315 | |||
| 316 | pub const SO_PEERNAME = 28; | ||
| 317 | pub const SO_TIMESTAMP = 29; | ||
| 318 | pub const SCM_TIMESTAMP = SO_TIMESTAMP; | ||
| 319 | |||
| 320 | pub const SO_PEERSEC = 31; | ||
| 321 | pub const SO_PASSSEC = 34; | ||
| 322 | pub const SO_TIMESTAMPNS = 35; | ||
| 323 | pub const SCM_TIMESTAMPNS = SO_TIMESTAMPNS; | ||
| 324 | pub const SO_MARK = 36; | ||
| 325 | pub const SO_TIMESTAMPING = 37; | ||
| 326 | pub const SCM_TIMESTAMPING = SO_TIMESTAMPING; | ||
| 327 | pub const SO_RXQ_OVFL = 40; | ||
| 328 | pub const SO_WIFI_STATUS = 41; | ||
| 329 | pub const SCM_WIFI_STATUS = SO_WIFI_STATUS; | ||
| 330 | pub const SO_PEEK_OFF = 42; | ||
| 331 | pub const SO_NOFCS = 43; | ||
| 332 | pub const SO_LOCK_FILTER = 44; | ||
| 333 | pub const SO_SELECT_ERR_QUEUE = 45; | ||
| 334 | pub const SO_BUSY_POLL = 46; | ||
| 335 | pub const SO_MAX_PACING_RATE = 47; | ||
| 336 | pub const SO_BPF_EXTENSIONS = 48; | ||
| 337 | pub const SO_INCOMING_CPU = 49; | ||
| 338 | pub const SO_ATTACH_BPF = 50; | ||
| 339 | pub const SO_DETACH_BPF = SO_DETACH_FILTER; | ||
| 340 | pub const SO_ATTACH_REUSEPORT_CBPF = 51; | ||
| 341 | pub const SO_ATTACH_REUSEPORT_EBPF = 52; | ||
| 342 | pub const SO_CNX_ADVICE = 53; | ||
| 343 | pub const SCM_TIMESTAMPING_OPT_STATS = 54; | ||
| 344 | pub const SO_MEMINFO = 55; | ||
| 345 | pub const SO_INCOMING_NAPI_ID = 56; | ||
| 346 | pub const SO_COOKIE = 57; | ||
| 347 | pub const SCM_TIMESTAMPING_PKTINFO = 58; | ||
| 348 | pub const SO_PEERGROUPS = 59; | ||
| 349 | pub const SO_ZEROCOPY = 60; | ||
| 350 | |||
| 351 | pub const SOL_SOCKET = 1; | ||
| 352 | |||
| 353 | pub const SOL_IP = 0; | ||
| 354 | pub const SOL_IPV6 = 41; | ||
| 355 | pub const SOL_ICMPV6 = 58; | ||
| 356 | |||
| 357 | pub const SOL_RAW = 255; | ||
| 358 | pub const SOL_DECNET = 261; | ||
| 359 | pub const SOL_X25 = 262; | ||
| 360 | pub const SOL_PACKET = 263; | ||
| 361 | pub const SOL_ATM = 264; | ||
| 362 | pub const SOL_AAL = 265; | ||
| 363 | pub const SOL_IRDA = 266; | ||
| 364 | pub const SOL_NETBEUI = 267; | ||
| 365 | pub const SOL_LLC = 268; | ||
| 366 | pub const SOL_DCCP = 269; | ||
| 367 | pub const SOL_NETLINK = 270; | ||
| 368 | pub const SOL_TIPC = 271; | ||
| 369 | pub const SOL_RXRPC = 272; | ||
| 370 | pub const SOL_PPPOL2TP = 273; | ||
| 371 | pub const SOL_BLUETOOTH = 274; | ||
| 372 | pub const SOL_PNPIPE = 275; | ||
| 373 | pub const SOL_RDS = 276; | ||
| 374 | pub const SOL_IUCV = 277; | ||
| 375 | pub const SOL_CAIF = 278; | ||
| 376 | pub const SOL_ALG = 279; | ||
| 377 | pub const SOL_NFC = 280; | ||
| 378 | pub const SOL_KCM = 281; | ||
| 379 | pub const SOL_TLS = 282; | ||
| 380 | |||
| 381 | pub const SOMAXCONN = 128; | ||
| 382 | |||
| 383 | pub const MSG_OOB = 0x0001; | ||
| 384 | pub const MSG_PEEK = 0x0002; | ||
| 385 | pub const MSG_DONTROUTE = 0x0004; | ||
| 386 | pub const MSG_CTRUNC = 0x0008; | ||
| 387 | pub const MSG_PROXY = 0x0010; | ||
| 388 | pub const MSG_TRUNC = 0x0020; | ||
| 389 | pub const MSG_DONTWAIT = 0x0040; | ||
| 390 | pub const MSG_EOR = 0x0080; | ||
| 391 | pub const MSG_WAITALL = 0x0100; | ||
| 392 | pub const MSG_FIN = 0x0200; | ||
| 393 | pub const MSG_SYN = 0x0400; | ||
| 394 | pub const MSG_CONFIRM = 0x0800; | ||
| 395 | pub const MSG_RST = 0x1000; | ||
| 396 | pub const MSG_ERRQUEUE = 0x2000; | ||
| 397 | pub const MSG_NOSIGNAL = 0x4000; | ||
| 398 | pub const MSG_MORE = 0x8000; | ||
| 399 | pub const MSG_WAITFORONE = 0x10000; | ||
| 400 | pub const MSG_BATCH = 0x40000; | ||
| 401 | pub const MSG_ZEROCOPY = 0x4000000; | ||
| 402 | pub const MSG_FASTOPEN = 0x20000000; | ||
| 403 | pub const MSG_CMSG_CLOEXEC = 0x40000000; | ||
| 404 | |||
| 405 | pub const DT_UNKNOWN = 0; | ||
| 406 | pub const DT_FIFO = 1; | ||
| 407 | pub const DT_CHR = 2; | ||
| 408 | pub const DT_DIR = 4; | ||
| 409 | pub const DT_BLK = 6; | ||
| 410 | pub const DT_REG = 8; | ||
| 411 | pub const DT_LNK = 10; | ||
| 412 | pub const DT_SOCK = 12; | ||
| 413 | pub const DT_WHT = 14; | ||
| 414 | |||
| 415 | pub const TCGETS = 0x5401; | ||
| 416 | pub const TCSETS = 0x5402; | ||
| 417 | pub const TCSETSW = 0x5403; | ||
| 418 | pub const TCSETSF = 0x5404; | ||
| 419 | pub const TCGETA = 0x5405; | ||
| 420 | pub const TCSETA = 0x5406; | ||
| 421 | pub const TCSETAW = 0x5407; | ||
| 422 | pub const TCSETAF = 0x5408; | ||
| 423 | pub const TCSBRK = 0x5409; | ||
| 424 | pub const TCXONC = 0x540A; | ||
| 425 | pub const TCFLSH = 0x540B; | ||
| 426 | pub const TIOCEXCL = 0x540C; | ||
| 427 | pub const TIOCNXCL = 0x540D; | ||
| 428 | pub const TIOCSCTTY = 0x540E; | ||
| 429 | pub const TIOCGPGRP = 0x540F; | ||
| 430 | pub const TIOCSPGRP = 0x5410; | ||
| 431 | pub const TIOCOUTQ = 0x5411; | ||
| 432 | pub const TIOCSTI = 0x5412; | ||
| 433 | pub const TIOCGWINSZ = 0x5413; | ||
| 434 | pub const TIOCSWINSZ = 0x5414; | ||
| 435 | pub const TIOCMGET = 0x5415; | ||
| 436 | pub const TIOCMBIS = 0x5416; | ||
| 437 | pub const TIOCMBIC = 0x5417; | ||
| 438 | pub const TIOCMSET = 0x5418; | ||
| 439 | pub const TIOCGSOFTCAR = 0x5419; | ||
| 440 | pub const TIOCSSOFTCAR = 0x541A; | ||
| 441 | pub const FIONREAD = 0x541B; | ||
| 442 | pub const TIOCINQ = FIONREAD; | ||
| 443 | pub const TIOCLINUX = 0x541C; | ||
| 444 | pub const TIOCCONS = 0x541D; | ||
| 445 | pub const TIOCGSERIAL = 0x541E; | ||
| 446 | pub const TIOCSSERIAL = 0x541F; | ||
| 447 | pub const TIOCPKT = 0x5420; | ||
| 448 | pub const FIONBIO = 0x5421; | ||
| 449 | pub const TIOCNOTTY = 0x5422; | ||
| 450 | pub const TIOCSETD = 0x5423; | ||
| 451 | pub const TIOCGETD = 0x5424; | ||
| 452 | pub const TCSBRKP = 0x5425; | ||
| 453 | pub const TIOCSBRK = 0x5427; | ||
| 454 | pub const TIOCCBRK = 0x5428; | ||
| 455 | pub const TIOCGSID = 0x5429; | ||
| 456 | pub const TIOCGRS485 = 0x542E; | ||
| 457 | pub const TIOCSRS485 = 0x542F; | ||
| 458 | pub const TIOCGPTN = 0x80045430; | ||
| 459 | pub const TIOCSPTLCK = 0x40045431; | ||
| 460 | pub const TIOCGDEV = 0x80045432; | ||
| 461 | pub const TCGETX = 0x5432; | ||
| 462 | pub const TCSETX = 0x5433; | ||
| 463 | pub const TCSETXF = 0x5434; | ||
| 464 | pub const TCSETXW = 0x5435; | ||
| 465 | pub const TIOCSIG = 0x40045436; | ||
| 466 | pub const TIOCVHANGUP = 0x5437; | ||
| 467 | pub const TIOCGPKT = 0x80045438; | ||
| 468 | pub const TIOCGPTLCK = 0x80045439; | ||
| 469 | pub const TIOCGEXCL = 0x80045440; | ||
| 470 | |||
| 471 | pub const EPOLL_CLOEXEC = O_CLOEXEC; | ||
| 472 | |||
| 473 | pub const EPOLL_CTL_ADD = 1; | ||
| 474 | pub const EPOLL_CTL_DEL = 2; | ||
| 475 | pub const EPOLL_CTL_MOD = 3; | ||
| 476 | |||
| 477 | pub const EPOLLIN = 0x001; | ||
| 478 | pub const EPOLLPRI = 0x002; | ||
| 479 | pub const EPOLLOUT = 0x004; | ||
| 480 | pub const EPOLLRDNORM = 0x040; | ||
| 481 | pub const EPOLLRDBAND = 0x080; | ||
| 482 | pub const EPOLLWRNORM = 0x100; | ||
| 483 | pub const EPOLLWRBAND = 0x200; | ||
| 484 | pub const EPOLLMSG = 0x400; | ||
| 485 | pub const EPOLLERR = 0x008; | ||
| 486 | pub const EPOLLHUP = 0x010; | ||
| 487 | pub const EPOLLRDHUP = 0x2000; | ||
| 488 | pub const EPOLLEXCLUSIVE = (u32(1) << 28); | ||
| 489 | pub const EPOLLWAKEUP = (u32(1) << 29); | ||
| 490 | pub const EPOLLONESHOT = (u32(1) << 30); | ||
| 491 | pub const EPOLLET = (u32(1) << 31); | ||
| 492 | |||
| 493 | pub const CLOCK_REALTIME = 0; | ||
| 494 | pub const CLOCK_MONOTONIC = 1; | ||
| 495 | pub const CLOCK_PROCESS_CPUTIME_ID = 2; | ||
| 496 | pub const CLOCK_THREAD_CPUTIME_ID = 3; | ||
| 497 | pub const CLOCK_MONOTONIC_RAW = 4; | ||
| 498 | pub const CLOCK_REALTIME_COARSE = 5; | ||
| 499 | pub const CLOCK_MONOTONIC_COARSE = 6; | ||
| 500 | pub const CLOCK_BOOTTIME = 7; | ||
| 501 | pub const CLOCK_REALTIME_ALARM = 8; | ||
| 502 | pub const CLOCK_BOOTTIME_ALARM = 9; | ||
| 503 | pub const CLOCK_SGI_CYCLE = 10; | ||
| 504 | pub const CLOCK_TAI = 11; | ||
| 505 | |||
| 506 | pub const CSIGNAL = 0x000000ff; | ||
| 507 | pub const CLONE_VM = 0x00000100; | ||
| 508 | pub const CLONE_FS = 0x00000200; | ||
| 509 | pub const CLONE_FILES = 0x00000400; | ||
| 510 | pub const CLONE_SIGHAND = 0x00000800; | ||
| 511 | pub const CLONE_PTRACE = 0x00002000; | ||
| 512 | pub const CLONE_VFORK = 0x00004000; | ||
| 513 | pub const CLONE_PARENT = 0x00008000; | ||
| 514 | pub const CLONE_THREAD = 0x00010000; | ||
| 515 | pub const CLONE_NEWNS = 0x00020000; | ||
| 516 | pub const CLONE_SYSVSEM = 0x00040000; | ||
| 517 | pub const CLONE_SETTLS = 0x00080000; | ||
| 518 | pub const CLONE_PARENT_SETTID = 0x00100000; | ||
| 519 | pub const CLONE_CHILD_CLEARTID = 0x00200000; | ||
| 520 | pub const CLONE_DETACHED = 0x00400000; | ||
| 521 | pub const CLONE_UNTRACED = 0x00800000; | ||
| 522 | pub const CLONE_CHILD_SETTID = 0x01000000; | ||
| 523 | pub const CLONE_NEWCGROUP = 0x02000000; | ||
| 524 | pub const CLONE_NEWUTS = 0x04000000; | ||
| 525 | pub const CLONE_NEWIPC = 0x08000000; | ||
| 526 | pub const CLONE_NEWUSER = 0x10000000; | ||
| 527 | pub const CLONE_NEWPID = 0x20000000; | ||
| 528 | pub const CLONE_NEWNET = 0x40000000; | ||
| 529 | pub const CLONE_IO = 0x80000000; | ||
| 530 | |||
| 531 | pub const EFD_SEMAPHORE = 1; | ||
| 532 | pub const EFD_CLOEXEC = O_CLOEXEC; | ||
| 533 | pub const EFD_NONBLOCK = O_NONBLOCK; | ||
| 534 | |||
| 535 | pub const MS_RDONLY = 1; | ||
| 536 | pub const MS_NOSUID = 2; | ||
| 537 | pub const MS_NODEV = 4; | ||
| 538 | pub const MS_NOEXEC = 8; | ||
| 539 | pub const MS_SYNCHRONOUS = 16; | ||
| 540 | pub const MS_REMOUNT = 32; | ||
| 541 | pub const MS_MANDLOCK = 64; | ||
| 542 | pub const MS_DIRSYNC = 128; | ||
| 543 | pub const MS_NOATIME = 1024; | ||
| 544 | pub const MS_NODIRATIME = 2048; | ||
| 545 | pub const MS_BIND = 4096; | ||
| 546 | pub const MS_MOVE = 8192; | ||
| 547 | pub const MS_REC = 16384; | ||
| 548 | pub const MS_SILENT = 32768; | ||
| 549 | pub const MS_POSIXACL = (1 << 16); | ||
| 550 | pub const MS_UNBINDABLE = (1 << 17); | ||
| 551 | pub const MS_PRIVATE = (1 << 18); | ||
| 552 | pub const MS_SLAVE = (1 << 19); | ||
| 553 | pub const MS_SHARED = (1 << 20); | ||
| 554 | pub const MS_RELATIME = (1 << 21); | ||
| 555 | pub const MS_KERNMOUNT = (1 << 22); | ||
| 556 | pub const MS_I_VERSION = (1 << 23); | ||
| 557 | pub const MS_STRICTATIME = (1 << 24); | ||
| 558 | pub const MS_LAZYTIME = (1 << 25); | ||
| 559 | pub const MS_NOREMOTELOCK = (1 << 27); | ||
| 560 | pub const MS_NOSEC = (1 << 28); | ||
| 561 | pub const MS_BORN = (1 << 29); | ||
| 562 | pub const MS_ACTIVE = (1 << 30); | ||
| 563 | pub const MS_NOUSER = (1 << 31); | ||
| 564 | |||
| 565 | pub const MS_RMT_MASK = (MS_RDONLY | MS_SYNCHRONOUS | MS_MANDLOCK | MS_I_VERSION | MS_LAZYTIME); | ||
| 566 | |||
| 567 | pub const MS_MGC_VAL = 0xc0ed0000; | ||
| 568 | pub const MS_MGC_MSK = 0xffff0000; | ||
| 569 | |||
| 570 | pub const MNT_FORCE = 1; | ||
| 571 | pub const MNT_DETACH = 2; | ||
| 572 | pub const MNT_EXPIRE = 4; | ||
| 573 | pub const UMOUNT_NOFOLLOW = 8; | ||
| 574 | |||
| 575 | pub const IN_CLOEXEC = O_CLOEXEC; | ||
| 576 | pub const IN_NONBLOCK = O_NONBLOCK; | ||
| 577 | |||
| 578 | pub const IN_ACCESS = 0x00000001; | ||
| 579 | pub const IN_MODIFY = 0x00000002; | ||
| 580 | pub const IN_ATTRIB = 0x00000004; | ||
| 581 | pub const IN_CLOSE_WRITE = 0x00000008; | ||
| 582 | pub const IN_CLOSE_NOWRITE = 0x00000010; | ||
| 583 | pub const IN_CLOSE = IN_CLOSE_WRITE | IN_CLOSE_NOWRITE; | ||
| 584 | pub const IN_OPEN = 0x00000020; | ||
| 585 | pub const IN_MOVED_FROM = 0x00000040; | ||
| 586 | pub const IN_MOVED_TO = 0x00000080; | ||
| 587 | pub const IN_MOVE = IN_MOVED_FROM | IN_MOVED_TO; | ||
| 588 | pub const IN_CREATE = 0x00000100; | ||
| 589 | pub const IN_DELETE = 0x00000200; | ||
| 590 | pub const IN_DELETE_SELF = 0x00000400; | ||
| 591 | pub const IN_MOVE_SELF = 0x00000800; | ||
| 592 | pub const IN_ALL_EVENTS = 0x00000fff; | ||
| 593 | |||
| 594 | pub const IN_UNMOUNT = 0x00002000; | ||
| 595 | pub const IN_Q_OVERFLOW = 0x00004000; | ||
| 596 | pub const IN_IGNORED = 0x00008000; | ||
| 597 | |||
| 598 | pub const IN_ONLYDIR = 0x01000000; | ||
| 599 | pub const IN_DONT_FOLLOW = 0x02000000; | ||
| 600 | pub const IN_EXCL_UNLINK = 0x04000000; | ||
| 601 | pub const IN_MASK_ADD = 0x20000000; | ||
| 602 | |||
| 603 | pub const IN_ISDIR = 0x40000000; | ||
| 604 | pub const IN_ONESHOT = 0x80000000; | ||
| 605 | |||
| 606 | pub const S_IFMT = 0o170000; | ||
| 607 | |||
| 608 | pub const S_IFDIR = 0o040000; | ||
| 609 | pub const S_IFCHR = 0o020000; | ||
| 610 | pub const S_IFBLK = 0o060000; | ||
| 611 | pub const S_IFREG = 0o100000; | ||
| 612 | pub const S_IFIFO = 0o010000; | ||
| 613 | pub const S_IFLNK = 0o120000; | ||
| 614 | pub const S_IFSOCK = 0o140000; | ||
| 615 | |||
| 616 | pub const S_ISUID = 0o4000; | ||
| 617 | pub const S_ISGID = 0o2000; | ||
| 618 | pub const S_ISVTX = 0o1000; | ||
| 619 | pub const S_IRUSR = 0o400; | ||
| 620 | pub const S_IWUSR = 0o200; | ||
| 621 | pub const S_IXUSR = 0o100; | ||
| 622 | pub const S_IRWXU = 0o700; | ||
| 623 | pub const S_IRGRP = 0o040; | ||
| 624 | pub const S_IWGRP = 0o020; | ||
| 625 | pub const S_IXGRP = 0o010; | ||
| 626 | pub const S_IRWXG = 0o070; | ||
| 627 | pub const S_IROTH = 0o004; | ||
| 628 | pub const S_IWOTH = 0o002; | ||
| 629 | pub const S_IXOTH = 0o001; | ||
| 630 | pub const S_IRWXO = 0o007; | ||
| 631 | |||
| 632 | pub fn S_ISREG(m: u32) bool { | ||
| 633 | return m & S_IFMT == S_IFREG; | ||
| 634 | } | ||
| 635 | |||
| 636 | pub fn S_ISDIR(m: u32) bool { | ||
| 637 | return m & S_IFMT == S_IFDIR; | ||
| 638 | } | ||
| 639 | |||
| 640 | pub fn S_ISCHR(m: u32) bool { | ||
| 641 | return m & S_IFMT == S_IFCHR; | ||
| 642 | } | ||
| 643 | |||
| 644 | pub fn S_ISBLK(m: u32) bool { | ||
| 645 | return m & S_IFMT == S_IFBLK; | ||
| 646 | } | ||
| 647 | |||
| 648 | pub fn S_ISFIFO(m: u32) bool { | ||
| 649 | return m & S_IFMT == S_IFIFO; | ||
| 650 | } | ||
| 651 | |||
| 652 | pub fn S_ISLNK(m: u32) bool { | ||
| 653 | return m & S_IFMT == S_IFLNK; | ||
| 654 | } | ||
| 655 | |||
| 656 | pub fn S_ISSOCK(m: u32) bool { | ||
| 657 | return m & S_IFMT == S_IFSOCK; | ||
| 658 | } | ||
| 659 | |||
| 660 | pub const TFD_NONBLOCK = O_NONBLOCK; | ||
| 661 | pub const TFD_CLOEXEC = O_CLOEXEC; | ||
| 662 | |||
| 663 | pub const TFD_TIMER_ABSTIME = 1; | ||
| 664 | pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1); | ||
| 665 | |||
| 666 | pub fn WEXITSTATUS(s: u32) u32 { | ||
| 667 | return (s & 0xff00) >> 8; | ||
| 668 | } | ||
| 669 | pub fn WTERMSIG(s: u32) u32 { | ||
| 670 | return s & 0x7f; | ||
| 671 | } | ||
| 672 | pub fn WSTOPSIG(s: u32) u32 { | ||
| 673 | return WEXITSTATUS(s); | ||
| 674 | } | ||
| 675 | pub fn WIFEXITED(s: u32) bool { | ||
| 676 | return WTERMSIG(s) == 0; | ||
| 677 | } | ||
| 678 | pub fn WIFSTOPPED(s: u32) bool { | ||
| 679 | return @intCast(u16, ((s & 0xffff) *% 0x10001) >> 8) > 0x7f00; | ||
| 680 | } | ||
| 681 | pub fn WIFSIGNALED(s: u32) bool { | ||
| 682 | return (s & 0xffff) -% 1 < 0xff; | ||
| 683 | } | ||
| 684 | |||
| 685 | pub const winsize = extern struct { | ||
| 686 | ws_row: u16, | ||
| 687 | ws_col: u16, | ||
| 688 | ws_xpixel: u16, | ||
| 689 | ws_ypixel: u16, | ||
| 690 | }; | ||
| 691 | |||
| 692 | pub const NSIG = 65; | ||
| 693 | pub const sigset_t = [128 / @sizeOf(usize)]usize; | ||
| 694 | pub const all_mask = []u32{ 0xffffffff, 0xffffffff }; | ||
| 695 | pub const app_mask = []u32{ 0xfffffffc, 0x7fffffff }; | ||
| 696 | |||
| 697 | pub 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. | ||
| 705 | pub const Sigaction = struct { | ||
| 706 | handler: extern fn (i32) void, | ||
| 707 | mask: sigset_t, | ||
| 708 | flags: u32, | ||
| 709 | }; | ||
| 710 | |||
| 711 | pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize)); | ||
| 712 | pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0); | ||
| 713 | pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1); | ||
| 714 | pub const empty_sigset = []usize{0} ** sigset_t.len; | ||
| 715 | |||
| 716 | pub const in_port_t = u16; | ||
| 717 | pub const sa_family_t = u16; | ||
| 718 | pub const socklen_t = u32; | ||
| 719 | |||
| 720 | /// This intentionally only has ip4 and ip6 | ||
| 721 | pub const sockaddr = extern union { | ||
| 722 | in: sockaddr_in, | ||
| 723 | in6: sockaddr_in6, | ||
| 724 | }; | ||
| 725 | |||
| 726 | pub const sockaddr_in = extern struct { | ||
| 727 | family: sa_family_t, | ||
| 728 | port: in_port_t, | ||
| 729 | addr: u32, | ||
| 730 | zero: [8]u8, | ||
| 731 | }; | ||
| 732 | |||
| 733 | pub 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 | |||
| 741 | pub const sockaddr_un = extern struct { | ||
| 742 | family: sa_family_t, | ||
| 743 | path: [108]u8, | ||
| 744 | }; | ||
| 745 | |||
| 746 | pub const mmsghdr = extern struct { | ||
| 747 | msg_hdr: msghdr, | ||
| 748 | msg_len: u32, | ||
| 749 | }; | ||
| 750 | |||
| 751 | pub const mmsghdr_const = extern struct { | ||
| 752 | msg_hdr: msghdr_const, | ||
| 753 | msg_len: u32, | ||
| 754 | }; | ||
| 755 | |||
| 756 | pub 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 | ||
| 765 | pub const epoll_event = if (builtin.arch != .x86_64) | ||
| 766 | extern struct { | ||
| 767 | events: u32, | ||
| 768 | data: epoll_data, | ||
| 769 | } | ||
| 770 | else | ||
| 771 | packed struct { | ||
| 772 | events: u32, | ||
| 773 | data: epoll_data, | ||
| 774 | }; | ||
| 775 | |||
| 776 | pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330; | ||
| 777 | pub const _LINUX_CAPABILITY_U32S_1 = 1; | ||
| 778 | |||
| 779 | pub const _LINUX_CAPABILITY_VERSION_2 = 0x20071026; | ||
| 780 | pub const _LINUX_CAPABILITY_U32S_2 = 2; | ||
| 781 | |||
| 782 | pub const _LINUX_CAPABILITY_VERSION_3 = 0x20080522; | ||
| 783 | pub const _LINUX_CAPABILITY_U32S_3 = 2; | ||
| 784 | |||
| 785 | pub const VFS_CAP_REVISION_MASK = 0xFF000000; | ||
| 786 | pub const VFS_CAP_REVISION_SHIFT = 24; | ||
| 787 | pub const VFS_CAP_FLAGS_MASK = ~VFS_CAP_REVISION_MASK; | ||
| 788 | pub const VFS_CAP_FLAGS_EFFECTIVE = 0x000001; | ||
| 789 | |||
| 790 | pub const VFS_CAP_REVISION_1 = 0x01000000; | ||
| 791 | pub const VFS_CAP_U32_1 = 1; | ||
| 792 | pub const XATTR_CAPS_SZ_1 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_1); | ||
| 793 | |||
| 794 | pub const VFS_CAP_REVISION_2 = 0x02000000; | ||
| 795 | pub const VFS_CAP_U32_2 = 2; | ||
| 796 | pub const XATTR_CAPS_SZ_2 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_2); | ||
| 797 | |||
| 798 | pub const XATTR_CAPS_SZ = XATTR_CAPS_SZ_2; | ||
| 799 | pub const VFS_CAP_U32 = VFS_CAP_U32_2; | ||
| 800 | pub const VFS_CAP_REVISION = VFS_CAP_REVISION_2; | ||
| 801 | |||
| 802 | pub 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 | |||
| 814 | pub const CAP_CHOWN = 0; | ||
| 815 | pub const CAP_DAC_OVERRIDE = 1; | ||
| 816 | pub const CAP_DAC_READ_SEARCH = 2; | ||
| 817 | pub const CAP_FOWNER = 3; | ||
| 818 | pub const CAP_FSETID = 4; | ||
| 819 | pub const CAP_KILL = 5; | ||
| 820 | pub const CAP_SETGID = 6; | ||
| 821 | pub const CAP_SETUID = 7; | ||
| 822 | pub const CAP_SETPCAP = 8; | ||
| 823 | pub const CAP_LINUX_IMMUTABLE = 9; | ||
| 824 | pub const CAP_NET_BIND_SERVICE = 10; | ||
| 825 | pub const CAP_NET_BROADCAST = 11; | ||
| 826 | pub const CAP_NET_ADMIN = 12; | ||
| 827 | pub const CAP_NET_RAW = 13; | ||
| 828 | pub const CAP_IPC_LOCK = 14; | ||
| 829 | pub const CAP_IPC_OWNER = 15; | ||
| 830 | pub const CAP_SYS_MODULE = 16; | ||
| 831 | pub const CAP_SYS_RAWIO = 17; | ||
| 832 | pub const CAP_SYS_CHROOT = 18; | ||
| 833 | pub const CAP_SYS_PTRACE = 19; | ||
| 834 | pub const CAP_SYS_PACCT = 20; | ||
| 835 | pub const CAP_SYS_ADMIN = 21; | ||
| 836 | pub const CAP_SYS_BOOT = 22; | ||
| 837 | pub const CAP_SYS_NICE = 23; | ||
| 838 | pub const CAP_SYS_RESOURCE = 24; | ||
| 839 | pub const CAP_SYS_TIME = 25; | ||
| 840 | pub const CAP_SYS_TTY_CONFIG = 26; | ||
| 841 | pub const CAP_MKNOD = 27; | ||
| 842 | pub const CAP_LEASE = 28; | ||
| 843 | pub const CAP_AUDIT_WRITE = 29; | ||
| 844 | pub const CAP_AUDIT_CONTROL = 30; | ||
| 845 | pub const CAP_SETFCAP = 31; | ||
| 846 | pub const CAP_MAC_OVERRIDE = 32; | ||
| 847 | pub const CAP_MAC_ADMIN = 33; | ||
| 848 | pub const CAP_SYSLOG = 34; | ||
| 849 | pub const CAP_WAKE_ALARM = 35; | ||
| 850 | pub const CAP_BLOCK_SUSPEND = 36; | ||
| 851 | pub const CAP_AUDIT_READ = 37; | ||
| 852 | pub const CAP_LAST_CAP = CAP_AUDIT_READ; | ||
| 853 | |||
| 854 | pub fn cap_valid(u8: x) bool { | ||
| 855 | return x >= 0 and x <= CAP_LAST_CAP; | ||
| 856 | } | ||
| 857 | |||
| 858 | pub fn CAP_TO_MASK(cap: u8) u32 { | ||
| 859 | return u32(1) << u5(cap & 31); | ||
| 860 | } | ||
| 861 | |||
| 862 | pub fn CAP_TO_INDEX(cap: u8) u8 { | ||
| 863 | return cap >> 5; | ||
| 864 | } | ||
| 865 | |||
| 866 | pub const cap_t = extern struct { | ||
| 867 | hdrp: *cap_user_header_t, | ||
| 868 | datap: *cap_user_data_t, | ||
| 869 | }; | ||
| 870 | |||
| 871 | pub const cap_user_header_t = extern struct { | ||
| 872 | version: u32, | ||
| 873 | pid: usize, | ||
| 874 | }; | ||
| 875 | |||
| 876 | pub const cap_user_data_t = extern struct { | ||
| 877 | effective: u32, | ||
| 878 | permitted: u32, | ||
| 879 | inheritable: u32, | ||
| 880 | }; | ||
| 881 | |||
| 882 | pub const inotify_event = extern struct { | ||
| 883 | wd: i32, | ||
| 884 | mask: u32, | ||
| 885 | cookie: u32, | ||
| 886 | len: u32, | ||
| 887 | //name: [?]u8, | ||
| 888 | }; | ||
| 889 | |||
| 890 | pub 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 | |||
| 898 | pub 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 | |||
| 905 | pub const pthread_attr_t = extern struct { | ||
| 906 | __size: [56]u8, | ||
| 907 | __align: c_long, | ||
| 908 | }; | ||
| 909 | |||
| 910 | pub const CPU_SETSIZE = 128; | ||
| 911 | pub const cpu_set_t = [CPU_SETSIZE / @sizeOf(usize)]usize; | ||
| 912 | pub const cpu_count_t = @IntType(false, std.math.log2(CPU_SETSIZE * 8)); | ||
| 913 | |||
| 914 | pub 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 | |||
| 4 | const std = @import("../../std.zig"); | ||
| 5 | const linux = std.os.linux; | ||
| 6 | const socklen_t = linux.socklen_t; | ||
| 7 | const iovec = linux.iovec; | ||
| 8 | const iovec_const = linux.iovec_const; | ||
| 9 | |||
| 10 | pub const SYS_io_setup = 0; | ||
| 11 | pub const SYS_io_destroy = 1; | ||
| 12 | pub const SYS_io_submit = 2; | ||
| 13 | pub const SYS_io_cancel = 3; | ||
| 14 | pub const SYS_io_getevents = 4; | ||
| 15 | pub const SYS_setxattr = 5; | ||
| 16 | pub const SYS_lsetxattr = 6; | ||
| 17 | pub const SYS_fsetxattr = 7; | ||
| 18 | pub const SYS_getxattr = 8; | ||
| 19 | pub const SYS_lgetxattr = 9; | ||
| 20 | pub const SYS_fgetxattr = 10; | ||
| 21 | pub const SYS_listxattr = 11; | ||
| 22 | pub const SYS_llistxattr = 12; | ||
| 23 | pub const SYS_flistxattr = 13; | ||
| 24 | pub const SYS_removexattr = 14; | ||
| 25 | pub const SYS_lremovexattr = 15; | ||
| 26 | pub const SYS_fremovexattr = 16; | ||
| 27 | pub const SYS_getcwd = 17; | ||
| 28 | pub const SYS_lookup_dcookie = 18; | ||
| 29 | pub const SYS_eventfd2 = 19; | ||
| 30 | pub const SYS_epoll_create1 = 20; | ||
| 31 | pub const SYS_epoll_ctl = 21; | ||
| 32 | pub const SYS_epoll_pwait = 22; | ||
| 33 | pub const SYS_dup = 23; | ||
| 34 | pub const SYS_dup3 = 24; | ||
| 35 | pub const SYS_fcntl = 25; | ||
| 36 | pub const SYS_inotify_init1 = 26; | ||
| 37 | pub const SYS_inotify_add_watch = 27; | ||
| 38 | pub const SYS_inotify_rm_watch = 28; | ||
| 39 | pub const SYS_ioctl = 29; | ||
| 40 | pub const SYS_ioprio_set = 30; | ||
| 41 | pub const SYS_ioprio_get = 31; | ||
| 42 | pub const SYS_flock = 32; | ||
| 43 | pub const SYS_mknodat = 33; | ||
| 44 | pub const SYS_mkdirat = 34; | ||
| 45 | pub const SYS_unlinkat = 35; | ||
| 46 | pub const SYS_symlinkat = 36; | ||
| 47 | pub const SYS_linkat = 37; | ||
| 48 | pub const SYS_renameat = 38; | ||
| 49 | pub const SYS_umount2 = 39; | ||
| 50 | pub const SYS_mount = 40; | ||
| 51 | pub const SYS_pivot_root = 41; | ||
| 52 | pub const SYS_nfsservctl = 42; | ||
| 53 | pub const SYS_statfs = 43; | ||
| 54 | pub const SYS_fstatfs = 44; | ||
| 55 | pub const SYS_truncate = 45; | ||
| 56 | pub const SYS_ftruncate = 46; | ||
| 57 | pub const SYS_fallocate = 47; | ||
| 58 | pub const SYS_faccessat = 48; | ||
| 59 | pub const SYS_chdir = 49; | ||
| 60 | pub const SYS_fchdir = 50; | ||
| 61 | pub const SYS_chroot = 51; | ||
| 62 | pub const SYS_fchmod = 52; | ||
| 63 | pub const SYS_fchmodat = 53; | ||
| 64 | pub const SYS_fchownat = 54; | ||
| 65 | pub const SYS_fchown = 55; | ||
| 66 | pub const SYS_openat = 56; | ||
| 67 | pub const SYS_close = 57; | ||
| 68 | pub const SYS_vhangup = 58; | ||
| 69 | pub const SYS_pipe2 = 59; | ||
| 70 | pub const SYS_quotactl = 60; | ||
| 71 | pub const SYS_getdents64 = 61; | ||
| 72 | pub const SYS_lseek = 62; | ||
| 73 | pub const SYS_read = 63; | ||
| 74 | pub const SYS_write = 64; | ||
| 75 | pub const SYS_readv = 65; | ||
| 76 | pub const SYS_writev = 66; | ||
| 77 | pub const SYS_pread64 = 67; | ||
| 78 | pub const SYS_pwrite64 = 68; | ||
| 79 | pub const SYS_preadv = 69; | ||
| 80 | pub const SYS_pwritev = 70; | ||
| 81 | pub const SYS_pselect6 = 72; | ||
| 82 | pub const SYS_ppoll = 73; | ||
| 83 | pub const SYS_signalfd4 = 74; | ||
| 84 | pub const SYS_vmsplice = 75; | ||
| 85 | pub const SYS_splice = 76; | ||
| 86 | pub const SYS_tee = 77; | ||
| 87 | pub const SYS_readlinkat = 78; | ||
| 88 | pub const SYS_fstatat = 79; | ||
| 89 | pub const SYS_fstat = 80; | ||
| 90 | pub const SYS_sync = 81; | ||
| 91 | pub const SYS_fsync = 82; | ||
| 92 | pub const SYS_fdatasync = 83; | ||
| 93 | pub const SYS_sync_file_range2 = 84; | ||
| 94 | pub const SYS_sync_file_range = 84; | ||
| 95 | pub const SYS_timerfd_create = 85; | ||
| 96 | pub const SYS_timerfd_settime = 86; | ||
| 97 | pub const SYS_timerfd_gettime = 87; | ||
| 98 | pub const SYS_utimensat = 88; | ||
| 99 | pub const SYS_acct = 89; | ||
| 100 | pub const SYS_capget = 90; | ||
| 101 | pub const SYS_capset = 91; | ||
| 102 | pub const SYS_personality = 92; | ||
| 103 | pub const SYS_exit = 93; | ||
| 104 | pub const SYS_exit_group = 94; | ||
| 105 | pub const SYS_waitid = 95; | ||
| 106 | pub const SYS_set_tid_address = 96; | ||
| 107 | pub const SYS_unshare = 97; | ||
| 108 | pub const SYS_futex = 98; | ||
| 109 | pub const SYS_set_robust_list = 99; | ||
| 110 | pub const SYS_get_robust_list = 100; | ||
| 111 | pub const SYS_nanosleep = 101; | ||
| 112 | pub const SYS_getitimer = 102; | ||
| 113 | pub const SYS_setitimer = 103; | ||
| 114 | pub const SYS_kexec_load = 104; | ||
| 115 | pub const SYS_init_module = 105; | ||
| 116 | pub const SYS_delete_module = 106; | ||
| 117 | pub const SYS_timer_create = 107; | ||
| 118 | pub const SYS_timer_gettime = 108; | ||
| 119 | pub const SYS_timer_getoverrun = 109; | ||
| 120 | pub const SYS_timer_settime = 110; | ||
| 121 | pub const SYS_timer_delete = 111; | ||
| 122 | pub const SYS_clock_settime = 112; | ||
| 123 | pub const SYS_clock_gettime = 113; | ||
| 124 | pub const SYS_clock_getres = 114; | ||
| 125 | pub const SYS_clock_nanosleep = 115; | ||
| 126 | pub const SYS_syslog = 116; | ||
| 127 | pub const SYS_ptrace = 117; | ||
| 128 | pub const SYS_sched_setparam = 118; | ||
| 129 | pub const SYS_sched_setscheduler = 119; | ||
| 130 | pub const SYS_sched_getscheduler = 120; | ||
| 131 | pub const SYS_sched_getparam = 121; | ||
| 132 | pub const SYS_sched_setaffinity = 122; | ||
| 133 | pub const SYS_sched_getaffinity = 123; | ||
| 134 | pub const SYS_sched_yield = 124; | ||
| 135 | pub const SYS_sched_get_priority_max = 125; | ||
| 136 | pub const SYS_sched_get_priority_min = 126; | ||
| 137 | pub const SYS_sched_rr_get_interval = 127; | ||
| 138 | pub const SYS_restart_syscall = 128; | ||
| 139 | pub const SYS_kill = 129; | ||
| 140 | pub const SYS_tkill = 130; | ||
| 141 | pub const SYS_tgkill = 131; | ||
| 142 | pub const SYS_sigaltstack = 132; | ||
| 143 | pub const SYS_rt_sigsuspend = 133; | ||
| 144 | pub const SYS_rt_sigaction = 134; | ||
| 145 | pub const SYS_rt_sigprocmask = 135; | ||
| 146 | pub const SYS_rt_sigpending = 136; | ||
| 147 | pub const SYS_rt_sigtimedwait = 137; | ||
| 148 | pub const SYS_rt_sigqueueinfo = 138; | ||
| 149 | pub const SYS_rt_sigreturn = 139; | ||
| 150 | pub const SYS_setpriority = 140; | ||
| 151 | pub const SYS_getpriority = 141; | ||
| 152 | pub const SYS_reboot = 142; | ||
| 153 | pub const SYS_setregid = 143; | ||
| 154 | pub const SYS_setgid = 144; | ||
| 155 | pub const SYS_setreuid = 145; | ||
| 156 | pub const SYS_setuid = 146; | ||
| 157 | pub const SYS_setresuid = 147; | ||
| 158 | pub const SYS_getresuid = 148; | ||
| 159 | pub const SYS_setresgid = 149; | ||
| 160 | pub const SYS_getresgid = 150; | ||
| 161 | pub const SYS_setfsuid = 151; | ||
| 162 | pub const SYS_setfsgid = 152; | ||
| 163 | pub const SYS_times = 153; | ||
| 164 | pub const SYS_setpgid = 154; | ||
| 165 | pub const SYS_getpgid = 155; | ||
| 166 | pub const SYS_getsid = 156; | ||
| 167 | pub const SYS_setsid = 157; | ||
| 168 | pub const SYS_getgroups = 158; | ||
| 169 | pub const SYS_setgroups = 159; | ||
| 170 | pub const SYS_uname = 160; | ||
| 171 | pub const SYS_sethostname = 161; | ||
| 172 | pub const SYS_setdomainname = 162; | ||
| 173 | pub const SYS_getrlimit = 163; | ||
| 174 | pub const SYS_setrlimit = 164; | ||
| 175 | pub const SYS_getrusage = 165; | ||
| 176 | pub const SYS_umask = 166; | ||
| 177 | pub const SYS_prctl = 167; | ||
| 178 | pub const SYS_getcpu = 168; | ||
| 179 | pub const SYS_gettimeofday = 169; | ||
| 180 | pub const SYS_settimeofday = 170; | ||
| 181 | pub const SYS_adjtimex = 171; | ||
| 182 | pub const SYS_getpid = 172; | ||
| 183 | pub const SYS_getppid = 173; | ||
| 184 | pub const SYS_getuid = 174; | ||
| 185 | pub const SYS_geteuid = 175; | ||
| 186 | pub const SYS_getgid = 176; | ||
| 187 | pub const SYS_getegid = 177; | ||
| 188 | pub const SYS_gettid = 178; | ||
| 189 | pub const SYS_sysinfo = 179; | ||
| 190 | pub const SYS_mq_open = 180; | ||
| 191 | pub const SYS_mq_unlink = 181; | ||
| 192 | pub const SYS_mq_timedsend = 182; | ||
| 193 | pub const SYS_mq_timedreceive = 183; | ||
| 194 | pub const SYS_mq_notify = 184; | ||
| 195 | pub const SYS_mq_getsetattr = 185; | ||
| 196 | pub const SYS_msgget = 186; | ||
| 197 | pub const SYS_msgctl = 187; | ||
| 198 | pub const SYS_msgrcv = 188; | ||
| 199 | pub const SYS_msgsnd = 189; | ||
| 200 | pub const SYS_semget = 190; | ||
| 201 | pub const SYS_semctl = 191; | ||
| 202 | pub const SYS_semtimedop = 192; | ||
| 203 | pub const SYS_semop = 193; | ||
| 204 | pub const SYS_shmget = 194; | ||
| 205 | pub const SYS_shmctl = 195; | ||
| 206 | pub const SYS_shmat = 196; | ||
| 207 | pub const SYS_shmdt = 197; | ||
| 208 | pub const SYS_socket = 198; | ||
| 209 | pub const SYS_socketpair = 199; | ||
| 210 | pub const SYS_bind = 200; | ||
| 211 | pub const SYS_listen = 201; | ||
| 212 | pub const SYS_accept = 202; | ||
| 213 | pub const SYS_connect = 203; | ||
| 214 | pub const SYS_getsockname = 204; | ||
| 215 | pub const SYS_getpeername = 205; | ||
| 216 | pub const SYS_sendto = 206; | ||
| 217 | pub const SYS_recvfrom = 207; | ||
| 218 | pub const SYS_setsockopt = 208; | ||
| 219 | pub const SYS_getsockopt = 209; | ||
| 220 | pub const SYS_shutdown = 210; | ||
| 221 | pub const SYS_sendmsg = 211; | ||
| 222 | pub const SYS_recvmsg = 212; | ||
| 223 | pub const SYS_readahead = 213; | ||
| 224 | pub const SYS_brk = 214; | ||
| 225 | pub const SYS_munmap = 215; | ||
| 226 | pub const SYS_mremap = 216; | ||
| 227 | pub const SYS_add_key = 217; | ||
| 228 | pub const SYS_request_key = 218; | ||
| 229 | pub const SYS_keyctl = 219; | ||
| 230 | pub const SYS_clone = 220; | ||
| 231 | pub const SYS_execve = 221; | ||
| 232 | pub const SYS_mmap = 222; | ||
| 233 | pub const SYS_fadvise64 = 223; | ||
| 234 | pub const SYS_swapon = 224; | ||
| 235 | pub const SYS_swapoff = 225; | ||
| 236 | pub const SYS_mprotect = 226; | ||
| 237 | pub const SYS_msync = 227; | ||
| 238 | pub const SYS_mlock = 228; | ||
| 239 | pub const SYS_munlock = 229; | ||
| 240 | pub const SYS_mlockall = 230; | ||
| 241 | pub const SYS_munlockall = 231; | ||
| 242 | pub const SYS_mincore = 232; | ||
| 243 | pub const SYS_madvise = 233; | ||
| 244 | pub const SYS_remap_file_pages = 234; | ||
| 245 | pub const SYS_mbind = 235; | ||
| 246 | pub const SYS_get_mempolicy = 236; | ||
| 247 | pub const SYS_set_mempolicy = 237; | ||
| 248 | pub const SYS_migrate_pages = 238; | ||
| 249 | pub const SYS_move_pages = 239; | ||
| 250 | pub const SYS_rt_tgsigqueueinfo = 240; | ||
| 251 | pub const SYS_perf_event_open = 241; | ||
| 252 | pub const SYS_accept4 = 242; | ||
| 253 | pub const SYS_recvmmsg = 243; | ||
| 254 | pub const SYS_arch_specific_syscall = 244; | ||
| 255 | pub const SYS_wait4 = 260; | ||
| 256 | pub const SYS_prlimit64 = 261; | ||
| 257 | pub const SYS_fanotify_init = 262; | ||
| 258 | pub const SYS_fanotify_mark = 263; | ||
| 259 | pub const SYS_clock_adjtime = 266; | ||
| 260 | pub const SYS_syncfs = 267; | ||
| 261 | pub const SYS_setns = 268; | ||
| 262 | pub const SYS_sendmmsg = 269; | ||
| 263 | pub const SYS_process_vm_readv = 270; | ||
| 264 | pub const SYS_process_vm_writev = 271; | ||
| 265 | pub const SYS_kcmp = 272; | ||
| 266 | pub const SYS_finit_module = 273; | ||
| 267 | pub const SYS_sched_setattr = 274; | ||
| 268 | pub const SYS_sched_getattr = 275; | ||
| 269 | pub const SYS_renameat2 = 276; | ||
| 270 | pub const SYS_seccomp = 277; | ||
| 271 | pub const SYS_getrandom = 278; | ||
| 272 | pub const SYS_memfd_create = 279; | ||
| 273 | pub const SYS_bpf = 280; | ||
| 274 | pub const SYS_execveat = 281; | ||
| 275 | pub const SYS_userfaultfd = 282; | ||
| 276 | pub const SYS_membarrier = 283; | ||
| 277 | pub const SYS_mlock2 = 284; | ||
| 278 | pub const SYS_copy_file_range = 285; | ||
| 279 | pub const SYS_preadv2 = 286; | ||
| 280 | pub const SYS_pwritev2 = 287; | ||
| 281 | pub const SYS_pkey_mprotect = 288; | ||
| 282 | pub const SYS_pkey_alloc = 289; | ||
| 283 | pub const SYS_pkey_free = 290; | ||
| 284 | pub const SYS_statx = 291; | ||
| 285 | pub const SYS_io_pgetevents = 292; | ||
| 286 | pub const SYS_rseq = 293; | ||
| 287 | pub const SYS_kexec_file_load = 294; | ||
| 288 | pub const SYS_pidfd_send_signal = 424; | ||
| 289 | pub const SYS_io_uring_setup = 425; | ||
| 290 | pub const SYS_io_uring_enter = 426; | ||
| 291 | pub const SYS_io_uring_register = 427; | ||
| 292 | |||
| 293 | pub const O_CREAT = 0o100; | ||
| 294 | pub const O_EXCL = 0o200; | ||
| 295 | pub const O_NOCTTY = 0o400; | ||
| 296 | pub const O_TRUNC = 0o1000; | ||
| 297 | pub const O_APPEND = 0o2000; | ||
| 298 | pub const O_NONBLOCK = 0o4000; | ||
| 299 | pub const O_DSYNC = 0o10000; | ||
| 300 | pub const O_SYNC = 0o4010000; | ||
| 301 | pub const O_RSYNC = 0o4010000; | ||
| 302 | pub const O_DIRECTORY = 0o200000; | ||
| 303 | pub const O_NOFOLLOW = 0o400000; | ||
| 304 | pub const O_CLOEXEC = 0o2000000; | ||
| 305 | |||
| 306 | pub const O_ASYNC = 0o20000; | ||
| 307 | pub const O_DIRECT = 0o40000; | ||
| 308 | pub const O_LARGEFILE = 0; | ||
| 309 | pub const O_NOATIME = 0o1000000; | ||
| 310 | pub const O_PATH = 0o10000000; | ||
| 311 | pub const O_TMPFILE = 0o20200000; | ||
| 312 | pub const O_NDELAY = O_NONBLOCK; | ||
| 313 | |||
| 314 | pub const F_DUPFD = 0; | ||
| 315 | pub const F_GETFD = 1; | ||
| 316 | pub const F_SETFD = 2; | ||
| 317 | pub const F_GETFL = 3; | ||
| 318 | pub const F_SETFL = 4; | ||
| 319 | |||
| 320 | pub const F_SETOWN = 8; | ||
| 321 | pub const F_GETOWN = 9; | ||
| 322 | pub const F_SETSIG = 10; | ||
| 323 | pub const F_GETSIG = 11; | ||
| 324 | |||
| 325 | pub const F_GETLK = 5; | ||
| 326 | pub const F_SETLK = 6; | ||
| 327 | pub const F_SETLKW = 7; | ||
| 328 | |||
| 329 | pub const F_SETOWN_EX = 15; | ||
| 330 | pub const F_GETOWN_EX = 16; | ||
| 331 | |||
| 332 | pub const F_GETOWNER_UIDS = 17; | ||
| 333 | |||
| 334 | pub const AT_FDCWD = -100; | ||
| 335 | pub const AT_SYMLINK_NOFOLLOW = 0x100; | ||
| 336 | pub const AT_REMOVEDIR = 0x200; | ||
| 337 | pub const AT_SYMLINK_FOLLOW = 0x400; | ||
| 338 | pub const AT_NO_AUTOMOUNT = 0x800; | ||
| 339 | pub const AT_EMPTY_PATH = 0x1000; | ||
| 340 | |||
| 341 | pub const VDSO_USEFUL = true; | ||
| 342 | pub const VDSO_CGT_SYM = "__kernel_clock_gettime"; | ||
| 343 | pub const VDSO_CGT_VER = "LINUX_2.6.39"; | ||
| 344 | |||
| 345 | pub 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 | |||
| 357 | pub 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. | ||
| 370 | pub 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 | |||
| 390 | pub const timespec = extern struct { | ||
| 391 | tv_sec: isize, | ||
| 392 | tv_nsec: isize, | ||
| 393 | }; | ||
| 394 | |||
| 395 | pub const timeval = extern struct { | ||
| 396 | tv_sec: isize, | ||
| 397 | tv_usec: isize, | ||
| 398 | }; | ||
| 399 | |||
| 400 | pub const timezone = extern struct { | ||
| 401 | tz_minuteswest: i32, | ||
| 402 | tz_dsttime: i32, | ||
| 403 | }; | ||
| 404 | |||
| 405 | pub const Elf_Symndx = u32; | ||
std/os/bits/linux/errno.zig created+428| ... | @@ -0,0 +1,428 @@ | ||
| 1 | /// Operation not permitted | ||
| 2 | pub const EPERM = 1; | ||
| 3 | |||
| 4 | /// No such file or directory | ||
| 5 | pub const ENOENT = 2; | ||
| 6 | |||
| 7 | /// No such process | ||
| 8 | pub const ESRCH = 3; | ||
| 9 | |||
| 10 | /// Interrupted system call | ||
| 11 | pub const EINTR = 4; | ||
| 12 | |||
| 13 | /// I/O error | ||
| 14 | pub const EIO = 5; | ||
| 15 | |||
| 16 | /// No such device or address | ||
| 17 | pub const ENXIO = 6; | ||
| 18 | |||
| 19 | /// Arg list too long | ||
| 20 | pub const E2BIG = 7; | ||
| 21 | |||
| 22 | /// Exec format error | ||
| 23 | pub const ENOEXEC = 8; | ||
| 24 | |||
| 25 | /// Bad file number | ||
| 26 | pub const EBADF = 9; | ||
| 27 | |||
| 28 | /// No child processes | ||
| 29 | pub const ECHILD = 10; | ||
| 30 | |||
| 31 | /// Try again | ||
| 32 | pub const EAGAIN = 11; | ||
| 33 | |||
| 34 | /// Out of memory | ||
| 35 | pub const ENOMEM = 12; | ||
| 36 | |||
| 37 | /// Permission denied | ||
| 38 | pub const EACCES = 13; | ||
| 39 | |||
| 40 | /// Bad address | ||
| 41 | pub const EFAULT = 14; | ||
| 42 | |||
| 43 | /// Block device required | ||
| 44 | pub const ENOTBLK = 15; | ||
| 45 | |||
| 46 | /// Device or resource busy | ||
| 47 | pub const EBUSY = 16; | ||
| 48 | |||
| 49 | /// File exists | ||
| 50 | pub const EEXIST = 17; | ||
| 51 | |||
| 52 | /// Cross-device link | ||
| 53 | pub const EXDEV = 18; | ||
| 54 | |||
| 55 | /// No such device | ||
| 56 | pub const ENODEV = 19; | ||
| 57 | |||
| 58 | /// Not a directory | ||
| 59 | pub const ENOTDIR = 20; | ||
| 60 | |||
| 61 | /// Is a directory | ||
| 62 | pub const EISDIR = 21; | ||
| 63 | |||
| 64 | /// Invalid argument | ||
| 65 | pub const EINVAL = 22; | ||
| 66 | |||
| 67 | /// File table overflow | ||
| 68 | pub const ENFILE = 23; | ||
| 69 | |||
| 70 | /// Too many open files | ||
| 71 | pub const EMFILE = 24; | ||
| 72 | |||
| 73 | /// Not a typewriter | ||
| 74 | pub const ENOTTY = 25; | ||
| 75 | |||
| 76 | /// Text file busy | ||
| 77 | pub const ETXTBSY = 26; | ||
| 78 | |||
| 79 | /// File too large | ||
| 80 | pub const EFBIG = 27; | ||
| 81 | |||
| 82 | /// No space left on device | ||
| 83 | pub const ENOSPC = 28; | ||
| 84 | |||
| 85 | /// Illegal seek | ||
| 86 | pub const ESPIPE = 29; | ||
| 87 | |||
| 88 | /// Read-only file system | ||
| 89 | pub const EROFS = 30; | ||
| 90 | |||
| 91 | /// Too many links | ||
| 92 | pub const EMLINK = 31; | ||
| 93 | |||
| 94 | /// Broken pipe | ||
| 95 | pub const EPIPE = 32; | ||
| 96 | |||
| 97 | /// Math argument out of domain of func | ||
| 98 | pub const EDOM = 33; | ||
| 99 | |||
| 100 | /// Math result not representable | ||
| 101 | pub const ERANGE = 34; | ||
| 102 | |||
| 103 | /// Resource deadlock would occur | ||
| 104 | pub const EDEADLK = 35; | ||
| 105 | |||
| 106 | /// File name too long | ||
| 107 | pub const ENAMETOOLONG = 36; | ||
| 108 | |||
| 109 | /// No record locks available | ||
| 110 | pub const ENOLCK = 37; | ||
| 111 | |||
| 112 | /// Function not implemented | ||
| 113 | pub const ENOSYS = 38; | ||
| 114 | |||
| 115 | /// Directory not empty | ||
| 116 | pub const ENOTEMPTY = 39; | ||
| 117 | |||
| 118 | /// Too many symbolic links encountered | ||
| 119 | pub const ELOOP = 40; | ||
| 120 | |||
| 121 | /// Operation would block | ||
| 122 | pub const EWOULDBLOCK = EAGAIN; | ||
| 123 | |||
| 124 | /// No message of desired type | ||
| 125 | pub const ENOMSG = 42; | ||
| 126 | |||
| 127 | /// Identifier removed | ||
| 128 | pub const EIDRM = 43; | ||
| 129 | |||
| 130 | /// Channel number out of range | ||
| 131 | pub const ECHRNG = 44; | ||
| 132 | |||
| 133 | /// Level 2 not synchronized | ||
| 134 | pub const EL2NSYNC = 45; | ||
| 135 | |||
| 136 | /// Level 3 halted | ||
| 137 | pub const EL3HLT = 46; | ||
| 138 | |||
| 139 | /// Level 3 reset | ||
| 140 | pub const EL3RST = 47; | ||
| 141 | |||
| 142 | /// Link number out of range | ||
| 143 | pub const ELNRNG = 48; | ||
| 144 | |||
| 145 | /// Protocol driver not attached | ||
| 146 | pub const EUNATCH = 49; | ||
| 147 | |||
| 148 | /// No CSI structure available | ||
| 149 | pub const ENOCSI = 50; | ||
| 150 | |||
| 151 | /// Level 2 halted | ||
| 152 | pub const EL2HLT = 51; | ||
| 153 | |||
| 154 | /// Invalid exchange | ||
| 155 | pub const EBADE = 52; | ||
| 156 | |||
| 157 | /// Invalid request descriptor | ||
| 158 | pub const EBADR = 53; | ||
| 159 | |||
| 160 | /// Exchange full | ||
| 161 | pub const EXFULL = 54; | ||
| 162 | |||
| 163 | /// No anode | ||
| 164 | pub const ENOANO = 55; | ||
| 165 | |||
| 166 | /// Invalid request code | ||
| 167 | pub const EBADRQC = 56; | ||
| 168 | |||
| 169 | /// Invalid slot | ||
| 170 | pub const EBADSLT = 57; | ||
| 171 | |||
| 172 | /// Bad font file format | ||
| 173 | pub const EBFONT = 59; | ||
| 174 | |||
| 175 | /// Device not a stream | ||
| 176 | pub const ENOSTR = 60; | ||
| 177 | |||
| 178 | /// No data available | ||
| 179 | pub const ENODATA = 61; | ||
| 180 | |||
| 181 | /// Timer expired | ||
| 182 | pub const ETIME = 62; | ||
| 183 | |||
| 184 | /// Out of streams resources | ||
| 185 | pub const ENOSR = 63; | ||
| 186 | |||
| 187 | /// Machine is not on the network | ||
| 188 | pub const ENONET = 64; | ||
| 189 | |||
| 190 | /// Package not installed | ||
| 191 | pub const ENOPKG = 65; | ||
| 192 | |||
| 193 | /// Object is remote | ||
| 194 | pub const EREMOTE = 66; | ||
| 195 | |||
| 196 | /// Link has been severed | ||
| 197 | pub const ENOLINK = 67; | ||
| 198 | |||
| 199 | /// Advertise error | ||
| 200 | pub const EADV = 68; | ||
| 201 | |||
| 202 | /// Srmount error | ||
| 203 | pub const ESRMNT = 69; | ||
| 204 | |||
| 205 | /// Communication error on send | ||
| 206 | pub const ECOMM = 70; | ||
| 207 | |||
| 208 | /// Protocol error | ||
| 209 | pub const EPROTO = 71; | ||
| 210 | |||
| 211 | /// Multihop attempted | ||
| 212 | pub const EMULTIHOP = 72; | ||
| 213 | |||
| 214 | /// RFS specific error | ||
| 215 | pub const EDOTDOT = 73; | ||
| 216 | |||
| 217 | /// Not a data message | ||
| 218 | pub const EBADMSG = 74; | ||
| 219 | |||
| 220 | /// Value too large for defined data type | ||
| 221 | pub const EOVERFLOW = 75; | ||
| 222 | |||
| 223 | /// Name not unique on network | ||
| 224 | pub const ENOTUNIQ = 76; | ||
| 225 | |||
| 226 | /// File descriptor in bad state | ||
| 227 | pub const EBADFD = 77; | ||
| 228 | |||
| 229 | /// Remote address changed | ||
| 230 | pub const EREMCHG = 78; | ||
| 231 | |||
| 232 | /// Can not access a needed shared library | ||
| 233 | pub const ELIBACC = 79; | ||
| 234 | |||
| 235 | /// Accessing a corrupted shared library | ||
| 236 | pub const ELIBBAD = 80; | ||
| 237 | |||
| 238 | /// .lib section in a.out corrupted | ||
| 239 | pub const ELIBSCN = 81; | ||
| 240 | |||
| 241 | /// Attempting to link in too many shared libraries | ||
| 242 | pub const ELIBMAX = 82; | ||
| 243 | |||
| 244 | /// Cannot exec a shared library directly | ||
| 245 | pub const ELIBEXEC = 83; | ||
| 246 | |||
| 247 | /// Illegal byte sequence | ||
| 248 | pub const EILSEQ = 84; | ||
| 249 | |||
| 250 | /// Interrupted system call should be restarted | ||
| 251 | pub const ERESTART = 85; | ||
| 252 | |||
| 253 | /// Streams pipe error | ||
| 254 | pub const ESTRPIPE = 86; | ||
| 255 | |||
| 256 | /// Too many users | ||
| 257 | pub const EUSERS = 87; | ||
| 258 | |||
| 259 | /// Socket operation on non-socket | ||
| 260 | pub const ENOTSOCK = 88; | ||
| 261 | |||
| 262 | /// Destination address required | ||
| 263 | pub const EDESTADDRREQ = 89; | ||
| 264 | |||
| 265 | /// Message too long | ||
| 266 | pub const EMSGSIZE = 90; | ||
| 267 | |||
| 268 | /// Protocol wrong type for socket | ||
| 269 | pub const EPROTOTYPE = 91; | ||
| 270 | |||
| 271 | /// Protocol not available | ||
| 272 | pub const ENOPROTOOPT = 92; | ||
| 273 | |||
| 274 | /// Protocol not supported | ||
| 275 | pub const EPROTONOSUPPORT = 93; | ||
| 276 | |||
| 277 | /// Socket type not supported | ||
| 278 | pub const ESOCKTNOSUPPORT = 94; | ||
| 279 | |||
| 280 | /// Operation not supported on transport endpoint | ||
| 281 | pub const EOPNOTSUPP = 95; | ||
| 282 | pub const ENOTSUP = EOPNOTSUPP; | ||
| 283 | |||
| 284 | /// Protocol family not supported | ||
| 285 | pub const EPFNOSUPPORT = 96; | ||
| 286 | |||
| 287 | /// Address family not supported by protocol | ||
| 288 | pub const EAFNOSUPPORT = 97; | ||
| 289 | |||
| 290 | /// Address already in use | ||
| 291 | pub const EADDRINUSE = 98; | ||
| 292 | |||
| 293 | /// Cannot assign requested address | ||
| 294 | pub const EADDRNOTAVAIL = 99; | ||
| 295 | |||
| 296 | /// Network is down | ||
| 297 | pub const ENETDOWN = 100; | ||
| 298 | |||
| 299 | /// Network is unreachable | ||
| 300 | pub const ENETUNREACH = 101; | ||
| 301 | |||
| 302 | /// Network dropped connection because of reset | ||
| 303 | pub const ENETRESET = 102; | ||
| 304 | |||
| 305 | /// Software caused connection abort | ||
| 306 | pub const ECONNABORTED = 103; | ||
| 307 | |||
| 308 | /// Connection reset by peer | ||
| 309 | pub const ECONNRESET = 104; | ||
| 310 | |||
| 311 | /// No buffer space available | ||
| 312 | pub const ENOBUFS = 105; | ||
| 313 | |||
| 314 | /// Transport endpoint is already connected | ||
| 315 | pub const EISCONN = 106; | ||
| 316 | |||
| 317 | /// Transport endpoint is not connected | ||
| 318 | pub const ENOTCONN = 107; | ||
| 319 | |||
| 320 | /// Cannot send after transport endpoint shutdown | ||
| 321 | pub const ESHUTDOWN = 108; | ||
| 322 | |||
| 323 | /// Too many references: cannot splice | ||
| 324 | pub const ETOOMANYREFS = 109; | ||
| 325 | |||
| 326 | /// Connection timed out | ||
| 327 | pub const ETIMEDOUT = 110; | ||
| 328 | |||
| 329 | /// Connection refused | ||
| 330 | pub const ECONNREFUSED = 111; | ||
| 331 | |||
| 332 | /// Host is down | ||
| 333 | pub const EHOSTDOWN = 112; | ||
| 334 | |||
| 335 | /// No route to host | ||
| 336 | pub const EHOSTUNREACH = 113; | ||
| 337 | |||
| 338 | /// Operation already in progress | ||
| 339 | pub const EALREADY = 114; | ||
| 340 | |||
| 341 | /// Operation now in progress | ||
| 342 | pub const EINPROGRESS = 115; | ||
| 343 | |||
| 344 | /// Stale NFS file handle | ||
| 345 | pub const ESTALE = 116; | ||
| 346 | |||
| 347 | /// Structure needs cleaning | ||
| 348 | pub const EUCLEAN = 117; | ||
| 349 | |||
| 350 | /// Not a XENIX named type file | ||
| 351 | pub const ENOTNAM = 118; | ||
| 352 | |||
| 353 | /// No XENIX semaphores available | ||
| 354 | pub const ENAVAIL = 119; | ||
| 355 | |||
| 356 | /// Is a named type file | ||
| 357 | pub const EISNAM = 120; | ||
| 358 | |||
| 359 | /// Remote I/O error | ||
| 360 | pub const EREMOTEIO = 121; | ||
| 361 | |||
| 362 | /// Quota exceeded | ||
| 363 | pub const EDQUOT = 122; | ||
| 364 | |||
| 365 | /// No medium found | ||
| 366 | pub const ENOMEDIUM = 123; | ||
| 367 | |||
| 368 | /// Wrong medium type | ||
| 369 | pub const EMEDIUMTYPE = 124; | ||
| 370 | |||
| 371 | // nameserver query return codes | ||
| 372 | |||
| 373 | /// DNS server returned answer with no data | ||
| 374 | pub const ENSROK = 0; | ||
| 375 | |||
| 376 | /// DNS server returned answer with no data | ||
| 377 | pub const ENSRNODATA = 160; | ||
| 378 | |||
| 379 | /// DNS server claims query was misformatted | ||
| 380 | pub const ENSRFORMERR = 161; | ||
| 381 | |||
| 382 | /// DNS server returned general failure | ||
| 383 | pub const ENSRSERVFAIL = 162; | ||
| 384 | |||
| 385 | /// Domain name not found | ||
| 386 | pub const ENSRNOTFOUND = 163; | ||
| 387 | |||
| 388 | /// DNS server does not implement requested operation | ||
| 389 | pub const ENSRNOTIMP = 164; | ||
| 390 | |||
| 391 | /// DNS server refused query | ||
| 392 | pub const ENSRREFUSED = 165; | ||
| 393 | |||
| 394 | /// Misformatted DNS query | ||
| 395 | pub const ENSRBADQUERY = 166; | ||
| 396 | |||
| 397 | /// Misformatted domain name | ||
| 398 | pub const ENSRBADNAME = 167; | ||
| 399 | |||
| 400 | /// Unsupported address family | ||
| 401 | pub const ENSRBADFAMILY = 168; | ||
| 402 | |||
| 403 | /// Misformatted DNS reply | ||
| 404 | pub const ENSRBADRESP = 169; | ||
| 405 | |||
| 406 | /// Could not contact DNS servers | ||
| 407 | pub const ENSRCONNREFUSED = 170; | ||
| 408 | |||
| 409 | /// Timeout while contacting DNS servers | ||
| 410 | pub const ENSRTIMEOUT = 171; | ||
| 411 | |||
| 412 | /// End of file | ||
| 413 | pub const ENSROF = 172; | ||
| 414 | |||
| 415 | /// Error reading file | ||
| 416 | pub const ENSRFILE = 173; | ||
| 417 | |||
| 418 | /// Out of memory | ||
| 419 | pub const ENSRNOMEM = 174; | ||
| 420 | |||
| 421 | /// Application terminated lookup | ||
| 422 | pub const ENSRDESTRUCTION = 175; | ||
| 423 | |||
| 424 | /// Domain name is too long | ||
| 425 | pub const ENSRQUERYDOMAINTOOLONG = 176; | ||
| 426 | |||
| 427 | /// Domain name is too long | ||
| 428 | pub 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. | ||
| 2 | const std = @import("../../../std.zig"); | ||
| 3 | |||
| 4 | const linux = std.os.linux; | ||
| 5 | const sockaddr = linux.sockaddr; | ||
| 6 | const socklen_t = linux.socklen_t; | ||
| 7 | const iovec = linux.iovec; | ||
| 8 | const iovec_const = linux.iovec_const; | ||
| 9 | |||
| 10 | pub const SYS_read = 0; | ||
| 11 | pub const SYS_write = 1; | ||
| 12 | pub const SYS_open = 2; | ||
| 13 | pub const SYS_close = 3; | ||
| 14 | pub const SYS_stat = 4; | ||
| 15 | pub const SYS_fstat = 5; | ||
| 16 | pub const SYS_lstat = 6; | ||
| 17 | pub const SYS_poll = 7; | ||
| 18 | pub const SYS_lseek = 8; | ||
| 19 | pub const SYS_mmap = 9; | ||
| 20 | pub const SYS_mprotect = 10; | ||
| 21 | pub const SYS_munmap = 11; | ||
| 22 | pub const SYS_brk = 12; | ||
| 23 | pub const SYS_rt_sigaction = 13; | ||
| 24 | pub const SYS_rt_sigprocmask = 14; | ||
| 25 | pub const SYS_rt_sigreturn = 15; | ||
| 26 | pub const SYS_ioctl = 16; | ||
| 27 | pub const SYS_pread = 17; | ||
| 28 | pub const SYS_pwrite = 18; | ||
| 29 | pub const SYS_readv = 19; | ||
| 30 | pub const SYS_writev = 20; | ||
| 31 | pub const SYS_access = 21; | ||
| 32 | pub const SYS_pipe = 22; | ||
| 33 | pub const SYS_select = 23; | ||
| 34 | pub const SYS_sched_yield = 24; | ||
| 35 | pub const SYS_mremap = 25; | ||
| 36 | pub const SYS_msync = 26; | ||
| 37 | pub const SYS_mincore = 27; | ||
| 38 | pub const SYS_madvise = 28; | ||
| 39 | pub const SYS_shmget = 29; | ||
| 40 | pub const SYS_shmat = 30; | ||
| 41 | pub const SYS_shmctl = 31; | ||
| 42 | pub const SYS_dup = 32; | ||
| 43 | pub const SYS_dup2 = 33; | ||
| 44 | pub const SYS_pause = 34; | ||
| 45 | pub const SYS_nanosleep = 35; | ||
| 46 | pub const SYS_getitimer = 36; | ||
| 47 | pub const SYS_alarm = 37; | ||
| 48 | pub const SYS_setitimer = 38; | ||
| 49 | pub const SYS_getpid = 39; | ||
| 50 | pub const SYS_sendfile = 40; | ||
| 51 | pub const SYS_socket = 41; | ||
| 52 | pub const SYS_connect = 42; | ||
| 53 | pub const SYS_accept = 43; | ||
| 54 | pub const SYS_sendto = 44; | ||
| 55 | pub const SYS_recvfrom = 45; | ||
| 56 | pub const SYS_sendmsg = 46; | ||
| 57 | pub const SYS_recvmsg = 47; | ||
| 58 | pub const SYS_shutdown = 48; | ||
| 59 | pub const SYS_bind = 49; | ||
| 60 | pub const SYS_listen = 50; | ||
| 61 | pub const SYS_getsockname = 51; | ||
| 62 | pub const SYS_getpeername = 52; | ||
| 63 | pub const SYS_socketpair = 53; | ||
| 64 | pub const SYS_setsockopt = 54; | ||
| 65 | pub const SYS_getsockopt = 55; | ||
| 66 | pub const SYS_clone = 56; | ||
| 67 | pub const SYS_fork = 57; | ||
| 68 | pub const SYS_vfork = 58; | ||
| 69 | pub const SYS_execve = 59; | ||
| 70 | pub const SYS_exit = 60; | ||
| 71 | pub const SYS_wait4 = 61; | ||
| 72 | pub const SYS_kill = 62; | ||
| 73 | pub const SYS_uname = 63; | ||
| 74 | pub const SYS_semget = 64; | ||
| 75 | pub const SYS_semop = 65; | ||
| 76 | pub const SYS_semctl = 66; | ||
| 77 | pub const SYS_shmdt = 67; | ||
| 78 | pub const SYS_msgget = 68; | ||
| 79 | pub const SYS_msgsnd = 69; | ||
| 80 | pub const SYS_msgrcv = 70; | ||
| 81 | pub const SYS_msgctl = 71; | ||
| 82 | pub const SYS_fcntl = 72; | ||
| 83 | pub const SYS_flock = 73; | ||
| 84 | pub const SYS_fsync = 74; | ||
| 85 | pub const SYS_fdatasync = 75; | ||
| 86 | pub const SYS_truncate = 76; | ||
| 87 | pub const SYS_ftruncate = 77; | ||
| 88 | pub const SYS_getdents = 78; | ||
| 89 | pub const SYS_getcwd = 79; | ||
| 90 | pub const SYS_chdir = 80; | ||
| 91 | pub const SYS_fchdir = 81; | ||
| 92 | pub const SYS_rename = 82; | ||
| 93 | pub const SYS_mkdir = 83; | ||
| 94 | pub const SYS_rmdir = 84; | ||
| 95 | pub const SYS_creat = 85; | ||
| 96 | pub const SYS_link = 86; | ||
| 97 | pub const SYS_unlink = 87; | ||
| 98 | pub const SYS_symlink = 88; | ||
| 99 | pub const SYS_readlink = 89; | ||
| 100 | pub const SYS_chmod = 90; | ||
| 101 | pub const SYS_fchmod = 91; | ||
| 102 | pub const SYS_chown = 92; | ||
| 103 | pub const SYS_fchown = 93; | ||
| 104 | pub const SYS_lchown = 94; | ||
| 105 | pub const SYS_umask = 95; | ||
| 106 | pub const SYS_gettimeofday = 96; | ||
| 107 | pub const SYS_getrlimit = 97; | ||
| 108 | pub const SYS_getrusage = 98; | ||
| 109 | pub const SYS_sysinfo = 99; | ||
| 110 | pub const SYS_times = 100; | ||
| 111 | pub const SYS_ptrace = 101; | ||
| 112 | pub const SYS_getuid = 102; | ||
| 113 | pub const SYS_syslog = 103; | ||
| 114 | pub const SYS_getgid = 104; | ||
| 115 | pub const SYS_setuid = 105; | ||
| 116 | pub const SYS_setgid = 106; | ||
| 117 | pub const SYS_geteuid = 107; | ||
| 118 | pub const SYS_getegid = 108; | ||
| 119 | pub const SYS_setpgid = 109; | ||
| 120 | pub const SYS_getppid = 110; | ||
| 121 | pub const SYS_getpgrp = 111; | ||
| 122 | pub const SYS_setsid = 112; | ||
| 123 | pub const SYS_setreuid = 113; | ||
| 124 | pub const SYS_setregid = 114; | ||
| 125 | pub const SYS_getgroups = 115; | ||
| 126 | pub const SYS_setgroups = 116; | ||
| 127 | pub const SYS_setresuid = 117; | ||
| 128 | pub const SYS_getresuid = 118; | ||
| 129 | pub const SYS_setresgid = 119; | ||
| 130 | pub const SYS_getresgid = 120; | ||
| 131 | pub const SYS_getpgid = 121; | ||
| 132 | pub const SYS_setfsuid = 122; | ||
| 133 | pub const SYS_setfsgid = 123; | ||
| 134 | pub const SYS_getsid = 124; | ||
| 135 | pub const SYS_capget = 125; | ||
| 136 | pub const SYS_capset = 126; | ||
| 137 | pub const SYS_rt_sigpending = 127; | ||
| 138 | pub const SYS_rt_sigtimedwait = 128; | ||
| 139 | pub const SYS_rt_sigqueueinfo = 129; | ||
| 140 | pub const SYS_rt_sigsuspend = 130; | ||
| 141 | pub const SYS_sigaltstack = 131; | ||
| 142 | pub const SYS_utime = 132; | ||
| 143 | pub const SYS_mknod = 133; | ||
| 144 | pub const SYS_uselib = 134; | ||
| 145 | pub const SYS_personality = 135; | ||
| 146 | pub const SYS_ustat = 136; | ||
| 147 | pub const SYS_statfs = 137; | ||
| 148 | pub const SYS_fstatfs = 138; | ||
| 149 | pub const SYS_sysfs = 139; | ||
| 150 | pub const SYS_getpriority = 140; | ||
| 151 | pub const SYS_setpriority = 141; | ||
| 152 | pub const SYS_sched_setparam = 142; | ||
| 153 | pub const SYS_sched_getparam = 143; | ||
| 154 | pub const SYS_sched_setscheduler = 144; | ||
| 155 | pub const SYS_sched_getscheduler = 145; | ||
| 156 | pub const SYS_sched_get_priority_max = 146; | ||
| 157 | pub const SYS_sched_get_priority_min = 147; | ||
| 158 | pub const SYS_sched_rr_get_interval = 148; | ||
| 159 | pub const SYS_mlock = 149; | ||
| 160 | pub const SYS_munlock = 150; | ||
| 161 | pub const SYS_mlockall = 151; | ||
| 162 | pub const SYS_munlockall = 152; | ||
| 163 | pub const SYS_vhangup = 153; | ||
| 164 | pub const SYS_modify_ldt = 154; | ||
| 165 | pub const SYS_pivot_root = 155; | ||
| 166 | pub const SYS__sysctl = 156; | ||
| 167 | pub const SYS_prctl = 157; | ||
| 168 | pub const SYS_arch_prctl = 158; | ||
| 169 | pub const SYS_adjtimex = 159; | ||
| 170 | pub const SYS_setrlimit = 160; | ||
| 171 | pub const SYS_chroot = 161; | ||
| 172 | pub const SYS_sync = 162; | ||
| 173 | pub const SYS_acct = 163; | ||
| 174 | pub const SYS_settimeofday = 164; | ||
| 175 | pub const SYS_mount = 165; | ||
| 176 | pub const SYS_umount2 = 166; | ||
| 177 | pub const SYS_swapon = 167; | ||
| 178 | pub const SYS_swapoff = 168; | ||
| 179 | pub const SYS_reboot = 169; | ||
| 180 | pub const SYS_sethostname = 170; | ||
| 181 | pub const SYS_setdomainname = 171; | ||
| 182 | pub const SYS_iopl = 172; | ||
| 183 | pub const SYS_ioperm = 173; | ||
| 184 | pub const SYS_create_module = 174; | ||
| 185 | pub const SYS_init_module = 175; | ||
| 186 | pub const SYS_delete_module = 176; | ||
| 187 | pub const SYS_get_kernel_syms = 177; | ||
| 188 | pub const SYS_query_module = 178; | ||
| 189 | pub const SYS_quotactl = 179; | ||
| 190 | pub const SYS_nfsservctl = 180; | ||
| 191 | pub const SYS_getpmsg = 181; | ||
| 192 | pub const SYS_putpmsg = 182; | ||
| 193 | pub const SYS_afs_syscall = 183; | ||
| 194 | pub const SYS_tuxcall = 184; | ||
| 195 | pub const SYS_security = 185; | ||
| 196 | pub const SYS_gettid = 186; | ||
| 197 | pub const SYS_readahead = 187; | ||
| 198 | pub const SYS_setxattr = 188; | ||
| 199 | pub const SYS_lsetxattr = 189; | ||
| 200 | pub const SYS_fsetxattr = 190; | ||
| 201 | pub const SYS_getxattr = 191; | ||
| 202 | pub const SYS_lgetxattr = 192; | ||
| 203 | pub const SYS_fgetxattr = 193; | ||
| 204 | pub const SYS_listxattr = 194; | ||
| 205 | pub const SYS_llistxattr = 195; | ||
| 206 | pub const SYS_flistxattr = 196; | ||
| 207 | pub const SYS_removexattr = 197; | ||
| 208 | pub const SYS_lremovexattr = 198; | ||
| 209 | pub const SYS_fremovexattr = 199; | ||
| 210 | pub const SYS_tkill = 200; | ||
| 211 | pub const SYS_time = 201; | ||
| 212 | pub const SYS_futex = 202; | ||
| 213 | pub const SYS_sched_setaffinity = 203; | ||
| 214 | pub const SYS_sched_getaffinity = 204; | ||
| 215 | pub const SYS_set_thread_area = 205; | ||
| 216 | pub const SYS_io_setup = 206; | ||
| 217 | pub const SYS_io_destroy = 207; | ||
| 218 | pub const SYS_io_getevents = 208; | ||
| 219 | pub const SYS_io_submit = 209; | ||
| 220 | pub const SYS_io_cancel = 210; | ||
| 221 | pub const SYS_get_thread_area = 211; | ||
| 222 | pub const SYS_lookup_dcookie = 212; | ||
| 223 | pub const SYS_epoll_create = 213; | ||
| 224 | pub const SYS_epoll_ctl_old = 214; | ||
| 225 | pub const SYS_epoll_wait_old = 215; | ||
| 226 | pub const SYS_remap_file_pages = 216; | ||
| 227 | pub const SYS_getdents64 = 217; | ||
| 228 | pub const SYS_set_tid_address = 218; | ||
| 229 | pub const SYS_restart_syscall = 219; | ||
| 230 | pub const SYS_semtimedop = 220; | ||
| 231 | pub const SYS_fadvise64 = 221; | ||
| 232 | pub const SYS_timer_create = 222; | ||
| 233 | pub const SYS_timer_settime = 223; | ||
| 234 | pub const SYS_timer_gettime = 224; | ||
| 235 | pub const SYS_timer_getoverrun = 225; | ||
| 236 | pub const SYS_timer_delete = 226; | ||
| 237 | pub const SYS_clock_settime = 227; | ||
| 238 | pub const SYS_clock_gettime = 228; | ||
| 239 | pub const SYS_clock_getres = 229; | ||
| 240 | pub const SYS_clock_nanosleep = 230; | ||
| 241 | pub const SYS_exit_group = 231; | ||
| 242 | pub const SYS_epoll_wait = 232; | ||
| 243 | pub const SYS_epoll_ctl = 233; | ||
| 244 | pub const SYS_tgkill = 234; | ||
| 245 | pub const SYS_utimes = 235; | ||
| 246 | pub const SYS_vserver = 236; | ||
| 247 | pub const SYS_mbind = 237; | ||
| 248 | pub const SYS_set_mempolicy = 238; | ||
| 249 | pub const SYS_get_mempolicy = 239; | ||
| 250 | pub const SYS_mq_open = 240; | ||
| 251 | pub const SYS_mq_unlink = 241; | ||
| 252 | pub const SYS_mq_timedsend = 242; | ||
| 253 | pub const SYS_mq_timedreceive = 243; | ||
| 254 | pub const SYS_mq_notify = 244; | ||
| 255 | pub const SYS_mq_getsetattr = 245; | ||
| 256 | pub const SYS_kexec_load = 246; | ||
| 257 | pub const SYS_waitid = 247; | ||
| 258 | pub const SYS_add_key = 248; | ||
| 259 | pub const SYS_request_key = 249; | ||
| 260 | pub const SYS_keyctl = 250; | ||
| 261 | pub const SYS_ioprio_set = 251; | ||
| 262 | pub const SYS_ioprio_get = 252; | ||
| 263 | pub const SYS_inotify_init = 253; | ||
| 264 | pub const SYS_inotify_add_watch = 254; | ||
| 265 | pub const SYS_inotify_rm_watch = 255; | ||
| 266 | pub const SYS_migrate_pages = 256; | ||
| 267 | pub const SYS_openat = 257; | ||
| 268 | pub const SYS_mkdirat = 258; | ||
| 269 | pub const SYS_mknodat = 259; | ||
| 270 | pub const SYS_fchownat = 260; | ||
| 271 | pub const SYS_futimesat = 261; | ||
| 272 | pub const SYS_newfstatat = 262; | ||
| 273 | pub const SYS_fstatat = 262; | ||
| 274 | pub const SYS_unlinkat = 263; | ||
| 275 | pub const SYS_renameat = 264; | ||
| 276 | pub const SYS_linkat = 265; | ||
| 277 | pub const SYS_symlinkat = 266; | ||
| 278 | pub const SYS_readlinkat = 267; | ||
| 279 | pub const SYS_fchmodat = 268; | ||
| 280 | pub const SYS_faccessat = 269; | ||
| 281 | pub const SYS_pselect6 = 270; | ||
| 282 | pub const SYS_ppoll = 271; | ||
| 283 | pub const SYS_unshare = 272; | ||
| 284 | pub const SYS_set_robust_list = 273; | ||
| 285 | pub const SYS_get_robust_list = 274; | ||
| 286 | pub const SYS_splice = 275; | ||
| 287 | pub const SYS_tee = 276; | ||
| 288 | pub const SYS_sync_file_range = 277; | ||
| 289 | pub const SYS_vmsplice = 278; | ||
| 290 | pub const SYS_move_pages = 279; | ||
| 291 | pub const SYS_utimensat = 280; | ||
| 292 | pub const SYS_epoll_pwait = 281; | ||
| 293 | pub const SYS_signalfd = 282; | ||
| 294 | pub const SYS_timerfd_create = 283; | ||
| 295 | pub const SYS_eventfd = 284; | ||
| 296 | pub const SYS_fallocate = 285; | ||
| 297 | pub const SYS_timerfd_settime = 286; | ||
| 298 | pub const SYS_timerfd_gettime = 287; | ||
| 299 | pub const SYS_accept4 = 288; | ||
| 300 | pub const SYS_signalfd4 = 289; | ||
| 301 | pub const SYS_eventfd2 = 290; | ||
| 302 | pub const SYS_epoll_create1 = 291; | ||
| 303 | pub const SYS_dup3 = 292; | ||
| 304 | pub const SYS_pipe2 = 293; | ||
| 305 | pub const SYS_inotify_init1 = 294; | ||
| 306 | pub const SYS_preadv = 295; | ||
| 307 | pub const SYS_pwritev = 296; | ||
| 308 | pub const SYS_rt_tgsigqueueinfo = 297; | ||
| 309 | pub const SYS_perf_event_open = 298; | ||
| 310 | pub const SYS_recvmmsg = 299; | ||
| 311 | pub const SYS_fanotify_init = 300; | ||
| 312 | pub const SYS_fanotify_mark = 301; | ||
| 313 | pub const SYS_prlimit64 = 302; | ||
| 314 | pub const SYS_name_to_handle_at = 303; | ||
| 315 | pub const SYS_open_by_handle_at = 304; | ||
| 316 | pub const SYS_clock_adjtime = 305; | ||
| 317 | pub const SYS_syncfs = 306; | ||
| 318 | pub const SYS_sendmmsg = 307; | ||
| 319 | pub const SYS_setns = 308; | ||
| 320 | pub const SYS_getcpu = 309; | ||
| 321 | pub const SYS_process_vm_readv = 310; | ||
| 322 | pub const SYS_process_vm_writev = 311; | ||
| 323 | pub const SYS_kcmp = 312; | ||
| 324 | pub const SYS_finit_module = 313; | ||
| 325 | pub const SYS_sched_setattr = 314; | ||
| 326 | pub const SYS_sched_getattr = 315; | ||
| 327 | pub const SYS_renameat2 = 316; | ||
| 328 | pub const SYS_seccomp = 317; | ||
| 329 | pub const SYS_getrandom = 318; | ||
| 330 | pub const SYS_memfd_create = 319; | ||
| 331 | pub const SYS_kexec_file_load = 320; | ||
| 332 | pub const SYS_bpf = 321; | ||
| 333 | pub const SYS_execveat = 322; | ||
| 334 | pub const SYS_userfaultfd = 323; | ||
| 335 | pub const SYS_membarrier = 324; | ||
| 336 | pub const SYS_mlock2 = 325; | ||
| 337 | pub const SYS_copy_file_range = 326; | ||
| 338 | pub const SYS_preadv2 = 327; | ||
| 339 | pub const SYS_pwritev2 = 328; | ||
| 340 | pub const SYS_pkey_mprotect = 329; | ||
| 341 | pub const SYS_pkey_alloc = 330; | ||
| 342 | pub const SYS_pkey_free = 331; | ||
| 343 | pub const SYS_statx = 332; | ||
| 344 | pub const SYS_io_pgetevents = 333; | ||
| 345 | pub const SYS_rseq = 334; | ||
| 346 | pub const SYS_pidfd_send_signal = 424; | ||
| 347 | pub const SYS_io_uring_setup = 425; | ||
| 348 | pub const SYS_io_uring_enter = 426; | ||
| 349 | pub const SYS_io_uring_register = 427; | ||
| 350 | |||
| 351 | pub const O_CREAT = 0o100; | ||
| 352 | pub const O_EXCL = 0o200; | ||
| 353 | pub const O_NOCTTY = 0o400; | ||
| 354 | pub const O_TRUNC = 0o1000; | ||
| 355 | pub const O_APPEND = 0o2000; | ||
| 356 | pub const O_NONBLOCK = 0o4000; | ||
| 357 | pub const O_DSYNC = 0o10000; | ||
| 358 | pub const O_SYNC = 0o4010000; | ||
| 359 | pub const O_RSYNC = 0o4010000; | ||
| 360 | pub const O_DIRECTORY = 0o200000; | ||
| 361 | pub const O_NOFOLLOW = 0o400000; | ||
| 362 | pub const O_CLOEXEC = 0o2000000; | ||
| 363 | |||
| 364 | pub const O_ASYNC = 0o20000; | ||
| 365 | pub const O_DIRECT = 0o40000; | ||
| 366 | pub const O_LARGEFILE = 0; | ||
| 367 | pub const O_NOATIME = 0o1000000; | ||
| 368 | pub const O_PATH = 0o10000000; | ||
| 369 | pub const O_TMPFILE = 0o20200000; | ||
| 370 | pub const O_NDELAY = O_NONBLOCK; | ||
| 371 | |||
| 372 | pub const F_DUPFD = 0; | ||
| 373 | pub const F_GETFD = 1; | ||
| 374 | pub const F_SETFD = 2; | ||
| 375 | pub const F_GETFL = 3; | ||
| 376 | pub const F_SETFL = 4; | ||
| 377 | |||
| 378 | pub const F_SETOWN = 8; | ||
| 379 | pub const F_GETOWN = 9; | ||
| 380 | pub const F_SETSIG = 10; | ||
| 381 | pub const F_GETSIG = 11; | ||
| 382 | |||
| 383 | pub const F_GETLK = 5; | ||
| 384 | pub const F_SETLK = 6; | ||
| 385 | pub const F_SETLKW = 7; | ||
| 386 | |||
| 387 | pub const F_SETOWN_EX = 15; | ||
| 388 | pub const F_GETOWN_EX = 16; | ||
| 389 | |||
| 390 | pub const F_GETOWNER_UIDS = 17; | ||
| 391 | |||
| 392 | pub const AT_FDCWD = -100; | ||
| 393 | pub const AT_SYMLINK_NOFOLLOW = 0x100; | ||
| 394 | pub const AT_REMOVEDIR = 0x200; | ||
| 395 | pub const AT_SYMLINK_FOLLOW = 0x400; | ||
| 396 | pub const AT_NO_AUTOMOUNT = 0x800; | ||
| 397 | pub const AT_EMPTY_PATH = 0x1000; | ||
| 398 | |||
| 399 | pub const VDSO_USEFUL = true; | ||
| 400 | pub const VDSO_CGT_SYM = "__vdso_clock_gettime"; | ||
| 401 | pub const VDSO_CGT_VER = "LINUX_2.6"; | ||
| 402 | pub const VDSO_GETCPU_SYM = "__vdso_getcpu"; | ||
| 403 | pub const VDSO_GETCPU_VER = "LINUX_2.6"; | ||
| 404 | |||
| 405 | pub const ARCH_SET_GS = 0x1001; | ||
| 406 | pub const ARCH_SET_FS = 0x1002; | ||
| 407 | pub const ARCH_GET_FS = 0x1003; | ||
| 408 | pub const ARCH_GET_GS = 0x1004; | ||
| 409 | |||
| 410 | pub 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 | |||
| 422 | pub 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. | ||
| 435 | pub 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 | |||
| 455 | pub const timespec = extern struct { | ||
| 456 | tv_sec: isize, | ||
| 457 | tv_nsec: isize, | ||
| 458 | }; | ||
| 459 | |||
| 460 | pub const timeval = extern struct { | ||
| 461 | tv_sec: isize, | ||
| 462 | tv_usec: isize, | ||
| 463 | }; | ||
| 464 | |||
| 465 | pub const timezone = extern struct { | ||
| 466 | tz_minuteswest: i32, | ||
| 467 | tz_dsttime: i32, | ||
| 468 | }; | ||
| 469 | |||
| 470 | pub const Elf_Symndx = u32; | ||
std/os/bits/netbsd.zig created+725| ... | @@ -0,0 +1,725 @@ | ||
| 1 | const std = @import("../../std.zig"); | ||
| 2 | const maxInt = std.math.maxInt; | ||
| 3 | |||
| 4 | pub const fd_t = c_int; | ||
| 5 | pub const pid_t = c_int; | ||
| 6 | |||
| 7 | /// Renamed from `kevent` to `Kevent` to avoid conflict with function name. | ||
| 8 | pub const Kevent = extern struct { | ||
| 9 | ident: usize, | ||
| 10 | filter: i32, | ||
| 11 | flags: u32, | ||
| 12 | fflags: u32, | ||
| 13 | data: i64, | ||
| 14 | udata: usize, | ||
| 15 | }; | ||
| 16 | |||
| 17 | pub const pthread_attr_t = extern struct { | ||
| 18 | pta_magic: u32, | ||
| 19 | pta_flags: c_int, | ||
| 20 | pta_private: *c_void, | ||
| 21 | }; | ||
| 22 | |||
| 23 | pub 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 | |||
| 46 | pub 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 | |||
| 69 | pub 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 | |||
| 92 | pub const timespec = extern struct { | ||
| 93 | tv_sec: i64, | ||
| 94 | tv_nsec: isize, | ||
| 95 | }; | ||
| 96 | |||
| 97 | pub 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 | |||
| 106 | pub const in_port_t = u16; | ||
| 107 | pub const sa_family_t = u8; | ||
| 108 | |||
| 109 | pub const sockaddr = extern union { | ||
| 110 | in: sockaddr_in, | ||
| 111 | in6: sockaddr_in6, | ||
| 112 | }; | ||
| 113 | |||
| 114 | pub 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 | |||
| 122 | pub 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 | |||
| 131 | pub const CTL_KERN = 1; | ||
| 132 | pub const CTL_DEBUG = 5; | ||
| 133 | |||
| 134 | pub const KERN_PROC_ARGS = 48; // struct: process argv/env | ||
| 135 | pub const KERN_PROC_PATHNAME = 5; // path to executable | ||
| 136 | |||
| 137 | pub const PATH_MAX = 1024; | ||
| 138 | |||
| 139 | pub const STDIN_FILENO = 0; | ||
| 140 | pub const STDOUT_FILENO = 1; | ||
| 141 | pub const STDERR_FILENO = 2; | ||
| 142 | |||
| 143 | pub const PROT_NONE = 0; | ||
| 144 | pub const PROT_READ = 1; | ||
| 145 | pub const PROT_WRITE = 2; | ||
| 146 | pub const PROT_EXEC = 4; | ||
| 147 | |||
| 148 | pub const CLOCK_REALTIME = 0; | ||
| 149 | pub const CLOCK_VIRTUAL = 1; | ||
| 150 | pub const CLOCK_PROF = 2; | ||
| 151 | pub const CLOCK_MONOTONIC = 3; | ||
| 152 | pub const CLOCK_THREAD_CPUTIME_ID = 0x20000000; | ||
| 153 | pub const CLOCK_PROCESS_CPUTIME_ID = 0x40000000; | ||
| 154 | |||
| 155 | pub const MAP_FAILED = @intToPtr(*c_void, maxInt(usize)); | ||
| 156 | pub const MAP_SHARED = 0x0001; | ||
| 157 | pub const MAP_PRIVATE = 0x0002; | ||
| 158 | pub const MAP_REMAPDUP = 0x0004; | ||
| 159 | pub const MAP_FIXED = 0x0010; | ||
| 160 | pub const MAP_RENAME = 0x0020; | ||
| 161 | pub const MAP_NORESERVE = 0x0040; | ||
| 162 | pub const MAP_INHERIT = 0x0080; | ||
| 163 | pub const MAP_HASSEMAPHORE = 0x0200; | ||
| 164 | pub const MAP_TRYFIXED = 0x0400; | ||
| 165 | pub const MAP_WIRED = 0x0800; | ||
| 166 | |||
| 167 | pub const MAP_FILE = 0x0000; | ||
| 168 | pub const MAP_NOSYNC = 0x0800; | ||
| 169 | pub const MAP_ANON = 0x1000; | ||
| 170 | pub const MAP_ANONYMOUS = MAP_ANON; | ||
| 171 | pub const MAP_STACK = 0x2000; | ||
| 172 | |||
| 173 | pub const WNOHANG = 0x00000001; | ||
| 174 | pub const WUNTRACED = 0x00000002; | ||
| 175 | pub const WSTOPPED = WUNTRACED; | ||
| 176 | pub const WCONTINUED = 0x00000010; | ||
| 177 | pub const WNOWAIT = 0x00010000; | ||
| 178 | pub const WEXITED = 0x00000020; | ||
| 179 | pub const WTRAPPED = 0x00000040; | ||
| 180 | |||
| 181 | pub const SA_ONSTACK = 0x0001; | ||
| 182 | pub const SA_RESTART = 0x0002; | ||
| 183 | pub const SA_RESETHAND = 0x0004; | ||
| 184 | pub const SA_NOCLDSTOP = 0x0008; | ||
| 185 | pub const SA_NODEFER = 0x0010; | ||
| 186 | pub const SA_NOCLDWAIT = 0x0020; | ||
| 187 | pub const SA_SIGINFO = 0x0040; | ||
| 188 | |||
| 189 | pub const SIGHUP = 1; | ||
| 190 | pub const SIGINT = 2; | ||
| 191 | pub const SIGQUIT = 3; | ||
| 192 | pub const SIGILL = 4; | ||
| 193 | pub const SIGTRAP = 5; | ||
| 194 | pub const SIGABRT = 6; | ||
| 195 | pub const SIGIOT = SIGABRT; | ||
| 196 | pub const SIGEMT = 7; | ||
| 197 | pub const SIGFPE = 8; | ||
| 198 | pub const SIGKILL = 9; | ||
| 199 | pub const SIGBUS = 10; | ||
| 200 | pub const SIGSEGV = 11; | ||
| 201 | pub const SIGSYS = 12; | ||
| 202 | pub const SIGPIPE = 13; | ||
| 203 | pub const SIGALRM = 14; | ||
| 204 | pub const SIGTERM = 15; | ||
| 205 | pub const SIGURG = 16; | ||
| 206 | pub const SIGSTOP = 17; | ||
| 207 | pub const SIGTSTP = 18; | ||
| 208 | pub const SIGCONT = 19; | ||
| 209 | pub const SIGCHLD = 20; | ||
| 210 | pub const SIGTTIN = 21; | ||
| 211 | pub const SIGTTOU = 22; | ||
| 212 | pub const SIGIO = 23; | ||
| 213 | pub const SIGXCPU = 24; | ||
| 214 | pub const SIGXFSZ = 25; | ||
| 215 | pub const SIGVTALRM = 26; | ||
| 216 | pub const SIGPROF = 27; | ||
| 217 | pub const SIGWINCH = 28; | ||
| 218 | pub const SIGINFO = 29; | ||
| 219 | pub const SIGUSR1 = 30; | ||
| 220 | pub const SIGUSR2 = 31; | ||
| 221 | pub const SIGPWR = 32; | ||
| 222 | |||
| 223 | pub const SIGRTMIN = 33; | ||
| 224 | pub const SIGRTMAX = 63; | ||
| 225 | |||
| 226 | // access function | ||
| 227 | pub const F_OK = 0; // test for existence of file | ||
| 228 | pub const X_OK = 1; // test for execute or search permission | ||
| 229 | pub const W_OK = 2; // test for write permission | ||
| 230 | pub const R_OK = 4; // test for read permission | ||
| 231 | |||
| 232 | pub const O_RDONLY = 0x0000; | ||
| 233 | pub const O_WRONLY = 0x0001; | ||
| 234 | pub const O_RDWR = 0x0002; | ||
| 235 | pub const O_ACCMODE = 0x0003; | ||
| 236 | |||
| 237 | pub const O_CREAT = 0x0200; | ||
| 238 | pub const O_EXCL = 0x0800; | ||
| 239 | pub const O_NOCTTY = 0x8000; | ||
| 240 | pub const O_TRUNC = 0x0400; | ||
| 241 | pub const O_APPEND = 0x0008; | ||
| 242 | pub const O_NONBLOCK = 0x0004; | ||
| 243 | pub const O_DSYNC = 0x00010000; | ||
| 244 | pub const O_SYNC = 0x0080; | ||
| 245 | pub const O_RSYNC = 0x00020000; | ||
| 246 | pub const O_DIRECTORY = 0x00080000; | ||
| 247 | pub const O_NOFOLLOW = 0x00000100; | ||
| 248 | pub const O_CLOEXEC = 0x00400000; | ||
| 249 | |||
| 250 | pub const O_ASYNC = 0x0040; | ||
| 251 | pub const O_DIRECT = 0x00080000; | ||
| 252 | pub const O_LARGEFILE = 0; | ||
| 253 | pub const O_NOATIME = 0; | ||
| 254 | pub const O_PATH = 0; | ||
| 255 | pub const O_TMPFILE = 0; | ||
| 256 | pub const O_NDELAY = O_NONBLOCK; | ||
| 257 | |||
| 258 | pub const F_DUPFD = 0; | ||
| 259 | pub const F_GETFD = 1; | ||
| 260 | pub const F_SETFD = 2; | ||
| 261 | pub const F_GETFL = 3; | ||
| 262 | pub const F_SETFL = 4; | ||
| 263 | |||
| 264 | pub const F_GETOWN = 5; | ||
| 265 | pub const F_SETOWN = 6; | ||
| 266 | |||
| 267 | pub const F_GETLK = 7; | ||
| 268 | pub const F_SETLK = 8; | ||
| 269 | pub const F_SETLKW = 9; | ||
| 270 | |||
| 271 | pub const SEEK_SET = 0; | ||
| 272 | pub const SEEK_CUR = 1; | ||
| 273 | pub const SEEK_END = 2; | ||
| 274 | |||
| 275 | pub const SIG_BLOCK = 1; | ||
| 276 | pub const SIG_UNBLOCK = 2; | ||
| 277 | pub const SIG_SETMASK = 3; | ||
| 278 | |||
| 279 | pub const SOCK_STREAM = 1; | ||
| 280 | pub const SOCK_DGRAM = 2; | ||
| 281 | pub const SOCK_RAW = 3; | ||
| 282 | pub const SOCK_RDM = 4; | ||
| 283 | pub const SOCK_SEQPACKET = 5; | ||
| 284 | |||
| 285 | pub const SOCK_CLOEXEC = 0x10000000; | ||
| 286 | pub const SOCK_NONBLOCK = 0x20000000; | ||
| 287 | |||
| 288 | pub const PROTO_ip = 0; | ||
| 289 | pub const PROTO_icmp = 1; | ||
| 290 | pub const PROTO_igmp = 2; | ||
| 291 | pub const PROTO_ggp = 3; | ||
| 292 | pub const PROTO_ipencap = 4; | ||
| 293 | pub const PROTO_tcp = 6; | ||
| 294 | pub const PROTO_egp = 8; | ||
| 295 | pub const PROTO_pup = 12; | ||
| 296 | pub const PROTO_udp = 17; | ||
| 297 | pub const PROTO_xns_idp = 22; | ||
| 298 | pub const PROTO_iso_tp4 = 29; | ||
| 299 | pub const PROTO_ipv6 = 41; | ||
| 300 | pub const PROTO_ipv6_route = 43; | ||
| 301 | pub const PROTO_ipv6_frag = 44; | ||
| 302 | pub const PROTO_rsvp = 46; | ||
| 303 | pub const PROTO_gre = 47; | ||
| 304 | pub const PROTO_esp = 50; | ||
| 305 | pub const PROTO_ah = 51; | ||
| 306 | pub const PROTO_ipv6_icmp = 58; | ||
| 307 | pub const PROTO_ipv6_nonxt = 59; | ||
| 308 | pub const PROTO_ipv6_opts = 60; | ||
| 309 | pub const PROTO_encap = 98; | ||
| 310 | pub const PROTO_pim = 103; | ||
| 311 | pub const PROTO_raw = 255; | ||
| 312 | |||
| 313 | pub const PF_UNSPEC = 0; | ||
| 314 | pub const PF_LOCAL = 1; | ||
| 315 | pub const PF_UNIX = PF_LOCAL; | ||
| 316 | pub const PF_FILE = PF_LOCAL; | ||
| 317 | pub const PF_INET = 2; | ||
| 318 | pub const PF_APPLETALK = 16; | ||
| 319 | pub const PF_INET6 = 24; | ||
| 320 | pub const PF_DECnet = 12; | ||
| 321 | pub const PF_KEY = 29; | ||
| 322 | pub const PF_ROUTE = 34; | ||
| 323 | pub const PF_SNA = 11; | ||
| 324 | pub const PF_MPLS = 33; | ||
| 325 | pub const PF_CAN = 35; | ||
| 326 | pub const PF_BLUETOOTH = 31; | ||
| 327 | pub const PF_ISDN = 26; | ||
| 328 | pub const PF_MAX = 37; | ||
| 329 | |||
| 330 | pub const AF_UNSPEC = PF_UNSPEC; | ||
| 331 | pub const AF_LOCAL = PF_LOCAL; | ||
| 332 | pub const AF_UNIX = AF_LOCAL; | ||
| 333 | pub const AF_FILE = AF_LOCAL; | ||
| 334 | pub const AF_INET = PF_INET; | ||
| 335 | pub const AF_APPLETALK = PF_APPLETALK; | ||
| 336 | pub const AF_INET6 = PF_INET6; | ||
| 337 | pub const AF_KEY = PF_KEY; | ||
| 338 | pub const AF_ROUTE = PF_ROUTE; | ||
| 339 | pub const AF_SNA = PF_SNA; | ||
| 340 | pub const AF_MPLS = PF_MPLS; | ||
| 341 | pub const AF_CAN = PF_CAN; | ||
| 342 | pub const AF_BLUETOOTH = PF_BLUETOOTH; | ||
| 343 | pub const AF_ISDN = PF_ISDN; | ||
| 344 | pub const AF_MAX = PF_MAX; | ||
| 345 | |||
| 346 | pub const DT_UNKNOWN = 0; | ||
| 347 | pub const DT_FIFO = 1; | ||
| 348 | pub const DT_CHR = 2; | ||
| 349 | pub const DT_DIR = 4; | ||
| 350 | pub const DT_BLK = 6; | ||
| 351 | pub const DT_REG = 8; | ||
| 352 | pub const DT_LNK = 10; | ||
| 353 | pub const DT_SOCK = 12; | ||
| 354 | pub const DT_WHT = 14; | ||
| 355 | |||
| 356 | /// add event to kq (implies enable) | ||
| 357 | pub const EV_ADD = 0x0001; | ||
| 358 | |||
| 359 | /// delete event from kq | ||
| 360 | pub const EV_DELETE = 0x0002; | ||
| 361 | |||
| 362 | /// enable event | ||
| 363 | pub const EV_ENABLE = 0x0004; | ||
| 364 | |||
| 365 | /// disable event (not reported) | ||
| 366 | pub const EV_DISABLE = 0x0008; | ||
| 367 | |||
| 368 | /// only report one occurrence | ||
| 369 | pub const EV_ONESHOT = 0x0010; | ||
| 370 | |||
| 371 | /// clear event state after reporting | ||
| 372 | pub 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 | ||
| 378 | pub const EV_RECEIPT = 0x0040; | ||
| 379 | |||
| 380 | /// disable event after reporting | ||
| 381 | pub const EV_DISPATCH = 0x0080; | ||
| 382 | |||
| 383 | pub const EVFILT_READ = 0; | ||
| 384 | pub const EVFILT_WRITE = 1; | ||
| 385 | |||
| 386 | /// attached to aio requests | ||
| 387 | pub const EVFILT_AIO = 2; | ||
| 388 | |||
| 389 | /// attached to vnodes | ||
| 390 | pub const EVFILT_VNODE = 3; | ||
| 391 | |||
| 392 | /// attached to struct proc | ||
| 393 | pub const EVFILT_PROC = 4; | ||
| 394 | |||
| 395 | /// attached to struct proc | ||
| 396 | pub const EVFILT_SIGNAL = 5; | ||
| 397 | |||
| 398 | /// timers | ||
| 399 | pub const EVFILT_TIMER = 6; | ||
| 400 | |||
| 401 | /// Filesystem events | ||
| 402 | pub const EVFILT_FS = 7; | ||
| 403 | |||
| 404 | /// On input, NOTE_TRIGGER causes the event to be triggered for output. | ||
| 405 | pub const NOTE_TRIGGER = 0x08000000; | ||
| 406 | |||
| 407 | /// low water mark | ||
| 408 | pub const NOTE_LOWAT = 0x00000001; | ||
| 409 | |||
| 410 | /// vnode was removed | ||
| 411 | pub const NOTE_DELETE = 0x00000001; | ||
| 412 | |||
| 413 | /// data contents changed | ||
| 414 | pub const NOTE_WRITE = 0x00000002; | ||
| 415 | |||
| 416 | /// size increased | ||
| 417 | pub const NOTE_EXTEND = 0x00000004; | ||
| 418 | |||
| 419 | /// attributes changed | ||
| 420 | pub const NOTE_ATTRIB = 0x00000008; | ||
| 421 | |||
| 422 | /// link count changed | ||
| 423 | pub const NOTE_LINK = 0x00000010; | ||
| 424 | |||
| 425 | /// vnode was renamed | ||
| 426 | pub const NOTE_RENAME = 0x00000020; | ||
| 427 | |||
| 428 | /// vnode access was revoked | ||
| 429 | pub const NOTE_REVOKE = 0x00000040; | ||
| 430 | |||
| 431 | /// process exited | ||
| 432 | pub const NOTE_EXIT = 0x80000000; | ||
| 433 | |||
| 434 | /// process forked | ||
| 435 | pub const NOTE_FORK = 0x40000000; | ||
| 436 | |||
| 437 | /// process exec'd | ||
| 438 | pub const NOTE_EXEC = 0x20000000; | ||
| 439 | |||
| 440 | /// mask for signal & exit status | ||
| 441 | pub const NOTE_PDATAMASK = 0x000fffff; | ||
| 442 | pub const NOTE_PCTRLMASK = 0xf0000000; | ||
| 443 | |||
| 444 | pub const TIOCCBRK = 0x2000747a; | ||
| 445 | pub const TIOCCDTR = 0x20007478; | ||
| 446 | pub const TIOCCONS = 0x80047462; | ||
| 447 | pub const TIOCDCDTIMESTAMP = 0x40107458; | ||
| 448 | pub const TIOCDRAIN = 0x2000745e; | ||
| 449 | pub const TIOCEXCL = 0x2000740d; | ||
| 450 | pub const TIOCEXT = 0x80047460; | ||
| 451 | pub const TIOCFLAG_CDTRCTS = 0x10; | ||
| 452 | pub const TIOCFLAG_CLOCAL = 0x2; | ||
| 453 | pub const TIOCFLAG_CRTSCTS = 0x4; | ||
| 454 | pub const TIOCFLAG_MDMBUF = 0x8; | ||
| 455 | pub const TIOCFLAG_SOFTCAR = 0x1; | ||
| 456 | pub const TIOCFLUSH = 0x80047410; | ||
| 457 | pub const TIOCGETA = 0x402c7413; | ||
| 458 | pub const TIOCGETD = 0x4004741a; | ||
| 459 | pub const TIOCGFLAGS = 0x4004745d; | ||
| 460 | pub const TIOCGLINED = 0x40207442; | ||
| 461 | pub const TIOCGPGRP = 0x40047477; | ||
| 462 | pub const TIOCGQSIZE = 0x40047481; | ||
| 463 | pub const TIOCGRANTPT = 0x20007447; | ||
| 464 | pub const TIOCGSID = 0x40047463; | ||
| 465 | pub const TIOCGSIZE = 0x40087468; | ||
| 466 | pub const TIOCGWINSZ = 0x40087468; | ||
| 467 | pub const TIOCMBIC = 0x8004746b; | ||
| 468 | pub const TIOCMBIS = 0x8004746c; | ||
| 469 | pub const TIOCMGET = 0x4004746a; | ||
| 470 | pub const TIOCMSET = 0x8004746d; | ||
| 471 | pub const TIOCM_CAR = 0x40; | ||
| 472 | pub const TIOCM_CD = 0x40; | ||
| 473 | pub const TIOCM_CTS = 0x20; | ||
| 474 | pub const TIOCM_DSR = 0x100; | ||
| 475 | pub const TIOCM_DTR = 0x2; | ||
| 476 | pub const TIOCM_LE = 0x1; | ||
| 477 | pub const TIOCM_RI = 0x80; | ||
| 478 | pub const TIOCM_RNG = 0x80; | ||
| 479 | pub const TIOCM_RTS = 0x4; | ||
| 480 | pub const TIOCM_SR = 0x10; | ||
| 481 | pub const TIOCM_ST = 0x8; | ||
| 482 | pub const TIOCNOTTY = 0x20007471; | ||
| 483 | pub const TIOCNXCL = 0x2000740e; | ||
| 484 | pub const TIOCOUTQ = 0x40047473; | ||
| 485 | pub const TIOCPKT = 0x80047470; | ||
| 486 | pub const TIOCPKT_DATA = 0x0; | ||
| 487 | pub const TIOCPKT_DOSTOP = 0x20; | ||
| 488 | pub const TIOCPKT_FLUSHREAD = 0x1; | ||
| 489 | pub const TIOCPKT_FLUSHWRITE = 0x2; | ||
| 490 | pub const TIOCPKT_IOCTL = 0x40; | ||
| 491 | pub const TIOCPKT_NOSTOP = 0x10; | ||
| 492 | pub const TIOCPKT_START = 0x8; | ||
| 493 | pub const TIOCPKT_STOP = 0x4; | ||
| 494 | pub const TIOCPTMGET = 0x40287446; | ||
| 495 | pub const TIOCPTSNAME = 0x40287448; | ||
| 496 | pub const TIOCRCVFRAME = 0x80087445; | ||
| 497 | pub const TIOCREMOTE = 0x80047469; | ||
| 498 | pub const TIOCSBRK = 0x2000747b; | ||
| 499 | pub const TIOCSCTTY = 0x20007461; | ||
| 500 | pub const TIOCSDTR = 0x20007479; | ||
| 501 | pub const TIOCSETA = 0x802c7414; | ||
| 502 | pub const TIOCSETAF = 0x802c7416; | ||
| 503 | pub const TIOCSETAW = 0x802c7415; | ||
| 504 | pub const TIOCSETD = 0x8004741b; | ||
| 505 | pub const TIOCSFLAGS = 0x8004745c; | ||
| 506 | pub const TIOCSIG = 0x2000745f; | ||
| 507 | pub const TIOCSLINED = 0x80207443; | ||
| 508 | pub const TIOCSPGRP = 0x80047476; | ||
| 509 | pub const TIOCSQSIZE = 0x80047480; | ||
| 510 | pub const TIOCSSIZE = 0x80087467; | ||
| 511 | pub const TIOCSTART = 0x2000746e; | ||
| 512 | pub const TIOCSTAT = 0x80047465; | ||
| 513 | pub const TIOCSTI = 0x80017472; | ||
| 514 | pub const TIOCSTOP = 0x2000746f; | ||
| 515 | pub const TIOCSWINSZ = 0x80087467; | ||
| 516 | pub const TIOCUCNTL = 0x80047466; | ||
| 517 | pub const TIOCXMTFRAME = 0x80087444; | ||
| 518 | |||
| 519 | pub fn WEXITSTATUS(s: u32) u32 { | ||
| 520 | return (s >> 8) & 0xff; | ||
| 521 | } | ||
| 522 | pub fn WTERMSIG(s: u32) u32 { | ||
| 523 | return s & 0x7f; | ||
| 524 | } | ||
| 525 | pub fn WSTOPSIG(s: u32) u32 { | ||
| 526 | return WEXITSTATUS(s); | ||
| 527 | } | ||
| 528 | pub fn WIFEXITED(s: u32) bool { | ||
| 529 | return WTERMSIG(s) == 0; | ||
| 530 | } | ||
| 531 | |||
| 532 | pub fn WIFCONTINUED(s: u32) bool { | ||
| 533 | return ((s & 0x7f) == 0xffff); | ||
| 534 | } | ||
| 535 | |||
| 536 | pub fn WIFSTOPPED(s: u32) bool { | ||
| 537 | return ((s & 0x7f != 0x7f) and !WIFCONTINUED(s)); | ||
| 538 | } | ||
| 539 | |||
| 540 | pub fn WIFSIGNALED(s: u32) bool { | ||
| 541 | return !WIFSTOPPED(s) and !WIFCONTINUED(s) and !WIFEXITED(s); | ||
| 542 | } | ||
| 543 | |||
| 544 | pub const winsize = extern struct { | ||
| 545 | ws_row: u16, | ||
| 546 | ws_col: u16, | ||
| 547 | ws_xpixel: u16, | ||
| 548 | ws_ypixel: u16, | ||
| 549 | }; | ||
| 550 | |||
| 551 | const NSIG = 32; | ||
| 552 | |||
| 553 | pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize)); | ||
| 554 | pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0); | ||
| 555 | pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1); | ||
| 556 | |||
| 557 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. | ||
| 558 | pub 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 | |||
| 572 | pub const _SIG_WORDS = 4; | ||
| 573 | pub const _SIG_MAXSIG = 128; | ||
| 574 | |||
| 575 | pub inline fn _SIG_IDX(sig: usize) usize { | ||
| 576 | return sig - 1; | ||
| 577 | } | ||
| 578 | pub inline fn _SIG_WORD(sig: usize) usize { | ||
| 579 | return_SIG_IDX(sig) >> 5; | ||
| 580 | } | ||
| 581 | pub inline fn _SIG_BIT(sig: usize) usize { | ||
| 582 | return 1 << (_SIG_IDX(sig) & 31); | ||
| 583 | } | ||
| 584 | pub inline fn _SIG_VALID(sig: usize) usize { | ||
| 585 | return sig <= _SIG_MAXSIG and sig > 0; | ||
| 586 | } | ||
| 587 | |||
| 588 | pub const sigset_t = extern struct { | ||
| 589 | __bits: [_SIG_WORDS]u32, | ||
| 590 | }; | ||
| 591 | |||
| 592 | pub const EPERM = 1; // Operation not permitted | ||
| 593 | pub const ENOENT = 2; // No such file or directory | ||
| 594 | pub const ESRCH = 3; // No such process | ||
| 595 | pub const EINTR = 4; // Interrupted system call | ||
| 596 | pub const EIO = 5; // Input/output error | ||
| 597 | pub const ENXIO = 6; // Device not configured | ||
| 598 | pub const E2BIG = 7; // Argument list too long | ||
| 599 | pub const ENOEXEC = 8; // Exec format error | ||
| 600 | pub const EBADF = 9; // Bad file descriptor | ||
| 601 | pub const ECHILD = 10; // No child processes | ||
| 602 | pub const EDEADLK = 11; // Resource deadlock avoided | ||
| 603 | // 11 was EAGAIN | ||
| 604 | pub const ENOMEM = 12; // Cannot allocate memory | ||
| 605 | pub const EACCES = 13; // Permission denied | ||
| 606 | pub const EFAULT = 14; // Bad address | ||
| 607 | pub const ENOTBLK = 15; // Block device required | ||
| 608 | pub const EBUSY = 16; // Device busy | ||
| 609 | pub const EEXIST = 17; // File exists | ||
| 610 | pub const EXDEV = 18; // Cross-device link | ||
| 611 | pub const ENODEV = 19; // Operation not supported by device | ||
| 612 | pub const ENOTDIR = 20; // Not a directory | ||
| 613 | pub const EISDIR = 21; // Is a directory | ||
| 614 | pub const EINVAL = 22; // Invalid argument | ||
| 615 | pub const ENFILE = 23; // Too many open files in system | ||
| 616 | pub const EMFILE = 24; // Too many open files | ||
| 617 | pub const ENOTTY = 25; // Inappropriate ioctl for device | ||
| 618 | pub const ETXTBSY = 26; // Text file busy | ||
| 619 | pub const EFBIG = 27; // File too large | ||
| 620 | pub const ENOSPC = 28; // No space left on device | ||
| 621 | pub const ESPIPE = 29; // Illegal seek | ||
| 622 | pub const EROFS = 30; // Read-only file system | ||
| 623 | pub const EMLINK = 31; // Too many links | ||
| 624 | pub const EPIPE = 32; // Broken pipe | ||
| 625 | |||
| 626 | // math software | ||
| 627 | pub const EDOM = 33; // Numerical argument out of domain | ||
| 628 | pub const ERANGE = 34; // Result too large or too small | ||
| 629 | |||
| 630 | // non-blocking and interrupt i/o | ||
| 631 | pub const EAGAIN = 35; // Resource temporarily unavailable | ||
| 632 | pub const EWOULDBLOCK = EAGAIN; // Operation would block | ||
| 633 | pub const EINPROGRESS = 36; // Operation now in progress | ||
| 634 | pub const EALREADY = 37; // Operation already in progress | ||
| 635 | |||
| 636 | // ipc/network software -- argument errors | ||
| 637 | pub const ENOTSOCK = 38; // Socket operation on non-socket | ||
| 638 | pub const EDESTADDRREQ = 39; // Destination address required | ||
| 639 | pub const EMSGSIZE = 40; // Message too long | ||
| 640 | pub const EPROTOTYPE = 41; // Protocol wrong type for socket | ||
| 641 | pub const ENOPROTOOPT = 42; // Protocol option not available | ||
| 642 | pub const EPROTONOSUPPORT = 43; // Protocol not supported | ||
| 643 | pub const ESOCKTNOSUPPORT = 44; // Socket type not supported | ||
| 644 | pub const EOPNOTSUPP = 45; // Operation not supported | ||
| 645 | pub const EPFNOSUPPORT = 46; // Protocol family not supported | ||
| 646 | pub const EAFNOSUPPORT = 47; // Address family not supported by protocol family | ||
| 647 | pub const EADDRINUSE = 48; // Address already in use | ||
| 648 | pub const EADDRNOTAVAIL = 49; // Can't assign requested address | ||
| 649 | |||
| 650 | // ipc/network software -- operational errors | ||
| 651 | pub const ENETDOWN = 50; // Network is down | ||
| 652 | pub const ENETUNREACH = 51; // Network is unreachable | ||
| 653 | pub const ENETRESET = 52; // Network dropped connection on reset | ||
| 654 | pub const ECONNABORTED = 53; // Software caused connection abort | ||
| 655 | pub const ECONNRESET = 54; // Connection reset by peer | ||
| 656 | pub const ENOBUFS = 55; // No buffer space available | ||
| 657 | pub const EISCONN = 56; // Socket is already connected | ||
| 658 | pub const ENOTCONN = 57; // Socket is not connected | ||
| 659 | pub const ESHUTDOWN = 58; // Can't send after socket shutdown | ||
| 660 | pub const ETOOMANYREFS = 59; // Too many references: can't splice | ||
| 661 | pub const ETIMEDOUT = 60; // Operation timed out | ||
| 662 | pub const ECONNREFUSED = 61; // Connection refused | ||
| 663 | |||
| 664 | pub const ELOOP = 62; // Too many levels of symbolic links | ||
| 665 | pub const ENAMETOOLONG = 63; // File name too long | ||
| 666 | |||
| 667 | // should be rearranged | ||
| 668 | pub const EHOSTDOWN = 64; // Host is down | ||
| 669 | pub const EHOSTUNREACH = 65; // No route to host | ||
| 670 | pub const ENOTEMPTY = 66; // Directory not empty | ||
| 671 | |||
| 672 | // quotas & mush | ||
| 673 | pub const EPROCLIM = 67; // Too many processes | ||
| 674 | pub const EUSERS = 68; // Too many users | ||
| 675 | pub const EDQUOT = 69; // Disc quota exceeded | ||
| 676 | |||
| 677 | // Network File System | ||
| 678 | pub const ESTALE = 70; // Stale NFS file handle | ||
| 679 | pub const EREMOTE = 71; // Too many levels of remote in path | ||
| 680 | pub const EBADRPC = 72; // RPC struct is bad | ||
| 681 | pub const ERPCMISMATCH = 73; // RPC version wrong | ||
| 682 | pub const EPROGUNAVAIL = 74; // RPC prog. not avail | ||
| 683 | pub const EPROGMISMATCH = 75; // Program version wrong | ||
| 684 | pub const EPROCUNAVAIL = 76; // Bad procedure for program | ||
| 685 | |||
| 686 | pub const ENOLCK = 77; // No locks available | ||
| 687 | pub const ENOSYS = 78; // Function not implemented | ||
| 688 | |||
| 689 | pub const EFTYPE = 79; // Inappropriate file type or format | ||
| 690 | pub const EAUTH = 80; // Authentication error | ||
| 691 | pub const ENEEDAUTH = 81; // Need authenticator | ||
| 692 | |||
| 693 | // SystemV IPC | ||
| 694 | pub const EIDRM = 82; // Identifier removed | ||
| 695 | pub const ENOMSG = 83; // No message of desired type | ||
| 696 | pub const EOVERFLOW = 84; // Value too large to be stored in data type | ||
| 697 | |||
| 698 | // Wide/multibyte-character handling, ISO/IEC 9899/AMD1:1995 | ||
| 699 | pub const EILSEQ = 85; // Illegal byte sequence | ||
| 700 | |||
| 701 | // From IEEE Std 1003.1-2001 | ||
| 702 | // Base, Realtime, Threads or Thread Priority Scheduling option errors | ||
| 703 | pub const ENOTSUP = 86; // Not supported | ||
| 704 | |||
| 705 | // Realtime option errors | ||
| 706 | pub const ECANCELED = 87; // Operation canceled | ||
| 707 | |||
| 708 | // Realtime, XSI STREAMS option errors | ||
| 709 | pub const EBADMSG = 88; // Bad or Corrupt message | ||
| 710 | |||
| 711 | // XSI STREAMS option errors | ||
| 712 | pub const ENODATA = 89; // No message available | ||
| 713 | pub const ENOSR = 90; // No STREAM resources | ||
| 714 | pub const ENOSTR = 91; // Not a STREAM | ||
| 715 | pub const ETIME = 92; // STREAM ioctl timeout | ||
| 716 | |||
| 717 | // File system extended attribute errors | ||
| 718 | pub const ENOATTR = 93; // Attribute not found | ||
| 719 | |||
| 720 | // Realtime, XSI STREAMS option errors | ||
| 721 | pub const EMULTIHOP = 94; // Multihop attempted | ||
| 722 | pub const ENOLINK = 95; // Link has been severed | ||
| 723 | pub const EPROTO = 96; // Protocol error | ||
| 724 | |||
| 725 | pub const ELAST = 96; // Must equal largest errno | ||
std/os/bits/wasi.zig created+307| ... | @@ -0,0 +1,307 @@ | ||
| 1 | pub const STDIN_FILENO = 0; | ||
| 2 | pub const STDOUT_FILENO = 1; | ||
| 3 | pub const STDERR_FILENO = 2; | ||
| 4 | |||
| 5 | pub const advice_t = u8; | ||
| 6 | pub const ADVICE_NORMAL: advice_t = 0; | ||
| 7 | pub const ADVICE_SEQUENTIAL: advice_t = 1; | ||
| 8 | pub const ADVICE_RANDOM: advice_t = 2; | ||
| 9 | pub const ADVICE_WILLNEED: advice_t = 3; | ||
| 10 | pub const ADVICE_DONTNEED: advice_t = 4; | ||
| 11 | pub const ADVICE_NOREUSE: advice_t = 5; | ||
| 12 | |||
| 13 | pub const clockid_t = u32; | ||
| 14 | pub const CLOCK_REALTIME: clockid_t = 0; | ||
| 15 | pub const CLOCK_MONOTONIC: clockid_t = 1; | ||
| 16 | pub const CLOCK_PROCESS_CPUTIME_ID: clockid_t = 2; | ||
| 17 | pub const CLOCK_THREAD_CPUTIME_ID: clockid_t = 3; | ||
| 18 | |||
| 19 | pub const device_t = u64; | ||
| 20 | |||
| 21 | pub const dircookie_t = u64; | ||
| 22 | pub const DIRCOOKIE_START: dircookie_t = 0; | ||
| 23 | |||
| 24 | pub 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 | |||
| 31 | pub const errno_t = u16; | ||
| 32 | pub const ESUCCESS: errno_t = 0; | ||
| 33 | pub const E2BIG: errno_t = 1; | ||
| 34 | pub const EACCES: errno_t = 2; | ||
| 35 | pub const EADDRINUSE: errno_t = 3; | ||
| 36 | pub const EADDRNOTAVAIL: errno_t = 4; | ||
| 37 | pub const EAFNOSUPPORT: errno_t = 5; | ||
| 38 | pub const EAGAIN: errno_t = 6; | ||
| 39 | pub const EALREADY: errno_t = 7; | ||
| 40 | pub const EBADF: errno_t = 8; | ||
| 41 | pub const EBADMSG: errno_t = 9; | ||
| 42 | pub const EBUSY: errno_t = 10; | ||
| 43 | pub const ECANCELED: errno_t = 11; | ||
| 44 | pub const ECHILD: errno_t = 12; | ||
| 45 | pub const ECONNABORTED: errno_t = 13; | ||
| 46 | pub const ECONNREFUSED: errno_t = 14; | ||
| 47 | pub const ECONNRESET: errno_t = 15; | ||
| 48 | pub const EDEADLK: errno_t = 16; | ||
| 49 | pub const EDESTADDRREQ: errno_t = 17; | ||
| 50 | pub const EDOM: errno_t = 18; | ||
| 51 | pub const EDQUOT: errno_t = 19; | ||
| 52 | pub const EEXIST: errno_t = 20; | ||
| 53 | pub const EFAULT: errno_t = 21; | ||
| 54 | pub const EFBIG: errno_t = 22; | ||
| 55 | pub const EHOSTUNREACH: errno_t = 23; | ||
| 56 | pub const EIDRM: errno_t = 24; | ||
| 57 | pub const EILSEQ: errno_t = 25; | ||
| 58 | pub const EINPROGRESS: errno_t = 26; | ||
| 59 | pub const EINTR: errno_t = 27; | ||
| 60 | pub const EINVAL: errno_t = 28; | ||
| 61 | pub const EIO: errno_t = 29; | ||
| 62 | pub const EISCONN: errno_t = 30; | ||
| 63 | pub const EISDIR: errno_t = 31; | ||
| 64 | pub const ELOOP: errno_t = 32; | ||
| 65 | pub const EMFILE: errno_t = 33; | ||
| 66 | pub const EMLINK: errno_t = 34; | ||
| 67 | pub const EMSGSIZE: errno_t = 35; | ||
| 68 | pub const EMULTIHOP: errno_t = 36; | ||
| 69 | pub const ENAMETOOLONG: errno_t = 37; | ||
| 70 | pub const ENETDOWN: errno_t = 38; | ||
| 71 | pub const ENETRESET: errno_t = 39; | ||
| 72 | pub const ENETUNREACH: errno_t = 40; | ||
| 73 | pub const ENFILE: errno_t = 41; | ||
| 74 | pub const ENOBUFS: errno_t = 42; | ||
| 75 | pub const ENODEV: errno_t = 43; | ||
| 76 | pub const ENOENT: errno_t = 44; | ||
| 77 | pub const ENOEXEC: errno_t = 45; | ||
| 78 | pub const ENOLCK: errno_t = 46; | ||
| 79 | pub const ENOLINK: errno_t = 47; | ||
| 80 | pub const ENOMEM: errno_t = 48; | ||
| 81 | pub const ENOMSG: errno_t = 49; | ||
| 82 | pub const ENOPROTOOPT: errno_t = 50; | ||
| 83 | pub const ENOSPC: errno_t = 51; | ||
| 84 | pub const ENOSYS: errno_t = 52; | ||
| 85 | pub const ENOTCONN: errno_t = 53; | ||
| 86 | pub const ENOTDIR: errno_t = 54; | ||
| 87 | pub const ENOTEMPTY: errno_t = 55; | ||
| 88 | pub const ENOTRECOVERABLE: errno_t = 56; | ||
| 89 | pub const ENOTSOCK: errno_t = 57; | ||
| 90 | pub const ENOTSUP: errno_t = 58; | ||
| 91 | pub const ENOTTY: errno_t = 59; | ||
| 92 | pub const ENXIO: errno_t = 60; | ||
| 93 | pub const EOVERFLOW: errno_t = 61; | ||
| 94 | pub const EOWNERDEAD: errno_t = 62; | ||
| 95 | pub const EPERM: errno_t = 63; | ||
| 96 | pub const EPIPE: errno_t = 64; | ||
| 97 | pub const EPROTO: errno_t = 65; | ||
| 98 | pub const EPROTONOSUPPORT: errno_t = 66; | ||
| 99 | pub const EPROTOTYPE: errno_t = 67; | ||
| 100 | pub const ERANGE: errno_t = 68; | ||
| 101 | pub const EROFS: errno_t = 69; | ||
| 102 | pub const ESPIPE: errno_t = 70; | ||
| 103 | pub const ESRCH: errno_t = 71; | ||
| 104 | pub const ESTALE: errno_t = 72; | ||
| 105 | pub const ETIMEDOUT: errno_t = 73; | ||
| 106 | pub const ETXTBSY: errno_t = 74; | ||
| 107 | pub const EXDEV: errno_t = 75; | ||
| 108 | pub const ENOTCAPABLE: errno_t = 76; | ||
| 109 | |||
| 110 | pub 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 | |||
| 122 | pub const eventrwflags_t = u16; | ||
| 123 | pub const EVENT_FD_READWRITE_HANGUP: eventrwflags_t = 0x0001; | ||
| 124 | |||
| 125 | pub const eventtype_t = u8; | ||
| 126 | pub const EVENTTYPE_CLOCK: eventtype_t = 0; | ||
| 127 | pub const EVENTTYPE_FD_READ: eventtype_t = 1; | ||
| 128 | pub const EVENTTYPE_FD_WRITE: eventtype_t = 2; | ||
| 129 | |||
| 130 | pub const exitcode_t = u32; | ||
| 131 | |||
| 132 | pub const fd_t = u32; | ||
| 133 | |||
| 134 | pub const fdflags_t = u16; | ||
| 135 | pub const FDFLAG_APPEND: fdflags_t = 0x0001; | ||
| 136 | pub const FDFLAG_DSYNC: fdflags_t = 0x0002; | ||
| 137 | pub const FDFLAG_NONBLOCK: fdflags_t = 0x0004; | ||
| 138 | pub const FDFLAG_RSYNC: fdflags_t = 0x0008; | ||
| 139 | pub const FDFLAG_SYNC: fdflags_t = 0x0010; | ||
| 140 | |||
| 141 | const 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 | |||
| 148 | pub const filedelta_t = i64; | ||
| 149 | |||
| 150 | pub const filesize_t = u64; | ||
| 151 | |||
| 152 | pub 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 | |||
| 163 | pub const filetype_t = u8; | ||
| 164 | pub const FILETYPE_UNKNOWN: filetype_t = 0; | ||
| 165 | pub const FILETYPE_BLOCK_DEVICE: filetype_t = 1; | ||
| 166 | pub const FILETYPE_CHARACTER_DEVICE: filetype_t = 2; | ||
| 167 | pub const FILETYPE_DIRECTORY: filetype_t = 3; | ||
| 168 | pub const FILETYPE_REGULAR_FILE: filetype_t = 4; | ||
| 169 | pub const FILETYPE_SOCKET_DGRAM: filetype_t = 5; | ||
| 170 | pub const FILETYPE_SOCKET_STREAM: filetype_t = 6; | ||
| 171 | pub const FILETYPE_SYMBOLIC_LINK: filetype_t = 7; | ||
| 172 | |||
| 173 | pub const fstflags_t = u16; | ||
| 174 | pub const FILESTAT_SET_ATIM: fstflags_t = 0x0001; | ||
| 175 | pub const FILESTAT_SET_ATIM_NOW: fstflags_t = 0x0002; | ||
| 176 | pub const FILESTAT_SET_MTIM: fstflags_t = 0x0004; | ||
| 177 | pub const FILESTAT_SET_MTIM_NOW: fstflags_t = 0x0008; | ||
| 178 | |||
| 179 | pub const inode_t = u64; | ||
| 180 | |||
| 181 | pub const linkcount_t = u32; | ||
| 182 | |||
| 183 | pub const lookupflags_t = u32; | ||
| 184 | pub const LOOKUP_SYMLINK_FOLLOW: lookupflags_t = 0x00000001; | ||
| 185 | |||
| 186 | pub const oflags_t = u16; | ||
| 187 | pub const O_CREAT: oflags_t = 0x0001; | ||
| 188 | pub const O_DIRECTORY: oflags_t = 0x0002; | ||
| 189 | pub const O_EXCL: oflags_t = 0x0004; | ||
| 190 | pub const O_TRUNC: oflags_t = 0x0008; | ||
| 191 | |||
| 192 | pub const preopentype_t = u8; | ||
| 193 | pub const PREOPENTYPE_DIR: preopentype_t = 0; | ||
| 194 | |||
| 195 | pub 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 | |||
| 204 | pub const riflags_t = u16; | ||
| 205 | pub const SOCK_RECV_PEEK: riflags_t = 0x0001; | ||
| 206 | pub const SOCK_RECV_WAITALL: riflags_t = 0x0002; | ||
| 207 | |||
| 208 | pub const rights_t = u64; | ||
| 209 | pub const RIGHT_FD_DATASYNC: rights_t = 0x0000000000000001; | ||
| 210 | pub const RIGHT_FD_READ: rights_t = 0x0000000000000002; | ||
| 211 | pub const RIGHT_FD_SEEK: rights_t = 0x0000000000000004; | ||
| 212 | pub const RIGHT_FD_FDSTAT_SET_FLAGS: rights_t = 0x0000000000000008; | ||
| 213 | pub const RIGHT_FD_SYNC: rights_t = 0x0000000000000010; | ||
| 214 | pub const RIGHT_FD_TELL: rights_t = 0x0000000000000020; | ||
| 215 | pub const RIGHT_FD_WRITE: rights_t = 0x0000000000000040; | ||
| 216 | pub const RIGHT_FD_ADVISE: rights_t = 0x0000000000000080; | ||
| 217 | pub const RIGHT_FD_ALLOCATE: rights_t = 0x0000000000000100; | ||
| 218 | pub const RIGHT_PATH_CREATE_DIRECTORY: rights_t = 0x0000000000000200; | ||
| 219 | pub const RIGHT_PATH_CREATE_FILE: rights_t = 0x0000000000000400; | ||
| 220 | pub const RIGHT_PATH_LINK_SOURCE: rights_t = 0x0000000000000800; | ||
| 221 | pub const RIGHT_PATH_LINK_TARGET: rights_t = 0x0000000000001000; | ||
| 222 | pub const RIGHT_PATH_OPEN: rights_t = 0x0000000000002000; | ||
| 223 | pub const RIGHT_FD_READDIR: rights_t = 0x0000000000004000; | ||
| 224 | pub const RIGHT_PATH_READLINK: rights_t = 0x0000000000008000; | ||
| 225 | pub const RIGHT_PATH_RENAME_SOURCE: rights_t = 0x0000000000010000; | ||
| 226 | pub const RIGHT_PATH_RENAME_TARGET: rights_t = 0x0000000000020000; | ||
| 227 | pub const RIGHT_PATH_FILESTAT_GET: rights_t = 0x0000000000040000; | ||
| 228 | pub const RIGHT_PATH_FILESTAT_SET_SIZE: rights_t = 0x0000000000080000; | ||
| 229 | pub const RIGHT_PATH_FILESTAT_SET_TIMES: rights_t = 0x0000000000100000; | ||
| 230 | pub const RIGHT_FD_FILESTAT_GET: rights_t = 0x0000000000200000; | ||
| 231 | pub const RIGHT_FD_FILESTAT_SET_SIZE: rights_t = 0x0000000000400000; | ||
| 232 | pub const RIGHT_FD_FILESTAT_SET_TIMES: rights_t = 0x0000000000800000; | ||
| 233 | pub const RIGHT_PATH_SYMLINK: rights_t = 0x0000000001000000; | ||
| 234 | pub const RIGHT_PATH_REMOVE_DIRECTORY: rights_t = 0x0000000002000000; | ||
| 235 | pub const RIGHT_PATH_UNLINK_FILE: rights_t = 0x0000000004000000; | ||
| 236 | pub const RIGHT_POLL_FD_READWRITE: rights_t = 0x0000000008000000; | ||
| 237 | pub const RIGHT_SOCK_SHUTDOWN: rights_t = 0x0000000010000000; | ||
| 238 | |||
| 239 | pub const roflags_t = u16; | ||
| 240 | pub const SOCK_RECV_DATA_TRUNCATED: roflags_t = 0x0001; | ||
| 241 | |||
| 242 | pub const sdflags_t = u8; | ||
| 243 | pub const SHUT_RD: sdflags_t = 0x01; | ||
| 244 | pub const SHUT_WR: sdflags_t = 0x02; | ||
| 245 | |||
| 246 | pub const siflags_t = u16; | ||
| 247 | |||
| 248 | pub const signal_t = u8; | ||
| 249 | pub const SIGHUP: signal_t = 1; | ||
| 250 | pub const SIGINT: signal_t = 2; | ||
| 251 | pub const SIGQUIT: signal_t = 3; | ||
| 252 | pub const SIGILL: signal_t = 4; | ||
| 253 | pub const SIGTRAP: signal_t = 5; | ||
| 254 | pub const SIGABRT: signal_t = 6; | ||
| 255 | pub const SIGBUS: signal_t = 7; | ||
| 256 | pub const SIGFPE: signal_t = 8; | ||
| 257 | pub const SIGKILL: signal_t = 9; | ||
| 258 | pub const SIGUSR1: signal_t = 10; | ||
| 259 | pub const SIGSEGV: signal_t = 11; | ||
| 260 | pub const SIGUSR2: signal_t = 12; | ||
| 261 | pub const SIGPIPE: signal_t = 13; | ||
| 262 | pub const SIGALRM: signal_t = 14; | ||
| 263 | pub const SIGTERM: signal_t = 15; | ||
| 264 | pub const SIGCHLD: signal_t = 16; | ||
| 265 | pub const SIGCONT: signal_t = 17; | ||
| 266 | pub const SIGSTOP: signal_t = 18; | ||
| 267 | pub const SIGTSTP: signal_t = 19; | ||
| 268 | pub const SIGTTIN: signal_t = 20; | ||
| 269 | pub const SIGTTOU: signal_t = 21; | ||
| 270 | pub const SIGURG: signal_t = 22; | ||
| 271 | pub const SIGXCPU: signal_t = 23; | ||
| 272 | pub const SIGXFSZ: signal_t = 24; | ||
| 273 | pub const SIGVTALRM: signal_t = 25; | ||
| 274 | pub const SIGPROF: signal_t = 26; | ||
| 275 | pub const SIGWINCH: signal_t = 27; | ||
| 276 | pub const SIGPOLL: signal_t = 28; | ||
| 277 | pub const SIGPWR: signal_t = 29; | ||
| 278 | pub const SIGSYS: signal_t = 30; | ||
| 279 | |||
| 280 | pub const subclockflags_t = u16; | ||
| 281 | pub const SUBSCRIPTION_CLOCK_ABSTIME: subclockflags_t = 0x0001; | ||
| 282 | |||
| 283 | pub 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 | |||
| 300 | pub const timestamp_t = u64; | ||
| 301 | |||
| 302 | pub const userdata_t = u64; | ||
| 303 | |||
| 304 | pub const whence_t = u8; | ||
| 305 | pub const WHENCE_CUR: whence_t = 0; | ||
| 306 | pub const WHENCE_END: whence_t = 1; | ||
| 307 | pub 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 | |||
| 3 | use @import("../windows/bits.zig"); | ||
| 4 | |||
| 5 | pub const fd_t = HANDLE; | ||
| 6 | pub const pid_t = HANDLE; | ||
| 7 | |||
| 8 | pub const PATH_MAX = 260; | ||
| 9 | |||
| 10 | pub const time_t = c_longlong; | ||
| 11 | |||
| 12 | pub const timespec = extern struct { | ||
| 13 | tv_sec: time_t, | ||
| 14 | tv_nsec: c_long, | ||
| 15 | }; | ||
| 16 | |||
| 17 | pub const sig_atomic_t = c_int; | ||
| 18 | |||
| 19 | /// maximum signal number + 1 | ||
| 20 | pub const NSIG = 23; | ||
| 21 | |||
| 22 | // Signal types | ||
| 23 | |||
| 24 | /// interrupt | ||
| 25 | pub const SIGINT = 2; | ||
| 26 | |||
| 27 | /// illegal instruction - invalid function image | ||
| 28 | pub const SIGILL = 4; | ||
| 29 | |||
| 30 | /// floating point exception | ||
| 31 | pub const SIGFPE = 8; | ||
| 32 | |||
| 33 | /// segment violation | ||
| 34 | pub const SIGSEGV = 11; | ||
| 35 | |||
| 36 | /// Software termination signal from kill | ||
| 37 | pub const SIGTERM = 15; | ||
| 38 | |||
| 39 | /// Ctrl-Break sequence | ||
| 40 | pub const SIGBREAK = 21; | ||
| 41 | |||
| 42 | /// abnormal termination triggered by abort call | ||
| 43 | pub const SIGABRT = 22; | ||
| 44 | |||
| 45 | /// SIGABRT compatible with other platforms, same as SIGABRT | ||
| 46 | pub const SIGABRT_COMPAT = 6; | ||
| 47 | |||
| 48 | // Signal action codes | ||
| 49 | |||
| 50 | /// default signal action | ||
| 51 | pub const SIG_DFL = 0; | ||
| 52 | |||
| 53 | /// ignore signal | ||
| 54 | pub const SIG_IGN = 1; | ||
| 55 | |||
| 56 | /// return current value | ||
| 57 | pub const SIG_GET = 2; | ||
| 58 | |||
| 59 | /// signal gets error | ||
| 60 | pub const SIG_SGE = 3; | ||
| 61 | |||
| 62 | /// acknowledge | ||
| 63 | pub const SIG_ACK = 4; | ||
| 64 | |||
| 65 | /// Signal error value (returned by signal call on error) | ||
| 66 | pub const SIG_ERR = -1; | ||
| 67 | |||
| 68 | pub const SEEK_SET = 0; | ||
| 69 | pub const SEEK_CUR = 1; | ||
| 70 | pub const SEEK_END = 2; | ||
| 71 | |||
| 72 | pub const EPERM = 1; | ||
| 73 | pub const ENOENT = 2; | ||
| 74 | pub const ESRCH = 3; | ||
| 75 | pub const EINTR = 4; | ||
| 76 | pub const EIO = 5; | ||
| 77 | pub const ENXIO = 6; | ||
| 78 | pub const E2BIG = 7; | ||
| 79 | pub const ENOEXEC = 8; | ||
| 80 | pub const EBADF = 9; | ||
| 81 | pub const ECHILD = 10; | ||
| 82 | pub const EAGAIN = 11; | ||
| 83 | pub const ENOMEM = 12; | ||
| 84 | pub const EACCES = 13; | ||
| 85 | pub const EFAULT = 14; | ||
| 86 | pub const EBUSY = 16; | ||
| 87 | pub const EEXIST = 17; | ||
| 88 | pub const EXDEV = 18; | ||
| 89 | pub const ENODEV = 19; | ||
| 90 | pub const ENOTDIR = 20; | ||
| 91 | pub const EISDIR = 21; | ||
| 92 | pub const ENFILE = 23; | ||
| 93 | pub const EMFILE = 24; | ||
| 94 | pub const ENOTTY = 25; | ||
| 95 | pub const EFBIG = 27; | ||
| 96 | pub const ENOSPC = 28; | ||
| 97 | pub const ESPIPE = 29; | ||
| 98 | pub const EROFS = 30; | ||
| 99 | pub const EMLINK = 31; | ||
| 100 | pub const EPIPE = 32; | ||
| 101 | pub const EDOM = 33; | ||
| 102 | pub const EDEADLK = 36; | ||
| 103 | pub const ENAMETOOLONG = 38; | ||
| 104 | pub const ENOLCK = 39; | ||
| 105 | pub const ENOSYS = 40; | ||
| 106 | pub const ENOTEMPTY = 41; | ||
| 107 | |||
| 108 | pub const EINVAL = 22; | ||
| 109 | pub const ERANGE = 34; | ||
| 110 | pub const EILSEQ = 42; | ||
| 111 | pub const STRUNCATE = 80; | ||
| 112 | |||
| 113 | // Support EDEADLOCK for compatibility with older Microsoft C versions | ||
| 114 | pub const EDEADLOCK = EDEADLK; | ||
| 115 | |||
| 116 | // POSIX Supplement | ||
| 117 | pub const EADDRINUSE = 100; | ||
| 118 | pub const EADDRNOTAVAIL = 101; | ||
| 119 | pub const EAFNOSUPPORT = 102; | ||
| 120 | pub const EALREADY = 103; | ||
| 121 | pub const EBADMSG = 104; | ||
| 122 | pub const ECANCELED = 105; | ||
| 123 | pub const ECONNABORTED = 106; | ||
| 124 | pub const ECONNREFUSED = 107; | ||
| 125 | pub const ECONNRESET = 108; | ||
| 126 | pub const EDESTADDRREQ = 109; | ||
| 127 | pub const EHOSTUNREACH = 110; | ||
| 128 | pub const EIDRM = 111; | ||
| 129 | pub const EINPROGRESS = 112; | ||
| 130 | pub const EISCONN = 113; | ||
| 131 | pub const ELOOP = 114; | ||
| 132 | pub const EMSGSIZE = 115; | ||
| 133 | pub const ENETDOWN = 116; | ||
| 134 | pub const ENETRESET = 117; | ||
| 135 | pub const ENETUNREACH = 118; | ||
| 136 | pub const ENOBUFS = 119; | ||
| 137 | pub const ENODATA = 120; | ||
| 138 | pub const ENOLINK = 121; | ||
| 139 | pub const ENOMSG = 122; | ||
| 140 | pub const ENOPROTOOPT = 123; | ||
| 141 | pub const ENOSR = 124; | ||
| 142 | pub const ENOSTR = 125; | ||
| 143 | pub const ENOTCONN = 126; | ||
| 144 | pub const ENOTRECOVERABLE = 127; | ||
| 145 | pub const ENOTSOCK = 128; | ||
| 146 | pub const ENOTSUP = 129; | ||
| 147 | pub const EOPNOTSUPP = 130; | ||
| 148 | pub const EOTHER = 131; | ||
| 149 | pub const EOVERFLOW = 132; | ||
| 150 | pub const EOWNERDEAD = 133; | ||
| 151 | pub const EPROTO = 134; | ||
| 152 | pub const EPROTONOSUPPORT = 135; | ||
| 153 | pub const EPROTOTYPE = 136; | ||
| 154 | pub const ETIME = 137; | ||
| 155 | pub const ETIMEDOUT = 138; | ||
| 156 | pub const ETXTBSY = 139; | ||
| 157 | pub const EWOULDBLOCK = 140; | ||
| 158 | pub const EDQUOT = 10069; | ||
| 159 | |||
| 160 | pub 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. | ||
| 165 | pub const SIGKILL = @compileError("Windows libc does not have this"); | ||
| 166 | |||
| 167 | |||
std/os/child_process.zig deleted-819| ... | @@ -1,819 +0,0 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const cstr = std.cstr; | ||
| 3 | const unicode = std.unicode; | ||
| 4 | const io = std.io; | ||
| 5 | const os = std.os; | ||
| 6 | const posix = os.posix; | ||
| 7 | const windows = os.windows; | ||
| 8 | const mem = std.mem; | ||
| 9 | const debug = std.debug; | ||
| 10 | const BufMap = std.BufMap; | ||
| 11 | const Buffer = std.Buffer; | ||
| 12 | const builtin = @import("builtin"); | ||
| 13 | const Os = builtin.Os; | ||
| 14 | const LinkedList = std.LinkedList; | ||
| 15 | const windows_util = @import("windows/util.zig"); | ||
| 16 | const maxInt = std.math.maxInt; | ||
| 17 | |||
| 18 | const is_windows = builtin.os == Os.windows; | ||
| 19 | |||
| 20 | pub 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 | |||
| 659 | fn 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]. | ||
| 702 | fn 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 | |||
| 738 | fn 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 | ||
| 745 | const SECURITY_ATTRIBUTES = windows.SECURITY_ATTRIBUTES; | ||
| 746 | |||
| 747 | fn 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 | |||
| 756 | fn 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 | |||
| 765 | fn 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 | |||
| 775 | fn 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 | |||
| 785 | fn 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 | |||
| 797 | fn 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. | ||
| 804 | fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn { | ||
| 805 | writeIntFd(fd, ErrInt(@errorToInt(err))) catch {}; | ||
| 806 | posix.exit(1); | ||
| 807 | } | ||
| 808 | |||
| 809 | const ErrInt = @IntType(false, @sizeOf(anyerror) * 8); | ||
| 810 | |||
| 811 | fn 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 | |||
| 816 | fn 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 @@ |
| 1 | const builtin = @import("builtin"); | ||
| 1 | const std = @import("../std.zig"); | 2 | const std = @import("../std.zig"); |
| 2 | const c = std.c; | 3 | pub const is_the_target = switch (builtin.os) { |
| 3 | const assert = std.debug.assert; | 4 | .macosx, .tvos, .watchos, .ios => true, |
| 4 | const maxInt = std.math.maxInt; | 5 | else => false, |
| 5 | |||
| 6 | pub use @import("darwin/errno.zig"); | ||
| 7 | |||
| 8 | pub const PATH_MAX = 1024; | ||
| 9 | |||
| 10 | pub const STDIN_FILENO = 0; | ||
| 11 | pub const STDOUT_FILENO = 1; | ||
| 12 | pub const STDERR_FILENO = 2; | ||
| 13 | |||
| 14 | /// [MC2] no permissions | ||
| 15 | pub const PROT_NONE = 0x00; | ||
| 16 | |||
| 17 | /// [MC2] pages can be read | ||
| 18 | pub const PROT_READ = 0x01; | ||
| 19 | |||
| 20 | /// [MC2] pages can be written | ||
| 21 | pub const PROT_WRITE = 0x02; | ||
| 22 | |||
| 23 | /// [MC2] pages can be executed | ||
| 24 | pub const PROT_EXEC = 0x04; | ||
| 25 | |||
| 26 | /// allocated from memory, swap space | ||
| 27 | pub const MAP_ANONYMOUS = 0x1000; | ||
| 28 | |||
| 29 | /// map from file (default) | ||
| 30 | pub const MAP_FILE = 0x0000; | ||
| 31 | |||
| 32 | /// interpret addr exactly | ||
| 33 | pub const MAP_FIXED = 0x0010; | ||
| 34 | |||
| 35 | /// region may contain semaphores | ||
| 36 | pub const MAP_HASSEMAPHORE = 0x0200; | ||
| 37 | |||
| 38 | /// changes are private | ||
| 39 | pub const MAP_PRIVATE = 0x0002; | ||
| 40 | |||
| 41 | /// share changes | ||
| 42 | pub const MAP_SHARED = 0x0001; | ||
| 43 | |||
| 44 | /// don't cache pages for this mapping | ||
| 45 | pub const MAP_NOCACHE = 0x0400; | ||
| 46 | |||
| 47 | /// don't reserve needed swap area | ||
| 48 | pub const MAP_NORESERVE = 0x0040; | ||
| 49 | pub const MAP_FAILED = maxInt(usize); | ||
| 50 | |||
| 51 | /// [XSI] no hang in wait/no child to reap | ||
| 52 | pub const WNOHANG = 0x00000001; | ||
| 53 | |||
| 54 | /// [XSI] notify on stop, untraced child | ||
| 55 | pub const WUNTRACED = 0x00000002; | ||
| 56 | |||
| 57 | /// take signal on signal stack | ||
| 58 | pub const SA_ONSTACK = 0x0001; | ||
| 59 | |||
| 60 | /// restart system on signal return | ||
| 61 | pub const SA_RESTART = 0x0002; | ||
| 62 | |||
| 63 | /// reset to SIG_DFL when taking signal | ||
| 64 | pub const SA_RESETHAND = 0x0004; | ||
| 65 | |||
| 66 | /// do not generate SIGCHLD on child stop | ||
| 67 | pub const SA_NOCLDSTOP = 0x0008; | ||
| 68 | |||
| 69 | /// don't mask the signal we're delivering | ||
| 70 | pub const SA_NODEFER = 0x0010; | ||
| 71 | |||
| 72 | /// don't keep zombies around | ||
| 73 | pub const SA_NOCLDWAIT = 0x0020; | ||
| 74 | |||
| 75 | /// signal handler with SA_SIGINFO args | ||
| 76 | pub const SA_SIGINFO = 0x0040; | ||
| 77 | |||
| 78 | /// do not bounce off kernel's sigtramp | ||
| 79 | pub const SA_USERTRAMP = 0x0100; | ||
| 80 | |||
| 81 | /// signal handler with SA_SIGINFO args with 64bit regs information | ||
| 82 | pub const SA_64REGSET = 0x0200; | ||
| 83 | |||
| 84 | pub const O_LARGEFILE = 0x0000; | ||
| 85 | pub const O_PATH = 0x0000; | ||
| 86 | |||
| 87 | pub const F_OK = 0; | ||
| 88 | pub const X_OK = 1; | ||
| 89 | pub const W_OK = 2; | ||
| 90 | pub const R_OK = 4; | ||
| 91 | |||
| 92 | /// open for reading only | ||
| 93 | pub const O_RDONLY = 0x0000; | ||
| 94 | |||
| 95 | /// open for writing only | ||
| 96 | pub const O_WRONLY = 0x0001; | ||
| 97 | |||
| 98 | /// open for reading and writing | ||
| 99 | pub const O_RDWR = 0x0002; | ||
| 100 | |||
| 101 | /// do not block on open or for data to become available | ||
| 102 | pub const O_NONBLOCK = 0x0004; | ||
| 103 | |||
| 104 | /// append on each write | ||
| 105 | pub const O_APPEND = 0x0008; | ||
| 106 | |||
| 107 | /// create file if it does not exist | ||
| 108 | pub const O_CREAT = 0x0200; | ||
| 109 | |||
| 110 | /// truncate size to 0 | ||
| 111 | pub const O_TRUNC = 0x0400; | ||
| 112 | |||
| 113 | /// error if O_CREAT and the file exists | ||
| 114 | pub const O_EXCL = 0x0800; | ||
| 115 | |||
| 116 | /// atomically obtain a shared lock | ||
| 117 | pub const O_SHLOCK = 0x0010; | ||
| 118 | |||
| 119 | /// atomically obtain an exclusive lock | ||
| 120 | pub const O_EXLOCK = 0x0020; | ||
| 121 | |||
| 122 | /// do not follow symlinks | ||
| 123 | pub const O_NOFOLLOW = 0x0100; | ||
| 124 | |||
| 125 | /// allow open of symlinks | ||
| 126 | pub const O_SYMLINK = 0x200000; | ||
| 127 | |||
| 128 | /// descriptor requested for event notifications only | ||
| 129 | pub const O_EVTONLY = 0x8000; | ||
| 130 | |||
| 131 | /// mark as close-on-exec | ||
| 132 | pub const O_CLOEXEC = 0x1000000; | ||
| 133 | |||
| 134 | pub const O_ACCMODE = 3; | ||
| 135 | pub const O_ALERT = 536870912; | ||
| 136 | pub const O_ASYNC = 64; | ||
| 137 | pub const O_DIRECTORY = 1048576; | ||
| 138 | pub const O_DP_GETRAWENCRYPTED = 1; | ||
| 139 | pub const O_DP_GETRAWUNENCRYPTED = 2; | ||
| 140 | pub const O_DSYNC = 4194304; | ||
| 141 | pub const O_FSYNC = O_SYNC; | ||
| 142 | pub const O_NOCTTY = 131072; | ||
| 143 | pub const O_POPUP = 2147483648; | ||
| 144 | pub const O_SYNC = 128; | ||
| 145 | |||
| 146 | pub const SEEK_SET = 0x0; | ||
| 147 | pub const SEEK_CUR = 0x1; | ||
| 148 | pub const SEEK_END = 0x2; | ||
| 149 | |||
| 150 | pub const DT_UNKNOWN = 0; | ||
| 151 | pub const DT_FIFO = 1; | ||
| 152 | pub const DT_CHR = 2; | ||
| 153 | pub const DT_DIR = 4; | ||
| 154 | pub const DT_BLK = 6; | ||
| 155 | pub const DT_REG = 8; | ||
| 156 | pub const DT_LNK = 10; | ||
| 157 | pub const DT_SOCK = 12; | ||
| 158 | pub const DT_WHT = 14; | ||
| 159 | |||
| 160 | /// block specified signal set | ||
| 161 | pub const SIG_BLOCK = 1; | ||
| 162 | |||
| 163 | /// unblock specified signal set | ||
| 164 | pub const SIG_UNBLOCK = 2; | ||
| 165 | |||
| 166 | /// set specified signal set | ||
| 167 | pub const SIG_SETMASK = 3; | ||
| 168 | |||
| 169 | /// hangup | ||
| 170 | pub const SIGHUP = 1; | ||
| 171 | |||
| 172 | /// interrupt | ||
| 173 | pub const SIGINT = 2; | ||
| 174 | |||
| 175 | /// quit | ||
| 176 | pub const SIGQUIT = 3; | ||
| 177 | |||
| 178 | /// illegal instruction (not reset when caught) | ||
| 179 | pub const SIGILL = 4; | ||
| 180 | |||
| 181 | /// trace trap (not reset when caught) | ||
| 182 | pub const SIGTRAP = 5; | ||
| 183 | |||
| 184 | /// abort() | ||
| 185 | pub const SIGABRT = 6; | ||
| 186 | |||
| 187 | /// pollable event ([XSR] generated, not supported) | ||
| 188 | pub const SIGPOLL = 7; | ||
| 189 | |||
| 190 | /// compatibility | ||
| 191 | pub const SIGIOT = SIGABRT; | ||
| 192 | |||
| 193 | /// EMT instruction | ||
| 194 | pub const SIGEMT = 7; | ||
| 195 | |||
| 196 | /// floating point exception | ||
| 197 | pub const SIGFPE = 8; | ||
| 198 | |||
| 199 | /// kill (cannot be caught or ignored) | ||
| 200 | pub const SIGKILL = 9; | ||
| 201 | |||
| 202 | /// bus error | ||
| 203 | pub const SIGBUS = 10; | ||
| 204 | |||
| 205 | /// segmentation violation | ||
| 206 | pub const SIGSEGV = 11; | ||
| 207 | |||
| 208 | /// bad argument to system call | ||
| 209 | pub const SIGSYS = 12; | ||
| 210 | |||
| 211 | /// write on a pipe with no one to read it | ||
| 212 | pub const SIGPIPE = 13; | ||
| 213 | |||
| 214 | /// alarm clock | ||
| 215 | pub const SIGALRM = 14; | ||
| 216 | |||
| 217 | /// software termination signal from kill | ||
| 218 | pub const SIGTERM = 15; | ||
| 219 | |||
| 220 | /// urgent condition on IO channel | ||
| 221 | pub const SIGURG = 16; | ||
| 222 | |||
| 223 | /// sendable stop signal not from tty | ||
| 224 | pub const SIGSTOP = 17; | ||
| 225 | |||
| 226 | /// stop signal from tty | ||
| 227 | pub const SIGTSTP = 18; | ||
| 228 | |||
| 229 | /// continue a stopped process | ||
| 230 | pub const SIGCONT = 19; | ||
| 231 | |||
| 232 | /// to parent on child stop or exit | ||
| 233 | pub const SIGCHLD = 20; | ||
| 234 | |||
| 235 | /// to readers pgrp upon background tty read | ||
| 236 | pub const SIGTTIN = 21; | ||
| 237 | |||
| 238 | /// like TTIN for output if (tp->t_local&LTOSTOP) | ||
| 239 | pub const SIGTTOU = 22; | ||
| 240 | |||
| 241 | /// input/output possible signal | ||
| 242 | pub const SIGIO = 23; | ||
| 243 | |||
| 244 | /// exceeded CPU time limit | ||
| 245 | pub const SIGXCPU = 24; | ||
| 246 | |||
| 247 | /// exceeded file size limit | ||
| 248 | pub const SIGXFSZ = 25; | ||
| 249 | |||
| 250 | /// virtual time alarm | ||
| 251 | pub const SIGVTALRM = 26; | ||
| 252 | |||
| 253 | /// profiling time alarm | ||
| 254 | pub const SIGPROF = 27; | ||
| 255 | |||
| 256 | /// window size changes | ||
| 257 | pub const SIGWINCH = 28; | ||
| 258 | |||
| 259 | /// information request | ||
| 260 | pub const SIGINFO = 29; | ||
| 261 | |||
| 262 | /// user defined signal 1 | ||
| 263 | pub const SIGUSR1 = 30; | ||
| 264 | |||
| 265 | /// user defined signal 2 | ||
| 266 | pub const SIGUSR2 = 31; | ||
| 267 | |||
| 268 | /// no flag value | ||
| 269 | pub const KEVENT_FLAG_NONE = 0x000; | ||
| 270 | |||
| 271 | /// immediate timeout | ||
| 272 | pub const KEVENT_FLAG_IMMEDIATE = 0x001; | ||
| 273 | |||
| 274 | /// output events only include change | ||
| 275 | pub const KEVENT_FLAG_ERROR_EVENTS = 0x002; | ||
| 276 | |||
| 277 | /// add event to kq (implies enable) | ||
| 278 | pub const EV_ADD = 0x0001; | ||
| 279 | |||
| 280 | /// delete event from kq | ||
| 281 | pub const EV_DELETE = 0x0002; | ||
| 282 | |||
| 283 | /// enable event | ||
| 284 | pub const EV_ENABLE = 0x0004; | ||
| 285 | |||
| 286 | /// disable event (not reported) | ||
| 287 | pub const EV_DISABLE = 0x0008; | ||
| 288 | |||
| 289 | /// only report one occurrence | ||
| 290 | pub const EV_ONESHOT = 0x0010; | ||
| 291 | |||
| 292 | /// clear event state after reporting | ||
| 293 | pub 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 | ||
| 299 | pub const EV_RECEIPT = 0x0040; | ||
| 300 | |||
| 301 | /// disable event after reporting | ||
| 302 | pub const EV_DISPATCH = 0x0080; | ||
| 303 | |||
| 304 | /// unique kevent per udata value | ||
| 305 | pub 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 | ||
| 311 | pub const EV_DISPATCH2 = EV_DISPATCH | EV_UDATA_SPECIFIC; | ||
| 312 | |||
| 313 | /// report that source has vanished | ||
| 314 | /// ... only valid with EV_DISPATCH2 | ||
| 315 | pub const EV_VANISHED = 0x0200; | ||
| 316 | |||
| 317 | /// reserved by system | ||
| 318 | pub const EV_SYSFLAGS = 0xF000; | ||
| 319 | |||
| 320 | /// filter-specific flag | ||
| 321 | pub const EV_FLAG0 = 0x1000; | ||
| 322 | |||
| 323 | /// filter-specific flag | ||
| 324 | pub const EV_FLAG1 = 0x2000; | ||
| 325 | |||
| 326 | /// EOF detected | ||
| 327 | pub const EV_EOF = 0x8000; | ||
| 328 | |||
| 329 | /// error, data contains errno | ||
| 330 | pub const EV_ERROR = 0x4000; | ||
| 331 | |||
| 332 | pub const EV_POLL = EV_FLAG0; | ||
| 333 | pub const EV_OOBAND = EV_FLAG1; | ||
| 334 | |||
| 335 | pub const EVFILT_READ = -1; | ||
| 336 | pub const EVFILT_WRITE = -2; | ||
| 337 | |||
| 338 | /// attached to aio requests | ||
| 339 | pub const EVFILT_AIO = -3; | ||
| 340 | |||
| 341 | /// attached to vnodes | ||
| 342 | pub const EVFILT_VNODE = -4; | ||
| 343 | |||
| 344 | /// attached to struct proc | ||
| 345 | pub const EVFILT_PROC = -5; | ||
| 346 | |||
| 347 | /// attached to struct proc | ||
| 348 | pub const EVFILT_SIGNAL = -6; | ||
| 349 | |||
| 350 | /// timers | ||
| 351 | pub const EVFILT_TIMER = -7; | ||
| 352 | |||
| 353 | /// Mach portsets | ||
| 354 | pub const EVFILT_MACHPORT = -8; | ||
| 355 | |||
| 356 | /// Filesystem events | ||
| 357 | pub const EVFILT_FS = -9; | ||
| 358 | |||
| 359 | /// User events | ||
| 360 | pub const EVFILT_USER = -10; | ||
| 361 | |||
| 362 | /// Virtual memory events | ||
| 363 | pub const EVFILT_VM = -12; | ||
| 364 | |||
| 365 | /// Exception events | ||
| 366 | pub const EVFILT_EXCEPT = -15; | ||
| 367 | |||
| 368 | pub const EVFILT_SYSCOUNT = 17; | ||
| 369 | |||
| 370 | /// On input, NOTE_TRIGGER causes the event to be triggered for output. | ||
| 371 | pub const NOTE_TRIGGER = 0x01000000; | ||
| 372 | |||
| 373 | /// ignore input fflags | ||
| 374 | pub const NOTE_FFNOP = 0x00000000; | ||
| 375 | |||
| 376 | /// and fflags | ||
| 377 | pub const NOTE_FFAND = 0x40000000; | ||
| 378 | |||
| 379 | /// or fflags | ||
| 380 | pub const NOTE_FFOR = 0x80000000; | ||
| 381 | |||
| 382 | /// copy fflags | ||
| 383 | pub const NOTE_FFCOPY = 0xc0000000; | ||
| 384 | |||
| 385 | /// mask for operations | ||
| 386 | pub const NOTE_FFCTRLMASK = 0xc0000000; | ||
| 387 | pub const NOTE_FFLAGSMASK = 0x00ffffff; | ||
| 388 | |||
| 389 | /// low water mark | ||
| 390 | pub const NOTE_LOWAT = 0x00000001; | ||
| 391 | |||
| 392 | /// OOB data | ||
| 393 | pub const NOTE_OOB = 0x00000002; | ||
| 394 | |||
| 395 | /// vnode was removed | ||
| 396 | pub const NOTE_DELETE = 0x00000001; | ||
| 397 | |||
| 398 | /// data contents changed | ||
| 399 | pub const NOTE_WRITE = 0x00000002; | ||
| 400 | |||
| 401 | /// size increased | ||
| 402 | pub const NOTE_EXTEND = 0x00000004; | ||
| 403 | |||
| 404 | /// attributes changed | ||
| 405 | pub const NOTE_ATTRIB = 0x00000008; | ||
| 406 | |||
| 407 | /// link count changed | ||
| 408 | pub const NOTE_LINK = 0x00000010; | ||
| 409 | |||
| 410 | /// vnode was renamed | ||
| 411 | pub const NOTE_RENAME = 0x00000020; | ||
| 412 | |||
| 413 | /// vnode access was revoked | ||
| 414 | pub const NOTE_REVOKE = 0x00000040; | ||
| 415 | |||
| 416 | /// No specific vnode event: to test for EVFILT_READ activation | ||
| 417 | pub const NOTE_NONE = 0x00000080; | ||
| 418 | |||
| 419 | /// vnode was unlocked by flock(2) | ||
| 420 | pub const NOTE_FUNLOCK = 0x00000100; | ||
| 421 | |||
| 422 | /// process exited | ||
| 423 | pub const NOTE_EXIT = 0x80000000; | ||
| 424 | |||
| 425 | /// process forked | ||
| 426 | pub const NOTE_FORK = 0x40000000; | ||
| 427 | |||
| 428 | /// process exec'd | ||
| 429 | pub const NOTE_EXEC = 0x20000000; | ||
| 430 | |||
| 431 | /// shared with EVFILT_SIGNAL | ||
| 432 | pub const NOTE_SIGNAL = 0x08000000; | ||
| 433 | |||
| 434 | /// exit status to be returned, valid for child process only | ||
| 435 | pub const NOTE_EXITSTATUS = 0x04000000; | ||
| 436 | |||
| 437 | /// provide details on reasons for exit | ||
| 438 | pub const NOTE_EXIT_DETAIL = 0x02000000; | ||
| 439 | |||
| 440 | /// mask for signal & exit status | ||
| 441 | pub const NOTE_PDATAMASK = 0x000fffff; | ||
| 442 | pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK); | ||
| 443 | |||
| 444 | pub const NOTE_EXIT_DETAIL_MASK = 0x00070000; | ||
| 445 | pub const NOTE_EXIT_DECRYPTFAIL = 0x00010000; | ||
| 446 | pub const NOTE_EXIT_MEMORY = 0x00020000; | ||
| 447 | pub const NOTE_EXIT_CSERROR = 0x00040000; | ||
| 448 | |||
| 449 | /// will react on memory pressure | ||
| 450 | pub const NOTE_VM_PRESSURE = 0x80000000; | ||
| 451 | |||
| 452 | /// will quit on memory pressure, possibly after cleaning up dirty state | ||
| 453 | pub const NOTE_VM_PRESSURE_TERMINATE = 0x40000000; | ||
| 454 | |||
| 455 | /// will quit immediately on memory pressure | ||
| 456 | pub const NOTE_VM_PRESSURE_SUDDEN_TERMINATE = 0x20000000; | ||
| 457 | |||
| 458 | /// there was an error | ||
| 459 | pub const NOTE_VM_ERROR = 0x10000000; | ||
| 460 | |||
| 461 | /// data is seconds | ||
| 462 | pub const NOTE_SECONDS = 0x00000001; | ||
| 463 | |||
| 464 | /// data is microseconds | ||
| 465 | pub const NOTE_USECONDS = 0x00000002; | ||
| 466 | |||
| 467 | /// data is nanoseconds | ||
| 468 | pub const NOTE_NSECONDS = 0x00000004; | ||
| 469 | |||
| 470 | /// absolute timeout | ||
| 471 | pub const NOTE_ABSOLUTE = 0x00000008; | ||
| 472 | |||
| 473 | /// ext[1] holds leeway for power aware timers | ||
| 474 | pub const NOTE_LEEWAY = 0x00000010; | ||
| 475 | |||
| 476 | /// system does minimal timer coalescing | ||
| 477 | pub const NOTE_CRITICAL = 0x00000020; | ||
| 478 | |||
| 479 | /// system does maximum timer coalescing | ||
| 480 | pub const NOTE_BACKGROUND = 0x00000040; | ||
| 481 | pub const NOTE_MACH_CONTINUOUS_TIME = 0x00000080; | ||
| 482 | |||
| 483 | /// data is mach absolute time units | ||
| 484 | pub const NOTE_MACHTIME = 0x00000100; | ||
| 485 | |||
| 486 | pub const AF_UNSPEC = 0; | ||
| 487 | pub const AF_LOCAL = 1; | ||
| 488 | pub const AF_UNIX = AF_LOCAL; | ||
| 489 | pub const AF_INET = 2; | ||
| 490 | pub const AF_SYS_CONTROL = 2; | ||
| 491 | pub const AF_IMPLINK = 3; | ||
| 492 | pub const AF_PUP = 4; | ||
| 493 | pub const AF_CHAOS = 5; | ||
| 494 | pub const AF_NS = 6; | ||
| 495 | pub const AF_ISO = 7; | ||
| 496 | pub const AF_OSI = AF_ISO; | ||
| 497 | pub const AF_ECMA = 8; | ||
| 498 | pub const AF_DATAKIT = 9; | ||
| 499 | pub const AF_CCITT = 10; | ||
| 500 | pub const AF_SNA = 11; | ||
| 501 | pub const AF_DECnet = 12; | ||
| 502 | pub const AF_DLI = 13; | ||
| 503 | pub const AF_LAT = 14; | ||
| 504 | pub const AF_HYLINK = 15; | ||
| 505 | pub const AF_APPLETALK = 16; | ||
| 506 | pub const AF_ROUTE = 17; | ||
| 507 | pub const AF_LINK = 18; | ||
| 508 | pub const AF_XTP = 19; | ||
| 509 | pub const AF_COIP = 20; | ||
| 510 | pub const AF_CNT = 21; | ||
| 511 | pub const AF_RTIP = 22; | ||
| 512 | pub const AF_IPX = 23; | ||
| 513 | pub const AF_SIP = 24; | ||
| 514 | pub const AF_PIP = 25; | ||
| 515 | pub const AF_ISDN = 28; | ||
| 516 | pub const AF_E164 = AF_ISDN; | ||
| 517 | pub const AF_KEY = 29; | ||
| 518 | pub const AF_INET6 = 30; | ||
| 519 | pub const AF_NATM = 31; | ||
| 520 | pub const AF_SYSTEM = 32; | ||
| 521 | pub const AF_NETBIOS = 33; | ||
| 522 | pub const AF_PPP = 34; | ||
| 523 | pub const AF_MAX = 40; | ||
| 524 | |||
| 525 | pub const PF_UNSPEC = AF_UNSPEC; | ||
| 526 | pub const PF_LOCAL = AF_LOCAL; | ||
| 527 | pub const PF_UNIX = PF_LOCAL; | ||
| 528 | pub const PF_INET = AF_INET; | ||
| 529 | pub const PF_IMPLINK = AF_IMPLINK; | ||
| 530 | pub const PF_PUP = AF_PUP; | ||
| 531 | pub const PF_CHAOS = AF_CHAOS; | ||
| 532 | pub const PF_NS = AF_NS; | ||
| 533 | pub const PF_ISO = AF_ISO; | ||
| 534 | pub const PF_OSI = AF_ISO; | ||
| 535 | pub const PF_ECMA = AF_ECMA; | ||
| 536 | pub const PF_DATAKIT = AF_DATAKIT; | ||
| 537 | pub const PF_CCITT = AF_CCITT; | ||
| 538 | pub const PF_SNA = AF_SNA; | ||
| 539 | pub const PF_DECnet = AF_DECnet; | ||
| 540 | pub const PF_DLI = AF_DLI; | ||
| 541 | pub const PF_LAT = AF_LAT; | ||
| 542 | pub const PF_HYLINK = AF_HYLINK; | ||
| 543 | pub const PF_APPLETALK = AF_APPLETALK; | ||
| 544 | pub const PF_ROUTE = AF_ROUTE; | ||
| 545 | pub const PF_LINK = AF_LINK; | ||
| 546 | pub const PF_XTP = AF_XTP; | ||
| 547 | pub const PF_COIP = AF_COIP; | ||
| 548 | pub const PF_CNT = AF_CNT; | ||
| 549 | pub const PF_SIP = AF_SIP; | ||
| 550 | pub const PF_IPX = AF_IPX; | ||
| 551 | pub const PF_RTIP = AF_RTIP; | ||
| 552 | pub const PF_PIP = AF_PIP; | ||
| 553 | pub const PF_ISDN = AF_ISDN; | ||
| 554 | pub const PF_KEY = AF_KEY; | ||
| 555 | pub const PF_INET6 = AF_INET6; | ||
| 556 | pub const PF_NATM = AF_NATM; | ||
| 557 | pub const PF_SYSTEM = AF_SYSTEM; | ||
| 558 | pub const PF_NETBIOS = AF_NETBIOS; | ||
| 559 | pub const PF_PPP = AF_PPP; | ||
| 560 | pub const PF_MAX = AF_MAX; | ||
| 561 | |||
| 562 | pub const SYSPROTO_EVENT = 1; | ||
| 563 | pub const SYSPROTO_CONTROL = 2; | ||
| 564 | |||
| 565 | pub const SOCK_STREAM = 1; | ||
| 566 | pub const SOCK_DGRAM = 2; | ||
| 567 | pub const SOCK_RAW = 3; | ||
| 568 | pub const SOCK_RDM = 4; | ||
| 569 | pub const SOCK_SEQPACKET = 5; | ||
| 570 | pub const SOCK_MAXADDRLEN = 255; | ||
| 571 | |||
| 572 | pub const IPPROTO_ICMP = 1; | ||
| 573 | pub const IPPROTO_ICMPV6 = 58; | ||
| 574 | pub const IPPROTO_TCP = 6; | ||
| 575 | pub const IPPROTO_UDP = 17; | ||
| 576 | pub const IPPROTO_IP = 0; | ||
| 577 | pub const IPPROTO_IPV6 = 41; | ||
| 578 | |||
| 579 | fn wstatus(x: i32) i32 { | ||
| 580 | return x & 0o177; | ||
| 581 | } | ||
| 582 | const wstopped = 0o177; | ||
| 583 | pub fn WEXITSTATUS(x: i32) i32 { | ||
| 584 | return x >> 8; | ||
| 585 | } | ||
| 586 | pub fn WTERMSIG(x: i32) i32 { | ||
| 587 | return wstatus(x); | ||
| 588 | } | ||
| 589 | pub fn WSTOPSIG(x: i32) i32 { | ||
| 590 | return x >> 8; | ||
| 591 | } | ||
| 592 | pub fn WIFEXITED(x: i32) bool { | ||
| 593 | return wstatus(x) == 0; | ||
| 594 | } | ||
| 595 | pub fn WIFSTOPPED(x: i32) bool { | ||
| 596 | return wstatus(x) == wstopped and WSTOPSIG(x) != 0x13; | ||
| 597 | } | ||
| 598 | pub 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. | ||
| 603 | pub 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 | |||
| 608 | pub fn close(fd: i32) usize { | ||
| 609 | return errnoWrap(c.close(fd)); | ||
| 610 | } | ||
| 611 | |||
| 612 | pub fn abort() noreturn { | ||
| 613 | c.abort(); | ||
| 614 | } | ||
| 615 | |||
| 616 | // bind(int socket, const struct sockaddr *address, socklen_t address_len) | ||
| 617 | pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize { | ||
| 618 | return errnoWrap(c.bind(@bitCast(c_int, fd), addr, len)); | ||
| 619 | } | ||
| 620 | |||
| 621 | pub fn exit(code: i32) noreturn { | ||
| 622 | c.exit(code); | ||
| 623 | } | ||
| 624 | |||
| 625 | pub fn isatty(fd: i32) bool { | ||
| 626 | return c.isatty(fd) != 0; | ||
| 627 | } | ||
| 628 | |||
| 629 | pub fn fstat(fd: i32, buf: *c.Stat) usize { | ||
| 630 | return errnoWrap(c.@"fstat$INODE64"(fd, buf)); | ||
| 631 | } | ||
| 632 | |||
| 633 | pub 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 | ||
| 638 | pub fn open(path: [*]const u8, flags: u32, mode: usize) usize { | ||
| 639 | return errnoWrap(c.open(path, @bitCast(c_int, flags), mode)); | ||
| 640 | } | ||
| 641 | |||
| 642 | pub fn raise(sig: i32) usize { | ||
| 643 | return errnoWrap(c.raise(sig)); | ||
| 644 | } | ||
| 645 | |||
| 646 | pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize { | ||
| 647 | return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte)); | ||
| 648 | } | ||
| 649 | |||
| 650 | pub 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 | |||
| 654 | pub fn stat(noalias path: [*]const u8, noalias buf: *stat) usize { | ||
| 655 | return errnoWrap(c.stat(path, buf)); | ||
| 656 | } | ||
| 657 | |||
| 658 | pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize { | ||
| 659 | return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte)); | ||
| 660 | } | ||
| 661 | |||
| 662 | pub 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 | |||
| 666 | pub 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 | |||
| 679 | pub fn munmap(address: usize, length: usize) usize { | ||
| 680 | return errnoWrap(c.munmap(@intToPtr(?*c_void, address), length)); | ||
| 681 | } | ||
| 682 | |||
| 683 | pub fn unlink(path: [*]const u8) usize { | ||
| 684 | return errnoWrap(c.unlink(path)); | ||
| 685 | } | ||
| 686 | |||
| 687 | pub fn getcwd(buf: [*]u8, size: usize) usize { | ||
| 688 | return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0; | ||
| 689 | } | ||
| 690 | |||
| 691 | pub 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 | |||
| 696 | pub fn fork() usize { | ||
| 697 | return errnoWrap(c.fork()); | ||
| 698 | } | ||
| 699 | |||
| 700 | pub fn access(path: [*]const u8, mode: u32) usize { | ||
| 701 | return errnoWrap(c.access(path, mode)); | ||
| 702 | } | ||
| 703 | |||
| 704 | pub 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 | |||
| 709 | pub 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 | |||
| 713 | pub fn kqueue() usize { | ||
| 714 | return errnoWrap(c.kqueue()); | ||
| 715 | } | ||
| 716 | |||
| 717 | pub 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 | |||
| 728 | pub 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 | |||
| 738 | pub fn mkdir(path: [*]const u8, mode: u32) usize { | ||
| 739 | return errnoWrap(c.mkdir(path, mode)); | ||
| 740 | } | ||
| 741 | |||
| 742 | pub fn symlink(existing: [*]const u8, new: [*]const u8) usize { | ||
| 743 | return errnoWrap(c.symlink(existing, new)); | ||
| 744 | } | ||
| 745 | |||
| 746 | pub 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 | |||
| 750 | pub 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 | |||
| 754 | pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize { | ||
| 755 | return errnoWrap(c.sysctlnametomib(name, wibp, sizep)); | ||
| 756 | } | ||
| 757 | |||
| 758 | pub fn rename(old: [*]const u8, new: [*]const u8) usize { | ||
| 759 | return errnoWrap(c.rename(old, new)); | ||
| 760 | } | ||
| 761 | |||
| 762 | pub fn rmdir(path: [*]const u8) usize { | ||
| 763 | return errnoWrap(c.rmdir(path)); | ||
| 764 | } | ||
| 765 | |||
| 766 | pub fn chdir(path: [*]const u8) usize { | ||
| 767 | return errnoWrap(c.chdir(path)); | ||
| 768 | } | ||
| 769 | |||
| 770 | pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize { | ||
| 771 | return errnoWrap(c.execve(path, argv, envp)); | ||
| 772 | } | ||
| 773 | |||
| 774 | pub fn dup2(old: i32, new: i32) usize { | ||
| 775 | return errnoWrap(c.dup2(old, new)); | ||
| 776 | } | ||
| 777 | |||
| 778 | pub 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 | |||
| 782 | pub fn gettimeofday(tv: ?*timeval, tz: ?*timezone) usize { | ||
| 783 | return errnoWrap(c.gettimeofday(tv, tz)); | ||
| 784 | } | ||
| 785 | |||
| 786 | pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize { | ||
| 787 | return errnoWrap(c.nanosleep(req, rem)); | ||
| 788 | } | ||
| 789 | |||
| 790 | pub 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 | |||
| 794 | pub fn setreuid(ruid: u32, euid: u32) usize { | ||
| 795 | return errnoWrap(c.setreuid(ruid, euid)); | ||
| 796 | } | ||
| 797 | |||
| 798 | pub fn setregid(rgid: u32, egid: u32) usize { | ||
| 799 | return errnoWrap(c.setregid(rgid, egid)); | ||
| 800 | } | ||
| 801 | |||
| 802 | pub 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 | |||
| 806 | pub 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 | |||
| 829 | pub 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 | |||
| 833 | pub const iovec = extern struct { | ||
| 834 | iov_base: [*]u8, | ||
| 835 | iov_len: usize, | ||
| 836 | }; | 6 | }; |
| 837 | 7 | pub use std.c; | |
| 838 | pub const iovec_const = extern struct { | ||
| 839 | iov_base: [*]const u8, | ||
| 840 | iov_len: usize, | ||
| 841 | }; | ||
| 842 | |||
| 843 | pub const sigset_t = c.sigset_t; | ||
| 844 | pub const empty_sigset = sigset_t(0); | ||
| 845 | |||
| 846 | pub const timespec = c.timespec; | ||
| 847 | pub const Stat = c.Stat; | ||
| 848 | pub const dirent = c.dirent; | ||
| 849 | |||
| 850 | pub const in_port_t = c.in_port_t; | ||
| 851 | pub const sa_family_t = c.sa_family_t; | ||
| 852 | pub const socklen_t = c.socklen_t; | ||
| 853 | |||
| 854 | pub const sockaddr = c.sockaddr; | ||
| 855 | pub const sockaddr_in = c.sockaddr_in; | ||
| 856 | pub const sockaddr_in6 = c.sockaddr_in6; | ||
| 857 | |||
| 858 | /// Renamed from `kevent` to `Kevent` to avoid conflict with the syscall. | ||
| 859 | pub const Kevent = c.Kevent; | ||
| 860 | pub const kevent64_s = c.kevent64_s; | ||
| 861 | |||
| 862 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. | ||
| 863 | pub const Sigaction = struct { | ||
| 864 | handler: extern fn (i32) void, | ||
| 865 | mask: sigset_t, | ||
| 866 | flags: u32, | ||
| 867 | }; | ||
| 868 | |||
| 869 | pub 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. | ||
| 876 | fn errnoWrap(value: isize) usize { | ||
| 877 | return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value); | ||
| 878 | } | ||
| 879 | |||
| 880 | pub const timezone = c.timezone; | ||
| 881 | pub const timeval = c.timeval; | ||
| 882 | pub const mach_timebase_info_data = c.mach_timebase_info_data; | ||
| 883 | |||
| 884 | pub const mach_absolute_time = c.mach_absolute_time; | ||
| 885 | pub const mach_timebase_info = c.mach_timebase_info; |
std/os/darwin/errno.zig deleted-328| ... | @@ -1,328 +0,0 @@ | ||
| 1 | /// Operation not permitted | ||
| 2 | pub const EPERM = 1; | ||
| 3 | |||
| 4 | /// No such file or directory | ||
| 5 | pub const ENOENT = 2; | ||
| 6 | |||
| 7 | /// No such process | ||
| 8 | pub const ESRCH = 3; | ||
| 9 | |||
| 10 | /// Interrupted system call | ||
| 11 | pub const EINTR = 4; | ||
| 12 | |||
| 13 | /// Input/output error | ||
| 14 | pub const EIO = 5; | ||
| 15 | |||
| 16 | /// Device not configured | ||
| 17 | pub const ENXIO = 6; | ||
| 18 | |||
| 19 | /// Argument list too long | ||
| 20 | pub const E2BIG = 7; | ||
| 21 | |||
| 22 | /// Exec format error | ||
| 23 | pub const ENOEXEC = 8; | ||
| 24 | |||
| 25 | /// Bad file descriptor | ||
| 26 | pub const EBADF = 9; | ||
| 27 | |||
| 28 | /// No child processes | ||
| 29 | pub const ECHILD = 10; | ||
| 30 | |||
| 31 | /// Resource deadlock avoided | ||
| 32 | pub const EDEADLK = 11; | ||
| 33 | |||
| 34 | /// Cannot allocate memory | ||
| 35 | pub const ENOMEM = 12; | ||
| 36 | |||
| 37 | /// Permission denied | ||
| 38 | pub const EACCES = 13; | ||
| 39 | |||
| 40 | /// Bad address | ||
| 41 | pub const EFAULT = 14; | ||
| 42 | |||
| 43 | /// Block device required | ||
| 44 | pub const ENOTBLK = 15; | ||
| 45 | |||
| 46 | /// Device / Resource busy | ||
| 47 | pub const EBUSY = 16; | ||
| 48 | |||
| 49 | /// File exists | ||
| 50 | pub const EEXIST = 17; | ||
| 51 | |||
| 52 | /// Cross-device link | ||
| 53 | pub const EXDEV = 18; | ||
| 54 | |||
| 55 | /// Operation not supported by device | ||
| 56 | pub const ENODEV = 19; | ||
| 57 | |||
| 58 | /// Not a directory | ||
| 59 | pub const ENOTDIR = 20; | ||
| 60 | |||
| 61 | /// Is a directory | ||
| 62 | pub const EISDIR = 21; | ||
| 63 | |||
| 64 | /// Invalid argument | ||
| 65 | pub const EINVAL = 22; | ||
| 66 | |||
| 67 | /// Too many open files in system | ||
| 68 | pub const ENFILE = 23; | ||
| 69 | |||
| 70 | /// Too many open files | ||
| 71 | pub const EMFILE = 24; | ||
| 72 | |||
| 73 | /// Inappropriate ioctl for device | ||
| 74 | pub const ENOTTY = 25; | ||
| 75 | |||
| 76 | /// Text file busy | ||
| 77 | pub const ETXTBSY = 26; | ||
| 78 | |||
| 79 | /// File too large | ||
| 80 | pub const EFBIG = 27; | ||
| 81 | |||
| 82 | /// No space left on device | ||
| 83 | pub const ENOSPC = 28; | ||
| 84 | |||
| 85 | /// Illegal seek | ||
| 86 | pub const ESPIPE = 29; | ||
| 87 | |||
| 88 | /// Read-only file system | ||
| 89 | pub const EROFS = 30; | ||
| 90 | |||
| 91 | /// Too many links | ||
| 92 | pub const EMLINK = 31; | ||
| 93 | /// Broken pipe | ||
| 94 | |||
| 95 | // math software | ||
| 96 | pub const EPIPE = 32; | ||
| 97 | |||
| 98 | /// Numerical argument out of domain | ||
| 99 | pub const EDOM = 33; | ||
| 100 | /// Result too large | ||
| 101 | |||
| 102 | // non-blocking and interrupt i/o | ||
| 103 | pub const ERANGE = 34; | ||
| 104 | |||
| 105 | /// Resource temporarily unavailable | ||
| 106 | pub const EAGAIN = 35; | ||
| 107 | |||
| 108 | /// Operation would block | ||
| 109 | pub const EWOULDBLOCK = EAGAIN; | ||
| 110 | |||
| 111 | /// Operation now in progress | ||
| 112 | pub const EINPROGRESS = 36; | ||
| 113 | /// Operation already in progress | ||
| 114 | |||
| 115 | // ipc/network software -- argument errors | ||
| 116 | pub const EALREADY = 37; | ||
| 117 | |||
| 118 | /// Socket operation on non-socket | ||
| 119 | pub const ENOTSOCK = 38; | ||
| 120 | |||
| 121 | /// Destination address required | ||
| 122 | pub const EDESTADDRREQ = 39; | ||
| 123 | |||
| 124 | /// Message too long | ||
| 125 | pub const EMSGSIZE = 40; | ||
| 126 | |||
| 127 | /// Protocol wrong type for socket | ||
| 128 | pub const EPROTOTYPE = 41; | ||
| 129 | |||
| 130 | /// Protocol not available | ||
| 131 | pub const ENOPROTOOPT = 42; | ||
| 132 | |||
| 133 | /// Protocol not supported | ||
| 134 | pub const EPROTONOSUPPORT = 43; | ||
| 135 | |||
| 136 | /// Socket type not supported | ||
| 137 | pub const ESOCKTNOSUPPORT = 44; | ||
| 138 | |||
| 139 | /// Operation not supported | ||
| 140 | pub const ENOTSUP = 45; | ||
| 141 | |||
| 142 | /// Protocol family not supported | ||
| 143 | pub const EPFNOSUPPORT = 46; | ||
| 144 | |||
| 145 | /// Address family not supported by protocol family | ||
| 146 | pub const EAFNOSUPPORT = 47; | ||
| 147 | |||
| 148 | /// Address already in use | ||
| 149 | pub const EADDRINUSE = 48; | ||
| 150 | /// Can't assign requested address | ||
| 151 | |||
| 152 | // ipc/network software -- operational errors | ||
| 153 | pub const EADDRNOTAVAIL = 49; | ||
| 154 | |||
| 155 | /// Network is down | ||
| 156 | pub const ENETDOWN = 50; | ||
| 157 | |||
| 158 | /// Network is unreachable | ||
| 159 | pub const ENETUNREACH = 51; | ||
| 160 | |||
| 161 | /// Network dropped connection on reset | ||
| 162 | pub const ENETRESET = 52; | ||
| 163 | |||
| 164 | /// Software caused connection abort | ||
| 165 | pub const ECONNABORTED = 53; | ||
| 166 | |||
| 167 | /// Connection reset by peer | ||
| 168 | pub const ECONNRESET = 54; | ||
| 169 | |||
| 170 | /// No buffer space available | ||
| 171 | pub const ENOBUFS = 55; | ||
| 172 | |||
| 173 | /// Socket is already connected | ||
| 174 | pub const EISCONN = 56; | ||
| 175 | |||
| 176 | /// Socket is not connected | ||
| 177 | pub const ENOTCONN = 57; | ||
| 178 | |||
| 179 | /// Can't send after socket shutdown | ||
| 180 | pub const ESHUTDOWN = 58; | ||
| 181 | |||
| 182 | /// Too many references: can't splice | ||
| 183 | pub const ETOOMANYREFS = 59; | ||
| 184 | |||
| 185 | /// Operation timed out | ||
| 186 | pub const ETIMEDOUT = 60; | ||
| 187 | |||
| 188 | /// Connection refused | ||
| 189 | pub const ECONNREFUSED = 61; | ||
| 190 | |||
| 191 | /// Too many levels of symbolic links | ||
| 192 | pub const ELOOP = 62; | ||
| 193 | |||
| 194 | /// File name too long | ||
| 195 | pub const ENAMETOOLONG = 63; | ||
| 196 | |||
| 197 | /// Host is down | ||
| 198 | pub const EHOSTDOWN = 64; | ||
| 199 | |||
| 200 | /// No route to host | ||
| 201 | pub const EHOSTUNREACH = 65; | ||
| 202 | /// Directory not empty | ||
| 203 | |||
| 204 | // quotas & mush | ||
| 205 | pub const ENOTEMPTY = 66; | ||
| 206 | |||
| 207 | /// Too many processes | ||
| 208 | pub const EPROCLIM = 67; | ||
| 209 | |||
| 210 | /// Too many users | ||
| 211 | pub const EUSERS = 68; | ||
| 212 | /// Disc quota exceeded | ||
| 213 | |||
| 214 | // Network File System | ||
| 215 | pub const EDQUOT = 69; | ||
| 216 | |||
| 217 | /// Stale NFS file handle | ||
| 218 | pub const ESTALE = 70; | ||
| 219 | |||
| 220 | /// Too many levels of remote in path | ||
| 221 | pub const EREMOTE = 71; | ||
| 222 | |||
| 223 | /// RPC struct is bad | ||
| 224 | pub const EBADRPC = 72; | ||
| 225 | |||
| 226 | /// RPC version wrong | ||
| 227 | pub const ERPCMISMATCH = 73; | ||
| 228 | |||
| 229 | /// RPC prog. not avail | ||
| 230 | pub const EPROGUNAVAIL = 74; | ||
| 231 | |||
| 232 | /// Program version wrong | ||
| 233 | pub const EPROGMISMATCH = 75; | ||
| 234 | |||
| 235 | /// Bad procedure for program | ||
| 236 | pub const EPROCUNAVAIL = 76; | ||
| 237 | |||
| 238 | /// No locks available | ||
| 239 | pub const ENOLCK = 77; | ||
| 240 | |||
| 241 | /// Function not implemented | ||
| 242 | pub const ENOSYS = 78; | ||
| 243 | |||
| 244 | /// Inappropriate file type or format | ||
| 245 | pub const EFTYPE = 79; | ||
| 246 | |||
| 247 | /// Authentication error | ||
| 248 | pub const EAUTH = 80; | ||
| 249 | /// Need authenticator | ||
| 250 | |||
| 251 | // Intelligent device errors | ||
| 252 | pub const ENEEDAUTH = 81; | ||
| 253 | |||
| 254 | /// Device power is off | ||
| 255 | pub const EPWROFF = 82; | ||
| 256 | |||
| 257 | /// Device error, e.g. paper out | ||
| 258 | pub const EDEVERR = 83; | ||
| 259 | /// Value too large to be stored in data type | ||
| 260 | |||
| 261 | // Program loading errors | ||
| 262 | pub const EOVERFLOW = 84; | ||
| 263 | |||
| 264 | /// Bad executable | ||
| 265 | pub const EBADEXEC = 85; | ||
| 266 | |||
| 267 | /// Bad CPU type in executable | ||
| 268 | pub const EBADARCH = 86; | ||
| 269 | |||
| 270 | /// Shared library version mismatch | ||
| 271 | pub const ESHLIBVERS = 87; | ||
| 272 | |||
| 273 | /// Malformed Macho file | ||
| 274 | pub const EBADMACHO = 88; | ||
| 275 | |||
| 276 | /// Operation canceled | ||
| 277 | pub const ECANCELED = 89; | ||
| 278 | |||
| 279 | /// Identifier removed | ||
| 280 | pub const EIDRM = 90; | ||
| 281 | |||
| 282 | /// No message of desired type | ||
| 283 | pub const ENOMSG = 91; | ||
| 284 | |||
| 285 | /// Illegal byte sequence | ||
| 286 | pub const EILSEQ = 92; | ||
| 287 | |||
| 288 | /// Attribute not found | ||
| 289 | pub const ENOATTR = 93; | ||
| 290 | |||
| 291 | /// Bad message | ||
| 292 | pub const EBADMSG = 94; | ||
| 293 | |||
| 294 | /// Reserved | ||
| 295 | pub const EMULTIHOP = 95; | ||
| 296 | |||
| 297 | /// No message available on STREAM | ||
| 298 | pub const ENODATA = 96; | ||
| 299 | |||
| 300 | /// Reserved | ||
| 301 | pub const ENOLINK = 97; | ||
| 302 | |||
| 303 | /// No STREAM resources | ||
| 304 | pub const ENOSR = 98; | ||
| 305 | |||
| 306 | /// Not a STREAM | ||
| 307 | pub const ENOSTR = 99; | ||
| 308 | |||
| 309 | /// Protocol error | ||
| 310 | pub const EPROTO = 100; | ||
| 311 | |||
| 312 | /// STREAM ioctl timeout | ||
| 313 | pub const ETIME = 101; | ||
| 314 | |||
| 315 | /// No such policy registered | ||
| 316 | pub const ENOPOLICY = 103; | ||
| 317 | |||
| 318 | /// State not recoverable | ||
| 319 | pub const ENOTRECOVERABLE = 104; | ||
| 320 | |||
| 321 | /// Previous owner died | ||
| 322 | pub const EOWNERDEAD = 105; | ||
| 323 | |||
| 324 | /// Interface output queue is full | ||
| 325 | pub const EQFULL = 106; | ||
| 326 | |||
| 327 | /// Must be equal largest errno | ||
| 328 | pub 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. | ||
| 3 | pub const posix = 0; //Jan 01, 1970 AD | ||
| 4 | pub const dos = 315532800; //Jan 01, 1980 AD | ||
| 5 | pub const ios = 978307200; //Jan 01, 2001 AD | ||
| 6 | pub const openvms = -3506716800; //Nov 17, 1858 AD | ||
| 7 | pub const zos = -2208988800; //Jan 01, 1900 AD | ||
| 8 | pub const windows = -11644473600; //Jan 01, 1601 AD | ||
| 9 | pub const amiga = 252460800; //Jan 01, 1978 AD | ||
| 10 | pub const pickos = -63244800; //Dec 31, 1967 AD | ||
| 11 | pub const gps = 315964800; //Jan 06, 1980 AD | ||
| 12 | pub const clr = -62135769600; //Jan 01, 0001 AD | ||
| 13 | |||
| 14 | pub const unix = posix; | ||
| 15 | pub const android = posix; | ||
| 16 | pub const os2 = dos; | ||
| 17 | pub const bios = dos; | ||
| 18 | pub const vfat = dos; | ||
| 19 | pub const ntfs = windows; | ||
| 20 | pub const ntp = zos; | ||
| 21 | pub const jbase = pickos; | ||
| 22 | pub const aros = amiga; | ||
| 23 | pub const morphos = amiga; | ||
| 24 | pub const brew = gps; | ||
| 25 | pub const atsc = gps; | ||
| 26 | pub const go = clr; | ||
std/os/file.zig deleted-512| ... | @@ -1,512 +0,0 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const os = std.os; | ||
| 4 | const io = std.io; | ||
| 5 | const mem = std.mem; | ||
| 6 | const math = std.math; | ||
| 7 | const assert = std.debug.assert; | ||
| 8 | const posix = os.posix; | ||
| 9 | const windows = os.windows; | ||
| 10 | const Os = builtin.Os; | ||
| 11 | const windows_util = @import("windows/util.zig"); | ||
| 12 | const maxInt = std.math.maxInt; | ||
| 13 | |||
| 14 | const is_posix = builtin.os != builtin.Os.windows; | ||
| 15 | const is_windows = builtin.os == builtin.Os.windows; | ||
| 16 | |||
| 17 | pub 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 @@ |
| 1 | const builtin = @import("builtin"); | ||
| 2 | |||
| 3 | pub use @import("freebsd/errno.zig"); | ||
| 4 | |||
| 5 | const std = @import("../std.zig"); | 1 | const std = @import("../std.zig"); |
| 6 | const c = std.c; | 2 | const builtin = @import("builtin"); |
| 7 | 3 | pub const is_the_target = builtin.os == .freebsd; | |
| 8 | const assert = std.debug.assert; | 4 | pub use std.c; |
| 9 | const maxInt = std.math.maxInt; | ||
| 10 | pub const Kevent = c.Kevent; | ||
| 11 | |||
| 12 | pub const CTL_KERN = 1; | ||
| 13 | pub const CTL_DEBUG = 5; | ||
| 14 | |||
| 15 | pub const KERN_PROC = 14; // struct: process entries | ||
| 16 | pub const KERN_PROC_PATHNAME = 12; // path to executable | ||
| 17 | |||
| 18 | pub const PATH_MAX = 1024; | ||
| 19 | |||
| 20 | pub const STDIN_FILENO = 0; | ||
| 21 | pub const STDOUT_FILENO = 1; | ||
| 22 | pub const STDERR_FILENO = 2; | ||
| 23 | |||
| 24 | pub const PROT_NONE = 0; | ||
| 25 | pub const PROT_READ = 1; | ||
| 26 | pub const PROT_WRITE = 2; | ||
| 27 | pub const PROT_EXEC = 4; | ||
| 28 | |||
| 29 | pub const CLOCK_REALTIME = 0; | ||
| 30 | pub const CLOCK_VIRTUAL = 1; | ||
| 31 | pub const CLOCK_PROF = 2; | ||
| 32 | pub const CLOCK_MONOTONIC = 4; | ||
| 33 | pub const CLOCK_UPTIME = 5; | ||
| 34 | pub const CLOCK_UPTIME_PRECISE = 7; | ||
| 35 | pub const CLOCK_UPTIME_FAST = 8; | ||
| 36 | pub const CLOCK_REALTIME_PRECISE = 9; | ||
| 37 | pub const CLOCK_REALTIME_FAST = 10; | ||
| 38 | pub const CLOCK_MONOTONIC_PRECISE = 11; | ||
| 39 | pub const CLOCK_MONOTONIC_FAST = 12; | ||
| 40 | pub const CLOCK_SECOND = 13; | ||
| 41 | pub const CLOCK_THREAD_CPUTIME_ID = 14; | ||
| 42 | pub const CLOCK_PROCESS_CPUTIME_ID = 15; | ||
| 43 | |||
| 44 | pub const MAP_FAILED = maxInt(usize); | ||
| 45 | pub const MAP_SHARED = 0x0001; | ||
| 46 | pub const MAP_PRIVATE = 0x0002; | ||
| 47 | pub const MAP_FIXED = 0x0010; | ||
| 48 | pub const MAP_STACK = 0x0400; | ||
| 49 | pub const MAP_NOSYNC = 0x0800; | ||
| 50 | pub const MAP_ANON = 0x1000; | ||
| 51 | pub const MAP_ANONYMOUS = MAP_ANON; | ||
| 52 | pub const MAP_FILE = 0; | ||
| 53 | pub const MAP_NORESERVE = 0; | ||
| 54 | |||
| 55 | pub const MAP_GUARD = 0x00002000; | ||
| 56 | pub const MAP_EXCL = 0x00004000; | ||
| 57 | pub const MAP_NOCORE = 0x00020000; | ||
| 58 | pub const MAP_PREFAULT_READ = 0x00040000; | ||
| 59 | pub const MAP_32BIT = 0x00080000; | ||
| 60 | |||
| 61 | pub const WNOHANG = 1; | ||
| 62 | pub const WUNTRACED = 2; | ||
| 63 | pub const WSTOPPED = WUNTRACED; | ||
| 64 | pub const WCONTINUED = 4; | ||
| 65 | pub const WNOWAIT = 8; | ||
| 66 | pub const WEXITED = 16; | ||
| 67 | pub const WTRAPPED = 32; | ||
| 68 | |||
| 69 | pub const SA_ONSTACK = 0x0001; | ||
| 70 | pub const SA_RESTART = 0x0002; | ||
| 71 | pub const SA_RESETHAND = 0x0004; | ||
| 72 | pub const SA_NOCLDSTOP = 0x0008; | ||
| 73 | pub const SA_NODEFER = 0x0010; | ||
| 74 | pub const SA_NOCLDWAIT = 0x0020; | ||
| 75 | pub const SA_SIGINFO = 0x0040; | ||
| 76 | |||
| 77 | pub const SIGHUP = 1; | ||
| 78 | pub const SIGINT = 2; | ||
| 79 | pub const SIGQUIT = 3; | ||
| 80 | pub const SIGILL = 4; | ||
| 81 | pub const SIGTRAP = 5; | ||
| 82 | pub const SIGABRT = 6; | ||
| 83 | pub const SIGIOT = SIGABRT; | ||
| 84 | pub const SIGEMT = 7; | ||
| 85 | pub const SIGFPE = 8; | ||
| 86 | pub const SIGKILL = 9; | ||
| 87 | pub const SIGBUS = 10; | ||
| 88 | pub const SIGSEGV = 11; | ||
| 89 | pub const SIGSYS = 12; | ||
| 90 | pub const SIGPIPE = 13; | ||
| 91 | pub const SIGALRM = 14; | ||
| 92 | pub const SIGTERM = 15; | ||
| 93 | pub const SIGURG = 16; | ||
| 94 | pub const SIGSTOP = 17; | ||
| 95 | pub const SIGTSTP = 18; | ||
| 96 | pub const SIGCONT = 19; | ||
| 97 | pub const SIGCHLD = 20; | ||
| 98 | pub const SIGTTIN = 21; | ||
| 99 | pub const SIGTTOU = 22; | ||
| 100 | pub const SIGIO = 23; | ||
| 101 | pub const SIGXCPU = 24; | ||
| 102 | pub const SIGXFSZ = 25; | ||
| 103 | pub const SIGVTALRM = 26; | ||
| 104 | pub const SIGPROF = 27; | ||
| 105 | pub const SIGWINCH = 28; | ||
| 106 | pub const SIGINFO = 29; | ||
| 107 | pub const SIGUSR1 = 30; | ||
| 108 | pub const SIGUSR2 = 31; | ||
| 109 | pub const SIGTHR = 32; | ||
| 110 | pub const SIGLWP = SIGTHR; | ||
| 111 | pub const SIGLIBRT = 33; | ||
| 112 | |||
| 113 | pub const SIGRTMIN = 65; | ||
| 114 | pub const SIGRTMAX = 126; | ||
| 115 | |||
| 116 | // access function | ||
| 117 | pub const F_OK = 0; // test for existence of file | ||
| 118 | pub const X_OK = 1; // test for execute or search permission | ||
| 119 | pub const W_OK = 2; // test for write permission | ||
| 120 | pub const R_OK = 4; // test for read permission | ||
| 121 | |||
| 122 | pub const O_RDONLY = 0x0000; | ||
| 123 | pub const O_WRONLY = 0x0001; | ||
| 124 | pub const O_RDWR = 0x0002; | ||
| 125 | pub const O_ACCMODE = 0x0003; | ||
| 126 | |||
| 127 | pub const O_CREAT = 0x0200; | ||
| 128 | pub const O_EXCL = 0x0800; | ||
| 129 | pub const O_NOCTTY = 0x8000; | ||
| 130 | pub const O_TRUNC = 0x0400; | ||
| 131 | pub const O_APPEND = 0x0008; | ||
| 132 | pub const O_NONBLOCK = 0x0004; | ||
| 133 | pub const O_DSYNC = 0o10000; | ||
| 134 | pub const O_SYNC = 0x0080; | ||
| 135 | pub const O_RSYNC = 0o4010000; | ||
| 136 | pub const O_DIRECTORY = 0o200000; | ||
| 137 | pub const O_NOFOLLOW = 0x0100; | ||
| 138 | pub const O_CLOEXEC = 0x00100000; | ||
| 139 | |||
| 140 | pub const O_ASYNC = 0x0040; | ||
| 141 | pub const O_DIRECT = 0x00010000; | ||
| 142 | pub const O_LARGEFILE = 0; | ||
| 143 | pub const O_NOATIME = 0o1000000; | ||
| 144 | pub const O_PATH = 0o10000000; | ||
| 145 | pub const O_TMPFILE = 0o20200000; | ||
| 146 | pub const O_NDELAY = O_NONBLOCK; | ||
| 147 | |||
| 148 | pub const F_DUPFD = 0; | ||
| 149 | pub const F_GETFD = 1; | ||
| 150 | pub const F_SETFD = 2; | ||
| 151 | pub const F_GETFL = 3; | ||
| 152 | pub const F_SETFL = 4; | ||
| 153 | |||
| 154 | pub const F_SETOWN = 8; | ||
| 155 | pub const F_GETOWN = 9; | ||
| 156 | pub const F_SETSIG = 10; | ||
| 157 | pub const F_GETSIG = 11; | ||
| 158 | |||
| 159 | pub const F_GETLK = 5; | ||
| 160 | pub const F_SETLK = 6; | ||
| 161 | pub const F_SETLKW = 7; | ||
| 162 | |||
| 163 | pub const F_SETOWN_EX = 15; | ||
| 164 | pub const F_GETOWN_EX = 16; | ||
| 165 | |||
| 166 | pub const F_GETOWNER_UIDS = 17; | ||
| 167 | |||
| 168 | pub const SEEK_SET = 0; | ||
| 169 | pub const SEEK_CUR = 1; | ||
| 170 | pub const SEEK_END = 2; | ||
| 171 | |||
| 172 | pub const SIG_BLOCK = 1; | ||
| 173 | pub const SIG_UNBLOCK = 2; | ||
| 174 | pub const SIG_SETMASK = 3; | ||
| 175 | |||
| 176 | pub const SOCK_STREAM = 1; | ||
| 177 | pub const SOCK_DGRAM = 2; | ||
| 178 | pub const SOCK_RAW = 3; | ||
| 179 | pub const SOCK_RDM = 4; | ||
| 180 | pub const SOCK_SEQPACKET = 5; | ||
| 181 | |||
| 182 | pub const SOCK_CLOEXEC = 0x10000000; | ||
| 183 | pub const SOCK_NONBLOCK = 0x20000000; | ||
| 184 | |||
| 185 | pub const PROTO_ip = 0o000; | ||
| 186 | pub const PROTO_icmp = 0o001; | ||
| 187 | pub const PROTO_igmp = 0o002; | ||
| 188 | pub const PROTO_ggp = 0o003; | ||
| 189 | pub const PROTO_ipencap = 0o004; | ||
| 190 | pub const PROTO_st = 0o005; | ||
| 191 | pub const PROTO_tcp = 0o006; | ||
| 192 | pub const PROTO_egp = 0o010; | ||
| 193 | pub const PROTO_pup = 0o014; | ||
| 194 | pub const PROTO_udp = 0o021; | ||
| 195 | pub const PROTO_hmp = 0o024; | ||
| 196 | pub const PROTO_xns_idp = 0o026; | ||
| 197 | pub const PROTO_rdp = 0o033; | ||
| 198 | pub const PROTO_iso_tp4 = 0o035; | ||
| 199 | pub const PROTO_xtp = 0o044; | ||
| 200 | pub const PROTO_ddp = 0o045; | ||
| 201 | pub const PROTO_idpr_cmtp = 0o046; | ||
| 202 | pub const PROTO_ipv6 = 0o051; | ||
| 203 | pub const PROTO_ipv6_route = 0o053; | ||
| 204 | pub const PROTO_ipv6_frag = 0o054; | ||
| 205 | pub const PROTO_idrp = 0o055; | ||
| 206 | pub const PROTO_rsvp = 0o056; | ||
| 207 | pub const PROTO_gre = 0o057; | ||
| 208 | pub const PROTO_esp = 0o062; | ||
| 209 | pub const PROTO_ah = 0o063; | ||
| 210 | pub const PROTO_skip = 0o071; | ||
| 211 | pub const PROTO_ipv6_icmp = 0o072; | ||
| 212 | pub const PROTO_ipv6_nonxt = 0o073; | ||
| 213 | pub const PROTO_ipv6_opts = 0o074; | ||
| 214 | pub const PROTO_rspf = 0o111; | ||
| 215 | pub const PROTO_vmtp = 0o121; | ||
| 216 | pub const PROTO_ospf = 0o131; | ||
| 217 | pub const PROTO_ipip = 0o136; | ||
| 218 | pub const PROTO_encap = 0o142; | ||
| 219 | pub const PROTO_pim = 0o147; | ||
| 220 | pub const PROTO_raw = 0o377; | ||
| 221 | |||
| 222 | pub const PF_UNSPEC = 0; | ||
| 223 | pub const PF_LOCAL = 1; | ||
| 224 | pub const PF_UNIX = PF_LOCAL; | ||
| 225 | pub const PF_FILE = PF_LOCAL; | ||
| 226 | pub const PF_INET = 2; | ||
| 227 | pub const PF_AX25 = 3; | ||
| 228 | pub const PF_IPX = 4; | ||
| 229 | pub const PF_APPLETALK = 5; | ||
| 230 | pub const PF_NETROM = 6; | ||
| 231 | pub const PF_BRIDGE = 7; | ||
| 232 | pub const PF_ATMPVC = 8; | ||
| 233 | pub const PF_X25 = 9; | ||
| 234 | pub const PF_INET6 = 10; | ||
| 235 | pub const PF_ROSE = 11; | ||
| 236 | pub const PF_DECnet = 12; | ||
| 237 | pub const PF_NETBEUI = 13; | ||
| 238 | pub const PF_SECURITY = 14; | ||
| 239 | pub const PF_KEY = 15; | ||
| 240 | pub const PF_NETLINK = 16; | ||
| 241 | pub const PF_ROUTE = PF_NETLINK; | ||
| 242 | pub const PF_PACKET = 17; | ||
| 243 | pub const PF_ASH = 18; | ||
| 244 | pub const PF_ECONET = 19; | ||
| 245 | pub const PF_ATMSVC = 20; | ||
| 246 | pub const PF_RDS = 21; | ||
| 247 | pub const PF_SNA = 22; | ||
| 248 | pub const PF_IRDA = 23; | ||
| 249 | pub const PF_PPPOX = 24; | ||
| 250 | pub const PF_WANPIPE = 25; | ||
| 251 | pub const PF_LLC = 26; | ||
| 252 | pub const PF_IB = 27; | ||
| 253 | pub const PF_MPLS = 28; | ||
| 254 | pub const PF_CAN = 29; | ||
| 255 | pub const PF_TIPC = 30; | ||
| 256 | pub const PF_BLUETOOTH = 31; | ||
| 257 | pub const PF_IUCV = 32; | ||
| 258 | pub const PF_RXRPC = 33; | ||
| 259 | pub const PF_ISDN = 34; | ||
| 260 | pub const PF_PHONET = 35; | ||
| 261 | pub const PF_IEEE802154 = 36; | ||
| 262 | pub const PF_CAIF = 37; | ||
| 263 | pub const PF_ALG = 38; | ||
| 264 | pub const PF_NFC = 39; | ||
| 265 | pub const PF_VSOCK = 40; | ||
| 266 | pub const PF_MAX = 41; | ||
| 267 | |||
| 268 | pub const AF_UNSPEC = PF_UNSPEC; | ||
| 269 | pub const AF_LOCAL = PF_LOCAL; | ||
| 270 | pub const AF_UNIX = AF_LOCAL; | ||
| 271 | pub const AF_FILE = AF_LOCAL; | ||
| 272 | pub const AF_INET = PF_INET; | ||
| 273 | pub const AF_AX25 = PF_AX25; | ||
| 274 | pub const AF_IPX = PF_IPX; | ||
| 275 | pub const AF_APPLETALK = PF_APPLETALK; | ||
| 276 | pub const AF_NETROM = PF_NETROM; | ||
| 277 | pub const AF_BRIDGE = PF_BRIDGE; | ||
| 278 | pub const AF_ATMPVC = PF_ATMPVC; | ||
| 279 | pub const AF_X25 = PF_X25; | ||
| 280 | pub const AF_INET6 = PF_INET6; | ||
| 281 | pub const AF_ROSE = PF_ROSE; | ||
| 282 | pub const AF_DECnet = PF_DECnet; | ||
| 283 | pub const AF_NETBEUI = PF_NETBEUI; | ||
| 284 | pub const AF_SECURITY = PF_SECURITY; | ||
| 285 | pub const AF_KEY = PF_KEY; | ||
| 286 | pub const AF_NETLINK = PF_NETLINK; | ||
| 287 | pub const AF_ROUTE = PF_ROUTE; | ||
| 288 | pub const AF_PACKET = PF_PACKET; | ||
| 289 | pub const AF_ASH = PF_ASH; | ||
| 290 | pub const AF_ECONET = PF_ECONET; | ||
| 291 | pub const AF_ATMSVC = PF_ATMSVC; | ||
| 292 | pub const AF_RDS = PF_RDS; | ||
| 293 | pub const AF_SNA = PF_SNA; | ||
| 294 | pub const AF_IRDA = PF_IRDA; | ||
| 295 | pub const AF_PPPOX = PF_PPPOX; | ||
| 296 | pub const AF_WANPIPE = PF_WANPIPE; | ||
| 297 | pub const AF_LLC = PF_LLC; | ||
| 298 | pub const AF_IB = PF_IB; | ||
| 299 | pub const AF_MPLS = PF_MPLS; | ||
| 300 | pub const AF_CAN = PF_CAN; | ||
| 301 | pub const AF_TIPC = PF_TIPC; | ||
| 302 | pub const AF_BLUETOOTH = PF_BLUETOOTH; | ||
| 303 | pub const AF_IUCV = PF_IUCV; | ||
| 304 | pub const AF_RXRPC = PF_RXRPC; | ||
| 305 | pub const AF_ISDN = PF_ISDN; | ||
| 306 | pub const AF_PHONET = PF_PHONET; | ||
| 307 | pub const AF_IEEE802154 = PF_IEEE802154; | ||
| 308 | pub const AF_CAIF = PF_CAIF; | ||
| 309 | pub const AF_ALG = PF_ALG; | ||
| 310 | pub const AF_NFC = PF_NFC; | ||
| 311 | pub const AF_VSOCK = PF_VSOCK; | ||
| 312 | pub const AF_MAX = PF_MAX; | ||
| 313 | |||
| 314 | pub const DT_UNKNOWN = 0; | ||
| 315 | pub const DT_FIFO = 1; | ||
| 316 | pub const DT_CHR = 2; | ||
| 317 | pub const DT_DIR = 4; | ||
| 318 | pub const DT_BLK = 6; | ||
| 319 | pub const DT_REG = 8; | ||
| 320 | pub const DT_LNK = 10; | ||
| 321 | pub const DT_SOCK = 12; | ||
| 322 | pub const DT_WHT = 14; | ||
| 323 | |||
| 324 | /// add event to kq (implies enable) | ||
| 325 | pub const EV_ADD = 0x0001; | ||
| 326 | |||
| 327 | /// delete event from kq | ||
| 328 | pub const EV_DELETE = 0x0002; | ||
| 329 | |||
| 330 | /// enable event | ||
| 331 | pub const EV_ENABLE = 0x0004; | ||
| 332 | |||
| 333 | /// disable event (not reported) | ||
| 334 | pub const EV_DISABLE = 0x0008; | ||
| 335 | |||
| 336 | /// only report one occurrence | ||
| 337 | pub const EV_ONESHOT = 0x0010; | ||
| 338 | |||
| 339 | /// clear event state after reporting | ||
| 340 | pub 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 | ||
| 346 | pub const EV_RECEIPT = 0x0040; | ||
| 347 | |||
| 348 | /// disable event after reporting | ||
| 349 | pub const EV_DISPATCH = 0x0080; | ||
| 350 | |||
| 351 | pub const EVFILT_READ = -1; | ||
| 352 | pub const EVFILT_WRITE = -2; | ||
| 353 | |||
| 354 | /// attached to aio requests | ||
| 355 | pub const EVFILT_AIO = -3; | ||
| 356 | |||
| 357 | /// attached to vnodes | ||
| 358 | pub const EVFILT_VNODE = -4; | ||
| 359 | |||
| 360 | /// attached to struct proc | ||
| 361 | pub const EVFILT_PROC = -5; | ||
| 362 | |||
| 363 | /// attached to struct proc | ||
| 364 | pub const EVFILT_SIGNAL = -6; | ||
| 365 | |||
| 366 | /// timers | ||
| 367 | pub const EVFILT_TIMER = -7; | ||
| 368 | |||
| 369 | /// Process descriptors | ||
| 370 | pub const EVFILT_PROCDESC = -8; | ||
| 371 | |||
| 372 | /// Filesystem events | ||
| 373 | pub const EVFILT_FS = -9; | ||
| 374 | |||
| 375 | pub const EVFILT_LIO = -10; | ||
| 376 | |||
| 377 | /// User events | ||
| 378 | pub const EVFILT_USER = -11; | ||
| 379 | |||
| 380 | /// Sendfile events | ||
| 381 | pub const EVFILT_SENDFILE = -12; | ||
| 382 | |||
| 383 | pub const EVFILT_EMPTY = -13; | ||
| 384 | |||
| 385 | /// On input, NOTE_TRIGGER causes the event to be triggered for output. | ||
| 386 | pub const NOTE_TRIGGER = 0x01000000; | ||
| 387 | |||
| 388 | /// ignore input fflags | ||
| 389 | pub const NOTE_FFNOP = 0x00000000; | ||
| 390 | |||
| 391 | /// and fflags | ||
| 392 | pub const NOTE_FFAND = 0x40000000; | ||
| 393 | |||
| 394 | /// or fflags | ||
| 395 | pub const NOTE_FFOR = 0x80000000; | ||
| 396 | |||
| 397 | /// copy fflags | ||
| 398 | pub const NOTE_FFCOPY = 0xc0000000; | ||
| 399 | |||
| 400 | /// mask for operations | ||
| 401 | pub const NOTE_FFCTRLMASK = 0xc0000000; | ||
| 402 | pub const NOTE_FFLAGSMASK = 0x00ffffff; | ||
| 403 | |||
| 404 | /// low water mark | ||
| 405 | pub const NOTE_LOWAT = 0x00000001; | ||
| 406 | |||
| 407 | /// behave like poll() | ||
| 408 | pub const NOTE_FILE_POLL = 0x00000002; | ||
| 409 | |||
| 410 | /// vnode was removed | ||
| 411 | pub const NOTE_DELETE = 0x00000001; | ||
| 412 | |||
| 413 | /// data contents changed | ||
| 414 | pub const NOTE_WRITE = 0x00000002; | ||
| 415 | |||
| 416 | /// size increased | ||
| 417 | pub const NOTE_EXTEND = 0x00000004; | ||
| 418 | |||
| 419 | /// attributes changed | ||
| 420 | pub const NOTE_ATTRIB = 0x00000008; | ||
| 421 | |||
| 422 | /// link count changed | ||
| 423 | pub const NOTE_LINK = 0x00000010; | ||
| 424 | |||
| 425 | /// vnode was renamed | ||
| 426 | pub const NOTE_RENAME = 0x00000020; | ||
| 427 | |||
| 428 | /// vnode access was revoked | ||
| 429 | pub const NOTE_REVOKE = 0x00000040; | ||
| 430 | |||
| 431 | /// vnode was opened | ||
| 432 | pub const NOTE_OPEN = 0x00000080; | ||
| 433 | |||
| 434 | /// file closed, fd did not allow write | ||
| 435 | pub const NOTE_CLOSE = 0x00000100; | ||
| 436 | |||
| 437 | /// file closed, fd did allow write | ||
| 438 | pub const NOTE_CLOSE_WRITE = 0x00000200; | ||
| 439 | |||
| 440 | /// file was read | ||
| 441 | pub const NOTE_READ = 0x00000400; | ||
| 442 | |||
| 443 | /// process exited | ||
| 444 | pub const NOTE_EXIT = 0x80000000; | ||
| 445 | |||
| 446 | /// process forked | ||
| 447 | pub const NOTE_FORK = 0x40000000; | ||
| 448 | |||
| 449 | /// process exec'd | ||
| 450 | pub const NOTE_EXEC = 0x20000000; | ||
| 451 | |||
| 452 | /// mask for signal & exit status | ||
| 453 | pub const NOTE_PDATAMASK = 0x000fffff; | ||
| 454 | pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK); | ||
| 455 | |||
| 456 | /// data is seconds | ||
| 457 | pub const NOTE_SECONDS = 0x00000001; | ||
| 458 | |||
| 459 | /// data is milliseconds | ||
| 460 | pub const NOTE_MSECONDS = 0x00000002; | ||
| 461 | |||
| 462 | /// data is microseconds | ||
| 463 | pub const NOTE_USECONDS = 0x00000004; | ||
| 464 | |||
| 465 | /// data is nanoseconds | ||
| 466 | pub const NOTE_NSECONDS = 0x00000008; | ||
| 467 | |||
| 468 | /// timeout is absolute | ||
| 469 | pub const NOTE_ABSTIME = 0x00000010; | ||
| 470 | |||
| 471 | pub const TCGETS = 0x5401; | ||
| 472 | pub const TCSETS = 0x5402; | ||
| 473 | pub const TCSETSW = 0x5403; | ||
| 474 | pub const TCSETSF = 0x5404; | ||
| 475 | pub const TCGETA = 0x5405; | ||
| 476 | pub const TCSETA = 0x5406; | ||
| 477 | pub const TCSETAW = 0x5407; | ||
| 478 | pub const TCSETAF = 0x5408; | ||
| 479 | pub const TCSBRK = 0x5409; | ||
| 480 | pub const TCXONC = 0x540A; | ||
| 481 | pub const TCFLSH = 0x540B; | ||
| 482 | pub const TIOCEXCL = 0x540C; | ||
| 483 | pub const TIOCNXCL = 0x540D; | ||
| 484 | pub const TIOCSCTTY = 0x540E; | ||
| 485 | pub const TIOCGPGRP = 0x540F; | ||
| 486 | pub const TIOCSPGRP = 0x5410; | ||
| 487 | pub const TIOCOUTQ = 0x5411; | ||
| 488 | pub const TIOCSTI = 0x5412; | ||
| 489 | pub const TIOCGWINSZ = 0x5413; | ||
| 490 | pub const TIOCSWINSZ = 0x5414; | ||
| 491 | pub const TIOCMGET = 0x5415; | ||
| 492 | pub const TIOCMBIS = 0x5416; | ||
| 493 | pub const TIOCMBIC = 0x5417; | ||
| 494 | pub const TIOCMSET = 0x5418; | ||
| 495 | pub const TIOCGSOFTCAR = 0x5419; | ||
| 496 | pub const TIOCSSOFTCAR = 0x541A; | ||
| 497 | pub const FIONREAD = 0x541B; | ||
| 498 | pub const TIOCINQ = FIONREAD; | ||
| 499 | pub const TIOCLINUX = 0x541C; | ||
| 500 | pub const TIOCCONS = 0x541D; | ||
| 501 | pub const TIOCGSERIAL = 0x541E; | ||
| 502 | pub const TIOCSSERIAL = 0x541F; | ||
| 503 | pub const TIOCPKT = 0x5420; | ||
| 504 | pub const FIONBIO = 0x5421; | ||
| 505 | pub const TIOCNOTTY = 0x5422; | ||
| 506 | pub const TIOCSETD = 0x5423; | ||
| 507 | pub const TIOCGETD = 0x5424; | ||
| 508 | pub const TCSBRKP = 0x5425; | ||
| 509 | pub const TIOCSBRK = 0x5427; | ||
| 510 | pub const TIOCCBRK = 0x5428; | ||
| 511 | pub const TIOCGSID = 0x5429; | ||
| 512 | pub const TIOCGRS485 = 0x542E; | ||
| 513 | pub const TIOCSRS485 = 0x542F; | ||
| 514 | pub const TIOCGPTN = 0x80045430; | ||
| 515 | pub const TIOCSPTLCK = 0x40045431; | ||
| 516 | pub const TIOCGDEV = 0x80045432; | ||
| 517 | pub const TCGETX = 0x5432; | ||
| 518 | pub const TCSETX = 0x5433; | ||
| 519 | pub const TCSETXF = 0x5434; | ||
| 520 | pub const TCSETXW = 0x5435; | ||
| 521 | pub const TIOCSIG = 0x40045436; | ||
| 522 | pub const TIOCVHANGUP = 0x5437; | ||
| 523 | pub const TIOCGPKT = 0x80045438; | ||
| 524 | pub const TIOCGPTLCK = 0x80045439; | ||
| 525 | pub const TIOCGEXCL = 0x80045440; | ||
| 526 | |||
| 527 | pub const sockaddr = c.sockaddr; | ||
| 528 | pub const sockaddr_in = c.sockaddr_in; | ||
| 529 | pub const sockaddr_in6 = c.sockaddr_in6; | ||
| 530 | |||
| 531 | fn unsigned(s: i32) u32 { | ||
| 532 | return @bitCast(u32, s); | ||
| 533 | } | ||
| 534 | fn signed(s: u32) i32 { | ||
| 535 | return @bitCast(i32, s); | ||
| 536 | } | ||
| 537 | pub fn WEXITSTATUS(s: i32) i32 { | ||
| 538 | return signed((unsigned(s) & 0xff00) >> 8); | ||
| 539 | } | ||
| 540 | pub fn WTERMSIG(s: i32) i32 { | ||
| 541 | return signed(unsigned(s) & 0x7f); | ||
| 542 | } | ||
| 543 | pub fn WSTOPSIG(s: i32) i32 { | ||
| 544 | return WEXITSTATUS(s); | ||
| 545 | } | ||
| 546 | pub fn WIFEXITED(s: i32) bool { | ||
| 547 | return WTERMSIG(s) == 0; | ||
| 548 | } | ||
| 549 | pub fn WIFSTOPPED(s: i32) bool { | ||
| 550 | return @intCast(u16, (((unsigned(s) & 0xffff) *% 0x10001) >> 8)) > 0x7f00; | ||
| 551 | } | ||
| 552 | pub fn WIFSIGNALED(s: i32) bool { | ||
| 553 | return (unsigned(s) & 0xffff) -% 1 < 0xff; | ||
| 554 | } | ||
| 555 | |||
| 556 | pub 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. | ||
| 564 | pub 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 | |||
| 569 | pub fn dup2(old: i32, new: i32) usize { | ||
| 570 | return errnoWrap(c.dup2(old, new)); | ||
| 571 | } | ||
| 572 | |||
| 573 | pub fn chdir(path: [*]const u8) usize { | ||
| 574 | return errnoWrap(c.chdir(path)); | ||
| 575 | } | ||
| 576 | |||
| 577 | pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize { | ||
| 578 | return errnoWrap(c.execve(path, argv, envp)); | ||
| 579 | } | ||
| 580 | |||
| 581 | pub fn fork() usize { | ||
| 582 | return errnoWrap(c.fork()); | ||
| 583 | } | ||
| 584 | |||
| 585 | pub fn access(path: [*]const u8, mode: u32) usize { | ||
| 586 | return errnoWrap(c.access(path, mode)); | ||
| 587 | } | ||
| 588 | |||
| 589 | pub fn getcwd(buf: [*]u8, size: usize) usize { | ||
| 590 | return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0; | ||
| 591 | } | ||
| 592 | |||
| 593 | pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize { | ||
| 594 | return errnoWrap(@bitCast(isize, c.getdents(fd, drip, count))); | ||
| 595 | } | ||
| 596 | |||
| 597 | pub 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 | |||
| 601 | pub 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 | |||
| 605 | pub fn isatty(fd: i32) bool { | ||
| 606 | return c.isatty(fd) != 0; | ||
| 607 | } | ||
| 608 | |||
| 609 | pub 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 | |||
| 613 | pub fn mkdir(path: [*]const u8, mode: u32) usize { | ||
| 614 | return errnoWrap(c.mkdir(path, mode)); | ||
| 615 | } | ||
| 616 | |||
| 617 | pub 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 | |||
| 630 | pub fn munmap(address: usize, length: usize) usize { | ||
| 631 | return errnoWrap(c.munmap(@intToPtr(?*c_void, address), length)); | ||
| 632 | } | ||
| 633 | |||
| 634 | pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize { | ||
| 635 | return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte)); | ||
| 636 | } | ||
| 637 | |||
| 638 | pub fn rmdir(path: [*]const u8) usize { | ||
| 639 | return errnoWrap(c.rmdir(path)); | ||
| 640 | } | ||
| 641 | |||
| 642 | pub fn symlink(existing: [*]const u8, new: [*]const u8) usize { | ||
| 643 | return errnoWrap(c.symlink(existing, new)); | ||
| 644 | } | ||
| 645 | |||
| 646 | pub 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 | |||
| 650 | pub 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 | |||
| 654 | pub fn pipe(fd: *[2]i32) usize { | ||
| 655 | return pipe2(fd, 0); | ||
| 656 | } | ||
| 657 | |||
| 658 | pub 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 | |||
| 663 | pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize { | ||
| 664 | return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte)); | ||
| 665 | } | ||
| 666 | |||
| 667 | pub 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 | |||
| 671 | pub 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 | |||
| 675 | pub fn rename(old: [*]const u8, new: [*]const u8) usize { | ||
| 676 | return errnoWrap(c.rename(old, new)); | ||
| 677 | } | ||
| 678 | |||
| 679 | pub fn open(path: [*]const u8, flags: u32, mode: usize) usize { | ||
| 680 | return errnoWrap(c.open(path, @bitCast(c_int, flags), mode)); | ||
| 681 | } | ||
| 682 | |||
| 683 | pub fn create(path: [*]const u8, perm: usize) usize { | ||
| 684 | return arch.syscall2(SYS_creat, @ptrToInt(path), perm); | ||
| 685 | } | ||
| 686 | |||
| 687 | pub 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 | |||
| 691 | pub fn close(fd: i32) usize { | ||
| 692 | return errnoWrap(c.close(fd)); | ||
| 693 | } | ||
| 694 | |||
| 695 | pub fn lseek(fd: i32, offset: isize, whence: c_int) usize { | ||
| 696 | return errnoWrap(c.lseek(fd, offset, whence)); | ||
| 697 | } | ||
| 698 | |||
| 699 | pub fn exit(code: i32) noreturn { | ||
| 700 | c.exit(code); | ||
| 701 | } | ||
| 702 | |||
| 703 | pub fn kill(pid: i32, sig: i32) usize { | ||
| 704 | return errnoWrap(c.kill(pid, sig)); | ||
| 705 | } | ||
| 706 | |||
| 707 | pub fn unlink(path: [*]const u8) usize { | ||
| 708 | return errnoWrap(c.unlink(path)); | ||
| 709 | } | ||
| 710 | |||
| 711 | pub 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 | |||
| 716 | pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize { | ||
| 717 | return errnoWrap(c.nanosleep(req, rem)); | ||
| 718 | } | ||
| 719 | |||
| 720 | pub fn clock_gettime(clk_id: i32, tp: *timespec) usize { | ||
| 721 | return errnoWrap(c.clock_gettime(clk_id, tp)); | ||
| 722 | } | ||
| 723 | |||
| 724 | pub fn clock_getres(clk_id: i32, tp: *timespec) usize { | ||
| 725 | return errnoWrap(c.clock_getres(clk_id, tp)); | ||
| 726 | } | ||
| 727 | |||
| 728 | pub fn setuid(uid: u32) usize { | ||
| 729 | return errnoWrap(c.setuid(uid)); | ||
| 730 | } | ||
| 731 | |||
| 732 | pub fn setgid(gid: u32) usize { | ||
| 733 | return errnoWrap(c.setgid(gid)); | ||
| 734 | } | ||
| 735 | |||
| 736 | pub fn setreuid(ruid: u32, euid: u32) usize { | ||
| 737 | return errnoWrap(c.setreuid(ruid, euid)); | ||
| 738 | } | ||
| 739 | |||
| 740 | pub fn setregid(rgid: u32, egid: u32) usize { | ||
| 741 | return errnoWrap(c.setregid(rgid, egid)); | ||
| 742 | } | ||
| 743 | |||
| 744 | const NSIG = 32; | ||
| 745 | |||
| 746 | pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize)); | ||
| 747 | pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0); | ||
| 748 | pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1); | ||
| 749 | |||
| 750 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. | ||
| 751 | pub 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 | |||
| 765 | pub const _SIG_WORDS = 4; | ||
| 766 | pub const _SIG_MAXSIG = 128; | ||
| 767 | |||
| 768 | pub inline fn _SIG_IDX(sig: usize) usize { | ||
| 769 | return sig - 1; | ||
| 770 | } | ||
| 771 | pub inline fn _SIG_WORD(sig: usize) usize { | ||
| 772 | return_SIG_IDX(sig) >> 5; | ||
| 773 | } | ||
| 774 | pub inline fn _SIG_BIT(sig: usize) usize { | ||
| 775 | return 1 << (_SIG_IDX(sig) & 31); | ||
| 776 | } | ||
| 777 | pub inline fn _SIG_VALID(sig: usize) usize { | ||
| 778 | return sig <= _SIG_MAXSIG and sig > 0; | ||
| 779 | } | ||
| 780 | |||
| 781 | pub const sigset_t = extern struct { | ||
| 782 | __bits: [_SIG_WORDS]u32, | ||
| 783 | }; | ||
| 784 | |||
| 785 | pub fn raise(sig: i32) usize { | ||
| 786 | return errnoWrap(c.raise(sig)); | ||
| 787 | } | ||
| 788 | |||
| 789 | pub const Stat = c.Stat; | ||
| 790 | pub const dirent = c.dirent; | ||
| 791 | pub const timespec = c.timespec; | ||
| 792 | |||
| 793 | pub fn fstat(fd: i32, buf: *c.Stat) usize { | ||
| 794 | return errnoWrap(c.fstat(fd, buf)); | ||
| 795 | } | ||
| 796 | pub const iovec = extern struct { | ||
| 797 | iov_base: [*]u8, | ||
| 798 | iov_len: usize, | ||
| 799 | }; | ||
| 800 | |||
| 801 | pub const iovec_const = extern struct { | ||
| 802 | iov_base: [*]const u8, | ||
| 803 | iov_len: usize, | ||
| 804 | }; | ||
| 805 | |||
| 806 | // TODO avoid libc dependency | ||
| 807 | pub fn kqueue() usize { | ||
| 808 | return errnoWrap(c.kqueue()); | ||
| 809 | } | ||
| 810 | |||
| 811 | // TODO avoid libc dependency | ||
| 812 | pub 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 | ||
| 824 | pub 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 | ||
| 829 | pub 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 | ||
| 834 | pub 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. | ||
| 843 | fn 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 @@ | ||
| 1 | pub const EPERM = 1; // Operation not permitted | ||
| 2 | pub const ENOENT = 2; // No such file or directory | ||
| 3 | pub const ESRCH = 3; // No such process | ||
| 4 | pub const EINTR = 4; // Interrupted system call | ||
| 5 | pub const EIO = 5; // Input/output error | ||
| 6 | pub const ENXIO = 6; // Device not configured | ||
| 7 | pub const E2BIG = 7; // Argument list too long | ||
| 8 | pub const ENOEXEC = 8; // Exec format error | ||
| 9 | pub const EBADF = 9; // Bad file descriptor | ||
| 10 | pub const ECHILD = 10; // No child processes | ||
| 11 | pub const EDEADLK = 11; // Resource deadlock avoided | ||
| 12 | // 11 was EAGAIN | ||
| 13 | pub const ENOMEM = 12; // Cannot allocate memory | ||
| 14 | pub const EACCES = 13; // Permission denied | ||
| 15 | pub const EFAULT = 14; // Bad address | ||
| 16 | pub const ENOTBLK = 15; // Block device required | ||
| 17 | pub const EBUSY = 16; // Device busy | ||
| 18 | pub const EEXIST = 17; // File exists | ||
| 19 | pub const EXDEV = 18; // Cross-device link | ||
| 20 | pub const ENODEV = 19; // Operation not supported by device | ||
| 21 | pub const ENOTDIR = 20; // Not a directory | ||
| 22 | pub const EISDIR = 21; // Is a directory | ||
| 23 | pub const EINVAL = 22; // Invalid argument | ||
| 24 | pub const ENFILE = 23; // Too many open files in system | ||
| 25 | pub const EMFILE = 24; // Too many open files | ||
| 26 | pub const ENOTTY = 25; // Inappropriate ioctl for device | ||
| 27 | pub const ETXTBSY = 26; // Text file busy | ||
| 28 | pub const EFBIG = 27; // File too large | ||
| 29 | pub const ENOSPC = 28; // No space left on device | ||
| 30 | pub const ESPIPE = 29; // Illegal seek | ||
| 31 | pub const EROFS = 30; // Read-only filesystem | ||
| 32 | pub const EMLINK = 31; // Too many links | ||
| 33 | pub const EPIPE = 32; // Broken pipe | ||
| 34 | |||
| 35 | // math software | ||
| 36 | pub const EDOM = 33; // Numerical argument out of domain | ||
| 37 | pub const ERANGE = 34; // Result too large | ||
| 38 | |||
| 39 | // non-blocking and interrupt i/o | ||
| 40 | pub const EAGAIN = 35; // Resource temporarily unavailable | ||
| 41 | pub const EWOULDBLOCK = EAGAIN; // Operation would block | ||
| 42 | pub const EINPROGRESS = 36; // Operation now in progress | ||
| 43 | pub const EALREADY = 37; // Operation already in progress | ||
| 44 | |||
| 45 | // ipc/network software -- argument errors | ||
| 46 | pub const ENOTSOCK = 38; // Socket operation on non-socket | ||
| 47 | pub const EDESTADDRREQ = 39; // Destination address required | ||
| 48 | pub const EMSGSIZE = 40; // Message too long | ||
| 49 | pub const EPROTOTYPE = 41; // Protocol wrong type for socket | ||
| 50 | pub const ENOPROTOOPT = 42; // Protocol not available | ||
| 51 | pub const EPROTONOSUPPORT = 43; // Protocol not supported | ||
| 52 | pub const ESOCKTNOSUPPORT = 44; // Socket type not supported | ||
| 53 | pub const EOPNOTSUPP = 45; // Operation not supported | ||
| 54 | pub const ENOTSUP = EOPNOTSUPP; // Operation not supported | ||
| 55 | pub const EPFNOSUPPORT = 46; // Protocol family not supported | ||
| 56 | pub const EAFNOSUPPORT = 47; // Address family not supported by protocol family | ||
| 57 | pub const EADDRINUSE = 48; // Address already in use | ||
| 58 | pub const EADDRNOTAVAIL = 49; // Can't assign requested address | ||
| 59 | |||
| 60 | // ipc/network software -- operational errors | ||
| 61 | pub const ENETDOWN = 50; // Network is down | ||
| 62 | pub const ENETUNREACH = 51; // Network is unreachable | ||
| 63 | pub const ENETRESET = 52; // Network dropped connection on reset | ||
| 64 | pub const ECONNABORTED = 53; // Software caused connection abort | ||
| 65 | pub const ECONNRESET = 54; // Connection reset by peer | ||
| 66 | pub const ENOBUFS = 55; // No buffer space available | ||
| 67 | pub const EISCONN = 56; // Socket is already connected | ||
| 68 | pub const ENOTCONN = 57; // Socket is not connected | ||
| 69 | pub const ESHUTDOWN = 58; // Can't send after socket shutdown | ||
| 70 | pub const ETOOMANYREFS = 59; // Too many references: can't splice | ||
| 71 | pub const ETIMEDOUT = 60; // Operation timed out | ||
| 72 | pub const ECONNREFUSED = 61; // Connection refused | ||
| 73 | |||
| 74 | pub const ELOOP = 62; // Too many levels of symbolic links | ||
| 75 | pub const ENAMETOOLONG = 63; // File name too long | ||
| 76 | |||
| 77 | // should be rearranged | ||
| 78 | pub const EHOSTDOWN = 64; // Host is down | ||
| 79 | pub const EHOSTUNREACH = 65; // No route to host | ||
| 80 | pub const ENOTEMPTY = 66; // Directory not empty | ||
| 81 | |||
| 82 | // quotas & mush | ||
| 83 | pub const EPROCLIM = 67; // Too many processes | ||
| 84 | pub const EUSERS = 68; // Too many users | ||
| 85 | pub const EDQUOT = 69; // Disc quota exceeded | ||
| 86 | |||
| 87 | // Network File System | ||
| 88 | pub const ESTALE = 70; // Stale NFS file handle | ||
| 89 | pub const EREMOTE = 71; // Too many levels of remote in path | ||
| 90 | pub const EBADRPC = 72; // RPC struct is bad | ||
| 91 | pub const ERPCMISMATCH = 73; // RPC version wrong | ||
| 92 | pub const EPROGUNAVAIL = 74; // RPC prog. not avail | ||
| 93 | pub const EPROGMISMATCH = 75; // Program version wrong | ||
| 94 | pub const EPROCUNAVAIL = 76; // Bad procedure for program | ||
| 95 | |||
| 96 | pub const ENOLCK = 77; // No locks available | ||
| 97 | pub const ENOSYS = 78; // Function not implemented | ||
| 98 | |||
| 99 | pub const EFTYPE = 79; // Inappropriate file type or format | ||
| 100 | pub const EAUTH = 80; // Authentication error | ||
| 101 | pub const ENEEDAUTH = 81; // Need authenticator | ||
| 102 | pub const EIDRM = 82; // Identifier removed | ||
| 103 | pub const ENOMSG = 83; // No message of desired type | ||
| 104 | pub const EOVERFLOW = 84; // Value too large to be stored in data type | ||
| 105 | pub const ECANCELED = 85; // Operation canceled | ||
| 106 | pub const EILSEQ = 86; // Illegal byte sequence | ||
| 107 | pub const ENOATTR = 87; // Attribute not found | ||
| 108 | |||
| 109 | pub const EDOOFUS = 88; // Programming error | ||
| 110 | |||
| 111 | pub const EBADMSG = 89; // Bad message | ||
| 112 | pub const EMULTIHOP = 90; // Multihop attempted | ||
| 113 | pub const ENOLINK = 91; // Link has been severed | ||
| 114 | pub const EPROTO = 92; // Protocol error | ||
| 115 | |||
| 116 | pub const ENOTCAPABLE = 93; // Capabilities insufficient | ||
| 117 | pub const ECAPMODE = 94; // Not permitted in capability mode | ||
| 118 | pub const ENOTRECOVERABLE = 95; // State not recoverable | ||
| 119 | pub const EOWNERDEAD = 96; // Previous owner died | ||
| 120 | |||
| 121 | pub const ELAST = 96; // Must be equal largest errno | ||
std/os/get_app_data_dir.zig deleted-69| ... | @@ -1,69 +0,0 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const unicode = std.unicode; | ||
| 4 | const mem = std.mem; | ||
| 5 | const os = std.os; | ||
| 6 | |||
| 7 | pub const GetAppDataDirError = error{ | ||
| 8 | OutOfMemory, | ||
| 9 | AppDataDirUnavailable, | ||
| 10 | }; | ||
| 11 | |||
| 12 | /// Caller owns returned memory. | ||
| 13 | /// TODO determine if we can remove the allocator requirement | ||
| 14 | pub 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 | |||
| 57 | fn 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 | |||
| 63 | test "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 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const Os = builtin.Os; | ||
| 3 | const os = @import("../os.zig"); | ||
| 4 | const io = @import("../io.zig"); | ||
| 5 | |||
| 6 | pub const UserInfo = struct { | ||
| 7 | uid: u32, | ||
| 8 | gid: u32, | ||
| 9 | }; | ||
| 10 | |||
| 11 | /// POSIX function which gets a uid from username. | ||
| 12 | pub 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 | |||
| 19 | const 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 | |||
| 30 | pub 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. | ||
| 1 | const std = @import("../std.zig"); | 8 | const std = @import("../std.zig"); |
| 2 | const assert = std.debug.assert; | ||
| 3 | const builtin = @import("builtin"); | 9 | const builtin = @import("builtin"); |
| 10 | const assert = std.debug.assert; | ||
| 4 | const maxInt = std.math.maxInt; | 11 | const maxInt = std.math.maxInt; |
| 5 | const elf = std.elf; | 12 | const elf = std.elf; |
| 6 | pub const tls = @import("linux/tls.zig"); | ||
| 7 | const vdso = @import("linux/vdso.zig"); | 13 | const vdso = @import("linux/vdso.zig"); |
| 8 | const dl = @import("../dynamic_library.zig"); | 14 | const dl = @import("../dynamic_library.zig"); |
| 15 | |||
| 16 | pub const is_the_target = builtin.os == .linux; | ||
| 9 | pub use switch (builtin.arch) { | 17 | pub 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 | }; |
| 15 | pub use @import("linux/errno.zig"); | 22 | pub use @import("bits.zig"); |
| 16 | 23 | pub const tls = @import("linux/tls.zig"); | |
| 17 | pub const PATH_MAX = 4096; | ||
| 18 | pub const IOV_MAX = 1024; | ||
| 19 | |||
| 20 | pub const STDIN_FILENO = 0; | ||
| 21 | pub const STDOUT_FILENO = 1; | ||
| 22 | pub const STDERR_FILENO = 2; | ||
| 23 | |||
| 24 | pub const FUTEX_WAIT = 0; | ||
| 25 | pub const FUTEX_WAKE = 1; | ||
| 26 | pub const FUTEX_FD = 2; | ||
| 27 | pub const FUTEX_REQUEUE = 3; | ||
| 28 | pub const FUTEX_CMP_REQUEUE = 4; | ||
| 29 | pub const FUTEX_WAKE_OP = 5; | ||
| 30 | pub const FUTEX_LOCK_PI = 6; | ||
| 31 | pub const FUTEX_UNLOCK_PI = 7; | ||
| 32 | pub const FUTEX_TRYLOCK_PI = 8; | ||
| 33 | pub const FUTEX_WAIT_BITSET = 9; | ||
| 34 | |||
| 35 | pub const FUTEX_PRIVATE_FLAG = 128; | ||
| 36 | |||
| 37 | pub const FUTEX_CLOCK_REALTIME = 256; | ||
| 38 | |||
| 39 | pub const PROT_NONE = 0; | ||
| 40 | pub const PROT_READ = 1; | ||
| 41 | pub const PROT_WRITE = 2; | ||
| 42 | pub const PROT_EXEC = 4; | ||
| 43 | pub const PROT_GROWSDOWN = 0x01000000; | ||
| 44 | pub const PROT_GROWSUP = 0x02000000; | ||
| 45 | |||
| 46 | pub const MAP_FAILED = maxInt(usize); | ||
| 47 | pub const MAP_SHARED = 0x01; | ||
| 48 | pub const MAP_PRIVATE = 0x02; | ||
| 49 | pub const MAP_TYPE = 0x0f; | ||
| 50 | pub const MAP_FIXED = 0x10; | ||
| 51 | pub const MAP_ANONYMOUS = 0x20; | ||
| 52 | pub const MAP_NORESERVE = 0x4000; | ||
| 53 | pub const MAP_GROWSDOWN = 0x0100; | ||
| 54 | pub const MAP_DENYWRITE = 0x0800; | ||
| 55 | pub const MAP_EXECUTABLE = 0x1000; | ||
| 56 | pub const MAP_LOCKED = 0x2000; | ||
| 57 | pub const MAP_POPULATE = 0x8000; | ||
| 58 | pub const MAP_NONBLOCK = 0x10000; | ||
| 59 | pub const MAP_STACK = 0x20000; | ||
| 60 | pub const MAP_HUGETLB = 0x40000; | ||
| 61 | pub const MAP_FILE = 0; | ||
| 62 | |||
| 63 | pub const F_OK = 0; | ||
| 64 | pub const X_OK = 1; | ||
| 65 | pub const W_OK = 2; | ||
| 66 | pub const R_OK = 4; | ||
| 67 | |||
| 68 | pub const WNOHANG = 1; | ||
| 69 | pub const WUNTRACED = 2; | ||
| 70 | pub const WSTOPPED = 2; | ||
| 71 | pub const WEXITED = 4; | ||
| 72 | pub const WCONTINUED = 8; | ||
| 73 | pub const WNOWAIT = 0x1000000; | ||
| 74 | |||
| 75 | pub const SA_NOCLDSTOP = 1; | ||
| 76 | pub const SA_NOCLDWAIT = 2; | ||
| 77 | pub const SA_SIGINFO = 4; | ||
| 78 | pub const SA_ONSTACK = 0x08000000; | ||
| 79 | pub const SA_RESTART = 0x10000000; | ||
| 80 | pub const SA_NODEFER = 0x40000000; | ||
| 81 | pub const SA_RESETHAND = 0x80000000; | ||
| 82 | pub const SA_RESTORER = 0x04000000; | ||
| 83 | |||
| 84 | pub const SIGHUP = 1; | ||
| 85 | pub const SIGINT = 2; | ||
| 86 | pub const SIGQUIT = 3; | ||
| 87 | pub const SIGILL = 4; | ||
| 88 | pub const SIGTRAP = 5; | ||
| 89 | pub const SIGABRT = 6; | ||
| 90 | pub const SIGIOT = SIGABRT; | ||
| 91 | pub const SIGBUS = 7; | ||
| 92 | pub const SIGFPE = 8; | ||
| 93 | pub const SIGKILL = 9; | ||
| 94 | pub const SIGUSR1 = 10; | ||
| 95 | pub const SIGSEGV = 11; | ||
| 96 | pub const SIGUSR2 = 12; | ||
| 97 | pub const SIGPIPE = 13; | ||
| 98 | pub const SIGALRM = 14; | ||
| 99 | pub const SIGTERM = 15; | ||
| 100 | pub const SIGSTKFLT = 16; | ||
| 101 | pub const SIGCHLD = 17; | ||
| 102 | pub const SIGCONT = 18; | ||
| 103 | pub const SIGSTOP = 19; | ||
| 104 | pub const SIGTSTP = 20; | ||
| 105 | pub const SIGTTIN = 21; | ||
| 106 | pub const SIGTTOU = 22; | ||
| 107 | pub const SIGURG = 23; | ||
| 108 | pub const SIGXCPU = 24; | ||
| 109 | pub const SIGXFSZ = 25; | ||
| 110 | pub const SIGVTALRM = 26; | ||
| 111 | pub const SIGPROF = 27; | ||
| 112 | pub const SIGWINCH = 28; | ||
| 113 | pub const SIGIO = 29; | ||
| 114 | pub const SIGPOLL = 29; | ||
| 115 | pub const SIGPWR = 30; | ||
| 116 | pub const SIGSYS = 31; | ||
| 117 | pub const SIGUNUSED = SIGSYS; | ||
| 118 | |||
| 119 | pub const O_RDONLY = 0o0; | ||
| 120 | pub const O_WRONLY = 0o1; | ||
| 121 | pub const O_RDWR = 0o2; | ||
| 122 | |||
| 123 | pub const SEEK_SET = 0; | ||
| 124 | pub const SEEK_CUR = 1; | ||
| 125 | pub const SEEK_END = 2; | ||
| 126 | |||
| 127 | pub const SIG_BLOCK = 0; | ||
| 128 | pub const SIG_UNBLOCK = 1; | ||
| 129 | pub const SIG_SETMASK = 2; | ||
| 130 | |||
| 131 | pub const PROTO_ip = 0o000; | ||
| 132 | pub const PROTO_icmp = 0o001; | ||
| 133 | pub const PROTO_igmp = 0o002; | ||
| 134 | pub const PROTO_ggp = 0o003; | ||
| 135 | pub const PROTO_ipencap = 0o004; | ||
| 136 | pub const PROTO_st = 0o005; | ||
| 137 | pub const PROTO_tcp = 0o006; | ||
| 138 | pub const PROTO_egp = 0o010; | ||
| 139 | pub const PROTO_pup = 0o014; | ||
| 140 | pub const PROTO_udp = 0o021; | ||
| 141 | pub const PROTO_hmp = 0o024; | ||
| 142 | pub const PROTO_xns_idp = 0o026; | ||
| 143 | pub const PROTO_rdp = 0o033; | ||
| 144 | pub const PROTO_iso_tp4 = 0o035; | ||
| 145 | pub const PROTO_xtp = 0o044; | ||
| 146 | pub const PROTO_ddp = 0o045; | ||
| 147 | pub const PROTO_idpr_cmtp = 0o046; | ||
| 148 | pub const PROTO_ipv6 = 0o051; | ||
| 149 | pub const PROTO_ipv6_route = 0o053; | ||
| 150 | pub const PROTO_ipv6_frag = 0o054; | ||
| 151 | pub const PROTO_idrp = 0o055; | ||
| 152 | pub const PROTO_rsvp = 0o056; | ||
| 153 | pub const PROTO_gre = 0o057; | ||
| 154 | pub const PROTO_esp = 0o062; | ||
| 155 | pub const PROTO_ah = 0o063; | ||
| 156 | pub const PROTO_skip = 0o071; | ||
| 157 | pub const PROTO_ipv6_icmp = 0o072; | ||
| 158 | pub const PROTO_ipv6_nonxt = 0o073; | ||
| 159 | pub const PROTO_ipv6_opts = 0o074; | ||
| 160 | pub const PROTO_rspf = 0o111; | ||
| 161 | pub const PROTO_vmtp = 0o121; | ||
| 162 | pub const PROTO_ospf = 0o131; | ||
| 163 | pub const PROTO_ipip = 0o136; | ||
| 164 | pub const PROTO_encap = 0o142; | ||
| 165 | pub const PROTO_pim = 0o147; | ||
| 166 | pub const PROTO_raw = 0o377; | ||
| 167 | |||
| 168 | pub const SHUT_RD = 0; | ||
| 169 | pub const SHUT_WR = 1; | ||
| 170 | pub const SHUT_RDWR = 2; | ||
| 171 | |||
| 172 | pub const SOCK_STREAM = 1; | ||
| 173 | pub const SOCK_DGRAM = 2; | ||
| 174 | pub const SOCK_RAW = 3; | ||
| 175 | pub const SOCK_RDM = 4; | ||
| 176 | pub const SOCK_SEQPACKET = 5; | ||
| 177 | pub const SOCK_DCCP = 6; | ||
| 178 | pub const SOCK_PACKET = 10; | ||
| 179 | pub const SOCK_CLOEXEC = 0o2000000; | ||
| 180 | pub const SOCK_NONBLOCK = 0o4000; | ||
| 181 | |||
| 182 | pub const PF_UNSPEC = 0; | ||
| 183 | pub const PF_LOCAL = 1; | ||
| 184 | pub const PF_UNIX = PF_LOCAL; | ||
| 185 | pub const PF_FILE = PF_LOCAL; | ||
| 186 | pub const PF_INET = 2; | ||
| 187 | pub const PF_AX25 = 3; | ||
| 188 | pub const PF_IPX = 4; | ||
| 189 | pub const PF_APPLETALK = 5; | ||
| 190 | pub const PF_NETROM = 6; | ||
| 191 | pub const PF_BRIDGE = 7; | ||
| 192 | pub const PF_ATMPVC = 8; | ||
| 193 | pub const PF_X25 = 9; | ||
| 194 | pub const PF_INET6 = 10; | ||
| 195 | pub const PF_ROSE = 11; | ||
| 196 | pub const PF_DECnet = 12; | ||
| 197 | pub const PF_NETBEUI = 13; | ||
| 198 | pub const PF_SECURITY = 14; | ||
| 199 | pub const PF_KEY = 15; | ||
| 200 | pub const PF_NETLINK = 16; | ||
| 201 | pub const PF_ROUTE = PF_NETLINK; | ||
| 202 | pub const PF_PACKET = 17; | ||
| 203 | pub const PF_ASH = 18; | ||
| 204 | pub const PF_ECONET = 19; | ||
| 205 | pub const PF_ATMSVC = 20; | ||
| 206 | pub const PF_RDS = 21; | ||
| 207 | pub const PF_SNA = 22; | ||
| 208 | pub const PF_IRDA = 23; | ||
| 209 | pub const PF_PPPOX = 24; | ||
| 210 | pub const PF_WANPIPE = 25; | ||
| 211 | pub const PF_LLC = 26; | ||
| 212 | pub const PF_IB = 27; | ||
| 213 | pub const PF_MPLS = 28; | ||
| 214 | pub const PF_CAN = 29; | ||
| 215 | pub const PF_TIPC = 30; | ||
| 216 | pub const PF_BLUETOOTH = 31; | ||
| 217 | pub const PF_IUCV = 32; | ||
| 218 | pub const PF_RXRPC = 33; | ||
| 219 | pub const PF_ISDN = 34; | ||
| 220 | pub const PF_PHONET = 35; | ||
| 221 | pub const PF_IEEE802154 = 36; | ||
| 222 | pub const PF_CAIF = 37; | ||
| 223 | pub const PF_ALG = 38; | ||
| 224 | pub const PF_NFC = 39; | ||
| 225 | pub const PF_VSOCK = 40; | ||
| 226 | pub const PF_KCM = 41; | ||
| 227 | pub const PF_QIPCRTR = 42; | ||
| 228 | pub const PF_SMC = 43; | ||
| 229 | pub const PF_MAX = 44; | ||
| 230 | |||
| 231 | pub const AF_UNSPEC = PF_UNSPEC; | ||
| 232 | pub const AF_LOCAL = PF_LOCAL; | ||
| 233 | pub const AF_UNIX = AF_LOCAL; | ||
| 234 | pub const AF_FILE = AF_LOCAL; | ||
| 235 | pub const AF_INET = PF_INET; | ||
| 236 | pub const AF_AX25 = PF_AX25; | ||
| 237 | pub const AF_IPX = PF_IPX; | ||
| 238 | pub const AF_APPLETALK = PF_APPLETALK; | ||
| 239 | pub const AF_NETROM = PF_NETROM; | ||
| 240 | pub const AF_BRIDGE = PF_BRIDGE; | ||
| 241 | pub const AF_ATMPVC = PF_ATMPVC; | ||
| 242 | pub const AF_X25 = PF_X25; | ||
| 243 | pub const AF_INET6 = PF_INET6; | ||
| 244 | pub const AF_ROSE = PF_ROSE; | ||
| 245 | pub const AF_DECnet = PF_DECnet; | ||
| 246 | pub const AF_NETBEUI = PF_NETBEUI; | ||
| 247 | pub const AF_SECURITY = PF_SECURITY; | ||
| 248 | pub const AF_KEY = PF_KEY; | ||
| 249 | pub const AF_NETLINK = PF_NETLINK; | ||
| 250 | pub const AF_ROUTE = PF_ROUTE; | ||
| 251 | pub const AF_PACKET = PF_PACKET; | ||
| 252 | pub const AF_ASH = PF_ASH; | ||
| 253 | pub const AF_ECONET = PF_ECONET; | ||
| 254 | pub const AF_ATMSVC = PF_ATMSVC; | ||
| 255 | pub const AF_RDS = PF_RDS; | ||
| 256 | pub const AF_SNA = PF_SNA; | ||
| 257 | pub const AF_IRDA = PF_IRDA; | ||
| 258 | pub const AF_PPPOX = PF_PPPOX; | ||
| 259 | pub const AF_WANPIPE = PF_WANPIPE; | ||
| 260 | pub const AF_LLC = PF_LLC; | ||
| 261 | pub const AF_IB = PF_IB; | ||
| 262 | pub const AF_MPLS = PF_MPLS; | ||
| 263 | pub const AF_CAN = PF_CAN; | ||
| 264 | pub const AF_TIPC = PF_TIPC; | ||
| 265 | pub const AF_BLUETOOTH = PF_BLUETOOTH; | ||
| 266 | pub const AF_IUCV = PF_IUCV; | ||
| 267 | pub const AF_RXRPC = PF_RXRPC; | ||
| 268 | pub const AF_ISDN = PF_ISDN; | ||
| 269 | pub const AF_PHONET = PF_PHONET; | ||
| 270 | pub const AF_IEEE802154 = PF_IEEE802154; | ||
| 271 | pub const AF_CAIF = PF_CAIF; | ||
| 272 | pub const AF_ALG = PF_ALG; | ||
| 273 | pub const AF_NFC = PF_NFC; | ||
| 274 | pub const AF_VSOCK = PF_VSOCK; | ||
| 275 | pub const AF_KCM = PF_KCM; | ||
| 276 | pub const AF_QIPCRTR = PF_QIPCRTR; | ||
| 277 | pub const AF_SMC = PF_SMC; | ||
| 278 | pub const AF_MAX = PF_MAX; | ||
| 279 | |||
| 280 | pub const SO_DEBUG = 1; | ||
| 281 | pub const SO_REUSEADDR = 2; | ||
| 282 | pub const SO_TYPE = 3; | ||
| 283 | pub const SO_ERROR = 4; | ||
| 284 | pub const SO_DONTROUTE = 5; | ||
| 285 | pub const SO_BROADCAST = 6; | ||
| 286 | pub const SO_SNDBUF = 7; | ||
| 287 | pub const SO_RCVBUF = 8; | ||
| 288 | pub const SO_KEEPALIVE = 9; | ||
| 289 | pub const SO_OOBINLINE = 10; | ||
| 290 | pub const SO_NO_CHECK = 11; | ||
| 291 | pub const SO_PRIORITY = 12; | ||
| 292 | pub const SO_LINGER = 13; | ||
| 293 | pub const SO_BSDCOMPAT = 14; | ||
| 294 | pub const SO_REUSEPORT = 15; | ||
| 295 | pub const SO_PASSCRED = 16; | ||
| 296 | pub const SO_PEERCRED = 17; | ||
| 297 | pub const SO_RCVLOWAT = 18; | ||
| 298 | pub const SO_SNDLOWAT = 19; | ||
| 299 | pub const SO_RCVTIMEO = 20; | ||
| 300 | pub const SO_SNDTIMEO = 21; | ||
| 301 | pub const SO_ACCEPTCONN = 30; | ||
| 302 | pub const SO_SNDBUFFORCE = 32; | ||
| 303 | pub const SO_RCVBUFFORCE = 33; | ||
| 304 | pub const SO_PROTOCOL = 38; | ||
| 305 | pub const SO_DOMAIN = 39; | ||
| 306 | |||
| 307 | pub const SO_SECURITY_AUTHENTICATION = 22; | ||
| 308 | pub const SO_SECURITY_ENCRYPTION_TRANSPORT = 23; | ||
| 309 | pub const SO_SECURITY_ENCRYPTION_NETWORK = 24; | ||
| 310 | |||
| 311 | pub const SO_BINDTODEVICE = 25; | ||
| 312 | |||
| 313 | pub const SO_ATTACH_FILTER = 26; | ||
| 314 | pub const SO_DETACH_FILTER = 27; | ||
| 315 | pub const SO_GET_FILTER = SO_ATTACH_FILTER; | ||
| 316 | |||
| 317 | pub const SO_PEERNAME = 28; | ||
| 318 | pub const SO_TIMESTAMP = 29; | ||
| 319 | pub const SCM_TIMESTAMP = SO_TIMESTAMP; | ||
| 320 | |||
| 321 | pub const SO_PEERSEC = 31; | ||
| 322 | pub const SO_PASSSEC = 34; | ||
| 323 | pub const SO_TIMESTAMPNS = 35; | ||
| 324 | pub const SCM_TIMESTAMPNS = SO_TIMESTAMPNS; | ||
| 325 | pub const SO_MARK = 36; | ||
| 326 | pub const SO_TIMESTAMPING = 37; | ||
| 327 | pub const SCM_TIMESTAMPING = SO_TIMESTAMPING; | ||
| 328 | pub const SO_RXQ_OVFL = 40; | ||
| 329 | pub const SO_WIFI_STATUS = 41; | ||
| 330 | pub const SCM_WIFI_STATUS = SO_WIFI_STATUS; | ||
| 331 | pub const SO_PEEK_OFF = 42; | ||
| 332 | pub const SO_NOFCS = 43; | ||
| 333 | pub const SO_LOCK_FILTER = 44; | ||
| 334 | pub const SO_SELECT_ERR_QUEUE = 45; | ||
| 335 | pub const SO_BUSY_POLL = 46; | ||
| 336 | pub const SO_MAX_PACING_RATE = 47; | ||
| 337 | pub const SO_BPF_EXTENSIONS = 48; | ||
| 338 | pub const SO_INCOMING_CPU = 49; | ||
| 339 | pub const SO_ATTACH_BPF = 50; | ||
| 340 | pub const SO_DETACH_BPF = SO_DETACH_FILTER; | ||
| 341 | pub const SO_ATTACH_REUSEPORT_CBPF = 51; | ||
| 342 | pub const SO_ATTACH_REUSEPORT_EBPF = 52; | ||
| 343 | pub const SO_CNX_ADVICE = 53; | ||
| 344 | pub const SCM_TIMESTAMPING_OPT_STATS = 54; | ||
| 345 | pub const SO_MEMINFO = 55; | ||
| 346 | pub const SO_INCOMING_NAPI_ID = 56; | ||
| 347 | pub const SO_COOKIE = 57; | ||
| 348 | pub const SCM_TIMESTAMPING_PKTINFO = 58; | ||
| 349 | pub const SO_PEERGROUPS = 59; | ||
| 350 | pub const SO_ZEROCOPY = 60; | ||
| 351 | |||
| 352 | pub const SOL_SOCKET = 1; | ||
| 353 | |||
| 354 | pub const SOL_IP = 0; | ||
| 355 | pub const SOL_IPV6 = 41; | ||
| 356 | pub const SOL_ICMPV6 = 58; | ||
| 357 | |||
| 358 | pub const SOL_RAW = 255; | ||
| 359 | pub const SOL_DECNET = 261; | ||
| 360 | pub const SOL_X25 = 262; | ||
| 361 | pub const SOL_PACKET = 263; | ||
| 362 | pub const SOL_ATM = 264; | ||
| 363 | pub const SOL_AAL = 265; | ||
| 364 | pub const SOL_IRDA = 266; | ||
| 365 | pub const SOL_NETBEUI = 267; | ||
| 366 | pub const SOL_LLC = 268; | ||
| 367 | pub const SOL_DCCP = 269; | ||
| 368 | pub const SOL_NETLINK = 270; | ||
| 369 | pub const SOL_TIPC = 271; | ||
| 370 | pub const SOL_RXRPC = 272; | ||
| 371 | pub const SOL_PPPOL2TP = 273; | ||
| 372 | pub const SOL_BLUETOOTH = 274; | ||
| 373 | pub const SOL_PNPIPE = 275; | ||
| 374 | pub const SOL_RDS = 276; | ||
| 375 | pub const SOL_IUCV = 277; | ||
| 376 | pub const SOL_CAIF = 278; | ||
| 377 | pub const SOL_ALG = 279; | ||
| 378 | pub const SOL_NFC = 280; | ||
| 379 | pub const SOL_KCM = 281; | ||
| 380 | pub const SOL_TLS = 282; | ||
| 381 | |||
| 382 | pub const SOMAXCONN = 128; | ||
| 383 | |||
| 384 | pub const MSG_OOB = 0x0001; | ||
| 385 | pub const MSG_PEEK = 0x0002; | ||
| 386 | pub const MSG_DONTROUTE = 0x0004; | ||
| 387 | pub const MSG_CTRUNC = 0x0008; | ||
| 388 | pub const MSG_PROXY = 0x0010; | ||
| 389 | pub const MSG_TRUNC = 0x0020; | ||
| 390 | pub const MSG_DONTWAIT = 0x0040; | ||
| 391 | pub const MSG_EOR = 0x0080; | ||
| 392 | pub const MSG_WAITALL = 0x0100; | ||
| 393 | pub const MSG_FIN = 0x0200; | ||
| 394 | pub const MSG_SYN = 0x0400; | ||
| 395 | pub const MSG_CONFIRM = 0x0800; | ||
| 396 | pub const MSG_RST = 0x1000; | ||
| 397 | pub const MSG_ERRQUEUE = 0x2000; | ||
| 398 | pub const MSG_NOSIGNAL = 0x4000; | ||
| 399 | pub const MSG_MORE = 0x8000; | ||
| 400 | pub const MSG_WAITFORONE = 0x10000; | ||
| 401 | pub const MSG_BATCH = 0x40000; | ||
| 402 | pub const MSG_ZEROCOPY = 0x4000000; | ||
| 403 | pub const MSG_FASTOPEN = 0x20000000; | ||
| 404 | pub const MSG_CMSG_CLOEXEC = 0x40000000; | ||
| 405 | |||
| 406 | pub const DT_UNKNOWN = 0; | ||
| 407 | pub const DT_FIFO = 1; | ||
| 408 | pub const DT_CHR = 2; | ||
| 409 | pub const DT_DIR = 4; | ||
| 410 | pub const DT_BLK = 6; | ||
| 411 | pub const DT_REG = 8; | ||
| 412 | pub const DT_LNK = 10; | ||
| 413 | pub const DT_SOCK = 12; | ||
| 414 | pub const DT_WHT = 14; | ||
| 415 | |||
| 416 | pub const TCGETS = 0x5401; | ||
| 417 | pub const TCSETS = 0x5402; | ||
| 418 | pub const TCSETSW = 0x5403; | ||
| 419 | pub const TCSETSF = 0x5404; | ||
| 420 | pub const TCGETA = 0x5405; | ||
| 421 | pub const TCSETA = 0x5406; | ||
| 422 | pub const TCSETAW = 0x5407; | ||
| 423 | pub const TCSETAF = 0x5408; | ||
| 424 | pub const TCSBRK = 0x5409; | ||
| 425 | pub const TCXONC = 0x540A; | ||
| 426 | pub const TCFLSH = 0x540B; | ||
| 427 | pub const TIOCEXCL = 0x540C; | ||
| 428 | pub const TIOCNXCL = 0x540D; | ||
| 429 | pub const TIOCSCTTY = 0x540E; | ||
| 430 | pub const TIOCGPGRP = 0x540F; | ||
| 431 | pub const TIOCSPGRP = 0x5410; | ||
| 432 | pub const TIOCOUTQ = 0x5411; | ||
| 433 | pub const TIOCSTI = 0x5412; | ||
| 434 | pub const TIOCGWINSZ = 0x5413; | ||
| 435 | pub const TIOCSWINSZ = 0x5414; | ||
| 436 | pub const TIOCMGET = 0x5415; | ||
| 437 | pub const TIOCMBIS = 0x5416; | ||
| 438 | pub const TIOCMBIC = 0x5417; | ||
| 439 | pub const TIOCMSET = 0x5418; | ||
| 440 | pub const TIOCGSOFTCAR = 0x5419; | ||
| 441 | pub const TIOCSSOFTCAR = 0x541A; | ||
| 442 | pub const FIONREAD = 0x541B; | ||
| 443 | pub const TIOCINQ = FIONREAD; | ||
| 444 | pub const TIOCLINUX = 0x541C; | ||
| 445 | pub const TIOCCONS = 0x541D; | ||
| 446 | pub const TIOCGSERIAL = 0x541E; | ||
| 447 | pub const TIOCSSERIAL = 0x541F; | ||
| 448 | pub const TIOCPKT = 0x5420; | ||
| 449 | pub const FIONBIO = 0x5421; | ||
| 450 | pub const TIOCNOTTY = 0x5422; | ||
| 451 | pub const TIOCSETD = 0x5423; | ||
| 452 | pub const TIOCGETD = 0x5424; | ||
| 453 | pub const TCSBRKP = 0x5425; | ||
| 454 | pub const TIOCSBRK = 0x5427; | ||
| 455 | pub const TIOCCBRK = 0x5428; | ||
| 456 | pub const TIOCGSID = 0x5429; | ||
| 457 | pub const TIOCGRS485 = 0x542E; | ||
| 458 | pub const TIOCSRS485 = 0x542F; | ||
| 459 | pub const TIOCGPTN = 0x80045430; | ||
| 460 | pub const TIOCSPTLCK = 0x40045431; | ||
| 461 | pub const TIOCGDEV = 0x80045432; | ||
| 462 | pub const TCGETX = 0x5432; | ||
| 463 | pub const TCSETX = 0x5433; | ||
| 464 | pub const TCSETXF = 0x5434; | ||
| 465 | pub const TCSETXW = 0x5435; | ||
| 466 | pub const TIOCSIG = 0x40045436; | ||
| 467 | pub const TIOCVHANGUP = 0x5437; | ||
| 468 | pub const TIOCGPKT = 0x80045438; | ||
| 469 | pub const TIOCGPTLCK = 0x80045439; | ||
| 470 | pub const TIOCGEXCL = 0x80045440; | ||
| 471 | |||
| 472 | pub const EPOLL_CLOEXEC = O_CLOEXEC; | ||
| 473 | |||
| 474 | pub const EPOLL_CTL_ADD = 1; | ||
| 475 | pub const EPOLL_CTL_DEL = 2; | ||
| 476 | pub const EPOLL_CTL_MOD = 3; | ||
| 477 | |||
| 478 | pub const EPOLLIN = 0x001; | ||
| 479 | pub const EPOLLPRI = 0x002; | ||
| 480 | pub const EPOLLOUT = 0x004; | ||
| 481 | pub const EPOLLRDNORM = 0x040; | ||
| 482 | pub const EPOLLRDBAND = 0x080; | ||
| 483 | pub const EPOLLWRNORM = 0x100; | ||
| 484 | pub const EPOLLWRBAND = 0x200; | ||
| 485 | pub const EPOLLMSG = 0x400; | ||
| 486 | pub const EPOLLERR = 0x008; | ||
| 487 | pub const EPOLLHUP = 0x010; | ||
| 488 | pub const EPOLLRDHUP = 0x2000; | ||
| 489 | pub const EPOLLEXCLUSIVE = (u32(1) << 28); | ||
| 490 | pub const EPOLLWAKEUP = (u32(1) << 29); | ||
| 491 | pub const EPOLLONESHOT = (u32(1) << 30); | ||
| 492 | pub const EPOLLET = (u32(1) << 31); | ||
| 493 | |||
| 494 | pub const CLOCK_REALTIME = 0; | ||
| 495 | pub const CLOCK_MONOTONIC = 1; | ||
| 496 | pub const CLOCK_PROCESS_CPUTIME_ID = 2; | ||
| 497 | pub const CLOCK_THREAD_CPUTIME_ID = 3; | ||
| 498 | pub const CLOCK_MONOTONIC_RAW = 4; | ||
| 499 | pub const CLOCK_REALTIME_COARSE = 5; | ||
| 500 | pub const CLOCK_MONOTONIC_COARSE = 6; | ||
| 501 | pub const CLOCK_BOOTTIME = 7; | ||
| 502 | pub const CLOCK_REALTIME_ALARM = 8; | ||
| 503 | pub const CLOCK_BOOTTIME_ALARM = 9; | ||
| 504 | pub const CLOCK_SGI_CYCLE = 10; | ||
| 505 | pub const CLOCK_TAI = 11; | ||
| 506 | |||
| 507 | pub const CSIGNAL = 0x000000ff; | ||
| 508 | pub const CLONE_VM = 0x00000100; | ||
| 509 | pub const CLONE_FS = 0x00000200; | ||
| 510 | pub const CLONE_FILES = 0x00000400; | ||
| 511 | pub const CLONE_SIGHAND = 0x00000800; | ||
| 512 | pub const CLONE_PTRACE = 0x00002000; | ||
| 513 | pub const CLONE_VFORK = 0x00004000; | ||
| 514 | pub const CLONE_PARENT = 0x00008000; | ||
| 515 | pub const CLONE_THREAD = 0x00010000; | ||
| 516 | pub const CLONE_NEWNS = 0x00020000; | ||
| 517 | pub const CLONE_SYSVSEM = 0x00040000; | ||
| 518 | pub const CLONE_SETTLS = 0x00080000; | ||
| 519 | pub const CLONE_PARENT_SETTID = 0x00100000; | ||
| 520 | pub const CLONE_CHILD_CLEARTID = 0x00200000; | ||
| 521 | pub const CLONE_DETACHED = 0x00400000; | ||
| 522 | pub const CLONE_UNTRACED = 0x00800000; | ||
| 523 | pub const CLONE_CHILD_SETTID = 0x01000000; | ||
| 524 | pub const CLONE_NEWCGROUP = 0x02000000; | ||
| 525 | pub const CLONE_NEWUTS = 0x04000000; | ||
| 526 | pub const CLONE_NEWIPC = 0x08000000; | ||
| 527 | pub const CLONE_NEWUSER = 0x10000000; | ||
| 528 | pub const CLONE_NEWPID = 0x20000000; | ||
| 529 | pub const CLONE_NEWNET = 0x40000000; | ||
| 530 | pub const CLONE_IO = 0x80000000; | ||
| 531 | |||
| 532 | pub const EFD_SEMAPHORE = 1; | ||
| 533 | pub const EFD_CLOEXEC = O_CLOEXEC; | ||
| 534 | pub const EFD_NONBLOCK = O_NONBLOCK; | ||
| 535 | |||
| 536 | pub const MS_RDONLY = 1; | ||
| 537 | pub const MS_NOSUID = 2; | ||
| 538 | pub const MS_NODEV = 4; | ||
| 539 | pub const MS_NOEXEC = 8; | ||
| 540 | pub const MS_SYNCHRONOUS = 16; | ||
| 541 | pub const MS_REMOUNT = 32; | ||
| 542 | pub const MS_MANDLOCK = 64; | ||
| 543 | pub const MS_DIRSYNC = 128; | ||
| 544 | pub const MS_NOATIME = 1024; | ||
| 545 | pub const MS_NODIRATIME = 2048; | ||
| 546 | pub const MS_BIND = 4096; | ||
| 547 | pub const MS_MOVE = 8192; | ||
| 548 | pub const MS_REC = 16384; | ||
| 549 | pub const MS_SILENT = 32768; | ||
| 550 | pub const MS_POSIXACL = (1 << 16); | ||
| 551 | pub const MS_UNBINDABLE = (1 << 17); | ||
| 552 | pub const MS_PRIVATE = (1 << 18); | ||
| 553 | pub const MS_SLAVE = (1 << 19); | ||
| 554 | pub const MS_SHARED = (1 << 20); | ||
| 555 | pub const MS_RELATIME = (1 << 21); | ||
| 556 | pub const MS_KERNMOUNT = (1 << 22); | ||
| 557 | pub const MS_I_VERSION = (1 << 23); | ||
| 558 | pub const MS_STRICTATIME = (1 << 24); | ||
| 559 | pub const MS_LAZYTIME = (1 << 25); | ||
| 560 | pub const MS_NOREMOTELOCK = (1 << 27); | ||
| 561 | pub const MS_NOSEC = (1 << 28); | ||
| 562 | pub const MS_BORN = (1 << 29); | ||
| 563 | pub const MS_ACTIVE = (1 << 30); | ||
| 564 | pub const MS_NOUSER = (1 << 31); | ||
| 565 | |||
| 566 | pub const MS_RMT_MASK = (MS_RDONLY | MS_SYNCHRONOUS | MS_MANDLOCK | MS_I_VERSION | MS_LAZYTIME); | ||
| 567 | |||
| 568 | pub const MS_MGC_VAL = 0xc0ed0000; | ||
| 569 | pub const MS_MGC_MSK = 0xffff0000; | ||
| 570 | |||
| 571 | pub const MNT_FORCE = 1; | ||
| 572 | pub const MNT_DETACH = 2; | ||
| 573 | pub const MNT_EXPIRE = 4; | ||
| 574 | pub const UMOUNT_NOFOLLOW = 8; | ||
| 575 | |||
| 576 | pub const IN_CLOEXEC = O_CLOEXEC; | ||
| 577 | pub const IN_NONBLOCK = O_NONBLOCK; | ||
| 578 | |||
| 579 | pub const IN_ACCESS = 0x00000001; | ||
| 580 | pub const IN_MODIFY = 0x00000002; | ||
| 581 | pub const IN_ATTRIB = 0x00000004; | ||
| 582 | pub const IN_CLOSE_WRITE = 0x00000008; | ||
| 583 | pub const IN_CLOSE_NOWRITE = 0x00000010; | ||
| 584 | pub const IN_CLOSE = IN_CLOSE_WRITE | IN_CLOSE_NOWRITE; | ||
| 585 | pub const IN_OPEN = 0x00000020; | ||
| 586 | pub const IN_MOVED_FROM = 0x00000040; | ||
| 587 | pub const IN_MOVED_TO = 0x00000080; | ||
| 588 | pub const IN_MOVE = IN_MOVED_FROM | IN_MOVED_TO; | ||
| 589 | pub const IN_CREATE = 0x00000100; | ||
| 590 | pub const IN_DELETE = 0x00000200; | ||
| 591 | pub const IN_DELETE_SELF = 0x00000400; | ||
| 592 | pub const IN_MOVE_SELF = 0x00000800; | ||
| 593 | pub const IN_ALL_EVENTS = 0x00000fff; | ||
| 594 | |||
| 595 | pub const IN_UNMOUNT = 0x00002000; | ||
| 596 | pub const IN_Q_OVERFLOW = 0x00004000; | ||
| 597 | pub const IN_IGNORED = 0x00008000; | ||
| 598 | |||
| 599 | pub const IN_ONLYDIR = 0x01000000; | ||
| 600 | pub const IN_DONT_FOLLOW = 0x02000000; | ||
| 601 | pub const IN_EXCL_UNLINK = 0x04000000; | ||
| 602 | pub const IN_MASK_ADD = 0x20000000; | ||
| 603 | |||
| 604 | pub const IN_ISDIR = 0x40000000; | ||
| 605 | pub const IN_ONESHOT = 0x80000000; | ||
| 606 | |||
| 607 | pub const S_IFMT = 0o170000; | ||
| 608 | |||
| 609 | pub const S_IFDIR = 0o040000; | ||
| 610 | pub const S_IFCHR = 0o020000; | ||
| 611 | pub const S_IFBLK = 0o060000; | ||
| 612 | pub const S_IFREG = 0o100000; | ||
| 613 | pub const S_IFIFO = 0o010000; | ||
| 614 | pub const S_IFLNK = 0o120000; | ||
| 615 | pub const S_IFSOCK = 0o140000; | ||
| 616 | |||
| 617 | pub const S_ISUID = 0o4000; | ||
| 618 | pub const S_ISGID = 0o2000; | ||
| 619 | pub const S_ISVTX = 0o1000; | ||
| 620 | pub const S_IRUSR = 0o400; | ||
| 621 | pub const S_IWUSR = 0o200; | ||
| 622 | pub const S_IXUSR = 0o100; | ||
| 623 | pub const S_IRWXU = 0o700; | ||
| 624 | pub const S_IRGRP = 0o040; | ||
| 625 | pub const S_IWGRP = 0o020; | ||
| 626 | pub const S_IXGRP = 0o010; | ||
| 627 | pub const S_IRWXG = 0o070; | ||
| 628 | pub const S_IROTH = 0o004; | ||
| 629 | pub const S_IWOTH = 0o002; | ||
| 630 | pub const S_IXOTH = 0o001; | ||
| 631 | pub const S_IRWXO = 0o007; | ||
| 632 | |||
| 633 | pub fn S_ISREG(m: u32) bool { | ||
| 634 | return m & S_IFMT == S_IFREG; | ||
| 635 | } | ||
| 636 | |||
| 637 | pub fn S_ISDIR(m: u32) bool { | ||
| 638 | return m & S_IFMT == S_IFDIR; | ||
| 639 | } | ||
| 640 | |||
| 641 | pub fn S_ISCHR(m: u32) bool { | ||
| 642 | return m & S_IFMT == S_IFCHR; | ||
| 643 | } | ||
| 644 | |||
| 645 | pub fn S_ISBLK(m: u32) bool { | ||
| 646 | return m & S_IFMT == S_IFBLK; | ||
| 647 | } | ||
| 648 | |||
| 649 | pub fn S_ISFIFO(m: u32) bool { | ||
| 650 | return m & S_IFMT == S_IFIFO; | ||
| 651 | } | ||
| 652 | |||
| 653 | pub fn S_ISLNK(m: u32) bool { | ||
| 654 | return m & S_IFMT == S_IFLNK; | ||
| 655 | } | ||
| 656 | |||
| 657 | pub fn S_ISSOCK(m: u32) bool { | ||
| 658 | return m & S_IFMT == S_IFSOCK; | ||
| 659 | } | ||
| 660 | |||
| 661 | pub const TFD_NONBLOCK = O_NONBLOCK; | ||
| 662 | pub const TFD_CLOEXEC = O_CLOEXEC; | ||
| 663 | 24 | ||
| 664 | pub const TFD_TIMER_ABSTIME = 1; | 25 | /// Set by startup code, used by `getauxval`. |
| 665 | pub const TFD_TIMER_CANCEL_ON_SET = (1 << 1); | 26 | pub var elf_aux_maybe: ?[*]std.elf.Auxv = null; |
| 666 | 27 | ||
| 667 | fn unsigned(s: i32) u32 { | 28 | /// See `std.elf` for the constants. |
| 668 | return @bitCast(u32, s); | 29 | pub fn getauxval(index: usize) usize { |
| 669 | } | 30 | const auxv = elf_aux_maybe orelse return 0; |
| 670 | fn 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) |
| 673 | pub 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; |
| 676 | pub fn WTERMSIG(s: i32) i32 { | ||
| 677 | return signed(unsigned(s) & 0x7f); | ||
| 678 | } | ||
| 679 | pub fn WSTOPSIG(s: i32) i32 { | ||
| 680 | return WEXITSTATUS(s); | ||
| 681 | } | ||
| 682 | pub fn WIFEXITED(s: i32) bool { | ||
| 683 | return WTERMSIG(s) == 0; | ||
| 684 | } | ||
| 685 | pub fn WIFSTOPPED(s: i32) bool { | ||
| 686 | return @intCast(u16, ((unsigned(s) & 0xffff) *% 0x10001) >> 8) > 0x7f00; | ||
| 687 | } | ||
| 688 | pub fn WIFSIGNALED(s: i32) bool { | ||
| 689 | return (unsigned(s) & 0xffff) -% 1 < 0xff; | ||
| 690 | } | 37 | } |
| 691 | 38 | ||
| 692 | pub 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. |
| 700 | pub fn getErrno(r: usize) usize { | 40 | pub 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 | } |
| 704 | 44 | ||
| 705 | pub fn dup2(old: i32, new: i32) usize { | 45 | pub 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 | } |
| 708 | 60 | ||
| 709 | pub fn dup3(old: i32, new: i32, flags: u32) usize { | 61 | pub fn dup3(old: i32, new: i32, flags: u32) usize { |
| ... | @@ -726,7 +78,11 @@ pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[* | ... | @@ -726,7 +78,11 @@ pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[* |
| 726 | } | 78 | } |
| 727 | 79 | ||
| 728 | pub fn fork() usize { | 80 | pub 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 | } |
| 731 | 87 | ||
| 732 | /// This must be inline, and inline call the syscall function, because if the | 88 | /// 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 | } |
| 752 | 108 | ||
| 109 | pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize { | ||
| 110 | return syscall3(SYS_getdents, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count); | ||
| 111 | } | ||
| 112 | |||
| 753 | pub fn getdents64(fd: i32, dirp: [*]u8, count: usize) usize { | 113 | pub 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 | } |
| 768 | 128 | ||
| 769 | pub 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/265 | 129 | // TODO https://github.com/ziglang/zig/issues/265 |
| 775 | pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize { | 130 | pub 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 | } |
| 778 | 137 | ||
| 779 | // TODO https://github.com/ziglang/zig/issues/265 | 138 | // 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, |
| 783 | 142 | ||
| 784 | // TODO https://github.com/ziglang/zig/issues/265 | 143 | // TODO https://github.com/ziglang/zig/issues/265 |
| 785 | pub fn mkdir(path: [*]const u8, mode: u32) usize { | 144 | pub 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 | } |
| 788 | 151 | ||
| 789 | // TODO https://github.com/ziglang/zig/issues/265 | 152 | // 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 | } |
| 812 | 175 | ||
| 813 | pub fn mprotect(address: usize, length: usize, protection: usize) usize { | 176 | pub 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 | } |
| 816 | 179 | ||
| 817 | pub fn munmap(address: usize, length: usize) usize { | 180 | pub 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 | } |
| 820 | 183 | ||
| 821 | pub fn read(fd: i32, buf: [*]u8, count: usize) usize { | 184 | pub fn read(fd: i32, buf: [*]u8, count: usize) usize { |
| ... | @@ -840,12 +203,20 @@ pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) us | ... | @@ -840,12 +203,20 @@ pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) us |
| 840 | 203 | ||
| 841 | // TODO https://github.com/ziglang/zig/issues/265 | 204 | // TODO https://github.com/ziglang/zig/issues/265 |
| 842 | pub fn rmdir(path: [*]const u8) usize { | 205 | pub 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 | } |
| 845 | 212 | ||
| 846 | // TODO https://github.com/ziglang/zig/issues/265 | 213 | // TODO https://github.com/ziglang/zig/issues/265 |
| 847 | pub fn symlink(existing: [*]const u8, new: [*]const u8) usize { | 214 | pub 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 | } |
| 850 | 221 | ||
| 851 | // TODO https://github.com/ziglang/zig/issues/265 | 222 | // 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 { |
| 860 | 231 | ||
| 861 | // TODO https://github.com/ziglang/zig/issues/265 | 232 | // TODO https://github.com/ziglang/zig/issues/265 |
| 862 | pub fn access(path: [*]const u8, mode: u32) usize { | 233 | pub 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 | } |
| 865 | 236 | ||
| 237 | // TODO https://github.com/ziglang/zig/issues/265 | ||
| 866 | pub fn faccessat(dirfd: i32, path: [*]const u8, mode: u32) usize { | 238 | pub 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 | } |
| 869 | 241 | ||
| 870 | pub fn pipe(fd: *[2]i32) usize { | 242 | pub 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 | } |
| 873 | 249 | ||
| 874 | pub fn pipe2(fd: *[2]i32, flags: u32) usize { | 250 | pub fn pipe2(fd: *[2]i32, flags: u32) usize { |
| ... | @@ -885,17 +261,51 @@ pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize { | ... | @@ -885,17 +261,51 @@ pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize { |
| 885 | 261 | ||
| 886 | // TODO https://github.com/ziglang/zig/issues/265 | 262 | // TODO https://github.com/ziglang/zig/issues/265 |
| 887 | pub fn rename(old: [*]const u8, new: [*]const u8) usize { | 263 | pub 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 | |||
| 273 | pub 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 | } |
| 890 | 293 | ||
| 891 | // TODO https://github.com/ziglang/zig/issues/265 | 294 | // TODO https://github.com/ziglang/zig/issues/265 |
| 892 | pub fn renameat2(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const u8, flags: u32) usize { | 295 | pub 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 | } |
| 895 | 305 | ||
| 896 | // TODO https://github.com/ziglang/zig/issues/265 | 306 | // TODO https://github.com/ziglang/zig/issues/265 |
| 897 | pub fn open(path: [*]const u8, flags: u32, perm: usize) usize { | 307 | pub 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 | } |
| 900 | 310 | ||
| 901 | // TODO https://github.com/ziglang/zig/issues/265 | 311 | // 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 | } |
| 925 | 335 | ||
| 926 | pub 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); | 337 | pub 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`. | ||
| 349 | pub fn lseek(fd: i32, offset: i64, whence: usize) usize { | ||
| 350 | return syscall3(SYS_lseek, @bitCast(usize, isize(fd)), @bitCast(usize, offset), whence); | ||
| 928 | } | 351 | } |
| 929 | 352 | ||
| 930 | pub fn exit(status: i32) noreturn { | 353 | pub 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 { |
| 947 | 370 | ||
| 948 | // TODO https://github.com/ziglang/zig/issues/265 | 371 | // TODO https://github.com/ziglang/zig/issues/265 |
| 949 | pub fn unlink(path: [*]const u8) usize { | 372 | pub 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 | } |
| 952 | 379 | ||
| 953 | // TODO https://github.com/ziglang/zig/issues/265 | 380 | // 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 | } |
| 957 | 384 | ||
| 958 | pub fn waitpid(pid: i32, status: *i32, options: i32) usize { | 385 | pub 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 | } |
| 961 | 388 | ||
| 962 | var vdso_clock_gettime = @ptrCast(?*const c_void, init_vdso_clock_gettime); | 389 | var vdso_clock_gettime = @ptrCast(?*const c_void, init_vdso_clock_gettime); |
| ... | @@ -1113,48 +540,15 @@ pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigacti | ... | @@ -1113,48 +540,15 @@ pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigacti |
| 1113 | return 0; | 540 | return 0; |
| 1114 | } | 541 | } |
| 1115 | 542 | ||
| 1116 | const NSIG = 65; | 543 | pub fn blockAllSignals(set: *sigset_t) void { |
| 1117 | const sigset_t = [128 / @sizeOf(usize)]usize; | ||
| 1118 | const all_mask = []u32{ 0xffffffff, 0xffffffff }; | ||
| 1119 | const app_mask = []u32{ 0xfffffffc, 0x7fffffff }; | ||
| 1120 | |||
| 1121 | const 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. | ||
| 1129 | pub const Sigaction = struct { | ||
| 1130 | handler: extern fn (i32) void, | ||
| 1131 | mask: sigset_t, | ||
| 1132 | flags: u32, | ||
| 1133 | }; | ||
| 1134 | |||
| 1135 | pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize)); | ||
| 1136 | pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0); | ||
| 1137 | pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1); | ||
| 1138 | pub const empty_sigset = []usize{0} ** sigset_t.len; | ||
| 1139 | |||
| 1140 | pub 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 | |||
| 1149 | fn 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 | } |
| 1152 | 546 | ||
| 1153 | fn blockAppSignals(set: *sigset_t) void { | 547 | pub 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 | } |
| 1156 | 550 | ||
| 1157 | fn restoreSignals(set: *sigset_t) void { | 551 | pub 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 | } |
| 1160 | 554 | ||
| ... | @@ -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 | } |
| 1170 | 564 | ||
| 1171 | pub const in_port_t = u16; | ||
| 1172 | pub const sa_family_t = u16; | ||
| 1173 | pub const socklen_t = u32; | ||
| 1174 | |||
| 1175 | /// This intentionally only has ip4 and ip6 | ||
| 1176 | pub const sockaddr = extern union { | ||
| 1177 | in: sockaddr_in, | ||
| 1178 | in6: sockaddr_in6, | ||
| 1179 | }; | ||
| 1180 | |||
| 1181 | pub const sockaddr_in = extern struct { | ||
| 1182 | family: sa_family_t, | ||
| 1183 | port: in_port_t, | ||
| 1184 | addr: u32, | ||
| 1185 | zero: [8]u8, | ||
| 1186 | }; | ||
| 1187 | |||
| 1188 | pub 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 | |||
| 1196 | pub const sockaddr_un = extern struct { | ||
| 1197 | family: sa_family_t, | ||
| 1198 | path: [108]u8, | ||
| 1199 | }; | ||
| 1200 | |||
| 1201 | pub const iovec = extern struct { | ||
| 1202 | iov_base: [*]u8, | ||
| 1203 | iov_len: usize, | ||
| 1204 | }; | ||
| 1205 | |||
| 1206 | pub const iovec_const = extern struct { | ||
| 1207 | iov_base: [*]const u8, | ||
| 1208 | iov_len: usize, | ||
| 1209 | }; | ||
| 1210 | |||
| 1211 | pub const mmsghdr = extern struct { | ||
| 1212 | msg_hdr: msghdr, | ||
| 1213 | msg_len: u32, | ||
| 1214 | }; | ||
| 1215 | |||
| 1216 | pub const mmsghdr_const = extern struct { | ||
| 1217 | msg_hdr: msghdr_const, | ||
| 1218 | msg_len: u32, | ||
| 1219 | }; | ||
| 1220 | |||
| 1221 | pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { | 565 | pub 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 { |
| 1328 | 672 | ||
| 1329 | // TODO https://github.com/ziglang/zig/issues/265 | 673 | // TODO https://github.com/ziglang/zig/issues/265 |
| 1330 | pub fn stat(pathname: [*]const u8, statbuf: *Stat) usize { | 674 | pub 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 | } |
| 1333 | 677 | ||
| 1334 | // TODO https://github.com/ziglang/zig/issues/265 | 678 | // TODO https://github.com/ziglang/zig/issues/265 |
| 1335 | pub fn lstat(pathname: [*]const u8, statbuf: *Stat) usize { | 679 | pub 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 | } |
| 1338 | 682 | ||
| 1339 | // TODO https://github.com/ziglang/zig/issues/265 | 683 | // 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 | } |
| 1402 | 746 | ||
| 1403 | pub fn sched_getaffinity(pid: i32, set: []usize) usize { | 747 | pub 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 | } |
| 1406 | 753 | ||
| 1407 | pub 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 | ||
| 1416 | pub const epoll_event = if (builtin.arch != .x86_64) | ||
| 1417 | extern struct { | ||
| 1418 | events: u32, | ||
| 1419 | data: epoll_data, | ||
| 1420 | } | ||
| 1421 | else | ||
| 1422 | packed struct { | ||
| 1423 | events: u32, | ||
| 1424 | data: epoll_data, | ||
| 1425 | }; | ||
| 1426 | |||
| 1427 | pub fn epoll_create() usize { | 754 | pub 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 | } |
| 1438 | 765 | ||
| 1439 | pub fn epoll_wait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32) usize { | 766 | pub 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 | } |
| 1442 | 775 | ||
| 1443 | pub fn epoll_pwait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32, sigmask: ?*sigset_t) usize { | 776 | pub fn epoll_pwait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32, sigmask: ?*sigset_t) usize { |
| ... | @@ -1473,112 +806,6 @@ pub fn timerfd_settime(fd: i32, flags: u32, new_value: *const itimerspec, old_va | ... | @@ -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 | } |
| 1475 | 808 | ||
| 1476 | pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330; | ||
| 1477 | pub const _LINUX_CAPABILITY_U32S_1 = 1; | ||
| 1478 | |||
| 1479 | pub const _LINUX_CAPABILITY_VERSION_2 = 0x20071026; | ||
| 1480 | pub const _LINUX_CAPABILITY_U32S_2 = 2; | ||
| 1481 | |||
| 1482 | pub const _LINUX_CAPABILITY_VERSION_3 = 0x20080522; | ||
| 1483 | pub const _LINUX_CAPABILITY_U32S_3 = 2; | ||
| 1484 | |||
| 1485 | pub const VFS_CAP_REVISION_MASK = 0xFF000000; | ||
| 1486 | pub const VFS_CAP_REVISION_SHIFT = 24; | ||
| 1487 | pub const VFS_CAP_FLAGS_MASK = ~VFS_CAP_REVISION_MASK; | ||
| 1488 | pub const VFS_CAP_FLAGS_EFFECTIVE = 0x000001; | ||
| 1489 | |||
| 1490 | pub const VFS_CAP_REVISION_1 = 0x01000000; | ||
| 1491 | pub const VFS_CAP_U32_1 = 1; | ||
| 1492 | pub const XATTR_CAPS_SZ_1 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_1); | ||
| 1493 | |||
| 1494 | pub const VFS_CAP_REVISION_2 = 0x02000000; | ||
| 1495 | pub const VFS_CAP_U32_2 = 2; | ||
| 1496 | pub const XATTR_CAPS_SZ_2 = @sizeOf(u32) * (1 + 2 * VFS_CAP_U32_2); | ||
| 1497 | |||
| 1498 | pub const XATTR_CAPS_SZ = XATTR_CAPS_SZ_2; | ||
| 1499 | pub const VFS_CAP_U32 = VFS_CAP_U32_2; | ||
| 1500 | pub const VFS_CAP_REVISION = VFS_CAP_REVISION_2; | ||
| 1501 | |||
| 1502 | pub 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 | |||
| 1514 | pub const CAP_CHOWN = 0; | ||
| 1515 | pub const CAP_DAC_OVERRIDE = 1; | ||
| 1516 | pub const CAP_DAC_READ_SEARCH = 2; | ||
| 1517 | pub const CAP_FOWNER = 3; | ||
| 1518 | pub const CAP_FSETID = 4; | ||
| 1519 | pub const CAP_KILL = 5; | ||
| 1520 | pub const CAP_SETGID = 6; | ||
| 1521 | pub const CAP_SETUID = 7; | ||
| 1522 | pub const CAP_SETPCAP = 8; | ||
| 1523 | pub const CAP_LINUX_IMMUTABLE = 9; | ||
| 1524 | pub const CAP_NET_BIND_SERVICE = 10; | ||
| 1525 | pub const CAP_NET_BROADCAST = 11; | ||
| 1526 | pub const CAP_NET_ADMIN = 12; | ||
| 1527 | pub const CAP_NET_RAW = 13; | ||
| 1528 | pub const CAP_IPC_LOCK = 14; | ||
| 1529 | pub const CAP_IPC_OWNER = 15; | ||
| 1530 | pub const CAP_SYS_MODULE = 16; | ||
| 1531 | pub const CAP_SYS_RAWIO = 17; | ||
| 1532 | pub const CAP_SYS_CHROOT = 18; | ||
| 1533 | pub const CAP_SYS_PTRACE = 19; | ||
| 1534 | pub const CAP_SYS_PACCT = 20; | ||
| 1535 | pub const CAP_SYS_ADMIN = 21; | ||
| 1536 | pub const CAP_SYS_BOOT = 22; | ||
| 1537 | pub const CAP_SYS_NICE = 23; | ||
| 1538 | pub const CAP_SYS_RESOURCE = 24; | ||
| 1539 | pub const CAP_SYS_TIME = 25; | ||
| 1540 | pub const CAP_SYS_TTY_CONFIG = 26; | ||
| 1541 | pub const CAP_MKNOD = 27; | ||
| 1542 | pub const CAP_LEASE = 28; | ||
| 1543 | pub const CAP_AUDIT_WRITE = 29; | ||
| 1544 | pub const CAP_AUDIT_CONTROL = 30; | ||
| 1545 | pub const CAP_SETFCAP = 31; | ||
| 1546 | pub const CAP_MAC_OVERRIDE = 32; | ||
| 1547 | pub const CAP_MAC_ADMIN = 33; | ||
| 1548 | pub const CAP_SYSLOG = 34; | ||
| 1549 | pub const CAP_WAKE_ALARM = 35; | ||
| 1550 | pub const CAP_BLOCK_SUSPEND = 36; | ||
| 1551 | pub const CAP_AUDIT_READ = 37; | ||
| 1552 | pub const CAP_LAST_CAP = CAP_AUDIT_READ; | ||
| 1553 | |||
| 1554 | pub fn cap_valid(u8: x) bool { | ||
| 1555 | return x >= 0 and x <= CAP_LAST_CAP; | ||
| 1556 | } | ||
| 1557 | |||
| 1558 | pub fn CAP_TO_MASK(cap: u8) u32 { | ||
| 1559 | return u32(1) << u5(cap & 31); | ||
| 1560 | } | ||
| 1561 | |||
| 1562 | pub fn CAP_TO_INDEX(cap: u8) u8 { | ||
| 1563 | return cap >> 5; | ||
| 1564 | } | ||
| 1565 | |||
| 1566 | pub const cap_t = extern struct { | ||
| 1567 | hdrp: *cap_user_header_t, | ||
| 1568 | datap: *cap_user_data_t, | ||
| 1569 | }; | ||
| 1570 | |||
| 1571 | pub const cap_user_header_t = extern struct { | ||
| 1572 | version: u32, | ||
| 1573 | pid: usize, | ||
| 1574 | }; | ||
| 1575 | |||
| 1576 | pub const cap_user_data_t = extern struct { | ||
| 1577 | effective: u32, | ||
| 1578 | permitted: u32, | ||
| 1579 | inheritable: u32, | ||
| 1580 | }; | ||
| 1581 | |||
| 1582 | pub fn unshare(flags: usize) usize { | 809 | pub 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 | } |
| 1593 | 820 | ||
| 1594 | pub const inotify_event = extern struct { | ||
| 1595 | wd: i32, | ||
| 1596 | mask: u32, | ||
| 1597 | cookie: u32, | ||
| 1598 | len: u32, | ||
| 1599 | //name: [?]u8, | ||
| 1600 | }; | ||
| 1601 | |||
| 1602 | pub 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 | |||
| 1610 | pub 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 weak | 821 | // XXX: This should be weak |
| 1618 | extern const __ehdr_start: elf.Ehdr = undefined; | 822 | extern const __ehdr_start: elf.Ehdr = undefined; |
| 1619 | 823 | ||
| ... | @@ -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 | } |
| 1673 | 877 | ||
| 1674 | test "import" { | 878 | test "" { |
| 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 @@ |
| 1 | const std = @import("../../std.zig"); | ||
| 2 | const linux = std.os.linux; | ||
| 3 | const socklen_t = linux.socklen_t; | ||
| 4 | const iovec = linux.iovec; | ||
| 5 | const iovec_const = linux.iovec_const; | ||
| 6 | |||
| 7 | pub const SYS_io_setup = 0; | ||
| 8 | pub const SYS_io_destroy = 1; | ||
| 9 | pub const SYS_io_submit = 2; | ||
| 10 | pub const SYS_io_cancel = 3; | ||
| 11 | pub const SYS_io_getevents = 4; | ||
| 12 | pub const SYS_setxattr = 5; | ||
| 13 | pub const SYS_lsetxattr = 6; | ||
| 14 | pub const SYS_fsetxattr = 7; | ||
| 15 | pub const SYS_getxattr = 8; | ||
| 16 | pub const SYS_lgetxattr = 9; | ||
| 17 | pub const SYS_fgetxattr = 10; | ||
| 18 | pub const SYS_listxattr = 11; | ||
| 19 | pub const SYS_llistxattr = 12; | ||
| 20 | pub const SYS_flistxattr = 13; | ||
| 21 | pub const SYS_removexattr = 14; | ||
| 22 | pub const SYS_lremovexattr = 15; | ||
| 23 | pub const SYS_fremovexattr = 16; | ||
| 24 | pub const SYS_getcwd = 17; | ||
| 25 | pub const SYS_lookup_dcookie = 18; | ||
| 26 | pub const SYS_eventfd2 = 19; | ||
| 27 | pub const SYS_epoll_create1 = 20; | ||
| 28 | pub const SYS_epoll_ctl = 21; | ||
| 29 | pub const SYS_epoll_pwait = 22; | ||
| 30 | pub const SYS_dup = 23; | ||
| 31 | pub const SYS_dup3 = 24; | ||
| 32 | pub const SYS_fcntl = 25; | ||
| 33 | pub const SYS_inotify_init1 = 26; | ||
| 34 | pub const SYS_inotify_add_watch = 27; | ||
| 35 | pub const SYS_inotify_rm_watch = 28; | ||
| 36 | pub const SYS_ioctl = 29; | ||
| 37 | pub const SYS_ioprio_set = 30; | ||
| 38 | pub const SYS_ioprio_get = 31; | ||
| 39 | pub const SYS_flock = 32; | ||
| 40 | pub const SYS_mknodat = 33; | ||
| 41 | pub const SYS_mkdirat = 34; | ||
| 42 | pub const SYS_unlinkat = 35; | ||
| 43 | pub const SYS_symlinkat = 36; | ||
| 44 | pub const SYS_linkat = 37; | ||
| 45 | pub const SYS_renameat = 38; | ||
| 46 | pub const SYS_umount2 = 39; | ||
| 47 | pub const SYS_mount = 40; | ||
| 48 | pub const SYS_pivot_root = 41; | ||
| 49 | pub const SYS_nfsservctl = 42; | ||
| 50 | pub const SYS_statfs = 43; | ||
| 51 | pub const SYS_fstatfs = 44; | ||
| 52 | pub const SYS_truncate = 45; | ||
| 53 | pub const SYS_ftruncate = 46; | ||
| 54 | pub const SYS_fallocate = 47; | ||
| 55 | pub const SYS_faccessat = 48; | ||
| 56 | pub const SYS_chdir = 49; | ||
| 57 | pub const SYS_fchdir = 50; | ||
| 58 | pub const SYS_chroot = 51; | ||
| 59 | pub const SYS_fchmod = 52; | ||
| 60 | pub const SYS_fchmodat = 53; | ||
| 61 | pub const SYS_fchownat = 54; | ||
| 62 | pub const SYS_fchown = 55; | ||
| 63 | pub const SYS_openat = 56; | ||
| 64 | pub const SYS_close = 57; | ||
| 65 | pub const SYS_vhangup = 58; | ||
| 66 | pub const SYS_pipe2 = 59; | ||
| 67 | pub const SYS_quotactl = 60; | ||
| 68 | pub const SYS_getdents64 = 61; | ||
| 69 | pub const SYS_lseek = 62; | ||
| 70 | pub const SYS_read = 63; | ||
| 71 | pub const SYS_write = 64; | ||
| 72 | pub const SYS_readv = 65; | ||
| 73 | pub const SYS_writev = 66; | ||
| 74 | pub const SYS_pread64 = 67; | ||
| 75 | pub const SYS_pwrite64 = 68; | ||
| 76 | pub const SYS_preadv = 69; | ||
| 77 | pub const SYS_pwritev = 70; | ||
| 78 | pub const SYS_pselect6 = 72; | ||
| 79 | pub const SYS_ppoll = 73; | ||
| 80 | pub const SYS_signalfd4 = 74; | ||
| 81 | pub const SYS_vmsplice = 75; | ||
| 82 | pub const SYS_splice = 76; | ||
| 83 | pub const SYS_tee = 77; | ||
| 84 | pub const SYS_readlinkat = 78; | ||
| 85 | pub const SYS_fstatat = 79; | ||
| 86 | pub const SYS_fstat = 80; | ||
| 87 | pub const SYS_sync = 81; | ||
| 88 | pub const SYS_fsync = 82; | ||
| 89 | pub const SYS_fdatasync = 83; | ||
| 90 | pub const SYS_sync_file_range2 = 84; | ||
| 91 | pub const SYS_sync_file_range = 84; | ||
| 92 | pub const SYS_timerfd_create = 85; | ||
| 93 | pub const SYS_timerfd_settime = 86; | ||
| 94 | pub const SYS_timerfd_gettime = 87; | ||
| 95 | pub const SYS_utimensat = 88; | ||
| 96 | pub const SYS_acct = 89; | ||
| 97 | pub const SYS_capget = 90; | ||
| 98 | pub const SYS_capset = 91; | ||
| 99 | pub const SYS_personality = 92; | ||
| 100 | pub const SYS_exit = 93; | ||
| 101 | pub const SYS_exit_group = 94; | ||
| 102 | pub const SYS_waitid = 95; | ||
| 103 | pub const SYS_set_tid_address = 96; | ||
| 104 | pub const SYS_unshare = 97; | ||
| 105 | pub const SYS_futex = 98; | ||
| 106 | pub const SYS_set_robust_list = 99; | ||
| 107 | pub const SYS_get_robust_list = 100; | ||
| 108 | pub const SYS_nanosleep = 101; | ||
| 109 | pub const SYS_getitimer = 102; | ||
| 110 | pub const SYS_setitimer = 103; | ||
| 111 | pub const SYS_kexec_load = 104; | ||
| 112 | pub const SYS_init_module = 105; | ||
| 113 | pub const SYS_delete_module = 106; | ||
| 114 | pub const SYS_timer_create = 107; | ||
| 115 | pub const SYS_timer_gettime = 108; | ||
| 116 | pub const SYS_timer_getoverrun = 109; | ||
| 117 | pub const SYS_timer_settime = 110; | ||
| 118 | pub const SYS_timer_delete = 111; | ||
| 119 | pub const SYS_clock_settime = 112; | ||
| 120 | pub const SYS_clock_gettime = 113; | ||
| 121 | pub const SYS_clock_getres = 114; | ||
| 122 | pub const SYS_clock_nanosleep = 115; | ||
| 123 | pub const SYS_syslog = 116; | ||
| 124 | pub const SYS_ptrace = 117; | ||
| 125 | pub const SYS_sched_setparam = 118; | ||
| 126 | pub const SYS_sched_setscheduler = 119; | ||
| 127 | pub const SYS_sched_getscheduler = 120; | ||
| 128 | pub const SYS_sched_getparam = 121; | ||
| 129 | pub const SYS_sched_setaffinity = 122; | ||
| 130 | pub const SYS_sched_getaffinity = 123; | ||
| 131 | pub const SYS_sched_yield = 124; | ||
| 132 | pub const SYS_sched_get_priority_max = 125; | ||
| 133 | pub const SYS_sched_get_priority_min = 126; | ||
| 134 | pub const SYS_sched_rr_get_interval = 127; | ||
| 135 | pub const SYS_restart_syscall = 128; | ||
| 136 | pub const SYS_kill = 129; | ||
| 137 | pub const SYS_tkill = 130; | ||
| 138 | pub const SYS_tgkill = 131; | ||
| 139 | pub const SYS_sigaltstack = 132; | ||
| 140 | pub const SYS_rt_sigsuspend = 133; | ||
| 141 | pub const SYS_rt_sigaction = 134; | ||
| 142 | pub const SYS_rt_sigprocmask = 135; | ||
| 143 | pub const SYS_rt_sigpending = 136; | ||
| 144 | pub const SYS_rt_sigtimedwait = 137; | ||
| 145 | pub const SYS_rt_sigqueueinfo = 138; | ||
| 146 | pub const SYS_rt_sigreturn = 139; | ||
| 147 | pub const SYS_setpriority = 140; | ||
| 148 | pub const SYS_getpriority = 141; | ||
| 149 | pub const SYS_reboot = 142; | ||
| 150 | pub const SYS_setregid = 143; | ||
| 151 | pub const SYS_setgid = 144; | ||
| 152 | pub const SYS_setreuid = 145; | ||
| 153 | pub const SYS_setuid = 146; | ||
| 154 | pub const SYS_setresuid = 147; | ||
| 155 | pub const SYS_getresuid = 148; | ||
| 156 | pub const SYS_setresgid = 149; | ||
| 157 | pub const SYS_getresgid = 150; | ||
| 158 | pub const SYS_setfsuid = 151; | ||
| 159 | pub const SYS_setfsgid = 152; | ||
| 160 | pub const SYS_times = 153; | ||
| 161 | pub const SYS_setpgid = 154; | ||
| 162 | pub const SYS_getpgid = 155; | ||
| 163 | pub const SYS_getsid = 156; | ||
| 164 | pub const SYS_setsid = 157; | ||
| 165 | pub const SYS_getgroups = 158; | ||
| 166 | pub const SYS_setgroups = 159; | ||
| 167 | pub const SYS_uname = 160; | ||
| 168 | pub const SYS_sethostname = 161; | ||
| 169 | pub const SYS_setdomainname = 162; | ||
| 170 | pub const SYS_getrlimit = 163; | ||
| 171 | pub const SYS_setrlimit = 164; | ||
| 172 | pub const SYS_getrusage = 165; | ||
| 173 | pub const SYS_umask = 166; | ||
| 174 | pub const SYS_prctl = 167; | ||
| 175 | pub const SYS_getcpu = 168; | ||
| 176 | pub const SYS_gettimeofday = 169; | ||
| 177 | pub const SYS_settimeofday = 170; | ||
| 178 | pub const SYS_adjtimex = 171; | ||
| 179 | pub const SYS_getpid = 172; | ||
| 180 | pub const SYS_getppid = 173; | ||
| 181 | pub const SYS_getuid = 174; | ||
| 182 | pub const SYS_geteuid = 175; | ||
| 183 | pub const SYS_getgid = 176; | ||
| 184 | pub const SYS_getegid = 177; | ||
| 185 | pub const SYS_gettid = 178; | ||
| 186 | pub const SYS_sysinfo = 179; | ||
| 187 | pub const SYS_mq_open = 180; | ||
| 188 | pub const SYS_mq_unlink = 181; | ||
| 189 | pub const SYS_mq_timedsend = 182; | ||
| 190 | pub const SYS_mq_timedreceive = 183; | ||
| 191 | pub const SYS_mq_notify = 184; | ||
| 192 | pub const SYS_mq_getsetattr = 185; | ||
| 193 | pub const SYS_msgget = 186; | ||
| 194 | pub const SYS_msgctl = 187; | ||
| 195 | pub const SYS_msgrcv = 188; | ||
| 196 | pub const SYS_msgsnd = 189; | ||
| 197 | pub const SYS_semget = 190; | ||
| 198 | pub const SYS_semctl = 191; | ||
| 199 | pub const SYS_semtimedop = 192; | ||
| 200 | pub const SYS_semop = 193; | ||
| 201 | pub const SYS_shmget = 194; | ||
| 202 | pub const SYS_shmctl = 195; | ||
| 203 | pub const SYS_shmat = 196; | ||
| 204 | pub const SYS_shmdt = 197; | ||
| 205 | pub const SYS_socket = 198; | ||
| 206 | pub const SYS_socketpair = 199; | ||
| 207 | pub const SYS_bind = 200; | ||
| 208 | pub const SYS_listen = 201; | ||
| 209 | pub const SYS_accept = 202; | ||
| 210 | pub const SYS_connect = 203; | ||
| 211 | pub const SYS_getsockname = 204; | ||
| 212 | pub const SYS_getpeername = 205; | ||
| 213 | pub const SYS_sendto = 206; | ||
| 214 | pub const SYS_recvfrom = 207; | ||
| 215 | pub const SYS_setsockopt = 208; | ||
| 216 | pub const SYS_getsockopt = 209; | ||
| 217 | pub const SYS_shutdown = 210; | ||
| 218 | pub const SYS_sendmsg = 211; | ||
| 219 | pub const SYS_recvmsg = 212; | ||
| 220 | pub const SYS_readahead = 213; | ||
| 221 | pub const SYS_brk = 214; | ||
| 222 | pub const SYS_munmap = 215; | ||
| 223 | pub const SYS_mremap = 216; | ||
| 224 | pub const SYS_add_key = 217; | ||
| 225 | pub const SYS_request_key = 218; | ||
| 226 | pub const SYS_keyctl = 219; | ||
| 227 | pub const SYS_clone = 220; | ||
| 228 | pub const SYS_execve = 221; | ||
| 229 | pub const SYS_mmap = 222; | ||
| 230 | pub const SYS_fadvise64 = 223; | ||
| 231 | pub const SYS_swapon = 224; | ||
| 232 | pub const SYS_swapoff = 225; | ||
| 233 | pub const SYS_mprotect = 226; | ||
| 234 | pub const SYS_msync = 227; | ||
| 235 | pub const SYS_mlock = 228; | ||
| 236 | pub const SYS_munlock = 229; | ||
| 237 | pub const SYS_mlockall = 230; | ||
| 238 | pub const SYS_munlockall = 231; | ||
| 239 | pub const SYS_mincore = 232; | ||
| 240 | pub const SYS_madvise = 233; | ||
| 241 | pub const SYS_remap_file_pages = 234; | ||
| 242 | pub const SYS_mbind = 235; | ||
| 243 | pub const SYS_get_mempolicy = 236; | ||
| 244 | pub const SYS_set_mempolicy = 237; | ||
| 245 | pub const SYS_migrate_pages = 238; | ||
| 246 | pub const SYS_move_pages = 239; | ||
| 247 | pub const SYS_rt_tgsigqueueinfo = 240; | ||
| 248 | pub const SYS_perf_event_open = 241; | ||
| 249 | pub const SYS_accept4 = 242; | ||
| 250 | pub const SYS_recvmmsg = 243; | ||
| 251 | pub const SYS_arch_specific_syscall = 244; | ||
| 252 | pub const SYS_wait4 = 260; | ||
| 253 | pub const SYS_prlimit64 = 261; | ||
| 254 | pub const SYS_fanotify_init = 262; | ||
| 255 | pub const SYS_fanotify_mark = 263; | ||
| 256 | pub const SYS_clock_adjtime = 266; | ||
| 257 | pub const SYS_syncfs = 267; | ||
| 258 | pub const SYS_setns = 268; | ||
| 259 | pub const SYS_sendmmsg = 269; | ||
| 260 | pub const SYS_process_vm_readv = 270; | ||
| 261 | pub const SYS_process_vm_writev = 271; | ||
| 262 | pub const SYS_kcmp = 272; | ||
| 263 | pub const SYS_finit_module = 273; | ||
| 264 | pub const SYS_sched_setattr = 274; | ||
| 265 | pub const SYS_sched_getattr = 275; | ||
| 266 | pub const SYS_renameat2 = 276; | ||
| 267 | pub const SYS_seccomp = 277; | ||
| 268 | pub const SYS_getrandom = 278; | ||
| 269 | pub const SYS_memfd_create = 279; | ||
| 270 | pub const SYS_bpf = 280; | ||
| 271 | pub const SYS_execveat = 281; | ||
| 272 | pub const SYS_userfaultfd = 282; | ||
| 273 | pub const SYS_membarrier = 283; | ||
| 274 | pub const SYS_mlock2 = 284; | ||
| 275 | pub const SYS_copy_file_range = 285; | ||
| 276 | pub const SYS_preadv2 = 286; | ||
| 277 | pub const SYS_pwritev2 = 287; | ||
| 278 | pub const SYS_pkey_mprotect = 288; | ||
| 279 | pub const SYS_pkey_alloc = 289; | ||
| 280 | pub const SYS_pkey_free = 290; | ||
| 281 | pub const SYS_statx = 291; | ||
| 282 | pub const SYS_io_pgetevents = 292; | ||
| 283 | pub const SYS_rseq = 293; | ||
| 284 | pub const SYS_kexec_file_load = 294; | ||
| 285 | pub const SYS_pidfd_send_signal = 424; | ||
| 286 | pub const SYS_io_uring_setup = 425; | ||
| 287 | pub const SYS_io_uring_enter = 426; | ||
| 288 | pub const SYS_io_uring_register = 427; | ||
| 289 | |||
| 290 | pub const O_CREAT = 0o100; | ||
| 291 | pub const O_EXCL = 0o200; | ||
| 292 | pub const O_NOCTTY = 0o400; | ||
| 293 | pub const O_TRUNC = 0o1000; | ||
| 294 | pub const O_APPEND = 0o2000; | ||
| 295 | pub const O_NONBLOCK = 0o4000; | ||
| 296 | pub const O_DSYNC = 0o10000; | ||
| 297 | pub const O_SYNC = 0o4010000; | ||
| 298 | pub const O_RSYNC = 0o4010000; | ||
| 299 | pub const O_DIRECTORY = 0o200000; | ||
| 300 | pub const O_NOFOLLOW = 0o400000; | ||
| 301 | pub const O_CLOEXEC = 0o2000000; | ||
| 302 | |||
| 303 | pub const O_ASYNC = 0o20000; | ||
| 304 | pub const O_DIRECT = 0o40000; | ||
| 305 | pub const O_LARGEFILE = 0; | ||
| 306 | pub const O_NOATIME = 0o1000000; | ||
| 307 | pub const O_PATH = 0o10000000; | ||
| 308 | pub const O_TMPFILE = 0o20200000; | ||
| 309 | pub const O_NDELAY = O_NONBLOCK; | ||
| 310 | |||
| 311 | pub const F_DUPFD = 0; | ||
| 312 | pub const F_GETFD = 1; | ||
| 313 | pub const F_SETFD = 2; | ||
| 314 | pub const F_GETFL = 3; | ||
| 315 | pub const F_SETFL = 4; | ||
| 316 | |||
| 317 | pub const F_SETOWN = 8; | ||
| 318 | pub const F_GETOWN = 9; | ||
| 319 | pub const F_SETSIG = 10; | ||
| 320 | pub const F_GETSIG = 11; | ||
| 321 | |||
| 322 | pub const F_GETLK = 5; | ||
| 323 | pub const F_SETLK = 6; | ||
| 324 | pub const F_SETLKW = 7; | ||
| 325 | |||
| 326 | pub const F_SETOWN_EX = 15; | ||
| 327 | pub const F_GETOWN_EX = 16; | ||
| 328 | |||
| 329 | pub const F_GETOWNER_UIDS = 17; | ||
| 330 | |||
| 331 | pub const AT_FDCWD = -100; | ||
| 332 | pub const AT_SYMLINK_NOFOLLOW = 0x100; | ||
| 333 | pub const AT_REMOVEDIR = 0x200; | ||
| 334 | pub const AT_SYMLINK_FOLLOW = 0x400; | ||
| 335 | pub const AT_NO_AUTOMOUNT = 0x800; | ||
| 336 | pub const AT_EMPTY_PATH = 0x1000; | ||
| 337 | |||
| 338 | pub const VDSO_USEFUL = true; | ||
| 339 | pub const VDSO_CGT_SYM = "__kernel_clock_gettime"; | ||
| 340 | pub const VDSO_CGT_VER = "LINUX_2.6.39"; | ||
| 341 | |||
| 342 | pub fn syscall0(number: usize) usize { | 1 | pub 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( |
| 419 | 78 | ||
| 420 | /// This matches the libc clone function. | 79 | /// This matches the libc clone function. |
| 421 | pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; | 80 | pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; |
| 422 | |||
| 423 | pub 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 | |||
| 435 | pub 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. | ||
| 448 | pub 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 | |||
| 468 | pub const timespec = extern struct { | ||
| 469 | tv_sec: isize, | ||
| 470 | tv_nsec: isize, | ||
| 471 | }; | ||
| 472 | |||
| 473 | pub const timeval = extern struct { | ||
| 474 | tv_sec: isize, | ||
| 475 | tv_usec: isize, | ||
| 476 | }; | ||
| 477 | |||
| 478 | pub const timezone = extern struct { | ||
| 479 | tz_minuteswest: i32, | ||
| 480 | tz_dsttime: i32, | ||
| 481 | }; | ||
| 482 | |||
| 483 | pub const Elf_Symndx = u32; |
std/os/linux/errno.zig deleted-427| ... | @@ -1,427 +0,0 @@ | ||
| 1 | /// Operation not permitted | ||
| 2 | pub const EPERM = 1; | ||
| 3 | |||
| 4 | /// No such file or directory | ||
| 5 | pub const ENOENT = 2; | ||
| 6 | |||
| 7 | /// No such process | ||
| 8 | pub const ESRCH = 3; | ||
| 9 | |||
| 10 | /// Interrupted system call | ||
| 11 | pub const EINTR = 4; | ||
| 12 | |||
| 13 | /// I/O error | ||
| 14 | pub const EIO = 5; | ||
| 15 | |||
| 16 | /// No such device or address | ||
| 17 | pub const ENXIO = 6; | ||
| 18 | |||
| 19 | /// Arg list too long | ||
| 20 | pub const E2BIG = 7; | ||
| 21 | |||
| 22 | /// Exec format error | ||
| 23 | pub const ENOEXEC = 8; | ||
| 24 | |||
| 25 | /// Bad file number | ||
| 26 | pub const EBADF = 9; | ||
| 27 | |||
| 28 | /// No child processes | ||
| 29 | pub const ECHILD = 10; | ||
| 30 | |||
| 31 | /// Try again | ||
| 32 | pub const EAGAIN = 11; | ||
| 33 | |||
| 34 | /// Out of memory | ||
| 35 | pub const ENOMEM = 12; | ||
| 36 | |||
| 37 | /// Permission denied | ||
| 38 | pub const EACCES = 13; | ||
| 39 | |||
| 40 | /// Bad address | ||
| 41 | pub const EFAULT = 14; | ||
| 42 | |||
| 43 | /// Block device required | ||
| 44 | pub const ENOTBLK = 15; | ||
| 45 | |||
| 46 | /// Device or resource busy | ||
| 47 | pub const EBUSY = 16; | ||
| 48 | |||
| 49 | /// File exists | ||
| 50 | pub const EEXIST = 17; | ||
| 51 | |||
| 52 | /// Cross-device link | ||
| 53 | pub const EXDEV = 18; | ||
| 54 | |||
| 55 | /// No such device | ||
| 56 | pub const ENODEV = 19; | ||
| 57 | |||
| 58 | /// Not a directory | ||
| 59 | pub const ENOTDIR = 20; | ||
| 60 | |||
| 61 | /// Is a directory | ||
| 62 | pub const EISDIR = 21; | ||
| 63 | |||
| 64 | /// Invalid argument | ||
| 65 | pub const EINVAL = 22; | ||
| 66 | |||
| 67 | /// File table overflow | ||
| 68 | pub const ENFILE = 23; | ||
| 69 | |||
| 70 | /// Too many open files | ||
| 71 | pub const EMFILE = 24; | ||
| 72 | |||
| 73 | /// Not a typewriter | ||
| 74 | pub const ENOTTY = 25; | ||
| 75 | |||
| 76 | /// Text file busy | ||
| 77 | pub const ETXTBSY = 26; | ||
| 78 | |||
| 79 | /// File too large | ||
| 80 | pub const EFBIG = 27; | ||
| 81 | |||
| 82 | /// No space left on device | ||
| 83 | pub const ENOSPC = 28; | ||
| 84 | |||
| 85 | /// Illegal seek | ||
| 86 | pub const ESPIPE = 29; | ||
| 87 | |||
| 88 | /// Read-only file system | ||
| 89 | pub const EROFS = 30; | ||
| 90 | |||
| 91 | /// Too many links | ||
| 92 | pub const EMLINK = 31; | ||
| 93 | |||
| 94 | /// Broken pipe | ||
| 95 | pub const EPIPE = 32; | ||
| 96 | |||
| 97 | /// Math argument out of domain of func | ||
| 98 | pub const EDOM = 33; | ||
| 99 | |||
| 100 | /// Math result not representable | ||
| 101 | pub const ERANGE = 34; | ||
| 102 | |||
| 103 | /// Resource deadlock would occur | ||
| 104 | pub const EDEADLK = 35; | ||
| 105 | |||
| 106 | /// File name too long | ||
| 107 | pub const ENAMETOOLONG = 36; | ||
| 108 | |||
| 109 | /// No record locks available | ||
| 110 | pub const ENOLCK = 37; | ||
| 111 | |||
| 112 | /// Function not implemented | ||
| 113 | pub const ENOSYS = 38; | ||
| 114 | |||
| 115 | /// Directory not empty | ||
| 116 | pub const ENOTEMPTY = 39; | ||
| 117 | |||
| 118 | /// Too many symbolic links encountered | ||
| 119 | pub const ELOOP = 40; | ||
| 120 | |||
| 121 | /// Operation would block | ||
| 122 | pub const EWOULDBLOCK = EAGAIN; | ||
| 123 | |||
| 124 | /// No message of desired type | ||
| 125 | pub const ENOMSG = 42; | ||
| 126 | |||
| 127 | /// Identifier removed | ||
| 128 | pub const EIDRM = 43; | ||
| 129 | |||
| 130 | /// Channel number out of range | ||
| 131 | pub const ECHRNG = 44; | ||
| 132 | |||
| 133 | /// Level 2 not synchronized | ||
| 134 | pub const EL2NSYNC = 45; | ||
| 135 | |||
| 136 | /// Level 3 halted | ||
| 137 | pub const EL3HLT = 46; | ||
| 138 | |||
| 139 | /// Level 3 reset | ||
| 140 | pub const EL3RST = 47; | ||
| 141 | |||
| 142 | /// Link number out of range | ||
| 143 | pub const ELNRNG = 48; | ||
| 144 | |||
| 145 | /// Protocol driver not attached | ||
| 146 | pub const EUNATCH = 49; | ||
| 147 | |||
| 148 | /// No CSI structure available | ||
| 149 | pub const ENOCSI = 50; | ||
| 150 | |||
| 151 | /// Level 2 halted | ||
| 152 | pub const EL2HLT = 51; | ||
| 153 | |||
| 154 | /// Invalid exchange | ||
| 155 | pub const EBADE = 52; | ||
| 156 | |||
| 157 | /// Invalid request descriptor | ||
| 158 | pub const EBADR = 53; | ||
| 159 | |||
| 160 | /// Exchange full | ||
| 161 | pub const EXFULL = 54; | ||
| 162 | |||
| 163 | /// No anode | ||
| 164 | pub const ENOANO = 55; | ||
| 165 | |||
| 166 | /// Invalid request code | ||
| 167 | pub const EBADRQC = 56; | ||
| 168 | |||
| 169 | /// Invalid slot | ||
| 170 | pub const EBADSLT = 57; | ||
| 171 | |||
| 172 | /// Bad font file format | ||
| 173 | pub const EBFONT = 59; | ||
| 174 | |||
| 175 | /// Device not a stream | ||
| 176 | pub const ENOSTR = 60; | ||
| 177 | |||
| 178 | /// No data available | ||
| 179 | pub const ENODATA = 61; | ||
| 180 | |||
| 181 | /// Timer expired | ||
| 182 | pub const ETIME = 62; | ||
| 183 | |||
| 184 | /// Out of streams resources | ||
| 185 | pub const ENOSR = 63; | ||
| 186 | |||
| 187 | /// Machine is not on the network | ||
| 188 | pub const ENONET = 64; | ||
| 189 | |||
| 190 | /// Package not installed | ||
| 191 | pub const ENOPKG = 65; | ||
| 192 | |||
| 193 | /// Object is remote | ||
| 194 | pub const EREMOTE = 66; | ||
| 195 | |||
| 196 | /// Link has been severed | ||
| 197 | pub const ENOLINK = 67; | ||
| 198 | |||
| 199 | /// Advertise error | ||
| 200 | pub const EADV = 68; | ||
| 201 | |||
| 202 | /// Srmount error | ||
| 203 | pub const ESRMNT = 69; | ||
| 204 | |||
| 205 | /// Communication error on send | ||
| 206 | pub const ECOMM = 70; | ||
| 207 | |||
| 208 | /// Protocol error | ||
| 209 | pub const EPROTO = 71; | ||
| 210 | |||
| 211 | /// Multihop attempted | ||
| 212 | pub const EMULTIHOP = 72; | ||
| 213 | |||
| 214 | /// RFS specific error | ||
| 215 | pub const EDOTDOT = 73; | ||
| 216 | |||
| 217 | /// Not a data message | ||
| 218 | pub const EBADMSG = 74; | ||
| 219 | |||
| 220 | /// Value too large for defined data type | ||
| 221 | pub const EOVERFLOW = 75; | ||
| 222 | |||
| 223 | /// Name not unique on network | ||
| 224 | pub const ENOTUNIQ = 76; | ||
| 225 | |||
| 226 | /// File descriptor in bad state | ||
| 227 | pub const EBADFD = 77; | ||
| 228 | |||
| 229 | /// Remote address changed | ||
| 230 | pub const EREMCHG = 78; | ||
| 231 | |||
| 232 | /// Can not access a needed shared library | ||
| 233 | pub const ELIBACC = 79; | ||
| 234 | |||
| 235 | /// Accessing a corrupted shared library | ||
| 236 | pub const ELIBBAD = 80; | ||
| 237 | |||
| 238 | /// .lib section in a.out corrupted | ||
| 239 | pub const ELIBSCN = 81; | ||
| 240 | |||
| 241 | /// Attempting to link in too many shared libraries | ||
| 242 | pub const ELIBMAX = 82; | ||
| 243 | |||
| 244 | /// Cannot exec a shared library directly | ||
| 245 | pub const ELIBEXEC = 83; | ||
| 246 | |||
| 247 | /// Illegal byte sequence | ||
| 248 | pub const EILSEQ = 84; | ||
| 249 | |||
| 250 | /// Interrupted system call should be restarted | ||
| 251 | pub const ERESTART = 85; | ||
| 252 | |||
| 253 | /// Streams pipe error | ||
| 254 | pub const ESTRPIPE = 86; | ||
| 255 | |||
| 256 | /// Too many users | ||
| 257 | pub const EUSERS = 87; | ||
| 258 | |||
| 259 | /// Socket operation on non-socket | ||
| 260 | pub const ENOTSOCK = 88; | ||
| 261 | |||
| 262 | /// Destination address required | ||
| 263 | pub const EDESTADDRREQ = 89; | ||
| 264 | |||
| 265 | /// Message too long | ||
| 266 | pub const EMSGSIZE = 90; | ||
| 267 | |||
| 268 | /// Protocol wrong type for socket | ||
| 269 | pub const EPROTOTYPE = 91; | ||
| 270 | |||
| 271 | /// Protocol not available | ||
| 272 | pub const ENOPROTOOPT = 92; | ||
| 273 | |||
| 274 | /// Protocol not supported | ||
| 275 | pub const EPROTONOSUPPORT = 93; | ||
| 276 | |||
| 277 | /// Socket type not supported | ||
| 278 | pub const ESOCKTNOSUPPORT = 94; | ||
| 279 | |||
| 280 | /// Operation not supported on transport endpoint | ||
| 281 | pub const EOPNOTSUPP = 95; | ||
| 282 | |||
| 283 | /// Protocol family not supported | ||
| 284 | pub const EPFNOSUPPORT = 96; | ||
| 285 | |||
| 286 | /// Address family not supported by protocol | ||
| 287 | pub const EAFNOSUPPORT = 97; | ||
| 288 | |||
| 289 | /// Address already in use | ||
| 290 | pub const EADDRINUSE = 98; | ||
| 291 | |||
| 292 | /// Cannot assign requested address | ||
| 293 | pub const EADDRNOTAVAIL = 99; | ||
| 294 | |||
| 295 | /// Network is down | ||
| 296 | pub const ENETDOWN = 100; | ||
| 297 | |||
| 298 | /// Network is unreachable | ||
| 299 | pub const ENETUNREACH = 101; | ||
| 300 | |||
| 301 | /// Network dropped connection because of reset | ||
| 302 | pub const ENETRESET = 102; | ||
| 303 | |||
| 304 | /// Software caused connection abort | ||
| 305 | pub const ECONNABORTED = 103; | ||
| 306 | |||
| 307 | /// Connection reset by peer | ||
| 308 | pub const ECONNRESET = 104; | ||
| 309 | |||
| 310 | /// No buffer space available | ||
| 311 | pub const ENOBUFS = 105; | ||
| 312 | |||
| 313 | /// Transport endpoint is already connected | ||
| 314 | pub const EISCONN = 106; | ||
| 315 | |||
| 316 | /// Transport endpoint is not connected | ||
| 317 | pub const ENOTCONN = 107; | ||
| 318 | |||
| 319 | /// Cannot send after transport endpoint shutdown | ||
| 320 | pub const ESHUTDOWN = 108; | ||
| 321 | |||
| 322 | /// Too many references: cannot splice | ||
| 323 | pub const ETOOMANYREFS = 109; | ||
| 324 | |||
| 325 | /// Connection timed out | ||
| 326 | pub const ETIMEDOUT = 110; | ||
| 327 | |||
| 328 | /// Connection refused | ||
| 329 | pub const ECONNREFUSED = 111; | ||
| 330 | |||
| 331 | /// Host is down | ||
| 332 | pub const EHOSTDOWN = 112; | ||
| 333 | |||
| 334 | /// No route to host | ||
| 335 | pub const EHOSTUNREACH = 113; | ||
| 336 | |||
| 337 | /// Operation already in progress | ||
| 338 | pub const EALREADY = 114; | ||
| 339 | |||
| 340 | /// Operation now in progress | ||
| 341 | pub const EINPROGRESS = 115; | ||
| 342 | |||
| 343 | /// Stale NFS file handle | ||
| 344 | pub const ESTALE = 116; | ||
| 345 | |||
| 346 | /// Structure needs cleaning | ||
| 347 | pub const EUCLEAN = 117; | ||
| 348 | |||
| 349 | /// Not a XENIX named type file | ||
| 350 | pub const ENOTNAM = 118; | ||
| 351 | |||
| 352 | /// No XENIX semaphores available | ||
| 353 | pub const ENAVAIL = 119; | ||
| 354 | |||
| 355 | /// Is a named type file | ||
| 356 | pub const EISNAM = 120; | ||
| 357 | |||
| 358 | /// Remote I/O error | ||
| 359 | pub const EREMOTEIO = 121; | ||
| 360 | |||
| 361 | /// Quota exceeded | ||
| 362 | pub const EDQUOT = 122; | ||
| 363 | |||
| 364 | /// No medium found | ||
| 365 | pub const ENOMEDIUM = 123; | ||
| 366 | |||
| 367 | /// Wrong medium type | ||
| 368 | pub const EMEDIUMTYPE = 124; | ||
| 369 | |||
| 370 | // nameserver query return codes | ||
| 371 | |||
| 372 | /// DNS server returned answer with no data | ||
| 373 | pub const ENSROK = 0; | ||
| 374 | |||
| 375 | /// DNS server returned answer with no data | ||
| 376 | pub const ENSRNODATA = 160; | ||
| 377 | |||
| 378 | /// DNS server claims query was misformatted | ||
| 379 | pub const ENSRFORMERR = 161; | ||
| 380 | |||
| 381 | /// DNS server returned general failure | ||
| 382 | pub const ENSRSERVFAIL = 162; | ||
| 383 | |||
| 384 | /// Domain name not found | ||
| 385 | pub const ENSRNOTFOUND = 163; | ||
| 386 | |||
| 387 | /// DNS server does not implement requested operation | ||
| 388 | pub const ENSRNOTIMP = 164; | ||
| 389 | |||
| 390 | /// DNS server refused query | ||
| 391 | pub const ENSRREFUSED = 165; | ||
| 392 | |||
| 393 | /// Misformatted DNS query | ||
| 394 | pub const ENSRBADQUERY = 166; | ||
| 395 | |||
| 396 | /// Misformatted domain name | ||
| 397 | pub const ENSRBADNAME = 167; | ||
| 398 | |||
| 399 | /// Unsupported address family | ||
| 400 | pub const ENSRBADFAMILY = 168; | ||
| 401 | |||
| 402 | /// Misformatted DNS reply | ||
| 403 | pub const ENSRBADRESP = 169; | ||
| 404 | |||
| 405 | /// Could not contact DNS servers | ||
| 406 | pub const ENSRCONNREFUSED = 170; | ||
| 407 | |||
| 408 | /// Timeout while contacting DNS servers | ||
| 409 | pub const ENSRTIMEOUT = 171; | ||
| 410 | |||
| 411 | /// End of file | ||
| 412 | pub const ENSROF = 172; | ||
| 413 | |||
| 414 | /// Error reading file | ||
| 415 | pub const ENSRFILE = 173; | ||
| 416 | |||
| 417 | /// Out of memory | ||
| 418 | pub const ENSRNOMEM = 174; | ||
| 419 | |||
| 420 | /// Application terminated lookup | ||
| 421 | pub const ENSRDESTRUCTION = 175; | ||
| 422 | |||
| 423 | /// Domain name is too long | ||
| 424 | pub const ENSRQUERYDOMAINTOOLONG = 176; | ||
| 425 | |||
| 426 | /// Domain name is too long | ||
| 427 | pub const ENSRCNAMELOOP = 177; | ||
std/os/linux/test.zig+1-1| ... | @@ -11,7 +11,7 @@ test "getpid" { | ... | @@ -11,7 +11,7 @@ test "getpid" { |
| 11 | 11 | ||
| 12 | test "timer" { | 12 | test "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); |
| 16 | 16 | ||
| 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 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const os = std.os; | ||
| 2 | const mem = std.mem; | 3 | const mem = std.mem; |
| 3 | const posix = std.os.posix; | ||
| 4 | const elf = std.elf; | 4 | const elf = std.elf; |
| 5 | const builtin = @import("builtin"); | 5 | const builtin = @import("builtin"); |
| 6 | const assert = std.debug.assert; | 6 | const 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; |
| 128 | 128 | ||
| 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 | } |
| 239 | 239 | ||
| 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"); | ||
| 241 | 248 | ||
| 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 @@ |
| 1 | const std = @import("../../std.zig"); | 1 | const std = @import("../../std.zig"); |
| 2 | const elf = std.elf; | 2 | const elf = std.elf; |
| 3 | const linux = std.os.linux; | 3 | const linux = std.os.linux; |
| 4 | const cstr = std.cstr; | ||
| 5 | const mem = std.mem; | 4 | const mem = std.mem; |
| 6 | const maxInt = std.math.maxInt; | 5 | const maxInt = std.math.maxInt; |
| 7 | 6 | ||
| 8 | pub fn lookup(vername: []const u8, name: []const u8) usize { | 7 | pub 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; |
| 11 | 10 | ||
| 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 @@ |
| 1 | const std = @import("../../std.zig"); | 1 | use @import("../bits.zig"); |
| 2 | const linux = std.os.linux; | ||
| 3 | const sockaddr = linux.sockaddr; | ||
| 4 | const socklen_t = linux.socklen_t; | ||
| 5 | const iovec = linux.iovec; | ||
| 6 | const iovec_const = linux.iovec_const; | ||
| 7 | |||
| 8 | pub const SYS_read = 0; | ||
| 9 | pub const SYS_write = 1; | ||
| 10 | pub const SYS_open = 2; | ||
| 11 | pub const SYS_close = 3; | ||
| 12 | pub const SYS_stat = 4; | ||
| 13 | pub const SYS_fstat = 5; | ||
| 14 | pub const SYS_lstat = 6; | ||
| 15 | pub const SYS_poll = 7; | ||
| 16 | pub const SYS_lseek = 8; | ||
| 17 | pub const SYS_mmap = 9; | ||
| 18 | pub const SYS_mprotect = 10; | ||
| 19 | pub const SYS_munmap = 11; | ||
| 20 | pub const SYS_brk = 12; | ||
| 21 | pub const SYS_rt_sigaction = 13; | ||
| 22 | pub const SYS_rt_sigprocmask = 14; | ||
| 23 | pub const SYS_rt_sigreturn = 15; | ||
| 24 | pub const SYS_ioctl = 16; | ||
| 25 | pub const SYS_pread = 17; | ||
| 26 | pub const SYS_pwrite = 18; | ||
| 27 | pub const SYS_readv = 19; | ||
| 28 | pub const SYS_writev = 20; | ||
| 29 | pub const SYS_access = 21; | ||
| 30 | pub const SYS_pipe = 22; | ||
| 31 | pub const SYS_select = 23; | ||
| 32 | pub const SYS_sched_yield = 24; | ||
| 33 | pub const SYS_mremap = 25; | ||
| 34 | pub const SYS_msync = 26; | ||
| 35 | pub const SYS_mincore = 27; | ||
| 36 | pub const SYS_madvise = 28; | ||
| 37 | pub const SYS_shmget = 29; | ||
| 38 | pub const SYS_shmat = 30; | ||
| 39 | pub const SYS_shmctl = 31; | ||
| 40 | pub const SYS_dup = 32; | ||
| 41 | pub const SYS_dup2 = 33; | ||
| 42 | pub const SYS_pause = 34; | ||
| 43 | pub const SYS_nanosleep = 35; | ||
| 44 | pub const SYS_getitimer = 36; | ||
| 45 | pub const SYS_alarm = 37; | ||
| 46 | pub const SYS_setitimer = 38; | ||
| 47 | pub const SYS_getpid = 39; | ||
| 48 | pub const SYS_sendfile = 40; | ||
| 49 | pub const SYS_socket = 41; | ||
| 50 | pub const SYS_connect = 42; | ||
| 51 | pub const SYS_accept = 43; | ||
| 52 | pub const SYS_sendto = 44; | ||
| 53 | pub const SYS_recvfrom = 45; | ||
| 54 | pub const SYS_sendmsg = 46; | ||
| 55 | pub const SYS_recvmsg = 47; | ||
| 56 | pub const SYS_shutdown = 48; | ||
| 57 | pub const SYS_bind = 49; | ||
| 58 | pub const SYS_listen = 50; | ||
| 59 | pub const SYS_getsockname = 51; | ||
| 60 | pub const SYS_getpeername = 52; | ||
| 61 | pub const SYS_socketpair = 53; | ||
| 62 | pub const SYS_setsockopt = 54; | ||
| 63 | pub const SYS_getsockopt = 55; | ||
| 64 | pub const SYS_clone = 56; | ||
| 65 | pub const SYS_fork = 57; | ||
| 66 | pub const SYS_vfork = 58; | ||
| 67 | pub const SYS_execve = 59; | ||
| 68 | pub const SYS_exit = 60; | ||
| 69 | pub const SYS_wait4 = 61; | ||
| 70 | pub const SYS_kill = 62; | ||
| 71 | pub const SYS_uname = 63; | ||
| 72 | pub const SYS_semget = 64; | ||
| 73 | pub const SYS_semop = 65; | ||
| 74 | pub const SYS_semctl = 66; | ||
| 75 | pub const SYS_shmdt = 67; | ||
| 76 | pub const SYS_msgget = 68; | ||
| 77 | pub const SYS_msgsnd = 69; | ||
| 78 | pub const SYS_msgrcv = 70; | ||
| 79 | pub const SYS_msgctl = 71; | ||
| 80 | pub const SYS_fcntl = 72; | ||
| 81 | pub const SYS_flock = 73; | ||
| 82 | pub const SYS_fsync = 74; | ||
| 83 | pub const SYS_fdatasync = 75; | ||
| 84 | pub const SYS_truncate = 76; | ||
| 85 | pub const SYS_ftruncate = 77; | ||
| 86 | pub const SYS_getdents = 78; | ||
| 87 | pub const SYS_getcwd = 79; | ||
| 88 | pub const SYS_chdir = 80; | ||
| 89 | pub const SYS_fchdir = 81; | ||
| 90 | pub const SYS_rename = 82; | ||
| 91 | pub const SYS_mkdir = 83; | ||
| 92 | pub const SYS_rmdir = 84; | ||
| 93 | pub const SYS_creat = 85; | ||
| 94 | pub const SYS_link = 86; | ||
| 95 | pub const SYS_unlink = 87; | ||
| 96 | pub const SYS_symlink = 88; | ||
| 97 | pub const SYS_readlink = 89; | ||
| 98 | pub const SYS_chmod = 90; | ||
| 99 | pub const SYS_fchmod = 91; | ||
| 100 | pub const SYS_chown = 92; | ||
| 101 | pub const SYS_fchown = 93; | ||
| 102 | pub const SYS_lchown = 94; | ||
| 103 | pub const SYS_umask = 95; | ||
| 104 | pub const SYS_gettimeofday = 96; | ||
| 105 | pub const SYS_getrlimit = 97; | ||
| 106 | pub const SYS_getrusage = 98; | ||
| 107 | pub const SYS_sysinfo = 99; | ||
| 108 | pub const SYS_times = 100; | ||
| 109 | pub const SYS_ptrace = 101; | ||
| 110 | pub const SYS_getuid = 102; | ||
| 111 | pub const SYS_syslog = 103; | ||
| 112 | pub const SYS_getgid = 104; | ||
| 113 | pub const SYS_setuid = 105; | ||
| 114 | pub const SYS_setgid = 106; | ||
| 115 | pub const SYS_geteuid = 107; | ||
| 116 | pub const SYS_getegid = 108; | ||
| 117 | pub const SYS_setpgid = 109; | ||
| 118 | pub const SYS_getppid = 110; | ||
| 119 | pub const SYS_getpgrp = 111; | ||
| 120 | pub const SYS_setsid = 112; | ||
| 121 | pub const SYS_setreuid = 113; | ||
| 122 | pub const SYS_setregid = 114; | ||
| 123 | pub const SYS_getgroups = 115; | ||
| 124 | pub const SYS_setgroups = 116; | ||
| 125 | pub const SYS_setresuid = 117; | ||
| 126 | pub const SYS_getresuid = 118; | ||
| 127 | pub const SYS_setresgid = 119; | ||
| 128 | pub const SYS_getresgid = 120; | ||
| 129 | pub const SYS_getpgid = 121; | ||
| 130 | pub const SYS_setfsuid = 122; | ||
| 131 | pub const SYS_setfsgid = 123; | ||
| 132 | pub const SYS_getsid = 124; | ||
| 133 | pub const SYS_capget = 125; | ||
| 134 | pub const SYS_capset = 126; | ||
| 135 | pub const SYS_rt_sigpending = 127; | ||
| 136 | pub const SYS_rt_sigtimedwait = 128; | ||
| 137 | pub const SYS_rt_sigqueueinfo = 129; | ||
| 138 | pub const SYS_rt_sigsuspend = 130; | ||
| 139 | pub const SYS_sigaltstack = 131; | ||
| 140 | pub const SYS_utime = 132; | ||
| 141 | pub const SYS_mknod = 133; | ||
| 142 | pub const SYS_uselib = 134; | ||
| 143 | pub const SYS_personality = 135; | ||
| 144 | pub const SYS_ustat = 136; | ||
| 145 | pub const SYS_statfs = 137; | ||
| 146 | pub const SYS_fstatfs = 138; | ||
| 147 | pub const SYS_sysfs = 139; | ||
| 148 | pub const SYS_getpriority = 140; | ||
| 149 | pub const SYS_setpriority = 141; | ||
| 150 | pub const SYS_sched_setparam = 142; | ||
| 151 | pub const SYS_sched_getparam = 143; | ||
| 152 | pub const SYS_sched_setscheduler = 144; | ||
| 153 | pub const SYS_sched_getscheduler = 145; | ||
| 154 | pub const SYS_sched_get_priority_max = 146; | ||
| 155 | pub const SYS_sched_get_priority_min = 147; | ||
| 156 | pub const SYS_sched_rr_get_interval = 148; | ||
| 157 | pub const SYS_mlock = 149; | ||
| 158 | pub const SYS_munlock = 150; | ||
| 159 | pub const SYS_mlockall = 151; | ||
| 160 | pub const SYS_munlockall = 152; | ||
| 161 | pub const SYS_vhangup = 153; | ||
| 162 | pub const SYS_modify_ldt = 154; | ||
| 163 | pub const SYS_pivot_root = 155; | ||
| 164 | pub const SYS__sysctl = 156; | ||
| 165 | pub const SYS_prctl = 157; | ||
| 166 | pub const SYS_arch_prctl = 158; | ||
| 167 | pub const SYS_adjtimex = 159; | ||
| 168 | pub const SYS_setrlimit = 160; | ||
| 169 | pub const SYS_chroot = 161; | ||
| 170 | pub const SYS_sync = 162; | ||
| 171 | pub const SYS_acct = 163; | ||
| 172 | pub const SYS_settimeofday = 164; | ||
| 173 | pub const SYS_mount = 165; | ||
| 174 | pub const SYS_umount2 = 166; | ||
| 175 | pub const SYS_swapon = 167; | ||
| 176 | pub const SYS_swapoff = 168; | ||
| 177 | pub const SYS_reboot = 169; | ||
| 178 | pub const SYS_sethostname = 170; | ||
| 179 | pub const SYS_setdomainname = 171; | ||
| 180 | pub const SYS_iopl = 172; | ||
| 181 | pub const SYS_ioperm = 173; | ||
| 182 | pub const SYS_create_module = 174; | ||
| 183 | pub const SYS_init_module = 175; | ||
| 184 | pub const SYS_delete_module = 176; | ||
| 185 | pub const SYS_get_kernel_syms = 177; | ||
| 186 | pub const SYS_query_module = 178; | ||
| 187 | pub const SYS_quotactl = 179; | ||
| 188 | pub const SYS_nfsservctl = 180; | ||
| 189 | pub const SYS_getpmsg = 181; | ||
| 190 | pub const SYS_putpmsg = 182; | ||
| 191 | pub const SYS_afs_syscall = 183; | ||
| 192 | pub const SYS_tuxcall = 184; | ||
| 193 | pub const SYS_security = 185; | ||
| 194 | pub const SYS_gettid = 186; | ||
| 195 | pub const SYS_readahead = 187; | ||
| 196 | pub const SYS_setxattr = 188; | ||
| 197 | pub const SYS_lsetxattr = 189; | ||
| 198 | pub const SYS_fsetxattr = 190; | ||
| 199 | pub const SYS_getxattr = 191; | ||
| 200 | pub const SYS_lgetxattr = 192; | ||
| 201 | pub const SYS_fgetxattr = 193; | ||
| 202 | pub const SYS_listxattr = 194; | ||
| 203 | pub const SYS_llistxattr = 195; | ||
| 204 | pub const SYS_flistxattr = 196; | ||
| 205 | pub const SYS_removexattr = 197; | ||
| 206 | pub const SYS_lremovexattr = 198; | ||
| 207 | pub const SYS_fremovexattr = 199; | ||
| 208 | pub const SYS_tkill = 200; | ||
| 209 | pub const SYS_time = 201; | ||
| 210 | pub const SYS_futex = 202; | ||
| 211 | pub const SYS_sched_setaffinity = 203; | ||
| 212 | pub const SYS_sched_getaffinity = 204; | ||
| 213 | pub const SYS_set_thread_area = 205; | ||
| 214 | pub const SYS_io_setup = 206; | ||
| 215 | pub const SYS_io_destroy = 207; | ||
| 216 | pub const SYS_io_getevents = 208; | ||
| 217 | pub const SYS_io_submit = 209; | ||
| 218 | pub const SYS_io_cancel = 210; | ||
| 219 | pub const SYS_get_thread_area = 211; | ||
| 220 | pub const SYS_lookup_dcookie = 212; | ||
| 221 | pub const SYS_epoll_create = 213; | ||
| 222 | pub const SYS_epoll_ctl_old = 214; | ||
| 223 | pub const SYS_epoll_wait_old = 215; | ||
| 224 | pub const SYS_remap_file_pages = 216; | ||
| 225 | pub const SYS_getdents64 = 217; | ||
| 226 | pub const SYS_set_tid_address = 218; | ||
| 227 | pub const SYS_restart_syscall = 219; | ||
| 228 | pub const SYS_semtimedop = 220; | ||
| 229 | pub const SYS_fadvise64 = 221; | ||
| 230 | pub const SYS_timer_create = 222; | ||
| 231 | pub const SYS_timer_settime = 223; | ||
| 232 | pub const SYS_timer_gettime = 224; | ||
| 233 | pub const SYS_timer_getoverrun = 225; | ||
| 234 | pub const SYS_timer_delete = 226; | ||
| 235 | pub const SYS_clock_settime = 227; | ||
| 236 | pub const SYS_clock_gettime = 228; | ||
| 237 | pub const SYS_clock_getres = 229; | ||
| 238 | pub const SYS_clock_nanosleep = 230; | ||
| 239 | pub const SYS_exit_group = 231; | ||
| 240 | pub const SYS_epoll_wait = 232; | ||
| 241 | pub const SYS_epoll_ctl = 233; | ||
| 242 | pub const SYS_tgkill = 234; | ||
| 243 | pub const SYS_utimes = 235; | ||
| 244 | pub const SYS_vserver = 236; | ||
| 245 | pub const SYS_mbind = 237; | ||
| 246 | pub const SYS_set_mempolicy = 238; | ||
| 247 | pub const SYS_get_mempolicy = 239; | ||
| 248 | pub const SYS_mq_open = 240; | ||
| 249 | pub const SYS_mq_unlink = 241; | ||
| 250 | pub const SYS_mq_timedsend = 242; | ||
| 251 | pub const SYS_mq_timedreceive = 243; | ||
| 252 | pub const SYS_mq_notify = 244; | ||
| 253 | pub const SYS_mq_getsetattr = 245; | ||
| 254 | pub const SYS_kexec_load = 246; | ||
| 255 | pub const SYS_waitid = 247; | ||
| 256 | pub const SYS_add_key = 248; | ||
| 257 | pub const SYS_request_key = 249; | ||
| 258 | pub const SYS_keyctl = 250; | ||
| 259 | pub const SYS_ioprio_set = 251; | ||
| 260 | pub const SYS_ioprio_get = 252; | ||
| 261 | pub const SYS_inotify_init = 253; | ||
| 262 | pub const SYS_inotify_add_watch = 254; | ||
| 263 | pub const SYS_inotify_rm_watch = 255; | ||
| 264 | pub const SYS_migrate_pages = 256; | ||
| 265 | pub const SYS_openat = 257; | ||
| 266 | pub const SYS_mkdirat = 258; | ||
| 267 | pub const SYS_mknodat = 259; | ||
| 268 | pub const SYS_fchownat = 260; | ||
| 269 | pub const SYS_futimesat = 261; | ||
| 270 | pub const SYS_newfstatat = 262; | ||
| 271 | // https://github.com/ziglang/zig/issues/1439 | ||
| 272 | pub const SYS_fstatat = 262; | ||
| 273 | pub const SYS_unlinkat = 263; | ||
| 274 | pub const SYS_renameat = 264; | ||
| 275 | pub const SYS_linkat = 265; | ||
| 276 | pub const SYS_symlinkat = 266; | ||
| 277 | pub const SYS_readlinkat = 267; | ||
| 278 | pub const SYS_fchmodat = 268; | ||
| 279 | pub const SYS_faccessat = 269; | ||
| 280 | pub const SYS_pselect6 = 270; | ||
| 281 | pub const SYS_ppoll = 271; | ||
| 282 | pub const SYS_unshare = 272; | ||
| 283 | pub const SYS_set_robust_list = 273; | ||
| 284 | pub const SYS_get_robust_list = 274; | ||
| 285 | pub const SYS_splice = 275; | ||
| 286 | pub const SYS_tee = 276; | ||
| 287 | pub const SYS_sync_file_range = 277; | ||
| 288 | pub const SYS_vmsplice = 278; | ||
| 289 | pub const SYS_move_pages = 279; | ||
| 290 | pub const SYS_utimensat = 280; | ||
| 291 | pub const SYS_epoll_pwait = 281; | ||
| 292 | pub const SYS_signalfd = 282; | ||
| 293 | pub const SYS_timerfd_create = 283; | ||
| 294 | pub const SYS_eventfd = 284; | ||
| 295 | pub const SYS_fallocate = 285; | ||
| 296 | pub const SYS_timerfd_settime = 286; | ||
| 297 | pub const SYS_timerfd_gettime = 287; | ||
| 298 | pub const SYS_accept4 = 288; | ||
| 299 | pub const SYS_signalfd4 = 289; | ||
| 300 | pub const SYS_eventfd2 = 290; | ||
| 301 | pub const SYS_epoll_create1 = 291; | ||
| 302 | pub const SYS_dup3 = 292; | ||
| 303 | pub const SYS_pipe2 = 293; | ||
| 304 | pub const SYS_inotify_init1 = 294; | ||
| 305 | pub const SYS_preadv = 295; | ||
| 306 | pub const SYS_pwritev = 296; | ||
| 307 | pub const SYS_rt_tgsigqueueinfo = 297; | ||
| 308 | pub const SYS_perf_event_open = 298; | ||
| 309 | pub const SYS_recvmmsg = 299; | ||
| 310 | pub const SYS_fanotify_init = 300; | ||
| 311 | pub const SYS_fanotify_mark = 301; | ||
| 312 | pub const SYS_prlimit64 = 302; | ||
| 313 | pub const SYS_name_to_handle_at = 303; | ||
| 314 | pub const SYS_open_by_handle_at = 304; | ||
| 315 | pub const SYS_clock_adjtime = 305; | ||
| 316 | pub const SYS_syncfs = 306; | ||
| 317 | pub const SYS_sendmmsg = 307; | ||
| 318 | pub const SYS_setns = 308; | ||
| 319 | pub const SYS_getcpu = 309; | ||
| 320 | pub const SYS_process_vm_readv = 310; | ||
| 321 | pub const SYS_process_vm_writev = 311; | ||
| 322 | pub const SYS_kcmp = 312; | ||
| 323 | pub const SYS_finit_module = 313; | ||
| 324 | pub const SYS_sched_setattr = 314; | ||
| 325 | pub const SYS_sched_getattr = 315; | ||
| 326 | pub const SYS_renameat2 = 316; | ||
| 327 | pub const SYS_seccomp = 317; | ||
| 328 | pub const SYS_getrandom = 318; | ||
| 329 | pub const SYS_memfd_create = 319; | ||
| 330 | pub const SYS_kexec_file_load = 320; | ||
| 331 | pub const SYS_bpf = 321; | ||
| 332 | pub const SYS_execveat = 322; | ||
| 333 | pub const SYS_userfaultfd = 323; | ||
| 334 | pub const SYS_membarrier = 324; | ||
| 335 | pub const SYS_mlock2 = 325; | ||
| 336 | pub const SYS_copy_file_range = 326; | ||
| 337 | pub const SYS_preadv2 = 327; | ||
| 338 | pub const SYS_pwritev2 = 328; | ||
| 339 | pub const SYS_pkey_mprotect = 329; | ||
| 340 | pub const SYS_pkey_alloc = 330; | ||
| 341 | pub const SYS_pkey_free = 331; | ||
| 342 | pub const SYS_statx = 332; | ||
| 343 | pub const SYS_io_pgetevents = 333; | ||
| 344 | pub const SYS_rseq = 334; | ||
| 345 | pub const SYS_pidfd_send_signal = 424; | ||
| 346 | pub const SYS_io_uring_setup = 425; | ||
| 347 | pub const SYS_io_uring_enter = 426; | ||
| 348 | pub const SYS_io_uring_register = 427; | ||
| 349 | |||
| 350 | pub const O_CREAT = 0o100; | ||
| 351 | pub const O_EXCL = 0o200; | ||
| 352 | pub const O_NOCTTY = 0o400; | ||
| 353 | pub const O_TRUNC = 0o1000; | ||
| 354 | pub const O_APPEND = 0o2000; | ||
| 355 | pub const O_NONBLOCK = 0o4000; | ||
| 356 | pub const O_DSYNC = 0o10000; | ||
| 357 | pub const O_SYNC = 0o4010000; | ||
| 358 | pub const O_RSYNC = 0o4010000; | ||
| 359 | pub const O_DIRECTORY = 0o200000; | ||
| 360 | pub const O_NOFOLLOW = 0o400000; | ||
| 361 | pub const O_CLOEXEC = 0o2000000; | ||
| 362 | |||
| 363 | pub const O_ASYNC = 0o20000; | ||
| 364 | pub const O_DIRECT = 0o40000; | ||
| 365 | pub const O_LARGEFILE = 0; | ||
| 366 | pub const O_NOATIME = 0o1000000; | ||
| 367 | pub const O_PATH = 0o10000000; | ||
| 368 | pub const O_TMPFILE = 0o20200000; | ||
| 369 | pub const O_NDELAY = O_NONBLOCK; | ||
| 370 | |||
| 371 | pub const F_DUPFD = 0; | ||
| 372 | pub const F_GETFD = 1; | ||
| 373 | pub const F_SETFD = 2; | ||
| 374 | pub const F_GETFL = 3; | ||
| 375 | pub const F_SETFL = 4; | ||
| 376 | |||
| 377 | pub const F_SETOWN = 8; | ||
| 378 | pub const F_GETOWN = 9; | ||
| 379 | pub const F_SETSIG = 10; | ||
| 380 | pub const F_GETSIG = 11; | ||
| 381 | |||
| 382 | pub const F_GETLK = 5; | ||
| 383 | pub const F_SETLK = 6; | ||
| 384 | pub const F_SETLKW = 7; | ||
| 385 | |||
| 386 | pub const F_SETOWN_EX = 15; | ||
| 387 | pub const F_GETOWN_EX = 16; | ||
| 388 | |||
| 389 | pub const F_GETOWNER_UIDS = 17; | ||
| 390 | |||
| 391 | pub const AT_FDCWD = -100; | ||
| 392 | pub const AT_SYMLINK_NOFOLLOW = 0x100; | ||
| 393 | pub const AT_REMOVEDIR = 0x200; | ||
| 394 | pub const AT_SYMLINK_FOLLOW = 0x400; | ||
| 395 | pub const AT_NO_AUTOMOUNT = 0x800; | ||
| 396 | pub const AT_EMPTY_PATH = 0x1000; | ||
| 397 | |||
| 398 | pub const VDSO_USEFUL = true; | ||
| 399 | pub const VDSO_CGT_SYM = "__vdso_clock_gettime"; | ||
| 400 | pub const VDSO_CGT_VER = "LINUX_2.6"; | ||
| 401 | pub const VDSO_GETCPU_SYM = "__vdso_getcpu"; | ||
| 402 | pub const VDSO_GETCPU_VER = "LINUX_2.6"; | ||
| 403 | |||
| 404 | pub const ARCH_SET_GS = 0x1001; | ||
| 405 | pub const ARCH_SET_FS = 0x1002; | ||
| 406 | pub const ARCH_GET_FS = 0x1003; | ||
| 407 | pub const ARCH_GET_GS = 0x1004; | ||
| 408 | 2 | ||
| 409 | pub fn syscall0(number: usize) usize { | 3 | pub 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 | |||
| 505 | pub 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 | |||
| 517 | pub 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. | ||
| 530 | pub 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 | |||
| 550 | pub const timespec = extern struct { | ||
| 551 | tv_sec: isize, | ||
| 552 | tv_nsec: isize, | ||
| 553 | }; | ||
| 554 | |||
| 555 | pub const timeval = extern struct { | ||
| 556 | tv_sec: isize, | ||
| 557 | tv_usec: isize, | ||
| 558 | }; | ||
| 559 | |||
| 560 | pub const timezone = extern struct { | ||
| 561 | tz_minuteswest: i32, | ||
| 562 | tz_dsttime: i32, | ||
| 563 | }; | ||
| 564 | |||
| 565 | pub const Elf_Symndx = u32; |
std/os/netbsd.zig+2-722| ... | @@ -1,724 +1,4 @@ | ... | @@ -1,724 +1,4 @@ |
| 1 | const builtin = @import("builtin"); | 1 | const builtin = @import("builtin"); |
| 2 | |||
| 3 | pub use @import("netbsd/errno.zig"); | ||
| 4 | |||
| 5 | const std = @import("../std.zig"); | 2 | const std = @import("../std.zig"); |
| 6 | const c = std.c; | 3 | pub const is_the_target = builtin.os == .netbsd; |
| 7 | 4 | pub use std.c; | |
| 8 | const assert = std.debug.assert; | ||
| 9 | const maxInt = std.math.maxInt; | ||
| 10 | pub const Kevent = c.Kevent; | ||
| 11 | |||
| 12 | pub const CTL_KERN = 1; | ||
| 13 | pub const CTL_DEBUG = 5; | ||
| 14 | |||
| 15 | pub const KERN_PROC_ARGS = 48; // struct: process argv/env | ||
| 16 | pub const KERN_PROC_PATHNAME = 5; // path to executable | ||
| 17 | |||
| 18 | pub const PATH_MAX = 1024; | ||
| 19 | |||
| 20 | pub const STDIN_FILENO = 0; | ||
| 21 | pub const STDOUT_FILENO = 1; | ||
| 22 | pub const STDERR_FILENO = 2; | ||
| 23 | |||
| 24 | pub const PROT_NONE = 0; | ||
| 25 | pub const PROT_READ = 1; | ||
| 26 | pub const PROT_WRITE = 2; | ||
| 27 | pub const PROT_EXEC = 4; | ||
| 28 | |||
| 29 | pub const CLOCK_REALTIME = 0; | ||
| 30 | pub const CLOCK_VIRTUAL = 1; | ||
| 31 | pub const CLOCK_PROF = 2; | ||
| 32 | pub const CLOCK_MONOTONIC = 3; | ||
| 33 | pub const CLOCK_THREAD_CPUTIME_ID = 0x20000000; | ||
| 34 | pub const CLOCK_PROCESS_CPUTIME_ID = 0x40000000; | ||
| 35 | |||
| 36 | pub const MAP_FAILED = maxInt(usize); | ||
| 37 | pub const MAP_SHARED = 0x0001; | ||
| 38 | pub const MAP_PRIVATE = 0x0002; | ||
| 39 | pub const MAP_REMAPDUP = 0x0004; | ||
| 40 | pub const MAP_FIXED = 0x0010; | ||
| 41 | pub const MAP_RENAME = 0x0020; | ||
| 42 | pub const MAP_NORESERVE = 0x0040; | ||
| 43 | pub const MAP_INHERIT = 0x0080; | ||
| 44 | pub const MAP_HASSEMAPHORE = 0x0200; | ||
| 45 | pub const MAP_TRYFIXED = 0x0400; | ||
| 46 | pub const MAP_WIRED = 0x0800; | ||
| 47 | |||
| 48 | pub const MAP_FILE = 0x0000; | ||
| 49 | pub const MAP_NOSYNC = 0x0800; | ||
| 50 | pub const MAP_ANON = 0x1000; | ||
| 51 | pub const MAP_ANONYMOUS = MAP_ANON; | ||
| 52 | pub const MAP_STACK = 0x2000; | ||
| 53 | |||
| 54 | pub const WNOHANG = 0x00000001; | ||
| 55 | pub const WUNTRACED = 0x00000002; | ||
| 56 | pub const WSTOPPED = WUNTRACED; | ||
| 57 | pub const WCONTINUED = 0x00000010; | ||
| 58 | pub const WNOWAIT = 0x00010000; | ||
| 59 | pub const WEXITED = 0x00000020; | ||
| 60 | pub const WTRAPPED = 0x00000040; | ||
| 61 | |||
| 62 | pub const SA_ONSTACK = 0x0001; | ||
| 63 | pub const SA_RESTART = 0x0002; | ||
| 64 | pub const SA_RESETHAND = 0x0004; | ||
| 65 | pub const SA_NOCLDSTOP = 0x0008; | ||
| 66 | pub const SA_NODEFER = 0x0010; | ||
| 67 | pub const SA_NOCLDWAIT = 0x0020; | ||
| 68 | pub const SA_SIGINFO = 0x0040; | ||
| 69 | |||
| 70 | pub const SIGHUP = 1; | ||
| 71 | pub const SIGINT = 2; | ||
| 72 | pub const SIGQUIT = 3; | ||
| 73 | pub const SIGILL = 4; | ||
| 74 | pub const SIGTRAP = 5; | ||
| 75 | pub const SIGABRT = 6; | ||
| 76 | pub const SIGIOT = SIGABRT; | ||
| 77 | pub const SIGEMT = 7; | ||
| 78 | pub const SIGFPE = 8; | ||
| 79 | pub const SIGKILL = 9; | ||
| 80 | pub const SIGBUS = 10; | ||
| 81 | pub const SIGSEGV = 11; | ||
| 82 | pub const SIGSYS = 12; | ||
| 83 | pub const SIGPIPE = 13; | ||
| 84 | pub const SIGALRM = 14; | ||
| 85 | pub const SIGTERM = 15; | ||
| 86 | pub const SIGURG = 16; | ||
| 87 | pub const SIGSTOP = 17; | ||
| 88 | pub const SIGTSTP = 18; | ||
| 89 | pub const SIGCONT = 19; | ||
| 90 | pub const SIGCHLD = 20; | ||
| 91 | pub const SIGTTIN = 21; | ||
| 92 | pub const SIGTTOU = 22; | ||
| 93 | pub const SIGIO = 23; | ||
| 94 | pub const SIGXCPU = 24; | ||
| 95 | pub const SIGXFSZ = 25; | ||
| 96 | pub const SIGVTALRM = 26; | ||
| 97 | pub const SIGPROF = 27; | ||
| 98 | pub const SIGWINCH = 28; | ||
| 99 | pub const SIGINFO = 29; | ||
| 100 | pub const SIGUSR1 = 30; | ||
| 101 | pub const SIGUSR2 = 31; | ||
| 102 | pub const SIGPWR = 32; | ||
| 103 | |||
| 104 | pub const SIGRTMIN = 33; | ||
| 105 | pub const SIGRTMAX = 63; | ||
| 106 | |||
| 107 | // access function | ||
| 108 | pub const F_OK = 0; // test for existence of file | ||
| 109 | pub const X_OK = 1; // test for execute or search permission | ||
| 110 | pub const W_OK = 2; // test for write permission | ||
| 111 | pub const R_OK = 4; // test for read permission | ||
| 112 | |||
| 113 | pub const O_RDONLY = 0x0000; | ||
| 114 | pub const O_WRONLY = 0x0001; | ||
| 115 | pub const O_RDWR = 0x0002; | ||
| 116 | pub const O_ACCMODE = 0x0003; | ||
| 117 | |||
| 118 | pub const O_CREAT = 0x0200; | ||
| 119 | pub const O_EXCL = 0x0800; | ||
| 120 | pub const O_NOCTTY = 0x8000; | ||
| 121 | pub const O_TRUNC = 0x0400; | ||
| 122 | pub const O_APPEND = 0x0008; | ||
| 123 | pub const O_NONBLOCK = 0x0004; | ||
| 124 | pub const O_DSYNC = 0x00010000; | ||
| 125 | pub const O_SYNC = 0x0080; | ||
| 126 | pub const O_RSYNC = 0x00020000; | ||
| 127 | pub const O_DIRECTORY = 0x00080000; | ||
| 128 | pub const O_NOFOLLOW = 0x00000100; | ||
| 129 | pub const O_CLOEXEC = 0x00400000; | ||
| 130 | |||
| 131 | pub const O_ASYNC = 0x0040; | ||
| 132 | pub const O_DIRECT = 0x00080000; | ||
| 133 | pub const O_LARGEFILE = 0; | ||
| 134 | pub const O_NOATIME = 0; | ||
| 135 | pub const O_PATH = 0; | ||
| 136 | pub const O_TMPFILE = 0; | ||
| 137 | pub const O_NDELAY = O_NONBLOCK; | ||
| 138 | |||
| 139 | pub const F_DUPFD = 0; | ||
| 140 | pub const F_GETFD = 1; | ||
| 141 | pub const F_SETFD = 2; | ||
| 142 | pub const F_GETFL = 3; | ||
| 143 | pub const F_SETFL = 4; | ||
| 144 | |||
| 145 | pub const F_GETOWN = 5; | ||
| 146 | pub const F_SETOWN = 6; | ||
| 147 | |||
| 148 | pub const F_GETLK = 7; | ||
| 149 | pub const F_SETLK = 8; | ||
| 150 | pub const F_SETLKW = 9; | ||
| 151 | |||
| 152 | pub const SEEK_SET = 0; | ||
| 153 | pub const SEEK_CUR = 1; | ||
| 154 | pub const SEEK_END = 2; | ||
| 155 | |||
| 156 | pub const SIG_BLOCK = 1; | ||
| 157 | pub const SIG_UNBLOCK = 2; | ||
| 158 | pub const SIG_SETMASK = 3; | ||
| 159 | |||
| 160 | pub const SOCK_STREAM = 1; | ||
| 161 | pub const SOCK_DGRAM = 2; | ||
| 162 | pub const SOCK_RAW = 3; | ||
| 163 | pub const SOCK_RDM = 4; | ||
| 164 | pub const SOCK_SEQPACKET = 5; | ||
| 165 | |||
| 166 | pub const SOCK_CLOEXEC = 0x10000000; | ||
| 167 | pub const SOCK_NONBLOCK = 0x20000000; | ||
| 168 | |||
| 169 | pub const PROTO_ip = 0; | ||
| 170 | pub const PROTO_icmp = 1; | ||
| 171 | pub const PROTO_igmp = 2; | ||
| 172 | pub const PROTO_ggp = 3; | ||
| 173 | pub const PROTO_ipencap = 4; | ||
| 174 | pub const PROTO_tcp = 6; | ||
| 175 | pub const PROTO_egp = 8; | ||
| 176 | pub const PROTO_pup = 12; | ||
| 177 | pub const PROTO_udp = 17; | ||
| 178 | pub const PROTO_xns_idp = 22; | ||
| 179 | pub const PROTO_iso_tp4 = 29; | ||
| 180 | pub const PROTO_ipv6 = 41; | ||
| 181 | pub const PROTO_ipv6_route = 43; | ||
| 182 | pub const PROTO_ipv6_frag = 44; | ||
| 183 | pub const PROTO_rsvp = 46; | ||
| 184 | pub const PROTO_gre = 47; | ||
| 185 | pub const PROTO_esp = 50; | ||
| 186 | pub const PROTO_ah = 51; | ||
| 187 | pub const PROTO_ipv6_icmp = 58; | ||
| 188 | pub const PROTO_ipv6_nonxt = 59; | ||
| 189 | pub const PROTO_ipv6_opts = 60; | ||
| 190 | pub const PROTO_encap = 98; | ||
| 191 | pub const PROTO_pim = 103; | ||
| 192 | pub const PROTO_raw = 255; | ||
| 193 | |||
| 194 | pub const PF_UNSPEC = 0; | ||
| 195 | pub const PF_LOCAL = 1; | ||
| 196 | pub const PF_UNIX = PF_LOCAL; | ||
| 197 | pub const PF_FILE = PF_LOCAL; | ||
| 198 | pub const PF_INET = 2; | ||
| 199 | pub const PF_APPLETALK = 16; | ||
| 200 | pub const PF_INET6 = 24; | ||
| 201 | pub const PF_DECnet = 12; | ||
| 202 | pub const PF_KEY = 29; | ||
| 203 | pub const PF_ROUTE = 34; | ||
| 204 | pub const PF_SNA = 11; | ||
| 205 | pub const PF_MPLS = 33; | ||
| 206 | pub const PF_CAN = 35; | ||
| 207 | pub const PF_BLUETOOTH = 31; | ||
| 208 | pub const PF_ISDN = 26; | ||
| 209 | pub const PF_MAX = 37; | ||
| 210 | |||
| 211 | pub const AF_UNSPEC = PF_UNSPEC; | ||
| 212 | pub const AF_LOCAL = PF_LOCAL; | ||
| 213 | pub const AF_UNIX = AF_LOCAL; | ||
| 214 | pub const AF_FILE = AF_LOCAL; | ||
| 215 | pub const AF_INET = PF_INET; | ||
| 216 | pub const AF_APPLETALK = PF_APPLETALK; | ||
| 217 | pub const AF_INET6 = PF_INET6; | ||
| 218 | pub const AF_KEY = PF_KEY; | ||
| 219 | pub const AF_ROUTE = PF_ROUTE; | ||
| 220 | pub const AF_SNA = PF_SNA; | ||
| 221 | pub const AF_MPLS = PF_MPLS; | ||
| 222 | pub const AF_CAN = PF_CAN; | ||
| 223 | pub const AF_BLUETOOTH = PF_BLUETOOTH; | ||
| 224 | pub const AF_ISDN = PF_ISDN; | ||
| 225 | pub const AF_MAX = PF_MAX; | ||
| 226 | |||
| 227 | pub const DT_UNKNOWN = 0; | ||
| 228 | pub const DT_FIFO = 1; | ||
| 229 | pub const DT_CHR = 2; | ||
| 230 | pub const DT_DIR = 4; | ||
| 231 | pub const DT_BLK = 6; | ||
| 232 | pub const DT_REG = 8; | ||
| 233 | pub const DT_LNK = 10; | ||
| 234 | pub const DT_SOCK = 12; | ||
| 235 | pub const DT_WHT = 14; | ||
| 236 | |||
| 237 | /// add event to kq (implies enable) | ||
| 238 | pub const EV_ADD = 0x0001; | ||
| 239 | |||
| 240 | /// delete event from kq | ||
| 241 | pub const EV_DELETE = 0x0002; | ||
| 242 | |||
| 243 | /// enable event | ||
| 244 | pub const EV_ENABLE = 0x0004; | ||
| 245 | |||
| 246 | /// disable event (not reported) | ||
| 247 | pub const EV_DISABLE = 0x0008; | ||
| 248 | |||
| 249 | /// only report one occurrence | ||
| 250 | pub const EV_ONESHOT = 0x0010; | ||
| 251 | |||
| 252 | /// clear event state after reporting | ||
| 253 | pub 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 | ||
| 259 | pub const EV_RECEIPT = 0x0040; | ||
| 260 | |||
| 261 | /// disable event after reporting | ||
| 262 | pub const EV_DISPATCH = 0x0080; | ||
| 263 | |||
| 264 | pub const EVFILT_READ = 0; | ||
| 265 | pub const EVFILT_WRITE = 1; | ||
| 266 | |||
| 267 | /// attached to aio requests | ||
| 268 | pub const EVFILT_AIO = 2; | ||
| 269 | |||
| 270 | /// attached to vnodes | ||
| 271 | pub const EVFILT_VNODE = 3; | ||
| 272 | |||
| 273 | /// attached to struct proc | ||
| 274 | pub const EVFILT_PROC = 4; | ||
| 275 | |||
| 276 | /// attached to struct proc | ||
| 277 | pub const EVFILT_SIGNAL = 5; | ||
| 278 | |||
| 279 | /// timers | ||
| 280 | pub const EVFILT_TIMER = 6; | ||
| 281 | |||
| 282 | /// Filesystem events | ||
| 283 | pub const EVFILT_FS = 7; | ||
| 284 | |||
| 285 | /// On input, NOTE_TRIGGER causes the event to be triggered for output. | ||
| 286 | pub const NOTE_TRIGGER = 0x08000000; | ||
| 287 | |||
| 288 | /// low water mark | ||
| 289 | pub const NOTE_LOWAT = 0x00000001; | ||
| 290 | |||
| 291 | /// vnode was removed | ||
| 292 | pub const NOTE_DELETE = 0x00000001; | ||
| 293 | |||
| 294 | /// data contents changed | ||
| 295 | pub const NOTE_WRITE = 0x00000002; | ||
| 296 | |||
| 297 | /// size increased | ||
| 298 | pub const NOTE_EXTEND = 0x00000004; | ||
| 299 | |||
| 300 | /// attributes changed | ||
| 301 | pub const NOTE_ATTRIB = 0x00000008; | ||
| 302 | |||
| 303 | /// link count changed | ||
| 304 | pub const NOTE_LINK = 0x00000010; | ||
| 305 | |||
| 306 | /// vnode was renamed | ||
| 307 | pub const NOTE_RENAME = 0x00000020; | ||
| 308 | |||
| 309 | /// vnode access was revoked | ||
| 310 | pub const NOTE_REVOKE = 0x00000040; | ||
| 311 | |||
| 312 | /// process exited | ||
| 313 | pub const NOTE_EXIT = 0x80000000; | ||
| 314 | |||
| 315 | /// process forked | ||
| 316 | pub const NOTE_FORK = 0x40000000; | ||
| 317 | |||
| 318 | /// process exec'd | ||
| 319 | pub const NOTE_EXEC = 0x20000000; | ||
| 320 | |||
| 321 | /// mask for signal & exit status | ||
| 322 | pub const NOTE_PDATAMASK = 0x000fffff; | ||
| 323 | pub const NOTE_PCTRLMASK = 0xf0000000; | ||
| 324 | |||
| 325 | pub const TIOCCBRK = 0x2000747a; | ||
| 326 | pub const TIOCCDTR = 0x20007478; | ||
| 327 | pub const TIOCCONS = 0x80047462; | ||
| 328 | pub const TIOCDCDTIMESTAMP = 0x40107458; | ||
| 329 | pub const TIOCDRAIN = 0x2000745e; | ||
| 330 | pub const TIOCEXCL = 0x2000740d; | ||
| 331 | pub const TIOCEXT = 0x80047460; | ||
| 332 | pub const TIOCFLAG_CDTRCTS = 0x10; | ||
| 333 | pub const TIOCFLAG_CLOCAL = 0x2; | ||
| 334 | pub const TIOCFLAG_CRTSCTS = 0x4; | ||
| 335 | pub const TIOCFLAG_MDMBUF = 0x8; | ||
| 336 | pub const TIOCFLAG_SOFTCAR = 0x1; | ||
| 337 | pub const TIOCFLUSH = 0x80047410; | ||
| 338 | pub const TIOCGETA = 0x402c7413; | ||
| 339 | pub const TIOCGETD = 0x4004741a; | ||
| 340 | pub const TIOCGFLAGS = 0x4004745d; | ||
| 341 | pub const TIOCGLINED = 0x40207442; | ||
| 342 | pub const TIOCGPGRP = 0x40047477; | ||
| 343 | pub const TIOCGQSIZE = 0x40047481; | ||
| 344 | pub const TIOCGRANTPT = 0x20007447; | ||
| 345 | pub const TIOCGSID = 0x40047463; | ||
| 346 | pub const TIOCGSIZE = 0x40087468; | ||
| 347 | pub const TIOCGWINSZ = 0x40087468; | ||
| 348 | pub const TIOCMBIC = 0x8004746b; | ||
| 349 | pub const TIOCMBIS = 0x8004746c; | ||
| 350 | pub const TIOCMGET = 0x4004746a; | ||
| 351 | pub const TIOCMSET = 0x8004746d; | ||
| 352 | pub const TIOCM_CAR = 0x40; | ||
| 353 | pub const TIOCM_CD = 0x40; | ||
| 354 | pub const TIOCM_CTS = 0x20; | ||
| 355 | pub const TIOCM_DSR = 0x100; | ||
| 356 | pub const TIOCM_DTR = 0x2; | ||
| 357 | pub const TIOCM_LE = 0x1; | ||
| 358 | pub const TIOCM_RI = 0x80; | ||
| 359 | pub const TIOCM_RNG = 0x80; | ||
| 360 | pub const TIOCM_RTS = 0x4; | ||
| 361 | pub const TIOCM_SR = 0x10; | ||
| 362 | pub const TIOCM_ST = 0x8; | ||
| 363 | pub const TIOCNOTTY = 0x20007471; | ||
| 364 | pub const TIOCNXCL = 0x2000740e; | ||
| 365 | pub const TIOCOUTQ = 0x40047473; | ||
| 366 | pub const TIOCPKT = 0x80047470; | ||
| 367 | pub const TIOCPKT_DATA = 0x0; | ||
| 368 | pub const TIOCPKT_DOSTOP = 0x20; | ||
| 369 | pub const TIOCPKT_FLUSHREAD = 0x1; | ||
| 370 | pub const TIOCPKT_FLUSHWRITE = 0x2; | ||
| 371 | pub const TIOCPKT_IOCTL = 0x40; | ||
| 372 | pub const TIOCPKT_NOSTOP = 0x10; | ||
| 373 | pub const TIOCPKT_START = 0x8; | ||
| 374 | pub const TIOCPKT_STOP = 0x4; | ||
| 375 | pub const TIOCPTMGET = 0x40287446; | ||
| 376 | pub const TIOCPTSNAME = 0x40287448; | ||
| 377 | pub const TIOCRCVFRAME = 0x80087445; | ||
| 378 | pub const TIOCREMOTE = 0x80047469; | ||
| 379 | pub const TIOCSBRK = 0x2000747b; | ||
| 380 | pub const TIOCSCTTY = 0x20007461; | ||
| 381 | pub const TIOCSDTR = 0x20007479; | ||
| 382 | pub const TIOCSETA = 0x802c7414; | ||
| 383 | pub const TIOCSETAF = 0x802c7416; | ||
| 384 | pub const TIOCSETAW = 0x802c7415; | ||
| 385 | pub const TIOCSETD = 0x8004741b; | ||
| 386 | pub const TIOCSFLAGS = 0x8004745c; | ||
| 387 | pub const TIOCSIG = 0x2000745f; | ||
| 388 | pub const TIOCSLINED = 0x80207443; | ||
| 389 | pub const TIOCSPGRP = 0x80047476; | ||
| 390 | pub const TIOCSQSIZE = 0x80047480; | ||
| 391 | pub const TIOCSSIZE = 0x80087467; | ||
| 392 | pub const TIOCSTART = 0x2000746e; | ||
| 393 | pub const TIOCSTAT = 0x80047465; | ||
| 394 | pub const TIOCSTI = 0x80017472; | ||
| 395 | pub const TIOCSTOP = 0x2000746f; | ||
| 396 | pub const TIOCSWINSZ = 0x80087467; | ||
| 397 | pub const TIOCUCNTL = 0x80047466; | ||
| 398 | pub const TIOCXMTFRAME = 0x80087444; | ||
| 399 | |||
| 400 | pub const sockaddr = c.sockaddr; | ||
| 401 | pub const sockaddr_in = c.sockaddr_in; | ||
| 402 | pub const sockaddr_in6 = c.sockaddr_in6; | ||
| 403 | |||
| 404 | fn unsigned(s: i32) u32 { | ||
| 405 | return @bitCast(u32, s); | ||
| 406 | } | ||
| 407 | fn signed(s: u32) i32 { | ||
| 408 | return @bitCast(i32, s); | ||
| 409 | } | ||
| 410 | pub fn WEXITSTATUS(s: i32) i32 { | ||
| 411 | return signed((unsigned(s) >> 8) & 0xff); | ||
| 412 | } | ||
| 413 | pub fn WTERMSIG(s: i32) i32 { | ||
| 414 | return signed(unsigned(s) & 0x7f); | ||
| 415 | } | ||
| 416 | pub fn WSTOPSIG(s: i32) i32 { | ||
| 417 | return WEXITSTATUS(s); | ||
| 418 | } | ||
| 419 | pub fn WIFEXITED(s: i32) bool { | ||
| 420 | return WTERMSIG(s) == 0; | ||
| 421 | } | ||
| 422 | |||
| 423 | pub fn WIFCONTINUED(s: i32) bool { | ||
| 424 | return ((s & 0x7f) == 0xffff); | ||
| 425 | } | ||
| 426 | |||
| 427 | pub fn WIFSTOPPED(s: i32) bool { | ||
| 428 | return ((s & 0x7f != 0x7f) and !WIFCONTINUED(s)); | ||
| 429 | } | ||
| 430 | |||
| 431 | pub fn WIFSIGNALED(s: i32) bool { | ||
| 432 | return !WIFSTOPPED(s) and !WIFCONTINUED(s) and !WIFEXITED(s); | ||
| 433 | } | ||
| 434 | |||
| 435 | pub 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. | ||
| 443 | pub 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 | |||
| 448 | pub fn dup2(old: i32, new: i32) usize { | ||
| 449 | return errnoWrap(c.dup2(old, new)); | ||
| 450 | } | ||
| 451 | |||
| 452 | pub fn chdir(path: [*]const u8) usize { | ||
| 453 | return errnoWrap(c.chdir(path)); | ||
| 454 | } | ||
| 455 | |||
| 456 | pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize { | ||
| 457 | return errnoWrap(c.execve(path, argv, envp)); | ||
| 458 | } | ||
| 459 | |||
| 460 | pub fn fork() usize { | ||
| 461 | return errnoWrap(c.fork()); | ||
| 462 | } | ||
| 463 | |||
| 464 | pub fn access(path: [*]const u8, mode: u32) usize { | ||
| 465 | return errnoWrap(c.access(path, mode)); | ||
| 466 | } | ||
| 467 | |||
| 468 | pub fn getcwd(buf: [*]u8, size: usize) usize { | ||
| 469 | return if (c.getcwd(buf, size) == null) @bitCast(usize, -isize(c._errno().*)) else 0; | ||
| 470 | } | ||
| 471 | |||
| 472 | pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize { | ||
| 473 | return errnoWrap(@bitCast(isize, c.getdents(fd, drip, count))); | ||
| 474 | } | ||
| 475 | |||
| 476 | pub 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 | |||
| 480 | pub 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 | |||
| 484 | pub fn isatty(fd: i32) bool { | ||
| 485 | return c.isatty(fd) != 0; | ||
| 486 | } | ||
| 487 | |||
| 488 | pub 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 | |||
| 492 | pub fn mkdir(path: [*]const u8, mode: u32) usize { | ||
| 493 | return errnoWrap(c.mkdir(path, mode)); | ||
| 494 | } | ||
| 495 | |||
| 496 | pub 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 | |||
| 509 | pub fn munmap(address: usize, length: usize) usize { | ||
| 510 | return errnoWrap(c.munmap(@intToPtr(*c_void, address), length)); | ||
| 511 | } | ||
| 512 | |||
| 513 | pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize { | ||
| 514 | return errnoWrap(c.read(fd, @ptrCast(*c_void, buf), nbyte)); | ||
| 515 | } | ||
| 516 | |||
| 517 | pub fn rmdir(path: [*]const u8) usize { | ||
| 518 | return errnoWrap(c.rmdir(path)); | ||
| 519 | } | ||
| 520 | |||
| 521 | pub fn symlink(existing: [*]const u8, new: [*]const u8) usize { | ||
| 522 | return errnoWrap(c.symlink(existing, new)); | ||
| 523 | } | ||
| 524 | |||
| 525 | pub 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 | |||
| 529 | pub 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 | |||
| 533 | pub fn pipe(fd: *[2]i32) usize { | ||
| 534 | return pipe2(fd, 0); | ||
| 535 | } | ||
| 536 | |||
| 537 | pub 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 | |||
| 542 | pub fn write(fd: i32, buf: [*]const u8, nbyte: usize) usize { | ||
| 543 | return errnoWrap(c.write(fd, @ptrCast(*const c_void, buf), nbyte)); | ||
| 544 | } | ||
| 545 | |||
| 546 | pub 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 | |||
| 550 | pub 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 | |||
| 554 | pub fn rename(old: [*]const u8, new: [*]const u8) usize { | ||
| 555 | return errnoWrap(c.rename(old, new)); | ||
| 556 | } | ||
| 557 | |||
| 558 | pub fn open(path: [*]const u8, flags: u32, mode: usize) usize { | ||
| 559 | return errnoWrap(c.open(path, @bitCast(c_int, flags), mode)); | ||
| 560 | } | ||
| 561 | |||
| 562 | pub fn create(path: [*]const u8, perm: usize) usize { | ||
| 563 | return arch.syscall2(SYS_creat, @ptrToInt(path), perm); | ||
| 564 | } | ||
| 565 | |||
| 566 | pub 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 | |||
| 570 | pub fn close(fd: i32) usize { | ||
| 571 | return errnoWrap(c.close(fd)); | ||
| 572 | } | ||
| 573 | |||
| 574 | pub fn lseek(fd: i32, offset: isize, whence: c_int) usize { | ||
| 575 | return errnoWrap(c.lseek(fd, offset, whence)); | ||
| 576 | } | ||
| 577 | |||
| 578 | pub fn exit(code: i32) noreturn { | ||
| 579 | c.exit(code); | ||
| 580 | } | ||
| 581 | |||
| 582 | pub fn kill(pid: i32, sig: i32) usize { | ||
| 583 | return errnoWrap(c.kill(pid, sig)); | ||
| 584 | } | ||
| 585 | |||
| 586 | pub fn unlink(path: [*]const u8) usize { | ||
| 587 | return errnoWrap(c.unlink(path)); | ||
| 588 | } | ||
| 589 | |||
| 590 | pub 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 | |||
| 595 | pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize { | ||
| 596 | return errnoWrap(c.nanosleep(req, rem)); | ||
| 597 | } | ||
| 598 | |||
| 599 | pub fn clock_gettime(clk_id: i32, tp: *timespec) usize { | ||
| 600 | return errnoWrap(c.clock_gettime(clk_id, tp)); | ||
| 601 | } | ||
| 602 | |||
| 603 | pub fn clock_getres(clk_id: i32, tp: *timespec) usize { | ||
| 604 | return errnoWrap(c.clock_getres(clk_id, tp)); | ||
| 605 | } | ||
| 606 | |||
| 607 | pub fn setuid(uid: u32) usize { | ||
| 608 | return errnoWrap(c.setuid(uid)); | ||
| 609 | } | ||
| 610 | |||
| 611 | pub fn setgid(gid: u32) usize { | ||
| 612 | return errnoWrap(c.setgid(gid)); | ||
| 613 | } | ||
| 614 | |||
| 615 | pub fn setreuid(ruid: u32, euid: u32) usize { | ||
| 616 | return errnoWrap(c.setreuid(ruid, euid)); | ||
| 617 | } | ||
| 618 | |||
| 619 | pub fn setregid(rgid: u32, egid: u32) usize { | ||
| 620 | return errnoWrap(c.setregid(rgid, egid)); | ||
| 621 | } | ||
| 622 | |||
| 623 | const NSIG = 32; | ||
| 624 | |||
| 625 | pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize)); | ||
| 626 | pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0); | ||
| 627 | pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1); | ||
| 628 | |||
| 629 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. | ||
| 630 | pub 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 | |||
| 644 | pub const _SIG_WORDS = 4; | ||
| 645 | pub const _SIG_MAXSIG = 128; | ||
| 646 | |||
| 647 | pub inline fn _SIG_IDX(sig: usize) usize { | ||
| 648 | return sig - 1; | ||
| 649 | } | ||
| 650 | pub inline fn _SIG_WORD(sig: usize) usize { | ||
| 651 | return_SIG_IDX(sig) >> 5; | ||
| 652 | } | ||
| 653 | pub inline fn _SIG_BIT(sig: usize) usize { | ||
| 654 | return 1 << (_SIG_IDX(sig) & 31); | ||
| 655 | } | ||
| 656 | pub inline fn _SIG_VALID(sig: usize) usize { | ||
| 657 | return sig <= _SIG_MAXSIG and sig > 0; | ||
| 658 | } | ||
| 659 | |||
| 660 | pub const sigset_t = extern struct { | ||
| 661 | __bits: [_SIG_WORDS]u32, | ||
| 662 | }; | ||
| 663 | |||
| 664 | pub fn raise(sig: i32) usize { | ||
| 665 | return errnoWrap(c.raise(sig)); | ||
| 666 | } | ||
| 667 | |||
| 668 | pub const Stat = c.Stat; | ||
| 669 | pub const dirent = c.dirent; | ||
| 670 | pub const timespec = c.timespec; | ||
| 671 | |||
| 672 | pub fn fstat(fd: i32, buf: *c.Stat) usize { | ||
| 673 | return errnoWrap(c.fstat(fd, buf)); | ||
| 674 | } | ||
| 675 | pub const iovec = extern struct { | ||
| 676 | iov_base: [*]u8, | ||
| 677 | iov_len: usize, | ||
| 678 | }; | ||
| 679 | |||
| 680 | pub const iovec_const = extern struct { | ||
| 681 | iov_base: [*]const u8, | ||
| 682 | iov_len: usize, | ||
| 683 | }; | ||
| 684 | |||
| 685 | // TODO avoid libc dependency | ||
| 686 | pub fn kqueue() usize { | ||
| 687 | return errnoWrap(c.kqueue()); | ||
| 688 | } | ||
| 689 | |||
| 690 | // TODO avoid libc dependency | ||
| 691 | pub 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 | ||
| 703 | pub 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 | ||
| 708 | pub 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 | ||
| 713 | pub 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. | ||
| 722 | fn 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 @@ | ||
| 1 | pub const EPERM = 1; // Operation not permitted | ||
| 2 | pub const ENOENT = 2; // No such file or directory | ||
| 3 | pub const ESRCH = 3; // No such process | ||
| 4 | pub const EINTR = 4; // Interrupted system call | ||
| 5 | pub const EIO = 5; // Input/output error | ||
| 6 | pub const ENXIO = 6; // Device not configured | ||
| 7 | pub const E2BIG = 7; // Argument list too long | ||
| 8 | pub const ENOEXEC = 8; // Exec format error | ||
| 9 | pub const EBADF = 9; // Bad file descriptor | ||
| 10 | pub const ECHILD = 10; // No child processes | ||
| 11 | pub const EDEADLK = 11; // Resource deadlock avoided | ||
| 12 | // 11 was EAGAIN | ||
| 13 | pub const ENOMEM = 12; // Cannot allocate memory | ||
| 14 | pub const EACCES = 13; // Permission denied | ||
| 15 | pub const EFAULT = 14; // Bad address | ||
| 16 | pub const ENOTBLK = 15; // Block device required | ||
| 17 | pub const EBUSY = 16; // Device busy | ||
| 18 | pub const EEXIST = 17; // File exists | ||
| 19 | pub const EXDEV = 18; // Cross-device link | ||
| 20 | pub const ENODEV = 19; // Operation not supported by device | ||
| 21 | pub const ENOTDIR = 20; // Not a directory | ||
| 22 | pub const EISDIR = 21; // Is a directory | ||
| 23 | pub const EINVAL = 22; // Invalid argument | ||
| 24 | pub const ENFILE = 23; // Too many open files in system | ||
| 25 | pub const EMFILE = 24; // Too many open files | ||
| 26 | pub const ENOTTY = 25; // Inappropriate ioctl for device | ||
| 27 | pub const ETXTBSY = 26; // Text file busy | ||
| 28 | pub const EFBIG = 27; // File too large | ||
| 29 | pub const ENOSPC = 28; // No space left on device | ||
| 30 | pub const ESPIPE = 29; // Illegal seek | ||
| 31 | pub const EROFS = 30; // Read-only file system | ||
| 32 | pub const EMLINK = 31; // Too many links | ||
| 33 | pub const EPIPE = 32; // Broken pipe | ||
| 34 | |||
| 35 | // math software | ||
| 36 | pub const EDOM = 33; // Numerical argument out of domain | ||
| 37 | pub const ERANGE = 34; // Result too large or too small | ||
| 38 | |||
| 39 | // non-blocking and interrupt i/o | ||
| 40 | pub const EAGAIN = 35; // Resource temporarily unavailable | ||
| 41 | pub const EWOULDBLOCK = EAGAIN; // Operation would block | ||
| 42 | pub const EINPROGRESS = 36; // Operation now in progress | ||
| 43 | pub const EALREADY = 37; // Operation already in progress | ||
| 44 | |||
| 45 | // ipc/network software -- argument errors | ||
| 46 | pub const ENOTSOCK = 38; // Socket operation on non-socket | ||
| 47 | pub const EDESTADDRREQ = 39; // Destination address required | ||
| 48 | pub const EMSGSIZE = 40; // Message too long | ||
| 49 | pub const EPROTOTYPE = 41; // Protocol wrong type for socket | ||
| 50 | pub const ENOPROTOOPT = 42; // Protocol option not available | ||
| 51 | pub const EPROTONOSUPPORT = 43; // Protocol not supported | ||
| 52 | pub const ESOCKTNOSUPPORT = 44; // Socket type not supported | ||
| 53 | pub const EOPNOTSUPP = 45; // Operation not supported | ||
| 54 | pub const EPFNOSUPPORT = 46; // Protocol family not supported | ||
| 55 | pub const EAFNOSUPPORT = 47; // Address family not supported by protocol family | ||
| 56 | pub const EADDRINUSE = 48; // Address already in use | ||
| 57 | pub const EADDRNOTAVAIL = 49; // Can't assign requested address | ||
| 58 | |||
| 59 | // ipc/network software -- operational errors | ||
| 60 | pub const ENETDOWN = 50; // Network is down | ||
| 61 | pub const ENETUNREACH = 51; // Network is unreachable | ||
| 62 | pub const ENETRESET = 52; // Network dropped connection on reset | ||
| 63 | pub const ECONNABORTED = 53; // Software caused connection abort | ||
| 64 | pub const ECONNRESET = 54; // Connection reset by peer | ||
| 65 | pub const ENOBUFS = 55; // No buffer space available | ||
| 66 | pub const EISCONN = 56; // Socket is already connected | ||
| 67 | pub const ENOTCONN = 57; // Socket is not connected | ||
| 68 | pub const ESHUTDOWN = 58; // Can't send after socket shutdown | ||
| 69 | pub const ETOOMANYREFS = 59; // Too many references: can't splice | ||
| 70 | pub const ETIMEDOUT = 60; // Operation timed out | ||
| 71 | pub const ECONNREFUSED = 61; // Connection refused | ||
| 72 | |||
| 73 | pub const ELOOP = 62; // Too many levels of symbolic links | ||
| 74 | pub const ENAMETOOLONG = 63; // File name too long | ||
| 75 | |||
| 76 | // should be rearranged | ||
| 77 | pub const EHOSTDOWN = 64; // Host is down | ||
| 78 | pub const EHOSTUNREACH = 65; // No route to host | ||
| 79 | pub const ENOTEMPTY = 66; // Directory not empty | ||
| 80 | |||
| 81 | // quotas & mush | ||
| 82 | pub const EPROCLIM = 67; // Too many processes | ||
| 83 | pub const EUSERS = 68; // Too many users | ||
| 84 | pub const EDQUOT = 69; // Disc quota exceeded | ||
| 85 | |||
| 86 | // Network File System | ||
| 87 | pub const ESTALE = 70; // Stale NFS file handle | ||
| 88 | pub const EREMOTE = 71; // Too many levels of remote in path | ||
| 89 | pub const EBADRPC = 72; // RPC struct is bad | ||
| 90 | pub const ERPCMISMATCH = 73; // RPC version wrong | ||
| 91 | pub const EPROGUNAVAIL = 74; // RPC prog. not avail | ||
| 92 | pub const EPROGMISMATCH = 75; // Program version wrong | ||
| 93 | pub const EPROCUNAVAIL = 76; // Bad procedure for program | ||
| 94 | |||
| 95 | pub const ENOLCK = 77; // No locks available | ||
| 96 | pub const ENOSYS = 78; // Function not implemented | ||
| 97 | |||
| 98 | pub const EFTYPE = 79; // Inappropriate file type or format | ||
| 99 | pub const EAUTH = 80; // Authentication error | ||
| 100 | pub const ENEEDAUTH = 81; // Need authenticator | ||
| 101 | |||
| 102 | // SystemV IPC | ||
| 103 | pub const EIDRM = 82; // Identifier removed | ||
| 104 | pub const ENOMSG = 83; // No message of desired type | ||
| 105 | pub const EOVERFLOW = 84; // Value too large to be stored in data type | ||
| 106 | |||
| 107 | // Wide/multibyte-character handling, ISO/IEC 9899/AMD1:1995 | ||
| 108 | pub const EILSEQ = 85; // Illegal byte sequence | ||
| 109 | |||
| 110 | // From IEEE Std 1003.1-2001 | ||
| 111 | // Base, Realtime, Threads or Thread Priority Scheduling option errors | ||
| 112 | pub const ENOTSUP = 86; // Not supported | ||
| 113 | |||
| 114 | // Realtime option errors | ||
| 115 | pub const ECANCELED = 87; // Operation canceled | ||
| 116 | |||
| 117 | // Realtime, XSI STREAMS option errors | ||
| 118 | pub const EBADMSG = 88; // Bad or Corrupt message | ||
| 119 | |||
| 120 | // XSI STREAMS option errors | ||
| 121 | pub const ENODATA = 89; // No message available | ||
| 122 | pub const ENOSR = 90; // No STREAM resources | ||
| 123 | pub const ENOSTR = 91; // Not a STREAM | ||
| 124 | pub const ETIME = 92; // STREAM ioctl timeout | ||
| 125 | |||
| 126 | // File system extended attribute errors | ||
| 127 | pub const ENOATTR = 93; // Attribute not found | ||
| 128 | |||
| 129 | // Realtime, XSI STREAMS option errors | ||
| 130 | pub const EMULTIHOP = 94; // Multihop attempted | ||
| 131 | pub const ENOLINK = 95; // Link has been severed | ||
| 132 | pub const EPROTO = 96; // Protocol error | ||
| 133 | |||
| 134 | pub const ELAST = 96; // Must equal largest errno | ||
std/os/path.zig deleted-1288| ... | @@ -1,1288 +0,0 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const Os = builtin.Os; | ||
| 4 | const debug = std.debug; | ||
| 5 | const assert = debug.assert; | ||
| 6 | const testing = std.testing; | ||
| 7 | const mem = std.mem; | ||
| 8 | const fmt = std.fmt; | ||
| 9 | const Allocator = mem.Allocator; | ||
| 10 | const os = std.os; | ||
| 11 | const math = std.math; | ||
| 12 | const posix = os.posix; | ||
| 13 | const windows = os.windows; | ||
| 14 | const cstr = std.cstr; | ||
| 15 | const windows_util = @import("windows/util.zig"); | ||
| 16 | |||
| 17 | pub const sep_windows = '\\'; | ||
| 18 | pub const sep_posix = '/'; | ||
| 19 | pub const sep = if (is_windows) sep_windows else sep_posix; | ||
| 20 | |||
| 21 | pub const sep_str = [1]u8{sep}; | ||
| 22 | |||
| 23 | pub const delimiter_windows = ';'; | ||
| 24 | pub const delimiter_posix = ':'; | ||
| 25 | pub const delimiter = if (is_windows) delimiter_windows else delimiter_posix; | ||
| 26 | |||
| 27 | const is_windows = builtin.os == builtin.Os.windows; | ||
| 28 | |||
| 29 | pub 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. | ||
| 39 | fn 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 | |||
| 80 | pub 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. | ||
| 84 | pub 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. | ||
| 90 | pub fn joinPosix(allocator: *Allocator, paths: []const []const u8) ![]u8 { | ||
| 91 | return joinSep(allocator, sep_posix, paths); | ||
| 92 | } | ||
| 93 | |||
| 94 | fn 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 | |||
| 101 | fn 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 | |||
| 108 | test "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 | |||
| 136 | pub fn isAbsolute(path: []const u8) bool { | ||
| 137 | if (is_windows) { | ||
| 138 | return isAbsoluteWindows(path); | ||
| 139 | } else { | ||
| 140 | return isAbsolutePosix(path); | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | pub 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 | |||
| 163 | pub fn isAbsolutePosix(path: []const u8) bool { | ||
| 164 | return path[0] == sep_posix; | ||
| 165 | } | ||
| 166 | |||
| 167 | test "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 | |||
| 189 | test "os.path.isAbsolutePosix" { | ||
| 190 | testIsAbsolutePosix("/home/foo", true); | ||
| 191 | testIsAbsolutePosix("/home/foo/..", true); | ||
| 192 | testIsAbsolutePosix("bar/", false); | ||
| 193 | testIsAbsolutePosix("./baz", false); | ||
| 194 | } | ||
| 195 | |||
| 196 | fn testIsAbsoluteWindows(path: []const u8, expected_result: bool) void { | ||
| 197 | testing.expectEqual(expected_result, isAbsoluteWindows(path)); | ||
| 198 | } | ||
| 199 | |||
| 200 | fn testIsAbsolutePosix(path: []const u8, expected_result: bool) void { | ||
| 201 | testing.expectEqual(expected_result, isAbsolutePosix(path)); | ||
| 202 | } | ||
| 203 | |||
| 204 | pub 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 | |||
| 216 | pub 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 | |||
| 282 | test "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 | |||
| 315 | pub fn diskDesignator(path: []const u8) []const u8 { | ||
| 316 | if (is_windows) { | ||
| 317 | return diskDesignatorWindows(path); | ||
| 318 | } else { | ||
| 319 | return ""; | ||
| 320 | } | ||
| 321 | } | ||
| 322 | |||
| 323 | pub fn diskDesignatorWindows(path: []const u8) []const u8 { | ||
| 324 | return windowsParsePath(path).disk_designator; | ||
| 325 | } | ||
| 326 | |||
| 327 | fn 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 | |||
| 338 | fn 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 | |||
| 361 | fn asciiUpper(byte: u8) u8 { | ||
| 362 | return switch (byte) { | ||
| 363 | 'a'...'z' => 'A' + (byte - 'a'), | ||
| 364 | else => byte, | ||
| 365 | }; | ||
| 366 | } | ||
| 367 | |||
| 368 | fn 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`. | ||
| 380 | pub 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. | ||
| 396 | pub 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. | ||
| 577 | pub 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 | |||
| 640 | test "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 | |||
| 653 | test "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 | |||
| 696 | test "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 | |||
| 709 | fn testResolveWindows(paths: []const []const u8) []u8 { | ||
| 710 | return resolveWindows(debug.global_allocator, paths) catch unreachable; | ||
| 711 | } | ||
| 712 | |||
| 713 | fn 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 | ||
| 719 | pub fn dirname(path: []const u8) ?[]const u8 { | ||
| 720 | if (is_windows) { | ||
| 721 | return dirnameWindows(path); | ||
| 722 | } else { | ||
| 723 | return dirnamePosix(path); | ||
| 724 | } | ||
| 725 | } | ||
| 726 | |||
| 727 | pub 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 | |||
| 761 | pub 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 | |||
| 787 | test "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 | |||
| 799 | test "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 | |||
| 835 | fn 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 | |||
| 843 | fn 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 | |||
| 851 | pub fn basename(path: []const u8) []const u8 { | ||
| 852 | if (is_windows) { | ||
| 853 | return basenameWindows(path); | ||
| 854 | } else { | ||
| 855 | return basenamePosix(path); | ||
| 856 | } | ||
| 857 | } | ||
| 858 | |||
| 859 | pub 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 | |||
| 880 | pub 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 | |||
| 912 | test "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 | |||
| 951 | fn testBasename(input: []const u8, expected_output: []const u8) void { | ||
| 952 | testing.expectEqualSlices(u8, expected_output, basename(input)); | ||
| 953 | } | ||
| 954 | |||
| 955 | fn testBasenamePosix(input: []const u8, expected_output: []const u8) void { | ||
| 956 | testing.expectEqualSlices(u8, expected_output, basenamePosix(input)); | ||
| 957 | } | ||
| 958 | |||
| 959 | fn 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 `\\`. | ||
| 967 | pub 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 | |||
| 975 | pub 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 | |||
| 1048 | pub 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 | |||
| 1093 | test "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 | |||
| 1133 | fn 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 | |||
| 1138 | fn 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 | |||
| 1143 | pub 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`. | ||
| 1174 | pub 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. | ||
| 1223 | pub 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. | ||
| 1264 | pub 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. | ||
| 1279 | pub 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 | |||
| 1284 | test "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 @@ |
| 1 | const std = @import("../std.zig"); | 1 | const std = @import("../std.zig"); |
| 2 | const os = std.os; | 2 | const os = std.os; |
| 3 | const testing = std.testing; | ||
| 3 | const expect = std.testing.expect; | 4 | const expect = std.testing.expect; |
| 4 | const io = std.io; | 5 | const io = std.io; |
| 6 | const fs = std.fs; | ||
| 5 | const mem = std.mem; | 7 | const mem = std.mem; |
| 8 | const File = std.fs.File; | ||
| 9 | const Thread = std.Thread; | ||
| 6 | 10 | ||
| 7 | const a = std.debug.global_allocator; | 11 | const a = std.debug.global_allocator; |
| 8 | 12 | ||
| ... | @@ -11,11 +15,11 @@ const AtomicRmwOp = builtin.AtomicRmwOp; | ... | @@ -11,11 +15,11 @@ const AtomicRmwOp = builtin.AtomicRmwOp; |
| 11 | const AtomicOrder = builtin.AtomicOrder; | 15 | const AtomicOrder = builtin.AtomicOrder; |
| 12 | 16 | ||
| 13 | test "makePath, put some files in it, deleteTree" { | 17 | test "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 | } |
| 24 | 28 | ||
| 25 | test "access file" { | 29 | test "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 | } |
| 32 | 36 | ||
| 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 | } |
| 37 | 41 | ||
| 38 | fn testThreadIdFn(thread_id: *os.Thread.Id) void { | 42 | fn testThreadIdFn(thread_id: *Thread.Id) void { |
| 39 | thread_id.* = os.Thread.getCurrentId(); | 43 | thread_id.* = Thread.getCurrentId(); |
| 40 | } | 44 | } |
| 41 | 45 | ||
| 42 | test "std.os.Thread.getCurrentId" { | 46 | test "std.Thread.getCurrentId" { |
| 43 | if (builtin.single_threaded) return error.SkipZigTest; | 47 | if (builtin.single_threaded) return error.SkipZigTest; |
| 44 | 48 | ||
| 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 | } |
| 62 | 63 | ||
| ... | @@ -65,10 +66,10 @@ test "spawn threads" { | ... | @@ -65,10 +66,10 @@ test "spawn threads" { |
| 65 | 66 | ||
| 66 | var shared_ctx: i32 = 1; | 67 | var shared_ctx: i32 = 1; |
| 67 | 68 | ||
| 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); |
| 72 | 73 | ||
| 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 | } |
| 89 | 90 | ||
| 90 | test "cpu count" { | 91 | test "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 | } |
| 94 | 95 | ||
| ... | @@ -101,7 +102,7 @@ test "AtomicFile" { | ... | @@ -101,7 +102,7 @@ test "AtomicFile" { |
| 101 | \\ this is a test file | 102 | \\ 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)); |
| 111 | 112 | ||
| 112 | try os.deleteFile(test_out_file); | 113 | try fs.deleteFile(test_out_file); |
| 113 | } | 114 | } |
| 114 | 115 | ||
| 115 | test "thread local storage" { | 116 | test "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 | |||
| 132 | test "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 | |||
| 142 | test "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 | |||
| 148 | test "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 @@ | ||
| 1 | const std = @import("../std.zig"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const Os = builtin.Os; | ||
| 4 | const debug = std.debug; | ||
| 5 | const testing = std.testing; | ||
| 6 | const math = std.math; | ||
| 7 | |||
| 8 | const windows = std.os.windows; | ||
| 9 | const linux = std.os.linux; | ||
| 10 | const darwin = std.os.darwin; | ||
| 11 | const wasi = std.os.wasi; | ||
| 12 | const posix = std.os.posix; | ||
| 13 | |||
| 14 | pub const epoch = @import("epoch.zig"); | ||
| 15 | |||
| 16 | /// Spurious wakeups are possible and no precision of timing is guaranteed. | ||
| 17 | pub 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. | ||
| 35 | pub 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 | ||
| 62 | pub fn timestamp() u64 { | ||
| 63 | return @divFloor(milliTimestamp(), ms_per_s); | ||
| 64 | } | ||
| 65 | |||
| 66 | /// Get the posix timestamp, UTC, in milliseconds | ||
| 67 | pub 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 | |||
| 75 | fn 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 | |||
| 86 | fn 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 | |||
| 98 | fn 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 | |||
| 107 | fn 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) | ||
| 120 | pub const nanosecond = 1; | ||
| 121 | pub const microsecond = 1000 * nanosecond; | ||
| 122 | pub const millisecond = 1000 * microsecond; | ||
| 123 | pub const second = 1000 * millisecond; | ||
| 124 | pub const minute = 60 * second; | ||
| 125 | pub const hour = 60 * minute; | ||
| 126 | |||
| 127 | /// Divisions of a second | ||
| 128 | pub const ns_per_s = 1000000000; | ||
| 129 | pub const us_per_s = 1000000; | ||
| 130 | pub const ms_per_s = 1000; | ||
| 131 | pub const cs_per_s = 100; | ||
| 132 | |||
| 133 | /// Common time divisions | ||
| 134 | pub const s_per_min = 60; | ||
| 135 | pub const s_per_hour = s_per_min * 60; | ||
| 136 | pub const s_per_day = s_per_hour * 24; | ||
| 137 | pub 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. | ||
| 147 | pub 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 | |||
| 278 | test "os.time.sleep" { | ||
| 279 | sleep(1); | ||
| 280 | } | ||
| 281 | |||
| 282 | test "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 | |||
| 293 | test "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 @@ |
| 1 | pub 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 | ||
| 3 | const builtin = @import("builtin"); | ||
| 4 | const std = @import("std"); | ||
| 5 | const assert = std.debug.assert; | ||
| 2 | 6 | ||
| 3 | pub const STDIN_FILENO = 0; | 7 | pub const is_the_target = builtin.os == .wasi; |
| 4 | pub const STDOUT_FILENO = 1; | 8 | pub use @import("bits.zig"); |
| 5 | pub const STDERR_FILENO = 2; | ||
| 6 | 9 | ||
| 7 | pub fn getErrno(r: usize) usize { | 10 | comptime { |
| 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 | } |
| 11 | 20 | ||
| 12 | pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { | 21 | pub const iovec_t = iovec; |
| 13 | var nwritten: usize = undefined; | 22 | pub const ciovec_t = iovec_const; |
| 14 | 23 | ||
| 15 | const ciovs = ciovec_t{ | 24 | pub extern "wasi_unstable" fn args_get(argv: [*][*]u8, argv_buf: [*]u8) errno_t; |
| 16 | .buf = buf, | 25 | pub extern "wasi_unstable" fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t; |
| 17 | .buf_len = count, | ||
| 18 | }; | ||
| 19 | 26 | ||
| 20 | const err = fd_write(@bitCast(fd_t, isize(fd)), &ciovs, 1, &nwritten); | 27 | pub extern "wasi_unstable" fn clock_res_get(clock_id: clockid_t, resolution: *timestamp_t) errno_t; |
| 21 | if (err == ESUCCESS) { | 28 | pub 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 | } | ||
| 27 | 29 | ||
| 28 | pub fn read(fd: i32, buf: [*]u8, nbyte: usize) usize { | 30 | pub extern "wasi_unstable" fn environ_get(environ: [*]?[*]u8, environ_buf: [*]u8) errno_t; |
| 29 | var nread: usize = undefined; | 31 | pub extern "wasi_unstable" fn environ_sizes_get(environ_count: *usize, environ_buf_size: *usize) errno_t; |
| 30 | 32 | ||
| 31 | const iovs = iovec_t{ | 33 | pub extern "wasi_unstable" fn fd_advise(fd: fd_t, offset: filesize_t, len: filesize_t, advice: advice_t) errno_t; |
| 32 | .buf = buf, | 34 | pub extern "wasi_unstable" fn fd_allocate(fd: fd_t, offset: filesize_t, len: filesize_t) errno_t; |
| 33 | .buf_len = nbyte, | 35 | pub extern "wasi_unstable" fn fd_close(fd: fd_t) errno_t; |
| 34 | }; | 36 | pub extern "wasi_unstable" fn fd_datasync(fd: fd_t) errno_t; |
| 37 | pub extern "wasi_unstable" fn fd_pread(fd: fd_t, iovs: [*]const iovec_t, iovs_len: usize, offset: filesize_t, nread: *usize) errno_t; | ||
| 38 | pub extern "wasi_unstable" fn fd_pwrite(fd: fd_t, iovs: [*]const ciovec_t, iovs_len: usize, offset: filesize_t, nwritten: *usize) errno_t; | ||
| 39 | pub extern "wasi_unstable" fn fd_read(fd: fd_t, iovs: [*]const iovec_t, iovs_len: usize, nread: *usize) errno_t; | ||
| 40 | pub extern "wasi_unstable" fn fd_readdir(fd: fd_t, buf: [*]u8, buf_len: usize, cookie: dircookie_t, bufused: *usize) errno_t; | ||
| 41 | pub extern "wasi_unstable" fn fd_renumber(from: fd_t, to: fd_t) errno_t; | ||
| 42 | pub extern "wasi_unstable" fn fd_seek(fd: fd_t, offset: filedelta_t, whence: whence_t, newoffset: *filesize_t) errno_t; | ||
| 43 | pub extern "wasi_unstable" fn fd_sync(fd: fd_t) errno_t; | ||
| 44 | pub extern "wasi_unstable" fn fd_tell(fd: fd_t, newoffset: *filesize_t) errno_t; | ||
| 45 | pub extern "wasi_unstable" fn fd_write(fd: fd_t, iovs: [*]const ciovec_t, iovs_len: usize, nwritten: *usize) errno_t; | ||
| 35 | 46 | ||
| 36 | const err = fd_read(@bitCast(fd_t, isize(fd)), &iovs, 1, &nread); | 47 | pub extern "wasi_unstable" fn fd_fdstat_get(fd: fd_t, buf: *fdstat_t) errno_t; |
| 37 | if (err == ESUCCESS) { | 48 | pub extern "wasi_unstable" fn fd_fdstat_set_flags(fd: fd_t, flags: fdflags_t) errno_t; |
| 38 | return nread; | 49 | pub 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)); | 51 | pub extern "wasi_unstable" fn fd_filestat_get(fd: fd_t, buf: *filestat_t) errno_t; |
| 41 | } | 52 | pub extern "wasi_unstable" fn fd_filestat_set_size(fd: fd_t, st_size: filesize_t) errno_t; |
| 42 | } | 53 | pub extern "wasi_unstable" fn fd_filestat_set_times(fd: fd_t, st_atim: timestamp_t, st_mtim: timestamp_t, fstflags: fstflags_t) errno_t; |
| 54 | |||
| 55 | pub extern "wasi_unstable" fn fd_prestat_get(fd: fd_t, buf: *prestat_t) errno_t; | ||
| 56 | pub extern "wasi_unstable" fn fd_prestat_dir_name(fd: fd_t, path: [*]u8, path_len: usize) errno_t; | ||
| 57 | |||
| 58 | pub extern "wasi_unstable" fn path_create_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t; | ||
| 59 | pub extern "wasi_unstable" fn path_filestat_get(fd: fd_t, flags: lookupflags_t, path: [*]const u8, path_len: usize, buf: *filestat_t) errno_t; | ||
| 60 | pub extern "wasi_unstable" fn path_filestat_set_times(fd: fd_t, flags: lookupflags_t, path: [*]const u8, path_len: usize, st_atim: timestamp_t, st_mtim: timestamp_t, fstflags: fstflags_t) errno_t; | ||
| 61 | pub extern "wasi_unstable" fn path_link(old_fd: fd_t, old_flags: lookupflags_t, old_path: [*]const u8, old_path_len: usize, new_fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t; | ||
| 62 | pub extern "wasi_unstable" fn path_open(dirfd: fd_t, dirflags: lookupflags_t, path: [*]const u8, path_len: usize, oflags: oflags_t, fs_rights_base: rights_t, fs_rights_inheriting: rights_t, fs_flags: fdflags_t, fd: *fd_t) errno_t; | ||
| 63 | pub extern "wasi_unstable" fn path_readlink(fd: fd_t, path: [*]const u8, path_len: usize, buf: [*]u8, buf_len: usize, bufused: *usize) errno_t; | ||
| 64 | pub extern "wasi_unstable" fn path_remove_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t; | ||
| 65 | pub extern "wasi_unstable" fn path_rename(old_fd: fd_t, old_path: [*]const u8, old_path_len: usize, new_fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t; | ||
| 66 | pub extern "wasi_unstable" fn path_symlink(old_path: [*]const u8, old_path_len: usize, fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t; | ||
| 67 | pub extern "wasi_unstable" fn path_unlink_file(fd: fd_t, path: [*]const u8, path_len: usize) errno_t; | ||
| 68 | |||
| 69 | pub extern "wasi_unstable" fn poll_oneoff(in: *const subscription_t, out: *event_t, nsubscriptions: usize, nevents: *usize) errno_t; | ||
| 70 | |||
| 71 | pub extern "wasi_unstable" fn proc_exit(rval: exitcode_t) noreturn; | ||
| 72 | pub extern "wasi_unstable" fn proc_raise(sig: signal_t) errno_t; | ||
| 73 | |||
| 74 | pub extern "wasi_unstable" fn random_get(buf: [*]u8, buf_len: usize) errno_t; | ||
| 75 | |||
| 76 | pub extern "wasi_unstable" fn sched_yield() errno_t; | ||
| 77 | |||
| 78 | pub extern "wasi_unstable" fn sock_recv(sock: fd_t, ri_data: *const iovec_t, ri_data_len: usize, ri_flags: riflags_t, ro_datalen: *usize, ro_flags: *roflags_t) errno_t; | ||
| 79 | pub extern "wasi_unstable" fn sock_send(sock: fd_t, si_data: *const ciovec_t, si_data_len: usize, si_flags: siflags_t, so_datalen: *usize) errno_t; | ||
| 80 | pub 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 | |||
| 4 | pub const advice_t = u8; | ||
| 5 | pub const ADVICE_NORMAL: advice_t = 0; | ||
| 6 | pub const ADVICE_SEQUENTIAL: advice_t = 1; | ||
| 7 | pub const ADVICE_RANDOM: advice_t = 2; | ||
| 8 | pub const ADVICE_WILLNEED: advice_t = 3; | ||
| 9 | pub const ADVICE_DONTNEED: advice_t = 4; | ||
| 10 | pub const ADVICE_NOREUSE: advice_t = 5; | ||
| 11 | |||
| 12 | pub const ciovec_t = extern struct { | ||
| 13 | buf: [*]const u8, | ||
| 14 | buf_len: usize, | ||
| 15 | }; | ||
| 16 | |||
| 17 | pub const clockid_t = u32; | ||
| 18 | pub const CLOCK_REALTIME: clockid_t = 0; | ||
| 19 | pub const CLOCK_MONOTONIC: clockid_t = 1; | ||
| 20 | pub const CLOCK_PROCESS_CPUTIME_ID: clockid_t = 2; | ||
| 21 | pub const CLOCK_THREAD_CPUTIME_ID: clockid_t = 3; | ||
| 22 | |||
| 23 | pub const device_t = u64; | ||
| 24 | |||
| 25 | pub const dircookie_t = u64; | ||
| 26 | pub const DIRCOOKIE_START: dircookie_t = 0; | ||
| 27 | |||
| 28 | pub 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 | |||
| 35 | pub const errno_t = u16; | ||
| 36 | pub const ESUCCESS: errno_t = 0; | ||
| 37 | pub const E2BIG: errno_t = 1; | ||
| 38 | pub const EACCES: errno_t = 2; | ||
| 39 | pub const EADDRINUSE: errno_t = 3; | ||
| 40 | pub const EADDRNOTAVAIL: errno_t = 4; | ||
| 41 | pub const EAFNOSUPPORT: errno_t = 5; | ||
| 42 | pub const EAGAIN: errno_t = 6; | ||
| 43 | pub const EALREADY: errno_t = 7; | ||
| 44 | pub const EBADF: errno_t = 8; | ||
| 45 | pub const EBADMSG: errno_t = 9; | ||
| 46 | pub const EBUSY: errno_t = 10; | ||
| 47 | pub const ECANCELED: errno_t = 11; | ||
| 48 | pub const ECHILD: errno_t = 12; | ||
| 49 | pub const ECONNABORTED: errno_t = 13; | ||
| 50 | pub const ECONNREFUSED: errno_t = 14; | ||
| 51 | pub const ECONNRESET: errno_t = 15; | ||
| 52 | pub const EDEADLK: errno_t = 16; | ||
| 53 | pub const EDESTADDRREQ: errno_t = 17; | ||
| 54 | pub const EDOM: errno_t = 18; | ||
| 55 | pub const EDQUOT: errno_t = 19; | ||
| 56 | pub const EEXIST: errno_t = 20; | ||
| 57 | pub const EFAULT: errno_t = 21; | ||
| 58 | pub const EFBIG: errno_t = 22; | ||
| 59 | pub const EHOSTUNREACH: errno_t = 23; | ||
| 60 | pub const EIDRM: errno_t = 24; | ||
| 61 | pub const EILSEQ: errno_t = 25; | ||
| 62 | pub const EINPROGRESS: errno_t = 26; | ||
| 63 | pub const EINTR: errno_t = 27; | ||
| 64 | pub const EINVAL: errno_t = 28; | ||
| 65 | pub const EIO: errno_t = 29; | ||
| 66 | pub const EISCONN: errno_t = 30; | ||
| 67 | pub const EISDIR: errno_t = 31; | ||
| 68 | pub const ELOOP: errno_t = 32; | ||
| 69 | pub const EMFILE: errno_t = 33; | ||
| 70 | pub const EMLINK: errno_t = 34; | ||
| 71 | pub const EMSGSIZE: errno_t = 35; | ||
| 72 | pub const EMULTIHOP: errno_t = 36; | ||
| 73 | pub const ENAMETOOLONG: errno_t = 37; | ||
| 74 | pub const ENETDOWN: errno_t = 38; | ||
| 75 | pub const ENETRESET: errno_t = 39; | ||
| 76 | pub const ENETUNREACH: errno_t = 40; | ||
| 77 | pub const ENFILE: errno_t = 41; | ||
| 78 | pub const ENOBUFS: errno_t = 42; | ||
| 79 | pub const ENODEV: errno_t = 43; | ||
| 80 | pub const ENOENT: errno_t = 44; | ||
| 81 | pub const ENOEXEC: errno_t = 45; | ||
| 82 | pub const ENOLCK: errno_t = 46; | ||
| 83 | pub const ENOLINK: errno_t = 47; | ||
| 84 | pub const ENOMEM: errno_t = 48; | ||
| 85 | pub const ENOMSG: errno_t = 49; | ||
| 86 | pub const ENOPROTOOPT: errno_t = 50; | ||
| 87 | pub const ENOSPC: errno_t = 51; | ||
| 88 | pub const ENOSYS: errno_t = 52; | ||
| 89 | pub const ENOTCONN: errno_t = 53; | ||
| 90 | pub const ENOTDIR: errno_t = 54; | ||
| 91 | pub const ENOTEMPTY: errno_t = 55; | ||
| 92 | pub const ENOTRECOVERABLE: errno_t = 56; | ||
| 93 | pub const ENOTSOCK: errno_t = 57; | ||
| 94 | pub const ENOTSUP: errno_t = 58; | ||
| 95 | pub const ENOTTY: errno_t = 59; | ||
| 96 | pub const ENXIO: errno_t = 60; | ||
| 97 | pub const EOVERFLOW: errno_t = 61; | ||
| 98 | pub const EOWNERDEAD: errno_t = 62; | ||
| 99 | pub const EPERM: errno_t = 63; | ||
| 100 | pub const EPIPE: errno_t = 64; | ||
| 101 | pub const EPROTO: errno_t = 65; | ||
| 102 | pub const EPROTONOSUPPORT: errno_t = 66; | ||
| 103 | pub const EPROTOTYPE: errno_t = 67; | ||
| 104 | pub const ERANGE: errno_t = 68; | ||
| 105 | pub const EROFS: errno_t = 69; | ||
| 106 | pub const ESPIPE: errno_t = 70; | ||
| 107 | pub const ESRCH: errno_t = 71; | ||
| 108 | pub const ESTALE: errno_t = 72; | ||
| 109 | pub const ETIMEDOUT: errno_t = 73; | ||
| 110 | pub const ETXTBSY: errno_t = 74; | ||
| 111 | pub const EXDEV: errno_t = 75; | ||
| 112 | pub const ENOTCAPABLE: errno_t = 76; | ||
| 113 | |||
| 114 | pub 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 | |||
| 126 | pub const eventrwflags_t = u16; | ||
| 127 | pub const EVENT_FD_READWRITE_HANGUP: eventrwflags_t = 0x0001; | ||
| 128 | |||
| 129 | pub const eventtype_t = u8; | ||
| 130 | pub const EVENTTYPE_CLOCK: eventtype_t = 0; | ||
| 131 | pub const EVENTTYPE_FD_READ: eventtype_t = 1; | ||
| 132 | pub const EVENTTYPE_FD_WRITE: eventtype_t = 2; | ||
| 133 | |||
| 134 | pub const exitcode_t = u32; | ||
| 135 | |||
| 136 | pub const fd_t = u32; | ||
| 137 | |||
| 138 | pub const fdflags_t = u16; | ||
| 139 | pub const FDFLAG_APPEND: fdflags_t = 0x0001; | ||
| 140 | pub const FDFLAG_DSYNC: fdflags_t = 0x0002; | ||
| 141 | pub const FDFLAG_NONBLOCK: fdflags_t = 0x0004; | ||
| 142 | pub const FDFLAG_RSYNC: fdflags_t = 0x0008; | ||
| 143 | pub const FDFLAG_SYNC: fdflags_t = 0x0010; | ||
| 144 | |||
| 145 | const 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 | |||
| 152 | pub const filedelta_t = i64; | ||
| 153 | |||
| 154 | pub const filesize_t = u64; | ||
| 155 | |||
| 156 | pub 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 | |||
| 167 | pub const filetype_t = u8; | ||
| 168 | pub const FILETYPE_UNKNOWN: filetype_t = 0; | ||
| 169 | pub const FILETYPE_BLOCK_DEVICE: filetype_t = 1; | ||
| 170 | pub const FILETYPE_CHARACTER_DEVICE: filetype_t = 2; | ||
| 171 | pub const FILETYPE_DIRECTORY: filetype_t = 3; | ||
| 172 | pub const FILETYPE_REGULAR_FILE: filetype_t = 4; | ||
| 173 | pub const FILETYPE_SOCKET_DGRAM: filetype_t = 5; | ||
| 174 | pub const FILETYPE_SOCKET_STREAM: filetype_t = 6; | ||
| 175 | pub const FILETYPE_SYMBOLIC_LINK: filetype_t = 7; | ||
| 176 | |||
| 177 | pub const fstflags_t = u16; | ||
| 178 | pub const FILESTAT_SET_ATIM: fstflags_t = 0x0001; | ||
| 179 | pub const FILESTAT_SET_ATIM_NOW: fstflags_t = 0x0002; | ||
| 180 | pub const FILESTAT_SET_MTIM: fstflags_t = 0x0004; | ||
| 181 | pub const FILESTAT_SET_MTIM_NOW: fstflags_t = 0x0008; | ||
| 182 | |||
| 183 | pub const inode_t = u64; | ||
| 184 | |||
| 185 | pub const iovec_t = extern struct { | ||
| 186 | buf: [*]u8, | ||
| 187 | buf_len: usize, | ||
| 188 | }; | ||
| 189 | |||
| 190 | pub const linkcount_t = u32; | ||
| 191 | |||
| 192 | pub const lookupflags_t = u32; | ||
| 193 | pub const LOOKUP_SYMLINK_FOLLOW: lookupflags_t = 0x00000001; | ||
| 194 | |||
| 195 | pub const oflags_t = u16; | ||
| 196 | pub const O_CREAT: oflags_t = 0x0001; | ||
| 197 | pub const O_DIRECTORY: oflags_t = 0x0002; | ||
| 198 | pub const O_EXCL: oflags_t = 0x0004; | ||
| 199 | pub const O_TRUNC: oflags_t = 0x0008; | ||
| 200 | |||
| 201 | pub const preopentype_t = u8; | ||
| 202 | pub const PREOPENTYPE_DIR: preopentype_t = 0; | ||
| 203 | |||
| 204 | pub 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 | |||
| 213 | pub const riflags_t = u16; | ||
| 214 | pub const SOCK_RECV_PEEK: riflags_t = 0x0001; | ||
| 215 | pub const SOCK_RECV_WAITALL: riflags_t = 0x0002; | ||
| 216 | |||
| 217 | pub const rights_t = u64; | ||
| 218 | pub const RIGHT_FD_DATASYNC: rights_t = 0x0000000000000001; | ||
| 219 | pub const RIGHT_FD_READ: rights_t = 0x0000000000000002; | ||
| 220 | pub const RIGHT_FD_SEEK: rights_t = 0x0000000000000004; | ||
| 221 | pub const RIGHT_FD_FDSTAT_SET_FLAGS: rights_t = 0x0000000000000008; | ||
| 222 | pub const RIGHT_FD_SYNC: rights_t = 0x0000000000000010; | ||
| 223 | pub const RIGHT_FD_TELL: rights_t = 0x0000000000000020; | ||
| 224 | pub const RIGHT_FD_WRITE: rights_t = 0x0000000000000040; | ||
| 225 | pub const RIGHT_FD_ADVISE: rights_t = 0x0000000000000080; | ||
| 226 | pub const RIGHT_FD_ALLOCATE: rights_t = 0x0000000000000100; | ||
| 227 | pub const RIGHT_PATH_CREATE_DIRECTORY: rights_t = 0x0000000000000200; | ||
| 228 | pub const RIGHT_PATH_CREATE_FILE: rights_t = 0x0000000000000400; | ||
| 229 | pub const RIGHT_PATH_LINK_SOURCE: rights_t = 0x0000000000000800; | ||
| 230 | pub const RIGHT_PATH_LINK_TARGET: rights_t = 0x0000000000001000; | ||
| 231 | pub const RIGHT_PATH_OPEN: rights_t = 0x0000000000002000; | ||
| 232 | pub const RIGHT_FD_READDIR: rights_t = 0x0000000000004000; | ||
| 233 | pub const RIGHT_PATH_READLINK: rights_t = 0x0000000000008000; | ||
| 234 | pub const RIGHT_PATH_RENAME_SOURCE: rights_t = 0x0000000000010000; | ||
| 235 | pub const RIGHT_PATH_RENAME_TARGET: rights_t = 0x0000000000020000; | ||
| 236 | pub const RIGHT_PATH_FILESTAT_GET: rights_t = 0x0000000000040000; | ||
| 237 | pub const RIGHT_PATH_FILESTAT_SET_SIZE: rights_t = 0x0000000000080000; | ||
| 238 | pub const RIGHT_PATH_FILESTAT_SET_TIMES: rights_t = 0x0000000000100000; | ||
| 239 | pub const RIGHT_FD_FILESTAT_GET: rights_t = 0x0000000000200000; | ||
| 240 | pub const RIGHT_FD_FILESTAT_SET_SIZE: rights_t = 0x0000000000400000; | ||
| 241 | pub const RIGHT_FD_FILESTAT_SET_TIMES: rights_t = 0x0000000000800000; | ||
| 242 | pub const RIGHT_PATH_SYMLINK: rights_t = 0x0000000001000000; | ||
| 243 | pub const RIGHT_PATH_REMOVE_DIRECTORY: rights_t = 0x0000000002000000; | ||
| 244 | pub const RIGHT_PATH_UNLINK_FILE: rights_t = 0x0000000004000000; | ||
| 245 | pub const RIGHT_POLL_FD_READWRITE: rights_t = 0x0000000008000000; | ||
| 246 | pub const RIGHT_SOCK_SHUTDOWN: rights_t = 0x0000000010000000; | ||
| 247 | |||
| 248 | pub const roflags_t = u16; | ||
| 249 | pub const SOCK_RECV_DATA_TRUNCATED: roflags_t = 0x0001; | ||
| 250 | |||
| 251 | pub const sdflags_t = u8; | ||
| 252 | pub const SHUT_RD: sdflags_t = 0x01; | ||
| 253 | pub const SHUT_WR: sdflags_t = 0x02; | ||
| 254 | |||
| 255 | pub const siflags_t = u16; | ||
| 256 | |||
| 257 | pub const signal_t = u8; | ||
| 258 | pub const SIGHUP: signal_t = 1; | ||
| 259 | pub const SIGINT: signal_t = 2; | ||
| 260 | pub const SIGQUIT: signal_t = 3; | ||
| 261 | pub const SIGILL: signal_t = 4; | ||
| 262 | pub const SIGTRAP: signal_t = 5; | ||
| 263 | pub const SIGABRT: signal_t = 6; | ||
| 264 | pub const SIGBUS: signal_t = 7; | ||
| 265 | pub const SIGFPE: signal_t = 8; | ||
| 266 | pub const SIGKILL: signal_t = 9; | ||
| 267 | pub const SIGUSR1: signal_t = 10; | ||
| 268 | pub const SIGSEGV: signal_t = 11; | ||
| 269 | pub const SIGUSR2: signal_t = 12; | ||
| 270 | pub const SIGPIPE: signal_t = 13; | ||
| 271 | pub const SIGALRM: signal_t = 14; | ||
| 272 | pub const SIGTERM: signal_t = 15; | ||
| 273 | pub const SIGCHLD: signal_t = 16; | ||
| 274 | pub const SIGCONT: signal_t = 17; | ||
| 275 | pub const SIGSTOP: signal_t = 18; | ||
| 276 | pub const SIGTSTP: signal_t = 19; | ||
| 277 | pub const SIGTTIN: signal_t = 20; | ||
| 278 | pub const SIGTTOU: signal_t = 21; | ||
| 279 | pub const SIGURG: signal_t = 22; | ||
| 280 | pub const SIGXCPU: signal_t = 23; | ||
| 281 | pub const SIGXFSZ: signal_t = 24; | ||
| 282 | pub const SIGVTALRM: signal_t = 25; | ||
| 283 | pub const SIGPROF: signal_t = 26; | ||
| 284 | pub const SIGWINCH: signal_t = 27; | ||
| 285 | pub const SIGPOLL: signal_t = 28; | ||
| 286 | pub const SIGPWR: signal_t = 29; | ||
| 287 | pub const SIGSYS: signal_t = 30; | ||
| 288 | |||
| 289 | pub const subclockflags_t = u16; | ||
| 290 | pub const SUBSCRIPTION_CLOCK_ABSTIME: subclockflags_t = 0x0001; | ||
| 291 | |||
| 292 | pub 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 | |||
| 309 | pub const timestamp_t = u64; | ||
| 310 | |||
| 311 | pub const userdata_t = u64; | ||
| 312 | |||
| 313 | pub const whence_t = u8; | ||
| 314 | pub const WHENCE_CUR: whence_t = 0; | ||
| 315 | pub const WHENCE_END: whence_t = 1; | ||
| 316 | pub const WHENCE_SET: whence_t = 2; | ||
| 317 | |||
| 318 | pub extern "wasi_unstable" fn args_get(argv: [*][*]u8, argv_buf: [*]u8) errno_t; | ||
| 319 | pub extern "wasi_unstable" fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t; | ||
| 320 | |||
| 321 | pub extern "wasi_unstable" fn clock_res_get(clock_id: clockid_t, resolution: *timestamp_t) errno_t; | ||
| 322 | pub extern "wasi_unstable" fn clock_time_get(clock_id: clockid_t, precision: timestamp_t, timestamp: *timestamp_t) errno_t; | ||
| 323 | |||
| 324 | pub extern "wasi_unstable" fn environ_get(environ: [*]?[*]u8, environ_buf: [*]u8) errno_t; | ||
| 325 | pub extern "wasi_unstable" fn environ_sizes_get(environ_count: *usize, environ_buf_size: *usize) errno_t; | ||
| 326 | |||
| 327 | pub extern "wasi_unstable" fn fd_advise(fd: fd_t, offset: filesize_t, len: filesize_t, advice: advice_t) errno_t; | ||
| 328 | pub extern "wasi_unstable" fn fd_allocate(fd: fd_t, offset: filesize_t, len: filesize_t) errno_t; | ||
| 329 | pub extern "wasi_unstable" fn fd_close(fd: fd_t) errno_t; | ||
| 330 | pub extern "wasi_unstable" fn fd_datasync(fd: fd_t) errno_t; | ||
| 331 | pub extern "wasi_unstable" fn fd_pread(fd: fd_t, iovs: *const iovec_t, iovs_len: usize, offset: filesize_t, nread: *usize) errno_t; | ||
| 332 | pub extern "wasi_unstable" fn fd_pwrite(fd: fd_t, iovs: *const ciovec_t, iovs_len: usize, offset: filesize_t, nwritten: *usize) errno_t; | ||
| 333 | pub extern "wasi_unstable" fn fd_read(fd: fd_t, iovs: *const iovec_t, iovs_len: usize, nread: *usize) errno_t; | ||
| 334 | pub extern "wasi_unstable" fn fd_readdir(fd: fd_t, buf: [*]u8, buf_len: usize, cookie: dircookie_t, bufused: *usize) errno_t; | ||
| 335 | pub extern "wasi_unstable" fn fd_renumber(from: fd_t, to: fd_t) errno_t; | ||
| 336 | pub extern "wasi_unstable" fn fd_seek(fd: fd_t, offset: filedelta_t, whence: whence_t, newoffset: *filesize_t) errno_t; | ||
| 337 | pub extern "wasi_unstable" fn fd_sync(fd: fd_t) errno_t; | ||
| 338 | pub extern "wasi_unstable" fn fd_tell(fd: fd_t, newoffset: *filesize_t) errno_t; | ||
| 339 | pub extern "wasi_unstable" fn fd_write(fd: fd_t, iovs: *const ciovec_t, iovs_len: usize, nwritten: *usize) errno_t; | ||
| 340 | |||
| 341 | pub extern "wasi_unstable" fn fd_fdstat_get(fd: fd_t, buf: *fdstat_t) errno_t; | ||
| 342 | pub extern "wasi_unstable" fn fd_fdstat_set_flags(fd: fd_t, flags: fdflags_t) errno_t; | ||
| 343 | pub extern "wasi_unstable" fn fd_fdstat_set_rights(fd: fd_t, fs_rights_base: rights_t, fs_rights_inheriting: rights_t) errno_t; | ||
| 344 | |||
| 345 | pub extern "wasi_unstable" fn fd_filestat_get(fd: fd_t, buf: *filestat_t) errno_t; | ||
| 346 | pub extern "wasi_unstable" fn fd_filestat_set_size(fd: fd_t, st_size: filesize_t) errno_t; | ||
| 347 | pub extern "wasi_unstable" fn fd_filestat_set_times(fd: fd_t, st_atim: timestamp_t, st_mtim: timestamp_t, fstflags: fstflags_t) errno_t; | ||
| 348 | |||
| 349 | pub extern "wasi_unstable" fn fd_prestat_get(fd: fd_t, buf: *prestat_t) errno_t; | ||
| 350 | pub extern "wasi_unstable" fn fd_prestat_dir_name(fd: fd_t, path: [*]u8, path_len: usize) errno_t; | ||
| 351 | |||
| 352 | pub extern "wasi_unstable" fn path_create_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t; | ||
| 353 | pub extern "wasi_unstable" fn path_filestat_get(fd: fd_t, flags: lookupflags_t, path: [*]const u8, path_len: usize, buf: *filestat_t) errno_t; | ||
| 354 | pub extern "wasi_unstable" fn path_filestat_set_times(fd: fd_t, flags: lookupflags_t, path: [*]const u8, path_len: usize, st_atim: timestamp_t, st_mtim: timestamp_t, fstflags: fstflags_t) errno_t; | ||
| 355 | pub extern "wasi_unstable" fn path_link(old_fd: fd_t, old_flags: lookupflags_t, old_path: [*]const u8, old_path_len: usize, new_fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t; | ||
| 356 | pub extern "wasi_unstable" fn path_open(dirfd: fd_t, dirflags: lookupflags_t, path: [*]const u8, path_len: usize, oflags: oflags_t, fs_rights_base: rights_t, fs_rights_inheriting: rights_t, fs_flags: fdflags_t, fd: *fd_t) errno_t; | ||
| 357 | pub extern "wasi_unstable" fn path_readlink(fd: fd_t, path: [*]const u8, path_len: usize, buf: [*]u8, buf_len: usize, bufused: *usize) errno_t; | ||
| 358 | pub extern "wasi_unstable" fn path_remove_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t; | ||
| 359 | pub extern "wasi_unstable" fn path_rename(old_fd: fd_t, old_path: [*]const u8, old_path_len: usize, new_fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t; | ||
| 360 | pub extern "wasi_unstable" fn path_symlink(old_path: [*]const u8, old_path_len: usize, fd: fd_t, new_path: [*]const u8, new_path_len: usize) errno_t; | ||
| 361 | pub extern "wasi_unstable" fn path_unlink_file(fd: fd_t, path: [*]const u8, path_len: usize) errno_t; | ||
| 362 | |||
| 363 | pub extern "wasi_unstable" fn poll_oneoff(in: *const subscription_t, out: *event_t, nsubscriptions: usize, nevents: *usize) errno_t; | ||
| 364 | |||
| 365 | pub extern "wasi_unstable" fn proc_exit(rval: exitcode_t) noreturn; | ||
| 366 | pub extern "wasi_unstable" fn proc_raise(sig: signal_t) errno_t; | ||
| 367 | |||
| 368 | pub extern "wasi_unstable" fn random_get(buf: [*]u8, buf_len: usize) errno_t; | ||
| 369 | |||
| 370 | pub extern "wasi_unstable" fn sched_yield() errno_t; | ||
| 371 | |||
| 372 | pub extern "wasi_unstable" fn sock_recv(sock: fd_t, ri_data: *const iovec_t, ri_data_len: usize, ri_flags: riflags_t, ro_datalen: *usize, ro_flags: *roflags_t) errno_t; | ||
| 373 | pub extern "wasi_unstable" fn sock_send(sock: fd_t, si_data: *const ciovec_t, si_data_len: usize, si_flags: siflags_t, so_datalen: *usize) errno_t; | ||
| 374 | pub 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 | |||
| 7 | const builtin = @import("builtin"); | ||
| 1 | const std = @import("../std.zig"); | 8 | const std = @import("../std.zig"); |
| 9 | const mem = std.mem; | ||
| 2 | const assert = std.debug.assert; | 10 | const assert = std.debug.assert; |
| 11 | const math = std.math; | ||
| 3 | const maxInt = std.math.maxInt; | 12 | const maxInt = std.math.maxInt; |
| 4 | 13 | ||
| 5 | pub use @import("windows/advapi32.zig"); | 14 | pub const is_the_target = builtin.os == .windows; |
| 6 | pub use @import("windows/kernel32.zig"); | 15 | pub const advapi32 = @import("windows/advapi32.zig"); |
| 7 | pub use @import("windows/ntdll.zig"); | 16 | pub const kernel32 = @import("windows/kernel32.zig"); |
| 8 | pub use @import("windows/ole32.zig"); | 17 | pub const ntdll = @import("windows/ntdll.zig"); |
| 9 | pub use @import("windows/shell32.zig"); | 18 | pub const ole32 = @import("windows/ole32.zig"); |
| 10 | 19 | pub const shell32 = @import("windows/shell32.zig"); | |
| 11 | test "import" { | 20 | |
| 12 | _ = @import("windows/util.zig"); | 21 | pub use @import("windows/bits.zig"); |
| 13 | } | 22 | |
| 14 | 23 | pub const CreateFileError = error{ | |
| 15 | pub const ERROR = @import("windows/error.zig"); | 24 | SharingViolation, |
| 16 | 25 | PathAlreadyExists, | |
| 17 | pub const SHORT = c_short; | 26 | |
| 18 | pub const BOOL = c_int; | 27 | /// When any of the path components can not be found or the file component can not |
| 19 | pub const BOOLEAN = BYTE; | 28 | /// be found. Some operating systems distinguish between path components not found and |
| 20 | pub const BYTE = u8; | 29 | /// file components not found, but they are collapsed into FileNotFound to gain |
| 21 | pub const CHAR = u8; | 30 | /// consistency across operating systems. |
| 22 | pub const DWORD = u32; | 31 | FileNotFound, |
| 23 | pub const FLOAT = f32; | 32 | |
| 24 | pub const HANDLE = *c_void; | 33 | AccessDenied, |
| 25 | pub const HCRYPTPROV = ULONG_PTR; | 34 | PipeBusy, |
| 26 | pub const HINSTANCE = *@OpaqueType(); | 35 | NameTooLong, |
| 27 | pub const HMODULE = *@OpaqueType(); | 36 | |
| 28 | pub const FARPROC = *@OpaqueType(); | 37 | /// On Windows, file paths must be valid Unicode. |
| 29 | pub const INT = c_int; | 38 | InvalidUtf8, |
| 30 | pub const LPBYTE = *BYTE; | 39 | |
| 31 | pub const LPCH = *CHAR; | 40 | /// On Windows, file paths cannot contain these characters: |
| 32 | pub const LPCSTR = [*]const CHAR; | 41 | /// '/', '*', '?', '"', '<', '>', '|' |
| 33 | pub const LPCTSTR = [*]const TCHAR; | 42 | BadPathName, |
| 34 | pub const LPCVOID = *const c_void; | 43 | |
| 35 | pub const LPDWORD = *DWORD; | 44 | Unexpected, |
| 36 | pub const LPSTR = [*]CHAR; | ||
| 37 | pub const LPTSTR = if (UNICODE) LPWSTR else LPSTR; | ||
| 38 | pub const LPVOID = *c_void; | ||
| 39 | pub const LPWSTR = [*]WCHAR; | ||
| 40 | pub const LPCWSTR = [*]const WCHAR; | ||
| 41 | pub const PVOID = *c_void; | ||
| 42 | pub const PWSTR = [*]WCHAR; | ||
| 43 | pub const SIZE_T = usize; | ||
| 44 | pub const TCHAR = if (UNICODE) WCHAR else u8; | ||
| 45 | pub const UINT = c_uint; | ||
| 46 | pub const ULONG_PTR = usize; | ||
| 47 | pub const DWORD_PTR = ULONG_PTR; | ||
| 48 | pub const UNICODE = false; | ||
| 49 | pub const WCHAR = u16; | ||
| 50 | pub const WORD = u16; | ||
| 51 | pub const LARGE_INTEGER = i64; | ||
| 52 | pub const ULONG = u32; | ||
| 53 | pub const LONG = i32; | ||
| 54 | pub const ULONGLONG = u64; | ||
| 55 | pub const LONGLONG = i64; | ||
| 56 | |||
| 57 | pub const TRUE = 1; | ||
| 58 | pub const FALSE = 0; | ||
| 59 | |||
| 60 | /// The standard input device. Initially, this is the console input buffer, CONIN$. | ||
| 61 | pub const STD_INPUT_HANDLE = maxInt(DWORD) - 10 + 1; | ||
| 62 | |||
| 63 | /// The standard output device. Initially, this is the active console screen buffer, CONOUT$. | ||
| 64 | pub const STD_OUTPUT_HANDLE = maxInt(DWORD) - 11 + 1; | ||
| 65 | |||
| 66 | /// The standard error device. Initially, this is the active console screen buffer, CONOUT$. | ||
| 67 | pub const STD_ERROR_HANDLE = maxInt(DWORD) - 12 + 1; | ||
| 68 | |||
| 69 | pub const INVALID_HANDLE_VALUE = @intToPtr(HANDLE, maxInt(usize)); | ||
| 70 | |||
| 71 | pub const INVALID_FILE_ATTRIBUTES = DWORD(maxInt(DWORD)); | ||
| 72 | |||
| 73 | pub const OVERLAPPED = extern struct { | ||
| 74 | Internal: ULONG_PTR, | ||
| 75 | InternalHigh: ULONG_PTR, | ||
| 76 | Offset: DWORD, | ||
| 77 | OffsetHigh: DWORD, | ||
| 78 | hEvent: ?HANDLE, | ||
| 79 | }; | ||
| 80 | pub const LPOVERLAPPED = *OVERLAPPED; | ||
| 81 | |||
| 82 | pub const MAX_PATH = 260; | ||
| 83 | |||
| 84 | // TODO issue #305 | ||
| 85 | pub const FILE_INFO_BY_HANDLE_CLASS = u32; | ||
| 86 | pub const FileBasicInfo = 0; | ||
| 87 | pub const FileStandardInfo = 1; | ||
| 88 | pub const FileNameInfo = 2; | ||
| 89 | pub const FileRenameInfo = 3; | ||
| 90 | pub const FileDispositionInfo = 4; | ||
| 91 | pub const FileAllocationInfo = 5; | ||
| 92 | pub const FileEndOfFileInfo = 6; | ||
| 93 | pub const FileStreamInfo = 7; | ||
| 94 | pub const FileCompressionInfo = 8; | ||
| 95 | pub const FileAttributeTagInfo = 9; | ||
| 96 | pub const FileIdBothDirectoryInfo = 10; | ||
| 97 | pub const FileIdBothDirectoryRestartInfo = 11; | ||
| 98 | pub const FileIoPriorityHintInfo = 12; | ||
| 99 | pub const FileRemoteProtocolInfo = 13; | ||
| 100 | pub const FileFullDirectoryInfo = 14; | ||
| 101 | pub const FileFullDirectoryRestartInfo = 15; | ||
| 102 | pub const FileStorageInfo = 16; | ||
| 103 | pub const FileAlignmentInfo = 17; | ||
| 104 | pub const FileIdInfo = 18; | ||
| 105 | pub const FileIdExtdDirectoryInfo = 19; | ||
| 106 | pub const FileIdExtdDirectoryRestartInfo = 20; | ||
| 107 | |||
| 108 | pub const FILE_NAME_INFO = extern struct { | ||
| 109 | FileNameLength: DWORD, | ||
| 110 | FileName: [1]WCHAR, | ||
| 111 | }; | 45 | }; |
| 112 | 46 | ||
| 113 | /// Return the normalized drive name. This is the default. | 47 | pub fn CreateFile( |
| 114 | pub 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 | |||
| 60 | pub 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 | |||
| 88 | pub const CreatePipeError = error{Unexpected}; | ||
| 115 | 89 | ||
| 116 | /// Return the opened file name (not normalized). | 90 | pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) CreatePipeError!void { |
| 117 | pub 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 | } | ||
| 118 | 97 | ||
| 119 | /// Return the path with the drive letter. This is the default. | 98 | pub const SetHandleInformationError = error{Unexpected}; |
| 120 | pub const VOLUME_NAME_DOS = 0x0; | ||
| 121 | 99 | ||
| 122 | /// Return the path with a volume GUID path instead of the drive name. | 100 | pub fn SetHandleInformation(h: HANDLE, mask: DWORD, flags: DWORD) SetHandleInformationError!void { |
| 123 | pub 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 | } | ||
| 124 | 107 | ||
| 125 | /// Return the path with no drive information. | 108 | pub const RtlGenRandomError = error{Unexpected}; |
| 126 | pub const VOLUME_NAME_NONE = 0x4; | ||
| 127 | 109 | ||
| 128 | /// Return the path with the volume device path. | 110 | /// Call RtlGenRandom() instead of CryptGetRandom() on Windows |
| 129 | pub 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 | ||
| 113 | pub 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 | } | ||
| 130 | 120 | ||
| 131 | pub const SECURITY_ATTRIBUTES = extern struct { | 121 | pub const WaitForSingleObjectError = error{ |
| 132 | nLength: DWORD, | 122 | WaitAbandoned, |
| 133 | lpSecurityDescriptor: ?*c_void, | 123 | WaitTimeOut, |
| 134 | bInheritHandle: BOOL, | 124 | Unexpected, |
| 135 | }; | 125 | }; |
| 136 | pub const PSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES; | 126 | |
| 137 | pub const LPSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES; | 127 | pub fn WaitForSingleObject(handle: HANDLE, milliseconds: DWORD) WaitForSingleObjectError!void { |
| 138 | 128 | switch (kernel32.WaitForSingleObject(handle, milliseconds)) { | |
| 139 | pub const GENERIC_READ = 0x80000000; | 129 | WAIT_ABANDONED => return error.WaitAbandoned, |
| 140 | pub const GENERIC_WRITE = 0x40000000; | 130 | WAIT_OBJECT_0 => return, |
| 141 | pub const GENERIC_EXECUTE = 0x20000000; | 131 | WAIT_TIMEOUT => return error.WaitTimeOut, |
| 142 | pub const GENERIC_ALL = 0x10000000; | 132 | WAIT_FAILED => switch (kernel32.GetLastError()) { |
| 143 | 133 | else => |err| return unexpectedError(err), | |
| 144 | pub const FILE_SHARE_DELETE = 0x00000004; | 134 | }, |
| 145 | pub const FILE_SHARE_READ = 0x00000001; | 135 | else => return error.Unexpected, |
| 146 | pub const FILE_SHARE_WRITE = 0x00000002; | 136 | } |
| 147 | 137 | } | |
| 148 | pub const CREATE_ALWAYS = 2; | 138 | |
| 149 | pub const CREATE_NEW = 1; | 139 | pub const FindFirstFileError = error{ |
| 150 | pub const OPEN_ALWAYS = 4; | 140 | FileNotFound, |
| 151 | pub const OPEN_EXISTING = 3; | 141 | InvalidUtf8, |
| 152 | pub const TRUNCATE_EXISTING = 5; | 142 | BadPathName, |
| 153 | 143 | NameTooLong, | |
| 154 | pub const FILE_ATTRIBUTE_ARCHIVE = 0x20; | 144 | Unexpected, |
| 155 | pub const FILE_ATTRIBUTE_COMPRESSED = 0x800; | ||
| 156 | pub const FILE_ATTRIBUTE_DEVICE = 0x40; | ||
| 157 | pub const FILE_ATTRIBUTE_DIRECTORY = 0x10; | ||
| 158 | pub const FILE_ATTRIBUTE_ENCRYPTED = 0x4000; | ||
| 159 | pub const FILE_ATTRIBUTE_HIDDEN = 0x2; | ||
| 160 | pub const FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x8000; | ||
| 161 | pub const FILE_ATTRIBUTE_NORMAL = 0x80; | ||
| 162 | pub const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000; | ||
| 163 | pub const FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x20000; | ||
| 164 | pub const FILE_ATTRIBUTE_OFFLINE = 0x1000; | ||
| 165 | pub const FILE_ATTRIBUTE_READONLY = 0x1; | ||
| 166 | pub const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x400000; | ||
| 167 | pub const FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x40000; | ||
| 168 | pub const FILE_ATTRIBUTE_REPARSE_POINT = 0x400; | ||
| 169 | pub const FILE_ATTRIBUTE_SPARSE_FILE = 0x200; | ||
| 170 | pub const FILE_ATTRIBUTE_SYSTEM = 0x4; | ||
| 171 | pub const FILE_ATTRIBUTE_TEMPORARY = 0x100; | ||
| 172 | pub const FILE_ATTRIBUTE_VIRTUAL = 0x10000; | ||
| 173 | |||
| 174 | pub const PROCESS_INFORMATION = extern struct { | ||
| 175 | hProcess: HANDLE, | ||
| 176 | hThread: HANDLE, | ||
| 177 | dwProcessId: DWORD, | ||
| 178 | dwThreadId: DWORD, | ||
| 179 | }; | 145 | }; |
| 180 | 146 | ||
| 181 | pub const STARTUPINFOW = extern struct { | 147 | pub 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, | 162 | pub const FindNextFileError = error{Unexpected}; |
| 197 | hStdInput: ?HANDLE, | 163 | |
| 198 | hStdOutput: ?HANDLE, | 164 | /// Returns `true` if there was another file, `false` otherwise. |
| 199 | hStdError: ?HANDLE, | 165 | pub 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 | |||
| 175 | pub const CreateIoCompletionPortError = error{Unexpected}; | ||
| 176 | |||
| 177 | pub 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 | |||
| 192 | pub const PostQueuedCompletionStatusError = error{Unexpected}; | ||
| 193 | |||
| 194 | pub 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 | |||
| 207 | pub const GetQueuedCompletionStatusResult = enum { | ||
| 208 | Normal, | ||
| 209 | Aborted, | ||
| 210 | Cancelled, | ||
| 211 | EOF, | ||
| 200 | }; | 212 | }; |
| 201 | 213 | ||
| 202 | pub const STARTF_FORCEONFEEDBACK = 0x00000040; | 214 | pub fn GetQueuedCompletionStatus( |
| 203 | pub const STARTF_FORCEOFFFEEDBACK = 0x00000080; | 215 | completion_port: HANDLE, |
| 204 | pub const STARTF_PREVENTPINNING = 0x00002000; | 216 | bytes_transferred_count: *DWORD, |
| 205 | pub const STARTF_RUNFULLSCREEN = 0x00000020; | 217 | lpCompletionKey: *usize, |
| 206 | pub const STARTF_TITLEISAPPID = 0x00001000; | 218 | lpOverlapped: *?*OVERLAPPED, |
| 207 | pub const STARTF_TITLEISLINKNAME = 0x00000800; | 219 | dwMilliseconds: DWORD, |
| 208 | pub const STARTF_UNTRUSTEDSOURCE = 0x00008000; | 220 | ) GetQueuedCompletionStatusResult { |
| 209 | pub const STARTF_USECOUNTCHARS = 0x00000008; | 221 | if (kernel32.GetQueuedCompletionStatus( |
| 210 | pub const STARTF_USEFILLATTRIBUTE = 0x00000010; | 222 | completion_port, |
| 211 | pub const STARTF_USEHOTKEY = 0x00000200; | 223 | bytes_transferred_count, |
| 212 | pub const STARTF_USEPOSITION = 0x00000004; | 224 | lpCompletionKey, |
| 213 | pub const STARTF_USESHOWWINDOW = 0x00000001; | 225 | lpOverlapped, |
| 214 | pub const STARTF_USESIZE = 0x00000002; | 226 | dwMilliseconds, |
| 215 | pub const STARTF_USESTDHANDLES = 0x00000100; | 227 | ) == FALSE) { |
| 216 | 228 | switch (kernel32.GetLastError()) { | |
| 217 | pub const INFINITE = 4294967295; | 229 | ERROR.ABANDONED_WAIT_0 => return GetQueuedCompletionStatusResult.Aborted, |
| 218 | 230 | ERROR.OPERATION_ABORTED => return GetQueuedCompletionStatusResult.Cancelled, | |
| 219 | pub const WAIT_ABANDONED = 0x00000080; | 231 | ERROR.HANDLE_EOF => return GetQueuedCompletionStatusResult.EOF, |
| 220 | pub const WAIT_OBJECT_0 = 0x00000000; | 232 | else => |err| { |
| 221 | pub const WAIT_TIMEOUT = 0x00000102; | 233 | if (std.debug.runtime_safety) { |
| 222 | pub const WAIT_FAILED = 0xFFFFFFFF; | 234 | std.debug.panic("unexpected error: {}\n", err); |
| 223 | 235 | } | |
| 224 | pub const HANDLE_FLAG_INHERIT = 0x00000001; | 236 | }, |
| 225 | pub const HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x00000002; | 237 | } |
| 226 | 238 | } | |
| 227 | pub const MOVEFILE_COPY_ALLOWED = 2; | 239 | return GetQueuedCompletionStatusResult.Normal; |
| 228 | pub const MOVEFILE_CREATE_HARDLINK = 16; | 240 | } |
| 229 | pub const MOVEFILE_DELAY_UNTIL_REBOOT = 4; | 241 | |
| 230 | pub const MOVEFILE_FAIL_IF_NOT_TRACKABLE = 32; | 242 | pub fn CloseHandle(hObject: HANDLE) void { |
| 231 | pub const MOVEFILE_REPLACE_EXISTING = 1; | 243 | assert(kernel32.CloseHandle(hObject) != 0); |
| 232 | pub const MOVEFILE_WRITE_THROUGH = 8; | 244 | } |
| 233 | 245 | ||
| 234 | pub const FILE_BEGIN = 0; | 246 | pub fn FindClose(hFindFile: HANDLE) void { |
| 235 | pub const FILE_CURRENT = 1; | 247 | assert(kernel32.FindClose(hFindFile) != 0); |
| 236 | pub const FILE_END = 2; | 248 | } |
| 237 | 249 | ||
| 238 | pub const HEAP_CREATE_ENABLE_EXECUTE = 0x00040000; | 250 | pub const ReadFileError = error{Unexpected}; |
| 239 | pub const HEAP_GENERATE_EXCEPTIONS = 0x00000004; | 251 | |
| 240 | pub const HEAP_NO_SERIALIZE = 0x00000001; | 252 | pub fn ReadFile(in_hFile: HANDLE, buffer: []u8) ReadFileError!usize { |
| 241 | 253 | var index: usize = 0; | |
| 242 | // AllocationType values | 254 | while (index < buffer.len) { |
| 243 | pub const MEM_COMMIT = 0x1000; | 255 | const want_read_count = @intCast(DWORD, math.min(DWORD(maxInt(DWORD)), buffer.len - index)); |
| 244 | pub const MEM_RESERVE = 0x2000; | 256 | var amt_read: DWORD = undefined; |
| 245 | pub const MEM_RESET = 0x80000; | 257 | if (kernel32.ReadFile(in_hFile, buffer.ptr + index, want_read_count, &amt_read, null) == 0) { |
| 246 | pub const MEM_RESET_UNDO = 0x1000000; | 258 | switch (kernel32.GetLastError()) { |
| 247 | pub const MEM_LARGE_PAGES = 0x20000000; | 259 | ERROR.OPERATION_ABORTED => continue, |
| 248 | pub const MEM_PHYSICAL = 0x400000; | 260 | ERROR.BROKEN_PIPE => return index, |
| 249 | pub const MEM_TOP_DOWN = 0x100000; | 261 | else => |err| return unexpectedError(err), |
| 250 | pub const MEM_WRITE_WATCH = 0x200000; | 262 | } |
| 251 | 263 | } | |
| 252 | // Protect values | 264 | if (amt_read == 0) return index; |
| 253 | pub const PAGE_EXECUTE = 0x10; | 265 | index += amt_read; |
| 254 | pub const PAGE_EXECUTE_READ = 0x20; | 266 | } |
| 255 | pub const PAGE_EXECUTE_READWRITE = 0x40; | 267 | return index; |
| 256 | pub const PAGE_EXECUTE_WRITECOPY = 0x80; | 268 | } |
| 257 | pub const PAGE_NOACCESS = 0x01; | 269 | |
| 258 | pub const PAGE_READONLY = 0x02; | 270 | pub const WriteFileError = error{ |
| 259 | pub const PAGE_READWRITE = 0x04; | 271 | SystemResources, |
| 260 | pub const PAGE_WRITECOPY = 0x08; | 272 | OperationAborted, |
| 261 | pub const PAGE_TARGETS_INVALID = 0x40000000; | 273 | BrokenPipe, |
| 262 | pub const PAGE_TARGETS_NO_UPDATE = 0x40000000; // Same as PAGE_TARGETS_INVALID | 274 | Unexpected, |
| 263 | pub const PAGE_GUARD = 0x100; | ||
| 264 | pub const PAGE_NOCACHE = 0x200; | ||
| 265 | pub const PAGE_WRITECOMBINE = 0x400; | ||
| 266 | |||
| 267 | // FreeType values | ||
| 268 | pub const MEM_COALESCE_PLACEHOLDERS = 0x1; | ||
| 269 | pub const MEM_RESERVE_PLACEHOLDERS = 0x2; | ||
| 270 | pub const MEM_DECOMMIT = 0x4000; | ||
| 271 | pub const MEM_RELEASE = 0x8000; | ||
| 272 | |||
| 273 | pub const PTHREAD_START_ROUTINE = extern fn (LPVOID) DWORD; | ||
| 274 | pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE; | ||
| 275 | |||
| 276 | pub 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 | }; |
| 288 | 276 | ||
| 289 | pub 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, | 279 | pub 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 | |||
| 295 | pub const GetCurrentDirectoryError = error{ | ||
| 296 | NameTooLong, | ||
| 297 | Unexpected, | ||
| 292 | }; | 298 | }; |
| 293 | 299 | ||
| 294 | pub const SYSTEM_INFO = extern struct { | 300 | /// The result is a slice of `buffer`, indexed from 0. |
| 295 | anon1: extern union { | 301 | pub 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 | |||
| 323 | pub const CreateSymbolicLinkError = error{Unexpected}; | ||
| 324 | |||
| 325 | pub 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 | |||
| 335 | pub 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 | |||
| 347 | pub const DeleteFileError = error{ | ||
| 348 | FileNotFound, | ||
| 349 | AccessDenied, | ||
| 350 | NameTooLong, | ||
| 351 | Unexpected, | ||
| 311 | }; | 352 | }; |
| 312 | 353 | ||
| 313 | pub const HRESULT = c_long; | 354 | pub fn DeleteFile(filename: []const u8) DeleteFileError!void { |
| 355 | const filename_w = try sliceToPrefixedFileW(filename); | ||
| 356 | return DeleteFileW(&filename_w); | ||
| 357 | } | ||
| 314 | 358 | ||
| 315 | pub const KNOWNFOLDERID = GUID; | 359 | pub fn DeleteFileW(filename: [*]const u16) DeleteFileError!void { |
| 316 | pub 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 | } | ||
| 321 | 370 | ||
| 322 | pub fn parse(str: []const u8) GUID { | 371 | pub const MoveFileError = error{Unexpected}; |
| 323 | var guid: GUID = undefined; | ||
| 324 | var index: usize = 0; | ||
| 325 | assert(str[index] == '{'); | ||
| 326 | index += 1; | ||
| 327 | 372 | ||
| 328 | guid.Data1 = std.fmt.parseUnsigned(c_ulong, str[index .. index + 8], 16) catch unreachable; | 373 | pub 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 | } | ||
| 330 | 378 | ||
| 331 | assert(str[index] == '-'); | 379 | pub 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 | } | ||
| 333 | 386 | ||
| 334 | guid.Data2 = std.fmt.parseUnsigned(c_ushort, str[index .. index + 4], 16) catch unreachable; | 387 | pub const CreateDirectoryError = error{ |
| 335 | index += 4; | 388 | PathAlreadyExists, |
| 389 | FileNotFound, | ||
| 390 | Unexpected, | ||
| 391 | }; | ||
| 336 | 392 | ||
| 337 | assert(str[index] == '-'); | 393 | pub 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 | } | ||
| 339 | 397 | ||
| 340 | guid.Data3 = std.fmt.parseUnsigned(c_ushort, str[index .. index + 4], 16) catch unreachable; | 398 | pub 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 | } | ||
| 342 | 407 | ||
| 343 | assert(str[index] == '-'); | 408 | pub const RemoveDirectoryError = error{ |
| 344 | index += 1; | 409 | FileNotFound, |
| 410 | DirNotEmpty, | ||
| 411 | Unexpected, | ||
| 412 | }; | ||
| 345 | 413 | ||
| 346 | guid.Data4[0] = std.fmt.parseUnsigned(u8, str[index .. index + 2], 16) catch unreachable; | 414 | pub 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 | } |
| 350 | 418 | ||
| 351 | assert(str[index] == '-'); | 419 | pub 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 | } | ||
| 353 | 428 | ||
| 354 | var i: usize = 2; | 429 | pub 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 | |||
| 434 | pub 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 | |||
| 444 | pub const SetFilePointerError = error{Unexpected}; | ||
| 445 | |||
| 446 | /// The SetFilePointerEx function with the `dwMoveMethod` parameter set to `FILE_BEGIN`. | ||
| 447 | pub 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`. | ||
| 462 | pub 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`. | ||
| 473 | pub 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 | } | ||
| 359 | 482 | ||
| 360 | assert(str[index] == '}'); | 483 | /// The SetFilePointerEx function with parameters to get the current offset. |
| 361 | index += 1; | 484 | pub 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 | |||
| 498 | pub const GetFinalPathNameByHandleError = error{ | ||
| 499 | FileNotFound, | ||
| 500 | SystemResources, | ||
| 501 | NameTooLong, | ||
| 502 | Unexpected, | ||
| 364 | }; | 503 | }; |
| 365 | 504 | ||
| 366 | pub const FOLDERID_LocalAppData = GUID.parse("{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}"); | 505 | pub fn GetFinalPathNameByHandleW( |
| 367 | 506 | hFile: HANDLE, | |
| 368 | pub const KF_FLAG_DEFAULT = 0; | 507 | buf_ptr: [*]u16, |
| 369 | pub const KF_FLAG_NO_APPCONTAINER_REDIRECTION = 65536; | 508 | buf_len: DWORD, |
| 370 | pub const KF_FLAG_CREATE = 32768; | 509 | flags: DWORD, |
| 371 | pub const KF_FLAG_DONT_VERIFY = 16384; | 510 | ) GetFinalPathNameByHandleError!DWORD { |
| 372 | pub const KF_FLAG_DONT_UNEXPAND = 8192; | 511 | const rc = kernel32.GetFinalPathNameByHandleW(hFile, buf_ptr, buf_len, flags); |
| 373 | pub const KF_FLAG_NO_ALIAS = 4096; | 512 | if (rc == 0) { |
| 374 | pub const KF_FLAG_INIT = 2048; | 513 | switch (kernel32.GetLastError()) { |
| 375 | pub const KF_FLAG_DEFAULT_PATH = 1024; | 514 | ERROR.FILE_NOT_FOUND => return error.FileNotFound, |
| 376 | pub const KF_FLAG_NOT_PARENT_RELATIVE = 512; | 515 | ERROR.PATH_NOT_FOUND => return error.FileNotFound, |
| 377 | pub const KF_FLAG_SIMPLE_IDLIST = 256; | 516 | ERROR.NOT_ENOUGH_MEMORY => return error.SystemResources, |
| 378 | pub const KF_FLAG_ALIAS_ONLY = -2147483648; | 517 | ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong, |
| 379 | 518 | ERROR.INVALID_PARAMETER => unreachable, | |
| 380 | pub const S_OK = 0; | 519 | else => |err| return unexpectedError(err), |
| 381 | pub const E_NOTIMPL = @bitCast(c_long, c_ulong(0x80004001)); | 520 | } |
| 382 | pub const E_NOINTERFACE = @bitCast(c_long, c_ulong(0x80004002)); | 521 | } |
| 383 | pub const E_POINTER = @bitCast(c_long, c_ulong(0x80004003)); | 522 | return rc; |
| 384 | pub const E_ABORT = @bitCast(c_long, c_ulong(0x80004004)); | 523 | } |
| 385 | pub const E_FAIL = @bitCast(c_long, c_ulong(0x80004005)); | 524 | |
| 386 | pub const E_UNEXPECTED = @bitCast(c_long, c_ulong(0x8000FFFF)); | 525 | pub const GetFileSizeError = error{Unexpected}; |
| 387 | pub const E_ACCESSDENIED = @bitCast(c_long, c_ulong(0x80070005)); | 526 | |
| 388 | pub const E_HANDLE = @bitCast(c_long, c_ulong(0x80070006)); | 527 | pub fn GetFileSizeEx(hFile: HANDLE) GetFileSizeError!u64 { |
| 389 | pub const E_OUTOFMEMORY = @bitCast(c_long, c_ulong(0x8007000E)); | 528 | var file_size: LARGE_INTEGER = undefined; |
| 390 | pub const E_INVALIDARG = @bitCast(c_long, c_ulong(0x80070057)); | 529 | if (kernel32.GetFileSizeEx(hFile, &file_size) == 0) { |
| 391 | 530 | switch (kernel32.GetLastError()) { | |
| 392 | pub const FILE_FLAG_BACKUP_SEMANTICS = 0x02000000; | 531 | else => |err| return unexpectedError(err), |
| 393 | pub const FILE_FLAG_DELETE_ON_CLOSE = 0x04000000; | 532 | } |
| 394 | pub const FILE_FLAG_NO_BUFFERING = 0x20000000; | 533 | } |
| 395 | pub const FILE_FLAG_OPEN_NO_RECALL = 0x00100000; | 534 | return @bitCast(u64, file_size); |
| 396 | pub const FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000; | 535 | } |
| 397 | pub const FILE_FLAG_OVERLAPPED = 0x40000000; | 536 | |
| 398 | pub const FILE_FLAG_POSIX_SEMANTICS = 0x0100000; | 537 | pub const GetFileAttributesError = error{ |
| 399 | pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000; | 538 | FileNotFound, |
| 400 | pub const FILE_FLAG_SESSION_AWARE = 0x00800000; | 539 | PermissionDenied, |
| 401 | pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000; | 540 | Unexpected, |
| 402 | pub const FILE_FLAG_WRITE_THROUGH = 0x80000000; | 541 | }; |
| 403 | 542 | ||
| 404 | pub const SMALL_RECT = extern struct { | 543 | pub 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 | |
| 548 | pub 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 | |||
| 561 | const GetModuleFileNameError = error{Unexpected}; | ||
| 562 | |||
| 563 | pub 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 | |||
| 573 | pub const TerminateProcessError = error{Unexpected}; | ||
| 574 | |||
| 575 | pub 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 | |||
| 583 | pub const VirtualAllocError = error{Unexpected}; | ||
| 584 | |||
| 585 | pub 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 | |||
| 593 | pub fn VirtualFree(lpAddress: ?LPVOID, dwSize: usize, dwFreeType: DWORD) void { | ||
| 594 | assert(kernel32.VirtualFree(lpAddress, dwSize, dwFreeType) != 0); | ||
| 595 | } | ||
| 596 | |||
| 597 | pub const SetConsoleTextAttributeError = error{Unexpected}; | ||
| 598 | |||
| 599 | pub 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 | |||
| 607 | pub const GetEnvironmentStringsError = error{OutOfMemory}; | ||
| 608 | |||
| 609 | pub fn GetEnvironmentStringsW() GetEnvironmentStringsError![*]u16 { | ||
| 610 | return kernel32.GetEnvironmentStringsW() orelse return error.OutOfMemory; | ||
| 611 | } | ||
| 612 | |||
| 613 | pub fn FreeEnvironmentStringsW(penv: [*]u16) void { | ||
| 614 | assert(kernel32.FreeEnvironmentStringsW(penv) != 0); | ||
| 615 | } | ||
| 616 | |||
| 617 | pub const GetEnvironmentVariableError = error{ | ||
| 618 | EnvironmentVariableNotFound, | ||
| 619 | Unexpected, | ||
| 409 | }; | 620 | }; |
| 410 | 621 | ||
| 411 | pub const COORD = extern struct { | 622 | pub 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 | |||
| 633 | pub const CreateProcessError = error{ | ||
| 634 | FileNotFound, | ||
| 635 | InvalidName, | ||
| 636 | Unexpected, | ||
| 414 | }; | 637 | }; |
| 415 | 638 | ||
| 416 | pub const CREATE_UNICODE_ENVIRONMENT = 1024; | 639 | pub 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 | } | ||
| 417 | 672 | ||
| 418 | pub const TLS_OUT_OF_INDEXES = 4294967295; | 673 | pub const LoadLibraryError = error{ |
| 419 | pub 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 | }; |
| 427 | pub const IMAGE_TLS_DIRECTORY64 = IMAGE_TLS_DIRECTORY; | ||
| 428 | pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY; | ||
| 429 | 677 | ||
| 430 | pub const PIMAGE_TLS_CALLBACK = ?extern fn (PVOID, DWORD, PVOID) void; | 678 | pub 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 | |||
| 689 | pub fn FreeLibrary(hModule: HMODULE) void { | ||
| 690 | assert(kernel32.FreeLibrary(hModule) != 0); | ||
| 691 | } | ||
| 692 | |||
| 693 | pub 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 | |||
| 702 | pub 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 | |||
| 711 | pub 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 | |||
| 715 | pub fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: *c_void) void { | ||
| 716 | assert(kernel32.HeapFree(hHeap, dwFlags, lpMem) != 0); | ||
| 717 | } | ||
| 718 | |||
| 719 | pub fn HeapDestroy(hHeap: HANDLE) void { | ||
| 720 | assert(kernel32.HeapDestroy(hHeap) != 0); | ||
| 721 | } | ||
| 722 | |||
| 723 | pub fn cStrToPrefixedFileW(s: [*]const u8) ![PATH_MAX_WIDE + 1]u16 { | ||
| 724 | return sliceToPrefixedFileW(mem.toSliceConst(u8, s)); | ||
| 725 | } | ||
| 726 | |||
| 727 | pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 { | ||
| 728 | return sliceToPrefixedSuffixedFileW(s, []u16{0}); | ||
| 729 | } | ||
| 730 | |||
| 731 | pub 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. | ||
| 761 | pub 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 @@ |
| 1 | use @import("../windows.zig"); | 1 | use @import("bits.zig"); |
| 2 | |||
| 3 | pub const PROV_RSA_FULL = 1; | ||
| 4 | |||
| 5 | pub const REGSAM = ACCESS_MASK; | ||
| 6 | pub const ACCESS_MASK = DWORD; | ||
| 7 | pub const PHKEY = *HKEY; | ||
| 8 | pub const HKEY = *HKEY__; | ||
| 9 | pub const HKEY__ = extern struct { | ||
| 10 | unused: c_int, | ||
| 11 | }; | ||
| 12 | pub const LSTATUS = LONG; | ||
| 13 | 2 | ||
| 14 | pub extern "advapi32" stdcallcc fn RegOpenKeyExW( | 3 | pub 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 | |||
| 3 | const builtin = @import("builtin"); | ||
| 4 | const std = @import("../../std.zig"); | ||
| 5 | const assert = std.debug.assert; | ||
| 6 | const maxInt = std.math.maxInt; | ||
| 7 | |||
| 8 | pub const ERROR = @import("error.zig"); | ||
| 9 | |||
| 10 | /// The standard input device. Initially, this is the console input buffer, CONIN$. | ||
| 11 | pub const STD_INPUT_HANDLE = maxInt(DWORD) - 10 + 1; | ||
| 12 | |||
| 13 | /// The standard output device. Initially, this is the active console screen buffer, CONOUT$. | ||
| 14 | pub const STD_OUTPUT_HANDLE = maxInt(DWORD) - 11 + 1; | ||
| 15 | |||
| 16 | /// The standard error device. Initially, this is the active console screen buffer, CONOUT$. | ||
| 17 | pub const STD_ERROR_HANDLE = maxInt(DWORD) - 12 + 1; | ||
| 18 | |||
| 19 | pub const SHORT = c_short; | ||
| 20 | pub const BOOL = c_int; | ||
| 21 | pub const BOOLEAN = BYTE; | ||
| 22 | pub const BYTE = u8; | ||
| 23 | pub const CHAR = u8; | ||
| 24 | pub const DWORD = u32; | ||
| 25 | pub const FLOAT = f32; | ||
| 26 | pub const HANDLE = *c_void; | ||
| 27 | pub const HCRYPTPROV = ULONG_PTR; | ||
| 28 | pub const HINSTANCE = *@OpaqueType(); | ||
| 29 | pub const HMODULE = *@OpaqueType(); | ||
| 30 | pub const FARPROC = *@OpaqueType(); | ||
| 31 | pub const INT = c_int; | ||
| 32 | pub const LPBYTE = *BYTE; | ||
| 33 | pub const LPCH = *CHAR; | ||
| 34 | pub const LPCSTR = [*]const CHAR; | ||
| 35 | pub const LPCTSTR = [*]const TCHAR; | ||
| 36 | pub const LPCVOID = *const c_void; | ||
| 37 | pub const LPDWORD = *DWORD; | ||
| 38 | pub const LPSTR = [*]CHAR; | ||
| 39 | pub const LPTSTR = if (UNICODE) LPWSTR else LPSTR; | ||
| 40 | pub const LPVOID = *c_void; | ||
| 41 | pub const LPWSTR = [*]WCHAR; | ||
| 42 | pub const LPCWSTR = [*]const WCHAR; | ||
| 43 | pub const PVOID = *c_void; | ||
| 44 | pub const PWSTR = [*]WCHAR; | ||
| 45 | pub const SIZE_T = usize; | ||
| 46 | pub const TCHAR = if (UNICODE) WCHAR else u8; | ||
| 47 | pub const UINT = c_uint; | ||
| 48 | pub const ULONG_PTR = usize; | ||
| 49 | pub const DWORD_PTR = ULONG_PTR; | ||
| 50 | pub const UNICODE = false; | ||
| 51 | pub const WCHAR = u16; | ||
| 52 | pub const WORD = u16; | ||
| 53 | pub const LARGE_INTEGER = i64; | ||
| 54 | pub const ULONG = u32; | ||
| 55 | pub const LONG = i32; | ||
| 56 | pub const ULONGLONG = u64; | ||
| 57 | pub const LONGLONG = i64; | ||
| 58 | |||
| 59 | pub const TRUE = 1; | ||
| 60 | pub const FALSE = 0; | ||
| 61 | |||
| 62 | pub const INVALID_HANDLE_VALUE = @intToPtr(HANDLE, maxInt(usize)); | ||
| 63 | |||
| 64 | pub const INVALID_FILE_ATTRIBUTES = DWORD(maxInt(DWORD)); | ||
| 65 | |||
| 66 | pub const OVERLAPPED = extern struct { | ||
| 67 | Internal: ULONG_PTR, | ||
| 68 | InternalHigh: ULONG_PTR, | ||
| 69 | Offset: DWORD, | ||
| 70 | OffsetHigh: DWORD, | ||
| 71 | hEvent: ?HANDLE, | ||
| 72 | }; | ||
| 73 | pub const LPOVERLAPPED = *OVERLAPPED; | ||
| 74 | |||
| 75 | pub const MAX_PATH = 260; | ||
| 76 | |||
| 77 | // TODO issue #305 | ||
| 78 | pub const FILE_INFO_BY_HANDLE_CLASS = u32; | ||
| 79 | pub const FileBasicInfo = 0; | ||
| 80 | pub const FileStandardInfo = 1; | ||
| 81 | pub const FileNameInfo = 2; | ||
| 82 | pub const FileRenameInfo = 3; | ||
| 83 | pub const FileDispositionInfo = 4; | ||
| 84 | pub const FileAllocationInfo = 5; | ||
| 85 | pub const FileEndOfFileInfo = 6; | ||
| 86 | pub const FileStreamInfo = 7; | ||
| 87 | pub const FileCompressionInfo = 8; | ||
| 88 | pub const FileAttributeTagInfo = 9; | ||
| 89 | pub const FileIdBothDirectoryInfo = 10; | ||
| 90 | pub const FileIdBothDirectoryRestartInfo = 11; | ||
| 91 | pub const FileIoPriorityHintInfo = 12; | ||
| 92 | pub const FileRemoteProtocolInfo = 13; | ||
| 93 | pub const FileFullDirectoryInfo = 14; | ||
| 94 | pub const FileFullDirectoryRestartInfo = 15; | ||
| 95 | pub const FileStorageInfo = 16; | ||
| 96 | pub const FileAlignmentInfo = 17; | ||
| 97 | pub const FileIdInfo = 18; | ||
| 98 | pub const FileIdExtdDirectoryInfo = 19; | ||
| 99 | pub const FileIdExtdDirectoryRestartInfo = 20; | ||
| 100 | |||
| 101 | pub 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. | ||
| 107 | pub const FILE_NAME_NORMALIZED = 0x0; | ||
| 108 | |||
| 109 | /// Return the opened file name (not normalized). | ||
| 110 | pub const FILE_NAME_OPENED = 0x8; | ||
| 111 | |||
| 112 | /// Return the path with the drive letter. This is the default. | ||
| 113 | pub const VOLUME_NAME_DOS = 0x0; | ||
| 114 | |||
| 115 | /// Return the path with a volume GUID path instead of the drive name. | ||
| 116 | pub const VOLUME_NAME_GUID = 0x1; | ||
| 117 | |||
| 118 | /// Return the path with no drive information. | ||
| 119 | pub const VOLUME_NAME_NONE = 0x4; | ||
| 120 | |||
| 121 | /// Return the path with the volume device path. | ||
| 122 | pub const VOLUME_NAME_NT = 0x2; | ||
| 123 | |||
| 124 | pub const SECURITY_ATTRIBUTES = extern struct { | ||
| 125 | nLength: DWORD, | ||
| 126 | lpSecurityDescriptor: ?*c_void, | ||
| 127 | bInheritHandle: BOOL, | ||
| 128 | }; | ||
| 129 | pub const PSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES; | ||
| 130 | pub const LPSECURITY_ATTRIBUTES = *SECURITY_ATTRIBUTES; | ||
| 131 | |||
| 132 | pub const GENERIC_READ = 0x80000000; | ||
| 133 | pub const GENERIC_WRITE = 0x40000000; | ||
| 134 | pub const GENERIC_EXECUTE = 0x20000000; | ||
| 135 | pub const GENERIC_ALL = 0x10000000; | ||
| 136 | |||
| 137 | pub const FILE_SHARE_DELETE = 0x00000004; | ||
| 138 | pub const FILE_SHARE_READ = 0x00000001; | ||
| 139 | pub const FILE_SHARE_WRITE = 0x00000002; | ||
| 140 | |||
| 141 | pub const CREATE_ALWAYS = 2; | ||
| 142 | pub const CREATE_NEW = 1; | ||
| 143 | pub const OPEN_ALWAYS = 4; | ||
| 144 | pub const OPEN_EXISTING = 3; | ||
| 145 | pub const TRUNCATE_EXISTING = 5; | ||
| 146 | |||
| 147 | pub const FILE_ATTRIBUTE_ARCHIVE = 0x20; | ||
| 148 | pub const FILE_ATTRIBUTE_COMPRESSED = 0x800; | ||
| 149 | pub const FILE_ATTRIBUTE_DEVICE = 0x40; | ||
| 150 | pub const FILE_ATTRIBUTE_DIRECTORY = 0x10; | ||
| 151 | pub const FILE_ATTRIBUTE_ENCRYPTED = 0x4000; | ||
| 152 | pub const FILE_ATTRIBUTE_HIDDEN = 0x2; | ||
| 153 | pub const FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x8000; | ||
| 154 | pub const FILE_ATTRIBUTE_NORMAL = 0x80; | ||
| 155 | pub const FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000; | ||
| 156 | pub const FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x20000; | ||
| 157 | pub const FILE_ATTRIBUTE_OFFLINE = 0x1000; | ||
| 158 | pub const FILE_ATTRIBUTE_READONLY = 0x1; | ||
| 159 | pub const FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x400000; | ||
| 160 | pub const FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x40000; | ||
| 161 | pub const FILE_ATTRIBUTE_REPARSE_POINT = 0x400; | ||
| 162 | pub const FILE_ATTRIBUTE_SPARSE_FILE = 0x200; | ||
| 163 | pub const FILE_ATTRIBUTE_SYSTEM = 0x4; | ||
| 164 | pub const FILE_ATTRIBUTE_TEMPORARY = 0x100; | ||
| 165 | pub const FILE_ATTRIBUTE_VIRTUAL = 0x10000; | ||
| 166 | |||
| 167 | pub const PROCESS_INFORMATION = extern struct { | ||
| 168 | hProcess: HANDLE, | ||
| 169 | hThread: HANDLE, | ||
| 170 | dwProcessId: DWORD, | ||
| 171 | dwThreadId: DWORD, | ||
| 172 | }; | ||
| 173 | |||
| 174 | pub 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 | |||
| 195 | pub const STARTF_FORCEONFEEDBACK = 0x00000040; | ||
| 196 | pub const STARTF_FORCEOFFFEEDBACK = 0x00000080; | ||
| 197 | pub const STARTF_PREVENTPINNING = 0x00002000; | ||
| 198 | pub const STARTF_RUNFULLSCREEN = 0x00000020; | ||
| 199 | pub const STARTF_TITLEISAPPID = 0x00001000; | ||
| 200 | pub const STARTF_TITLEISLINKNAME = 0x00000800; | ||
| 201 | pub const STARTF_UNTRUSTEDSOURCE = 0x00008000; | ||
| 202 | pub const STARTF_USECOUNTCHARS = 0x00000008; | ||
| 203 | pub const STARTF_USEFILLATTRIBUTE = 0x00000010; | ||
| 204 | pub const STARTF_USEHOTKEY = 0x00000200; | ||
| 205 | pub const STARTF_USEPOSITION = 0x00000004; | ||
| 206 | pub const STARTF_USESHOWWINDOW = 0x00000001; | ||
| 207 | pub const STARTF_USESIZE = 0x00000002; | ||
| 208 | pub const STARTF_USESTDHANDLES = 0x00000100; | ||
| 209 | |||
| 210 | pub const INFINITE = 4294967295; | ||
| 211 | |||
| 212 | pub const WAIT_ABANDONED = 0x00000080; | ||
| 213 | pub const WAIT_OBJECT_0 = 0x00000000; | ||
| 214 | pub const WAIT_TIMEOUT = 0x00000102; | ||
| 215 | pub const WAIT_FAILED = 0xFFFFFFFF; | ||
| 216 | |||
| 217 | pub const HANDLE_FLAG_INHERIT = 0x00000001; | ||
| 218 | pub const HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x00000002; | ||
| 219 | |||
| 220 | pub const MOVEFILE_COPY_ALLOWED = 2; | ||
| 221 | pub const MOVEFILE_CREATE_HARDLINK = 16; | ||
| 222 | pub const MOVEFILE_DELAY_UNTIL_REBOOT = 4; | ||
| 223 | pub const MOVEFILE_FAIL_IF_NOT_TRACKABLE = 32; | ||
| 224 | pub const MOVEFILE_REPLACE_EXISTING = 1; | ||
| 225 | pub const MOVEFILE_WRITE_THROUGH = 8; | ||
| 226 | |||
| 227 | pub const FILE_BEGIN = 0; | ||
| 228 | pub const FILE_CURRENT = 1; | ||
| 229 | pub const FILE_END = 2; | ||
| 230 | |||
| 231 | pub const HEAP_CREATE_ENABLE_EXECUTE = 0x00040000; | ||
| 232 | pub const HEAP_GENERATE_EXCEPTIONS = 0x00000004; | ||
| 233 | pub const HEAP_NO_SERIALIZE = 0x00000001; | ||
| 234 | |||
| 235 | // AllocationType values | ||
| 236 | pub const MEM_COMMIT = 0x1000; | ||
| 237 | pub const MEM_RESERVE = 0x2000; | ||
| 238 | pub const MEM_RESET = 0x80000; | ||
| 239 | pub const MEM_RESET_UNDO = 0x1000000; | ||
| 240 | pub const MEM_LARGE_PAGES = 0x20000000; | ||
| 241 | pub const MEM_PHYSICAL = 0x400000; | ||
| 242 | pub const MEM_TOP_DOWN = 0x100000; | ||
| 243 | pub const MEM_WRITE_WATCH = 0x200000; | ||
| 244 | |||
| 245 | // Protect values | ||
| 246 | pub const PAGE_EXECUTE = 0x10; | ||
| 247 | pub const PAGE_EXECUTE_READ = 0x20; | ||
| 248 | pub const PAGE_EXECUTE_READWRITE = 0x40; | ||
| 249 | pub const PAGE_EXECUTE_WRITECOPY = 0x80; | ||
| 250 | pub const PAGE_NOACCESS = 0x01; | ||
| 251 | pub const PAGE_READONLY = 0x02; | ||
| 252 | pub const PAGE_READWRITE = 0x04; | ||
| 253 | pub const PAGE_WRITECOPY = 0x08; | ||
| 254 | pub const PAGE_TARGETS_INVALID = 0x40000000; | ||
| 255 | pub const PAGE_TARGETS_NO_UPDATE = 0x40000000; // Same as PAGE_TARGETS_INVALID | ||
| 256 | pub const PAGE_GUARD = 0x100; | ||
| 257 | pub const PAGE_NOCACHE = 0x200; | ||
| 258 | pub const PAGE_WRITECOMBINE = 0x400; | ||
| 259 | |||
| 260 | // FreeType values | ||
| 261 | pub const MEM_COALESCE_PLACEHOLDERS = 0x1; | ||
| 262 | pub const MEM_RESERVE_PLACEHOLDERS = 0x2; | ||
| 263 | pub const MEM_DECOMMIT = 0x4000; | ||
| 264 | pub const MEM_RELEASE = 0x8000; | ||
| 265 | |||
| 266 | pub const PTHREAD_START_ROUTINE = extern fn (LPVOID) DWORD; | ||
| 267 | pub const LPTHREAD_START_ROUTINE = PTHREAD_START_ROUTINE; | ||
| 268 | |||
| 269 | pub 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 | |||
| 282 | pub const FILETIME = extern struct { | ||
| 283 | dwLowDateTime: DWORD, | ||
| 284 | dwHighDateTime: DWORD, | ||
| 285 | }; | ||
| 286 | |||
| 287 | pub 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 | |||
| 306 | pub const HRESULT = c_long; | ||
| 307 | |||
| 308 | pub const KNOWNFOLDERID = GUID; | ||
| 309 | pub 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 | |||
| 359 | pub const FOLDERID_LocalAppData = GUID.parse("{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}"); | ||
| 360 | |||
| 361 | pub const KF_FLAG_DEFAULT = 0; | ||
| 362 | pub const KF_FLAG_NO_APPCONTAINER_REDIRECTION = 65536; | ||
| 363 | pub const KF_FLAG_CREATE = 32768; | ||
| 364 | pub const KF_FLAG_DONT_VERIFY = 16384; | ||
| 365 | pub const KF_FLAG_DONT_UNEXPAND = 8192; | ||
| 366 | pub const KF_FLAG_NO_ALIAS = 4096; | ||
| 367 | pub const KF_FLAG_INIT = 2048; | ||
| 368 | pub const KF_FLAG_DEFAULT_PATH = 1024; | ||
| 369 | pub const KF_FLAG_NOT_PARENT_RELATIVE = 512; | ||
| 370 | pub const KF_FLAG_SIMPLE_IDLIST = 256; | ||
| 371 | pub const KF_FLAG_ALIAS_ONLY = -2147483648; | ||
| 372 | |||
| 373 | pub const S_OK = 0; | ||
| 374 | pub const E_NOTIMPL = @bitCast(c_long, c_ulong(0x80004001)); | ||
| 375 | pub const E_NOINTERFACE = @bitCast(c_long, c_ulong(0x80004002)); | ||
| 376 | pub const E_POINTER = @bitCast(c_long, c_ulong(0x80004003)); | ||
| 377 | pub const E_ABORT = @bitCast(c_long, c_ulong(0x80004004)); | ||
| 378 | pub const E_FAIL = @bitCast(c_long, c_ulong(0x80004005)); | ||
| 379 | pub const E_UNEXPECTED = @bitCast(c_long, c_ulong(0x8000FFFF)); | ||
| 380 | pub const E_ACCESSDENIED = @bitCast(c_long, c_ulong(0x80070005)); | ||
| 381 | pub const E_HANDLE = @bitCast(c_long, c_ulong(0x80070006)); | ||
| 382 | pub const E_OUTOFMEMORY = @bitCast(c_long, c_ulong(0x8007000E)); | ||
| 383 | pub const E_INVALIDARG = @bitCast(c_long, c_ulong(0x80070057)); | ||
| 384 | |||
| 385 | pub const FILE_FLAG_BACKUP_SEMANTICS = 0x02000000; | ||
| 386 | pub const FILE_FLAG_DELETE_ON_CLOSE = 0x04000000; | ||
| 387 | pub const FILE_FLAG_NO_BUFFERING = 0x20000000; | ||
| 388 | pub const FILE_FLAG_OPEN_NO_RECALL = 0x00100000; | ||
| 389 | pub const FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000; | ||
| 390 | pub const FILE_FLAG_OVERLAPPED = 0x40000000; | ||
| 391 | pub const FILE_FLAG_POSIX_SEMANTICS = 0x0100000; | ||
| 392 | pub const FILE_FLAG_RANDOM_ACCESS = 0x10000000; | ||
| 393 | pub const FILE_FLAG_SESSION_AWARE = 0x00800000; | ||
| 394 | pub const FILE_FLAG_SEQUENTIAL_SCAN = 0x08000000; | ||
| 395 | pub const FILE_FLAG_WRITE_THROUGH = 0x80000000; | ||
| 396 | |||
| 397 | pub const SMALL_RECT = extern struct { | ||
| 398 | Left: SHORT, | ||
| 399 | Top: SHORT, | ||
| 400 | Right: SHORT, | ||
| 401 | Bottom: SHORT, | ||
| 402 | }; | ||
| 403 | |||
| 404 | pub const COORD = extern struct { | ||
| 405 | X: SHORT, | ||
| 406 | Y: SHORT, | ||
| 407 | }; | ||
| 408 | |||
| 409 | pub const CREATE_UNICODE_ENVIRONMENT = 1024; | ||
| 410 | |||
| 411 | pub const TLS_OUT_OF_INDEXES = 4294967295; | ||
| 412 | pub 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 | }; | ||
| 420 | pub const IMAGE_TLS_DIRECTORY64 = IMAGE_TLS_DIRECTORY; | ||
| 421 | pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY; | ||
| 422 | |||
| 423 | pub const PIMAGE_TLS_CALLBACK = ?extern fn (PVOID, DWORD, PVOID) void; | ||
| 424 | |||
| 425 | pub const PROV_RSA_FULL = 1; | ||
| 426 | |||
| 427 | pub const REGSAM = ACCESS_MASK; | ||
| 428 | pub const ACCESS_MASK = DWORD; | ||
| 429 | pub const PHKEY = *HKEY; | ||
| 430 | pub const HKEY = *HKEY__; | ||
| 431 | pub const HKEY__ = extern struct { | ||
| 432 | unused: c_int, | ||
| 433 | }; | ||
| 434 | pub const LSTATUS = LONG; | ||
| 435 | |||
| 436 | pub const FILE_NOTIFY_INFORMATION = extern struct { | ||
| 437 | NextEntryOffset: DWORD, | ||
| 438 | Action: DWORD, | ||
| 439 | FileNameLength: DWORD, | ||
| 440 | FileName: [1]WCHAR, | ||
| 441 | }; | ||
| 442 | |||
| 443 | pub const FILE_ACTION_ADDED = 0x00000001; | ||
| 444 | pub const FILE_ACTION_REMOVED = 0x00000002; | ||
| 445 | pub const FILE_ACTION_MODIFIED = 0x00000003; | ||
| 446 | pub const FILE_ACTION_RENAMED_OLD_NAME = 0x00000004; | ||
| 447 | pub const FILE_ACTION_RENAMED_NEW_NAME = 0x00000005; | ||
| 448 | |||
| 449 | pub const LPOVERLAPPED_COMPLETION_ROUTINE = ?extern fn (DWORD, DWORD, *OVERLAPPED) void; | ||
| 450 | |||
| 451 | pub const FILE_LIST_DIRECTORY = 1; | ||
| 452 | |||
| 453 | pub const FILE_NOTIFY_CHANGE_CREATION = 64; | ||
| 454 | pub const FILE_NOTIFY_CHANGE_SIZE = 8; | ||
| 455 | pub const FILE_NOTIFY_CHANGE_SECURITY = 256; | ||
| 456 | pub const FILE_NOTIFY_CHANGE_LAST_ACCESS = 32; | ||
| 457 | pub const FILE_NOTIFY_CHANGE_LAST_WRITE = 16; | ||
| 458 | pub const FILE_NOTIFY_CHANGE_DIR_NAME = 2; | ||
| 459 | pub const FILE_NOTIFY_CHANGE_FILE_NAME = 1; | ||
| 460 | pub const FILE_NOTIFY_CHANGE_ATTRIBUTES = 4; | ||
| 461 | |||
| 462 | pub 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 | |||
| 470 | pub const FOREGROUND_BLUE = 1; | ||
| 471 | pub const FOREGROUND_GREEN = 2; | ||
| 472 | pub const FOREGROUND_RED = 4; | ||
| 473 | pub const FOREGROUND_INTENSITY = 8; | ||
| 474 | |||
| 475 | pub const LIST_ENTRY = extern struct { | ||
| 476 | Flink: *LIST_ENTRY, | ||
| 477 | Blink: *LIST_ENTRY, | ||
| 478 | }; | ||
| 479 | |||
| 480 | pub 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 | |||
| 492 | pub 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 | |||
| 501 | pub const CRITICAL_SECTION = RTL_CRITICAL_SECTION; | ||
| 502 | pub const INIT_ONCE = RTL_RUN_ONCE; | ||
| 503 | pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE_INIT; | ||
| 504 | pub const INIT_ONCE_FN = extern fn (InitOnce: *INIT_ONCE, Parameter: ?*c_void, Context: ?*c_void) BOOL; | ||
| 505 | |||
| 506 | pub const RTL_RUN_ONCE = extern struct { | ||
| 507 | Ptr: ?*c_void, | ||
| 508 | }; | ||
| 509 | |||
| 510 | pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE{ .Ptr = null }; | ||
| 511 | |||
| 512 | pub const COINIT_APARTMENTTHREADED = COINIT.COINIT_APARTMENTTHREADED; | ||
| 513 | pub const COINIT_MULTITHREADED = COINIT.COINIT_MULTITHREADED; | ||
| 514 | pub const COINIT_DISABLE_OLE1DDE = COINIT.COINIT_DISABLE_OLE1DDE; | ||
| 515 | pub const COINIT_SPEED_OVER_MEMORY = COINIT.COINIT_SPEED_OVER_MEMORY; | ||
| 516 | pub 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 | ||
| 527 | pub const PATH_MAX_WIDE = 32767; | ||
std/os/windows/kernel32.zig+1-78| ... | @@ -1,4 +1,4 @@ | ... | @@ -1,4 +1,4 @@ |
| 1 | use @import("../windows.zig"); | 1 | use @import("bits.zig"); |
| 2 | 2 | ||
| 3 | pub extern "kernel32" stdcallcc fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) BOOL; | 3 | pub extern "kernel32" stdcallcc fn CancelIoEx(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) BOOL; |
| 4 | 4 | ||
| ... | @@ -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: |
| 189 | 189 | ||
| 190 | pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) BOOL; | 190 | pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) BOOL; |
| 191 | 191 | ||
| 192 | pub const FILE_NOTIFY_INFORMATION = extern struct { | ||
| 193 | NextEntryOffset: DWORD, | ||
| 194 | Action: DWORD, | ||
| 195 | FileNameLength: DWORD, | ||
| 196 | FileName: [1]WCHAR, | ||
| 197 | }; | ||
| 198 | |||
| 199 | pub const FILE_ACTION_ADDED = 0x00000001; | ||
| 200 | pub const FILE_ACTION_REMOVED = 0x00000002; | ||
| 201 | pub const FILE_ACTION_MODIFIED = 0x00000003; | ||
| 202 | pub const FILE_ACTION_RENAMED_OLD_NAME = 0x00000004; | ||
| 203 | pub const FILE_ACTION_RENAMED_NEW_NAME = 0x00000005; | ||
| 204 | |||
| 205 | pub const LPOVERLAPPED_COMPLETION_ROUTINE = ?extern fn (DWORD, DWORD, *OVERLAPPED) void; | ||
| 206 | |||
| 207 | pub const FILE_LIST_DIRECTORY = 1; | ||
| 208 | |||
| 209 | pub const FILE_NOTIFY_CHANGE_CREATION = 64; | ||
| 210 | pub const FILE_NOTIFY_CHANGE_SIZE = 8; | ||
| 211 | pub const FILE_NOTIFY_CHANGE_SECURITY = 256; | ||
| 212 | pub const FILE_NOTIFY_CHANGE_LAST_ACCESS = 32; | ||
| 213 | pub const FILE_NOTIFY_CHANGE_LAST_WRITE = 16; | ||
| 214 | pub const FILE_NOTIFY_CHANGE_DIR_NAME = 2; | ||
| 215 | pub const FILE_NOTIFY_CHANGE_FILE_NAME = 1; | ||
| 216 | pub const FILE_NOTIFY_CHANGE_ATTRIBUTES = 4; | ||
| 217 | |||
| 218 | pub 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 | |||
| 226 | pub const FOREGROUND_BLUE = 1; | ||
| 227 | pub const FOREGROUND_GREEN = 2; | ||
| 228 | pub const FOREGROUND_RED = 4; | ||
| 229 | pub const FOREGROUND_INTENSITY = 8; | ||
| 230 | |||
| 231 | pub extern "kernel32" stdcallcc fn InitializeCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; | 192 | pub extern "kernel32" stdcallcc fn InitializeCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; |
| 232 | pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; | 193 | pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; |
| 233 | pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; | 194 | pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; |
| 234 | pub extern "kernel32" stdcallcc fn DeleteCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; | 195 | pub extern "kernel32" stdcallcc fn DeleteCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; |
| 235 | 196 | ||
| 236 | pub const LIST_ENTRY = extern struct { | ||
| 237 | Flink: *LIST_ENTRY, | ||
| 238 | Blink: *LIST_ENTRY, | ||
| 239 | }; | ||
| 240 | |||
| 241 | pub 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 | |||
| 253 | pub 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 | |||
| 262 | pub const CRITICAL_SECTION = RTL_CRITICAL_SECTION; | ||
| 263 | pub const INIT_ONCE = RTL_RUN_ONCE; | ||
| 264 | pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE_INIT; | ||
| 265 | |||
| 266 | pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter: ?*c_void, Context: ?*c_void) BOOL; | 197 | pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter: ?*c_void, Context: ?*c_void) BOOL; |
| 267 | |||
| 268 | pub const INIT_ONCE_FN = extern fn (InitOnce: *INIT_ONCE, Parameter: ?*c_void, Context: ?*c_void) BOOL; | ||
| 269 | |||
| 270 | pub const RTL_RUN_ONCE = extern struct { | ||
| 271 | Ptr: ?*c_void, | ||
| 272 | }; | ||
| 273 | |||
| 274 | pub 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 @@ |
| 1 | use @import("../windows.zig"); | 1 | use @import("bits.zig"); |
| 2 | 2 | ||
| 3 | pub extern "NtDll" stdcallcc fn RtlCaptureStackBackTrace(FramesToSkip: DWORD, FramesToCapture: DWORD, BackTrace: **c_void, BackTraceHash: ?*DWORD) WORD; | 3 | pub 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 @@ |
| 1 | use @import("../windows.zig"); | 1 | use @import("bits.zig"); |
| 2 | 2 | ||
| 3 | pub extern "ole32" stdcallcc fn CoTaskMemFree(pv: LPVOID) void; | 3 | pub extern "ole32" stdcallcc fn CoTaskMemFree(pv: LPVOID) void; |
| 4 | pub extern "ole32" stdcallcc fn CoUninitialize() void; | 4 | pub extern "ole32" stdcallcc fn CoUninitialize() void; |
| 5 | pub extern "ole32" stdcallcc fn CoGetCurrentProcess() DWORD; | 5 | pub extern "ole32" stdcallcc fn CoGetCurrentProcess() DWORD; |
| 6 | pub extern "ole32" stdcallcc fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) HRESULT; | 6 | pub extern "ole32" stdcallcc fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) HRESULT; |
| 7 | |||
| 8 | pub const COINIT_APARTMENTTHREADED = COINIT.COINIT_APARTMENTTHREADED; | ||
| 9 | pub const COINIT_MULTITHREADED = COINIT.COINIT_MULTITHREADED; | ||
| 10 | pub const COINIT_DISABLE_OLE1DDE = COINIT.COINIT_DISABLE_OLE1DDE; | ||
| 11 | pub const COINIT_SPEED_OVER_MEMORY = COINIT.COINIT_SPEED_OVER_MEMORY; | ||
| 12 | pub 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 @@ |
| 1 | use @import("../windows.zig"); | 1 | use @import("bits.zig"); |
| 2 | 2 | ||
| 3 | pub extern "shell32" stdcallcc fn SHGetKnownFolderPath(rfid: *const KNOWNFOLDERID, dwFlags: DWORD, hToken: ?HANDLE, ppszPath: *[*]WCHAR) HRESULT; | 3 | pub 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 @@ | ||
| 1 | const std = @import("../../std.zig"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const os = std.os; | ||
| 4 | const unicode = std.unicode; | ||
| 5 | const windows = std.os.windows; | ||
| 6 | const assert = std.debug.assert; | ||
| 7 | const mem = std.mem; | ||
| 8 | const BufMap = std.BufMap; | ||
| 9 | const 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 | ||
| 15 | pub const PATH_MAX_WIDE = 32767; | ||
| 16 | |||
| 17 | pub const WaitError = error{ | ||
| 18 | WaitAbandoned, | ||
| 19 | WaitTimeOut, | ||
| 20 | |||
| 21 | /// See https://github.com/ziglang/zig/issues/1396 | ||
| 22 | Unexpected, | ||
| 23 | }; | ||
| 24 | |||
| 25 | pub 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 | |||
| 41 | pub fn windowsClose(handle: windows.HANDLE) void { | ||
| 42 | assert(windows.CloseHandle(handle) != 0); | ||
| 43 | } | ||
| 44 | |||
| 45 | pub const ReadError = error{ | ||
| 46 | OperationAborted, | ||
| 47 | BrokenPipe, | ||
| 48 | Unexpected, | ||
| 49 | }; | ||
| 50 | |||
| 51 | pub const WriteError = error{ | ||
| 52 | SystemResources, | ||
| 53 | OperationAborted, | ||
| 54 | BrokenPipe, | ||
| 55 | |||
| 56 | /// See https://github.com/ziglang/zig/issues/1396 | ||
| 57 | Unexpected, | ||
| 58 | }; | ||
| 59 | |||
| 60 | pub 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 | |||
| 76 | pub 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 | |||
| 84 | pub 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 | |||
| 104 | pub 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 | |||
| 129 | pub 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 | |||
| 155 | pub 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. | ||
| 167 | pub 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 | |||
| 203 | pub 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. | ||
| 223 | pub 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 | |||
| 234 | pub const WindowsCreateIoCompletionPortError = error{Unexpected}; | ||
| 235 | |||
| 236 | pub 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 | |||
| 247 | pub const WindowsPostQueuedCompletionStatusError = error{Unexpected}; | ||
| 248 | |||
| 249 | pub 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 | |||
| 258 | pub const WindowsWaitResult = enum { | ||
| 259 | Normal, | ||
| 260 | Aborted, | ||
| 261 | Cancelled, | ||
| 262 | EOF, | ||
| 263 | }; | ||
| 264 | |||
| 265 | pub 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 | |||
| 282 | pub fn cStrToPrefixedFileW(s: [*]const u8) ![PATH_MAX_WIDE + 1]u16 { | ||
| 283 | return sliceToPrefixedFileW(mem.toSliceConst(u8, s)); | ||
| 284 | } | ||
| 285 | |||
| 286 | pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 { | ||
| 287 | return sliceToPrefixedSuffixedFileW(s, []u16{0}); | ||
| 288 | } | ||
| 289 | |||
| 290 | pub 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; |
| 80 | pub const STDERR_FILENO = 2; | 80 | pub const STDERR_FILENO = 2; |
| 81 | 81 | ||
| 82 | // FIXME: let's borrow Linux's error numbers for now. | 82 | // FIXME: let's borrow Linux's error numbers for now. |
| 83 | use @import("linux/errno.zig"); | 83 | use @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. |
| 85 | pub fn getErrno(r: usize) usize { | 85 | pub 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); |
| 620 | 620 | ||
| 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 | }; |
| 625 | 625 | ||
| ... | @@ -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; |
| 643 | 643 | ||
| 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); |
| 646 | 646 | ||
| 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; |
| 6 | const os = std.os; | 6 | const os = std.os; |
| 7 | const warn = std.debug.warn; | 7 | const warn = std.debug.warn; |
| 8 | const coff = std.coff; | 8 | const coff = std.coff; |
| 9 | const File = std.fs.File; | ||
| 9 | 10 | ||
| 10 | const ArrayList = std.ArrayList; | 11 | const ArrayList = std.ArrayList; |
| 11 | 12 | ||
| ... | @@ -459,7 +460,7 @@ pub const PDBStringTableHeader = packed struct { | ... | @@ -459,7 +460,7 @@ pub const PDBStringTableHeader = packed struct { |
| 459 | }; | 460 | }; |
| 460 | 461 | ||
| 461 | pub const Pdb = struct { | 462 | pub 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, |
| 469 | 470 | ||
| 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; |
| 474 | 475 | ||
| ... | @@ -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, |
| 494 | 495 | ||
| 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; |
| 498 | 499 | ||
| ... | @@ -587,7 +588,7 @@ const SuperBlock = packed struct { | ... | @@ -587,7 +588,7 @@ const SuperBlock = packed struct { |
| 587 | }; | 588 | }; |
| 588 | 589 | ||
| 589 | const MsfStream = struct { | 590 | const 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); |
| 600 | 601 | ||
| 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 | } |
| 662 | 663 | ||
| 663 | // XXX: The `len` parameter should be signed | 664 | 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 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("std.zig"); | ||
| 3 | const os = std.os; | ||
| 4 | const fs = std.fs; | ||
| 5 | const BufMap = std.BufMap; | ||
| 6 | const Buffer = std.Buffer; | ||
| 7 | const mem = std.mem; | ||
| 8 | const math = std.math; | ||
| 9 | const Allocator = mem.Allocator; | ||
| 10 | const assert = std.debug.assert; | ||
| 11 | const testing = std.testing; | ||
| 12 | |||
| 13 | pub const abort = os.abort; | ||
| 14 | pub const exit = os.exit; | ||
| 15 | pub const changeCurDir = os.chdir; | ||
| 16 | pub const changeCurDirC = os.chdirC; | ||
| 17 | |||
| 18 | /// The result is a slice of `out_buffer`, from index `0`. | ||
| 19 | pub 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. | ||
| 24 | pub 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 | |||
| 29 | test "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 | ||
| 38 | pub 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 | |||
| 116 | test "os.getEnvMap" { | ||
| 117 | var env = try getEnvMap(std.debug.global_allocator); | ||
| 118 | defer env.deinit(); | ||
| 119 | } | ||
| 120 | |||
| 121 | pub 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 | ||
| 131 | pub 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 | |||
| 168 | test "os.getEnvVarOwned" { | ||
| 169 | var ga = std.debug.global_allocator; | ||
| 170 | testing.expectError(error.EnvironmentVariableNotFound, getEnvVarOwned(ga, "BADENV")); | ||
| 171 | } | ||
| 172 | |||
| 173 | pub 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 | |||
| 200 | pub 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 | |||
| 349 | pub 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 | |||
| 386 | pub fn args() ArgIterator { | ||
| 387 | return ArgIterator.init(); | ||
| 388 | } | ||
| 389 | |||
| 390 | /// Caller must call argsFree on result. | ||
| 391 | pub 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 | |||
| 456 | pub 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 | |||
| 476 | test "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 | |||
| 493 | fn 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 | |||
| 502 | pub const UserInfo = struct { | ||
| 503 | uid: u32, | ||
| 504 | gid: u32, | ||
| 505 | }; | ||
| 506 | |||
| 507 | /// POSIX function which gets a uid from username. | ||
| 508 | pub 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`. | ||
| 517 | pub 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 | |||
| 601 | pub 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, getRandomBytes | 1 | // 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 using | 2 | // 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 | } |
| 67 | 67 | ||
| 68 | // TODO https://github.com/ziglang/zig/issues/265 | 68 | // 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]; |
| 80 | 80 | ||
| 81 | if (builtin.os == builtin.Os.linux) { | 81 | if (builtin.os == .linux) { |
| 82 | // Find the beginning of the auxiliary vector | 82 | // 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 area | 85 | // Initialize the TLS area |
| 86 | std.os.linux.tls.initTLS(); | 86 | std.os.linux.tls.initTLS(); |
| 87 | 87 | ||
| ... | @@ -92,14 +92,14 @@ fn posixCallMainAndExit() noreturn { | ... | @@ -92,14 +92,14 @@ fn posixCallMainAndExit() noreturn { |
| 92 | } | 92 | } |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | std.os.posix.exit(callMainWithArgs(argc, argv, envp)); | 95 | std.os.exit(callMainWithArgs(argc, argv, envp)); |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 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. |
| 100 | inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 { | 100 | inline 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 | } |
| 105 | 105 |
std/special/build_runner.zig+7-6| ... | @@ -3,14 +3,15 @@ const std = @import("std"); | ... | @@ -3,14 +3,15 @@ const std = @import("std"); |
| 3 | const builtin = @import("builtin"); | 3 | const builtin = @import("builtin"); |
| 4 | const io = std.io; | 4 | const io = std.io; |
| 5 | const fmt = std.fmt; | 5 | const fmt = std.fmt; |
| 6 | const os = std.os; | ||
| 7 | const Builder = std.build.Builder; | 6 | const Builder = std.build.Builder; |
| 8 | const mem = std.mem; | 7 | const mem = std.mem; |
| 8 | const process = std.process; | ||
| 9 | const ArrayList = std.ArrayList; | 9 | const ArrayList = std.ArrayList; |
| 10 | const warn = std.debug.warn; | 10 | const warn = std.debug.warn; |
| 11 | const File = std.fs.File; | ||
| 11 | 12 | ||
| 12 | pub fn main() !void { | 13 | pub fn main() !void { |
| 13 | var arg_it = os.args(); | 14 | var arg_it = process.args(); |
| 14 | 15 | ||
| 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 squish | 17 | // 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; |
| 49 | 50 | ||
| 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; |
| 56 | 57 | ||
| 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 { |
| 214 | 215 | ||
| 215 | fn usageAndErr(builder: *Builder, already_ran_build: bool, out_stream: var) void { | 216 | fn 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 | } |
| 219 | 220 | ||
| 220 | const UnwrapArgError = error{OutOfMemory}; | 221 | const 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, |
| 24 | 24 | ||
| 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 | }; |
| 29 | 29 | ||
| ... | @@ -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 | } |
| 46 | 46 | ||
| 47 | /// TODO: once https://github.com/ziglang/zig/issues/287 is solved and std.Mutex has a better | 47 | /// 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 | } |
| 53 | 53 | ||
| 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; |
| 17 | pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex; | 17 | pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex; |
| 18 | pub const SegmentedList = @import("segmented_list.zig").SegmentedList; | 18 | pub const SegmentedList = @import("segmented_list.zig").SegmentedList; |
| 19 | pub const SpinLock = @import("spinlock.zig").SpinLock; | 19 | pub const SpinLock = @import("spinlock.zig").SpinLock; |
| 20 | pub const ChildProcess = @import("child_process.zig").ChildProcess; | ||
| 21 | pub const Thread = @import("thread.zig").Thread; | ||
| 20 | 22 | ||
| 21 | pub const atomic = @import("atomic.zig"); | 23 | pub const atomic = @import("atomic.zig"); |
| 22 | pub const base64 = @import("base64.zig"); | 24 | pub 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"); |
| 30 | pub const elf = @import("elf.zig"); | 32 | pub const elf = @import("elf.zig"); |
| 31 | pub const event = @import("event.zig"); | 33 | pub const event = @import("event.zig"); |
| 32 | pub const fmt = @import("fmt.zig"); | 34 | pub const fmt = @import("fmt.zig"); |
| 35 | pub const fs = @import("fs.zig"); | ||
| 33 | pub const hash = @import("hash.zig"); | 36 | pub const hash = @import("hash.zig"); |
| 34 | pub const hash_map = @import("hash_map.zig"); | 37 | pub const hash_map = @import("hash_map.zig"); |
| 35 | pub const heap = @import("heap.zig"); | 38 | pub 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"); |
| 43 | pub const net = @import("net.zig"); | 46 | pub const net = @import("net.zig"); |
| 44 | pub const os = @import("os.zig"); | 47 | pub const os = @import("os.zig"); |
| 45 | pub const pdb = @import("pdb.zig"); | 48 | pub const pdb = @import("pdb.zig"); |
| 49 | pub const process = @import("process.zig"); | ||
| 46 | pub const rand = @import("rand.zig"); | 50 | pub const rand = @import("rand.zig"); |
| 47 | pub const rb = @import("rb.zig"); | 51 | pub const rb = @import("rb.zig"); |
| 48 | pub const sort = @import("sort.zig"); | 52 | pub const sort = @import("sort.zig"); |
| 49 | pub const ascii = @import("ascii.zig"); | 53 | pub const ascii = @import("ascii.zig"); |
| 50 | pub const testing = @import("testing.zig"); | 54 | pub const testing = @import("testing.zig"); |
| 55 | pub const time = @import("time.zig"); | ||
| 51 | pub const unicode = @import("unicode.zig"); | 56 | pub const unicode = @import("unicode.zig"); |
| 52 | pub const valgrind = @import("valgrind.zig"); | 57 | pub const valgrind = @import("valgrind.zig"); |
| 53 | pub const zig = @import("zig.zig"); | 58 | pub 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"); | ||
| 68 | 74 | ||
| 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 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("std.zig"); | ||
| 3 | const os = std.os; | ||
| 4 | const mem = std.mem; | ||
| 5 | const windows = std.os.windows; | ||
| 6 | const c = std.c; | ||
| 7 | const assert = std.debug.assert; | ||
| 8 | |||
| 9 | pub 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 @@ | ||
| 1 | const builtin = @import("builtin"); | ||
| 2 | const std = @import("std.zig"); | ||
| 3 | const assert = std.debug.assert; | ||
| 4 | const testing = std.testing; | ||
| 5 | const os = std.os; | ||
| 6 | const math = std.math; | ||
| 7 | |||
| 8 | pub const epoch = @import("time/epoch.zig"); | ||
| 9 | |||
| 10 | /// Spurious wakeups are possible and no precision of timing is guaranteed. | ||
| 11 | pub 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? | ||
| 26 | pub 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? | ||
| 32 | pub 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) | ||
| 73 | pub const nanosecond = 1; | ||
| 74 | pub const microsecond = 1000 * nanosecond; | ||
| 75 | pub const millisecond = 1000 * microsecond; | ||
| 76 | pub const second = 1000 * millisecond; | ||
| 77 | pub const minute = 60 * second; | ||
| 78 | pub const hour = 60 * minute; | ||
| 79 | |||
| 80 | /// Divisions of a second | ||
| 81 | pub const ns_per_s = 1000000000; | ||
| 82 | pub const us_per_s = 1000000; | ||
| 83 | pub const ms_per_s = 1000; | ||
| 84 | pub const cs_per_s = 100; | ||
| 85 | |||
| 86 | /// Common time divisions | ||
| 87 | pub const s_per_min = 60; | ||
| 88 | pub const s_per_hour = s_per_min * 60; | ||
| 89 | pub const s_per_day = s_per_hour * 24; | ||
| 90 | pub 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. | ||
| 100 | pub 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 | |||
| 192 | test "sleep" { | ||
| 193 | sleep(1); | ||
| 194 | } | ||
| 195 | |||
| 196 | test "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 | |||
| 207 | test "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. | ||
| 3 | pub const posix = 0; //Jan 01, 1970 AD | ||
| 4 | pub const dos = 315532800; //Jan 01, 1980 AD | ||
| 5 | pub const ios = 978307200; //Jan 01, 2001 AD | ||
| 6 | pub const openvms = -3506716800; //Nov 17, 1858 AD | ||
| 7 | pub const zos = -2208988800; //Jan 01, 1900 AD | ||
| 8 | pub const windows = -11644473600; //Jan 01, 1601 AD | ||
| 9 | pub const amiga = 252460800; //Jan 01, 1978 AD | ||
| 10 | pub const pickos = -63244800; //Dec 31, 1967 AD | ||
| 11 | pub const gps = 315964800; //Jan 06, 1980 AD | ||
| 12 | pub const clr = -62135769600; //Jan 01, 0001 AD | ||
| 13 | |||
| 14 | pub const unix = posix; | ||
| 15 | pub const android = posix; | ||
| 16 | pub const os2 = dos; | ||
| 17 | pub const bios = dos; | ||
| 18 | pub const vfat = dos; | ||
| 19 | pub const ntfs = windows; | ||
| 20 | pub const ntp = zos; | ||
| 21 | pub const jbase = pickos; | ||
| 22 | pub const aros = amiga; | ||
| 23 | pub const morphos = amiga; | ||
| 24 | pub const brew = gps; | ||
| 25 | pub const atsc = gps; | ||
| 26 | pub 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; |
| 10 | 10 | ||
| 11 | pub fn main() !void { | 11 | pub 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); |
| 25 | 25 |
test/cli.zig+21-19| ... | @@ -1,7 +1,9 @@ | ... | @@ -1,7 +1,9 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const os = std.os; | ||
| 4 | const testing = std.testing; | 3 | const testing = std.testing; |
| 4 | const process = std.process; | ||
| 5 | const fs = std.fs; | ||
| 6 | const ChildProcess = std.ChildProcess; | ||
| 5 | 7 | ||
| 6 | var a: *std.mem.Allocator = undefined; | 8 | var a: *std.mem.Allocator = undefined; |
| 7 | 9 | ||
| ... | @@ -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(); |
| 14 | 16 | ||
| 15 | var arg_it = os.args(); | 17 | var arg_it = process.args(); |
| 16 | 18 | ||
| 17 | // skip my own exe name | 19 | // 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}); |
| 31 | 33 | ||
| 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 | } |
| 60 | 62 | ||
| 61 | fn exec(cwd: []const u8, argv: []const []const u8) !os.ChildProcess.ExecResult { | 63 | fn 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 | } |
| 98 | 100 | ||
| 99 | fn testGodboltApi(zig_exe: []const u8, dir_path: []const u8) anyerror!void { | 101 | fn 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; |
| 101 | 103 | ||
| 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" }); |
| 104 | 106 | ||
| 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 | ); |
| 115 | 117 | ||
| 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"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | 3 | ||
| 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { | 4 | pub 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 { |
| 318 | test "cast *[1][*]const u8 to [*]const ?[*]const u8" { | 318 | test "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 | } |
| 323 | 323 | ||
| 324 | test "@intCast comptime_int" { | 324 | test "@intCast comptime_int" { |
test/stage1/behavior/hasdecl.zig created+21| ... | @@ -0,0 +1,21 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const expect = std.testing.expect; | ||
| 3 | |||
| 4 | const Foo = @import("hasdecl/foo.zig"); | ||
| 5 | |||
| 6 | const Bar = struct { | ||
| 7 | nope: i32, | ||
| 8 | |||
| 9 | const hi = 1; | ||
| 10 | pub var blah = "xxx"; | ||
| 11 | }; | ||
| 12 | |||
| 13 | test "@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 @@ | ||
| 1 | pub const public_thing = 42; | ||
| 2 | const 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"); |
| 2 | const expect = std.testing.expect; | 2 | const expect = std.testing.expect; |
| 3 | const expectEqualSlices = std.testing.expectEqualSlices; | 3 | const expectEqualSlices = std.testing.expectEqualSlices; |
| 4 | const mem = std.mem; | 4 | const mem = std.mem; |
| 5 | const cstr = std.cstr; | ||
| 6 | const builtin = @import("builtin"); | 5 | const builtin = @import("builtin"); |
| 7 | const maxInt = std.math.maxInt; | 6 | const maxInt = std.math.maxInt; |
| 8 | 7 | ||
| ... | @@ -210,7 +209,7 @@ test "multiline C string" { | ... | @@ -210,7 +209,7 @@ test "multiline C string" { |
| 210 | c\\three | 209 | 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 | } |
| 215 | 214 | ||
| 216 | test "type equality" { | 215 | test "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"; |
| 365 | 364 | ||
| 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 | |||
| 62 | test "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 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | 2 | ||
| 3 | pub fn main() void { | 3 | pub 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"); |
| 2 | const debug = std.debug; | 2 | const debug = std.debug; |
| 3 | const warn = debug.warn; | 3 | const warn = debug.warn; |
| 4 | const build = std.build; | 4 | const build = std.build; |
| 5 | const os = std.os; | ||
| 6 | const StdIo = os.ChildProcess.StdIo; | ||
| 7 | const Term = os.ChildProcess.Term; | ||
| 8 | const Buffer = std.Buffer; | 5 | const Buffer = std.Buffer; |
| 9 | const io = std.io; | 6 | const io = std.io; |
| 7 | const fs = std.fs; | ||
| 10 | const mem = std.mem; | 8 | const mem = std.mem; |
| 11 | const fmt = std.fmt; | 9 | const fmt = std.fmt; |
| 12 | const ArrayList = std.ArrayList; | 10 | const ArrayList = std.ArrayList; |
| ... | @@ -30,19 +28,19 @@ const TestTarget = struct { | ... | @@ -30,19 +28,19 @@ const TestTarget = struct { |
| 30 | 28 | ||
| 31 | const test_targets = []TestTarget{ | 29 | const 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 | }; |
| 48 | 46 | ||
| ... | @@ -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 | }); |
| 120 | 118 | ||
| ... | @@ -301,12 +299,12 @@ pub const CompareOutputContext = struct { | ... | @@ -301,12 +299,12 @@ pub const CompareOutputContext = struct { |
| 301 | 299 | ||
| 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); |
| 303 | 301 | ||
| 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(); |
| 306 | 304 | ||
| 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; |
| 311 | 309 | ||
| 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 { |
| 383 | 381 | ||
| 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); |
| 385 | 383 | ||
| 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(); |
| 388 | 386 | ||
| 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; |
| 393 | 391 | ||
| 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 | }; |
| 397 | 395 | ||
| 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; |
| 461 | 459 | ||
| 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); |
| 476 | 474 | ||
| 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 | } |
| 508 | 506 | ||
| 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 | } |
| 539 | 537 | ||
| 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; |
| 635 | 633 | ||
| 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 | } |
| 671 | 669 | ||
| 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(); |
| 674 | 672 | ||
| 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; |
| 679 | 677 | ||
| 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)); |
| 681 | 679 | ||
| ... | @@ -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); |
| 824 | 822 | ||
| 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 | } |
| 859 | 857 | ||
| 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; |
| 864 | 862 | ||
| ... | @@ -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; |
| 960 | 958 | ||
| 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 | } |
| 978 | 976 | ||
| 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(); |
| 981 | 979 | ||
| 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; |
| 986 | 984 | ||
| 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)); |
| 988 | 986 | ||
| ... | @@ -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); |
| 1132 | 1130 | ||
| 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 { |
| 1254 | 1252 | ||
| 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); |
| 1270 | 1268 | ||
| 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; |