| ... | ... | @@ -2211,18 +2211,93 @@ pub const Dir = struct { |
| 2211 | 2211 | } |
| 2212 | 2212 | } |
| 2213 | 2213 | |
| 2214 | | top.parent_dir.deleteDir(top.name) catch |err| switch (err) { |
| 2214 | // On Windows, we can't delete until the dir's handle has been closed, so |
| 2215 | // close it before we try to delete. |
| 2216 | top.iter.dir.close(); |
| 2217 | |
| 2218 | // In order to avoid double-closing the directory when cleaning up |
| 2219 | // the stack in the case of an error, we save the relevant portions and |
| 2220 | // pop the value from the stack. |
| 2221 | const parent_dir = top.parent_dir; |
| 2222 | const name = top.name; |
| 2223 | _ = stack.pop(); |
| 2224 | |
| 2225 | var need_to_retry: bool = false; |
| 2226 | parent_dir.deleteDir(name) catch |err| switch (err) { |
| 2215 | 2227 | error.FileNotFound => {}, |
| 2216 | | error.DirNotEmpty => { |
| 2217 | | // reset the iterator and try again |
| 2218 | | top.iter.reset(); |
| 2219 | | continue :process_stack; |
| 2220 | | }, |
| 2228 | error.DirNotEmpty => need_to_retry = false, |
| 2221 | 2229 | else => |e| return e, |
| 2222 | 2230 | }; |
| 2223 | 2231 | |
| 2224 | | top.iter.dir.close(); |
| 2225 | | _ = stack.pop(); |
| 2232 | if (need_to_retry) { |
| 2233 | // Since we closed the handle that the previous iterator used, we |
| 2234 | // need to re-open the dir and re-create the iterator. |
| 2235 | var iterable_dir = iterable_dir: { |
| 2236 | var treat_as_dir = true; |
| 2237 | handle_entry: while (true) { |
| 2238 | if (treat_as_dir) { |
| 2239 | break :iterable_dir parent_dir.openIterableDir(name, .{ .no_follow = true }) catch |err| switch (err) { |
| 2240 | error.NotDir => { |
| 2241 | treat_as_dir = false; |
| 2242 | continue :handle_entry; |
| 2243 | }, |
| 2244 | error.FileNotFound => { |
| 2245 | // That's fine, we were trying to remove this directory anyway. |
| 2246 | continue :process_stack; |
| 2247 | }, |
| 2248 | |
| 2249 | error.InvalidHandle, |
| 2250 | error.AccessDenied, |
| 2251 | error.SymLinkLoop, |
| 2252 | error.ProcessFdQuotaExceeded, |
| 2253 | error.NameTooLong, |
| 2254 | error.SystemFdQuotaExceeded, |
| 2255 | error.NoDevice, |
| 2256 | error.SystemResources, |
| 2257 | error.Unexpected, |
| 2258 | error.InvalidUtf8, |
| 2259 | error.BadPathName, |
| 2260 | error.DeviceBusy, |
| 2261 | => |e| return e, |
| 2262 | }; |
| 2263 | } else { |
| 2264 | if (parent_dir.deleteFile(name)) { |
| 2265 | continue :process_stack; |
| 2266 | } else |err| switch (err) { |
| 2267 | error.FileNotFound => continue :process_stack, |
| 2268 | |
| 2269 | // Impossible because we do not pass any path separators. |
| 2270 | error.NotDir => unreachable, |
| 2271 | |
| 2272 | error.IsDir => { |
| 2273 | treat_as_dir = true; |
| 2274 | continue :handle_entry; |
| 2275 | }, |
| 2276 | |
| 2277 | error.AccessDenied, |
| 2278 | error.InvalidUtf8, |
| 2279 | error.SymLinkLoop, |
| 2280 | error.NameTooLong, |
| 2281 | error.SystemResources, |
| 2282 | error.ReadOnlyFileSystem, |
| 2283 | error.FileSystem, |
| 2284 | error.FileBusy, |
| 2285 | error.BadPathName, |
| 2286 | error.Unexpected, |
| 2287 | => |e| return e, |
| 2288 | } |
| 2289 | } |
| 2290 | } |
| 2291 | }; |
| 2292 | // We know there is room on the stack since we are just re-adding |
| 2293 | // the StackItem that we previously popped. |
| 2294 | stack.appendAssumeCapacity(StackItem{ |
| 2295 | .name = name, |
| 2296 | .parent_dir = parent_dir, |
| 2297 | .iter = iterable_dir.iterateAssumeFirstIteration(), |
| 2298 | }); |
| 2299 | continue :process_stack; |
| 2300 | } |
| 2226 | 2301 | } |
| 2227 | 2302 | } |
| 2228 | 2303 | |