| author | |
| committer | |
| log | 89bda60d28de5a44f445eaf056db45735176c1e3 |
| tree | 4a2cd6740444f24aaf30c5ee6800849aedacdb69 |
| parent | c3f2de5e519926eb0029062fe8e782a6f9df9c05 |
3 files changed, 47 insertions(+), 55 deletions(-)
lib/std/Io.zig+1-1| ... | ... | @@ -663,7 +663,7 @@ pub const VTable = struct { |
| 663 | 663 | futexWake: *const fn (?*anyopaque, ptr: *const u32, max_waiters: u32) void, |
| 664 | 664 | |
| 665 | 665 | dirMake: *const fn (?*anyopaque, Dir, sub_path: []const u8, Dir.Mode) Dir.MakeError!void, |
| 666 | dirMakePath: *const fn (?*anyopaque, Dir, sub_path: []const u8, Dir.Mode) Dir.MakeError!void, | |
| 666 | dirMakePath: *const fn (?*anyopaque, Dir, sub_path: []const u8, Dir.Mode) Dir.MakePathError!Dir.MakePathStatus, | |
| 667 | 667 | dirMakeOpenPath: *const fn (?*anyopaque, Dir, sub_path: []const u8, Dir.OpenOptions) Dir.MakeOpenPathError!Dir, |
| 668 | 668 | dirStat: *const fn (?*anyopaque, Dir) Dir.StatError!Dir.Stat, |
| 669 | 669 | dirStatPath: *const fn (?*anyopaque, Dir, sub_path: []const u8, Dir.StatPathOptions) Dir.StatPathError!File.Stat, |
lib/std/Io/Dir.zig+12-35| ... | ... | @@ -206,7 +206,7 @@ pub fn updateFile( |
| 206 | 206 | } |
| 207 | 207 | |
| 208 | 208 | if (std.fs.path.dirname(dest_path)) |dirname| { |
| 209 | try dest_dir.makePath(io, dirname); | |
| 209 | try dest_dir.makePathMode(io, dirname, default_mode); | |
| 210 | 210 | } |
| 211 | 211 | |
| 212 | 212 | 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 { |
| 287 | 287 | |
| 288 | 288 | pub const MakePathError = MakeError || StatPathError; |
| 289 | 289 | |
| 290 | /// Calls makeDir iteratively to make an entire path, creating any parent | |
| 291 | /// directories that do not exist. | |
| 290 | /// Same as `makePathMode` but passes `default_mode`. | |
| 291 | pub fn makePath(dir: Dir, io: Io, sub_path: []const u8) MakePathError!void { | |
| 292 | _ = try io.vtable.dirMakePath(io.userdata, dir, sub_path, default_mode); | |
| 293 | } | |
| 294 | ||
| 295 | /// Creates parent directories as necessary to ensure `sub_path` exists as a directory. | |
| 292 | 296 | /// |
| 293 | 297 | /// Returns success if the path already exists and is a directory. |
| 294 | 298 | /// |
| 295 | /// This function is not atomic, and if it returns an error, the file system | |
| 296 | /// may have been modified regardless. | |
| 299 | /// This function may not be atomic. If it returns an error, the file system | |
| 300 | /// may have been modified. | |
| 297 | 301 | /// |
| 298 | 302 | /// Fails on an empty path with `error.BadPathName` as that is not a path that |
| 299 | 303 | /// can be created. |
| ... | ... | @@ -309,8 +313,8 @@ pub const MakePathError = MakeError || StatPathError; |
| 309 | 313 | /// - On other platforms, `..` are not resolved before the path is passed to `mkdirat`, |
| 310 | 314 | /// meaning a `sub_path` like "first/../second" will create both a `./first` |
| 311 | 315 | /// and a `./second` directory. |
| 312 | pub fn makePath(dir: Dir, io: Io, sub_path: []const u8) MakePathError!void { | |
| 313 | _ = try makePathStatus(dir, io, sub_path); | |
| 316 | pub fn makePathMode(dir: Dir, io: Io, sub_path: []const u8, mode: Mode) MakePathError!void { | |
| 317 | _ = try io.vtable.dirMakePath(io.userdata, dir, sub_path, mode); | |
| 314 | 318 | } |
| 315 | 319 | |
| 316 | 320 | pub const MakePathStatus = enum { existed, created }; |
| ... | ... | @@ -318,34 +322,7 @@ pub const MakePathStatus = enum { existed, created }; |
| 318 | 322 | /// Same as `makePath` except returns whether the path already existed or was |
| 319 | 323 | /// successfully created. |
| 320 | 324 | pub fn makePathStatus(dir: Dir, io: Io, sub_path: []const u8) MakePathError!MakePathStatus { |
| 321 | var it = std.fs.path.componentIterator(sub_path); | |
| 322 | var status: MakePathStatus = .existed; | |
| 323 | var component = it.last() orelse return error.BadPathName; | |
| 324 | while (true) { | |
| 325 | if (makeDir(dir, io, component.path)) { | |
| 326 | status = .created; | |
| 327 | } else |err| switch (err) { | |
| 328 | error.PathAlreadyExists => { | |
| 329 | // stat the file and return an error if it's not a directory | |
| 330 | // this is important because otherwise a dangling symlink | |
| 331 | // could cause an infinite loop | |
| 332 | check_dir: { | |
| 333 | // workaround for windows, see https://github.com/ziglang/zig/issues/16738 | |
| 334 | const fstat = statPath(dir, io, component.path, .{}) catch |stat_err| switch (stat_err) { | |
| 335 | error.IsDir => break :check_dir, | |
| 336 | else => |e| return e, | |
| 337 | }; | |
| 338 | if (fstat.kind != .directory) return error.NotDir; | |
| 339 | } | |
| 340 | }, | |
| 341 | error.FileNotFound => |e| { | |
| 342 | component = it.previous() orelse return e; | |
| 343 | continue; | |
| 344 | }, | |
| 345 | else => |e| return e, | |
| 346 | } | |
| 347 | component = it.next() orelse return status; | |
| 348 | } | |
| 325 | return io.vtable.dirMakePath(io.userdata, dir, sub_path, default_mode); | |
| 349 | 326 | } |
| 350 | 327 | |
| 351 | 328 | pub const MakeOpenPathError = MakeError || OpenError || StatPathError; |
lib/std/Io/Threaded.zig+34-19| ... | ... | @@ -1455,27 +1455,42 @@ fn dirMakeWindows(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode |
| 1455 | 1455 | windows.CloseHandle(sub_dir_handle); |
| 1456 | 1456 | } |
| 1457 | 1457 | |
| 1458 | const dirMakePath = switch (native_os) { | |
| 1459 | .windows => dirMakePathWindows, | |
| 1460 | else => dirMakePathPosix, | |
| 1461 | }; | |
| 1462 | ||
| 1463 | fn dirMakePathPosix(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void { | |
| 1458 | fn dirMakePath( | |
| 1459 | userdata: ?*anyopaque, | |
| 1460 | dir: Io.Dir, | |
| 1461 | sub_path: []const u8, | |
| 1462 | mode: Io.Dir.Mode, | |
| 1463 | ) Io.Dir.MakePathError!Io.Dir.MakePathStatus { | |
| 1464 | 1464 | const t: *Threaded = @ptrCast(@alignCast(userdata)); |
| 1465 | _ = t; | |
| 1466 | _ = dir; | |
| 1467 | _ = sub_path; | |
| 1468 | _ = mode; | |
| 1469 | @panic("TODO implement dirMakePathPosix"); | |
| 1470 | } | |
| 1471 | 1465 | |
| 1472 | fn dirMakePathWindows(userdata: ?*anyopaque, dir: Io.Dir, sub_path: []const u8, mode: Io.Dir.Mode) Io.Dir.MakeError!void { | |
| 1473 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | |
| 1474 | _ = t; | |
| 1475 | _ = dir; | |
| 1476 | _ = sub_path; | |
| 1477 | _ = mode; | |
| 1478 | @panic("TODO implement dirMakePathWindows"); | |
| 1466 | var it = std.fs.path.componentIterator(sub_path); | |
| 1467 | var status: Io.Dir.MakePathStatus = .existed; | |
| 1468 | var component = it.last() orelse return error.BadPathName; | |
| 1469 | while (true) { | |
| 1470 | if (dirMake(t, dir, component.path, mode)) |_| { | |
| 1471 | status = .created; | |
| 1472 | } else |err| switch (err) { | |
| 1473 | error.PathAlreadyExists => { | |
| 1474 | // stat the file and return an error if it's not a directory | |
| 1475 | // this is important because otherwise a dangling symlink | |
| 1476 | // could cause an infinite loop | |
| 1477 | check_dir: { | |
| 1478 | // workaround for windows, see https://github.com/ziglang/zig/issues/16738 | |
| 1479 | const fstat = dirStatPath(t, dir, component.path, .{}) catch |stat_err| switch (stat_err) { | |
| 1480 | error.IsDir => break :check_dir, | |
| 1481 | else => |e| return e, | |
| 1482 | }; | |
| 1483 | if (fstat.kind != .directory) return error.NotDir; | |
| 1484 | } | |
| 1485 | }, | |
| 1486 | error.FileNotFound => |e| { | |
| 1487 | component = it.previous() orelse return e; | |
| 1488 | continue; | |
| 1489 | }, | |
| 1490 | else => |e| return e, | |
| 1491 | } | |
| 1492 | component = it.next() orelse return status; | |
| 1493 | } | |
| 1479 | 1494 | } |
| 1480 | 1495 | |
| 1481 | 1496 | const dirMakeOpenPath = switch (native_os) { |