diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2024-03-18 22:39:59 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2024-03-19 11:45:09 -0700 |
| commit | cd62005f19ff966d2c42de4daeb9a1e4b644bf76 (patch) | |
| tree | 4bb316708afaf79c971808df792d8fe86274789b /lib/std/fs.zig | |
| parent | 7057bffc14602add697eb566b83934b7ad3fd81c (diff) | |
| download | zig-cd62005f19ff966d2c42de4daeb9a1e4b644bf76.tar.gz zig-cd62005f19ff966d2c42de4daeb9a1e4b644bf76.zip | |
extract std.posix from std.os
closes #5019
Diffstat (limited to 'lib/std/fs.zig')
| -rw-r--r-- | lib/std/fs.zig | 169 |
1 files changed, 89 insertions, 80 deletions
diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 5c6e8c9c3a..06b9cf3e12 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -3,21 +3,23 @@ const std = @import("std.zig"); const builtin = @import("builtin"); const root = @import("root"); -const os = std.os; 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; -const is_darwin = builtin.os.tag.isDarwin(); +const is_darwin = native_os.isDarwin(); pub const AtomicFile = @import("fs/AtomicFile.zig"); pub const Dir = @import("fs/Dir.zig"); pub const File = @import("fs/File.zig"); pub const path = @import("fs/path.zig"); -pub const has_executable_bit = switch (builtin.os.tag) { +pub const has_executable_bit = switch (native_os) { .windows, .wasi => false, else => true, }; @@ -26,36 +28,43 @@ pub const wasi = @import("fs/wasi.zig"); // TODO audit these APIs with respect to Dir and absolute paths -pub const realpath = os.realpath; -pub const realpathZ = os.realpathZ; -pub const realpathW = os.realpathW; +pub const realpath = posix.realpath; +pub const realpathZ = posix.realpathZ; +pub const realpathW = posix.realpathW; pub const getAppDataDir = @import("fs/get_app_data_dir.zig").getAppDataDir; pub const GetAppDataDirError = @import("fs/get_app_data_dir.zig").GetAppDataDirError; -/// This represents the maximum size of a `[]u8` 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. +/// Deprecated: use `max_path_bytes`. +pub const MAX_PATH_BYTES = max_path_bytes; + +/// 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 (builtin.os.tag) { - .linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly, .haiku, .solaris, .illumos, .plan9, .emscripten => os.PATH_MAX, +/// +/// * 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 => 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 => os.windows.PATH_MAX_WIDE * 3 + 1, + .windows => windows.PATH_MAX_WIDE * 3 + 1, // TODO work out what a reasonable value we should use here .wasi => 4096, else => if (@hasDecl(root, "os") and @hasDecl(root.os, "PATH_MAX")) root.os.PATH_MAX else - @compileError("PATH_MAX not implemented for " ++ @tagName(builtin.os.tag)), + @compileError("PATH_MAX not implemented for " ++ @tagName(native_os)), }; /// This represents the maximum size of a `[]u8` file name component that @@ -66,22 +75,22 @@ pub const MAX_PATH_BYTES = switch (builtin.os.tag) { /// 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 (builtin.os.tag) { - .linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly, .solaris, .illumos => os.NAME_MAX, +pub const MAX_NAME_BYTES = switch (native_os) { + .linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly, .solaris, .illumos => posix.NAME_MAX, // Haiku's NAME_MAX includes the null terminator, so subtract one. - .haiku => os.NAME_MAX - 1, + .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 => os.windows.NAME_MAX * 3, + .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 => os.windows.NAME_MAX * 3, + .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(builtin.os.tag)), + @compileError("NAME_MAX not implemented for " ++ @tagName(native_os)), }; pub const base64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".*; @@ -167,19 +176,19 @@ pub fn copyFileAbsolute( /// 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 os.mkdir(absolute_path, Dir.default_mode); + return posix.mkdir(absolute_path, Dir.default_mode); } /// 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 os.mkdirZ(absolute_path_z, Dir.default_mode); + return posix.mkdirZ(absolute_path_z, Dir.default_mode); } /// 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 os.mkdirW(absolute_path_w, Dir.default_mode); + return posix.mkdirW(absolute_path_w, Dir.default_mode); } /// Same as `Dir.deleteDir` except the path is absolute. @@ -188,19 +197,19 @@ pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void { /// 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 os.rmdir(dir_path); + return posix.rmdir(dir_path); } /// 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 os.rmdirZ(dir_path); + return posix.rmdirZ(dir_path); } /// 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 os.rmdirW(dir_path); + return posix.rmdirW(dir_path); } /// Same as `Dir.rename` except the paths are absolute. @@ -210,49 +219,49 @@ pub fn deleteDirAbsoluteW(dir_path: [*:0]const u16) !void { pub fn renameAbsolute(old_path: []const u8, new_path: []const u8) !void { assert(path.isAbsolute(old_path)); assert(path.isAbsolute(new_path)); - return os.rename(old_path, new_path); + return posix.rename(old_path, new_path); } /// 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 os.renameZ(old_path, new_path); + return posix.renameZ(old_path, new_path); } /// 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 os.renameW(old_path, new_path); + return posix.renameW(old_path, new_path); } /// 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 os.renameat(old_dir.fd, old_sub_path, new_dir.fd, new_sub_path); + return posix.renameat(old_dir.fd, old_sub_path, new_dir.fd, new_sub_path); } /// 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 os.renameatZ(old_dir.fd, old_sub_path_z, new_dir.fd, new_sub_path_z); + return posix.renameatZ(old_dir.fd, old_sub_path_z, new_dir.fd, new_sub_path_z); } /// 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 os.renameatW(old_dir.fd, old_sub_path_w, new_dir.fd, new_sub_path_w); + return posix.renameatW(old_dir.fd, old_sub_path_w, new_dir.fd, new_sub_path_w); } /// 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 (builtin.os.tag == .windows) { - return .{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle }; - } else if (builtin.os.tag == .wasi) { + if (native_os == .windows) { + return .{ .fd = windows.peb().ProcessParameters.CurrentDirectory.Handle }; + } else if (native_os == .wasi) { return .{ .fd = std.options.wasiCwd() }; } else { - return .{ .fd = os.AT.FDCWD }; + return .{ .fd = posix.AT.FDCWD }; } } @@ -412,20 +421,20 @@ pub fn deleteTreeAbsolute(absolute_path: []const u8) !void { /// 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 os.readlink(pathname, buffer); + return posix.readlink(pathname, buffer); } /// 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 os.readlinkW(pathname_w, buffer); + return posix.readlinkW(pathname_w, buffer); } /// 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 os.readlinkZ(pathname_c, buffer); + return posix.readlinkZ(pathname_c, buffer); } /// Creates a symbolic link named `sym_link_path` which contains the string `target_path`. @@ -443,12 +452,12 @@ pub fn symLinkAbsolute( ) !void { assert(path.isAbsolute(target_path)); assert(path.isAbsolute(sym_link_path)); - if (builtin.os.tag == .windows) { - const target_path_w = try os.windows.sliceToPrefixedFileW(null, target_path); - const sym_link_path_w = try os.windows.sliceToPrefixedFileW(null, sym_link_path); - return os.windows.CreateSymbolicLink(null, sym_link_path_w.span(), target_path_w.span(), flags.is_directory); + 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 os.symlink(target_path, sym_link_path); + return posix.symlink(target_path, sym_link_path); } /// Windows-only. Same as `symLinkAbsolute` except the parameters are null-terminated, WTF16 LE encoded. @@ -462,7 +471,7 @@ pub fn symLinkAbsoluteW( ) !void { assert(path.isAbsoluteWindowsWTF16(target_path_w)); assert(path.isAbsoluteWindowsWTF16(sym_link_path_w)); - return os.windows.CreateSymbolicLink(null, sym_link_path_w, target_path_w, flags.is_directory); + return windows.CreateSymbolicLink(null, sym_link_path_w, target_path_w, flags.is_directory); } /// Same as `symLinkAbsolute` except the parameters are null-terminated pointers. @@ -474,27 +483,27 @@ pub fn symLinkAbsoluteZ( ) !void { assert(path.isAbsoluteZ(target_path_c)); assert(path.isAbsoluteZ(sym_link_path_c)); - if (builtin.os.tag == .windows) { - const target_path_w = try os.windows.cStrToPrefixedFileW(null, target_path_c); - const sym_link_path_w = try os.windows.cStrToPrefixedFileW(null, sym_link_path_c); - return os.windows.CreateSymbolicLink(null, sym_link_path_w.span(), target_path_w.span(), flags.is_directory); + 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 os.symlinkZ(target_path_c, sym_link_path_c); + return posix.symlinkZ(target_path_c, sym_link_path_c); } -pub const OpenSelfExeError = os.OpenError || SelfExePathError || os.FlockError; +pub const OpenSelfExeError = posix.OpenError || SelfExePathError || posix.FlockError; pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File { - if (builtin.os.tag == .linux) { + if (native_os == .linux) { return openFileAbsoluteZ("/proc/self/exe", flags); } - if (builtin.os.tag == .windows) { + 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 = &os.windows.peb().ProcessParameters.ImagePathName; + 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 os.windows.wToPrefixedFileW(null, image_path_name); + 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 @@ -505,7 +514,7 @@ pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File { return openFileAbsoluteZ(buf[0..self_exe_path.len :0].ptr, flags); } -// This is os.ReadLinkError || os.RealPathError with impossible errors excluded +// This is `posix.ReadLinkError || posix.RealPathError` with impossible errors excluded pub const SelfExePathError = error{ FileNotFound, AccessDenied, @@ -542,7 +551,7 @@ pub const SelfExePathError = error{ /// 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, -} || os.SysCtlError; +} || posix.SysCtlError; /// `selfExePath` except allocates the result on the heap. /// Caller owns returned memory. @@ -580,7 +589,7 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 { if (rc != 0) return error.NameTooLong; var real_path_buf: [MAX_PATH_BYTES]u8 = undefined; - const real_path = std.os.realpathZ(&symlink_path_buf, &real_path_buf) catch |err| switch (err) { + 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, @@ -590,15 +599,15 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 { @memcpy(result, real_path); return result; } - switch (builtin.os.tag) { - .linux => return os.readlinkZ("/proc/self/exe", out_buffer) catch |err| switch (err) { + switch (native_os) { + .linux => 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 os.readlinkZ("/proc/self/path/a.out", out_buffer) catch |err| switch (err) { + .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 @@ -606,29 +615,29 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 { else => |e| return e, }, .freebsd, .dragonfly => { - var mib = [4]c_int{ os.CTL.KERN, os.KERN.PROC, os.KERN.PROC_PATHNAME, -1 }; + var mib = [4]c_int{ posix.CTL.KERN, posix.KERN.PROC, posix.KERN.PROC_PATHNAME, -1 }; var out_len: usize = out_buffer.len; - try os.sysctl(&mib, out_buffer.ptr, &out_len, null, 0); + 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{ os.CTL.KERN, os.KERN.PROC_ARGS, -1, os.KERN.PROC_PATHNAME }; + 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 os.sysctl(&mib, out_buffer.ptr, &out_len, null, 0); + 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 (os.argv.len == 0) + if (std.os.argv.len == 0) return error.FileNotFound; - const argv0 = mem.span(os.argv[0]); + 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 = os.realpathZ(os.argv[0], &real_path_buf) catch |err| switch (err) { + 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, @@ -640,17 +649,17 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 { return result; } else if (argv0.len != 0) { // argv[0] is not empty (and not a path): search it inside PATH - const PATH = std.os.getenvZ("PATH") orelse return error.FileNotFound; + 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, - os.argv[0], + std.os.argv[0], }) catch continue; var real_path_buf: [MAX_PATH_BYTES]u8 = undefined; - if (os.realpathZ(resolved_path, &real_path_buf)) |real_path| { + 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; @@ -663,13 +672,13 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 { return error.FileNotFound; }, .windows => { - const image_path_unicode_string = &os.windows.peb().ProcessParameters.ImagePathName; + 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 os.windows.wToPrefixedFileW(null, image_path_name); + 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, @@ -718,11 +727,11 @@ pub fn realpathAlloc(allocator: Allocator, pathname: []const u8) ![]u8 { // 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 os.realpath(pathname, &buf)); + return allocator.dupe(u8, try posix.realpath(pathname, &buf)); } test { - if (builtin.os.tag != .wasi) { + if (native_os != .wasi) { _ = &makeDirAbsolute; _ = &makeDirAbsoluteZ; _ = ©FileAbsolute; |
