std.fs.deleteTree: Unify how the initial sub_path is treated between deleteTree/deleteTreeMinStackSize

This commit is contained in:
Ryan Liptak 2022-10-05 20:08:53 -07:00
parent 063c5f43e9
commit 1468eb12f3

View File

@ -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 {