Commit 89412fda77
Changed files (7)
lib
std
lib/std/debug/SelfInfo/Elf.zig
@@ -336,6 +336,7 @@ const Module = struct {
var elf_file = load_result catch |err| switch (err) {
error.OutOfMemory,
error.Unexpected,
+ error.Canceled,
=> |e| return e,
error.Overflow,
lib/std/debug/ElfFile.zig
@@ -108,6 +108,7 @@ pub const LoadError = error{
LockedMemoryLimitExceeded,
ProcessFdQuotaExceeded,
SystemFdQuotaExceeded,
+ Canceled,
Unexpected,
};
@@ -408,7 +409,7 @@ fn loadInner(
arena: Allocator,
elf_file: std.fs.File,
opt_crc: ?u32,
-) (LoadError || error{CrcMismatch})!LoadInnerResult {
+) (LoadError || error{ CrcMismatch, Canceled })!LoadInnerResult {
const mapped_mem: []align(std.heap.page_size_min) const u8 = mapped: {
const file_len = std.math.cast(
usize,
lib/std/fs/File.zig
@@ -1,10 +1,12 @@
+const File = @This();
+
const builtin = @import("builtin");
-const Os = std.builtin.Os;
const native_os = builtin.os.tag;
const is_windows = native_os == .windows;
-const File = @This();
const std = @import("../std.zig");
+const Io = std.Io;
+const Os = std.builtin.Os;
const Allocator = std.mem.Allocator;
const posix = std.posix;
const math = std.math;
@@ -17,12 +19,12 @@ const Alignment = std.mem.Alignment;
/// The OS-specific file descriptor or file handle.
handle: Handle,
-pub const Handle = std.Io.File.Handle;
-pub const Mode = std.Io.File.Mode;
-pub const INode = std.Io.File.INode;
+pub const Handle = Io.File.Handle;
+pub const Mode = Io.File.Mode;
+pub const INode = Io.File.INode;
pub const Uid = posix.uid_t;
pub const Gid = posix.gid_t;
-pub const Kind = std.Io.File.Kind;
+pub const Kind = Io.File.Kind;
/// This is the default mode given to POSIX operating systems for creating
/// files. `0o666` is "-rw-rw-rw-" which is counter-intuitive at first,
@@ -386,7 +388,7 @@ pub fn mode(self: File) ModeError!Mode {
return (try self.stat()).mode;
}
-pub const Stat = std.Io.File.Stat;
+pub const Stat = Io.File.Stat;
pub const StatError = posix.FStatError;
@@ -436,39 +438,9 @@ pub fn stat(self: File) StatError!Stat {
};
}
- if (builtin.os.tag == .wasi and !builtin.link_libc) {
- const st = try std.os.fstat_wasi(self.handle);
- return Stat.fromWasi(st);
- }
-
- if (builtin.os.tag == .linux) {
- var stx = std.mem.zeroes(linux.Statx);
-
- const rc = linux.statx(
- self.handle,
- "",
- linux.AT.EMPTY_PATH,
- linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_ATIME | linux.STATX_MTIME | linux.STATX_CTIME,
- &stx,
- );
-
- return switch (linux.E.init(rc)) {
- .SUCCESS => Stat.fromLinux(stx),
- .ACCES => unreachable,
- .BADF => unreachable,
- .FAULT => unreachable,
- .INVAL => unreachable,
- .LOOP => unreachable,
- .NAMETOOLONG => unreachable,
- .NOENT => unreachable,
- .NOMEM => error.SystemResources,
- .NOTDIR => unreachable,
- else => |err| posix.unexpectedErrno(err),
- };
- }
-
- const st = try posix.fstat(self.handle);
- return Stat.fromPosix(st);
+ var threaded: Io.Threaded = .init_single_threaded;
+ const io = threaded.io();
+ return Io.File.stat(.{ .handle = self.handle }, io);
}
pub const ChmodError = posix.FChmodError;
@@ -785,8 +757,8 @@ pub fn pwritev(self: File, iovecs: []posix.iovec_const, offset: u64) PWriteError
return posix.pwritev(self.handle, iovecs, offset);
}
-/// Deprecated in favor of `std.Io.File.Reader`.
-pub const Reader = std.Io.File.Reader;
+/// Deprecated in favor of `Io.File.Reader`.
+pub const Reader = Io.File.Reader;
pub const Writer = struct {
file: File,
@@ -799,7 +771,7 @@ pub const Writer = struct {
copy_file_range_err: ?CopyFileRangeError = null,
fcopyfile_err: ?FcopyfileError = null,
seek_err: ?Writer.SeekError = null,
- interface: std.Io.Writer,
+ interface: Io.Writer,
pub const Mode = Reader.Mode;
@@ -845,13 +817,13 @@ pub const Writer = struct {
};
}
- pub fn initInterface(buffer: []u8) std.Io.Writer {
+ pub fn initInterface(buffer: []u8) Io.Writer {
return .{
.vtable = &.{
.drain = drain,
.sendFile = switch (builtin.zig_backend) {
else => sendFile,
- .stage2_aarch64 => std.Io.Writer.unimplementedSendFile,
+ .stage2_aarch64 => Io.Writer.unimplementedSendFile,
},
},
.buffer = buffer,
@@ -859,7 +831,7 @@ pub const Writer = struct {
}
/// TODO when this logic moves from fs.File to Io.File the io parameter should be deleted
- pub fn moveToReader(w: *Writer, io: std.Io) Reader {
+ pub fn moveToReader(w: *Writer, io: Io) Reader {
defer w.* = undefined;
return .{
.io = io,
@@ -871,7 +843,7 @@ pub const Writer = struct {
};
}
- pub fn drain(io_w: *std.Io.Writer, data: []const []const u8, splat: usize) std.Io.Writer.Error!usize {
+ pub fn drain(io_w: *Io.Writer, data: []const []const u8, splat: usize) Io.Writer.Error!usize {
const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w));
const handle = w.file.handle;
const buffered = io_w.buffered();
@@ -1021,10 +993,10 @@ pub const Writer = struct {
}
pub fn sendFile(
- io_w: *std.Io.Writer,
- file_reader: *std.Io.File.Reader,
- limit: std.Io.Limit,
- ) std.Io.Writer.FileError!usize {
+ io_w: *Io.Writer,
+ file_reader: *Io.File.Reader,
+ limit: Io.Limit,
+ ) Io.Writer.FileError!usize {
const reader_buffered = file_reader.interface.buffered();
if (reader_buffered.len >= @intFromEnum(limit))
return sendFileBuffered(io_w, file_reader, limit.slice(reader_buffered));
@@ -1288,16 +1260,16 @@ pub const Writer = struct {
}
fn sendFileBuffered(
- io_w: *std.Io.Writer,
- file_reader: *std.Io.File.Reader,
+ io_w: *Io.Writer,
+ file_reader: *Io.File.Reader,
reader_buffered: []const u8,
- ) std.Io.Writer.FileError!usize {
+ ) Io.Writer.FileError!usize {
const n = try drain(io_w, &.{reader_buffered}, 1);
file_reader.seekBy(@intCast(n)) catch return error.ReadFailed;
return n;
}
- pub fn seekTo(w: *Writer, offset: u64) (Writer.SeekError || std.Io.Writer.Error)!void {
+ pub fn seekTo(w: *Writer, offset: u64) (Writer.SeekError || Io.Writer.Error)!void {
try w.interface.flush();
try seekToUnbuffered(w, offset);
}
@@ -1321,7 +1293,7 @@ pub const Writer = struct {
}
}
- pub const EndError = SetEndPosError || std.Io.Writer.Error;
+ pub const EndError = SetEndPosError || Io.Writer.Error;
/// Flushes any buffered data and sets the end position of the file.
///
@@ -1352,14 +1324,14 @@ pub const Writer = struct {
///
/// Positional is more threadsafe, since the global seek position is not
/// affected.
-pub fn reader(file: File, io: std.Io, buffer: []u8) Reader {
+pub fn reader(file: File, io: Io, buffer: []u8) Reader {
return .init(.{ .handle = file.handle }, io, buffer);
}
/// Positional is more threadsafe, since the global seek position is not
/// affected, but when such syscalls are not available, preemptively
/// initializing in streaming mode skips a failed syscall.
-pub fn readerStreaming(file: File, io: std.Io, buffer: []u8) Reader {
+pub fn readerStreaming(file: File, io: Io, buffer: []u8) Reader {
return .initStreaming(.{ .handle = file.handle }, io, buffer);
}
@@ -1541,10 +1513,10 @@ pub fn downgradeLock(file: File) LockError!void {
}
}
-pub fn adaptToNewApi(file: File) std.Io.File {
+pub fn adaptToNewApi(file: File) Io.File {
return .{ .handle = file.handle };
}
-pub fn adaptFromNewApi(file: std.Io.File) File {
+pub fn adaptFromNewApi(file: Io.File) File {
return .{ .handle = file.handle };
}
lib/std/Io/File.zig
@@ -47,90 +47,14 @@ pub const Stat = struct {
kind: Kind,
/// Last access time in nanoseconds, relative to UTC 1970-01-01.
+ /// TODO change this to Io.Timestamp except don't waste storage on clock
atime: i128,
/// Last modification time in nanoseconds, relative to UTC 1970-01-01.
+ /// TODO change this to Io.Timestamp except don't waste storage on clock
mtime: i128,
/// Last status/metadata change time in nanoseconds, relative to UTC 1970-01-01.
+ /// TODO change this to Io.Timestamp except don't waste storage on clock
ctime: i128,
-
- pub fn fromPosix(st: std.posix.Stat) Stat {
- const atime = st.atime();
- const mtime = st.mtime();
- const ctime = st.ctime();
- return .{
- .inode = st.ino,
- .size = @bitCast(st.size),
- .mode = st.mode,
- .kind = k: {
- const m = st.mode & std.posix.S.IFMT;
- switch (m) {
- std.posix.S.IFBLK => break :k .block_device,
- std.posix.S.IFCHR => break :k .character_device,
- std.posix.S.IFDIR => break :k .directory,
- std.posix.S.IFIFO => break :k .named_pipe,
- std.posix.S.IFLNK => break :k .sym_link,
- std.posix.S.IFREG => break :k .file,
- std.posix.S.IFSOCK => break :k .unix_domain_socket,
- else => {},
- }
- if (builtin.os.tag == .illumos) switch (m) {
- std.posix.S.IFDOOR => break :k .door,
- std.posix.S.IFPORT => break :k .event_port,
- else => {},
- };
-
- break :k .unknown;
- },
- .atime = @as(i128, atime.sec) * std.time.ns_per_s + atime.nsec,
- .mtime = @as(i128, mtime.sec) * std.time.ns_per_s + mtime.nsec,
- .ctime = @as(i128, ctime.sec) * std.time.ns_per_s + ctime.nsec,
- };
- }
-
- pub fn fromLinux(stx: std.os.linux.Statx) Stat {
- const atime = stx.atime;
- const mtime = stx.mtime;
- const ctime = stx.ctime;
-
- return .{
- .inode = stx.ino,
- .size = stx.size,
- .mode = stx.mode,
- .kind = switch (stx.mode & std.os.linux.S.IFMT) {
- std.os.linux.S.IFDIR => .directory,
- std.os.linux.S.IFCHR => .character_device,
- std.os.linux.S.IFBLK => .block_device,
- std.os.linux.S.IFREG => .file,
- std.os.linux.S.IFIFO => .named_pipe,
- std.os.linux.S.IFLNK => .sym_link,
- std.os.linux.S.IFSOCK => .unix_domain_socket,
- else => .unknown,
- },
- .atime = @as(i128, atime.sec) * std.time.ns_per_s + atime.nsec,
- .mtime = @as(i128, mtime.sec) * std.time.ns_per_s + mtime.nsec,
- .ctime = @as(i128, ctime.sec) * std.time.ns_per_s + ctime.nsec,
- };
- }
-
- pub fn fromWasi(st: std.os.wasi.filestat_t) Stat {
- return .{
- .inode = st.ino,
- .size = @bitCast(st.size),
- .mode = 0,
- .kind = switch (st.filetype) {
- .BLOCK_DEVICE => .block_device,
- .CHARACTER_DEVICE => .character_device,
- .DIRECTORY => .directory,
- .SYMBOLIC_LINK => .sym_link,
- .REGULAR_FILE => .file,
- .SOCKET_STREAM, .SOCKET_DGRAM => .unix_domain_socket,
- else => .unknown,
- },
- .atime = st.atim,
- .mtime = st.mtim,
- .ctime = st.ctim,
- };
- }
};
pub fn stdout() File {
@@ -145,13 +69,17 @@ pub fn stdin() File {
return .{ .handle = if (is_windows) std.os.windows.peb().ProcessParameters.hStdInput else std.posix.STDIN_FILENO };
}
-pub const StatError = std.posix.FStatError || Io.Cancelable;
+pub const StatError = error{
+ SystemResources,
+ /// In WASI, this error may occur when the file descriptor does
+ /// not hold the required rights to get its filestat information.
+ AccessDenied,
+ PermissionDenied,
+} || Io.Cancelable || Io.UnexpectedError;
/// Returns `Stat` containing basic information about the `File`.
pub fn stat(file: File, io: Io) StatError!Stat {
- _ = file;
- _ = io;
- @panic("TODO");
+ return io.vtable.fileStat(io.userdata, file);
}
pub const OpenFlags = std.fs.File.OpenFlags;
lib/std/Io/Threaded.zig
@@ -163,7 +163,12 @@ pub fn io(pool: *Pool) Io {
.dirMake = dirMake,
.dirStat = dirStat,
.dirStatPath = dirStatPath,
- .fileStat = fileStat,
+ .fileStat = switch (builtin.os.tag) {
+ .linux => fileStatLinux,
+ .windows => fileStatWindows,
+ .wasi => fileStatWasi,
+ else => fileStatPosix,
+ },
.createFile = createFile,
.fileOpen = fileOpen,
.fileClose = fileClose,
@@ -781,14 +786,80 @@ fn dirStatPath(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8) Io.Dir.
@panic("TODO");
}
-fn fileStat(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
+fn fileStatPosix(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
const pool: *Pool = @ptrCast(@alignCast(userdata));
- try pool.checkCancel();
+ const fstat_sym = if (posix.lfs64_abi) posix.system.fstat64 else posix.system.fstat;
+ while (true) {
+ try pool.checkCancel();
+ var stat = std.mem.zeroes(posix.Stat);
+ switch (posix.errno(fstat_sym(file.handle, &stat))) {
+ .SUCCESS => return statFromPosix(&stat),
+ .INTR => continue,
+ .INVAL => |err| return errnoBug(err),
+ .BADF => |err| return errnoBug(err),
+ .NOMEM => return error.SystemResources,
+ .ACCES => return error.AccessDenied,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ }
+}
+
+fn fileStatLinux(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
+ const pool: *Pool = @ptrCast(@alignCast(userdata));
+ const linux = std.os.linux;
+ while (true) {
+ try pool.checkCancel();
+ var statx = std.mem.zeroes(linux.Statx);
+ const rc = linux.statx(
+ file.handle,
+ "",
+ linux.AT.EMPTY_PATH,
+ linux.STATX_TYPE | linux.STATX_MODE | linux.STATX_ATIME | linux.STATX_MTIME | linux.STATX_CTIME,
+ &statx,
+ );
+ switch (linux.E.init(rc)) {
+ .SUCCESS => return statFromLinux(&statx),
+ .INTR => continue,
+ .ACCES => |err| return errnoBug(err),
+ .BADF => |err| return errnoBug(err),
+ .FAULT => |err| return errnoBug(err),
+ .INVAL => |err| return errnoBug(err),
+ .LOOP => |err| return errnoBug(err),
+ .NAMETOOLONG => |err| return errnoBug(err),
+ .NOENT => |err| return errnoBug(err),
+ .NOMEM => return error.SystemResources,
+ .NOTDIR => |err| return errnoBug(err),
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ }
+}
+fn fileStatWindows(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
+ const pool: *Pool = @ptrCast(@alignCast(userdata));
+ try pool.checkCancel();
_ = file;
@panic("TODO");
}
+fn fileStatWasi(userdata: ?*anyopaque, file: Io.File) Io.File.StatError!Io.File.Stat {
+ if (builtin.link_libc) return fileStatPosix(userdata, file);
+ const pool: *Pool = @ptrCast(@alignCast(userdata));
+ while (true) {
+ try pool.checkCancel();
+ var stat: std.os.wasi.filestat_t = undefined;
+ switch (std.os.wasi.fd_filestat_get(file.handle, &stat)) {
+ .SUCCESS => return statFromWasi(&stat),
+ .INTR => continue,
+ .INVAL => |err| return errnoBug(err),
+ .BADF => |err| return errnoBug(err),
+ .NOMEM => return error.SystemResources,
+ .ACCES => return error.AccessDenied,
+ .NOTCAPABLE => return error.AccessDenied,
+ else => |err| return posix.unexpectedErrno(err),
+ }
+ }
+}
+
fn createFile(
userdata: ?*anyopaque,
dir: Io.Dir,
@@ -2114,3 +2185,81 @@ fn clockToWasi(clock: Io.Timestamp.Clock) std.os.wasi.clockid_t {
.cpu_thread => .THREAD_CPUTIME_ID,
};
}
+
+fn statFromLinux(stx: *const std.os.linux.Statx) Io.File.Stat {
+ const atime = stx.atime;
+ const mtime = stx.mtime;
+ const ctime = stx.ctime;
+ return .{
+ .inode = stx.ino,
+ .size = stx.size,
+ .mode = stx.mode,
+ .kind = switch (stx.mode & std.os.linux.S.IFMT) {
+ std.os.linux.S.IFDIR => .directory,
+ std.os.linux.S.IFCHR => .character_device,
+ std.os.linux.S.IFBLK => .block_device,
+ std.os.linux.S.IFREG => .file,
+ std.os.linux.S.IFIFO => .named_pipe,
+ std.os.linux.S.IFLNK => .sym_link,
+ std.os.linux.S.IFSOCK => .unix_domain_socket,
+ else => .unknown,
+ },
+ .atime = @as(i128, atime.sec) * std.time.ns_per_s + atime.nsec,
+ .mtime = @as(i128, mtime.sec) * std.time.ns_per_s + mtime.nsec,
+ .ctime = @as(i128, ctime.sec) * std.time.ns_per_s + ctime.nsec,
+ };
+}
+
+fn statFromPosix(st: *const std.posix.Stat) Io.File.Stat {
+ const atime = st.atime();
+ const mtime = st.mtime();
+ const ctime = st.ctime();
+ return .{
+ .inode = st.ino,
+ .size = @bitCast(st.size),
+ .mode = st.mode,
+ .kind = k: {
+ const m = st.mode & std.posix.S.IFMT;
+ switch (m) {
+ std.posix.S.IFBLK => break :k .block_device,
+ std.posix.S.IFCHR => break :k .character_device,
+ std.posix.S.IFDIR => break :k .directory,
+ std.posix.S.IFIFO => break :k .named_pipe,
+ std.posix.S.IFLNK => break :k .sym_link,
+ std.posix.S.IFREG => break :k .file,
+ std.posix.S.IFSOCK => break :k .unix_domain_socket,
+ else => {},
+ }
+ if (builtin.os.tag == .illumos) switch (m) {
+ std.posix.S.IFDOOR => break :k .door,
+ std.posix.S.IFPORT => break :k .event_port,
+ else => {},
+ };
+
+ break :k .unknown;
+ },
+ .atime = @as(i128, atime.sec) * std.time.ns_per_s + atime.nsec,
+ .mtime = @as(i128, mtime.sec) * std.time.ns_per_s + mtime.nsec,
+ .ctime = @as(i128, ctime.sec) * std.time.ns_per_s + ctime.nsec,
+ };
+}
+
+fn statFromWasi(st: *const std.os.wasi.filestat_t) Io.File.Stat {
+ return .{
+ .inode = st.ino,
+ .size = @bitCast(st.size),
+ .mode = 0,
+ .kind = switch (st.filetype) {
+ .BLOCK_DEVICE => .block_device,
+ .CHARACTER_DEVICE => .character_device,
+ .DIRECTORY => .directory,
+ .SYMBOLIC_LINK => .sym_link,
+ .REGULAR_FILE => .file,
+ .SOCKET_STREAM, .SOCKET_DGRAM => .unix_domain_socket,
+ else => .unknown,
+ },
+ .atime = st.atim,
+ .mtime = st.mtim,
+ .ctime = st.ctim,
+ };
+}
lib/std/debug.zig
@@ -82,6 +82,7 @@ pub const SelfInfoError = error{
/// The required debug info could not be read from disk due to some IO error.
ReadFailed,
OutOfMemory,
+ Canceled,
Unexpected,
};
@@ -691,6 +692,7 @@ pub noinline fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Wri
error.UnsupportedDebugInfo => "unwind info unsupported",
error.ReadFailed => "filesystem error",
error.OutOfMemory => "out of memory",
+ error.Canceled => "operation canceled",
error.Unexpected => "unexpected error",
};
if (it.stratOk(options.allow_unsafe_unwind)) {
@@ -1079,7 +1081,7 @@ fn printSourceAtAddress(gpa: Allocator, debug_info: *SelfInfo, writer: *Writer,
error.UnsupportedDebugInfo,
error.InvalidDebugInfo,
=> .unknown,
- error.ReadFailed, error.Unexpected => s: {
+ error.ReadFailed, error.Unexpected, error.Canceled => s: {
tty_config.setColor(writer, .dim) catch {};
try writer.print("Failed to read debug info from filesystem, trace may be incomplete\n\n", .{});
tty_config.setColor(writer, .reset) catch {};
lib/std/posix.zig
@@ -4458,14 +4458,7 @@ pub fn wait4(pid: pid_t, flags: u32, ru: ?*rusage) WaitPidResult {
}
}
-pub const FStatError = error{
- SystemResources,
-
- /// In WASI, this error may occur when the file descriptor does
- /// not hold the required rights to get its filestat information.
- AccessDenied,
- PermissionDenied,
-} || UnexpectedError;
+pub const FStatError = std.Io.File.StatError;
/// Return information about a file descriptor.
pub fn fstat(fd: fd_t) FStatError!Stat {