sbase

suckless unix tools
git clone git://git.2f30.org/sbase
Log | Files | Refs | README | LICENSE

recurse.c (2257B)


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