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