Skip to documentation
SLOP

tiny.sys.fs

Reference tiny.sys fs

Defined in tiny.sys.

API (92)

Actions

Public operations.

Types and contracts

Public types and contracts.

Values and defaults

Public values and defaults.

No direct callersNo direct callstiny.sysfs
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallsNo direct callsfslistDirAllocfs.Entrydeinit
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callstest sourcelib.sys.src.fstest: writeFile and readFileAlloc rou...fsabsoluteFileExists
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallstest sourcelib.sys.src.fstest: absolute path helpers access cr...test sourcelib.sys.src.fstest: deleteTree removes cwd director...fsaccessAbsolutefsabsolutePathExists
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsfsabsolutePathExiststest sourcelib.sys.src.fstest: absolute path helpers access cr...fsaccessAbsolute
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.sys.src.linuxerrnofsaddWatch
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallstest sourcelib.sys.src.fstest: allocated blocks report support...private sourcelib.sys.src.fsallocatedBlocksLinuxfsallocatedBlocks
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.sys.src.fstest: appendFile appends chunks to cw...fsappendFile
Static calls · unresolved targets: 1 · external targets: 5.
Called byCallsNo direct callstest sourcelib.sys.src.fstest: appendFileSync appends chunks a...fsappendFileSync
Static calls · unresolved targets: 1 · external targets: 6.
Called byCallsNo direct callsprivate sourcelib.sys.src.pulseloadCookiefscloseHandle
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallstest sourcelib.sys.src.fstest: absolute path helpers access cr...fscreateDirPathfscreateAbsoluteDirPath
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsfscreateAbsoluteDirPathtest sourcelib.sys.src.fstest: deleteTree removes cwd director...test sourcelib.sys.src.fstest: listDirAlloc returns owned entr...fscreateDirPath
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsprivate sourcelib.sys.src.fscreateNamedPipeForTestprivate sourcelib.sys.src.fs.darwinmkfifoatfscreateNamedPipe
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallsNo direct callersprivate sourcelib.sys.src.linuxerrnofscreateWatch
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callstest sourcelib.sys.src.fstest: cwd handle is available through...x11.authloadCookiefscwd
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallsNo direct callstest sourcelib.sys.src.fstest: cwd handle is available through...x11.authloadCookiefsdebugIo
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.sys.src.fstest: absolute path helpers access cr...fsdeleteAbsoluteFile
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.sys.src.fstest: deleteTree removes cwd director...fsdeleteTree
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.sys.src.fstest: exchange swaps a file and a dir...private sourcelib.sys.src.linuxerrnofsexchange
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallstest sourcelib.sys.src.fstest: rename replaces cwd destinationtest sourcelib.sys.src.fstest: writeFile and readFileAlloc rou...fsstatFilefsexists
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsfsfileOwnerUserIdtest sourcelib.sys.src.fstest: file owner identity matches the...test sourcelib.sys.src.fstest: file owner policy is explicitfsfileOwnerPolicy
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.sys.src.fstest: file owner identity matches the...fsfileOwnerPolicyprivate sourcelib.sys.src.fsfileOwnerUserIdLinuxfsfileOwnerUserId
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.sys.src.fstest: listDirAlloc returns owned entr...fsfreeEntries
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallstest sourcelib.sys.src.fstest: listDirAlloc returns owned entr...fs.Entrydeinitprivate sourcelib.sys.src.fsentryKindfslistDirAlloc
Static calls · unresolved targets: 3 · external targets: 5.
Called byCallsNo direct callsprivate sourcelib.sys.src.pulseloadCookiefsopenAbsoluteFile
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsprivate sourcelib.sys.src.fsexpectRegularOpenRejectedtest sourcelib.sys.src.fstest: regular file opener returns des...fsopenRegularFile
Static calls · unresolved targets: 1 · external targets: 1.
Called byCallsNo direct callstest sourcelib.sys.src.fstest: appendFileSync appends chunks a...test sourcelib.sys.src.fstest: appendFile appends chunks to cw...test sourcelib.sys.src.fstest: rename replaces cwd destinationtest sourcelib.sys.src.fstest: writeFile and readFileAlloc rou...fsreadFileAlloc
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsprivate sourcelib.sys.src.pulseloadCookieprivate sourcelib.sys.src.x11.authreadAuthorityFilefsreadHandle
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.sys.src.fstest: Journal data sync persists desc...test sourcelib.sys.src.fstest: handle helpers write, read posi...fsreadHandleAt
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callstest sourcelib.sys.src.fstest: handle helpers write, read posi...fsreadHandleToEndAlloc
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallsNo direct callersprivate sourcelib.sys.src.linuxerrnofsremoveWatch
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callstest sourcelib.sys.src.fstest: rename replaces cwd destinationprivate sourcelib.tldr.src.profiling.collect.sources.lua.stubswriteLuaStubsfsrename
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsfssealFilefsrequireImmutableFile
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallsNo direct callersfsrequireImmutableFilefssealFile
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallsNo direct callsfsexistsfsstatFile
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.sys.src.fstest: Journal data sync persists desc...fssyncData
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.sys.src.fstest: syncFilesystem flushes the file...private sourcelib.sys.src.fssyncDarwinFilesystemfssyncFilesystem
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallsNo direct callersprivate sourcelib.sys.src.fstruncateDescriptorWithfstruncateDescriptor
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.sys.src.fstest: absolute path helpers access cr...test sourcelib.sys.src.fstest: deleteTree removes cwd director...test sourcelib.sys.src.fstest: listDirAlloc returns owned entr...test sourcelib.sys.src.fstest: rename replaces cwd destinationtest sourcelib.sys.src.fstest: writeFile and readFileAlloc rou...fswriteFile
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.sys.src.fstest: allocated blocks report support...test sourcelib.sys.src.fstest: handle helpers write, read posi...test sourcelib.sys.src.x11.authtest: authority file read accepts exa...fswriteHandleAll
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callstest sourcelib.sys.src.fstest: Journal data sync persists desc...fswriteHandleAt
Static calls · unresolved targets: 0 · external targets: 1.

Source: lib/sys/src/fs.zig

