1#include <dirent.h>
2#include <errno.h>
3#include <stddef.h>
4#include <stdint.h>
5#include <stdlib.h>
6#include <string.h>
7
8int scandir(const char* path, struct dirent*** res, int (*sel)(const struct dirent*),
9            int (*cmp)(const struct dirent**, const struct dirent**)) {
10    DIR* d = opendir(path);
11    struct dirent *de, **names = 0, **tmp;
12    size_t cnt = 0, len = 0;
13    int old_errno = errno;
14
15    if (!d)
16        return -1;
17
18    while ((errno = 0), (de = readdir(d))) {
19        if (sel && !sel(de))
20            continue;
21        if (cnt >= len) {
22            len = 2 * len + 1;
23            if (len > SIZE_MAX / sizeof *names)
24                break;
25            tmp = realloc(names, len * sizeof *names);
26            if (!tmp)
27                break;
28            names = tmp;
29        }
30        names[cnt] = malloc(de->d_reclen);
31        if (!names[cnt])
32            break;
33        memcpy(names[cnt++], de, de->d_reclen);
34    }
35
36    closedir(d);
37
38    if (errno) {
39        if (names)
40            while (cnt-- > 0)
41                free(names[cnt]);
42        free(names);
43        return -1;
44    }
45    errno = old_errno;
46
47    if (cmp)
48        qsort(names, cnt, sizeof *names, (int (*)(const void*, const void*))cmp);
49    *res = names;
50    return cnt;
51}
52