zig/lib/std / fs.zig

File System.

//! File System.

AtomicFile

fs/AtomicFile.zig

The maximum length of a file path that the operating system will accept. Paths, including those returned from file system operations, may be longer than this length, but such paths cannot be successfully passed back in other file system operations. However, all path components returned by file system operations are assumed to fit into a u8 array of this length. The byte count includes room for a null sentinel byte. * On Windows, []u8 file paths are encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). * On WASI, []u8 file paths are encoded as valid UTF-8. * On other platforms, []u8 file paths are opaque sequences of bytes with no particular encoding.


const std = @import("std.zig");
const builtin = @import("builtin");
const root = @import("root");
const mem = std.mem;
const base64 = std.base64;
const crypto = std.crypto;
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const native_os = builtin.os.tag;
const posix = std.posix;
const windows = std.os.windows;

Dir

fs/Dir.zig

This represents the maximum size of a []u8 file name component that the platform's common file systems support. File name components returned by file system operations are likely to fit into a u8 array of this length, but (depending on the platform) this assumption may not hold for every configuration. The byte count does not include a null sentinel byte. On Windows, []u8 file name components are encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). On WASI, file name components are encoded as valid UTF-8. On other platforms, []u8 components are an opaque sequence of bytes with no particular encoding.


const is_darwin = native_os.isDarwin();

File

fs/File.zig

Base64 encoder, replacing the standard +/ with -_ so that it can be used in a file name on any filesystem.


pub const AtomicFile = @import("fs/AtomicFile.zig");
pub const Dir = @import("fs/Dir.zig");
pub const File = @import("fs/File.zig");

path

fs/path.zig

Base64 decoder, replacing the standard +/ with -_ so that it can be used in a file name on any filesystem.

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

has_executable_bit

Same as Dir.updateFile, except asserts that both source_path and dest_path are absolute. See Dir.updateFile for a function that operates on both absolute and relative paths. On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). On WASI, both paths should be encoded as valid UTF-8. On other platforms, both paths are an opaque sequence of bytes with no particular encoding.


pub const has_executable_bit = switch (native_os) {
    .windows, .wasi => false,
    else => true,
};

wasi

fs/wasi.zig

Same as Dir.copyFile, except asserts that both source_path and dest_path are absolute. See Dir.copyFile for a function that operates on both absolute and relative paths. On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). On WASI, both paths should be encoded as valid UTF-8. On other platforms, both paths are an opaque sequence of bytes with no particular encoding.


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

realpath

Create a new directory, based on an absolute path. Asserts that the path is absolute. See Dir.makeDir for a function that operates on both absolute and relative paths. On Windows, absolute_path should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). On WASI, absolute_path should be encoded as valid UTF-8. On other platforms, absolute_path is an opaque sequence of bytes with no particular encoding.


// TODO audit these APIs with respect to Dir and absolute paths

realpathZ

Same as makeDirAbsolute except the parameter is null-terminated.


pub const realpath = posix.realpath;
pub const realpathZ = posix.realpathZ;

realpathW

Same as makeDirAbsolute except the parameter is a null-terminated WTF-16 LE-encoded string.

pub const realpathW = posix.realpathW;

getAppDataDir

fs/get_app_data_dir.zig

Same as Dir.deleteDir except the path is absolute. On Windows, dir_path should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). On WASI, dir_path should be encoded as valid UTF-8. On other platforms, dir_path is an opaque sequence of bytes with no particular encoding.


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

GetAppDataDirError

fs/get_app_data_dir.zig

Same as deleteDirAbsolute except the path parameter is null-terminated.

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

max_path_bytes

Same as deleteDirAbsolute except the path parameter is WTF-16 and target OS is assumed Windows.


/// The maximum length of a file path that the operating system will accept.
///
/// Paths, including those returned from file system operations, may be longer
/// than this length, but such paths cannot be successfully passed back in
/// other file system operations. However, all path components returned by file
/// system operations are assumed to fit into a `u8` array of this length.
///
/// The byte count includes room for a null sentinel byte.
///
/// * On Windows, `[]u8` file paths are encoded as
///   [WTF-8](https://simonsapin.github.io/wtf-8/).
/// * On WASI, `[]u8` file paths are encoded as valid UTF-8.
/// * On other platforms, `[]u8` file paths are opaque sequences of bytes with
///   no particular encoding.
pub const max_path_bytes = switch (native_os) {
    .linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly, .haiku, .solaris, .illumos, .plan9, .emscripten, .wasi, .serenity => posix.PATH_MAX,
    // Each WTF-16LE code unit may be expanded to 3 WTF-8 bytes.
    // If it would require 4 WTF-8 bytes, then there would be a surrogate
    // pair in the WTF-16LE, and we (over)account 3 bytes for it that way.
    // +1 for the null byte at the end, which can be encoded in 1 byte.
    .windows => windows.PATH_MAX_WIDE * 3 + 1,
    else => if (@hasDecl(root, "os") and @hasDecl(root.os, "PATH_MAX"))
        root.os.PATH_MAX
    else
        @compileError("PATH_MAX not implemented for " ++ @tagName(native_os)),
};

max_name_bytes

Same as Dir.rename except the paths are absolute. On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). On WASI, both paths should be encoded as valid UTF-8. On other platforms, both paths are an opaque sequence of bytes with no particular encoding.


