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