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 33pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; 34 35static 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 59void 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 99void 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 179void 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 */ 201void 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 */ 216void 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 */ 227void 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 237int 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}