| author | |
| committer | |
| log | 2def23063fbabb4128da17aca27745a7e8062ce5 |
| tree | 53d8e79eebc72a0ff171ff6f911e2c4eb2ef5cdc |
| parent | daae7e1f5aa5aac02a342c9a60d703c2a0cba579 |
| signature | Commit is signed but in an unrecognized format. |
14 files changed, 1331 insertions(+), 1317 deletions(-)
CMakeLists.txt+1| ... | ... | @@ -619,6 +619,7 @@ set(ZIG_STD_FILES |
| 619 | 619 | "os/linux/posix.zig" |
| 620 | 620 | "os/linux/posix/arm64.zig" |
| 621 | 621 | "os/linux/posix/x86_64.zig" |
| 622 | "os/linux/sys.zig" | |
| 622 | 623 | "os/linux/tls.zig" |
| 623 | 624 | "os/linux/vdso.zig" |
| 624 | 625 | "os/linux/x86_64.zig" |
std/dynamic_library.zig+2-3| ... | ... | @@ -261,12 +261,11 @@ pub const WindowsDynLib = struct { |
| 261 | 261 | return WindowsDynLib{ |
| 262 | 262 | .allocator = allocator, |
| 263 | 263 | .dll = windows.LoadLibraryW(&wpath) orelse { |
| 264 | const err = windows.GetLastError(); | |
| 265 | switch (err) { | |
| 264 | switch (windows.GetLastError()) { | |
| 266 | 265 | windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound, |
| 267 | 266 | windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound, |
| 268 | 267 | windows.ERROR.MOD_NOT_FOUND => return error.FileNotFound, |
| 269 | else => return os.unexpectedErrorWindows(err), | |
| 268 | else => |err| return windows.unexpectedError(err), | |
| 270 | 269 | } |
| 271 | 270 | }, |
| 272 | 271 | }; |
std/event/fs.zig+14-18| ... | ... | @@ -154,16 +154,15 @@ pub async fn pwriteWindows(loop: *Loop, fd: fd_t, data: []const u8, offset: u64) |
| 154 | 154 | } |
| 155 | 155 | var bytes_transferred: windows.DWORD = undefined; |
| 156 | 156 | if (windows.GetOverlappedResult(fd, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) { |
| 157 | const err = windows.GetLastError(); | |
| 158 | return switch (err) { | |
| 157 | switch (windows.GetLastError()) { | |
| 159 | 158 | windows.ERROR.IO_PENDING => unreachable, |
| 160 | windows.ERROR.INVALID_USER_BUFFER => error.SystemResources, | |
| 161 | windows.ERROR.NOT_ENOUGH_MEMORY => error.SystemResources, | |
| 162 | windows.ERROR.OPERATION_ABORTED => error.OperationAborted, | |
| 163 | windows.ERROR.NOT_ENOUGH_QUOTA => error.SystemResources, | |
| 164 | windows.ERROR.BROKEN_PIPE => error.BrokenPipe, | |
| 165 | else => os.unexpectedErrorWindows(err), | |
| 166 | }; | |
| 159 | windows.ERROR.INVALID_USER_BUFFER => return error.SystemResources, | |
| 160 | windows.ERROR.NOT_ENOUGH_MEMORY => return error.SystemResources, | |
| 161 | windows.ERROR.OPERATION_ABORTED => return error.OperationAborted, | |
| 162 | windows.ERROR.NOT_ENOUGH_QUOTA => return error.SystemResources, | |
| 163 | windows.ERROR.BROKEN_PIPE => return error.BrokenPipe, | |
| 164 | else => |err| return windows.unexpectedError(err), | |
| 165 | } | |
| 167 | 166 | } |
| 168 | 167 | } |
| 169 | 168 | |
| ... | ... | @@ -304,13 +303,12 @@ pub async fn preadWindows(loop: *Loop, fd: fd_t, data: []u8, offset: u64) !usize |
| 304 | 303 | } |
| 305 | 304 | var bytes_transferred: windows.DWORD = undefined; |
| 306 | 305 | if (windows.GetOverlappedResult(fd, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) { |
| 307 | const err = windows.GetLastError(); | |
| 308 | switch (err) { | |
| 306 | switch (windows.GetLastError()) { | |
| 309 | 307 | windows.ERROR.IO_PENDING => unreachable, |
| 310 | 308 | windows.ERROR.OPERATION_ABORTED => return error.OperationAborted, |
| 311 | 309 | windows.ERROR.BROKEN_PIPE => return error.BrokenPipe, |
| 312 | 310 | windows.ERROR.HANDLE_EOF => return usize(bytes_transferred), |
| 313 | else => return os.unexpectedErrorWindows(err), | |
| 311 | else => |err| return windows.unexpectedError(err), | |
| 314 | 312 | } |
| 315 | 313 | } |
| 316 | 314 | return usize(bytes_transferred); |
| ... | ... | @@ -1042,11 +1040,10 @@ pub fn Watch(comptime V: type) type { |
| 1042 | 1040 | null, |
| 1043 | 1041 | ); |
| 1044 | 1042 | if (dir_handle == windows.INVALID_HANDLE_VALUE) { |
| 1045 | const err = windows.GetLastError(); | |
| 1046 | switch (err) { | |
| 1043 | switch (windows.GetLastError()) { | |
| 1047 | 1044 | windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound, |
| 1048 | 1045 | windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound, |
| 1049 | else => return os.unexpectedErrorWindows(err), | |
| 1046 | else => |err| return windows.unexpectedError(err), | |
| 1050 | 1047 | } |
| 1051 | 1048 | } |
| 1052 | 1049 | var dir_handle_consumed = false; |
| ... | ... | @@ -1165,9 +1162,8 @@ pub fn Watch(comptime V: type) type { |
| 1165 | 1162 | } |
| 1166 | 1163 | var bytes_transferred: windows.DWORD = undefined; |
| 1167 | 1164 | if (windows.GetOverlappedResult(dir_handle, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) { |
| 1168 | const errno = windows.GetLastError(); | |
| 1169 | const err = switch (errno) { | |
| 1170 | else => os.unexpectedErrorWindows(errno), | |
| 1165 | const err = switch (windows.GetLastError()) { | |
| 1166 | else => |err| windows.unexpectedError(err), | |
| 1171 | 1167 | }; |
| 1172 | 1168 | await (async self.channel.put(err) catch unreachable); |
| 1173 | 1169 | } else { |
std/os.zig+14-8| ... | ... | @@ -31,13 +31,14 @@ pub const zen = @import("os/zen.zig"); |
| 31 | 31 | pub const uefi = @import("os/uefi.zig"); |
| 32 | 32 | pub const wasi = @import("os/wasi.zig"); |
| 33 | 33 | |
| 34 | pub const system = switch (builtin.os) { | |
| 34 | pub const system = if (builtin.link_libc) std.c else switch (builtin.os) { | |
| 35 | 35 | .linux => linux, |
| 36 | 36 | .macosx, .ios, .watchos, .tvos => darwin, |
| 37 | 37 | .freebsd => freebsd, |
| 38 | 38 | .netbsd => netbsd, |
| 39 | 39 | .zen => zen, |
| 40 | 40 | .wasi => wasi, |
| 41 | .windows => windows, | |
| 41 | 42 | else => struct {}, |
| 42 | 43 | }; |
| 43 | 44 | |
| ... | ... | @@ -53,6 +54,12 @@ pub const page_size = switch (builtin.arch) { |
| 53 | 54 | else => 4 * 1024, |
| 54 | 55 | }; |
| 55 | 56 | |
| 57 | pub const unexpected_error_tracing = builtin.mode == .Debug; | |
| 58 | pub const UnexpectedError = error{ | |
| 59 | /// The Operating System returned an undocumented error code. | |
| 60 | Unexpected, | |
| 61 | }; | |
| 62 | ||
| 56 | 63 | /// This represents the maximum size of a UTF-8 encoded file path. |
| 57 | 64 | /// All file system operations which return a path are guaranteed to |
| 58 | 65 | /// fit into a UTF-8 encoded array of this length. |
| ... | ... | @@ -259,7 +266,7 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned |
| 259 | 266 | return switch (err) { |
| 260 | 267 | windows.ERROR.ENVVAR_NOT_FOUND => error.EnvironmentVariableNotFound, |
| 261 | 268 | else => { |
| 262 | unexpectedErrorWindows(err) catch {}; | |
| 269 | windows.unexpectedError(err) catch {}; | |
| 263 | 270 | return error.EnvironmentVariableNotFound; |
| 264 | 271 | }, |
| 265 | 272 | }; |
| ... | ... | @@ -825,7 +832,7 @@ pub const Dir = struct { |
| 825 | 832 | if (self.handle.first) { |
| 826 | 833 | self.handle.first = false; |
| 827 | 834 | } else { |
| 828 | if (!try windows_util.windowsFindNextFile(self.handle.handle, &self.handle.find_file_data)) | |
| 835 | if (!try posix.FindNextFile(self.handle.handle, &self.handle.find_file_data)) | |
| 829 | 836 | return null; |
| 830 | 837 | } |
| 831 | 838 | const name_utf16le = mem.toSlice(u16, self.handle.find_file_data.cFileName[0..].ptr); |
| ... | ... | @@ -1333,7 +1340,7 @@ pub fn selfExePathW(out_buffer: *[posix.PATH_MAX_WIDE]u16) ![]u16 { |
| 1333 | 1340 | if (rc == 0) { |
| 1334 | 1341 | const err = windows.GetLastError(); |
| 1335 | 1342 | switch (err) { |
| 1336 | else => return unexpectedErrorWindows(err), | |
| 1343 | else => return windows.unexpectedError(err), | |
| 1337 | 1344 | } |
| 1338 | 1345 | } |
| 1339 | 1346 | return out_buffer[0..rc]; |
| ... | ... | @@ -1597,10 +1604,9 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread |
| 1597 | 1604 | |
| 1598 | 1605 | const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner); |
| 1599 | 1606 | outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse { |
| 1600 | const err = windows.GetLastError(); | |
| 1601 | return switch (err) { | |
| 1602 | else => os.unexpectedErrorWindows(err), | |
| 1603 | }; | |
| 1607 | switch (windows.GetLastError()) { | |
| 1608 | else => |err| windows.unexpectedError(err), | |
| 1609 | } | |
| 1604 | 1610 | }; |
| 1605 | 1611 | return &outer_context.thread; |
| 1606 | 1612 | } |
std/os/child_process.zig+42-28| ... | ... | @@ -558,7 +558,7 @@ pub const ChildProcess = struct { |
| 558 | 558 | defer if (cwd_w) |cwd| self.allocator.free(cwd); |
| 559 | 559 | const cwd_w_ptr = if (cwd_w) |cwd| cwd.ptr else null; |
| 560 | 560 | |
| 561 | const maybe_envp_buf = if (self.env_map) |env_map| try os.createWindowsEnvBlock(self.allocator, env_map) else null; | |
| 561 | const maybe_envp_buf = if (self.env_map) |env_map| try createWindowsEnvBlock(self.allocator, env_map) else null; | |
| 562 | 562 | defer if (maybe_envp_buf) |envp_buf| self.allocator.free(envp_buf); |
| 563 | 563 | const envp_ptr = if (maybe_envp_buf) |envp_buf| envp_buf.ptr else null; |
| 564 | 564 | |
| ... | ... | @@ -679,13 +679,12 @@ fn windowsCreateProcess(app_name: [*]u16, cmd_line: [*]u16, envp_ptr: ?[*]u16, c |
| 679 | 679 | lpStartupInfo, |
| 680 | 680 | lpProcessInformation, |
| 681 | 681 | ) == 0) { |
| 682 | const err = windows.GetLastError(); | |
| 683 | switch (err) { | |
| 682 | switch (windows.GetLastError()) { | |
| 684 | 683 | windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound, |
| 685 | 684 | windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound, |
| 686 | 685 | windows.ERROR.INVALID_PARAMETER => unreachable, |
| 687 | 686 | windows.ERROR.INVALID_NAME => return error.InvalidName, |
| 688 | else => return os.unexpectedErrorWindows(err), | |
| 687 | else => |err| return windows.unexpectedError(err), | |
| 689 | 688 | } |
| 690 | 689 | } |
| 691 | 690 | } |
| ... | ... | @@ -733,32 +732,10 @@ fn windowsDestroyPipe(rd: ?windows.HANDLE, wr: ?windows.HANDLE) void { |
| 733 | 732 | if (wr) |h| os.close(h); |
| 734 | 733 | } |
| 735 | 734 | |
| 736 | // TODO: workaround for bug where the `const` from `&const` is dropped when the type is | |
| 737 | // a namespace field lookup | |
| 738 | const SECURITY_ATTRIBUTES = windows.SECURITY_ATTRIBUTES; | |
| 739 | ||
| 740 | fn windowsMakePipe(rd: *windows.HANDLE, wr: *windows.HANDLE, sattr: *const SECURITY_ATTRIBUTES) !void { | |
| 741 | if (windows.CreatePipe(rd, wr, sattr, 0) == 0) { | |
| 742 | const err = windows.GetLastError(); | |
| 743 | return switch (err) { | |
| 744 | else => os.unexpectedErrorWindows(err), | |
| 745 | }; | |
| 746 | } | |
| 747 | } | |
| 748 | ||
| 749 | fn windowsSetHandleInfo(h: windows.HANDLE, mask: windows.DWORD, flags: windows.DWORD) !void { | |
| 750 | if (windows.SetHandleInformation(h, mask, flags) == 0) { | |
| 751 | const err = windows.GetLastError(); | |
| 752 | return switch (err) { | |
| 753 | else => os.unexpectedErrorWindows(err), | |
| 754 | }; | |
| 755 | } | |
| 756 | } | |
| 757 | ||
| 758 | 735 | fn windowsMakePipeIn(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const SECURITY_ATTRIBUTES) !void { |
| 759 | 736 | var rd_h: windows.HANDLE = undefined; |
| 760 | 737 | var wr_h: windows.HANDLE = undefined; |
| 761 | try windowsMakePipe(&rd_h, &wr_h, sattr); | |
| 738 | try windows.CreatePipe(&rd_h, &wr_h, sattr); | |
| 762 | 739 | errdefer windowsDestroyPipe(rd_h, wr_h); |
| 763 | 740 | try windowsSetHandleInfo(wr_h, windows.HANDLE_FLAG_INHERIT, 0); |
| 764 | 741 | rd.* = rd_h; |
| ... | ... | @@ -768,7 +745,7 @@ fn windowsMakePipeIn(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const S |
| 768 | 745 | fn windowsMakePipeOut(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const SECURITY_ATTRIBUTES) !void { |
| 769 | 746 | var rd_h: windows.HANDLE = undefined; |
| 770 | 747 | var wr_h: windows.HANDLE = undefined; |
| 771 | try windowsMakePipe(&rd_h, &wr_h, sattr); | |
| 748 | try windows.CreatePipe(&rd_h, &wr_h, sattr); | |
| 772 | 749 | errdefer windowsDestroyPipe(rd_h, wr_h); |
| 773 | 750 | try windowsSetHandleInfo(rd_h, windows.HANDLE_FLAG_INHERIT, 0); |
| 774 | 751 | rd.* = rd_h; |
| ... | ... | @@ -810,3 +787,40 @@ fn readIntFd(fd: i32) !ErrInt { |
| 810 | 787 | const stream = &os.File.openHandle(fd).inStream().stream; |
| 811 | 788 | return stream.readIntNative(ErrInt) catch return error.SystemResources; |
| 812 | 789 | } |
| 790 | ||
| 791 | /// Caller must free result. | |
| 792 | pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u16 { | |
| 793 | // count bytes needed | |
| 794 | const max_chars_needed = x: { | |
| 795 | var max_chars_needed: usize = 4; // 4 for the final 4 null bytes | |
| 796 | var it = env_map.iterator(); | |
| 797 | while (it.next()) |pair| { | |
| 798 | // +1 for '=' | |
| 799 | // +1 for null byte | |
| 800 | max_chars_needed += pair.key.len + pair.value.len + 2; | |
| 801 | } | |
| 802 | break :x max_chars_needed; | |
| 803 | }; | |
| 804 | const result = try allocator.alloc(u16, max_chars_needed); | |
| 805 | errdefer allocator.free(result); | |
| 806 | ||
| 807 | var it = env_map.iterator(); | |
| 808 | var i: usize = 0; | |
| 809 | while (it.next()) |pair| { | |
| 810 | i += try unicode.utf8ToUtf16Le(result[i..], pair.key); | |
| 811 | result[i] = '='; | |
| 812 | i += 1; | |
| 813 | i += try unicode.utf8ToUtf16Le(result[i..], pair.value); | |
| 814 | result[i] = 0; | |
| 815 | i += 1; | |
| 816 | } | |
| 817 | result[i] = 0; | |
| 818 | i += 1; | |
| 819 | result[i] = 0; | |
| 820 | i += 1; | |
| 821 | result[i] = 0; | |
| 822 | i += 1; | |
| 823 | result[i] = 0; | |
| 824 | i += 1; | |
| 825 | return allocator.shrink(result, i); | |
| 826 | } |
std/os/linux.zig+2-765| ... | ... | @@ -1,771 +1,8 @@ |
| 1 | 1 | const std = @import("../std.zig"); |
| 2 | const assert = std.debug.assert; | |
| 3 | 2 | const builtin = @import("builtin"); |
| 4 | const maxInt = std.math.maxInt; | |
| 5 | const elf = std.elf; | |
| 6 | pub const tls = @import("linux/tls.zig"); | |
| 7 | const vdso = @import("linux/vdso.zig"); | |
| 8 | const dl = @import("../dynamic_library.zig"); | |
| 9 | pub use switch (builtin.arch) { | |
| 10 | .x86_64 => @import("linux/x86_64.zig"), | |
| 11 | .aarch64 => @import("linux/arm64.zig"), | |
| 12 | else => struct {}, | |
| 13 | }; | |
| 14 | 3 | pub const is_the_target = builtin.os == .linux; |
| 15 | pub const posix = @import("linux/posix.zig"); | |
| 16 | pub use posix; | |
| 17 | ||
| 18 | /// See `std.os.posix.getauxval`. | |
| 19 | pub var elf_aux_maybe: ?[*]std.elf.Auxv = null; | |
| 20 | ||
| 21 | /// Get the errno from a syscall return value, or 0 for no error. | |
| 22 | pub fn getErrno(r: usize) u12 { | |
| 23 | const signed_r = @bitCast(isize, r); | |
| 24 | return if (signed_r > -4096 and signed_r < 0) @intCast(u12, -signed_r) else 0; | |
| 25 | } | |
| 26 | ||
| 27 | pub fn dup2(old: i32, new: i32) usize { | |
| 28 | return syscall2(SYS_dup2, @bitCast(usize, isize(old)), @bitCast(usize, isize(new))); | |
| 29 | } | |
| 30 | ||
| 31 | pub fn dup3(old: i32, new: i32, flags: u32) usize { | |
| 32 | return syscall3(SYS_dup3, @bitCast(usize, isize(old)), @bitCast(usize, isize(new)), flags); | |
| 33 | } | |
| 34 | ||
| 35 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 36 | pub fn chdir(path: [*]const u8) usize { | |
| 37 | return syscall1(SYS_chdir, @ptrToInt(path)); | |
| 38 | } | |
| 39 | ||
| 40 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 41 | pub fn chroot(path: [*]const u8) usize { | |
| 42 | return syscall1(SYS_chroot, @ptrToInt(path)); | |
| 43 | } | |
| 44 | ||
| 45 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 46 | pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize { | |
| 47 | return syscall3(SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp)); | |
| 48 | } | |
| 49 | ||
| 50 | pub fn fork() usize { | |
| 51 | return syscall0(SYS_fork); | |
| 52 | } | |
| 53 | ||
| 54 | /// This must be inline, and inline call the syscall function, because if the | |
| 55 | /// child does a return it will clobber the parent's stack. | |
| 56 | /// It is advised to avoid this function and use clone instead, because | |
| 57 | /// the compiler is not aware of how vfork affects control flow and you may | |
| 58 | /// see different results in optimized builds. | |
| 59 | pub inline fn vfork() usize { | |
| 60 | return @inlineCall(syscall0, SYS_vfork); | |
| 61 | } | |
| 62 | ||
| 63 | pub fn futex_wait(uaddr: *const i32, futex_op: u32, val: i32, timeout: ?*timespec) usize { | |
| 64 | return syscall4(SYS_futex, @ptrToInt(uaddr), futex_op, @bitCast(u32, val), @ptrToInt(timeout)); | |
| 65 | } | |
| 66 | ||
| 67 | pub fn futex_wake(uaddr: *const i32, futex_op: u32, val: i32) usize { | |
| 68 | return syscall3(SYS_futex, @ptrToInt(uaddr), futex_op, @bitCast(u32, val)); | |
| 69 | } | |
| 70 | ||
| 71 | pub fn getcwd(buf: [*]u8, size: usize) usize { | |
| 72 | return syscall2(SYS_getcwd, @ptrToInt(buf), size); | |
| 73 | } | |
| 74 | ||
| 75 | pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize { | |
| 76 | return syscall3(SYS_getdents, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count); | |
| 77 | } | |
| 78 | ||
| 79 | pub fn getdents64(fd: i32, dirp: [*]u8, count: usize) usize { | |
| 80 | return syscall3(SYS_getdents64, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count); | |
| 81 | } | |
| 82 | ||
| 83 | pub fn inotify_init1(flags: u32) usize { | |
| 84 | return syscall1(SYS_inotify_init1, flags); | |
| 85 | } | |
| 86 | ||
| 87 | pub fn inotify_add_watch(fd: i32, pathname: [*]const u8, mask: u32) usize { | |
| 88 | return syscall3(SYS_inotify_add_watch, @bitCast(usize, isize(fd)), @ptrToInt(pathname), mask); | |
| 89 | } | |
| 90 | ||
| 91 | pub fn inotify_rm_watch(fd: i32, wd: i32) usize { | |
| 92 | return syscall2(SYS_inotify_rm_watch, @bitCast(usize, isize(fd)), @bitCast(usize, isize(wd))); | |
| 93 | } | |
| 94 | ||
| 95 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 96 | pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize { | |
| 97 | return syscall3(SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len); | |
| 98 | } | |
| 99 | ||
| 100 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 101 | pub fn readlinkat(dirfd: i32, noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize { | |
| 102 | return syscall4(SYS_readlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(buf_ptr), buf_len); | |
| 103 | } | |
| 104 | ||
| 105 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 106 | pub fn mkdir(path: [*]const u8, mode: u32) usize { | |
| 107 | return syscall2(SYS_mkdir, @ptrToInt(path), mode); | |
| 108 | } | |
| 109 | ||
| 110 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 111 | pub fn mkdirat(dirfd: i32, path: [*]const u8, mode: u32) usize { | |
| 112 | return syscall3(SYS_mkdirat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode); | |
| 113 | } | |
| 114 | ||
| 115 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 116 | pub fn mount(special: [*]const u8, dir: [*]const u8, fstype: [*]const u8, flags: u32, data: usize) usize { | |
| 117 | return syscall5(SYS_mount, @ptrToInt(special), @ptrToInt(dir), @ptrToInt(fstype), flags, data); | |
| 118 | } | |
| 119 | ||
| 120 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 121 | pub fn umount(special: [*]const u8) usize { | |
| 122 | return syscall2(SYS_umount2, @ptrToInt(special), 0); | |
| 123 | } | |
| 124 | ||
| 125 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 126 | pub fn umount2(special: [*]const u8, flags: u32) usize { | |
| 127 | return syscall2(SYS_umount2, @ptrToInt(special), flags); | |
| 128 | } | |
| 129 | ||
| 130 | pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize { | |
| 131 | return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @bitCast(usize, isize(fd)), @bitCast(usize, offset)); | |
| 132 | } | |
| 133 | ||
| 134 | pub fn mprotect(address: usize, length: usize, protection: usize) usize { | |
| 135 | return syscall3(SYS_mprotect, address, length, protection); | |
| 136 | } | |
| 137 | ||
| 138 | pub fn munmap(address: usize, length: usize) usize { | |
| 139 | return syscall2(SYS_munmap, address, length); | |
| 140 | } | |
| 141 | ||
| 142 | pub fn read(fd: i32, buf: [*]u8, count: usize) usize { | |
| 143 | return syscall3(SYS_read, @bitCast(usize, isize(fd)), @ptrToInt(buf), count); | |
| 144 | } | |
| 145 | ||
| 146 | pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: u64) usize { | |
| 147 | return syscall4(SYS_preadv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset); | |
| 148 | } | |
| 149 | ||
| 150 | pub fn readv(fd: i32, iov: [*]const iovec, count: usize) usize { | |
| 151 | return syscall3(SYS_readv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count); | |
| 152 | } | |
| 153 | ||
| 154 | pub fn writev(fd: i32, iov: [*]const iovec_const, count: usize) usize { | |
| 155 | return syscall3(SYS_writev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count); | |
| 156 | } | |
| 157 | ||
| 158 | pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) usize { | |
| 159 | return syscall4(SYS_pwritev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset); | |
| 160 | } | |
| 161 | ||
| 162 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 163 | pub fn rmdir(path: [*]const u8) usize { | |
| 164 | return syscall1(SYS_rmdir, @ptrToInt(path)); | |
| 165 | } | |
| 166 | ||
| 167 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 168 | pub fn symlink(existing: [*]const u8, new: [*]const u8) usize { | |
| 169 | return syscall2(SYS_symlink, @ptrToInt(existing), @ptrToInt(new)); | |
| 170 | } | |
| 171 | ||
| 172 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 173 | pub fn symlinkat(existing: [*]const u8, newfd: i32, newpath: [*]const u8) usize { | |
| 174 | return syscall3(SYS_symlinkat, @ptrToInt(existing), @bitCast(usize, isize(newfd)), @ptrToInt(newpath)); | |
| 175 | } | |
| 176 | ||
| 177 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 178 | pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize { | |
| 179 | return syscall4(SYS_pread, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset); | |
| 180 | } | |
| 181 | ||
| 182 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 183 | pub fn access(path: [*]const u8, mode: u32) usize { | |
| 184 | return syscall2(SYS_access, @ptrToInt(path), mode); | |
| 185 | } | |
| 186 | ||
| 187 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 188 | pub fn faccessat(dirfd: i32, path: [*]const u8, mode: u32) usize { | |
| 189 | return syscall3(SYS_faccessat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode); | |
| 190 | } | |
| 191 | ||
| 192 | pub fn pipe(fd: *[2]i32) usize { | |
| 193 | return pipe2(fd, 0); | |
| 194 | } | |
| 195 | ||
| 196 | pub fn pipe2(fd: *[2]i32, flags: u32) usize { | |
| 197 | return syscall2(SYS_pipe2, @ptrToInt(fd), flags); | |
| 198 | } | |
| 199 | ||
| 200 | pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { | |
| 201 | return syscall3(SYS_write, @bitCast(usize, isize(fd)), @ptrToInt(buf), count); | |
| 202 | } | |
| 203 | ||
| 204 | pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize { | |
| 205 | return syscall4(SYS_pwrite, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset); | |
| 206 | } | |
| 207 | ||
| 208 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 209 | pub fn rename(old: [*]const u8, new: [*]const u8) usize { | |
| 210 | return syscall2(SYS_rename, @ptrToInt(old), @ptrToInt(new)); | |
| 211 | } | |
| 212 | ||
| 213 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 214 | pub fn renameat2(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const u8, flags: u32) usize { | |
| 215 | return syscall5(SYS_renameat2, @bitCast(usize, isize(oldfd)), @ptrToInt(oldpath), @bitCast(usize, isize(newfd)), @ptrToInt(newpath), flags); | |
| 216 | } | |
| 217 | ||
| 218 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 219 | pub fn open(path: [*]const u8, flags: u32, perm: usize) usize { | |
| 220 | return syscall3(SYS_open, @ptrToInt(path), flags, perm); | |
| 221 | } | |
| 222 | ||
| 223 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 224 | pub fn create(path: [*]const u8, perm: usize) usize { | |
| 225 | return syscall2(SYS_creat, @ptrToInt(path), perm); | |
| 226 | } | |
| 227 | ||
| 228 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 229 | pub fn openat(dirfd: i32, path: [*]const u8, flags: u32, mode: usize) usize { | |
| 230 | // dirfd could be negative, for example AT_FDCWD is -100 | |
| 231 | return syscall4(SYS_openat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode); | |
| 232 | } | |
| 233 | ||
| 234 | /// See also `clone` (from the arch-specific include) | |
| 235 | pub fn clone5(flags: usize, child_stack_ptr: usize, parent_tid: *i32, child_tid: *i32, newtls: usize) usize { | |
| 236 | return syscall5(SYS_clone, flags, child_stack_ptr, @ptrToInt(parent_tid), @ptrToInt(child_tid), newtls); | |
| 237 | } | |
| 238 | ||
| 239 | /// See also `clone` (from the arch-specific include) | |
| 240 | pub fn clone2(flags: u32, child_stack_ptr: usize) usize { | |
| 241 | return syscall2(SYS_clone, flags, child_stack_ptr); | |
| 242 | } | |
| 243 | ||
| 244 | pub fn close(fd: i32) usize { | |
| 245 | return syscall1(SYS_close, @bitCast(usize, isize(fd))); | |
| 246 | } | |
| 247 | ||
| 248 | pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize { | |
| 249 | return syscall3(SYS_lseek, @bitCast(usize, isize(fd)), @bitCast(usize, offset), ref_pos); | |
| 250 | } | |
| 251 | ||
| 252 | pub fn exit(status: i32) noreturn { | |
| 253 | _ = syscall1(SYS_exit, @bitCast(usize, isize(status))); | |
| 254 | unreachable; | |
| 255 | } | |
| 256 | ||
| 257 | pub fn exit_group(status: i32) noreturn { | |
| 258 | _ = syscall1(SYS_exit_group, @bitCast(usize, isize(status))); | |
| 259 | unreachable; | |
| 260 | } | |
| 261 | ||
| 262 | pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize { | |
| 263 | return syscall3(SYS_getrandom, @ptrToInt(buf), count, flags); | |
| 264 | } | |
| 265 | ||
| 266 | pub fn kill(pid: i32, sig: i32) usize { | |
| 267 | return syscall2(SYS_kill, @bitCast(usize, isize(pid)), @bitCast(usize, isize(sig))); | |
| 268 | } | |
| 269 | ||
| 270 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 271 | pub fn unlink(path: [*]const u8) usize { | |
| 272 | return syscall1(SYS_unlink, @ptrToInt(path)); | |
| 273 | } | |
| 274 | ||
| 275 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 276 | pub fn unlinkat(dirfd: i32, path: [*]const u8, flags: u32) usize { | |
| 277 | return syscall3(SYS_unlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags); | |
| 278 | } | |
| 279 | ||
| 280 | pub fn waitpid(pid: i32, status: *i32, options: i32) usize { | |
| 281 | return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0); | |
| 282 | } | |
| 283 | ||
| 284 | var vdso_clock_gettime = @ptrCast(?*const c_void, init_vdso_clock_gettime); | |
| 285 | ||
| 286 | // We must follow the C calling convention when we call into the VDSO | |
| 287 | const vdso_clock_gettime_ty = extern fn (i32, *timespec) usize; | |
| 288 | ||
| 289 | pub fn clock_gettime(clk_id: i32, tp: *timespec) usize { | |
| 290 | if (VDSO_CGT_SYM.len != 0) { | |
| 291 | const ptr = @atomicLoad(?*const c_void, &vdso_clock_gettime, .Unordered); | |
| 292 | if (ptr) |fn_ptr| { | |
| 293 | const f = @ptrCast(vdso_clock_gettime_ty, fn_ptr); | |
| 294 | const rc = f(clk_id, tp); | |
| 295 | switch (rc) { | |
| 296 | 0, @bitCast(usize, isize(-EINVAL)) => return rc, | |
| 297 | else => {}, | |
| 298 | } | |
| 299 | } | |
| 300 | } | |
| 301 | return syscall2(SYS_clock_gettime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp)); | |
| 302 | } | |
| 303 | ||
| 304 | extern fn init_vdso_clock_gettime(clk: i32, ts: *timespec) usize { | |
| 305 | const ptr = @intToPtr(?*const c_void, vdso.lookup(VDSO_CGT_VER, VDSO_CGT_SYM)); | |
| 306 | // Note that we may not have a VDSO at all, update the stub address anyway | |
| 307 | // so that clock_gettime will fall back on the good old (and slow) syscall | |
| 308 | _ = @cmpxchgStrong(?*const c_void, &vdso_clock_gettime, &init_vdso_clock_gettime, ptr, .Monotonic, .Monotonic); | |
| 309 | // Call into the VDSO if available | |
| 310 | if (ptr) |fn_ptr| { | |
| 311 | const f = @ptrCast(vdso_clock_gettime_ty, fn_ptr); | |
| 312 | return f(clk, ts); | |
| 313 | } | |
| 314 | return @bitCast(usize, isize(-ENOSYS)); | |
| 315 | } | |
| 316 | ||
| 317 | pub fn clock_getres(clk_id: i32, tp: *timespec) usize { | |
| 318 | return syscall2(SYS_clock_getres, @bitCast(usize, isize(clk_id)), @ptrToInt(tp)); | |
| 319 | } | |
| 320 | ||
| 321 | pub fn clock_settime(clk_id: i32, tp: *const timespec) usize { | |
| 322 | return syscall2(SYS_clock_settime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp)); | |
| 323 | } | |
| 324 | ||
| 325 | pub fn gettimeofday(tv: *timeval, tz: *timezone) usize { | |
| 326 | return syscall2(SYS_gettimeofday, @ptrToInt(tv), @ptrToInt(tz)); | |
| 327 | } | |
| 328 | ||
| 329 | pub fn settimeofday(tv: *const timeval, tz: *const timezone) usize { | |
| 330 | return syscall2(SYS_settimeofday, @ptrToInt(tv), @ptrToInt(tz)); | |
| 331 | } | |
| 332 | ||
| 333 | pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize { | |
| 334 | return syscall2(SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem)); | |
| 335 | } | |
| 336 | ||
| 337 | pub fn setuid(uid: u32) usize { | |
| 338 | return syscall1(SYS_setuid, uid); | |
| 339 | } | |
| 340 | ||
| 341 | pub fn setgid(gid: u32) usize { | |
| 342 | return syscall1(SYS_setgid, gid); | |
| 343 | } | |
| 344 | ||
| 345 | pub fn setreuid(ruid: u32, euid: u32) usize { | |
| 346 | return syscall2(SYS_setreuid, ruid, euid); | |
| 347 | } | |
| 348 | ||
| 349 | pub fn setregid(rgid: u32, egid: u32) usize { | |
| 350 | return syscall2(SYS_setregid, rgid, egid); | |
| 351 | } | |
| 352 | ||
| 353 | pub fn getuid() u32 { | |
| 354 | return u32(syscall0(SYS_getuid)); | |
| 355 | } | |
| 356 | ||
| 357 | pub fn getgid() u32 { | |
| 358 | return u32(syscall0(SYS_getgid)); | |
| 359 | } | |
| 360 | ||
| 361 | pub fn geteuid() u32 { | |
| 362 | return u32(syscall0(SYS_geteuid)); | |
| 363 | } | |
| 364 | ||
| 365 | pub fn getegid() u32 { | |
| 366 | return u32(syscall0(SYS_getegid)); | |
| 367 | } | |
| 368 | ||
| 369 | pub fn seteuid(euid: u32) usize { | |
| 370 | return syscall1(SYS_seteuid, euid); | |
| 371 | } | |
| 372 | ||
| 373 | pub fn setegid(egid: u32) usize { | |
| 374 | return syscall1(SYS_setegid, egid); | |
| 375 | } | |
| 376 | ||
| 377 | pub fn getresuid(ruid: *u32, euid: *u32, suid: *u32) usize { | |
| 378 | return syscall3(SYS_getresuid, @ptrToInt(ruid), @ptrToInt(euid), @ptrToInt(suid)); | |
| 379 | } | |
| 380 | ||
| 381 | pub fn getresgid(rgid: *u32, egid: *u32, sgid: *u32) usize { | |
| 382 | return syscall3(SYS_getresgid, @ptrToInt(rgid), @ptrToInt(egid), @ptrToInt(sgid)); | |
| 383 | } | |
| 384 | ||
| 385 | pub fn setresuid(ruid: u32, euid: u32, suid: u32) usize { | |
| 386 | return syscall3(SYS_setresuid, ruid, euid, suid); | |
| 387 | } | |
| 388 | ||
| 389 | pub fn setresgid(rgid: u32, egid: u32, sgid: u32) usize { | |
| 390 | return syscall3(SYS_setresgid, rgid, egid, sgid); | |
| 391 | } | |
| 392 | ||
| 393 | pub fn getgroups(size: usize, list: *u32) usize { | |
| 394 | return syscall2(SYS_getgroups, size, @ptrToInt(list)); | |
| 395 | } | |
| 396 | ||
| 397 | pub fn setgroups(size: usize, list: *const u32) usize { | |
| 398 | return syscall2(SYS_setgroups, size, @ptrToInt(list)); | |
| 399 | } | |
| 400 | ||
| 401 | pub fn getpid() i32 { | |
| 402 | return @bitCast(i32, @truncate(u32, syscall0(SYS_getpid))); | |
| 403 | } | |
| 404 | ||
| 405 | pub fn gettid() i32 { | |
| 406 | return @bitCast(i32, @truncate(u32, syscall0(SYS_gettid))); | |
| 407 | } | |
| 408 | ||
| 409 | pub fn sigprocmask(flags: u32, noalias set: *const sigset_t, noalias oldset: ?*sigset_t) usize { | |
| 410 | return syscall4(SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG / 8); | |
| 411 | } | |
| 412 | ||
| 413 | pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigaction) usize { | |
| 414 | assert(sig >= 1); | |
| 415 | assert(sig != SIGKILL); | |
| 416 | assert(sig != SIGSTOP); | |
| 417 | var ksa = k_sigaction{ | |
| 418 | .handler = act.handler, | |
| 419 | .flags = act.flags | SA_RESTORER, | |
| 420 | .mask = undefined, | |
| 421 | .restorer = @ptrCast(extern fn () void, restore_rt), | |
| 422 | }; | |
| 423 | var ksa_old: k_sigaction = undefined; | |
| 424 | @memcpy(@ptrCast([*]u8, &ksa.mask), @ptrCast([*]const u8, &act.mask), 8); | |
| 425 | const result = syscall4(SYS_rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), @sizeOf(@typeOf(ksa.mask))); | |
| 426 | const err = getErrno(result); | |
| 427 | if (err != 0) { | |
| 428 | return result; | |
| 429 | } | |
| 430 | if (oact) |old| { | |
| 431 | old.handler = ksa_old.handler; | |
| 432 | old.flags = @truncate(u32, ksa_old.flags); | |
| 433 | @memcpy(@ptrCast([*]u8, &old.mask), @ptrCast([*]const u8, &ksa_old.mask), @sizeOf(@typeOf(ksa_old.mask))); | |
| 434 | } | |
| 435 | return 0; | |
| 436 | } | |
| 437 | ||
| 438 | fn blockAllSignals(set: *sigset_t) void { | |
| 439 | _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG / 8); | |
| 440 | } | |
| 441 | ||
| 442 | fn blockAppSignals(set: *sigset_t) void { | |
| 443 | _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG / 8); | |
| 444 | } | |
| 445 | ||
| 446 | fn restoreSignals(set: *sigset_t) void { | |
| 447 | _ = syscall4(SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG / 8); | |
| 448 | } | |
| 449 | ||
| 450 | pub fn sigaddset(set: *sigset_t, sig: u6) void { | |
| 451 | const s = sig - 1; | |
| 452 | (set.*)[@intCast(usize, s) / usize.bit_count] |= @intCast(usize, 1) << (s & (usize.bit_count - 1)); | |
| 453 | } | |
| 454 | ||
| 455 | pub fn sigismember(set: *const sigset_t, sig: u6) bool { | |
| 456 | const s = sig - 1; | |
| 457 | return ((set.*)[@intCast(usize, s) / usize.bit_count] & (@intCast(usize, 1) << (s & (usize.bit_count - 1)))) != 0; | |
| 458 | } | |
| 459 | ||
| 460 | pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { | |
| 461 | return syscall3(SYS_getsockname, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len)); | |
| 462 | } | |
| 463 | ||
| 464 | pub fn getpeername(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { | |
| 465 | return syscall3(SYS_getpeername, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len)); | |
| 466 | } | |
| 467 | ||
| 468 | pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize { | |
| 469 | return syscall3(SYS_socket, domain, socket_type, protocol); | |
| 470 | } | |
| 471 | ||
| 472 | pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: [*]const u8, optlen: socklen_t) usize { | |
| 473 | return syscall5(SYS_setsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen)); | |
| 474 | } | |
| 475 | ||
| 476 | pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noalias optlen: *socklen_t) usize { | |
| 477 | return syscall5(SYS_getsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen)); | |
| 478 | } | |
| 479 | ||
| 480 | pub fn sendmsg(fd: i32, msg: *msghdr_const, flags: u32) usize { | |
| 481 | return syscall3(SYS_sendmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags); | |
| 482 | } | |
| 483 | ||
| 484 | pub fn sendmmsg(fd: i32, msgvec: [*]mmsghdr_const, vlen: u32, flags: u32) usize { | |
| 485 | if (@typeInfo(usize).Int.bits > @typeInfo(@typeOf(mmsghdr(undefined).msg_len)).Int.bits) { | |
| 486 | // workaround kernel brokenness: | |
| 487 | // if adding up all iov_len overflows a i32 then split into multiple calls | |
| 488 | // see https://www.openwall.com/lists/musl/2014/06/07/5 | |
| 489 | const kvlen = if (vlen > IOV_MAX) IOV_MAX else vlen; // matches kernel | |
| 490 | var next_unsent: usize = 0; | |
| 491 | for (msgvec[0..kvlen]) |*msg, i| { | |
| 492 | var size: i32 = 0; | |
| 493 | const msg_iovlen = @intCast(usize, msg.msg_hdr.msg_iovlen); // kernel side this is treated as unsigned | |
| 494 | for (msg.msg_hdr.msg_iov[0..msg_iovlen]) |iov, j| { | |
| 495 | if (iov.iov_len > std.math.maxInt(i32) or @addWithOverflow(i32, size, @intCast(i32, iov.iov_len), &size)) { | |
| 496 | // batch-send all messages up to the current message | |
| 497 | if (next_unsent < i) { | |
| 498 | const batch_size = i - next_unsent; | |
| 499 | const r = syscall4(SYS_sendmmsg, @bitCast(usize, isize(fd)), @ptrToInt(&msgvec[next_unsent]), batch_size, flags); | |
| 500 | if (getErrno(r) != 0) return next_unsent; | |
| 501 | if (r < batch_size) return next_unsent + r; | |
| 502 | } | |
| 503 | // send current message as own packet | |
| 504 | const r = sendmsg(fd, &msg.msg_hdr, flags); | |
| 505 | if (getErrno(r) != 0) return r; | |
| 506 | // Linux limits the total bytes sent by sendmsg to INT_MAX, so this cast is safe. | |
| 507 | msg.msg_len = @intCast(u32, r); | |
| 508 | next_unsent = i + 1; | |
| 509 | break; | |
| 510 | } | |
| 511 | } | |
| 512 | } | |
| 513 | if (next_unsent < kvlen or next_unsent == 0) { // want to make sure at least one syscall occurs (e.g. to trigger MSG_EOR) | |
| 514 | const batch_size = kvlen - next_unsent; | |
| 515 | const r = syscall4(SYS_sendmmsg, @bitCast(usize, isize(fd)), @ptrToInt(&msgvec[next_unsent]), batch_size, flags); | |
| 516 | if (getErrno(r) != 0) return r; | |
| 517 | return next_unsent + r; | |
| 518 | } | |
| 519 | return kvlen; | |
| 520 | } | |
| 521 | return syscall4(SYS_sendmmsg, @bitCast(usize, isize(fd)), @ptrToInt(msgvec), vlen, flags); | |
| 522 | } | |
| 523 | ||
| 524 | pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize { | |
| 525 | return syscall3(SYS_connect, @bitCast(usize, isize(fd)), @ptrToInt(addr), len); | |
| 526 | } | |
| 527 | ||
| 528 | pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize { | |
| 529 | return syscall3(SYS_recvmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags); | |
| 530 | } | |
| 531 | ||
| 532 | pub fn recvfrom(fd: i32, noalias buf: [*]u8, len: usize, flags: u32, noalias addr: ?*sockaddr, noalias alen: ?*socklen_t) usize { | |
| 533 | return syscall6(SYS_recvfrom, @bitCast(usize, isize(fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen)); | |
| 534 | } | |
| 535 | ||
| 536 | pub fn shutdown(fd: i32, how: i32) usize { | |
| 537 | return syscall2(SYS_shutdown, @bitCast(usize, isize(fd)), @bitCast(usize, isize(how))); | |
| 538 | } | |
| 539 | ||
| 540 | pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize { | |
| 541 | return syscall3(SYS_bind, @bitCast(usize, isize(fd)), @ptrToInt(addr), @intCast(usize, len)); | |
| 542 | } | |
| 543 | ||
| 544 | pub fn listen(fd: i32, backlog: u32) usize { | |
| 545 | return syscall2(SYS_listen, @bitCast(usize, isize(fd)), backlog); | |
| 546 | } | |
| 547 | ||
| 548 | pub fn sendto(fd: i32, buf: [*]const u8, len: usize, flags: u32, addr: ?*const sockaddr, alen: socklen_t) usize { | |
| 549 | return syscall6(SYS_sendto, @bitCast(usize, isize(fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen)); | |
| 550 | } | |
| 551 | ||
| 552 | pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize { | |
| 553 | return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0])); | |
| 554 | } | |
| 555 | ||
| 556 | pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { | |
| 557 | return accept4(fd, addr, len, 0); | |
| 558 | } | |
| 559 | ||
| 560 | pub fn accept4(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t, flags: u32) usize { | |
| 561 | return syscall4(SYS_accept4, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len), flags); | |
| 562 | } | |
| 563 | ||
| 564 | pub fn fstat(fd: i32, stat_buf: *Stat) usize { | |
| 565 | return syscall2(SYS_fstat, @bitCast(usize, isize(fd)), @ptrToInt(stat_buf)); | |
| 566 | } | |
| 567 | ||
| 568 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 569 | pub fn stat(pathname: [*]const u8, statbuf: *Stat) usize { | |
| 570 | return syscall2(SYS_stat, @ptrToInt(pathname), @ptrToInt(statbuf)); | |
| 571 | } | |
| 572 | ||
| 573 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 574 | pub fn lstat(pathname: [*]const u8, statbuf: *Stat) usize { | |
| 575 | return syscall2(SYS_lstat, @ptrToInt(pathname), @ptrToInt(statbuf)); | |
| 576 | } | |
| 577 | ||
| 578 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 579 | pub fn fstatat(dirfd: i32, path: [*]const u8, stat_buf: *Stat, flags: u32) usize { | |
| 580 | return syscall4(SYS_fstatat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(stat_buf), flags); | |
| 581 | } | |
| 582 | ||
| 583 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 584 | pub fn listxattr(path: [*]const u8, list: [*]u8, size: usize) usize { | |
| 585 | return syscall3(SYS_listxattr, @ptrToInt(path), @ptrToInt(list), size); | |
| 586 | } | |
| 587 | ||
| 588 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 589 | pub fn llistxattr(path: [*]const u8, list: [*]u8, size: usize) usize { | |
| 590 | return syscall3(SYS_llistxattr, @ptrToInt(path), @ptrToInt(list), size); | |
| 591 | } | |
| 592 | ||
| 593 | pub fn flistxattr(fd: usize, list: [*]u8, size: usize) usize { | |
| 594 | return syscall3(SYS_flistxattr, fd, @ptrToInt(list), size); | |
| 595 | } | |
| 596 | ||
| 597 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 598 | pub fn getxattr(path: [*]const u8, name: [*]const u8, value: [*]u8, size: usize) usize { | |
| 599 | return syscall4(SYS_getxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size); | |
| 600 | } | |
| 601 | ||
| 602 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 603 | pub fn lgetxattr(path: [*]const u8, name: [*]const u8, value: [*]u8, size: usize) usize { | |
| 604 | return syscall4(SYS_lgetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size); | |
| 605 | } | |
| 606 | ||
| 607 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 608 | pub fn fgetxattr(fd: usize, name: [*]const u8, value: [*]u8, size: usize) usize { | |
| 609 | return syscall4(SYS_lgetxattr, fd, @ptrToInt(name), @ptrToInt(value), size); | |
| 610 | } | |
| 611 | ||
| 612 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 613 | pub fn setxattr(path: [*]const u8, name: [*]const u8, value: *const void, size: usize, flags: usize) usize { | |
| 614 | return syscall5(SYS_setxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size, flags); | |
| 615 | } | |
| 616 | ||
| 617 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 618 | pub fn lsetxattr(path: [*]const u8, name: [*]const u8, value: *const void, size: usize, flags: usize) usize { | |
| 619 | return syscall5(SYS_lsetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size, flags); | |
| 620 | } | |
| 621 | ||
| 622 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 623 | pub fn fsetxattr(fd: usize, name: [*]const u8, value: *const void, size: usize, flags: usize) usize { | |
| 624 | return syscall5(SYS_fsetxattr, fd, @ptrToInt(name), @ptrToInt(value), size, flags); | |
| 625 | } | |
| 626 | ||
| 627 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 628 | pub fn removexattr(path: [*]const u8, name: [*]const u8) usize { | |
| 629 | return syscall2(SYS_removexattr, @ptrToInt(path), @ptrToInt(name)); | |
| 630 | } | |
| 631 | ||
| 632 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 633 | pub fn lremovexattr(path: [*]const u8, name: [*]const u8) usize { | |
| 634 | return syscall2(SYS_lremovexattr, @ptrToInt(path), @ptrToInt(name)); | |
| 635 | } | |
| 636 | ||
| 637 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 638 | pub fn fremovexattr(fd: usize, name: [*]const u8) usize { | |
| 639 | return syscall2(SYS_fremovexattr, fd, @ptrToInt(name)); | |
| 640 | } | |
| 641 | ||
| 642 | pub fn sched_getaffinity(pid: i32, set: []usize) usize { | |
| 643 | return syscall3(SYS_sched_getaffinity, @bitCast(usize, isize(pid)), set.len * @sizeOf(usize), @ptrToInt(set.ptr)); | |
| 644 | } | |
| 645 | ||
| 646 | pub fn epoll_create() usize { | |
| 647 | return epoll_create1(0); | |
| 648 | } | |
| 649 | ||
| 650 | pub fn epoll_create1(flags: usize) usize { | |
| 651 | return syscall1(SYS_epoll_create1, flags); | |
| 652 | } | |
| 653 | ||
| 654 | pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: *epoll_event) usize { | |
| 655 | return syscall4(SYS_epoll_ctl, @bitCast(usize, isize(epoll_fd)), @intCast(usize, op), @bitCast(usize, isize(fd)), @ptrToInt(ev)); | |
| 656 | } | |
| 657 | ||
| 658 | pub fn epoll_wait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32) usize { | |
| 659 | return syscall4( | |
| 660 | SYS_epoll_wait, | |
| 661 | @bitCast(usize, isize(epoll_fd)), | |
| 662 | @ptrToInt(events), | |
| 663 | maxevents, | |
| 664 | @bitCast(usize, isize(timeout)), | |
| 665 | ); | |
| 666 | } | |
| 667 | ||
| 668 | pub fn epoll_pwait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32, sigmask: ?*sigset_t) usize { | |
| 669 | return syscall6( | |
| 670 | SYS_epoll_pwait, | |
| 671 | @bitCast(usize, isize(epoll_fd)), | |
| 672 | @ptrToInt(events), | |
| 673 | @intCast(usize, maxevents), | |
| 674 | @bitCast(usize, isize(timeout)), | |
| 675 | @ptrToInt(sigmask), | |
| 676 | @sizeOf(sigset_t), | |
| 677 | ); | |
| 678 | } | |
| 679 | ||
| 680 | pub fn eventfd(count: u32, flags: u32) usize { | |
| 681 | return syscall2(SYS_eventfd2, count, flags); | |
| 682 | } | |
| 683 | ||
| 684 | pub fn timerfd_create(clockid: i32, flags: u32) usize { | |
| 685 | return syscall2(SYS_timerfd_create, @bitCast(usize, isize(clockid)), flags); | |
| 686 | } | |
| 687 | ||
| 688 | pub const itimerspec = extern struct { | |
| 689 | it_interval: timespec, | |
| 690 | it_value: timespec, | |
| 691 | }; | |
| 692 | ||
| 693 | pub fn timerfd_gettime(fd: i32, curr_value: *itimerspec) usize { | |
| 694 | return syscall2(SYS_timerfd_gettime, @bitCast(usize, isize(fd)), @ptrToInt(curr_value)); | |
| 695 | } | |
| 696 | ||
| 697 | pub fn timerfd_settime(fd: i32, flags: u32, new_value: *const itimerspec, old_value: ?*itimerspec) usize { | |
| 698 | return syscall4(SYS_timerfd_settime, @bitCast(usize, isize(fd)), flags, @ptrToInt(new_value), @ptrToInt(old_value)); | |
| 699 | } | |
| 700 | ||
| 701 | pub fn unshare(flags: usize) usize { | |
| 702 | return syscall1(SYS_unshare, flags); | |
| 703 | } | |
| 704 | ||
| 705 | pub fn capget(hdrp: *cap_user_header_t, datap: *cap_user_data_t) usize { | |
| 706 | return syscall2(SYS_capget, @ptrToInt(hdrp), @ptrToInt(datap)); | |
| 707 | } | |
| 708 | ||
| 709 | pub fn capset(hdrp: *cap_user_header_t, datap: *const cap_user_data_t) usize { | |
| 710 | return syscall2(SYS_capset, @ptrToInt(hdrp), @ptrToInt(datap)); | |
| 711 | } | |
| 712 | ||
| 713 | // XXX: This should be weak | |
| 714 | extern const __ehdr_start: elf.Ehdr = undefined; | |
| 715 | ||
| 716 | pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_info, size: usize, data: ?*T) i32, data: ?*T) isize { | |
| 717 | if (builtin.link_libc) { | |
| 718 | return std.c.dl_iterate_phdr(@ptrCast(std.c.dl_iterate_phdr_callback, callback), @ptrCast(?*c_void, data)); | |
| 719 | } | |
| 720 | ||
| 721 | const elf_base = @ptrToInt(&__ehdr_start); | |
| 722 | const n_phdr = __ehdr_start.e_phnum; | |
| 723 | const phdrs = (@intToPtr([*]elf.Phdr, elf_base + __ehdr_start.e_phoff))[0..n_phdr]; | |
| 724 | ||
| 725 | var it = dl.linkmap_iterator(phdrs) catch return 0; | |
| 726 | ||
| 727 | // The executable has no dynamic link segment, create a single entry for | |
| 728 | // the whole ELF image | |
| 729 | if (it.end()) { | |
| 730 | var info = dl_phdr_info{ | |
| 731 | .dlpi_addr = elf_base, | |
| 732 | .dlpi_name = c"/proc/self/exe", | |
| 733 | .dlpi_phdr = @intToPtr([*]elf.Phdr, elf_base + __ehdr_start.e_phoff), | |
| 734 | .dlpi_phnum = __ehdr_start.e_phnum, | |
| 735 | }; | |
| 736 | ||
| 737 | return callback(&info, @sizeOf(dl_phdr_info), data); | |
| 738 | } | |
| 739 | ||
| 740 | // Last return value from the callback function | |
| 741 | var last_r: isize = 0; | |
| 742 | while (it.next()) |entry| { | |
| 743 | var dlpi_phdr: usize = undefined; | |
| 744 | var dlpi_phnum: u16 = undefined; | |
| 745 | ||
| 746 | if (entry.l_addr != 0) { | |
| 747 | const elf_header = @intToPtr(*elf.Ehdr, entry.l_addr); | |
| 748 | dlpi_phdr = entry.l_addr + elf_header.e_phoff; | |
| 749 | dlpi_phnum = elf_header.e_phnum; | |
| 750 | } else { | |
| 751 | // This is the running ELF image | |
| 752 | dlpi_phdr = elf_base + __ehdr_start.e_phoff; | |
| 753 | dlpi_phnum = __ehdr_start.e_phnum; | |
| 754 | } | |
| 755 | ||
| 756 | var info = dl_phdr_info{ | |
| 757 | .dlpi_addr = entry.l_addr, | |
| 758 | .dlpi_name = entry.l_name, | |
| 759 | .dlpi_phdr = @intToPtr([*]elf.Phdr, dlpi_phdr), | |
| 760 | .dlpi_phnum = dlpi_phnum, | |
| 761 | }; | |
| 762 | ||
| 763 | last_r = callback(&info, @sizeOf(dl_phdr_info), data); | |
| 764 | if (last_r != 0) break; | |
| 765 | } | |
| 766 | ||
| 767 | return last_r; | |
| 768 | } | |
| 4 | pub const sys = @import("linux/sys.zig"); | |
| 5 | pub use if (builtin.link_libc) std.c else sys; | |
| 769 | 6 | |
| 770 | 7 | test "import" { |
| 771 | 8 | if (is_the_target) { |
std/os/linux/sys.zig created+847| ... | ... | @@ -0,0 +1,847 @@ |
| 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. | |
| 8 | const std = @import("../../std.zig"); | |
| 9 | const builtin = @import("builtin"); | |
| 10 | const assert = std.debug.assert; | |
| 11 | const maxInt = std.math.maxInt; | |
| 12 | const elf = std.elf; | |
| 13 | const vdso = @import("vdso.zig"); | |
| 14 | const dl = @import("../../dynamic_library.zig"); | |
| 15 | pub use switch (builtin.arch) { | |
| 16 | .x86_64 => @import("x86_64.zig"), | |
| 17 | .aarch64 => @import("arm64.zig"), | |
| 18 | else => struct {}, | |
| 19 | }; | |
| 20 | pub const posix = @import("posix.zig"); | |
| 21 | pub use posix; | |
| 22 | ||
| 23 | /// See `std.os.posix.getauxval`. | |
| 24 | pub var elf_aux_maybe: ?[*]std.elf.Auxv = null; | |
| 25 | ||
| 26 | /// Get the errno from a syscall return value, or 0 for no error. | |
| 27 | pub fn getErrno(r: usize) u12 { | |
| 28 | const signed_r = @bitCast(isize, r); | |
| 29 | return if (signed_r > -4096 and signed_r < 0) @intCast(u12, -signed_r) else 0; | |
| 30 | } | |
| 31 | ||
| 32 | pub fn dup2(old: i32, new: i32) usize { | |
| 33 | if (@hasDecl(@This(), "SYS_dup2")) { | |
| 34 | return syscall2(SYS_dup2, @bitCast(usize, isize(old)), @bitCast(usize, isize(new))); | |
| 35 | } else { | |
| 36 | if (old == new) { | |
| 37 | if (std.debug.runtime_safety) { | |
| 38 | const rc = syscall2(SYS_fcntl, @bitCast(usize, isize(old)), F_GETFD); | |
| 39 | if (@bitCast(isize, rc) < 0) return rc; | |
| 40 | } | |
| 41 | return @intCast(usize, old); | |
| 42 | } else { | |
| 43 | return syscall3(SYS_dup3, @bitCast(usize, isize(old)), @bitCast(usize, isize(new)), 0); | |
| 44 | } | |
| 45 | } | |
| 46 | } | |
| 47 | ||
| 48 | pub fn dup3(old: i32, new: i32, flags: u32) usize { | |
| 49 | return syscall3(SYS_dup3, @bitCast(usize, isize(old)), @bitCast(usize, isize(new)), flags); | |
| 50 | } | |
| 51 | ||
| 52 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 53 | pub fn chdir(path: [*]const u8) usize { | |
| 54 | return syscall1(SYS_chdir, @ptrToInt(path)); | |
| 55 | } | |
| 56 | ||
| 57 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 58 | pub fn chroot(path: [*]const u8) usize { | |
| 59 | return syscall1(SYS_chroot, @ptrToInt(path)); | |
| 60 | } | |
| 61 | ||
| 62 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 63 | pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize { | |
| 64 | return syscall3(SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp)); | |
| 65 | } | |
| 66 | ||
| 67 | pub fn fork() usize { | |
| 68 | if (@hasDecl(@This(), "SYS_fork")) { | |
| 69 | return syscall0(SYS_fork); | |
| 70 | } else { | |
| 71 | return syscall2(SYS_clone, SIGCHLD, 0); | |
| 72 | } | |
| 73 | } | |
| 74 | ||
| 75 | /// This must be inline, and inline call the syscall function, because if the | |
| 76 | /// child does a return it will clobber the parent's stack. | |
| 77 | /// It is advised to avoid this function and use clone instead, because | |
| 78 | /// the compiler is not aware of how vfork affects control flow and you may | |
| 79 | /// see different results in optimized builds. | |
| 80 | pub inline fn vfork() usize { | |
| 81 | return @inlineCall(syscall0, SYS_vfork); | |
| 82 | } | |
| 83 | ||
| 84 | pub fn futex_wait(uaddr: *const i32, futex_op: u32, val: i32, timeout: ?*timespec) usize { | |
| 85 | return syscall4(SYS_futex, @ptrToInt(uaddr), futex_op, @bitCast(u32, val), @ptrToInt(timeout)); | |
| 86 | } | |
| 87 | ||
| 88 | pub fn futex_wake(uaddr: *const i32, futex_op: u32, val: i32) usize { | |
| 89 | return syscall3(SYS_futex, @ptrToInt(uaddr), futex_op, @bitCast(u32, val)); | |
| 90 | } | |
| 91 | ||
| 92 | pub fn getcwd(buf: [*]u8, size: usize) usize { | |
| 93 | return syscall2(SYS_getcwd, @ptrToInt(buf), size); | |
| 94 | } | |
| 95 | ||
| 96 | pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize { | |
| 97 | return syscall3(SYS_getdents, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count); | |
| 98 | } | |
| 99 | ||
| 100 | pub fn getdents64(fd: i32, dirp: [*]u8, count: usize) usize { | |
| 101 | return syscall3(SYS_getdents64, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count); | |
| 102 | } | |
| 103 | ||
| 104 | pub fn inotify_init1(flags: u32) usize { | |
| 105 | return syscall1(SYS_inotify_init1, flags); | |
| 106 | } | |
| 107 | ||
| 108 | pub fn inotify_add_watch(fd: i32, pathname: [*]const u8, mask: u32) usize { | |
| 109 | return syscall3(SYS_inotify_add_watch, @bitCast(usize, isize(fd)), @ptrToInt(pathname), mask); | |
| 110 | } | |
| 111 | ||
| 112 | pub fn inotify_rm_watch(fd: i32, wd: i32) usize { | |
| 113 | return syscall2(SYS_inotify_rm_watch, @bitCast(usize, isize(fd)), @bitCast(usize, isize(wd))); | |
| 114 | } | |
| 115 | ||
| 116 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 117 | pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize { | |
| 118 | if (@hasDecl(@This(), "SYS_readlink")) { | |
| 119 | return syscall3(SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len); | |
| 120 | } else { | |
| 121 | return syscall4(SYS_readlinkat, AT_FDCWD, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len); | |
| 122 | } | |
| 123 | } | |
| 124 | ||
| 125 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 126 | pub fn readlinkat(dirfd: i32, noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize { | |
| 127 | return syscall4(SYS_readlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(buf_ptr), buf_len); | |
| 128 | } | |
| 129 | ||
| 130 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 131 | pub fn mkdir(path: [*]const u8, mode: u32) usize { | |
| 132 | if (@hasDecl(@This(), "SYS_mkdir")) { | |
| 133 | return syscall2(SYS_mkdir, @ptrToInt(path), mode); | |
| 134 | } else { | |
| 135 | return syscall3(SYS_mkdirat, AT_FDCWD, @ptrToInt(path), mode); | |
| 136 | } | |
| 137 | } | |
| 138 | ||
| 139 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 140 | pub fn mkdirat(dirfd: i32, path: [*]const u8, mode: u32) usize { | |
| 141 | return syscall3(SYS_mkdirat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode); | |
| 142 | } | |
| 143 | ||
| 144 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 145 | pub fn mount(special: [*]const u8, dir: [*]const u8, fstype: [*]const u8, flags: u32, data: usize) usize { | |
| 146 | return syscall5(SYS_mount, @ptrToInt(special), @ptrToInt(dir), @ptrToInt(fstype), flags, data); | |
| 147 | } | |
| 148 | ||
| 149 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 150 | pub fn umount(special: [*]const u8) usize { | |
| 151 | return syscall2(SYS_umount2, @ptrToInt(special), 0); | |
| 152 | } | |
| 153 | ||
| 154 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 155 | pub fn umount2(special: [*]const u8, flags: u32) usize { | |
| 156 | return syscall2(SYS_umount2, @ptrToInt(special), flags); | |
| 157 | } | |
| 158 | ||
| 159 | pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize { | |
| 160 | return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @bitCast(usize, isize(fd)), @bitCast(usize, offset)); | |
| 161 | } | |
| 162 | ||
| 163 | pub fn mprotect(address: usize, length: usize, protection: usize) usize { | |
| 164 | return syscall3(SYS_mprotect, address, length, protection); | |
| 165 | } | |
| 166 | ||
| 167 | pub fn munmap(address: usize, length: usize) usize { | |
| 168 | return syscall2(SYS_munmap, address, length); | |
| 169 | } | |
| 170 | ||
| 171 | pub fn read(fd: i32, buf: [*]u8, count: usize) usize { | |
| 172 | return syscall3(SYS_read, @bitCast(usize, isize(fd)), @ptrToInt(buf), count); | |
| 173 | } | |
| 174 | ||
| 175 | pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: u64) usize { | |
| 176 | return syscall4(SYS_preadv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset); | |
| 177 | } | |
| 178 | ||
| 179 | pub fn readv(fd: i32, iov: [*]const iovec, count: usize) usize { | |
| 180 | return syscall3(SYS_readv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count); | |
| 181 | } | |
| 182 | ||
| 183 | pub fn writev(fd: i32, iov: [*]const iovec_const, count: usize) usize { | |
| 184 | return syscall3(SYS_writev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count); | |
| 185 | } | |
| 186 | ||
| 187 | pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) usize { | |
| 188 | return syscall4(SYS_pwritev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset); | |
| 189 | } | |
| 190 | ||
| 191 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 192 | pub fn rmdir(path: [*]const u8) usize { | |
| 193 | if (@hasDecl(@This(), "SYS_rmdir")) { | |
| 194 | return syscall1(SYS_rmdir, @ptrToInt(path)); | |
| 195 | } else { | |
| 196 | return syscall3(SYS_unlinkat, AT_FDCWD, @ptrToInt(path), AT_REMOVEDIR); | |
| 197 | } | |
| 198 | } | |
| 199 | ||
| 200 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 201 | pub fn symlink(existing: [*]const u8, new: [*]const u8) usize { | |
| 202 | if (@hasDecl(@This(), "SYS_symlink")) { | |
| 203 | return syscall2(SYS_symlink, @ptrToInt(existing), @ptrToInt(new)); | |
| 204 | } else { | |
| 205 | return syscall3(SYS_symlinkat, @ptrToInt(existing), AT_FDCWD, @ptrToInt(new)); | |
| 206 | } | |
| 207 | } | |
| 208 | ||
| 209 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 210 | pub fn symlinkat(existing: [*]const u8, newfd: i32, newpath: [*]const u8) usize { | |
| 211 | return syscall3(SYS_symlinkat, @ptrToInt(existing), @bitCast(usize, isize(newfd)), @ptrToInt(newpath)); | |
| 212 | } | |
| 213 | ||
| 214 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 215 | pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize { | |
| 216 | return syscall4(SYS_pread, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset); | |
| 217 | } | |
| 218 | ||
| 219 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 220 | pub fn access(path: [*]const u8, mode: u32) usize { | |
| 221 | return syscall2(SYS_access, @ptrToInt(path), mode); | |
| 222 | } | |
| 223 | ||
| 224 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 225 | pub fn faccessat(dirfd: i32, path: [*]const u8, mode: u32) usize { | |
| 226 | return syscall3(SYS_faccessat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode); | |
| 227 | } | |
| 228 | ||
| 229 | pub fn pipe(fd: *[2]i32) usize { | |
| 230 | if (@hasDecl(@This(), "SYS_pipe")) { | |
| 231 | return syscall1(SYS_pipe, @ptrToInt(fd)); | |
| 232 | } else { | |
| 233 | return syscall2(SYS_pipe2, @ptrToInt(fd), 0); | |
| 234 | } | |
| 235 | } | |
| 236 | ||
| 237 | pub fn pipe2(fd: *[2]i32, flags: u32) usize { | |
| 238 | return syscall2(SYS_pipe2, @ptrToInt(fd), flags); | |
| 239 | } | |
| 240 | ||
| 241 | pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { | |
| 242 | return syscall3(SYS_write, @bitCast(usize, isize(fd)), @ptrToInt(buf), count); | |
| 243 | } | |
| 244 | ||
| 245 | pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize { | |
| 246 | return syscall4(SYS_pwrite, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset); | |
| 247 | } | |
| 248 | ||
| 249 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 250 | pub fn rename(old: [*]const u8, new: [*]const u8) usize { | |
| 251 | if (@hasDecl(@This(), "SYS_rename")) { | |
| 252 | return syscall2(SYS_rename, @ptrToInt(old), @ptrToInt(new)); | |
| 253 | } else if (@hasDecl(@This(), "SYS_renameat")) { | |
| 254 | return syscall4(SYS_renameat, AT_FDCWD, @ptrToInt(old), AT_FDCWD, @ptrToInt(new)); | |
| 255 | } else { | |
| 256 | return syscall5(SYS_renameat2, AT_FDCWD, @ptrToInt(old), AT_FDCWD, @ptrToInt(new), 0); | |
| 257 | } | |
| 258 | } | |
| 259 | ||
| 260 | pub fn renameat(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const u8) usize { | |
| 261 | if (@hasDecl(@This(), "SYS_renameat")) { | |
| 262 | return syscall4( | |
| 263 | SYS_renameat, | |
| 264 | @bitCast(usize, isize(oldfd)), | |
| 265 | @ptrToInt(old), | |
| 266 | @bitCast(usize, isize(newfd)), | |
| 267 | @ptrToInt(new), | |
| 268 | ); | |
| 269 | } else { | |
| 270 | return syscall5( | |
| 271 | SYS_renameat2, | |
| 272 | @bitCast(usize, isize(oldfd)), | |
| 273 | @ptrToInt(old), | |
| 274 | @bitCast(usize, isize(newfd)), | |
| 275 | @ptrToInt(new), | |
| 276 | 0, | |
| 277 | ); | |
| 278 | } | |
| 279 | } | |
| 280 | ||
| 281 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 282 | pub fn renameat2(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const u8, flags: u32) usize { | |
| 283 | return syscall5( | |
| 284 | SYS_renameat2, | |
| 285 | @bitCast(usize, isize(oldfd)), | |
| 286 | @ptrToInt(oldpath), | |
| 287 | @bitCast(usize, isize(newfd)), | |
| 288 | @ptrToInt(newpath), | |
| 289 | flags, | |
| 290 | ); | |
| 291 | } | |
| 292 | ||
| 293 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 294 | pub fn open(path: [*]const u8, flags: u32, perm: usize) usize { | |
| 295 | return syscall3(SYS_open, @ptrToInt(path), flags, perm); | |
| 296 | } | |
| 297 | ||
| 298 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 299 | pub fn create(path: [*]const u8, perm: usize) usize { | |
| 300 | return syscall2(SYS_creat, @ptrToInt(path), perm); | |
| 301 | } | |
| 302 | ||
| 303 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 304 | pub fn openat(dirfd: i32, path: [*]const u8, flags: u32, mode: usize) usize { | |
| 305 | // dirfd could be negative, for example AT_FDCWD is -100 | |
| 306 | return syscall4(SYS_openat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode); | |
| 307 | } | |
| 308 | ||
| 309 | /// See also `clone` (from the arch-specific include) | |
| 310 | pub fn clone5(flags: usize, child_stack_ptr: usize, parent_tid: *i32, child_tid: *i32, newtls: usize) usize { | |
| 311 | return syscall5(SYS_clone, flags, child_stack_ptr, @ptrToInt(parent_tid), @ptrToInt(child_tid), newtls); | |
| 312 | } | |
| 313 | ||
| 314 | /// See also `clone` (from the arch-specific include) | |
| 315 | pub fn clone2(flags: u32, child_stack_ptr: usize) usize { | |
| 316 | return syscall2(SYS_clone, flags, child_stack_ptr); | |
| 317 | } | |
| 318 | ||
| 319 | pub fn close(fd: i32) usize { | |
| 320 | return syscall1(SYS_close, @bitCast(usize, isize(fd))); | |
| 321 | } | |
| 322 | ||
| 323 | pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize { | |
| 324 | return syscall3(SYS_lseek, @bitCast(usize, isize(fd)), @bitCast(usize, offset), ref_pos); | |
| 325 | } | |
| 326 | ||
| 327 | pub fn exit(status: i32) noreturn { | |
| 328 | _ = syscall1(SYS_exit, @bitCast(usize, isize(status))); | |
| 329 | unreachable; | |
| 330 | } | |
| 331 | ||
| 332 | pub fn exit_group(status: i32) noreturn { | |
| 333 | _ = syscall1(SYS_exit_group, @bitCast(usize, isize(status))); | |
| 334 | unreachable; | |
| 335 | } | |
| 336 | ||
| 337 | pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize { | |
| 338 | return syscall3(SYS_getrandom, @ptrToInt(buf), count, flags); | |
| 339 | } | |
| 340 | ||
| 341 | pub fn kill(pid: i32, sig: i32) usize { | |
| 342 | return syscall2(SYS_kill, @bitCast(usize, isize(pid)), @bitCast(usize, isize(sig))); | |
| 343 | } | |
| 344 | ||
| 345 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 346 | pub fn unlink(path: [*]const u8) usize { | |
| 347 | if (@hasDecl(@This(), "SYS_unlink")) { | |
| 348 | return syscall1(SYS_unlink, @ptrToInt(path)); | |
| 349 | } else { | |
| 350 | return syscall3(SYS_unlinkat, AT_FDCWD, @ptrToInt(path), 0); | |
| 351 | } | |
| 352 | } | |
| 353 | ||
| 354 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 355 | pub fn unlinkat(dirfd: i32, path: [*]const u8, flags: u32) usize { | |
| 356 | return syscall3(SYS_unlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags); | |
| 357 | } | |
| 358 | ||
| 359 | pub fn waitpid(pid: i32, status: *i32, options: i32) usize { | |
| 360 | return syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0); | |
| 361 | } | |
| 362 | ||
| 363 | var vdso_clock_gettime = @ptrCast(?*const c_void, init_vdso_clock_gettime); | |
| 364 | ||
| 365 | // We must follow the C calling convention when we call into the VDSO | |
| 366 | const vdso_clock_gettime_ty = extern fn (i32, *timespec) usize; | |
| 367 | ||
| 368 | pub fn clock_gettime(clk_id: i32, tp: *timespec) usize { | |
| 369 | if (VDSO_CGT_SYM.len != 0) { | |
| 370 | const ptr = @atomicLoad(?*const c_void, &vdso_clock_gettime, .Unordered); | |
| 371 | if (ptr) |fn_ptr| { | |
| 372 | const f = @ptrCast(vdso_clock_gettime_ty, fn_ptr); | |
| 373 | const rc = f(clk_id, tp); | |
| 374 | switch (rc) { | |
| 375 | 0, @bitCast(usize, isize(-EINVAL)) => return rc, | |
| 376 | else => {}, | |
| 377 | } | |
| 378 | } | |
| 379 | } | |
| 380 | return syscall2(SYS_clock_gettime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp)); | |
| 381 | } | |
| 382 | ||
| 383 | extern fn init_vdso_clock_gettime(clk: i32, ts: *timespec) usize { | |
| 384 | const ptr = @intToPtr(?*const c_void, vdso.lookup(VDSO_CGT_VER, VDSO_CGT_SYM)); | |
| 385 | // Note that we may not have a VDSO at all, update the stub address anyway | |
| 386 | // so that clock_gettime will fall back on the good old (and slow) syscall | |
| 387 | _ = @cmpxchgStrong(?*const c_void, &vdso_clock_gettime, &init_vdso_clock_gettime, ptr, .Monotonic, .Monotonic); | |
| 388 | // Call into the VDSO if available | |
| 389 | if (ptr) |fn_ptr| { | |
| 390 | const f = @ptrCast(vdso_clock_gettime_ty, fn_ptr); | |
| 391 | return f(clk, ts); | |
| 392 | } | |
| 393 | return @bitCast(usize, isize(-ENOSYS)); | |
| 394 | } | |
| 395 | ||
| 396 | pub fn clock_getres(clk_id: i32, tp: *timespec) usize { | |
| 397 | return syscall2(SYS_clock_getres, @bitCast(usize, isize(clk_id)), @ptrToInt(tp)); | |
| 398 | } | |
| 399 | ||
| 400 | pub fn clock_settime(clk_id: i32, tp: *const timespec) usize { | |
| 401 | return syscall2(SYS_clock_settime, @bitCast(usize, isize(clk_id)), @ptrToInt(tp)); | |
| 402 | } | |
| 403 | ||
| 404 | pub fn gettimeofday(tv: *timeval, tz: *timezone) usize { | |
| 405 | return syscall2(SYS_gettimeofday, @ptrToInt(tv), @ptrToInt(tz)); | |
| 406 | } | |
| 407 | ||
| 408 | pub fn settimeofday(tv: *const timeval, tz: *const timezone) usize { | |
| 409 | return syscall2(SYS_settimeofday, @ptrToInt(tv), @ptrToInt(tz)); | |
| 410 | } | |
| 411 | ||
| 412 | pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize { | |
| 413 | return syscall2(SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem)); | |
| 414 | } | |
| 415 | ||
| 416 | pub fn setuid(uid: u32) usize { | |
| 417 | return syscall1(SYS_setuid, uid); | |
| 418 | } | |
| 419 | ||
| 420 | pub fn setgid(gid: u32) usize { | |
| 421 | return syscall1(SYS_setgid, gid); | |
| 422 | } | |
| 423 | ||
| 424 | pub fn setreuid(ruid: u32, euid: u32) usize { | |
| 425 | return syscall2(SYS_setreuid, ruid, euid); | |
| 426 | } | |
| 427 | ||
| 428 | pub fn setregid(rgid: u32, egid: u32) usize { | |
| 429 | return syscall2(SYS_setregid, rgid, egid); | |
| 430 | } | |
| 431 | ||
| 432 | pub fn getuid() u32 { | |
| 433 | return u32(syscall0(SYS_getuid)); | |
| 434 | } | |
| 435 | ||
| 436 | pub fn getgid() u32 { | |
| 437 | return u32(syscall0(SYS_getgid)); | |
| 438 | } | |
| 439 | ||
| 440 | pub fn geteuid() u32 { | |
| 441 | return u32(syscall0(SYS_geteuid)); | |
| 442 | } | |
| 443 | ||
| 444 | pub fn getegid() u32 { | |
| 445 | return u32(syscall0(SYS_getegid)); | |
| 446 | } | |
| 447 | ||
| 448 | pub fn seteuid(euid: u32) usize { | |
| 449 | return syscall1(SYS_seteuid, euid); | |
| 450 | } | |
| 451 | ||
| 452 | pub fn setegid(egid: u32) usize { | |
| 453 | return syscall1(SYS_setegid, egid); | |
| 454 | } | |
| 455 | ||
| 456 | pub fn getresuid(ruid: *u32, euid: *u32, suid: *u32) usize { | |
| 457 | return syscall3(SYS_getresuid, @ptrToInt(ruid), @ptrToInt(euid), @ptrToInt(suid)); | |
| 458 | } | |
| 459 | ||
| 460 | pub fn getresgid(rgid: *u32, egid: *u32, sgid: *u32) usize { | |
| 461 | return syscall3(SYS_getresgid, @ptrToInt(rgid), @ptrToInt(egid), @ptrToInt(sgid)); | |
| 462 | } | |
| 463 | ||
| 464 | pub fn setresuid(ruid: u32, euid: u32, suid: u32) usize { | |
| 465 | return syscall3(SYS_setresuid, ruid, euid, suid); | |
| 466 | } | |
| 467 | ||
| 468 | pub fn setresgid(rgid: u32, egid: u32, sgid: u32) usize { | |
| 469 | return syscall3(SYS_setresgid, rgid, egid, sgid); | |
| 470 | } | |
| 471 | ||
| 472 | pub fn getgroups(size: usize, list: *u32) usize { | |
| 473 | return syscall2(SYS_getgroups, size, @ptrToInt(list)); | |
| 474 | } | |
| 475 | ||
| 476 | pub fn setgroups(size: usize, list: *const u32) usize { | |
| 477 | return syscall2(SYS_setgroups, size, @ptrToInt(list)); | |
| 478 | } | |
| 479 | ||
| 480 | pub fn getpid() i32 { | |
| 481 | return @bitCast(i32, @truncate(u32, syscall0(SYS_getpid))); | |
| 482 | } | |
| 483 | ||
| 484 | pub fn gettid() i32 { | |
| 485 | return @bitCast(i32, @truncate(u32, syscall0(SYS_gettid))); | |
| 486 | } | |
| 487 | ||
| 488 | pub fn sigprocmask(flags: u32, noalias set: *const sigset_t, noalias oldset: ?*sigset_t) usize { | |
| 489 | return syscall4(SYS_rt_sigprocmask, flags, @ptrToInt(set), @ptrToInt(oldset), NSIG / 8); | |
| 490 | } | |
| 491 | ||
| 492 | pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigaction) usize { | |
| 493 | assert(sig >= 1); | |
| 494 | assert(sig != SIGKILL); | |
| 495 | assert(sig != SIGSTOP); | |
| 496 | var ksa = k_sigaction{ | |
| 497 | .handler = act.handler, | |
| 498 | .flags = act.flags | SA_RESTORER, | |
| 499 | .mask = undefined, | |
| 500 | .restorer = @ptrCast(extern fn () void, restore_rt), | |
| 501 | }; | |
| 502 | var ksa_old: k_sigaction = undefined; | |
| 503 | @memcpy(@ptrCast([*]u8, &ksa.mask), @ptrCast([*]const u8, &act.mask), 8); | |
| 504 | const result = syscall4(SYS_rt_sigaction, sig, @ptrToInt(&ksa), @ptrToInt(&ksa_old), @sizeOf(@typeOf(ksa.mask))); | |
| 505 | const err = getErrno(result); | |
| 506 | if (err != 0) { | |
| 507 | return result; | |
| 508 | } | |
| 509 | if (oact) |old| { | |
| 510 | old.handler = ksa_old.handler; | |
| 511 | old.flags = @truncate(u32, ksa_old.flags); | |
| 512 | @memcpy(@ptrCast([*]u8, &old.mask), @ptrCast([*]const u8, &ksa_old.mask), @sizeOf(@typeOf(ksa_old.mask))); | |
| 513 | } | |
| 514 | return 0; | |
| 515 | } | |
| 516 | ||
| 517 | fn blockAllSignals(set: *sigset_t) void { | |
| 518 | _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&all_mask), @ptrToInt(set), NSIG / 8); | |
| 519 | } | |
| 520 | ||
| 521 | fn blockAppSignals(set: *sigset_t) void { | |
| 522 | _ = syscall4(SYS_rt_sigprocmask, SIG_BLOCK, @ptrToInt(&app_mask), @ptrToInt(set), NSIG / 8); | |
| 523 | } | |
| 524 | ||
| 525 | fn restoreSignals(set: *sigset_t) void { | |
| 526 | _ = syscall4(SYS_rt_sigprocmask, SIG_SETMASK, @ptrToInt(set), 0, NSIG / 8); | |
| 527 | } | |
| 528 | ||
| 529 | pub fn sigaddset(set: *sigset_t, sig: u6) void { | |
| 530 | const s = sig - 1; | |
| 531 | (set.*)[@intCast(usize, s) / usize.bit_count] |= @intCast(usize, 1) << (s & (usize.bit_count - 1)); | |
| 532 | } | |
| 533 | ||
| 534 | pub fn sigismember(set: *const sigset_t, sig: u6) bool { | |
| 535 | const s = sig - 1; | |
| 536 | return ((set.*)[@intCast(usize, s) / usize.bit_count] & (@intCast(usize, 1) << (s & (usize.bit_count - 1)))) != 0; | |
| 537 | } | |
| 538 | ||
| 539 | pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { | |
| 540 | return syscall3(SYS_getsockname, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len)); | |
| 541 | } | |
| 542 | ||
| 543 | pub fn getpeername(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { | |
| 544 | return syscall3(SYS_getpeername, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len)); | |
| 545 | } | |
| 546 | ||
| 547 | pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize { | |
| 548 | return syscall3(SYS_socket, domain, socket_type, protocol); | |
| 549 | } | |
| 550 | ||
| 551 | pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: [*]const u8, optlen: socklen_t) usize { | |
| 552 | return syscall5(SYS_setsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen)); | |
| 553 | } | |
| 554 | ||
| 555 | pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noalias optlen: *socklen_t) usize { | |
| 556 | return syscall5(SYS_getsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen)); | |
| 557 | } | |
| 558 | ||
| 559 | pub fn sendmsg(fd: i32, msg: *msghdr_const, flags: u32) usize { | |
| 560 | return syscall3(SYS_sendmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags); | |
| 561 | } | |
| 562 | ||
| 563 | pub fn sendmmsg(fd: i32, msgvec: [*]mmsghdr_const, vlen: u32, flags: u32) usize { | |
| 564 | if (@typeInfo(usize).Int.bits > @typeInfo(@typeOf(mmsghdr(undefined).msg_len)).Int.bits) { | |
| 565 | // workaround kernel brokenness: | |
| 566 | // if adding up all iov_len overflows a i32 then split into multiple calls | |
| 567 | // see https://www.openwall.com/lists/musl/2014/06/07/5 | |
| 568 | const kvlen = if (vlen > IOV_MAX) IOV_MAX else vlen; // matches kernel | |
| 569 | var next_unsent: usize = 0; | |
| 570 | for (msgvec[0..kvlen]) |*msg, i| { | |
| 571 | var size: i32 = 0; | |
| 572 | const msg_iovlen = @intCast(usize, msg.msg_hdr.msg_iovlen); // kernel side this is treated as unsigned | |
| 573 | for (msg.msg_hdr.msg_iov[0..msg_iovlen]) |iov, j| { | |
| 574 | if (iov.iov_len > std.math.maxInt(i32) or @addWithOverflow(i32, size, @intCast(i32, iov.iov_len), &size)) { | |
| 575 | // batch-send all messages up to the current message | |
| 576 | if (next_unsent < i) { | |
| 577 | const batch_size = i - next_unsent; | |
| 578 | const r = syscall4(SYS_sendmmsg, @bitCast(usize, isize(fd)), @ptrToInt(&msgvec[next_unsent]), batch_size, flags); | |
| 579 | if (getErrno(r) != 0) return next_unsent; | |
| 580 | if (r < batch_size) return next_unsent + r; | |
| 581 | } | |
| 582 | // send current message as own packet | |
| 583 | const r = sendmsg(fd, &msg.msg_hdr, flags); | |
| 584 | if (getErrno(r) != 0) return r; | |
| 585 | // Linux limits the total bytes sent by sendmsg to INT_MAX, so this cast is safe. | |
| 586 | msg.msg_len = @intCast(u32, r); | |
| 587 | next_unsent = i + 1; | |
| 588 | break; | |
| 589 | } | |
| 590 | } | |
| 591 | } | |
| 592 | if (next_unsent < kvlen or next_unsent == 0) { // want to make sure at least one syscall occurs (e.g. to trigger MSG_EOR) | |
| 593 | const batch_size = kvlen - next_unsent; | |
| 594 | const r = syscall4(SYS_sendmmsg, @bitCast(usize, isize(fd)), @ptrToInt(&msgvec[next_unsent]), batch_size, flags); | |
| 595 | if (getErrno(r) != 0) return r; | |
| 596 | return next_unsent + r; | |
| 597 | } | |
| 598 | return kvlen; | |
| 599 | } | |
| 600 | return syscall4(SYS_sendmmsg, @bitCast(usize, isize(fd)), @ptrToInt(msgvec), vlen, flags); | |
| 601 | } | |
| 602 | ||
| 603 | pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize { | |
| 604 | return syscall3(SYS_connect, @bitCast(usize, isize(fd)), @ptrToInt(addr), len); | |
| 605 | } | |
| 606 | ||
| 607 | pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize { | |
| 608 | return syscall3(SYS_recvmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags); | |
| 609 | } | |
| 610 | ||
| 611 | pub fn recvfrom(fd: i32, noalias buf: [*]u8, len: usize, flags: u32, noalias addr: ?*sockaddr, noalias alen: ?*socklen_t) usize { | |
| 612 | return syscall6(SYS_recvfrom, @bitCast(usize, isize(fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen)); | |
| 613 | } | |
| 614 | ||
| 615 | pub fn shutdown(fd: i32, how: i32) usize { | |
| 616 | return syscall2(SYS_shutdown, @bitCast(usize, isize(fd)), @bitCast(usize, isize(how))); | |
| 617 | } | |
| 618 | ||
| 619 | pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize { | |
| 620 | return syscall3(SYS_bind, @bitCast(usize, isize(fd)), @ptrToInt(addr), @intCast(usize, len)); | |
| 621 | } | |
| 622 | ||
| 623 | pub fn listen(fd: i32, backlog: u32) usize { | |
| 624 | return syscall2(SYS_listen, @bitCast(usize, isize(fd)), backlog); | |
| 625 | } | |
| 626 | ||
| 627 | pub fn sendto(fd: i32, buf: [*]const u8, len: usize, flags: u32, addr: ?*const sockaddr, alen: socklen_t) usize { | |
| 628 | return syscall6(SYS_sendto, @bitCast(usize, isize(fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen)); | |
| 629 | } | |
| 630 | ||
| 631 | pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize { | |
| 632 | return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0])); | |
| 633 | } | |
| 634 | ||
| 635 | pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { | |
| 636 | return accept4(fd, addr, len, 0); | |
| 637 | } | |
| 638 | ||
| 639 | pub fn accept4(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t, flags: u32) usize { | |
| 640 | return syscall4(SYS_accept4, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len), flags); | |
| 641 | } | |
| 642 | ||
| 643 | pub fn fstat(fd: i32, stat_buf: *Stat) usize { | |
| 644 | return syscall2(SYS_fstat, @bitCast(usize, isize(fd)), @ptrToInt(stat_buf)); | |
| 645 | } | |
| 646 | ||
| 647 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 648 | pub fn stat(pathname: [*]const u8, statbuf: *Stat) usize { | |
| 649 | return syscall2(SYS_stat, @ptrToInt(pathname), @ptrToInt(statbuf)); | |
| 650 | } | |
| 651 | ||
| 652 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 653 | pub fn lstat(pathname: [*]const u8, statbuf: *Stat) usize { | |
| 654 | return syscall2(SYS_lstat, @ptrToInt(pathname), @ptrToInt(statbuf)); | |
| 655 | } | |
| 656 | ||
| 657 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 658 | pub fn fstatat(dirfd: i32, path: [*]const u8, stat_buf: *Stat, flags: u32) usize { | |
| 659 | return syscall4(SYS_fstatat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(stat_buf), flags); | |
| 660 | } | |
| 661 | ||
| 662 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 663 | pub fn listxattr(path: [*]const u8, list: [*]u8, size: usize) usize { | |
| 664 | return syscall3(SYS_listxattr, @ptrToInt(path), @ptrToInt(list), size); | |
| 665 | } | |
| 666 | ||
| 667 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 668 | pub fn llistxattr(path: [*]const u8, list: [*]u8, size: usize) usize { | |
| 669 | return syscall3(SYS_llistxattr, @ptrToInt(path), @ptrToInt(list), size); | |
| 670 | } | |
| 671 | ||
| 672 | pub fn flistxattr(fd: usize, list: [*]u8, size: usize) usize { | |
| 673 | return syscall3(SYS_flistxattr, fd, @ptrToInt(list), size); | |
| 674 | } | |
| 675 | ||
| 676 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 677 | pub fn getxattr(path: [*]const u8, name: [*]const u8, value: [*]u8, size: usize) usize { | |
| 678 | return syscall4(SYS_getxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size); | |
| 679 | } | |
| 680 | ||
| 681 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 682 | pub fn lgetxattr(path: [*]const u8, name: [*]const u8, value: [*]u8, size: usize) usize { | |
| 683 | return syscall4(SYS_lgetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size); | |
| 684 | } | |
| 685 | ||
| 686 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 687 | pub fn fgetxattr(fd: usize, name: [*]const u8, value: [*]u8, size: usize) usize { | |
| 688 | return syscall4(SYS_lgetxattr, fd, @ptrToInt(name), @ptrToInt(value), size); | |
| 689 | } | |
| 690 | ||
| 691 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 692 | pub fn setxattr(path: [*]const u8, name: [*]const u8, value: *const void, size: usize, flags: usize) usize { | |
| 693 | return syscall5(SYS_setxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size, flags); | |
| 694 | } | |
| 695 | ||
| 696 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 697 | pub fn lsetxattr(path: [*]const u8, name: [*]const u8, value: *const void, size: usize, flags: usize) usize { | |
| 698 | return syscall5(SYS_lsetxattr, @ptrToInt(path), @ptrToInt(name), @ptrToInt(value), size, flags); | |
| 699 | } | |
| 700 | ||
| 701 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 702 | pub fn fsetxattr(fd: usize, name: [*]const u8, value: *const void, size: usize, flags: usize) usize { | |
| 703 | return syscall5(SYS_fsetxattr, fd, @ptrToInt(name), @ptrToInt(value), size, flags); | |
| 704 | } | |
| 705 | ||
| 706 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 707 | pub fn removexattr(path: [*]const u8, name: [*]const u8) usize { | |
| 708 | return syscall2(SYS_removexattr, @ptrToInt(path), @ptrToInt(name)); | |
| 709 | } | |
| 710 | ||
| 711 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 712 | pub fn lremovexattr(path: [*]const u8, name: [*]const u8) usize { | |
| 713 | return syscall2(SYS_lremovexattr, @ptrToInt(path), @ptrToInt(name)); | |
| 714 | } | |
| 715 | ||
| 716 | // TODO https://github.com/ziglang/zig/issues/265 | |
| 717 | pub fn fremovexattr(fd: usize, name: [*]const u8) usize { | |
| 718 | return syscall2(SYS_fremovexattr, fd, @ptrToInt(name)); | |
| 719 | } | |
| 720 | ||
| 721 | pub fn sched_getaffinity(pid: i32, set: []usize) usize { | |
| 722 | return syscall3(SYS_sched_getaffinity, @bitCast(usize, isize(pid)), set.len * @sizeOf(usize), @ptrToInt(set.ptr)); | |
| 723 | } | |
| 724 | ||
| 725 | pub fn epoll_create() usize { | |
| 726 | return epoll_create1(0); | |
| 727 | } | |
| 728 | ||
| 729 | pub fn epoll_create1(flags: usize) usize { | |
| 730 | return syscall1(SYS_epoll_create1, flags); | |
| 731 | } | |
| 732 | ||
| 733 | pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: *epoll_event) usize { | |
| 734 | return syscall4(SYS_epoll_ctl, @bitCast(usize, isize(epoll_fd)), @intCast(usize, op), @bitCast(usize, isize(fd)), @ptrToInt(ev)); | |
| 735 | } | |
| 736 | ||
| 737 | pub fn epoll_wait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32) usize { | |
| 738 | return syscall4( | |
| 739 | SYS_epoll_wait, | |
| 740 | @bitCast(usize, isize(epoll_fd)), | |
| 741 | @ptrToInt(events), | |
| 742 | maxevents, | |
| 743 | @bitCast(usize, isize(timeout)), | |
| 744 | ); | |
| 745 | } | |
| 746 | ||
| 747 | pub fn epoll_pwait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32, sigmask: ?*sigset_t) usize { | |
| 748 | return syscall6( | |
| 749 | SYS_epoll_pwait, | |
| 750 | @bitCast(usize, isize(epoll_fd)), | |
| 751 | @ptrToInt(events), | |
| 752 | @intCast(usize, maxevents), | |
| 753 | @bitCast(usize, isize(timeout)), | |
| 754 | @ptrToInt(sigmask), | |
| 755 | @sizeOf(sigset_t), | |
| 756 | ); | |
| 757 | } | |
| 758 | ||
| 759 | pub fn eventfd(count: u32, flags: u32) usize { | |
| 760 | return syscall2(SYS_eventfd2, count, flags); | |
| 761 | } | |
| 762 | ||
| 763 | pub fn timerfd_create(clockid: i32, flags: u32) usize { | |
| 764 | return syscall2(SYS_timerfd_create, @bitCast(usize, isize(clockid)), flags); | |
| 765 | } | |
| 766 | ||
| 767 | pub const itimerspec = extern struct { | |
| 768 | it_interval: timespec, | |
| 769 | it_value: timespec, | |
| 770 | }; | |
| 771 | ||
| 772 | pub fn timerfd_gettime(fd: i32, curr_value: *itimerspec) usize { | |
| 773 | return syscall2(SYS_timerfd_gettime, @bitCast(usize, isize(fd)), @ptrToInt(curr_value)); | |
| 774 | } | |
| 775 | ||
| 776 | pub fn timerfd_settime(fd: i32, flags: u32, new_value: *const itimerspec, old_value: ?*itimerspec) usize { | |
| 777 | return syscall4(SYS_timerfd_settime, @bitCast(usize, isize(fd)), flags, @ptrToInt(new_value), @ptrToInt(old_value)); | |
| 778 | } | |
| 779 | ||
| 780 | pub fn unshare(flags: usize) usize { | |
| 781 | return syscall1(SYS_unshare, flags); | |
| 782 | } | |
| 783 | ||
| 784 | pub fn capget(hdrp: *cap_user_header_t, datap: *cap_user_data_t) usize { | |
| 785 | return syscall2(SYS_capget, @ptrToInt(hdrp), @ptrToInt(datap)); | |
| 786 | } | |
| 787 | ||
| 788 | pub fn capset(hdrp: *cap_user_header_t, datap: *const cap_user_data_t) usize { | |
| 789 | return syscall2(SYS_capset, @ptrToInt(hdrp), @ptrToInt(datap)); | |
| 790 | } | |
| 791 | ||
| 792 | // XXX: This should be weak | |
| 793 | extern const __ehdr_start: elf.Ehdr = undefined; | |
| 794 | ||
| 795 | pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_info, size: usize, data: ?*T) i32, data: ?*T) isize { | |
| 796 | if (builtin.link_libc) { | |
| 797 | return std.c.dl_iterate_phdr(@ptrCast(std.c.dl_iterate_phdr_callback, callback), @ptrCast(?*c_void, data)); | |
| 798 | } | |
| 799 | ||
| 800 | const elf_base = @ptrToInt(&__ehdr_start); | |
| 801 | const n_phdr = __ehdr_start.e_phnum; | |
| 802 | const phdrs = (@intToPtr([*]elf.Phdr, elf_base + __ehdr_start.e_phoff))[0..n_phdr]; | |
| 803 | ||
| 804 | var it = dl.linkmap_iterator(phdrs) catch return 0; | |
| 805 | ||
| 806 | // The executable has no dynamic link segment, create a single entry for | |
| 807 | // the whole ELF image | |
| 808 | if (it.end()) { | |
| 809 | var info = dl_phdr_info{ | |
| 810 | .dlpi_addr = elf_base, | |
| 811 | .dlpi_name = c"/proc/self/exe", | |
| 812 | .dlpi_phdr = @intToPtr([*]elf.Phdr, elf_base + __ehdr_start.e_phoff), | |
| 813 | .dlpi_phnum = __ehdr_start.e_phnum, | |
| 814 | }; | |
| 815 | ||
| 816 | return callback(&info, @sizeOf(dl_phdr_info), data); | |
| 817 | } | |
| 818 | ||
| 819 | // Last return value from the callback function | |
| 820 | var last_r: isize = 0; | |
| 821 | while (it.next()) |entry| { | |
| 822 | var dlpi_phdr: usize = undefined; | |
| 823 | var dlpi_phnum: u16 = undefined; | |
| 824 | ||
| 825 | if (entry.l_addr != 0) { | |
| 826 | const elf_header = @intToPtr(*elf.Ehdr, entry.l_addr); | |
| 827 | dlpi_phdr = entry.l_addr + elf_header.e_phoff; | |
| 828 | dlpi_phnum = elf_header.e_phnum; | |
| 829 | } else { | |
| 830 | // This is the running ELF image | |
| 831 | dlpi_phdr = elf_base + __ehdr_start.e_phoff; | |
| 832 | dlpi_phnum = __ehdr_start.e_phnum; | |
| 833 | } | |
| 834 | ||
| 835 | var info = dl_phdr_info{ | |
| 836 | .dlpi_addr = entry.l_addr, | |
| 837 | .dlpi_name = entry.l_name, | |
| 838 | .dlpi_phdr = @intToPtr([*]elf.Phdr, dlpi_phdr), | |
| 839 | .dlpi_phnum = dlpi_phnum, | |
| 840 | }; | |
| 841 | ||
| 842 | last_r = callback(&info, @sizeOf(dl_phdr_info), data); | |
| 843 | if (last_r != 0) break; | |
| 844 | } | |
| 845 | ||
| 846 | return last_r; | |
| 847 | } |
std/os/posix.zig+157-220| ... | ... | @@ -2,21 +2,18 @@ |
| 2 | 2 | // The purpose is not to match POSIX as closely as possible. Instead, |
| 3 | 3 | // the goal is to provide a very specific layer of abstraction: |
| 4 | 4 | // * Implement the POSIX functions, types, and definitions where possible, |
| 5 | // using lower-level target-specific API. For example, on Linux `rename` might call | |
| 6 | // SYS_renameat or SYS_rename depending on the architecture. | |
| 5 | // using lower-level target-specific API. | |
| 7 | 6 | // * When null-terminated byte buffers are required, provide APIs which accept |
| 8 | 7 | // slices as well as APIs which accept null-terminated byte buffers. Same goes |
| 9 | 8 | // for UTF-16LE encoding. |
| 10 | 9 | // * Convert "errno"-style error codes into Zig errors. |
| 11 | // * Work around kernel bugs and limitations. For example, if a function accepts | |
| 12 | // a `usize` number of bytes to write, but the kernel can only handle maxInt(u32) | |
| 13 | // number of bytes, this API layer should introduce a loop to make multiple | |
| 14 | // syscalls so that the full `usize` number of bytes are written. | |
| 15 | 10 | // * Implement the OS-specific functions, types, and definitions that the Zig |
| 16 | 11 | // standard library needs, at the same API abstraction layer as outlined above. |
| 17 | // this includes, for example Windows functions. | |
| 18 | // * When there exists a corresponding libc function and linking libc, call the | |
| 19 | // libc function. | |
| 12 | // For example kevent() and getrandom(). Windows-specific functions are separate, | |
| 13 | // in `std.os.windows`. | |
| 14 | // * When there exists a corresponding libc function and linking libc, the libc | |
| 15 | // implementation is used. Exceptions are made for known buggy areas of libc. | |
| 16 | // On Linux libc can be side-stepped by using `std.os.linux.sys`. | |
| 20 | 17 | // Note: The Zig standard library does not support POSIX thread cancellation, and |
| 21 | 18 | // in general EINTR is handled by trying again. |
| 22 | 19 | |
| ... | ... | @@ -29,18 +26,13 @@ const mem = std.mem; |
| 29 | 26 | const BufMap = std.BufMap; |
| 30 | 27 | const Allocator = mem.Allocator; |
| 31 | 28 | const windows = os.windows; |
| 29 | const kernel32 = windows.kernel32; | |
| 32 | 30 | const wasi = os.wasi; |
| 33 | 31 | const linux = os.linux; |
| 34 | 32 | const testing = std.testing; |
| 35 | 33 | |
| 36 | 34 | pub use system.posix; |
| 37 | 35 | |
| 38 | /// > The maximum path of 32,767 characters is approximate, because the "\\?\" | |
| 39 | /// > prefix may be expanded to a longer string by the system at run time, and | |
| 40 | /// > this expansion applies to the total length. | |
| 41 | /// from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation | |
| 42 | pub const PATH_MAX_WIDE = 32767; | |
| 43 | ||
| 44 | 36 | /// See also `getenv`. |
| 45 | 37 | pub var environ: [][*]u8 = undefined; |
| 46 | 38 | |
| ... | ... | @@ -59,7 +51,7 @@ pub const errno = system.getErrno; |
| 59 | 51 | /// Note: The Zig standard library does not support POSIX thread cancellation. |
| 60 | 52 | pub fn close(fd: fd_t) void { |
| 61 | 53 | if (windows.is_the_target and !builtin.link_libc) { |
| 62 | assert(windows.CloseHandle(fd) != 0); | |
| 54 | assert(kernel32.CloseHandle(fd) != 0); | |
| 63 | 55 | return; |
| 64 | 56 | } |
| 65 | 57 | if (wasi.is_the_target) { |
| ... | ... | @@ -87,11 +79,10 @@ pub fn getrandom(buf: []u8) GetRandomError!void { |
| 87 | 79 | // Call RtlGenRandom() instead of CryptGetRandom() on Windows |
| 88 | 80 | // https://github.com/rust-lang-nursery/rand/issues/111 |
| 89 | 81 | // https://bugzilla.mozilla.org/show_bug.cgi?id=504270 |
| 90 | if (windows.RtlGenRandom(buf.ptr, buf.len) == 0) { | |
| 91 | const err = windows.GetLastError(); | |
| 92 | return switch (err) { | |
| 93 | else => unexpectedErrorWindows(err), | |
| 94 | }; | |
| 82 | if (windows.advapi32.RtlGenRandom(buf.ptr, buf.len) == 0) { | |
| 83 | switch (kernel32.GetLastError()) { | |
| 84 | else => |err| return windows.unexpectedError(err), | |
| 85 | } | |
| 95 | 86 | } |
| 96 | 87 | return; |
| 97 | 88 | } |
| ... | ... | @@ -230,12 +221,11 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { |
| 230 | 221 | const want_read_count = @intCast(windows.DWORD, math.min(windows.DWORD(math.maxInt(windows.DWORD)), buffer.len - index)); |
| 231 | 222 | var amt_read: windows.DWORD = undefined; |
| 232 | 223 | if (windows.ReadFile(fd, buffer.ptr + index, want_read_count, &amt_read, null) == 0) { |
| 233 | const err = windows.GetLastError(); | |
| 234 | return switch (err) { | |
| 224 | switch (windows.GetLastError()) { | |
| 235 | 225 | windows.ERROR.OPERATION_ABORTED => continue, |
| 236 | 226 | windows.ERROR.BROKEN_PIPE => return index, |
| 237 | else => unexpectedErrorWindows(err), | |
| 238 | }; | |
| 227 | else => |err| return windows.unexpectedError(err), | |
| 228 | } | |
| 239 | 229 | } |
| 240 | 230 | if (amt_read == 0) return index; |
| 241 | 231 | index += amt_read; |
| ... | ... | @@ -372,7 +362,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!void { |
| 372 | 362 | windows.ERROR.NOT_ENOUGH_QUOTA => return error.SystemResources, |
| 373 | 363 | windows.ERROR.IO_PENDING => unreachable, |
| 374 | 364 | windows.ERROR.BROKEN_PIPE => return error.BrokenPipe, |
| 375 | else => |err| return unexpectedErrorWindows(err), | |
| 365 | else => |err| return windows.unexpectedError(err), | |
| 376 | 366 | } |
| 377 | 367 | } |
| 378 | 368 | } |
| ... | ... | @@ -543,67 +533,6 @@ pub fn openC(file_path: [*]const u8, flags: u32, perm: usize) OpenError!fd_t { |
| 543 | 533 | } |
| 544 | 534 | } |
| 545 | 535 | |
| 546 | pub const WindowsOpenError = error{ | |
| 547 | SharingViolation, | |
| 548 | PathAlreadyExists, | |
| 549 | ||
| 550 | /// When any of the path components can not be found or the file component can not | |
| 551 | /// be found. Some operating systems distinguish between path components not found and | |
| 552 | /// file components not found, but they are collapsed into FileNotFound to gain | |
| 553 | /// consistency across operating systems. | |
| 554 | FileNotFound, | |
| 555 | ||
| 556 | AccessDenied, | |
| 557 | PipeBusy, | |
| 558 | NameTooLong, | |
| 559 | ||
| 560 | /// On Windows, file paths must be valid Unicode. | |
| 561 | InvalidUtf8, | |
| 562 | ||
| 563 | /// On Windows, file paths cannot contain these characters: | |
| 564 | /// '/', '*', '?', '"', '<', '>', '|' | |
| 565 | BadPathName, | |
| 566 | ||
| 567 | Unexpected, | |
| 568 | }; | |
| 569 | ||
| 570 | pub fn openWindows( | |
| 571 | file_path: []const u8, | |
| 572 | desired_access: windows.DWORD, | |
| 573 | share_mode: windows.DWORD, | |
| 574 | creation_disposition: windows.DWORD, | |
| 575 | flags_and_attrs: windows.DWORD, | |
| 576 | ) WindowsOpenError!fd_t { | |
| 577 | const file_path_w = try sliceToPrefixedFileW(file_path); | |
| 578 | return openW(&file_path_w, desired_access, share_mode, creation_disposition, flags_and_attrs); | |
| 579 | } | |
| 580 | ||
| 581 | pub fn openW( | |
| 582 | file_path_w: [*]const u16, | |
| 583 | desired_access: windows.DWORD, | |
| 584 | share_mode: windows.DWORD, | |
| 585 | creation_disposition: windows.DWORD, | |
| 586 | flags_and_attrs: windows.DWORD, | |
| 587 | ) WindowsOpenError!windows.HANDLE { | |
| 588 | const result = windows.CreateFileW(file_path_w, desired_access, share_mode, null, creation_disposition, flags_and_attrs, null); | |
| 589 | ||
| 590 | if (result == windows.INVALID_HANDLE_VALUE) { | |
| 591 | const err = windows.GetLastError(); | |
| 592 | switch (err) { | |
| 593 | windows.ERROR.SHARING_VIOLATION => return error.SharingViolation, | |
| 594 | windows.ERROR.ALREADY_EXISTS => return error.PathAlreadyExists, | |
| 595 | windows.ERROR.FILE_EXISTS => return error.PathAlreadyExists, | |
| 596 | windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound, | |
| 597 | windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound, | |
| 598 | windows.ERROR.ACCESS_DENIED => return error.AccessDenied, | |
| 599 | windows.ERROR.PIPE_BUSY => return error.PipeBusy, | |
| 600 | else => return unexpectedErrorWindows(err), | |
| 601 | } | |
| 602 | } | |
| 603 | ||
| 604 | return result; | |
| 605 | } | |
| 606 | ||
| 607 | 536 | pub fn dup2(old_fd: fd_t, new_fd: fd_t) !void { |
| 608 | 537 | while (true) { |
| 609 | 538 | switch (errno(system.dup2(old_fd, new_fd))) { |
| ... | ... | @@ -797,14 +726,13 @@ pub const GetCwdError = error{ |
| 797 | 726 | /// The result is a slice of out_buffer, indexed from 0. |
| 798 | 727 | pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 { |
| 799 | 728 | if (windows.is_the_target and !builtin.link_libc) { |
| 800 | var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined; | |
| 729 | var utf16le_buf: [windows.PATH_MAX_WIDE]u16 = undefined; | |
| 801 | 730 | const casted_len = @intCast(windows.DWORD, utf16le_buf.len); // TODO shouldn't need this cast |
| 802 | 731 | const casted_ptr = ([*]u16)(&utf16le_buf); // TODO shouldn't need this cast |
| 803 | 732 | const result = windows.GetCurrentDirectoryW(casted_len, casted_ptr); |
| 804 | 733 | if (result == 0) { |
| 805 | const err = windows.GetLastError(); | |
| 806 | switch (err) { | |
| 807 | else => return unexpectedErrorWindows(err), | |
| 734 | switch (windows.GetLastError()) { | |
| 735 | else => |err| return windows.unexpectedError(err), | |
| 808 | 736 | } |
| 809 | 737 | } |
| 810 | 738 | assert(result <= utf16le_buf.len); |
| ... | ... | @@ -910,12 +838,7 @@ pub fn symlinkC(target_path: [*]const u8, new_path: [*]const u8) SymLinkError!vo |
| 910 | 838 | const new_path_w = try cStrToPrefixedFileW(new_path); |
| 911 | 839 | return symlinkW(&target_path_w, &new_path_w); |
| 912 | 840 | } |
| 913 | const err = if (builtin.link_libc or @hasDecl(system, "SYS_symlink")) blk: { | |
| 914 | break :blk errno(system.symlink(target_path, new_path)); | |
| 915 | } else blk: { | |
| 916 | break :blk errno(system.symlinkat(target_path, AT_FDCWD, new_path)); | |
| 917 | }; | |
| 918 | switch (err) { | |
| 841 | switch (errno(system.symlink(target_path, new_path))) { | |
| 919 | 842 | 0 => return, |
| 920 | 843 | EFAULT => unreachable, |
| 921 | 844 | EINVAL => unreachable, |
| ... | ... | @@ -931,7 +854,7 @@ pub fn symlinkC(target_path: [*]const u8, new_path: [*]const u8) SymLinkError!vo |
| 931 | 854 | ENOMEM => return error.SystemResources, |
| 932 | 855 | ENOSPC => return error.NoSpaceLeft, |
| 933 | 856 | EROFS => return error.ReadOnlyFileSystem, |
| 934 | else => return unexpectedErrno(err), | |
| 857 | else => |err| return unexpectedErrno(err), | |
| 935 | 858 | } |
| 936 | 859 | } |
| 937 | 860 | |
| ... | ... | @@ -941,9 +864,8 @@ pub fn symlinkC(target_path: [*]const u8, new_path: [*]const u8) SymLinkError!vo |
| 941 | 864 | /// TODO handle when linking libc |
| 942 | 865 | pub fn symlinkW(target_path_w: [*]const u16, new_path_w: [*]const u16) SymLinkError!void { |
| 943 | 866 | if (windows.CreateSymbolicLinkW(target_path_w, new_path_w, 0) == 0) { |
| 944 | const err = windows.GetLastError(); | |
| 945 | switch (err) { | |
| 946 | else => return unexpectedErrorWindows(err), | |
| 867 | switch (windows.GetLastError()) { | |
| 868 | else => |err| return windows.unexpectedError(err), | |
| 947 | 869 | } |
| 948 | 870 | } |
| 949 | 871 | } |
| ... | ... | @@ -984,13 +906,12 @@ pub fn unlink(file_path: []const u8) UnlinkError!void { |
| 984 | 906 | /// TODO handle when linking libc |
| 985 | 907 | pub fn unlinkW(file_path: [*]const u16) UnlinkError!void { |
| 986 | 908 | if (windows.unlinkW(file_path) == 0) { |
| 987 | const err = windows.GetLastError(); | |
| 988 | switch (err) { | |
| 909 | switch (windows.GetLastError()) { | |
| 989 | 910 | windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound, |
| 990 | 911 | windows.ERROR.ACCESS_DENIED => return error.AccessDenied, |
| 991 | 912 | windows.ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong, |
| 992 | 913 | windows.ERROR.INVALID_PARAMETER => return error.NameTooLong, |
| 993 | else => return unexpectedErrorWindows(err), | |
| 914 | else => |err| return windows.unexpectedError(err), | |
| 994 | 915 | } |
| 995 | 916 | } |
| 996 | 917 | } |
| ... | ... | @@ -1001,12 +922,7 @@ pub fn unlinkC(file_path: [*]const u8) UnlinkError!void { |
| 1001 | 922 | const file_path_w = try cStrToPrefixedFileW(file_path); |
| 1002 | 923 | return unlinkW(&file_path_w); |
| 1003 | 924 | } |
| 1004 | const err = if (builtin.link_libc or @hasDecl(system, "SYS_unlink")) blk: { | |
| 1005 | break :blk errno(system.unlink(file_path)); | |
| 1006 | } else blk: { | |
| 1007 | break :blk errno(system.unlinkat(AT_FDCWD, file_path, 0)); | |
| 1008 | }; | |
| 1009 | switch (err) { | |
| 925 | switch (errno(system.unlink(file_path))) { | |
| 1010 | 926 | 0 => return, |
| 1011 | 927 | EACCES => return error.AccessDenied, |
| 1012 | 928 | EPERM => return error.AccessDenied, |
| ... | ... | @@ -1021,7 +937,7 @@ pub fn unlinkC(file_path: [*]const u8) UnlinkError!void { |
| 1021 | 937 | ENOTDIR => return error.NotDir, |
| 1022 | 938 | ENOMEM => return error.SystemResources, |
| 1023 | 939 | EROFS => return error.ReadOnlyFileSystem, |
| 1024 | else => return unexpectedErrno(err), | |
| 940 | else => |err| return unexpectedErrno(err), | |
| 1025 | 941 | } |
| 1026 | 942 | } |
| 1027 | 943 | |
| ... | ... | @@ -1047,14 +963,7 @@ pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) RenameError!void { |
| 1047 | 963 | const new_path_w = try cStrToPrefixedFileW(new_path); |
| 1048 | 964 | return renameW(&old_path_w, &new_path_w); |
| 1049 | 965 | } |
| 1050 | const err = if (builtin.link_libc or @hasDecl(system, "SYS_rename")) blk: { | |
| 1051 | break :blk errno(system.rename(old_path, new_path)); | |
| 1052 | } else if (@hasDecl(system, "SYS_renameat")) blk: { | |
| 1053 | break :blk errno(system.renameat(AT_FDCWD, old_path, AT_FDCWD, new_path)); | |
| 1054 | } else blk: { | |
| 1055 | break :blk errno(system.renameat2(AT_FDCWD, old_path, AT_FDCWD, new_path, 0)); | |
| 1056 | }; | |
| 1057 | switch (err) { | |
| 966 | switch (errno(system.rename(old_path, new_path))) { | |
| 1058 | 967 | 0 => return, |
| 1059 | 968 | EACCES => return error.AccessDenied, |
| 1060 | 969 | EPERM => return error.AccessDenied, |
| ... | ... | @@ -1074,7 +983,7 @@ pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) RenameError!void { |
| 1074 | 983 | ENOTEMPTY => return error.PathAlreadyExists, |
| 1075 | 984 | EROFS => return error.ReadOnlyFileSystem, |
| 1076 | 985 | EXDEV => return error.RenameAcrossMountPoints, |
| 1077 | else => return unexpectedErrno(err), | |
| 986 | else => |err| return unexpectedErrno(err), | |
| 1078 | 987 | } |
| 1079 | 988 | } |
| 1080 | 989 | |
| ... | ... | @@ -1083,9 +992,8 @@ pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) RenameError!void { |
| 1083 | 992 | pub fn renameW(old_path: [*]const u16, new_path: [*]const u16) RenameError!void { |
| 1084 | 993 | const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH; |
| 1085 | 994 | if (windows.MoveFileExW(old_path, new_path, flags) == 0) { |
| 1086 | const err = windows.GetLastError(); | |
| 1087 | switch (err) { | |
| 1088 | else => return unexpectedErrorWindows(err), | |
| 995 | switch (windows.GetLastError()) { | |
| 996 | else => |err| return windows.unexpectedError(err), | |
| 1089 | 997 | } |
| 1090 | 998 | } |
| 1091 | 999 | } |
| ... | ... | @@ -1110,12 +1018,7 @@ pub fn mkdirC(dir_path: [*]const u8, mode: u32) MakeDirError!void { |
| 1110 | 1018 | const dir_path_w = try cStrToPrefixedFileW(dir_path); |
| 1111 | 1019 | return mkdirW(&dir_path_w, mode); |
| 1112 | 1020 | } |
| 1113 | const err = if (builtin.link_libc or @hasDecl(system, "SYS_mkdir")) blk: { | |
| 1114 | break :blk errno(system.mkdir(dir_path, mode)); | |
| 1115 | } else blk: { | |
| 1116 | break :blk errno(system.mkdirat(AT_FDCWD, dir_path, mode)); | |
| 1117 | }; | |
| 1118 | switch (err) { | |
| 1021 | switch (errno(system.mkdir(dir_path, mode))) { | |
| 1119 | 1022 | 0 => return, |
| 1120 | 1023 | EACCES => return error.AccessDenied, |
| 1121 | 1024 | EPERM => return error.AccessDenied, |
| ... | ... | @@ -1130,7 +1033,7 @@ pub fn mkdirC(dir_path: [*]const u8, mode: u32) MakeDirError!void { |
| 1130 | 1033 | ENOSPC => return error.NoSpaceLeft, |
| 1131 | 1034 | ENOTDIR => return error.NotDir, |
| 1132 | 1035 | EROFS => return error.ReadOnlyFileSystem, |
| 1133 | else => return unexpectedErrno(err), | |
| 1036 | else => |err| return unexpectedErrno(err), | |
| 1134 | 1037 | } |
| 1135 | 1038 | } |
| 1136 | 1039 | |
| ... | ... | @@ -1139,11 +1042,10 @@ pub fn mkdirW(dir_path: []const u8, mode: u32) MakeDirError!void { |
| 1139 | 1042 | const dir_path_w = try sliceToPrefixedFileW(dir_path); |
| 1140 | 1043 | |
| 1141 | 1044 | if (windows.CreateDirectoryW(&dir_path_w, null) == 0) { |
| 1142 | const err = windows.GetLastError(); | |
| 1143 | switch (err) { | |
| 1045 | switch (windows.GetLastError()) { | |
| 1144 | 1046 | windows.ERROR.ALREADY_EXISTS => return error.PathAlreadyExists, |
| 1145 | 1047 | windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound, |
| 1146 | else => return unexpectedErrorWindows(err), | |
| 1048 | else => |err| return windows.unexpectedError(err), | |
| 1147 | 1049 | } |
| 1148 | 1050 | } |
| 1149 | 1051 | } |
| ... | ... | @@ -1180,12 +1082,7 @@ pub fn rmdirC(dir_path: [*]const u8) DeleteDirError!void { |
| 1180 | 1082 | const dir_path_w = try cStrToPrefixedFileW(dir_path); |
| 1181 | 1083 | return rmdirW(&dir_path_w); |
| 1182 | 1084 | } |
| 1183 | const err = if (builtin.link_libc or @hasDecl(system, "SYS_rmdir")) blk: { | |
| 1184 | break :blk errno(system.rmdir(dir_path)); | |
| 1185 | } else blk: { | |
| 1186 | break :blk errno(system.unlinkat(AT_FDCWD, dir_path, AT_REMOVEDIR)); | |
| 1187 | }; | |
| 1188 | switch (err) { | |
| 1085 | switch (errno(system.rmdir(dir_path))) { | |
| 1189 | 1086 | 0 => return, |
| 1190 | 1087 | EACCES => return error.AccessDenied, |
| 1191 | 1088 | EPERM => return error.AccessDenied, |
| ... | ... | @@ -1200,7 +1097,7 @@ pub fn rmdirC(dir_path: [*]const u8) DeleteDirError!void { |
| 1200 | 1097 | EEXIST => return error.DirNotEmpty, |
| 1201 | 1098 | ENOTEMPTY => return error.DirNotEmpty, |
| 1202 | 1099 | EROFS => return error.ReadOnlyFileSystem, |
| 1203 | else => return unexpectedErrno(err), | |
| 1100 | else => |err| return unexpectedErrno(err), | |
| 1204 | 1101 | } |
| 1205 | 1102 | } |
| 1206 | 1103 | |
| ... | ... | @@ -1208,11 +1105,10 @@ pub fn rmdirC(dir_path: [*]const u8) DeleteDirError!void { |
| 1208 | 1105 | /// TODO handle linking libc |
| 1209 | 1106 | pub fn rmdirW(dir_path_w: [*]const u16) DeleteDirError!void { |
| 1210 | 1107 | if (windows.RemoveDirectoryW(dir_path_w) == 0) { |
| 1211 | const err = windows.GetLastError(); | |
| 1212 | switch (err) { | |
| 1108 | switch (windows.GetLastError()) { | |
| 1213 | 1109 | windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound, |
| 1214 | 1110 | windows.ERROR.DIR_NOT_EMPTY => return error.DirNotEmpty, |
| 1215 | else => return unexpectedErrorWindows(err), | |
| 1111 | else => |err| return windows.unexpectedError(err), | |
| 1216 | 1112 | } |
| 1217 | 1113 | } |
| 1218 | 1114 | } |
| ... | ... | @@ -1277,11 +1173,7 @@ pub fn readlinkC(file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 { |
| 1277 | 1173 | const file_path_w = try cStrToPrefixedFileW(file_path); |
| 1278 | 1174 | return readlinkW(&file_path_w, out_buffer); |
| 1279 | 1175 | } |
| 1280 | const rc = if (builtin.link_libc or @hasDecl(system, "SYS_readlink")) blk: { | |
| 1281 | break :blk system.readlink(file_path, out_buffer.ptr, out_buffer.len); | |
| 1282 | } else blk: { | |
| 1283 | break :blk system.readlinkat(AT_FDCWD, file_path, out_buffer.ptr, out_buffer.len); | |
| 1284 | }; | |
| 1176 | const rc = system.readlink(file_path, out_buffer.ptr, out_buffer.len); | |
| 1285 | 1177 | switch (errno(rc)) { |
| 1286 | 1178 | 0 => return out_buffer[0..rc], |
| 1287 | 1179 | EACCES => return error.AccessDenied, |
| ... | ... | @@ -1354,7 +1246,7 @@ pub fn GetStdHandle(handle_id: windows.DWORD) GetStdHandleError!fd_t { |
| 1354 | 1246 | const handle = windows.GetStdHandle(handle_id) orelse return error.NoStandardHandleAttached; |
| 1355 | 1247 | if (handle == windows.INVALID_HANDLE_VALUE) { |
| 1356 | 1248 | switch (windows.GetLastError()) { |
| 1357 | else => |err| unexpectedErrorWindows(err), | |
| 1249 | else => |err| windows.unexpectedError(err), | |
| 1358 | 1250 | } |
| 1359 | 1251 | } |
| 1360 | 1252 | return handle; |
| ... | ... | @@ -2070,17 +1962,12 @@ pub const ForkError = error{ |
| 2070 | 1962 | }; |
| 2071 | 1963 | |
| 2072 | 1964 | pub fn fork() ForkError!pid_t { |
| 2073 | if (builtin.link_libc) { | |
| 2074 | return system.fork(); | |
| 2075 | } | |
| 2076 | if (linux.is_the_target) { | |
| 2077 | const rc = if (@hasDecl(system, "SYS_fork")) system.fork() else system.clone2(SIGCHLD, 0); | |
| 2078 | switch (errno(rc)) { | |
| 2079 | 0 => return rc, | |
| 2080 | EAGAIN => return error.SystemResources, | |
| 2081 | ENOMEM => return error.SystemResources, | |
| 2082 | else => |err| return unexpectedErrno(err), | |
| 2083 | } | |
| 1965 | const rc = system.fork(); | |
| 1966 | switch (errno(rc)) { | |
| 1967 | 0 => return rc, | |
| 1968 | EAGAIN => return error.SystemResources, | |
| 1969 | ENOMEM => return error.SystemResources, | |
| 1970 | else => |err| return unexpectedErrno(err), | |
| 2084 | 1971 | } |
| 2085 | 1972 | } |
| 2086 | 1973 | |
| ... | ... | @@ -2173,7 +2060,7 @@ pub fn accessW(path: [*]const u16, mode: u32) AccessError!void { |
| 2173 | 2060 | windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound, |
| 2174 | 2061 | windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound, |
| 2175 | 2062 | windows.ERROR.ACCESS_DENIED => return error.PermissionDenied, |
| 2176 | else => |err| return unexpectedErrorWindows(err), | |
| 2063 | else => |err| return windows.unexpectedError(err), | |
| 2177 | 2064 | } |
| 2178 | 2065 | } |
| 2179 | 2066 | |
| ... | ... | @@ -2209,11 +2096,7 @@ pub const PipeError = error{ |
| 2209 | 2096 | |
| 2210 | 2097 | /// Creates a unidirectional data channel that can be used for interprocess communication. |
| 2211 | 2098 | pub fn pipe(fds: *[2]fd_t) PipeError!void { |
| 2212 | const rc = if (builtin.link_libc or @hasDecl(system, SYS_pipe)) | |
| 2213 | system.pipe(fds) | |
| 2214 | else | |
| 2215 | system.pipe2(fds, 0); | |
| 2216 | switch (errno(rc)) { | |
| 2099 | switch (errno(system.pipe(fds))) { | |
| 2217 | 2100 | 0 => return, |
| 2218 | 2101 | EINVAL => unreachable, // Invalid parameters to pipe() |
| 2219 | 2102 | EFAULT => unreachable, // Invalid fds pointer |
| ... | ... | @@ -2296,6 +2179,112 @@ pub const realpath = std.os.path.real; |
| 2296 | 2179 | pub const realpathC = std.os.path.realC; |
| 2297 | 2180 | pub const realpathW = std.os.path.realW; |
| 2298 | 2181 | |
| 2182 | pub const WaitForSingleObjectError = error{ | |
| 2183 | WaitAbandoned, | |
| 2184 | WaitTimeOut, | |
| 2185 | Unexpected, | |
| 2186 | }; | |
| 2187 | ||
| 2188 | pub fn WaitForSingleObject(handle: windows.HANDLE, milliseconds: windows.DWORD) WaitForSingleObjectError!void { | |
| 2189 | switch (windows.WaitForSingleObject(handle, milliseconds)) { | |
| 2190 | windows.WAIT_ABANDONED => return error.WaitAbandoned, | |
| 2191 | windows.WAIT_OBJECT_0 => return, | |
| 2192 | windows.WAIT_TIMEOUT => return error.WaitTimeOut, | |
| 2193 | windows.WAIT_FAILED => { | |
| 2194 | switch (windows.GetLastError()) { | |
| 2195 | else => |err| return windows.unexpectedError(err), | |
| 2196 | } | |
| 2197 | }, | |
| 2198 | else => return error.Unexpected, | |
| 2199 | } | |
| 2200 | } | |
| 2201 | ||
| 2202 | pub fn FindFirstFile( | |
| 2203 | dir_path: []const u8, | |
| 2204 | find_file_data: *windows.WIN32_FIND_DATAW, | |
| 2205 | ) !windows.HANDLE { | |
| 2206 | const dir_path_w = try sliceToPrefixedSuffixedFileW(dir_path, []u16{ '\\', '*', 0 }); | |
| 2207 | const handle = windows.FindFirstFileW(&dir_path_w, find_file_data); | |
| 2208 | ||
| 2209 | if (handle == windows.INVALID_HANDLE_VALUE) { | |
| 2210 | switch (windows.GetLastError()) { | |
| 2211 | windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound, | |
| 2212 | windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound, | |
| 2213 | else => |err| return windows.unexpectedError(err), | |
| 2214 | } | |
| 2215 | } | |
| 2216 | ||
| 2217 | return handle; | |
| 2218 | } | |
| 2219 | ||
| 2220 | /// Returns `true` if there was another file, `false` otherwise. | |
| 2221 | pub fn FindNextFile(handle: windows.HANDLE, find_file_data: *windows.WIN32_FIND_DATAW) !bool { | |
| 2222 | if (windows.FindNextFileW(handle, find_file_data) == 0) { | |
| 2223 | switch (windows.GetLastError()) { | |
| 2224 | windows.ERROR.NO_MORE_FILES => return false, | |
| 2225 | else => |err| return windows.unexpectedError(err), | |
| 2226 | } | |
| 2227 | } | |
| 2228 | return true; | |
| 2229 | } | |
| 2230 | ||
| 2231 | pub const CreateIoCompletionPortError = error{Unexpected}; | |
| 2232 | ||
| 2233 | pub fn CreateIoCompletionPort( | |
| 2234 | file_handle: windows.HANDLE, | |
| 2235 | existing_completion_port: ?windows.HANDLE, | |
| 2236 | completion_key: usize, | |
| 2237 | concurrent_thread_count: windows.DWORD, | |
| 2238 | ) CreateIoCompletionPortError!windows.HANDLE { | |
| 2239 | const handle = windows.CreateIoCompletionPort(file_handle, existing_completion_port, completion_key, concurrent_thread_count) orelse { | |
| 2240 | switch (windows.GetLastError()) { | |
| 2241 | windows.ERROR.INVALID_PARAMETER => unreachable, | |
| 2242 | else => |err| return windows.unexpectedError(err), | |
| 2243 | } | |
| 2244 | }; | |
| 2245 | return handle; | |
| 2246 | } | |
| 2247 | ||
| 2248 | pub const WindowsPostQueuedCompletionStatusError = error{Unexpected}; | |
| 2249 | ||
| 2250 | pub fn windowsPostQueuedCompletionStatus(completion_port: windows.HANDLE, bytes_transferred_count: windows.DWORD, completion_key: usize, lpOverlapped: ?*windows.OVERLAPPED) WindowsPostQueuedCompletionStatusError!void { | |
| 2251 | if (windows.PostQueuedCompletionStatus(completion_port, bytes_transferred_count, completion_key, lpOverlapped) == 0) { | |
| 2252 | const err = windows.GetLastError(); | |
| 2253 | switch (err) { | |
| 2254 | else => return windows.unexpectedError(err), | |
| 2255 | } | |
| 2256 | } | |
| 2257 | } | |
| 2258 | ||
| 2259 | pub const GetQueuedCompletionStatusResult = enum { | |
| 2260 | Normal, | |
| 2261 | Aborted, | |
| 2262 | Cancelled, | |
| 2263 | EOF, | |
| 2264 | }; | |
| 2265 | ||
| 2266 | pub fn GetQueuedCompletionStatus( | |
| 2267 | completion_port: windows.HANDLE, | |
| 2268 | bytes_transferred_count: *windows.DWORD, | |
| 2269 | lpCompletionKey: *usize, | |
| 2270 | lpOverlapped: *?*windows.OVERLAPPED, | |
| 2271 | dwMilliseconds: windows.DWORD, | |
| 2272 | ) GetQueuedCompletionStatusResult { | |
| 2273 | if (windows.GetQueuedCompletionStatus(completion_port, bytes_transferred_count, lpCompletionKey, lpOverlapped, dwMilliseconds) == windows.FALSE) { | |
| 2274 | switch (windows.GetLastError()) { | |
| 2275 | windows.ERROR.ABANDONED_WAIT_0 => return GetQueuedCompletionStatusResult.Aborted, | |
| 2276 | windows.ERROR.OPERATION_ABORTED => return GetQueuedCompletionStatusResult.Cancelled, | |
| 2277 | windows.ERROR.HANDLE_EOF => return GetQueuedCompletionStatusResult.EOF, | |
| 2278 | else => |err| { | |
| 2279 | if (std.debug.runtime_safety) { | |
| 2280 | std.debug.panic("unexpected error: {}\n", err); | |
| 2281 | } | |
| 2282 | }, | |
| 2283 | } | |
| 2284 | } | |
| 2285 | return GetQueuedCompletionStatusResult.Normal; | |
| 2286 | } | |
| 2287 | ||
| 2299 | 2288 | /// Used to convert a slice to a null terminated slice on the stack. |
| 2300 | 2289 | /// TODO https://github.com/ziglang/zig/issues/287 |
| 2301 | 2290 | pub fn toPosixPath(file_path: []const u8) ![PATH_MAX]u8 { |
| ... | ... | @@ -2307,64 +2296,12 @@ pub fn toPosixPath(file_path: []const u8) ![PATH_MAX]u8 { |
| 2307 | 2296 | return path_with_null; |
| 2308 | 2297 | } |
| 2309 | 2298 | |
| 2310 | const unexpected_error_tracing = builtin.mode == .Debug; | |
| 2311 | const UnexpectedError = error{ | |
| 2312 | /// The Operating System returned an undocumented error code. | |
| 2313 | Unexpected, | |
| 2314 | }; | |
| 2315 | ||
| 2316 | 2299 | /// Call this when you made a syscall or something that sets errno |
| 2317 | 2300 | /// and you get an unexpected error. |
| 2318 | pub fn unexpectedErrno(errno: usize) UnexpectedError { | |
| 2319 | if (unexpected_error_tracing) { | |
| 2301 | pub fn unexpectedErrno(errno: usize) os.UnexpectedError { | |
| 2302 | if (os.unexpected_error_tracing) { | |
| 2320 | 2303 | std.debug.warn("unexpected errno: {}\n", errno); |
| 2321 | 2304 | std.debug.dumpCurrentStackTrace(null); |
| 2322 | 2305 | } |
| 2323 | 2306 | return error.Unexpected; |
| 2324 | 2307 | } |
| 2325 | ||
| 2326 | /// Call this when you made a windows DLL call or something that does SetLastError | |
| 2327 | /// and you get an unexpected error. | |
| 2328 | pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError { | |
| 2329 | if (unexpected_error_tracing) { | |
| 2330 | std.debug.warn("unexpected GetLastError(): {}\n", err); | |
| 2331 | std.debug.dumpCurrentStackTrace(null); | |
| 2332 | } | |
| 2333 | return error.Unexpected; | |
| 2334 | } | |
| 2335 | ||
| 2336 | pub fn cStrToPrefixedFileW(s: [*]const u8) ![PATH_MAX_WIDE + 1]u16 { | |
| 2337 | return sliceToPrefixedFileW(mem.toSliceConst(u8, s)); | |
| 2338 | } | |
| 2339 | ||
| 2340 | pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 { | |
| 2341 | return sliceToPrefixedSuffixedFileW(s, []u16{0}); | |
| 2342 | } | |
| 2343 | ||
| 2344 | pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) ![PATH_MAX_WIDE + suffix.len]u16 { | |
| 2345 | // TODO well defined copy elision | |
| 2346 | var result: [PATH_MAX_WIDE + suffix.len]u16 = undefined; | |
| 2347 | ||
| 2348 | // > File I/O functions in the Windows API convert "/" to "\" as part of | |
| 2349 | // > converting the name to an NT-style name, except when using the "\\?\" | |
| 2350 | // > prefix as detailed in the following sections. | |
| 2351 | // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation | |
| 2352 | // Because we want the larger maximum path length for absolute paths, we | |
| 2353 | // disallow forward slashes in zig std lib file functions on Windows. | |
| 2354 | for (s) |byte| { | |
| 2355 | switch (byte) { | |
| 2356 | '/', '*', '?', '"', '<', '>', '|' => return error.BadPathName, | |
| 2357 | else => {}, | |
| 2358 | } | |
| 2359 | } | |
| 2360 | const start_index = if (mem.startsWith(u8, s, "\\\\") or !os.path.isAbsolute(s)) 0 else blk: { | |
| 2361 | const prefix = []u16{ '\\', '\\', '?', '\\' }; | |
| 2362 | mem.copy(u16, result[0..], prefix); | |
| 2363 | break :blk prefix.len; | |
| 2364 | }; | |
| 2365 | const end_index = start_index + try std.unicode.utf8ToUtf16Le(result[start_index..], s); | |
| 2366 | assert(end_index <= result.len); | |
| 2367 | if (end_index + suffix.len > result.len) return error.NameTooLong; | |
| 2368 | mem.copy(u16, result[end_index..], suffix); | |
| 2369 | return result; | |
| 2370 | } |
std/os/windows.zig+248-16| ... | ... | @@ -1,28 +1,30 @@ |
| 1 | // This file contains the types and constants of the Windows API, | |
| 2 | // as well as the Windows-equivalent of "Zig-flavored POSIX" API layer. | |
| 1 | 3 | const std = @import("../std.zig"); |
| 2 | 4 | const assert = std.debug.assert; |
| 3 | 5 | const maxInt = std.math.maxInt; |
| 4 | 6 | |
| 5 | pub const is_the_target = switch (builtin.os) { | |
| 6 | .windows => true, | |
| 7 | else => false, | |
| 8 | }; | |
| 9 | pub const posix = @import("windows/posix.zig"); | |
| 7 | pub const is_the_target = builtin.os == .windows; | |
| 8 | pub const posix = if (builtin.link_libc) struct {} else @import("windows/posix.zig"); | |
| 10 | 9 | pub use posix; |
| 11 | 10 | |
| 12 | pub use @import("windows/advapi32.zig"); | |
| 13 | pub use @import("windows/kernel32.zig"); | |
| 14 | pub use @import("windows/ntdll.zig"); | |
| 15 | pub use @import("windows/ole32.zig"); | |
| 16 | pub use @import("windows/shell32.zig"); | |
| 17 | ||
| 18 | test "import" { | |
| 19 | if (is_the_target) { | |
| 20 | _ = @import("windows/util.zig"); | |
| 21 | } | |
| 22 | } | |
| 11 | pub const advapi32 = @import("windows/advapi32.zig"); | |
| 12 | pub const kernel32 = @import("windows/kernel32.zig"); | |
| 13 | pub const ntdll = @import("windows/ntdll.zig"); | |
| 14 | pub const ole32 = @import("windows/ole32.zig"); | |
| 15 | pub const shell32 = @import("windows/shell32.zig"); | |
| 23 | 16 | |
| 24 | 17 | pub const ERROR = @import("windows/error.zig"); |
| 25 | 18 | |
| 19 | /// The standard input device. Initially, this is the console input buffer, CONIN$. | |
| 20 | pub const STD_INPUT_HANDLE = maxInt(DWORD) - 10 + 1; | |
| 21 | ||
| 22 | /// The standard output device. Initially, this is the active console screen buffer, CONOUT$. | |
| 23 | pub const STD_OUTPUT_HANDLE = maxInt(DWORD) - 11 + 1; | |
| 24 | ||
| 25 | /// The standard error device. Initially, this is the active console screen buffer, CONOUT$. | |
| 26 | pub const STD_ERROR_HANDLE = maxInt(DWORD) - 12 + 1; | |
| 27 | ||
| 26 | 28 | pub const SHORT = c_short; |
| 27 | 29 | pub const BOOL = c_int; |
| 28 | 30 | pub const BOOLEAN = BYTE; |
| ... | ... | @@ -428,3 +430,233 @@ pub const IMAGE_TLS_DIRECTORY64 = IMAGE_TLS_DIRECTORY; |
| 428 | 430 | pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY; |
| 429 | 431 | |
| 430 | 432 | pub const PIMAGE_TLS_CALLBACK = ?extern fn (PVOID, DWORD, PVOID) void; |
| 433 | ||
| 434 | pub const PROV_RSA_FULL = 1; | |
| 435 | ||
| 436 | pub const REGSAM = ACCESS_MASK; | |
| 437 | pub const ACCESS_MASK = DWORD; | |
| 438 | pub const PHKEY = *HKEY; | |
| 439 | pub const HKEY = *HKEY__; | |
| 440 | pub const HKEY__ = extern struct { | |
| 441 | unused: c_int, | |
| 442 | }; | |
| 443 | pub const LSTATUS = LONG; | |
| 444 | ||
| 445 | pub const FILE_NOTIFY_INFORMATION = extern struct { | |
| 446 | NextEntryOffset: DWORD, | |
| 447 | Action: DWORD, | |
| 448 | FileNameLength: DWORD, | |
| 449 | FileName: [1]WCHAR, | |
| 450 | }; | |
| 451 | ||
| 452 | pub const FILE_ACTION_ADDED = 0x00000001; | |
| 453 | pub const FILE_ACTION_REMOVED = 0x00000002; | |
| 454 | pub const FILE_ACTION_MODIFIED = 0x00000003; | |
| 455 | pub const FILE_ACTION_RENAMED_OLD_NAME = 0x00000004; | |
| 456 | pub const FILE_ACTION_RENAMED_NEW_NAME = 0x00000005; | |
| 457 | ||
| 458 | pub const LPOVERLAPPED_COMPLETION_ROUTINE = ?extern fn (DWORD, DWORD, *OVERLAPPED) void; | |
| 459 | ||
| 460 | pub const FILE_LIST_DIRECTORY = 1; | |
| 461 | ||
| 462 | pub const FILE_NOTIFY_CHANGE_CREATION = 64; | |
| 463 | pub const FILE_NOTIFY_CHANGE_SIZE = 8; | |
| 464 | pub const FILE_NOTIFY_CHANGE_SECURITY = 256; | |
| 465 | pub const FILE_NOTIFY_CHANGE_LAST_ACCESS = 32; | |
| 466 | pub const FILE_NOTIFY_CHANGE_LAST_WRITE = 16; | |
| 467 | pub const FILE_NOTIFY_CHANGE_DIR_NAME = 2; | |
| 468 | pub const FILE_NOTIFY_CHANGE_FILE_NAME = 1; | |
| 469 | pub const FILE_NOTIFY_CHANGE_ATTRIBUTES = 4; | |
| 470 | ||
| 471 | pub const CONSOLE_SCREEN_BUFFER_INFO = extern struct { | |
| 472 | dwSize: COORD, | |
| 473 | dwCursorPosition: COORD, | |
| 474 | wAttributes: WORD, | |
| 475 | srWindow: SMALL_RECT, | |
| 476 | dwMaximumWindowSize: COORD, | |
| 477 | }; | |
| 478 | ||
| 479 | pub const FOREGROUND_BLUE = 1; | |
| 480 | pub const FOREGROUND_GREEN = 2; | |
| 481 | pub const FOREGROUND_RED = 4; | |
| 482 | pub const FOREGROUND_INTENSITY = 8; | |
| 483 | ||
| 484 | pub const LIST_ENTRY = extern struct { | |
| 485 | Flink: *LIST_ENTRY, | |
| 486 | Blink: *LIST_ENTRY, | |
| 487 | }; | |
| 488 | ||
| 489 | pub const RTL_CRITICAL_SECTION_DEBUG = extern struct { | |
| 490 | Type: WORD, | |
| 491 | CreatorBackTraceIndex: WORD, | |
| 492 | CriticalSection: *RTL_CRITICAL_SECTION, | |
| 493 | ProcessLocksList: LIST_ENTRY, | |
| 494 | EntryCount: DWORD, | |
| 495 | ContentionCount: DWORD, | |
| 496 | Flags: DWORD, | |
| 497 | CreatorBackTraceIndexHigh: WORD, | |
| 498 | SpareWORD: WORD, | |
| 499 | }; | |
| 500 | ||
| 501 | pub const RTL_CRITICAL_SECTION = extern struct { | |
| 502 | DebugInfo: *RTL_CRITICAL_SECTION_DEBUG, | |
| 503 | LockCount: LONG, | |
| 504 | RecursionCount: LONG, | |
| 505 | OwningThread: HANDLE, | |
| 506 | LockSemaphore: HANDLE, | |
| 507 | SpinCount: ULONG_PTR, | |
| 508 | }; | |
| 509 | ||
| 510 | pub const CRITICAL_SECTION = RTL_CRITICAL_SECTION; | |
| 511 | pub const INIT_ONCE = RTL_RUN_ONCE; | |
| 512 | pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE_INIT; | |
| 513 | pub const INIT_ONCE_FN = extern fn (InitOnce: *INIT_ONCE, Parameter: ?*c_void, Context: ?*c_void) BOOL; | |
| 514 | ||
| 515 | pub const RTL_RUN_ONCE = extern struct { | |
| 516 | Ptr: ?*c_void, | |
| 517 | }; | |
| 518 | ||
| 519 | pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE{ .Ptr = null }; | |
| 520 | ||
| 521 | pub const COINIT_APARTMENTTHREADED = COINIT.COINIT_APARTMENTTHREADED; | |
| 522 | pub const COINIT_MULTITHREADED = COINIT.COINIT_MULTITHREADED; | |
| 523 | pub const COINIT_DISABLE_OLE1DDE = COINIT.COINIT_DISABLE_OLE1DDE; | |
| 524 | pub const COINIT_SPEED_OVER_MEMORY = COINIT.COINIT_SPEED_OVER_MEMORY; | |
| 525 | pub const COINIT = extern enum { | |
| 526 | COINIT_APARTMENTTHREADED = 2, | |
| 527 | COINIT_MULTITHREADED = 0, | |
| 528 | COINIT_DISABLE_OLE1DDE = 4, | |
| 529 | COINIT_SPEED_OVER_MEMORY = 8, | |
| 530 | }; | |
| 531 | ||
| 532 | /// > The maximum path of 32,767 characters is approximate, because the "\\?\" | |
| 533 | /// > prefix may be expanded to a longer string by the system at run time, and | |
| 534 | /// > this expansion applies to the total length. | |
| 535 | /// from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation | |
| 536 | pub const PATH_MAX_WIDE = 32767; | |
| 537 | ||
| 538 | pub const OpenError = error{ | |
| 539 | SharingViolation, | |
| 540 | PathAlreadyExists, | |
| 541 | ||
| 542 | /// When any of the path components can not be found or the file component can not | |
| 543 | /// be found. Some operating systems distinguish between path components not found and | |
| 544 | /// file components not found, but they are collapsed into FileNotFound to gain | |
| 545 | /// consistency across operating systems. | |
| 546 | FileNotFound, | |
| 547 | ||
| 548 | AccessDenied, | |
| 549 | PipeBusy, | |
| 550 | NameTooLong, | |
| 551 | ||
| 552 | /// On Windows, file paths must be valid Unicode. | |
| 553 | InvalidUtf8, | |
| 554 | ||
| 555 | /// On Windows, file paths cannot contain these characters: | |
| 556 | /// '/', '*', '?', '"', '<', '>', '|' | |
| 557 | BadPathName, | |
| 558 | ||
| 559 | Unexpected, | |
| 560 | }; | |
| 561 | ||
| 562 | pub fn CreateFile( | |
| 563 | file_path: []const u8, | |
| 564 | desired_access: DWORD, | |
| 565 | share_mode: DWORD, | |
| 566 | creation_disposition: DWORD, | |
| 567 | flags_and_attrs: DWORD, | |
| 568 | ) OpenError!fd_t { | |
| 569 | const file_path_w = try sliceToPrefixedFileW(file_path); | |
| 570 | return CreateFileW(&file_path_w, desired_access, share_mode, creation_disposition, flags_and_attrs); | |
| 571 | } | |
| 572 | ||
| 573 | pub fn CreateFileW( | |
| 574 | file_path_w: [*]const u16, | |
| 575 | desired_access: DWORD, | |
| 576 | share_mode: DWORD, | |
| 577 | creation_disposition: DWORD, | |
| 578 | flags_and_attrs: DWORD, | |
| 579 | ) OpenError!HANDLE { | |
| 580 | const result = kernel32.CreateFileW(file_path_w, desired_access, share_mode, null, creation_disposition, flags_and_attrs, null); | |
| 581 | ||
| 582 | if (result == INVALID_HANDLE_VALUE) { | |
| 583 | switch (kernel32.GetLastError()) { | |
| 584 | ERROR.SHARING_VIOLATION => return error.SharingViolation, | |
| 585 | ERROR.ALREADY_EXISTS => return error.PathAlreadyExists, | |
| 586 | ERROR.FILE_EXISTS => return error.PathAlreadyExists, | |
| 587 | ERROR.FILE_NOT_FOUND => return error.FileNotFound, | |
| 588 | ERROR.PATH_NOT_FOUND => return error.FileNotFound, | |
| 589 | ERROR.ACCESS_DENIED => return error.AccessDenied, | |
| 590 | ERROR.PIPE_BUSY => return error.PipeBusy, | |
| 591 | else => |err| return unexpectedErrorWindows(err), | |
| 592 | } | |
| 593 | } | |
| 594 | ||
| 595 | return result; | |
| 596 | } | |
| 597 | ||
| 598 | pub const CreatePipeError = error{Unexpected}; | |
| 599 | ||
| 600 | fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) CreatePipeError!void { | |
| 601 | if (kernel32.CreatePipe(rd, wr, sattr, 0) == 0) { | |
| 602 | switch (kernel32.GetLastError()) { | |
| 603 | else => |err| return unexpectedError(err), | |
| 604 | } | |
| 605 | } | |
| 606 | } | |
| 607 | ||
| 608 | pub const SetHandleInformationError = error{Unexpected}; | |
| 609 | ||
| 610 | fn SetHandleInformation(h: HANDLE, mask: DWORD, flags: DWORD) SetHandleInformationError!void { | |
| 611 | if (SetHandleInformation(h, mask, flags) == 0) { | |
| 612 | switch (kernel32.GetLastError()) { | |
| 613 | else => |err| return unexpectedError(err), | |
| 614 | } | |
| 615 | } | |
| 616 | } | |
| 617 | ||
| 618 | pub fn cStrToPrefixedFileW(s: [*]const u8) ![PATH_MAX_WIDE + 1]u16 { | |
| 619 | return sliceToPrefixedFileW(mem.toSliceConst(u8, s)); | |
| 620 | } | |
| 621 | ||
| 622 | pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 { | |
| 623 | return sliceToPrefixedSuffixedFileW(s, []u16{0}); | |
| 624 | } | |
| 625 | ||
| 626 | pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) ![PATH_MAX_WIDE + suffix.len]u16 { | |
| 627 | // TODO well defined copy elision | |
| 628 | var result: [PATH_MAX_WIDE + suffix.len]u16 = undefined; | |
| 629 | ||
| 630 | // > File I/O functions in the Windows API convert "/" to "\" as part of | |
| 631 | // > converting the name to an NT-style name, except when using the "\\?\" | |
| 632 | // > prefix as detailed in the following sections. | |
| 633 | // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation | |
| 634 | // Because we want the larger maximum path length for absolute paths, we | |
| 635 | // disallow forward slashes in zig std lib file functions on Windows. | |
| 636 | for (s) |byte| { | |
| 637 | switch (byte) { | |
| 638 | '/', '*', '?', '"', '<', '>', '|' => return error.BadPathName, | |
| 639 | else => {}, | |
| 640 | } | |
| 641 | } | |
| 642 | const start_index = if (mem.startsWith(u8, s, "\\\\") or !os.path.isAbsolute(s)) 0 else blk: { | |
| 643 | const prefix = []u16{ '\\', '\\', '?', '\\' }; | |
| 644 | mem.copy(u16, result[0..], prefix); | |
| 645 | break :blk prefix.len; | |
| 646 | }; | |
| 647 | const end_index = start_index + try std.unicode.utf8ToUtf16Le(result[start_index..], s); | |
| 648 | assert(end_index <= result.len); | |
| 649 | if (end_index + suffix.len > result.len) return error.NameTooLong; | |
| 650 | mem.copy(u16, result[end_index..], suffix); | |
| 651 | return result; | |
| 652 | } | |
| 653 | ||
| 654 | /// Call this when you made a windows DLL call or something that does SetLastError | |
| 655 | /// and you get an unexpected error. | |
| 656 | pub fn unexpectedError(err: DWORD) std.os.UnexpectedError { | |
| 657 | if (std.os.unexpected_error_tracing) { | |
| 658 | std.debug.warn("unexpected GetLastError(): {}\n", err); | |
| 659 | std.debug.dumpCurrentStackTrace(null); | |
| 660 | } | |
| 661 | return error.Unexpected; | |
| 662 | } |
std/os/windows/advapi32.zig-11| ... | ... | @@ -1,16 +1,5 @@ |
| 1 | 1 | use @import("../windows.zig"); |
| 2 | 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 | ||
| 14 | 3 | pub extern "advapi32" stdcallcc fn RegOpenKeyExW( |
| 15 | 4 | hKey: HKEY, |
| 16 | 5 | lpSubKey: LPCWSTR, |
std/os/windows/kernel32.zig-77| ... | ... | @@ -189,86 +189,9 @@ pub extern "kernel32" stdcallcc fn GetProcAddress(hModule: HMODULE, lpProcName: |
| 189 | 189 | |
| 190 | 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 | 192 | pub extern "kernel32" stdcallcc fn InitializeCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; |
| 232 | 193 | pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; |
| 233 | 194 | pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; |
| 234 | 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 | 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/ole32.zig-11| ... | ... | @@ -4,14 +4,3 @@ pub extern "ole32" stdcallcc fn CoTaskMemFree(pv: LPVOID) void; |
| 4 | 4 | pub extern "ole32" stdcallcc fn CoUninitialize() void; |
| 5 | 5 | pub extern "ole32" stdcallcc fn CoGetCurrentProcess() DWORD; |
| 6 | 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/posix.zig+4-13| ... | ... | @@ -1,15 +1,6 @@ |
| 1 | // Declarations that are intended to be imported into the POSIX namespace. | |
| 1 | // Declarations that are intended to be imported into the POSIX namespace, | |
| 2 | // when not linking libc. | |
| 2 | 3 | const std = @import("../../std.zig"); |
| 3 | const maxInt = std.math.maxInt; | |
| 4 | use std.os.windows; | |
| 4 | const builtin = @import("builtin"); | |
| 5 | 5 | |
| 6 | pub const fd_t = HANDLE; | |
| 7 | ||
| 8 | /// The standard input device. Initially, this is the console input buffer, CONIN$. | |
| 9 | pub const STD_INPUT_HANDLE = maxInt(DWORD) - 10 + 1; | |
| 10 | ||
| 11 | /// The standard output device. Initially, this is the active console screen buffer, CONOUT$. | |
| 12 | pub const STD_OUTPUT_HANDLE = maxInt(DWORD) - 11 + 1; | |
| 13 | ||
| 14 | /// The standard error device. Initially, this is the active console screen buffer, CONOUT$. | |
| 15 | pub const STD_ERROR_HANDLE = maxInt(DWORD) - 12 + 1; | |
| 6 | pub const fd_t = std.os.windows.HANDLE; |
std/os/windows/util.zig deleted-147| ... | ... | @@ -1,147 +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 | pub const WaitError = error{ | |
| 12 | WaitAbandoned, | |
| 13 | WaitTimeOut, | |
| 14 | Unexpected, | |
| 15 | }; | |
| 16 | ||
| 17 | pub fn windowsWaitSingle(handle: windows.HANDLE, milliseconds: windows.DWORD) WaitError!void { | |
| 18 | const result = windows.WaitForSingleObject(handle, milliseconds); | |
| 19 | return switch (result) { | |
| 20 | windows.WAIT_ABANDONED => error.WaitAbandoned, | |
| 21 | windows.WAIT_OBJECT_0 => {}, | |
| 22 | windows.WAIT_TIMEOUT => error.WaitTimeOut, | |
| 23 | windows.WAIT_FAILED => x: { | |
| 24 | const err = windows.GetLastError(); | |
| 25 | break :x switch (err) { | |
| 26 | else => os.unexpectedErrorWindows(err), | |
| 27 | }; | |
| 28 | }, | |
| 29 | else => error.Unexpected, | |
| 30 | }; | |
| 31 | } | |
| 32 | ||
| 33 | /// Caller must free result. | |
| 34 | pub fn createWindowsEnvBlock(allocator: *mem.Allocator, env_map: *const BufMap) ![]u16 { | |
| 35 | // count bytes needed | |
| 36 | const max_chars_needed = x: { | |
| 37 | var max_chars_needed: usize = 4; // 4 for the final 4 null bytes | |
| 38 | var it = env_map.iterator(); | |
| 39 | while (it.next()) |pair| { | |
| 40 | // +1 for '=' | |
| 41 | // +1 for null byte | |
| 42 | max_chars_needed += pair.key.len + pair.value.len + 2; | |
| 43 | } | |
| 44 | break :x max_chars_needed; | |
| 45 | }; | |
| 46 | const result = try allocator.alloc(u16, max_chars_needed); | |
| 47 | errdefer allocator.free(result); | |
| 48 | ||
| 49 | var it = env_map.iterator(); | |
| 50 | var i: usize = 0; | |
| 51 | while (it.next()) |pair| { | |
| 52 | i += try unicode.utf8ToUtf16Le(result[i..], pair.key); | |
| 53 | result[i] = '='; | |
| 54 | i += 1; | |
| 55 | i += try unicode.utf8ToUtf16Le(result[i..], pair.value); | |
| 56 | result[i] = 0; | |
| 57 | i += 1; | |
| 58 | } | |
| 59 | result[i] = 0; | |
| 60 | i += 1; | |
| 61 | result[i] = 0; | |
| 62 | i += 1; | |
| 63 | result[i] = 0; | |
| 64 | i += 1; | |
| 65 | result[i] = 0; | |
| 66 | i += 1; | |
| 67 | return allocator.shrink(result, i); | |
| 68 | } | |
| 69 | ||
| 70 | pub fn windowsFindFirstFile( | |
| 71 | dir_path: []const u8, | |
| 72 | find_file_data: *windows.WIN32_FIND_DATAW, | |
| 73 | ) !windows.HANDLE { | |
| 74 | const dir_path_w = try sliceToPrefixedSuffixedFileW(dir_path, []u16{ '\\', '*', 0 }); | |
| 75 | const handle = windows.FindFirstFileW(&dir_path_w, find_file_data); | |
| 76 | ||
| 77 | if (handle == windows.INVALID_HANDLE_VALUE) { | |
| 78 | const err = windows.GetLastError(); | |
| 79 | switch (err) { | |
| 80 | windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound, | |
| 81 | windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound, | |
| 82 | else => return os.unexpectedErrorWindows(err), | |
| 83 | } | |
| 84 | } | |
| 85 | ||
| 86 | return handle; | |
| 87 | } | |
| 88 | ||
| 89 | /// Returns `true` if there was another file, `false` otherwise. | |
| 90 | pub fn windowsFindNextFile(handle: windows.HANDLE, find_file_data: *windows.WIN32_FIND_DATAW) !bool { | |
| 91 | if (windows.FindNextFileW(handle, find_file_data) == 0) { | |
| 92 | const err = windows.GetLastError(); | |
| 93 | return switch (err) { | |
| 94 | windows.ERROR.NO_MORE_FILES => false, | |
| 95 | else => os.unexpectedErrorWindows(err), | |
| 96 | }; | |
| 97 | } | |
| 98 | return true; | |
| 99 | } | |
| 100 | ||
| 101 | pub const WindowsCreateIoCompletionPortError = error{Unexpected}; | |
| 102 | ||
| 103 | pub fn windowsCreateIoCompletionPort(file_handle: windows.HANDLE, existing_completion_port: ?windows.HANDLE, completion_key: usize, concurrent_thread_count: windows.DWORD) !windows.HANDLE { | |
| 104 | const handle = windows.CreateIoCompletionPort(file_handle, existing_completion_port, completion_key, concurrent_thread_count) orelse { | |
| 105 | const err = windows.GetLastError(); | |
| 106 | switch (err) { | |
| 107 | windows.ERROR.INVALID_PARAMETER => unreachable, | |
| 108 | else => return os.unexpectedErrorWindows(err), | |
| 109 | } | |
| 110 | }; | |
| 111 | return handle; | |
| 112 | } | |
| 113 | ||
| 114 | pub const WindowsPostQueuedCompletionStatusError = error{Unexpected}; | |
| 115 | ||
| 116 | pub fn windowsPostQueuedCompletionStatus(completion_port: windows.HANDLE, bytes_transferred_count: windows.DWORD, completion_key: usize, lpOverlapped: ?*windows.OVERLAPPED) WindowsPostQueuedCompletionStatusError!void { | |
| 117 | if (windows.PostQueuedCompletionStatus(completion_port, bytes_transferred_count, completion_key, lpOverlapped) == 0) { | |
| 118 | const err = windows.GetLastError(); | |
| 119 | switch (err) { | |
| 120 | else => return os.unexpectedErrorWindows(err), | |
| 121 | } | |
| 122 | } | |
| 123 | } | |
| 124 | ||
| 125 | pub const WindowsWaitResult = enum { | |
| 126 | Normal, | |
| 127 | Aborted, | |
| 128 | Cancelled, | |
| 129 | EOF, | |
| 130 | }; | |
| 131 | ||
| 132 | pub fn windowsGetQueuedCompletionStatus(completion_port: windows.HANDLE, bytes_transferred_count: *windows.DWORD, lpCompletionKey: *usize, lpOverlapped: *?*windows.OVERLAPPED, dwMilliseconds: windows.DWORD) WindowsWaitResult { | |
| 133 | if (windows.GetQueuedCompletionStatus(completion_port, bytes_transferred_count, lpCompletionKey, lpOverlapped, dwMilliseconds) == windows.FALSE) { | |
| 134 | const err = windows.GetLastError(); | |
| 135 | switch (err) { | |
| 136 | windows.ERROR.ABANDONED_WAIT_0 => return WindowsWaitResult.Aborted, | |
| 137 | windows.ERROR.OPERATION_ABORTED => return WindowsWaitResult.Cancelled, | |
| 138 | windows.ERROR.HANDLE_EOF => return WindowsWaitResult.EOF, | |
| 139 | else => { | |
| 140 | if (std.debug.runtime_safety) { | |
| 141 | std.debug.panic("unexpected error: {}\n", err); | |
| 142 | } | |
| 143 | }, | |
| 144 | } | |
| 145 | } | |
| 146 | return WindowsWaitResult.Normal; | |
| 147 | } |