xref: /aosp_15_r20/bionic/tests/ftw_test.cpp (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
1*8d67ca89SAndroid Build Coastguard Worker /*
2*8d67ca89SAndroid Build Coastguard Worker  * Copyright (C) 2014 The Android Open Source Project
3*8d67ca89SAndroid Build Coastguard Worker  *
4*8d67ca89SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*8d67ca89SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*8d67ca89SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*8d67ca89SAndroid Build Coastguard Worker  *
8*8d67ca89SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*8d67ca89SAndroid Build Coastguard Worker  *
10*8d67ca89SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*8d67ca89SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*8d67ca89SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*8d67ca89SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*8d67ca89SAndroid Build Coastguard Worker  * limitations under the License.
15*8d67ca89SAndroid Build Coastguard Worker  */
16*8d67ca89SAndroid Build Coastguard Worker 
17*8d67ca89SAndroid Build Coastguard Worker #include <ftw.h>
18*8d67ca89SAndroid Build Coastguard Worker 
19*8d67ca89SAndroid Build Coastguard Worker #include <fcntl.h>
20*8d67ca89SAndroid Build Coastguard Worker #include <pwd.h>
21*8d67ca89SAndroid Build Coastguard Worker #include <stdio.h>
22*8d67ca89SAndroid Build Coastguard Worker #include <stdlib.h>
23*8d67ca89SAndroid Build Coastguard Worker #include <sys/stat.h>
24*8d67ca89SAndroid Build Coastguard Worker #include <sys/types.h>
25*8d67ca89SAndroid Build Coastguard Worker #include <unistd.h>
26*8d67ca89SAndroid Build Coastguard Worker 
27*8d67ca89SAndroid Build Coastguard Worker #include <android-base/file.h>
28*8d67ca89SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
29*8d67ca89SAndroid Build Coastguard Worker #include <gtest/gtest.h>
30*8d67ca89SAndroid Build Coastguard Worker 
31*8d67ca89SAndroid Build Coastguard Worker #include "utils.h"
32*8d67ca89SAndroid Build Coastguard Worker 
MakeTree(const char * root)33*8d67ca89SAndroid Build Coastguard Worker static void MakeTree(const char* root) {
34*8d67ca89SAndroid Build Coastguard Worker   char path[PATH_MAX];
35*8d67ca89SAndroid Build Coastguard Worker 
36*8d67ca89SAndroid Build Coastguard Worker   snprintf(path, sizeof(path), "%s/dir", root);
37*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, mkdir(path, 0755)) << path;
38*8d67ca89SAndroid Build Coastguard Worker   snprintf(path, sizeof(path), "%s/dir/sub", root);
39*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, mkdir(path, 0555)) << path;
40*8d67ca89SAndroid Build Coastguard Worker   snprintf(path, sizeof(path), "%s/unreadable-dir", root);
41*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, mkdir(path, 0000)) << path;
42*8d67ca89SAndroid Build Coastguard Worker 
43*8d67ca89SAndroid Build Coastguard Worker   snprintf(path, sizeof(path), "%s/dangler", root);
44*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, symlink("/does-not-exist", path));
45*8d67ca89SAndroid Build Coastguard Worker   snprintf(path, sizeof(path), "%s/symlink", root);
46*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, symlink("dir/sub", path));
47*8d67ca89SAndroid Build Coastguard Worker 
48*8d67ca89SAndroid Build Coastguard Worker   int fd;
49*8d67ca89SAndroid Build Coastguard Worker   snprintf(path, sizeof(path), "%s/regular", root);
50*8d67ca89SAndroid Build Coastguard Worker   ASSERT_NE(-1, fd = open(path, O_CREAT|O_TRUNC, 0666));
51*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, close(fd));
52*8d67ca89SAndroid Build Coastguard Worker }
53*8d67ca89SAndroid Build Coastguard Worker 
smoke_test_ftw(const char * fpath,const struct stat * sb,int tflag)54*8d67ca89SAndroid Build Coastguard Worker void smoke_test_ftw(const char* fpath, const struct stat* sb, int tflag) {
55*8d67ca89SAndroid Build Coastguard Worker   ASSERT_TRUE(fpath != nullptr);
56*8d67ca89SAndroid Build Coastguard Worker   ASSERT_TRUE(sb != nullptr);
57*8d67ca89SAndroid Build Coastguard Worker 
58*8d67ca89SAndroid Build Coastguard Worker   // Was it a case where the struct stat we're given is meaningless?
59*8d67ca89SAndroid Build Coastguard Worker   if (tflag == FTW_NS || tflag == FTW_SLN) {
60*8d67ca89SAndroid Build Coastguard Worker     // If so, double-check that we really can't stat.
61*8d67ca89SAndroid Build Coastguard Worker     struct stat sb;
62*8d67ca89SAndroid Build Coastguard Worker     EXPECT_EQ(-1, stat(fpath, &sb));
63*8d67ca89SAndroid Build Coastguard Worker     return;
64*8d67ca89SAndroid Build Coastguard Worker   }
65*8d67ca89SAndroid Build Coastguard Worker 
66*8d67ca89SAndroid Build Coastguard Worker   // Otherwise check that the struct stat matches the type flag.
67*8d67ca89SAndroid Build Coastguard Worker   if (S_ISDIR(sb->st_mode)) {
68*8d67ca89SAndroid Build Coastguard Worker     if (access(fpath, R_OK) == 0) {
69*8d67ca89SAndroid Build Coastguard Worker       EXPECT_TRUE(tflag == FTW_D || tflag == FTW_DP) << fpath << ' ' << tflag;
70*8d67ca89SAndroid Build Coastguard Worker     } else {
71*8d67ca89SAndroid Build Coastguard Worker       EXPECT_EQ(FTW_DNR, tflag) << fpath;
72*8d67ca89SAndroid Build Coastguard Worker     }
73*8d67ca89SAndroid Build Coastguard Worker   } else if (S_ISLNK(sb->st_mode)) {
74*8d67ca89SAndroid Build Coastguard Worker     EXPECT_EQ(FTW_SL, tflag) << fpath;
75*8d67ca89SAndroid Build Coastguard Worker   } else {
76*8d67ca89SAndroid Build Coastguard Worker     EXPECT_EQ(FTW_F, tflag) << fpath;
77*8d67ca89SAndroid Build Coastguard Worker   }
78*8d67ca89SAndroid Build Coastguard Worker }
79*8d67ca89SAndroid Build Coastguard Worker 
smoke_test_nftw(const char * fpath,const struct stat * sb,int tflag,FTW * ftwbuf)80*8d67ca89SAndroid Build Coastguard Worker void smoke_test_nftw(const char* fpath, const struct stat* sb, int tflag, FTW* ftwbuf) {
81*8d67ca89SAndroid Build Coastguard Worker   smoke_test_ftw(fpath, sb, tflag);
82*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ('/', fpath[ftwbuf->base - 1]) << fpath;
83*8d67ca89SAndroid Build Coastguard Worker }
84*8d67ca89SAndroid Build Coastguard Worker 
check_ftw(const char * fpath,const struct stat * sb,int tflag)85*8d67ca89SAndroid Build Coastguard Worker int check_ftw(const char* fpath, const struct stat* sb, int tflag) {
86*8d67ca89SAndroid Build Coastguard Worker   smoke_test_ftw(fpath, sb, tflag);
87*8d67ca89SAndroid Build Coastguard Worker   return 0;
88*8d67ca89SAndroid Build Coastguard Worker }
89*8d67ca89SAndroid Build Coastguard Worker 
check_ftw64(const char * fpath,const struct stat64 * sb,int tflag)90*8d67ca89SAndroid Build Coastguard Worker int check_ftw64(const char* fpath, const struct stat64* sb, int tflag) {
91*8d67ca89SAndroid Build Coastguard Worker   smoke_test_ftw(fpath, reinterpret_cast<const struct stat*>(sb), tflag);
92*8d67ca89SAndroid Build Coastguard Worker   return 0;
93*8d67ca89SAndroid Build Coastguard Worker }
94*8d67ca89SAndroid Build Coastguard Worker 
check_nftw(const char * fpath,const struct stat * sb,int tflag,FTW * ftwbuf)95*8d67ca89SAndroid Build Coastguard Worker int check_nftw(const char* fpath, const struct stat* sb, int tflag, FTW* ftwbuf) {
96*8d67ca89SAndroid Build Coastguard Worker   smoke_test_nftw(fpath, sb, tflag, ftwbuf);
97*8d67ca89SAndroid Build Coastguard Worker   return 0;
98*8d67ca89SAndroid Build Coastguard Worker }
99*8d67ca89SAndroid Build Coastguard Worker 
check_nftw64(const char * fpath,const struct stat64 * sb,int tflag,FTW * ftwbuf)100*8d67ca89SAndroid Build Coastguard Worker int check_nftw64(const char* fpath, const struct stat64* sb, int tflag, FTW* ftwbuf) {
101*8d67ca89SAndroid Build Coastguard Worker   smoke_test_nftw(fpath, reinterpret_cast<const struct stat*>(sb), tflag, ftwbuf);
102*8d67ca89SAndroid Build Coastguard Worker   return 0;
103*8d67ca89SAndroid Build Coastguard Worker }
104*8d67ca89SAndroid Build Coastguard Worker 
TEST(ftw,ftw)105*8d67ca89SAndroid Build Coastguard Worker TEST(ftw, ftw) {
106*8d67ca89SAndroid Build Coastguard Worker   TemporaryDir root;
107*8d67ca89SAndroid Build Coastguard Worker   MakeTree(root.path);
108*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, ftw(root.path, check_ftw, 128));
109*8d67ca89SAndroid Build Coastguard Worker }
110*8d67ca89SAndroid Build Coastguard Worker 
TEST(ftw,ftw64_smoke)111*8d67ca89SAndroid Build Coastguard Worker TEST(ftw, ftw64_smoke) {
112*8d67ca89SAndroid Build Coastguard Worker   TemporaryDir root;
113*8d67ca89SAndroid Build Coastguard Worker   MakeTree(root.path);
114*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, ftw64(root.path, check_ftw64, 128));
115*8d67ca89SAndroid Build Coastguard Worker }
116*8d67ca89SAndroid Build Coastguard Worker 
TEST(ftw,nftw)117*8d67ca89SAndroid Build Coastguard Worker TEST(ftw, nftw) {
118*8d67ca89SAndroid Build Coastguard Worker   TemporaryDir root;
119*8d67ca89SAndroid Build Coastguard Worker   MakeTree(root.path);
120*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, nftw(root.path, check_nftw, 128, 0));
121*8d67ca89SAndroid Build Coastguard Worker }
122*8d67ca89SAndroid Build Coastguard Worker 
TEST(ftw,nftw64_smoke)123*8d67ca89SAndroid Build Coastguard Worker TEST(ftw, nftw64_smoke) {
124*8d67ca89SAndroid Build Coastguard Worker   TemporaryDir root;
125*8d67ca89SAndroid Build Coastguard Worker   MakeTree(root.path);
126*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, nftw64(root.path, check_nftw64, 128, 0));
127*8d67ca89SAndroid Build Coastguard Worker }
128*8d67ca89SAndroid Build Coastguard Worker 
129*8d67ca89SAndroid Build Coastguard Worker template <typename StatT>
bug_28197840_ftw(const char * path,const StatT *,int flag)130*8d67ca89SAndroid Build Coastguard Worker static int bug_28197840_ftw(const char* path, const StatT*, int flag) {
131*8d67ca89SAndroid Build Coastguard Worker   EXPECT_EQ(strstr(path, "unreadable") != nullptr ? FTW_DNR : FTW_D, flag) << path;
132*8d67ca89SAndroid Build Coastguard Worker   return 0;
133*8d67ca89SAndroid Build Coastguard Worker }
134*8d67ca89SAndroid Build Coastguard Worker 
135*8d67ca89SAndroid Build Coastguard Worker template <typename StatT>
bug_28197840_nftw(const char * path,const StatT * sb,int flag,FTW *)136*8d67ca89SAndroid Build Coastguard Worker static int bug_28197840_nftw(const char* path, const StatT* sb, int flag, FTW*) {
137*8d67ca89SAndroid Build Coastguard Worker   return bug_28197840_ftw(path, sb, flag);
138*8d67ca89SAndroid Build Coastguard Worker }
139*8d67ca89SAndroid Build Coastguard Worker 
TEST(ftw,bug_28197840)140*8d67ca89SAndroid Build Coastguard Worker TEST(ftw, bug_28197840) {
141*8d67ca89SAndroid Build Coastguard Worker   // Drop root for this test, because root can still read directories even if
142*8d67ca89SAndroid Build Coastguard Worker   // permissions would imply otherwise.
143*8d67ca89SAndroid Build Coastguard Worker   if (getuid() == 0) {
144*8d67ca89SAndroid Build Coastguard Worker     passwd* pwd = getpwnam("shell");
145*8d67ca89SAndroid Build Coastguard Worker     ASSERT_EQ(0, setuid(pwd->pw_uid));
146*8d67ca89SAndroid Build Coastguard Worker   }
147*8d67ca89SAndroid Build Coastguard Worker 
148*8d67ca89SAndroid Build Coastguard Worker   TemporaryDir root;
149*8d67ca89SAndroid Build Coastguard Worker 
150*8d67ca89SAndroid Build Coastguard Worker   std::string path = android::base::StringPrintf("%s/unreadable-directory", root.path);
151*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, mkdir(path.c_str(), 0000)) << path;
152*8d67ca89SAndroid Build Coastguard Worker 
153*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, ftw(root.path, bug_28197840_ftw<struct stat>, 128));
154*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, ftw64(root.path, bug_28197840_ftw<struct stat64>, 128));
155*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, nftw(root.path, bug_28197840_nftw<struct stat>, 128, FTW_PHYS));
156*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(0, nftw64(root.path, bug_28197840_nftw<struct stat64>, 128, FTW_PHYS));
157*8d67ca89SAndroid Build Coastguard Worker }
158*8d67ca89SAndroid Build Coastguard Worker 
159*8d67ca89SAndroid Build Coastguard Worker template <typename StatT>
null_ftw_callback(const char *,const StatT *,int)160*8d67ca89SAndroid Build Coastguard Worker static int null_ftw_callback(const char*, const StatT*, int) {
161*8d67ca89SAndroid Build Coastguard Worker   return 0;
162*8d67ca89SAndroid Build Coastguard Worker }
163*8d67ca89SAndroid Build Coastguard Worker 
164*8d67ca89SAndroid Build Coastguard Worker template <typename StatT>
null_nftw_callback(const char *,const StatT *,int,FTW *)165*8d67ca89SAndroid Build Coastguard Worker static int null_nftw_callback(const char*, const StatT*, int, FTW*) {
166*8d67ca89SAndroid Build Coastguard Worker   return 0;
167*8d67ca89SAndroid Build Coastguard Worker }
168*8d67ca89SAndroid Build Coastguard Worker 
TEST(ftw,ftw_non_existent_ENOENT)169*8d67ca89SAndroid Build Coastguard Worker TEST(ftw, ftw_non_existent_ENOENT) {
170*8d67ca89SAndroid Build Coastguard Worker   errno = 0;
171*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(-1, ftw("/does/not/exist", null_ftw_callback<struct stat>, 128));
172*8d67ca89SAndroid Build Coastguard Worker   ASSERT_ERRNO(ENOENT);
173*8d67ca89SAndroid Build Coastguard Worker   errno = 0;
174*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(-1, ftw64("/does/not/exist", null_ftw_callback<struct stat64>, 128));
175*8d67ca89SAndroid Build Coastguard Worker   ASSERT_ERRNO(ENOENT);
176*8d67ca89SAndroid Build Coastguard Worker }
177*8d67ca89SAndroid Build Coastguard Worker 
TEST(ftw,nftw_non_existent_ENOENT)178*8d67ca89SAndroid Build Coastguard Worker TEST(ftw, nftw_non_existent_ENOENT) {
179*8d67ca89SAndroid Build Coastguard Worker   errno = 0;
180*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(-1, nftw("/does/not/exist", null_nftw_callback<struct stat>, 128, FTW_PHYS));
181*8d67ca89SAndroid Build Coastguard Worker   ASSERT_ERRNO(ENOENT);
182*8d67ca89SAndroid Build Coastguard Worker   errno = 0;
183*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(-1, nftw64("/does/not/exist", null_nftw_callback<struct stat64>, 128, FTW_PHYS));
184*8d67ca89SAndroid Build Coastguard Worker   ASSERT_ERRNO(ENOENT);
185*8d67ca89SAndroid Build Coastguard Worker }
186*8d67ca89SAndroid Build Coastguard Worker 
TEST(ftw,ftw_empty_ENOENT)187*8d67ca89SAndroid Build Coastguard Worker TEST(ftw, ftw_empty_ENOENT) {
188*8d67ca89SAndroid Build Coastguard Worker   errno = 0;
189*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(-1, ftw("", null_ftw_callback<struct stat>, 128));
190*8d67ca89SAndroid Build Coastguard Worker   ASSERT_ERRNO(ENOENT);
191*8d67ca89SAndroid Build Coastguard Worker   errno = 0;
192*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(-1, ftw64("", null_ftw_callback<struct stat64>, 128));
193*8d67ca89SAndroid Build Coastguard Worker   ASSERT_ERRNO(ENOENT);
194*8d67ca89SAndroid Build Coastguard Worker }
195*8d67ca89SAndroid Build Coastguard Worker 
TEST(ftw,nftw_empty_ENOENT)196*8d67ca89SAndroid Build Coastguard Worker TEST(ftw, nftw_empty_ENOENT) {
197*8d67ca89SAndroid Build Coastguard Worker   errno = 0;
198*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(-1, nftw("", null_nftw_callback<struct stat>, 128, FTW_PHYS));
199*8d67ca89SAndroid Build Coastguard Worker   ASSERT_ERRNO(ENOENT);
200*8d67ca89SAndroid Build Coastguard Worker   errno = 0;
201*8d67ca89SAndroid Build Coastguard Worker   ASSERT_EQ(-1, nftw64("", null_nftw_callback<struct stat64>, 128, FTW_PHYS));
202*8d67ca89SAndroid Build Coastguard Worker   ASSERT_ERRNO(ENOENT);
203*8d67ca89SAndroid Build Coastguard Worker }
204