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