recurse.c - sbase - suckless unix tools
 (HTM) git clone git://git.suckless.org/sbase
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       recurse.c (2454B)
       ---
            1 /* See LICENSE file for copyright and license details. */
            2 #include <dirent.h>
            3 #include <errno.h>
            4 #include <fcntl.h>
            5 #include <limits.h>
            6 #include <stdio.h>
            7 #include <stdlib.h>
            8 #include <string.h>
            9 #include <sys/stat.h>
           10 #include <sys/types.h>
           11 #include <unistd.h>
           12 
           13 #include "../fs.h"
           14 #include "../util.h"
           15 
           16 int recurse_status = 0;
           17 
           18 void
           19 recurse(int dirfd, const char *name, void *data, struct recursor *r)
           20 {
           21         struct dirent *d;
           22         struct history *new, *h;
           23         struct stat st, dst;
           24         DIR *dp;
           25         int flags = 0, fd;
           26         size_t pathlen = r->pathlen;
           27 
           28         if (dirfd == AT_FDCWD)
           29                 pathlen = estrlcpy(r->path, name, sizeof(r->path));
           30 
           31         if (r->follow == 'P' || (r->follow == 'H' && r->depth))
           32                 flags |= AT_SYMLINK_NOFOLLOW;
           33 
           34         if (fstatat(dirfd, name, &st, flags) < 0) {
           35                 if (!(r->flags & SILENT)) {
           36                         weprintf("stat %s:", r->path);
           37                         recurse_status = 1;
           38                 }
           39                 return;
           40         }
           41         if (!S_ISDIR(st.st_mode)) {
           42                 r->fn(dirfd, name, &st, data, r);
           43                 return;
           44         }
           45 
           46         new = emalloc(sizeof(struct history));
           47         new->prev  = r->hist;
           48         r->hist    = new;
           49         new->dev   = st.st_dev;
           50         new->ino   = st.st_ino;
           51 
           52         for (h = new->prev; h; h = h->prev)
           53                 if (h->ino == st.st_ino && h->dev == st.st_dev)
           54                         return;
           55 
           56         if (!r->depth && (r->flags & DIRFIRST))
           57                 r->fn(dirfd, name, &st, data, r);
           58 
           59         if (!r->maxdepth || r->depth + 1 < r->maxdepth) {
           60                 fd = openat(dirfd, name, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
           61                 if (fd < 0) {
           62                         weprintf("open %s:", r->path);
           63                         recurse_status = 1;
           64                 }
           65                 if (!(dp = fdopendir(fd))) {
           66                         if (!(r->flags & SILENT)) {
           67                                 weprintf("fdopendir:");
           68                                 recurse_status = 1;
           69                         }
           70                         return;
           71                 }
           72                 if (r->path[pathlen - 1] != '/')
           73                         r->path[pathlen++] = '/';
           74                 if (r->follow == 'H')
           75                         flags |= AT_SYMLINK_NOFOLLOW;
           76                 while ((d = readdir(dp))) {
           77                         if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
           78                                 continue;
           79                         r->pathlen = pathlen + estrlcpy(r->path + pathlen, d->d_name, sizeof(r->path) - pathlen);
           80                         if (fstatat(fd, d->d_name, &dst, flags) < 0) {
           81                                 if (!(r->flags & SILENT)) {
           82                                         weprintf("stat %s:", r->path);
           83                                         recurse_status = 1;
           84                                 }
           85                         } else if ((r->flags & SAMEDEV) && dst.st_dev != st.st_dev) {
           86                                 continue;
           87                         } else {
           88                                 r->depth++;
           89                                 r->fn(fd, d->d_name, &dst, data, r);
           90                                 r->depth--;
           91                         }
           92                 }
           93                 r->path[pathlen - 1] = '\0';
           94                 r->pathlen = pathlen - 1;
           95                 closedir(dp);
           96         }
           97 
           98         if (!r->depth) {
           99                 if (!(r->flags & DIRFIRST))
          100                         r->fn(dirfd, name, &st, data, r);
          101 
          102                 while (r->hist) {
          103                         h = r->hist;
          104                         r->hist = r->hist->prev;
          105                         free(h);
          106                 }
          107         }
          108 }