]> err.no Git - util-linux/commitdiff
namei: better mount points detection
authorKarel Zak <kzak@redhat.com>
Fri, 9 Oct 2009 14:26:45 +0000 (16:26 +0200)
committerKarel Zak <kzak@redhat.com>
Fri, 9 Oct 2009 14:43:35 +0000 (16:43 +0200)
Reported-by: Sami Kerola <kerolasa@iki.fi>
Signed-off-by: Karel Zak <kzak@redhat.com>
misc-utils/namei.c

index 94a3c25914679e8adaf85e9eed58e546c4507555..f8f096d8679b46ebd94f22d157e3c4bee8d59b22 100644 (file)
@@ -61,6 +61,7 @@ struct namei {
        int             relstart;       /* offset of relative path in 'abslink' */
        struct namei    *next;          /* next item */
        int             level;
+       int             mountpoint;     /* is mount point */
 };
 
 struct idcache {
@@ -209,6 +210,31 @@ readlink_to_namei(struct namei *nm, const char *path)
        nm->abslink[sz] = '\0';
 }
 
+static struct stat *
+dotdot_stat(const char *dirname, struct stat *st)
+{
+       char *path;
+       size_t len;
+
+#define DOTDOTDIR      "/.."
+
+       if (!dirname)
+               return NULL;
+
+       len = strlen(dirname);
+       path = malloc(len + sizeof(DOTDOTDIR));
+       if (!path)
+               err(EXIT_FAILURE, _("out of memory?"));
+
+       memcpy(path, dirname, len);
+       memcpy(path + len, DOTDOTDIR, sizeof(DOTDOTDIR));
+
+       if (stat(path, st))
+               err(EXIT_FAILURE, _("could not stat '%s'"), path);
+       free(path);
+       return st;
+}
+
 static struct namei *
 new_namei(struct namei *parent, const char *path, const char *fname, int lev)
 {
@@ -236,6 +262,19 @@ new_namei(struct namei *parent, const char *path, const char *fname, int lev)
                add_gid(nm->st.st_gid);
        }
 
+       if ((flags & NAMEI_MNTS) && S_ISDIR(nm->st.st_mode)) {
+               struct stat stbuf, *sb = NULL;
+
+               if (parent && S_ISDIR(parent->st.st_mode))
+                       sb = &parent->st;
+               else if (!parent || S_ISLNK(parent->st.st_mode))
+                       sb = dotdot_stat(path, &stbuf);
+
+               if (sb && (sb->st_dev != nm->st.st_dev ||   /* different device */
+                          sb->st_ino == nm->st.st_ino))    /* root directory */
+                       nm->mountpoint = 1;
+       }
+
        return nm;
 }
 
@@ -368,9 +407,7 @@ print_namei(struct namei *nm, char *path)
 
                strmode(nm->st.st_mode, md);
 
-               if ((flags & NAMEI_MNTS) && prev &&
-                   S_ISDIR(nm->st.st_mode) && S_ISDIR(prev->st.st_mode) &&
-                   prev->st.st_dev != nm->st.st_dev)
+               if (nm->mountpoint)
                        md[0] = 'D';
 
                if (!(flags & NAMEI_VERTICAL)) {