[systemd-devel] [PATCH] util: rm_rf_children() add root_dev parameter

harald at redhat.com harald at redhat.com
Tue May 22 06:19:12 PDT 2012


From: Harald Hoyer <harald at redhat.com>

if root_dev is set, remove subdirectories only, if the device is the
same as the root_dev. This prevents to remove files across device
boundaries.
---
 src/shared/util.c |   39 ++++++++++++++++++++++++++-------------
 src/shared/util.h |    2 +-
 2 files changed, 27 insertions(+), 14 deletions(-)

diff --git a/src/shared/util.c b/src/shared/util.c
index bfa9509..e6afc50 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -3131,7 +3131,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;
 
@@ -3200,24 +3200,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) {
@@ -3251,7 +3264,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 58db27f..698b60b 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -348,7 +348,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);
-- 
1.7.10.1



More information about the systemd-devel mailing list