1 #include <dirent.h>
2 #include <stdlib.h>
3 
4 #include "scandir.h"
5 #include "util.h"
6 
ag_scandir(const char * dirname,struct dirent *** namelist,filter_fp filter,void * baton)7 int ag_scandir(const char *dirname,
8                struct dirent ***namelist,
9                filter_fp filter,
10                void *baton) {
11     DIR *dirp = NULL;
12     struct dirent **names = NULL;
13     struct dirent *entry, *d;
14     int names_len = 32;
15     int results_len = 0;
16 
17     dirp = opendir(dirname);
18     if (dirp == NULL) {
19         goto fail;
20     }
21 
22     names = malloc(sizeof(struct dirent *) * names_len);
23     if (names == NULL) {
24         goto fail;
25     }
26 
27     while ((entry = readdir(dirp)) != NULL) {
28         if ((*filter)(dirname, entry, baton) == FALSE) {
29             continue;
30         }
31         if (results_len >= names_len) {
32             struct dirent **tmp_names = names;
33             names_len *= 2;
34             names = realloc(names, sizeof(struct dirent *) * names_len);
35             if (names == NULL) {
36                 free(tmp_names);
37                 goto fail;
38             }
39         }
40 
41 #if defined(__MINGW32__) || defined(__CYGWIN__)
42         d = malloc(sizeof(struct dirent));
43 #else
44         d = malloc(_DIRENT_RECLEN(entry->d_namlen));
45 #endif
46 
47         if (d == NULL) {
48             goto fail;
49         }
50 #if defined(__MINGW32__) || defined(__CYGWIN__)
51         memcpy(d, entry, sizeof(struct dirent));
52 #else
53         memcpy(d, entry, _DIRENT_RECLEN(entry->d_namlen));
54 #endif
55 
56         names[results_len] = d;
57         results_len++;
58     }
59 
60     closedir(dirp);
61     *namelist = names;
62     return results_len;
63 
64 fail:
65     if (dirp) {
66         closedir(dirp);
67     }
68 
69     if (names != NULL) {
70         int i;
71         for (i = 0; i < results_len; i++) {
72             free(names[i]);
73         }
74         free(names);
75     }
76     return -1;
77 }
78