aboutsummaryrefslogtreecommitdiffstats
path: root/brillo/files/safe_fd.cc
diff options
context:
space:
mode:
Diffstat (limited to 'brillo/files/safe_fd.cc')
-rw-r--r--brillo/files/safe_fd.cc56
1 files changed, 35 insertions, 21 deletions
diff --git a/brillo/files/safe_fd.cc b/brillo/files/safe_fd.cc
index 855207d..ac19dc3 100644
--- a/brillo/files/safe_fd.cc
+++ b/brillo/files/safe_fd.cc
@@ -446,7 +446,8 @@ SafeFD::Error SafeFD::Unlink(const std::string& name) {
SafeFD::Error SafeFD::Rmdir(const std::string& name,
bool recursive,
- size_t max_depth) {
+ size_t max_depth,
+ bool keep_going) {
if (!fd_.is_valid()) {
return SafeFD::Error::kNotInitialized;
}
@@ -460,6 +461,8 @@ SafeFD::Error SafeFD::Rmdir(const std::string& name,
return err;
}
+ SafeFD::Error last_err = SafeFD::Error::kNoError;
+
if (recursive) {
SafeFD dir_fd;
std::tie(dir_fd, err) =
@@ -490,32 +493,36 @@ SafeFD::Error SafeFD::Rmdir(const std::string& name,
errno = 0;
const dirent* entry = HANDLE_EINTR_IF_EQ(readdir(dir.get()), nullptr);
while (entry != nullptr) {
- if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
- goto continue_;
- }
+ SafeFD::Error err = [&]() {
+ if (strcmp(entry->d_name, ".") == 0 ||
+ strcmp(entry->d_name, "..") == 0) {
+ return SafeFD::Error::kNoError;
+ }
- struct stat child_info;
- if (fstatat(dir_fd.get(), entry->d_name, &child_info,
- AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW) != 0) {
- return SafeFD::Error::kIOError;
- }
+ struct stat child_info;
+ if (fstatat(dir_fd.get(), entry->d_name, &child_info,
+ AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW) != 0) {
+ return SafeFD::Error::kIOError;
+ }
- if (child_info.st_dev != dir_info.st_dev) {
- return SafeFD::Error::kBoundaryDetected;
- }
+ if (child_info.st_dev != dir_info.st_dev) {
+ return SafeFD::Error::kBoundaryDetected;
+ }
- SafeFD::Error err;
- if (entry->d_type == DT_DIR) {
- err = dir_fd.Rmdir(entry->d_name, true, max_depth - 1);
- } else {
- err = dir_fd.Unlink(entry->d_name);
- }
+ if (entry->d_type != DT_DIR) {
+ return dir_fd.Unlink(entry->d_name);
+ }
+
+ return dir_fd.Rmdir(entry->d_name, true, max_depth - 1, keep_going);
+ }();
if (IsError(err)) {
- return err;
+ if (!keep_going) {
+ return err;
+ }
+ last_err = err;
}
- continue_:
errno = 0;
entry = HANDLE_EINTR_IF_EQ(readdir(dir.get()), nullptr);
}
@@ -530,9 +537,16 @@ SafeFD::Error SafeFD::Rmdir(const std::string& name,
if (errno == ENOTDIR) {
return SafeFD::Error::kWrongType;
}
+ // If there was an error during the recursive delete, we expect unlink
+ // to fail with ENOTEMPTY and we bubble the error from recursion
+ // instead.
+ if (IsError(last_err) && errno == ENOTEMPTY) {
+ return last_err;
+ }
return SafeFD::Error::kIOError;
}
- return SafeFD::Error::kNoError;
+
+ return last_err;
}
} // namespace brillo