diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2025-12-06 21:06:30 -0800 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2025-12-23 22:15:08 -0800 |
| commit | 916998315967f73c91e682e9ea05dd3232818654 (patch) | |
| tree | 6cd1ee9b952441c6b6ea1ddbad17a5cfd4b5f860 /lib/std | |
| parent | 877032ec6a0007316f42658d12042f1473de4856 (diff) | |
| download | zig-916998315967f73c91e682e9ea05dd3232818654.tar.gz zig-916998315967f73c91e682e9ea05dd3232818654.zip | |
std.fs: migrate most of the API elsewhere
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/Io/Dir.zig | 173 | ||||
| -rw-r--r-- | lib/std/Io/File.zig | 22 | ||||
| -rw-r--r-- | lib/std/crypto/Certificate/Bundle.zig | 2 | ||||
| -rw-r--r-- | lib/std/fs.zig | 266 | ||||
| -rw-r--r-- | lib/std/fs/test.zig | 29 | ||||
| -rw-r--r-- | lib/std/os.zig | 5 | ||||
| -rw-r--r-- | lib/std/process.zig | 2 | ||||
| -rw-r--r-- | lib/std/std.zig | 2 | ||||
| -rw-r--r-- | lib/std/zig/system.zig | 2 | ||||
| -rw-r--r-- | lib/std/zig/system/linux.zig | 2 |
10 files changed, 193 insertions, 312 deletions
diff --git a/lib/std/Io/Dir.zig b/lib/std/Io/Dir.zig index 71ea3b465a..3b552a556a 100644 --- a/lib/std/Io/Dir.zig +++ b/lib/std/Io/Dir.zig @@ -1,4 +1,5 @@ const Dir = @This(); +const root = @import("root"); const builtin = @import("builtin"); const native_os = builtin.os.tag; @@ -11,6 +12,61 @@ const Allocator = std.mem.Allocator; handle: Handle, +pub const path = std.fs.path; + +/// 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://wtf-8.codeberg.page/). +/// * 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, .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos, .freebsd, .openbsd, .netbsd, .dragonfly, .haiku, .illumos, .plan9, .emscripten, .wasi, .serenity => std.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 => std.os.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)), +}; + +/// 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://wtf-8.codeberg.page/). +/// 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, .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos, .freebsd, .openbsd, .netbsd, .dragonfly, .illumos, .serenity => std.posix.NAME_MAX, + // Haiku's NAME_MAX includes the null terminator, so subtract one. + .haiku => std.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 => std.os.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 => std.os.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)), +}; + pub const Entry = struct { name: []const u8, kind: File.Kind, @@ -148,7 +204,7 @@ pub const SelectiveWalker = struct { }) |entry| { self.name_buffer.shrinkRetainingCapacity(dirname_len); if (self.name_buffer.items.len != 0) { - try self.name_buffer.append(self.allocator, std.fs.path.sep); + try self.name_buffer.append(self.allocator, path.sep); dirname_len += 1; } try self.name_buffer.ensureUnusedCapacity(self.allocator, entry.name.len + 1); @@ -252,7 +308,7 @@ pub const Walker = struct { /// Returns 1 for a direct child of the initial directory, 2 for an entry /// within a direct child of the initial directory, etc. pub fn depth(self: Walker.Entry) usize { - return std.mem.countScalar(u8, self.path, std.fs.path.sep) + 1; + return std.mem.countScalar(u8, self.path, path.sep) + 1; } }; @@ -340,6 +396,11 @@ pub fn access(dir: Dir, io: Io, sub_path: []const u8, options: AccessOptions) Ac return io.vtable.dirAccess(io.userdata, dir, sub_path, options); } +pub fn accessAbsolute(io: Io, absolute_path: []const u8, options: AccessOptions) AccessError!void { + assert(path.isAbsolute(absolute_path)); + return access(.cwd(), io, absolute_path, options); +} + pub const OpenError = error{ FileNotFound, NotDir, @@ -379,6 +440,11 @@ pub fn openDir(dir: Dir, io: Io, sub_path: []const u8, options: OpenOptions) Ope return io.vtable.dirOpenDir(io.userdata, dir, sub_path, options); } +pub fn openDirAbsolute(io: Io, absolute_path: []const u8, options: OpenOptions) OpenError!Dir { + assert(path.isAbsolute(absolute_path)); + return openDir(.cwd(), io, absolute_path, options); +} + pub fn close(dir: Dir, io: Io) void { return io.vtable.dirClose(io.userdata, dir); } @@ -396,6 +462,11 @@ pub fn openFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.OpenFlags) F return io.vtable.dirOpenFile(io.userdata, dir, sub_path, flags); } +pub fn openFileAbsolute(io: Io, absolute_path: []const u8, flags: File.OpenFlags) File.OpenError!File { + assert(path.isAbsolute(absolute_path)); + return openFile(.cwd(), io, absolute_path, flags); +} + /// Creates, opens, or overwrites a file with write access. /// /// Allocates a resource to be dellocated with `File.close`. @@ -407,6 +478,10 @@ pub fn createFile(dir: Dir, io: Io, sub_path: []const u8, flags: File.CreateFlag return io.vtable.dirCreateFile(io.userdata, dir, sub_path, flags); } +pub fn createFileAbsolute(io: Io, absolute_path: []const u8, flags: File.CreateFlags) File.OpenError!File { + return createFile(.cwd(), io, absolute_path, flags); +} + pub const WriteFileOptions = struct { /// On Windows, `sub_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/). /// On WASI, `sub_path` should be encoded as valid UTF-8. @@ -476,7 +551,7 @@ pub fn updateFile( } } - if (std.fs.path.dirname(dest_path)) |dirname| { + if (path.dirname(dest_path)) |dirname| { try dest_dir.makePath(io, dirname, .default_dir); } @@ -556,6 +631,21 @@ pub fn makeDir(dir: Dir, io: Io, sub_path: []const u8, permissions: Permissions) return io.vtable.dirMake(io.userdata, dir, sub_path, permissions); } +/// Create a new directory, based on an absolute path. +/// +/// Asserts that the path is absolute. See `makeDir` for a function that +/// operates on both absolute and relative paths. +/// +/// On Windows, `absolute_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/). +/// 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(io: Io, absolute_path: []const u8, permissions: Permissions) MakeError!void { + assert(path.isAbsolute(absolute_path)); + return makeDir(.cwd(), io, absolute_path, permissions); +} + +test makeDirAbsolute {} + pub const MakePathError = MakeError || StatPathError; /// Creates parent directories with default permissions as necessary to ensure @@ -703,19 +793,20 @@ pub const RealPathAllocError = RealPathError || Allocator.Error; /// Same as `realPath` except allocates result. pub fn realPathAlloc(dir: Dir, io: Io, sub_path: []const u8, allocator: Allocator) RealPathAllocError![:0]u8 { - var buffer: [std.fs.max_path_bytes]u8 = undefined; + var buffer: [max_path_bytes]u8 = undefined; const n = try realPath(dir, io, sub_path, &buffer); return allocator.dupeZ(u8, buffer[0..n]); } -pub fn realPathAbsolute(io: Io, path: []const u8, out_buffer: []u8) RealPathError!usize { - return io.vtable.dirRealPath(io.userdata, .cwd(), path, out_buffer); +pub fn realPathAbsolute(io: Io, absolute_path: []const u8, out_buffer: []u8) RealPathError!usize { + assert(path.isAbsolute(absolute_path)); + return io.vtable.dirRealPath(io.userdata, .cwd(), absolute_path, out_buffer); } /// Same as `realPathAbsolute` except allocates result. -pub fn realPathAbsoluteAlloc(io: Io, path: []const u8, allocator: Allocator) RealPathAllocError![:0]u8 { - var buffer: [std.fs.max_path_bytes]u8 = undefined; - const n = try realPathAbsolute(io, path, &buffer); +pub fn realPathAbsoluteAlloc(io: Io, absolute_path: []const u8, allocator: Allocator) RealPathAllocError![:0]u8 { + var buffer: [max_path_bytes]u8 = undefined; + const n = try realPathAbsolute(io, absolute_path, &buffer); return allocator.dupeZ(u8, buffer[0..n]); } @@ -754,6 +845,13 @@ pub fn deleteFile(dir: Dir, io: Io, sub_path: []const u8) DeleteFileError!void { return io.vtable.dirDeleteFile(io.userdata, dir, sub_path); } +pub fn deleteFileAbsolute(io: Io, absolute_path: []const u8) DeleteFileError!void { + assert(path.isAbsolute(absolute_path)); + return deleteFile(.cwd(), io, absolute_path); +} + +test deleteFileAbsolute {} + pub const DeleteDirError = error{ DirNotEmpty, FileNotFound, @@ -785,6 +883,16 @@ pub fn deleteDir(dir: Dir, io: Io, sub_path: []const u8) DeleteDirError!void { return io.vtable.dirDeleteDir(io.userdata, dir, sub_path); } +/// Same as `deleteDir` except the path is absolute. +/// +/// On Windows, `dir_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/). +/// 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(io: Io, absolute_path: []const u8) DeleteDirError!void { + assert(path.isAbsolute(absolute_path)); + return deleteDir(.cwd(), io, absolute_path); +} + pub const RenameError = error{ /// In WASI, this error may occur when the file descriptor does /// not hold the required rights to rename a resource by path relative to it. @@ -893,6 +1001,17 @@ pub fn symLink( return io.vtable.dirSymLink(io.userdata, dir, target_path, sym_link_path, flags); } +pub fn symLinkAbsolute( + io: Io, + target_path: []const u8, + sym_link_path: []const u8, + flags: SymLinkFlags, +) SymLinkError!void { + assert(path.isAbsolute(target_path)); + assert(path.isAbsolute(sym_link_path)); + return symLink(.cwd(), io, target_path, sym_link_path, flags); +} + /// Same as `symLink`, except tries to create the symbolic link until it /// succeeds or encounters an error other than `error.PathAlreadyExists`. /// @@ -913,15 +1032,15 @@ pub fn symLinkAtomic( else => |e| return e, } - const dirname = std.fs.path.dirname(sym_link_path) orelse "."; + const dirname = path.dirname(sym_link_path) orelse "."; const rand_len = @sizeOf(u64) * 2; const temp_path_len = dirname.len + 1 + rand_len; - var temp_path_buf: [std.fs.max_path_bytes]u8 = undefined; + var temp_path_buf: [max_path_bytes]u8 = undefined; if (temp_path_len > temp_path_buf.len) return error.NameTooLong; @memcpy(temp_path_buf[0..dirname.len], dirname); - temp_path_buf[dirname.len] = std.fs.path.sep; + temp_path_buf[dirname.len] = path.sep; const temp_path = temp_path_buf[0..temp_path_len]; @@ -985,8 +1104,8 @@ pub fn readLink(dir: Dir, io: Io, sub_path: []const u8, buffer: []u8) ReadLinkEr /// On Windows, `path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/). /// On WASI, `path` should be encoded as valid UTF-8. /// On other platforms, `path` is an opaque sequence of bytes with no particular encoding. -pub fn readLinkAbsolute(io: Io, path: []const u8, buffer: []u8) ReadLinkError!usize { - assert(std.fs.path.isAbsolute(path)); +pub fn readLinkAbsolute(io: Io, absolute_path: []const u8, buffer: []u8) ReadLinkError!usize { + assert(path.isAbsolute(absolute_path)); return io.vtable.dirReadLink(io.userdata, .cwd(), path, buffer); } @@ -1298,7 +1417,7 @@ fn deleteTreeMinStackSizeWithKindHint(parent: Dir, io: Io, sub_path: []const u8, // Valid use of max_path_bytes because dir_name_buf will only // ever store a single path component that was returned from the // filesystem. - var dir_name_buf: [std.fs.max_path_bytes]u8 = undefined; + var dir_name_buf: [max_path_bytes]u8 = undefined; var dir_name: []const u8 = sub_path; // Here we must avoid recursion, in order to provide O(1) memory guarantee of this function. @@ -1521,6 +1640,26 @@ pub fn copyFile( try atomic_file.finish(); } +/// Same as `copyFile`, except asserts that both `source_path` and `dest_path` +/// are absolute. +/// +/// On Windows, both paths should be encoded as [WTF-8](https://wtf-8.codeberg.page/). +/// 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, + io: Io, + options: CopyFileOptions, +) !void { + assert(path.isAbsolute(source_path)); + assert(path.isAbsolute(dest_path)); + const my_cwd = cwd(); + return copyFile(my_cwd, source_path, my_cwd, dest_path, io, options); +} + +test copyFileAbsolute {} + pub const AtomicFileOptions = struct { permissions: File.Permissions = .default_file, make_path: bool = false, @@ -1538,13 +1677,13 @@ pub const AtomicFileOptions = struct { /// On WASI, `dest_path` should be encoded as valid UTF-8. /// On other platforms, `dest_path` is an opaque sequence of bytes with no particular encoding. pub fn atomicFile(parent: Dir, io: Io, dest_path: []const u8, options: AtomicFileOptions) !File.Atomic { - if (std.fs.path.dirname(dest_path)) |dirname| { + if (path.dirname(dest_path)) |dirname| { const dir = if (options.make_path) try parent.makeOpenPath(io, dirname, .{}) else try parent.openDir(io, dirname, .{}); - return .init(std.fs.path.basename(dest_path), options.permissions, dir, true, options.write_buffer); + return .init(path.basename(dest_path), options.permissions, dir, true, options.write_buffer); } else { return .init(dest_path, options.permissions, parent, false, options.write_buffer); } diff --git a/lib/std/Io/File.zig b/lib/std/Io/File.zig index b24c0b5100..8e71f648e2 100644 --- a/lib/std/Io/File.zig +++ b/lib/std/Io/File.zig @@ -489,22 +489,6 @@ pub const WriteFileStreamingError = error{ SystemResources, } || Io.Cancelable || Io.UnexpectedError; -/// Opens a file for reading or writing, without attempting to create a new -/// file, based on an absolute path. -/// -/// Returns an open resource to be released with `close`. -/// -/// Asserts that the path is absolute. See `Dir.openFile` for a function that -/// operates on both absolute and relative paths. -/// -/// On Windows, `absolute_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/). -/// 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 openAbsolute(io: Io, absolute_path: []const u8, flags: OpenFlags) OpenError!File { - assert(std.fs.path.isAbsolute(absolute_path)); - return Io.Dir.cwd().openFile(io, absolute_path, flags); -} - pub const SeekError = error{ Unseekable, /// The file descriptor does not hold the required rights to seek on it. @@ -579,3 +563,9 @@ pub const DowngradeLockError = Io.Cancelable || Io.UnexpectedError; pub fn downgradeLock(file: File, io: Io) LockError!void { return io.vtable.fileDowngradeLock(io.userdata, file); } + +test { + _ = Reader; + _ = Writer; + _ = Atomic; +} diff --git a/lib/std/crypto/Certificate/Bundle.zig b/lib/std/crypto/Certificate/Bundle.zig index eb60ad37a8..d4a9f1e757 100644 --- a/lib/std/crypto/Certificate/Bundle.zig +++ b/lib/std/crypto/Certificate/Bundle.zig @@ -221,7 +221,7 @@ pub fn addCertsFromFilePathAbsolute( now: Io.Timestamp, abs_file_path: []const u8, ) AddCertsFromFilePathError!void { - var file = try fs.openFileAbsolute(abs_file_path, .{}); + var file = try Io.Dir.openFileAbsolute(io, abs_file_path, .{}); defer file.close(io); var file_reader = file.reader(io, &.{}); return addCertsFromFile(cb, gpa, &file_reader, now.toSeconds()); diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 78c924f8d9..5f2d36323a 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -1,280 +1,28 @@ //! File System. -const builtin = @import("builtin"); -const native_os = builtin.os.tag; const std = @import("std.zig"); -const Io = std.Io; -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 posix = std.posix; -const windows = std.os.windows; - -const is_darwin = native_os.isDarwin(); - -/// Deprecated. -pub const AtomicFile = std.Io.File.Atomic; -/// Deprecated. -pub const Dir = std.Io.Dir; -/// Deprecated. -pub const File = std.Io.File; +/// Deprecated, use `std.Io.Dir.path`. pub const path = @import("fs/path.zig"); pub const wasi = @import("fs/wasi.zig"); pub const getAppDataDir = @import("fs/get_app_data_dir.zig").getAppDataDir; pub const GetAppDataDirError = @import("fs/get_app_data_dir.zig").GetAppDataDirError; -/// 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://wtf-8.codeberg.page/). -/// * 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, .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos, .freebsd, .openbsd, .netbsd, .dragonfly, .haiku, .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)), -}; - -/// 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://wtf-8.codeberg.page/). -/// 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, .driverkit, .ios, .maccatalyst, .macos, .tvos, .visionos, .watchos, .freebsd, .openbsd, .netbsd, .dragonfly, .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)), -}; - pub const base64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".*; /// 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); +pub const base64_encoder = std.base64.Base64Encoder.init(base64_alphabet, null); /// 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); - -/// 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://wtf-8.codeberg.page/). -/// 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, -) !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); -} - -test copyFileAbsolute {} - -/// 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://wtf-8.codeberg.page/). -/// 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); -} - -test makeDirAbsolute {} - -/// 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); -} - -test makeDirAbsoluteZ {} - -/// Same as `Dir.deleteDir` except the path is absolute. -/// On Windows, `dir_path` should be encoded as [WTF-8](https://wtf-8.codeberg.page/). -/// 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); -} - -/// 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); -} - -/// Deprecated in favor of `Io.Dir.cwd`. -pub fn cwd() Io.Dir { - return .cwd(); -} +pub const base64_decoder = std.base64.Base64Decoder.init(base64_alphabet, null); -pub fn defaultWasiCwd() std.os.wasi.fd_t { - // Expect the first preopen to be current working directory. - return 3; -} - -/// 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://wtf-8.codeberg.page/). -/// 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); -} - -/// Deprecated in favor of `Io.File.openAbsolute`. -pub fn openFileAbsolute(absolute_path: []const u8, flags: File.OpenFlags) Io.File.OpenError!Io.File { - var threaded: Io.Threaded = .init_single_threaded; - const io = threaded.ioBasic(); - return Io.File.openAbsolute(io, absolute_path, flags); -} - -/// 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://wtf-8.codeberg.page/). -/// 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: Io.Dir.AccessOptions) Dir.AccessError!void { - assert(path.isAbsolute(absolute_path)); - try cwd().access(absolute_path, flags); -} -/// 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://wtf-8.codeberg.page/). -/// 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); -} - -/// 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://wtf-8.codeberg.page/). -/// 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); -} - -/// 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://wtf-8.codeberg.page/). -/// 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(io: Io, 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; - - var dir = try cwd().openDir(dirname, .{}); - defer dir.close(io); - - return dir.deleteTree(path.basename(absolute_path)); -} - -/// 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://wtf-8.codeberg.page/). -/// 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); -} - -/// 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); -} +/// Deprecated, use `std.Io.Dir.max_path_bytes`. +pub const max_path_bytes = std.Io.Dir.max_path_bytes; +/// Deprecated, use `std.Io.Dir.max_name_bytes`. +pub const max_name_bytes = std.Io.Dir.max_name_bytes; test { - _ = AtomicFile; - _ = Dir; - _ = File; _ = path; _ = @import("fs/test.zig"); _ = @import("fs/get_app_data_dir.zig"); diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index 1a600fb82c..f4bdecf89d 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -2087,7 +2087,7 @@ test "'.' and '..' in absolute functions" { try fs.copyFileAbsolute(created_file_path, copied_file_path, .{}); const renamed_file_path = try fs.path.join(allocator, &.{ subdir_path, "../rename" }); try fs.renameAbsolute(copied_file_path, renamed_file_path); - const renamed_file = try fs.openFileAbsolute(renamed_file_path, .{}); + const renamed_file = try Dir.openFileAbsolute(renamed_file_path, .{}); renamed_file.close(io); try fs.deleteFileAbsolute(renamed_file_path); @@ -2202,20 +2202,19 @@ test "invalid UTF-8/WTF-8 paths" { try testing.expectError(expected_err, fs.rename(ctx.dir, invalid_path, ctx.dir, invalid_path)); if (native_os != .wasi and ctx.path_type != .relative) { - try testing.expectError(expected_err, fs.copyFileAbsolute(invalid_path, invalid_path, .{})); - try testing.expectError(expected_err, fs.makeDirAbsolute(invalid_path)); - try testing.expectError(expected_err, fs.deleteDirAbsolute(invalid_path)); - try testing.expectError(expected_err, fs.renameAbsolute(invalid_path, invalid_path)); - try testing.expectError(expected_err, fs.openDirAbsolute(invalid_path, .{})); - try testing.expectError(expected_err, fs.openFileAbsolute(invalid_path, .{})); - try testing.expectError(expected_err, fs.accessAbsolute(invalid_path, .{})); - try testing.expectError(expected_err, fs.createFileAbsolute(invalid_path, .{})); - try testing.expectError(expected_err, fs.deleteFileAbsolute(invalid_path)); - try testing.expectError(expected_err, fs.deleteTreeAbsolute(invalid_path)); - var readlink_buf: [fs.max_path_bytes]u8 = undefined; - try testing.expectError(expected_err, fs.readLinkAbsolute(invalid_path, &readlink_buf)); - try testing.expectError(expected_err, fs.symLinkAbsolute(invalid_path, invalid_path, .{})); - try testing.expectError(expected_err, fs.realpathAlloc(testing.allocator, invalid_path)); + try testing.expectError(expected_err, Dir.copyFileAbsolute(invalid_path, invalid_path, .{})); + try testing.expectError(expected_err, Dir.makeDirAbsolute(invalid_path)); + try testing.expectError(expected_err, Dir.deleteDirAbsolute(invalid_path)); + try testing.expectError(expected_err, Dir.renameAbsolute(invalid_path, invalid_path)); + try testing.expectError(expected_err, Dir.openDirAbsolute(invalid_path, .{})); + try testing.expectError(expected_err, Dir.openFileAbsolute(invalid_path, .{})); + try testing.expectError(expected_err, Dir.accessAbsolute(invalid_path, .{})); + try testing.expectError(expected_err, Dir.createFileAbsolute(invalid_path, .{})); + try testing.expectError(expected_err, Dir.deleteFileAbsolute(invalid_path)); + var readlink_buf: [Dir.max_path_bytes]u8 = undefined; + try testing.expectError(expected_err, Dir.readLinkAbsolute(invalid_path, &readlink_buf)); + try testing.expectError(expected_err, Dir.symLinkAbsolute(invalid_path, invalid_path, .{})); + try testing.expectError(expected_err, Dir.realpathAlloc(testing.allocator, invalid_path)); } } }.impl); diff --git a/lib/std/os.zig b/lib/std/os.zig index 77a3833c2b..667d743f3d 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -72,3 +72,8 @@ pub fn fstat_wasi(fd: posix.fd_t) FstatError!wasi.filestat_t { else => |err| return posix.unexpectedErrno(err), } } + +pub fn defaultWasiCwd() std.os.wasi.fd_t { + // Expect the first preopen to be current working directory. + return 3; +} diff --git a/lib/std/process.zig b/lib/std/process.zig index 77f91587fe..5d60190c2b 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -1576,7 +1576,7 @@ pub fn getUserInfo(name: []const u8) !UserInfo { /// TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else /// like NIS, AD, etc. See `man nss` or look at an strace for `id myuser`. pub fn posixGetUserInfo(io: Io, name: []const u8) !UserInfo { - const file = try std.fs.openFileAbsolute("/etc/passwd", .{}); + const file = try Io.Dir.openFileAbsolute(io, "/etc/passwd", .{}); defer file.close(io); var buffer: [4096]u8 = undefined; var file_reader = file.reader(&buffer); diff --git a/lib/std/std.zig b/lib/std/std.zig index 84e402f52b..106811859b 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -115,7 +115,7 @@ pub const Options = struct { enable_segfault_handler: bool = debug.default_enable_segfault_handler, /// Function used to implement `std.fs.cwd` for WASI. - wasiCwd: fn () os.wasi.fd_t = fs.defaultWasiCwd, + wasiCwd: fn () os.wasi.fd_t = os.defaultWasiCwd, /// The current log level. log_level: log.Level = log.default_level, diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index 5c110a576d..d3bafc16f2 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -1024,7 +1024,7 @@ fn detectAbiAndDynamicLinker(io: Io, cpu: Target.Cpu, os: Target.Os, query: Targ }; while (true) { - const file = fs.openFileAbsolute(file_name, .{}) catch |err| switch (err) { + const file = Io.Dir.openFileAbsolute(io, file_name, .{}) catch |err| switch (err) { error.NoSpaceLeft => return error.Unexpected, error.NameTooLong => return error.Unexpected, error.PathAlreadyExists => return error.Unexpected, diff --git a/lib/std/zig/system/linux.zig b/lib/std/zig/system/linux.zig index 668e5a1d99..60f4d7bfec 100644 --- a/lib/std/zig/system/linux.zig +++ b/lib/std/zig/system/linux.zig @@ -444,7 +444,7 @@ inline fn getAArch64CpuFeature(comptime feat_reg: []const u8) u64 { } pub fn detectNativeCpuAndFeatures(io: Io) ?Target.Cpu { - var file = fs.openFileAbsolute("/proc/cpuinfo", .{}) catch |err| switch (err) { + var file = Io.Dir.openFileAbsolute(io, "/proc/cpuinfo", .{}) catch |err| switch (err) { else => return null, }; defer file.close(io); |
