sbase

suckless unix tools
git clone git://git.suckless.org/sbase
Log | Files | Refs | README | 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 }