zig
const std = @import("std");const builtin = @import("builtin");const capabilities = @import("capabilities.zig");const fd = @import("fd.zig");const debug_io = std.Options.debug_io;const linux = std.os.linux;const native_os = builtin.os.tag;const posix = std.posix;pub const required_capabilities = capabilities.host(&.{.filesystem});pub const Dir = std.Io.Dir;pub const CwdError = std.process.CurrentPathAllocError;pub const ReadFileError = std.Io.Dir.ReadFileAllocError;pub const WriteFileError = std.Io.Dir.WriteFileError;pub const AppendFileError = std.Io.File.OpenError || std.Io.File.StatError || std.Io.File.Writer.SeekError || std.Io.Writer.Error;pub const AppendFileSyncError = AppendFileError || std.Io.File.SyncError;pub const SyncFilesystemError = std.Io.File.SyncError;pub const ExistsError = std.Io.Dir.StatFileError;pub const AccessOptions = std.Io.Dir.AccessOptions;pub const AccessError = std.Io.Dir.AccessError;pub const OpenFileError = std.Io.File.OpenError;pub const OpenFileOptions = std.Io.Dir.OpenFileOptions;pub const OpenRegularFileError = std.posix.OpenError ||    std.Io.File.StatError ||    error{ UnsupportedPlatform, NotRegularFile };pub const OpenDirError = std.Io.Dir.OpenError;pub const OpenDirOptions = std.Io.Dir.OpenOptions;pub const ReadHandleError = std.posix.ReadError;pub const CreateFileOptions = std.Io.Dir.CreateFileOptions;pub const CreateDirPathError = std.Io.Dir.CreateDirPathError;pub const DeleteFileError = std.Io.Dir.DeleteFileError;pub const DeleteTreeError = std.Io.Dir.DeleteTreeError;pub const FilePermissions = std.Io.File.Permissions;pub const SetFilePermissionsOptions = std.Io.Dir.SetFilePermissionsOptions;pub const SetFilePermissionsError = std.Io.Dir.SetFilePermissionsError;pub const RenameError = std.Io.Dir.RenameError;pub const ExchangeError = error{    FileNotFound,    AccessDenied,    ExchangeUnsupported,} || posix.UnexpectedError;pub const RealPathError = std.Io.Dir.RealPathFileAllocError;pub const ListDirError = std.Io.Dir.OpenError || std.Io.Dir.Iterator.Error || std.mem.Allocator.Error;pub const FileOwnerUserId = linux.uid_t;pub const FileMode = posix.mode_t;pub const WatchEvent = linux.inotify_event;pub const NamedPipeError = error{    UnsupportedPlatform,    AccessDenied,    CreateFailed,};pub const AnonymousFileError = error{    UnsupportedPlatform,    OutOfMemory,    CreateFailed,};pub const TruncateError = error{    UnsupportedPlatform,    OutOfMemory,    TruncateFailed,};pub const WatchError = error{    UnsupportedPlatform,    WatchFailed,};pub const WatchMask = struct {    pub const close_write = linux.IN.CLOSE_WRITE;    pub const create = linux.IN.CREATE;    pub const delete = linux.IN.DELETE;    pub const delete_self = linux.IN.DELETE_SELF;    pub const ignored = linux.IN.IGNORED;    pub const moved_from = linux.IN.MOVED_FROM;    pub const moved_to = linux.IN.MOVED_TO;    pub const move_self = linux.IN.MOVE_SELF;    pub const queue_overflow = linux.IN.Q_OVERFLOW;    pub const unmount = linux.IN.UNMOUNT;};pub const FileOwnerPolicy = enum {    unsupported,    linux_statx,};pub const AllocatedBlocksUnsupported = enum {    platform,    statx_unavailable,};pub const AllocatedBlocks = union(enum) {    supported: u64,    unsupported: AllocatedBlocksUnsupported,};pub const FileOwnerError = error{    UnsupportedPlatform,    BadPathName,    NameTooLong,    AccessDenied,    FileNotFound,    NotDir,    SymLinkLoop,    SystemResources,    OwnerUnavailable,};pub const EntryKind = enum {    file,    directory,    sym_link,    other,};pub const Entry = struct {    name: []u8,    kind: EntryKind,    path: []u8,    pub fn deinit(self: Entry, allocator: std.mem.Allocator) void {        allocator.free(self.name);        allocator.free(self.path);    }};pub const OpenedRegularFile = struct {    file: std.Io.File,    stat: std.Io.File.Stat,};pub fn debugIo() std.Io {    return debug_io;}pub fn cwd() Dir {    return Dir.cwd();}pub fn cwdAlloc(allocator: std.mem.Allocator) CwdError![]u8 {    const path_z = try std.process.currentPathAlloc(debug_io, allocator);    defer allocator.free(path_z);    return try allocator.dupe(u8, path_z);}pub fn setCreationMask(mask: FileMode) error{UnsupportedPlatform}!FileMode {    if (comptime native_os != .linux) return error.UnsupportedPlatform;    return @intCast(linux.syscall1(.umask, mask));}pub fn createNamedPipe(    directory: Dir,    name: [:0]const u8,    mode: FileMode,) NamedPipeError!void {    const result = switch (native_os) {        .linux => linux.mknodat(directory.handle, name.ptr, linux.S.IFIFO | mode, 0),        .macos => darwin.mkfifoat(directory.handle, name.ptr, mode),        else => return error.UnsupportedPlatform,    };    return switch (posix.errno(result)) {        .SUCCESS => {},        .ACCES, .PERM => error.AccessDenied,        else => error.CreateFailed,    };}pub fn createAnonymousFile(name: []const u8) AnonymousFileError!fd.Descriptor {    if (comptime native_os != .linux) return error.UnsupportedPlatform;    return posix.memfd_create(name, posix.MFD.CLOEXEC) catch |err| switch (err) {        error.OutOfMemory => error.OutOfMemory,        else => error.CreateFailed,    };}/// Creates a Linux memory file that allows seals and carries none yet, for a/// caller that will later seal the file because sealing has to be allowed at/// creation. Bytes go in before the seals, because the immutable check requires/// the seals to be present. The descriptor is close-on-exec, and the caller/// closes it, while a host other than Linux returns `UnsupportedPlatform`.pub fn createSealableFile(name: []const u8) AnonymousFileError!fd.Descriptor {    if (comptime native_os != .linux) return error.UnsupportedPlatform;    return posix.memfd_create(name, posix.MFD.CLOEXEC | posix.MFD.ALLOW_SEALING) catch |err|        switch (err) {            error.OutOfMemory => error.OutOfMemory,            else => error.CreateFailed,        };}/// Seals a populated file so that every later mapping of it sees the same/// bytes, adding the write, shrink, and grow seals, which stop mutation of the/// file through any descriptor. The seals are read back before the call/// returns, so a return means they are in place, while every failure, including/// a host other than Linux, reports `UnsupportedImageBacking`.pub fn sealFile(descriptor: fd.Descriptor) error{UnsupportedImageBacking}!void {    if (comptime native_os != .linux) return error.UnsupportedImageBacking;    const seals = linux.F.SEAL_WRITE | linux.F.SEAL_SHRINK | linux.F.SEAL_GROW;    if (posix.errno(linux.fcntl(descriptor, linux.F.ADD_SEALS, seals)) != .SUCCESS) {        return error.UnsupportedImageBacking;    }    try requireImmutableFile(descriptor);}/// Admits a descriptor for an immutable mapping only when the Linux write,/// shrink, and grow seals are all present, so a mutable ordinary file returns/// `UnsupportedImageBacking`. Read-only permissions, a matching digest, and a/// private mapping do not qualify a file on their own.pub fn requireImmutableFile(descriptor: fd.Descriptor) error{UnsupportedImageBacking}!void {    if (comptime native_os != .linux) return error.UnsupportedImageBacking;    const required = linux.F.SEAL_WRITE | linux.F.SEAL_SHRINK | linux.F.SEAL_GROW;    const actual = linux.fcntl(descriptor, linux.F.GET_SEALS, 0);    if (posix.errno(actual) != .SUCCESS or actual & required != required) {        return error.UnsupportedImageBacking;    }}pub fn truncateDescriptor(    descriptor: fd.Descriptor,    byte_len: usize,) TruncateError!void {    switch (comptime native_os) {        .linux => {            var operation: LinuxTruncateOperation = .{};            return truncateDescriptorWith(&operation, descriptor, byte_len);        },        .macos => {            var operation: DarwinTruncateOperation = .{};            return truncateDescriptorWith(&operation, descriptor, byte_len);        },        else => return error.UnsupportedPlatform,    }}pub fn createWatch() WatchError!fd.Descriptor {    if (comptime native_os != .linux) return error.UnsupportedPlatform;    const result = linux.inotify_init1(linux.IN.CLOEXEC | linux.IN.NONBLOCK);    return switch (linux.errno(result)) {        .SUCCESS => @intCast(result),        else => error.WatchFailed,    };}pub fn addWatch(    descriptor: fd.Descriptor,    path: [:0]const u8,    mask: u32,) WatchError!i32 {    if (comptime native_os != .linux) return error.UnsupportedPlatform;    const result = linux.inotify_add_watch(descriptor, path.ptr, mask);    return switch (linux.errno(result)) {        .SUCCESS => @intCast(result),        else => error.WatchFailed,    };}pub fn removeWatch(descriptor: fd.Descriptor, watch: i32) WatchError!void {    if (comptime native_os != .linux) return error.UnsupportedPlatform;    return switch (linux.errno(linux.inotify_rm_watch(descriptor, watch))) {        .SUCCESS => {},        else => error.WatchFailed,    };}pub fn readFileAlloc(    allocator: std.mem.Allocator,    path: []const u8,    limit: usize,) ReadFileError![]u8 {    return std.Io.Dir.cwd().readFileAlloc(debug_io, path, allocator, .limited(limit));}pub fn writeFile(path: []const u8, contents: []const u8) WriteFileError!void {    try std.Io.Dir.cwd().writeFile(debug_io, .{        .sub_path = path,        .data = contents,        .flags = .{ .truncate = true },    });}pub fn createFile(path: []const u8, options: CreateFileOptions) OpenFileError!std.Io.File {    return try std.Io.Dir.cwd().createFile(debug_io, path, options);}pub fn openAbsoluteFile(path: []const u8, options: OpenFileOptions) OpenFileError!std.Io.File {    return try std.Io.Dir.openFileAbsolute(debug_io, path, options);}pub fn openAbsoluteDir(path: []const u8, options: OpenDirOptions) OpenDirError!Dir {    return try std.Io.Dir.openDirAbsolute(debug_io, path, options);}pub fn openRegularFile(    io: std.Io,    directory: Dir,    path: []const u8,) OpenRegularFileError!OpenedRegularFile {    if (comptime native_os != .linux and native_os != .macos) {        return error.UnsupportedPlatform;    }    const descriptor = std.posix.openat(directory.handle, path, .{        .ACCMODE = .RDONLY,        .NONBLOCK = true,        .CLOEXEC = true,        .NOFOLLOW = true,    }, 0) catch |err| switch (err) {        error.SymLinkLoop => return error.NotRegularFile,        else => |other| return other,    };    var file = std.Io.File{        .handle = descriptor,        .flags = .{ .nonblocking = true },    };    errdefer file.close(io);    const stat = file.stat(io) catch |err| switch (err) {        error.Streaming => return error.NotRegularFile,        else => |other| return other,    };    if (stat.kind != .file) return error.NotRegularFile;    return .{ .file = file, .stat = stat };}pub fn readHandle(file: std.Io.File, buffer: []u8) ReadHandleError!usize {    return try std.posix.read(file.handle, buffer);}pub fn readHandleAt(file: std.Io.File, buffer: []u8, offset: u64) !usize {    return file.readPositionalAll(debug_io, buffer, offset);}pub fn readHandleToEndAlloc(allocator: std.mem.Allocator, file: std.Io.File, limit: usize) ![]u8 {    var buffer: [4096]u8 = undefined;    var reader = file.reader(debug_io, &buffer);    return reader.interface.allocRemaining(allocator, .limited(limit));}pub fn writeHandleAll(file: std.Io.File, bytes: []const u8) !void {    try file.writeStreamingAll(debug_io, bytes);}pub fn writeHandleAt(file: std.Io.File, bytes: []const u8, offset: u64) !void {    try file.writePositionalAll(debug_io, bytes, offset);}pub fn closeHandle(file: std.Io.File) void {    file.close(debug_io);}/// Flushes the open file's dirty data pages to the storage device before a/// caller reports written records durable, so that the records can be found/// again after a crash. Surviving a power loss still depends on the device's/// own caches and on its support for the flush command, so a return carries no/// unconditional hardware guarantee. On Linux the call is `fdatasync`, which/// leaves unchanged metadata alone, while a host other than Linux returns/// `error.Unexpected`.pub fn syncData(file: std.Io.File) std.posix.SyncError!void {    if (comptime builtin.os.tag == .linux) return std.posix.fdatasync(file.handle);    return error.Unexpected;}test "Journal data sync persists descriptor writes" {    if (comptime builtin.os.tag != .linux) return error.SkipZigTest;    var tmp = std.testing.tmpDir(.{});    defer tmp.cleanup();    const file = try tmp.dir.createFile(debug_io, "journal", .{ .read = true });    defer file.close(debug_io);    try writeHandleAt(file, "selected Journal bytes", 0);    try syncData(file);    const reopened = try tmp.dir.openFile(debug_io, "journal", .{});    defer reopened.close(debug_io);    var bytes: [22]u8 = undefined;    const count = try readHandleAt(reopened, &bytes, 0);    try std.testing.expectEqualStrings("selected Journal bytes", bytes[0..count]);}pub fn syncFilesystem(file: std.Io.File) SyncFilesystemError!void {    if (comptime builtin.os.tag == .linux) return std.posix.syncfs(file.handle);    if (comptime builtin.os.tag.isDarwin()) return syncDarwinFilesystem(file);    if (comptime builtin.os.tag == .windows) return;    return file.sync(debug_io);}fn syncDarwinFilesystem(file: std.Io.File) SyncFilesystemError!void {    while (true) switch (@as(std.posix.E, @fromBackingInt(@intCast(darwin.fsync_volume_np(        file.handle,        darwin.sync_volume_wait,    ))))) {        .SUCCESS => return,        .INTR => {},        .BADF, .INVAL, .ROFS => unreachable,        .IO => return error.InputOutput,        .NOSPC => return error.NoSpaceLeft,        .DQUOT => return error.DiskQuota,        .ACCES, .PERM => return error.AccessDenied,        else => |err| return std.posix.unexpectedErrno(err),    };}const darwin = struct {    const sync_volume_wait = 0x02;    extern "c" fn fsync_volume_np(fd: std.posix.fd_t, flags: c_int) c_int;    extern "c" fn ftruncate(fd: std.posix.fd_t, length: std.posix.off_t) c_int;    extern "c" fn mkfifoat(        fd: std.posix.fd_t,        path: [*:0]const u8,        mode: std.posix.mode_t,    ) c_int;};pub fn appendFile(path: []const u8, chunks: []const []const u8) AppendFileError!void {    var file = try std.Io.Dir.cwd().createFile(debug_io, path, .{        .truncate = false,        .read = false,    });    defer file.close(debug_io);    const stat = try file.stat(debug_io);    var write_buffer: [1024]u8 = undefined;    var writer = file.writer(debug_io, &write_buffer);    try writer.seekTo(stat.size);    for (chunks) |chunk| try writer.interface.writeAll(chunk);    try writer.interface.flush();}pub fn appendFileSync(path: []const u8, chunks: []const []const u8) AppendFileSyncError!void {    var file = try std.Io.Dir.cwd().createFile(debug_io, path, .{        .truncate = false,        .read = false,    });    defer file.close(debug_io);    const stat = try file.stat(debug_io);    var write_buffer: [1024]u8 = undefined;    var writer = file.writer(debug_io, &write_buffer);    try writer.seekTo(stat.size);    for (chunks) |chunk| try writer.interface.writeAll(chunk);    try writer.interface.flush();    try file.sync(debug_io);}pub fn exists(path: []const u8) bool {    _ = statFile(path) catch return false;    return true;}pub fn accessAbsolute(path: []const u8, options: AccessOptions) AccessError!void {    try std.Io.Dir.accessAbsolute(debug_io, path, options);}pub fn absolutePathExists(path: []const u8) bool {    accessAbsolute(path, .{}) catch return false;    return true;}pub fn statFile(path: []const u8) ExistsError!std.Io.Dir.Stat {    return std.Io.Dir.cwd().statFile(debug_io, path, .{});}pub fn allocatedBlocks(file: std.Io.File) AllocatedBlocks {    return switch (comptime native_os) {        .linux => allocatedBlocksLinux(file),        else => .{ .unsupported = .platform },    };}fn allocatedBlocksLinux(file: std.Io.File) AllocatedBlocks {    while (true) {        var statx = std.mem.zeroes(linux.Statx);        const rc = linux.statx(            file.handle,            "",            linux.AT.EMPTY_PATH,            .{ .BLOCKS = true },            &statx,        );        switch (linux.errno(rc)) {            .SUCCESS => return if (statx.mask.BLOCKS)                .{ .supported = statx.blocks }            else                .{ .unsupported = .statx_unavailable },            .INTR => {},            .BADF => unreachable,            else => return .{ .unsupported = .statx_unavailable },        }    }}pub fn fileOwnerPolicy() FileOwnerPolicy {    return switch (native_os) {        .linux => .linux_statx,        else => .unsupported,    };}pub fn fileOwnerUserId(    path: []const u8,) FileOwnerError!FileOwnerUserId {    return switch (comptime fileOwnerPolicy()) {        .unsupported => error.UnsupportedPlatform,        .linux_statx => fileOwnerUserIdLinux(path),    };}fn fileOwnerUserIdLinux(    path: []const u8,) FileOwnerError!FileOwnerUserId {    if (comptime native_os != .linux) {        return error.UnsupportedPlatform;    }    if (std.mem.indexOfScalar(u8, path, 0) != null) {        return error.BadPathName;    }    var path_buffer: [std.posix.PATH_MAX]u8 =        undefined;    if (path.len >= path_buffer.len) {        return error.NameTooLong;    }    @memcpy(path_buffer[0..path.len], path);    path_buffer[path.len] = 0;    const path_z = path_buffer[0..path.len :0];    while (true) {        var statx = std.mem.zeroes(linux.Statx);        const rc = linux.statx(            linux.AT.FDCWD,            path_z,            linux.AT.NO_AUTOMOUNT,            .{ .UID = true },            &statx,        );        switch (linux.errno(rc)) {            .SUCCESS => {                if (!statx.mask.UID) {                    return error.OwnerUnavailable;                }                return statx.uid;            },            .INTR => {},            .ACCES => return error.AccessDenied,            .LOOP => return error.SymLinkLoop,            .NAMETOOLONG => return error.NameTooLong,            .NOENT => return error.FileNotFound,            .NOTDIR => return error.NotDir,            .NOMEM => return error.SystemResources,            else => return error.OwnerUnavailable,        }    }}pub fn absoluteFileExists(path: []const u8) OpenFileError!bool {    var file = std.Io.Dir.openFileAbsolute(debug_io, path, .{}) catch |err| switch (err) {        error.FileNotFound => return false,        else => return err,    };    defer file.close(debug_io);    return true;}pub fn createDirPath(path: []const u8) CreateDirPathError!void {    try std.Io.Dir.cwd().createDirPath(debug_io, path);}pub fn createAbsoluteDirPath(path: []const u8) CreateDirPathError!void {    std.debug.assert(std.fs.path.isAbsolute(path));    try createDirPath(path);}pub fn deleteFile(path: []const u8) DeleteFileError!void {    try std.Io.Dir.cwd().deleteFile(debug_io, path);}pub fn deleteAbsoluteFile(path: []const u8) DeleteFileError!void {    try std.Io.Dir.deleteFileAbsolute(debug_io, path);}pub fn deleteTree(path: []const u8) DeleteTreeError!void {    try std.Io.Dir.cwd().deleteTree(debug_io, path);}pub fn setFilePermissions(    path: []const u8,    permissions: FilePermissions,    options: SetFilePermissionsOptions,) SetFilePermissionsError!void {    try std.Io.Dir.cwd().setFilePermissions(debug_io, path, permissions, options);}pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void {    try std.Io.Dir.cwd().rename(old_path, std.Io.Dir.cwd(), new_path, debug_io);}/// Swaps two entries of one directory in a single atomic rename, so every/// observer sees either both old names or both new names. Linux provides it/// through renameat2 RENAME_EXCHANGE. A kernel or filesystem without it/// refuses with ExchangeUnsupported.pub fn exchange(directory: Dir, first: [:0]const u8, second: [:0]const u8) ExchangeError!void {    if (comptime native_os != .linux) return error.ExchangeUnsupported;    const result = linux.renameat2(directory.handle, first, directory.handle, second, .{ .EXCHANGE = true });    switch (linux.errno(result)) {        .SUCCESS => {},        .NOENT => return error.FileNotFound,        .ACCES, .PERM => return error.AccessDenied,        .INVAL, .NOSYS, .OPNOTSUPP => return error.ExchangeUnsupported,        else => |code| return posix.unexpectedErrno(code),    }}test "exchange swaps a file and a directory in one rename" {    if (comptime native_os != .linux) return error.SkipZigTest;    var tmp = std.testing.tmpDir(.{});    defer tmp.cleanup();    try tmp.dir.writeFile(debug_io, .{ .sub_path = "first", .data = "first bytes" });    try tmp.dir.createDir(debug_io, "second", .fromMode(0o700));    try exchange(tmp.dir, "first", "second");    try std.testing.expectEqual(.directory, (try tmp.dir.statFile(debug_io, "first", .{})).kind);    var bytes: [16]u8 = undefined;    const contents = try tmp.dir.readFile(debug_io, "second", &bytes);    try std.testing.expectEqualStrings("first bytes", contents);    try std.testing.expectError(error.FileNotFound, exchange(tmp.dir, "first", "missing"));}pub fn realPathAlloc(allocator: std.mem.Allocator, path: []const u8) RealPathError![]u8 {    const path_z = try std.Io.Dir.cwd().realPathFileAlloc(debug_io, path, allocator);    defer allocator.free(path_z);    return try allocator.dupe(u8, path_z);}pub fn listDirAlloc(allocator: std.mem.Allocator, path: []const u8) ListDirError![]Entry {    var handle = try std.Io.Dir.cwd().openDir(debug_io, path, .{ .iterate = true });    defer handle.close(debug_io);    var entries: std.ArrayListUnmanaged(Entry) = .empty;    errdefer {        for (entries.items) |entry| entry.deinit(allocator);        entries.deinit(allocator);    }    var iterator = handle.iterate();    while (try iterator.next(debug_io)) |entry| {        const entry_path = try std.fs.path.join(allocator, &.{ path, entry.name });        const entry_name = try allocator.dupe(u8, entry.name);        var appended = false;        errdefer if (!appended) {            allocator.free(entry_path);            allocator.free(entry_name);        };        try entries.append(allocator, .{            .name = entry_name,            .kind = entryKind(entry.kind),            .path = entry_path,        });        appended = true;    }    return try entries.toOwnedSlice(allocator);}pub fn freeEntries(allocator: std.mem.Allocator, entries: []Entry) void {    for (entries) |entry| entry.deinit(allocator);    allocator.free(entries);}const TruncateStatus = enum {    success,    interrupted,    out_of_memory,    failed,};const LinuxTruncateOperation = struct {    fn run(        _: *@This(),        descriptor: fd.Descriptor,        byte_len: usize,    ) TruncateStatus {        return switch (linux.errno(linux.ftruncate(descriptor, @intCast(byte_len)))) {            .SUCCESS => .success,            .INTR => .interrupted,            .NOMEM => .out_of_memory,            else => .failed,        };    }};const DarwinTruncateOperation = struct {    fn run(        _: *@This(),        descriptor: fd.Descriptor,        byte_len: usize,    ) TruncateStatus {        return switch (posix.errno(darwin.ftruncate(descriptor, @intCast(byte_len)))) {            .SUCCESS => .success,            .INTR => .interrupted,            .NOMEM => .out_of_memory,            else => .failed,        };    }};fn truncateDescriptorWith(    operation: anytype,    descriptor: fd.Descriptor,    byte_len: usize,) TruncateError!void {    while (true) {        switch (operation.run(descriptor, byte_len)) {            .success => return,            .interrupted => continue,            .out_of_memory => return error.OutOfMemory,            .failed => return error.TruncateFailed,        }    }}fn entryKind(kind: std.Io.File.Kind) EntryKind {    return switch (kind) {        .file => .file,        .directory => .directory,        .sym_link => .sym_link,        else => .other,    };}const regular_open_input: [:0]const u8 = ".tiny-regular-open-input";const regular_open_ready: [:0]const u8 = ".tiny-regular-open-ready";const regular_open_go: [:0]const u8 = ".tiny-regular-open-go";const handshake_attempts_max: usize = 500;const handshake_wait_ms: u64 = 10;fn supportsRegularFileOpen() bool {    return native_os == .linux or native_os == .macos;}fn createNamedPipeForTest(    directory: Dir,    name: [:0]const u8,) !void {    createNamedPipe(directory, name, 0o600) catch |err| switch (err) {        error.UnsupportedPlatform, error.AccessDenied => return error.SkipZigTest,        error.CreateFailed => return error.CreateNamedPipeFailed,    };}const InterruptingTruncateOperation = struct {    attempts: usize = 0,    fn run(self: *@This(), _: fd.Descriptor, _: usize) TruncateStatus {        self.attempts += 1;        return if (self.attempts == 1) .interrupted else .success;    }};const FixedTruncateOperation = struct {    status: TruncateStatus,    attempts: usize = 0,    fn run(self: *@This(), _: fd.Descriptor, _: usize) TruncateStatus {        self.attempts += 1;        return self.status;    }};test "descriptor truncate accepts success" {    var operation: FixedTruncateOperation = .{ .status = .success };    try truncateDescriptorWith(&operation, 7, 4096);    try std.testing.expectEqual(@as(usize, 1), operation.attempts);}test "descriptor truncate retries interruptions" {    var operation: InterruptingTruncateOperation = .{};    try truncateDescriptorWith(&operation, 7, 4096);    try std.testing.expectEqual(@as(usize, 2), operation.attempts);}test "descriptor truncate maps operation errors" {    var exhausted: FixedTruncateOperation = .{ .status = .out_of_memory };    try std.testing.expectError(        error.OutOfMemory,        truncateDescriptorWith(&exhausted, 7, 4096),    );    try std.testing.expectEqual(@as(usize, 1), exhausted.attempts);    var failed: FixedTruncateOperation = .{ .status = .failed };    try std.testing.expectError(        error.TruncateFailed,        truncateDescriptorWith(&failed, 7, 4096),    );    try std.testing.expectEqual(@as(usize, 1), failed.attempts);}fn openNamedPipeGuardForTest(    directory: Dir,    name: [:0]const u8,) !std.Io.File {    const descriptor = try std.posix.openat(directory.handle, name, .{        .ACCMODE = .RDWR,        .NONBLOCK = true,        .CLOEXEC = true,        .NOFOLLOW = true,    }, 0);    return .{        .handle = descriptor,        .flags = .{ .nonblocking = true },    };}fn expectRegularOpenRejected(directory: Dir, name: []const u8) !void {    var opened = openRegularFile(debug_io, directory, name) catch |err| {        if (err != error.NotRegularFile) return err;        return;    };    defer opened.file.close(debug_io);    return error.ExpectedRegularFileRejection;}fn expectRegularOpenFlags(file: std.Io.File) !void {    const descriptor_flags = std.posix.system.fcntl(        file.handle,        std.posix.F.GETFD,        @as(usize, 0),    );    try std.testing.expectEqual(        std.posix.E.SUCCESS,        std.posix.errno(descriptor_flags),    );    const descriptor_bits: usize = @intCast(descriptor_flags);    try std.testing.expect(        descriptor_bits & @as(usize, std.posix.FD_CLOEXEC) != 0,    );    const status_flags = std.posix.system.fcntl(        file.handle,        std.posix.F.GETFL,        @as(usize, 0),    );    try std.testing.expectEqual(        std.posix.E.SUCCESS,        std.posix.errno(status_flags),    );    const status_bits: usize = @intCast(status_flags);    const nonblocking: u32 = @bitCast(std.posix.O{ .NONBLOCK = true });    try std.testing.expect(status_bits & nonblocking != 0);}fn waitForTestEntry(directory: Dir, name: []const u8) !void {    const time = @import("time.zig");    for (0..handshake_attempts_max) |_| {        if (directory.statFile(            debug_io,            name,            .{ .follow_symlinks = false },        )) |_| {            return;        } else |err| switch (err) {            error.FileNotFound => time.sleepMilliseconds(handshake_wait_ms),            else => return err,        }    }    return error.TestHandshakeTimedOut;}fn waitForReplacementChild(child: *@import("process/root.zig").Child) !void {    const process = @import("process/root.zig");    const time = @import("time.zig");    const child_id = child.id orelse return error.ExpectedChildProcess;    for (0..handshake_attempts_max) |_| {        if (try process.waitNoHang(child_id)) |outcome| {            child.id = null;            if (process.exitCode(outcome.term) != 0) {                return error.ReplacementChildFailed;            }            return;        }        time.sleepMilliseconds(handshake_wait_ms);    }    return error.ReplacementChildTimedOut;}test "regular file opener returns descriptor-bound read-only bytes" {    if (!supportsRegularFileOpen()) return error.SkipZigTest;    var temporary = std.testing.tmpDir(.{});    defer temporary.cleanup();    try temporary.dir.writeFile(debug_io, .{        .sub_path = "read-only.txt",        .data = "descriptor bytes",    });    try temporary.dir.setFilePermissions(        debug_io,        "read-only.txt",        .fromMode(0o400),        .{},    );    var opened = try openRegularFile(        debug_io,        temporary.dir,        "read-only.txt",    );    defer opened.file.close(debug_io);    try std.testing.expectEqual(std.Io.File.Kind.file, opened.stat.kind);    try std.testing.expect(opened.file.flags.nonblocking);    try expectRegularOpenFlags(opened.file);    var reader = opened.file.reader(debug_io, &.{});    const bytes = try reader.interface.allocRemaining(        std.testing.allocator,        .limited(32),    );    defer std.testing.allocator.free(bytes);    try std.testing.expectEqualStrings("descriptor bytes", bytes);}test "regular file opener rejects final symlinks" {    if (!supportsRegularFileOpen()) return error.SkipZigTest;    var temporary = std.testing.tmpDir(.{});    defer temporary.cleanup();    try temporary.dir.writeFile(debug_io, .{        .sub_path = "target.txt",        .data = "target",    });    temporary.dir.symLink(        debug_io,        "target.txt",        "link.txt",        .{},    ) catch |err| switch (err) {        error.AccessDenied, error.PermissionDenied, error.FileSystem => {            return error.SkipZigTest;        },        else => return err,    };    try expectRegularOpenRejected(temporary.dir, "link.txt");}test "regular file opener rejects named pipes" {    if (!supportsRegularFileOpen()) return error.SkipZigTest;    var temporary = std.testing.tmpDir(.{});    defer temporary.cleanup();    try createNamedPipeForTest(temporary.dir, "named-pipe");    var guard = try openNamedPipeGuardForTest(        temporary.dir,        "named-pipe",    );    defer guard.close(debug_io);    try expectRegularOpenRejected(temporary.dir, "named-pipe");}test "regular file opener rejects replacement without waiting" {    if (!supportsRegularFileOpen()) return error.SkipZigTest;    const process = @import("process/root.zig");    var io_state = std.Io.Threaded.init(std.testing.allocator, .{});    defer io_state.deinit();    const process_io = io_state.io();    var temporary = std.testing.tmpDir(.{});    defer temporary.cleanup();    try temporary.dir.writeFile(debug_io, .{        .sub_path = regular_open_input,        .data = "regular",    });    const root = try temporary.dir.realPathFileAlloc(        debug_io,        ".",        std.testing.allocator,    );    defer std.testing.allocator.free(root);    const child_path = try std.Io.Dir.cwd().realPathFileAlloc(        debug_io,        @import("fs_test_options").regular_open_child_path,        std.testing.allocator,    );    defer std.testing.allocator.free(child_path);    var child = try process.spawn(process_io, .{        .argv = &.{            child_path,            regular_open_input,            regular_open_ready,            regular_open_go,        },        .cwd = .{ .path = root },        .stdin = .ignore,        .stdout = .ignore,        .stderr = .inherit,    });    defer process.killAndReap(&child, process_io);    try waitForTestEntry(temporary.dir, regular_open_ready);    try temporary.dir.deleteFile(debug_io, regular_open_input);    try createNamedPipeForTest(temporary.dir, regular_open_input);    try temporary.dir.writeFile(debug_io, .{        .sub_path = regular_open_go,        .data = "",    });    try waitForReplacementChild(&child);}test "writeFile and readFileAlloc round-trip through cwd" {    var tmp = std.testing.tmpDir(.{});    defer tmp.cleanup();    const allocator = std.testing.allocator;    const tmp_root = try tmp.dir.realPathFileAlloc(debug_io, ".", allocator);    defer allocator.free(tmp_root);    const path = try std.fs.path.join(allocator, &.{ tmp_root, "round-trip.txt" });    defer allocator.free(path);    try writeFile(path, "hello");    try std.testing.expect(exists(path));    try std.testing.expect(try absoluteFileExists(path));    const contents = try readFileAlloc(allocator, path, 1024);    defer allocator.free(contents);    try std.testing.expectEqualStrings("hello", contents);}test "cwd handle is available through sys fs" {    _ = cwd();    _ = debugIo();}test "file owner policy is explicit" {    const expected: FileOwnerPolicy = switch (native_os) {        .linux => .linux_statx,        else => .unsupported,    };    try std.testing.expectEqual(        expected,        fileOwnerPolicy(),    );}test "file owner identity matches the effective user" {    if (comptime fileOwnerPolicy() == .unsupported) {        return error.SkipZigTest;    }    const process = @import("process/root.zig");    var tmp = std.testing.tmpDir(.{});    defer tmp.cleanup();    const allocator = std.testing.allocator;    const tmp_root = try tmp.dir.realPathFileAlloc(        debug_io,        ".",        allocator,    );    defer allocator.free(tmp_root);    try std.testing.expectEqual(        try process.effectiveUserId(),        try fileOwnerUserId(tmp_root),    );    try std.testing.expectError(        error.BadPathName,        fileOwnerUserId("invalid\x00path"),    );}test "appendFile appends chunks to cwd file" {    var tmp = std.testing.tmpDir(.{});    defer tmp.cleanup();    const allocator = std.testing.allocator;    const tmp_root = try tmp.dir.realPathFileAlloc(debug_io, ".", allocator);    defer allocator.free(tmp_root);    const path = try std.fs.path.join(allocator, &.{ tmp_root, "append.txt" });    defer allocator.free(path);    try appendFile(path, &.{ "one", "\x00" });    try appendFile(path, &.{ "two", "\x00" });    const contents = try readFileAlloc(allocator, path, 1024);    defer allocator.free(contents);    try std.testing.expectEqualStrings("one\x00two\x00", contents);}test "appendFileSync appends chunks and syncs cwd file" {    var tmp = std.testing.tmpDir(.{});    defer tmp.cleanup();    const allocator = std.testing.allocator;    const tmp_root = try tmp.dir.realPathFileAlloc(debug_io, ".", allocator);    defer allocator.free(tmp_root);    const path = try std.fs.path.join(allocator, &.{ tmp_root, "append-sync.txt" });    defer allocator.free(path);    try appendFileSync(path, &.{ "first", "\n" });    try appendFileSync(path, &.{ "second", "\n" });    const contents = try readFileAlloc(allocator, path, 1024);    defer allocator.free(contents);    try std.testing.expectEqualStrings("first\nsecond\n", contents);}test "syncFilesystem flushes the filesystem containing a live file" {    var tmp = std.testing.tmpDir(.{});    defer tmp.cleanup();    var file = try tmp.dir.createFile(debug_io, "filesystem-sync.txt", .{});    defer file.close(debug_io);    try file.writeStreamingAll(debug_io, "durable");    try syncFilesystem(file);}test "absolute path helpers access create and delete" {    var tmp = std.testing.tmpDir(.{});    defer tmp.cleanup();    const allocator = std.testing.allocator;    const tmp_root = try tmp.dir.realPathFileAlloc(debug_io, ".", allocator);    defer allocator.free(tmp_root);    const nested_dir = try std.fs.path.join(allocator, &.{ tmp_root, "nested", "child" });    defer allocator.free(nested_dir);    try createAbsoluteDirPath(nested_dir);    try accessAbsolute(nested_dir, .{});    try std.testing.expect(absolutePathExists(nested_dir));    const path = try std.fs.path.join(allocator, &.{ nested_dir, "remove.txt" });    defer allocator.free(path);    try writeFile(path, "temporary");    try std.testing.expect(absolutePathExists(path));    try deleteAbsoluteFile(path);    try std.testing.expect(!absolutePathExists(path));}test "deleteTree removes cwd directory trees" {    var tmp = std.testing.tmpDir(.{});    defer tmp.cleanup();    const allocator = std.testing.allocator;    const tmp_root = try tmp.dir.realPathFileAlloc(debug_io, ".", allocator);    defer allocator.free(tmp_root);    const nested_dir = try std.fs.path.join(allocator, &.{ tmp_root, "tree", "nested" });    defer allocator.free(nested_dir);    try createDirPath(nested_dir);    const file_path = try std.fs.path.join(allocator, &.{ nested_dir, "child.txt" });    defer allocator.free(file_path);    try writeFile(file_path, "child");    const tree_root = try std.fs.path.join(allocator, &.{ tmp_root, "tree" });    defer allocator.free(tree_root);    try deleteTree(tree_root);    try std.testing.expect(!absolutePathExists(tree_root));}test "rename replaces cwd destination" {    var tmp = std.testing.tmpDir(.{});    defer tmp.cleanup();    const allocator = std.testing.allocator;    const tmp_root = try tmp.dir.realPathFileAlloc(debug_io, ".", allocator);    defer allocator.free(tmp_root);    const source_path = try std.fs.path.join(allocator, &.{ tmp_root, "source.txt" });    defer allocator.free(source_path);    const dest_path = try std.fs.path.join(allocator, &.{ tmp_root, "dest.txt" });    defer allocator.free(dest_path);    try writeFile(source_path, "replacement");    try writeFile(dest_path, "old");    try rename(source_path, dest_path);    try std.testing.expect(!exists(source_path));    const contents = try readFileAlloc(allocator, dest_path, 1024);    defer allocator.free(contents);    try std.testing.expectEqualStrings("replacement", contents);}test "listDirAlloc returns owned entries" {    var tmp = std.testing.tmpDir(.{});    defer tmp.cleanup();    const allocator = std.testing.allocator;    const tmp_root = try tmp.dir.realPathFileAlloc(debug_io, ".", allocator);    defer allocator.free(tmp_root);    const child_dir = try std.fs.path.join(allocator, &.{ tmp_root, "child" });    defer allocator.free(child_dir);    try createDirPath(child_dir);    const child_file = try std.fs.path.join(allocator, &.{ tmp_root, "file.txt" });    defer allocator.free(child_file);    try writeFile(child_file, "x");    const entries = try listDirAlloc(allocator, tmp_root);    defer freeEntries(allocator, entries);    var saw_dir = false;    var saw_file = false;    for (entries) |entry| {        if (std.mem.eql(u8, entry.name, "child")) {            saw_dir = entry.kind == .directory;        } else if (std.mem.eql(u8, entry.name, "file.txt")) {            saw_file = entry.kind == .file;        }    }    try std.testing.expect(saw_dir);    try std.testing.expect(saw_file);}test "handle helpers write, read positionally, and read to end" {    var tmp = std.testing.tmpDir(.{});    defer tmp.cleanup();    const allocator = std.testing.allocator;    var file = try tmp.dir.createFile(debug_io, "handle.txt", .{ .read = true });    defer file.close(debug_io);    try writeHandleAll(file, "positional ");    try writeHandleAll(file, "bytes");    var window: [10]u8 = undefined;    const read_count = try readHandleAt(file, &window, 11);    try std.testing.expectEqualStrings("bytes", window[0..read_count]);    var fresh = try tmp.dir.openFile(debug_io, "handle.txt", .{});    defer fresh.close(debug_io);    const all = try readHandleToEndAlloc(allocator, fresh, 1024);    defer allocator.free(all);    try std.testing.expectEqualStrings("positional bytes", all);    var limited = try tmp.dir.openFile(debug_io, "handle.txt", .{});    defer limited.close(debug_io);    try std.testing.expectError(error.StreamTooLong, readHandleToEndAlloc(allocator, limited, 4));}test "allocated blocks report support without inferring file size" {    var tmp = std.testing.tmpDir(.{});    defer tmp.cleanup();    var file = try tmp.dir.createFile(debug_io, "blocks.bin", .{});    defer file.close(debug_io);    var bytes: [4096]u8 = @splat(0xa5);    try writeHandleAll(file, &bytes);    try file.sync(debug_io);    switch (allocatedBlocks(file)) {        .supported => |blocks| {            try std.testing.expectEqual(.linux, native_os);            try std.testing.expect(blocks > 0);        },        .unsupported => |reason| switch (native_os) {            .linux => try std.testing.expectEqual(                AllocatedBlocksUnsupported.statx_unavailable,                reason,            ),            else => try std.testing.expectEqual(                AllocatedBlocksUnsupported.platform,                reason,            ),        },    }}

Source: lib/sys/src/root.zig:32

zig
pub const fs = @import("fs.zig");

Audit

Definitions92
Public names92
Members35
Version26.7.0
Revisiondaab053ee433