aboutsummaryrefslogtreecommitdiffstats
path: root/get.c
blob: fe92ab32663a3b883c062ac7e8bddb555e1bec99 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/* 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;
}