commit f1bbe6529ab0a092731e5fa8ec9bf7d82a806f69
Author:     Quentin Rameau <[email protected]>
AuthorDate: Fri Jun 12 20:03:04 2015 +0200
Commit:     sin <[email protected]>
CommitDate: Mon Aug 31 18:10:25 2015 +0100

    ls: detect infinite loop with recursivity
    
    populate an history of visited directories inodes and search it before
    recursing

diff --git a/ls.c b/ls.c
index e726a7e..bb44357 100644
--- a/ls.c
+++ b/ls.c
@@ -21,9 +21,15 @@ struct entry {
        gid_t   gid;
        off_t   size;
        time_t  t;
-       ino_t   ino;
+       dev_t   dev;
+       ino_t   ino, tino;
 };
 
+static struct {
+       dev_t dev;
+       ino_t ino;
+} tree[PATH_MAX] = { { 0, 0 } };
+
 static int Aflag = 0;
 static int aflag = 0;
 static int cflag = 0;
@@ -69,9 +75,17 @@ mkent(struct entry *ent, char *path, int dostat, int follow)
                ent->t = st.st_atime;
        else
                ent->t = st.st_mtime;
+       ent->dev   = st.st_dev;
        ent->ino   = st.st_ino;
-       if (S_ISLNK(ent->mode))
-               ent->tmode = stat(path, &st) == 0 ? st.st_mode : 0;
+       if (S_ISLNK(ent->mode)) {
+               if (stat(path, &st) == 0) {
+                       ent->tmode = st.st_mode;
+                       ent->dev   = st.st_dev;
+                       ent->tino  = st.st_ino;
+               } else {
+                       ent->tmode = ent->tino = 0;
+               }
+       }
 }
 
 static char *
@@ -270,15 +284,42 @@ lsdir(const char *path, const struct entry *dir)
        free(ents);
 }
 
+static int
+visit(const struct entry *ent)
+{
+       dev_t dev;
+       ino_t ino;
+       int i;
+
+       dev = ent->dev;
+       ino = S_ISLNK(ent->mode) ? ent->tino : ent->ino;
+
+       for (i = 0; tree[i].ino && i < PATH_MAX; ++i) {
+               if (ino == tree[i].ino && dev == tree[i].dev)
+                       return -1;
+       }
+
+       tree[i].ino = ino;
+       tree[i].dev = dev;
+       return i;
+}
+
 static void
 ls(const char *path, const struct entry *ent, int listdir)
 {
+       int treeind;
        char cwd[PATH_MAX];
 
        if (!listdir) {
                output(ent);
        } else if (S_ISDIR(ent->mode) ||
            (S_ISLNK(ent->mode) && S_ISDIR(ent->tmode))) {
+               if ((treeind = visit(ent)) < 0) {
+                       fprintf(stderr, "%s%s: already visited\n",
+                           path, ent->name);
+                       return;
+               }
+
                if (!getcwd(cwd, PATH_MAX))
                        eprintf("getcwd:");
 
@@ -289,6 +330,7 @@ ls(const char *path, const struct entry *ent, int listdir)
 
                printf("%s", path);
                lsdir(path, ent);
+               tree[treeind].ino = 0;
 
                if (chdir(cwd) < 0)
                        eprintf("chdir %s:", cwd);

Reply via email to