You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
310 lines
10 KiB
310 lines
10 KiB
/*
|
|
* Copyright (C) 2019 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#pragma once
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <array>
|
|
#include <chrono>
|
|
#include <functional>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "incfs_ndk.h"
|
|
|
|
namespace android::incfs {
|
|
|
|
using ByteBuffer = std::vector<char>;
|
|
|
|
enum MountFlags {
|
|
createOnly = INCFS_MOUNT_CREATE_ONLY,
|
|
truncate = INCFS_MOUNT_TRUNCATE,
|
|
};
|
|
|
|
enum Features {
|
|
none = INCFS_FEATURE_NONE,
|
|
core = INCFS_FEATURE_CORE,
|
|
v2 = INCFS_FEATURE_V2,
|
|
};
|
|
|
|
enum class HashAlgorithm {
|
|
none = INCFS_HASH_NONE,
|
|
sha256 = INCFS_HASH_SHA256,
|
|
};
|
|
|
|
enum class CompressionKind {
|
|
none = INCFS_COMPRESSION_KIND_NONE,
|
|
lz4 = INCFS_COMPRESSION_KIND_LZ4,
|
|
zstd = INCFS_COMPRESSION_KIND_ZSTD,
|
|
};
|
|
|
|
enum class BlockKind {
|
|
data = INCFS_BLOCK_KIND_DATA,
|
|
hash = INCFS_BLOCK_KIND_HASH,
|
|
};
|
|
|
|
class UniqueFd {
|
|
public:
|
|
explicit UniqueFd(int fd) : fd_(fd) {}
|
|
UniqueFd() : UniqueFd(-1) {}
|
|
~UniqueFd() { close(); }
|
|
UniqueFd(UniqueFd&& other) noexcept : fd_(other.release()) {}
|
|
UniqueFd& operator=(UniqueFd&& other) noexcept {
|
|
close();
|
|
fd_ = other.release();
|
|
return *this;
|
|
}
|
|
|
|
void close() {
|
|
if (ok()) {
|
|
::close(fd_);
|
|
fd_ = -1;
|
|
}
|
|
}
|
|
int get() const { return fd_; }
|
|
[[nodiscard]] bool ok() const { return fd_ >= 0; }
|
|
[[nodiscard]] int release() { return std::exchange(fd_, -1); }
|
|
|
|
private:
|
|
int fd_;
|
|
};
|
|
|
|
class UniqueControl {
|
|
public:
|
|
UniqueControl(IncFsControl* control = nullptr) : mControl(control) {}
|
|
~UniqueControl() { close(); }
|
|
UniqueControl(UniqueControl&& other) noexcept
|
|
: mControl(std::exchange(other.mControl, nullptr)) {}
|
|
UniqueControl& operator=(UniqueControl&& other) noexcept {
|
|
close();
|
|
mControl = std::exchange(other.mControl, nullptr);
|
|
return *this;
|
|
}
|
|
|
|
IncFsFd cmd() const;
|
|
IncFsFd pendingReads() const;
|
|
IncFsFd logs() const;
|
|
IncFsFd blocksWritten() const;
|
|
|
|
void close();
|
|
|
|
operator IncFsControl*() const { return mControl; }
|
|
|
|
using Fds = std::array<UniqueFd, IncFsFdType::FDS_COUNT>;
|
|
[[nodiscard]] Fds releaseFds();
|
|
|
|
private:
|
|
IncFsControl* mControl;
|
|
};
|
|
|
|
// A mini version of std::span
|
|
template <class T>
|
|
class Span {
|
|
public:
|
|
using iterator = T*;
|
|
using const_iterator = const T*;
|
|
|
|
constexpr Span(T* array, size_t length) : ptr_(array), len_(length) {}
|
|
template <typename V>
|
|
constexpr Span(const std::vector<V>& x) : Span(x.data(), x.size()) {}
|
|
template <typename V, size_t Size>
|
|
constexpr Span(V (&x)[Size]) : Span(x, Size) {}
|
|
|
|
constexpr T* data() const { return ptr_; }
|
|
constexpr size_t size() const { return len_; }
|
|
constexpr T& operator[](size_t i) const { return *(data() + i); }
|
|
constexpr iterator begin() const { return data(); }
|
|
constexpr const_iterator cbegin() const { return begin(); }
|
|
constexpr iterator end() const { return data() + size(); }
|
|
constexpr const_iterator cend() const { return end(); }
|
|
|
|
private:
|
|
T* ptr_;
|
|
size_t len_;
|
|
};
|
|
|
|
struct BlockRange final : public IncFsBlockRange {
|
|
constexpr size_t size() const { return end - begin; }
|
|
constexpr bool empty() const { return end == begin; }
|
|
};
|
|
|
|
class FilledRanges final {
|
|
public:
|
|
using RangeBuffer = std::vector<BlockRange>;
|
|
|
|
FilledRanges() = default;
|
|
FilledRanges(RangeBuffer&& buffer, IncFsFilledRanges ranges)
|
|
: buffer_(std::move(buffer)), rawFilledRanges_(ranges) {}
|
|
|
|
constexpr Span<BlockRange> dataRanges() const {
|
|
return {(BlockRange*)rawFilledRanges_.dataRanges, (size_t)rawFilledRanges_.dataRangesCount};
|
|
}
|
|
constexpr Span<BlockRange> hashRanges() const {
|
|
return {(BlockRange*)rawFilledRanges_.hashRanges, (size_t)rawFilledRanges_.hashRangesCount};
|
|
}
|
|
|
|
constexpr size_t totalSize() const { return dataRanges().size() + hashRanges().size(); }
|
|
|
|
RangeBuffer extractInternalBufferAndClear() {
|
|
rawFilledRanges_ = {};
|
|
return std::move(buffer_);
|
|
}
|
|
|
|
constexpr const RangeBuffer& internalBuffer() const { return buffer_; }
|
|
constexpr IncFsFilledRanges internalRawRanges() const { return rawFilledRanges_; }
|
|
|
|
private:
|
|
RangeBuffer buffer_;
|
|
IncFsFilledRanges rawFilledRanges_;
|
|
};
|
|
|
|
using Control = UniqueControl;
|
|
|
|
using FileId = IncFsFileId;
|
|
using Size = IncFsSize;
|
|
using BlockIndex = IncFsBlockIndex;
|
|
using ErrorCode = IncFsErrorCode;
|
|
using Fd = IncFsFd;
|
|
using Uid = IncFsUid;
|
|
using ReadInfo = IncFsReadInfo;
|
|
using ReadInfoWithUid = IncFsReadInfoWithUid;
|
|
using RawMetadata = ByteBuffer;
|
|
using RawSignature = ByteBuffer;
|
|
using MountOptions = IncFsMountOptions;
|
|
using DataBlock = IncFsDataBlock;
|
|
using NewFileParams = IncFsNewFileParams;
|
|
using NewMappedFileParams = IncFsNewMappedFileParams;
|
|
using BlockCounts = IncFsBlockCounts;
|
|
using UidReadTimeouts = IncFsUidReadTimeouts;
|
|
using Metrics = IncFsMetrics;
|
|
using LastReadError = IncFsLastReadError;
|
|
|
|
constexpr auto kDefaultReadTimeout = std::chrono::milliseconds(INCFS_DEFAULT_READ_TIMEOUT_MS);
|
|
constexpr int kBlockSize = INCFS_DATA_FILE_BLOCK_SIZE;
|
|
const auto kInvalidFileId = kIncFsInvalidFileId;
|
|
const auto kNoUid = kIncFsNoUid;
|
|
|
|
bool enabled();
|
|
Features features();
|
|
bool isValidFileId(FileId fileId);
|
|
std::string toString(FileId fileId);
|
|
IncFsFileId toFileId(std::string_view str);
|
|
bool isIncFsFd(int fd);
|
|
bool isIncFsPath(std::string_view path);
|
|
|
|
UniqueControl mount(std::string_view backingPath, std::string_view targetDir,
|
|
IncFsMountOptions options);
|
|
UniqueControl open(std::string_view dir);
|
|
UniqueControl createControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs, IncFsFd blocksWritten);
|
|
|
|
ErrorCode setOptions(const Control& control, MountOptions newOptions);
|
|
|
|
ErrorCode bindMount(std::string_view sourceDir, std::string_view targetDir);
|
|
ErrorCode unmount(std::string_view dir);
|
|
|
|
std::string root(const Control& control);
|
|
|
|
ErrorCode makeFile(const Control& control, std::string_view path, int mode, FileId fileId,
|
|
NewFileParams params);
|
|
ErrorCode makeMappedFile(const Control& control, std::string_view path, int mode,
|
|
NewMappedFileParams params);
|
|
ErrorCode makeDir(const Control& control, std::string_view path, int mode = 0555);
|
|
ErrorCode makeDirs(const Control& control, std::string_view path, int mode = 0555);
|
|
|
|
RawMetadata getMetadata(const Control& control, FileId fileId);
|
|
RawMetadata getMetadata(const Control& control, std::string_view path);
|
|
FileId getFileId(const Control& control, std::string_view path);
|
|
|
|
RawSignature getSignature(const Control& control, FileId fileId);
|
|
RawSignature getSignature(const Control& control, std::string_view path);
|
|
|
|
ErrorCode link(const Control& control, std::string_view sourcePath, std::string_view targetPath);
|
|
ErrorCode unlink(const Control& control, std::string_view path);
|
|
|
|
enum class WaitResult { HaveData, Timeout, Error };
|
|
|
|
WaitResult waitForPendingReads(const Control& control, std::chrono::milliseconds timeout,
|
|
std::vector<ReadInfo>* pendingReadsBuffer);
|
|
WaitResult waitForPageReads(const Control& control, std::chrono::milliseconds timeout,
|
|
std::vector<ReadInfo>* pageReadsBuffer);
|
|
WaitResult waitForPendingReads(const Control& control, std::chrono::milliseconds timeout,
|
|
std::vector<ReadInfoWithUid>* pendingReadsBuffer);
|
|
WaitResult waitForPageReads(const Control& control, std::chrono::milliseconds timeout,
|
|
std::vector<ReadInfoWithUid>* pageReadsBuffer);
|
|
|
|
UniqueFd openForSpecialOps(const Control& control, FileId fileId);
|
|
UniqueFd openForSpecialOps(const Control& control, std::string_view path);
|
|
ErrorCode writeBlocks(Span<const DataBlock> blocks);
|
|
|
|
std::pair<ErrorCode, FilledRanges> getFilledRanges(int fd);
|
|
std::pair<ErrorCode, FilledRanges> getFilledRanges(int fd, FilledRanges::RangeBuffer&& buffer);
|
|
std::pair<ErrorCode, FilledRanges> getFilledRanges(int fd, FilledRanges&& resumeFrom);
|
|
|
|
ErrorCode setUidReadTimeouts(const Control& control, Span<const UidReadTimeouts> timeouts);
|
|
std::optional<std::vector<UidReadTimeouts>> getUidReadTimeouts(const Control& control);
|
|
|
|
std::optional<BlockCounts> getBlockCount(const Control& control, FileId fileId);
|
|
std::optional<BlockCounts> getBlockCount(const Control& control, std::string_view path);
|
|
|
|
std::optional<std::vector<FileId>> listIncompleteFiles(const Control& control);
|
|
|
|
template <class Callback>
|
|
ErrorCode forEachFile(const Control& control, Callback&& cb);
|
|
template <class Callback>
|
|
ErrorCode forEachIncompleteFile(const Control& control, Callback&& cb);
|
|
|
|
WaitResult waitForLoadingComplete(const Control& control, std::chrono::milliseconds timeout);
|
|
|
|
enum class LoadingState { Full, MissingBlocks };
|
|
LoadingState isFullyLoaded(int fd);
|
|
LoadingState isFullyLoaded(const Control& control, std::string_view path);
|
|
LoadingState isFullyLoaded(const Control& control, FileId fileId);
|
|
LoadingState isEverythingFullyLoaded(const Control& control);
|
|
|
|
static const auto kTrimReservedSpace = kIncFsTrimReservedSpace;
|
|
ErrorCode reserveSpace(const Control& control, std::string_view path, Size size);
|
|
ErrorCode reserveSpace(const Control& control, FileId id, Size size);
|
|
|
|
std::optional<Metrics> getMetrics(std::string_view sysfsName);
|
|
std::optional<LastReadError> getLastReadError(const Control& control);
|
|
|
|
// Some internal secret API as well that's not backed by C API yet.
|
|
class MountRegistry;
|
|
MountRegistry& defaultMountRegistry();
|
|
|
|
} // namespace android::incfs
|
|
|
|
bool operator==(const IncFsFileId& l, const IncFsFileId& r);
|
|
inline bool operator!=(const IncFsFileId& l, const IncFsFileId& r) {
|
|
return !(l == r);
|
|
}
|
|
|
|
namespace std {
|
|
|
|
template <>
|
|
struct hash<IncFsFileId> {
|
|
size_t operator()(const IncFsFileId& id) const noexcept {
|
|
return std::hash<std::string_view>()({&id.data[0], sizeof(id)});
|
|
}
|
|
};
|
|
|
|
} // namespace std
|
|
|
|
#include "incfs_inline.h"
|