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 }