/// This represents the maximum size of a `[]u8` file name component that
/// the platform's common file systems support. File name components returned by file system
/// operations are likely to fit into a `u8` array of this length, but
/// (depending on the platform) this assumption may not hold for every configuration.
/// The byte count does not include a null sentinel byte.
/// On Windows, `[]u8` file name components are encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// On WASI, file name components are encoded as valid UTF-8.
/// On other platforms, `[]u8` components are an opaque sequence of bytes with no particular encoding.
pub const max_name_bytes = switch (native_os) {
    .linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly, .solaris, .illumos, .serenity => posix.NAME_MAX,
    // Haiku's NAME_MAX includes the null terminator, so subtract one.
    .haiku => posix.NAME_MAX - 1,
    // Each WTF-16LE character may be expanded to 3 WTF-8 bytes.
    // If it would require 4 WTF-8 bytes, then there would be a surrogate
    // pair in the WTF-16LE, and we (over)account 3 bytes for it that way.
    .windows => windows.NAME_MAX * 3,
    // For WASI, the MAX_NAME will depend on the host OS, so it needs to be
    // as large as the largest max_name_bytes (Windows) in order to work on any host OS.
    // TODO determine if this is a reasonable approach
    .wasi => windows.NAME_MAX * 3,
    else => if (@hasDecl(root, "os") and @hasDecl(root.os, "NAME_MAX"))
        root.os.NAME_MAX
    else
        @compileError("NAME_MAX not implemented for " ++ @tagName(native_os)),
};

base64_alphabet

Same as renameAbsolute except the path parameters are null-terminated.


pub const base64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".*;

base64_encoder

Same as renameAbsolute except the path parameters are WTF-16 and target OS is assumed Windows.


/// Base64 encoder, replacing the standard `+/` with `-_` so that it can be used in a file name on any filesystem.
pub const base64_encoder = base64.Base64Encoder.init(base64_alphabet, null);

base64_decoder

Same as Dir.rename, except new_sub_path is relative to new_dir


/// Base64 decoder, replacing the standard `+/` with `-_` so that it can be used in a file name on any filesystem.
pub const base64_decoder = base64.Base64Decoder.init(base64_alphabet, null);

updateFileAbsolute()

Same as rename except the parameters are null-terminated.


/// Same as `Dir.updateFile`, except asserts that both `source_path` and `dest_path`
/// are absolute. See `Dir.updateFile` for a function that operates on both
/// absolute and relative paths.
/// On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// On WASI, both paths should be encoded as valid UTF-8.
/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
pub fn updateFileAbsolute(
    source_path: []const u8,
    dest_path: []const u8,
    args: Dir.CopyFileOptions,
) !Dir.PrevStatus {
    assert(path.isAbsolute(source_path));
    assert(path.isAbsolute(dest_path));
    const my_cwd = cwd();
    return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, args);
}

copyFileAbsolute()

Same as rename except the parameters are WTF16LE, NT prefixed. This function is Windows-only.


/// Same as `Dir.copyFile`, except asserts that both `source_path` and `dest_path`
/// are absolute. See `Dir.copyFile` for a function that operates on both
/// absolute and relative paths.
/// On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// On WASI, both paths should be encoded as valid UTF-8.
/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
pub fn copyFileAbsolute(
    source_path: []const u8,
    dest_path: []const u8,
    args: Dir.CopyFileOptions,

makeDirAbsolute()

Returns a handle to the current working directory. It is not opened with iteration capability. Closing the returned Dir is checked illegal behavior. Iterating over the result is illegal behavior. On POSIX targets, this function is comptime-callable.

) !void {
    assert(path.isAbsolute(source_path));
    assert(path.isAbsolute(dest_path));
    const my_cwd = cwd();
    return Dir.copyFile(my_cwd, source_path, my_cwd, dest_path, args);
}

makeDirAbsoluteZ()

Opens a directory at the given path. The directory is a system resource that remains open until close is called on the result. See openDirAbsoluteZ for a function that accepts a null-terminated path. Asserts that the path parameter has no null bytes. On Windows, absolute_path should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). On WASI, absolute_path should be encoded as valid UTF-8. On other platforms, absolute_path is an opaque sequence of bytes with no particular encoding.


/// Create a new directory, based on an absolute path.
/// Asserts that the path is absolute. See `Dir.makeDir` for a function that operates
/// on both absolute and relative paths.
/// On Windows, `absolute_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// On WASI, `absolute_path` should be encoded as valid UTF-8.
/// On other platforms, `absolute_path` is an opaque sequence of bytes with no particular encoding.
pub fn makeDirAbsolute(absolute_path: []const u8) !void {
    assert(path.isAbsolute(absolute_path));
    return posix.mkdir(absolute_path, Dir.default_mode);
}

makeDirAbsoluteW()

Same as openDirAbsolute but the path parameter is null-terminated.


/// Same as `makeDirAbsolute` except the parameter is null-terminated.
pub fn makeDirAbsoluteZ(absolute_path_z: [*:0]const u8) !void {
    assert(path.isAbsoluteZ(absolute_path_z));
    return posix.mkdirZ(absolute_path_z, Dir.default_mode);
}

deleteDirAbsolute()

Same as openDirAbsolute but the path parameter is null-terminated.


/// Same as `makeDirAbsolute` except the parameter is a null-terminated WTF-16 LE-encoded string.
pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void {
    assert(path.isAbsoluteWindowsW(absolute_path_w));
    return posix.mkdirW(mem.span(absolute_path_w), Dir.default_mode);
}

deleteDirAbsoluteZ()

