1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "util.h"
6 
7 #include <fbl/algorithm.h>
8 
check_dir_contents(const char * dirname,expected_dirent_t * edirents,size_t len)9 bool check_dir_contents(const char* dirname, expected_dirent_t* edirents, size_t len) {
10     BEGIN_HELPER;
11     DIR* dir = emu_opendir(dirname);
12 
13     emu_rewinddir(dir);
14     size_t seen = 0;
15     while (seen != len) {
16         struct dirent* de = emu_readdir(dir);
17         ASSERT_NE(de, (void*)0, "Didn't see all expected direntries");
18         bool found = false;
19         for (size_t i = 0; i < len; i++) {
20             if (strcmp(edirents[i].d_name, de->d_name) == 0) {
21                 ASSERT_EQ(edirents[i].d_type, de->d_type, "Saw direntry with unexpected type");
22                 ASSERT_FALSE(edirents[i].seen, "Direntry seen twice");
23                 edirents[i].seen = true;
24                 seen++;
25                 found = true;
26                 break;
27             }
28         }
29 
30         ASSERT_TRUE(found, "Saw an unexpected dirent");
31     }
32 
33     ASSERT_EQ(emu_readdir(dir), (void*)0, "There exists an entry we didn't expect to see");
34     ASSERT_EQ(emu_closedir(dir), 0, "Couldn't close inspected directory");
35     END_HELPER;
36 }
37 
38 #define LARGE_PATH_LENGTH 128
39 
TestDirectoryLarge(void)40 bool TestDirectoryLarge(void) {
41     BEGIN_TEST;
42 
43     const int num_files = 1024;
44     for (int i = 0; i < num_files; i++) {
45         char path[LARGE_PATH_LENGTH + 1];
46         snprintf(path, sizeof(path), "::%0*d", LARGE_PATH_LENGTH - 2, i);
47         int fd = emu_open(path, O_RDWR | O_CREAT | O_EXCL, 0644);
48         ASSERT_GT(fd, 0);
49         ASSERT_EQ(emu_close(fd), 0);
50     }
51 
52     ASSERT_EQ(run_fsck(), 0);
53     END_TEST;
54 }
55 
TestDirectoryReaddir(void)56 bool TestDirectoryReaddir(void) {
57     BEGIN_TEST;
58 
59     ASSERT_EQ(emu_mkdir("::a", 0755), 0);
60     ASSERT_EQ(emu_mkdir("::a", 0755), -1);
61 
62     expected_dirent_t empty_dir[] = {
63         {false, ".", DT_DIR},
64     };
65     ASSERT_TRUE(check_dir_contents("::a", empty_dir, fbl::count_of(empty_dir)));
66 
67     ASSERT_EQ(emu_mkdir("::a/dir1", 0755), 0);
68     int fd = emu_open("::a/file1", O_RDWR | O_CREAT | O_EXCL, 0644);
69     ASSERT_GT(fd, 0);
70     ASSERT_EQ(emu_close(fd), 0);
71 
72     fd = emu_open("::a/file2", O_RDWR | O_CREAT | O_EXCL, 0644);
73     ASSERT_GT(fd, 0);
74     ASSERT_EQ(emu_close(fd), 0);
75 
76     ASSERT_EQ(emu_mkdir("::a/dir2", 0755), 0);
77     expected_dirent_t filled_dir[] = {
78         {false, ".", DT_DIR},
79         {false, "dir1", DT_DIR},
80         {false, "dir2", DT_DIR},
81         {false, "file1", DT_REG},
82         {false, "file2", DT_REG},
83     };
84     ASSERT_TRUE(check_dir_contents("::a", filled_dir, fbl::count_of(filled_dir)));
85     ASSERT_EQ(run_fsck(), 0);
86     END_TEST;
87 }
88 
TestDirectoryReaddirLarge(void)89 bool TestDirectoryReaddirLarge(void) {
90     BEGIN_TEST;
91 
92     size_t num_entries = 1000;
93     ASSERT_EQ(emu_mkdir("::dir", 0755), 0);
94 
95     for (size_t i = 0; i < num_entries; i++) {
96         char dirname[100];
97         snprintf(dirname, 100, "::dir/%05lu", i);
98         ASSERT_EQ(emu_mkdir(dirname, 0755), 0);
99     }
100 
101     DIR* dir = emu_opendir("::dir");
102     ASSERT_NONNULL(dir);
103 
104     struct dirent* de;
105     size_t num_seen = 0;
106     size_t i = 0;
107     while ((de = emu_readdir(dir)) != NULL) {
108         if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
109             continue;
110         }
111         char dirname[100];
112         snprintf(dirname, 100, "%05lu", i++);
113         ASSERT_EQ(strcmp(de->d_name, dirname), 0, "Unexpected dirent");
114         num_seen++;
115     }
116 
117     ASSERT_EQ(num_seen, num_entries, "Did not see all expected entries");
118     ASSERT_EQ(emu_closedir(dir), 0);
119     ASSERT_EQ(run_fsck(), 0);
120     END_TEST;
121 }
122 
123 RUN_MINFS_TESTS(directory_tests,
124     RUN_TEST_LARGE(TestDirectoryLarge)
125     RUN_TEST_MEDIUM(TestDirectoryReaddir)
126     RUN_TEST_MEDIUM(TestDirectoryReaddirLarge)
127 )
128