chiark / gitweb /
util: rm_rf_children() add root_dev parameter
authorHarald Hoyer <harald@redhat.com>
Wed, 16 May 2012 13:08:27 +0000 (15:08 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 21 May 2012 16:52:49 +0000 (18:52 +0200)
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
src/shared/util.h

index 681484bc0f01591bbfd5a15db233a01c8837d0d2..5acddd3e0f9250c61a6bfc0a5be4d19c3fca5a53 100644 (file)
@@ -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) {
 
index 4fccf96a6d3d9a8414c965ac17b762c7ecc4a525..2d890fa6a376a18ac5268a324835fa57b1ca2250 100644 (file)
@@ -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);