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