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