| author | |
| committer | |
| log | f160d5f979c9f2bcc98ef0169a879a76d0234ed2 |
| tree | 0d0ffdb2d1399ed0001c792d81d11491743bab58 |
| parent | feeed922e1a7d89b99572d5577c814f9e6293b9b |
3 files changed, 92 insertions(+), 167 deletions(-)
lib/std/Io/Threaded.zig+88-2| ... | @@ -7420,7 +7420,18 @@ fn fileWritePositional( | ... | @@ -7420,7 +7420,18 @@ fn fileWritePositional( |
| 7420 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 7420 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 7421 | const current_thread = Thread.getCurrent(t); | 7421 | const current_thread = Thread.getCurrent(t); |
| 7422 | 7422 | ||
| 7423 | if (is_windows) @panic("TODO implement fileWritePositional windows"); | 7423 | if (is_windows) { |
| 7424 | if (header.len != 0) { | ||
| 7425 | return writeFilePositionalWindows(current_thread, file.handle, header, offset); | ||
| 7426 | } | ||
| 7427 | for (data[0 .. data.len - 1]) |buf| { | ||
| 7428 | if (buf.len == 0) continue; | ||
| 7429 | return writeFilePositionalWindows(current_thread, file.handle, buf, offset); | ||
| 7430 | } | ||
| 7431 | const pattern = data[data.len - 1]; | ||
| 7432 | if (pattern.len == 0 or splat == 0) return 0; | ||
| 7433 | return writeFilePositionalWindows(current_thread, file.handle, pattern, offset); | ||
| 7434 | } | ||
| 7424 | 7435 | ||
| 7425 | var iovecs: [max_iovecs_len]posix.iovec_const = undefined; | 7436 | var iovecs: [max_iovecs_len]posix.iovec_const = undefined; |
| 7426 | var iovlen: iovlen_t = 0; | 7437 | var iovlen: iovlen_t = 0; |
| ... | @@ -7532,6 +7543,44 @@ fn fileWritePositional( | ... | @@ -7532,6 +7543,44 @@ fn fileWritePositional( |
| 7532 | } | 7543 | } |
| 7533 | } | 7544 | } |
| 7534 | 7545 | ||
| 7546 | fn writeFilePositionalWindows( | ||
| 7547 | current_thread: *Thread, | ||
| 7548 | handle: windows.HANDLE, | ||
| 7549 | bytes: []const u8, | ||
| 7550 | offset: u64, | ||
| 7551 | ) File.WritePositionalError!usize { | ||
| 7552 | try current_thread.checkCancel(); | ||
| 7553 | |||
| 7554 | var bytes_written: windows.DWORD = undefined; | ||
| 7555 | var overlapped: windows.OVERLAPPED = .{ | ||
| 7556 | .Internal = 0, | ||
| 7557 | .InternalHigh = 0, | ||
| 7558 | .DUMMYUNIONNAME = .{ | ||
| 7559 | .DUMMYSTRUCTNAME = .{ | ||
| 7560 | .Offset = @truncate(offset), | ||
| 7561 | .OffsetHigh = @truncate(offset >> 32), | ||
| 7562 | }, | ||
| 7563 | }, | ||
| 7564 | .hEvent = null, | ||
| 7565 | }; | ||
| 7566 | const adjusted_len = std.math.lossyCast(u32, bytes.len); | ||
| 7567 | if (windows.kernel32.WriteFile(handle, bytes.ptr, adjusted_len, &bytes_written, &overlapped) == 0) { | ||
| 7568 | switch (windows.GetLastError()) { | ||
| 7569 | .INVALID_USER_BUFFER => return error.SystemResources, | ||
| 7570 | .NOT_ENOUGH_MEMORY => return error.SystemResources, | ||
| 7571 | .OPERATION_ABORTED => return error.Canceled, | ||
| 7572 | .NOT_ENOUGH_QUOTA => return error.SystemResources, | ||
| 7573 | .NO_DATA => return error.BrokenPipe, | ||
| 7574 | .INVALID_HANDLE => return error.NotOpenForWriting, | ||
| 7575 | .LOCK_VIOLATION => return error.LockViolation, | ||
| 7576 | .ACCESS_DENIED => return error.AccessDenied, | ||
| 7577 | .WORKING_SET_QUOTA => return error.SystemResources, | ||
| 7578 | else => |err| return windows.unexpectedError(err), | ||
| 7579 | } | ||
| 7580 | } | ||
| 7581 | return bytes_written; | ||
| 7582 | } | ||
| 7583 | |||
| 7535 | fn fileWriteStreaming( | 7584 | fn fileWriteStreaming( |
| 7536 | userdata: ?*anyopaque, | 7585 | userdata: ?*anyopaque, |
| 7537 | file: File, | 7586 | file: File, |
| ... | @@ -7542,7 +7591,18 @@ fn fileWriteStreaming( | ... | @@ -7542,7 +7591,18 @@ fn fileWriteStreaming( |
| 7542 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | 7591 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 7543 | const current_thread = Thread.getCurrent(t); | 7592 | const current_thread = Thread.getCurrent(t); |
| 7544 | 7593 | ||
| 7545 | if (is_windows) @panic("TODO implement fileWriteStreaming windows"); | 7594 | if (is_windows) { |
| 7595 | if (header.len != 0) { | ||
| 7596 | return writeFileStreamingWindows(current_thread, file.handle, header); | ||
| 7597 | } | ||
| 7598 | for (data[0 .. data.len - 1]) |buf| { | ||
| 7599 | if (buf.len == 0) continue; | ||
| 7600 | return writeFileStreamingWindows(current_thread, file.handle, buf); | ||
| 7601 | } | ||
| 7602 | const pattern = data[data.len - 1]; | ||
| 7603 | if (pattern.len == 0 or splat == 0) return 0; | ||
| 7604 | return writeFileStreamingWindows(current_thread, file.handle, pattern); | ||
| 7605 | } | ||
| 7546 | 7606 | ||
| 7547 | var iovecs: [max_iovecs_len]posix.iovec_const = undefined; | 7607 | var iovecs: [max_iovecs_len]posix.iovec_const = undefined; |
| 7548 | var iovlen: iovlen_t = 0; | 7608 | var iovlen: iovlen_t = 0; |
| ... | @@ -7647,6 +7707,32 @@ fn fileWriteStreaming( | ... | @@ -7647,6 +7707,32 @@ fn fileWriteStreaming( |
| 7647 | } | 7707 | } |
| 7648 | } | 7708 | } |
| 7649 | 7709 | ||
| 7710 | fn writeFileStreamingWindows( | ||
| 7711 | current_thread: *Thread, | ||
| 7712 | handle: windows.HANDLE, | ||
| 7713 | bytes: []const u8, | ||
| 7714 | ) File.Writer.Error!usize { | ||
| 7715 | try current_thread.checkCancel(); | ||
| 7716 | |||
| 7717 | var bytes_written: windows.DWORD = undefined; | ||
| 7718 | const adjusted_len = std.math.lossyCast(u32, bytes.len); | ||
| 7719 | if (windows.kernel32.WriteFile(handle, bytes.ptr, adjusted_len, &bytes_written, null) == 0) { | ||
| 7720 | switch (windows.GetLastError()) { | ||
| 7721 | .INVALID_USER_BUFFER => return error.SystemResources, | ||
| 7722 | .NOT_ENOUGH_MEMORY => return error.SystemResources, | ||
| 7723 | .OPERATION_ABORTED => return error.Canceled, | ||
| 7724 | .NOT_ENOUGH_QUOTA => return error.SystemResources, | ||
| 7725 | .NO_DATA => return error.BrokenPipe, | ||
| 7726 | .INVALID_HANDLE => return error.NotOpenForWriting, | ||
| 7727 | .LOCK_VIOLATION => return error.LockViolation, | ||
| 7728 | .ACCESS_DENIED => return error.AccessDenied, | ||
| 7729 | .WORKING_SET_QUOTA => return error.SystemResources, | ||
| 7730 | else => |err| return windows.unexpectedError(err), | ||
| 7731 | } | ||
| 7732 | } | ||
| 7733 | return bytes_written; | ||
| 7734 | } | ||
| 7735 | |||
| 7650 | fn fileWriteFileStreaming( | 7736 | fn fileWriteFileStreaming( |
| 7651 | userdata: ?*anyopaque, | 7737 | userdata: ?*anyopaque, |
| 7652 | file: File, | 7738 | file: File, |
lib/std/os/windows.zig-109| ... | @@ -2830,115 +2830,6 @@ pub fn CloseHandle(hObject: HANDLE) void { | ... | @@ -2830,115 +2830,6 @@ pub fn CloseHandle(hObject: HANDLE) void { |
| 2830 | assert(ntdll.NtClose(hObject) == .SUCCESS); | 2830 | assert(ntdll.NtClose(hObject) == .SUCCESS); |
| 2831 | } | 2831 | } |
| 2832 | 2832 | ||
| 2833 | pub const ReadFileError = error{ | ||
| 2834 | BrokenPipe, | ||
| 2835 | /// The specified network name is no longer available. | ||
| 2836 | ConnectionResetByPeer, | ||
| 2837 | Canceled, | ||
| 2838 | /// Unable to read file due to lock. | ||
| 2839 | LockViolation, | ||
| 2840 | /// Known to be possible when: | ||
| 2841 | /// - Unable to read from disconnected virtual com port (Windows) | ||
| 2842 | AccessDenied, | ||
| 2843 | NotOpenForReading, | ||
| 2844 | Unexpected, | ||
| 2845 | }; | ||
| 2846 | |||
| 2847 | /// If buffer's length exceeds what a Windows DWORD integer can hold, it will be broken into | ||
| 2848 | /// multiple non-atomic reads. | ||
| 2849 | pub fn ReadFile(in_hFile: HANDLE, buffer: []u8, offset: ?u64) ReadFileError!usize { | ||
| 2850 | while (true) { | ||
| 2851 | const want_read_count: DWORD = @min(@as(DWORD, maxInt(DWORD)), buffer.len); | ||
| 2852 | var amt_read: DWORD = undefined; | ||
| 2853 | var overlapped_data: OVERLAPPED = undefined; | ||
| 2854 | const overlapped: ?*OVERLAPPED = if (offset) |off| blk: { | ||
| 2855 | overlapped_data = .{ | ||
| 2856 | .Internal = 0, | ||
| 2857 | .InternalHigh = 0, | ||
| 2858 | .DUMMYUNIONNAME = .{ | ||
| 2859 | .DUMMYSTRUCTNAME = .{ | ||
| 2860 | .Offset = @as(u32, @truncate(off)), | ||
| 2861 | .OffsetHigh = @as(u32, @truncate(off >> 32)), | ||
| 2862 | }, | ||
| 2863 | }, | ||
| 2864 | .hEvent = null, | ||
| 2865 | }; | ||
| 2866 | break :blk &overlapped_data; | ||
| 2867 | } else null; | ||
| 2868 | if (kernel32.ReadFile(in_hFile, buffer.ptr, want_read_count, &amt_read, overlapped) == 0) { | ||
| 2869 | switch (GetLastError()) { | ||
| 2870 | .IO_PENDING => unreachable, | ||
| 2871 | .OPERATION_ABORTED => continue, | ||
| 2872 | .BROKEN_PIPE => return 0, | ||
| 2873 | .HANDLE_EOF => return 0, | ||
| 2874 | .NETNAME_DELETED => return error.ConnectionResetByPeer, | ||
| 2875 | .LOCK_VIOLATION => return error.LockViolation, | ||
| 2876 | .ACCESS_DENIED => return error.AccessDenied, | ||
| 2877 | .INVALID_HANDLE => return error.NotOpenForReading, | ||
| 2878 | else => |err| return unexpectedError(err), | ||
| 2879 | } | ||
| 2880 | } | ||
| 2881 | return amt_read; | ||
| 2882 | } | ||
| 2883 | } | ||
| 2884 | |||
| 2885 | pub const WriteFileError = error{ | ||
| 2886 | SystemResources, | ||
| 2887 | Canceled, | ||
| 2888 | BrokenPipe, | ||
| 2889 | NotOpenForWriting, | ||
| 2890 | /// The process cannot access the file because another process has locked | ||
| 2891 | /// a portion of the file. | ||
| 2892 | LockViolation, | ||
| 2893 | /// The specified network name is no longer available. | ||
| 2894 | ConnectionResetByPeer, | ||
| 2895 | /// Known to be possible when: | ||
| 2896 | /// - Unable to write to disconnected virtual com port (Windows) | ||
| 2897 | AccessDenied, | ||
| 2898 | Unexpected, | ||
| 2899 | }; | ||
| 2900 | |||
| 2901 | pub fn WriteFile( | ||
| 2902 | handle: HANDLE, | ||
| 2903 | bytes: []const u8, | ||
| 2904 | offset: ?u64, | ||
| 2905 | ) WriteFileError!usize { | ||
| 2906 | var bytes_written: DWORD = undefined; | ||
| 2907 | var overlapped_data: OVERLAPPED = undefined; | ||
| 2908 | const overlapped: ?*OVERLAPPED = if (offset) |off| blk: { | ||
| 2909 | overlapped_data = .{ | ||
| 2910 | .Internal = 0, | ||
| 2911 | .InternalHigh = 0, | ||
| 2912 | .DUMMYUNIONNAME = .{ | ||
| 2913 | .DUMMYSTRUCTNAME = .{ | ||
| 2914 | .Offset = @truncate(off), | ||
| 2915 | .OffsetHigh = @truncate(off >> 32), | ||
| 2916 | }, | ||
| 2917 | }, | ||
| 2918 | .hEvent = null, | ||
| 2919 | }; | ||
| 2920 | break :blk &overlapped_data; | ||
| 2921 | } else null; | ||
| 2922 | const adjusted_len = math.cast(u32, bytes.len) orelse maxInt(u32); | ||
| 2923 | if (kernel32.WriteFile(handle, bytes.ptr, adjusted_len, &bytes_written, overlapped) == 0) { | ||
| 2924 | switch (GetLastError()) { | ||
| 2925 | .INVALID_USER_BUFFER => return error.SystemResources, | ||
| 2926 | .NOT_ENOUGH_MEMORY => return error.SystemResources, | ||
| 2927 | .OPERATION_ABORTED => return error.Canceled, | ||
| 2928 | .NOT_ENOUGH_QUOTA => return error.SystemResources, | ||
| 2929 | .IO_PENDING => unreachable, | ||
| 2930 | .NO_DATA => return error.BrokenPipe, | ||
| 2931 | .INVALID_HANDLE => return error.NotOpenForWriting, | ||
| 2932 | .LOCK_VIOLATION => return error.LockViolation, | ||
| 2933 | .NETNAME_DELETED => return error.ConnectionResetByPeer, | ||
| 2934 | .ACCESS_DENIED => return error.AccessDenied, | ||
| 2935 | .WORKING_SET_QUOTA => return error.SystemResources, | ||
| 2936 | else => |err| return unexpectedError(err), | ||
| 2937 | } | ||
| 2938 | } | ||
| 2939 | return bytes_written; | ||
| 2940 | } | ||
| 2941 | |||
| 2942 | pub const GetCurrentDirectoryError = error{ | 2833 | pub const GetCurrentDirectoryError = error{ |
| 2943 | NameTooLong, | 2834 | NameTooLong, |
| 2944 | Unexpected, | 2835 | Unexpected, |
lib/std/posix.zig+4-56| ... | @@ -486,34 +486,8 @@ pub const ReadError = std.Io.File.Reader.Error; | ... | @@ -486,34 +486,8 @@ pub const ReadError = std.Io.File.Reader.Error; |
| 486 | /// The corresponding POSIX limit is `maxInt(isize)`. | 486 | /// The corresponding POSIX limit is `maxInt(isize)`. |
| 487 | pub fn read(fd: fd_t, buf: []u8) ReadError!usize { | 487 | pub fn read(fd: fd_t, buf: []u8) ReadError!usize { |
| 488 | if (buf.len == 0) return 0; | 488 | if (buf.len == 0) return 0; |
| 489 | if (native_os == .windows) { | 489 | if (native_os == .windows) @compileError("unsupported OS"); |
| 490 | return windows.ReadFile(fd, buf, null); | 490 | if (native_os == .wasi) @compileError("unsupported OS"); |
| 491 | } | ||
| 492 | if (native_os == .wasi and !builtin.link_libc) { | ||
| 493 | const iovs = [1]iovec{iovec{ | ||
| 494 | .base = buf.ptr, | ||
| 495 | .len = buf.len, | ||
| 496 | }}; | ||
| 497 | |||
| 498 | var nread: usize = undefined; | ||
| 499 | switch (wasi.fd_read(fd, &iovs, iovs.len, &nread)) { | ||
| 500 | .SUCCESS => return nread, | ||
| 501 | .INTR => unreachable, | ||
| 502 | .INVAL => unreachable, | ||
| 503 | .FAULT => unreachable, | ||
| 504 | .AGAIN => unreachable, | ||
| 505 | .BADF => return error.NotOpenForReading, // Can be a race condition. | ||
| 506 | .IO => return error.InputOutput, | ||
| 507 | .ISDIR => return error.IsDir, | ||
| 508 | .NOBUFS => return error.SystemResources, | ||
| 509 | .NOMEM => return error.SystemResources, | ||
| 510 | .NOTCONN => return error.SocketUnconnected, | ||
| 511 | .CONNRESET => return error.ConnectionResetByPeer, | ||
| 512 | .TIMEDOUT => return error.Timeout, | ||
| 513 | .NOTCAPABLE => return error.AccessDenied, | ||
| 514 | else => |err| return unexpectedErrno(err), | ||
| 515 | } | ||
| 516 | } | ||
| 517 | 491 | ||
| 518 | // Prevents EINVAL. | 492 | // Prevents EINVAL. |
| 519 | const max_count = switch (native_os) { | 493 | const max_count = switch (native_os) { |
| ... | @@ -606,34 +580,8 @@ pub const WriteError = error{ | ... | @@ -606,34 +580,8 @@ pub const WriteError = error{ |
| 606 | /// The corresponding POSIX limit is `maxInt(isize)`. | 580 | /// The corresponding POSIX limit is `maxInt(isize)`. |
| 607 | pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize { | 581 | pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize { |
| 608 | if (bytes.len == 0) return 0; | 582 | if (bytes.len == 0) return 0; |
| 609 | if (native_os == .windows) { | 583 | if (native_os == .windows) @compileError("unsupported OS"); |
| 610 | return windows.WriteFile(fd, bytes, null); | 584 | if (native_os == .wasi) @compileError("unsupported OS"); |
| 611 | } | ||
| 612 | |||
| 613 | if (native_os == .wasi and !builtin.link_libc) { | ||
| 614 | const ciovs = [_]iovec_const{iovec_const{ | ||
| 615 | .base = bytes.ptr, | ||
| 616 | .len = bytes.len, | ||
| 617 | }}; | ||
| 618 | var nwritten: usize = undefined; | ||
| 619 | switch (wasi.fd_write(fd, &ciovs, ciovs.len, &nwritten)) { | ||
| 620 | .SUCCESS => return nwritten, | ||
| 621 | .INTR => unreachable, | ||
| 622 | .INVAL => unreachable, | ||
| 623 | .FAULT => unreachable, | ||
| 624 | .AGAIN => unreachable, | ||
| 625 | .BADF => return error.NotOpenForWriting, // can be a race condition. | ||
| 626 | .DESTADDRREQ => unreachable, // `connect` was never called. | ||
| 627 | .DQUOT => return error.DiskQuota, | ||
| 628 | .FBIG => return error.FileTooBig, | ||
| 629 | .IO => return error.InputOutput, | ||
| 630 | .NOSPC => return error.NoSpaceLeft, | ||
| 631 | .PERM => return error.PermissionDenied, | ||
| 632 | .PIPE => return error.BrokenPipe, | ||
| 633 | .NOTCAPABLE => return error.AccessDenied, | ||
| 634 | else => |err| return unexpectedErrno(err), | ||
| 635 | } | ||
| 636 | } | ||
| 637 | 585 | ||
| 638 | const max_count = switch (native_os) { | 586 | const max_count = switch (native_os) { |
| 639 | .linux => 0x7ffff000, | 587 | .linux => 0x7ffff000, |