authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-08 20:35:34-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-10-29 06:20:48-07:00
log89412fda775aecdedf4047355f2c45b48334a285
tree1aa3818600ec8bdead689f0a60bf507b4c259370
parent69b54b0cd12fb90f8ff101bc66e433a81d4b8409

std.Io: implement fileStat


7 files changed, 202 insertions(+), 156 deletions(-)

lib/std/Io/File.zig+11-83
...@@ -47,90 +47,14 @@ pub const Stat = struct {...@@ -47,90 +47,14 @@ pub const Stat = struct {
47 kind: Kind,47 kind: Kind,
4848
49 /// Last access time in nanoseconds, relative to UTC 1970-01-01.49 /// Last access time in nanoseconds, relative to UTC 1970-01-01.
50 /// TODO change this to Io.Timestamp except don't waste storage on clock
50 atime: i128,51 atime: i128,
51 /// Last modification time in nanoseconds, relative to UTC 1970-01-01.52 /// Last modification time in nanoseconds, relative to UTC 1970-01-01.
53 /// TODO change this to Io.Timestamp except don't waste storage on clock
52 mtime: i128,54 mtime: i128,
53 /// Last status/metadata change time in nanoseconds, relative to UTC 1970-01-01.55 /// Last status/metadata change time in nanoseconds, relative to UTC 1970-01-01.
56 /// TODO change this to Io.Timestamp except don't waste storage on clock
54 ctime: i128,57 ctime: i128,
55
56 pub fn fromPosix(st: std.posix.Stat) Stat {
57 const atime = st.atime();
58 const mtime = st.mtime();
59 const ctime = st.ctime();
60 return .{
61 .inode = st.ino,
62 .size = @bitCast(st.size),
63 .mode = st.mode,
64 .kind = k: {
65 const m = st.mode & std.posix.S.IFMT;
66 switch (m) {
67 std.posix.S.IFBLK => break :k .block_device,
68 std.posix.S.IFCHR => break :k .character_device,
69 std.posix.S.IFDIR => break :k .directory,
70 std.posix.S.IFIFO => break :k .named_pipe,
71 std.posix.S.IFLNK => break :k .sym_link,
72 std.posix.S.IFREG => break :k .file,
73 std.posix.S.IFSOCK => break :k .unix_domain_socket,
74 else => {},
75 }
76 if (builtin.os.tag == .illumos) switch (m) {
77 std.posix.S.IFDOOR => break :k .door,
78 std.posix.S.IFPORT => break :k .event_port,
79 else => {},
80 };
81
82 break :k .unknown;
83 },
84 .atime = @as(i128, atime.sec) * std.time.ns_per_s + atime.nsec,
85 .mtime = @as(i128, mtime.sec) * std.time.ns_per_s + mtime.nsec,
86 .ctime = @as(i128, ctime.sec) * std.time.ns_per_s + ctime.nsec,
87 };
88 }
89
90 pub fn fromLinux(stx: std.os.linux.Statx) Stat {
91 const atime = stx.atime;
92 const mtime = stx.mtime;
93 const ctime = stx.ctime;
94
95 return .{
96 .inode = stx.ino,
97 .size = stx.size,
98 .mode = stx.mode,
99 .kind = switch (stx.mode & std.os.linux.S.IFMT) {
100 std.os.linux.S.IFDIR => .directory,
101 std.os.linux.S.IFCHR => .character_device,
102 std.os.linux.S.IFBLK => .block_device,
103 std.os.linux.S.IFREG => .file,
104 std.os.linux.S.IFIFO => .named_pipe,
105 std.os.linux.S.IFLNK => .sym_link,
106 std.os.linux.S.IFSOCK => .unix_domain_socket,
107 else => .unknown,
108 },
109 .atime = @as(i128, atime.sec) * std.time.ns_per_s + atime.nsec,
110 .mtime = @as(i128, mtime.sec) * std.time.ns_per_s + mtime.nsec,
111 .ctime = @as(i128, ctime.sec) * std.time.ns_per_s + ctime.nsec,
112 };
113 }
114
115 pub fn fromWasi(st: std.os.wasi.filestat_t) Stat {
116 return .{
117 .inode = st.ino,
118 .size = @bitCast(st.size),
119 .mode = 0,
120 .kind = switch (st.filetype) {
121 .BLOCK_DEVICE => .block_device,
122 .CHARACTER_DEVICE => .character_device,
123 .DIRECTORY => .directory,
124 .SYMBOLIC_LINK => .sym_link,
125 .REGULAR_FILE => .file,
126 .SOCKET_STREAM, .SOCKET_DGRAM => .unix_domain_socket,
127 else => .unknown,
128 },
129 .atime = st.atim,
130 .mtime = st.mtim,
131 .ctime = st.ctim,
132 };
133 }
134};58};
13559
136pub fn stdout() File {60pub fn stdout() File {
...@@ -145,13 +69,17 @@ pub fn stdin() File {...@@ -145,13 +69,17 @@ pub fn stdin() File {
145 return .{ .handle = if (is_windows) std.os.windows.peb().ProcessParameters.hStdInput else std.posix.STDIN_FILENO };69 return .{ .handle = if (is_windows) std.os.windows.peb().ProcessParameters.hStdInput else std.posix.STDIN_FILENO };
146}70}
14771
148pub const StatError = std.posix.FStatError || Io.Cancelable;72pub const StatError = error{
73 SystemResources,
74 /// In WASI, this error may occur when the file descriptor does
75 /// not hold the required rights to get its filestat information.
76 AccessDenied,
77 PermissionDenied,
78} || Io.Cancelable || Io.UnexpectedError;
14979
150/// Returns `Stat` containing basic information about the `File`.80/// Returns `Stat` containing basic information about the `File`.
151pub fn stat(file: File, io: Io) StatError!Stat {81pub fn stat(file: File, io: Io) StatError!Stat {
152 _ = file;82 return io.vtable.fileStat(io.userdata, file);
153 _ = io;
154 @panic("TODO");
155}83}
15684
157pub const OpenFlags = std.fs.File.OpenFlags;85pub const OpenFlags = std.fs.File.OpenFlags;
lib/std/Io/Threaded.zig+152-3
...@@ -163,7 +163,12 @@ pub fn io(pool: *Pool) Io {...@@ -163,7 +163,12 @@ pub fn io(pool: *Pool) Io {
163 .dirMake = dirMake,163 .dirMake = dirMake,
164 .dirStat = dirStat,164 .dirStat = dirStat,
165 .dirStatPath = dirStatPath,165 .dirStatPath = dirStatPath,
166 .fileStat = fileStat,166 .fileStat = switch (builtin.os.tag) {
167 .linux => fileStatLinux,
168 .windows => fileStatWindows,
169 .wasi => fileStatWasi,
170 else => fileStatPosix,
171 },
167 .createFile = createFile,172 .createFile = createFile,
168 .fileOpen = fileOpen,173 .fileOpen = fileOpen,
169 .fileClose = fileClose,174 .fileClose = fileClose,
...@@ -781,14 +786,80 @@ fn dirStatPath(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8) Io.Dir....@@ -781,14 +786,80 @@ fn dirStatPath(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8) Io.Dir.
781 @panic("TODO");786 @panic("TODO");
782}787}
783788
784fn fileStat(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {789fn fileStatPosix(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
785 const pool: *Pool = @ptrCast(@alignCast(userdata));790 const pool: *Pool = @ptrCast(@alignCast(userdata));
786 try pool.checkCancel();791 const fstat_sym = if (posix.lfs64_abi) posix.system.fstat64 else posix.system.fstat;
792 while (true) {
793 try pool.checkCancel();
794 var stat = std.mem.zeroes(posix.Stat);
795 switch (posix.errno(fstat_sym(file.handle, &stat))) {
796 .SUCCESS => return statFromPosix(&stat),
797 .INTR => continue,
798 .INVAL => |err| return errnoBug(err),
799 .BADF => |err| return errnoBug(err),
800 .NOMEM => return error.SystemResources,
801 .ACCES => return error.AccessDenied,
802 else => |err| return posix.unexpectedErrno(err),
803 }
804 }
805}
806
807fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
808 const pool: *Pool = @ptrCast(@alignCast(userdata));
809 const linux = std.os.linux;
810 while (true) {
811 try pool.checkCancel();
812 var statx = std.mem.zeroes(linux.Statx);
813 const rc = linux.statx(
814 file.handle,
815 "",
816 linux.AT.EMPTY_PATH,
817 linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_ATIME | linux.STATX_MTIME | linux.STATX_CTIME,
818 &statx,
819 );
820 switch (linux.E.init(rc)) {
821 .SUCCESS => return statFromLinux(&statx),
822 .INTR => continue,
823 .ACCES => |err| return errnoBug(err),
824 .BADF => |err| return errnoBug(err),
825 .FAULT => |err| return errnoBug(err),
826 .INVAL => |err| return errnoBug(err),
827 .LOOP => |err| return errnoBug(err),
828 .NAMETOOLONG => |err| return errnoBug(err),
829 .NOENT => |err| return errnoBug(err),
830 .NOMEM => return error.SystemResources,
831 .NOTDIR => |err| return errnoBug(err),
832 else => |err| return posix.unexpectedErrno(err),
833 }
834 }
835}
787836
837fn fileStatWindows(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
838 const pool: *Pool = @ptrCast(@alignCast(userdata));
839 try pool.checkCancel();
788 _ = file;840 _ = file;
789 @panic("TODO");841 @panic("TODO");
790}842}
791843
844fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
845 if (builtin.link_libc) return fileStatPosix(userdata, file);
846 const pool: *Pool = @ptrCast(@alignCast(userdata));
847 while (true) {
848 try pool.checkCancel();
849 var stat: std.os.wasi.filestat_t = undefined;
850 switch (std.os.wasi.fd_filestat_get(file.handle, &stat)) {
851 .SUCCESS => return statFromWasi(&stat),
852 .INTR => continue,
853 .INVAL => |err| return errnoBug(err),
854 .BADF => |err| return errnoBug(err),
855 .NOMEM => return error.SystemResources,
856 .ACCES => return error.AccessDenied,
857 .NOTCAPABLE => return error.AccessDenied,
858 else => |err| return posix.unexpectedErrno(err),
859 }
860 }
861}
862
792fn createFile(863fn createFile(
793 userdata: ?*anyopaque,864 userdata: ?*anyopaque,
794 dir: Io.Dir,865 dir: Io.Dir,
...@@ -2114,3 +2185,81 @@ fn clockToWasi(clock: Io.Timestamp.Clock) std.os.wasi.clockid_t {...@@ -2114,3 +2185,81 @@ fn clockToWasi(clock: Io.Timestamp.Clock) std.os.wasi.clockid_t {
2114 .cpu_thread => .THREAD_CPUTIME_ID,2185 .cpu_thread => .THREAD_CPUTIME_ID,
2115 };2186 };
2116}2187}
2188
2189fn statFromLinux(stx: *const std.os.linux.Statx) Io.File.Stat {
2190 const atime = stx.atime;
2191 const mtime = stx.mtime;
2192 const ctime = stx.ctime;
2193 return .{
2194 .inode = stx.ino,
2195 .size = stx.size,
2196 .mode = stx.mode,
2197 .kind = switch (stx.mode & std.os.linux.S.IFMT) {
2198 std.os.linux.S.IFDIR => .directory,
2199 std.os.linux.S.IFCHR => .character_device,
2200 std.os.linux.S.IFBLK => .block_device,
2201 std.os.linux.S.IFREG => .file,
2202 std.os.linux.S.IFIFO => .named_pipe,
2203 std.os.linux.S.IFLNK => .sym_link,
2204 std.os.linux.S.IFSOCK => .unix_domain_socket,
2205 else => .unknown,
2206 },
2207 .atime = @as(i128, atime.sec) * std.time.ns_per_s + atime.nsec,
2208 .mtime = @as(i128, mtime.sec) * std.time.ns_per_s + mtime.nsec,
2209 .ctime = @as(i128, ctime.sec) * std.time.ns_per_s + ctime.nsec,
2210 };
2211}
2212
2213fn statFromPosix(st: *const std.posix.Stat) Io.File.Stat {
2214 const atime = st.atime();
2215 const mtime = st.mtime();
2216 const ctime = st.ctime();
2217 return .{
2218 .inode = st.ino,
2219 .size = @bitCast(st.size),
2220 .mode = st.mode,
2221 .kind = k: {
2222 const m = st.mode & std.posix.S.IFMT;
2223 switch (m) {
2224 std.posix.S.IFBLK => break :k .block_device,
2225 std.posix.S.IFCHR => break :k .character_device,
2226 std.posix.S.IFDIR => break :k .directory,
2227 std.posix.S.IFIFO => break :k .named_pipe,
2228 std.posix.S.IFLNK => break :k .sym_link,
2229 std.posix.S.IFREG => break :k .file,
2230 std.posix.S.IFSOCK => break :k .unix_domain_socket,
2231 else => {},
2232 }
2233 if (builtin.os.tag == .illumos) switch (m) {
2234 std.posix.S.IFDOOR => break :k .door,
2235 std.posix.S.IFPORT => break :k .event_port,
2236 else => {},
2237 };
2238
2239 break :k .unknown;
2240 },
2241 .atime = @as(i128, atime.sec) * std.time.ns_per_s + atime.nsec,
2242 .mtime = @as(i128, mtime.sec) * std.time.ns_per_s + mtime.nsec,
2243 .ctime = @as(i128, ctime.sec) * std.time.ns_per_s + ctime.nsec,
2244 };
2245}
2246
2247fn statFromWasi(st: *const std.os.wasi.filestat_t) Io.File.Stat {
2248 return .{
2249 .inode = st.ino,
2250 .size = @bitCast(st.size),
2251 .mode = 0,
2252 .kind = switch (st.filetype) {
2253 .BLOCK_DEVICE => .block_device,
2254 .CHARACTER_DEVICE => .character_device,
2255 .DIRECTORY => .directory,
2256 .SYMBOLIC_LINK => .sym_link,
2257 .REGULAR_FILE => .file,
2258 .SOCKET_STREAM, .SOCKET_DGRAM => .unix_domain_socket,
2259 else => .unknown,
2260 },
2261 .atime = st.atim,
2262 .mtime = st.mtim,
2263 .ctime = st.ctim,
2264 };
2265}
lib/std/debug.zig+3-1
...@@ -82,6 +82,7 @@ pub const SelfInfoError = error{...@@ -82,6 +82,7 @@ pub const SelfInfoError = error{
82 /// The required debug info could not be read from disk due to some IO error.82 /// The required debug info could not be read from disk due to some IO error.
83 ReadFailed,83 ReadFailed,
84 OutOfMemory,84 OutOfMemory,
85 Canceled,
85 Unexpected,86 Unexpected,
86};87};
8788
...@@ -691,6 +692,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Wri...@@ -691,6 +692,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Wri
691 error.UnsupportedDebugInfo => "unwind info unsupported",692 error.UnsupportedDebugInfo => "unwind info unsupported",
692 error.ReadFailed => "filesystem error",693 error.ReadFailed => "filesystem error",
693 error.OutOfMemory => "out of memory",694 error.OutOfMemory => "out of memory",
695 error.Canceled => "operation canceled",
694 error.Unexpected => "unexpected error",696 error.Unexpected => "unexpected error",
695 };697 };
696 if (it.stratOk(options.allow_unsafe_unwind)) {698 if (it.stratOk(options.allow_unsafe_unwind)) {
...@@ -1079,7 +1081,7 @@ fn printSourceAtAddress(gpa: Allocator, debug_info: *SelfInfo, writer: *Writer,...@@ -1079,7 +1081,7 @@ fn printSourceAtAddress(gpa: Allocator, debug_info: *SelfInfo, writer: *Writer,
1079 error.UnsupportedDebugInfo,1081 error.UnsupportedDebugInfo,
1080 error.InvalidDebugInfo,1082 error.InvalidDebugInfo,
1081 => .unknown,1083 => .unknown,
1082 error.ReadFailed, error.Unexpected => s: {1084 error.ReadFailed, error.Unexpected, error.Canceled => s: {
1083 tty_config.setColor(writer, .dim) catch {};1085 tty_config.setColor(writer, .dim) catch {};
1084 try writer.print("Failed to read debug info from filesystem, trace may be incomplete\n\n", .{});1086 try writer.print("Failed to read debug info from filesystem, trace may be incomplete\n\n", .{});
1085 tty_config.setColor(writer, .reset) catch {};1087 tty_config.setColor(writer, .reset) catch {};
lib/std/debug/ElfFile.zig+2-1
...@@ -108,6 +108,7 @@ pub const LoadError = error{...@@ -108,6 +108,7 @@ pub const LoadError = error{
108 LockedMemoryLimitExceeded,108 LockedMemoryLimitExceeded,
109 ProcessFdQuotaExceeded,109 ProcessFdQuotaExceeded,
110 SystemFdQuotaExceeded,110 SystemFdQuotaExceeded,
111 Canceled,
111 Unexpected,112 Unexpected,
112};113};
113114
...@@ -408,7 +409,7 @@ fn loadInner(...@@ -408,7 +409,7 @@ fn loadInner(
408 arena: Allocator,409 arena: Allocator,
409 elf_file: std.fs.File,410 elf_file: std.fs.File,
410 opt_crc: ?u32,411 opt_crc: ?u32,
411) (LoadError || error{CrcMismatch})!LoadInnerResult {412) (LoadError || error{ CrcMismatch, Canceled })!LoadInnerResult {
412 const mapped_mem: []align(std.heap.page_size_min) const u8 = mapped: {413 const mapped_mem: []align(std.heap.page_size_min) const u8 = mapped: {
413 const file_len = std.math.cast(414 const file_len = std.math.cast(
414 usize,415 usize,
lib/std/debug/SelfInfo/Elf.zig+1
...@@ -336,6 +336,7 @@ const Module = struct {...@@ -336,6 +336,7 @@ const Module = struct {
336 var elf_file = load_result catch |err| switch (err) {336 var elf_file = load_result catch |err| switch (err) {
337 error.OutOfMemory,337 error.OutOfMemory,
338 error.Unexpected,338 error.Unexpected,
339 error.Canceled,
339 => |e| return e,340 => |e| return e,
340341
341 error.Overflow,342 error.Overflow,
lib/std/fs/File.zig+32-60
...@@ -1,10 +1,12 @@...@@ -1,10 +1,12 @@
1const File = @This();
2
1const builtin = @import("builtin");3const builtin = @import("builtin");
2const Os = std.builtin.Os;
3const native_os = builtin.os.tag;4const native_os = builtin.os.tag;
4const is_windows = native_os == .windows;5const is_windows = native_os == .windows;
56
6const File = @This();
7const std = @import("../std.zig");7const std = @import("../std.zig");
8const Io = std.Io;
9const Os = std.builtin.Os;
8const Allocator = std.mem.Allocator;10const Allocator = std.mem.Allocator;
9const posix = std.posix;11const posix = std.posix;
10const math = std.math;12const math = std.math;
...@@ -17,12 +19,12 @@ const Alignment = std.mem.Alignment;...@@ -17,12 +19,12 @@ const Alignment = std.mem.Alignment;
17/// The OS-specific file descriptor or file handle.19/// The OS-specific file descriptor or file handle.
18handle: Handle,20handle: Handle,
1921
20pub const Handle = std.Io.File.Handle;22pub const Handle = Io.File.Handle;
21pub const Mode = std.Io.File.Mode;23pub const Mode = Io.File.Mode;
22pub const INode = std.Io.File.INode;24pub const INode = Io.File.INode;
23pub const Uid = posix.uid_t;25pub const Uid = posix.uid_t;
24pub const Gid = posix.gid_t;26pub const Gid = posix.gid_t;
25pub const Kind = std.Io.File.Kind;27pub const Kind = Io.File.Kind;
2628
27/// This is the default mode given to POSIX operating systems for creating29/// This is the default mode given to POSIX operating systems for creating
28/// files. `0o666` is "-rw-rw-rw-" which is counter-intuitive at first,30/// files. `0o666` is "-rw-rw-rw-" which is counter-intuitive at first,
...@@ -386,7 +388,7 @@ pub fn mode(self: File) ModeError!Mode {...@@ -386,7 +388,7 @@ pub fn mode(self: File) ModeError!Mode {
386 return (try self.stat()).mode;388 return (try self.stat()).mode;
387}389}
388390
389pub const Stat = std.Io.File.Stat;391pub const Stat = Io.File.Stat;
390392
391pub const StatError = posix.FStatError;393pub const StatError = posix.FStatError;
392394
...@@ -436,39 +438,9 @@ pub fn stat(self: File) StatError!Stat {...@@ -436,39 +438,9 @@ pub fn stat(self: File) StatError!Stat {
436 };438 };
437 }439 }
438440
439 if (builtin.os.tag == .wasi and !builtin.link_libc) {441 var threaded: Io.Threaded = .init_single_threaded;
440 const st = try std.os.fstat_wasi(self.handle);442 const io = threaded.io();
441 return Stat.fromWasi(st);443 return Io.File.stat(.{ .handle = self.handle }, io);
442 }
443
444 if (builtin.os.tag == .linux) {
445 var stx = std.mem.zeroes(linux.Statx);
446
447 const rc = linux.statx(
448 self.handle,
449 "",
450 linux.AT.EMPTY_PATH,
451 linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_ATIME | linux.STATX_MTIME | linux.STATX_CTIME,
452 &stx,
453 );
454
455 return switch (linux.E.init(rc)) {
456 .SUCCESS => Stat.fromLinux(stx),
457 .ACCES => unreachable,
458 .BADF => unreachable,
459 .FAULT => unreachable,
460 .INVAL => unreachable,
461 .LOOP => unreachable,
462 .NAMETOOLONG => unreachable,
463 .NOENT => unreachable,
464 .NOMEM => error.SystemResources,
465 .NOTDIR => unreachable,
466 else => |err| posix.unexpectedErrno(err),
467 };
468 }
469
470 const st = try posix.fstat(self.handle);
471 return Stat.fromPosix(st);
472}444}
473445
474pub const ChmodError = posix.FChmodError;446pub const ChmodError = posix.FChmodError;
...@@ -785,8 +757,8 @@ pub fn pwritev(self: File, iovecs: []posix.iovec_const, offset: u64) PWriteError...@@ -785,8 +757,8 @@ pub fn pwritev(self: File, iovecs: []posix.iovec_const, offset: u64) PWriteError
785 return posix.pwritev(self.handle, iovecs, offset);757 return posix.pwritev(self.handle, iovecs, offset);
786}758}
787759
788/// Deprecated in favor of `std.Io.File.Reader`.760/// Deprecated in favor of `Io.File.Reader`.
789pub const Reader = std.Io.File.Reader;761pub const Reader = Io.File.Reader;
790762
791pub const Writer = struct {763pub const Writer = struct {
792 file: File,764 file: File,
...@@ -799,7 +771,7 @@ pub const Writer = struct {...@@ -799,7 +771,7 @@ pub const Writer = struct {
799 copy_file_range_err: ?CopyFileRangeError = null,771 copy_file_range_err: ?CopyFileRangeError = null,
800 fcopyfile_err: ?FcopyfileError = null,772 fcopyfile_err: ?FcopyfileError = null,
801 seek_err: ?Writer.SeekError = null,773 seek_err: ?Writer.SeekError = null,
802 interface: std.Io.Writer,774 interface: Io.Writer,
803775
804 pub const Mode = Reader.Mode;776 pub const Mode = Reader.Mode;
805777
...@@ -845,13 +817,13 @@ pub const Writer = struct {...@@ -845,13 +817,13 @@ pub const Writer = struct {
845 };817 };
846 }818 }
847819
848 pub fn initInterface(buffer: []u8) std.Io.Writer {820 pub fn initInterface(buffer: []u8) Io.Writer {
849 return .{821 return .{
850 .vtable = &.{822 .vtable = &.{
851 .drain = drain,823 .drain = drain,
852 .sendFile = switch (builtin.zig_backend) {824 .sendFile = switch (builtin.zig_backend) {
853 else => sendFile,825 else => sendFile,
854 .stage2_aarch64 => std.Io.Writer.unimplementedSendFile,826 .stage2_aarch64 => Io.Writer.unimplementedSendFile,
855 },827 },
856 },828 },
857 .buffer = buffer,829 .buffer = buffer,
...@@ -859,7 +831,7 @@ pub const Writer = struct {...@@ -859,7 +831,7 @@ pub const Writer = struct {
859 }831 }
860832
861 /// TODO when this logic moves from fs.File to Io.File the io parameter should be deleted833 /// TODO when this logic moves from fs.File to Io.File the io parameter should be deleted
862 pub fn moveToReader(w: *Writer, io: std.Io) Reader {834 pub fn moveToReader(w: *Writer, io: Io) Reader {
863 defer w.* = undefined;835 defer w.* = undefined;
864 return .{836 return .{
865 .io = io,837 .io = io,
...@@ -871,7 +843,7 @@ pub const Writer = struct {...@@ -871,7 +843,7 @@ pub const Writer = struct {
871 };843 };
872 }844 }
873845
874 pub fn drain(io_w: *std.Io.Writer, data: []const []const u8, splat: usize) std.Io.Writer.Error!usize {846 pub fn drain(io_w: *Io.Writer, data: []const []const u8, splat: usize) Io.Writer.Error!usize {
875 const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));847 const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));
876 const handle = w.file.handle;848 const handle = w.file.handle;
877 const buffered = io_w.buffered();849 const buffered = io_w.buffered();
...@@ -1021,10 +993,10 @@ pub const Writer = struct {...@@ -1021,10 +993,10 @@ pub const Writer = struct {
1021 }993 }
1022994
1023 pub fn sendFile(995 pub fn sendFile(
1024 io_w: *std.Io.Writer,996 io_w: *Io.Writer,
1025 file_reader: *std.Io.File.Reader,997 file_reader: *Io.File.Reader,
1026 limit: std.Io.Limit,998 limit: Io.Limit,
1027 ) std.Io.Writer.FileError!usize {999 ) Io.Writer.FileError!usize {
1028 const reader_buffered = file_reader.interface.buffered();1000 const reader_buffered = file_reader.interface.buffered();
1029 if (reader_buffered.len >= @intFromEnum(limit))1001 if (reader_buffered.len >= @intFromEnum(limit))
1030 return sendFileBuffered(io_w, file_reader, limit.slice(reader_buffered));1002 return sendFileBuffered(io_w, file_reader, limit.slice(reader_buffered));
...@@ -1288,16 +1260,16 @@ pub const Writer = struct {...@@ -1288,16 +1260,16 @@ pub const Writer = struct {
1288 }1260 }
12891261
1290 fn sendFileBuffered(1262 fn sendFileBuffered(
1291 io_w: *std.Io.Writer,1263 io_w: *Io.Writer,
1292 file_reader: *std.Io.File.Reader,1264 file_reader: *Io.File.Reader,
1293 reader_buffered: []const u8,1265 reader_buffered: []const u8,
1294 ) std.Io.Writer.FileError!usize {1266 ) Io.Writer.FileError!usize {
1295 const n = try drain(io_w, &.{reader_buffered}, 1);1267 const n = try drain(io_w, &.{reader_buffered}, 1);
1296 file_reader.seekBy(@intCast(n)) catch return error.ReadFailed;1268 file_reader.seekBy(@intCast(n)) catch return error.ReadFailed;
1297 return n;1269 return n;
1298 }1270 }
12991271
1300 pub fn seekTo(w: *Writer, offset: u64) (Writer.SeekError || std.Io.Writer.Error)!void {1272 pub fn seekTo(w: *Writer, offset: u64) (Writer.SeekError || Io.Writer.Error)!void {
1301 try w.interface.flush();1273 try w.interface.flush();
1302 try seekToUnbuffered(w, offset);1274 try seekToUnbuffered(w, offset);
1303 }1275 }
...@@ -1321,7 +1293,7 @@ pub const Writer = struct {...@@ -1321,7 +1293,7 @@ pub const Writer = struct {
1321 }1293 }
1322 }1294 }
13231295
1324 pub const EndError = SetEndPosError || std.Io.Writer.Error;1296 pub const EndError = SetEndPosError || Io.Writer.Error;
13251297
1326 /// Flushes any buffered data and sets the end position of the file.1298 /// Flushes any buffered data and sets the end position of the file.
1327 ///1299 ///
...@@ -1352,14 +1324,14 @@ pub const Writer = struct {...@@ -1352,14 +1324,14 @@ pub const Writer = struct {
1352///1324///
1353/// Positional is more threadsafe, since the global seek position is not1325/// Positional is more threadsafe, since the global seek position is not
1354/// affected.1326/// affected.
1355pub fn reader(file: File, io: std.Io, buffer: []u8) Reader {1327pub fn reader(file: File, io: Io, buffer: []u8) Reader {
1356 return .init(.{ .handle = file.handle }, io, buffer);1328 return .init(.{ .handle = file.handle }, io, buffer);
1357}1329}
13581330
1359/// Positional is more threadsafe, since the global seek position is not1331/// Positional is more threadsafe, since the global seek position is not
1360/// affected, but when such syscalls are not available, preemptively1332/// affected, but when such syscalls are not available, preemptively
1361/// initializing in streaming mode skips a failed syscall.1333/// initializing in streaming mode skips a failed syscall.
1362pub fn readerStreaming(file: File, io: std.Io, buffer: []u8) Reader {1334pub fn readerStreaming(file: File, io: Io, buffer: []u8) Reader {
1363 return .initStreaming(.{ .handle = file.handle }, io, buffer);1335 return .initStreaming(.{ .handle = file.handle }, io, buffer);
1364}1336}
13651337
...@@ -1541,10 +1513,10 @@ pub fn downgradeLock(file: File) LockError!void {...@@ -1541,10 +1513,10 @@ pub fn downgradeLock(file: File) LockError!void {
1541 }1513 }
1542}1514}
15431515
1544pub fn adaptToNewApi(file: File) std.Io.File {1516pub fn adaptToNewApi(file: File) Io.File {
1545 return .{ .handle = file.handle };1517 return .{ .handle = file.handle };
1546}1518}
15471519
1548pub fn adaptFromNewApi(file: std.Io.File) File {1520pub fn adaptFromNewApi(file: Io.File) File {
1549 return .{ .handle = file.handle };1521 return .{ .handle = file.handle };
1550}1522}
lib/std/posix.zig+1-8
...@@ -4458,14 +4458,7 @@ pub fn wait4(pid: pid_t, flags: u32, ru: ?*rusage) WaitPidResult {...@@ -4458,14 +4458,7 @@ pub fn wait4(pid: pid_t, flags: u32, ru: ?*rusage) WaitPidResult {
4458 }4458 }
4459}4459}
44604460
4461pub const FStatError = error{4461pub const FStatError = std.Io.File.StatError;
4462 SystemResources,
4463
4464 /// In WASI, this error may occur when the file descriptor does
4465 /// not hold the required rights to get its filestat information.
4466 AccessDenied,
4467 PermissionDenied,
4468} || UnexpectedError;
44694462
4470/// Return information about a file descriptor.4463/// Return information about a file descriptor.
4471pub fn fstat(fd: fd_t) FStatError!Stat {4464pub fn fstat(fd: fd_t) FStatError!Stat {