blob: 9d9c1d3db9305a60c8df076a557faf745da5b4c8 [file] [log] [blame]
Calin Juravled4934a72014-02-24 16:13:50 +00001/*
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
Calin Juravled4934a72014-02-24 16:13:50 +000017#include <ftw.h>
Elliott Hughes63bd43b2014-11-18 15:57:23 -080018
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -080019#include <fcntl.h>
Elliott Hughes13d79ab2016-04-15 17:40:33 -070020#include <pwd.h>
Elliott Hughes7f925092015-02-10 14:15:33 -080021#include <stdio.h>
Calin Juravled4934a72014-02-24 16:13:50 +000022#include <stdlib.h>
23#include <sys/stat.h>
Elliott Hughes7f925092015-02-10 14:15:33 -080024#include <sys/types.h>
25#include <unistd.h>
26
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -080027#include <android-base/file.h>
Elliott Hughes13d79ab2016-04-15 17:40:33 -070028#include <android-base/stringprintf.h>
Elliott Hughes63bd43b2014-11-18 15:57:23 -080029#include <gtest/gtest.h>
30
Elliott Hughes95646e62023-09-21 14:11:19 -070031#include "utils.h"
32
Elliott Hughes7f925092015-02-10 14:15:33 -080033static void MakeTree(const char* root) {
34 char path[PATH_MAX];
35
36 snprintf(path, sizeof(path), "%s/dir", root);
Elliott Hughes0ad256c2015-04-01 12:22:40 -070037 ASSERT_EQ(0, mkdir(path, 0755)) << path;
Elliott Hughes7f925092015-02-10 14:15:33 -080038 snprintf(path, sizeof(path), "%s/dir/sub", root);
Elliott Hughes0ad256c2015-04-01 12:22:40 -070039 ASSERT_EQ(0, mkdir(path, 0555)) << path;
Elliott Hughes7f925092015-02-10 14:15:33 -080040 snprintf(path, sizeof(path), "%s/unreadable-dir", root);
Elliott Hughes0ad256c2015-04-01 12:22:40 -070041 ASSERT_EQ(0, mkdir(path, 0000)) << path;
Elliott Hughes7f925092015-02-10 14:15:33 -080042
43 snprintf(path, sizeof(path), "%s/dangler", root);
44 ASSERT_EQ(0, symlink("/does-not-exist", path));
45 snprintf(path, sizeof(path), "%s/symlink", root);
Elliott Hughes13d79ab2016-04-15 17:40:33 -070046 ASSERT_EQ(0, symlink("dir/sub", path));
Elliott Hughes7f925092015-02-10 14:15:33 -080047
48 int fd;
49 snprintf(path, sizeof(path), "%s/regular", root);
50 ASSERT_NE(-1, fd = open(path, O_CREAT|O_TRUNC, 0666));
51 ASSERT_EQ(0, close(fd));
52}
53
Elliott Hughes68ae6ad2020-07-21 16:11:30 -070054void smoke_test_ftw(const char* fpath, const struct stat* sb, int tflag) {
Yi Kong32bc0fc2018-08-02 17:31:13 -070055 ASSERT_TRUE(fpath != nullptr);
56 ASSERT_TRUE(sb != nullptr);
Elliott Hughes7f925092015-02-10 14:15:33 -080057
Elliott Hughes13d79ab2016-04-15 17:40:33 -070058 // Was it a case where the struct stat we're given is meaningless?
59 if (tflag == FTW_NS || tflag == FTW_SLN) {
60 // If so, double-check that we really can't stat.
61 struct stat sb;
62 EXPECT_EQ(-1, stat(fpath, &sb));
63 return;
64 }
65
66 // Otherwise check that the struct stat matches the type flag.
Elliott Hughes63bd43b2014-11-18 15:57:23 -080067 if (S_ISDIR(sb->st_mode)) {
Elliott Hughes13d79ab2016-04-15 17:40:33 -070068 if (access(fpath, R_OK) == 0) {
69 EXPECT_TRUE(tflag == FTW_D || tflag == FTW_DP) << fpath << ' ' << tflag;
70 } else {
71 EXPECT_EQ(FTW_DNR, tflag) << fpath;
72 }
Elliott Hughes63bd43b2014-11-18 15:57:23 -080073 } else if (S_ISLNK(sb->st_mode)) {
Elliott Hughes7f925092015-02-10 14:15:33 -080074 EXPECT_EQ(FTW_SL, tflag) << fpath;
Elliott Hughes63bd43b2014-11-18 15:57:23 -080075 } else {
Elliott Hughes7f925092015-02-10 14:15:33 -080076 EXPECT_EQ(FTW_F, tflag) << fpath;
Elliott Hughes63bd43b2014-11-18 15:57:23 -080077 }
Calin Juravled4934a72014-02-24 16:13:50 +000078}
79
Elliott Hughes68ae6ad2020-07-21 16:11:30 -070080void smoke_test_nftw(const char* fpath, const struct stat* sb, int tflag, FTW* ftwbuf) {
81 smoke_test_ftw(fpath, sb, tflag);
Elliott Hughes63bd43b2014-11-18 15:57:23 -080082 ASSERT_EQ('/', fpath[ftwbuf->base - 1]) << fpath;
Calin Juravled4934a72014-02-24 16:13:50 +000083}
84
85int check_ftw(const char* fpath, const struct stat* sb, int tflag) {
Elliott Hughes68ae6ad2020-07-21 16:11:30 -070086 smoke_test_ftw(fpath, sb, tflag);
Calin Juravled4934a72014-02-24 16:13:50 +000087 return 0;
88}
89
90int check_ftw64(const char* fpath, const struct stat64* sb, int tflag) {
Elliott Hughes68ae6ad2020-07-21 16:11:30 -070091 smoke_test_ftw(fpath, reinterpret_cast<const struct stat*>(sb), tflag);
Calin Juravled4934a72014-02-24 16:13:50 +000092 return 0;
93}
94
Elliott Hughes13d79ab2016-04-15 17:40:33 -070095int check_nftw(const char* fpath, const struct stat* sb, int tflag, FTW* ftwbuf) {
Elliott Hughes68ae6ad2020-07-21 16:11:30 -070096 smoke_test_nftw(fpath, sb, tflag, ftwbuf);
Calin Juravled4934a72014-02-24 16:13:50 +000097 return 0;
98}
99
Elliott Hughes13d79ab2016-04-15 17:40:33 -0700100int check_nftw64(const char* fpath, const struct stat64* sb, int tflag, FTW* ftwbuf) {
Elliott Hughes68ae6ad2020-07-21 16:11:30 -0700101 smoke_test_nftw(fpath, reinterpret_cast<const struct stat*>(sb), tflag, ftwbuf);
Calin Juravled4934a72014-02-24 16:13:50 +0000102 return 0;
103}
104
105TEST(ftw, ftw) {
Elliott Hughes7f925092015-02-10 14:15:33 -0800106 TemporaryDir root;
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800107 MakeTree(root.path);
108 ASSERT_EQ(0, ftw(root.path, check_ftw, 128));
Calin Juravled4934a72014-02-24 16:13:50 +0000109}
110
Colin Cross7da20342021-07-28 11:18:11 -0700111TEST(ftw, ftw64_smoke) {
Elliott Hughes7f925092015-02-10 14:15:33 -0800112 TemporaryDir root;
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800113 MakeTree(root.path);
114 ASSERT_EQ(0, ftw64(root.path, check_ftw64, 128));
Calin Juravled4934a72014-02-24 16:13:50 +0000115}
116
117TEST(ftw, nftw) {
Elliott Hughes7f925092015-02-10 14:15:33 -0800118 TemporaryDir root;
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800119 MakeTree(root.path);
120 ASSERT_EQ(0, nftw(root.path, check_nftw, 128, 0));
Calin Juravled4934a72014-02-24 16:13:50 +0000121}
122
Colin Cross7da20342021-07-28 11:18:11 -0700123TEST(ftw, nftw64_smoke) {
Elliott Hughes7f925092015-02-10 14:15:33 -0800124 TemporaryDir root;
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800125 MakeTree(root.path);
126 ASSERT_EQ(0, nftw64(root.path, check_nftw64, 128, 0));
Calin Juravled4934a72014-02-24 16:13:50 +0000127}
Elliott Hughes13d79ab2016-04-15 17:40:33 -0700128
129template <typename StatT>
130static int bug_28197840_ftw(const char* path, const StatT*, int flag) {
131 EXPECT_EQ(strstr(path, "unreadable") != nullptr ? FTW_DNR : FTW_D, flag) << path;
132 return 0;
133}
134
135template <typename StatT>
136static int bug_28197840_nftw(const char* path, const StatT* sb, int flag, FTW*) {
137 return bug_28197840_ftw(path, sb, flag);
138}
139
140TEST(ftw, bug_28197840) {
141 // Drop root for this test, because root can still read directories even if
142 // permissions would imply otherwise.
143 if (getuid() == 0) {
144 passwd* pwd = getpwnam("shell");
145 ASSERT_EQ(0, setuid(pwd->pw_uid));
146 }
147
148 TemporaryDir root;
149
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800150 std::string path = android::base::StringPrintf("%s/unreadable-directory", root.path);
Elliott Hughes13d79ab2016-04-15 17:40:33 -0700151 ASSERT_EQ(0, mkdir(path.c_str(), 0000)) << path;
152
Mark Salyzyn68a3bcc2018-11-13 07:35:21 -0800153 ASSERT_EQ(0, ftw(root.path, bug_28197840_ftw<struct stat>, 128));
154 ASSERT_EQ(0, ftw64(root.path, bug_28197840_ftw<struct stat64>, 128));
155 ASSERT_EQ(0, nftw(root.path, bug_28197840_nftw<struct stat>, 128, FTW_PHYS));
156 ASSERT_EQ(0, nftw64(root.path, bug_28197840_nftw<struct stat64>, 128, FTW_PHYS));
Elliott Hughes13d79ab2016-04-15 17:40:33 -0700157}
Elliott Hughes70a8f222018-05-07 16:44:13 -0700158
159template <typename StatT>
160static int null_ftw_callback(const char*, const StatT*, int) {
161 return 0;
162}
163
164template <typename StatT>
165static int null_nftw_callback(const char*, const StatT*, int, FTW*) {
166 return 0;
167}
168
169TEST(ftw, ftw_non_existent_ENOENT) {
170 errno = 0;
171 ASSERT_EQ(-1, ftw("/does/not/exist", null_ftw_callback<struct stat>, 128));
Elliott Hughes95646e62023-09-21 14:11:19 -0700172 ASSERT_ERRNO(ENOENT);
Elliott Hughes70a8f222018-05-07 16:44:13 -0700173 errno = 0;
174 ASSERT_EQ(-1, ftw64("/does/not/exist", null_ftw_callback<struct stat64>, 128));
Elliott Hughes95646e62023-09-21 14:11:19 -0700175 ASSERT_ERRNO(ENOENT);
Elliott Hughes70a8f222018-05-07 16:44:13 -0700176}
177
178TEST(ftw, nftw_non_existent_ENOENT) {
179 errno = 0;
180 ASSERT_EQ(-1, nftw("/does/not/exist", null_nftw_callback<struct stat>, 128, FTW_PHYS));
Elliott Hughes95646e62023-09-21 14:11:19 -0700181 ASSERT_ERRNO(ENOENT);
Elliott Hughes70a8f222018-05-07 16:44:13 -0700182 errno = 0;
183 ASSERT_EQ(-1, nftw64("/does/not/exist", null_nftw_callback<struct stat64>, 128, FTW_PHYS));
Elliott Hughes95646e62023-09-21 14:11:19 -0700184 ASSERT_ERRNO(ENOENT);
Elliott Hughes70a8f222018-05-07 16:44:13 -0700185}
186
187TEST(ftw, ftw_empty_ENOENT) {
188 errno = 0;
189 ASSERT_EQ(-1, ftw("", null_ftw_callback<struct stat>, 128));
Elliott Hughes95646e62023-09-21 14:11:19 -0700190 ASSERT_ERRNO(ENOENT);
Elliott Hughes70a8f222018-05-07 16:44:13 -0700191 errno = 0;
192 ASSERT_EQ(-1, ftw64("", null_ftw_callback<struct stat64>, 128));
Elliott Hughes95646e62023-09-21 14:11:19 -0700193 ASSERT_ERRNO(ENOENT);
Elliott Hughes70a8f222018-05-07 16:44:13 -0700194}
195
196TEST(ftw, nftw_empty_ENOENT) {
197 errno = 0;
198 ASSERT_EQ(-1, nftw("", null_nftw_callback<struct stat>, 128, FTW_PHYS));
Elliott Hughes95646e62023-09-21 14:11:19 -0700199 ASSERT_ERRNO(ENOENT);
Elliott Hughes70a8f222018-05-07 16:44:13 -0700200 errno = 0;
201 ASSERT_EQ(-1, nftw64("", null_nftw_callback<struct stat64>, 128, FTW_PHYS));
Elliott Hughes95646e62023-09-21 14:11:19 -0700202 ASSERT_ERRNO(ENOENT);
Elliott Hughes70a8f222018-05-07 16:44:13 -0700203}