xref: /aosp_15_r20/system/incremental_delivery/incfs/incfs.cpp (revision 9190c2a8bd3622b7aa9bd7bfe4b3aec77820f478)
1*9190c2a8SAndroid Build Coastguard Worker /*
2*9190c2a8SAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*9190c2a8SAndroid Build Coastguard Worker  *
4*9190c2a8SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*9190c2a8SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*9190c2a8SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*9190c2a8SAndroid Build Coastguard Worker  *
8*9190c2a8SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*9190c2a8SAndroid Build Coastguard Worker  *
10*9190c2a8SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*9190c2a8SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*9190c2a8SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*9190c2a8SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*9190c2a8SAndroid Build Coastguard Worker  * limitations under the License.
15*9190c2a8SAndroid Build Coastguard Worker  */
16*9190c2a8SAndroid Build Coastguard Worker 
17*9190c2a8SAndroid Build Coastguard Worker #define LOG_TAG "incfs"
18*9190c2a8SAndroid Build Coastguard Worker 
19*9190c2a8SAndroid Build Coastguard Worker #include "incfs.h"
20*9190c2a8SAndroid Build Coastguard Worker 
21*9190c2a8SAndroid Build Coastguard Worker #include <IncrementalProperties.sysprop.h>
22*9190c2a8SAndroid Build Coastguard Worker #include <android-base/file.h>
23*9190c2a8SAndroid Build Coastguard Worker #include <android-base/logging.h>
24*9190c2a8SAndroid Build Coastguard Worker #include <android-base/no_destructor.h>
25*9190c2a8SAndroid Build Coastguard Worker #include <android-base/parsebool.h>
26*9190c2a8SAndroid Build Coastguard Worker #include <android-base/properties.h>
27*9190c2a8SAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
28*9190c2a8SAndroid Build Coastguard Worker #include <android-base/strings.h>
29*9190c2a8SAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
30*9190c2a8SAndroid Build Coastguard Worker #include <dirent.h>
31*9190c2a8SAndroid Build Coastguard Worker #include <errno.h>
32*9190c2a8SAndroid Build Coastguard Worker #include <fcntl.h>
33*9190c2a8SAndroid Build Coastguard Worker #include <libgen.h>
34*9190c2a8SAndroid Build Coastguard Worker #include <openssl/sha.h>
35*9190c2a8SAndroid Build Coastguard Worker #include <selinux/android.h>
36*9190c2a8SAndroid Build Coastguard Worker #include <selinux/selinux.h>
37*9190c2a8SAndroid Build Coastguard Worker #include <sys/inotify.h>
38*9190c2a8SAndroid Build Coastguard Worker #include <sys/mount.h>
39*9190c2a8SAndroid Build Coastguard Worker #include <sys/poll.h>
40*9190c2a8SAndroid Build Coastguard Worker #include <sys/stat.h>
41*9190c2a8SAndroid Build Coastguard Worker #include <sys/syscall.h>
42*9190c2a8SAndroid Build Coastguard Worker #include <sys/types.h>
43*9190c2a8SAndroid Build Coastguard Worker #include <sys/vfs.h>
44*9190c2a8SAndroid Build Coastguard Worker #include <sys/xattr.h>
45*9190c2a8SAndroid Build Coastguard Worker #include <unistd.h>
46*9190c2a8SAndroid Build Coastguard Worker 
47*9190c2a8SAndroid Build Coastguard Worker #include <charconv>
48*9190c2a8SAndroid Build Coastguard Worker #include <chrono>
49*9190c2a8SAndroid Build Coastguard Worker #include <iterator>
50*9190c2a8SAndroid Build Coastguard Worker #include <mutex>
51*9190c2a8SAndroid Build Coastguard Worker #include <optional>
52*9190c2a8SAndroid Build Coastguard Worker #include <string_view>
53*9190c2a8SAndroid Build Coastguard Worker 
54*9190c2a8SAndroid Build Coastguard Worker #include "MountRegistry.h"
55*9190c2a8SAndroid Build Coastguard Worker #include "path.h"
56*9190c2a8SAndroid Build Coastguard Worker 
57*9190c2a8SAndroid Build Coastguard Worker using namespace std::literals;
58*9190c2a8SAndroid Build Coastguard Worker using namespace android::incfs;
59*9190c2a8SAndroid Build Coastguard Worker using namespace android::sysprop;
60*9190c2a8SAndroid Build Coastguard Worker namespace ab = android::base;
61*9190c2a8SAndroid Build Coastguard Worker 
62*9190c2a8SAndroid Build Coastguard Worker namespace android::incfs {
63*9190c2a8SAndroid Build Coastguard Worker extern const size_t kPageSize = getpagesize();
64*9190c2a8SAndroid Build Coastguard Worker }
65*9190c2a8SAndroid Build Coastguard Worker 
66*9190c2a8SAndroid Build Coastguard Worker struct IncFsControl final {
67*9190c2a8SAndroid Build Coastguard Worker     IncFsFd cmd;
68*9190c2a8SAndroid Build Coastguard Worker     IncFsFd pendingReads;
69*9190c2a8SAndroid Build Coastguard Worker     IncFsFd logs;
70*9190c2a8SAndroid Build Coastguard Worker     IncFsFd blocksWritten;
IncFsControlIncFsControl71*9190c2a8SAndroid Build Coastguard Worker     constexpr IncFsControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs, IncFsFd blocksWritten)
72*9190c2a8SAndroid Build Coastguard Worker           : cmd(cmd), pendingReads(pendingReads), logs(logs), blocksWritten(blocksWritten) {}
73*9190c2a8SAndroid Build Coastguard Worker };
74*9190c2a8SAndroid Build Coastguard Worker 
registry()75*9190c2a8SAndroid Build Coastguard Worker static MountRegistry& registry() {
76*9190c2a8SAndroid Build Coastguard Worker     static ab::NoDestructor<MountRegistry> instance{};
77*9190c2a8SAndroid Build Coastguard Worker     return *instance;
78*9190c2a8SAndroid Build Coastguard Worker }
79*9190c2a8SAndroid Build Coastguard Worker 
openRaw(std::string_view file)80*9190c2a8SAndroid Build Coastguard Worker static ab::unique_fd openRaw(std::string_view file) {
81*9190c2a8SAndroid Build Coastguard Worker     auto fd = ab::unique_fd(::open(details::c_str(file), O_RDONLY | O_CLOEXEC));
82*9190c2a8SAndroid Build Coastguard Worker     if (fd < 0) {
83*9190c2a8SAndroid Build Coastguard Worker         return ab::unique_fd{-errno};
84*9190c2a8SAndroid Build Coastguard Worker     }
85*9190c2a8SAndroid Build Coastguard Worker     return fd;
86*9190c2a8SAndroid Build Coastguard Worker }
87*9190c2a8SAndroid Build Coastguard Worker 
openAt(int fd,std::string_view name,int flags=0)88*9190c2a8SAndroid Build Coastguard Worker static ab::unique_fd openAt(int fd, std::string_view name, int flags = 0) {
89*9190c2a8SAndroid Build Coastguard Worker     auto res = ab::unique_fd(
90*9190c2a8SAndroid Build Coastguard Worker             ::openat(fd, details::c_str(name), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | flags));
91*9190c2a8SAndroid Build Coastguard Worker     if (res < 0) {
92*9190c2a8SAndroid Build Coastguard Worker         return ab::unique_fd{-errno};
93*9190c2a8SAndroid Build Coastguard Worker     }
94*9190c2a8SAndroid Build Coastguard Worker     return res;
95*9190c2a8SAndroid Build Coastguard Worker }
96*9190c2a8SAndroid Build Coastguard Worker 
indexPath(std::string_view root,IncFsFileId fileId)97*9190c2a8SAndroid Build Coastguard Worker static std::string indexPath(std::string_view root, IncFsFileId fileId) {
98*9190c2a8SAndroid Build Coastguard Worker     return path::join(root, INCFS_INDEX_NAME, toString(fileId));
99*9190c2a8SAndroid Build Coastguard Worker }
100*9190c2a8SAndroid Build Coastguard Worker 
rootForCmd(int fd)101*9190c2a8SAndroid Build Coastguard Worker static std::string rootForCmd(int fd) {
102*9190c2a8SAndroid Build Coastguard Worker     auto cmdFile = path::fromFd(fd);
103*9190c2a8SAndroid Build Coastguard Worker     if (cmdFile.empty()) {
104*9190c2a8SAndroid Build Coastguard Worker         LOG(INFO) << __func__ << "(): name empty for " << fd;
105*9190c2a8SAndroid Build Coastguard Worker         return {};
106*9190c2a8SAndroid Build Coastguard Worker     }
107*9190c2a8SAndroid Build Coastguard Worker     auto res = path::dirName(cmdFile);
108*9190c2a8SAndroid Build Coastguard Worker     if (res.empty()) {
109*9190c2a8SAndroid Build Coastguard Worker         LOG(INFO) << __func__ << "(): dirname empty for " << cmdFile;
110*9190c2a8SAndroid Build Coastguard Worker         return {};
111*9190c2a8SAndroid Build Coastguard Worker     }
112*9190c2a8SAndroid Build Coastguard Worker     if (!path::endsWith(cmdFile, INCFS_PENDING_READS_FILENAME)) {
113*9190c2a8SAndroid Build Coastguard Worker         LOG(INFO) << __func__ << "(): invalid file name " << cmdFile;
114*9190c2a8SAndroid Build Coastguard Worker         return {};
115*9190c2a8SAndroid Build Coastguard Worker     }
116*9190c2a8SAndroid Build Coastguard Worker     if (cmdFile.data() == res.data() || cmdFile.starts_with(res)) {
117*9190c2a8SAndroid Build Coastguard Worker         cmdFile.resize(res.size());
118*9190c2a8SAndroid Build Coastguard Worker         return cmdFile;
119*9190c2a8SAndroid Build Coastguard Worker     }
120*9190c2a8SAndroid Build Coastguard Worker     return std::string(res);
121*9190c2a8SAndroid Build Coastguard Worker }
122*9190c2a8SAndroid Build Coastguard Worker 
isFsAvailable()123*9190c2a8SAndroid Build Coastguard Worker static bool isFsAvailable() {
124*9190c2a8SAndroid Build Coastguard Worker     static const char kProcFilesystems[] = "/proc/filesystems";
125*9190c2a8SAndroid Build Coastguard Worker     std::string filesystems;
126*9190c2a8SAndroid Build Coastguard Worker     if (!ab::ReadFileToString(kProcFilesystems, &filesystems)) {
127*9190c2a8SAndroid Build Coastguard Worker         return false;
128*9190c2a8SAndroid Build Coastguard Worker     }
129*9190c2a8SAndroid Build Coastguard Worker     const auto result = filesystems.find("\t" INCFS_NAME "\n") != std::string::npos;
130*9190c2a8SAndroid Build Coastguard Worker     LOG(INFO) << "isFsAvailable: " << (result ? "true" : "false");
131*9190c2a8SAndroid Build Coastguard Worker     return result;
132*9190c2a8SAndroid Build Coastguard Worker }
133*9190c2a8SAndroid Build Coastguard Worker 
getFirstApiLevel()134*9190c2a8SAndroid Build Coastguard Worker static int getFirstApiLevel() {
135*9190c2a8SAndroid Build Coastguard Worker     uint64_t api_level = android::base::GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
136*9190c2a8SAndroid Build Coastguard Worker     LOG(INFO) << "Initial API level of the device: " << api_level;
137*9190c2a8SAndroid Build Coastguard Worker     return api_level;
138*9190c2a8SAndroid Build Coastguard Worker }
139*9190c2a8SAndroid Build Coastguard Worker 
incFsPropertyValue()140*9190c2a8SAndroid Build Coastguard Worker static std::string_view incFsPropertyValue() {
141*9190c2a8SAndroid Build Coastguard Worker     constexpr const int R_API = 30;
142*9190c2a8SAndroid Build Coastguard Worker     static const auto kDefaultValue{getFirstApiLevel() > R_API ? "on" : ""};
143*9190c2a8SAndroid Build Coastguard Worker     static const ab::NoDestructor<std::string> kValue{
144*9190c2a8SAndroid Build Coastguard Worker             IncrementalProperties::enable().value_or(kDefaultValue)};
145*9190c2a8SAndroid Build Coastguard Worker     LOG(INFO) << "ro.incremental.enable: " << *kValue;
146*9190c2a8SAndroid Build Coastguard Worker     return *kValue;
147*9190c2a8SAndroid Build Coastguard Worker }
148*9190c2a8SAndroid Build Coastguard Worker 
parseProperty(std::string_view property)149*9190c2a8SAndroid Build Coastguard Worker static std::pair<bool, std::string_view> parseProperty(std::string_view property) {
150*9190c2a8SAndroid Build Coastguard Worker     auto boolVal = ab::ParseBool(property);
151*9190c2a8SAndroid Build Coastguard Worker     if (boolVal == ab::ParseBoolResult::kTrue) {
152*9190c2a8SAndroid Build Coastguard Worker         return {isFsAvailable(), {}};
153*9190c2a8SAndroid Build Coastguard Worker     }
154*9190c2a8SAndroid Build Coastguard Worker     if (boolVal == ab::ParseBoolResult::kFalse) {
155*9190c2a8SAndroid Build Coastguard Worker         return {false, {}};
156*9190c2a8SAndroid Build Coastguard Worker     }
157*9190c2a8SAndroid Build Coastguard Worker 
158*9190c2a8SAndroid Build Coastguard Worker     // Don't load the module at once, but instead only check if it is loadable.
159*9190c2a8SAndroid Build Coastguard Worker     static const auto kModulePrefix = "module:"sv;
160*9190c2a8SAndroid Build Coastguard Worker     if (property.starts_with(kModulePrefix)) {
161*9190c2a8SAndroid Build Coastguard Worker         const auto modulePath = property.substr(kModulePrefix.size());
162*9190c2a8SAndroid Build Coastguard Worker         return {::access(details::c_str(modulePath), R_OK | X_OK), modulePath};
163*9190c2a8SAndroid Build Coastguard Worker     }
164*9190c2a8SAndroid Build Coastguard Worker     return {false, {}};
165*9190c2a8SAndroid Build Coastguard Worker }
166*9190c2a8SAndroid Build Coastguard Worker 
167*9190c2a8SAndroid Build Coastguard Worker template <class Callback>
forEachFileIn(std::string_view dirPath,Callback cb)168*9190c2a8SAndroid Build Coastguard Worker static IncFsErrorCode forEachFileIn(std::string_view dirPath, Callback cb) {
169*9190c2a8SAndroid Build Coastguard Worker     auto dir = path::openDir(details::c_str(dirPath));
170*9190c2a8SAndroid Build Coastguard Worker     if (!dir) {
171*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
172*9190c2a8SAndroid Build Coastguard Worker     }
173*9190c2a8SAndroid Build Coastguard Worker 
174*9190c2a8SAndroid Build Coastguard Worker     int res = 0;
175*9190c2a8SAndroid Build Coastguard Worker     while (auto entry = (errno = 0, ::readdir(dir.get()))) {
176*9190c2a8SAndroid Build Coastguard Worker         if (entry->d_type != DT_REG) {
177*9190c2a8SAndroid Build Coastguard Worker             continue;
178*9190c2a8SAndroid Build Coastguard Worker         }
179*9190c2a8SAndroid Build Coastguard Worker         ++res;
180*9190c2a8SAndroid Build Coastguard Worker         if (!cb(entry->d_name)) {
181*9190c2a8SAndroid Build Coastguard Worker             break;
182*9190c2a8SAndroid Build Coastguard Worker         }
183*9190c2a8SAndroid Build Coastguard Worker     }
184*9190c2a8SAndroid Build Coastguard Worker     if (errno) {
185*9190c2a8SAndroid Build Coastguard Worker         return -errno;
186*9190c2a8SAndroid Build Coastguard Worker     }
187*9190c2a8SAndroid Build Coastguard Worker     return res;
188*9190c2a8SAndroid Build Coastguard Worker }
189*9190c2a8SAndroid Build Coastguard Worker 
190*9190c2a8SAndroid Build Coastguard Worker namespace {
191*9190c2a8SAndroid Build Coastguard Worker 
192*9190c2a8SAndroid Build Coastguard Worker class IncFsInit {
193*9190c2a8SAndroid Build Coastguard Worker public:
IncFsInit()194*9190c2a8SAndroid Build Coastguard Worker     IncFsInit() {
195*9190c2a8SAndroid Build Coastguard Worker         auto [featureEnabled, moduleName] = parseProperty(incFsPropertyValue());
196*9190c2a8SAndroid Build Coastguard Worker         featureEnabled_ = featureEnabled;
197*9190c2a8SAndroid Build Coastguard Worker         moduleName_ = moduleName;
198*9190c2a8SAndroid Build Coastguard Worker         loaded_ = featureEnabled_ && isFsAvailable();
199*9190c2a8SAndroid Build Coastguard Worker     }
200*9190c2a8SAndroid Build Coastguard Worker 
201*9190c2a8SAndroid Build Coastguard Worker     constexpr ~IncFsInit() = default;
202*9190c2a8SAndroid Build Coastguard Worker 
enabled() const203*9190c2a8SAndroid Build Coastguard Worker     bool enabled() const { return featureEnabled_; }
enabledAndReady() const204*9190c2a8SAndroid Build Coastguard Worker     bool enabledAndReady() const {
205*9190c2a8SAndroid Build Coastguard Worker         if (!featureEnabled_) {
206*9190c2a8SAndroid Build Coastguard Worker             return false;
207*9190c2a8SAndroid Build Coastguard Worker         }
208*9190c2a8SAndroid Build Coastguard Worker         if (moduleName_.empty()) {
209*9190c2a8SAndroid Build Coastguard Worker             return true;
210*9190c2a8SAndroid Build Coastguard Worker         }
211*9190c2a8SAndroid Build Coastguard Worker         if (loaded_) {
212*9190c2a8SAndroid Build Coastguard Worker             return true;
213*9190c2a8SAndroid Build Coastguard Worker         }
214*9190c2a8SAndroid Build Coastguard Worker         std::call_once(loadedFlag_, [this] {
215*9190c2a8SAndroid Build Coastguard Worker             if (isFsAvailable()) {
216*9190c2a8SAndroid Build Coastguard Worker                 // Loaded from a different process, I suppose.
217*9190c2a8SAndroid Build Coastguard Worker                 loaded_ = true;
218*9190c2a8SAndroid Build Coastguard Worker                 LOG(INFO) << "IncFS is already available, skipped loading";
219*9190c2a8SAndroid Build Coastguard Worker                 return;
220*9190c2a8SAndroid Build Coastguard Worker             }
221*9190c2a8SAndroid Build Coastguard Worker             const ab::unique_fd fd(TEMP_FAILURE_RETRY(
222*9190c2a8SAndroid Build Coastguard Worker                     ::open(details::c_str(moduleName_), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
223*9190c2a8SAndroid Build Coastguard Worker             if (fd < 0) {
224*9190c2a8SAndroid Build Coastguard Worker                 PLOG(ERROR) << "could not open IncFs kernel module \"" << moduleName_ << '"';
225*9190c2a8SAndroid Build Coastguard Worker                 return;
226*9190c2a8SAndroid Build Coastguard Worker             }
227*9190c2a8SAndroid Build Coastguard Worker 
228*9190c2a8SAndroid Build Coastguard Worker             const auto rc = syscall(__NR_finit_module, fd.get(), "", 0);
229*9190c2a8SAndroid Build Coastguard Worker             if (rc < 0) {
230*9190c2a8SAndroid Build Coastguard Worker                 PLOG(ERROR) << "finit_module for IncFs \"" << moduleName_ << "\" failed";
231*9190c2a8SAndroid Build Coastguard Worker                 return;
232*9190c2a8SAndroid Build Coastguard Worker             }
233*9190c2a8SAndroid Build Coastguard Worker             if (!isFsAvailable()) {
234*9190c2a8SAndroid Build Coastguard Worker                 LOG(ERROR) << "loaded IncFs kernel module \"" << moduleName_
235*9190c2a8SAndroid Build Coastguard Worker                            << "\" but incremental-fs is still not available";
236*9190c2a8SAndroid Build Coastguard Worker             }
237*9190c2a8SAndroid Build Coastguard Worker             loaded_ = true;
238*9190c2a8SAndroid Build Coastguard Worker             LOG(INFO) << "successfully loaded IncFs kernel module \"" << moduleName_ << '"';
239*9190c2a8SAndroid Build Coastguard Worker         });
240*9190c2a8SAndroid Build Coastguard Worker         return loaded_;
241*9190c2a8SAndroid Build Coastguard Worker     }
242*9190c2a8SAndroid Build Coastguard Worker 
243*9190c2a8SAndroid Build Coastguard Worker private:
244*9190c2a8SAndroid Build Coastguard Worker     bool featureEnabled_;
245*9190c2a8SAndroid Build Coastguard Worker     std::string_view moduleName_;
246*9190c2a8SAndroid Build Coastguard Worker     mutable std::once_flag loadedFlag_;
247*9190c2a8SAndroid Build Coastguard Worker     mutable bool loaded_;
248*9190c2a8SAndroid Build Coastguard Worker };
249*9190c2a8SAndroid Build Coastguard Worker 
250*9190c2a8SAndroid Build Coastguard Worker } // namespace
251*9190c2a8SAndroid Build Coastguard Worker 
init()252*9190c2a8SAndroid Build Coastguard Worker static IncFsInit& init() {
253*9190c2a8SAndroid Build Coastguard Worker     static IncFsInit initer;
254*9190c2a8SAndroid Build Coastguard Worker     return initer;
255*9190c2a8SAndroid Build Coastguard Worker }
256*9190c2a8SAndroid Build Coastguard Worker 
IncFs_IsEnabled()257*9190c2a8SAndroid Build Coastguard Worker bool IncFs_IsEnabled() {
258*9190c2a8SAndroid Build Coastguard Worker     return init().enabled();
259*9190c2a8SAndroid Build Coastguard Worker }
260*9190c2a8SAndroid Build Coastguard Worker 
readIncFsFeatures()261*9190c2a8SAndroid Build Coastguard Worker static Features readIncFsFeatures() {
262*9190c2a8SAndroid Build Coastguard Worker     init().enabledAndReady();
263*9190c2a8SAndroid Build Coastguard Worker 
264*9190c2a8SAndroid Build Coastguard Worker     int res = Features::none | Features::mappingFilesProgressFixed;
265*9190c2a8SAndroid Build Coastguard Worker 
266*9190c2a8SAndroid Build Coastguard Worker     static const char kSysfsFeaturesDir[] = "/sys/fs/" INCFS_NAME "/features";
267*9190c2a8SAndroid Build Coastguard Worker     const auto dir = path::openDir(kSysfsFeaturesDir);
268*9190c2a8SAndroid Build Coastguard Worker     if (!dir) {
269*9190c2a8SAndroid Build Coastguard Worker         PLOG(ERROR) << "IncFs_Features: failed to open features dir, assuming v1/none.";
270*9190c2a8SAndroid Build Coastguard Worker         return Features(res);
271*9190c2a8SAndroid Build Coastguard Worker     }
272*9190c2a8SAndroid Build Coastguard Worker 
273*9190c2a8SAndroid Build Coastguard Worker     while (auto entry = ::readdir(dir.get())) {
274*9190c2a8SAndroid Build Coastguard Worker         if (entry->d_type != DT_REG) {
275*9190c2a8SAndroid Build Coastguard Worker             continue;
276*9190c2a8SAndroid Build Coastguard Worker         }
277*9190c2a8SAndroid Build Coastguard Worker         if (entry->d_name == "corefs"sv) {
278*9190c2a8SAndroid Build Coastguard Worker             res |= Features::core;
279*9190c2a8SAndroid Build Coastguard Worker         } else if (entry->d_name == "v2"sv || entry->d_name == "report_uid"sv) {
280*9190c2a8SAndroid Build Coastguard Worker             res |= Features::v2;
281*9190c2a8SAndroid Build Coastguard Worker         }
282*9190c2a8SAndroid Build Coastguard Worker     }
283*9190c2a8SAndroid Build Coastguard Worker 
284*9190c2a8SAndroid Build Coastguard Worker     LOG(INFO) << "IncFs_Features: " << ((res & Features::v2) ? "v2" : "v1");
285*9190c2a8SAndroid Build Coastguard Worker 
286*9190c2a8SAndroid Build Coastguard Worker     return Features(res);
287*9190c2a8SAndroid Build Coastguard Worker }
288*9190c2a8SAndroid Build Coastguard Worker 
IncFs_Features()289*9190c2a8SAndroid Build Coastguard Worker IncFsFeatures IncFs_Features() {
290*9190c2a8SAndroid Build Coastguard Worker     static const auto features = IncFsFeatures(readIncFsFeatures());
291*9190c2a8SAndroid Build Coastguard Worker     return features;
292*9190c2a8SAndroid Build Coastguard Worker }
293*9190c2a8SAndroid Build Coastguard Worker 
isIncFsFdImpl(int fd)294*9190c2a8SAndroid Build Coastguard Worker bool isIncFsFdImpl(int fd) {
295*9190c2a8SAndroid Build Coastguard Worker     struct statfs fs = {};
296*9190c2a8SAndroid Build Coastguard Worker     if (::fstatfs(fd, &fs) != 0) {
297*9190c2a8SAndroid Build Coastguard Worker         PLOG(WARNING) << __func__ << "(): could not fstatfs fd " << fd;
298*9190c2a8SAndroid Build Coastguard Worker         return false;
299*9190c2a8SAndroid Build Coastguard Worker     }
300*9190c2a8SAndroid Build Coastguard Worker 
301*9190c2a8SAndroid Build Coastguard Worker     return fs.f_type == (decltype(fs.f_type))INCFS_MAGIC_NUMBER;
302*9190c2a8SAndroid Build Coastguard Worker }
303*9190c2a8SAndroid Build Coastguard Worker 
isIncFsPathImpl(const char * path)304*9190c2a8SAndroid Build Coastguard Worker bool isIncFsPathImpl(const char* path) {
305*9190c2a8SAndroid Build Coastguard Worker     struct statfs fs = {};
306*9190c2a8SAndroid Build Coastguard Worker     if (::statfs(path, &fs) != 0) {
307*9190c2a8SAndroid Build Coastguard Worker         PLOG(WARNING) << __func__ << "(): could not statfs " << path;
308*9190c2a8SAndroid Build Coastguard Worker         return false;
309*9190c2a8SAndroid Build Coastguard Worker     }
310*9190c2a8SAndroid Build Coastguard Worker 
311*9190c2a8SAndroid Build Coastguard Worker     return fs.f_type == (decltype(fs.f_type))INCFS_MAGIC_NUMBER;
312*9190c2a8SAndroid Build Coastguard Worker }
313*9190c2a8SAndroid Build Coastguard Worker 
isDir(const char * path)314*9190c2a8SAndroid Build Coastguard Worker static int isDir(const char* path) {
315*9190c2a8SAndroid Build Coastguard Worker     struct stat st;
316*9190c2a8SAndroid Build Coastguard Worker     if (::stat(path, &st) != 0) {
317*9190c2a8SAndroid Build Coastguard Worker         return -errno;
318*9190c2a8SAndroid Build Coastguard Worker     }
319*9190c2a8SAndroid Build Coastguard Worker     if (!S_ISDIR(st.st_mode)) {
320*9190c2a8SAndroid Build Coastguard Worker         return -ENOTDIR;
321*9190c2a8SAndroid Build Coastguard Worker     }
322*9190c2a8SAndroid Build Coastguard Worker     return 0;
323*9190c2a8SAndroid Build Coastguard Worker }
324*9190c2a8SAndroid Build Coastguard Worker 
isAbsolute(const char * path)325*9190c2a8SAndroid Build Coastguard Worker static bool isAbsolute(const char* path) {
326*9190c2a8SAndroid Build Coastguard Worker     return path && path[0] == '/';
327*9190c2a8SAndroid Build Coastguard Worker }
328*9190c2a8SAndroid Build Coastguard Worker 
isValidMountTarget(const char * path)329*9190c2a8SAndroid Build Coastguard Worker static int isValidMountTarget(const char* path) {
330*9190c2a8SAndroid Build Coastguard Worker     if (!isAbsolute(path)) {
331*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
332*9190c2a8SAndroid Build Coastguard Worker     }
333*9190c2a8SAndroid Build Coastguard Worker     if (isIncFsPath(path)) {
334*9190c2a8SAndroid Build Coastguard Worker         LOG(ERROR) << "[incfs] mounting over existing incfs mount is not allowed";
335*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
336*9190c2a8SAndroid Build Coastguard Worker     }
337*9190c2a8SAndroid Build Coastguard Worker     if (const auto err = isDir(path); err != 0) {
338*9190c2a8SAndroid Build Coastguard Worker         return err;
339*9190c2a8SAndroid Build Coastguard Worker     }
340*9190c2a8SAndroid Build Coastguard Worker     if (const auto err = path::isEmptyDir(path); err != 0) {
341*9190c2a8SAndroid Build Coastguard Worker         return err;
342*9190c2a8SAndroid Build Coastguard Worker     }
343*9190c2a8SAndroid Build Coastguard Worker     return 0;
344*9190c2a8SAndroid Build Coastguard Worker }
345*9190c2a8SAndroid Build Coastguard Worker 
rmDirContent(int dirFd)346*9190c2a8SAndroid Build Coastguard Worker static int rmDirContent(int dirFd) {
347*9190c2a8SAndroid Build Coastguard Worker     auto dir = path::openDir(dirFd);
348*9190c2a8SAndroid Build Coastguard Worker     if (!dir) {
349*9190c2a8SAndroid Build Coastguard Worker         return -errno;
350*9190c2a8SAndroid Build Coastguard Worker     }
351*9190c2a8SAndroid Build Coastguard Worker     while (auto entry = ::readdir(dir.get())) {
352*9190c2a8SAndroid Build Coastguard Worker         if (entry->d_name == "."sv || entry->d_name == ".."sv) {
353*9190c2a8SAndroid Build Coastguard Worker             continue;
354*9190c2a8SAndroid Build Coastguard Worker         }
355*9190c2a8SAndroid Build Coastguard Worker         if (entry->d_type == DT_DIR) {
356*9190c2a8SAndroid Build Coastguard Worker             auto fd = openAt(dirFd, entry->d_name, O_DIRECTORY);
357*9190c2a8SAndroid Build Coastguard Worker             if (!fd.ok()) {
358*9190c2a8SAndroid Build Coastguard Worker                 return -errno;
359*9190c2a8SAndroid Build Coastguard Worker             }
360*9190c2a8SAndroid Build Coastguard Worker             if (const auto err = rmDirContent(fd.get())) {
361*9190c2a8SAndroid Build Coastguard Worker                 return err;
362*9190c2a8SAndroid Build Coastguard Worker             }
363*9190c2a8SAndroid Build Coastguard Worker             if (::unlinkat(fd.get(), entry->d_name, AT_REMOVEDIR)) {
364*9190c2a8SAndroid Build Coastguard Worker                 return -errno;
365*9190c2a8SAndroid Build Coastguard Worker             }
366*9190c2a8SAndroid Build Coastguard Worker         } else {
367*9190c2a8SAndroid Build Coastguard Worker             auto fd = openAt(dirFd, entry->d_name);
368*9190c2a8SAndroid Build Coastguard Worker             if (!fd.ok()) {
369*9190c2a8SAndroid Build Coastguard Worker                 return -errno;
370*9190c2a8SAndroid Build Coastguard Worker             }
371*9190c2a8SAndroid Build Coastguard Worker             if (::unlinkat(fd.get(), entry->d_name, 0)) {
372*9190c2a8SAndroid Build Coastguard Worker                 return -errno;
373*9190c2a8SAndroid Build Coastguard Worker             }
374*9190c2a8SAndroid Build Coastguard Worker         }
375*9190c2a8SAndroid Build Coastguard Worker     }
376*9190c2a8SAndroid Build Coastguard Worker     return 0;
377*9190c2a8SAndroid Build Coastguard Worker }
378*9190c2a8SAndroid Build Coastguard Worker 
rmDirContent(const char * path)379*9190c2a8SAndroid Build Coastguard Worker static int rmDirContent(const char* path) {
380*9190c2a8SAndroid Build Coastguard Worker     auto fd = openAt(-1, path, O_DIRECTORY);
381*9190c2a8SAndroid Build Coastguard Worker     if (!fd.ok()) {
382*9190c2a8SAndroid Build Coastguard Worker         return -errno;
383*9190c2a8SAndroid Build Coastguard Worker     }
384*9190c2a8SAndroid Build Coastguard Worker     return rmDirContent(fd.get());
385*9190c2a8SAndroid Build Coastguard Worker }
386*9190c2a8SAndroid Build Coastguard Worker 
makeMountOptionsString(IncFsMountOptions options)387*9190c2a8SAndroid Build Coastguard Worker static std::string makeMountOptionsString(IncFsMountOptions options) {
388*9190c2a8SAndroid Build Coastguard Worker     auto opts = ab::StringPrintf("read_timeout_ms=%u,readahead=0,rlog_pages=%u,rlog_wakeup_cnt=1,",
389*9190c2a8SAndroid Build Coastguard Worker                                  unsigned(options.defaultReadTimeoutMs),
390*9190c2a8SAndroid Build Coastguard Worker                                  unsigned(options.readLogBufferPages < 0
391*9190c2a8SAndroid Build Coastguard Worker                                                   ? INCFS_DEFAULT_PAGE_READ_BUFFER_PAGES
392*9190c2a8SAndroid Build Coastguard Worker                                                   : options.readLogBufferPages));
393*9190c2a8SAndroid Build Coastguard Worker     if (features() & Features::v2) {
394*9190c2a8SAndroid Build Coastguard Worker         ab::StringAppendF(&opts, "report_uid,");
395*9190c2a8SAndroid Build Coastguard Worker         if (options.sysfsName && *options.sysfsName) {
396*9190c2a8SAndroid Build Coastguard Worker             ab::StringAppendF(&opts, "sysfs_name=%s,", options.sysfsName);
397*9190c2a8SAndroid Build Coastguard Worker         }
398*9190c2a8SAndroid Build Coastguard Worker     }
399*9190c2a8SAndroid Build Coastguard Worker     return opts;
400*9190c2a8SAndroid Build Coastguard Worker }
401*9190c2a8SAndroid Build Coastguard Worker 
makeControl(int fd)402*9190c2a8SAndroid Build Coastguard Worker static IncFsControl* makeControl(int fd) {
403*9190c2a8SAndroid Build Coastguard Worker     auto cmd = openAt(fd, INCFS_PENDING_READS_FILENAME);
404*9190c2a8SAndroid Build Coastguard Worker     if (!cmd.ok()) {
405*9190c2a8SAndroid Build Coastguard Worker         return nullptr;
406*9190c2a8SAndroid Build Coastguard Worker     }
407*9190c2a8SAndroid Build Coastguard Worker     ab::unique_fd pendingReads(fcntl(cmd.get(), F_DUPFD_CLOEXEC, cmd.get()));
408*9190c2a8SAndroid Build Coastguard Worker     if (!pendingReads.ok()) {
409*9190c2a8SAndroid Build Coastguard Worker         return nullptr;
410*9190c2a8SAndroid Build Coastguard Worker     }
411*9190c2a8SAndroid Build Coastguard Worker     auto logs = openAt(fd, INCFS_LOG_FILENAME);
412*9190c2a8SAndroid Build Coastguard Worker     if (!logs.ok()) {
413*9190c2a8SAndroid Build Coastguard Worker         return nullptr;
414*9190c2a8SAndroid Build Coastguard Worker     }
415*9190c2a8SAndroid Build Coastguard Worker     ab::unique_fd blocksWritten;
416*9190c2a8SAndroid Build Coastguard Worker     if (features() & Features::v2) {
417*9190c2a8SAndroid Build Coastguard Worker         blocksWritten = openAt(fd, INCFS_BLOCKS_WRITTEN_FILENAME);
418*9190c2a8SAndroid Build Coastguard Worker         if (!blocksWritten.ok()) {
419*9190c2a8SAndroid Build Coastguard Worker             return nullptr;
420*9190c2a8SAndroid Build Coastguard Worker         }
421*9190c2a8SAndroid Build Coastguard Worker     }
422*9190c2a8SAndroid Build Coastguard Worker     auto control =
423*9190c2a8SAndroid Build Coastguard Worker             IncFs_CreateControl(cmd.get(), pendingReads.get(), logs.get(), blocksWritten.get());
424*9190c2a8SAndroid Build Coastguard Worker     if (control) {
425*9190c2a8SAndroid Build Coastguard Worker         (void)cmd.release();
426*9190c2a8SAndroid Build Coastguard Worker         (void)pendingReads.release();
427*9190c2a8SAndroid Build Coastguard Worker         (void)logs.release();
428*9190c2a8SAndroid Build Coastguard Worker         (void)blocksWritten.release();
429*9190c2a8SAndroid Build Coastguard Worker     } else {
430*9190c2a8SAndroid Build Coastguard Worker         errno = ENOMEM;
431*9190c2a8SAndroid Build Coastguard Worker     }
432*9190c2a8SAndroid Build Coastguard Worker     return control;
433*9190c2a8SAndroid Build Coastguard Worker }
434*9190c2a8SAndroid Build Coastguard Worker 
makeCommandPath(std::string_view root,std::string_view item)435*9190c2a8SAndroid Build Coastguard Worker static std::string makeCommandPath(std::string_view root, std::string_view item) {
436*9190c2a8SAndroid Build Coastguard Worker     auto [itemRoot, subpath] = registry().rootAndSubpathFor(item);
437*9190c2a8SAndroid Build Coastguard Worker     if (itemRoot != root) {
438*9190c2a8SAndroid Build Coastguard Worker         return {};
439*9190c2a8SAndroid Build Coastguard Worker     }
440*9190c2a8SAndroid Build Coastguard Worker     // TODO: add "/.cmd/" if we decide to use a separate control tree.
441*9190c2a8SAndroid Build Coastguard Worker     return path::join(itemRoot, subpath);
442*9190c2a8SAndroid Build Coastguard Worker }
443*9190c2a8SAndroid Build Coastguard Worker 
toString(IncFsFileId id,char * out)444*9190c2a8SAndroid Build Coastguard Worker static void toString(IncFsFileId id, char* out) {
445*9190c2a8SAndroid Build Coastguard Worker     // Make sure this function matches the one in the kernel (e.g. same case for a-f digits).
446*9190c2a8SAndroid Build Coastguard Worker     static constexpr char kHexChar[] = "0123456789abcdef";
447*9190c2a8SAndroid Build Coastguard Worker 
448*9190c2a8SAndroid Build Coastguard Worker     for (auto item = std::begin(id.data); item != std::end(id.data); ++item, out += 2) {
449*9190c2a8SAndroid Build Coastguard Worker         out[0] = kHexChar[(*item & 0xf0) >> 4];
450*9190c2a8SAndroid Build Coastguard Worker         out[1] = kHexChar[(*item & 0x0f)];
451*9190c2a8SAndroid Build Coastguard Worker     }
452*9190c2a8SAndroid Build Coastguard Worker }
453*9190c2a8SAndroid Build Coastguard Worker 
toStringImpl(IncFsFileId id)454*9190c2a8SAndroid Build Coastguard Worker static std::string toStringImpl(IncFsFileId id) {
455*9190c2a8SAndroid Build Coastguard Worker     std::string res(kIncFsFileIdStringLength, '\0');
456*9190c2a8SAndroid Build Coastguard Worker     toString(id, res.data());
457*9190c2a8SAndroid Build Coastguard Worker     return res;
458*9190c2a8SAndroid Build Coastguard Worker }
459*9190c2a8SAndroid Build Coastguard Worker 
toFileIdImpl(std::string_view str)460*9190c2a8SAndroid Build Coastguard Worker static IncFsFileId toFileIdImpl(std::string_view str) {
461*9190c2a8SAndroid Build Coastguard Worker     if (str.size() != kIncFsFileIdStringLength) {
462*9190c2a8SAndroid Build Coastguard Worker         return kIncFsInvalidFileId;
463*9190c2a8SAndroid Build Coastguard Worker     }
464*9190c2a8SAndroid Build Coastguard Worker 
465*9190c2a8SAndroid Build Coastguard Worker     IncFsFileId res;
466*9190c2a8SAndroid Build Coastguard Worker     auto out = (char*)&res;
467*9190c2a8SAndroid Build Coastguard Worker     for (auto it = str.begin(); it != str.end(); it += 2, ++out) {
468*9190c2a8SAndroid Build Coastguard Worker         static const auto fromChar = [](char src) -> int {
469*9190c2a8SAndroid Build Coastguard Worker             if (src >= '0' && src <= '9') {
470*9190c2a8SAndroid Build Coastguard Worker                 return src - '0';
471*9190c2a8SAndroid Build Coastguard Worker             }
472*9190c2a8SAndroid Build Coastguard Worker             if (src >= 'a' && src <= 'f') {
473*9190c2a8SAndroid Build Coastguard Worker                 return src - 'a' + 10;
474*9190c2a8SAndroid Build Coastguard Worker             }
475*9190c2a8SAndroid Build Coastguard Worker             return -1;
476*9190c2a8SAndroid Build Coastguard Worker         };
477*9190c2a8SAndroid Build Coastguard Worker 
478*9190c2a8SAndroid Build Coastguard Worker         const int c[2] = {fromChar(it[0]), fromChar(it[1])};
479*9190c2a8SAndroid Build Coastguard Worker         if (c[0] == -1 || c[1] == -1) {
480*9190c2a8SAndroid Build Coastguard Worker             errno = EINVAL;
481*9190c2a8SAndroid Build Coastguard Worker             return kIncFsInvalidFileId;
482*9190c2a8SAndroid Build Coastguard Worker         }
483*9190c2a8SAndroid Build Coastguard Worker         *out = (c[0] << 4) | c[1];
484*9190c2a8SAndroid Build Coastguard Worker     }
485*9190c2a8SAndroid Build Coastguard Worker     return res;
486*9190c2a8SAndroid Build Coastguard Worker }
487*9190c2a8SAndroid Build Coastguard Worker 
IncFs_FileIdToString(IncFsFileId id,char * out)488*9190c2a8SAndroid Build Coastguard Worker int IncFs_FileIdToString(IncFsFileId id, char* out) {
489*9190c2a8SAndroid Build Coastguard Worker     if (!out) {
490*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
491*9190c2a8SAndroid Build Coastguard Worker     }
492*9190c2a8SAndroid Build Coastguard Worker     toString(id, out);
493*9190c2a8SAndroid Build Coastguard Worker     return 0;
494*9190c2a8SAndroid Build Coastguard Worker }
495*9190c2a8SAndroid Build Coastguard Worker 
IncFs_FileIdFromString(const char * in)496*9190c2a8SAndroid Build Coastguard Worker IncFsFileId IncFs_FileIdFromString(const char* in) {
497*9190c2a8SAndroid Build Coastguard Worker     return toFileIdImpl({in, kIncFsFileIdStringLength});
498*9190c2a8SAndroid Build Coastguard Worker }
499*9190c2a8SAndroid Build Coastguard Worker 
IncFs_FileIdFromMetadata(IncFsSpan metadata)500*9190c2a8SAndroid Build Coastguard Worker IncFsFileId IncFs_FileIdFromMetadata(IncFsSpan metadata) {
501*9190c2a8SAndroid Build Coastguard Worker     IncFsFileId id = {};
502*9190c2a8SAndroid Build Coastguard Worker     if (size_t(metadata.size) <= sizeof(id)) {
503*9190c2a8SAndroid Build Coastguard Worker         memcpy(&id, metadata.data, metadata.size);
504*9190c2a8SAndroid Build Coastguard Worker     } else {
505*9190c2a8SAndroid Build Coastguard Worker         uint8_t buffer[SHA_DIGEST_LENGTH];
506*9190c2a8SAndroid Build Coastguard Worker         static_assert(sizeof(buffer) >= sizeof(id));
507*9190c2a8SAndroid Build Coastguard Worker 
508*9190c2a8SAndroid Build Coastguard Worker         SHA_CTX ctx;
509*9190c2a8SAndroid Build Coastguard Worker         SHA1_Init(&ctx);
510*9190c2a8SAndroid Build Coastguard Worker         SHA1_Update(&ctx, metadata.data, metadata.size);
511*9190c2a8SAndroid Build Coastguard Worker         SHA1_Final(buffer, &ctx);
512*9190c2a8SAndroid Build Coastguard Worker         memcpy(&id, buffer, sizeof(id));
513*9190c2a8SAndroid Build Coastguard Worker     }
514*9190c2a8SAndroid Build Coastguard Worker     return id;
515*9190c2a8SAndroid Build Coastguard Worker }
516*9190c2a8SAndroid Build Coastguard Worker 
restoreconControlFiles(std::string_view targetDir)517*9190c2a8SAndroid Build Coastguard Worker static bool restoreconControlFiles(std::string_view targetDir) {
518*9190c2a8SAndroid Build Coastguard Worker     static constexpr auto restorecon = [](const char* name) {
519*9190c2a8SAndroid Build Coastguard Worker         if (const auto err = selinux_android_restorecon(name, SELINUX_ANDROID_RESTORECON_FORCE);
520*9190c2a8SAndroid Build Coastguard Worker             err != 0) {
521*9190c2a8SAndroid Build Coastguard Worker             errno = -err;
522*9190c2a8SAndroid Build Coastguard Worker             PLOG(ERROR) << "[incfs] Failed to restorecon: " << name;
523*9190c2a8SAndroid Build Coastguard Worker             return false;
524*9190c2a8SAndroid Build Coastguard Worker         }
525*9190c2a8SAndroid Build Coastguard Worker         return true;
526*9190c2a8SAndroid Build Coastguard Worker     };
527*9190c2a8SAndroid Build Coastguard Worker     if (!restorecon(path::join(targetDir, INCFS_PENDING_READS_FILENAME).c_str())) {
528*9190c2a8SAndroid Build Coastguard Worker         return false;
529*9190c2a8SAndroid Build Coastguard Worker     }
530*9190c2a8SAndroid Build Coastguard Worker     if (!restorecon(path::join(targetDir, INCFS_LOG_FILENAME).c_str())) {
531*9190c2a8SAndroid Build Coastguard Worker         return false;
532*9190c2a8SAndroid Build Coastguard Worker     }
533*9190c2a8SAndroid Build Coastguard Worker     if ((features() & Features::v2) &&
534*9190c2a8SAndroid Build Coastguard Worker         !restorecon(path::join(targetDir, INCFS_BLOCKS_WRITTEN_FILENAME).c_str())) {
535*9190c2a8SAndroid Build Coastguard Worker         return false;
536*9190c2a8SAndroid Build Coastguard Worker     }
537*9190c2a8SAndroid Build Coastguard Worker     return true;
538*9190c2a8SAndroid Build Coastguard Worker }
539*9190c2a8SAndroid Build Coastguard Worker 
IncFs_Mount(const char * backingPath,const char * targetDir,IncFsMountOptions options)540*9190c2a8SAndroid Build Coastguard Worker IncFsControl* IncFs_Mount(const char* backingPath, const char* targetDir,
541*9190c2a8SAndroid Build Coastguard Worker                           IncFsMountOptions options) {
542*9190c2a8SAndroid Build Coastguard Worker     if (!init().enabledAndReady()) {
543*9190c2a8SAndroid Build Coastguard Worker         LOG(WARNING) << "[incfs] Feature is not enabled";
544*9190c2a8SAndroid Build Coastguard Worker         errno = ENOTSUP;
545*9190c2a8SAndroid Build Coastguard Worker         return nullptr;
546*9190c2a8SAndroid Build Coastguard Worker     }
547*9190c2a8SAndroid Build Coastguard Worker 
548*9190c2a8SAndroid Build Coastguard Worker     if (auto err = isValidMountTarget(targetDir); err != 0) {
549*9190c2a8SAndroid Build Coastguard Worker         errno = -err;
550*9190c2a8SAndroid Build Coastguard Worker         return nullptr;
551*9190c2a8SAndroid Build Coastguard Worker     }
552*9190c2a8SAndroid Build Coastguard Worker     if (!isAbsolute(backingPath)) {
553*9190c2a8SAndroid Build Coastguard Worker         errno = EINVAL;
554*9190c2a8SAndroid Build Coastguard Worker         return nullptr;
555*9190c2a8SAndroid Build Coastguard Worker     }
556*9190c2a8SAndroid Build Coastguard Worker 
557*9190c2a8SAndroid Build Coastguard Worker     if (options.flags & createOnly) {
558*9190c2a8SAndroid Build Coastguard Worker         if (const auto err = path::isEmptyDir(backingPath); err != 0) {
559*9190c2a8SAndroid Build Coastguard Worker             errno = -err;
560*9190c2a8SAndroid Build Coastguard Worker             return nullptr;
561*9190c2a8SAndroid Build Coastguard Worker         }
562*9190c2a8SAndroid Build Coastguard Worker     } else if (options.flags & android::incfs::truncate) {
563*9190c2a8SAndroid Build Coastguard Worker         if (const auto err = rmDirContent(backingPath); err != 0) {
564*9190c2a8SAndroid Build Coastguard Worker             errno = -err;
565*9190c2a8SAndroid Build Coastguard Worker             return nullptr;
566*9190c2a8SAndroid Build Coastguard Worker         }
567*9190c2a8SAndroid Build Coastguard Worker     }
568*9190c2a8SAndroid Build Coastguard Worker 
569*9190c2a8SAndroid Build Coastguard Worker     const auto opts = makeMountOptionsString(options);
570*9190c2a8SAndroid Build Coastguard Worker     if (::mount(backingPath, targetDir, INCFS_NAME, MS_NOSUID | MS_NODEV | MS_NOATIME,
571*9190c2a8SAndroid Build Coastguard Worker                 opts.c_str())) {
572*9190c2a8SAndroid Build Coastguard Worker         PLOG(ERROR) << "[incfs] Failed to mount IncFS filesystem: " << targetDir;
573*9190c2a8SAndroid Build Coastguard Worker         return nullptr;
574*9190c2a8SAndroid Build Coastguard Worker     }
575*9190c2a8SAndroid Build Coastguard Worker 
576*9190c2a8SAndroid Build Coastguard Worker     // in case when the path is given in a form of a /proc/.../fd/ link, we need to update
577*9190c2a8SAndroid Build Coastguard Worker     // it here: old fd refers to the original empty directory, not to the mount
578*9190c2a8SAndroid Build Coastguard Worker     std::string updatedTargetDir;
579*9190c2a8SAndroid Build Coastguard Worker     if (path::dirName(targetDir) == path::procfsFdDir) {
580*9190c2a8SAndroid Build Coastguard Worker         updatedTargetDir = path::readlink(targetDir);
581*9190c2a8SAndroid Build Coastguard Worker     } else {
582*9190c2a8SAndroid Build Coastguard Worker         updatedTargetDir = targetDir;
583*9190c2a8SAndroid Build Coastguard Worker     }
584*9190c2a8SAndroid Build Coastguard Worker 
585*9190c2a8SAndroid Build Coastguard Worker     auto rootFd = ab::unique_fd(::open(updatedTargetDir.c_str(), O_PATH | O_CLOEXEC | O_DIRECTORY));
586*9190c2a8SAndroid Build Coastguard Worker     if (updatedTargetDir != targetDir) {
587*9190c2a8SAndroid Build Coastguard Worker         // ensure that the new directory is still the same after reopening
588*9190c2a8SAndroid Build Coastguard Worker         if (path::fromFd(rootFd) != updatedTargetDir) {
589*9190c2a8SAndroid Build Coastguard Worker             errno = EINVAL;
590*9190c2a8SAndroid Build Coastguard Worker             return nullptr;
591*9190c2a8SAndroid Build Coastguard Worker         }
592*9190c2a8SAndroid Build Coastguard Worker     }
593*9190c2a8SAndroid Build Coastguard Worker 
594*9190c2a8SAndroid Build Coastguard Worker     if (!restoreconControlFiles(path::procfsForFd(rootFd))) {
595*9190c2a8SAndroid Build Coastguard Worker         (void)IncFs_Unmount(targetDir);
596*9190c2a8SAndroid Build Coastguard Worker         return nullptr;
597*9190c2a8SAndroid Build Coastguard Worker     }
598*9190c2a8SAndroid Build Coastguard Worker 
599*9190c2a8SAndroid Build Coastguard Worker     auto control = makeControl(rootFd);
600*9190c2a8SAndroid Build Coastguard Worker     if (control == nullptr) {
601*9190c2a8SAndroid Build Coastguard Worker         (void)IncFs_Unmount(targetDir);
602*9190c2a8SAndroid Build Coastguard Worker         return nullptr;
603*9190c2a8SAndroid Build Coastguard Worker     }
604*9190c2a8SAndroid Build Coastguard Worker     return control;
605*9190c2a8SAndroid Build Coastguard Worker }
606*9190c2a8SAndroid Build Coastguard Worker 
IncFs_Open(const char * dir)607*9190c2a8SAndroid Build Coastguard Worker IncFsControl* IncFs_Open(const char* dir) {
608*9190c2a8SAndroid Build Coastguard Worker     auto root = registry().rootFor(dir);
609*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
610*9190c2a8SAndroid Build Coastguard Worker         errno = EINVAL;
611*9190c2a8SAndroid Build Coastguard Worker         return nullptr;
612*9190c2a8SAndroid Build Coastguard Worker     }
613*9190c2a8SAndroid Build Coastguard Worker     auto rootFd = ab::unique_fd(::open(details::c_str(root), O_PATH | O_CLOEXEC | O_DIRECTORY));
614*9190c2a8SAndroid Build Coastguard Worker     return makeControl(rootFd);
615*9190c2a8SAndroid Build Coastguard Worker }
616*9190c2a8SAndroid Build Coastguard Worker 
IncFs_GetControlFd(const IncFsControl * control,IncFsFdType type)617*9190c2a8SAndroid Build Coastguard Worker IncFsFd IncFs_GetControlFd(const IncFsControl* control, IncFsFdType type) {
618*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
619*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
620*9190c2a8SAndroid Build Coastguard Worker     }
621*9190c2a8SAndroid Build Coastguard Worker     switch (type) {
622*9190c2a8SAndroid Build Coastguard Worker         case CMD:
623*9190c2a8SAndroid Build Coastguard Worker             return control->cmd;
624*9190c2a8SAndroid Build Coastguard Worker         case PENDING_READS:
625*9190c2a8SAndroid Build Coastguard Worker             return control->pendingReads;
626*9190c2a8SAndroid Build Coastguard Worker         case LOGS:
627*9190c2a8SAndroid Build Coastguard Worker             return control->logs;
628*9190c2a8SAndroid Build Coastguard Worker         case BLOCKS_WRITTEN:
629*9190c2a8SAndroid Build Coastguard Worker             return control->blocksWritten;
630*9190c2a8SAndroid Build Coastguard Worker         default:
631*9190c2a8SAndroid Build Coastguard Worker             return -EINVAL;
632*9190c2a8SAndroid Build Coastguard Worker     }
633*9190c2a8SAndroid Build Coastguard Worker }
634*9190c2a8SAndroid Build Coastguard Worker 
IncFs_ReleaseControlFds(IncFsControl * control,IncFsFd out[],IncFsSize outSize)635*9190c2a8SAndroid Build Coastguard Worker IncFsSize IncFs_ReleaseControlFds(IncFsControl* control, IncFsFd out[], IncFsSize outSize) {
636*9190c2a8SAndroid Build Coastguard Worker     if (!control || !out) {
637*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
638*9190c2a8SAndroid Build Coastguard Worker     }
639*9190c2a8SAndroid Build Coastguard Worker     if (outSize < IncFsFdType::FDS_COUNT) {
640*9190c2a8SAndroid Build Coastguard Worker         return -ERANGE;
641*9190c2a8SAndroid Build Coastguard Worker     }
642*9190c2a8SAndroid Build Coastguard Worker     out[CMD] = std::exchange(control->cmd, -1);
643*9190c2a8SAndroid Build Coastguard Worker     out[PENDING_READS] = std::exchange(control->pendingReads, -1);
644*9190c2a8SAndroid Build Coastguard Worker     out[LOGS] = std::exchange(control->logs, -1);
645*9190c2a8SAndroid Build Coastguard Worker     out[BLOCKS_WRITTEN] = std::exchange(control->blocksWritten, -1);
646*9190c2a8SAndroid Build Coastguard Worker     return IncFsFdType::FDS_COUNT;
647*9190c2a8SAndroid Build Coastguard Worker }
648*9190c2a8SAndroid Build Coastguard Worker 
IncFs_CreateControl(IncFsFd cmd,IncFsFd pendingReads,IncFsFd logs,IncFsFd blocksWritten)649*9190c2a8SAndroid Build Coastguard Worker IncFsControl* IncFs_CreateControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs,
650*9190c2a8SAndroid Build Coastguard Worker                                   IncFsFd blocksWritten) {
651*9190c2a8SAndroid Build Coastguard Worker     return new IncFsControl(cmd, pendingReads, logs, blocksWritten);
652*9190c2a8SAndroid Build Coastguard Worker }
653*9190c2a8SAndroid Build Coastguard Worker 
IncFs_DeleteControl(IncFsControl * control)654*9190c2a8SAndroid Build Coastguard Worker void IncFs_DeleteControl(IncFsControl* control) {
655*9190c2a8SAndroid Build Coastguard Worker     if (control) {
656*9190c2a8SAndroid Build Coastguard Worker         if (control->cmd >= 0) {
657*9190c2a8SAndroid Build Coastguard Worker             close(control->cmd);
658*9190c2a8SAndroid Build Coastguard Worker         }
659*9190c2a8SAndroid Build Coastguard Worker         if (control->pendingReads >= 0) {
660*9190c2a8SAndroid Build Coastguard Worker             close(control->pendingReads);
661*9190c2a8SAndroid Build Coastguard Worker         }
662*9190c2a8SAndroid Build Coastguard Worker         if (control->logs >= 0) {
663*9190c2a8SAndroid Build Coastguard Worker             close(control->logs);
664*9190c2a8SAndroid Build Coastguard Worker         }
665*9190c2a8SAndroid Build Coastguard Worker         if (control->blocksWritten >= 0) {
666*9190c2a8SAndroid Build Coastguard Worker             close(control->blocksWritten);
667*9190c2a8SAndroid Build Coastguard Worker         }
668*9190c2a8SAndroid Build Coastguard Worker         delete control;
669*9190c2a8SAndroid Build Coastguard Worker     }
670*9190c2a8SAndroid Build Coastguard Worker }
671*9190c2a8SAndroid Build Coastguard Worker 
IncFs_SetOptions(const IncFsControl * control,IncFsMountOptions options)672*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_SetOptions(const IncFsControl* control, IncFsMountOptions options) {
673*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
674*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
675*9190c2a8SAndroid Build Coastguard Worker     }
676*9190c2a8SAndroid Build Coastguard Worker     auto root = rootForCmd(control->cmd);
677*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
678*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
679*9190c2a8SAndroid Build Coastguard Worker     }
680*9190c2a8SAndroid Build Coastguard Worker     auto opts = makeMountOptionsString(options);
681*9190c2a8SAndroid Build Coastguard Worker     if (::mount(nullptr, root.c_str(), nullptr, MS_REMOUNT | MS_NOSUID | MS_NODEV | MS_NOATIME,
682*9190c2a8SAndroid Build Coastguard Worker                 opts.c_str()) != 0) {
683*9190c2a8SAndroid Build Coastguard Worker         const auto error = errno;
684*9190c2a8SAndroid Build Coastguard Worker         PLOG(ERROR) << "[incfs] Failed to remount IncFS filesystem: " << root;
685*9190c2a8SAndroid Build Coastguard Worker         return -error;
686*9190c2a8SAndroid Build Coastguard Worker     }
687*9190c2a8SAndroid Build Coastguard Worker     return 0;
688*9190c2a8SAndroid Build Coastguard Worker }
689*9190c2a8SAndroid Build Coastguard Worker 
IncFs_Root(const IncFsControl * control,char buffer[],size_t * bufferSize)690*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_Root(const IncFsControl* control, char buffer[], size_t* bufferSize) {
691*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
692*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
693*9190c2a8SAndroid Build Coastguard Worker     }
694*9190c2a8SAndroid Build Coastguard Worker     std::string result = rootForCmd(control->cmd);
695*9190c2a8SAndroid Build Coastguard Worker     if (*bufferSize <= result.size()) {
696*9190c2a8SAndroid Build Coastguard Worker         *bufferSize = result.size() + 1;
697*9190c2a8SAndroid Build Coastguard Worker         return -EOVERFLOW;
698*9190c2a8SAndroid Build Coastguard Worker     }
699*9190c2a8SAndroid Build Coastguard Worker     result.copy(buffer, result.size());
700*9190c2a8SAndroid Build Coastguard Worker     buffer[result.size()] = '\0';
701*9190c2a8SAndroid Build Coastguard Worker     *bufferSize = result.size();
702*9190c2a8SAndroid Build Coastguard Worker     return 0;
703*9190c2a8SAndroid Build Coastguard Worker }
704*9190c2a8SAndroid Build Coastguard Worker 
705*9190c2a8SAndroid Build Coastguard Worker template <class T>
read(IncFsSpan & data)706*9190c2a8SAndroid Build Coastguard Worker std::optional<T> read(IncFsSpan& data) {
707*9190c2a8SAndroid Build Coastguard Worker     if (data.size < (int32_t)sizeof(T)) {
708*9190c2a8SAndroid Build Coastguard Worker         return {};
709*9190c2a8SAndroid Build Coastguard Worker     }
710*9190c2a8SAndroid Build Coastguard Worker     T res;
711*9190c2a8SAndroid Build Coastguard Worker     memcpy(&res, data.data, sizeof(res));
712*9190c2a8SAndroid Build Coastguard Worker     data.data += sizeof(res);
713*9190c2a8SAndroid Build Coastguard Worker     data.size -= sizeof(res);
714*9190c2a8SAndroid Build Coastguard Worker     return res;
715*9190c2a8SAndroid Build Coastguard Worker }
716*9190c2a8SAndroid Build Coastguard Worker 
validateSignatureFormat(IncFsSpan signature)717*9190c2a8SAndroid Build Coastguard Worker static IncFsErrorCode validateSignatureFormat(IncFsSpan signature) {
718*9190c2a8SAndroid Build Coastguard Worker     if (signature.data == nullptr && signature.size == 0) {
719*9190c2a8SAndroid Build Coastguard Worker         return 0; // it's fine to have unverified files too
720*9190c2a8SAndroid Build Coastguard Worker     }
721*9190c2a8SAndroid Build Coastguard Worker     if ((signature.data == nullptr) != (signature.size == 0)) {
722*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
723*9190c2a8SAndroid Build Coastguard Worker     }
724*9190c2a8SAndroid Build Coastguard Worker 
725*9190c2a8SAndroid Build Coastguard Worker     // These structs are here purely for checking the minimum size. Maybe will use them for
726*9190c2a8SAndroid Build Coastguard Worker     // parsing later.
727*9190c2a8SAndroid Build Coastguard Worker     struct __attribute__((packed)) Hashing {
728*9190c2a8SAndroid Build Coastguard Worker         int32_t size;
729*9190c2a8SAndroid Build Coastguard Worker         int32_t algorithm;
730*9190c2a8SAndroid Build Coastguard Worker         int8_t log2_blocksize;
731*9190c2a8SAndroid Build Coastguard Worker         int32_t salt_size;
732*9190c2a8SAndroid Build Coastguard Worker         int32_t raw_root_hash_size;
733*9190c2a8SAndroid Build Coastguard Worker     };
734*9190c2a8SAndroid Build Coastguard Worker     struct __attribute__((packed)) Signing {
735*9190c2a8SAndroid Build Coastguard Worker         int32_t size;
736*9190c2a8SAndroid Build Coastguard Worker         int32_t apk_digest_size;
737*9190c2a8SAndroid Build Coastguard Worker         int32_t certificate_size;
738*9190c2a8SAndroid Build Coastguard Worker         int32_t addl_data_size;
739*9190c2a8SAndroid Build Coastguard Worker         int32_t public_key_size;
740*9190c2a8SAndroid Build Coastguard Worker         int32_t algorithm;
741*9190c2a8SAndroid Build Coastguard Worker         int32_t signature_size;
742*9190c2a8SAndroid Build Coastguard Worker     };
743*9190c2a8SAndroid Build Coastguard Worker     struct __attribute__((packed)) MinSignature {
744*9190c2a8SAndroid Build Coastguard Worker         int32_t version;
745*9190c2a8SAndroid Build Coastguard Worker         Hashing hashing_info;
746*9190c2a8SAndroid Build Coastguard Worker         Signing signing_info;
747*9190c2a8SAndroid Build Coastguard Worker     };
748*9190c2a8SAndroid Build Coastguard Worker 
749*9190c2a8SAndroid Build Coastguard Worker     if (signature.size < (int32_t)sizeof(MinSignature)) {
750*9190c2a8SAndroid Build Coastguard Worker         return -ERANGE;
751*9190c2a8SAndroid Build Coastguard Worker     }
752*9190c2a8SAndroid Build Coastguard Worker     if (signature.size > INCFS_MAX_SIGNATURE_SIZE) {
753*9190c2a8SAndroid Build Coastguard Worker         return -ERANGE;
754*9190c2a8SAndroid Build Coastguard Worker     }
755*9190c2a8SAndroid Build Coastguard Worker 
756*9190c2a8SAndroid Build Coastguard Worker     auto version = read<int32_t>(signature);
757*9190c2a8SAndroid Build Coastguard Worker     if (version.value_or(-1) != INCFS_SIGNATURE_VERSION) {
758*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
759*9190c2a8SAndroid Build Coastguard Worker     }
760*9190c2a8SAndroid Build Coastguard Worker     auto hashSize = read<int32_t>(signature);
761*9190c2a8SAndroid Build Coastguard Worker     if (!hashSize || signature.size < *hashSize) {
762*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
763*9190c2a8SAndroid Build Coastguard Worker     }
764*9190c2a8SAndroid Build Coastguard Worker     auto hashAlgo = read<int32_t>(signature);
765*9190c2a8SAndroid Build Coastguard Worker     if (hashAlgo.value_or(-1) != INCFS_HASH_TREE_SHA256) {
766*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
767*9190c2a8SAndroid Build Coastguard Worker     }
768*9190c2a8SAndroid Build Coastguard Worker     auto logBlockSize = read<int8_t>(signature);
769*9190c2a8SAndroid Build Coastguard Worker     if (logBlockSize.value_or(-1) != 12 /* 2^12 == 4096 */) {
770*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
771*9190c2a8SAndroid Build Coastguard Worker     }
772*9190c2a8SAndroid Build Coastguard Worker     auto saltSize = read<int32_t>(signature);
773*9190c2a8SAndroid Build Coastguard Worker     if (saltSize.value_or(-1) != 0) {
774*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
775*9190c2a8SAndroid Build Coastguard Worker     }
776*9190c2a8SAndroid Build Coastguard Worker     auto rootHashSize = read<int32_t>(signature);
777*9190c2a8SAndroid Build Coastguard Worker     if (rootHashSize.value_or(-1) != INCFS_MAX_HASH_SIZE) {
778*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
779*9190c2a8SAndroid Build Coastguard Worker     }
780*9190c2a8SAndroid Build Coastguard Worker     if (signature.size < *rootHashSize) {
781*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
782*9190c2a8SAndroid Build Coastguard Worker     }
783*9190c2a8SAndroid Build Coastguard Worker     signature.data += *rootHashSize;
784*9190c2a8SAndroid Build Coastguard Worker     signature.size -= *rootHashSize;
785*9190c2a8SAndroid Build Coastguard Worker     auto signingSize = read<int32_t>(signature);
786*9190c2a8SAndroid Build Coastguard Worker     // everything remaining has to be in the signing info
787*9190c2a8SAndroid Build Coastguard Worker     if (signingSize.value_or(-1) != signature.size) {
788*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
789*9190c2a8SAndroid Build Coastguard Worker     }
790*9190c2a8SAndroid Build Coastguard Worker 
791*9190c2a8SAndroid Build Coastguard Worker     // TODO: validate the signature part too.
792*9190c2a8SAndroid Build Coastguard Worker     return 0;
793*9190c2a8SAndroid Build Coastguard Worker }
794*9190c2a8SAndroid Build Coastguard Worker 
IncFs_MakeFile(const IncFsControl * control,const char * path,int32_t mode,IncFsFileId id,IncFsNewFileParams params)795*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_MakeFile(const IncFsControl* control, const char* path, int32_t mode,
796*9190c2a8SAndroid Build Coastguard Worker                               IncFsFileId id, IncFsNewFileParams params) {
797*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
798*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
799*9190c2a8SAndroid Build Coastguard Worker     }
800*9190c2a8SAndroid Build Coastguard Worker 
801*9190c2a8SAndroid Build Coastguard Worker     auto [root, subpath] = registry().rootAndSubpathFor(path);
802*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
803*9190c2a8SAndroid Build Coastguard Worker         PLOG(WARNING) << "[incfs] makeFile failed for path " << path << ", root is empty.";
804*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
805*9190c2a8SAndroid Build Coastguard Worker     }
806*9190c2a8SAndroid Build Coastguard Worker     if (params.size < 0) {
807*9190c2a8SAndroid Build Coastguard Worker         LOG(WARNING) << "[incfs] makeFile failed for path " << path
808*9190c2a8SAndroid Build Coastguard Worker                      << ", size is invalid: " << params.size;
809*9190c2a8SAndroid Build Coastguard Worker         return -ERANGE;
810*9190c2a8SAndroid Build Coastguard Worker     }
811*9190c2a8SAndroid Build Coastguard Worker 
812*9190c2a8SAndroid Build Coastguard Worker     const auto [subdir, name] = path::splitDirBase(subpath);
813*9190c2a8SAndroid Build Coastguard Worker     incfs_new_file_args args = {
814*9190c2a8SAndroid Build Coastguard Worker             .size = (uint64_t)params.size,
815*9190c2a8SAndroid Build Coastguard Worker             .mode = (uint16_t)mode,
816*9190c2a8SAndroid Build Coastguard Worker             .directory_path = (uint64_t)subdir.data(),
817*9190c2a8SAndroid Build Coastguard Worker             .file_name = (uint64_t)name.data(),
818*9190c2a8SAndroid Build Coastguard Worker             .file_attr = (uint64_t)params.metadata.data,
819*9190c2a8SAndroid Build Coastguard Worker             .file_attr_len = (uint32_t)params.metadata.size,
820*9190c2a8SAndroid Build Coastguard Worker     };
821*9190c2a8SAndroid Build Coastguard Worker     static_assert(sizeof(args.file_id.bytes) == sizeof(id.data));
822*9190c2a8SAndroid Build Coastguard Worker     memcpy(args.file_id.bytes, id.data, sizeof(args.file_id.bytes));
823*9190c2a8SAndroid Build Coastguard Worker 
824*9190c2a8SAndroid Build Coastguard Worker     if (auto err = validateSignatureFormat(params.signature)) {
825*9190c2a8SAndroid Build Coastguard Worker         return err;
826*9190c2a8SAndroid Build Coastguard Worker     }
827*9190c2a8SAndroid Build Coastguard Worker     args.signature_info = (uint64_t)(uintptr_t)params.signature.data;
828*9190c2a8SAndroid Build Coastguard Worker     args.signature_size = (uint64_t)params.signature.size;
829*9190c2a8SAndroid Build Coastguard Worker 
830*9190c2a8SAndroid Build Coastguard Worker     if (::ioctl(control->cmd, INCFS_IOC_CREATE_FILE, &args)) {
831*9190c2a8SAndroid Build Coastguard Worker         PLOG(WARNING) << "[incfs] makeFile failed for " << root << " / " << subdir << " / " << name
832*9190c2a8SAndroid Build Coastguard Worker                       << " of " << params.size << " bytes";
833*9190c2a8SAndroid Build Coastguard Worker         return -errno;
834*9190c2a8SAndroid Build Coastguard Worker     }
835*9190c2a8SAndroid Build Coastguard Worker     if (::chmod(path::join(root, subdir, name).c_str(), mode)) {
836*9190c2a8SAndroid Build Coastguard Worker         PLOG(WARNING) << "[incfs] couldn't change file mode to 0" << std::oct << mode;
837*9190c2a8SAndroid Build Coastguard Worker     }
838*9190c2a8SAndroid Build Coastguard Worker 
839*9190c2a8SAndroid Build Coastguard Worker     return 0;
840*9190c2a8SAndroid Build Coastguard Worker }
841*9190c2a8SAndroid Build Coastguard Worker 
IncFs_MakeMappedFile(const IncFsControl * control,const char * path,int32_t mode,IncFsNewMappedFileParams params)842*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_MakeMappedFile(const IncFsControl* control, const char* path, int32_t mode,
843*9190c2a8SAndroid Build Coastguard Worker                                     IncFsNewMappedFileParams params) {
844*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
845*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
846*9190c2a8SAndroid Build Coastguard Worker     }
847*9190c2a8SAndroid Build Coastguard Worker 
848*9190c2a8SAndroid Build Coastguard Worker     auto [root, subpath] = registry().rootAndSubpathFor(path);
849*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
850*9190c2a8SAndroid Build Coastguard Worker         PLOG(WARNING) << "[incfs] makeMappedFile failed for path " << path << ", root is empty.";
851*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
852*9190c2a8SAndroid Build Coastguard Worker     }
853*9190c2a8SAndroid Build Coastguard Worker     if (params.size < 0) {
854*9190c2a8SAndroid Build Coastguard Worker         LOG(WARNING) << "[incfs] makeMappedFile failed for path " << path
855*9190c2a8SAndroid Build Coastguard Worker                      << ", size is invalid: " << params.size;
856*9190c2a8SAndroid Build Coastguard Worker         return -ERANGE;
857*9190c2a8SAndroid Build Coastguard Worker     }
858*9190c2a8SAndroid Build Coastguard Worker 
859*9190c2a8SAndroid Build Coastguard Worker     const auto [subdir, name] = path::splitDirBase(subpath);
860*9190c2a8SAndroid Build Coastguard Worker     incfs_create_mapped_file_args args = {
861*9190c2a8SAndroid Build Coastguard Worker             .size = (uint64_t)params.size,
862*9190c2a8SAndroid Build Coastguard Worker             .mode = (uint16_t)mode,
863*9190c2a8SAndroid Build Coastguard Worker             .directory_path = (uint64_t)subdir.data(),
864*9190c2a8SAndroid Build Coastguard Worker             .file_name = (uint64_t)name.data(),
865*9190c2a8SAndroid Build Coastguard Worker             .source_offset = (uint64_t)params.sourceOffset,
866*9190c2a8SAndroid Build Coastguard Worker     };
867*9190c2a8SAndroid Build Coastguard Worker     static_assert(sizeof(args.source_file_id.bytes) == sizeof(params.sourceId.data));
868*9190c2a8SAndroid Build Coastguard Worker     memcpy(args.source_file_id.bytes, params.sourceId.data, sizeof(args.source_file_id.bytes));
869*9190c2a8SAndroid Build Coastguard Worker 
870*9190c2a8SAndroid Build Coastguard Worker     if (::ioctl(control->cmd, INCFS_IOC_CREATE_MAPPED_FILE, &args)) {
871*9190c2a8SAndroid Build Coastguard Worker         PLOG(WARNING) << "[incfs] makeMappedFile failed for " << root << " / " << subdir << " / "
872*9190c2a8SAndroid Build Coastguard Worker                       << name << " of " << params.size << " bytes starting at "
873*9190c2a8SAndroid Build Coastguard Worker                       << params.sourceOffset;
874*9190c2a8SAndroid Build Coastguard Worker         return -errno;
875*9190c2a8SAndroid Build Coastguard Worker     }
876*9190c2a8SAndroid Build Coastguard Worker     if (::chmod(path::join(root, subpath).c_str(), mode)) {
877*9190c2a8SAndroid Build Coastguard Worker         PLOG(WARNING) << "[incfs] makeMappedFile error: couldn't change file mode to 0" << std::oct
878*9190c2a8SAndroid Build Coastguard Worker                       << mode;
879*9190c2a8SAndroid Build Coastguard Worker     }
880*9190c2a8SAndroid Build Coastguard Worker 
881*9190c2a8SAndroid Build Coastguard Worker     return 0;
882*9190c2a8SAndroid Build Coastguard Worker }
883*9190c2a8SAndroid Build Coastguard Worker 
makeDir(const char * commandPath,int32_t mode,bool allowExisting)884*9190c2a8SAndroid Build Coastguard Worker static IncFsErrorCode makeDir(const char* commandPath, int32_t mode, bool allowExisting) {
885*9190c2a8SAndroid Build Coastguard Worker     if (!::mkdir(commandPath, mode)) {
886*9190c2a8SAndroid Build Coastguard Worker         if (::chmod(commandPath, mode)) {
887*9190c2a8SAndroid Build Coastguard Worker             PLOG(WARNING) << "[incfs] couldn't change directory mode to 0" << std::oct << mode;
888*9190c2a8SAndroid Build Coastguard Worker         }
889*9190c2a8SAndroid Build Coastguard Worker         return 0;
890*9190c2a8SAndroid Build Coastguard Worker     }
891*9190c2a8SAndroid Build Coastguard Worker     // don't touch the existing dir's mode - mkdir(1) works that way.
892*9190c2a8SAndroid Build Coastguard Worker     return (allowExisting && errno == EEXIST) ? 0 : -errno;
893*9190c2a8SAndroid Build Coastguard Worker }
894*9190c2a8SAndroid Build Coastguard Worker 
makeDirs(std::string_view commandPath,std::string_view path,std::string_view root,int32_t mode)895*9190c2a8SAndroid Build Coastguard Worker static IncFsErrorCode makeDirs(std::string_view commandPath, std::string_view path,
896*9190c2a8SAndroid Build Coastguard Worker                                std::string_view root, int32_t mode) {
897*9190c2a8SAndroid Build Coastguard Worker     auto commandCPath = details::c_str(commandPath);
898*9190c2a8SAndroid Build Coastguard Worker     const auto mkdirRes = makeDir(commandCPath, mode, true);
899*9190c2a8SAndroid Build Coastguard Worker     if (!mkdirRes) {
900*9190c2a8SAndroid Build Coastguard Worker         return 0;
901*9190c2a8SAndroid Build Coastguard Worker     }
902*9190c2a8SAndroid Build Coastguard Worker     if (mkdirRes != -ENOENT) {
903*9190c2a8SAndroid Build Coastguard Worker         LOG(ERROR) << __func__ << "(): mkdir failed for " << path << " - " << mkdirRes;
904*9190c2a8SAndroid Build Coastguard Worker         return mkdirRes;
905*9190c2a8SAndroid Build Coastguard Worker     }
906*9190c2a8SAndroid Build Coastguard Worker 
907*9190c2a8SAndroid Build Coastguard Worker     const auto parent = path::dirName(commandPath);
908*9190c2a8SAndroid Build Coastguard Worker     if (!path::startsWith(parent, root)) {
909*9190c2a8SAndroid Build Coastguard Worker         // went too far, already out of the root mount
910*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
911*9190c2a8SAndroid Build Coastguard Worker     }
912*9190c2a8SAndroid Build Coastguard Worker 
913*9190c2a8SAndroid Build Coastguard Worker     if (auto parentMkdirRes = makeDirs(parent, path::dirName(path), root, mode)) {
914*9190c2a8SAndroid Build Coastguard Worker         return parentMkdirRes;
915*9190c2a8SAndroid Build Coastguard Worker     }
916*9190c2a8SAndroid Build Coastguard Worker     return makeDir(commandCPath, mode, true);
917*9190c2a8SAndroid Build Coastguard Worker }
918*9190c2a8SAndroid Build Coastguard Worker 
IncFs_MakeDir(const IncFsControl * control,const char * path,int32_t mode)919*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_MakeDir(const IncFsControl* control, const char* path, int32_t mode) {
920*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
921*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
922*9190c2a8SAndroid Build Coastguard Worker     }
923*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(control->cmd);
924*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
925*9190c2a8SAndroid Build Coastguard Worker         LOG(ERROR) << __func__ << "(): root is empty for " << path;
926*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
927*9190c2a8SAndroid Build Coastguard Worker     }
928*9190c2a8SAndroid Build Coastguard Worker     auto commandPath = makeCommandPath(root, path);
929*9190c2a8SAndroid Build Coastguard Worker     if (commandPath.empty()) {
930*9190c2a8SAndroid Build Coastguard Worker         LOG(ERROR) << __func__ << "(): commandPath is empty for " << path;
931*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
932*9190c2a8SAndroid Build Coastguard Worker     }
933*9190c2a8SAndroid Build Coastguard Worker     if (auto res = makeDir(commandPath.c_str(), mode, false)) {
934*9190c2a8SAndroid Build Coastguard Worker         LOG(ERROR) << __func__ << "(): mkdir failed for " << commandPath << " - " << res;
935*9190c2a8SAndroid Build Coastguard Worker         return res;
936*9190c2a8SAndroid Build Coastguard Worker     }
937*9190c2a8SAndroid Build Coastguard Worker     return 0;
938*9190c2a8SAndroid Build Coastguard Worker }
939*9190c2a8SAndroid Build Coastguard Worker 
IncFs_MakeDirs(const IncFsControl * control,const char * path,int32_t mode)940*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_MakeDirs(const IncFsControl* control, const char* path, int32_t mode) {
941*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
942*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
943*9190c2a8SAndroid Build Coastguard Worker     }
944*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(control->cmd);
945*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
946*9190c2a8SAndroid Build Coastguard Worker         LOG(ERROR) << __func__ << "(): root is empty for " << path;
947*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
948*9190c2a8SAndroid Build Coastguard Worker     }
949*9190c2a8SAndroid Build Coastguard Worker     auto commandPath = makeCommandPath(root, path);
950*9190c2a8SAndroid Build Coastguard Worker     if (commandPath.empty()) {
951*9190c2a8SAndroid Build Coastguard Worker         LOG(ERROR) << __func__ << "(): commandPath is empty for " << path;
952*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
953*9190c2a8SAndroid Build Coastguard Worker     }
954*9190c2a8SAndroid Build Coastguard Worker     return makeDirs(commandPath, path, root, mode);
955*9190c2a8SAndroid Build Coastguard Worker }
956*9190c2a8SAndroid Build Coastguard Worker 
getMetadata(const char * path,char buffer[],size_t * bufferSize)957*9190c2a8SAndroid Build Coastguard Worker static IncFsErrorCode getMetadata(const char* path, char buffer[], size_t* bufferSize) {
958*9190c2a8SAndroid Build Coastguard Worker     const auto res = ::getxattr(path, kMetadataAttrName, buffer, *bufferSize);
959*9190c2a8SAndroid Build Coastguard Worker     if (res < 0) {
960*9190c2a8SAndroid Build Coastguard Worker         if (errno == ERANGE) {
961*9190c2a8SAndroid Build Coastguard Worker             auto neededSize = ::getxattr(path, kMetadataAttrName, buffer, 0);
962*9190c2a8SAndroid Build Coastguard Worker             if (neededSize >= 0) {
963*9190c2a8SAndroid Build Coastguard Worker                 *bufferSize = neededSize;
964*9190c2a8SAndroid Build Coastguard Worker                 return 0;
965*9190c2a8SAndroid Build Coastguard Worker             }
966*9190c2a8SAndroid Build Coastguard Worker         }
967*9190c2a8SAndroid Build Coastguard Worker         return -errno;
968*9190c2a8SAndroid Build Coastguard Worker     }
969*9190c2a8SAndroid Build Coastguard Worker     *bufferSize = res;
970*9190c2a8SAndroid Build Coastguard Worker     return 0;
971*9190c2a8SAndroid Build Coastguard Worker }
972*9190c2a8SAndroid Build Coastguard Worker 
IncFs_GetMetadataById(const IncFsControl * control,IncFsFileId fileId,char buffer[],size_t * bufferSize)973*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_GetMetadataById(const IncFsControl* control, IncFsFileId fileId, char buffer[],
974*9190c2a8SAndroid Build Coastguard Worker                                      size_t* bufferSize) {
975*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
976*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
977*9190c2a8SAndroid Build Coastguard Worker     }
978*9190c2a8SAndroid Build Coastguard Worker 
979*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(control->cmd);
980*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
981*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
982*9190c2a8SAndroid Build Coastguard Worker     }
983*9190c2a8SAndroid Build Coastguard Worker     auto name = indexPath(root, fileId);
984*9190c2a8SAndroid Build Coastguard Worker     return getMetadata(details::c_str(name), buffer, bufferSize);
985*9190c2a8SAndroid Build Coastguard Worker }
986*9190c2a8SAndroid Build Coastguard Worker 
IncFs_GetMetadataByPath(const IncFsControl * control,const char * path,char buffer[],size_t * bufferSize)987*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_GetMetadataByPath(const IncFsControl* control, const char* path, char buffer[],
988*9190c2a8SAndroid Build Coastguard Worker                                        size_t* bufferSize) {
989*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
990*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
991*9190c2a8SAndroid Build Coastguard Worker     }
992*9190c2a8SAndroid Build Coastguard Worker     const auto pathRoot = registry().rootFor(path);
993*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(control->cmd);
994*9190c2a8SAndroid Build Coastguard Worker     if (root.empty() || root != pathRoot) {
995*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
996*9190c2a8SAndroid Build Coastguard Worker     }
997*9190c2a8SAndroid Build Coastguard Worker 
998*9190c2a8SAndroid Build Coastguard Worker     return getMetadata(path, buffer, bufferSize);
999*9190c2a8SAndroid Build Coastguard Worker }
1000*9190c2a8SAndroid Build Coastguard Worker 
1001*9190c2a8SAndroid Build Coastguard Worker template <class GetterFunc, class Param>
getId(GetterFunc getter,Param param)1002*9190c2a8SAndroid Build Coastguard Worker static IncFsFileId getId(GetterFunc getter, Param param) {
1003*9190c2a8SAndroid Build Coastguard Worker     char buffer[kIncFsFileIdStringLength];
1004*9190c2a8SAndroid Build Coastguard Worker     const auto res = getter(param, kIdAttrName, buffer, sizeof(buffer));
1005*9190c2a8SAndroid Build Coastguard Worker     if (res != sizeof(buffer)) {
1006*9190c2a8SAndroid Build Coastguard Worker         return kIncFsInvalidFileId;
1007*9190c2a8SAndroid Build Coastguard Worker     }
1008*9190c2a8SAndroid Build Coastguard Worker     return toFileIdImpl({buffer, std::size(buffer)});
1009*9190c2a8SAndroid Build Coastguard Worker }
1010*9190c2a8SAndroid Build Coastguard Worker 
IncFs_GetId(const IncFsControl * control,const char * path)1011*9190c2a8SAndroid Build Coastguard Worker IncFsFileId IncFs_GetId(const IncFsControl* control, const char* path) {
1012*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
1013*9190c2a8SAndroid Build Coastguard Worker         return kIncFsInvalidFileId;
1014*9190c2a8SAndroid Build Coastguard Worker     }
1015*9190c2a8SAndroid Build Coastguard Worker     const auto pathRoot = registry().rootFor(path);
1016*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(control->cmd);
1017*9190c2a8SAndroid Build Coastguard Worker     if (root.empty() || root != pathRoot) {
1018*9190c2a8SAndroid Build Coastguard Worker         errno = EINVAL;
1019*9190c2a8SAndroid Build Coastguard Worker         return kIncFsInvalidFileId;
1020*9190c2a8SAndroid Build Coastguard Worker     }
1021*9190c2a8SAndroid Build Coastguard Worker     return getId(::getxattr, path);
1022*9190c2a8SAndroid Build Coastguard Worker }
1023*9190c2a8SAndroid Build Coastguard Worker 
getSignature(int fd,char buffer[],size_t * bufferSize)1024*9190c2a8SAndroid Build Coastguard Worker static IncFsErrorCode getSignature(int fd, char buffer[], size_t* bufferSize) {
1025*9190c2a8SAndroid Build Coastguard Worker     incfs_get_file_sig_args args = {
1026*9190c2a8SAndroid Build Coastguard Worker             .file_signature = (uint64_t)buffer,
1027*9190c2a8SAndroid Build Coastguard Worker             .file_signature_buf_size = (uint32_t)*bufferSize,
1028*9190c2a8SAndroid Build Coastguard Worker     };
1029*9190c2a8SAndroid Build Coastguard Worker 
1030*9190c2a8SAndroid Build Coastguard Worker     auto res = ::ioctl(fd, INCFS_IOC_READ_FILE_SIGNATURE, &args);
1031*9190c2a8SAndroid Build Coastguard Worker     if (res < 0) {
1032*9190c2a8SAndroid Build Coastguard Worker         if (errno == E2BIG) {
1033*9190c2a8SAndroid Build Coastguard Worker             *bufferSize = INCFS_MAX_SIGNATURE_SIZE;
1034*9190c2a8SAndroid Build Coastguard Worker         }
1035*9190c2a8SAndroid Build Coastguard Worker         return -errno;
1036*9190c2a8SAndroid Build Coastguard Worker     }
1037*9190c2a8SAndroid Build Coastguard Worker     *bufferSize = args.file_signature_len_out;
1038*9190c2a8SAndroid Build Coastguard Worker     return 0;
1039*9190c2a8SAndroid Build Coastguard Worker }
1040*9190c2a8SAndroid Build Coastguard Worker 
IncFs_GetSignatureById(const IncFsControl * control,IncFsFileId fileId,char buffer[],size_t * bufferSize)1041*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_GetSignatureById(const IncFsControl* control, IncFsFileId fileId,
1042*9190c2a8SAndroid Build Coastguard Worker                                       char buffer[], size_t* bufferSize) {
1043*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
1044*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1045*9190c2a8SAndroid Build Coastguard Worker     }
1046*9190c2a8SAndroid Build Coastguard Worker 
1047*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(control->cmd);
1048*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
1049*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1050*9190c2a8SAndroid Build Coastguard Worker     }
1051*9190c2a8SAndroid Build Coastguard Worker     auto file = indexPath(root, fileId);
1052*9190c2a8SAndroid Build Coastguard Worker     auto fd = openRaw(file);
1053*9190c2a8SAndroid Build Coastguard Worker     if (fd < 0) {
1054*9190c2a8SAndroid Build Coastguard Worker         return fd.get();
1055*9190c2a8SAndroid Build Coastguard Worker     }
1056*9190c2a8SAndroid Build Coastguard Worker     return getSignature(fd, buffer, bufferSize);
1057*9190c2a8SAndroid Build Coastguard Worker }
1058*9190c2a8SAndroid Build Coastguard Worker 
IncFs_GetSignatureByPath(const IncFsControl * control,const char * path,char buffer[],size_t * bufferSize)1059*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_GetSignatureByPath(const IncFsControl* control, const char* path,
1060*9190c2a8SAndroid Build Coastguard Worker                                         char buffer[], size_t* bufferSize) {
1061*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
1062*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1063*9190c2a8SAndroid Build Coastguard Worker     }
1064*9190c2a8SAndroid Build Coastguard Worker 
1065*9190c2a8SAndroid Build Coastguard Worker     const auto pathRoot = registry().rootFor(path);
1066*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(control->cmd);
1067*9190c2a8SAndroid Build Coastguard Worker     if (root.empty() || root != pathRoot) {
1068*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1069*9190c2a8SAndroid Build Coastguard Worker     }
1070*9190c2a8SAndroid Build Coastguard Worker     return IncFs_UnsafeGetSignatureByPath(path, buffer, bufferSize);
1071*9190c2a8SAndroid Build Coastguard Worker }
1072*9190c2a8SAndroid Build Coastguard Worker 
IncFs_UnsafeGetSignatureByPath(const char * path,char buffer[],size_t * bufferSize)1073*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_UnsafeGetSignatureByPath(const char* path, char buffer[], size_t* bufferSize) {
1074*9190c2a8SAndroid Build Coastguard Worker     if (!isIncFsPath(path)) {
1075*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1076*9190c2a8SAndroid Build Coastguard Worker     }
1077*9190c2a8SAndroid Build Coastguard Worker     auto fd = openRaw(path);
1078*9190c2a8SAndroid Build Coastguard Worker     if (fd < 0) {
1079*9190c2a8SAndroid Build Coastguard Worker         return fd.get();
1080*9190c2a8SAndroid Build Coastguard Worker     }
1081*9190c2a8SAndroid Build Coastguard Worker     return getSignature(fd, buffer, bufferSize);
1082*9190c2a8SAndroid Build Coastguard Worker }
1083*9190c2a8SAndroid Build Coastguard Worker 
IncFs_Link(const IncFsControl * control,const char * fromPath,const char * wherePath)1084*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_Link(const IncFsControl* control, const char* fromPath,
1085*9190c2a8SAndroid Build Coastguard Worker                           const char* wherePath) {
1086*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
1087*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1088*9190c2a8SAndroid Build Coastguard Worker     }
1089*9190c2a8SAndroid Build Coastguard Worker 
1090*9190c2a8SAndroid Build Coastguard Worker     auto root = rootForCmd(control->cmd);
1091*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
1092*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1093*9190c2a8SAndroid Build Coastguard Worker     }
1094*9190c2a8SAndroid Build Coastguard Worker     auto cmdFrom = makeCommandPath(root, fromPath);
1095*9190c2a8SAndroid Build Coastguard Worker     if (cmdFrom.empty()) {
1096*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1097*9190c2a8SAndroid Build Coastguard Worker     }
1098*9190c2a8SAndroid Build Coastguard Worker     auto cmdWhere = makeCommandPath(root, wherePath);
1099*9190c2a8SAndroid Build Coastguard Worker     if (cmdWhere.empty()) {
1100*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1101*9190c2a8SAndroid Build Coastguard Worker     }
1102*9190c2a8SAndroid Build Coastguard Worker     if (::link(cmdFrom.c_str(), cmdWhere.c_str())) {
1103*9190c2a8SAndroid Build Coastguard Worker         return -errno;
1104*9190c2a8SAndroid Build Coastguard Worker     }
1105*9190c2a8SAndroid Build Coastguard Worker     return 0;
1106*9190c2a8SAndroid Build Coastguard Worker }
1107*9190c2a8SAndroid Build Coastguard Worker 
IncFs_Unlink(const IncFsControl * control,const char * path)1108*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_Unlink(const IncFsControl* control, const char* path) {
1109*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
1110*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1111*9190c2a8SAndroid Build Coastguard Worker     }
1112*9190c2a8SAndroid Build Coastguard Worker 
1113*9190c2a8SAndroid Build Coastguard Worker     auto root = rootForCmd(control->cmd);
1114*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
1115*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1116*9190c2a8SAndroid Build Coastguard Worker     }
1117*9190c2a8SAndroid Build Coastguard Worker     auto cmdPath = makeCommandPath(root, path);
1118*9190c2a8SAndroid Build Coastguard Worker     if (cmdPath.empty()) {
1119*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1120*9190c2a8SAndroid Build Coastguard Worker     }
1121*9190c2a8SAndroid Build Coastguard Worker     if (::unlink(cmdPath.c_str())) {
1122*9190c2a8SAndroid Build Coastguard Worker         if (errno == EISDIR) {
1123*9190c2a8SAndroid Build Coastguard Worker             if (!::rmdir(cmdPath.c_str())) {
1124*9190c2a8SAndroid Build Coastguard Worker                 return 0;
1125*9190c2a8SAndroid Build Coastguard Worker             }
1126*9190c2a8SAndroid Build Coastguard Worker         }
1127*9190c2a8SAndroid Build Coastguard Worker         return -errno;
1128*9190c2a8SAndroid Build Coastguard Worker     }
1129*9190c2a8SAndroid Build Coastguard Worker     return 0;
1130*9190c2a8SAndroid Build Coastguard Worker }
1131*9190c2a8SAndroid Build Coastguard Worker 
1132*9190c2a8SAndroid Build Coastguard Worker template <class RawPendingRead>
waitForReadsImpl(int fd,int32_t timeoutMs,RawPendingRead pendingReadsBuffer[],size_t * pendingReadsBufferSize)1133*9190c2a8SAndroid Build Coastguard Worker static int waitForReadsImpl(int fd, int32_t timeoutMs, RawPendingRead pendingReadsBuffer[],
1134*9190c2a8SAndroid Build Coastguard Worker                             size_t* pendingReadsBufferSize) {
1135*9190c2a8SAndroid Build Coastguard Worker     using namespace std::chrono;
1136*9190c2a8SAndroid Build Coastguard Worker     auto hrTimeout = steady_clock::duration(milliseconds(timeoutMs));
1137*9190c2a8SAndroid Build Coastguard Worker 
1138*9190c2a8SAndroid Build Coastguard Worker     while (hrTimeout > hrTimeout.zero() || (!pendingReadsBuffer && hrTimeout == hrTimeout.zero())) {
1139*9190c2a8SAndroid Build Coastguard Worker         const auto startTs = steady_clock::now();
1140*9190c2a8SAndroid Build Coastguard Worker 
1141*9190c2a8SAndroid Build Coastguard Worker         pollfd pfd = {fd, POLLIN, 0};
1142*9190c2a8SAndroid Build Coastguard Worker         const auto res = ::poll(&pfd, 1, duration_cast<milliseconds>(hrTimeout).count());
1143*9190c2a8SAndroid Build Coastguard Worker         if (res > 0) {
1144*9190c2a8SAndroid Build Coastguard Worker             break;
1145*9190c2a8SAndroid Build Coastguard Worker         }
1146*9190c2a8SAndroid Build Coastguard Worker         if (res == 0) {
1147*9190c2a8SAndroid Build Coastguard Worker             if (pendingReadsBufferSize) {
1148*9190c2a8SAndroid Build Coastguard Worker                 *pendingReadsBufferSize = 0;
1149*9190c2a8SAndroid Build Coastguard Worker             }
1150*9190c2a8SAndroid Build Coastguard Worker             return -ETIMEDOUT;
1151*9190c2a8SAndroid Build Coastguard Worker         }
1152*9190c2a8SAndroid Build Coastguard Worker         const auto error = errno;
1153*9190c2a8SAndroid Build Coastguard Worker         if (error != EINTR) {
1154*9190c2a8SAndroid Build Coastguard Worker             PLOG(ERROR) << "poll() failed";
1155*9190c2a8SAndroid Build Coastguard Worker             return -error;
1156*9190c2a8SAndroid Build Coastguard Worker         }
1157*9190c2a8SAndroid Build Coastguard Worker         hrTimeout -= steady_clock::now() - startTs;
1158*9190c2a8SAndroid Build Coastguard Worker     }
1159*9190c2a8SAndroid Build Coastguard Worker     if (!pendingReadsBuffer) {
1160*9190c2a8SAndroid Build Coastguard Worker         return hrTimeout < hrTimeout.zero() ? -ETIMEDOUT : 0;
1161*9190c2a8SAndroid Build Coastguard Worker     }
1162*9190c2a8SAndroid Build Coastguard Worker 
1163*9190c2a8SAndroid Build Coastguard Worker     auto res =
1164*9190c2a8SAndroid Build Coastguard Worker             ::read(fd, pendingReadsBuffer, *pendingReadsBufferSize * sizeof(*pendingReadsBuffer));
1165*9190c2a8SAndroid Build Coastguard Worker     if (res < 0) {
1166*9190c2a8SAndroid Build Coastguard Worker         const auto error = errno;
1167*9190c2a8SAndroid Build Coastguard Worker         PLOG(ERROR) << "read() failed";
1168*9190c2a8SAndroid Build Coastguard Worker         return -error;
1169*9190c2a8SAndroid Build Coastguard Worker     }
1170*9190c2a8SAndroid Build Coastguard Worker     if (res == 0) {
1171*9190c2a8SAndroid Build Coastguard Worker         *pendingReadsBufferSize = 0;
1172*9190c2a8SAndroid Build Coastguard Worker         return -ETIMEDOUT;
1173*9190c2a8SAndroid Build Coastguard Worker     }
1174*9190c2a8SAndroid Build Coastguard Worker     if ((res % sizeof(*pendingReadsBuffer)) != 0) {
1175*9190c2a8SAndroid Build Coastguard Worker         PLOG(ERROR) << "read() returned half of a struct??";
1176*9190c2a8SAndroid Build Coastguard Worker         return -EFAULT;
1177*9190c2a8SAndroid Build Coastguard Worker     }
1178*9190c2a8SAndroid Build Coastguard Worker     *pendingReadsBufferSize = res / sizeof(*pendingReadsBuffer);
1179*9190c2a8SAndroid Build Coastguard Worker     return 0;
1180*9190c2a8SAndroid Build Coastguard Worker }
1181*9190c2a8SAndroid Build Coastguard Worker 
1182*9190c2a8SAndroid Build Coastguard Worker template <class PublicPendingRead, class RawPendingRead>
convertRead(RawPendingRead rawRead)1183*9190c2a8SAndroid Build Coastguard Worker PublicPendingRead convertRead(RawPendingRead rawRead) {
1184*9190c2a8SAndroid Build Coastguard Worker     PublicPendingRead res = {
1185*9190c2a8SAndroid Build Coastguard Worker             .bootClockTsUs = rawRead.timestamp_us,
1186*9190c2a8SAndroid Build Coastguard Worker             .block = (IncFsBlockIndex)rawRead.block_index,
1187*9190c2a8SAndroid Build Coastguard Worker             .serialNo = rawRead.serial_number,
1188*9190c2a8SAndroid Build Coastguard Worker     };
1189*9190c2a8SAndroid Build Coastguard Worker     memcpy(&res.id.data, rawRead.file_id.bytes, sizeof(res.id.data));
1190*9190c2a8SAndroid Build Coastguard Worker 
1191*9190c2a8SAndroid Build Coastguard Worker     if constexpr (std::is_same_v<PublicPendingRead, IncFsReadInfoWithUid>) {
1192*9190c2a8SAndroid Build Coastguard Worker         if constexpr (std::is_same_v<RawPendingRead, incfs_pending_read_info2>) {
1193*9190c2a8SAndroid Build Coastguard Worker             res.uid = rawRead.uid;
1194*9190c2a8SAndroid Build Coastguard Worker         } else {
1195*9190c2a8SAndroid Build Coastguard Worker             res.uid = kIncFsNoUid;
1196*9190c2a8SAndroid Build Coastguard Worker         }
1197*9190c2a8SAndroid Build Coastguard Worker     }
1198*9190c2a8SAndroid Build Coastguard Worker     return res;
1199*9190c2a8SAndroid Build Coastguard Worker }
1200*9190c2a8SAndroid Build Coastguard Worker 
1201*9190c2a8SAndroid Build Coastguard Worker template <class RawPendingRead, class PublicPendingRead>
waitForReads(IncFsFd readFd,int32_t timeoutMs,PublicPendingRead buffer[],size_t * bufferSize)1202*9190c2a8SAndroid Build Coastguard Worker static int waitForReads(IncFsFd readFd, int32_t timeoutMs, PublicPendingRead buffer[],
1203*9190c2a8SAndroid Build Coastguard Worker                         size_t* bufferSize) {
1204*9190c2a8SAndroid Build Coastguard Worker     std::vector<RawPendingRead> pendingReads(*bufferSize);
1205*9190c2a8SAndroid Build Coastguard Worker     if (const auto res = waitForReadsImpl(readFd, timeoutMs, pendingReads.data(), bufferSize)) {
1206*9190c2a8SAndroid Build Coastguard Worker         return res;
1207*9190c2a8SAndroid Build Coastguard Worker     }
1208*9190c2a8SAndroid Build Coastguard Worker     for (size_t i = 0; i != *bufferSize; ++i) {
1209*9190c2a8SAndroid Build Coastguard Worker         buffer[i] = convertRead<PublicPendingRead>(pendingReads[i]);
1210*9190c2a8SAndroid Build Coastguard Worker     }
1211*9190c2a8SAndroid Build Coastguard Worker     return 0;
1212*9190c2a8SAndroid Build Coastguard Worker }
1213*9190c2a8SAndroid Build Coastguard Worker 
1214*9190c2a8SAndroid Build Coastguard Worker template <class PublicPendingRead>
waitForReads(IncFsFd readFd,int32_t timeoutMs,PublicPendingRead buffer[],size_t * bufferSize)1215*9190c2a8SAndroid Build Coastguard Worker static int waitForReads(IncFsFd readFd, int32_t timeoutMs, PublicPendingRead buffer[],
1216*9190c2a8SAndroid Build Coastguard Worker                         size_t* bufferSize) {
1217*9190c2a8SAndroid Build Coastguard Worker     if (features() & Features::v2) {
1218*9190c2a8SAndroid Build Coastguard Worker         return waitForReads<incfs_pending_read_info2>(readFd, timeoutMs, buffer, bufferSize);
1219*9190c2a8SAndroid Build Coastguard Worker     }
1220*9190c2a8SAndroid Build Coastguard Worker     return waitForReads<incfs_pending_read_info>(readFd, timeoutMs, buffer, bufferSize);
1221*9190c2a8SAndroid Build Coastguard Worker }
1222*9190c2a8SAndroid Build Coastguard Worker 
IncFs_WaitForPendingReads(const IncFsControl * control,int32_t timeoutMs,IncFsReadInfo buffer[],size_t * bufferSize)1223*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_WaitForPendingReads(const IncFsControl* control, int32_t timeoutMs,
1224*9190c2a8SAndroid Build Coastguard Worker                                          IncFsReadInfo buffer[], size_t* bufferSize) {
1225*9190c2a8SAndroid Build Coastguard Worker     if (!control || control->pendingReads < 0) {
1226*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1227*9190c2a8SAndroid Build Coastguard Worker     }
1228*9190c2a8SAndroid Build Coastguard Worker 
1229*9190c2a8SAndroid Build Coastguard Worker     return waitForReads(control->pendingReads, timeoutMs, buffer, bufferSize);
1230*9190c2a8SAndroid Build Coastguard Worker }
1231*9190c2a8SAndroid Build Coastguard Worker 
IncFs_WaitForPendingReadsWithUid(const IncFsControl * control,int32_t timeoutMs,IncFsReadInfoWithUid buffer[],size_t * bufferSize)1232*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_WaitForPendingReadsWithUid(const IncFsControl* control, int32_t timeoutMs,
1233*9190c2a8SAndroid Build Coastguard Worker                                                 IncFsReadInfoWithUid buffer[], size_t* bufferSize) {
1234*9190c2a8SAndroid Build Coastguard Worker     if (!control || control->pendingReads < 0) {
1235*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1236*9190c2a8SAndroid Build Coastguard Worker     }
1237*9190c2a8SAndroid Build Coastguard Worker 
1238*9190c2a8SAndroid Build Coastguard Worker     return waitForReads(control->pendingReads, timeoutMs, buffer, bufferSize);
1239*9190c2a8SAndroid Build Coastguard Worker }
1240*9190c2a8SAndroid Build Coastguard Worker 
IncFs_WaitForPageReads(const IncFsControl * control,int32_t timeoutMs,IncFsReadInfo buffer[],size_t * bufferSize)1241*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_WaitForPageReads(const IncFsControl* control, int32_t timeoutMs,
1242*9190c2a8SAndroid Build Coastguard Worker                                       IncFsReadInfo buffer[], size_t* bufferSize) {
1243*9190c2a8SAndroid Build Coastguard Worker     if (!control || control->logs < 0) {
1244*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1245*9190c2a8SAndroid Build Coastguard Worker     }
1246*9190c2a8SAndroid Build Coastguard Worker 
1247*9190c2a8SAndroid Build Coastguard Worker     return waitForReads(control->logs, timeoutMs, buffer, bufferSize);
1248*9190c2a8SAndroid Build Coastguard Worker }
1249*9190c2a8SAndroid Build Coastguard Worker 
IncFs_WaitForPageReadsWithUid(const IncFsControl * control,int32_t timeoutMs,IncFsReadInfoWithUid buffer[],size_t * bufferSize)1250*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_WaitForPageReadsWithUid(const IncFsControl* control, int32_t timeoutMs,
1251*9190c2a8SAndroid Build Coastguard Worker                                              IncFsReadInfoWithUid buffer[], size_t* bufferSize) {
1252*9190c2a8SAndroid Build Coastguard Worker     if (!control || control->logs < 0) {
1253*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1254*9190c2a8SAndroid Build Coastguard Worker     }
1255*9190c2a8SAndroid Build Coastguard Worker 
1256*9190c2a8SAndroid Build Coastguard Worker     return waitForReads(control->logs, timeoutMs, buffer, bufferSize);
1257*9190c2a8SAndroid Build Coastguard Worker }
1258*9190c2a8SAndroid Build Coastguard Worker 
openForSpecialOps(int cmd,const char * path)1259*9190c2a8SAndroid Build Coastguard Worker static IncFsFd openForSpecialOps(int cmd, const char* path) {
1260*9190c2a8SAndroid Build Coastguard Worker     ab::unique_fd fd(::open(path, O_RDONLY | O_CLOEXEC));
1261*9190c2a8SAndroid Build Coastguard Worker     if (fd < 0) {
1262*9190c2a8SAndroid Build Coastguard Worker         return -errno;
1263*9190c2a8SAndroid Build Coastguard Worker     }
1264*9190c2a8SAndroid Build Coastguard Worker     struct incfs_permit_fill args = {.file_descriptor = (uint32_t)fd.get()};
1265*9190c2a8SAndroid Build Coastguard Worker     auto err = ::ioctl(cmd, INCFS_IOC_PERMIT_FILL, &args);
1266*9190c2a8SAndroid Build Coastguard Worker     if (err < 0) {
1267*9190c2a8SAndroid Build Coastguard Worker         return -errno;
1268*9190c2a8SAndroid Build Coastguard Worker     }
1269*9190c2a8SAndroid Build Coastguard Worker     return fd.release();
1270*9190c2a8SAndroid Build Coastguard Worker }
1271*9190c2a8SAndroid Build Coastguard Worker 
IncFs_OpenForSpecialOpsByPath(const IncFsControl * control,const char * path)1272*9190c2a8SAndroid Build Coastguard Worker IncFsFd IncFs_OpenForSpecialOpsByPath(const IncFsControl* control, const char* path) {
1273*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
1274*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1275*9190c2a8SAndroid Build Coastguard Worker     }
1276*9190c2a8SAndroid Build Coastguard Worker 
1277*9190c2a8SAndroid Build Coastguard Worker     const auto pathRoot = registry().rootFor(path);
1278*9190c2a8SAndroid Build Coastguard Worker     const auto cmd = control->cmd;
1279*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(cmd);
1280*9190c2a8SAndroid Build Coastguard Worker     if (root.empty() || root != pathRoot) {
1281*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1282*9190c2a8SAndroid Build Coastguard Worker     }
1283*9190c2a8SAndroid Build Coastguard Worker     return openForSpecialOps(cmd, makeCommandPath(root, path).c_str());
1284*9190c2a8SAndroid Build Coastguard Worker }
1285*9190c2a8SAndroid Build Coastguard Worker 
IncFs_OpenForSpecialOpsById(const IncFsControl * control,IncFsFileId id)1286*9190c2a8SAndroid Build Coastguard Worker IncFsFd IncFs_OpenForSpecialOpsById(const IncFsControl* control, IncFsFileId id) {
1287*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
1288*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1289*9190c2a8SAndroid Build Coastguard Worker     }
1290*9190c2a8SAndroid Build Coastguard Worker 
1291*9190c2a8SAndroid Build Coastguard Worker     const auto cmd = control->cmd;
1292*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(cmd);
1293*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
1294*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1295*9190c2a8SAndroid Build Coastguard Worker     }
1296*9190c2a8SAndroid Build Coastguard Worker     auto name = indexPath(root, id);
1297*9190c2a8SAndroid Build Coastguard Worker     return openForSpecialOps(cmd, makeCommandPath(root, name).c_str());
1298*9190c2a8SAndroid Build Coastguard Worker }
1299*9190c2a8SAndroid Build Coastguard Worker 
writeBlocks(int fd,const incfs_fill_block blocks[],int blocksCount)1300*9190c2a8SAndroid Build Coastguard Worker static int writeBlocks(int fd, const incfs_fill_block blocks[], int blocksCount) {
1301*9190c2a8SAndroid Build Coastguard Worker     if (fd < 0 || blocksCount == 0) {
1302*9190c2a8SAndroid Build Coastguard Worker         return 0;
1303*9190c2a8SAndroid Build Coastguard Worker     }
1304*9190c2a8SAndroid Build Coastguard Worker     if (blocksCount < 0) {
1305*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1306*9190c2a8SAndroid Build Coastguard Worker     }
1307*9190c2a8SAndroid Build Coastguard Worker 
1308*9190c2a8SAndroid Build Coastguard Worker     auto ptr = blocks;
1309*9190c2a8SAndroid Build Coastguard Worker     const auto end = blocks + blocksCount;
1310*9190c2a8SAndroid Build Coastguard Worker     do {
1311*9190c2a8SAndroid Build Coastguard Worker         struct incfs_fill_blocks args = {.count = uint64_t(end - ptr),
1312*9190c2a8SAndroid Build Coastguard Worker                                          .fill_blocks = (uint64_t)(uintptr_t)ptr};
1313*9190c2a8SAndroid Build Coastguard Worker         const auto written = ::ioctl(fd, INCFS_IOC_FILL_BLOCKS, &args);
1314*9190c2a8SAndroid Build Coastguard Worker         if (written < 0) {
1315*9190c2a8SAndroid Build Coastguard Worker             if (errno == EINTR) {
1316*9190c2a8SAndroid Build Coastguard Worker                 continue;
1317*9190c2a8SAndroid Build Coastguard Worker             }
1318*9190c2a8SAndroid Build Coastguard Worker             const auto error = errno;
1319*9190c2a8SAndroid Build Coastguard Worker             PLOG(WARNING) << "writing IncFS blocks failed";
1320*9190c2a8SAndroid Build Coastguard Worker             if (ptr == blocks) {
1321*9190c2a8SAndroid Build Coastguard Worker                 return -error;
1322*9190c2a8SAndroid Build Coastguard Worker             }
1323*9190c2a8SAndroid Build Coastguard Worker             // something has been written, return a success here and let the
1324*9190c2a8SAndroid Build Coastguard Worker             // next call handle the error.
1325*9190c2a8SAndroid Build Coastguard Worker             break;
1326*9190c2a8SAndroid Build Coastguard Worker         }
1327*9190c2a8SAndroid Build Coastguard Worker         ptr += written;
1328*9190c2a8SAndroid Build Coastguard Worker     } while (ptr < end);
1329*9190c2a8SAndroid Build Coastguard Worker     return ptr - blocks;
1330*9190c2a8SAndroid Build Coastguard Worker }
1331*9190c2a8SAndroid Build Coastguard Worker 
IncFs_WriteBlocks(const IncFsDataBlock blocks[],size_t blocksCount)1332*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_WriteBlocks(const IncFsDataBlock blocks[], size_t blocksCount) {
1333*9190c2a8SAndroid Build Coastguard Worker     incfs_fill_block incfsBlocks[128];
1334*9190c2a8SAndroid Build Coastguard Worker     int writtenCount = 0;
1335*9190c2a8SAndroid Build Coastguard Worker     int incfsBlocksUsed = 0;
1336*9190c2a8SAndroid Build Coastguard Worker     int lastBlockFd = -1;
1337*9190c2a8SAndroid Build Coastguard Worker     for (size_t i = 0; i < blocksCount; ++i) {
1338*9190c2a8SAndroid Build Coastguard Worker         if (lastBlockFd != blocks[i].fileFd || incfsBlocksUsed == std::size(incfsBlocks)) {
1339*9190c2a8SAndroid Build Coastguard Worker             auto count = writeBlocks(lastBlockFd, incfsBlocks, incfsBlocksUsed);
1340*9190c2a8SAndroid Build Coastguard Worker             if (count > 0) {
1341*9190c2a8SAndroid Build Coastguard Worker                 writtenCount += count;
1342*9190c2a8SAndroid Build Coastguard Worker             }
1343*9190c2a8SAndroid Build Coastguard Worker             if (count != incfsBlocksUsed) {
1344*9190c2a8SAndroid Build Coastguard Worker                 return writtenCount ? writtenCount : count;
1345*9190c2a8SAndroid Build Coastguard Worker             }
1346*9190c2a8SAndroid Build Coastguard Worker             lastBlockFd = blocks[i].fileFd;
1347*9190c2a8SAndroid Build Coastguard Worker             incfsBlocksUsed = 0;
1348*9190c2a8SAndroid Build Coastguard Worker         }
1349*9190c2a8SAndroid Build Coastguard Worker         incfsBlocks[incfsBlocksUsed] = incfs_fill_block{
1350*9190c2a8SAndroid Build Coastguard Worker                 .block_index = (uint32_t)blocks[i].pageIndex,
1351*9190c2a8SAndroid Build Coastguard Worker                 .data_len = blocks[i].dataSize,
1352*9190c2a8SAndroid Build Coastguard Worker                 .data = (uint64_t)blocks[i].data,
1353*9190c2a8SAndroid Build Coastguard Worker                 .compression = (uint8_t)blocks[i].compression,
1354*9190c2a8SAndroid Build Coastguard Worker                 .flags = uint8_t(blocks[i].kind == INCFS_BLOCK_KIND_HASH ? INCFS_BLOCK_FLAGS_HASH
1355*9190c2a8SAndroid Build Coastguard Worker                                                                          : 0),
1356*9190c2a8SAndroid Build Coastguard Worker         };
1357*9190c2a8SAndroid Build Coastguard Worker         ++incfsBlocksUsed;
1358*9190c2a8SAndroid Build Coastguard Worker     }
1359*9190c2a8SAndroid Build Coastguard Worker     auto count = writeBlocks(lastBlockFd, incfsBlocks, incfsBlocksUsed);
1360*9190c2a8SAndroid Build Coastguard Worker     if (count > 0) {
1361*9190c2a8SAndroid Build Coastguard Worker         writtenCount += count;
1362*9190c2a8SAndroid Build Coastguard Worker     }
1363*9190c2a8SAndroid Build Coastguard Worker     return writtenCount ? writtenCount : count;
1364*9190c2a8SAndroid Build Coastguard Worker }
1365*9190c2a8SAndroid Build Coastguard Worker 
IncFs_BindMount(const char * sourceDir,const char * targetDir)1366*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_BindMount(const char* sourceDir, const char* targetDir) {
1367*9190c2a8SAndroid Build Coastguard Worker     if (!enabled()) {
1368*9190c2a8SAndroid Build Coastguard Worker         return -ENOTSUP;
1369*9190c2a8SAndroid Build Coastguard Worker     }
1370*9190c2a8SAndroid Build Coastguard Worker 
1371*9190c2a8SAndroid Build Coastguard Worker     if (path::dirName(sourceDir) == path::procfsFdDir) {
1372*9190c2a8SAndroid Build Coastguard Worker         // can't find such path in the mount registry, but still can verify the filesystem
1373*9190c2a8SAndroid Build Coastguard Worker         // via the stat() call
1374*9190c2a8SAndroid Build Coastguard Worker         if (!isIncFsPathImpl(sourceDir)) {
1375*9190c2a8SAndroid Build Coastguard Worker             return -EINVAL;
1376*9190c2a8SAndroid Build Coastguard Worker         }
1377*9190c2a8SAndroid Build Coastguard Worker     } else {
1378*9190c2a8SAndroid Build Coastguard Worker         auto [sourceRoot, subpath] = registry().rootAndSubpathFor(sourceDir);
1379*9190c2a8SAndroid Build Coastguard Worker         if (sourceRoot.empty()) {
1380*9190c2a8SAndroid Build Coastguard Worker             return -EINVAL;
1381*9190c2a8SAndroid Build Coastguard Worker         }
1382*9190c2a8SAndroid Build Coastguard Worker         if (subpath.empty()) {
1383*9190c2a8SAndroid Build Coastguard Worker             LOG(WARNING) << "[incfs] Binding the root mount '" << sourceRoot << "' is not allowed";
1384*9190c2a8SAndroid Build Coastguard Worker             return -EINVAL;
1385*9190c2a8SAndroid Build Coastguard Worker         }
1386*9190c2a8SAndroid Build Coastguard Worker     }
1387*9190c2a8SAndroid Build Coastguard Worker 
1388*9190c2a8SAndroid Build Coastguard Worker     if (auto err = isValidMountTarget(targetDir); err != 0) {
1389*9190c2a8SAndroid Build Coastguard Worker         return err;
1390*9190c2a8SAndroid Build Coastguard Worker     }
1391*9190c2a8SAndroid Build Coastguard Worker 
1392*9190c2a8SAndroid Build Coastguard Worker     if (::mount(sourceDir, targetDir, nullptr, MS_BIND, nullptr)) {
1393*9190c2a8SAndroid Build Coastguard Worker         PLOG(ERROR) << "[incfs] Failed to bind mount '" << sourceDir << "' to '" << targetDir
1394*9190c2a8SAndroid Build Coastguard Worker                     << '\'';
1395*9190c2a8SAndroid Build Coastguard Worker         return -errno;
1396*9190c2a8SAndroid Build Coastguard Worker     }
1397*9190c2a8SAndroid Build Coastguard Worker     return 0;
1398*9190c2a8SAndroid Build Coastguard Worker }
1399*9190c2a8SAndroid Build Coastguard Worker 
IncFs_Unmount(const char * dir)1400*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_Unmount(const char* dir) {
1401*9190c2a8SAndroid Build Coastguard Worker     if (!enabled()) {
1402*9190c2a8SAndroid Build Coastguard Worker         return -ENOTSUP;
1403*9190c2a8SAndroid Build Coastguard Worker     }
1404*9190c2a8SAndroid Build Coastguard Worker     if (!isIncFsPathImpl(dir)) {
1405*9190c2a8SAndroid Build Coastguard Worker         LOG(WARNING) << __func__ << ": umount() called on non-incfs directory '" << dir << '\'';
1406*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1407*9190c2a8SAndroid Build Coastguard Worker     }
1408*9190c2a8SAndroid Build Coastguard Worker 
1409*9190c2a8SAndroid Build Coastguard Worker     errno = 0;
1410*9190c2a8SAndroid Build Coastguard Worker     if (::umount2(dir, MNT_FORCE) == 0 || errno == EINVAL || errno == ENOENT) {
1411*9190c2a8SAndroid Build Coastguard Worker         // EINVAL - not a mount point, ENOENT - doesn't exist at all
1412*9190c2a8SAndroid Build Coastguard Worker         if (errno == 0) {
1413*9190c2a8SAndroid Build Coastguard Worker             LOG(INFO) << __func__ << ": succeeded on the first try for '" << dir << '\'';
1414*9190c2a8SAndroid Build Coastguard Worker         }
1415*9190c2a8SAndroid Build Coastguard Worker         return -errno;
1416*9190c2a8SAndroid Build Coastguard Worker     }
1417*9190c2a8SAndroid Build Coastguard Worker     errno = 0;
1418*9190c2a8SAndroid Build Coastguard Worker     if (!::umount2(dir, MNT_DETACH)) {
1419*9190c2a8SAndroid Build Coastguard Worker         return 0;
1420*9190c2a8SAndroid Build Coastguard Worker     }
1421*9190c2a8SAndroid Build Coastguard Worker     PLOG(WARNING) << __func__ << ": umount(detach) returned non-zero for '" << dir << '\'';
1422*9190c2a8SAndroid Build Coastguard Worker     return 0;
1423*9190c2a8SAndroid Build Coastguard Worker }
1424*9190c2a8SAndroid Build Coastguard Worker 
IncFs_IsIncFsFd(int fd)1425*9190c2a8SAndroid Build Coastguard Worker bool IncFs_IsIncFsFd(int fd) {
1426*9190c2a8SAndroid Build Coastguard Worker     return isIncFsFdImpl(fd);
1427*9190c2a8SAndroid Build Coastguard Worker }
1428*9190c2a8SAndroid Build Coastguard Worker 
IncFs_IsIncFsPath(const char * path)1429*9190c2a8SAndroid Build Coastguard Worker bool IncFs_IsIncFsPath(const char* path) {
1430*9190c2a8SAndroid Build Coastguard Worker     return isIncFsPathImpl(path);
1431*9190c2a8SAndroid Build Coastguard Worker }
1432*9190c2a8SAndroid Build Coastguard Worker 
IncFs_GetFilledRanges(int fd,IncFsSpan outBuffer,IncFsFilledRanges * filledRanges)1433*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_GetFilledRanges(int fd, IncFsSpan outBuffer, IncFsFilledRanges* filledRanges) {
1434*9190c2a8SAndroid Build Coastguard Worker     return IncFs_GetFilledRangesStartingFrom(fd, 0, outBuffer, filledRanges);
1435*9190c2a8SAndroid Build Coastguard Worker }
1436*9190c2a8SAndroid Build Coastguard Worker 
IncFs_GetFilledRangesStartingFrom(int fd,int startBlockIndex,IncFsSpan outBuffer,IncFsFilledRanges * filledRanges)1437*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_GetFilledRangesStartingFrom(int fd, int startBlockIndex, IncFsSpan outBuffer,
1438*9190c2a8SAndroid Build Coastguard Worker                                                  IncFsFilledRanges* filledRanges) {
1439*9190c2a8SAndroid Build Coastguard Worker     if (fd < 0) {
1440*9190c2a8SAndroid Build Coastguard Worker         return -EBADF;
1441*9190c2a8SAndroid Build Coastguard Worker     }
1442*9190c2a8SAndroid Build Coastguard Worker     if (startBlockIndex < 0) {
1443*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1444*9190c2a8SAndroid Build Coastguard Worker     }
1445*9190c2a8SAndroid Build Coastguard Worker     if (!outBuffer.data && outBuffer.size > 0) {
1446*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1447*9190c2a8SAndroid Build Coastguard Worker     }
1448*9190c2a8SAndroid Build Coastguard Worker     if (!filledRanges) {
1449*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1450*9190c2a8SAndroid Build Coastguard Worker     }
1451*9190c2a8SAndroid Build Coastguard Worker     // Use this to optimize the incfs call and have the same buffer for both the incfs and the
1452*9190c2a8SAndroid Build Coastguard Worker     // public structs.
1453*9190c2a8SAndroid Build Coastguard Worker     static_assert(sizeof(IncFsBlockRange) == sizeof(incfs_filled_range));
1454*9190c2a8SAndroid Build Coastguard Worker 
1455*9190c2a8SAndroid Build Coastguard Worker     *filledRanges = {};
1456*9190c2a8SAndroid Build Coastguard Worker 
1457*9190c2a8SAndroid Build Coastguard Worker     auto outStart = (IncFsBlockRange*)outBuffer.data;
1458*9190c2a8SAndroid Build Coastguard Worker     auto outEnd = outStart + outBuffer.size / sizeof(*outStart);
1459*9190c2a8SAndroid Build Coastguard Worker 
1460*9190c2a8SAndroid Build Coastguard Worker     auto outPtr = outStart;
1461*9190c2a8SAndroid Build Coastguard Worker     int error = 0;
1462*9190c2a8SAndroid Build Coastguard Worker     int dataBlocks;
1463*9190c2a8SAndroid Build Coastguard Worker     incfs_get_filled_blocks_args args = {};
1464*9190c2a8SAndroid Build Coastguard Worker     for (;;) {
1465*9190c2a8SAndroid Build Coastguard Worker         auto start = args.index_out ? args.index_out : startBlockIndex;
1466*9190c2a8SAndroid Build Coastguard Worker         args = incfs_get_filled_blocks_args{
1467*9190c2a8SAndroid Build Coastguard Worker                 .range_buffer = (uint64_t)(uintptr_t)outPtr,
1468*9190c2a8SAndroid Build Coastguard Worker                 .range_buffer_size = uint32_t((outEnd - outPtr) * sizeof(*outPtr)),
1469*9190c2a8SAndroid Build Coastguard Worker                 .start_index = start,
1470*9190c2a8SAndroid Build Coastguard Worker         };
1471*9190c2a8SAndroid Build Coastguard Worker         errno = 0;
1472*9190c2a8SAndroid Build Coastguard Worker         auto res = ::ioctl(fd, INCFS_IOC_GET_FILLED_BLOCKS, &args);
1473*9190c2a8SAndroid Build Coastguard Worker         error = errno;
1474*9190c2a8SAndroid Build Coastguard Worker         if (res && error != EINTR && error != ERANGE) {
1475*9190c2a8SAndroid Build Coastguard Worker             return -error;
1476*9190c2a8SAndroid Build Coastguard Worker         }
1477*9190c2a8SAndroid Build Coastguard Worker 
1478*9190c2a8SAndroid Build Coastguard Worker         dataBlocks = args.data_blocks_out;
1479*9190c2a8SAndroid Build Coastguard Worker         outPtr += args.range_buffer_size_out / sizeof(incfs_filled_range);
1480*9190c2a8SAndroid Build Coastguard Worker         if (!res || error == ERANGE) {
1481*9190c2a8SAndroid Build Coastguard Worker             break;
1482*9190c2a8SAndroid Build Coastguard Worker         }
1483*9190c2a8SAndroid Build Coastguard Worker         // in case of EINTR we want to continue calling the function
1484*9190c2a8SAndroid Build Coastguard Worker     }
1485*9190c2a8SAndroid Build Coastguard Worker 
1486*9190c2a8SAndroid Build Coastguard Worker     if (outPtr > outEnd) {
1487*9190c2a8SAndroid Build Coastguard Worker         outPtr = outEnd;
1488*9190c2a8SAndroid Build Coastguard Worker         error = ERANGE;
1489*9190c2a8SAndroid Build Coastguard Worker     }
1490*9190c2a8SAndroid Build Coastguard Worker 
1491*9190c2a8SAndroid Build Coastguard Worker     filledRanges->endIndex = args.index_out;
1492*9190c2a8SAndroid Build Coastguard Worker     auto hashStartPtr = outPtr;
1493*9190c2a8SAndroid Build Coastguard Worker     if (outPtr != outStart) {
1494*9190c2a8SAndroid Build Coastguard Worker         // figure out the ranges for data block and hash blocks in the output
1495*9190c2a8SAndroid Build Coastguard Worker         for (; hashStartPtr != outStart; --hashStartPtr) {
1496*9190c2a8SAndroid Build Coastguard Worker             if ((hashStartPtr - 1)->begin < dataBlocks) {
1497*9190c2a8SAndroid Build Coastguard Worker                 break;
1498*9190c2a8SAndroid Build Coastguard Worker             }
1499*9190c2a8SAndroid Build Coastguard Worker         }
1500*9190c2a8SAndroid Build Coastguard Worker         auto lastDataPtr = hashStartPtr - 1;
1501*9190c2a8SAndroid Build Coastguard Worker         // here we go, this is the first block that's before or at the hashes
1502*9190c2a8SAndroid Build Coastguard Worker         if (lastDataPtr->end <= dataBlocks) {
1503*9190c2a8SAndroid Build Coastguard Worker             ; // we're good, the boundary is between the ranges - |hashStartPtr| is correct
1504*9190c2a8SAndroid Build Coastguard Worker         } else {
1505*9190c2a8SAndroid Build Coastguard Worker             // the hard part: split the |lastDataPtr| range into the data and the hash pieces
1506*9190c2a8SAndroid Build Coastguard Worker             if (outPtr == outEnd) {
1507*9190c2a8SAndroid Build Coastguard Worker                 // the buffer turned out to be too small, even though it actually wasn't
1508*9190c2a8SAndroid Build Coastguard Worker                 error = ERANGE;
1509*9190c2a8SAndroid Build Coastguard Worker                 if (hashStartPtr == outEnd) {
1510*9190c2a8SAndroid Build Coastguard Worker                     // this is even worse: there's no room to put even a single hash block into.
1511*9190c2a8SAndroid Build Coastguard Worker                     filledRanges->endIndex = lastDataPtr->end = dataBlocks;
1512*9190c2a8SAndroid Build Coastguard Worker                 } else {
1513*9190c2a8SAndroid Build Coastguard Worker                     std::copy_backward(lastDataPtr, outPtr - 1, outPtr);
1514*9190c2a8SAndroid Build Coastguard Worker                     lastDataPtr->end = hashStartPtr->begin = dataBlocks;
1515*9190c2a8SAndroid Build Coastguard Worker                     filledRanges->endIndex = (outPtr - 1)->end;
1516*9190c2a8SAndroid Build Coastguard Worker                 }
1517*9190c2a8SAndroid Build Coastguard Worker             } else {
1518*9190c2a8SAndroid Build Coastguard Worker                 std::copy_backward(lastDataPtr, outPtr, outPtr + 1);
1519*9190c2a8SAndroid Build Coastguard Worker                 lastDataPtr->end = hashStartPtr->begin = dataBlocks;
1520*9190c2a8SAndroid Build Coastguard Worker                 ++outPtr;
1521*9190c2a8SAndroid Build Coastguard Worker             }
1522*9190c2a8SAndroid Build Coastguard Worker         }
1523*9190c2a8SAndroid Build Coastguard Worker         // now fix the indices of all hash blocks - no one should know they're simply past the
1524*9190c2a8SAndroid Build Coastguard Worker         // regular data blocks in the file!
1525*9190c2a8SAndroid Build Coastguard Worker         for (auto ptr = hashStartPtr; ptr != outPtr; ++ptr) {
1526*9190c2a8SAndroid Build Coastguard Worker             ptr->begin -= dataBlocks;
1527*9190c2a8SAndroid Build Coastguard Worker             ptr->end -= dataBlocks;
1528*9190c2a8SAndroid Build Coastguard Worker         }
1529*9190c2a8SAndroid Build Coastguard Worker     }
1530*9190c2a8SAndroid Build Coastguard Worker 
1531*9190c2a8SAndroid Build Coastguard Worker     filledRanges->dataRanges = outStart;
1532*9190c2a8SAndroid Build Coastguard Worker     filledRanges->dataRangesCount = hashStartPtr - outStart;
1533*9190c2a8SAndroid Build Coastguard Worker     filledRanges->hashRanges = hashStartPtr;
1534*9190c2a8SAndroid Build Coastguard Worker     filledRanges->hashRangesCount = outPtr - hashStartPtr;
1535*9190c2a8SAndroid Build Coastguard Worker 
1536*9190c2a8SAndroid Build Coastguard Worker     return -error;
1537*9190c2a8SAndroid Build Coastguard Worker }
1538*9190c2a8SAndroid Build Coastguard Worker 
isFullyLoadedV2(std::string_view root,IncFsFileId id)1539*9190c2a8SAndroid Build Coastguard Worker static IncFsErrorCode isFullyLoadedV2(std::string_view root, IncFsFileId id) {
1540*9190c2a8SAndroid Build Coastguard Worker     if (::access(path::join(root, INCFS_INCOMPLETE_NAME, toStringImpl(id)).c_str(), F_OK)) {
1541*9190c2a8SAndroid Build Coastguard Worker         if (errno == ENOENT) {
1542*9190c2a8SAndroid Build Coastguard Worker             return 0; // no such incomplete file -> it's fully loaded.
1543*9190c2a8SAndroid Build Coastguard Worker         }
1544*9190c2a8SAndroid Build Coastguard Worker         return -errno;
1545*9190c2a8SAndroid Build Coastguard Worker     }
1546*9190c2a8SAndroid Build Coastguard Worker     return -ENODATA;
1547*9190c2a8SAndroid Build Coastguard Worker }
1548*9190c2a8SAndroid Build Coastguard Worker 
isFullyLoadedSlow(int fd)1549*9190c2a8SAndroid Build Coastguard Worker static IncFsErrorCode isFullyLoadedSlow(int fd) {
1550*9190c2a8SAndroid Build Coastguard Worker     char buffer[2 * sizeof(IncFsBlockRange)];
1551*9190c2a8SAndroid Build Coastguard Worker     IncFsFilledRanges ranges;
1552*9190c2a8SAndroid Build Coastguard Worker     auto res = IncFs_GetFilledRanges(fd, IncFsSpan{.data = buffer, .size = std::size(buffer)},
1553*9190c2a8SAndroid Build Coastguard Worker                                      &ranges);
1554*9190c2a8SAndroid Build Coastguard Worker     if (res == -ERANGE) {
1555*9190c2a8SAndroid Build Coastguard Worker         // need room for more than two ranges - definitely not fully loaded
1556*9190c2a8SAndroid Build Coastguard Worker         return -ENODATA;
1557*9190c2a8SAndroid Build Coastguard Worker     }
1558*9190c2a8SAndroid Build Coastguard Worker     if (res != 0) {
1559*9190c2a8SAndroid Build Coastguard Worker         return res;
1560*9190c2a8SAndroid Build Coastguard Worker     }
1561*9190c2a8SAndroid Build Coastguard Worker     // empty file
1562*9190c2a8SAndroid Build Coastguard Worker     if (ranges.endIndex == 0) {
1563*9190c2a8SAndroid Build Coastguard Worker         return 0;
1564*9190c2a8SAndroid Build Coastguard Worker     }
1565*9190c2a8SAndroid Build Coastguard Worker     // file with no hash tree
1566*9190c2a8SAndroid Build Coastguard Worker     if (ranges.dataRangesCount == 1 && ranges.hashRangesCount == 0) {
1567*9190c2a8SAndroid Build Coastguard Worker         return (ranges.dataRanges[0].begin == 0 && ranges.dataRanges[0].end == ranges.endIndex)
1568*9190c2a8SAndroid Build Coastguard Worker                 ? 0
1569*9190c2a8SAndroid Build Coastguard Worker                 : -ENODATA;
1570*9190c2a8SAndroid Build Coastguard Worker     }
1571*9190c2a8SAndroid Build Coastguard Worker     // file with a hash tree
1572*9190c2a8SAndroid Build Coastguard Worker     if (ranges.dataRangesCount == 1 && ranges.hashRangesCount == 1) {
1573*9190c2a8SAndroid Build Coastguard Worker         // calculate the expected data size from the size of the hash range and |endIndex|, which is
1574*9190c2a8SAndroid Build Coastguard Worker         // the total number of blocks in the file, both data and hash blocks together.
1575*9190c2a8SAndroid Build Coastguard Worker         if (ranges.hashRanges[0].begin != 0) {
1576*9190c2a8SAndroid Build Coastguard Worker             return -ENODATA;
1577*9190c2a8SAndroid Build Coastguard Worker         }
1578*9190c2a8SAndroid Build Coastguard Worker         const auto expectedDataBlocks =
1579*9190c2a8SAndroid Build Coastguard Worker                 ranges.endIndex - (ranges.hashRanges[0].end - ranges.hashRanges[0].begin);
1580*9190c2a8SAndroid Build Coastguard Worker         return (ranges.dataRanges[0].begin == 0 && ranges.dataRanges[0].end == expectedDataBlocks)
1581*9190c2a8SAndroid Build Coastguard Worker                 ? 0
1582*9190c2a8SAndroid Build Coastguard Worker                 : -ENODATA;
1583*9190c2a8SAndroid Build Coastguard Worker     }
1584*9190c2a8SAndroid Build Coastguard Worker     return -ENODATA;
1585*9190c2a8SAndroid Build Coastguard Worker }
1586*9190c2a8SAndroid Build Coastguard Worker 
IncFs_IsFullyLoaded(int fd)1587*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_IsFullyLoaded(int fd) {
1588*9190c2a8SAndroid Build Coastguard Worker     if (features() & Features::v2) {
1589*9190c2a8SAndroid Build Coastguard Worker         const auto fdPath = path::fromFd(fd);
1590*9190c2a8SAndroid Build Coastguard Worker         if (fdPath.empty()) {
1591*9190c2a8SAndroid Build Coastguard Worker             return errno ? -errno : -EINVAL;
1592*9190c2a8SAndroid Build Coastguard Worker         }
1593*9190c2a8SAndroid Build Coastguard Worker         const auto id = getId(::fgetxattr, fd);
1594*9190c2a8SAndroid Build Coastguard Worker         if (id == kIncFsInvalidFileId) {
1595*9190c2a8SAndroid Build Coastguard Worker             return -errno;
1596*9190c2a8SAndroid Build Coastguard Worker         }
1597*9190c2a8SAndroid Build Coastguard Worker         return isFullyLoadedV2(registry().rootFor(fdPath), id);
1598*9190c2a8SAndroid Build Coastguard Worker     }
1599*9190c2a8SAndroid Build Coastguard Worker     return isFullyLoadedSlow(fd);
1600*9190c2a8SAndroid Build Coastguard Worker }
IncFs_IsFullyLoadedByPath(const IncFsControl * control,const char * path)1601*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_IsFullyLoadedByPath(const IncFsControl* control, const char* path) {
1602*9190c2a8SAndroid Build Coastguard Worker     if (!control || !path) {
1603*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1604*9190c2a8SAndroid Build Coastguard Worker     }
1605*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(control->cmd);
1606*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
1607*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1608*9190c2a8SAndroid Build Coastguard Worker     }
1609*9190c2a8SAndroid Build Coastguard Worker     const auto pathRoot = registry().rootFor(path);
1610*9190c2a8SAndroid Build Coastguard Worker     if (pathRoot != root) {
1611*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1612*9190c2a8SAndroid Build Coastguard Worker     }
1613*9190c2a8SAndroid Build Coastguard Worker     if (features() & Features::v2) {
1614*9190c2a8SAndroid Build Coastguard Worker         const auto id = getId(::getxattr, path);
1615*9190c2a8SAndroid Build Coastguard Worker         if (id == kIncFsInvalidFileId) {
1616*9190c2a8SAndroid Build Coastguard Worker             return -ENOTSUP;
1617*9190c2a8SAndroid Build Coastguard Worker         }
1618*9190c2a8SAndroid Build Coastguard Worker         return isFullyLoadedV2(root, id);
1619*9190c2a8SAndroid Build Coastguard Worker     }
1620*9190c2a8SAndroid Build Coastguard Worker     auto fd = ab::unique_fd(openForSpecialOps(control->cmd, makeCommandPath(root, path).c_str()));
1621*9190c2a8SAndroid Build Coastguard Worker     return isFullyLoadedSlow(fd.get());
1622*9190c2a8SAndroid Build Coastguard Worker }
IncFs_IsFullyLoadedById(const IncFsControl * control,IncFsFileId fileId)1623*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_IsFullyLoadedById(const IncFsControl* control, IncFsFileId fileId) {
1624*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
1625*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1626*9190c2a8SAndroid Build Coastguard Worker     }
1627*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(control->cmd);
1628*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
1629*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1630*9190c2a8SAndroid Build Coastguard Worker     }
1631*9190c2a8SAndroid Build Coastguard Worker     if (features() & Features::v2) {
1632*9190c2a8SAndroid Build Coastguard Worker         return isFullyLoadedV2(root, fileId);
1633*9190c2a8SAndroid Build Coastguard Worker     }
1634*9190c2a8SAndroid Build Coastguard Worker     auto fd = ab::unique_fd(
1635*9190c2a8SAndroid Build Coastguard Worker             openForSpecialOps(control->cmd,
1636*9190c2a8SAndroid Build Coastguard Worker                               makeCommandPath(root, indexPath(root, fileId)).c_str()));
1637*9190c2a8SAndroid Build Coastguard Worker     return isFullyLoadedSlow(fd.get());
1638*9190c2a8SAndroid Build Coastguard Worker }
1639*9190c2a8SAndroid Build Coastguard Worker 
isEverythingLoadedV2(const IncFsControl * control)1640*9190c2a8SAndroid Build Coastguard Worker static IncFsErrorCode isEverythingLoadedV2(const IncFsControl* control) {
1641*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(control->cmd);
1642*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
1643*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1644*9190c2a8SAndroid Build Coastguard Worker     }
1645*9190c2a8SAndroid Build Coastguard Worker     auto res = forEachFileIn(path::join(root, INCFS_INCOMPLETE_NAME), [](auto) { return false; });
1646*9190c2a8SAndroid Build Coastguard Worker     return res < 0 ? res : res > 0 ? -ENODATA : 0;
1647*9190c2a8SAndroid Build Coastguard Worker }
1648*9190c2a8SAndroid Build Coastguard Worker 
isEverythingLoadedSlow(const IncFsControl * control)1649*9190c2a8SAndroid Build Coastguard Worker static IncFsErrorCode isEverythingLoadedSlow(const IncFsControl* control) {
1650*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(control->cmd);
1651*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
1652*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1653*9190c2a8SAndroid Build Coastguard Worker     }
1654*9190c2a8SAndroid Build Coastguard Worker     // No special API for this version of the driver, need to recurse and check each file
1655*9190c2a8SAndroid Build Coastguard Worker     // separately. Can at least speed it up by iterating over the .index/ dir and not dealing with
1656*9190c2a8SAndroid Build Coastguard Worker     // the directory tree.
1657*9190c2a8SAndroid Build Coastguard Worker     const auto indexPath = path::join(root, INCFS_INDEX_NAME);
1658*9190c2a8SAndroid Build Coastguard Worker     const auto dir = path::openDir(indexPath.c_str());
1659*9190c2a8SAndroid Build Coastguard Worker     if (!dir) {
1660*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1661*9190c2a8SAndroid Build Coastguard Worker     }
1662*9190c2a8SAndroid Build Coastguard Worker     while (const auto entry = ::readdir(dir.get())) {
1663*9190c2a8SAndroid Build Coastguard Worker         if (entry->d_type != DT_REG) {
1664*9190c2a8SAndroid Build Coastguard Worker             continue;
1665*9190c2a8SAndroid Build Coastguard Worker         }
1666*9190c2a8SAndroid Build Coastguard Worker         const auto name = path::join(indexPath, entry->d_name);
1667*9190c2a8SAndroid Build Coastguard Worker         auto fd =
1668*9190c2a8SAndroid Build Coastguard Worker                 ab::unique_fd(openForSpecialOps(control->cmd, makeCommandPath(root, name).c_str()));
1669*9190c2a8SAndroid Build Coastguard Worker         if (fd.get() < 0) {
1670*9190c2a8SAndroid Build Coastguard Worker             PLOG(WARNING) << __func__ << "(): can't open " << entry->d_name << " for special ops";
1671*9190c2a8SAndroid Build Coastguard Worker             return fd.release();
1672*9190c2a8SAndroid Build Coastguard Worker         }
1673*9190c2a8SAndroid Build Coastguard Worker         const auto checkFullyLoaded = IncFs_IsFullyLoaded(fd.get());
1674*9190c2a8SAndroid Build Coastguard Worker         if (checkFullyLoaded == 0 || checkFullyLoaded == -EOPNOTSUPP ||
1675*9190c2a8SAndroid Build Coastguard Worker             checkFullyLoaded == -ENOTSUP || checkFullyLoaded == -ENOENT) {
1676*9190c2a8SAndroid Build Coastguard Worker             // special kinds of files may return an error here, but it still means
1677*9190c2a8SAndroid Build Coastguard Worker             // _this_ file is OK - you simply need to check the rest. E.g. can't query
1678*9190c2a8SAndroid Build Coastguard Worker             // a mapped file, instead need to check its parent.
1679*9190c2a8SAndroid Build Coastguard Worker             continue;
1680*9190c2a8SAndroid Build Coastguard Worker         }
1681*9190c2a8SAndroid Build Coastguard Worker         return checkFullyLoaded;
1682*9190c2a8SAndroid Build Coastguard Worker     }
1683*9190c2a8SAndroid Build Coastguard Worker     return 0;
1684*9190c2a8SAndroid Build Coastguard Worker }
1685*9190c2a8SAndroid Build Coastguard Worker 
IncFs_IsEverythingFullyLoaded(const IncFsControl * control)1686*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_IsEverythingFullyLoaded(const IncFsControl* control) {
1687*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
1688*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1689*9190c2a8SAndroid Build Coastguard Worker     }
1690*9190c2a8SAndroid Build Coastguard Worker     if (features() & Features::v2) {
1691*9190c2a8SAndroid Build Coastguard Worker         return isEverythingLoadedV2(control);
1692*9190c2a8SAndroid Build Coastguard Worker     }
1693*9190c2a8SAndroid Build Coastguard Worker     return isEverythingLoadedSlow(control);
1694*9190c2a8SAndroid Build Coastguard Worker }
1695*9190c2a8SAndroid Build Coastguard Worker 
IncFs_SetUidReadTimeouts(const IncFsControl * control,const IncFsUidReadTimeouts timeouts[],size_t count)1696*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_SetUidReadTimeouts(const IncFsControl* control,
1697*9190c2a8SAndroid Build Coastguard Worker                                         const IncFsUidReadTimeouts timeouts[], size_t count) {
1698*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
1699*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1700*9190c2a8SAndroid Build Coastguard Worker     }
1701*9190c2a8SAndroid Build Coastguard Worker     if (!(features() & Features::v2)) {
1702*9190c2a8SAndroid Build Coastguard Worker         return -ENOTSUP;
1703*9190c2a8SAndroid Build Coastguard Worker     }
1704*9190c2a8SAndroid Build Coastguard Worker 
1705*9190c2a8SAndroid Build Coastguard Worker     std::vector<incfs_per_uid_read_timeouts> argTimeouts(count);
1706*9190c2a8SAndroid Build Coastguard Worker     for (size_t i = 0; i != count; ++i) {
1707*9190c2a8SAndroid Build Coastguard Worker         argTimeouts[i] = incfs_per_uid_read_timeouts{
1708*9190c2a8SAndroid Build Coastguard Worker                 .uid = (uint32_t)timeouts[i].uid,
1709*9190c2a8SAndroid Build Coastguard Worker                 .min_time_us = timeouts[i].minTimeUs,
1710*9190c2a8SAndroid Build Coastguard Worker                 .min_pending_time_us = timeouts[i].minPendingTimeUs,
1711*9190c2a8SAndroid Build Coastguard Worker                 .max_pending_time_us = timeouts[i].maxPendingTimeUs,
1712*9190c2a8SAndroid Build Coastguard Worker         };
1713*9190c2a8SAndroid Build Coastguard Worker     }
1714*9190c2a8SAndroid Build Coastguard Worker     incfs_set_read_timeouts_args args = {.timeouts_array = (uint64_t)(uintptr_t)argTimeouts.data(),
1715*9190c2a8SAndroid Build Coastguard Worker                                          .timeouts_array_size = uint32_t(
1716*9190c2a8SAndroid Build Coastguard Worker                                                  argTimeouts.size() * sizeof(*argTimeouts.data()))};
1717*9190c2a8SAndroid Build Coastguard Worker     if (::ioctl(control->cmd, INCFS_IOC_SET_READ_TIMEOUTS, &args)) {
1718*9190c2a8SAndroid Build Coastguard Worker         PLOG(WARNING) << "[incfs] setUidReadTimeouts failed";
1719*9190c2a8SAndroid Build Coastguard Worker         return -errno;
1720*9190c2a8SAndroid Build Coastguard Worker     }
1721*9190c2a8SAndroid Build Coastguard Worker     return 0;
1722*9190c2a8SAndroid Build Coastguard Worker }
1723*9190c2a8SAndroid Build Coastguard Worker 
IncFs_GetUidReadTimeouts(const IncFsControl * control,IncFsUidReadTimeouts timeouts[],size_t * bufferSize)1724*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_GetUidReadTimeouts(const IncFsControl* control,
1725*9190c2a8SAndroid Build Coastguard Worker                                         IncFsUidReadTimeouts timeouts[], size_t* bufferSize) {
1726*9190c2a8SAndroid Build Coastguard Worker     if (!control || !bufferSize) {
1727*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1728*9190c2a8SAndroid Build Coastguard Worker     }
1729*9190c2a8SAndroid Build Coastguard Worker     if (!(features() & Features::v2)) {
1730*9190c2a8SAndroid Build Coastguard Worker         return -ENOTSUP;
1731*9190c2a8SAndroid Build Coastguard Worker     }
1732*9190c2a8SAndroid Build Coastguard Worker 
1733*9190c2a8SAndroid Build Coastguard Worker     std::vector<incfs_per_uid_read_timeouts> argTimeouts(*bufferSize);
1734*9190c2a8SAndroid Build Coastguard Worker     incfs_get_read_timeouts_args args = {.timeouts_array = (uint64_t)(uintptr_t)argTimeouts.data(),
1735*9190c2a8SAndroid Build Coastguard Worker                                          .timeouts_array_size = uint32_t(
1736*9190c2a8SAndroid Build Coastguard Worker                                                  argTimeouts.size() * sizeof(*argTimeouts.data())),
1737*9190c2a8SAndroid Build Coastguard Worker                                          .timeouts_array_size_out = args.timeouts_array_size};
1738*9190c2a8SAndroid Build Coastguard Worker     if (::ioctl(control->cmd, INCFS_IOC_GET_READ_TIMEOUTS, &args)) {
1739*9190c2a8SAndroid Build Coastguard Worker         if (errno == E2BIG) {
1740*9190c2a8SAndroid Build Coastguard Worker             *bufferSize = args.timeouts_array_size_out / sizeof(*argTimeouts.data());
1741*9190c2a8SAndroid Build Coastguard Worker         }
1742*9190c2a8SAndroid Build Coastguard Worker         return -errno;
1743*9190c2a8SAndroid Build Coastguard Worker     }
1744*9190c2a8SAndroid Build Coastguard Worker 
1745*9190c2a8SAndroid Build Coastguard Worker     *bufferSize = args.timeouts_array_size_out / sizeof(*argTimeouts.data());
1746*9190c2a8SAndroid Build Coastguard Worker     for (size_t i = 0; i != *bufferSize; ++i) {
1747*9190c2a8SAndroid Build Coastguard Worker         timeouts[i].uid = argTimeouts[i].uid;
1748*9190c2a8SAndroid Build Coastguard Worker         timeouts[i].minTimeUs = argTimeouts[i].min_time_us;
1749*9190c2a8SAndroid Build Coastguard Worker         timeouts[i].minPendingTimeUs = argTimeouts[i].min_pending_time_us;
1750*9190c2a8SAndroid Build Coastguard Worker         timeouts[i].maxPendingTimeUs = argTimeouts[i].max_pending_time_us;
1751*9190c2a8SAndroid Build Coastguard Worker     }
1752*9190c2a8SAndroid Build Coastguard Worker     return 0;
1753*9190c2a8SAndroid Build Coastguard Worker }
1754*9190c2a8SAndroid Build Coastguard Worker 
1755*9190c2a8SAndroid Build Coastguard Worker // Trying to detect if this is a mapped file.
1756*9190c2a8SAndroid Build Coastguard Worker // Not the best way as it might return true for other system files.
1757*9190c2a8SAndroid Build Coastguard Worker // TODO: remove after IncFS returns ENOTSUP for such files.
isMapped(int fd)1758*9190c2a8SAndroid Build Coastguard Worker static bool isMapped(int fd) {
1759*9190c2a8SAndroid Build Coastguard Worker     char buffer[kIncFsFileIdStringLength];
1760*9190c2a8SAndroid Build Coastguard Worker     const auto res = ::fgetxattr(fd, kIdAttrName, buffer, sizeof(buffer));
1761*9190c2a8SAndroid Build Coastguard Worker     return res != sizeof(buffer);
1762*9190c2a8SAndroid Build Coastguard Worker }
1763*9190c2a8SAndroid Build Coastguard Worker 
getFileBlockCount(int fd,IncFsBlockCounts * blockCount)1764*9190c2a8SAndroid Build Coastguard Worker static IncFsErrorCode getFileBlockCount(int fd, IncFsBlockCounts* blockCount) {
1765*9190c2a8SAndroid Build Coastguard Worker     if (isMapped(fd)) {
1766*9190c2a8SAndroid Build Coastguard Worker         return -ENOTSUP;
1767*9190c2a8SAndroid Build Coastguard Worker     }
1768*9190c2a8SAndroid Build Coastguard Worker 
1769*9190c2a8SAndroid Build Coastguard Worker     incfs_get_block_count_args args = {};
1770*9190c2a8SAndroid Build Coastguard Worker     auto res = ::ioctl(fd, INCFS_IOC_GET_BLOCK_COUNT, &args);
1771*9190c2a8SAndroid Build Coastguard Worker     if (res < 0) {
1772*9190c2a8SAndroid Build Coastguard Worker         return -errno;
1773*9190c2a8SAndroid Build Coastguard Worker     }
1774*9190c2a8SAndroid Build Coastguard Worker     *blockCount = IncFsBlockCounts{
1775*9190c2a8SAndroid Build Coastguard Worker             .totalDataBlocks = args.total_data_blocks_out,
1776*9190c2a8SAndroid Build Coastguard Worker             .filledDataBlocks = args.filled_data_blocks_out,
1777*9190c2a8SAndroid Build Coastguard Worker             .totalHashBlocks = args.total_hash_blocks_out,
1778*9190c2a8SAndroid Build Coastguard Worker             .filledHashBlocks = args.filled_hash_blocks_out,
1779*9190c2a8SAndroid Build Coastguard Worker     };
1780*9190c2a8SAndroid Build Coastguard Worker     return 0;
1781*9190c2a8SAndroid Build Coastguard Worker }
1782*9190c2a8SAndroid Build Coastguard Worker 
IncFs_GetFileBlockCountById(const IncFsControl * control,IncFsFileId id,IncFsBlockCounts * blockCount)1783*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_GetFileBlockCountById(const IncFsControl* control, IncFsFileId id,
1784*9190c2a8SAndroid Build Coastguard Worker                                            IncFsBlockCounts* blockCount) {
1785*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
1786*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1787*9190c2a8SAndroid Build Coastguard Worker     }
1788*9190c2a8SAndroid Build Coastguard Worker     if (!(features() & Features::v2)) {
1789*9190c2a8SAndroid Build Coastguard Worker         return -ENOTSUP;
1790*9190c2a8SAndroid Build Coastguard Worker     }
1791*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(control->cmd);
1792*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
1793*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1794*9190c2a8SAndroid Build Coastguard Worker     }
1795*9190c2a8SAndroid Build Coastguard Worker     auto name = indexPath(root, id);
1796*9190c2a8SAndroid Build Coastguard Worker     auto fd = openRaw(name);
1797*9190c2a8SAndroid Build Coastguard Worker     if (fd < 0) {
1798*9190c2a8SAndroid Build Coastguard Worker         return fd.get();
1799*9190c2a8SAndroid Build Coastguard Worker     }
1800*9190c2a8SAndroid Build Coastguard Worker     return getFileBlockCount(fd, blockCount);
1801*9190c2a8SAndroid Build Coastguard Worker }
1802*9190c2a8SAndroid Build Coastguard Worker 
IncFs_GetFileBlockCountByPath(const IncFsControl * control,const char * path,IncFsBlockCounts * blockCount)1803*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_GetFileBlockCountByPath(const IncFsControl* control, const char* path,
1804*9190c2a8SAndroid Build Coastguard Worker                                              IncFsBlockCounts* blockCount) {
1805*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
1806*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1807*9190c2a8SAndroid Build Coastguard Worker     }
1808*9190c2a8SAndroid Build Coastguard Worker     if (!(features() & Features::v2)) {
1809*9190c2a8SAndroid Build Coastguard Worker         return -ENOTSUP;
1810*9190c2a8SAndroid Build Coastguard Worker     }
1811*9190c2a8SAndroid Build Coastguard Worker     const auto pathRoot = registry().rootFor(path);
1812*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(control->cmd);
1813*9190c2a8SAndroid Build Coastguard Worker     if (root.empty() || root != pathRoot) {
1814*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1815*9190c2a8SAndroid Build Coastguard Worker     }
1816*9190c2a8SAndroid Build Coastguard Worker     auto fd = openRaw(path);
1817*9190c2a8SAndroid Build Coastguard Worker     if (fd < 0) {
1818*9190c2a8SAndroid Build Coastguard Worker         return fd.get();
1819*9190c2a8SAndroid Build Coastguard Worker     }
1820*9190c2a8SAndroid Build Coastguard Worker     return getFileBlockCount(fd, blockCount);
1821*9190c2a8SAndroid Build Coastguard Worker }
1822*9190c2a8SAndroid Build Coastguard Worker 
IncFs_ListIncompleteFiles(const IncFsControl * control,IncFsFileId ids[],size_t * bufferSize)1823*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_ListIncompleteFiles(const IncFsControl* control, IncFsFileId ids[],
1824*9190c2a8SAndroid Build Coastguard Worker                                          size_t* bufferSize) {
1825*9190c2a8SAndroid Build Coastguard Worker     if (!control || !bufferSize) {
1826*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1827*9190c2a8SAndroid Build Coastguard Worker     }
1828*9190c2a8SAndroid Build Coastguard Worker     if (!(features() & Features::v2)) {
1829*9190c2a8SAndroid Build Coastguard Worker         return -ENOTSUP;
1830*9190c2a8SAndroid Build Coastguard Worker     }
1831*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(control->cmd);
1832*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
1833*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1834*9190c2a8SAndroid Build Coastguard Worker     }
1835*9190c2a8SAndroid Build Coastguard Worker     size_t index = 0;
1836*9190c2a8SAndroid Build Coastguard Worker     int error = 0;
1837*9190c2a8SAndroid Build Coastguard Worker     const auto res = forEachFileIn(path::join(root, INCFS_INCOMPLETE_NAME), [&](const char* name) {
1838*9190c2a8SAndroid Build Coastguard Worker         if (index >= *bufferSize) {
1839*9190c2a8SAndroid Build Coastguard Worker             error = -E2BIG;
1840*9190c2a8SAndroid Build Coastguard Worker         } else {
1841*9190c2a8SAndroid Build Coastguard Worker             ids[index] = IncFs_FileIdFromString(name);
1842*9190c2a8SAndroid Build Coastguard Worker         }
1843*9190c2a8SAndroid Build Coastguard Worker         ++index;
1844*9190c2a8SAndroid Build Coastguard Worker         return true;
1845*9190c2a8SAndroid Build Coastguard Worker     });
1846*9190c2a8SAndroid Build Coastguard Worker     if (res < 0) {
1847*9190c2a8SAndroid Build Coastguard Worker         return res;
1848*9190c2a8SAndroid Build Coastguard Worker     }
1849*9190c2a8SAndroid Build Coastguard Worker     *bufferSize = index;
1850*9190c2a8SAndroid Build Coastguard Worker     return error ? error : 0;
1851*9190c2a8SAndroid Build Coastguard Worker }
1852*9190c2a8SAndroid Build Coastguard Worker 
IncFs_ForEachFile(const IncFsControl * control,void * context,FileCallback cb)1853*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_ForEachFile(const IncFsControl* control, void* context, FileCallback cb) {
1854*9190c2a8SAndroid Build Coastguard Worker     if (!control || !cb) {
1855*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1856*9190c2a8SAndroid Build Coastguard Worker     }
1857*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(control->cmd);
1858*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
1859*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1860*9190c2a8SAndroid Build Coastguard Worker     }
1861*9190c2a8SAndroid Build Coastguard Worker     return forEachFileIn(path::join(root, INCFS_INDEX_NAME), [&](const char* name) {
1862*9190c2a8SAndroid Build Coastguard Worker         return cb(context, control, IncFs_FileIdFromString(name));
1863*9190c2a8SAndroid Build Coastguard Worker     });
1864*9190c2a8SAndroid Build Coastguard Worker }
1865*9190c2a8SAndroid Build Coastguard Worker 
IncFs_ForEachIncompleteFile(const IncFsControl * control,void * context,FileCallback cb)1866*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_ForEachIncompleteFile(const IncFsControl* control, void* context,
1867*9190c2a8SAndroid Build Coastguard Worker                                            FileCallback cb) {
1868*9190c2a8SAndroid Build Coastguard Worker     if (!control || !cb) {
1869*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1870*9190c2a8SAndroid Build Coastguard Worker     }
1871*9190c2a8SAndroid Build Coastguard Worker     if (!(features() & Features::v2)) {
1872*9190c2a8SAndroid Build Coastguard Worker         return -ENOTSUP;
1873*9190c2a8SAndroid Build Coastguard Worker     }
1874*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(control->cmd);
1875*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
1876*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1877*9190c2a8SAndroid Build Coastguard Worker     }
1878*9190c2a8SAndroid Build Coastguard Worker     return forEachFileIn(path::join(root, INCFS_INCOMPLETE_NAME), [&](const char* name) {
1879*9190c2a8SAndroid Build Coastguard Worker         return cb(context, control, IncFs_FileIdFromString(name));
1880*9190c2a8SAndroid Build Coastguard Worker     });
1881*9190c2a8SAndroid Build Coastguard Worker }
1882*9190c2a8SAndroid Build Coastguard Worker 
IncFs_WaitForLoadingComplete(const IncFsControl * control,int32_t timeoutMs)1883*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_WaitForLoadingComplete(const IncFsControl* control, int32_t timeoutMs) {
1884*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
1885*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1886*9190c2a8SAndroid Build Coastguard Worker     }
1887*9190c2a8SAndroid Build Coastguard Worker     if (!(features() & Features::v2)) {
1888*9190c2a8SAndroid Build Coastguard Worker         return -ENOTSUP;
1889*9190c2a8SAndroid Build Coastguard Worker     }
1890*9190c2a8SAndroid Build Coastguard Worker 
1891*9190c2a8SAndroid Build Coastguard Worker     using namespace std::chrono;
1892*9190c2a8SAndroid Build Coastguard Worker     auto hrTimeout = steady_clock::duration(milliseconds(timeoutMs));
1893*9190c2a8SAndroid Build Coastguard Worker 
1894*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(control->cmd);
1895*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
1896*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1897*9190c2a8SAndroid Build Coastguard Worker     }
1898*9190c2a8SAndroid Build Coastguard Worker 
1899*9190c2a8SAndroid Build Coastguard Worker     ab::unique_fd fd(inotify_init1(IN_NONBLOCK | IN_CLOEXEC));
1900*9190c2a8SAndroid Build Coastguard Worker     if (!fd.ok()) {
1901*9190c2a8SAndroid Build Coastguard Worker         return -EFAULT;
1902*9190c2a8SAndroid Build Coastguard Worker     }
1903*9190c2a8SAndroid Build Coastguard Worker 
1904*9190c2a8SAndroid Build Coastguard Worker     // first create all the watches, and only then list existing files to prevent races
1905*9190c2a8SAndroid Build Coastguard Worker     auto dirPath = path::join(root, INCFS_INCOMPLETE_NAME);
1906*9190c2a8SAndroid Build Coastguard Worker     int watchFd = inotify_add_watch(fd.get(), dirPath.c_str(), IN_DELETE);
1907*9190c2a8SAndroid Build Coastguard Worker     if (watchFd < 0) {
1908*9190c2a8SAndroid Build Coastguard Worker         return -errno;
1909*9190c2a8SAndroid Build Coastguard Worker     }
1910*9190c2a8SAndroid Build Coastguard Worker 
1911*9190c2a8SAndroid Build Coastguard Worker     size_t count = 0;
1912*9190c2a8SAndroid Build Coastguard Worker     auto res = IncFs_ListIncompleteFiles(control, nullptr, &count);
1913*9190c2a8SAndroid Build Coastguard Worker     if (!res) {
1914*9190c2a8SAndroid Build Coastguard Worker         return 0;
1915*9190c2a8SAndroid Build Coastguard Worker     }
1916*9190c2a8SAndroid Build Coastguard Worker     if (res != -E2BIG) {
1917*9190c2a8SAndroid Build Coastguard Worker         return res;
1918*9190c2a8SAndroid Build Coastguard Worker     }
1919*9190c2a8SAndroid Build Coastguard Worker 
1920*9190c2a8SAndroid Build Coastguard Worker     while (hrTimeout > hrTimeout.zero()) {
1921*9190c2a8SAndroid Build Coastguard Worker         const auto startTs = steady_clock::now();
1922*9190c2a8SAndroid Build Coastguard Worker 
1923*9190c2a8SAndroid Build Coastguard Worker         pollfd pfd = {fd.get(), POLLIN, 0};
1924*9190c2a8SAndroid Build Coastguard Worker         const auto res = ::poll(&pfd, 1, duration_cast<milliseconds>(hrTimeout).count());
1925*9190c2a8SAndroid Build Coastguard Worker         if (res == 0) {
1926*9190c2a8SAndroid Build Coastguard Worker             return -ETIMEDOUT;
1927*9190c2a8SAndroid Build Coastguard Worker         }
1928*9190c2a8SAndroid Build Coastguard Worker         if (res < 0) {
1929*9190c2a8SAndroid Build Coastguard Worker             const auto error = errno;
1930*9190c2a8SAndroid Build Coastguard Worker             if (error != EINTR) {
1931*9190c2a8SAndroid Build Coastguard Worker                 PLOG(ERROR) << "poll() failed";
1932*9190c2a8SAndroid Build Coastguard Worker                 return -error;
1933*9190c2a8SAndroid Build Coastguard Worker             }
1934*9190c2a8SAndroid Build Coastguard Worker         } else {
1935*9190c2a8SAndroid Build Coastguard Worker             // empty the inotify fd first to not miss any new deletions,
1936*9190c2a8SAndroid Build Coastguard Worker             // then check if the directory is empty.
1937*9190c2a8SAndroid Build Coastguard Worker             char buffer[sizeof(inotify_event) + NAME_MAX + 1];
1938*9190c2a8SAndroid Build Coastguard Worker             for (;;) {
1939*9190c2a8SAndroid Build Coastguard Worker                 auto err = TEMP_FAILURE_RETRY(::read(fd.get(), buffer, sizeof(buffer)));
1940*9190c2a8SAndroid Build Coastguard Worker                 if (err < 0) {
1941*9190c2a8SAndroid Build Coastguard Worker                     if (errno == EAGAIN) { // no new events
1942*9190c2a8SAndroid Build Coastguard Worker                         break;
1943*9190c2a8SAndroid Build Coastguard Worker                     }
1944*9190c2a8SAndroid Build Coastguard Worker                     return -errno;
1945*9190c2a8SAndroid Build Coastguard Worker                 }
1946*9190c2a8SAndroid Build Coastguard Worker             }
1947*9190c2a8SAndroid Build Coastguard Worker 
1948*9190c2a8SAndroid Build Coastguard Worker             size_t count = 0;
1949*9190c2a8SAndroid Build Coastguard Worker             auto res = IncFs_ListIncompleteFiles(control, nullptr, &count);
1950*9190c2a8SAndroid Build Coastguard Worker             if (!res) {
1951*9190c2a8SAndroid Build Coastguard Worker                 return 0;
1952*9190c2a8SAndroid Build Coastguard Worker             }
1953*9190c2a8SAndroid Build Coastguard Worker             if (res != -E2BIG) {
1954*9190c2a8SAndroid Build Coastguard Worker                 return res;
1955*9190c2a8SAndroid Build Coastguard Worker             }
1956*9190c2a8SAndroid Build Coastguard Worker         }
1957*9190c2a8SAndroid Build Coastguard Worker         hrTimeout -= steady_clock::now() - startTs;
1958*9190c2a8SAndroid Build Coastguard Worker     }
1959*9190c2a8SAndroid Build Coastguard Worker 
1960*9190c2a8SAndroid Build Coastguard Worker     return -ETIMEDOUT;
1961*9190c2a8SAndroid Build Coastguard Worker }
1962*9190c2a8SAndroid Build Coastguard Worker 
IncFs_WaitForFsWrittenBlocksChange(const IncFsControl * control,int32_t timeoutMs,IncFsSize * count)1963*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_WaitForFsWrittenBlocksChange(const IncFsControl* control, int32_t timeoutMs,
1964*9190c2a8SAndroid Build Coastguard Worker                                                   IncFsSize* count) {
1965*9190c2a8SAndroid Build Coastguard Worker     if (!control || !count) {
1966*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
1967*9190c2a8SAndroid Build Coastguard Worker     }
1968*9190c2a8SAndroid Build Coastguard Worker     if (!(features() & Features::v2)) {
1969*9190c2a8SAndroid Build Coastguard Worker         return -ENOTSUP;
1970*9190c2a8SAndroid Build Coastguard Worker     }
1971*9190c2a8SAndroid Build Coastguard Worker 
1972*9190c2a8SAndroid Build Coastguard Worker     using namespace std::chrono;
1973*9190c2a8SAndroid Build Coastguard Worker     auto hrTimeout = steady_clock::duration(milliseconds(timeoutMs));
1974*9190c2a8SAndroid Build Coastguard Worker 
1975*9190c2a8SAndroid Build Coastguard Worker     while (hrTimeout > hrTimeout.zero()) {
1976*9190c2a8SAndroid Build Coastguard Worker         const auto startTs = steady_clock::now();
1977*9190c2a8SAndroid Build Coastguard Worker 
1978*9190c2a8SAndroid Build Coastguard Worker         pollfd pfd = {control->blocksWritten, POLLIN, 0};
1979*9190c2a8SAndroid Build Coastguard Worker         const auto res = ::poll(&pfd, 1, duration_cast<milliseconds>(hrTimeout).count());
1980*9190c2a8SAndroid Build Coastguard Worker         if (res > 0) {
1981*9190c2a8SAndroid Build Coastguard Worker             break;
1982*9190c2a8SAndroid Build Coastguard Worker         }
1983*9190c2a8SAndroid Build Coastguard Worker         if (res == 0) {
1984*9190c2a8SAndroid Build Coastguard Worker             return -ETIMEDOUT;
1985*9190c2a8SAndroid Build Coastguard Worker         }
1986*9190c2a8SAndroid Build Coastguard Worker         const auto error = errno;
1987*9190c2a8SAndroid Build Coastguard Worker         if (error != EINTR) {
1988*9190c2a8SAndroid Build Coastguard Worker             PLOG(ERROR) << "poll() failed";
1989*9190c2a8SAndroid Build Coastguard Worker             return -error;
1990*9190c2a8SAndroid Build Coastguard Worker         }
1991*9190c2a8SAndroid Build Coastguard Worker         hrTimeout -= steady_clock::now() - startTs;
1992*9190c2a8SAndroid Build Coastguard Worker     }
1993*9190c2a8SAndroid Build Coastguard Worker 
1994*9190c2a8SAndroid Build Coastguard Worker     char str[32];
1995*9190c2a8SAndroid Build Coastguard Worker     auto size = ::read(control->blocksWritten, str, sizeof(str));
1996*9190c2a8SAndroid Build Coastguard Worker     if (size < 0) {
1997*9190c2a8SAndroid Build Coastguard Worker         const auto error = errno;
1998*9190c2a8SAndroid Build Coastguard Worker         PLOG(ERROR) << "read() failed";
1999*9190c2a8SAndroid Build Coastguard Worker         return -error;
2000*9190c2a8SAndroid Build Coastguard Worker     }
2001*9190c2a8SAndroid Build Coastguard Worker     const auto res = std::from_chars(str, str + size, *count);
2002*9190c2a8SAndroid Build Coastguard Worker     if (res.ec != std::errc{}) {
2003*9190c2a8SAndroid Build Coastguard Worker         return res.ec == std::errc::invalid_argument ? -EINVAL : -ERANGE;
2004*9190c2a8SAndroid Build Coastguard Worker     }
2005*9190c2a8SAndroid Build Coastguard Worker 
2006*9190c2a8SAndroid Build Coastguard Worker     return 0;
2007*9190c2a8SAndroid Build Coastguard Worker }
2008*9190c2a8SAndroid Build Coastguard Worker 
reserveSpace(const char * backingPath,IncFsSize size)2009*9190c2a8SAndroid Build Coastguard Worker static IncFsErrorCode reserveSpace(const char* backingPath, IncFsSize size) {
2010*9190c2a8SAndroid Build Coastguard Worker     auto fd = ab::unique_fd(::open(backingPath, O_WRONLY | O_CLOEXEC));
2011*9190c2a8SAndroid Build Coastguard Worker     if (fd < 0) {
2012*9190c2a8SAndroid Build Coastguard Worker         return -errno;
2013*9190c2a8SAndroid Build Coastguard Worker     }
2014*9190c2a8SAndroid Build Coastguard Worker     struct stat st = {};
2015*9190c2a8SAndroid Build Coastguard Worker     if (::fstat(fd.get(), &st)) {
2016*9190c2a8SAndroid Build Coastguard Worker         return -errno;
2017*9190c2a8SAndroid Build Coastguard Worker     }
2018*9190c2a8SAndroid Build Coastguard Worker     if (size == kIncFsTrimReservedSpace) {
2019*9190c2a8SAndroid Build Coastguard Worker         if (::ftruncate(fd.get(), st.st_size)) {
2020*9190c2a8SAndroid Build Coastguard Worker             return -errno;
2021*9190c2a8SAndroid Build Coastguard Worker         }
2022*9190c2a8SAndroid Build Coastguard Worker     } else {
2023*9190c2a8SAndroid Build Coastguard Worker         // Add 1.5% of the size for the hash tree and the blockmap, and some more blocks
2024*9190c2a8SAndroid Build Coastguard Worker         // for fixed overhead.
2025*9190c2a8SAndroid Build Coastguard Worker         // hash tree is ~33 bytes / page, and blockmap is 10 bytes / page
2026*9190c2a8SAndroid Build Coastguard Worker         // no need to round to a page size as filesystems already do that.
2027*9190c2a8SAndroid Build Coastguard Worker         const auto backingSize = IncFsSize(size * 1.015) + INCFS_DATA_FILE_BLOCK_SIZE * 4;
2028*9190c2a8SAndroid Build Coastguard Worker         if (backingSize < st.st_size) {
2029*9190c2a8SAndroid Build Coastguard Worker             return -EPERM;
2030*9190c2a8SAndroid Build Coastguard Worker         }
2031*9190c2a8SAndroid Build Coastguard Worker         if (::fallocate(fd.get(), FALLOC_FL_KEEP_SIZE, 0, backingSize)) {
2032*9190c2a8SAndroid Build Coastguard Worker             return -errno;
2033*9190c2a8SAndroid Build Coastguard Worker         }
2034*9190c2a8SAndroid Build Coastguard Worker     }
2035*9190c2a8SAndroid Build Coastguard Worker     return 0;
2036*9190c2a8SAndroid Build Coastguard Worker }
2037*9190c2a8SAndroid Build Coastguard Worker 
IncFs_ReserveSpaceByPath(const IncFsControl * control,const char * path,IncFsSize size)2038*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_ReserveSpaceByPath(const IncFsControl* control, const char* path,
2039*9190c2a8SAndroid Build Coastguard Worker                                         IncFsSize size) {
2040*9190c2a8SAndroid Build Coastguard Worker     if (!control || (size != kIncFsTrimReservedSpace && size < 0)) {
2041*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
2042*9190c2a8SAndroid Build Coastguard Worker     }
2043*9190c2a8SAndroid Build Coastguard Worker     const auto [pathRoot, backingRoot, subpath] = registry().detailsFor(path);
2044*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(control->cmd);
2045*9190c2a8SAndroid Build Coastguard Worker     if (root.empty() || root != pathRoot) {
2046*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
2047*9190c2a8SAndroid Build Coastguard Worker     }
2048*9190c2a8SAndroid Build Coastguard Worker     return reserveSpace(path::join(backingRoot, subpath).c_str(), size);
2049*9190c2a8SAndroid Build Coastguard Worker }
2050*9190c2a8SAndroid Build Coastguard Worker 
IncFs_ReserveSpaceById(const IncFsControl * control,IncFsFileId id,IncFsSize size)2051*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_ReserveSpaceById(const IncFsControl* control, IncFsFileId id, IncFsSize size) {
2052*9190c2a8SAndroid Build Coastguard Worker     if (!control || (size != kIncFsTrimReservedSpace && size < 0)) {
2053*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
2054*9190c2a8SAndroid Build Coastguard Worker     }
2055*9190c2a8SAndroid Build Coastguard Worker     const auto root = rootForCmd(control->cmd);
2056*9190c2a8SAndroid Build Coastguard Worker     if (root.empty()) {
2057*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
2058*9190c2a8SAndroid Build Coastguard Worker     }
2059*9190c2a8SAndroid Build Coastguard Worker     auto path = indexPath(root, id);
2060*9190c2a8SAndroid Build Coastguard Worker     const auto [pathRoot, backingRoot, subpath] = registry().detailsFor(path);
2061*9190c2a8SAndroid Build Coastguard Worker     if (root != pathRoot) {
2062*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
2063*9190c2a8SAndroid Build Coastguard Worker     }
2064*9190c2a8SAndroid Build Coastguard Worker     return reserveSpace(path::join(backingRoot, subpath).c_str(), size);
2065*9190c2a8SAndroid Build Coastguard Worker }
2066*9190c2a8SAndroid Build Coastguard Worker 
2067*9190c2a8SAndroid Build Coastguard Worker template <class IntType>
readIntFromFile(std::string_view rootDir,std::string_view subPath,IntType & result)2068*9190c2a8SAndroid Build Coastguard Worker static int readIntFromFile(std::string_view rootDir, std::string_view subPath, IntType& result) {
2069*9190c2a8SAndroid Build Coastguard Worker     std::string content;
2070*9190c2a8SAndroid Build Coastguard Worker     if (!ab::ReadFileToString(path::join(rootDir, subPath), &content)) {
2071*9190c2a8SAndroid Build Coastguard Worker         PLOG(ERROR) << "IncFs_GetMetrics: failed to read file: " << rootDir << "/" << subPath;
2072*9190c2a8SAndroid Build Coastguard Worker         return -errno;
2073*9190c2a8SAndroid Build Coastguard Worker     }
2074*9190c2a8SAndroid Build Coastguard Worker     const auto res = std::from_chars(content.data(), content.data() + content.size(), result);
2075*9190c2a8SAndroid Build Coastguard Worker     if (res.ec != std::errc()) {
2076*9190c2a8SAndroid Build Coastguard Worker         return -static_cast<int>(res.ec);
2077*9190c2a8SAndroid Build Coastguard Worker     }
2078*9190c2a8SAndroid Build Coastguard Worker     return 0;
2079*9190c2a8SAndroid Build Coastguard Worker }
2080*9190c2a8SAndroid Build Coastguard Worker 
IncFs_GetMetrics(const char * sysfsName,IncFsMetrics * metrics)2081*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_GetMetrics(const char* sysfsName, IncFsMetrics* metrics) {
2082*9190c2a8SAndroid Build Coastguard Worker     if (!sysfsName || !*sysfsName) {
2083*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
2084*9190c2a8SAndroid Build Coastguard Worker     }
2085*9190c2a8SAndroid Build Coastguard Worker 
2086*9190c2a8SAndroid Build Coastguard Worker     const auto kSysfsMetricsDir =
2087*9190c2a8SAndroid Build Coastguard Worker             ab::StringPrintf("/sys/fs/%s/instances/%s", INCFS_NAME, sysfsName);
2088*9190c2a8SAndroid Build Coastguard Worker 
2089*9190c2a8SAndroid Build Coastguard Worker     int err;
2090*9190c2a8SAndroid Build Coastguard Worker     if (err = readIntFromFile(kSysfsMetricsDir, "reads_delayed_min", metrics->readsDelayedMin);
2091*9190c2a8SAndroid Build Coastguard Worker         err != 0) {
2092*9190c2a8SAndroid Build Coastguard Worker         return err;
2093*9190c2a8SAndroid Build Coastguard Worker     }
2094*9190c2a8SAndroid Build Coastguard Worker     if (err = readIntFromFile(kSysfsMetricsDir, "reads_delayed_min_us", metrics->readsDelayedMinUs);
2095*9190c2a8SAndroid Build Coastguard Worker         err != 0) {
2096*9190c2a8SAndroid Build Coastguard Worker         return err;
2097*9190c2a8SAndroid Build Coastguard Worker     }
2098*9190c2a8SAndroid Build Coastguard Worker     if (err = readIntFromFile(kSysfsMetricsDir, "reads_delayed_pending",
2099*9190c2a8SAndroid Build Coastguard Worker                               metrics->readsDelayedPending);
2100*9190c2a8SAndroid Build Coastguard Worker         err != 0) {
2101*9190c2a8SAndroid Build Coastguard Worker         return err;
2102*9190c2a8SAndroid Build Coastguard Worker     }
2103*9190c2a8SAndroid Build Coastguard Worker     if (err = readIntFromFile(kSysfsMetricsDir, "reads_delayed_pending_us",
2104*9190c2a8SAndroid Build Coastguard Worker                               metrics->readsDelayedPendingUs);
2105*9190c2a8SAndroid Build Coastguard Worker         err != 0) {
2106*9190c2a8SAndroid Build Coastguard Worker         return err;
2107*9190c2a8SAndroid Build Coastguard Worker     }
2108*9190c2a8SAndroid Build Coastguard Worker     if (err = readIntFromFile(kSysfsMetricsDir, "reads_failed_hash_verification",
2109*9190c2a8SAndroid Build Coastguard Worker                               metrics->readsFailedHashVerification);
2110*9190c2a8SAndroid Build Coastguard Worker         err != 0) {
2111*9190c2a8SAndroid Build Coastguard Worker         return err;
2112*9190c2a8SAndroid Build Coastguard Worker     }
2113*9190c2a8SAndroid Build Coastguard Worker     if (err = readIntFromFile(kSysfsMetricsDir, "reads_failed_other", metrics->readsFailedOther);
2114*9190c2a8SAndroid Build Coastguard Worker         err != 0) {
2115*9190c2a8SAndroid Build Coastguard Worker         return err;
2116*9190c2a8SAndroid Build Coastguard Worker     }
2117*9190c2a8SAndroid Build Coastguard Worker     if (err = readIntFromFile(kSysfsMetricsDir, "reads_failed_timed_out",
2118*9190c2a8SAndroid Build Coastguard Worker                               metrics->readsFailedTimedOut);
2119*9190c2a8SAndroid Build Coastguard Worker         err != 0) {
2120*9190c2a8SAndroid Build Coastguard Worker         return err;
2121*9190c2a8SAndroid Build Coastguard Worker     }
2122*9190c2a8SAndroid Build Coastguard Worker     return 0;
2123*9190c2a8SAndroid Build Coastguard Worker }
2124*9190c2a8SAndroid Build Coastguard Worker 
IncFs_GetLastReadError(const IncFsControl * control,IncFsLastReadError * lastReadError)2125*9190c2a8SAndroid Build Coastguard Worker IncFsErrorCode IncFs_GetLastReadError(const IncFsControl* control,
2126*9190c2a8SAndroid Build Coastguard Worker                                       IncFsLastReadError* lastReadError) {
2127*9190c2a8SAndroid Build Coastguard Worker     if (!control) {
2128*9190c2a8SAndroid Build Coastguard Worker         return -EINVAL;
2129*9190c2a8SAndroid Build Coastguard Worker     }
2130*9190c2a8SAndroid Build Coastguard Worker     if (!(features() & Features::v2)) {
2131*9190c2a8SAndroid Build Coastguard Worker         return -ENOTSUP;
2132*9190c2a8SAndroid Build Coastguard Worker     }
2133*9190c2a8SAndroid Build Coastguard Worker     incfs_get_last_read_error_args args = {};
2134*9190c2a8SAndroid Build Coastguard Worker     auto res = ::ioctl(control->cmd, INCFS_IOC_GET_LAST_READ_ERROR, &args);
2135*9190c2a8SAndroid Build Coastguard Worker     if (res < 0) {
2136*9190c2a8SAndroid Build Coastguard Worker         PLOG(ERROR) << "[incfs] IncFs_GetLastReadError failed.";
2137*9190c2a8SAndroid Build Coastguard Worker         return -errno;
2138*9190c2a8SAndroid Build Coastguard Worker     }
2139*9190c2a8SAndroid Build Coastguard Worker     *lastReadError = IncFsLastReadError{
2140*9190c2a8SAndroid Build Coastguard Worker             .timestampUs = args.time_us_out,
2141*9190c2a8SAndroid Build Coastguard Worker             .block = static_cast<IncFsBlockIndex>(args.page_out),
2142*9190c2a8SAndroid Build Coastguard Worker             .errorNo = args.errno_out,
2143*9190c2a8SAndroid Build Coastguard Worker             .uid = static_cast<IncFsUid>(args.uid_out),
2144*9190c2a8SAndroid Build Coastguard Worker     };
2145*9190c2a8SAndroid Build Coastguard Worker     static_assert(sizeof(args.file_id_out.bytes) == sizeof(lastReadError->id.data));
2146*9190c2a8SAndroid Build Coastguard Worker     memcpy(lastReadError->id.data, args.file_id_out.bytes, sizeof(args.file_id_out.bytes));
2147*9190c2a8SAndroid Build Coastguard Worker     return 0;
2148*9190c2a8SAndroid Build Coastguard Worker }
2149*9190c2a8SAndroid Build Coastguard Worker 
defaultMountRegistry()2150*9190c2a8SAndroid Build Coastguard Worker MountRegistry& android::incfs::defaultMountRegistry() {
2151*9190c2a8SAndroid Build Coastguard Worker     return registry();
2152*9190c2a8SAndroid Build Coastguard Worker }
2153