| ... | @@ -1104,27 +1104,29 @@ pub fn createFileW(self: Dir, sub_path_w: []const u16, flags: File.CreateFlags) | ... | @@ -1104,27 +1104,29 @@ pub fn createFileW(self: Dir, sub_path_w: []const u16, flags: File.CreateFlags) |
| 1104 | return file; | 1104 | return file; |
| 1105 | } | 1105 | } |
| 1106 | | 1106 | |
| | 1107 | pub const MakeError = posix.MakeDirError; |
| | 1108 | |
| 1107 | /// Creates a single directory with a relative or absolute path. | 1109 | /// Creates a single directory with a relative or absolute path. |
| 1108 | /// To create multiple directories to make an entire path, see `makePath`. | 1110 | /// To create multiple directories to make an entire path, see `makePath`. |
| 1109 | /// To operate on only absolute paths, see `makeDirAbsolute`. | 1111 | /// To operate on only absolute paths, see `makeDirAbsolute`. |
| 1110 | /// On Windows, `sub_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). | 1112 | /// On Windows, `sub_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). |
| 1111 | /// On WASI, `sub_path` should be encoded as valid UTF-8. | 1113 | /// On WASI, `sub_path` should be encoded as valid UTF-8. |
| 1112 | /// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding. | 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 | try posix.mkdirat(self.fd, sub_path, default_mode); | 1116 | try posix.mkdirat(self.fd, sub_path, default_mode); |
| 1115 | } | 1117 | } |
| 1116 | | 1118 | |
| 1117 | /// Same as `makeDir`, but `sub_path` is null-terminated. | 1119 | /// Same as `makeDir`, but `sub_path` is null-terminated. |
| 1118 | /// To create multiple directories to make an entire path, see `makePath`. | 1120 | /// To create multiple directories to make an entire path, see `makePath`. |
| 1119 | /// To operate on only absolute paths, see `makeDirAbsoluteZ`. | 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 | try posix.mkdiratZ(self.fd, sub_path, default_mode); | 1123 | try posix.mkdiratZ(self.fd, sub_path, default_mode); |
| 1122 | } | 1124 | } |
| 1123 | | 1125 | |
| 1124 | /// Creates a single directory with a relative or absolute null-terminated WTF-16 LE-encoded path. | 1126 | /// Creates a single directory with a relative or absolute null-terminated WTF-16 LE-encoded path. |
| 1125 | /// To create multiple directories to make an entire path, see `makePath`. | 1127 | /// To create multiple directories to make an entire path, see `makePath`. |
| 1126 | /// To operate on only absolute paths, see `makeDirAbsoluteW`. | 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 | try posix.mkdiratW(self.fd, sub_path, default_mode); | 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,7 +1146,7 @@ pub fn makeDirW(self: Dir, sub_path: [*:0]const u16) !void { |
| 1144 | /// - On other platforms, `..` are not resolved before the path is passed to `mkdirat`, | 1146 | /// - On other platforms, `..` are not resolved before the path is passed to `mkdirat`, |
| 1145 | /// meaning a `sub_path` like "first/../second" will create both a `./first` | 1147 | /// meaning a `sub_path` like "first/../second" will create both a `./first` |
| 1146 | /// and a `./second` directory. | 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 | var it = try fs.path.componentIterator(sub_path); | 1150 | var it = try fs.path.componentIterator(sub_path); |
| 1149 | var component = it.last() orelse return; | 1151 | var component = it.last() orelse return; |
| 1150 | while (true) { | 1152 | while (true) { |
| ... | @@ -1178,7 +1180,7 @@ pub fn makePath(self: Dir, sub_path: []const u8) !void { | ... | @@ -1178,7 +1180,7 @@ pub fn makePath(self: Dir, sub_path: []const u8) !void { |
| 1178 | /// This function is not atomic, and if it returns an error, the file system may | 1180 | /// This function is not atomic, and if it returns an error, the file system may |
| 1179 | /// have been modified regardless. | 1181 | /// have been modified regardless. |
| 1180 | /// `sub_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). | 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 | const w = windows; | 1184 | const w = windows; |
| 1183 | var it = try fs.path.componentIterator(sub_path); | 1185 | var it = try fs.path.componentIterator(sub_path); |
| 1184 | // If there are no components in the path, then create a dummy component with the full path. | 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,12 +1200,27 @@ fn makeOpenPathAccessMaskW(self: Dir, sub_path: []const u8, access_mask: u32, no |
| 1198 | component = it.previous() orelse return e; | 1200 | component = it.previous() orelse return e; |
| 1199 | continue; | 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 | else => |e| return e, | 1218 | else => |e| return e, |
| 1202 | }; | 1219 | }; |
| 1203 | | | |
| 1204 | component = it.next() orelse return result; | | |
| 1205 | // Don't leak the intermediate file handles | 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,7 +1230,7 @@ fn makeOpenPathAccessMaskW(self: Dir, sub_path: []const u8, access_mask: u32, no |
| 1213 | /// On Windows, `sub_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). | 1230 | /// On Windows, `sub_path` should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). |
| 1214 | /// On WASI, `sub_path` should be encoded as valid UTF-8. | 1231 | /// On WASI, `sub_path` should be encoded as valid UTF-8. |
| 1215 | /// On other platforms, `sub_path` is an opaque sequence of bytes with no particular encoding. | 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 | return switch (native_os) { | 1234 | return switch (native_os) { |
| 1218 | .windows => { | 1235 | .windows => { |
| 1219 | const w = windows; | 1236 | const w = windows; |
| ... | @@ -1516,10 +1533,17 @@ pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions) Ope | ... | @@ -1516,10 +1533,17 @@ pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions) Ope |
| 1516 | const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | | 1533 | const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | |
| 1517 | w.SYNCHRONIZE | w.FILE_TRAVERSE; | 1534 | w.SYNCHRONIZE | w.FILE_TRAVERSE; |
| 1518 | const flags: u32 = if (args.iterate) base_flags | w.FILE_LIST_DIRECTORY else base_flags; | 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 | .no_follow = args.no_follow, | 1537 | .no_follow = args.no_follow, |
| 1521 | .create_disposition = w.FILE_OPEN, | 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 | return dir; | 1547 | return dir; |
| 1524 | } | 1548 | } |
| 1525 | | 1549 | |
| ... | @@ -1544,7 +1568,7 @@ const MakeOpenDirAccessMaskWOptions = struct { | ... | @@ -1544,7 +1568,7 @@ const MakeOpenDirAccessMaskWOptions = struct { |
| 1544 | create_disposition: u32, | 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 | const w = windows; | 1572 | const w = windows; |
| 1549 | | 1573 | |
| 1550 | var result = Dir{ | 1574 | var result = Dir{ |
| ... | @@ -1585,6 +1609,7 @@ fn makeOpenDirAccessMaskW(self: Dir, sub_path_w: [*:0]const u16, access_mask: u3 | ... | @@ -1585,6 +1609,7 @@ fn makeOpenDirAccessMaskW(self: Dir, sub_path_w: [*:0]const u16, access_mask: u3 |
| 1585 | .SUCCESS => return result, | 1609 | .SUCCESS => return result, |
| 1586 | .OBJECT_NAME_INVALID => return error.BadPathName, | 1610 | .OBJECT_NAME_INVALID => return error.BadPathName, |
| 1587 | .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, | 1611 | .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, |
| | 1612 | .OBJECT_NAME_COLLISION => return error.PathAlreadyExists, |
| 1588 | .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, | 1613 | .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, |
| 1589 | .NOT_A_DIRECTORY => return error.NotDir, | 1614 | .NOT_A_DIRECTORY => return error.NotDir, |
| 1590 | // This can happen if the directory has 'List folder contents' permission set to 'Deny' | 1615 | // This can happen if the directory has 'List folder contents' permission set to 'Deny' |