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 <unistd.h> 19 20 #include <array> 21 #include <chrono> 22 #include <functional> 23 #include <optional> 24 #include <string> 25 #include <string_view> 26 #include <utility> 27 #include <vector> 28 29 #include "incfs_ndk.h" 30 31 namespace android::incfs { 32 33 using ByteBuffer = std::vector<char>; 34 35 enum MountFlags { 36 createOnly = INCFS_MOUNT_CREATE_ONLY, 37 truncate = INCFS_MOUNT_TRUNCATE, 38 }; 39 40 enum Features { 41 none = INCFS_FEATURE_NONE, 42 core = INCFS_FEATURE_CORE, 43 v2 = INCFS_FEATURE_V2, 44 mappingFilesProgressFixed = INCFS_FEATURE_MAPPING_FILES_PROGRESS_FIXED, 45 }; 46 47 enum class HashAlgorithm { 48 none = INCFS_HASH_NONE, 49 sha256 = INCFS_HASH_SHA256, 50 }; 51 52 enum class CompressionKind { 53 none = INCFS_COMPRESSION_KIND_NONE, 54 lz4 = INCFS_COMPRESSION_KIND_LZ4, 55 zstd = INCFS_COMPRESSION_KIND_ZSTD, 56 }; 57 58 enum class BlockKind { 59 data = INCFS_BLOCK_KIND_DATA, 60 hash = INCFS_BLOCK_KIND_HASH, 61 }; 62 63 class UniqueFd { 64 public: UniqueFd(int fd)65 explicit UniqueFd(int fd) : fd_(fd) {} UniqueFd()66 UniqueFd() : UniqueFd(-1) {} ~UniqueFd()67 ~UniqueFd() { close(); } UniqueFd(UniqueFd && other)68 UniqueFd(UniqueFd&& other) noexcept : fd_(other.release()) {} 69 UniqueFd& operator=(UniqueFd&& other) noexcept { 70 close(); 71 fd_ = other.release(); 72 return *this; 73 } 74 close()75 void close() { 76 if (ok()) { 77 ::close(fd_); 78 fd_ = -1; 79 } 80 } get()81 int get() const { return fd_; } ok()82 [[nodiscard]] bool ok() const { return fd_ >= 0; } release()83 [[nodiscard]] int release() { return std::exchange(fd_, -1); } 84 85 private: 86 int fd_; 87 }; 88 89 class UniqueControl { 90 public: mControl(control)91 UniqueControl(IncFsControl* control = nullptr) : mControl(control) {} ~UniqueControl()92 ~UniqueControl() { close(); } UniqueControl(UniqueControl && other)93 UniqueControl(UniqueControl&& other) noexcept 94 : mControl(std::exchange(other.mControl, nullptr)) {} 95 UniqueControl& operator=(UniqueControl&& other) noexcept { 96 close(); 97 mControl = std::exchange(other.mControl, nullptr); 98 return *this; 99 } 100 101 IncFsFd cmd() const; 102 IncFsFd pendingReads() const; 103 IncFsFd logs() const; 104 IncFsFd blocksWritten() const; 105 106 void close(); 107 108 operator IncFsControl*() const { return mControl; } 109 110 using Fds = std::array<UniqueFd, IncFsFdType::FDS_COUNT>; 111 [[nodiscard]] Fds releaseFds(); 112 113 private: 114 IncFsControl* mControl; 115 }; 116 117 // A mini version of std::span 118 template <class T> 119 class Span { 120 public: 121 using iterator = T*; 122 using const_iterator = const T*; 123 Span(T * array,size_t length)124 constexpr Span(T* array, size_t length) : ptr_(array), len_(length) {} 125 template <typename V> Span(const std::vector<V> & x)126 constexpr Span(const std::vector<V>& x) : Span(x.data(), x.size()) {} 127 template <typename V, size_t Size> Span(V (& x)[Size])128 constexpr Span(V (&x)[Size]) : Span(x, Size) {} 129 data()130 constexpr T* data() const { return ptr_; } size()131 constexpr size_t size() const { return len_; } 132 constexpr T& operator[](size_t i) const { return *(data() + i); } begin()133 constexpr iterator begin() const { return data(); } cbegin()134 constexpr const_iterator cbegin() const { return begin(); } end()135 constexpr iterator end() const { return data() + size(); } cend()136 constexpr const_iterator cend() const { return end(); } 137 138 private: 139 T* ptr_; 140 size_t len_; 141 }; 142 143 struct BlockRange final : public IncFsBlockRange { sizefinal144 constexpr size_t size() const { return end - begin; } emptyfinal145 constexpr bool empty() const { return end == begin; } 146 }; 147 148 class FilledRanges final { 149 public: 150 using RangeBuffer = std::vector<BlockRange>; 151 152 FilledRanges() = default; FilledRanges(RangeBuffer && buffer,IncFsFilledRanges ranges)153 FilledRanges(RangeBuffer&& buffer, IncFsFilledRanges ranges) 154 : buffer_(std::move(buffer)), rawFilledRanges_(ranges) {} 155 dataRanges()156 constexpr Span<BlockRange> dataRanges() const { 157 return {(BlockRange*)rawFilledRanges_.dataRanges, (size_t)rawFilledRanges_.dataRangesCount}; 158 } hashRanges()159 constexpr Span<BlockRange> hashRanges() const { 160 return {(BlockRange*)rawFilledRanges_.hashRanges, (size_t)rawFilledRanges_.hashRangesCount}; 161 } 162 totalSize()163 constexpr size_t totalSize() const { return dataRanges().size() + hashRanges().size(); } 164 extractInternalBufferAndClear()165 RangeBuffer extractInternalBufferAndClear() { 166 rawFilledRanges_ = {}; 167 return std::move(buffer_); 168 } 169 internalBuffer()170 constexpr const RangeBuffer& internalBuffer() const { return buffer_; } internalRawRanges()171 constexpr IncFsFilledRanges internalRawRanges() const { return rawFilledRanges_; } 172 173 private: 174 RangeBuffer buffer_; 175 IncFsFilledRanges rawFilledRanges_; 176 }; 177 178 using Control = UniqueControl; 179 180 using FileId = IncFsFileId; 181 using Size = IncFsSize; 182 using BlockIndex = IncFsBlockIndex; 183 using ErrorCode = IncFsErrorCode; 184 using Fd = IncFsFd; 185 using Uid = IncFsUid; 186 using ReadInfo = IncFsReadInfo; 187 using ReadInfoWithUid = IncFsReadInfoWithUid; 188 using RawMetadata = ByteBuffer; 189 using RawSignature = ByteBuffer; 190 using MountOptions = IncFsMountOptions; 191 using DataBlock = IncFsDataBlock; 192 using NewFileParams = IncFsNewFileParams; 193 using NewMappedFileParams = IncFsNewMappedFileParams; 194 using BlockCounts = IncFsBlockCounts; 195 using UidReadTimeouts = IncFsUidReadTimeouts; 196 using Metrics = IncFsMetrics; 197 using LastReadError = IncFsLastReadError; 198 199 constexpr auto kDefaultReadTimeout = std::chrono::milliseconds(INCFS_DEFAULT_READ_TIMEOUT_MS); 200 constexpr int kBlockSize = INCFS_DATA_FILE_BLOCK_SIZE; 201 const auto kInvalidFileId = kIncFsInvalidFileId; 202 const auto kNoUid = kIncFsNoUid; 203 204 bool enabled(); 205 Features features(); 206 bool isValidFileId(FileId fileId); 207 std::string toString(FileId fileId); 208 IncFsFileId toFileId(std::string_view str); 209 bool isIncFsFd(int fd); 210 bool isIncFsPath(std::string_view path); 211 212 UniqueControl mount(std::string_view backingPath, std::string_view targetDir, 213 IncFsMountOptions options); 214 UniqueControl open(std::string_view dir); 215 UniqueControl createControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs, IncFsFd blocksWritten); 216 217 ErrorCode setOptions(const Control& control, MountOptions newOptions); 218 219 ErrorCode bindMount(std::string_view sourceDir, std::string_view targetDir); 220 ErrorCode unmount(std::string_view dir); 221 222 std::string root(const Control& control); 223 224 ErrorCode makeFile(const Control& control, std::string_view path, int mode, FileId fileId, 225 NewFileParams params); 226 ErrorCode makeMappedFile(const Control& control, std::string_view path, int mode, 227 NewMappedFileParams params); 228 ErrorCode makeDir(const Control& control, std::string_view path, int mode = 0555); 229 ErrorCode makeDirs(const Control& control, std::string_view path, int mode = 0555); 230 231 RawMetadata getMetadata(const Control& control, FileId fileId); 232 RawMetadata getMetadata(const Control& control, std::string_view path); 233 FileId getFileId(const Control& control, std::string_view path); 234 235 RawSignature getSignature(const Control& control, FileId fileId); 236 RawSignature getSignature(const Control& control, std::string_view path); 237 238 ErrorCode link(const Control& control, std::string_view sourcePath, std::string_view targetPath); 239 ErrorCode unlink(const Control& control, std::string_view path); 240 241 enum class WaitResult { HaveData, Timeout, Error }; 242 243 WaitResult waitForPendingReads(const Control& control, std::chrono::milliseconds timeout, 244 std::vector<ReadInfo>* pendingReadsBuffer); 245 WaitResult waitForPageReads(const Control& control, std::chrono::milliseconds timeout, 246 std::vector<ReadInfo>* pageReadsBuffer); 247 WaitResult waitForPendingReads(const Control& control, std::chrono::milliseconds timeout, 248 std::vector<ReadInfoWithUid>* pendingReadsBuffer); 249 WaitResult waitForPageReads(const Control& control, std::chrono::milliseconds timeout, 250 std::vector<ReadInfoWithUid>* pageReadsBuffer); 251 252 UniqueFd openForSpecialOps(const Control& control, FileId fileId); 253 UniqueFd openForSpecialOps(const Control& control, std::string_view path); 254 ErrorCode writeBlocks(Span<const DataBlock> blocks); 255 256 std::pair<ErrorCode, FilledRanges> getFilledRanges(int fd); 257 std::pair<ErrorCode, FilledRanges> getFilledRanges(int fd, FilledRanges::RangeBuffer&& buffer); 258 std::pair<ErrorCode, FilledRanges> getFilledRanges(int fd, FilledRanges&& resumeFrom); 259 260 ErrorCode setUidReadTimeouts(const Control& control, Span<const UidReadTimeouts> timeouts); 261 std::optional<std::vector<UidReadTimeouts>> getUidReadTimeouts(const Control& control); 262 263 std::optional<BlockCounts> getBlockCount(const Control& control, FileId fileId); 264 std::optional<BlockCounts> getBlockCount(const Control& control, std::string_view path); 265 266 std::optional<std::vector<FileId>> listIncompleteFiles(const Control& control); 267 268 template <class Callback> 269 ErrorCode forEachFile(const Control& control, Callback&& cb); 270 template <class Callback> 271 ErrorCode forEachIncompleteFile(const Control& control, Callback&& cb); 272 273 WaitResult waitForLoadingComplete(const Control& control, std::chrono::milliseconds timeout); 274 275 enum class LoadingState { Full, MissingBlocks }; 276 LoadingState isFullyLoaded(int fd); 277 LoadingState isFullyLoaded(const Control& control, std::string_view path); 278 LoadingState isFullyLoaded(const Control& control, FileId fileId); 279 LoadingState isEverythingFullyLoaded(const Control& control); 280 281 static const auto kTrimReservedSpace = kIncFsTrimReservedSpace; 282 ErrorCode reserveSpace(const Control& control, std::string_view path, Size size); 283 ErrorCode reserveSpace(const Control& control, FileId id, Size size); 284 285 std::optional<Metrics> getMetrics(std::string_view sysfsName); 286 std::optional<LastReadError> getLastReadError(const Control& control); 287 288 // Some internal secret API as well that's not backed by C API yet. 289 class MountRegistry; 290 MountRegistry& defaultMountRegistry(); 291 292 } // namespace android::incfs 293 294 bool operator==(const IncFsFileId& l, const IncFsFileId& r); 295 inline bool operator!=(const IncFsFileId& l, const IncFsFileId& r) { 296 return !(l == r); 297 } 298 299 namespace std { 300 301 template <> 302 struct hash<IncFsFileId> { 303 size_t operator()(const IncFsFileId& id) const noexcept { 304 return std::hash<std::string_view>()({&id.data[0], sizeof(id)}); 305 } 306 }; 307 308 } // namespace std 309 310 #include "incfs_inline.h" 311