Opens a file for reading or writing, without attempting to create a new file, based on an absolute path. Call File.close to release the resource. Asserts that the path is absolute. See Dir.openFile for a function that operates on both absolute and relative paths. Asserts that the path parameter has no null bytes. See openFileAbsoluteZ for a function that accepts a null-terminated path. On Windows, absolute_path should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). On WASI, absolute_path should be encoded as valid UTF-8. On other platforms, absolute_path is an opaque sequence of bytes with no particular encoding.


/// Same as `Dir.deleteDir` except the path is absolute.
/// On Windows, `dir_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// On WASI, `dir_path` should be encoded as valid UTF-8.
/// On other platforms, `dir_path` is an opaque sequence of bytes with no particular encoding.
pub fn deleteDirAbsolute(dir_path: []const u8) !void {
    assert(path.isAbsolute(dir_path));
    return posix.rmdir(dir_path);
}

deleteDirAbsoluteW()

Same as openFileAbsolute but the path parameter is null-terminated.


/// Same as `deleteDirAbsolute` except the path parameter is null-terminated.
pub fn deleteDirAbsoluteZ(dir_path: [*:0]const u8) !void {
    assert(path.isAbsoluteZ(dir_path));
    return posix.rmdirZ(dir_path);
}

renameAbsolute()

Same as openFileAbsolute but the path parameter is WTF-16-encoded.


/// Same as `deleteDirAbsolute` except the path parameter is WTF-16 and target OS is assumed Windows.
pub fn deleteDirAbsoluteW(dir_path: [*:0]const u16) !void {
    assert(path.isAbsoluteWindowsW(dir_path));
    return posix.rmdirW(mem.span(dir_path));
}

renameAbsoluteZ()

Test accessing path. Be careful of Time-Of-Check-Time-Of-Use race conditions when using this function. For example, instead of testing if a file exists and then opening it, just open it and handle the error for file not found. See accessAbsoluteZ for a function that accepts a null-terminated path. On Windows, absolute_path should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). On WASI, absolute_path should be encoded as valid UTF-8. On other platforms, absolute_path is an opaque sequence of bytes with no particular encoding.


/// Same as `Dir.rename` except the paths are absolute.
/// On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// On WASI, both paths should be encoded as valid UTF-8.
/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
pub fn renameAbsolute(old_path: []const u8, new_path: []const u8) !void {
    assert(path.isAbsolute(old_path));
    assert(path.isAbsolute(new_path));
    return posix.rename(old_path, new_path);
}

renameAbsoluteW()

Same as accessAbsolute but the path parameter is null-terminated.


/// Same as `renameAbsolute` except the path parameters are null-terminated.
pub fn renameAbsoluteZ(old_path: [*:0]const u8, new_path: [*:0]const u8) !void {
    assert(path.isAbsoluteZ(old_path));
    assert(path.isAbsoluteZ(new_path));
    return posix.renameZ(old_path, new_path);
}

rename()

Same as accessAbsolute but the path parameter is WTF-16 encoded.


/// Same as `renameAbsolute` except the path parameters are WTF-16 and target OS is assumed Windows.
pub fn renameAbsoluteW(old_path: [*:0]const u16, new_path: [*:0]const u16) !void {
    assert(path.isAbsoluteWindowsW(old_path));
    assert(path.isAbsoluteWindowsW(new_path));
    return posix.renameW(old_path, new_path);
}

renameZ()

Creates, opens, or overwrites a file with write access, based on an absolute path. Call File.close to release the resource. Asserts that the path is absolute. See Dir.createFile for a function that operates on both absolute and relative paths. Asserts that the path parameter has no null bytes. See createFileAbsoluteC for a function that accepts a null-terminated path. On Windows, absolute_path should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). On WASI, absolute_path should be encoded as valid UTF-8. On other platforms, absolute_path is an opaque sequence of bytes with no particular encoding.


/// Same as `Dir.rename`, except `new_sub_path` is relative to `new_dir`
pub fn rename(old_dir: Dir, old_sub_path: []const u8, new_dir: Dir, new_sub_path: []const u8) !void {
    return posix.renameat(old_dir.fd, old_sub_path, new_dir.fd, new_sub_path);
}

renameW()

Same as createFileAbsolute but the path parameter is null-terminated.


/// Same as `rename` except the parameters are null-terminated.
pub fn renameZ(old_dir: Dir, old_sub_path_z: [*:0]const u8, new_dir: Dir, new_sub_path_z: [*:0]const u8) !void {
    return posix.renameatZ(old_dir.fd, old_sub_path_z, new_dir.fd, new_sub_path_z);
}

cwd()

Same as createFileAbsolute but the path parameter is WTF-16 encoded.


/// Same as `rename` except the parameters are WTF16LE, NT prefixed.
/// This function is Windows-only.
pub fn renameW(old_dir: Dir, old_sub_path_w: []const u16, new_dir: Dir, new_sub_path_w: []const u16) !void {
    return posix.renameatW(old_dir.fd, old_sub_path_w, new_dir.fd, new_sub_path_w, windows.TRUE);
}

defaultWasiCwd()

Delete a file name and possibly the file it refers to, based on an absolute path. Asserts that the path is absolute. See Dir.deleteFile for a function that operates on both absolute and relative paths. Asserts that the path parameter has no null bytes. On Windows, absolute_path should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). On WASI, absolute_path should be encoded as valid UTF-8. On other platforms, absolute_path is an opaque sequence of bytes with no particular encoding.


