1*70a7ec85SAndroid Build Coastguard Worker
2*70a7ec85SAndroid Build Coastguard Worker /*
3*70a7ec85SAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project
4*70a7ec85SAndroid Build Coastguard Worker *
5*70a7ec85SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
6*70a7ec85SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
7*70a7ec85SAndroid Build Coastguard Worker * You may obtain a copy of the License at
8*70a7ec85SAndroid Build Coastguard Worker *
9*70a7ec85SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
10*70a7ec85SAndroid Build Coastguard Worker *
11*70a7ec85SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
12*70a7ec85SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
13*70a7ec85SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*70a7ec85SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
15*70a7ec85SAndroid Build Coastguard Worker * limitations under the License.
16*70a7ec85SAndroid Build Coastguard Worker */
17*70a7ec85SAndroid Build Coastguard Worker
18*70a7ec85SAndroid Build Coastguard Worker #include <vintf/FileSystem.h>
19*70a7ec85SAndroid Build Coastguard Worker
20*70a7ec85SAndroid Build Coastguard Worker #include <android-base/file.h>
21*70a7ec85SAndroid Build Coastguard Worker #include <android-base/strings.h>
22*70a7ec85SAndroid Build Coastguard Worker
23*70a7ec85SAndroid Build Coastguard Worker #include <ranges>
24*70a7ec85SAndroid Build Coastguard Worker
25*70a7ec85SAndroid Build Coastguard Worker #include <dirent.h>
26*70a7ec85SAndroid Build Coastguard Worker
27*70a7ec85SAndroid Build Coastguard Worker namespace android {
28*70a7ec85SAndroid Build Coastguard Worker namespace vintf {
29*70a7ec85SAndroid Build Coastguard Worker namespace details {
30*70a7ec85SAndroid Build Coastguard Worker
fetch(const std::string & path,std::string * fetched,std::string * error) const31*70a7ec85SAndroid Build Coastguard Worker status_t FileSystemImpl::fetch(const std::string& path, std::string* fetched,
32*70a7ec85SAndroid Build Coastguard Worker std::string* error) const {
33*70a7ec85SAndroid Build Coastguard Worker if (!android::base::ReadFileToString(path, fetched, true /* follow_symlinks */)) {
34*70a7ec85SAndroid Build Coastguard Worker int saved_errno = errno;
35*70a7ec85SAndroid Build Coastguard Worker if (error) {
36*70a7ec85SAndroid Build Coastguard Worker *error = "Cannot read " + path + ": " + strerror(saved_errno);
37*70a7ec85SAndroid Build Coastguard Worker }
38*70a7ec85SAndroid Build Coastguard Worker return saved_errno == 0 ? UNKNOWN_ERROR : -saved_errno;
39*70a7ec85SAndroid Build Coastguard Worker }
40*70a7ec85SAndroid Build Coastguard Worker return OK;
41*70a7ec85SAndroid Build Coastguard Worker }
42*70a7ec85SAndroid Build Coastguard Worker
listFiles(const std::string & path,std::vector<std::string> * out,std::string * error) const43*70a7ec85SAndroid Build Coastguard Worker status_t FileSystemImpl::listFiles(const std::string& path, std::vector<std::string>* out,
44*70a7ec85SAndroid Build Coastguard Worker std::string* error) const {
45*70a7ec85SAndroid Build Coastguard Worker std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
46*70a7ec85SAndroid Build Coastguard Worker if (!dir) {
47*70a7ec85SAndroid Build Coastguard Worker int saved_errno = errno;
48*70a7ec85SAndroid Build Coastguard Worker if (error) {
49*70a7ec85SAndroid Build Coastguard Worker *error = "Cannot open " + path + ": " + strerror(saved_errno);
50*70a7ec85SAndroid Build Coastguard Worker }
51*70a7ec85SAndroid Build Coastguard Worker return saved_errno == 0 ? UNKNOWN_ERROR : -saved_errno;
52*70a7ec85SAndroid Build Coastguard Worker }
53*70a7ec85SAndroid Build Coastguard Worker
54*70a7ec85SAndroid Build Coastguard Worker dirent* dp;
55*70a7ec85SAndroid Build Coastguard Worker while (errno = 0, dp = readdir(dir.get()), dp != nullptr) {
56*70a7ec85SAndroid Build Coastguard Worker if (dp->d_type != DT_DIR) {
57*70a7ec85SAndroid Build Coastguard Worker out->push_back(dp->d_name);
58*70a7ec85SAndroid Build Coastguard Worker }
59*70a7ec85SAndroid Build Coastguard Worker }
60*70a7ec85SAndroid Build Coastguard Worker int saved_errno = errno;
61*70a7ec85SAndroid Build Coastguard Worker if (saved_errno != 0) {
62*70a7ec85SAndroid Build Coastguard Worker if (error) {
63*70a7ec85SAndroid Build Coastguard Worker *error = "Failed while reading directory " + path + ": " + strerror(saved_errno);
64*70a7ec85SAndroid Build Coastguard Worker }
65*70a7ec85SAndroid Build Coastguard Worker }
66*70a7ec85SAndroid Build Coastguard Worker return -saved_errno;
67*70a7ec85SAndroid Build Coastguard Worker }
68*70a7ec85SAndroid Build Coastguard Worker
modifiedTime(const std::string & path,timespec * mtime,std::string * error) const69*70a7ec85SAndroid Build Coastguard Worker status_t FileSystemImpl::modifiedTime(const std::string& path, timespec* mtime,
70*70a7ec85SAndroid Build Coastguard Worker std::string* error) const {
71*70a7ec85SAndroid Build Coastguard Worker struct stat stat_buf;
72*70a7ec85SAndroid Build Coastguard Worker if (stat(path.c_str(), &stat_buf) != 0) {
73*70a7ec85SAndroid Build Coastguard Worker int saved_errno = errno;
74*70a7ec85SAndroid Build Coastguard Worker if (error) {
75*70a7ec85SAndroid Build Coastguard Worker *error = "Cannot open " + path + ": " + strerror(saved_errno);
76*70a7ec85SAndroid Build Coastguard Worker }
77*70a7ec85SAndroid Build Coastguard Worker return saved_errno == 0 ? UNKNOWN_ERROR : -saved_errno;
78*70a7ec85SAndroid Build Coastguard Worker }
79*70a7ec85SAndroid Build Coastguard Worker *mtime = stat_buf.st_mtim;
80*70a7ec85SAndroid Build Coastguard Worker return OK;
81*70a7ec85SAndroid Build Coastguard Worker }
82*70a7ec85SAndroid Build Coastguard Worker
fetch(const std::string &,std::string *,std::string *) const83*70a7ec85SAndroid Build Coastguard Worker status_t FileSystemNoOp::fetch(const std::string&, std::string*, std::string*) const {
84*70a7ec85SAndroid Build Coastguard Worker return NAME_NOT_FOUND;
85*70a7ec85SAndroid Build Coastguard Worker }
86*70a7ec85SAndroid Build Coastguard Worker
listFiles(const std::string &,std::vector<std::string> *,std::string *) const87*70a7ec85SAndroid Build Coastguard Worker status_t FileSystemNoOp::listFiles(const std::string&, std::vector<std::string>*,
88*70a7ec85SAndroid Build Coastguard Worker std::string*) const {
89*70a7ec85SAndroid Build Coastguard Worker return NAME_NOT_FOUND;
90*70a7ec85SAndroid Build Coastguard Worker }
91*70a7ec85SAndroid Build Coastguard Worker
modifiedTime(const std::string &,timespec *,std::string *) const92*70a7ec85SAndroid Build Coastguard Worker status_t FileSystemNoOp::modifiedTime(const std::string&, timespec*, std::string*) const {
93*70a7ec85SAndroid Build Coastguard Worker return NAME_NOT_FOUND;
94*70a7ec85SAndroid Build Coastguard Worker }
95*70a7ec85SAndroid Build Coastguard Worker
FileSystemUnderPath(const std::string & rootdir)96*70a7ec85SAndroid Build Coastguard Worker FileSystemUnderPath::FileSystemUnderPath(const std::string& rootdir) {
97*70a7ec85SAndroid Build Coastguard Worker mRootDir = rootdir;
98*70a7ec85SAndroid Build Coastguard Worker if (!mRootDir.empty() && mRootDir.back() != '/') {
99*70a7ec85SAndroid Build Coastguard Worker mRootDir.push_back('/');
100*70a7ec85SAndroid Build Coastguard Worker }
101*70a7ec85SAndroid Build Coastguard Worker }
102*70a7ec85SAndroid Build Coastguard Worker
fetch(const std::string & path,std::string * fetched,std::string * error) const103*70a7ec85SAndroid Build Coastguard Worker status_t FileSystemUnderPath::fetch(const std::string& path, std::string* fetched,
104*70a7ec85SAndroid Build Coastguard Worker std::string* error) const {
105*70a7ec85SAndroid Build Coastguard Worker return mImpl.fetch(mRootDir + path, fetched, error);
106*70a7ec85SAndroid Build Coastguard Worker }
107*70a7ec85SAndroid Build Coastguard Worker
listFiles(const std::string & path,std::vector<std::string> * out,std::string * error) const108*70a7ec85SAndroid Build Coastguard Worker status_t FileSystemUnderPath::listFiles(const std::string& path, std::vector<std::string>* out,
109*70a7ec85SAndroid Build Coastguard Worker std::string* error) const {
110*70a7ec85SAndroid Build Coastguard Worker return mImpl.listFiles(mRootDir + path, out, error);
111*70a7ec85SAndroid Build Coastguard Worker }
112*70a7ec85SAndroid Build Coastguard Worker
modifiedTime(const std::string & path,timespec * mtime,std::string * error) const113*70a7ec85SAndroid Build Coastguard Worker status_t FileSystemUnderPath::modifiedTime(const std::string& path, timespec* mtime,
114*70a7ec85SAndroid Build Coastguard Worker std::string* error) const {
115*70a7ec85SAndroid Build Coastguard Worker return mImpl.modifiedTime(mRootDir + path, mtime, error);
116*70a7ec85SAndroid Build Coastguard Worker }
117*70a7ec85SAndroid Build Coastguard Worker
getRootDir() const118*70a7ec85SAndroid Build Coastguard Worker const std::string& FileSystemUnderPath::getRootDir() const {
119*70a7ec85SAndroid Build Coastguard Worker return mRootDir;
120*70a7ec85SAndroid Build Coastguard Worker }
121*70a7ec85SAndroid Build Coastguard Worker
enforceTrailingSlash(const std::string & path)122*70a7ec85SAndroid Build Coastguard Worker static std::string enforceTrailingSlash(const std::string& path) {
123*70a7ec85SAndroid Build Coastguard Worker if (android::base::EndsWith(path, '/')) {
124*70a7ec85SAndroid Build Coastguard Worker return path;
125*70a7ec85SAndroid Build Coastguard Worker }
126*70a7ec85SAndroid Build Coastguard Worker return path + "/";
127*70a7ec85SAndroid Build Coastguard Worker }
128*70a7ec85SAndroid Build Coastguard Worker
PathReplacingFileSystem(std::unique_ptr<FileSystem> impl,const std::map<std::string,std::string> & path_replacements)129*70a7ec85SAndroid Build Coastguard Worker PathReplacingFileSystem::PathReplacingFileSystem(
130*70a7ec85SAndroid Build Coastguard Worker std::unique_ptr<FileSystem> impl, const std::map<std::string, std::string>& path_replacements)
131*70a7ec85SAndroid Build Coastguard Worker : impl_{std::move(impl)} {
132*70a7ec85SAndroid Build Coastguard Worker // Enforce a trailing slash on the path-to-be-replaced, prevents
133*70a7ec85SAndroid Build Coastguard Worker // the problem (for example) of /foo matching and changing /fooxyz
134*70a7ec85SAndroid Build Coastguard Worker for (const auto& [to_replace, replacement] : path_replacements) {
135*70a7ec85SAndroid Build Coastguard Worker path_replacements_.emplace(enforceTrailingSlash(to_replace),
136*70a7ec85SAndroid Build Coastguard Worker enforceTrailingSlash(replacement));
137*70a7ec85SAndroid Build Coastguard Worker }
138*70a7ec85SAndroid Build Coastguard Worker }
139*70a7ec85SAndroid Build Coastguard Worker
fetch(const std::string & path,std::string * fetched,std::string * error) const140*70a7ec85SAndroid Build Coastguard Worker status_t PathReplacingFileSystem::fetch(const std::string& path, std::string* fetched,
141*70a7ec85SAndroid Build Coastguard Worker std::string* error) const {
142*70a7ec85SAndroid Build Coastguard Worker return impl_->fetch(path_replace(path), fetched, error);
143*70a7ec85SAndroid Build Coastguard Worker }
144*70a7ec85SAndroid Build Coastguard Worker
listFiles(const std::string & path,std::vector<std::string> * out,std::string * error) const145*70a7ec85SAndroid Build Coastguard Worker status_t PathReplacingFileSystem::listFiles(const std::string& path, std::vector<std::string>* out,
146*70a7ec85SAndroid Build Coastguard Worker std::string* error) const {
147*70a7ec85SAndroid Build Coastguard Worker return impl_->listFiles(path_replace(path), out, error);
148*70a7ec85SAndroid Build Coastguard Worker }
149*70a7ec85SAndroid Build Coastguard Worker
modifiedTime(const std::string & path,timespec * mtime,std::string * error) const150*70a7ec85SAndroid Build Coastguard Worker status_t PathReplacingFileSystem::modifiedTime(const std::string& path, timespec* mtime,
151*70a7ec85SAndroid Build Coastguard Worker std::string* error) const {
152*70a7ec85SAndroid Build Coastguard Worker return impl_->modifiedTime(path_replace(path), mtime, error);
153*70a7ec85SAndroid Build Coastguard Worker }
154*70a7ec85SAndroid Build Coastguard Worker
path_replace(std::string_view path) const155*70a7ec85SAndroid Build Coastguard Worker std::string PathReplacingFileSystem::path_replace(std::string_view path) const {
156*70a7ec85SAndroid Build Coastguard Worker // reverse for "longer match wins".
157*70a7ec85SAndroid Build Coastguard Worker for (const auto& [to_replace, replacement] : path_replacements_ | std::views::reverse) {
158*70a7ec85SAndroid Build Coastguard Worker if (android::base::ConsumePrefix(&path, to_replace)) {
159*70a7ec85SAndroid Build Coastguard Worker return replacement + std::string{path};
160*70a7ec85SAndroid Build Coastguard Worker }
161*70a7ec85SAndroid Build Coastguard Worker }
162*70a7ec85SAndroid Build Coastguard Worker return std::string{path};
163*70a7ec85SAndroid Build Coastguard Worker }
164*70a7ec85SAndroid Build Coastguard Worker
165*70a7ec85SAndroid Build Coastguard Worker } // namespace details
166*70a7ec85SAndroid Build Coastguard Worker } // namespace vintf
167*70a7ec85SAndroid Build Coastguard Worker } // namespace android
168