/* See LICENSE file for copyright and license details. */ #include "common.h" struct recursion_buffer { char *buf; size_t size; size_t len; }; static int calculate_and_print(const char *file, struct barrier_group *group, struct global_data *global, struct recursion_buffer *recbuf, int is_top, int xlink, int xdev, dev_t dev) { static struct stat st; struct dirent *f; DIR *dir; size_t i, len, old_len; if (!recbuf) goto as_file; dir = opendir(file); if (!dir) goto as_file; if (!is_top && !xlink) { if (lstat(file, &st)) goto recusion_error_print; if (S_ISLNK(st.st_mode)) return 0; } if (!xdev) { if (fstat(dirfd(dir), &st)) goto recusion_error_print; if (is_top) dev = st.st_dev; else if (st.st_dev != dev) return 0; } if (recbuf->size - recbuf->len < strlen(file) + 1U) { recbuf->size = recbuf->len + strlen(file) + 1U; recbuf->buf = erealloc(recbuf->buf, recbuf->size); } old_len = recbuf->len; stpcpy(&recbuf->buf[recbuf->len], file); recbuf->len += strlen(file); if (recbuf->buf[recbuf->len - 1U] != '/') recbuf->buf[recbuf->len++] = '/'; len = recbuf->len; while ((errno = 0, f = readdir(dir))) { if (f->d_name[0] == '.' && !f->d_name[f->d_name[1] == '.' ? 2 : 1]) continue; if (recbuf->size - len < strlen(f->d_name) + 1U) { recbuf->size = len + strlen(f->d_name) + 1U; recbuf->buf = erealloc(recbuf->buf, recbuf->size); } stpcpy(&recbuf->buf[len], f->d_name); if (calculate_and_print(recbuf->buf, group, global, recbuf, 0, xlink, xdev, dev)) goto recusion_error; } recbuf->len = old_len; recbuf->buf[recbuf->len] = '\0'; if (errno) { recusion_error_print: weprintf("%s:", file); recusion_error: closedir(dir); return -1; } closedir(dir); return 0; as_file: global->file = file; if (calculate(global->file, group, global)) return -1; for (i = 0; i < global->nalgorithms; i++) writeall(STDOUT_FILENO, global->algorithms[i].result, global->algorithms[i].result_length, ""); return 0; } int calculate_and_print_each(char **files, struct algorithm *algorithms, size_t nalgorithms, size_t nthreads, enum format format, int hexinput, int recursive, int xdev, int xlink) { struct recursion_buffer recbuf = {NULL, 0, 0}; size_t wanted_nalgorithms = nalgorithms; struct buffer buffer = {0}; struct barrier_group group; struct global_data global; int ret = 0; global.format = format; global.hexinput = hexinput; global.buffer = &buffer; global.algorithms = algorithms; global.nalgorithms = nalgorithms; if (!nthreads) nthreads = getautonthreads(); nthreads = MAX(MIN(nalgorithms, nthreads), 1U); createbarriergroup(&group, nthreads, &global); for (; *files; files++) if (calculate_and_print(*files, &group, &global, recursive ? &recbuf : NULL, 1, xlink, xdev, 0)) ret = 2; if (global.nalgorithms != wanted_nalgorithms) ret = 2; killbarriergroup(&group, &global); free(buffer.buf); free(recbuf.buf); return ret; }