aboutsummaryrefslogblamecommitdiffstats
path: root/get.c
blob: fe92ab32663a3b883c062ac7e8bddb555e1bec99 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12











                                                         

                                                                                                
 
                              








                               













                                                  










                                                                  

                                                                                   




                                                                          
                                                                                                 




                                            
                             



















                                                                                                                       

                                                                                          




















                                                       
                                                                                                                










                                                     
/* 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;
}