aboutsummaryrefslogtreecommitdiff
blob: f28ba0d86239618e5e121334ae08803453365f6a (plain)
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
/*
 * Copyright 2005-2019 Gentoo Foundation
 * Distributed under the terms of the GNU General Public License v2
 *
 * Copyright 2005-2010 Ned Ludd        - <solar@gentoo.org>
 * Copyright 2005-2014 Mike Frysinger  - <vapier@gentoo.org>
 * Copyright 2018-     Fabian Groffen  - <grobian@gentoo.org>
 */

#include "main.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <xalloc.h>

#include "scandirat.h"

#if !defined(HAVE_SCANDIRAT)

int
scandirat(int dir_fd, const char *dir, struct dirent ***dirlist,
	int (*filter)(const struct dirent *),
	int (*compar)(const struct dirent **, const struct dirent **))
{
	int fd;
	DIR *dirp;
	struct dirent *de, **ret;
	size_t retlen = 0;
	size_t retsize = 0;
#define INCRSZ 64

	/* Cannot use O_PATH as we want to use fdopendir() */
	fd = openat(dir_fd, dir, O_RDONLY|O_CLOEXEC);
	if (fd == -1)
		return -1;
	dirp = fdopendir(fd);
	if (!dirp) {
		close(fd);
		return -1;
	}

	ret = NULL;
	while ((de = readdir(dirp))) {
		size_t sdesz;
		size_t sdenamelen;

		if (filter(de) == 0)
			continue;

		if (retlen == retsize) {
			retsize += INCRSZ;
			ret = xrealloc(ret, sizeof(*ret) * retsize);
		}
		sdesz = (void *)de->d_name - (void *)de;
		sdenamelen = strlen(de->d_name) + 1;
		ret[retlen] = xmalloc(sdesz + sdenamelen);
		memcpy(ret[retlen], de, sdesz);
		strncpy(ret[retlen]->d_name, de->d_name, sdenamelen);
		retlen++;
	}
	*dirlist = ret;

	if (compar != NULL)
		qsort(ret, retlen, sizeof(*ret), (void *)compar);

	/* closes underlying fd */
	closedir(dirp);

	return (int)retlen;
}

#endif

void
scandir_free(struct dirent **de, int cnt)
{
	if (cnt <= 0)
		return;

	while (cnt--)
		free(de[cnt]);
	free(de);
}

int
filter_hidden(const struct dirent *dentry)
{
	if (dentry->d_name[0] == '.')
		return 0;
	return 1;
}