| author | |
| committer | |
| log | 0e9280ef1a80e8fdeaec40a41b9cb6f2c2d4a490 |
| tree | c069e1a0b58fe0eb1729652406b6dcea440a764c |
| parent | fc1e3d5bc9f4279ae6cd19577bb443aff8d4ccb6 |
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://wtf-8.codeberg.page/). | ||
| 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://wtf-8.codeberg.page/). | ||
| 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| ... | @@ -107,13 +107,15 @@ pub fn updateFileAbsolute( | ... | @@ -107,13 +107,15 @@ pub fn updateFileAbsolute( |
| 107 | source_path: []const u8, | 107 | source_path: []const u8, |
| 108 | dest_path: []const u8, | 108 | dest_path: []const u8, |
| 109 | args: Dir.CopyFileOptions, | 109 | args: Dir.CopyFileOptions, |
| 110 | ) !Dir.PrevStatus { | 110 | ) !std.Io.Dir.PrevStatus { |
| 111 | assert(path.isAbsolute(source_path)); | 111 | assert(path.isAbsolute(source_path)); |
| 112 | assert(path.isAbsolute(dest_path)); | 112 | assert(path.isAbsolute(dest_path)); |
| 113 | const my_cwd = cwd(); | 113 | const my_cwd = cwd(); |
| 114 | return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, args); | 114 | return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, args); |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | test updateFileAbsolute {} | ||
| 118 | |||
| 117 | /// Same as `Dir.copyFile`, except asserts that both `source_path` and `dest_path` | 119 | /// Same as `Dir.copyFile`, except asserts that both `source_path` and `dest_path` |
| 118 | /// are absolute. See `Dir.copyFile` for a function that operates on both | 120 | /// are absolute. See `Dir.copyFile` for a function that operates on both |
| 119 | /// absolute and relative paths. | 121 | /// absolute and relative paths. |
| ... | @@ -131,6 +133,8 @@ pub fn copyFileAbsolute( | ... | @@ -131,6 +133,8 @@ pub fn copyFileAbsolute( |
| 131 | return Dir.copyFile(my_cwd, source_path, my_cwd, dest_path, args); | 133 | return Dir.copyFile(my_cwd, source_path, my_cwd, dest_path, args); |
| 132 | } | 134 | } |
| 133 | 135 | ||
| 136 | test copyFileAbsolute {} | ||
| 137 | |||
| 134 | /// Create a new directory, based on an absolute path. | 138 | /// Create a new directory, based on an absolute path. |
| 135 | /// Asserts that the path is absolute. See `Dir.makeDir` for a function that operates | 139 | /// Asserts that the path is absolute. See `Dir.makeDir` for a function that operates |
| 136 | /// on both absolute and relative paths. | 140 | /// on both absolute and relative paths. |
| ... | @@ -142,12 +146,16 @@ pub fn makeDirAbsolute(absolute_path: []const u8) !void { | ... | @@ -142,12 +146,16 @@ pub fn makeDirAbsolute(absolute_path: []const u8) !void { |
| 142 | return posix.mkdir(absolute_path, Dir.default_mode); | 146 | return posix.mkdir(absolute_path, Dir.default_mode); |
| 143 | } | 147 | } |
| 144 | 148 | ||
| 149 | test makeDirAbsolute {} | ||
| 150 | |||
| 145 | /// Same as `makeDirAbsolute` except the parameter is null-terminated. | 151 | /// Same as `makeDirAbsolute` except the parameter is null-terminated. |
| 146 | pub fn makeDirAbsoluteZ(absolute_path_z: [*:0]const u8) !void { | 152 | pub fn makeDirAbsoluteZ(absolute_path_z: [*:0]const u8) !void { |
| 147 | assert(path.isAbsoluteZ(absolute_path_z)); | 153 | assert(path.isAbsoluteZ(absolute_path_z)); |
| 148 | return posix.mkdirZ(absolute_path_z, Dir.default_mode); | 154 | return posix.mkdirZ(absolute_path_z, Dir.default_mode); |
| 149 | } | 155 | } |
| 150 | 156 | ||
| 157 | test makeDirAbsoluteZ {} | ||
| 158 | |||
| 151 | /// Same as `makeDirAbsolute` except the parameter is a null-terminated WTF-16 LE-encoded string. | 159 | /// Same as `makeDirAbsolute` except the parameter is a null-terminated WTF-16 LE-encoded string. |
| 152 | pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void { | 160 | pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void { |
| 153 | assert(path.isAbsoluteWindowsW(absolute_path_w)); | 161 | assert(path.isAbsoluteWindowsW(absolute_path_w)); |
| ... | @@ -702,16 +710,10 @@ pub fn realpathAlloc(allocator: Allocator, pathname: []const u8) ![]u8 { | ... | @@ -702,16 +710,10 @@ pub fn realpathAlloc(allocator: Allocator, pathname: []const u8) ![]u8 { |
| 702 | } | 710 | } |
| 703 | 711 | ||
| 704 | test { | 712 | test { |
| 705 | if (native_os != .wasi) { | 713 | _ = AtomicFile; |
| 706 | _ = &makeDirAbsolute; | 714 | _ = Dir; |
| 707 | _ = &makeDirAbsoluteZ; | 715 | _ = File; |
| 708 | _ = &copyFileAbsolute; | 716 | _ = path; |
| 709 | _ = &updateFileAbsolute; | ||
| 710 | } | ||
| 711 | _ = &AtomicFile; | ||
| 712 | _ = &Dir; | ||
| 713 | _ = &File; | ||
| 714 | _ = &path; | ||
| 715 | _ = @import("fs/test.zig"); | 717 | _ = @import("fs/test.zig"); |
| 716 | _ = @import("fs/get_app_data_dir.zig"); | 718 | _ = @import("fs/get_app_data_dir.zig"); |
| 717 | } | 719 | } |
lib/std/fs/Dir.zig-68| ... | @@ -2630,74 +2630,6 @@ pub const CopyFileOptions = struct { | ... | @@ -2630,74 +2630,6 @@ pub const CopyFileOptions = struct { |
| 2630 | override_mode: ?File.Mode = null, | 2630 | override_mode: ?File.Mode = null, |
| 2631 | }; | 2631 | }; |
| 2632 | 2632 | ||
| 2633 | pub const PrevStatus = enum { | ||
| 2634 | stale, | ||
| 2635 | fresh, | ||
| 2636 | }; | ||
| 2637 | |||
| 2638 | /// Check the file size, mtime, and mode of `source_path` and `dest_path`. If they are equal, does nothing. | ||
| 2639 | /// Otherwise, atomically copies `source_path` to `dest_path`. The destination file gains the mtime, | ||
| 2640 | /// atime, and mode of the source file so that the next call to `updateFile` will not need a copy. | ||
| 2641 | /// Returns the previous status of the file before updating. | ||
| 2642 | /// If any of the directories do not exist for dest_path, they are created. | ||
| 2643 | /// On Windows, both paths should be encoded as [WTF-8](https://wtf-8.codeberg.page/). | ||
| 2644 | /// On WASI, both paths should be encoded as valid UTF-8. | ||
| 2645 | /// On other platforms, both paths are an opaque sequence of bytes with no particular encoding. | ||
| 2646 | pub fn updateFile( | ||
| 2647 | source_dir: Dir, | ||
| 2648 | source_path: []const u8, | ||
| 2649 | dest_dir: Dir, | ||
| 2650 | dest_path: []const u8, | ||
| 2651 | options: CopyFileOptions, | ||
| 2652 | ) !PrevStatus { | ||
| 2653 | var src_file = try source_dir.openFile(source_path, .{}); | ||
| 2654 | defer src_file.close(); | ||
| 2655 | |||
| 2656 | const src_stat = try src_file.stat(); | ||
| 2657 | const actual_mode = options.override_mode orelse src_stat.mode; | ||
| 2658 | check_dest_stat: { | ||
| 2659 | const dest_stat = blk: { | ||
| 2660 | var dest_file = dest_dir.openFile(dest_path, .{}) catch |err| switch (err) { | ||
| 2661 | error.FileNotFound => break :check_dest_stat, | ||
| 2662 | else => |e| return e, | ||
| 2663 | }; | ||
| 2664 | defer dest_file.close(); | ||
| 2665 | |||
| 2666 | break :blk try dest_file.stat(); | ||
| 2667 | }; | ||
| 2668 | |||
| 2669 | if (src_stat.size == dest_stat.size and | ||
| 2670 | src_stat.mtime == dest_stat.mtime and | ||
| 2671 | actual_mode == dest_stat.mode) | ||
| 2672 | { | ||
| 2673 | return PrevStatus.fresh; | ||
| 2674 | } | ||
| 2675 | } | ||
| 2676 | |||
| 2677 | if (fs.path.dirname(dest_path)) |dirname| { | ||
| 2678 | try dest_dir.makePath(dirname); | ||
| 2679 | } | ||
| 2680 | |||
| 2681 | var buffer: [1000]u8 = undefined; // Used only when direct fd-to-fd is not available. | ||
| 2682 | var atomic_file = try dest_dir.atomicFile(dest_path, .{ | ||
| 2683 | .mode = actual_mode, | ||
| 2684 | .write_buffer = &buffer, | ||
| 2685 | }); | ||
| 2686 | defer atomic_file.deinit(); | ||
| 2687 | |||
| 2688 | var src_reader: File.Reader = .initSize(src_file, &.{}, src_stat.size); | ||
| 2689 | const dest_writer = &atomic_file.file_writer.interface; | ||
| 2690 | |||
| 2691 | _ = dest_writer.sendFileAll(&src_reader, .unlimited) catch |err| switch (err) { | ||
| 2692 | error.ReadFailed => return src_reader.err.?, | ||
| 2693 | error.WriteFailed => return atomic_file.file_writer.err.?, | ||
| 2694 | }; | ||
| 2695 | try atomic_file.flush(); | ||
| 2696 | try atomic_file.file_writer.file.updateTimes(src_stat.atime, src_stat.mtime); | ||
| 2697 | try atomic_file.renameIntoPlace(); | ||
| 2698 | return .stale; | ||
| 2699 | } | ||
| 2700 | |||
| 2701 | pub const CopyFileError = File.OpenError || File.StatError || | 2633 | pub const CopyFileError = File.OpenError || File.StatError || |
| 2702 | AtomicFile.InitError || AtomicFile.FinishError || | 2634 | AtomicFile.InitError || AtomicFile.FinishError || |
| 2703 | File.ReadError || File.WriteError; | 2635 | File.ReadError || File.WriteError; |
lib/std/fs/File.zig+1-7| ... | @@ -1144,13 +1144,7 @@ pub const Reader = struct { | ... | @@ -1144,13 +1144,7 @@ pub const Reader = struct { |
| 1144 | fn stream(io_reader: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize { | 1144 | fn stream(io_reader: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize { |
| 1145 | const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader)); | 1145 | const r: *Reader = @alignCast(@fieldParentPtr("interface", io_reader)); |
| 1146 | switch (r.mode) { | 1146 | switch (r.mode) { |
| 1147 | .positional, .streaming => return w.sendFile(r, limit) catch |write_err| switch (write_err) { | 1147 | .positional, .streaming => @panic("TODO"), |
| 1148 | error.Unimplemented => { | ||
| 1149 | r.mode = r.mode.toReading(); | ||
| 1150 | return 0; | ||
| 1151 | }, | ||
| 1152 | else => |e| return e, | ||
| 1153 | }, | ||
| 1154 | .positional_reading => { | 1148 | .positional_reading => { |
| 1155 | const dest = limit.slice(try w.writableSliceGreedy(1)); | 1149 | const dest = limit.slice(try w.writableSliceGreedy(1)); |
| 1156 | var data: [1][]u8 = .{dest}; | 1150 | var data: [1][]u8 = .{dest}; |
lib/std/posix.zig+1-1| ... | @@ -939,7 +939,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize { | ... | @@ -939,7 +939,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize { |
| 939 | } | 939 | } |
| 940 | } | 940 | } |
| 941 | 941 | ||
| 942 | pub const PReadError = std.Io.ReadPositionalError; | 942 | pub const PReadError = std.Io.File.ReadPositionalError; |
| 943 | 943 | ||
| 944 | /// Number of bytes read is returned. Upon reading end-of-file, zero is returned. | 944 | /// Number of bytes read is returned. Upon reading end-of-file, zero is returned. |
| 945 | /// | 945 | /// |