/* 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, "<stdout>");
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;
}