blob: 5dfe0605c9880be814f3dc060e777af4797845bb [file] [log] [blame]
/*
* 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,
mappingFilesProgressFixed = INCFS_FEATURE_MAPPING_FILES_PROGRESS_FIXED,
};
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"