xref: /aosp_15_r20/system/libvintf/FileSystem.cpp (revision 70a7ec852fcefd15a4fb57f8f183a8b1c3aacb08)
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