/// Returns a handle to the current working directory. It is not opened with iteration capability.
/// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior.
/// On POSIX targets, this function is comptime-callable.
pub fn cwd() Dir {
    if (native_os == .windows) {
        return .{ .fd = windows.peb().ProcessParameters.CurrentDirectory.Handle };
    } else if (native_os == .wasi) {
        return .{ .fd = std.options.wasiCwd() };
    } else {
        return .{ .fd = posix.AT.FDCWD };
    }
}

openDirAbsolute()

Same as deleteFileAbsolute except the parameter is null-terminated.


pub fn defaultWasiCwd() std.os.wasi.fd_t {
    // Expect the first preopen to be current working directory.
    return 3;
}

openDirAbsoluteZ()

Same as deleteFileAbsolute except the parameter is WTF-16 encoded.


/// Opens a directory at the given path. The directory is a system resource that remains
/// open until `close` is called on the result.
/// See `openDirAbsoluteZ` for a function that accepts a null-terminated path.
///
/// Asserts that the path parameter has no null bytes.
/// On Windows, `absolute_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// On WASI, `absolute_path` should be encoded as valid UTF-8.
/// On other platforms, `absolute_path` is an opaque sequence of bytes with no particular encoding.
pub fn openDirAbsolute(absolute_path: []const u8, flags: Dir.OpenOptions) File.OpenError!Dir {
    assert(path.isAbsolute(absolute_path));
    return cwd().openDir(absolute_path, flags);
}

openDirAbsoluteW()

Removes a symlink, file, or directory. This is equivalent to Dir.deleteTree with the base directory. Asserts that the path is absolute. See Dir.deleteTree for a function that operates on both absolute and relative paths. Asserts that the path parameter has no null bytes. On Windows, absolute_path should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). On WASI, absolute_path should be encoded as valid UTF-8. On other platforms, absolute_path is an opaque sequence of bytes with no particular encoding.


/// Same as `openDirAbsolute` but the path parameter is null-terminated.
pub fn openDirAbsoluteZ(absolute_path_c: [*:0]const u8, flags: Dir.OpenOptions) File.OpenError!Dir {
    assert(path.isAbsoluteZ(absolute_path_c));
    return cwd().openDirZ(absolute_path_c, flags);
}
/// Same as `openDirAbsolute` but the path parameter is null-terminated.
pub fn openDirAbsoluteW(absolute_path_c: [*:0]const u16, flags: Dir.OpenOptions) File.OpenError!Dir {
    assert(path.isAbsoluteWindowsW(absolute_path_c));
    return cwd().openDirW(absolute_path_c, flags);
}

openFileAbsolute()

Attempt to remove the root file system path. This error is unreachable if absolute_path is relative.


/// Opens a file for reading or writing, without attempting to create a new file, based on an absolute path.
/// Call `File.close` to release the resource.
/// Asserts that the path is absolute. See `Dir.openFile` for a function that
/// operates on both absolute and relative paths.
/// Asserts that the path parameter has no null bytes. See `openFileAbsoluteZ` for a function
/// that accepts a null-terminated path.
/// On Windows, `absolute_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// On WASI, `absolute_path` should be encoded as valid UTF-8.
/// On other platforms, `absolute_path` is an opaque sequence of bytes with no particular encoding.
pub fn openFileAbsolute(absolute_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
    assert(path.isAbsolute(absolute_path));
    return cwd().openFile(absolute_path, flags);
}

openFileAbsoluteZ()

Same as Dir.readLink, except it asserts the path is absolute. On Windows, pathname should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). On WASI, pathname should be encoded as valid UTF-8. On other platforms, pathname is an opaque sequence of bytes with no particular encoding.


/// Same as `openFileAbsolute` but the path parameter is null-terminated.
pub fn openFileAbsoluteZ(absolute_path_c: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {
    assert(path.isAbsoluteZ(absolute_path_c));
    return cwd().openFileZ(absolute_path_c, flags);
}

openFileAbsoluteW()

Windows-only. Same as readlinkW, except the path parameter is null-terminated, WTF16 encoded.


/// Same as `openFileAbsolute` but the path parameter is WTF-16-encoded.
pub fn openFileAbsoluteW(absolute_path_w: []const u16, flags: File.OpenFlags) File.OpenError!File {
    assert(path.isAbsoluteWindowsWTF16(absolute_path_w));
    return cwd().openFileW(absolute_path_w, flags);
}

accessAbsolute()

Same as readLink, except the path parameter is null-terminated.


/// Test accessing `path`.
/// Be careful of Time-Of-Check-Time-Of-Use race conditions when using this function.
/// For example, instead of testing if a file exists and then opening it, just
/// open it and handle the error for file not found.
/// See `accessAbsoluteZ` for a function that accepts a null-terminated path.
/// On Windows, `absolute_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// On WASI, `absolute_path` should be encoded as valid UTF-8.
/// On other platforms, `absolute_path` is an opaque sequence of bytes with no particular encoding.
pub fn accessAbsolute(absolute_path: []const u8, flags: File.OpenFlags) Dir.AccessError!void {
    assert(path.isAbsolute(absolute_path));
    try cwd().access(absolute_path, flags);
}
/// Same as `accessAbsolute` but the path parameter is null-terminated.

accessAbsoluteZ()

Creates a symbolic link named sym_link_path which contains the string target_path. A symbolic link (also known as a soft link) may point to an existing file or to a nonexistent one; the latter case is known as a dangling link. If sym_link_path exists, it will not be overwritten. See also symLinkAbsoluteZ and symLinkAbsoluteW. On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). On WASI, both paths should be encoded as valid UTF-8. On other platforms, both paths are an opaque sequence of bytes with no particular encoding.

