1570af302Sopenharmony_ci/**
2570af302Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
3570af302Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4570af302Sopenharmony_ci * you may not use this file except in compliance with the License.
5570af302Sopenharmony_ci * You may obtain a copy of the License at
6570af302Sopenharmony_ci *
7570af302Sopenharmony_ci *   http://www.apache.org/licenses/LICENSE-2.0
8570af302Sopenharmony_ci *
9570af302Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10570af302Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11570af302Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12570af302Sopenharmony_ci * See the License for the specific language governing permissions and
13570af302Sopenharmony_ci * limitations under the License.
14570af302Sopenharmony_ci */
15570af302Sopenharmony_ci
16570af302Sopenharmony_ci#include <errno.h>
17570af302Sopenharmony_ci#include <ftw.h>
18570af302Sopenharmony_ci#include <limits.h>
19570af302Sopenharmony_ci#include <fcntl.h>
20570af302Sopenharmony_ci#include <unistd.h>
21570af302Sopenharmony_ci#include <stdlib.h>
22570af302Sopenharmony_ci#include <dirent.h>
23570af302Sopenharmony_ci#include <pthread.h>
24570af302Sopenharmony_ci#include <sys/stat.h>
25570af302Sopenharmony_ci#include "functionalext.h"
26570af302Sopenharmony_ci
27570af302Sopenharmony_ci#define TEST_FD_LIMIT 128
28570af302Sopenharmony_ci#define TEST_FLAG_SIZE 4
29570af302Sopenharmony_ci#define TEST_DIGIT_TWO 2
30570af302Sopenharmony_ci#define TEST_PATH_DEPTH 5
31570af302Sopenharmony_ci#define TEST_NFTW_PATH "/data/local/tmp/nftwPath"
32570af302Sopenharmony_ci
33570af302Sopenharmony_cipthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
34570af302Sopenharmony_ci
35570af302Sopenharmony_cistatic int nftw_callback(const char *pathname, const struct stat *sb, int flag, struct FTW *ftw)
36570af302Sopenharmony_ci{
37570af302Sopenharmony_ci    EXPECT_TRUE("nftw_callback", pathname != NULL);
38570af302Sopenharmony_ci    EXPECT_TRUE("nftw_callback", sb != NULL);
39570af302Sopenharmony_ci    if (flag == FTW_NS) {
40570af302Sopenharmony_ci        struct stat st;
41570af302Sopenharmony_ci        EXPECT_EQ("nftw_callback", stat(pathname, &st), -1);
42570af302Sopenharmony_ci        return 0;
43570af302Sopenharmony_ci    }
44570af302Sopenharmony_ci
45570af302Sopenharmony_ci    if (S_ISDIR(sb->st_mode)) {
46570af302Sopenharmony_ci        if (access(pathname, R_OK) == 0) {
47570af302Sopenharmony_ci            EXPECT_TRUE("nftw_callback", flag == FTW_D || flag == FTW_DP);
48570af302Sopenharmony_ci        } else {
49570af302Sopenharmony_ci            EXPECT_EQ("nftw_callback", flag, FTW_DNR);
50570af302Sopenharmony_ci        }
51570af302Sopenharmony_ci    } else if (S_ISLNK(sb->st_mode)) {
52570af302Sopenharmony_ci        EXPECT_TRUE("nftw_callback", flag == FTW_SL || flag == FTW_SLN);
53570af302Sopenharmony_ci    } else {
54570af302Sopenharmony_ci        EXPECT_EQ("nftw_callback", flag, FTW_F);
55570af302Sopenharmony_ci    }
56570af302Sopenharmony_ci    return 0;
57570af302Sopenharmony_ci}
58570af302Sopenharmony_ci
59570af302Sopenharmony_civoid remove_directory(const char *path)
60570af302Sopenharmony_ci{
61570af302Sopenharmony_ci    DIR *dir;
62570af302Sopenharmony_ci    struct dirent *entry;
63570af302Sopenharmony_ci    char filepath[PATH_MAX];
64570af302Sopenharmony_ci
65570af302Sopenharmony_ci    if (!(dir = opendir(path))) {
66570af302Sopenharmony_ci        return;
67570af302Sopenharmony_ci    }
68570af302Sopenharmony_ci
69570af302Sopenharmony_ci    while ((entry = readdir(dir)) != NULL) {
70570af302Sopenharmony_ci        if (entry->d_type == DT_DIR) {
71570af302Sopenharmony_ci            if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
72570af302Sopenharmony_ci                continue;
73570af302Sopenharmony_ci            }
74570af302Sopenharmony_ci
75570af302Sopenharmony_ci            int result = snprintf(filepath, sizeof(filepath), "%s/%s", path, entry->d_name);
76570af302Sopenharmony_ci            if (result >= sizeof(filepath)) {
77570af302Sopenharmony_ci                t_error("%s error in snprintf! \n", __func__);
78570af302Sopenharmony_ci            }
79570af302Sopenharmony_ci            remove_directory(filepath);
80570af302Sopenharmony_ci        } else {
81570af302Sopenharmony_ci            int result = snprintf(filepath, sizeof(filepath), "%s/%s", path, entry->d_name);
82570af302Sopenharmony_ci            if (result >= sizeof(filepath)) {
83570af302Sopenharmony_ci                t_error("%s error in snprintf! \n", __func__);
84570af302Sopenharmony_ci            }
85570af302Sopenharmony_ci            if (remove(filepath) == -1) {
86570af302Sopenharmony_ci                t_error("%s error in remove test nftw filepath! \n", __func__);
87570af302Sopenharmony_ci            }
88570af302Sopenharmony_ci        }
89570af302Sopenharmony_ci    }
90570af302Sopenharmony_ci
91570af302Sopenharmony_ci    closedir(dir);
92570af302Sopenharmony_ci
93570af302Sopenharmony_ci    // Now we can remove the empty directory
94570af302Sopenharmony_ci    if (rmdir(path) == -1) {
95570af302Sopenharmony_ci        t_error("%s error in rmdir test nftw path! \n", __func__);
96570af302Sopenharmony_ci    }
97570af302Sopenharmony_ci}
98570af302Sopenharmony_ci
99570af302Sopenharmony_civoid nftw_build_testfile(const char *path)
100570af302Sopenharmony_ci{
101570af302Sopenharmony_ci    // Create directory
102570af302Sopenharmony_ci    if (mkdir(path, 0755) == -1) {
103570af302Sopenharmony_ci        t_error("%s error in mkdir test nftw path! %s \n", __func__, path);
104570af302Sopenharmony_ci        return;
105570af302Sopenharmony_ci    }
106570af302Sopenharmony_ci
107570af302Sopenharmony_ci    char file[PATH_MAX];
108570af302Sopenharmony_ci    int result = snprintf(file, sizeof(file), "%s/normal_file.txt", path);
109570af302Sopenharmony_ci    if (result >= sizeof(file)) {
110570af302Sopenharmony_ci        t_error("%s error in snprintf! \n", __func__);
111570af302Sopenharmony_ci    }
112570af302Sopenharmony_ci    // Create plain file
113570af302Sopenharmony_ci    int fd = open(file, O_WRONLY | O_CREAT, 0644);
114570af302Sopenharmony_ci    if (fd == -1) {
115570af302Sopenharmony_ci        t_error("%s error in open normal_file.txt! \n", __func__);
116570af302Sopenharmony_ci        return;
117570af302Sopenharmony_ci    }
118570af302Sopenharmony_ci    close(fd);
119570af302Sopenharmony_ci
120570af302Sopenharmony_ci    result = snprintf(file, sizeof(file), "%s/non-executable_file.txt", path);
121570af302Sopenharmony_ci    if (result >= sizeof(file)) {
122570af302Sopenharmony_ci        t_error("%s error in snprintf! \n", __func__);
123570af302Sopenharmony_ci    }
124570af302Sopenharmony_ci    // Create non-executable file
125570af302Sopenharmony_ci    fd = open(file, O_WRONLY | O_CREAT, 0666);
126570af302Sopenharmony_ci    if (fd == -1) {
127570af302Sopenharmony_ci        t_error("%s error in open normal_file.txt! \n", __func__);
128570af302Sopenharmony_ci        return;
129570af302Sopenharmony_ci    }
130570af302Sopenharmony_ci    close(fd);
131570af302Sopenharmony_ci
132570af302Sopenharmony_ci    result = snprintf(file, sizeof(file), "%s/unauthorized_file.txt", path);
133570af302Sopenharmony_ci    if (result >= sizeof(file)) {
134570af302Sopenharmony_ci        t_error("%s error in snprintf! \n", __func__);
135570af302Sopenharmony_ci    }
136570af302Sopenharmony_ci    // Create unauthorized file
137570af302Sopenharmony_ci    fd = open(file, O_WRONLY | O_CREAT, 0000);
138570af302Sopenharmony_ci    if (fd == -1) {
139570af302Sopenharmony_ci        t_error("%s error in open normal_file.txt! \n", __func__);
140570af302Sopenharmony_ci        return;
141570af302Sopenharmony_ci    }
142570af302Sopenharmony_ci    close(fd);
143570af302Sopenharmony_ci
144570af302Sopenharmony_ci    result = snprintf(file, sizeof(file), "%s/.hidden_file.txt", path);
145570af302Sopenharmony_ci    if (result >= sizeof(file)) {
146570af302Sopenharmony_ci        t_error("%s error in snprintf! \n", __func__);
147570af302Sopenharmony_ci    }
148570af302Sopenharmony_ci    // Create Hidden Files
149570af302Sopenharmony_ci    fd = open(file, O_WRONLY | O_CREAT, 0644);
150570af302Sopenharmony_ci    if (fd == -1) {
151570af302Sopenharmony_ci        t_error("%s error in open hidden_file.txt! \n", __func__);
152570af302Sopenharmony_ci        return;
153570af302Sopenharmony_ci    }
154570af302Sopenharmony_ci    close(fd);
155570af302Sopenharmony_ci
156570af302Sopenharmony_ci    result = snprintf(file, sizeof(file), "%s/read_only_file.txt", path);
157570af302Sopenharmony_ci    if (result >= sizeof(file)) {
158570af302Sopenharmony_ci        t_error("%s error in snprintf! \n", __func__);
159570af302Sopenharmony_ci    }
160570af302Sopenharmony_ci    //Create Read-only files
161570af302Sopenharmony_ci    fd = open(file, O_WRONLY | O_CREAT, 0444);
162570af302Sopenharmony_ci    if (fd == -1) {
163570af302Sopenharmony_ci        t_error("%s error in open read_only_file.txt! \n", __func__);
164570af302Sopenharmony_ci        return;
165570af302Sopenharmony_ci    }
166570af302Sopenharmony_ci    close(fd);
167570af302Sopenharmony_ci
168570af302Sopenharmony_ci    result = snprintf(file, sizeof(file), "%s/symlink_to_normal_file", path);
169570af302Sopenharmony_ci    if (result >= sizeof(file)) {
170570af302Sopenharmony_ci        t_error("%s error in snprintf! \n", __func__);
171570af302Sopenharmony_ci    }
172570af302Sopenharmony_ci    // Create Symbolic links
173570af302Sopenharmony_ci    if (symlink("normal_file.txt", file) == -1) {
174570af302Sopenharmony_ci        t_error("%s error in open symlink_to_normal_file.txt! \n", __func__);
175570af302Sopenharmony_ci        return;
176570af302Sopenharmony_ci    }
177570af302Sopenharmony_ci}
178570af302Sopenharmony_ci
179570af302Sopenharmony_civoid nftw_build_testDir()
180570af302Sopenharmony_ci{
181570af302Sopenharmony_ci    nftw_build_testfile(TEST_NFTW_PATH);
182570af302Sopenharmony_ci    char path[PATH_MAX];
183570af302Sopenharmony_ci    int result = snprintf(path, sizeof(path), "%s", TEST_NFTW_PATH);
184570af302Sopenharmony_ci    if (result >= sizeof(path)) {
185570af302Sopenharmony_ci        t_error("%s error in snprintf! \n", __func__);
186570af302Sopenharmony_ci    }
187570af302Sopenharmony_ci    for (int i = 0 ; i < TEST_PATH_DEPTH ; i++) {
188570af302Sopenharmony_ci        result = snprintf(path, sizeof(path), "%s/data", path);
189570af302Sopenharmony_ci        if (result >= sizeof(path)) {
190570af302Sopenharmony_ci            t_error("%s error in snprintf! \n", __func__);
191570af302Sopenharmony_ci        }
192570af302Sopenharmony_ci        nftw_build_testfile(path);
193570af302Sopenharmony_ci    }
194570af302Sopenharmony_ci}
195570af302Sopenharmony_ci
196570af302Sopenharmony_ci/**
197570af302Sopenharmony_ci * @tc.name      : nftw_0100
198570af302Sopenharmony_ci * @tc.desc      : Traverse directory /data
199570af302Sopenharmony_ci * @tc.level     : Level 0
200570af302Sopenharmony_ci */
201570af302Sopenharmony_civoid nftw_0100(void)
202570af302Sopenharmony_ci{
203570af302Sopenharmony_ci    int flag[TEST_FLAG_SIZE] = {FTW_PHYS, FTW_MOUNT, FTW_CHDIR, FTW_DEPTH};
204570af302Sopenharmony_ci    int i;
205570af302Sopenharmony_ci    for (i = 0; i < TEST_FLAG_SIZE; i++) {
206570af302Sopenharmony_ci        int ret = nftw(TEST_NFTW_PATH, nftw_callback, TEST_FD_LIMIT, flag[i]);
207570af302Sopenharmony_ci        EXPECT_EQ("nftw_0100", ret, 0);
208570af302Sopenharmony_ci    }
209570af302Sopenharmony_ci}
210570af302Sopenharmony_ci
211570af302Sopenharmony_ci/**
212570af302Sopenharmony_ci * @tc.name      : nftw_0200
213570af302Sopenharmony_ci * @tc.desc      : Traverse directory /data, but the maximum number of file descriptors is 0
214570af302Sopenharmony_ci * @tc.level     : Level 0
215570af302Sopenharmony_ci */
216570af302Sopenharmony_civoid nftw_0200(void)
217570af302Sopenharmony_ci{
218570af302Sopenharmony_ci    int ret = nftw(TEST_NFTW_PATH, nftw_callback, 0, FTW_PHYS);
219570af302Sopenharmony_ci    EXPECT_EQ("nftw_0200", ret, 0);
220570af302Sopenharmony_ci}
221570af302Sopenharmony_ci
222570af302Sopenharmony_ci/**
223570af302Sopenharmony_ci * @tc.name      : nftw_0300
224570af302Sopenharmony_ci * @tc.desc      : The file path length exceeds PATH_MAX, traverse the directory
225570af302Sopenharmony_ci * @tc.level     : Level 2
226570af302Sopenharmony_ci */
227570af302Sopenharmony_civoid nftw_0300(void)
228570af302Sopenharmony_ci{
229570af302Sopenharmony_ci    char path[PATH_MAX * TEST_DIGIT_TWO];
230570af302Sopenharmony_ci    memset(path, 'a', sizeof(path));
231570af302Sopenharmony_ci    path[PATH_MAX * TEST_DIGIT_TWO - 1] = 0;
232570af302Sopenharmony_ci    int ret = nftw(path, nftw_callback, TEST_FD_LIMIT, FTW_PHYS);
233570af302Sopenharmony_ci    EXPECT_EQ("nftw_0300", ret, -1);
234570af302Sopenharmony_ci    EXPECT_EQ("nftw_0300", errno, ENAMETOOLONG);
235570af302Sopenharmony_ci}
236570af302Sopenharmony_ci
237570af302Sopenharmony_ciint main(void)
238570af302Sopenharmony_ci{
239570af302Sopenharmony_ci    pthread_mutex_lock(&g_mutex);
240570af302Sopenharmony_ci    nftw_build_testDir();
241570af302Sopenharmony_ci    nftw_0100();
242570af302Sopenharmony_ci    nftw_0200();
243570af302Sopenharmony_ci    nftw_0300();
244570af302Sopenharmony_ci    remove_directory(TEST_NFTW_PATH);
245570af302Sopenharmony_ci    pthread_mutex_unlock(&g_mutex);
246570af302Sopenharmony_ci    return t_status;
247570af302Sopenharmony_ci}