1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #pragma once
17
18 #include <errno.h>
19
20 #include <optional>
21 #include <string>
22
23 #include "incfs.h"
24
25 namespace android::incfs {
26
27 constexpr char kIdAttrName[] = INCFS_XATTR_ID_NAME;
28 constexpr char kSizeAttrName[] = INCFS_XATTR_SIZE_NAME;
29 constexpr char kMetadataAttrName[] = INCFS_XATTR_METADATA_NAME;
30
31 extern const size_t kPageSize;
32
33 namespace details {
34
35 class CStrWrapper {
36 public:
CStrWrapper(std::string_view sv)37 CStrWrapper(std::string_view sv) {
38 if (!sv.data()) {
39 mCstr = "";
40 } else if (sv[sv.size()] == '\0') {
41 mCstr = sv.data();
42 } else {
43 mCopy.emplace(sv);
44 mCstr = mCopy->c_str();
45 }
46 }
47
48 CStrWrapper(const CStrWrapper&) = delete;
49 void operator=(const CStrWrapper&) = delete;
50 CStrWrapper(CStrWrapper&&) = delete;
51 void operator=(CStrWrapper&&) = delete;
52
get()53 const char* get() const { return mCstr; }
54 operator const char*() const { return get(); }
55
56 private:
57 const char* mCstr;
58 std::optional<std::string> mCopy;
59 };
60
c_str(std::string_view sv)61 inline CStrWrapper c_str(std::string_view sv) {
62 return {sv};
63 }
64
65 } // namespace details
66
enabled()67 inline bool enabled() {
68 return IncFs_IsEnabled();
69 }
70
features()71 inline Features features() {
72 return Features(IncFs_Features());
73 }
74
isIncFsFd(int fd)75 inline bool isIncFsFd(int fd) {
76 return IncFs_IsIncFsFd(fd);
77 }
78
isIncFsPath(std::string_view path)79 inline bool isIncFsPath(std::string_view path) {
80 return IncFs_IsIncFsPath(details::c_str(path));
81 }
82
isValidFileId(FileId fileId)83 inline bool isValidFileId(FileId fileId) {
84 return IncFs_IsValidFileId(fileId);
85 }
86
toString(FileId fileId)87 inline std::string toString(FileId fileId) {
88 std::string res(kIncFsFileIdStringLength, '\0');
89 auto err = IncFs_FileIdToString(fileId, res.data());
90 if (err) {
91 errno = err;
92 return {};
93 }
94 return res;
95 }
96
toFileId(std::string_view str)97 inline IncFsFileId toFileId(std::string_view str) {
98 if (str.size() != kIncFsFileIdStringLength) {
99 return kIncFsInvalidFileId;
100 }
101 return IncFs_FileIdFromString(str.data());
102 }
103
close()104 inline void UniqueControl::close() {
105 IncFs_DeleteControl(mControl);
106 mControl = nullptr;
107 }
108
cmd()109 inline IncFsFd UniqueControl::cmd() const {
110 return IncFs_GetControlFd(mControl, CMD);
111 }
112
pendingReads()113 inline IncFsFd UniqueControl::pendingReads() const {
114 return IncFs_GetControlFd(mControl, PENDING_READS);
115 }
116
logs()117 inline IncFsFd UniqueControl::logs() const {
118 return IncFs_GetControlFd(mControl, LOGS);
119 }
120
blocksWritten()121 inline IncFsFd UniqueControl::blocksWritten() const {
122 return IncFs_GetControlFd(mControl, BLOCKS_WRITTEN);
123 }
124
releaseFds()125 inline UniqueControl::Fds UniqueControl::releaseFds() {
126 Fds result;
127 IncFsFd fds[result.size()];
128 auto count = IncFs_ReleaseControlFds(mControl, fds, std::size(fds));
129 for (auto i = 0; i < count; ++i) {
130 result[i] = UniqueFd(fds[i]);
131 }
132 return result;
133 }
134
mount(std::string_view backingPath,std::string_view targetDir,MountOptions options)135 inline UniqueControl mount(std::string_view backingPath, std::string_view targetDir,
136 MountOptions options) {
137 auto control = IncFs_Mount(details::c_str(backingPath), details::c_str(targetDir), options);
138 return UniqueControl(control);
139 }
140
open(std::string_view dir)141 inline UniqueControl open(std::string_view dir) {
142 auto control = IncFs_Open(details::c_str(dir));
143 return UniqueControl(control);
144 }
145
createControl(IncFsFd cmd,IncFsFd pendingReads,IncFsFd logs,IncFsFd blocksWritten)146 inline UniqueControl createControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs,
147 IncFsFd blocksWritten) {
148 return UniqueControl(IncFs_CreateControl(cmd, pendingReads, logs, blocksWritten));
149 }
150
setOptions(const Control & control,MountOptions newOptions)151 inline ErrorCode setOptions(const Control& control, MountOptions newOptions) {
152 return IncFs_SetOptions(control, newOptions);
153 }
154
bindMount(std::string_view sourceDir,std::string_view targetDir)155 inline ErrorCode bindMount(std::string_view sourceDir, std::string_view targetDir) {
156 return IncFs_BindMount(details::c_str(sourceDir), details::c_str(targetDir));
157 }
158
unmount(std::string_view dir)159 inline ErrorCode unmount(std::string_view dir) {
160 return IncFs_Unmount(details::c_str(dir));
161 }
162
root(const Control & control)163 inline std::string root(const Control& control) {
164 std::string result;
165 result.resize(PATH_MAX);
166 size_t size = result.size();
167 if (auto err = IncFs_Root(control, result.data(), &size); err < 0) {
168 errno = -err;
169 return {};
170 }
171 result.resize(size);
172 return result;
173 }
174
makeFile(const Control & control,std::string_view path,int mode,FileId fileId,NewFileParams params)175 inline ErrorCode makeFile(const Control& control, std::string_view path, int mode, FileId fileId,
176 NewFileParams params) {
177 return IncFs_MakeFile(control, details::c_str(path), mode, fileId, params);
178 }
makeMappedFile(const Control & control,std::string_view path,int mode,NewMappedFileParams params)179 inline ErrorCode makeMappedFile(const Control& control, std::string_view path, int mode,
180 NewMappedFileParams params) {
181 return IncFs_MakeMappedFile(control, details::c_str(path), mode, params);
182 }
makeDir(const Control & control,std::string_view path,int mode)183 inline ErrorCode makeDir(const Control& control, std::string_view path, int mode) {
184 return IncFs_MakeDir(control, details::c_str(path), mode);
185 }
makeDirs(const Control & control,std::string_view path,int mode)186 inline ErrorCode makeDirs(const Control& control, std::string_view path, int mode) {
187 return IncFs_MakeDirs(control, details::c_str(path), mode);
188 }
189
getMetadata(const Control & control,FileId fileId)190 inline RawMetadata getMetadata(const Control& control, FileId fileId) {
191 RawMetadata metadata(INCFS_MAX_FILE_ATTR_SIZE);
192 size_t size = metadata.size();
193 if (IncFs_GetMetadataById(control, fileId, metadata.data(), &size) < 0) {
194 return {};
195 }
196 metadata.resize(size);
197 return metadata;
198 }
199
getMetadata(const Control & control,std::string_view path)200 inline RawMetadata getMetadata(const Control& control, std::string_view path) {
201 RawMetadata metadata(INCFS_MAX_FILE_ATTR_SIZE);
202 size_t size = metadata.size();
203 if (IncFs_GetMetadataByPath(control, details::c_str(path), metadata.data(), &size) < 0) {
204 return {};
205 }
206 metadata.resize(size);
207 return metadata;
208 }
209
getSignature(const Control & control,FileId fileId)210 inline RawSignature getSignature(const Control& control, FileId fileId) {
211 RawSignature signature(INCFS_MAX_SIGNATURE_SIZE);
212 size_t size = signature.size();
213 if (IncFs_GetSignatureById(control, fileId, signature.data(), &size) < 0) {
214 return {};
215 }
216 signature.resize(size);
217 return signature;
218 }
219
getSignature(const Control & control,std::string_view path)220 inline RawSignature getSignature(const Control& control, std::string_view path) {
221 RawSignature signature(INCFS_MAX_SIGNATURE_SIZE);
222 size_t size = signature.size();
223 if (IncFs_GetSignatureByPath(control, details::c_str(path), signature.data(), &size) < 0) {
224 return {};
225 }
226 signature.resize(size);
227 return signature;
228 }
229
getFileId(const Control & control,std::string_view path)230 inline FileId getFileId(const Control& control, std::string_view path) {
231 return IncFs_GetId(control, details::c_str(path));
232 }
233
link(const Control & control,std::string_view sourcePath,std::string_view targetPath)234 inline ErrorCode link(const Control& control, std::string_view sourcePath,
235 std::string_view targetPath) {
236 return IncFs_Link(control, details::c_str(sourcePath), details::c_str(targetPath));
237 }
238
unlink(const Control & control,std::string_view path)239 inline ErrorCode unlink(const Control& control, std::string_view path) {
240 return IncFs_Unlink(control, details::c_str(path));
241 }
242
243 template <class ReadInfoStruct, class Impl>
waitForReads(const Control & control,std::chrono::milliseconds timeout,std::vector<ReadInfoStruct> * pendingReadsBuffer,size_t defaultBufferSize,Impl impl)244 WaitResult waitForReads(const Control& control, std::chrono::milliseconds timeout,
245 std::vector<ReadInfoStruct>* pendingReadsBuffer, size_t defaultBufferSize,
246 Impl impl) {
247 if (pendingReadsBuffer->empty()) {
248 pendingReadsBuffer->resize(defaultBufferSize);
249 }
250 size_t size = pendingReadsBuffer->size();
251 IncFsErrorCode err = impl(control, timeout.count(), pendingReadsBuffer->data(), &size);
252 pendingReadsBuffer->resize(size);
253 switch (err) {
254 case 0:
255 return WaitResult::HaveData;
256 case -ETIMEDOUT:
257 return WaitResult::Timeout;
258 }
259 return WaitResult(err);
260 }
261
waitForPendingReads(const Control & control,std::chrono::milliseconds timeout,std::vector<ReadInfo> * pendingReadsBuffer)262 inline WaitResult waitForPendingReads(const Control& control, std::chrono::milliseconds timeout,
263 std::vector<ReadInfo>* pendingReadsBuffer) {
264 return waitForReads(control, timeout, pendingReadsBuffer,
265 INCFS_DEFAULT_PENDING_READ_BUFFER_SIZE, IncFs_WaitForPendingReads);
266 }
267
waitForPendingReads(const Control & control,std::chrono::milliseconds timeout,std::vector<ReadInfoWithUid> * pendingReadsBuffer)268 inline WaitResult waitForPendingReads(const Control& control, std::chrono::milliseconds timeout,
269 std::vector<ReadInfoWithUid>* pendingReadsBuffer) {
270 return waitForReads(control, timeout, pendingReadsBuffer,
271 INCFS_DEFAULT_PENDING_READ_BUFFER_SIZE, IncFs_WaitForPendingReadsWithUid);
272 }
273
waitForPageReads(const Control & control,std::chrono::milliseconds timeout,std::vector<ReadInfo> * pageReadsBuffer)274 inline WaitResult waitForPageReads(const Control& control, std::chrono::milliseconds timeout,
275 std::vector<ReadInfo>* pageReadsBuffer) {
276 static const auto kDefaultBufferSize =
277 INCFS_DEFAULT_PAGE_READ_BUFFER_PAGES * kPageSize / sizeof(ReadInfo);
278 return waitForReads(control, timeout, pageReadsBuffer, kDefaultBufferSize,
279 IncFs_WaitForPageReads);
280 }
281
waitForPageReads(const Control & control,std::chrono::milliseconds timeout,std::vector<ReadInfoWithUid> * pageReadsBuffer)282 inline WaitResult waitForPageReads(const Control& control, std::chrono::milliseconds timeout,
283 std::vector<ReadInfoWithUid>* pageReadsBuffer) {
284 static const auto kDefaultBufferSize =
285 INCFS_DEFAULT_PAGE_READ_BUFFER_PAGES * kPageSize / sizeof(ReadInfoWithUid);
286 return waitForReads(control, timeout, pageReadsBuffer, kDefaultBufferSize,
287 IncFs_WaitForPageReadsWithUid);
288 }
289
openForSpecialOps(const Control & control,FileId fileId)290 inline UniqueFd openForSpecialOps(const Control& control, FileId fileId) {
291 return UniqueFd(IncFs_OpenForSpecialOpsById(control, fileId));
292 }
openForSpecialOps(const Control & control,std::string_view path)293 inline UniqueFd openForSpecialOps(const Control& control, std::string_view path) {
294 return UniqueFd(IncFs_OpenForSpecialOpsByPath(control, details::c_str(path)));
295 }
296
writeBlocks(Span<const DataBlock> blocks)297 inline ErrorCode writeBlocks(Span<const DataBlock> blocks) {
298 return IncFs_WriteBlocks(blocks.data(), blocks.size());
299 }
300
getFilledRanges(int fd)301 inline std::pair<ErrorCode, FilledRanges> getFilledRanges(int fd) {
302 return getFilledRanges(fd, FilledRanges());
303 }
304
getFilledRanges(int fd,FilledRanges::RangeBuffer && buffer)305 inline std::pair<ErrorCode, FilledRanges> getFilledRanges(int fd,
306 FilledRanges::RangeBuffer&& buffer) {
307 return getFilledRanges(fd, FilledRanges(std::move(buffer), {}));
308 }
309
getFilledRanges(int fd,FilledRanges && resumeFrom)310 inline std::pair<ErrorCode, FilledRanges> getFilledRanges(int fd, FilledRanges&& resumeFrom) {
311 auto totalRanges = resumeFrom.dataRanges().size() + resumeFrom.hashRanges().size();
312 auto rawRanges = resumeFrom.internalRawRanges();
313 auto buffer = resumeFrom.extractInternalBufferAndClear();
314 auto remainingSpace = buffer.size() - totalRanges;
315 const bool loadAll = remainingSpace == 0;
316 int res;
317 do {
318 if (remainingSpace == 0) {
319 remainingSpace = std::max<size_t>(32, buffer.size() / 2);
320 buffer.resize(buffer.size() + remainingSpace);
321 }
322 auto outBuffer = IncFsSpan{(const char*)(buffer.data() + rawRanges.dataRangesCount +
323 rawRanges.hashRangesCount),
324 IncFsSize(remainingSpace * sizeof(buffer[0]))};
325 IncFsFilledRanges newRanges;
326 res = IncFs_GetFilledRangesStartingFrom(fd, rawRanges.endIndex, outBuffer, &newRanges);
327 if (res && res != -ERANGE) {
328 return {res, FilledRanges(std::move(buffer), {})};
329 }
330
331 rawRanges.dataRangesCount += newRanges.dataRangesCount;
332 rawRanges.hashRangesCount += newRanges.hashRangesCount;
333 rawRanges.endIndex = newRanges.endIndex;
334 remainingSpace = buffer.size() - rawRanges.dataRangesCount - rawRanges.hashRangesCount;
335 } while (res && loadAll);
336
337 rawRanges.dataRanges = buffer.data();
338 rawRanges.hashRanges = buffer.data() + rawRanges.dataRangesCount;
339 return {res, FilledRanges(std::move(buffer), rawRanges)};
340 }
341
toLoadingState(IncFsErrorCode res)342 inline LoadingState toLoadingState(IncFsErrorCode res) {
343 switch (res) {
344 case 0:
345 return LoadingState::Full;
346 case -ENODATA:
347 return LoadingState::MissingBlocks;
348 default:
349 return LoadingState(res);
350 }
351 }
352
isFullyLoaded(int fd)353 inline LoadingState isFullyLoaded(int fd) {
354 return toLoadingState(IncFs_IsFullyLoaded(fd));
355 }
isFullyLoaded(const Control & control,std::string_view path)356 inline LoadingState isFullyLoaded(const Control& control, std::string_view path) {
357 return toLoadingState(IncFs_IsFullyLoadedByPath(control, details::c_str(path)));
358 }
isFullyLoaded(const Control & control,FileId fileId)359 inline LoadingState isFullyLoaded(const Control& control, FileId fileId) {
360 return toLoadingState(IncFs_IsFullyLoadedById(control, fileId));
361 }
362
isEverythingFullyLoaded(const Control & control)363 inline LoadingState isEverythingFullyLoaded(const Control& control) {
364 return toLoadingState(IncFs_IsEverythingFullyLoaded(control));
365 }
366
listIncompleteFiles(const Control & control)367 inline std::optional<std::vector<FileId>> listIncompleteFiles(const Control& control) {
368 std::vector<FileId> ids(32);
369 size_t count = ids.size();
370 auto err = IncFs_ListIncompleteFiles(control, ids.data(), &count);
371 if (err == -E2BIG) {
372 ids.resize(count);
373 err = IncFs_ListIncompleteFiles(control, ids.data(), &count);
374 }
375 if (err) {
376 errno = -err;
377 return {};
378 }
379 ids.resize(count);
380 return std::move(ids);
381 }
382
383 template <class Callback>
forEachFile(const Control & control,Callback && cb)384 inline ErrorCode forEachFile(const Control& control, Callback&& cb) {
385 struct Context {
386 const Control& c;
387 const Callback& cb;
388 } context = {control, cb};
389 return IncFs_ForEachFile(control, &context, [](void* pcontext, const IncFsControl*, FileId id) {
390 const auto context = (Context*)pcontext;
391 return context->cb(context->c, id);
392 });
393 }
394 template <class Callback>
forEachIncompleteFile(const Control & control,Callback && cb)395 inline ErrorCode forEachIncompleteFile(const Control& control, Callback&& cb) {
396 struct Context {
397 const Control& c;
398 const Callback& cb;
399 } context = {control, cb};
400 return IncFs_ForEachIncompleteFile(control, &context,
401 [](void* pcontext, const IncFsControl*, FileId id) {
402 const auto context = (Context*)pcontext;
403 return context->cb(context->c, id);
404 });
405 }
406
waitForLoadingComplete(const Control & control,std::chrono::milliseconds timeout)407 inline WaitResult waitForLoadingComplete(const Control& control,
408 std::chrono::milliseconds timeout) {
409 const auto res = IncFs_WaitForLoadingComplete(control, timeout.count());
410 switch (res) {
411 case 0:
412 return WaitResult::HaveData;
413 case -ETIMEDOUT:
414 return WaitResult::Timeout;
415 default:
416 return WaitResult(res);
417 }
418 }
419
getBlockCount(const Control & control,FileId fileId)420 inline std::optional<BlockCounts> getBlockCount(const Control& control, FileId fileId) {
421 BlockCounts counts;
422 auto res = IncFs_GetFileBlockCountById(control, fileId, &counts);
423 if (res) {
424 errno = -res;
425 return {};
426 }
427 return counts;
428 }
429
getBlockCount(const Control & control,std::string_view path)430 inline std::optional<BlockCounts> getBlockCount(const Control& control, std::string_view path) {
431 BlockCounts counts;
432 auto res = IncFs_GetFileBlockCountByPath(control, details::c_str(path), &counts);
433 if (res) {
434 errno = -res;
435 return {};
436 }
437 return counts;
438 }
439
setUidReadTimeouts(const Control & control,Span<const UidReadTimeouts> timeouts)440 inline ErrorCode setUidReadTimeouts(const Control& control, Span<const UidReadTimeouts> timeouts) {
441 return IncFs_SetUidReadTimeouts(control, timeouts.data(), timeouts.size());
442 }
443
getUidReadTimeouts(const Control & control)444 inline std::optional<std::vector<UidReadTimeouts>> getUidReadTimeouts(const Control& control) {
445 std::vector<UidReadTimeouts> timeouts(32);
446 size_t count = timeouts.size();
447 auto res = IncFs_GetUidReadTimeouts(control, timeouts.data(), &count);
448 if (res == -E2BIG) {
449 timeouts.resize(count);
450 res = IncFs_GetUidReadTimeouts(control, timeouts.data(), &count);
451 }
452 if (res) {
453 errno = -res;
454 return {};
455 }
456 timeouts.resize(count);
457 return std::move(timeouts);
458 }
459
reserveSpace(const Control & control,std::string_view path,Size size)460 inline ErrorCode reserveSpace(const Control& control, std::string_view path, Size size) {
461 return IncFs_ReserveSpaceByPath(control, details::c_str(path), size);
462 }
reserveSpace(const Control & control,FileId id,Size size)463 inline ErrorCode reserveSpace(const Control& control, FileId id, Size size) {
464 return IncFs_ReserveSpaceById(control, id, size);
465 }
466
getMetrics(std::string_view sysfsName)467 inline std::optional<Metrics> getMetrics(std::string_view sysfsName) {
468 Metrics metrics;
469 if (const auto res = IncFs_GetMetrics(details::c_str(sysfsName), &metrics); res < 0) {
470 errno = -res;
471 return {};
472 }
473 return metrics;
474 }
475
getLastReadError(const Control & control)476 inline std::optional<LastReadError> getLastReadError(const Control& control) {
477 LastReadError lastReadError;
478 if (const auto res = IncFs_GetLastReadError(control, &lastReadError); res < 0) {
479 errno = -res;
480 return {};
481 }
482 return lastReadError;
483 }
484
485 } // namespace android::incfs
486
487 inline bool operator==(const IncFsFileId& l, const IncFsFileId& r) {
488 return memcmp(&l, &r, sizeof(l)) == 0;
489 }
490