pub fn accessAbsoluteZ(absolute_path: [*:0]const u8, flags: File.OpenFlags) Dir.AccessError!void {
    assert(path.isAbsoluteZ(absolute_path));
    try cwd().accessZ(absolute_path, flags);
}
/// Same as `accessAbsolute` but the path parameter is WTF-16 encoded.

accessAbsoluteW()

Windows-only. Same as symLinkAbsolute except the parameters are null-terminated, WTF16 LE encoded. Note that this function will by default try creating a symbolic link to a file. If you would like to create a symbolic link to a directory, specify this with SymLinkFlags{ .is_directory = true }. See also symLinkAbsolute, symLinkAbsoluteZ.

pub fn accessAbsoluteW(absolute_path: [*:0]const u16, flags: File.OpenFlags) Dir.AccessError!void {
    assert(path.isAbsoluteWindowsW(absolute_path));
    try cwd().accessW(absolute_path, flags);
}

createFileAbsolute()

Same as symLinkAbsolute except the parameters are null-terminated pointers. See also symLinkAbsolute.


/// Creates, opens, or overwrites a file with write access, based on an absolute path.
/// Call `File.close` to release the resource.
/// Asserts that the path is absolute. See `Dir.createFile` for a function that
/// operates on both absolute and relative paths.
/// Asserts that the path parameter has no null bytes. See `createFileAbsoluteC` for a function
/// that accepts a null-terminated path.
/// On Windows, `absolute_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// On WASI, `absolute_path` should be encoded as valid UTF-8.
/// On other platforms, `absolute_path` is an opaque sequence of bytes with no particular encoding.
pub fn createFileAbsolute(absolute_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
    assert(path.isAbsolute(absolute_path));
    return cwd().createFile(absolute_path, flags);
}

createFileAbsoluteZ()

On Windows, \\server or \\server\share was not found.


/// Same as `createFileAbsolute` but the path parameter is null-terminated.
pub fn createFileAbsoluteZ(absolute_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File {
    assert(path.isAbsoluteZ(absolute_path_c));
    return cwd().createFileZ(absolute_path_c, flags);
}

createFileAbsoluteW()

On Windows, antivirus software is enabled by default. It can be disabled, but Windows Update sometimes ignores the user's preference and re-enables it. When enabled, antivirus software on Windows intercepts file system operations and makes them significantly slower in addition to possibly failing with this error code.


/// Same as `createFileAbsolute` but the path parameter is WTF-16 encoded.
pub fn createFileAbsoluteW(absolute_path_w: [*:0]const u16, flags: File.CreateFlags) File.OpenError!File {
    assert(path.isAbsoluteWindowsW(absolute_path_w));
    return cwd().createFileW(mem.span(absolute_path_w), flags);
}

deleteFileAbsolute()

On Windows, the volume does not contain a recognized file system. File system drivers might not be loaded, or the volume may be corrupt.


/// Delete a file name and possibly the file it refers to, based on an absolute path.
/// Asserts that the path is absolute. See `Dir.deleteFile` for a function that
/// operates on both absolute and relative paths.
/// Asserts that the path parameter has no null bytes.
/// On Windows, `absolute_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// On WASI, `absolute_path` should be encoded as valid UTF-8.
/// On other platforms, `absolute_path` is an opaque sequence of bytes with no particular encoding.
pub fn deleteFileAbsolute(absolute_path: []const u8) Dir.DeleteFileError!void {
    assert(path.isAbsolute(absolute_path));
    return cwd().deleteFile(absolute_path);
}

deleteFileAbsoluteZ()

selfExePath except allocates the result on the heap. Caller owns returned memory.


/// Same as `deleteFileAbsolute` except the parameter is null-terminated.
pub fn deleteFileAbsoluteZ(absolute_path_c: [*:0]const u8) Dir.DeleteFileError!void {
    assert(path.isAbsoluteZ(absolute_path_c));
    return cwd().deleteFileZ(absolute_path_c);
}

deleteFileAbsoluteW()

Get the path to the current executable. Follows symlinks. If you only need the directory, use selfExeDirPath. If you only want an open file handle, use openSelfExe. This function may return an error if the current executable was deleted after spawning. Returned value is a slice of out_buffer. On Windows, the result is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). On other platforms, the result is an opaque sequence of bytes with no particular encoding. On Linux, depends on procfs being mounted. If the currently executing binary has been deleted, the file path looks something like /a/b/c/exe (deleted). TODO make the return type of this a null terminated pointer


/// Same as `deleteFileAbsolute` except the parameter is WTF-16 encoded.
pub fn deleteFileAbsoluteW(absolute_path_w: [*:0]const u16) Dir.DeleteFileError!void {
    assert(path.isAbsoluteWindowsW(absolute_path_w));
    return cwd().deleteFileW(mem.span(absolute_path_w));
}

deleteTreeAbsolute()

selfExeDirPath except allocates the result on the heap. Caller owns returned memory.


/// Removes a symlink, file, or directory.
/// This is equivalent to `Dir.deleteTree` with the base directory.
/// Asserts that the path is absolute. See `Dir.deleteTree` for a function that
/// operates on both absolute and relative paths.
/// Asserts that the path parameter has no null bytes.
/// On Windows, `absolute_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// On WASI, `absolute_path` should be encoded as valid UTF-8.
/// On other platforms, `absolute_path` is an opaque sequence of bytes with no particular encoding.
pub fn deleteTreeAbsolute(absolute_path: []const u8) !void {
    assert(path.isAbsolute(absolute_path));
    const dirname = path.dirname(absolute_path) orelse return error{
        /// Attempt to remove the root file system path.
        /// This error is unreachable if `absolute_path` is relative.
        CannotDeleteRootDirectory,
    }.CannotDeleteRootDirectory;

readLinkAbsolute()

Get the directory path that contains the current executable. Returned value is a slice of out_buffer. On Windows, the result is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). On other platforms, the result is an opaque sequence of bytes with no particular encoding.


    var dir = try cwd().openDir(dirname, .{});
    defer dir.close();

