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