| ... | ... | @@ -1104,27 +1104,29 @@ pub fn createFileW(self: Dir, sub_path_w: []const u16, flags: File.CreateFlags) |
| 1104 | 1104 | return file; |
| 1105 | 1105 | } |
| 1106 | 1106 | |
| 1107 | pub const MakeError = posix.MakeDirError; |
| 1108 | |
| 1107 | 1109 | /// Creates a single directory with a relative or absolute path. |
| 1108 | 1110 | /// To create multiple directories to make an entire path, see `makePath`. |
| 1109 | 1111 | /// To operate on only absolute paths, see `makeDirAbsolute`. |
| 1110 | 1112 | /// On Windows, `sub_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). |
| 1111 | 1113 | /// On WASI, `sub_path` should be encoded as valid UTF-8. |
| 1112 | 1114 | /// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding. |
| 1113 | | pub fn makeDir(self: Dir, sub_path: []const u8) !void { |
| 1115 | pub fn makeDir(self: Dir, sub_path: []const u8) MakeError!void { |
| 1114 | 1116 | try posix.mkdirat(self.fd, sub_path, default_mode); |
| 1115 | 1117 | } |
| 1116 | 1118 | |
| 1117 | 1119 | /// Same as `makeDir`, but `sub_path` is null-terminated. |
| 1118 | 1120 | /// To create multiple directories to make an entire path, see `makePath`. |
| 1119 | 1121 | /// To operate on only absolute paths, see `makeDirAbsoluteZ`. |
| 1120 | | pub fn makeDirZ(self: Dir, sub_path: [*:0]const u8) !void { |
| 1122 | pub fn makeDirZ(self: Dir, sub_path: [*:0]const u8) MakeError!void { |
| 1121 | 1123 | try posix.mkdiratZ(self.fd, sub_path, default_mode); |
| 1122 | 1124 | } |
| 1123 | 1125 | |
| 1124 | 1126 | /// Creates a single directory with a relative or absolute null-terminated WTF-16 LE-encoded path. |
| 1125 | 1127 | /// To create multiple directories to make an entire path, see `makePath`. |
| 1126 | 1128 | /// To operate on only absolute paths, see `makeDirAbsoluteW`. |
| 1127 | | pub fn makeDirW(self: Dir, sub_path: [*:0]const u16) !void { |
| 1129 | pub fn makeDirW(self: Dir, sub_path: [*:0]const u16) MakeError!void { |
| 1128 | 1130 | try posix.mkdiratW(self.fd, sub_path, default_mode); |
| 1129 | 1131 | } |
| 1130 | 1132 | |
| ... | ... | @@ -1144,7 +1146,7 @@ pub fn makeDirW(self: Dir, sub_path: [*:0]const u16) !void { |
| 1144 | 1146 | /// - On other platforms, `..` are not resolved before the path is passed to `mkdirat`, |
| 1145 | 1147 | /// meaning a `sub_path` like "first/../second" will create both a `./first` |
| 1146 | 1148 | /// and a `./second` directory. |
| 1147 | | pub fn makePath(self: Dir, sub_path: []const u8) !void { |
| 1149 | pub fn makePath(self: Dir, sub_path: []const u8) (MakeError || StatFileError)!void { |
| 1148 | 1150 | var it = try fs.path.componentIterator(sub_path); |
| 1149 | 1151 | var component = it.last() orelse return; |
| 1150 | 1152 | while (true) { |
| ... | ... | @@ -1178,7 +1180,7 @@ pub fn makePath(self: Dir, sub_path: []const u8) !void { |
| 1178 | 1180 | /// This function is not atomic, and if it returns an error, the file system may |
| 1179 | 1181 | /// have been modified regardless. |
| 1180 | 1182 | /// `sub_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). |
| 1181 | | fn makeOpenPathAccessMaskW(self: Dir, sub_path: []const u8, access_mask: u32, no_follow: bool) OpenError!Dir { |
| 1183 | fn makeOpenPathAccessMaskW(self: Dir, sub_path: []const u8, access_mask: u32, no_follow: bool) (MakeError || OpenError || StatFileError)!Dir { |
| 1182 | 1184 | const w = windows; |
| 1183 | 1185 | var it = try fs.path.componentIterator(sub_path); |
| 1184 | 1186 | // If there are no components in the path, then create a dummy component with the full path. |
| ... | ... | @@ -1198,12 +1200,27 @@ fn makeOpenPathAccessMaskW(self: Dir, sub_path: []const u8, access_mask: u32, no |
| 1198 | 1200 | component = it.previous() orelse return e; |
| 1199 | 1201 | continue; |
| 1200 | 1202 | }, |
| 1203 | error.PathAlreadyExists => result: { |
| 1204 | assert(!is_last); |
| 1205 | // stat the file and return an error if it's not a directory |
| 1206 | // this is important because otherwise a dangling symlink |
| 1207 | // could cause an infinite loop |
| 1208 | check_dir: { |
| 1209 | // workaround for windows, see https://github.com/ziglang/zig/issues/16738 |
| 1210 | const fstat = self.statFile(component.path) catch |stat_err| switch (stat_err) { |
| 1211 | error.IsDir => break :check_dir, |
| 1212 | else => |e| return e, |
| 1213 | }; |
| 1214 | if (fstat.kind != .directory) return error.NotDir; |
| 1215 | } |
| 1216 | break :result null; |
| 1217 | }, |
| 1201 | 1218 | else => |e| return e, |
| 1202 | 1219 | }; |
| 1203 | | |
| 1204 | | component = it.next() orelse return result; |
| 1205 | 1220 | // Don't leak the intermediate file handles |
| 1206 | | result.close(); |
| 1221 | errdefer if (result) |*dir| dir.close(); |
| 1222 | |
| 1223 | component = it.next() orelse return result.?; |
| 1207 | 1224 | } |
| 1208 | 1225 | } |
| 1209 | 1226 | |
| ... | ... | @@ -1213,7 +1230,7 @@ fn makeOpenPathAccessMaskW(self: Dir, sub_path: []const u8, access_mask: u32, no |
| 1213 | 1230 | /// On Windows, `sub_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). |
| 1214 | 1231 | /// On WASI, `sub_path` should be encoded as valid UTF-8. |
| 1215 | 1232 | /// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding. |
| 1216 | | pub fn makeOpenPath(self: Dir, sub_path: []const u8, open_dir_options: OpenDirOptions) !Dir { |
| 1233 | pub fn makeOpenPath(self: Dir, sub_path: []const u8, open_dir_options: OpenDirOptions) (MakeError || OpenError || StatFileError)!Dir { |
| 1217 | 1234 | return switch (native_os) { |
| 1218 | 1235 | .windows => { |
| 1219 | 1236 | const w = windows; |
| ... | ... | @@ -1516,10 +1533,17 @@ pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions) Ope |
| 1516 | 1533 | const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | |
| 1517 | 1534 | w.SYNCHRONIZE | w.FILE_TRAVERSE; |
| 1518 | 1535 | const flags: u32 = if (args.iterate) base_flags | w.FILE_LIST_DIRECTORY else base_flags; |
| 1519 | | const dir = try self.makeOpenDirAccessMaskW(sub_path_w, flags, .{ |
| 1536 | const dir = self.makeOpenDirAccessMaskW(sub_path_w, flags, .{ |
| 1520 | 1537 | .no_follow = args.no_follow, |
| 1521 | 1538 | .create_disposition = w.FILE_OPEN, |
| 1522 | | }); |
| 1539 | }) catch |err| switch (err) { |
| 1540 | error.ReadOnlyFileSystem => unreachable, |
| 1541 | error.DiskQuota => unreachable, |
| 1542 | error.NoSpaceLeft => unreachable, |
| 1543 | error.PathAlreadyExists => unreachable, |
| 1544 | error.LinkQuotaExceeded => unreachable, |
| 1545 | else => |e| return e, |
| 1546 | }; |
| 1523 | 1547 | return dir; |
| 1524 | 1548 | } |
| 1525 | 1549 | |
| ... | ... | @@ -1544,7 +1568,7 @@ const MakeOpenDirAccessMaskWOptions = struct { |
| 1544 | 1568 | create_disposition: u32, |
| 1545 | 1569 | }; |
| 1546 | 1570 | |
| 1547 | | fn makeOpenDirAccessMaskW(self: Dir, sub_path_w: [*:0]const u16, access_mask: u32, flags: MakeOpenDirAccessMaskWOptions) OpenError!Dir { |
| 1571 | fn makeOpenDirAccessMaskW(self: Dir, sub_path_w: [*:0]const u16, access_mask: u32, flags: MakeOpenDirAccessMaskWOptions) (MakeError || OpenError)!Dir { |
| 1548 | 1572 | const w = windows; |
| 1549 | 1573 | |
| 1550 | 1574 | var result = Dir{ |
| ... | ... | @@ -1585,6 +1609,7 @@ fn makeOpenDirAccessMaskW(self: Dir, sub_path_w: [*:0]const u16, access_mask: u3 |
| 1585 | 1609 | .SUCCESS => return result, |
| 1586 | 1610 | .OBJECT_NAME_INVALID => return error.BadPathName, |
| 1587 | 1611 | .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, |
| 1612 | .OBJECT_NAME_COLLISION => return error.PathAlreadyExists, |
| 1588 | 1613 | .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, |
| 1589 | 1614 | .NOT_A_DIRECTORY => return error.NotDir, |
| 1590 | 1615 | // This can happen if the directory has 'List folder contents' permission set to 'Deny' |