1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <gtest/gtest.h>
18
19 #include <dirent.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <limits.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26
27 #include <algorithm>
28 #include <set>
29 #include <string>
30
CheckProcSelf(std::set<std::string> & names)31 static void CheckProcSelf(std::set<std::string>& names) {
32 // We have a good idea of what should be in /proc/self.
33 ASSERT_TRUE(names.find(".") != names.end());
34 ASSERT_TRUE(names.find("..") != names.end());
35 ASSERT_TRUE(names.find("cmdline") != names.end());
36 ASSERT_TRUE(names.find("fd") != names.end());
37 ASSERT_TRUE(names.find("stat") != names.end());
38 }
39
40 template <typename DirEntT>
ScanEntries(DirEntT ** entries,int entry_count,std::set<std::string> & name_set,std::vector<std::string> & name_list)41 void ScanEntries(DirEntT** entries, int entry_count,
42 std::set<std::string>& name_set, std::vector<std::string>& name_list) {
43 for (size_t i = 0; i < static_cast<size_t>(entry_count); ++i) {
44 name_set.insert(entries[i]->d_name);
45 name_list.push_back(entries[i]->d_name);
46 free(entries[i]);
47 }
48 free(entries);
49 }
50
TEST(dirent,scandir_scandir64)51 TEST(dirent, scandir_scandir64) {
52 // Get everything from /proc/self...
53 dirent** entries;
54 int entry_count = scandir("/proc/self", &entries, nullptr, alphasort);
55 ASSERT_GE(entry_count, 0);
56
57 dirent64** entries64;
58 int entry_count64 = scandir64("/proc/self", &entries64, nullptr, alphasort64);
59 ASSERT_EQ(entry_count, entry_count64);
60
61 // Turn the directory entries into a set and vector of the names.
62 std::set<std::string> name_set;
63 std::vector<std::string> unsorted_name_list;
64 ScanEntries(entries, entry_count, name_set, unsorted_name_list);
65
66 // No duplicates.
67 ASSERT_EQ(name_set.size(), unsorted_name_list.size());
68
69 // All entries sorted.
70 std::vector<std::string> sorted_name_list(unsorted_name_list);
71 std::sort(sorted_name_list.begin(), sorted_name_list.end());
72 ASSERT_EQ(sorted_name_list, unsorted_name_list);
73
74 // scandir64 returned the same results as scandir.
75 std::set<std::string> name_set64;
76 std::vector<std::string> unsorted_name_list64;
77 ScanEntries(entries64, entry_count64, name_set64, unsorted_name_list64);
78 ASSERT_EQ(name_set, name_set64);
79 ASSERT_EQ(unsorted_name_list, unsorted_name_list64);
80
81 CheckProcSelf(name_set);
82 }
83
TEST(dirent,scandirat_scandirat64)84 TEST(dirent, scandirat_scandirat64) {
85 // Get everything from /proc/self...
86 dirent** entries;
87 int entry_count = scandir("/proc/self", &entries, nullptr, alphasort);
88 ASSERT_GE(entry_count, 0);
89
90 int proc_fd = open("/proc", O_DIRECTORY);
91 ASSERT_NE(-1, proc_fd);
92
93 dirent** entries_at;
94 int entry_count_at = scandirat(proc_fd, "self", &entries_at, nullptr, alphasort);
95 ASSERT_EQ(entry_count, entry_count_at);
96
97 dirent64** entries_at64;
98 int entry_count_at64 = scandirat64(proc_fd, "self", &entries_at64, nullptr, alphasort64);
99 ASSERT_EQ(entry_count, entry_count_at64);
100
101 close(proc_fd);
102
103 // scandirat and scandirat64 should return the same results as scandir.
104 std::set<std::string> name_set, name_set_at, name_set_at64;
105 std::vector<std::string> unsorted_name_list, unsorted_name_list_at, unsorted_name_list_at64;
106 ScanEntries(entries, entry_count, name_set, unsorted_name_list);
107 ScanEntries(entries_at, entry_count_at, name_set_at, unsorted_name_list_at);
108 ScanEntries(entries_at64, entry_count_at64, name_set_at64, unsorted_name_list_at64);
109
110 ASSERT_EQ(name_set, name_set_at);
111 ASSERT_EQ(name_set, name_set_at64);
112 ASSERT_EQ(unsorted_name_list, unsorted_name_list_at);
113 ASSERT_EQ(unsorted_name_list, unsorted_name_list_at64);
114 }
115
is_version_filter(const dirent * de)116 static int is_version_filter(const dirent* de) {
117 return !strcmp(de->d_name, "version");
118 }
119
TEST(dirent,scandir_filter)120 TEST(dirent, scandir_filter) {
121 dirent** entries;
122 errno = 0;
123 ASSERT_EQ(1, scandir("/proc", &entries, is_version_filter, nullptr));
124 ASSERT_STREQ("version", entries[0]->d_name);
125 free(entries);
126 }
127
TEST(dirent,scandir_ENOENT)128 TEST(dirent, scandir_ENOENT) {
129 dirent** entries;
130 errno = 0;
131 ASSERT_EQ(-1, scandir("/does-not-exist", &entries, nullptr, nullptr));
132 ASSERT_EQ(ENOENT, errno);
133 }
134
TEST(dirent,scandir64_ENOENT)135 TEST(dirent, scandir64_ENOENT) {
136 dirent64** entries;
137 errno = 0;
138 ASSERT_EQ(-1, scandir64("/does-not-exist", &entries, nullptr, nullptr));
139 ASSERT_EQ(ENOENT, errno);
140 }
141
TEST(dirent,scandirat_ENOENT)142 TEST(dirent, scandirat_ENOENT) {
143 int root_fd = open("/", O_DIRECTORY | O_RDONLY);
144 ASSERT_NE(-1, root_fd);
145 dirent** entries;
146 errno = 0;
147 ASSERT_EQ(-1, scandirat(root_fd, "does-not-exist", &entries, nullptr, nullptr));
148 ASSERT_EQ(ENOENT, errno);
149 close(root_fd);
150 }
151
TEST(dirent,scandirat64_ENOENT)152 TEST(dirent, scandirat64_ENOENT) {
153 int root_fd = open("/", O_DIRECTORY | O_RDONLY);
154 ASSERT_NE(-1, root_fd);
155 dirent64** entries;
156 errno = 0;
157 ASSERT_EQ(-1, scandirat64(root_fd, "does-not-exist", &entries, nullptr, nullptr));
158 ASSERT_EQ(ENOENT, errno);
159 close(root_fd);
160 }
161
TEST(dirent,fdopendir_invalid)162 TEST(dirent, fdopendir_invalid) {
163 ASSERT_TRUE(fdopendir(-1) == nullptr);
164 ASSERT_EQ(EBADF, errno);
165
166 int fd = open("/dev/null", O_RDONLY);
167 ASSERT_NE(fd, -1);
168 ASSERT_TRUE(fdopendir(fd) == nullptr);
169 ASSERT_EQ(ENOTDIR, errno);
170 close(fd);
171 }
172
TEST(dirent,fdopendir)173 TEST(dirent, fdopendir) {
174 int fd = open("/proc/self", O_RDONLY);
175 DIR* d = fdopendir(fd);
176 ASSERT_TRUE(d != nullptr);
177 dirent* e = readdir(d);
178 ASSERT_STREQ(e->d_name, ".");
179 ASSERT_EQ(closedir(d), 0);
180
181 // fdopendir(3) took ownership, so closedir(3) closed our fd.
182 ASSERT_EQ(close(fd), -1);
183 ASSERT_EQ(EBADF, errno);
184 }
185
TEST(dirent,opendir_invalid)186 TEST(dirent, opendir_invalid) {
187 ASSERT_TRUE(opendir("/does/not/exist") == nullptr);
188 ASSERT_EQ(ENOENT, errno);
189
190 ASSERT_TRUE(opendir("/dev/null") == nullptr);
191 ASSERT_EQ(ENOTDIR, errno);
192 }
193
TEST(dirent,opendir)194 TEST(dirent, opendir) {
195 DIR* d = opendir("/proc/self");
196 ASSERT_TRUE(d != nullptr);
197 dirent* e = readdir(d);
198 ASSERT_STREQ(e->d_name, ".");
199 ASSERT_EQ(closedir(d), 0);
200 }
201
TEST(dirent,closedir_invalid)202 TEST(dirent, closedir_invalid) {
203 DIR* d = nullptr;
204 ASSERT_EQ(closedir(d), -1);
205 ASSERT_EQ(EINVAL, errno);
206 }
207
TEST(dirent,closedir)208 TEST(dirent, closedir) {
209 DIR* d = opendir("/proc/self");
210 ASSERT_TRUE(d != nullptr);
211 ASSERT_EQ(closedir(d), 0);
212 }
213
TEST(dirent,readdir)214 TEST(dirent, readdir) {
215 DIR* d = opendir("/proc/self");
216 ASSERT_TRUE(d != nullptr);
217 std::set<std::string> name_set;
218 errno = 0;
219 dirent* e;
220 while ((e = readdir(d)) != nullptr) {
221 name_set.insert(e->d_name);
222 }
223 // Reading to the end of the directory is not an error.
224 // readdir(3) returns NULL, but leaves errno as 0.
225 ASSERT_EQ(0, errno);
226 ASSERT_EQ(closedir(d), 0);
227
228 CheckProcSelf(name_set);
229 }
230
TEST(dirent,readdir64)231 TEST(dirent, readdir64) {
232 DIR* d = opendir("/proc/self");
233 ASSERT_TRUE(d != nullptr);
234 std::set<std::string> name_set;
235 errno = 0;
236 dirent64* e;
237 while ((e = readdir64(d)) != nullptr) {
238 name_set.insert(e->d_name);
239 }
240 // Reading to the end of the directory is not an error.
241 // readdir64(3) returns NULL, but leaves errno as 0.
242 ASSERT_EQ(0, errno);
243 ASSERT_EQ(closedir(d), 0);
244
245 CheckProcSelf(name_set);
246 }
247
TEST(dirent,readdir_r)248 TEST(dirent, readdir_r) {
249 DIR* d = opendir("/proc/self");
250 ASSERT_TRUE(d != nullptr);
251 std::set<std::string> name_set;
252 errno = 0;
253 dirent storage;
254 dirent* e = nullptr;
255 while (readdir_r(d, &storage, &e) == 0 && e != nullptr) {
256 name_set.insert(e->d_name);
257 }
258 // Reading to the end of the directory is not an error.
259 // readdir_r(3) returns NULL, but leaves errno as 0.
260 ASSERT_EQ(0, errno);
261 ASSERT_EQ(closedir(d), 0);
262
263 CheckProcSelf(name_set);
264 }
265
TEST(dirent,readdir64_r)266 TEST(dirent, readdir64_r) {
267 DIR* d = opendir("/proc/self");
268 ASSERT_TRUE(d != nullptr);
269 std::set<std::string> name_set;
270 errno = 0;
271 dirent64 storage;
272 dirent64* e = nullptr;
273 while (readdir64_r(d, &storage, &e) == 0 && e != nullptr) {
274 name_set.insert(e->d_name);
275 }
276 // Reading to the end of the directory is not an error.
277 // readdir64_r(3) returns NULL, but leaves errno as 0.
278 ASSERT_EQ(0, errno);
279 ASSERT_EQ(closedir(d), 0);
280
281 CheckProcSelf(name_set);
282 }
283
TEST(dirent,rewinddir)284 TEST(dirent, rewinddir) {
285 DIR* d = opendir("/proc/self");
286 ASSERT_TRUE(d != nullptr);
287
288 // Get all the names once...
289 std::vector<std::string> pass1;
290 dirent* e;
291 while ((e = readdir(d)) != nullptr) {
292 pass1.push_back(e->d_name);
293 }
294
295 // ...rewind...
296 rewinddir(d);
297
298 // ...and get all the names again.
299 std::vector<std::string> pass2;
300 while ((e = readdir(d)) != nullptr) {
301 pass2.push_back(e->d_name);
302 }
303
304 ASSERT_EQ(closedir(d), 0);
305
306 // We should have seen the same names in the same order both times.
307 ASSERT_EQ(pass1.size(), pass2.size());
308 for (size_t i = 0; i < pass1.size(); ++i) {
309 ASSERT_EQ(pass1[i], pass2[i]);
310 }
311 }
312
TEST(dirent,seekdir_telldir)313 TEST(dirent, seekdir_telldir) {
314 DIR* d = opendir("/proc/self");
315 ASSERT_TRUE(d != nullptr);
316 std::vector<long> offset_list;
317 std::vector<std::string> name_list;
318 dirent* e = nullptr;
319
320 offset_list.push_back(telldir(d));
321 ASSERT_EQ(0L, offset_list.back());
322
323 while ((e = readdir(d)) != nullptr) {
324 name_list.push_back(e->d_name);
325 offset_list.push_back(telldir(d));
326 // Make sure telldir() point to the next entry.
327 ASSERT_EQ(e->d_off, offset_list.back());
328 }
329
330 long end_offset = telldir(d);
331 // telldir() should not pass the end of the file.
332 ASSERT_EQ(offset_list.back(), end_offset);
333 offset_list.pop_back();
334
335 for (size_t i = 0; i < offset_list.size(); ++i) {
336 seekdir(d, offset_list[i]);
337 ASSERT_EQ(offset_list[i], telldir(d));
338 e = readdir(d);
339 ASSERT_TRUE(e != nullptr);
340 ASSERT_STREQ(name_list[i].c_str(), e->d_name);
341 }
342 for (int i = static_cast<int>(offset_list.size()) - 1; i >= 0; --i) {
343 seekdir(d, offset_list[i]);
344 ASSERT_EQ(offset_list[i], telldir(d));
345 e = readdir(d);
346 ASSERT_TRUE(e != nullptr);
347 ASSERT_STREQ(name_list[i].c_str(), e->d_name);
348 }
349
350 // Seek to the end, read NULL.
351 seekdir(d, end_offset);
352 ASSERT_EQ(end_offset, telldir(d));
353 errno = 0;
354 ASSERT_EQ(nullptr, readdir(d));
355 ASSERT_EQ(0, errno);
356
357 ASSERT_EQ(0, closedir(d));
358 }
359