| author | |
| committer | |
| log | 2def23063fbabb4128da17aca27745a7e8062ce5 |
| tree | 53d8e79eebc72a0ff171ff6f911e2c4eb2ef5cdc |
| parent | daae7e1f5aa5aac02a342c9a60d703c2a0cba579 |
| signature |
14 files changed, 1331 insertions(+), 1317 deletions(-)
CMakeLists.txt+1| ... | @@ -619,6 +619,7 @@ set(ZIG_STD_FILES | ... | @@ -619,6 +619,7 @@ set(ZIG_STD_FILES |
| 619 | "os/linux/posix.zig" | 619 | "os/linux/posix.zig" |
| 620 | "os/linux/posix/arm64.zig" | 620 | "os/linux/posix/arm64.zig" |
| 621 | "os/linux/posix/x86_64.zig" | 621 | "os/linux/posix/x86_64.zig" |
| 622 | "os/linux/sys.zig" | ||
| 622 | "os/linux/tls.zig" | 623 | "os/linux/tls.zig" |
| 623 | "os/linux/vdso.zig" | 624 | "os/linux/vdso.zig" |
| 624 | "os/linux/x86_64.zig" | 625 | "os/linux/x86_64.zig" |
std/dynamic_library.zig+2-3| ... | @@ -261,12 +261,11 @@ pub const WindowsDynLib = struct { | ... | @@ -261,12 +261,11 @@ pub const WindowsDynLib = struct { |
| 261 | return WindowsDynLib{ | 261 | return WindowsDynLib{ |
| 262 | .allocator = allocator, | 262 | .allocator = allocator, |
| 263 | .dll = windows.LoadLibraryW(&wpath) orelse { | 263 | .dll = windows.LoadLibraryW(&wpath) orelse { |
| 264 | const err = windows.GetLastError(); | 264 | switch (windows.GetLastError()) { |
| 265 | switch (err) { | ||
| 266 | windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound, | 265 | windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound, |
| 267 | windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound, | 266 | windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound, |
| 268 | windows.ERROR.MOD_NOT_FOUND => return error.FileNotFound, | 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,16 +154,15 @@ pub async fn pwriteWindows(loop: *Loop, fd: fd_t, data: []const u8, offset: u64) |
| 154 | } | 154 | } |
| 155 | var bytes_transferred: windows.DWORD = undefined; | 155 | var bytes_transferred: windows.DWORD = undefined; |
| 156 | if (windows.GetOverlappedResult(fd, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) { | 156 | if (windows.GetOverlappedResult(fd, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) { |
| 157 | const err = windows.GetLastError(); | 157 | switch (windows.GetLastError()) { |
| 158 | return switch (err) { | ||
| 159 | windows.ERROR.IO_PENDING => unreachable, | 158 | windows.ERROR.IO_PENDING => unreachable, |
| 160 | windows.ERROR.INVALID_USER_BUFFER => error.SystemResources, | 159 | windows.ERROR.INVALID_USER_BUFFER => return error.SystemResources, |
| 161 | windows.ERROR.NOT_ENOUGH_MEMORY => error.SystemResources, | 160 | windows.ERROR.NOT_ENOUGH_MEMORY => return error.SystemResources, |
| 162 | windows.ERROR.OPERATION_ABORTED => error.OperationAborted, | 161 | windows.ERROR.OPERATION_ABORTED => return error.OperationAborted, |
| 163 | windows.ERROR.NOT_ENOUGH_QUOTA => error.SystemResources, | 162 | windows.ERROR.NOT_ENOUGH_QUOTA => return error.SystemResources, |
| 164 | windows.ERROR.BROKEN_PIPE => error.BrokenPipe, | 163 | windows.ERROR.BROKEN_PIPE => return error.BrokenPipe, |
| 165 | else => os.unexpectedErrorWindows(err), | 164 | else => |err| return windows.unexpectedError(err), |
| 166 | }; | 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,13 +303,12 @@ pub async fn preadWindows(loop: *Loop, fd: fd_t, data: []u8, offset: u64) !usize |
| 304 | } | 303 | } |
| 305 | var bytes_transferred: windows.DWORD = undefined; | 304 | var bytes_transferred: windows.DWORD = undefined; |
| 306 | if (windows.GetOverlappedResult(fd, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) { | 305 | if (windows.GetOverlappedResult(fd, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) { |
| 307 | const err = windows.GetLastError(); | 306 | switch (windows.GetLastError()) { |
| 308 | switch (err) { | ||
| 309 | windows.ERROR.IO_PENDING => unreachable, | 307 | windows.ERROR.IO_PENDING => unreachable, |
| 310 | windows.ERROR.OPERATION_ABORTED => return error.OperationAborted, | 308 | windows.ERROR.OPERATION_ABORTED => return error.OperationAborted, |
| 311 | windows.ERROR.BROKEN_PIPE => return error.BrokenPipe, | 309 | windows.ERROR.BROKEN_PIPE => return error.BrokenPipe, |
| 312 | windows.ERROR.HANDLE_EOF => return usize(bytes_transferred), | 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 | return usize(bytes_transferred); | 314 | return usize(bytes_transferred); |
| ... | @@ -1042,11 +1040,10 @@ pub fn Watch(comptime V: type) type { | ... | @@ -1042,11 +1040,10 @@ pub fn Watch(comptime V: type) type { |
| 1042 | null, | 1040 | null, |
| 1043 | ); | 1041 | ); |
| 1044 | if (dir_handle == windows.INVALID_HANDLE_VALUE) { | 1042 | if (dir_handle == windows.INVALID_HANDLE_VALUE) { |
| 1045 | const err = windows.GetLastError(); | 1043 | switch (windows.GetLastError()) { |
| 1046 | switch (err) { | ||
| 1047 | windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound, | 1044 | windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound, |
| 1048 | windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound, | 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 | var dir_handle_consumed = false; | 1049 | var dir_handle_consumed = false; |
| ... | @@ -1165,9 +1162,8 @@ pub fn Watch(comptime V: type) type { | ... | @@ -1165,9 +1162,8 @@ pub fn Watch(comptime V: type) type { |
| 1165 | } | 1162 | } |
| 1166 | var bytes_transferred: windows.DWORD = undefined; | 1163 | var bytes_transferred: windows.DWORD = undefined; |
| 1167 | if (windows.GetOverlappedResult(dir_handle, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) { | 1164 | if (windows.GetOverlappedResult(dir_handle, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) { |
| 1168 | const errno = windows.GetLastError(); | 1165 | const err = switch (windows.GetLastError()) { |
| 1169 | const err = switch (errno) { | 1166 | else => |err| windows.unexpectedError(err), |
| 1170 | else => os.unexpectedErrorWindows(errno), | ||
| 1171 | }; | 1167 | }; |
| 1172 | await (async self.channel.put(err) catch unreachable); | 1168 | await (async self.channel.put(err) catch unreachable); |
| 1173 | } else { | 1169 | } else { |
std/os.zig+14-8| ... | @@ -31,13 +31,14 @@ pub const zen = @import("os/zen.zig"); | ... | @@ -31,13 +31,14 @@ pub const zen = @import("os/zen.zig"); |
| 31 | pub const uefi = @import("os/uefi.zig"); | 31 | pub const uefi = @import("os/uefi.zig"); |
| 32 | pub const wasi = @import("os/wasi.zig"); | 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 | .linux => linux, | 35 | .linux => linux, |
| 36 | .macosx, .ios, .watchos, .tvos => darwin, | 36 | .macosx, .ios, .watchos, .tvos => darwin, |
| 37 | .freebsd => freebsd, | 37 | .freebsd => freebsd, |
| 38 | .netbsd => netbsd, | 38 | .netbsd => netbsd, |
| 39 | .zen => zen, | 39 | .zen => zen, |
| 40 | .wasi => wasi, | 40 | .wasi => wasi, |
| 41 | .windows => windows, | ||
| 41 | else => struct {}, | 42 | else => struct {}, |
| 42 | }; | 43 | }; |
| 43 | 44 | ||
| ... | @@ -53,6 +54,12 @@ pub const page_size = switch (builtin.arch) { | ... | @@ -53,6 +54,12 @@ pub const page_size = switch (builtin.arch) { |
| 53 | else => 4 * 1024, | 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 | /// This represents the maximum size of a UTF-8 encoded file path. | 63 | /// This represents the maximum size of a UTF-8 encoded file path. |
| 57 | /// All file system operations which return a path are guaranteed to | 64 | /// All file system operations which return a path are guaranteed to |
| 58 | /// fit into a UTF-8 encoded array of this length. | 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,7 +266,7 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned |
| 259 | return switch (err) { | 266 | return switch (err) { |
| 260 | windows.ERROR.ENVVAR_NOT_FOUND => error.EnvironmentVariableNotFound, | 267 | windows.ERROR.ENVVAR_NOT_FOUND => error.EnvironmentVariableNotFound, |
| 261 | else => { | 268 | else => { |
| 262 | unexpectedErrorWindows(err) catch {}; | 269 | windows.unexpectedError(err) catch {}; |
| 263 | return error.EnvironmentVariableNotFound; | 270 | return error.EnvironmentVariableNotFound; |
| 264 | }, | 271 | }, |
| 265 | }; | 272 | }; |
| ... | @@ -825,7 +832,7 @@ pub const Dir = struct { | ... | @@ -825,7 +832,7 @@ pub const Dir = struct { |
| 825 | if (self.handle.first) { | 832 | if (self.handle.first) { |
| 826 | self.handle.first = false; | 833 | self.handle.first = false; |
| 827 | } else { | 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 | return null; | 836 | return null; |
| 830 | } | 837 | } |
| 831 | const name_utf16le = mem.toSlice(u16, self.handle.find_file_data.cFileName[0..].ptr); | 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,7 +1340,7 @@ pub fn selfExePathW(out_buffer: *[posix.PATH_MAX_WIDE]u16) ![]u16 { |
| 1333 | if (rc == 0) { | 1340 | if (rc == 0) { |
| 1334 | const err = windows.GetLastError(); | 1341 | const err = windows.GetLastError(); |
| 1335 | switch (err) { | 1342 | switch (err) { |
| 1336 | else => return unexpectedErrorWindows(err), | 1343 | else => return windows.unexpectedError(err), |
| 1337 | } | 1344 | } |
| 1338 | } | 1345 | } |
| 1339 | return out_buffer[0..rc]; | 1346 | return out_buffer[0..rc]; |
| ... | @@ -1597,10 +1604,9 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread | ... | @@ -1597,10 +1604,9 @@ pub fn spawnThread(context: var, comptime startFn: var) SpawnThreadError!*Thread |
| 1597 | 1604 | ||
| 1598 | const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner); | 1605 | const parameter = if (@sizeOf(Context) == 0) null else @ptrCast(*c_void, &outer_context.inner); |
| 1599 | outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse { | 1606 | outer_context.thread.data.handle = windows.CreateThread(null, default_stack_size, WinThread.threadMain, parameter, 0, null) orelse { |
| 1600 | const err = windows.GetLastError(); | 1607 | switch (windows.GetLastError()) { |
| 1601 | return switch (err) { | 1608 | else => |err| windows.unexpectedError(err), |
| 1602 | else => os.unexpectedErrorWindows(err), | 1609 | } |
| 1603 | }; | ||
| 1604 | }; | 1610 | }; |
| 1605 | return &outer_context.thread; | 1611 | return &outer_context.thread; |
| 1606 | } | 1612 | } |
std/os/child_process.zig+42-28| ... | @@ -558,7 +558,7 @@ pub const ChildProcess = struct { | ... | @@ -558,7 +558,7 @@ pub const ChildProcess = struct { |
| 558 | defer if (cwd_w) |cwd| self.allocator.free(cwd); | 558 | defer if (cwd_w) |cwd| self.allocator.free(cwd); |
| 559 | const cwd_w_ptr = if (cwd_w) |cwd| cwd.ptr else null; | 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 | defer if (maybe_envp_buf) |envp_buf| self.allocator.free(envp_buf); | 562 | defer if (maybe_envp_buf) |envp_buf| self.allocator.free(envp_buf); |
| 563 | const envp_ptr = if (maybe_envp_buf) |envp_buf| envp_buf.ptr else null; | 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,13 +679,12 @@ fn windowsCreateProcess(app_name: [*]u16, cmd_line: [*]u16, envp_ptr: ?[*]u16, c |
| 679 | lpStartupInfo, | 679 | lpStartupInfo, |
| 680 | lpProcessInformation, | 680 | lpProcessInformation, |
| 681 | ) == 0) { | 681 | ) == 0) { |
| 682 | const err = windows.GetLastError(); | 682 | switch (windows.GetLastError()) { |
| 683 | switch (err) { | ||
| 684 | windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound, | 683 | windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound, |
| 685 | windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound, | 684 | windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound, |
| 686 | windows.ERROR.INVALID_PARAMETER => unreachable, | 685 | windows.ERROR.INVALID_PARAMETER => unreachable, |
| 687 | windows.ERROR.INVALID_NAME => return error.InvalidName, | 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,32 +732,10 @@ fn windowsDestroyPipe(rd: ?windows.HANDLE, wr: ?windows.HANDLE) void { |
| 733 | if (wr) |h| os.close(h); | 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 | fn windowsMakePipeIn(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const SECURITY_ATTRIBUTES) !void { | 735 | fn windowsMakePipeIn(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const SECURITY_ATTRIBUTES) !void { |
| 759 | var rd_h: windows.HANDLE = undefined; | 736 | var rd_h: windows.HANDLE = undefined; |
| 760 | var wr_h: windows.HANDLE = undefined; | 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 | errdefer windowsDestroyPipe(rd_h, wr_h); | 739 | errdefer windowsDestroyPipe(rd_h, wr_h); |
| 763 | try windowsSetHandleInfo(wr_h, windows.HANDLE_FLAG_INHERIT, 0); | 740 | try windowsSetHandleInfo(wr_h, windows.HANDLE_FLAG_INHERIT, 0); |
| 764 | rd.* = rd_h; | 741 | rd.* = rd_h; |
| ... | @@ -768,7 +745,7 @@ fn windowsMakePipeIn(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const S | ... | @@ -768,7 +745,7 @@ fn windowsMakePipeIn(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const S |
| 768 | fn windowsMakePipeOut(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const SECURITY_ATTRIBUTES) !void { | 745 | fn windowsMakePipeOut(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const SECURITY_ATTRIBUTES) !void { |
| 769 | var rd_h: windows.HANDLE = undefined; | 746 | var rd_h: windows.HANDLE = undefined; |
| 770 | var wr_h: windows.HANDLE = undefined; | 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 | errdefer windowsDestroyPipe(rd_h, wr_h); | 749 | errdefer windowsDestroyPipe(rd_h, wr_h); |
| 773 | try windowsSetHandleInfo(rd_h, windows.HANDLE_FLAG_INHERIT, 0); | 750 | try windowsSetHandleInfo(rd_h, windows.HANDLE_FLAG_INHERIT, 0); |
| 774 | rd.* = rd_h; | 751 | rd.* = rd_h; |
| ... | @@ -810,3 +787,40 @@ fn readIntFd(fd: i32) !ErrInt { | ... | @@ -810,3 +787,40 @@ fn readIntFd(fd: i32) !ErrInt { |
| 810 | const stream = &os.File.openHandle(fd).inStream().stream; | 787 | const stream = &os.File.openHandle(fd).inStream().stream; |
| 811 | return stream.readIntNative(ErrInt) catch return error.SystemResources; | 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,771 +1,8 @@ |
| 1 | const std = @import("../std.zig"); | 1 | const std = @import("../std.zig"); |
| 2 | const assert = std.debug.assert; | ||
| 3 | const builtin = @import("builtin"); | 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 | pub const is_the_target = builtin.os == .linux; | 3 | pub const is_the_target = builtin.os == .linux; |
| 15 | pub const posix = @import("linux/posix.zig"); | 4 | pub const sys = @import("linux/sys.zig"); |
| 16 | pub use posix; | 5 | pub use if (builtin.link_libc) std.c else sys; |
| 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 | } | ||
| 769 | 6 | ||
| 770 | test "import" { | 7 | test "import" { |
| 771 | if (is_the_target) { | 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,21 +2,18 @@ |
| 2 | // The purpose is not to match POSIX as closely as possible. Instead, | 2 | // The purpose is not to match POSIX as closely as possible. Instead, |
| 3 | // the goal is to provide a very specific layer of abstraction: | 3 | // the goal is to provide a very specific layer of abstraction: |
| 4 | // * Implement the POSIX functions, types, and definitions where possible, | 4 | // * Implement the POSIX functions, types, and definitions where possible, |
| 5 | // using lower-level target-specific API. For example, on Linux `rename` might call | 5 | // using lower-level target-specific API. |
| 6 | // SYS_renameat or SYS_rename depending on the architecture. | ||
| 7 | // * When null-terminated byte buffers are required, provide APIs which accept | 6 | // * When null-terminated byte buffers are required, provide APIs which accept |
| 8 | // slices as well as APIs which accept null-terminated byte buffers. Same goes | 7 | // slices as well as APIs which accept null-terminated byte buffers. Same goes |
| 9 | // for UTF-16LE encoding. | 8 | // for UTF-16LE encoding. |
| 10 | // * Convert "errno"-style error codes into Zig errors. | 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 | // * Implement the OS-specific functions, types, and definitions that the Zig | 10 | // * Implement the OS-specific functions, types, and definitions that the Zig |
| 16 | // standard library needs, at the same API abstraction layer as outlined above. | 11 | // standard library needs, at the same API abstraction layer as outlined above. |
| 17 | // this includes, for example Windows functions. | 12 | // For example kevent() and getrandom(). Windows-specific functions are separate, |
| 18 | // * When there exists a corresponding libc function and linking libc, call the | 13 | // in `std.os.windows`. |
| 19 | // libc function. | 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 | // Note: The Zig standard library does not support POSIX thread cancellation, and | 17 | // Note: The Zig standard library does not support POSIX thread cancellation, and |
| 21 | // in general EINTR is handled by trying again. | 18 | // in general EINTR is handled by trying again. |
| 22 | 19 | ||
| ... | @@ -29,18 +26,13 @@ const mem = std.mem; | ... | @@ -29,18 +26,13 @@ const mem = std.mem; |
| 29 | const BufMap = std.BufMap; | 26 | const BufMap = std.BufMap; |
| 30 | const Allocator = mem.Allocator; | 27 | const Allocator = mem.Allocator; |
| 31 | const windows = os.windows; | 28 | const windows = os.windows; |
| 29 | const kernel32 = windows.kernel32; | ||
| 32 | const wasi = os.wasi; | 30 | const wasi = os.wasi; |
| 33 | const linux = os.linux; | 31 | const linux = os.linux; |
| 34 | const testing = std.testing; | 32 | const testing = std.testing; |
| 35 | 33 | ||
| 36 | pub use system.posix; | 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 | /// See also `getenv`. | 36 | /// See also `getenv`. |
| 45 | pub var environ: [][*]u8 = undefined; | 37 | pub var environ: [][*]u8 = undefined; |
| 46 | 38 | ||
| ... | @@ -59,7 +51,7 @@ pub const errno = system.getErrno; | ... | @@ -59,7 +51,7 @@ pub const errno = system.getErrno; |
| 59 | /// Note: The Zig standard library does not support POSIX thread cancellation. | 51 | /// Note: The Zig standard library does not support POSIX thread cancellation. |
| 60 | pub fn close(fd: fd_t) void { | 52 | pub fn close(fd: fd_t) void { |
| 61 | if (windows.is_the_target and !builtin.link_libc) { | 53 | if (windows.is_the_target and !builtin.link_libc) { |
| 62 | assert(windows.CloseHandle(fd) != 0); | 54 | assert(kernel32.CloseHandle(fd) != 0); |
| 63 | return; | 55 | return; |
| 64 | } | 56 | } |
| 65 | if (wasi.is_the_target) { | 57 | if (wasi.is_the_target) { |
| ... | @@ -87,11 +79,10 @@ pub fn getrandom(buf: []u8) GetRandomError!void { | ... | @@ -87,11 +79,10 @@ pub fn getrandom(buf: []u8) GetRandomError!void { |
| 87 | // Call RtlGenRandom() instead of CryptGetRandom() on Windows | 79 | // Call RtlGenRandom() instead of CryptGetRandom() on Windows |
| 88 | // https://github.com/rust-lang-nursery/rand/issues/111 | 80 | // https://github.com/rust-lang-nursery/rand/issues/111 |
| 89 | // https://bugzilla.mozilla.org/show_bug.cgi?id=504270 | 81 | // https://bugzilla.mozilla.org/show_bug.cgi?id=504270 |
| 90 | if (windows.RtlGenRandom(buf.ptr, buf.len) == 0) { | 82 | if (windows.advapi32.RtlGenRandom(buf.ptr, buf.len) == 0) { |
| 91 | const err = windows.GetLastError(); | 83 | switch (kernel32.GetLastError()) { |
| 92 | return switch (err) { | 84 | else => |err| return windows.unexpectedError(err), |
| 93 | else => unexpectedErrorWindows(err), | 85 | } |
| 94 | }; | ||
| 95 | } | 86 | } |
| 96 | return; | 87 | return; |
| 97 | } | 88 | } |
| ... | @@ -230,12 +221,11 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { | ... | @@ -230,12 +221,11 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { |
| 230 | const want_read_count = @intCast(windows.DWORD, math.min(windows.DWORD(math.maxInt(windows.DWORD)), buffer.len - index)); | 221 | const want_read_count = @intCast(windows.DWORD, math.min(windows.DWORD(math.maxInt(windows.DWORD)), buffer.len - index)); |
| 231 | var amt_read: windows.DWORD = undefined; | 222 | var amt_read: windows.DWORD = undefined; |
| 232 | if (windows.ReadFile(fd, buffer.ptr + index, want_read_count, &amt_read, null) == 0) { | 223 | if (windows.ReadFile(fd, buffer.ptr + index, want_read_count, &amt_read, null) == 0) { |
| 233 | const err = windows.GetLastError(); | 224 | switch (windows.GetLastError()) { |
| 234 | return switch (err) { | ||
| 235 | windows.ERROR.OPERATION_ABORTED => continue, | 225 | windows.ERROR.OPERATION_ABORTED => continue, |
| 236 | windows.ERROR.BROKEN_PIPE => return index, | 226 | windows.ERROR.BROKEN_PIPE => return index, |
| 237 | else => unexpectedErrorWindows(err), | 227 | else => |err| return windows.unexpectedError(err), |
| 238 | }; | 228 | } |
| 239 | } | 229 | } |
| 240 | if (amt_read == 0) return index; | 230 | if (amt_read == 0) return index; |
| 241 | index += amt_read; | 231 | index += amt_read; |
| ... | @@ -372,7 +362,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!void { | ... | @@ -372,7 +362,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!void { |
| 372 | windows.ERROR.NOT_ENOUGH_QUOTA => return error.SystemResources, | 362 | windows.ERROR.NOT_ENOUGH_QUOTA => return error.SystemResources, |
| 373 | windows.ERROR.IO_PENDING => unreachable, | 363 | windows.ERROR.IO_PENDING => unreachable, |
| 374 | windows.ERROR.BROKEN_PIPE => return error.BrokenPipe, | 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,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 | pub fn dup2(old_fd: fd_t, new_fd: fd_t) !void { | 536 | pub fn dup2(old_fd: fd_t, new_fd: fd_t) !void { |
| 608 | while (true) { | 537 | while (true) { |
| 609 | switch (errno(system.dup2(old_fd, new_fd))) { | 538 | switch (errno(system.dup2(old_fd, new_fd))) { |
| ... | @@ -797,14 +726,13 @@ pub const GetCwdError = error{ | ... | @@ -797,14 +726,13 @@ pub const GetCwdError = error{ |
| 797 | /// The result is a slice of out_buffer, indexed from 0. | 726 | /// The result is a slice of out_buffer, indexed from 0. |
| 798 | pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 { | 727 | pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 { |
| 799 | if (windows.is_the_target and !builtin.link_libc) { | 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 | const casted_len = @intCast(windows.DWORD, utf16le_buf.len); // TODO shouldn't need this cast | 730 | const casted_len = @intCast(windows.DWORD, utf16le_buf.len); // TODO shouldn't need this cast |
| 802 | const casted_ptr = ([*]u16)(&utf16le_buf); // TODO shouldn't need this cast | 731 | const casted_ptr = ([*]u16)(&utf16le_buf); // TODO shouldn't need this cast |
| 803 | const result = windows.GetCurrentDirectoryW(casted_len, casted_ptr); | 732 | const result = windows.GetCurrentDirectoryW(casted_len, casted_ptr); |
| 804 | if (result == 0) { | 733 | if (result == 0) { |
| 805 | const err = windows.GetLastError(); | 734 | switch (windows.GetLastError()) { |
| 806 | switch (err) { | 735 | else => |err| return windows.unexpectedError(err), |
| 807 | else => return unexpectedErrorWindows(err), | ||
| 808 | } | 736 | } |
| 809 | } | 737 | } |
| 810 | assert(result <= utf16le_buf.len); | 738 | assert(result <= utf16le_buf.len); |
| ... | @@ -910,12 +838,7 @@ pub fn symlinkC(target_path: [*]const u8, new_path: [*]const u8) SymLinkError!vo | ... | @@ -910,12 +838,7 @@ pub fn symlinkC(target_path: [*]const u8, new_path: [*]const u8) SymLinkError!vo |
| 910 | const new_path_w = try cStrToPrefixedFileW(new_path); | 838 | const new_path_w = try cStrToPrefixedFileW(new_path); |
| 911 | return symlinkW(&target_path_w, &new_path_w); | 839 | return symlinkW(&target_path_w, &new_path_w); |
| 912 | } | 840 | } |
| 913 | const err = if (builtin.link_libc or @hasDecl(system, "SYS_symlink")) blk: { | 841 | switch (errno(system.symlink(target_path, new_path))) { |
| 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) { | ||
| 919 | 0 => return, | 842 | 0 => return, |
| 920 | EFAULT => unreachable, | 843 | EFAULT => unreachable, |
| 921 | EINVAL => unreachable, | 844 | EINVAL => unreachable, |
| ... | @@ -931,7 +854,7 @@ pub fn symlinkC(target_path: [*]const u8, new_path: [*]const u8) SymLinkError!vo | ... | @@ -931,7 +854,7 @@ pub fn symlinkC(target_path: [*]const u8, new_path: [*]const u8) SymLinkError!vo |
| 931 | ENOMEM => return error.SystemResources, | 854 | ENOMEM => return error.SystemResources, |
| 932 | ENOSPC => return error.NoSpaceLeft, | 855 | ENOSPC => return error.NoSpaceLeft, |
| 933 | EROFS => return error.ReadOnlyFileSystem, | 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,9 +864,8 @@ pub fn symlinkC(target_path: [*]const u8, new_path: [*]const u8) SymLinkError!vo |
| 941 | /// TODO handle when linking libc | 864 | /// TODO handle when linking libc |
| 942 | pub fn symlinkW(target_path_w: [*]const u16, new_path_w: [*]const u16) SymLinkError!void { | 865 | pub fn symlinkW(target_path_w: [*]const u16, new_path_w: [*]const u16) SymLinkError!void { |
| 943 | if (windows.CreateSymbolicLinkW(target_path_w, new_path_w, 0) == 0) { | 866 | if (windows.CreateSymbolicLinkW(target_path_w, new_path_w, 0) == 0) { |
| 944 | const err = windows.GetLastError(); | 867 | switch (windows.GetLastError()) { |
| 945 | switch (err) { | 868 | else => |err| return windows.unexpectedError(err), |
| 946 | else => return unexpectedErrorWindows(err), | ||
| 947 | } | 869 | } |
| 948 | } | 870 | } |
| 949 | } | 871 | } |
| ... | @@ -984,13 +906,12 @@ pub fn unlink(file_path: []const u8) UnlinkError!void { | ... | @@ -984,13 +906,12 @@ pub fn unlink(file_path: []const u8) UnlinkError!void { |
| 984 | /// TODO handle when linking libc | 906 | /// TODO handle when linking libc |
| 985 | pub fn unlinkW(file_path: [*]const u16) UnlinkError!void { | 907 | pub fn unlinkW(file_path: [*]const u16) UnlinkError!void { |
| 986 | if (windows.unlinkW(file_path) == 0) { | 908 | if (windows.unlinkW(file_path) == 0) { |
| 987 | const err = windows.GetLastError(); | 909 | switch (windows.GetLastError()) { |
| 988 | switch (err) { | ||
| 989 | windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound, | 910 | windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound, |
| 990 | windows.ERROR.ACCESS_DENIED => return error.AccessDenied, | 911 | windows.ERROR.ACCESS_DENIED => return error.AccessDenied, |
| 991 | windows.ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong, | 912 | windows.ERROR.FILENAME_EXCED_RANGE => return error.NameTooLong, |
| 992 | windows.ERROR.INVALID_PARAMETER => return error.NameTooLong, | 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,12 +922,7 @@ pub fn unlinkC(file_path: [*]const u8) UnlinkError!void { |
| 1001 | const file_path_w = try cStrToPrefixedFileW(file_path); | 922 | const file_path_w = try cStrToPrefixedFileW(file_path); |
| 1002 | return unlinkW(&file_path_w); | 923 | return unlinkW(&file_path_w); |
| 1003 | } | 924 | } |
| 1004 | const err = if (builtin.link_libc or @hasDecl(system, "SYS_unlink")) blk: { | 925 | switch (errno(system.unlink(file_path))) { |
| 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) { | ||
| 1010 | 0 => return, | 926 | 0 => return, |
| 1011 | EACCES => return error.AccessDenied, | 927 | EACCES => return error.AccessDenied, |
| 1012 | EPERM => return error.AccessDenied, | 928 | EPERM => return error.AccessDenied, |
| ... | @@ -1021,7 +937,7 @@ pub fn unlinkC(file_path: [*]const u8) UnlinkError!void { | ... | @@ -1021,7 +937,7 @@ pub fn unlinkC(file_path: [*]const u8) UnlinkError!void { |
| 1021 | ENOTDIR => return error.NotDir, | 937 | ENOTDIR => return error.NotDir, |
| 1022 | ENOMEM => return error.SystemResources, | 938 | ENOMEM => return error.SystemResources, |
| 1023 | EROFS => return error.ReadOnlyFileSystem, | 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,14 +963,7 @@ pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) RenameError!void { |
| 1047 | const new_path_w = try cStrToPrefixedFileW(new_path); | 963 | const new_path_w = try cStrToPrefixedFileW(new_path); |
| 1048 | return renameW(&old_path_w, &new_path_w); | 964 | return renameW(&old_path_w, &new_path_w); |
| 1049 | } | 965 | } |
| 1050 | const err = if (builtin.link_libc or @hasDecl(system, "SYS_rename")) blk: { | 966 | switch (errno(system.rename(old_path, new_path))) { |
| 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) { | ||
| 1058 | 0 => return, | 967 | 0 => return, |
| 1059 | EACCES => return error.AccessDenied, | 968 | EACCES => return error.AccessDenied, |
| 1060 | EPERM => return error.AccessDenied, | 969 | EPERM => return error.AccessDenied, |
| ... | @@ -1074,7 +983,7 @@ pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) RenameError!void { | ... | @@ -1074,7 +983,7 @@ pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) RenameError!void { |
| 1074 | ENOTEMPTY => return error.PathAlreadyExists, | 983 | ENOTEMPTY => return error.PathAlreadyExists, |
| 1075 | EROFS => return error.ReadOnlyFileSystem, | 984 | EROFS => return error.ReadOnlyFileSystem, |
| 1076 | EXDEV => return error.RenameAcrossMountPoints, | 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,9 +992,8 @@ pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) RenameError!void { |
| 1083 | pub fn renameW(old_path: [*]const u16, new_path: [*]const u16) RenameError!void { | 992 | pub fn renameW(old_path: [*]const u16, new_path: [*]const u16) RenameError!void { |
| 1084 | const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH; | 993 | const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH; |
| 1085 | if (windows.MoveFileExW(old_path, new_path, flags) == 0) { | 994 | if (windows.MoveFileExW(old_path, new_path, flags) == 0) { |
| 1086 | const err = windows.GetLastError(); | 995 | switch (windows.GetLastError()) { |
| 1087 | switch (err) { | 996 | else => |err| return windows.unexpectedError(err), |
| 1088 | else => return unexpectedErrorWindows(err), | ||
| 1089 | } | 997 | } |
| 1090 | } | 998 | } |
| 1091 | } | 999 | } |
| ... | @@ -1110,12 +1018,7 @@ pub fn mkdirC(dir_path: [*]const u8, mode: u32) MakeDirError!void { | ... | @@ -1110,12 +1018,7 @@ pub fn mkdirC(dir_path: [*]const u8, mode: u32) MakeDirError!void { |
| 1110 | const dir_path_w = try cStrToPrefixedFileW(dir_path); | 1018 | const dir_path_w = try cStrToPrefixedFileW(dir_path); |
| 1111 | return mkdirW(&dir_path_w, mode); | 1019 | return mkdirW(&dir_path_w, mode); |
| 1112 | } | 1020 | } |
| 1113 | const err = if (builtin.link_libc or @hasDecl(system, "SYS_mkdir")) blk: { | 1021 | switch (errno(system.mkdir(dir_path, mode))) { |
| 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) { | ||
| 1119 | 0 => return, | 1022 | 0 => return, |
| 1120 | EACCES => return error.AccessDenied, | 1023 | EACCES => return error.AccessDenied, |
| 1121 | EPERM => return error.AccessDenied, | 1024 | EPERM => return error.AccessDenied, |
| ... | @@ -1130,7 +1033,7 @@ pub fn mkdirC(dir_path: [*]const u8, mode: u32) MakeDirError!void { | ... | @@ -1130,7 +1033,7 @@ pub fn mkdirC(dir_path: [*]const u8, mode: u32) MakeDirError!void { |
| 1130 | ENOSPC => return error.NoSpaceLeft, | 1033 | ENOSPC => return error.NoSpaceLeft, |
| 1131 | ENOTDIR => return error.NotDir, | 1034 | ENOTDIR => return error.NotDir, |
| 1132 | EROFS => return error.ReadOnlyFileSystem, | 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,11 +1042,10 @@ pub fn mkdirW(dir_path: []const u8, mode: u32) MakeDirError!void { |
| 1139 | const dir_path_w = try sliceToPrefixedFileW(dir_path); | 1042 | const dir_path_w = try sliceToPrefixedFileW(dir_path); |
| 1140 | 1043 | ||
| 1141 | if (windows.CreateDirectoryW(&dir_path_w, null) == 0) { | 1044 | if (windows.CreateDirectoryW(&dir_path_w, null) == 0) { |
| 1142 | const err = windows.GetLastError(); | 1045 | switch (windows.GetLastError()) { |
| 1143 | switch (err) { | ||
| 1144 | windows.ERROR.ALREADY_EXISTS => return error.PathAlreadyExists, | 1046 | windows.ERROR.ALREADY_EXISTS => return error.PathAlreadyExists, |
| 1145 | windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound, | 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,12 +1082,7 @@ pub fn rmdirC(dir_path: [*]const u8) DeleteDirError!void { |
| 1180 | const dir_path_w = try cStrToPrefixedFileW(dir_path); | 1082 | const dir_path_w = try cStrToPrefixedFileW(dir_path); |
| 1181 | return rmdirW(&dir_path_w); | 1083 | return rmdirW(&dir_path_w); |
| 1182 | } | 1084 | } |
| 1183 | const err = if (builtin.link_libc or @hasDecl(system, "SYS_rmdir")) blk: { | 1085 | switch (errno(system.rmdir(dir_path))) { |
| 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) { | ||
| 1189 | 0 => return, | 1086 | 0 => return, |
| 1190 | EACCES => return error.AccessDenied, | 1087 | EACCES => return error.AccessDenied, |
| 1191 | EPERM => return error.AccessDenied, | 1088 | EPERM => return error.AccessDenied, |
| ... | @@ -1200,7 +1097,7 @@ pub fn rmdirC(dir_path: [*]const u8) DeleteDirError!void { | ... | @@ -1200,7 +1097,7 @@ pub fn rmdirC(dir_path: [*]const u8) DeleteDirError!void { |
| 1200 | EEXIST => return error.DirNotEmpty, | 1097 | EEXIST => return error.DirNotEmpty, |
| 1201 | ENOTEMPTY => return error.DirNotEmpty, | 1098 | ENOTEMPTY => return error.DirNotEmpty, |
| 1202 | EROFS => return error.ReadOnlyFileSystem, | 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,11 +1105,10 @@ pub fn rmdirC(dir_path: [*]const u8) DeleteDirError!void { |
| 1208 | /// TODO handle linking libc | 1105 | /// TODO handle linking libc |
| 1209 | pub fn rmdirW(dir_path_w: [*]const u16) DeleteDirError!void { | 1106 | pub fn rmdirW(dir_path_w: [*]const u16) DeleteDirError!void { |
| 1210 | if (windows.RemoveDirectoryW(dir_path_w) == 0) { | 1107 | if (windows.RemoveDirectoryW(dir_path_w) == 0) { |
| 1211 | const err = windows.GetLastError(); | 1108 | switch (windows.GetLastError()) { |
| 1212 | switch (err) { | ||
| 1213 | windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound, | 1109 | windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound, |
| 1214 | windows.ERROR.DIR_NOT_EMPTY => return error.DirNotEmpty, | 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,11 +1173,7 @@ pub fn readlinkC(file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 { |
| 1277 | const file_path_w = try cStrToPrefixedFileW(file_path); | 1173 | const file_path_w = try cStrToPrefixedFileW(file_path); |
| 1278 | return readlinkW(&file_path_w, out_buffer); | 1174 | return readlinkW(&file_path_w, out_buffer); |
| 1279 | } | 1175 | } |
| 1280 | const rc = if (builtin.link_libc or @hasDecl(system, "SYS_readlink")) blk: { | 1176 | const rc = system.readlink(file_path, out_buffer.ptr, out_buffer.len); |
| 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 | }; | ||
| 1285 | switch (errno(rc)) { | 1177 | switch (errno(rc)) { |
| 1286 | 0 => return out_buffer[0..rc], | 1178 | 0 => return out_buffer[0..rc], |
| 1287 | EACCES => return error.AccessDenied, | 1179 | EACCES => return error.AccessDenied, |
| ... | @@ -1354,7 +1246,7 @@ pub fn GetStdHandle(handle_id: windows.DWORD) GetStdHandleError!fd_t { | ... | @@ -1354,7 +1246,7 @@ pub fn GetStdHandle(handle_id: windows.DWORD) GetStdHandleError!fd_t { |
| 1354 | const handle = windows.GetStdHandle(handle_id) orelse return error.NoStandardHandleAttached; | 1246 | const handle = windows.GetStdHandle(handle_id) orelse return error.NoStandardHandleAttached; |
| 1355 | if (handle == windows.INVALID_HANDLE_VALUE) { | 1247 | if (handle == windows.INVALID_HANDLE_VALUE) { |
| 1356 | switch (windows.GetLastError()) { | 1248 | switch (windows.GetLastError()) { |
| 1357 | else => |err| unexpectedErrorWindows(err), | 1249 | else => |err| windows.unexpectedError(err), |
| 1358 | } | 1250 | } |
| 1359 | } | 1251 | } |
| 1360 | return handle; | 1252 | return handle; |
| ... | @@ -2070,17 +1962,12 @@ pub const ForkError = error{ | ... | @@ -2070,17 +1962,12 @@ pub const ForkError = error{ |
| 2070 | }; | 1962 | }; |
| 2071 | 1963 | ||
| 2072 | pub fn fork() ForkError!pid_t { | 1964 | pub fn fork() ForkError!pid_t { |
| 2073 | if (builtin.link_libc) { | 1965 | const rc = system.fork(); |
| 2074 | return system.fork(); | 1966 | switch (errno(rc)) { |
| 2075 | } | 1967 | 0 => return rc, |
| 2076 | if (linux.is_the_target) { | 1968 | EAGAIN => return error.SystemResources, |
| 2077 | const rc = if (@hasDecl(system, "SYS_fork")) system.fork() else system.clone2(SIGCHLD, 0); | 1969 | ENOMEM => return error.SystemResources, |
| 2078 | switch (errno(rc)) { | 1970 | else => |err| return unexpectedErrno(err), |
| 2079 | 0 => return rc, | ||
| 2080 | EAGAIN => return error.SystemResources, | ||
| 2081 | ENOMEM => return error.SystemResources, | ||
| 2082 | else => |err| return unexpectedErrno(err), | ||
| 2083 | } | ||
| 2084 | } | 1971 | } |
| 2085 | } | 1972 | } |
| 2086 | 1973 | ||
| ... | @@ -2173,7 +2060,7 @@ pub fn accessW(path: [*]const u16, mode: u32) AccessError!void { | ... | @@ -2173,7 +2060,7 @@ pub fn accessW(path: [*]const u16, mode: u32) AccessError!void { |
| 2173 | windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound, | 2060 | windows.ERROR.FILE_NOT_FOUND => return error.FileNotFound, |
| 2174 | windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound, | 2061 | windows.ERROR.PATH_NOT_FOUND => return error.FileNotFound, |
| 2175 | windows.ERROR.ACCESS_DENIED => return error.PermissionDenied, | 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,11 +2096,7 @@ pub const PipeError = error{ |
| 2209 | 2096 | ||
| 2210 | /// Creates a unidirectional data channel that can be used for interprocess communication. | 2097 | /// Creates a unidirectional data channel that can be used for interprocess communication. |
| 2211 | pub fn pipe(fds: *[2]fd_t) PipeError!void { | 2098 | pub fn pipe(fds: *[2]fd_t) PipeError!void { |
| 2212 | const rc = if (builtin.link_libc or @hasDecl(system, SYS_pipe)) | 2099 | switch (errno(system.pipe(fds))) { |
| 2213 | system.pipe(fds) | ||
| 2214 | else | ||
| 2215 | system.pipe2(fds, 0); | ||
| 2216 | switch (errno(rc)) { | ||
| 2217 | 0 => return, | 2100 | 0 => return, |
| 2218 | EINVAL => unreachable, // Invalid parameters to pipe() | 2101 | EINVAL => unreachable, // Invalid parameters to pipe() |
| 2219 | EFAULT => unreachable, // Invalid fds pointer | 2102 | EFAULT => unreachable, // Invalid fds pointer |
| ... | @@ -2296,6 +2179,112 @@ pub const realpath = std.os.path.real; | ... | @@ -2296,6 +2179,112 @@ pub const realpath = std.os.path.real; |
| 2296 | pub const realpathC = std.os.path.realC; | 2179 | pub const realpathC = std.os.path.realC; |
| 2297 | pub const realpathW = std.os.path.realW; | 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 | /// Used to convert a slice to a null terminated slice on the stack. | 2288 | /// Used to convert a slice to a null terminated slice on the stack. |
| 2300 | /// TODO https://github.com/ziglang/zig/issues/287 | 2289 | /// TODO https://github.com/ziglang/zig/issues/287 |
| 2301 | pub fn toPosixPath(file_path: []const u8) ![PATH_MAX]u8 { | 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,64 +2296,12 @@ pub fn toPosixPath(file_path: []const u8) ![PATH_MAX]u8 { |
| 2307 | return path_with_null; | 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 | /// Call this when you made a syscall or something that sets errno | 2299 | /// Call this when you made a syscall or something that sets errno |
| 2317 | /// and you get an unexpected error. | 2300 | /// and you get an unexpected error. |
| 2318 | pub fn unexpectedErrno(errno: usize) UnexpectedError { | 2301 | pub fn unexpectedErrno(errno: usize) os.UnexpectedError { |
| 2319 | if (unexpected_error_tracing) { | 2302 | if (os.unexpected_error_tracing) { |
| 2320 | std.debug.warn("unexpected errno: {}\n", errno); | 2303 | std.debug.warn("unexpected errno: {}\n", errno); |
| 2321 | std.debug.dumpCurrentStackTrace(null); | 2304 | std.debug.dumpCurrentStackTrace(null); |
| 2322 | } | 2305 | } |
| 2323 | return error.Unexpected; | 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,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 | const std = @import("../std.zig"); | 3 | const std = @import("../std.zig"); |
| 2 | const assert = std.debug.assert; | 4 | const assert = std.debug.assert; |
| 3 | const maxInt = std.math.maxInt; | 5 | const maxInt = std.math.maxInt; |
| 4 | 6 | ||
| 5 | pub const is_the_target = switch (builtin.os) { | 7 | pub const is_the_target = builtin.os == .windows; |
| 6 | .windows => true, | 8 | pub const posix = if (builtin.link_libc) struct {} else @import("windows/posix.zig"); |
| 7 | else => false, | ||
| 8 | }; | ||
| 9 | pub const posix = @import("windows/posix.zig"); | ||
| 10 | pub use posix; | 9 | pub use posix; |
| 11 | 10 | ||
| 12 | pub use @import("windows/advapi32.zig"); | 11 | pub const advapi32 = @import("windows/advapi32.zig"); |
| 13 | pub use @import("windows/kernel32.zig"); | 12 | pub const kernel32 = @import("windows/kernel32.zig"); |
| 14 | pub use @import("windows/ntdll.zig"); | 13 | pub const ntdll = @import("windows/ntdll.zig"); |
| 15 | pub use @import("windows/ole32.zig"); | 14 | pub const ole32 = @import("windows/ole32.zig"); |
| 16 | pub use @import("windows/shell32.zig"); | 15 | pub const shell32 = @import("windows/shell32.zig"); |
| 17 | |||
| 18 | test "import" { | ||
| 19 | if (is_the_target) { | ||
| 20 | _ = @import("windows/util.zig"); | ||
| 21 | } | ||
| 22 | } | ||
| 23 | 16 | ||
| 24 | pub const ERROR = @import("windows/error.zig"); | 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 | pub const SHORT = c_short; | 28 | pub const SHORT = c_short; |
| 27 | pub const BOOL = c_int; | 29 | pub const BOOL = c_int; |
| 28 | pub const BOOLEAN = BYTE; | 30 | pub const BOOLEAN = BYTE; |
| ... | @@ -428,3 +430,233 @@ pub const IMAGE_TLS_DIRECTORY64 = IMAGE_TLS_DIRECTORY; | ... | @@ -428,3 +430,233 @@ pub const IMAGE_TLS_DIRECTORY64 = IMAGE_TLS_DIRECTORY; |
| 428 | pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY; | 430 | pub const IMAGE_TLS_DIRECTORY32 = IMAGE_TLS_DIRECTORY; |
| 429 | 431 | ||
| 430 | pub const PIMAGE_TLS_CALLBACK = ?extern fn (PVOID, DWORD, PVOID) void; | 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,16 +1,5 @@ |
| 1 | use @import("../windows.zig"); | 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 | pub extern "advapi32" stdcallcc fn RegOpenKeyExW( | 3 | pub extern "advapi32" stdcallcc fn RegOpenKeyExW( |
| 15 | hKey: HKEY, | 4 | hKey: HKEY, |
| 16 | lpSubKey: LPCWSTR, | 5 | lpSubKey: LPCWSTR, |
std/os/windows/kernel32.zig-77| ... | @@ -189,86 +189,9 @@ pub extern "kernel32" stdcallcc fn GetProcAddress(hModule: HMODULE, lpProcName: | ... | @@ -189,86 +189,9 @@ pub extern "kernel32" stdcallcc fn GetProcAddress(hModule: HMODULE, lpProcName: |
| 189 | 189 | ||
| 190 | pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) BOOL; | 190 | pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) BOOL; |
| 191 | 191 | ||
| 192 | pub const FILE_NOTIFY_INFORMATION = extern struct { | ||
| 193 | NextEntryOffset: DWORD, | ||
| 194 | Action: DWORD, | ||
| 195 | FileNameLength: DWORD, | ||
| 196 | FileName: [1]WCHAR, | ||
| 197 | }; | ||
| 198 | |||
| 199 | pub const FILE_ACTION_ADDED = 0x00000001; | ||
| 200 | pub const FILE_ACTION_REMOVED = 0x00000002; | ||
| 201 | pub const FILE_ACTION_MODIFIED = 0x00000003; | ||
| 202 | pub const FILE_ACTION_RENAMED_OLD_NAME = 0x00000004; | ||
| 203 | pub const FILE_ACTION_RENAMED_NEW_NAME = 0x00000005; | ||
| 204 | |||
| 205 | pub const LPOVERLAPPED_COMPLETION_ROUTINE = ?extern fn (DWORD, DWORD, *OVERLAPPED) void; | ||
| 206 | |||
| 207 | pub const FILE_LIST_DIRECTORY = 1; | ||
| 208 | |||
| 209 | pub const FILE_NOTIFY_CHANGE_CREATION = 64; | ||
| 210 | pub const FILE_NOTIFY_CHANGE_SIZE = 8; | ||
| 211 | pub const FILE_NOTIFY_CHANGE_SECURITY = 256; | ||
| 212 | pub const FILE_NOTIFY_CHANGE_LAST_ACCESS = 32; | ||
| 213 | pub const FILE_NOTIFY_CHANGE_LAST_WRITE = 16; | ||
| 214 | pub const FILE_NOTIFY_CHANGE_DIR_NAME = 2; | ||
| 215 | pub const FILE_NOTIFY_CHANGE_FILE_NAME = 1; | ||
| 216 | pub const FILE_NOTIFY_CHANGE_ATTRIBUTES = 4; | ||
| 217 | |||
| 218 | pub const CONSOLE_SCREEN_BUFFER_INFO = extern struct { | ||
| 219 | dwSize: COORD, | ||
| 220 | dwCursorPosition: COORD, | ||
| 221 | wAttributes: WORD, | ||
| 222 | srWindow: SMALL_RECT, | ||
| 223 | dwMaximumWindowSize: COORD, | ||
| 224 | }; | ||
| 225 | |||
| 226 | pub const FOREGROUND_BLUE = 1; | ||
| 227 | pub const FOREGROUND_GREEN = 2; | ||
| 228 | pub const FOREGROUND_RED = 4; | ||
| 229 | pub const FOREGROUND_INTENSITY = 8; | ||
| 230 | |||
| 231 | pub extern "kernel32" stdcallcc fn InitializeCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; | 192 | pub extern "kernel32" stdcallcc fn InitializeCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; |
| 232 | pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; | 193 | pub extern "kernel32" stdcallcc fn EnterCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; |
| 233 | pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; | 194 | pub extern "kernel32" stdcallcc fn LeaveCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; |
| 234 | pub extern "kernel32" stdcallcc fn DeleteCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; | 195 | pub extern "kernel32" stdcallcc fn DeleteCriticalSection(lpCriticalSection: *CRITICAL_SECTION) void; |
| 235 | 196 | ||
| 236 | pub const LIST_ENTRY = extern struct { | ||
| 237 | Flink: *LIST_ENTRY, | ||
| 238 | Blink: *LIST_ENTRY, | ||
| 239 | }; | ||
| 240 | |||
| 241 | pub const RTL_CRITICAL_SECTION_DEBUG = extern struct { | ||
| 242 | Type: WORD, | ||
| 243 | CreatorBackTraceIndex: WORD, | ||
| 244 | CriticalSection: *RTL_CRITICAL_SECTION, | ||
| 245 | ProcessLocksList: LIST_ENTRY, | ||
| 246 | EntryCount: DWORD, | ||
| 247 | ContentionCount: DWORD, | ||
| 248 | Flags: DWORD, | ||
| 249 | CreatorBackTraceIndexHigh: WORD, | ||
| 250 | SpareWORD: WORD, | ||
| 251 | }; | ||
| 252 | |||
| 253 | pub const RTL_CRITICAL_SECTION = extern struct { | ||
| 254 | DebugInfo: *RTL_CRITICAL_SECTION_DEBUG, | ||
| 255 | LockCount: LONG, | ||
| 256 | RecursionCount: LONG, | ||
| 257 | OwningThread: HANDLE, | ||
| 258 | LockSemaphore: HANDLE, | ||
| 259 | SpinCount: ULONG_PTR, | ||
| 260 | }; | ||
| 261 | |||
| 262 | pub const CRITICAL_SECTION = RTL_CRITICAL_SECTION; | ||
| 263 | pub const INIT_ONCE = RTL_RUN_ONCE; | ||
| 264 | pub const INIT_ONCE_STATIC_INIT = RTL_RUN_ONCE_INIT; | ||
| 265 | |||
| 266 | pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter: ?*c_void, Context: ?*c_void) BOOL; | 197 | pub extern "kernel32" stdcallcc fn InitOnceExecuteOnce(InitOnce: *INIT_ONCE, InitFn: INIT_ONCE_FN, Parameter: ?*c_void, Context: ?*c_void) BOOL; |
| 267 | |||
| 268 | pub const INIT_ONCE_FN = extern fn (InitOnce: *INIT_ONCE, Parameter: ?*c_void, Context: ?*c_void) BOOL; | ||
| 269 | |||
| 270 | pub const RTL_RUN_ONCE = extern struct { | ||
| 271 | Ptr: ?*c_void, | ||
| 272 | }; | ||
| 273 | |||
| 274 | pub const RTL_RUN_ONCE_INIT = RTL_RUN_ONCE{ .Ptr = null }; |
std/os/windows/ole32.zig-11| ... | @@ -4,14 +4,3 @@ pub extern "ole32" stdcallcc fn CoTaskMemFree(pv: LPVOID) void; | ... | @@ -4,14 +4,3 @@ pub extern "ole32" stdcallcc fn CoTaskMemFree(pv: LPVOID) void; |
| 4 | pub extern "ole32" stdcallcc fn CoUninitialize() void; | 4 | pub extern "ole32" stdcallcc fn CoUninitialize() void; |
| 5 | pub extern "ole32" stdcallcc fn CoGetCurrentProcess() DWORD; | 5 | pub extern "ole32" stdcallcc fn CoGetCurrentProcess() DWORD; |
| 6 | pub extern "ole32" stdcallcc fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) HRESULT; | 6 | pub extern "ole32" stdcallcc fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) HRESULT; |
| 7 | |||
| 8 | pub const COINIT_APARTMENTTHREADED = COINIT.COINIT_APARTMENTTHREADED; | ||
| 9 | pub const COINIT_MULTITHREADED = COINIT.COINIT_MULTITHREADED; | ||
| 10 | pub const COINIT_DISABLE_OLE1DDE = COINIT.COINIT_DISABLE_OLE1DDE; | ||
| 11 | pub const COINIT_SPEED_OVER_MEMORY = COINIT.COINIT_SPEED_OVER_MEMORY; | ||
| 12 | pub const COINIT = extern enum { | ||
| 13 | COINIT_APARTMENTTHREADED = 2, | ||
| 14 | COINIT_MULTITHREADED = 0, | ||
| 15 | COINIT_DISABLE_OLE1DDE = 4, | ||
| 16 | COINIT_SPEED_OVER_MEMORY = 8, | ||
| 17 | }; |
std/os/windows/posix.zig+4-13| ... | @@ -1,15 +1,6 @@ | ... | @@ -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 | const std = @import("../../std.zig"); | 3 | const std = @import("../../std.zig"); |
| 3 | const maxInt = std.math.maxInt; | 4 | const builtin = @import("builtin"); |
| 4 | use std.os.windows; | ||
| 5 | 5 | ||
| 6 | pub const fd_t = HANDLE; | 6 | pub const fd_t = std.os.windows.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; |
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 | } | ||