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