| ... | @@ -2076,24 +2076,7 @@ pub const Dir = struct { | ... | @@ -2076,24 +2076,7 @@ pub const Dir = struct { |
| 2076 | /// this function recursively removes its entries and then tries again. | 2076 | /// this function recursively removes its entries and then tries again. |
| 2077 | /// This operation is not atomic on most file systems. | 2077 | /// This operation is not atomic on most file systems. |
| 2078 | pub fn deleteTree(self: Dir, sub_path: []const u8) DeleteTreeError!void { | 2078 | pub fn deleteTree(self: Dir, sub_path: []const u8) DeleteTreeError!void { |
| 2079 | if (self.deleteFile(sub_path)) { | 2079 | var initial_iterable_dir = (try self.deleteTreeOpenInitialSubpath(sub_path, .File)) orelse return; |
| 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 | } | | |
| 2097 | | 2080 | |
| 2098 | const StackItem = struct { | 2081 | const StackItem = struct { |
| 2099 | name: []const u8, | 2082 | name: []const u8, |
| ... | @@ -2108,32 +2091,6 @@ pub const Dir = struct { | ... | @@ -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 | stack.appendAssumeCapacity(StackItem{ | 2094 | stack.appendAssumeCapacity(StackItem{ |
| 2138 | .name = sub_path, | 2095 | .name = sub_path, |
| 2139 | .parent_dir = self, | 2096 | .parent_dir = self, |
| ... | @@ -2309,62 +2266,7 @@ pub const Dir = struct { | ... | @@ -2309,62 +2266,7 @@ pub const Dir = struct { |
| 2309 | | 2266 | |
| 2310 | fn deleteTreeMinStackSizeWithKindHint(self: Dir, sub_path: []const u8, kind_hint: File.Kind) DeleteTreeError!void { | 2267 | fn deleteTreeMinStackSizeWithKindHint(self: Dir, sub_path: []const u8, kind_hint: File.Kind) DeleteTreeError!void { |
| 2311 | start_over: while (true) { | 2268 | start_over: while (true) { |
| 2312 | var iterable_dir = iterable_dir: { | 2269 | var iterable_dir = (try self.deleteTreeOpenInitialSubpath(sub_path, kind_hint)) orelse return; |
| 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 | }; | | |
| 2368 | var cleanup_dir_parent: ?IterableDir = null; | 2270 | var cleanup_dir_parent: ?IterableDir = null; |
| 2369 | defer if (cleanup_dir_parent) |*d| d.close(); | 2271 | defer if (cleanup_dir_parent) |*d| d.close(); |
| 2370 | | 2272 | |
| ... | @@ -2470,6 +2372,67 @@ pub const Dir = struct { | ... | @@ -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 | /// Writes content to the file system, creating a new file if it does not exist, truncating | 2436 | /// Writes content to the file system, creating a new file if it does not exist, truncating |
| 2474 | /// if it already exists. | 2437 | /// if it already exists. |
| 2475 | pub fn writeFile(self: Dir, sub_path: []const u8, data: []const u8) !void { | 2438 | pub fn writeFile(self: Dir, sub_path: []const u8, data: []const u8) !void { |