| author | |
| committer | |
| log | f612d5ae96c9f327e9cb5e53d8e47db7ba206418 |
| tree | 6431826dcf2a83d44ee6059de783ca926f39b983 |
| parent | 46b5eb6ec3fed3c97512c05c13aa6f3dd9b71b87 |
and make reading file streaming allowed to return 0 byte reads.
According to Microsoft documentation, on Windows it is possible to get
0-byte reads from pipes when 0-byte writes are made.6 files changed, 62 insertions(+), 75 deletions(-)
lib/std/Io.zig+4-7| ... | ... | @@ -264,10 +264,7 @@ pub fn Poller(comptime StreamEnum: type) type { |
| 264 | 264 | // always check if there's some data waiting to be read first. |
| 265 | 265 | if (poll_fd.revents & posix.POLL.IN != 0) { |
| 266 | 266 | const buf = try writableSliceGreedyAlloc(r, gpa, bump_amt); |
| 267 | const amt = posix.read(poll_fd.fd, buf) catch |err| switch (err) { | |
| 268 | error.BrokenPipe => 0, // Handle the same as EOF. | |
| 269 | else => |e| return e, | |
| 270 | }; | |
| 267 | const amt = try posix.read(poll_fd.fd, buf); | |
| 271 | 268 | advanceBufferEnd(r, amt); |
| 272 | 269 | if (amt == 0) { |
| 273 | 270 | // Remove the fd when the EOF condition is met. |
| ... | ... | @@ -633,9 +630,9 @@ pub const VTable = struct { |
| 633 | 630 | fileWritePositional: *const fn (?*anyopaque, File, header: []const u8, data: []const []const u8, splat: usize, offset: u64) File.WritePositionalError!usize, |
| 634 | 631 | fileWriteFileStreaming: *const fn (?*anyopaque, File, header: []const u8, *Io.File.Reader, Io.Limit) File.Writer.WriteFileError!usize, |
| 635 | 632 | fileWriteFilePositional: *const fn (?*anyopaque, File, header: []const u8, *Io.File.Reader, Io.Limit, offset: u64) File.WriteFilePositionalError!usize, |
| 636 | /// Returns 0 on end of stream. | |
| 637 | fileReadStreaming: *const fn (?*anyopaque, File, data: []const []u8) File.Reader.Error!usize, | |
| 638 | /// Returns 0 on end of stream. | |
| 633 | /// May return 0 reads which is different than `error.EndOfStream`. | |
| 634 | fileReadStreaming: *const fn (?*anyopaque, File, data: []const []u8) File.ReadStreamingError!usize, | |
| 635 | /// Returns 0 if reading at or past the end. | |
| 639 | 636 | fileReadPositional: *const fn (?*anyopaque, File, data: []const []u8, offset: u64) File.ReadPositionalError!usize, |
| 640 | 637 | fileSeekBy: *const fn (?*anyopaque, File, relative_offset: i64) File.SeekError!void, |
| 641 | 638 | fileSeekTo: *const fn (?*anyopaque, File, absolute_offset: u64) File.SeekError!void, |
lib/std/Io/File.zig+3-2| ... | ... | @@ -550,11 +550,13 @@ pub fn setTimestampsNow(file: File, io: Io) SetTimestampsError!void { |
| 550 | 550 | }); |
| 551 | 551 | } |
| 552 | 552 | |
| 553 | pub const ReadStreamingError = error{EndOfStream} || Reader.Error; | |
| 554 | ||
| 553 | 555 | /// Returns 0 on stream end or if `buffer` has no space available for data. |
| 554 | 556 | /// |
| 555 | 557 | /// See also: |
| 556 | 558 | /// * `reader` |
| 557 | pub fn readStreaming(file: File, io: Io, buffer: []const []u8) Reader.Error!usize { | |
| 559 | pub fn readStreaming(file: File, io: Io, buffer: []const []u8) ReadStreamingError!usize { | |
| 558 | 560 | return io.vtable.fileReadStreaming(io.userdata, file, buffer); |
| 559 | 561 | } |
| 560 | 562 | |
| ... | ... | @@ -563,7 +565,6 @@ pub const ReadPositionalError = error{ |
| 563 | 565 | SystemResources, |
| 564 | 566 | /// Trying to read a directory file descriptor as if it were a file. |
| 565 | 567 | IsDir, |
| 566 | BrokenPipe, | |
| 567 | 568 | /// Non-blocking has been enabled, and reading from the file descriptor |
| 568 | 569 | /// would block. |
| 569 | 570 | WouldBlock, |
lib/std/Io/File/Reader.zig+18-15| ... | ... | @@ -31,7 +31,6 @@ pub const Error = error{ |
| 31 | 31 | SystemResources, |
| 32 | 32 | /// Trying to read a directory file descriptor as if it were a file. |
| 33 | 33 | IsDir, |
| 34 | BrokenPipe, | |
| 35 | 34 | ConnectionResetByPeer, |
| 36 | 35 | /// File was not opened with read capability. |
| 37 | 36 | NotOpenForReading, |
| ... | ... | @@ -300,14 +299,16 @@ fn readVecStreaming(r: *Reader, data: [][]u8) Io.Reader.Error!usize { |
| 300 | 299 | const dest_n, const data_size = try r.interface.writableVector(&iovecs_buffer, data); |
| 301 | 300 | const dest = iovecs_buffer[0..dest_n]; |
| 302 | 301 | assert(dest[0].len > 0); |
| 303 | const n = io.vtable.fileReadStreaming(io.userdata, r.file, dest) catch |err| { | |
| 304 | r.err = err; | |
| 305 | return error.ReadFailed; | |
| 302 | const n = io.vtable.fileReadStreaming(io.userdata, r.file, dest) catch |err| switch (err) { | |
| 303 | error.EndOfStream => { | |
| 304 | r.size = r.pos; | |
| 305 | return error.EndOfStream; | |
| 306 | }, | |
| 307 | else => |e| { | |
| 308 | r.err = e; | |
| 309 | return error.ReadFailed; | |
| 310 | }, | |
| 306 | 311 | }; |
| 307 | if (n == 0) { | |
| 308 | r.size = r.pos; | |
| 309 | return error.EndOfStream; | |
| 310 | } | |
| 311 | 312 | r.pos += n; |
| 312 | 313 | if (n > data_size) { |
| 313 | 314 | r.interface.end += n - data_size; |
| ... | ... | @@ -355,14 +356,16 @@ fn discard(io_reader: *Io.Reader, limit: Io.Limit) Io.Reader.Error!usize { |
| 355 | 356 | const dest_n, const data_size = try r.interface.writableVector(&iovecs_buffer, &data); |
| 356 | 357 | const dest = iovecs_buffer[0..dest_n]; |
| 357 | 358 | assert(dest[0].len > 0); |
| 358 | const n = io.vtable.fileReadStreaming(io.userdata, file, dest) catch |err| { | |
| 359 | r.err = err; | |
| 360 | return error.ReadFailed; | |
| 359 | const n = io.vtable.fileReadStreaming(io.userdata, file, dest) catch |err| switch (err) { | |
| 360 | error.EndOfStream => { | |
| 361 | r.size = r.pos; | |
| 362 | return error.EndOfStream; | |
| 363 | }, | |
| 364 | else => |e| { | |
| 365 | r.err = e; | |
| 366 | return error.ReadFailed; | |
| 367 | }, | |
| 361 | 368 | }; |
| 362 | if (n == 0) { | |
| 363 | r.size = r.pos; | |
| 364 | return error.EndOfStream; | |
| 365 | } | |
| 366 | 369 | r.pos += n; |
| 367 | 370 | if (n > data_size) { |
| 368 | 371 | r.interface.end += n - data_size; |
lib/std/Io/Threaded.zig+36-48| ... | ... | @@ -8139,14 +8139,14 @@ fn fileClose(userdata: ?*anyopaque, files: []const File) void { |
| 8139 | 8139 | for (files) |file| posix.close(file.handle); |
| 8140 | 8140 | } |
| 8141 | 8141 | |
| 8142 | fn fileReadStreaming(userdata: ?*anyopaque, file: File, data: []const []u8) File.Reader.Error!usize { | |
| 8142 | fn fileReadStreaming(userdata: ?*anyopaque, file: File, data: []const []u8) File.ReadStreamingError!usize { | |
| 8143 | 8143 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 8144 | 8144 | _ = t; |
| 8145 | 8145 | if (is_windows) return fileReadStreamingWindows(file, data); |
| 8146 | 8146 | return fileReadStreamingPosix(file, data); |
| 8147 | 8147 | } |
| 8148 | 8148 | |
| 8149 | fn fileReadStreamingPosix(file: File, data: []const []u8) File.Reader.Error!usize { | |
| 8149 | fn fileReadStreamingPosix(file: File, data: []const []u8) File.ReadStreamingError!usize { | |
| 8150 | 8150 | var iovecs_buffer: [max_iovecs_len]posix.iovec = undefined; |
| 8151 | 8151 | var i: usize = 0; |
| 8152 | 8152 | for (data) |buf| { |
| ... | ... | @@ -8167,28 +8167,24 @@ fn fileReadStreamingPosix(file: File, data: []const []u8) File.Reader.Error!usiz |
| 8167 | 8167 | switch (std.os.wasi.fd_read(file.handle, dest.ptr, dest.len, &nread)) { |
| 8168 | 8168 | .SUCCESS => { |
| 8169 | 8169 | syscall.finish(); |
| 8170 | if (nread == 0) return error.EndOfStream; | |
| 8170 | 8171 | return nread; |
| 8171 | 8172 | }, |
| 8172 | 8173 | .INTR, .TIMEDOUT => { |
| 8173 | 8174 | try syscall.checkCancel(); |
| 8174 | 8175 | continue; |
| 8175 | 8176 | }, |
| 8176 | else => |e| { | |
| 8177 | syscall.finish(); | |
| 8178 | switch (e) { | |
| 8179 | .INVAL => |err| return errnoBug(err), | |
| 8180 | .FAULT => |err| return errnoBug(err), | |
| 8181 | .BADF => return error.IsDir, // File operation on directory. | |
| 8182 | .IO => return error.InputOutput, | |
| 8183 | .ISDIR => return error.IsDir, | |
| 8184 | .NOBUFS => return error.SystemResources, | |
| 8185 | .NOMEM => return error.SystemResources, | |
| 8186 | .NOTCONN => return error.SocketUnconnected, | |
| 8187 | .CONNRESET => return error.ConnectionResetByPeer, | |
| 8188 | .NOTCAPABLE => return error.AccessDenied, | |
| 8189 | else => |err| return posix.unexpectedErrno(err), | |
| 8190 | } | |
| 8191 | }, | |
| 8177 | .BADF => return syscall.fail(error.IsDir), // File operation on directory. | |
| 8178 | .IO => return syscall.fail(error.InputOutput), | |
| 8179 | .ISDIR => return syscall.fail(error.IsDir), | |
| 8180 | .NOBUFS => return syscall.fail(error.SystemResources), | |
| 8181 | .NOMEM => return syscall.fail(error.SystemResources), | |
| 8182 | .NOTCONN => return syscall.fail(error.SocketUnconnected), | |
| 8183 | .CONNRESET => return syscall.fail(error.ConnectionResetByPeer), | |
| 8184 | .NOTCAPABLE => return syscall.fail(error.AccessDenied), | |
| 8185 | .INVAL => |err| return syscall.errnoBug(err), | |
| 8186 | .FAULT => |err| return syscall.errnoBug(err), | |
| 8187 | else => |err| return syscall.unexpectedErrno(err), | |
| 8192 | 8188 | } |
| 8193 | 8189 | } |
| 8194 | 8190 | } |
| ... | ... | @@ -8199,36 +8195,33 @@ fn fileReadStreamingPosix(file: File, data: []const []u8) File.Reader.Error!usiz |
| 8199 | 8195 | switch (posix.errno(rc)) { |
| 8200 | 8196 | .SUCCESS => { |
| 8201 | 8197 | syscall.finish(); |
| 8198 | if (rc == 0) return error.EndOfStream; | |
| 8202 | 8199 | return @intCast(rc); |
| 8203 | 8200 | }, |
| 8204 | 8201 | .INTR, .TIMEDOUT => { |
| 8205 | 8202 | try syscall.checkCancel(); |
| 8206 | 8203 | continue; |
| 8207 | 8204 | }, |
| 8208 | else => |e| { | |
| 8205 | .BADF => { | |
| 8209 | 8206 | syscall.finish(); |
| 8210 | switch (e) { | |
| 8211 | .INVAL => |err| return errnoBug(err), | |
| 8212 | .FAULT => |err| return errnoBug(err), | |
| 8213 | .AGAIN => return error.WouldBlock, | |
| 8214 | .BADF => { | |
| 8215 | if (native_os == .wasi) return error.IsDir; // File operation on directory. | |
| 8216 | return error.NotOpenForReading; | |
| 8217 | }, | |
| 8218 | .IO => return error.InputOutput, | |
| 8219 | .ISDIR => return error.IsDir, | |
| 8220 | .NOBUFS => return error.SystemResources, | |
| 8221 | .NOMEM => return error.SystemResources, | |
| 8222 | .NOTCONN => return error.SocketUnconnected, | |
| 8223 | .CONNRESET => return error.ConnectionResetByPeer, | |
| 8224 | else => |err| return posix.unexpectedErrno(err), | |
| 8225 | } | |
| 8207 | if (native_os == .wasi) return error.IsDir; // File operation on directory. | |
| 8208 | return error.NotOpenForReading; | |
| 8226 | 8209 | }, |
| 8210 | .AGAIN => return syscall.fail(error.WouldBlock), | |
| 8211 | .IO => return syscall.fail(error.InputOutput), | |
| 8212 | .ISDIR => return syscall.fail(error.IsDir), | |
| 8213 | .NOBUFS => return syscall.fail(error.SystemResources), | |
| 8214 | .NOMEM => return syscall.fail(error.SystemResources), | |
| 8215 | .NOTCONN => return syscall.fail(error.SocketUnconnected), | |
| 8216 | .CONNRESET => return syscall.fail(error.ConnectionResetByPeer), | |
| 8217 | .INVAL => |err| return syscall.errnoBug(err), | |
| 8218 | .FAULT => |err| return syscall.errnoBug(err), | |
| 8219 | else => |err| return syscall.unexpectedErrno(err), | |
| 8227 | 8220 | } |
| 8228 | 8221 | } |
| 8229 | 8222 | } |
| 8230 | 8223 | |
| 8231 | fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!usize { | |
| 8224 | fn fileReadStreamingWindows(file: File, data: []const []u8) File.ReadStreamingError!usize { | |
| 8232 | 8225 | var index: usize = 0; |
| 8233 | 8226 | while (index < data.len and data[index].len == 0) index += 1; |
| 8234 | 8227 | if (index == data.len) return 0; |
| ... | ... | @@ -8250,25 +8243,18 @@ fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!us |
| 8250 | 8243 | null, // key |
| 8251 | 8244 | )) { |
| 8252 | 8245 | .SUCCESS => { |
| 8253 | // Only END_OF_FILE is the true end. | |
| 8254 | if (io_status_block.Information == 0) { | |
| 8255 | try syscall.checkCancel(); | |
| 8256 | continue; | |
| 8257 | } else { | |
| 8258 | syscall.finish(); | |
| 8259 | io_status_block.u.Status = .SUCCESS; | |
| 8260 | return io_status_block.Information; | |
| 8261 | } | |
| 8246 | syscall.finish(); | |
| 8247 | return io_status_block.Information; | |
| 8262 | 8248 | }, |
| 8263 | 8249 | .END_OF_FILE, .PIPE_BROKEN => { |
| 8264 | 8250 | syscall.finish(); |
| 8265 | return io_status_block.Information; | |
| 8251 | return error.EndOfStream; | |
| 8266 | 8252 | }, |
| 8267 | .PENDING => break, | |
| 8268 | 8253 | .CANCELLED => { |
| 8269 | 8254 | try syscall.checkCancel(); |
| 8270 | 8255 | continue; |
| 8271 | 8256 | }, |
| 8257 | .PENDING => break, | |
| 8272 | 8258 | .INVALID_DEVICE_REQUEST => return syscall.fail(error.IsDir), |
| 8273 | 8259 | .LOCK_NOT_GRANTED => return syscall.fail(error.LockViolation), |
| 8274 | 8260 | .ACCESS_DENIED => return syscall.fail(error.AccessDenied), |
| ... | ... | @@ -8302,7 +8288,9 @@ fn fileReadStreamingWindows(file: File, data: []const []u8) File.Reader.Error!us |
| 8302 | 8288 | alertable_syscall.finish(); |
| 8303 | 8289 | } |
| 8304 | 8290 | switch (io_status_block.u.Status) { |
| 8305 | .SUCCESS, .END_OF_FILE, .PIPE_BROKEN => return io_status_block.Information, | |
| 8291 | .SUCCESS => return io_status_block.Information, | |
| 8292 | .END_OF_FILE => return error.EndOfStream, | |
| 8293 | .PIPE_BROKEN => return error.EndOfStream, | |
| 8306 | 8294 | .PENDING => unreachable, // cannot return until the operation completes |
| 8307 | 8295 | .INVALID_DEVICE_REQUEST => return error.IsDir, |
| 8308 | 8296 | .LOCK_NOT_GRANTED => return error.LockViolation, |
lib/std/Progress.zig+1-2| ... | ... | @@ -984,7 +984,7 @@ fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buff |
| 984 | 984 | var bytes_read: usize = 0; |
| 985 | 985 | while (true) { |
| 986 | 986 | const n = file.readStreaming(io, &.{pipe_buf[bytes_read..]}) catch |err| switch (err) { |
| 987 | error.WouldBlock => break, | |
| 987 | error.WouldBlock, error.EndOfStream => break, | |
| 988 | 988 | else => |e| { |
| 989 | 989 | std.log.debug("failed to read child progress data: {t}", .{e}); |
| 990 | 990 | main_storage.completed_count = 0; |
| ... | ... | @@ -992,7 +992,6 @@ fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buff |
| 992 | 992 | continue :main_loop; |
| 993 | 993 | }, |
| 994 | 994 | }; |
| 995 | if (n == 0) break; | |
| 996 | 995 | if (opt_saved_metadata) |m| { |
| 997 | 996 | if (m.remaining_read_trash_bytes > 0) { |
| 998 | 997 | assert(bytes_read == 0); |
lib/std/zig/system.zig-1| ... | ... | @@ -418,7 +418,6 @@ pub fn resolveTargetQuery(io: Io, query: Target.Query) DetectError!Target { |
| 418 | 418 | error.Canceled => |e| return e, |
| 419 | 419 | error.Unexpected => |e| return e, |
| 420 | 420 | error.WouldBlock => return error.Unexpected, |
| 421 | error.BrokenPipe => return error.Unexpected, | |
| 422 | 421 | error.ConnectionResetByPeer => return error.Unexpected, |
| 423 | 422 | error.NotOpenForReading => return error.Unexpected, |
| 424 | 423 | error.SocketUnconnected => return error.Unexpected, |