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