| ... | @@ -2211,18 +2211,93 @@ pub const Dir = struct { | ... | @@ -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 | error.FileNotFound => {}, | 2227 | error.FileNotFound => {}, |
| 2216 | error.DirNotEmpty => { | 2228 | error.DirNotEmpty => need_to_retry = false, |
| 2217 | // reset the iterator and try again | | |
| 2218 | top.iter.reset(); | | |
| 2219 | continue :process_stack; | | |
| 2220 | }, | | |
| 2221 | else => |e| return e, | 2229 | else => |e| return e, |
| 2222 | }; | 2230 | }; |
| 2223 | | 2231 | |
| 2224 | top.iter.dir.close(); | 2232 | if (need_to_retry) { |
| 2225 | _ = stack.pop(); | 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 | |