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
31static 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
40template <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) {
52  // Get everything from /proc/self...
53  dirent** entries;
54  int entry_count = scandir("/proc/self", &entries, NULL, alphasort);
55  ASSERT_GE(entry_count, 0);
56
57  dirent64** entries64;
58  int entry_count64 = scandir64("/proc/self", &entries64, NULL, 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
84TEST(dirent, scandirat_scandirat64) {
85  // Get everything from /proc/self...
86  dirent** entries;
87  int entry_count = scandir("/proc/self", &entries, NULL, 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, NULL, 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, NULL, 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
116TEST(dirent, scandir_ENOENT) {
117  dirent** entries;
118  errno = 0;
119  ASSERT_EQ(-1, scandir("/does-not-exist", &entries, nullptr, nullptr));
120  ASSERT_EQ(ENOENT, errno);
121}
122
123TEST(dirent, scandir64_ENOENT) {
124  dirent64** entries;
125  errno = 0;
126  ASSERT_EQ(-1, scandir64("/does-not-exist", &entries, nullptr, nullptr));
127  ASSERT_EQ(ENOENT, errno);
128}
129
130TEST(dirent, scandirat_ENOENT) {
131  int root_fd = open("/", O_DIRECTORY | O_RDONLY);
132  ASSERT_NE(-1, root_fd);
133  dirent** entries;
134  errno = 0;
135  ASSERT_EQ(-1, scandirat(root_fd, "does-not-exist", &entries, nullptr, nullptr));
136  ASSERT_EQ(ENOENT, errno);
137  close(root_fd);
138}
139
140TEST(dirent, scandirat64_ENOENT) {
141  int root_fd = open("/", O_DIRECTORY | O_RDONLY);
142  ASSERT_NE(-1, root_fd);
143  dirent64** entries;
144  errno = 0;
145  ASSERT_EQ(-1, scandirat64(root_fd, "does-not-exist", &entries, nullptr, nullptr));
146  ASSERT_EQ(ENOENT, errno);
147  close(root_fd);
148}
149
150TEST(dirent, fdopendir_invalid) {
151  ASSERT_TRUE(fdopendir(-1) == NULL);
152  ASSERT_EQ(EBADF, errno);
153
154  int fd = open("/dev/null", O_RDONLY);
155  ASSERT_NE(fd, -1);
156  ASSERT_TRUE(fdopendir(fd) == NULL);
157  ASSERT_EQ(ENOTDIR, errno);
158  close(fd);
159}
160
161TEST(dirent, fdopendir) {
162  int fd = open("/proc/self", O_RDONLY);
163  DIR* d = fdopendir(fd);
164  ASSERT_TRUE(d != NULL);
165  dirent* e = readdir(d);
166  ASSERT_STREQ(e->d_name, ".");
167  ASSERT_EQ(closedir(d), 0);
168
169  // fdopendir(3) took ownership, so closedir(3) closed our fd.
170  ASSERT_EQ(close(fd), -1);
171  ASSERT_EQ(EBADF, errno);
172}
173
174TEST(dirent, opendir_invalid) {
175  ASSERT_TRUE(opendir("/does/not/exist") == NULL);
176  ASSERT_EQ(ENOENT, errno);
177
178  ASSERT_TRUE(opendir("/dev/null") == NULL);
179  ASSERT_EQ(ENOTDIR, errno);
180}
181
182TEST(dirent, opendir) {
183  DIR* d = opendir("/proc/self");
184  ASSERT_TRUE(d != NULL);
185  dirent* e = readdir(d);
186  ASSERT_STREQ(e->d_name, ".");
187  ASSERT_EQ(closedir(d), 0);
188}
189
190TEST(dirent, closedir_invalid) {
191  DIR* d = NULL;
192  ASSERT_EQ(closedir(d), -1);
193  ASSERT_EQ(EINVAL, errno);
194}
195
196TEST(dirent, closedir) {
197  DIR* d = opendir("/proc/self");
198  ASSERT_TRUE(d != NULL);
199  ASSERT_EQ(closedir(d), 0);
200}
201
202TEST(dirent, readdir) {
203  DIR* d = opendir("/proc/self");
204  ASSERT_TRUE(d != NULL);
205  std::set<std::string> name_set;
206  errno = 0;
207  dirent* e;
208  while ((e = readdir(d)) != NULL) {
209    name_set.insert(e->d_name);
210  }
211  // Reading to the end of the directory is not an error.
212  // readdir(3) returns NULL, but leaves errno as 0.
213  ASSERT_EQ(0, errno);
214  ASSERT_EQ(closedir(d), 0);
215
216  CheckProcSelf(name_set);
217}
218
219TEST(dirent, readdir64) {
220  DIR* d = opendir("/proc/self");
221  ASSERT_TRUE(d != NULL);
222  std::set<std::string> name_set;
223  errno = 0;
224  dirent64* e;
225  while ((e = readdir64(d)) != NULL) {
226    name_set.insert(e->d_name);
227  }
228  // Reading to the end of the directory is not an error.
229  // readdir64(3) returns NULL, but leaves errno as 0.
230  ASSERT_EQ(0, errno);
231  ASSERT_EQ(closedir(d), 0);
232
233  CheckProcSelf(name_set);
234}
235
236TEST(dirent, readdir_r) {
237  DIR* d = opendir("/proc/self");
238  ASSERT_TRUE(d != NULL);
239  std::set<std::string> name_set;
240  errno = 0;
241  dirent storage;
242  dirent* e = NULL;
243  while (readdir_r(d, &storage, &e) == 0 && e != NULL) {
244    name_set.insert(e->d_name);
245  }
246  // Reading to the end of the directory is not an error.
247  // readdir_r(3) returns NULL, but leaves errno as 0.
248  ASSERT_EQ(0, errno);
249  ASSERT_EQ(closedir(d), 0);
250
251  CheckProcSelf(name_set);
252}
253
254TEST(dirent, readdir64_r) {
255  DIR* d = opendir("/proc/self");
256  ASSERT_TRUE(d != NULL);
257  std::set<std::string> name_set;
258  errno = 0;
259  dirent64 storage;
260  dirent64* e = NULL;
261  while (readdir64_r(d, &storage, &e) == 0 && e != NULL) {
262    name_set.insert(e->d_name);
263  }
264  // Reading to the end of the directory is not an error.
265  // readdir64_r(3) returns NULL, but leaves errno as 0.
266  ASSERT_EQ(0, errno);
267  ASSERT_EQ(closedir(d), 0);
268
269  CheckProcSelf(name_set);
270}
271
272TEST(dirent, rewinddir) {
273  DIR* d = opendir("/proc/self");
274  ASSERT_TRUE(d != NULL);
275
276  // Get all the names once...
277  std::vector<std::string> pass1;
278  dirent* e;
279  while ((e = readdir(d)) != NULL) {
280    pass1.push_back(e->d_name);
281  }
282
283  // ...rewind...
284  rewinddir(d);
285
286  // ...and get all the names again.
287  std::vector<std::string> pass2;
288  while ((e = readdir(d)) != NULL) {
289    pass2.push_back(e->d_name);
290  }
291
292  ASSERT_EQ(closedir(d), 0);
293
294  // We should have seen the same names in the same order both times.
295  ASSERT_EQ(pass1.size(), pass2.size());
296  for (size_t i = 0; i < pass1.size(); ++i) {
297    ASSERT_EQ(pass1[i], pass2[i]);
298  }
299}
300
301TEST(dirent, seekdir_telldir) {
302  DIR* d = opendir("/proc/self");
303  ASSERT_TRUE(d != NULL);
304  std::vector<long> offset_list;
305  std::vector<std::string> name_list;
306  dirent* e = NULL;
307
308  offset_list.push_back(telldir(d));
309  ASSERT_EQ(0L, offset_list.back());
310
311  while ((e = readdir(d)) != NULL) {
312    name_list.push_back(e->d_name);
313    offset_list.push_back(telldir(d));
314    // Make sure telldir() point to the next entry.
315    ASSERT_EQ(e->d_off, offset_list.back());
316  }
317
318  long end_offset = telldir(d);
319  // telldir() should not pass the end of the file.
320  ASSERT_EQ(offset_list.back(), end_offset);
321  offset_list.pop_back();
322
323  for (size_t i = 0; i < offset_list.size(); ++i) {
324    seekdir(d, offset_list[i]);
325    ASSERT_EQ(offset_list[i], telldir(d));
326    e = readdir(d);
327    ASSERT_TRUE(e != NULL);
328    ASSERT_STREQ(name_list[i].c_str(), e->d_name);
329  }
330  for (int i = static_cast<int>(offset_list.size()) - 1; i >= 0; --i) {
331    seekdir(d, offset_list[i]);
332    ASSERT_EQ(offset_list[i], telldir(d));
333    e = readdir(d);
334    ASSERT_TRUE(e != NULL);
335    ASSERT_STREQ(name_list[i].c_str(), e->d_name);
336  }
337
338  // Seek to the end, read NULL.
339  seekdir(d, end_offset);
340  ASSERT_EQ(end_offset, telldir(d));
341  errno = 0;
342  ASSERT_EQ(NULL, readdir(d));
343  ASSERT_EQ(0, errno);
344
345  ASSERT_EQ(0, closedir(d));
346}
347