|
//! File System. |
AtomicFilefs/AtomicFile.zigThe 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 |
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; |
Dirfs/Dir.zigThis represents the maximum size of a |
const is_darwin = native_os.isDarwin(); |
Filefs/File.zigBase64 encoder, replacing the standard |
pub const AtomicFile = @import("fs/AtomicFile.zig"); pub const Dir = @import("fs/Dir.zig"); pub const File = @import("fs/File.zig"); |
pathfs/path.zigBase64 decoder, replacing the standard |
pub const path = @import("fs/path.zig"); |
has_executable_bitSame as |
pub const has_executable_bit = switch (native_os) { .windows, .wasi => false, else => true, }; |
wasifs/wasi.zigSame as |
pub const wasi = @import("fs/wasi.zig"); |
realpathCreate a new directory, based on an absolute path.
Asserts that the path is absolute. See |
// TODO audit these APIs with respect to Dir and absolute paths |
realpathZSame as |
pub const realpath = posix.realpath; pub const realpathZ = posix.realpathZ; |
realpathWSame as |
pub const realpathW = posix.realpathW; |
getAppDataDirfs/get_app_data_dir.zigSame as |
pub const getAppDataDir = @import("fs/get_app_data_dir.zig").getAppDataDir; |
GetAppDataDirErrorfs/get_app_data_dir.zigSame as |
pub const GetAppDataDirError = @import("fs/get_app_data_dir.zig").GetAppDataDirError; |
max_path_bytesSame as |
/// 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_bytesSame as |
/// 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_alphabetSame as |
pub const base64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".*; |
base64_encoderSame as |
/// 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_decoderSame as |
/// 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 |
/// 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 |
/// 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 |
) !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 |
/// 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 |
/// 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 |
/// 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 |
/// 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 |
/// 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 |
/// 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 |
/// 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 |
/// 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 |
/// 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 |
/// 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 |
/// 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 |
/// 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 |
/// 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 |
pub fn defaultWasiCwd() std.os.wasi.fd_t { // Expect the first preopen to be current working directory. return 3; } |
openDirAbsoluteZ()Same as |
/// 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 |
/// 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 |
/// 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 |
/// 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 |
/// 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 |
/// 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 |
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 |
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 |
/// 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, |
/// 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()
|
/// 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 |
/// 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()
|
/// 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()
|
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; _ = ©FileAbsolute; _ = &updateFileAbsolute; } _ = &AtomicFile; _ = &Dir; _ = &File; _ = &path; _ = @import("fs/test.zig"); _ = @import("fs/get_app_data_dir.zig"); } |
Generated by zstd-live on 2025-08-10 02:45:58 UTC. |