1
2 /*
3 * Copyright (C) 2018 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include <vintf/FileSystem.h>
19
20 #include <dirent.h>
21
22 #include <android-base/file.h>
23 #include <android-base/strings.h>
24
25 namespace android {
26 namespace vintf {
27 namespace details {
28
fetch(const std::string & path,std::string * fetched,std::string * error) const29 status_t FileSystemImpl::fetch(const std::string& path, std::string* fetched,
30 std::string* error) const {
31 if (!android::base::ReadFileToString(path, fetched, true /* follow_symlinks */)) {
32 int saved_errno = errno;
33 if (error) {
34 *error = "Cannot read " + path + ": " + strerror(saved_errno);
35 }
36 return saved_errno == 0 ? UNKNOWN_ERROR : -saved_errno;
37 }
38 return OK;
39 }
40
listFiles(const std::string & path,std::vector<std::string> * out,std::string * error) const41 status_t FileSystemImpl::listFiles(const std::string& path, std::vector<std::string>* out,
42 std::string* error) const {
43 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
44 if (!dir) {
45 int saved_errno = errno;
46 if (error) {
47 *error = "Cannot open " + path + ": " + strerror(saved_errno);
48 }
49 return saved_errno == 0 ? UNKNOWN_ERROR : -saved_errno;
50 }
51
52 dirent* dp;
53 while (errno = 0, dp = readdir(dir.get()), dp != nullptr) {
54 if (dp->d_type != DT_DIR) {
55 out->push_back(dp->d_name);
56 }
57 }
58 int saved_errno = errno;
59 if (saved_errno != 0) {
60 if (error) {
61 *error = "Failed while reading directory " + path + ": " + strerror(saved_errno);
62 }
63 }
64 return -saved_errno;
65 }
66
modifiedTime(const std::string & path,timespec * mtime,std::string * error) const67 status_t FileSystemImpl::modifiedTime(const std::string& path, timespec* mtime,
68 std::string* error) const {
69 struct stat stat_buf;
70 if (stat(path.c_str(), &stat_buf) != 0) {
71 int saved_errno = errno;
72 if (error) {
73 *error = "Cannot open " + path + ": " + strerror(saved_errno);
74 }
75 return saved_errno == 0 ? UNKNOWN_ERROR : -saved_errno;
76 }
77 *mtime = stat_buf.st_mtim;
78 return OK;
79 }
80
fetch(const std::string &,std::string *,std::string *) const81 status_t FileSystemNoOp::fetch(const std::string&, std::string*, std::string*) const {
82 return NAME_NOT_FOUND;
83 }
84
listFiles(const std::string &,std::vector<std::string> *,std::string *) const85 status_t FileSystemNoOp::listFiles(const std::string&, std::vector<std::string>*,
86 std::string*) const {
87 return NAME_NOT_FOUND;
88 }
89
modifiedTime(const std::string &,timespec *,std::string *) const90 status_t FileSystemNoOp::modifiedTime(const std::string&, timespec*, std::string*) const {
91 return NAME_NOT_FOUND;
92 }
93
FileSystemUnderPath(const std::string & rootdir)94 FileSystemUnderPath::FileSystemUnderPath(const std::string& rootdir) {
95 mRootDir = rootdir;
96 if (!mRootDir.empty() && mRootDir.back() != '/') {
97 mRootDir.push_back('/');
98 }
99 }
100
fetch(const std::string & path,std::string * fetched,std::string * error) const101 status_t FileSystemUnderPath::fetch(const std::string& path, std::string* fetched,
102 std::string* error) const {
103 return mImpl.fetch(mRootDir + path, fetched, error);
104 }
105
listFiles(const std::string & path,std::vector<std::string> * out,std::string * error) const106 status_t FileSystemUnderPath::listFiles(const std::string& path, std::vector<std::string>* out,
107 std::string* error) const {
108 return mImpl.listFiles(mRootDir + path, out, error);
109 }
110
modifiedTime(const std::string & path,timespec * mtime,std::string * error) const111 status_t FileSystemUnderPath::modifiedTime(const std::string& path, timespec* mtime,
112 std::string* error) const {
113 return mImpl.modifiedTime(mRootDir + path, mtime, error);
114 }
115
getRootDir() const116 const std::string& FileSystemUnderPath::getRootDir() const {
117 return mRootDir;
118 }
119
PathReplacingFileSystem(std::string path_to_replace,std::string path_replacement,std::unique_ptr<FileSystem> impl)120 PathReplacingFileSystem::PathReplacingFileSystem(std::string path_to_replace,
121 std::string path_replacement,
122 std::unique_ptr<FileSystem> impl)
123 : path_to_replace_{std::move(path_to_replace)},
124 path_replacement_{std::move(path_replacement)},
125 impl_{std::move(impl)} {
126 // Enforce a trailing slash on the path-to-be-replaced, prevents
127 // the problem (for example) of /foo matching and changing /fooxyz
128 if (!android::base::EndsWith(path_to_replace_, '/')) {
129 path_to_replace_ += "/";
130 }
131 // Enforce a trailing slash on the replacement path. This ensures
132 // we are replacing a directory with a directory.
133 if (!android::base::EndsWith(path_replacement_, '/')) {
134 path_replacement_ += "/";
135 }
136 }
137
fetch(const std::string & path,std::string * fetched,std::string * error) const138 status_t PathReplacingFileSystem::fetch(const std::string& path, std::string* fetched,
139 std::string* error) const {
140 return impl_->fetch(path_replace(path), fetched, error);
141 }
142
listFiles(const std::string & path,std::vector<std::string> * out,std::string * error) const143 status_t PathReplacingFileSystem::listFiles(const std::string& path, std::vector<std::string>* out,
144 std::string* error) const {
145 return impl_->listFiles(path_replace(path), out, error);
146 }
147
modifiedTime(const std::string & path,timespec * mtime,std::string * error) const148 status_t PathReplacingFileSystem::modifiedTime(const std::string& path, timespec* mtime,
149 std::string* error) const {
150 return impl_->modifiedTime(path_replace(path), mtime, error);
151 }
152
path_replace(std::string_view path) const153 std::string PathReplacingFileSystem::path_replace(std::string_view path) const {
154 std::string retstr;
155 if (android::base::ConsumePrefix(&path, path_to_replace_)) {
156 retstr.reserve(path_replacement_.size() + path.size());
157 retstr.append(path_replacement_);
158 retstr.append(path);
159 return retstr;
160 }
161 return std::string{path};
162 }
163
164 } // namespace details
165 } // namespace vintf
166 } // namespace android
167