readlinkAbsoluteW()

realpath, except caller must free the returned memory. On Windows, the result is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). On other platforms, the result is an opaque sequence of bytes with no particular encoding. See also Dir.realpath.


    return dir.deleteTree(path.basename(absolute_path));
}

readLinkAbsoluteZ()


/// Same as `Dir.readLink`, except it asserts the path is absolute.
/// On Windows, `pathname` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// On WASI, `pathname` should be encoded as valid UTF-8.
/// On other platforms, `pathname` is an opaque sequence of bytes with no particular encoding.
pub fn readLinkAbsolute(pathname: []const u8, buffer: *[max_path_bytes]u8) ![]u8 {
    assert(path.isAbsolute(pathname));
    return posix.readlink(pathname, buffer);
}

symLinkAbsolute()


/// Windows-only. Same as `readlinkW`, except the path parameter is null-terminated, WTF16
/// encoded.
pub fn readlinkAbsoluteW(pathname_w: [*:0]const u16, buffer: *[max_path_bytes]u8) ![]u8 {
    assert(path.isAbsoluteWindowsW(pathname_w));
    return posix.readlinkW(mem.span(pathname_w), buffer);
}

symLinkAbsoluteW()


/// Same as `readLink`, except the path parameter is null-terminated.
pub fn readLinkAbsoluteZ(pathname_c: [*:0]const u8, buffer: *[max_path_bytes]u8) ![]u8 {
    assert(path.isAbsoluteZ(pathname_c));
    return posix.readlinkZ(pathname_c, buffer);
}

symLinkAbsoluteZ()


/// Creates a symbolic link named `sym_link_path` which contains the string `target_path`.
/// A symbolic link (also known as a soft link) may point to an existing file or to a nonexistent
/// one; the latter case is known as a dangling link.
/// If `sym_link_path` exists, it will not be overwritten.
/// See also `symLinkAbsoluteZ` and `symLinkAbsoluteW`.
/// On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// On WASI, both paths should be encoded as valid UTF-8.
/// On other platforms, both paths are an opaque sequence of bytes with no particular encoding.
pub fn symLinkAbsolute(
    target_path: []const u8,
    sym_link_path: []const u8,
    flags: Dir.SymLinkFlags,
) !void {
    assert(path.isAbsolute(target_path));
    assert(path.isAbsolute(sym_link_path));
    if (native_os == .windows) {
        const target_path_w = try windows.sliceToPrefixedFileW(null, target_path);
        const sym_link_path_w = try windows.sliceToPrefixedFileW(null, sym_link_path);
        return windows.CreateSymbolicLink(null, sym_link_path_w.span(), target_path_w.span(), flags.is_directory);
    }
    return posix.symlink(target_path, sym_link_path);
}

OpenSelfExeError


/// Windows-only. Same as `symLinkAbsolute` except the parameters are null-terminated, WTF16 LE encoded.
/// Note that this function will by default try creating a symbolic link to a file. If you would
/// like to create a symbolic link to a directory, specify this with `SymLinkFlags{ .is_directory = true }`.
/// See also `symLinkAbsolute`, `symLinkAbsoluteZ`.
pub fn symLinkAbsoluteW(
    target_path_w: [*:0]const u16,
    sym_link_path_w: [*:0]const u16,
    flags: Dir.SymLinkFlags,
) !void {
    assert(path.isAbsoluteWindowsW(target_path_w));
    assert(path.isAbsoluteWindowsW(sym_link_path_w));
    return windows.CreateSymbolicLink(null, mem.span(sym_link_path_w), mem.span(target_path_w), flags.is_directory);
}

openSelfExe()


/// Same as `symLinkAbsolute` except the parameters are null-terminated pointers.
/// See also `symLinkAbsolute`.
pub fn symLinkAbsoluteZ(
    target_path_c: [*:0]const u8,
    sym_link_path_c: [*:0]const u8,
    flags: Dir.SymLinkFlags,
) !void {
    assert(path.isAbsoluteZ(target_path_c));
    assert(path.isAbsoluteZ(sym_link_path_c));
    if (native_os == .windows) {
        const target_path_w = try windows.cStrToPrefixedFileW(null, target_path_c);
        const sym_link_path_w = try windows.cStrToPrefixedFileW(null, sym_link_path_c);
        return windows.CreateSymbolicLink(null, sym_link_path_w.span(), target_path_w.span(), flags.is_directory);
    }
    return posix.symlinkZ(target_path_c, sym_link_path_c);
}

SelfExePathError


pub const OpenSelfExeError = posix.OpenError || SelfExePathError || posix.FlockError;

selfExePathAlloc()


pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File {
    if (native_os == .linux or native_os == .serenity) {
        return openFileAbsoluteZ("/proc/self/exe", flags);
    }
    if (native_os == .windows) {
        // If ImagePathName is a symlink, then it will contain the path of the symlink,
        // not the path that the symlink points to. However, because we are opening
        // the file, we can let the openFileW call follow the symlink for us.
        const image_path_unicode_string = &windows.peb().ProcessParameters.ImagePathName;
        const image_path_name = image_path_unicode_string.Buffer.?[0 .. image_path_unicode_string.Length / 2 :0];
        const prefixed_path_w = try windows.wToPrefixedFileW(null, image_path_name);
        return cwd().openFileW(prefixed_path_w.span(), flags);
    }
    // Use of max_path_bytes here is valid as the resulting path is immediately
    // opened with no modification.
    var buf: [max_path_bytes]u8 = undefined;
    const self_exe_path = try selfExePath(&buf);
    buf[self_exe_path.len] = 0;
    return openFileAbsoluteZ(buf[0..self_exe_path.len :0].ptr, flags);
}

selfExePath()


// This is `posix.ReadLinkError || posix.RealPathError` with impossible errors excluded
pub const SelfExePathError = error{
    FileNotFound,
    AccessDenied,
    NameTooLong,
    NotSupported,
    NotDir,
    SymLinkLoop,
    InputOutput,
    FileTooBig,
    IsDir,
    ProcessFdQuotaExceeded,
    SystemFdQuotaExceeded,
    NoDevice,
    SystemResources,
    NoSpaceLeft,
    FileSystem,
    BadPathName,
    DeviceBusy,
    SharingViolation,
    PipeBusy,
    NotLink,
    PathAlreadyExists,

selfExeDirPathAlloc()


    /// On Windows, `\\server` or `\\server\share` was not found.
    NetworkNotFound,
    ProcessNotFound,

selfExeDirPath()


    /// On Windows, antivirus software is enabled by default. It can be
    /// disabled, but Windows Update sometimes ignores the user's preference
    /// and re-enables it. When enabled, antivirus software on Windows
    /// intercepts file system operations and makes them significantly slower
    /// in addition to possibly failing with this error code.
    AntivirusInterference,

realpathAlloc()


    /// On Windows, the volume does not contain a recognized file system. File
    /// system drivers might not be loaded, or the volume may be corrupt.
    UnrecognizedVolume,
} || posix.SysCtlError;

/// `selfExePath` except allocates the result on the heap.
/// Caller owns returned memory.
pub fn selfExePathAlloc(allocator: Allocator) ![]u8 {
    // Use of max_path_bytes here is justified as, at least on one tested Linux
    // system, readlink will completely fail to return a result larger than
    // PATH_MAX even if given a sufficiently large buffer. This makes it
    // fundamentally impossible to get the selfExePath of a program running in
    // a very deeply nested directory chain in this way.
    // TODO(#4812): Investigate other systems and whether it is possible to get
    // this path by trying larger and larger buffers until one succeeds.
    var buf: [max_path_bytes]u8 = undefined;
    return allocator.dupe(u8, try selfExePath(&buf));
}

