summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/shared/util.c39
-rw-r--r--src/shared/util.h2
2 files changed, 27 insertions, 14 deletions
diff --git a/src/shared/util.c b/src/shared/util.c
index 681484bc0f..5acddd3e0f 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -3139,7 +3139,7 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
return 0;
}
-int rm_rf_children(int fd, bool only_dirs, bool honour_sticky) {
+int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) {
DIR *d;
int ret = 0;
@@ -3208,24 +3208,37 @@ int rm_rf_children(int fd, bool only_dirs, bool honour_sticky) {
if (is_dir) {
int subdir_fd;
-
- subdir_fd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
- if (subdir_fd < 0) {
- if (ret == 0 && errno != ENOENT)
- ret = -errno;
- continue;
+ struct stat sb;
+ if (root_dev) {
+ if (fstatat(fd, de->d_name, &sb, AT_SYMLINK_NOFOLLOW)) {
+ if (ret == 0 && errno != ENOENT)
+ ret = -errno;
+ continue;
+ }
}
- r = rm_rf_children(subdir_fd, only_dirs, honour_sticky);
- if (r < 0 && ret == 0)
- ret = r;
+ /* if root_dev is set, remove subdirectories only, if device is same as dir */
+ if ((root_dev == NULL) || (sb.st_dev == root_dev->st_dev)) {
- if (!keep_around)
- if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
+ subdir_fd = openat(fd, de->d_name,
+ O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
+ if (subdir_fd < 0) {
if (ret == 0 && errno != ENOENT)
ret = -errno;
+ continue;
}
+ r = rm_rf_children(subdir_fd, only_dirs, honour_sticky, root_dev);
+ if (r < 0 && ret == 0)
+ ret = r;
+
+ if (!keep_around)
+ if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) {
+ if (ret == 0 && errno != ENOENT)
+ ret = -errno;
+ }
+ }
+
} else if (!only_dirs && !keep_around) {
if (unlinkat(fd, de->d_name, 0) < 0) {
@@ -3259,7 +3272,7 @@ int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky
return 0;
}
- r = rm_rf_children(fd, only_dirs, honour_sticky);
+ r = rm_rf_children(fd, only_dirs, honour_sticky, NULL);
if (delete_root) {
diff --git a/src/shared/util.h b/src/shared/util.h
index 4fccf96a6d..2d890fa6a3 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -349,7 +349,7 @@ int get_ctty(pid_t, dev_t *_devnr, char **r);
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid);
-int rm_rf_children(int fd, bool only_dirs, bool honour_sticky);
+int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev);
int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky);
int pipe_eof(int fd);