| ... | ... | @@ -2076,24 +2076,7 @@ pub const Dir = struct { |
| 2076 | 2076 | /// this function recursively removes its entries and then tries again. |
| 2077 | 2077 | /// This operation is not atomic on most file systems. |
| 2078 | 2078 | pub fn deleteTree(self: Dir, sub_path: []const u8) DeleteTreeError!void { |
| 2079 | | if (self.deleteFile(sub_path)) { |
| 2080 | | return; |
| 2081 | | } else |err| switch (err) { |
| 2082 | | error.FileNotFound => return, |
| 2083 | | error.IsDir => {}, |
| 2084 | | error.AccessDenied, |
| 2085 | | error.InvalidUtf8, |
| 2086 | | error.SymLinkLoop, |
| 2087 | | error.NameTooLong, |
| 2088 | | error.SystemResources, |
| 2089 | | error.ReadOnlyFileSystem, |
| 2090 | | error.NotDir, |
| 2091 | | error.FileSystem, |
| 2092 | | error.FileBusy, |
| 2093 | | error.BadPathName, |
| 2094 | | error.Unexpected, |
| 2095 | | => |e| return e, |
| 2096 | | } |
| 2079 | var initial_iterable_dir = (try self.deleteTreeOpenInitialSubpath(sub_path, .File)) orelse return; |
| 2097 | 2080 | |
| 2098 | 2081 | const StackItem = struct { |
| 2099 | 2082 | name: []const u8, |
| ... | ... | @@ -2108,32 +2091,6 @@ pub const Dir = struct { |
| 2108 | 2091 | } |
| 2109 | 2092 | } |
| 2110 | 2093 | |
| 2111 | | var initial_iterable_dir = self.openIterableDir(sub_path, .{ .no_follow = true }) catch |err| switch (err) { |
| 2112 | | error.NotDir => { |
| 2113 | | // Somehow the sub_path got changed into a file while we were trying to delete the tree. |
| 2114 | | // This implies that the dir at the sub_path was deleted at some point so we consider this |
| 2115 | | // as a successful delete and return. |
| 2116 | | return; |
| 2117 | | }, |
| 2118 | | error.FileNotFound => { |
| 2119 | | // That's fine, we were trying to remove this directory anyway. |
| 2120 | | return; |
| 2121 | | }, |
| 2122 | | error.InvalidHandle, |
| 2123 | | error.AccessDenied, |
| 2124 | | error.SymLinkLoop, |
| 2125 | | error.ProcessFdQuotaExceeded, |
| 2126 | | error.NameTooLong, |
| 2127 | | error.SystemFdQuotaExceeded, |
| 2128 | | error.NoDevice, |
| 2129 | | error.SystemResources, |
| 2130 | | error.Unexpected, |
| 2131 | | error.InvalidUtf8, |
| 2132 | | error.BadPathName, |
| 2133 | | error.DeviceBusy, |
| 2134 | | => |e| return e, |
| 2135 | | }; |
| 2136 | | |
| 2137 | 2094 | stack.appendAssumeCapacity(StackItem{ |
| 2138 | 2095 | .name = sub_path, |
| 2139 | 2096 | .parent_dir = self, |
| ... | ... | @@ -2309,62 +2266,7 @@ pub const Dir = struct { |
| 2309 | 2266 | |
| 2310 | 2267 | fn deleteTreeMinStackSizeWithKindHint(self: Dir, sub_path: []const u8, kind_hint: File.Kind) DeleteTreeError!void { |
| 2311 | 2268 | start_over: while (true) { |
| 2312 | | var iterable_dir = iterable_dir: { |
| 2313 | | var treat_as_dir = kind_hint == .Directory; |
| 2314 | | |
| 2315 | | handle_entry: while (true) { |
| 2316 | | if (treat_as_dir) { |
| 2317 | | break :iterable_dir self.openIterableDir(sub_path, .{ .no_follow = true }) catch |err| switch (err) { |
| 2318 | | error.NotDir => { |
| 2319 | | treat_as_dir = false; |
| 2320 | | continue :handle_entry; |
| 2321 | | }, |
| 2322 | | error.FileNotFound => { |
| 2323 | | // That's fine, we were trying to remove this directory anyway. |
| 2324 | | return; |
| 2325 | | }, |
| 2326 | | |
| 2327 | | error.InvalidHandle, |
| 2328 | | error.AccessDenied, |
| 2329 | | error.SymLinkLoop, |
| 2330 | | error.ProcessFdQuotaExceeded, |
| 2331 | | error.NameTooLong, |
| 2332 | | error.SystemFdQuotaExceeded, |
| 2333 | | error.NoDevice, |
| 2334 | | error.SystemResources, |
| 2335 | | error.Unexpected, |
| 2336 | | error.InvalidUtf8, |
| 2337 | | error.BadPathName, |
| 2338 | | error.DeviceBusy, |
| 2339 | | => |e| return e, |
| 2340 | | }; |
| 2341 | | } else { |
| 2342 | | if (self.deleteFile(sub_path)) { |
| 2343 | | return; |
| 2344 | | } else |err| switch (err) { |
| 2345 | | error.FileNotFound => return, |
| 2346 | | |
| 2347 | | error.IsDir => { |
| 2348 | | treat_as_dir = true; |
| 2349 | | continue :handle_entry; |
| 2350 | | }, |
| 2351 | | |
| 2352 | | error.AccessDenied, |
| 2353 | | error.InvalidUtf8, |
| 2354 | | error.SymLinkLoop, |
| 2355 | | error.NameTooLong, |
| 2356 | | error.SystemResources, |
| 2357 | | error.ReadOnlyFileSystem, |
| 2358 | | error.NotDir, |
| 2359 | | error.FileSystem, |
| 2360 | | error.FileBusy, |
| 2361 | | error.BadPathName, |
| 2362 | | error.Unexpected, |
| 2363 | | => |e| return e, |
| 2364 | | } |
| 2365 | | } |
| 2366 | | } |
| 2367 | | }; |
| 2269 | var iterable_dir = (try self.deleteTreeOpenInitialSubpath(sub_path, kind_hint)) orelse return; |
| 2368 | 2270 | var cleanup_dir_parent: ?IterableDir = null; |
| 2369 | 2271 | defer if (cleanup_dir_parent) |*d| d.close(); |
| 2370 | 2272 | |
| ... | ... | @@ -2470,6 +2372,67 @@ pub const Dir = struct { |
| 2470 | 2372 | } |
| 2471 | 2373 | } |
| 2472 | 2374 | |
| 2375 | /// On successful delete, returns null. |
| 2376 | fn deleteTreeOpenInitialSubpath(self: Dir, sub_path: []const u8, kind_hint: File.Kind) !?IterableDir { |
| 2377 | return iterable_dir: { |
| 2378 | // Treat as a file by default |
| 2379 | var treat_as_dir = kind_hint == .Directory; |
| 2380 | |
| 2381 | handle_entry: while (true) { |
| 2382 | if (treat_as_dir) { |
| 2383 | break :iterable_dir self.openIterableDir(sub_path, .{ .no_follow = true }) catch |err| switch (err) { |
| 2384 | error.NotDir => { |
| 2385 | treat_as_dir = false; |
| 2386 | continue :handle_entry; |
| 2387 | }, |
| 2388 | error.FileNotFound => { |
| 2389 | // That's fine, we were trying to remove this directory anyway. |
| 2390 | return null; |
| 2391 | }, |
| 2392 | |
| 2393 | error.InvalidHandle, |
| 2394 | error.AccessDenied, |
| 2395 | error.SymLinkLoop, |
| 2396 | error.ProcessFdQuotaExceeded, |
| 2397 | error.NameTooLong, |
| 2398 | error.SystemFdQuotaExceeded, |
| 2399 | error.NoDevice, |
| 2400 | error.SystemResources, |
| 2401 | error.Unexpected, |
| 2402 | error.InvalidUtf8, |
| 2403 | error.BadPathName, |
| 2404 | error.DeviceBusy, |
| 2405 | => |e| return e, |
| 2406 | }; |
| 2407 | } else { |
| 2408 | if (self.deleteFile(sub_path)) { |
| 2409 | return null; |
| 2410 | } else |err| switch (err) { |
| 2411 | error.FileNotFound => return null, |
| 2412 | |
| 2413 | error.IsDir => { |
| 2414 | treat_as_dir = true; |
| 2415 | continue :handle_entry; |
| 2416 | }, |
| 2417 | |
| 2418 | error.AccessDenied, |
| 2419 | error.InvalidUtf8, |
| 2420 | error.SymLinkLoop, |
| 2421 | error.NameTooLong, |
| 2422 | error.SystemResources, |
| 2423 | error.ReadOnlyFileSystem, |
| 2424 | error.NotDir, |
| 2425 | error.FileSystem, |
| 2426 | error.FileBusy, |
| 2427 | error.BadPathName, |
| 2428 | error.Unexpected, |
| 2429 | => |e| return e, |
| 2430 | } |
| 2431 | } |
| 2432 | } |
| 2433 | }; |
| 2434 | } |
| 2435 | |
| 2473 | 2436 | /// Writes content to the file system, creating a new file if it does not exist, truncating |
| 2474 | 2437 | /// if it already exists. |
| 2475 | 2438 | pub fn writeFile(self: Dir, sub_path: []const u8, data: []const u8) !void { |