/// Get the path to the current executable. Follows symlinks.
/// If you only need the directory, use selfExeDirPath.
/// If you only want an open file handle, use openSelfExe.
/// This function may return an error if the current executable
/// was deleted after spawning.
/// Returned value is a slice of out_buffer.
/// On Windows, the result is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// On other platforms, the result is an opaque sequence of bytes with no particular encoding.
///
/// On Linux, depends on procfs being mounted. If the currently executing binary has
/// been deleted, the file path looks something like `/a/b/c/exe (deleted)`.
/// TODO make the return type of this a null terminated pointer
pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 {
    if (is_darwin) {
        // Note that _NSGetExecutablePath() will return "a path" to
        // the executable not a "real path" to the executable.
        var symlink_path_buf: [max_path_bytes:0]u8 = undefined;
        var u32_len: u32 = max_path_bytes + 1; // include the sentinel
        const rc = std.c._NSGetExecutablePath(&symlink_path_buf, &u32_len);
        if (rc != 0) return error.NameTooLong;

        var real_path_buf: [max_path_bytes]u8 = undefined;
        const real_path = std.posix.realpathZ(&symlink_path_buf, &real_path_buf) catch |err| switch (err) {
            error.InvalidWtf8 => unreachable, // Windows-only
            error.NetworkNotFound => unreachable, // Windows-only
            else => |e| return e,
        };
        if (real_path.len > out_buffer.len) return error.NameTooLong;
        const result = out_buffer[0..real_path.len];
        @memcpy(result, real_path);
        return result;
    }
    switch (native_os) {
        .linux, .serenity => return posix.readlinkZ("/proc/self/exe", out_buffer) catch |err| switch (err) {
            error.InvalidUtf8 => unreachable, // WASI-only
            error.InvalidWtf8 => unreachable, // Windows-only
            error.UnsupportedReparsePointType => unreachable, // Windows-only
            error.NetworkNotFound => unreachable, // Windows-only
            else => |e| return e,
        },
        .solaris, .illumos => return posix.readlinkZ("/proc/self/path/a.out", out_buffer) catch |err| switch (err) {
            error.InvalidUtf8 => unreachable, // WASI-only
            error.InvalidWtf8 => unreachable, // Windows-only
            error.UnsupportedReparsePointType => unreachable, // Windows-only
            error.NetworkNotFound => unreachable, // Windows-only
            else => |e| return e,
        },
        .freebsd, .dragonfly => {
            var mib = [4]c_int{ posix.CTL.KERN, posix.KERN.PROC, posix.KERN.PROC_PATHNAME, -1 };
            var out_len: usize = out_buffer.len;
            try posix.sysctl(&mib, out_buffer.ptr, &out_len, null, 0);
            // TODO could this slice from 0 to out_len instead?
            return mem.sliceTo(out_buffer, 0);
        },
        .netbsd => {
            var mib = [4]c_int{ posix.CTL.KERN, posix.KERN.PROC_ARGS, -1, posix.KERN.PROC_PATHNAME };
            var out_len: usize = out_buffer.len;
            try posix.sysctl(&mib, out_buffer.ptr, &out_len, null, 0);
            // TODO could this slice from 0 to out_len instead?
            return mem.sliceTo(out_buffer, 0);
        },
        .openbsd, .haiku => {
            // OpenBSD doesn't support getting the path of a running process, so try to guess it
            if (std.os.argv.len == 0)
                return error.FileNotFound;

            const argv0 = mem.span(std.os.argv[0]);
            if (mem.indexOf(u8, argv0, "/") != null) {
                // argv[0] is a path (relative or absolute): use realpath(3) directly
                var real_path_buf: [max_path_bytes]u8 = undefined;
                const real_path = posix.realpathZ(std.os.argv[0], &real_path_buf) catch |err| switch (err) {
                    error.InvalidWtf8 => unreachable, // Windows-only
                    error.NetworkNotFound => unreachable, // Windows-only
                    else => |e| return e,
                };
                if (real_path.len > out_buffer.len)
                    return error.NameTooLong;
                const result = out_buffer[0..real_path.len];
                @memcpy(result, real_path);
                return result;
            } else if (argv0.len != 0) {
                // argv[0] is not empty (and not a path): search it inside PATH
                const PATH = posix.getenvZ("PATH") orelse return error.FileNotFound;
                var path_it = mem.tokenizeScalar(u8, PATH, path.delimiter);
                while (path_it.next()) |a_path| {
                    var resolved_path_buf: [max_path_bytes - 1:0]u8 = undefined;
                    const resolved_path = std.fmt.bufPrintZ(&resolved_path_buf, "{s}/{s}", .{
                        a_path,
                        std.os.argv[0],
                    }) catch continue;

                    var real_path_buf: [max_path_bytes]u8 = undefined;
                    if (posix.realpathZ(resolved_path, &real_path_buf)) |real_path| {
                        // found a file, and hope it is the right file
                        if (real_path.len > out_buffer.len)
                            return error.NameTooLong;
                        const result = out_buffer[0..real_path.len];
                        @memcpy(result, real_path);
                        return result;
                    } else |_| continue;
                }
            }
            return error.FileNotFound;
        },
        .windows => {
            const image_path_unicode_string = &windows.peb().ProcessParameters.ImagePathName;
            const image_path_name = image_path_unicode_string.Buffer.?[0 .. image_path_unicode_string.Length / 2 :0];

            // If ImagePathName is a symlink, then it will contain the path of the
            // symlink, not the path that the symlink points to. We want the path
            // that the symlink points to, though, so we need to get the realpath.
            const pathname_w = try windows.wToPrefixedFileW(null, image_path_name);
            return std.fs.cwd().realpathW(pathname_w.span(), out_buffer) catch |err| switch (err) {
                error.InvalidWtf8 => unreachable,
                else => |e| return e,
            };
        },
        else => @compileError("std.fs.selfExePath not supported for this target"),
    }
}

/// `selfExeDirPath` except allocates the result on the heap.
/// Caller owns returned memory.
pub fn selfExeDirPathAlloc(allocator: Allocator) ![]u8 {
    // Use of max_path_bytes here is justified as, at least on one tested Linux
    // system, readlink will completely fail to return a result larger than
    // PATH_MAX even if given a sufficiently large buffer. This makes it
    // fundamentally impossible to get the selfExeDirPath of a program running
    // in a very deeply nested directory chain in this way.
    // TODO(#4812): Investigate other systems and whether it is possible to get
    // this path by trying larger and larger buffers until one succeeds.
    var buf: [max_path_bytes]u8 = undefined;
    return allocator.dupe(u8, try selfExeDirPath(&buf));
}

/// Get the directory path that contains the current executable.
/// Returned value is a slice of out_buffer.
/// On Windows, the result is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// On other platforms, the result is an opaque sequence of bytes with no particular encoding.
pub fn selfExeDirPath(out_buffer: []u8) SelfExePathError![]const u8 {
    const self_exe_path = try selfExePath(out_buffer);
    // Assume that the OS APIs return absolute paths, and therefore dirname
    // will not return null.
    return path.dirname(self_exe_path).?;
}

/// `realpath`, except caller must free the returned memory.
/// On Windows, the result is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// On other platforms, the result is an opaque sequence of bytes with no particular encoding.
/// See also `Dir.realpath`.
pub fn realpathAlloc(allocator: Allocator, pathname: []const u8) ![]u8 {
    // Use of max_path_bytes here is valid as the realpath function does not
    // have a variant that takes an arbitrary-size buffer.
    // TODO(#4812): Consider reimplementing realpath or using the POSIX.1-2008
    // NULL out parameter (GNU's canonicalize_file_name) to handle overelong
    // paths. musl supports passing NULL but restricts the output to PATH_MAX
    // anyway.
    var buf: [max_path_bytes]u8 = undefined;
    return allocator.dupe(u8, try posix.realpath(pathname, &buf));
}

test {
    if (native_os != .wasi) {
        _ = &makeDirAbsolute;
        _ = &makeDirAbsoluteZ;
        _ = &copyFileAbsolute;
        _ = &updateFileAbsolute;
    }
    _ = &AtomicFile;
    _ = &Dir;
    _ = &File;
    _ = &path;
    _ = @import("fs/test.zig");
    _ = @import("fs/get_app_data_dir.zig");
}