2
#include "dir.h"
3
#include "iterator.h"
4
#include "dir-iterator.h"
5
+#include "string-list.h"
6
7
struct dir_iterator_level {
8
DIR *dir;
9
10
+ /*
11
+ * The directory entries of the current level. This list will only be
12
+ * populated when the iterator is ordered. In that case, `dir` will be
13
+ * set to `NULL`.
14
+ */
15
+ struct string_list entries;
16
+ size_t entries_idx;
17
+
18
/*
19
* The length of the directory part of path at this level
20
* (including a trailing '/'):
52
unsigned int flags;
53
};
54
55
+static int next_directory_entry(DIR *dir, const char *path,
56
+ struct dirent **out)
57
+{
58
+ struct dirent *de;
59
+
60
+repeat:
61
+ errno = 0;
62
+ de = readdir(dir);
63
+ if (!de) {
64
+ if (errno) {
65
+ warning_errno("error reading directory '%s'",
66
+ path);
67
+ return -1;
68
+ }
69
+
70
+ return 1;
71
+ }
72
+
73
+ if (is_dot_or_dotdot(de->d_name))
74
+ goto repeat;
75
+
76
+ *out = de;
77
+ return 0;
78
+}
79
+
80
/*
81
* Push a level in the iter stack and initialize it with information from
82
* the directory pointed by iter->base->path. It is assumed that this
106
return -1;
107
}
108
109
+ string_list_init_dup(&level->entries);
110
+ level->entries_idx = 0;
111
+
112
+ /*
113
+ * When the iterator is sorted we read and sort all directory entries
114
+ * directly.
115
+ */
116
+ if (iter->flags & DIR_ITERATOR_SORTED) {
117
+ struct dirent *de;
118
+
119
+ while (1) {
120
+ int ret = next_directory_entry(level->dir, iter->base.path.buf, &de);
121
+ if (ret < 0) {
122
+ if (errno != ENOENT &&
123
+ iter->flags & DIR_ITERATOR_PEDANTIC)
124
+ return -1;
125
+ continue;
126
+ } else if (ret > 0) {
127
+ break;
128
+ }
129
+
130
+ string_list_append(&level->entries, de->d_name);
131
+ }
132
+ string_list_sort(&level->entries);
133
+
134
+ closedir(level->dir);
135
+ level->dir = NULL;
136
+ }
137
+
138
return 0;
139
}
140
151
warning_errno("error closing directory '%s'",
152
iter->base.path.buf);
153
level->dir = NULL;
154
+ string_list_clear(&level->entries, 0);
155
156
return --iter->levels_nr;
157
}
203
struct dirent *de;
204
struct dir_iterator_level *level =
205
&iter->levels[iter->levels_nr - 1];
206
+ const char *name;
207
208
strbuf_setlen(&iter->base.path, level->prefix_len);
144
- errno = 0;
145
- de = readdir(level->dir);
209
147
- if (!de) {
148
- if (errno) {
149
- warning_errno("error reading directory '%s'",
150
- iter->base.path.buf);
210
+ if (level->dir) {
211
+ int ret = next_directory_entry(level->dir, iter->base.path.buf, &de);
212
+ if (ret < 0) {
213
if (iter->flags & DIR_ITERATOR_PEDANTIC)
214
goto error_out;
153
- } else if (pop_level(iter) == 0) {
154
- return dir_iterator_abort(dir_iterator);
215
+ continue;
216
+ } else if (ret > 0) {
217
+ if (pop_level(iter) == 0)
218
+ return dir_iterator_abort(dir_iterator);
219
+ continue;
220
}
156
- continue;
157
- }
221
159
- if (is_dot_or_dotdot(de->d_name))
160
- continue;
222
+ name = de->d_name;
223
+ } else {
224
+ if (level->entries_idx >= level->entries.nr) {
225
+ if (pop_level(iter) == 0)
226
+ return dir_iterator_abort(dir_iterator);
227
+ continue;
228
+ }
229
162
- if (prepare_next_entry_data(iter, de->d_name)) {
230
+ name = level->entries.items[level->entries_idx++].string;
231
+ }
232
+
233
+ if (prepare_next_entry_data(iter, name)) {
234
if (errno != ENOENT && iter->flags & DIR_ITERATOR_PEDANTIC)
235
goto error_out;
236
continue;
259
warning_errno("error closing directory '%s'",
260
iter->base.path.buf);
261
}
262
+
263
+ string_list_clear(&level->entries, 0);
264
}
265
266
free(iter->levels);