]>
Commit | Line | Data |
---|---|---|
b061a43b A |
1 | #include <dirent.h> |
2 | #include <fcntl.h> | |
3 | #include <stdio.h> | |
4 | #include <unistd.h> | |
5 | ||
6 | #include <darwintest.h> | |
7 | #include <darwintest_utils.h> | |
8 | ||
9 | T_DECL(seekdir_basic, "seekdir") | |
10 | { | |
11 | const char *path = dt_tmpdir(); | |
12 | // make sure there are a couple of entries in the dir aside from . and .. | |
13 | int fd = open(path, O_RDONLY | O_DIRECTORY); | |
14 | openat(fd, "a", O_CREAT | O_WRONLY, 0600); | |
15 | openat(fd, "b", O_CREAT | O_WRONLY, 0600); | |
16 | openat(fd, "c", O_CREAT | O_WRONLY, 0600); | |
17 | ||
18 | DIR *dirp = fdopendir(fd); | |
19 | struct dirent *entry = NULL; | |
20 | ||
21 | T_ASSERT_NOTNULL(dirp, NULL); | |
22 | ||
23 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); // . | |
24 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); // .. | |
25 | ||
26 | // we can get any entry -- no ordering | |
27 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
28 | // remember position for the second entry | |
29 | long second_pos = telldir(dirp); | |
30 | // read the second entry | |
31 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
32 | char *second_name = strdup(entry->d_name); | |
33 | T_ASSERT_NOTNULL(second_name, NULL); | |
34 | // read the third entry | |
35 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
36 | ||
37 | // go back to the second entry and read it | |
38 | seekdir(dirp, second_pos); | |
39 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
40 | ||
41 | // make sure the name matches the old copy | |
42 | T_ASSERT_EQ_STR(second_name, entry->d_name, NULL); | |
43 | ||
44 | // return to 2nd once again, reinitializing second_pos and re-reading | |
45 | seekdir(dirp, second_pos); | |
46 | second_pos = telldir(dirp); | |
47 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
48 | ||
49 | // make sure the name matches the old copy | |
50 | T_ASSERT_EQ_STR(second_name, entry->d_name, NULL); | |
51 | ||
52 | // verify that last pos | |
53 | seekdir(dirp, second_pos); | |
54 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
55 | T_ASSERT_EQ_STR(second_name, entry->d_name, NULL); | |
56 | ||
57 | free(second_name); | |
58 | T_ASSERT_POSIX_ZERO(closedir(dirp), NULL); | |
59 | } | |
60 | ||
61 | T_DECL(readdir, "readdir") | |
62 | { | |
63 | const char *path = dt_tmpdir(); | |
64 | int fd = open(path, O_RDONLY | O_DIRECTORY); | |
65 | openat(fd, "foobarbaz", O_CREAT | O_WRONLY, 0600); | |
66 | ||
67 | DIR *dirp = fdopendir(fd); | |
68 | T_ASSERT_NOTNULL(dirp, NULL); | |
69 | ||
70 | struct dirent *entry = NULL; | |
71 | while ((entry = readdir(dirp)) != NULL) { | |
72 | if (strcmp(entry->d_name, "foobarbaz")) { | |
73 | break; | |
74 | } | |
75 | } | |
76 | ||
77 | T_ASSERT_NOTNULL(entry, "found the entry"); | |
78 | ||
79 | T_ASSERT_POSIX_ZERO(closedir(dirp), NULL); | |
80 | } | |
81 | ||
82 | T_DECL(tell_seek_tell, "tell-seek-tell returns the same location") | |
83 | { | |
84 | // http://pubs.opengroup.org/onlinepubs/009695399/functions/telldir.html | |
85 | // If the most recent operation on the directory stream was a seekdir(), | |
86 | // the directory position returned from the telldir() shall be the same as | |
87 | // that supplied as a loc argument for seekdir(). | |
88 | ||
89 | const char *path = dt_tmpdir(); | |
90 | // make sure there are a couple of entries in the dir aside from . and .. | |
91 | { | |
92 | int fd = open(path, O_RDONLY | O_DIRECTORY); | |
93 | openat(fd, "a", O_CREAT | O_WRONLY, 0600); | |
94 | openat(fd, "b", O_CREAT | O_WRONLY, 0600); | |
95 | openat(fd, "c", O_CREAT | O_WRONLY, 0600); | |
96 | close(fd); | |
97 | } | |
98 | ||
99 | DIR *dirp = opendir(path); | |
100 | T_ASSERT_NOTNULL(dirp, NULL); | |
101 | struct dirent *entry = NULL; | |
102 | ||
103 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
104 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
105 | long pos1 = telldir(dirp); | |
106 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
107 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
108 | seekdir(dirp, pos1); | |
109 | long pos2 = telldir(dirp); | |
110 | ||
111 | T_ASSERT_EQ(pos1, pos2, NULL); | |
112 | ||
113 | T_ASSERT_POSIX_ZERO(closedir(dirp), NULL); | |
114 | } | |
115 | ||
116 | T_DECL(rewinddir, "rewinddir") | |
117 | { | |
118 | const char *path = dt_tmpdir(); | |
119 | // make sure there are a couple of entries in the dir aside from . and .. | |
120 | { | |
121 | int fd = open(path, O_RDONLY | O_DIRECTORY); | |
122 | openat(fd, "a", O_CREAT | O_WRONLY, 0600); | |
123 | openat(fd, "b", O_CREAT | O_WRONLY, 0600); | |
124 | openat(fd, "c", O_CREAT | O_WRONLY, 0600); | |
125 | close(fd); | |
126 | } | |
127 | ||
128 | DIR *dirp = opendir(path); | |
129 | T_ASSERT_NOTNULL(dirp, NULL); | |
130 | struct dirent *entry = NULL; | |
131 | ||
132 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
133 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
134 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
135 | char *third_name = strdup(entry->d_name); | |
136 | ||
137 | rewinddir(dirp); | |
138 | ||
139 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
140 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
141 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
142 | ||
143 | T_ASSERT_EQ_STR(third_name, entry->d_name, NULL); | |
144 | ||
145 | free(third_name); | |
146 | T_ASSERT_POSIX_ZERO(closedir(dirp), NULL); | |
147 | } | |
148 | ||
149 | ||
150 | T_DECL(rewinddir_dup, "rewinddir dup") | |
151 | { | |
152 | // An older implementation of rewinddir failed to seek the fd which was | |
153 | // passed to fdopendir() | |
154 | ||
155 | const char *path = dt_tmpdir(); | |
156 | // make sure there are a couple of entries in the dir aside from . and .. | |
157 | int fd = open(path, O_RDONLY | O_DIRECTORY); | |
158 | openat(fd, "a", O_CREAT | O_WRONLY, 0600); | |
159 | openat(fd, "b", O_CREAT | O_WRONLY, 0600); | |
160 | openat(fd, "c", O_CREAT | O_WRONLY, 0600); | |
161 | ||
162 | // prep an fd with a non-zero seek | |
163 | DIR *dirp = fdopendir(fd); | |
164 | T_ASSERT_NOTNULL(dirp, NULL); | |
165 | struct dirent *entry = NULL; | |
166 | ||
167 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
168 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
169 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
170 | ||
171 | // remember the entry name and dup the fd | |
172 | char *third_name = strdup(entry->d_name); | |
173 | int fd2 = dup(fd); | |
174 | ||
175 | T_ASSERT_POSIX_ZERO(closedir(dirp), NULL); | |
176 | ||
177 | dirp = fdopendir(fd2); | |
178 | // rewind back to 0 | |
179 | rewinddir(dirp); | |
180 | ||
181 | T_ASSERT_NOTNULL(dirp, NULL); | |
182 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
183 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
184 | T_ASSERT_NOTNULL(entry = readdir(dirp), NULL); | |
185 | ||
186 | T_ASSERT_EQ_STR(third_name, entry->d_name, NULL); | |
187 | ||
188 | free(third_name); | |
189 | T_ASSERT_POSIX_ZERO(closedir(dirp), NULL); | |
190 | } | |
191 | ||
192 | static int | |
193 | _select_abc(const struct dirent *entry) | |
194 | { | |
195 | return strcmp(entry->d_name, "a") == 0 || | |
196 | strcmp(entry->d_name, "b") == 0 || | |
197 | strcmp(entry->d_name, "c") == 0; | |
198 | } | |
199 | ||
200 | T_DECL(scandir, "scandir") | |
201 | { | |
202 | const char *path = dt_tmpdir(); | |
203 | { | |
204 | int fd = open(path, O_RDONLY | O_DIRECTORY); | |
205 | openat(fd, "a", O_CREAT | O_WRONLY, 0600); | |
206 | openat(fd, "b", O_CREAT | O_WRONLY, 0600); | |
207 | openat(fd, "c", O_CREAT | O_WRONLY, 0600); | |
208 | close(fd); | |
209 | } | |
210 | ||
211 | struct dirent **entries = NULL; | |
212 | int found = scandir(path, &entries, _select_abc, alphasort); | |
213 | ||
214 | T_ASSERT_EQ(found, 3, NULL); | |
215 | ||
216 | T_ASSERT_EQ_STR(entries[0]->d_name, "a", NULL); | |
217 | T_ASSERT_EQ_STR(entries[1]->d_name, "b", NULL); | |
218 | T_ASSERT_EQ_STR(entries[2]->d_name, "c", NULL); | |
219 | ||
220 | free(entries[0]); | |
221 | free(entries[1]); | |
222 | free(entries[2]); | |
223 | free(entries); | |
224 | } | |
225 | ||
226 | T_DECL(scandir_b, "scandir_b") | |
227 | { | |
228 | const char *path = dt_tmpdir(); | |
229 | { | |
230 | int fd = open(path, O_RDONLY | O_DIRECTORY); | |
231 | openat(fd, "a", O_CREAT | O_WRONLY, 0600); | |
232 | openat(fd, "b", O_CREAT | O_WRONLY, 0600); | |
233 | openat(fd, "c", O_CREAT | O_WRONLY, 0600); | |
234 | close(fd); | |
235 | } | |
236 | ||
237 | const struct dirent **entries = NULL; | |
238 | int found = scandir_b(path, &entries, | |
239 | ^(const struct dirent *entry) { | |
240 | return strcmp(entry->d_name, "a") == 0 || | |
241 | strcmp(entry->d_name, "b") == 0 || | |
242 | strcmp(entry->d_name, "c") == 0; | |
243 | }, | |
244 | ^(const struct dirent **d1, const struct dirent **d2) { | |
245 | return strcoll((*d1)->d_name, (*d2)->d_name); | |
246 | }); | |
247 | ||
248 | T_ASSERT_EQ(found, 3, NULL); | |
249 | ||
250 | T_ASSERT_EQ_STR(entries[0]->d_name, "a", NULL); | |
251 | T_ASSERT_EQ_STR(entries[1]->d_name, "b", NULL); | |
252 | T_ASSERT_EQ_STR(entries[2]->d_name, "c", NULL); | |
253 | ||
254 | free(entries[0]); | |
255 | free(entries[1]); | |
256 | free(entries[2]); | |
257 | free(entries); | |
258 | } |