| author | |
| committer | |
| log | 43eea7beecaeb29d048cf971d6d08d0297109ce0 |
| tree | 715928a1485823da385abd27cb374bf9b3d84414 |
| parent | e34bb9a4131c2f0f328a53419d237877152917fa |
9 files changed, 162 insertions(+), 124 deletions(-)
lib/std/Io.zig+2-36| ... | @@ -548,6 +548,7 @@ pub fn PollFiles(comptime StreamEnum: type) type { | ... | @@ -548,6 +548,7 @@ pub fn PollFiles(comptime StreamEnum: type) type { |
| 548 | } | 548 | } |
| 549 | 549 | ||
| 550 | test { | 550 | test { |
| 551 | _ = net; | ||
| 551 | _ = Reader; | 552 | _ = Reader; |
| 552 | _ = Writer; | 553 | _ = Writer; |
| 553 | _ = tty; | 554 | _ = tty; |
| ... | @@ -688,42 +689,7 @@ pub const UnexpectedError = error{ | ... | @@ -688,42 +689,7 @@ pub const UnexpectedError = error{ |
| 688 | Unexpected, | 689 | Unexpected, |
| 689 | }; | 690 | }; |
| 690 | 691 | ||
| 691 | pub const Dir = struct { | 692 | pub const Dir = @import("Io/Dir.zig"); |
| 692 | handle: Handle, | ||
| 693 | |||
| 694 | pub fn cwd() Dir { | ||
| 695 | return .{ .handle = std.fs.cwd().fd }; | ||
| 696 | } | ||
| 697 | |||
| 698 | pub const Handle = std.posix.fd_t; | ||
| 699 | |||
| 700 | pub fn openFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File { | ||
| 701 | return io.vtable.fileOpen(io.userdata, dir, sub_path, flags); | ||
| 702 | } | ||
| 703 | |||
| 704 | pub fn createFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File { | ||
| 705 | return io.vtable.createFile(io.userdata, dir, sub_path, flags); | ||
| 706 | } | ||
| 707 | |||
| 708 | pub const WriteFileOptions = struct { | ||
| 709 | /// On Windows, `sub_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). | ||
| 710 | /// On WASI, `sub_path` should be encoded as valid UTF-8. | ||
| 711 | /// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding. | ||
| 712 | sub_path: []const u8, | ||
| 713 | data: []const u8, | ||
| 714 | flags: File.CreateFlags = .{}, | ||
| 715 | }; | ||
| 716 | |||
| 717 | pub const WriteFileError = File.WriteError || File.OpenError || Cancelable; | ||
| 718 | |||
| 719 | /// Writes content to the file system, using the file creation flags provided. | ||
| 720 | pub fn writeFile(dir: Dir, io: Io, options: WriteFileOptions) WriteFileError!void { | ||
| 721 | var file = try dir.createFile(io, options.sub_path, options.flags); | ||
| 722 | defer file.close(io); | ||
| 723 | try file.writeAll(io, options.data); | ||
| 724 | } | ||
| 725 | }; | ||
| 726 | |||
| 727 | pub const File = @import("Io/File.zig"); | 693 | pub const File = @import("Io/File.zig"); |
| 728 | 694 | ||
| 729 | pub const Timestamp = enum(i96) { | 695 | pub const Timestamp = enum(i96) { |
lib/std/Io/Dir.zig created+113| ... | @@ -0,0 +1,113 @@ | ||
| 1 | const Dir = @This(); | ||
| 2 | |||
| 3 | const std = @import("../std.zig"); | ||
| 4 | const Io = std.Io; | ||
| 5 | const File = Io.File; | ||
| 6 | |||
| 7 | handle: Handle, | ||
| 8 | |||
| 9 | pub fn cwd() Dir { | ||
| 10 | return .{ .handle = std.fs.cwd().fd }; | ||
| 11 | } | ||
| 12 | |||
| 13 | pub const Handle = std.posix.fd_t; | ||
| 14 | |||
| 15 | pub fn openFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File { | ||
| 16 | return io.vtable.fileOpen(io.userdata, dir, sub_path, flags); | ||
| 17 | } | ||
| 18 | |||
| 19 | pub fn createFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File { | ||
| 20 | return io.vtable.createFile(io.userdata, dir, sub_path, flags); | ||
| 21 | } | ||
| 22 | |||
| 23 | pub const WriteFileOptions = struct { | ||
| 24 | /// On Windows, `sub_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). | ||
| 25 | /// On WASI, `sub_path` should be encoded as valid UTF-8. | ||
| 26 | /// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding. | ||
| 27 | sub_path: []const u8, | ||
| 28 | data: []const u8, | ||
| 29 | flags: File.CreateFlags = .{}, | ||
| 30 | }; | ||
| 31 | |||
| 32 | pub const WriteFileError = File.WriteError || File.OpenError || Io.Cancelable; | ||
| 33 | |||
| 34 | /// Writes content to the file system, using the file creation flags provided. | ||
| 35 | pub fn writeFile(dir: Dir, io: Io, options: WriteFileOptions) WriteFileError!void { | ||
| 36 | var file = try dir.createFile(io, options.sub_path, options.flags); | ||
| 37 | defer file.close(io); | ||
| 38 | try file.writeAll(io, options.data); | ||
| 39 | } | ||
| 40 | |||
| 41 | pub const PrevStatus = enum { | ||
| 42 | stale, | ||
| 43 | fresh, | ||
| 44 | }; | ||
| 45 | |||
| 46 | pub const UpdateFileError = File.OpenError; | ||
| 47 | |||
| 48 | /// Check the file size, mtime, and mode of `source_path` and `dest_path`. If | ||
| 49 | /// they are equal, does nothing. Otherwise, atomically copies `source_path` to | ||
| 50 | /// `dest_path`. The destination file gains the mtime, atime, and mode of the | ||
| 51 | /// source file so that the next call to `updateFile` will not need a copy. | ||
| 52 | /// | ||
| 53 | /// Returns the previous status of the file before updating. | ||
| 54 | /// | ||
| 55 | /// * On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). | ||
| 56 | /// * On WASI, both paths should be encoded as valid UTF-8. | ||
| 57 | /// * On other platforms, both paths are an opaque sequence of bytes with no particular encoding. | ||
| 58 | pub fn updateFile( | ||
| 59 | source_dir: Dir, | ||
| 60 | io: Io, | ||
| 61 | source_path: []const u8, | ||
| 62 | dest_dir: Dir, | ||
| 63 | /// If directories in this path do not exist, they are created. | ||
| 64 | dest_path: []const u8, | ||
| 65 | options: std.fs.Dir.CopyFileOptions, | ||
| 66 | ) !PrevStatus { | ||
| 67 | var src_file = try source_dir.openFile(io, source_path, .{}); | ||
| 68 | defer src_file.close(); | ||
| 69 | |||
| 70 | const src_stat = try src_file.stat(io); | ||
| 71 | const actual_mode = options.override_mode orelse src_stat.mode; | ||
| 72 | check_dest_stat: { | ||
| 73 | const dest_stat = blk: { | ||
| 74 | var dest_file = dest_dir.openFile(io, dest_path, .{}) catch |err| switch (err) { | ||
| 75 | error.FileNotFound => break :check_dest_stat, | ||
| 76 | else => |e| return e, | ||
| 77 | }; | ||
| 78 | defer dest_file.close(io); | ||
| 79 | |||
| 80 | break :blk try dest_file.stat(io); | ||
| 81 | }; | ||
| 82 | |||
| 83 | if (src_stat.size == dest_stat.size and | ||
| 84 | src_stat.mtime == dest_stat.mtime and | ||
| 85 | actual_mode == dest_stat.mode) | ||
| 86 | { | ||
| 87 | return .fresh; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | if (std.fs.path.dirname(dest_path)) |dirname| { | ||
| 92 | try dest_dir.makePath(io, dirname); | ||
| 93 | } | ||
| 94 | |||
| 95 | var buffer: [1000]u8 = undefined; // Used only when direct fd-to-fd is not available. | ||
| 96 | var atomic_file = try dest_dir.atomicFile(io, dest_path, .{ | ||
| 97 | .mode = actual_mode, | ||
| 98 | .write_buffer = &buffer, | ||
| 99 | }); | ||
| 100 | defer atomic_file.deinit(); | ||
| 101 | |||
| 102 | var src_reader: File.Reader = .initSize(io, src_file, &.{}, src_stat.size); | ||
| 103 | const dest_writer = &atomic_file.file_writer.interface; | ||
| 104 | |||
| 105 | _ = dest_writer.sendFileAll(&src_reader, .unlimited) catch |err| switch (err) { | ||
| 106 | error.ReadFailed => return src_reader.err.?, | ||
| 107 | error.WriteFailed => return atomic_file.file_writer.err.?, | ||
| 108 | }; | ||
| 109 | try atomic_file.flush(); | ||
| 110 | try atomic_file.file_writer.file.updateTimes(src_stat.atime, src_stat.mtime); | ||
| 111 | try atomic_file.renameIntoPlace(); | ||
| 112 | return .stale; | ||
| 113 | } | ||
lib/std/Io/File.zig+3-1| ... | @@ -1,7 +1,9 @@ | ... | @@ -1,7 +1,9 @@ |
| 1 | const File = @This(); | ||
| 2 | |||
| 1 | const builtin = @import("builtin"); | 3 | const builtin = @import("builtin"); |
| 4 | |||
| 2 | const std = @import("../std.zig"); | 5 | const std = @import("../std.zig"); |
| 3 | const Io = std.Io; | 6 | const Io = std.Io; |
| 4 | const File = @This(); | ||
| 5 | const assert = std.debug.assert; | 7 | const assert = std.debug.assert; |
| 6 | 8 | ||
| 7 | handle: Handle, | 9 | handle: Handle, |
lib/std/Io/net.zig+4| ... | @@ -593,3 +593,7 @@ pub const InterfaceIndexError = error{ | ... | @@ -593,3 +593,7 @@ pub const InterfaceIndexError = error{ |
| 593 | pub fn interfaceIndex(io: Io, name: []const u8) InterfaceIndexError!u32 { | 593 | pub fn interfaceIndex(io: Io, name: []const u8) InterfaceIndexError!u32 { |
| 594 | return io.vtable.netInterfaceIndex(io.userdata, name); | 594 | return io.vtable.netInterfaceIndex(io.userdata, name); |
| 595 | } | 595 | } |
| 596 | |||
| 597 | test { | ||
| 598 | _ = HostName; | ||
| 599 | } |
lib/std/Io/net/HostName.zig+25| ... | @@ -629,3 +629,28 @@ pub const ResolvConf = struct { | ... | @@ -629,3 +629,28 @@ pub const ResolvConf = struct { |
| 629 | @panic("TODO"); | 629 | @panic("TODO"); |
| 630 | } | 630 | } |
| 631 | }; | 631 | }; |
| 632 | |||
| 633 | test ResolvConf { | ||
| 634 | const input = | ||
| 635 | \\# Generated by resolvconf | ||
| 636 | \\nameserver 1.0.0.1 | ||
| 637 | \\nameserver 1.1.1.1 | ||
| 638 | \\nameserver fe80::e0e:76ff:fed4:cf22%eno1 | ||
| 639 | \\options edns0 | ||
| 640 | \\ | ||
| 641 | ; | ||
| 642 | var reader: Io.Reader = .fixed(input); | ||
| 643 | |||
| 644 | var rc: ResolvConf = .{ | ||
| 645 | .nameservers_buffer = undefined, | ||
| 646 | .nameservers_len = 0, | ||
| 647 | .search_buffer = undefined, | ||
| 648 | .search_len = 0, | ||
| 649 | .ndots = 1, | ||
| 650 | .timeout = 5, | ||
| 651 | .attempts = 2, | ||
| 652 | }; | ||
| 653 | |||
| 654 | try rc.parse(&reader); | ||
| 655 | try std.testing.expect(false); | ||
| 656 | } |
lib/std/fs.zig+13-11| ... | @@ -106,13 +106,15 @@ pub fn updateFileAbsolute( | ... | @@ -106,13 +106,15 @@ pub fn updateFileAbsolute( |
| 106 | source_path: []const u8, | 106 | source_path: []const u8, |
| 107 | dest_path: []const u8, | 107 | dest_path: []const u8, |
| 108 | args: Dir.CopyFileOptions, | 108 | args: Dir.CopyFileOptions, |
| 109 | ) !Dir.PrevStatus { | 109 | ) !std.Io.Dir.PrevStatus { |
| 110 | assert(path.isAbsolute(source_path)); | 110 | assert(path.isAbsolute(source_path)); |
| 111 | assert(path.isAbsolute(dest_path)); | 111 | assert(path.isAbsolute(dest_path)); |
| 112 | const my_cwd = cwd(); | 112 | const my_cwd = cwd(); |
| 113 | return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, args); | 113 | return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, args); |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | test updateFileAbsolute {} | ||
| 117 | |||
| 116 | /// Same as `Dir.copyFile`, except asserts that both `source_path` and `dest_path` | 118 | /// Same as `Dir.copyFile`, except asserts that both `source_path` and `dest_path` |
| 117 | /// are absolute. See `Dir.copyFile` for a function that operates on both | 119 | /// are absolute. See `Dir.copyFile` for a function that operates on both |
| 118 | /// absolute and relative paths. | 120 | /// absolute and relative paths. |
| ... | @@ -130,6 +132,8 @@ pub fn copyFileAbsolute( | ... | @@ -130,6 +132,8 @@ pub fn copyFileAbsolute( |
| 130 | return Dir.copyFile(my_cwd, source_path, my_cwd, dest_path, args); | 132 | return Dir.copyFile(my_cwd, source_path, my_cwd, dest_path, args); |
| 131 | } | 133 | } |
| 132 | 134 | ||
| 135 | test copyFileAbsolute {} | ||
| 136 | |||
| 133 | /// Create a new directory, based on an absolute path. | 137 | /// Create a new directory, based on an absolute path. |
| 134 | /// Asserts that the path is absolute. See `Dir.makeDir` for a function that operates | 138 | /// Asserts that the path is absolute. See `Dir.makeDir` for a function that operates |
| 135 | /// on both absolute and relative paths. | 139 | /// on both absolute and relative paths. |
| ... | @@ -141,12 +145,16 @@ pub fn makeDirAbsolute(absolute_path: []const u8) !void { | ... | @@ -141,12 +145,16 @@ pub fn makeDirAbsolute(absolute_path: []const u8) !void { |
| 141 | return posix.mkdir(absolute_path, Dir.default_mode); | 145 | return posix.mkdir(absolute_path, Dir.default_mode); |
| 142 | } | 146 | } |
| 143 | 147 | ||
| 148 | test makeDirAbsolute {} | ||
| 149 | |||
| 144 | /// Same as `makeDirAbsolute` except the parameter is null-terminated. | 150 | /// Same as `makeDirAbsolute` except the parameter is null-terminated. |
| 145 | pub fn makeDirAbsoluteZ(absolute_path_z: [*:0]const u8) !void { | 151 | pub fn makeDirAbsoluteZ(absolute_path_z: [*:0]const u8) !void { |
| 146 | assert(path.isAbsoluteZ(absolute_path_z)); | 152 | assert(path.isAbsoluteZ(absolute_path_z)); |
| 147 | return posix.mkdirZ(absolute_path_z, Dir.default_mode); | 153 | return posix.mkdirZ(absolute_path_z, Dir.default_mode); |
| 148 | } | 154 | } |
| 149 | 155 | ||
| 156 | test makeDirAbsoluteZ {} | ||
| 157 | |||
| 150 | /// Same as `makeDirAbsolute` except the parameter is a null-terminated WTF-16 LE-encoded string. | 158 | /// Same as `makeDirAbsolute` except the parameter is a null-terminated WTF-16 LE-encoded string. |
| 151 | pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void { | 159 | pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void { |
| 152 | assert(path.isAbsoluteWindowsW(absolute_path_w)); | 160 | assert(path.isAbsoluteWindowsW(absolute_path_w)); |
| ... | @@ -693,16 +701,10 @@ pub fn realpathAlloc(allocator: Allocator, pathname: []const u8) ![]u8 { | ... | @@ -693,16 +701,10 @@ pub fn realpathAlloc(allocator: Allocator, pathname: []const u8) ![]u8 { |
| 693 | } | 701 | } |
| 694 | 702 | ||
| 695 | test { | 703 | test { |
| 696 | if (native_os != .wasi) { | 704 | _ = AtomicFile; |
| 697 | _ = &makeDirAbsolute; | 705 | _ = Dir; |
| 698 | _ = &makeDirAbsoluteZ; | 706 | _ = File; |
| 699 | _ = &copyFileAbsolute; | 707 | _ = path; |
| 700 | _ = &updateFileAbsolute; | ||
| 701 | } | ||
| 702 | _ = &AtomicFile; | ||
| 703 | _ = &Dir; | ||
| 704 | _ = &File; | ||
| 705 | _ = &path; | ||
| 706 | _ = @import("fs/test.zig"); | 708 | _ = @import("fs/test.zig"); |
| 707 | _ = @import("fs/get_app_data_dir.zig"); | 709 | _ = @import("fs/get_app_data_dir.zig"); |
| 708 | } | 710 | } |
lib/std/fs/Dir.zig-68| ... | @@ -2539,74 +2539,6 @@ pub const CopyFileOptions = struct { | ... | @@ -2539,74 +2539,6 @@ pub const CopyFileOptions = struct { |
| 2539 | override_mode: ?File.Mode = null, | 2539 | override_mode: ?File.Mode = null, |
| 2540 | }; | 2540 | }; |
| 2541 | 2541 | ||
| 2542 | pub const PrevStatus = enum { | ||
| 2543 | stale, | ||
| 2544 | fresh, | ||
| 2545 | }; | ||
| 2546 | |||
| 2547 | /// Check the file size, mtime, and mode of `source_path` and `dest_path`. If they are equal, does nothing. | ||
| 2548 | /// Otherwise, atomically copies `source_path` to `dest_path`. The destination file gains the mtime, | ||
| 2549 | /// atime, and mode of the source file so that the next call to `updateFile` will not need a copy. | ||
| 2550 | /// Returns the previous status of the file before updating. | ||
| 2551 | /// If any of the directories do not exist for dest_path, they are created. | ||
| 2552 | /// On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). | ||
| 2553 | /// On WASI, both paths should be encoded as valid UTF-8. | ||
| 2554 | /// On other platforms, both paths are an opaque sequence of bytes with no particular encoding. | ||
| 2555 | pub fn updateFile( | ||
| 2556 | source_dir: Dir, | ||
| 2557 | source_path: []const u8, | ||
| 2558 | dest_dir: Dir, | ||
| 2559 | dest_path: []const u8, | ||
| 2560 | options: CopyFileOptions, | ||
| 2561 | ) !PrevStatus { | ||
| 2562 | var src_file = try source_dir.openFile(source_path, .{}); | ||
| 2563 | defer src_file.close(); | ||
| 2564 | |||
| 2565 | const src_stat = try src_file.stat(); | ||
| 2566 | const actual_mode = options.override_mode orelse src_stat.mode; | ||
| 2567 | check_dest_stat: { | ||
| 2568 | const dest_stat = blk: { | ||
| 2569 | var dest_file = dest_dir.openFile(dest_path, .{}) catch |err| switch (err) { | ||
| 2570 | error.FileNotFound => break :check_dest_stat, | ||
| 2571 | else => |e| return e, | ||
| 2572 | }; | ||
| 2573 | defer dest_file.close(); | ||
| 2574 | |||
| 2575 | break :blk try dest_file.stat(); | ||
| 2576 | }; | ||
| 2577 | |||
| 2578 | if (src_stat.size == dest_stat.size and | ||
| 2579 | src_stat.mtime == dest_stat.mtime and | ||
| 2580 | actual_mode == dest_stat.mode) | ||
| 2581 | { | ||
| 2582 | return PrevStatus.fresh; | ||
| 2583 | } | ||
| 2584 | } | ||
| 2585 | |||
| 2586 | if (fs.path.dirname(dest_path)) |dirname| { | ||
| 2587 | try dest_dir.makePath(dirname); | ||
| 2588 | } | ||
| 2589 | |||
| 2590 | var buffer: [1000]u8 = undefined; // Used only when direct fd-to-fd is not available. | ||
| 2591 | var atomic_file = try dest_dir.atomicFile(dest_path, .{ | ||
| 2592 | .mode = actual_mode, | ||
| 2593 | .write_buffer = &buffer, | ||
| 2594 | }); | ||
| 2595 | defer atomic_file.deinit(); | ||
| 2596 | |||
| 2597 | var src_reader: File.Reader = .initSize(src_file, &.{}, src_stat.size); | ||
| 2598 | const dest_writer = &atomic_file.file_writer.interface; | ||
| 2599 | |||
| 2600 | _ = dest_writer.sendFileAll(&src_reader, .unlimited) catch |err| switch (err) { | ||
| 2601 | error.ReadFailed => return src_reader.err.?, | ||
| 2602 | error.WriteFailed => return atomic_file.file_writer.err.?, | ||
| 2603 | }; | ||
| 2604 | try atomic_file.flush(); | ||
| 2605 | try atomic_file.file_writer.file.updateTimes(src_stat.atime, src_stat.mtime); | ||
| 2606 | try atomic_file.renameIntoPlace(); | ||
| 2607 | return .stale; | ||
| 2608 | } | ||
| 2609 | |||
| 2610 | pub const CopyFileError = File.OpenError || File.StatError || | 2542 | pub const CopyFileError = File.OpenError || File.StatError || |
| 2611 | AtomicFile.InitError || AtomicFile.FinishError || | 2543 | AtomicFile.InitError || AtomicFile.FinishError || |
| 2612 | File.ReadError || File.WriteError; | 2544 | File.ReadError || File.WriteError; |
lib/std/fs/File.zig+1-7| ... | @@ -1143,13 +1143,7 @@ pub const Reader = struct { | ... | @@ -1143,13 +1143,7 @@ pub const Reader = struct { |
| 1143 | fn stream(io_reader: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize { | 1143 | fn stream(io_reader: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize { |
| 1144 | const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader)); | 1144 | const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader)); |
| 1145 | switch (r.mode) { | 1145 | switch (r.mode) { |
| 1146 | .positional, .streaming => return w.sendFile(r, limit) catch |write_err| switch (write_err) { | 1146 | .positional, .streaming => @panic("TODO"), |
| 1147 | error.Unimplemented => { | ||
| 1148 | r.mode = r.mode.toReading(); | ||
| 1149 | return 0; | ||
| 1150 | }, | ||
| 1151 | else => |e| return e, | ||
| 1152 | }, | ||
| 1153 | .positional_reading => { | 1147 | .positional_reading => { |
| 1154 | const dest = limit.slice(try w.writableSliceGreedy(1)); | 1148 | const dest = limit.slice(try w.writableSliceGreedy(1)); |
| 1155 | const n = try readPositional(r, dest); | 1149 | const n = try readPositional(r, dest); |
lib/std/posix.zig+1-1| ... | @@ -940,7 +940,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize { | ... | @@ -940,7 +940,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize { |
| 940 | } | 940 | } |
| 941 | } | 941 | } |
| 942 | 942 | ||
| 943 | pub const PReadError = std.Io.ReadPositionalError; | 943 | pub const PReadError = std.Io.File.ReadPositionalError; |
| 944 | 944 | ||
| 945 | /// Number of bytes read is returned. Upon reading end-of-file, zero is returned. | 945 | /// Number of bytes read is returned. Upon reading end-of-file, zero is returned. |
| 946 | /// | 946 | /// |