]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
switch_root: make dirent d_type usage more robust
authorKarel Zak <kzak@redhat.com>
Tue, 4 Mar 2014 10:45:44 +0000 (11:45 +0100)
committerKarel Zak <kzak@redhat.com>
Tue, 4 Mar 2014 10:45:44 +0000 (11:45 +0100)
Signed-off-by: Karel Zak <kzak@redhat.com>
sys-utils/switch_root.c

index f26f7dae4326163a0543428cbb167b49233a33e2..1222fb1b49fe74fd98b3edbaf8896338d9c1a981 100644 (file)
@@ -68,6 +68,7 @@ static int recursiveRemove(int fd)
 
        while(1) {
                struct dirent *d;
+               int isdir = 0;
 
                errno = 0;
                if (!(d = readdir(dir))) {
@@ -80,8 +81,10 @@ static int recursiveRemove(int fd)
 
                if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                        continue;
-
-               if (d->d_type == DT_DIR) {
+#ifdef _DIRENT_HAVE_D_TYPE
+               if (d->d_type == DT_DIR || d->d_type == DT_UNKNOWN)
+#endif
+               {
                        struct stat sb;
 
                        if (fstatat(dfd, d->d_name, &sb, AT_SYMLINK_NOFOLLOW)) {
@@ -90,7 +93,7 @@ static int recursiveRemove(int fd)
                        }
 
                        /* remove subdirectories if device is same as dir */
-                       if (sb.st_dev == rb.st_dev) {
+                       if (S_ISDIR(sb.st_mode) && sb.st_dev == rb.st_dev) {
                                int cfd;
 
                                cfd = openat(dfd, d->d_name, O_RDONLY);
@@ -98,12 +101,12 @@ static int recursiveRemove(int fd)
                                        recursiveRemove(cfd);
                                        close(cfd);
                                }
+                               isdir = 1;
                        } else
                                continue;
                }
 
-               if (unlinkat(dfd, d->d_name,
-                            d->d_type == DT_DIR ? AT_REMOVEDIR : 0))
+               if (unlinkat(dfd, d->d_name, isdir ? AT_REMOVEDIR : 0))
                        warn(_("failed to unlink %s"), d->d_name);
        }