aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2025-11-25 06:36:49 -0800
committerAndrew Kelley <andrew@ziglang.org>2025-12-23 22:15:07 -0800
commit89bda60d28de5a44f445eaf056db45735176c1e3 (patch)
tree4a2cd6740444f24aaf30c5ee6800849aedacdb69 /lib/std
parentc3f2de5e519926eb0029062fe8e782a6f9df9c05 (diff)
downloadzig-89bda60d28de5a44f445eaf056db45735176c1e3.tar.gz
zig-89bda60d28de5a44f445eaf056db45735176c1e3.zip
std.Io.Threaded: implement makePath
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/Io.zig2
-rw-r--r--lib/std/Io/Dir.zig47
-rw-r--r--lib/std/Io/Threaded.zig53
3 files changed, 47 insertions, 55 deletions
diff --git a/lib/std/Io.zig b/lib/std/Io.zig
index dbf544c6d5..2453d10217 100644
--- a/lib/std/Io.zig
+++ b/lib/std/Io.zig
@@ -663,7 +663,7 @@ pub const VTable = struct {
futexWake: *const fn (?*anyopaque, ptr: *const u32, max_waiters: u32) void,
dirMake: *const fn (?*anyopaque, Dir, sub_path: []const u8, Dir.Mode) Dir.MakeError!void,
- dirMakePath: *const fn (?*anyopaque, Dir, sub_path: []const u8, Dir.Mode) Dir.MakeError!void,
+ dirMakePath: *const fn (?*anyopaque, Dir, sub_path: []const u8, Dir.Mode) Dir.MakePathError!Dir.MakePathStatus,
dirMakeOpenPath: *const fn (?*anyopaque, Dir, sub_path: []const u8, Dir.OpenOptions) Dir.MakeOpenPathError!Dir,
dirStat: *const fn (?*anyopaque, Dir) Dir.StatError!Dir.Stat,
dirStatPath: *const fn (?*anyopaque, Dir, sub_path: []const u8, Dir.StatPathOptions) Dir.StatPathError!File.Stat,
diff --git a/lib/std/Io/Dir.zig b/lib/std/Io/Dir.zig
index 3429fa6fdf..9116434191 100644
--- a/lib/std/Io/Dir.zig
+++ b/lib/std/Io/Dir.zig
@@ -206,7 +206,7 @@ pub fn updateFile(
}
if (std.fs.path.dirname(dest_path)) |dirname| {
- try dest_dir.makePath(io, dirname);
+ try dest_dir.makePathMode(io, dirname, default_mode);
}
var buffer: [1000]u8 = undefined; // Used only when direct fd-to-fd is not available.
@@ -287,13 +287,17 @@ pub fn makeDir(dir: Dir, io: Io, sub_path: []const u8) MakeError!void {
pub const MakePathError = MakeError || StatPathError;
-/// Calls makeDir iteratively to make an entire path, creating any parent
-/// directories that do not exist.
+/// Same as `makePathMode` but passes `default_mode`.
+pub fn makePath(dir: Dir, io: Io, sub_path: []const u8) MakePathError!void {
+ _ = try io.vtable.dirMakePath(io.userdata, dir, sub_path, default_mode);
+}
+
+/// Creates parent directories as necessary to ensure `sub_path` exists as a directory.
///
/// Returns success if the path already exists and is a directory.
///
-/// This function is not atomic, and if it returns an error, the file system
-/// may have been modified regardless.
+/// This function may not be atomic. If it returns an error, the file system
+/// may have been modified.
///
/// Fails on an empty path with `error.BadPathName` as that is not a path that
/// can be created.
@@ -309,8 +313,8 @@ pub const MakePathError = MakeError || StatPathError;
/// - On other platforms, `..` are not resolved before the path is passed to `mkdirat`,
/// meaning a `sub_path` like "first/../second" will create both a `./first`
/// and a `./second` directory.
-pub fn makePath(dir: Dir, io: Io, sub_path: []const u8) MakePathError!void {
- _ = try makePathStatus(dir, io, sub_path);
+pub fn makePathMode(dir: Dir, io: Io, sub_path: []const u8, mode: Mode) MakePathError!void {
+ _ = try io.vtable.dirMakePath(io.userdata, dir, sub_path, mode);
}
pub const MakePathStatus = enum { existed, created };
@@ -318,34 +322,7 @@ pub const MakePathStatus = enum { existed, created };
/// Same as `makePath` except returns whether the path already existed or was
/// successfully created.
pub fn makePathStatus(dir: Dir, io: Io, sub_path: []const u8) MakePathError!MakePathStatus {
- var it = std.fs.path.componentIterator(sub_path);
- var status: MakePathStatus = .existed;
- var component = it.last() orelse return error.BadPathName;
- while (true) {
- if (makeDir(dir, io, component.path)) {
- status = .created;
- } else |err| switch (err) {
- error.PathAlreadyExists => {
- // stat the file and return an error if it's not a directory
- // this is important because otherwise a dangling symlink
- // could cause an infinite loop
- check_dir: {
- // workaround for windows, see https://github.com/ziglang/zig/issues/16738
- const fstat = statPath(dir, io, component.path, .{}) catch |stat_err| switch (stat_err) {
- error.IsDir => break :check_dir,
- else => |e| return e,
- };
- if (fstat.kind != .directory) return error.NotDir;
- }
- },
- error.FileNotFound => |e| {
- component = it.previous() orelse return e;
- continue;
- },
- else => |e| return e,
- }
- component = it.next() orelse return status;
- }
+ return io.vtable.dirMakePath(io.userdata, dir, sub_path, default_mode);
}
pub const MakeOpenPathError = MakeError || OpenError || StatPathError;
diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig
index 2a38fdf543..91f990498c 100644
--- a/lib/std/Io/Threaded.zig
+++ b/lib/std/Io/Threaded.zig
@@ -1455,27 +1455,42 @@ fn dirMakeWindows(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode
windows.CloseHandle(sub_dir_handle);
}
-const dirMakePath = switch (native_os) {
- .windows => dirMakePathWindows,
- else => dirMakePathPosix,
-};
-
-fn dirMakePathPosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {
+fn dirMakePath(
+ userdata: ?*anyopaque,
+ dir: Io.Dir,
+ sub_path: []const u8,
+ mode: Io.Dir.Mode,
+) Io.Dir.MakePathError!Io.Dir.MakePathStatus {
const t: *Threaded = @ptrCast(@alignCast(userdata));
- _ = t;
- _ = dir;
- _ = sub_path;
- _ = mode;
- @panic("TODO implement dirMakePathPosix");
-}
-fn dirMakePathWindows(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void {
- const t: *Threaded = @ptrCast(@alignCast(userdata));
- _ = t;
- _ = dir;
- _ = sub_path;
- _ = mode;
- @panic("TODO implement dirMakePathWindows");
+ var it = std.fs.path.componentIterator(sub_path);
+ var status: Io.Dir.MakePathStatus = .existed;
+ var component = it.last() orelse return error.BadPathName;
+ while (true) {
+ if (dirMake(t, dir, component.path, mode)) |_| {
+ status = .created;
+ } else |err| switch (err) {
+ error.PathAlreadyExists => {
+ // stat the file and return an error if it's not a directory
+ // this is important because otherwise a dangling symlink
+ // could cause an infinite loop
+ check_dir: {
+ // workaround for windows, see https://github.com/ziglang/zig/issues/16738
+ const fstat = dirStatPath(t, dir, component.path, .{}) catch |stat_err| switch (stat_err) {
+ error.IsDir => break :check_dir,
+ else => |e| return e,
+ };
+ if (fstat.kind != .directory) return error.NotDir;
+ }
+ },
+ error.FileNotFound => |e| {
+ component = it.previous() orelse return e;
+ continue;
+ },
+ else => |e| return e,
+ }
+ component = it.next() orelse return status;
+ }
}
const dirMakeOpenPath = switch (native_os) {