| ... | @@ -1111,10 +1111,18 @@ pub const Dir = struct { | ... | @@ -1111,10 +1111,18 @@ pub const Dir = struct { |
| 1111 | /// Delete a file name and possibly the file it refers to, based on an open directory handle. | 1111 | /// Delete a file name and possibly the file it refers to, based on an open directory handle. |
| 1112 | /// Asserts that the path parameter has no null bytes. | 1112 | /// Asserts that the path parameter has no null bytes. |
| 1113 | pub fn deleteFile(self: Dir, sub_path: []const u8) DeleteFileError!void { | 1113 | pub fn deleteFile(self: Dir, sub_path: []const u8) DeleteFileError!void { |
| 1114 | os.unlinkat(self.fd, sub_path, 0) catch |err| switch (err) { | 1114 | if (builtin.os.tag == .windows) { |
| 1115 | error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR | 1115 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); |
| 1116 | else => |e| return e, | 1116 | return self.deleteFileW(sub_path_w.span().ptr); |
| 1117 | }; | 1117 | } else if (builtin.os.tag == .wasi) { |
| | 1118 | os.unlinkatWasi(self.fd, sub_path, 0) catch |err| switch (err) { |
| | 1119 | error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR |
| | 1120 | else => |e| return e, |
| | 1121 | }; |
| | 1122 | } else { |
| | 1123 | const sub_path_c = try os.toPosixPath(sub_path); |
| | 1124 | return self.deleteFileZ(&sub_path_c); |
| | 1125 | } |
| 1118 | } | 1126 | } |
| 1119 | | 1127 | |
| 1120 | pub const deleteFileC = @compileError("deprecated: renamed to deleteFileZ"); | 1128 | pub const deleteFileC = @compileError("deprecated: renamed to deleteFileZ"); |
| ... | @@ -1123,6 +1131,17 @@ pub const Dir = struct { | ... | @@ -1123,6 +1131,17 @@ pub const Dir = struct { |
| 1123 | pub fn deleteFileZ(self: Dir, sub_path_c: [*:0]const u8) DeleteFileError!void { | 1131 | pub fn deleteFileZ(self: Dir, sub_path_c: [*:0]const u8) DeleteFileError!void { |
| 1124 | os.unlinkatZ(self.fd, sub_path_c, 0) catch |err| switch (err) { | 1132 | os.unlinkatZ(self.fd, sub_path_c, 0) catch |err| switch (err) { |
| 1125 | error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR | 1133 | error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR |
| | 1134 | error.AccessDenied => |e| switch (builtin.os.tag) { |
| | 1135 | // non-Linux POSIX systems return EPERM when trying to delete a directory, so |
| | 1136 | // we need to handle that case specifically and translate the error |
| | 1137 | .macosx, .ios, .freebsd, .netbsd, .dragonfly => { |
| | 1138 | // Don't follow symlinks to match unlinkat (which acts on symlinks rather than follows them) |
| | 1139 | const fstat = os.fstatatZ(self.fd, sub_path_c, os.AT_SYMLINK_NOFOLLOW) catch return e; |
| | 1140 | const is_dir = fstat.mode & os.S_IFMT == os.S_IFDIR; |
| | 1141 | return if (is_dir) error.IsDir else e; |
| | 1142 | }, |
| | 1143 | else => return e, |
| | 1144 | }, |
| 1126 | else => |e| return e, | 1145 | else => |e| return e, |
| 1127 | }; | 1146 | }; |
| 1128 | } | 1147 | } |