mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
std.Io.Threaded: implement makePath
This commit is contained in:
parent
1e616096d4
commit
3edce5ea12
3 changed files with 47 additions and 55 deletions
|
|
@ -663,7 +663,7 @@ pub const VTable = struct {
|
|||
conditionWake: *const fn (?*anyopaque, cond: *Condition, wake: Condition.Wake) 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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1315,27 +1315,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 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));
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
fn dirMakePathPosix(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 dirMakePathPosix");
|
||||
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;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
const dirMakeOpenPath = switch (native_os) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue