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 }