| ... | ... | @@ -63,3 +63,34 @@ pub fn statFile(self: Dir, sub_path: [:0]const u8) !File.Stat { |
| 63 | 63 | if (os == .linux) |
| 64 | 64 | return .fromPosix(try sys_linux.fstatat(@intFromEnum(self.fd), sub_path, 0)); |
| 65 | 65 | } |
| 66 | |
| 67 | pub fn makePath(self: Dir, sub_path: [:0]const u8) !void { |
| 68 | var it = try std.fs.path.componentIterator(sub_path); |
| 69 | var component = it.last() orelse return; |
| 70 | var zuffer: [sys_linux.NAME_MAX + 1]u8 = undefined; |
| 71 | while (true) { |
| 72 | @memcpy(zuffer[0..component.path.len], component.path); |
| 73 | zuffer[component.path.len] = 0; |
| 74 | self.makeDir(zuffer[0..component.path.len :0]) catch |err| switch (err) { |
| 75 | error.EEXIST => { |
| 76 | // stat the file and return an error if it's not a directory |
| 77 | // this is important because otherwise a dangling symlink |
| 78 | // could cause an infinite loop |
| 79 | check_dir: { |
| 80 | // workaround for windows, see https://github.com/ziglang/zig/issues/16738 |
| 81 | const fstat = self.statFile(zuffer[0..component.path.len :0]) catch |stat_err| switch (stat_err) { |
| 82 | error.EISDIR => break :check_dir, |
| 83 | else => |e| return e, |
| 84 | }; |
| 85 | if (fstat.kind() != .directory) return error.NotDir; |
| 86 | } |
| 87 | }, |
| 88 | error.ENOENT => |e| { |
| 89 | component = it.previous() orelse return e; |
| 90 | continue; |
| 91 | }, |
| 92 | else => |e| return e, |
| 93 | }; |
| 94 | component = it.next() orelse return; |
| 95 | } |
| 96 | } |