| author | |
| committer | |
| log | 71ff6e0ef748fbc78cd469317f546c99c0dc5074 |
| tree | 3f2d60e4af02b30b0ce81452d5507c3d1f37a518 |
| parent | d40803284e6395e7a4a065a73c9fb09d1c0ff7a8 |
7 files changed, 114 insertions(+), 20 deletions(-)
lib/std/Io.zig+2-2| ... | ... | @@ -666,8 +666,8 @@ pub const VTable = struct { |
| 666 | 666 | fileReadStreaming: *const fn (?*anyopaque, File, data: [][]u8) File.ReadStreamingError!usize, |
| 667 | 667 | /// Returns 0 on end of stream. |
| 668 | 668 | fileReadPositional: *const fn (?*anyopaque, File, data: [][]u8, offset: u64) File.ReadPositionalError!usize, |
| 669 | fileSeekBy: *const fn (?*anyopaque, File, offset: i64) File.SeekError!void, | |
| 670 | fileSeekTo: *const fn (?*anyopaque, File, offset: u64) File.SeekError!void, | |
| 669 | fileSeekBy: *const fn (?*anyopaque, File, relative_offset: i64) File.SeekError!void, | |
| 670 | fileSeekTo: *const fn (?*anyopaque, File, absolute_offset: u64) File.SeekError!void, | |
| 671 | 671 | |
| 672 | 672 | now: *const fn (?*anyopaque, Clock) Clock.Error!Timestamp, |
| 673 | 673 | sleep: *const fn (?*anyopaque, Timeout) SleepError!void, |
lib/std/Io/File.zig+48-9| ... | ... | @@ -71,6 +71,8 @@ pub const StatError = error{ |
| 71 | 71 | /// not hold the required rights to get its filestat information. |
| 72 | 72 | AccessDenied, |
| 73 | 73 | PermissionDenied, |
| 74 | /// Attempted to stat a non-file stream. | |
| 75 | Streaming, | |
| 74 | 76 | } || Io.Cancelable || Io.UnexpectedError; |
| 75 | 77 | |
| 76 | 78 | /// Returns `Stat` containing basic information about the `File`. |
| ... | ... | @@ -357,10 +359,6 @@ pub const Reader = struct { |
| 357 | 359 | setLogicalPos(r, @intCast(@as(i64, @intCast(logicalPos(r))) + offset)); |
| 358 | 360 | }, |
| 359 | 361 | .streaming, .streaming_reading => { |
| 360 | if (std.posix.SEEK == void) { | |
| 361 | r.seek_err = error.Unseekable; | |
| 362 | return error.Unseekable; | |
| 363 | } | |
| 364 | 362 | const seek_err = r.seek_err orelse e: { |
| 365 | 363 | if (io.vtable.fileSeekBy(io.userdata, r.file, offset)) |_| { |
| 366 | 364 | setLogicalPos(r, @intCast(@as(i64, @intCast(logicalPos(r))) + offset)); |
| ... | ... | @@ -384,6 +382,7 @@ pub const Reader = struct { |
| 384 | 382 | } |
| 385 | 383 | } |
| 386 | 384 | |
| 385 | /// Repositions logical read offset relative to the beginning of the file. | |
| 387 | 386 | pub fn seekTo(r: *Reader, offset: u64) Reader.SeekError!void { |
| 388 | 387 | const io = r.io; |
| 389 | 388 | switch (r.mode) { |
| ... | ... | @@ -527,25 +526,65 @@ pub const Reader = struct { |
| 527 | 526 | const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader)); |
| 528 | 527 | const io = r.io; |
| 529 | 528 | const file = r.file; |
| 530 | const pos = r.pos; | |
| 531 | 529 | switch (r.mode) { |
| 532 | 530 | .positional, .positional_reading => { |
| 533 | 531 | const size = r.getSize() catch { |
| 534 | 532 | r.mode = r.mode.toStreaming(); |
| 535 | 533 | return 0; |
| 536 | 534 | }; |
| 537 | const delta = @min(@intFromEnum(limit), size - pos); | |
| 538 | r.pos = pos + delta; | |
| 535 | const logical_pos = logicalPos(r); | |
| 536 | const delta = @min(@intFromEnum(limit), size - logical_pos); | |
| 537 | setLogicalPos(r, logical_pos + delta); | |
| 539 | 538 | return delta; |
| 540 | 539 | }, |
| 541 | 540 | .streaming, .streaming_reading => { |
| 541 | // Unfortunately we can't seek forward without knowing the | |
| 542 | // size because the seek syscalls provided to us will not | |
| 543 | // return the true end position if a seek would exceed the | |
| 544 | // end. | |
| 545 | fallback: { | |
| 546 | if (r.size_err == null and r.seek_err == null) break :fallback; | |
| 547 | ||
| 548 | const buffered_len = r.interface.bufferedLen(); | |
| 549 | var remaining = @intFromEnum(limit); | |
| 550 | if (remaining <= buffered_len) { | |
| 551 | r.interface.seek += remaining; | |
| 552 | return remaining; | |
| 553 | } | |
| 554 | remaining -= buffered_len; | |
| 555 | r.interface.seek = 0; | |
| 556 | r.interface.end = 0; | |
| 557 | ||
| 558 | var trash_buffer: [128]u8 = undefined; | |
| 559 | var data: [1][]u8 = .{trash_buffer[0..@min(trash_buffer.len, remaining)]}; | |
| 560 | var iovecs_buffer: [max_buffers_len][]u8 = undefined; | |
| 561 | const dest_n, const data_size = try r.interface.writableVector(&iovecs_buffer, &data); | |
| 562 | const dest = iovecs_buffer[0..dest_n]; | |
| 563 | assert(dest[0].len > 0); | |
| 564 | const n = io.vtable.fileReadStreaming(io.userdata, file, dest) catch |err| { | |
| 565 | r.err = err; | |
| 566 | return error.ReadFailed; | |
| 567 | }; | |
| 568 | if (n == 0) { | |
| 569 | r.size = r.pos; | |
| 570 | return error.EndOfStream; | |
| 571 | } | |
| 572 | r.pos += n; | |
| 573 | if (n > data_size) { | |
| 574 | r.interface.end += n - data_size; | |
| 575 | remaining -= data_size; | |
| 576 | } else { | |
| 577 | remaining -= n; | |
| 578 | } | |
| 579 | return @intFromEnum(limit) - remaining; | |
| 580 | } | |
| 542 | 581 | const size = r.getSize() catch return 0; |
| 543 | const n = @min(size - pos, std.math.maxInt(i64), @intFromEnum(limit)); | |
| 582 | const n = @min(size - r.pos, std.math.maxInt(i64), @intFromEnum(limit)); | |
| 544 | 583 | io.vtable.fileSeekBy(io.userdata, file, n) catch |err| { |
| 545 | 584 | r.seek_err = err; |
| 546 | 585 | return 0; |
| 547 | 586 | }; |
| 548 | r.pos = pos + n; | |
| 587 | r.pos += n; | |
| 549 | 588 | return n; |
| 550 | 589 | }, |
| 551 | 590 | .failure => return error.ReadFailed, |
lib/std/Io/Threaded.zig+59-7| ... | ... | @@ -869,7 +869,6 @@ fn dirStatPathPosix( |
| 869 | 869 | const sub_path_posix = try pathToPosix(sub_path, &path_buffer); |
| 870 | 870 | |
| 871 | 871 | const flags: u32 = if (!options.follow_symlinks) posix.AT.SYMLINK_NOFOLLOW else 0; |
| 872 | const fstatat_sym = if (posix.lfs64_abi) posix.system.fstatat64 else posix.system.fstatat; | |
| 873 | 872 | |
| 874 | 873 | while (true) { |
| 875 | 874 | try pool.checkCancel(); |
| ... | ... | @@ -895,7 +894,9 @@ fn dirStatPathPosix( |
| 895 | 894 | |
| 896 | 895 | fn fileStatPosix(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat { |
| 897 | 896 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 898 | const fstat_sym = if (posix.lfs64_abi) posix.system.fstat64 else posix.system.fstat; | |
| 897 | ||
| 898 | if (posix.Stat == void) return error.Streaming; | |
| 899 | ||
| 899 | 900 | while (true) { |
| 900 | 901 | try pool.checkCancel(); |
| 901 | 902 | var stat = std.mem.zeroes(posix.Stat); |
| ... | ... | @@ -969,6 +970,10 @@ fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File. |
| 969 | 970 | |
| 970 | 971 | const have_flock = @TypeOf(posix.system.flock) != void; |
| 971 | 972 | const openat_sym = if (posix.lfs64_abi) posix.system.openat64 else posix.system.openat; |
| 973 | const fstat_sym = if (posix.lfs64_abi) posix.system.fstat64 else posix.system.fstat; | |
| 974 | const fstatat_sym = if (posix.lfs64_abi) posix.system.fstatat64 else posix.system.fstatat; | |
| 975 | const lseek_sym = if (posix.lfs64_abi) posix.system.lseek64 else posix.system.lseek; | |
| 976 | const preadv_sym = if (posix.lfs64_abi) posix.system.preadv64 else posix.system.preadv; | |
| 972 | 977 | |
| 973 | 978 | fn dirCreateFilePosix( |
| 974 | 979 | userdata: ?*anyopaque, |
| ... | ... | @@ -1423,7 +1428,6 @@ fn fileReadPositional(userdata: ?*anyopaque, file: Io.File, data: [][]u8, offset |
| 1423 | 1428 | } |
| 1424 | 1429 | }; |
| 1425 | 1430 | |
| 1426 | const preadv_sym = if (posix.lfs64_abi) posix.system.preadv64 else posix.system.preadv; | |
| 1427 | 1431 | while (true) { |
| 1428 | 1432 | try pool.checkCancel(); |
| 1429 | 1433 | const rc = preadv_sym(file.handle, dest.ptr, @intCast(dest.len), @bitCast(offset)); |
| ... | ... | @@ -1461,11 +1465,59 @@ fn fileSeekBy(userdata: ?*anyopaque, file: Io.File, offset: i64) Io.File.SeekErr |
| 1461 | 1465 | |
| 1462 | 1466 | fn fileSeekTo(userdata: ?*anyopaque, file: Io.File, offset: u64) Io.File.SeekError!void { |
| 1463 | 1467 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 1464 | try pool.checkCancel(); | |
| 1468 | const fd = file.handle; | |
| 1465 | 1469 | |
| 1466 | _ = file; | |
| 1467 | _ = offset; | |
| 1468 | @panic("TODO"); | |
| 1470 | if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) while (true) { | |
| 1471 | try pool.checkCancel(); | |
| 1472 | var result: u64 = undefined; | |
| 1473 | switch (posix.errno(posix.system.llseek(fd, offset, &result, posix.SEEK.SET))) { | |
| 1474 | .SUCCESS => return, | |
| 1475 | .INTR => continue, | |
| 1476 | .BADF => |err| return errnoBug(err), // Always a race condition. | |
| 1477 | .INVAL => return error.Unseekable, | |
| 1478 | .OVERFLOW => return error.Unseekable, | |
| 1479 | .SPIPE => return error.Unseekable, | |
| 1480 | .NXIO => return error.Unseekable, | |
| 1481 | else => |err| return posix.unexpectedErrno(err), | |
| 1482 | } | |
| 1483 | }; | |
| 1484 | ||
| 1485 | if (native_os == .windows) { | |
| 1486 | try pool.checkCancel(); | |
| 1487 | return windows.SetFilePointerEx_BEGIN(fd, offset); | |
| 1488 | } | |
| 1489 | ||
| 1490 | if (native_os == .wasi and !builtin.link_libc) while (true) { | |
| 1491 | try pool.checkCancel(); | |
| 1492 | var new_offset: std.os.wasi.filesize_t = undefined; | |
| 1493 | switch (std.os.wasi.fd_seek(fd, @bitCast(offset), .SET, &new_offset)) { | |
| 1494 | .SUCCESS => return, | |
| 1495 | .INTR => continue, | |
| 1496 | .BADF => |err| return errnoBug(err), // Always a race condition. | |
| 1497 | .INVAL => return error.Unseekable, | |
| 1498 | .OVERFLOW => return error.Unseekable, | |
| 1499 | .SPIPE => return error.Unseekable, | |
| 1500 | .NXIO => return error.Unseekable, | |
| 1501 | .NOTCAPABLE => return error.AccessDenied, | |
| 1502 | else => |err| return posix.unexpectedErrno(err), | |
| 1503 | } | |
| 1504 | }; | |
| 1505 | ||
| 1506 | if (posix.SEEK == void) return error.Unseekable; | |
| 1507 | ||
| 1508 | while (true) { | |
| 1509 | try pool.checkCancel(); | |
| 1510 | switch (posix.errno(lseek_sym(fd, @bitCast(offset), posix.SEEK.SET))) { | |
| 1511 | .SUCCESS => return, | |
| 1512 | .INTR => continue, | |
| 1513 | .BADF => |err| return errnoBug(err), // Always a race condition. | |
| 1514 | .INVAL => return error.Unseekable, | |
| 1515 | .OVERFLOW => return error.Unseekable, | |
| 1516 | .SPIPE => return error.Unseekable, | |
| 1517 | .NXIO => return error.Unseekable, | |
| 1518 | else => |err| return posix.unexpectedErrno(err), | |
| 1519 | } | |
| 1520 | } | |
| 1469 | 1521 | } |
| 1470 | 1522 | |
| 1471 | 1523 | fn pwrite(userdata: ?*anyopaque, file: Io.File, buffer: []const u8, offset: posix.off_t) Io.File.PWriteError!usize { |
lib/std/debug/ElfFile.zig+2-1| ... | ... | @@ -108,6 +108,7 @@ pub const LoadError = error{ |
| 108 | 108 | LockedMemoryLimitExceeded, |
| 109 | 109 | ProcessFdQuotaExceeded, |
| 110 | 110 | SystemFdQuotaExceeded, |
| 111 | Streaming, | |
| 111 | 112 | Canceled, |
| 112 | 113 | Unexpected, |
| 113 | 114 | }; |
| ... | ... | @@ -409,7 +410,7 @@ fn loadInner( |
| 409 | 410 | arena: Allocator, |
| 410 | 411 | elf_file: std.fs.File, |
| 411 | 412 | opt_crc: ?u32, |
| 412 | ) (LoadError || error{ CrcMismatch, Canceled })!LoadInnerResult { | |
| 413 | ) (LoadError || error{ CrcMismatch, Streaming, Canceled })!LoadInnerResult { | |
| 413 | 414 | const mapped_mem: []align(std.heap.page_size_min) const u8 = mapped: { |
| 414 | 415 | const file_len = std.math.cast( |
| 415 | 416 | usize, |
lib/std/debug/SelfInfo/Elf.zig+1| ... | ... | @@ -354,6 +354,7 @@ const Module = struct { |
| 354 | 354 | error.LockedMemoryLimitExceeded, |
| 355 | 355 | error.ProcessFdQuotaExceeded, |
| 356 | 356 | error.SystemFdQuotaExceeded, |
| 357 | error.Streaming, | |
| 357 | 358 | => return error.ReadFailed, |
| 358 | 359 | }; |
| 359 | 360 | errdefer elf_file.deinit(gpa); |
lib/std/dynamic_library.zig+1| ... | ... | @@ -138,6 +138,7 @@ const ElfDynLibError = error{ |
| 138 | 138 | ElfSymSectionNotFound, |
| 139 | 139 | ElfHashTableNotFound, |
| 140 | 140 | Canceled, |
| 141 | Streaming, | |
| 141 | 142 | } || posix.OpenError || posix.MMapError; |
| 142 | 143 | |
| 143 | 144 | pub const ElfDynLib = struct { |
lib/std/posix.zig+1-1| ... | ... | @@ -488,6 +488,7 @@ fn fchmodat2(dirfd: fd_t, path: []const u8, mode: mode_t, flags: u32) FChmodAtEr |
| 488 | 488 | error.NameTooLong => unreachable, |
| 489 | 489 | error.FileNotFound => unreachable, |
| 490 | 490 | error.InvalidUtf8 => unreachable, |
| 491 | error.Streaming => unreachable, | |
| 491 | 492 | error.Canceled => return error.Canceled, |
| 492 | 493 | else => |e| return e, |
| 493 | 494 | }; |
| ... | ... | @@ -5262,7 +5263,6 @@ pub fn gettimeofday(tv: ?*timeval, tz: ?*timezone) void { |
| 5262 | 5263 | |
| 5263 | 5264 | pub const SeekError = std.Io.File.SeekError; |
| 5264 | 5265 | |
| 5265 | /// Repositions read/write file offset relative to the beginning. | |
| 5266 | 5266 | pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void { |
| 5267 | 5267 | if (native_os == .linux and !builtin.link_libc and @sizeOf(usize) == 4) { |
| 5268 | 5268 | var result: u64 = undefined; |