Commit 1468eb12f3

Ryan Liptak <squeek502@hotmail.com>
2022-10-06 05:08:53
std.fs.deleteTree: Unify how the initial sub_path is treated between deleteTree/deleteTreeMinStackSize
1 parent 063c5f4
Changed files (1)
lib
std
lib/std/fs.zig
@@ -2076,24 +2076,7 @@ pub const Dir = struct {
     /// this function recursively removes its entries and then tries again.
     /// This operation is not atomic on most file systems.
     pub fn deleteTree(self: Dir, sub_path: []const u8) DeleteTreeError!void {
-        if (self.deleteFile(sub_path)) {
-            return;
-        } else |err| switch (err) {
-            error.FileNotFound => return,
-            error.IsDir => {},
-            error.AccessDenied,
-            error.InvalidUtf8,
-            error.SymLinkLoop,
-            error.NameTooLong,
-            error.SystemResources,
-            error.ReadOnlyFileSystem,
-            error.NotDir,
-            error.FileSystem,
-            error.FileBusy,
-            error.BadPathName,
-            error.Unexpected,
-            => |e| return e,
-        }
+        var initial_iterable_dir = (try self.deleteTreeOpenInitialSubpath(sub_path, .File)) orelse return;
 
         const StackItem = struct {
             name: []const u8,
@@ -2108,32 +2091,6 @@ pub const Dir = struct {
             }
         }
 
-        var initial_iterable_dir = self.openIterableDir(sub_path, .{ .no_follow = true }) catch |err| switch (err) {
-            error.NotDir => {
-                // Somehow the sub_path got changed into a file while we were trying to delete the tree.
-                // This implies that the dir at the sub_path was deleted at some point so we consider this
-                // as a successful delete and return.
-                return;
-            },
-            error.FileNotFound => {
-                // That's fine, we were trying to remove this directory anyway.
-                return;
-            },
-            error.InvalidHandle,
-            error.AccessDenied,
-            error.SymLinkLoop,
-            error.ProcessFdQuotaExceeded,
-            error.NameTooLong,
-            error.SystemFdQuotaExceeded,
-            error.NoDevice,
-            error.SystemResources,
-            error.Unexpected,
-            error.InvalidUtf8,
-            error.BadPathName,
-            error.DeviceBusy,
-            => |e| return e,
-        };
-
         stack.appendAssumeCapacity(StackItem{
             .name = sub_path,
             .parent_dir = self,
@@ -2309,62 +2266,7 @@ pub const Dir = struct {
 
     fn deleteTreeMinStackSizeWithKindHint(self: Dir, sub_path: []const u8, kind_hint: File.Kind) DeleteTreeError!void {
         start_over: while (true) {
-            var iterable_dir = iterable_dir: {
-                var treat_as_dir = kind_hint == .Directory;
-
-                handle_entry: while (true) {
-                    if (treat_as_dir) {
-                        break :iterable_dir self.openIterableDir(sub_path, .{ .no_follow = true }) catch |err| switch (err) {
-                            error.NotDir => {
-                                treat_as_dir = false;
-                                continue :handle_entry;
-                            },
-                            error.FileNotFound => {
-                                // That's fine, we were trying to remove this directory anyway.
-                                return;
-                            },
-
-                            error.InvalidHandle,
-                            error.AccessDenied,
-                            error.SymLinkLoop,
-                            error.ProcessFdQuotaExceeded,
-                            error.NameTooLong,
-                            error.SystemFdQuotaExceeded,
-                            error.NoDevice,
-                            error.SystemResources,
-                            error.Unexpected,
-                            error.InvalidUtf8,
-                            error.BadPathName,
-                            error.DeviceBusy,
-                            => |e| return e,
-                        };
-                    } else {
-                        if (self.deleteFile(sub_path)) {
-                            return;
-                        } else |err| switch (err) {
-                            error.FileNotFound => return,
-
-                            error.IsDir => {
-                                treat_as_dir = true;
-                                continue :handle_entry;
-                            },
-
-                            error.AccessDenied,
-                            error.InvalidUtf8,
-                            error.SymLinkLoop,
-                            error.NameTooLong,
-                            error.SystemResources,
-                            error.ReadOnlyFileSystem,
-                            error.NotDir,
-                            error.FileSystem,
-                            error.FileBusy,
-                            error.BadPathName,
-                            error.Unexpected,
-                            => |e| return e,
-                        }
-                    }
-                }
-            };
+            var iterable_dir = (try self.deleteTreeOpenInitialSubpath(sub_path, kind_hint)) orelse return;
             var cleanup_dir_parent: ?IterableDir = null;
             defer if (cleanup_dir_parent) |*d| d.close();
 
@@ -2470,6 +2372,67 @@ pub const Dir = struct {
         }
     }
 
+    /// On successful delete, returns null.
+    fn deleteTreeOpenInitialSubpath(self: Dir, sub_path: []const u8, kind_hint: File.Kind) !?IterableDir {
+        return iterable_dir: {
+            // Treat as a file by default
+            var treat_as_dir = kind_hint == .Directory;
+
+            handle_entry: while (true) {
+                if (treat_as_dir) {
+                    break :iterable_dir self.openIterableDir(sub_path, .{ .no_follow = true }) catch |err| switch (err) {
+                        error.NotDir => {
+                            treat_as_dir = false;
+                            continue :handle_entry;
+                        },
+                        error.FileNotFound => {
+                            // That's fine, we were trying to remove this directory anyway.
+                            return null;
+                        },
+
+                        error.InvalidHandle,
+                        error.AccessDenied,
+                        error.SymLinkLoop,
+                        error.ProcessFdQuotaExceeded,
+                        error.NameTooLong,
+                        error.SystemFdQuotaExceeded,
+                        error.NoDevice,
+                        error.SystemResources,
+                        error.Unexpected,
+                        error.InvalidUtf8,
+                        error.BadPathName,
+                        error.DeviceBusy,
+                        => |e| return e,
+                    };
+                } else {
+                    if (self.deleteFile(sub_path)) {
+                        return null;
+                    } else |err| switch (err) {
+                        error.FileNotFound => return null,
+
+                        error.IsDir => {
+                            treat_as_dir = true;
+                            continue :handle_entry;
+                        },
+
+                        error.AccessDenied,
+                        error.InvalidUtf8,
+                        error.SymLinkLoop,
+                        error.NameTooLong,
+                        error.SystemResources,
+                        error.ReadOnlyFileSystem,
+                        error.NotDir,
+                        error.FileSystem,
+                        error.FileBusy,
+                        error.BadPathName,
+                        error.Unexpected,
+                        => |e| return e,
+                    }
+                }
+            }
+        };
+    }
+
     /// Writes content to the file system, creating a new file if it does not exist, truncating
     /// if it already exists.
     pub fn writeFile(self: Dir, sub_path: []const u8, data: []const u8) !void {