1 /**
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <errno.h>
17 #include <ftw.h>
18 #include <limits.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include <dirent.h>
23 #include <pthread.h>
24 #include <sys/stat.h>
25 #include "functionalext.h"
26
27 #define TEST_FD_LIMIT 128
28 #define TEST_FLAG_SIZE 4
29 #define TEST_DIGIT_TWO 2
30 #define TEST_PATH_DEPTH 5
31 #define TEST_NFTW_PATH "/data/local/tmp/nftwPath"
32
33 pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
34
nftw_callback(const char * pathname,const struct stat * sb,int flag,struct FTW * ftw)35 static int nftw_callback(const char *pathname, const struct stat *sb, int flag, struct FTW *ftw)
36 {
37 EXPECT_TRUE("nftw_callback", pathname != NULL);
38 EXPECT_TRUE("nftw_callback", sb != NULL);
39 if (flag == FTW_NS) {
40 struct stat st;
41 EXPECT_EQ("nftw_callback", stat(pathname, &st), -1);
42 return 0;
43 }
44
45 if (S_ISDIR(sb->st_mode)) {
46 if (access(pathname, R_OK) == 0) {
47 EXPECT_TRUE("nftw_callback", flag == FTW_D || flag == FTW_DP);
48 } else {
49 EXPECT_EQ("nftw_callback", flag, FTW_DNR);
50 }
51 } else if (S_ISLNK(sb->st_mode)) {
52 EXPECT_TRUE("nftw_callback", flag == FTW_SL || flag == FTW_SLN);
53 } else {
54 EXPECT_EQ("nftw_callback", flag, FTW_F);
55 }
56 return 0;
57 }
58
remove_directory(const char * path)59 void remove_directory(const char *path)
60 {
61 DIR *dir;
62 struct dirent *entry;
63 char filepath[PATH_MAX];
64
65 if (!(dir = opendir(path))) {
66 return;
67 }
68
69 while ((entry = readdir(dir)) != NULL) {
70 if (entry->d_type == DT_DIR) {
71 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
72 continue;
73 }
74
75 int result = snprintf(filepath, sizeof(filepath), "%s/%s", path, entry->d_name);
76 if (result >= sizeof(filepath)) {
77 t_error("%s error in snprintf! \n", __func__);
78 }
79 remove_directory(filepath);
80 } else {
81 int result = snprintf(filepath, sizeof(filepath), "%s/%s", path, entry->d_name);
82 if (result >= sizeof(filepath)) {
83 t_error("%s error in snprintf! \n", __func__);
84 }
85 if (remove(filepath) == -1) {
86 t_error("%s error in remove test nftw filepath! \n", __func__);
87 }
88 }
89 }
90
91 closedir(dir);
92
93 // Now we can remove the empty directory
94 if (rmdir(path) == -1) {
95 t_error("%s error in rmdir test nftw path! \n", __func__);
96 }
97 }
98
nftw_build_testfile(const char * path)99 void nftw_build_testfile(const char *path)
100 {
101 // Create directory
102 if (mkdir(path, 0755) == -1) {
103 t_error("%s error in mkdir test nftw path! %s \n", __func__, path);
104 return;
105 }
106
107 char file[PATH_MAX];
108 int result = snprintf(file, sizeof(file), "%s/normal_file.txt", path);
109 if (result >= sizeof(file)) {
110 t_error("%s error in snprintf! \n", __func__);
111 }
112 // Create plain file
113 int fd = open(file, O_WRONLY | O_CREAT, 0644);
114 if (fd == -1) {
115 t_error("%s error in open normal_file.txt! \n", __func__);
116 return;
117 }
118 close(fd);
119
120 result = snprintf(file, sizeof(file), "%s/non-executable_file.txt", path);
121 if (result >= sizeof(file)) {
122 t_error("%s error in snprintf! \n", __func__);
123 }
124 // Create non-executable file
125 fd = open(file, O_WRONLY | O_CREAT, 0666);
126 if (fd == -1) {
127 t_error("%s error in open normal_file.txt! \n", __func__);
128 return;
129 }
130 close(fd);
131
132 result = snprintf(file, sizeof(file), "%s/unauthorized_file.txt", path);
133 if (result >= sizeof(file)) {
134 t_error("%s error in snprintf! \n", __func__);
135 }
136 // Create unauthorized file
137 fd = open(file, O_WRONLY | O_CREAT, 0000);
138 if (fd == -1) {
139 t_error("%s error in open normal_file.txt! \n", __func__);
140 return;
141 }
142 close(fd);
143
144 result = snprintf(file, sizeof(file), "%s/.hidden_file.txt", path);
145 if (result >= sizeof(file)) {
146 t_error("%s error in snprintf! \n", __func__);
147 }
148 // Create Hidden Files
149 fd = open(file, O_WRONLY | O_CREAT, 0644);
150 if (fd == -1) {
151 t_error("%s error in open hidden_file.txt! \n", __func__);
152 return;
153 }
154 close(fd);
155
156 result = snprintf(file, sizeof(file), "%s/read_only_file.txt", path);
157 if (result >= sizeof(file)) {
158 t_error("%s error in snprintf! \n", __func__);
159 }
160 //Create Read-only files
161 fd = open(file, O_WRONLY | O_CREAT, 0444);
162 if (fd == -1) {
163 t_error("%s error in open read_only_file.txt! \n", __func__);
164 return;
165 }
166 close(fd);
167
168 result = snprintf(file, sizeof(file), "%s/symlink_to_normal_file", path);
169 if (result >= sizeof(file)) {
170 t_error("%s error in snprintf! \n", __func__);
171 }
172 // Create Symbolic links
173 if (symlink("normal_file.txt", file) == -1) {
174 t_error("%s error in open symlink_to_normal_file.txt! \n", __func__);
175 return;
176 }
177 }
178
nftw_build_testDir()179 void nftw_build_testDir()
180 {
181 nftw_build_testfile(TEST_NFTW_PATH);
182 char path[PATH_MAX];
183 int result = snprintf(path, sizeof(path), "%s", TEST_NFTW_PATH);
184 if (result >= sizeof(path)) {
185 t_error("%s error in snprintf! \n", __func__);
186 }
187 for (int i = 0 ; i < TEST_PATH_DEPTH ; i++) {
188 result = snprintf(path, sizeof(path), "%s/data", path);
189 if (result >= sizeof(path)) {
190 t_error("%s error in snprintf! \n", __func__);
191 }
192 nftw_build_testfile(path);
193 }
194 }
195
196 /**
197 * @tc.name : nftw_0100
198 * @tc.desc : Traverse directory /data
199 * @tc.level : Level 0
200 */
nftw_0100(void)201 void nftw_0100(void)
202 {
203 int flag[TEST_FLAG_SIZE] = {FTW_PHYS, FTW_MOUNT, FTW_CHDIR, FTW_DEPTH};
204 int i;
205 for (i = 0; i < TEST_FLAG_SIZE; i++) {
206 int ret = nftw(TEST_NFTW_PATH, nftw_callback, TEST_FD_LIMIT, flag[i]);
207 EXPECT_EQ("nftw_0100", ret, 0);
208 }
209 }
210
211 /**
212 * @tc.name : nftw_0200
213 * @tc.desc : Traverse directory /data, but the maximum number of file descriptors is 0
214 * @tc.level : Level 0
215 */
nftw_0200(void)216 void nftw_0200(void)
217 {
218 int ret = nftw(TEST_NFTW_PATH, nftw_callback, 0, FTW_PHYS);
219 EXPECT_EQ("nftw_0200", ret, 0);
220 }
221
222 /**
223 * @tc.name : nftw_0300
224 * @tc.desc : The file path length exceeds PATH_MAX, traverse the directory
225 * @tc.level : Level 2
226 */
nftw_0300(void)227 void nftw_0300(void)
228 {
229 char path[PATH_MAX * TEST_DIGIT_TWO];
230 memset(path, 'a', sizeof(path));
231 path[PATH_MAX * TEST_DIGIT_TWO - 1] = 0;
232 int ret = nftw(path, nftw_callback, TEST_FD_LIMIT, FTW_PHYS);
233 EXPECT_EQ("nftw_0300", ret, -1);
234 EXPECT_EQ("nftw_0300", errno, ENAMETOOLONG);
235 }
236
main(void)237 int main(void)
238 {
239 pthread_mutex_lock(&g_mutex);
240 nftw_build_testDir();
241 nftw_0100();
242 nftw_0200();
243 nftw_0300();
244 remove_directory(TEST_NFTW_PATH);
245 pthread_mutex_unlock(&g_mutex);
246 return t_status;
247 }