blob: 56929d138e5e4bbb0d9c8ce80c173fc8e25f367c [file] [log] [blame]
Elliott Hughes063cfb22012-10-25 20:55:23 -07001/*
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
Elliott Hughes063cfb22012-10-25 20:55:23 -070031static 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
Elliott Hughesdb1ea342014-01-17 18:42:49 -080040template <typename DirEntT>
41void 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
51TEST(dirent, scandir_scandir64) {
Elliott Hughes063cfb22012-10-25 20:55:23 -070052 // Get everything from /proc/self...
53 dirent** entries;
Yi Kong32bc0fc2018-08-02 17:31:13 -070054 int entry_count = scandir("/proc/self", &entries, nullptr, alphasort);
Elliott Hughes063cfb22012-10-25 20:55:23 -070055 ASSERT_GE(entry_count, 0);
56
Elliott Hughesdb1ea342014-01-17 18:42:49 -080057 dirent64** entries64;
Yi Kong32bc0fc2018-08-02 17:31:13 -070058 int entry_count64 = scandir64("/proc/self", &entries64, nullptr, alphasort64);
Elliott Hughesdb1ea342014-01-17 18:42:49 -080059 ASSERT_EQ(entry_count, entry_count64);
60
Elliott Hughes063cfb22012-10-25 20:55:23 -070061 // 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;
Elliott Hughesdb1ea342014-01-17 18:42:49 -080064 ScanEntries(entries, entry_count, name_set, unsorted_name_list);
Elliott Hughes063cfb22012-10-25 20:55:23 -070065
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
Elliott Hughesdb1ea342014-01-17 18:42:49 -080074 // 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
Elliott Hughes063cfb22012-10-25 20:55:23 -070081 CheckProcSelf(name_set);
82}
83
Elliott Hughes6331e802015-10-27 11:10:36 -070084TEST(dirent, scandirat_scandirat64) {
85 // Get everything from /proc/self...
86 dirent** entries;
Yi Kong32bc0fc2018-08-02 17:31:13 -070087 int entry_count = scandir("/proc/self", &entries, nullptr, alphasort);
Elliott Hughes6331e802015-10-27 11:10:36 -070088 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;
Yi Kong32bc0fc2018-08-02 17:31:13 -070094 int entry_count_at = scandirat(proc_fd, "self", &entries_at, nullptr, alphasort);
Elliott Hughes6331e802015-10-27 11:10:36 -070095 ASSERT_EQ(entry_count, entry_count_at);
96
97 dirent64** entries_at64;
Yi Kong32bc0fc2018-08-02 17:31:13 -070098 int entry_count_at64 = scandirat64(proc_fd, "self", &entries_at64, nullptr, alphasort64);
Elliott Hughes6331e802015-10-27 11:10:36 -070099 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
Elliott Hughes7cebf832020-08-12 14:25:41 -0700116static int is_version_filter(const dirent* de) {
117 return !strcmp(de->d_name, "version");
118}
119
120TEST(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
Elliott Hughes6331e802015-10-27 11:10:36 -0700128TEST(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
135TEST(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
142TEST(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
152TEST(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
Elliott Hughes063cfb22012-10-25 20:55:23 -0700162TEST(dirent, fdopendir_invalid) {
Yi Kong32bc0fc2018-08-02 17:31:13 -0700163 ASSERT_TRUE(fdopendir(-1) == nullptr);
Elliott Hughes5e3fc432013-02-11 16:36:48 -0800164 ASSERT_EQ(EBADF, errno);
Elliott Hughes063cfb22012-10-25 20:55:23 -0700165
166 int fd = open("/dev/null", O_RDONLY);
167 ASSERT_NE(fd, -1);
Yi Kong32bc0fc2018-08-02 17:31:13 -0700168 ASSERT_TRUE(fdopendir(fd) == nullptr);
Elliott Hughes5e3fc432013-02-11 16:36:48 -0800169 ASSERT_EQ(ENOTDIR, errno);
Elliott Hughes063cfb22012-10-25 20:55:23 -0700170 close(fd);
171}
172
173TEST(dirent, fdopendir) {
174 int fd = open("/proc/self", O_RDONLY);
175 DIR* d = fdopendir(fd);
Yi Kong32bc0fc2018-08-02 17:31:13 -0700176 ASSERT_TRUE(d != nullptr);
Elliott Hughes063cfb22012-10-25 20:55:23 -0700177 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);
Elliott Hughes5e3fc432013-02-11 16:36:48 -0800183 ASSERT_EQ(EBADF, errno);
Elliott Hughes063cfb22012-10-25 20:55:23 -0700184}
185
186TEST(dirent, opendir_invalid) {
Yi Kong32bc0fc2018-08-02 17:31:13 -0700187 ASSERT_TRUE(opendir("/does/not/exist") == nullptr);
Elliott Hughes5e3fc432013-02-11 16:36:48 -0800188 ASSERT_EQ(ENOENT, errno);
Elliott Hughes063cfb22012-10-25 20:55:23 -0700189
Yi Kong32bc0fc2018-08-02 17:31:13 -0700190 ASSERT_TRUE(opendir("/dev/null") == nullptr);
Elliott Hughes5e3fc432013-02-11 16:36:48 -0800191 ASSERT_EQ(ENOTDIR, errno);
Elliott Hughes063cfb22012-10-25 20:55:23 -0700192}
193
194TEST(dirent, opendir) {
195 DIR* d = opendir("/proc/self");
Yi Kong32bc0fc2018-08-02 17:31:13 -0700196 ASSERT_TRUE(d != nullptr);
Elliott Hughes063cfb22012-10-25 20:55:23 -0700197 dirent* e = readdir(d);
198 ASSERT_STREQ(e->d_name, ".");
199 ASSERT_EQ(closedir(d), 0);
200}
201
202TEST(dirent, closedir_invalid) {
Yi Kong32bc0fc2018-08-02 17:31:13 -0700203 DIR* d = nullptr;
Elliott Hughes063cfb22012-10-25 20:55:23 -0700204 ASSERT_EQ(closedir(d), -1);
Elliott Hughes5e3fc432013-02-11 16:36:48 -0800205 ASSERT_EQ(EINVAL, errno);
Elliott Hughes063cfb22012-10-25 20:55:23 -0700206}
207
208TEST(dirent, closedir) {
209 DIR* d = opendir("/proc/self");
Yi Kong32bc0fc2018-08-02 17:31:13 -0700210 ASSERT_TRUE(d != nullptr);
Elliott Hughes063cfb22012-10-25 20:55:23 -0700211 ASSERT_EQ(closedir(d), 0);
212}
213
214TEST(dirent, readdir) {
215 DIR* d = opendir("/proc/self");
Yi Kong32bc0fc2018-08-02 17:31:13 -0700216 ASSERT_TRUE(d != nullptr);
Elliott Hughes063cfb22012-10-25 20:55:23 -0700217 std::set<std::string> name_set;
218 errno = 0;
219 dirent* e;
Yi Kong32bc0fc2018-08-02 17:31:13 -0700220 while ((e = readdir(d)) != nullptr) {
Elliott Hughes063cfb22012-10-25 20:55:23 -0700221 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.
Elliott Hughes5e3fc432013-02-11 16:36:48 -0800225 ASSERT_EQ(0, errno);
Elliott Hughes063cfb22012-10-25 20:55:23 -0700226 ASSERT_EQ(closedir(d), 0);
227
228 CheckProcSelf(name_set);
229}
230
Elliott Hughesdb1ea342014-01-17 18:42:49 -0800231TEST(dirent, readdir64) {
232 DIR* d = opendir("/proc/self");
Yi Kong32bc0fc2018-08-02 17:31:13 -0700233 ASSERT_TRUE(d != nullptr);
Elliott Hughesdb1ea342014-01-17 18:42:49 -0800234 std::set<std::string> name_set;
235 errno = 0;
236 dirent64* e;
Yi Kong32bc0fc2018-08-02 17:31:13 -0700237 while ((e = readdir64(d)) != nullptr) {
Elliott Hughesdb1ea342014-01-17 18:42:49 -0800238 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
Elliott Hughes063cfb22012-10-25 20:55:23 -0700248TEST(dirent, readdir_r) {
249 DIR* d = opendir("/proc/self");
Yi Kong32bc0fc2018-08-02 17:31:13 -0700250 ASSERT_TRUE(d != nullptr);
Elliott Hughes063cfb22012-10-25 20:55:23 -0700251 std::set<std::string> name_set;
252 errno = 0;
253 dirent storage;
Yi Kong32bc0fc2018-08-02 17:31:13 -0700254 dirent* e = nullptr;
255 while (readdir_r(d, &storage, &e) == 0 && e != nullptr) {
Elliott Hughes063cfb22012-10-25 20:55:23 -0700256 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.
Elliott Hughes5e3fc432013-02-11 16:36:48 -0800260 ASSERT_EQ(0, errno);
Elliott Hughes063cfb22012-10-25 20:55:23 -0700261 ASSERT_EQ(closedir(d), 0);
262
263 CheckProcSelf(name_set);
264}
265
Elliott Hughesdb1ea342014-01-17 18:42:49 -0800266TEST(dirent, readdir64_r) {
267 DIR* d = opendir("/proc/self");
Yi Kong32bc0fc2018-08-02 17:31:13 -0700268 ASSERT_TRUE(d != nullptr);
Elliott Hughesdb1ea342014-01-17 18:42:49 -0800269 std::set<std::string> name_set;
270 errno = 0;
271 dirent64 storage;
Yi Kong32bc0fc2018-08-02 17:31:13 -0700272 dirent64* e = nullptr;
273 while (readdir64_r(d, &storage, &e) == 0 && e != nullptr) {
Elliott Hughesdb1ea342014-01-17 18:42:49 -0800274 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
Elliott Hughes063cfb22012-10-25 20:55:23 -0700284TEST(dirent, rewinddir) {
285 DIR* d = opendir("/proc/self");
Yi Kong32bc0fc2018-08-02 17:31:13 -0700286 ASSERT_TRUE(d != nullptr);
Elliott Hughes063cfb22012-10-25 20:55:23 -0700287
288 // Get all the names once...
289 std::vector<std::string> pass1;
290 dirent* e;
Yi Kong32bc0fc2018-08-02 17:31:13 -0700291 while ((e = readdir(d)) != nullptr) {
Elliott Hughes063cfb22012-10-25 20:55:23 -0700292 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;
Yi Kong32bc0fc2018-08-02 17:31:13 -0700300 while ((e = readdir(d)) != nullptr) {
Elliott Hughes063cfb22012-10-25 20:55:23 -0700301 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}
Yabin Cui5ca4a9e2014-11-06 19:55:09 -0800312
313TEST(dirent, seekdir_telldir) {
314 DIR* d = opendir("/proc/self");
Yi Kong32bc0fc2018-08-02 17:31:13 -0700315 ASSERT_TRUE(d != nullptr);
Yabin Cui5ca4a9e2014-11-06 19:55:09 -0800316 std::vector<long> offset_list;
317 std::vector<std::string> name_list;
Yi Kong32bc0fc2018-08-02 17:31:13 -0700318 dirent* e = nullptr;
Yabin Cui5ca4a9e2014-11-06 19:55:09 -0800319
320 offset_list.push_back(telldir(d));
321 ASSERT_EQ(0L, offset_list.back());
322
Yi Kong32bc0fc2018-08-02 17:31:13 -0700323 while ((e = readdir(d)) != nullptr) {
Yabin Cui5ca4a9e2014-11-06 19:55:09 -0800324 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);
Yi Kong32bc0fc2018-08-02 17:31:13 -0700339 ASSERT_TRUE(e != nullptr);
Yabin Cui5ca4a9e2014-11-06 19:55:09 -0800340 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);
Yi Kong32bc0fc2018-08-02 17:31:13 -0700346 ASSERT_TRUE(e != nullptr);
Yabin Cui5ca4a9e2014-11-06 19:55:09 -0800347 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;
Yi Kong32bc0fc2018-08-02 17:31:13 -0700354 ASSERT_EQ(nullptr, readdir(d));
Yabin Cui5ca4a9e2014-11-06 19:55:09 -0800355 ASSERT_EQ(0, errno);
356
357 ASSERT_EQ(0, closedir(d));
358}