Skip to content

Commit

Permalink
Split Area to QuotaArea and TransactionsArea (#58)
Browse files Browse the repository at this point in the history
Continue with area creation code
  • Loading branch information
koolkdev authored Apr 23, 2024
1 parent 4f07f2a commit 8a038a9
Show file tree
Hide file tree
Showing 21 changed files with 471 additions and 238 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,12 @@ add_library(${PROJECT_NAME}
src/ftrees.cpp
src/key_file.cpp
src/ptree.cpp
src/quota_area.cpp
src/recovery.cpp
src/rtree.cpp
src/structs.cpp
src/sub_block_allocator.cpp
src/transactions_area.cpp
src/wfs_device.cpp
src/wfs_item.cpp
)
Expand Down
6 changes: 3 additions & 3 deletions include/wfslib/directory.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ struct DirectoryTreeNode;
class Directory : public WfsItem, public std::enable_shared_from_this<Directory> {
public:
// TODO: Replace name with tree iterator?
Directory(std::string name, AttributesRef attributes, std::shared_ptr<Area> area, std::shared_ptr<Block> block);
Directory(std::string name, AttributesRef attributes, std::shared_ptr<QuotaArea> quota, std::shared_ptr<Block> block);

std::expected<std::shared_ptr<WfsItem>, WfsError> GetObject(const std::string& name) const;
std::expected<std::shared_ptr<Directory>, WfsError> GetDirectory(const std::string& name) const;
Expand All @@ -34,14 +34,14 @@ class Directory : public WfsItem, public std::enable_shared_from_this<Directory>
DirectoryItemsIterator begin() const;
DirectoryItemsIterator end() const;

const std::shared_ptr<Area>& area() const { return area_; }
const std::shared_ptr<QuotaArea>& quota() const { return quota_; }

private:
friend DirectoryItemsIterator;
friend class Recovery;

// TODO: We may have cyclic reference here if we do cache in area.
std::shared_ptr<Area> area_;
std::shared_ptr<QuotaArea> quota_;

std::shared_ptr<Block> block_;

Expand Down
10 changes: 5 additions & 5 deletions include/wfslib/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#include <vector>
#include "wfs_item.h"

class Area;
class QuotaArea;

class File : public WfsItem, public std::enable_shared_from_this<File> {
public:
Expand All @@ -26,8 +26,8 @@ class File : public WfsItem, public std::enable_shared_from_this<File> {
class DataCategory3Reader;
class DataCategory4Reader;

File(std::string name, AttributesRef attributes, std::shared_ptr<Area> area)
: WfsItem(std::move(name), std::move(attributes)), area_(std::move(area)) {}
File(std::string name, AttributesRef attributes, std::shared_ptr<QuotaArea> quota)
: WfsItem(std::move(name), std::move(attributes)), quota_(std::move(quota)) {}

uint32_t Size() const;
uint32_t SizeOnDisk() const;
Expand All @@ -54,10 +54,10 @@ class File : public WfsItem, public std::enable_shared_from_this<File> {
typedef boost::iostreams::stream<file_device> stream;

private:
std::shared_ptr<Area> area() const { return area_; }
std::shared_ptr<QuotaArea> quota() const { return quota_; }

// TODO: We may have cyclic reference here if we do cache in area.
std::shared_ptr<Area> area_;
std::shared_ptr<QuotaArea> quota_;

static std::shared_ptr<DataCategoryReader> CreateReader(std::shared_ptr<File> file);
};
8 changes: 4 additions & 4 deletions include/wfslib/link.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@

#include "wfs_item.h"

class Area;
class QuotaArea;

class Link : public WfsItem, public std::enable_shared_from_this<Link> {
public:
Link(std::string name, AttributesRef attributes, std::shared_ptr<Area> area)
: WfsItem(std::move(name), std::move(attributes)), area_(std::move(area)) {}
Link(std::string name, AttributesRef attributes, std::shared_ptr<QuotaArea> quota)
: WfsItem(std::move(name), std::move(attributes)), quota_(std::move(quota)) {}

private:
// TODO: We may have cyclic reference here if we do cache in area.
std::shared_ptr<Area> area_;
std::shared_ptr<QuotaArea> quota_;
};
17 changes: 12 additions & 5 deletions include/wfslib/wfs_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

class BlocksDevice;
class Area;
class QuotaArea;
class TransactionsArea;
class WfsItem;
class File;
class Directory;
Expand All @@ -36,12 +38,12 @@ class WfsDevice : public std::enable_shared_from_this<WfsDevice> {
std::shared_ptr<File> GetFile(const std::string& filename);
std::shared_ptr<Directory> GetDirectory(const std::string& filename);

std::shared_ptr<Area> GetRootArea();
std::shared_ptr<QuotaArea> GetRootArea();
std::expected<std::shared_ptr<Directory>, WfsError> GetRootDirectory();

void Flush();

std::expected<std::shared_ptr<Area>, WfsError> GetTransactionsArea(bool backup_area = false);
std::expected<std::shared_ptr<TransactionsArea>, WfsError> GetTransactionsArea(bool backup_area = false);

std::expected<std::shared_ptr<Block>, WfsError> LoadMetadataBlock(const Area* area,
uint32_t device_block_number,
Expand All @@ -55,19 +57,24 @@ class WfsDevice : public std::enable_shared_from_this<WfsDevice> {
bool encrypted,
bool new_block = false) const;

uint32_t CalcIV(const Area* area, uint32_t device_block_number) const;

static std::expected<std::shared_ptr<WfsDevice>, WfsError> Open(std::shared_ptr<BlocksDevice> device);
// Create
static std::expected<std::shared_ptr<WfsDevice>, WfsError> Create(std::shared_ptr<BlocksDevice> device);

private:
friend class Area;
friend class QuotaArea;

void Init();

uint32_t CalcIV(const Area* area, uint32_t device_block_number) const;

static constexpr uint16_t header_offset() { return sizeof(MetadataBlockHeader); }

auto* mutable_header() { return root_block_->get_mutable_object<WfsDeviceHeader>(header_offset()); }
const auto* header() const { return root_block_->get_object<WfsDeviceHeader>(header_offset()); }

const std::shared_ptr<Block>& root_block() const { return root_block_; }

std::shared_ptr<BlocksDevice> device_;
std::shared_ptr<Block> root_block_;
};
4 changes: 2 additions & 2 deletions include/wfslib/wfs_item.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#include "block.h"
#include "structs.h"

class Area;
class QuotaArea;

struct AttributesRef {
std::shared_ptr<Block> block;
Expand All @@ -34,7 +34,7 @@ class WfsItem {
bool is_link() const { return attributes()->is_link(); }
bool is_quota() const { return attributes()->is_directory() && attributes()->is_quota(); }

static std::expected<std::shared_ptr<WfsItem>, WfsError> Load(std::shared_ptr<Area> area,
static std::expected<std::shared_ptr<WfsItem>, WfsError> Load(std::shared_ptr<QuotaArea> quota,
std::string name,
AttributesRef attributes_ref);

Expand Down
126 changes: 4 additions & 122 deletions src/area.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,102 +10,28 @@
#include <numeric>
#include <random>

#include "directory.h"
#include "free_blocks_allocator.h"
#include "wfs_device.h"

Area::Area(std::shared_ptr<WfsDevice> wfs_device, std::shared_ptr<Block> header_block)
: wfs_device_(std::move(wfs_device)), header_block_(std::move(header_block)) {}

// static
#if 0
std::expected<std::shared_ptr<Area>, WfsError> Area::CreateRootArea(const std::shared_ptr<BlocksDevice>& device) {
constexpr uint32_t kTransactionsAreaEnd = 0x1000;

auto block = MetadataBlock::LoadBlock(device, /*block_number=*/0, Block::BlockSize::Regular, /*iv=*/0,
/*check_hash=*/false, /*load_data=*/false);
if (!block.has_value()) {
return std::unexpected(block.error());
}

uint32_t blocks_count =
device->device()->SectorsCount() >> (Block::BlockSize::Regular - device->device()->Log2SectorSize());

AttributesBlock attributes{*block, sizeof(MetadataBlockHeader) + offsetof(WfsHeader, root_area_attributes)};
auto area = std::make_shared<Area>(device, nullptr, *block, "", attributes);

void Area::Init(std::shared_ptr<Area> parent_area, uint32_t blocks_count, Block::BlockSize block_size) {
std::random_device rand_device;
std::default_random_engine rand_engine{rand_device()};
std::uniform_int_distribution<uint32_t> random_iv_generator(std::numeric_limits<uint32_t>::min(),
std::numeric_limits<uint32_t>::max());

auto* header = area->mutable_header();
auto* header = mutable_header();
std::fill(reinterpret_cast<std::byte*>(header), reinterpret_cast<std::byte*>(header + 1), std::byte{0});
header->iv = random_iv_generator(rand_engine);
header->blocks_count = blocks_count;
header->root_directory_block_number = kRootDirectoryBlockNumber;
header->shadow_directory_block_number_1 = kShadowDirectory1BlockNumber;
header->shadow_directory_block_number_2 = kShadowDirectory2BlockNumber;
header->depth = 0;
header->block_size_log2 = static_cast<uint8_t>(Block::BlockSize::Regular);
header->depth = parent_area ? parent_area->header()->depth.value() + 1 : 0;
header->block_size_log2 = static_cast<uint8_t>(block_size);
header->large_block_size_log2 = header->block_size_log2.value() + static_cast<uint8_t>(Block::BlockSizeType::Large);
header->large_block_cluster_size_log2 =
header->block_size_log2.value() + static_cast<uint8_t>(Block::BlockSizeType::LargeCluster);
header->area_type = static_cast<uint8_t>(WfsAreaHeader::AreaType::QuotaArea);
header->maybe_always_zero = 0;
header->remainder_blocks_count = 0;
header->first_fragments[0].block_number = 0;
header->first_fragments[0].blocks_count = area->ToAbsoluteBlocksCount(blocks_count);
header->fragments_log2_block_size = static_cast<uint32_be_t>(Block::BlockSize::Basic);

auto* wfs_header = area->mutable_wfs_header();
std::fill(reinterpret_cast<std::byte*>(wfs_header), reinterpret_cast<std::byte*>(wfs_header + 1), std::byte{0});
wfs_header->iv = random_iv_generator(rand_engine);
wfs_header->device_type = static_cast<uint16_t>(DeviceType::USB); // TODO
wfs_header->version = WFS_VERSION;
wfs_header->root_area_attributes.flags = Attributes::DIRECTORY | Attributes::AREA_SIZE_REGULAR | Attributes::QUOTA;
wfs_header->root_area_attributes.blocks_count = blocks_count;
wfs_header->transactions_area_block_number = area->ToAbsoluteBlockNumber(kTransactionsBlockNumber);
wfs_header->transactions_area_blocks_count =
kTransactionsAreaEnd - wfs_header->transactions_area_block_number.value();

// Initialize FreeBlocksAllocator:
auto free_blocks_allocator_block = area->GetMetadataBlock(kFreeBlocksAllocatorBlockNumber, /*new_block=*/true);
if (!free_blocks_allocator_block.has_value()) {
return std::unexpected(free_blocks_allocator_block.error());
}
auto free_blocks_allocator = std::make_unique<FreeBlocksAllocator>(area, std::move(*free_blocks_allocator_block));
free_blocks_allocator->Init();

// TODO: Initialize:
// 1. Root directory
// 2. shadow directories
// 3. Transactions area

return area;
}
#endif

std::expected<std::shared_ptr<Directory>, WfsError> Area::LoadDirectory(uint32_t area_block_number,
std::string name,
AttributesRef attributes) {
auto block = LoadMetadataBlock(area_block_number);
if (!block.has_value())
return std::unexpected(WfsError::kDirectoryCorrupted);
return std::make_shared<Directory>(std::move(name), std::move(attributes), shared_from_this(), std::move(*block));
}

std::expected<std::shared_ptr<Directory>, WfsError> Area::LoadRootDirectory(std::string name,
AttributesRef attributes) {
return LoadDirectory(header()->root_directory_block_number.value(), std::move(name), std::move(attributes));
}

std::expected<std::shared_ptr<Directory>, WfsError> Area::GetShadowDirectory1() {
return LoadDirectory(header()->shadow_directory_block_number_1.value(), ".shadow_dir_1", {});
}

std::expected<std::shared_ptr<Directory>, WfsError> Area::GetShadowDirectory2() {
return LoadDirectory(header()->shadow_directory_block_number_2.value(), ".shadow_dir_2", {});
}

std::expected<std::shared_ptr<Area>, WfsError> Area::GetArea(uint32_t area_block_number, Block::BlockSize size) {
Expand Down Expand Up @@ -135,47 +61,3 @@ std::expected<std::shared_ptr<Block>, WfsError> Area::LoadDataBlock(uint32_t are
return wfs_device_->LoadDataBlock(this, to_device_block_number(area_block_number), size, data_size,
std::move(data_hash), encrypted, new_block);
}

std::expected<std::shared_ptr<FreeBlocksAllocator>, WfsError> Area::GetFreeBlocksAllocator() {
auto block = LoadMetadataBlock(kFreeBlocksAllocatorBlockNumber);
if (!block.has_value())
return std::unexpected(WfsError::kFreeBlocksAllocatorCorrupted);
return std::make_unique<FreeBlocksAllocator>(shared_from_this(), std::move(*block));
}

uint32_t Area::ReservedBlocksCount() const {
uint32_t reserved_blocks = kReservedAreaBlocks;
if (is_root_area()) {
// Root area also reserve for transaction
reserved_blocks += to_area_blocks_count(wfs_device_->header()->transactions_area_blocks_count.value());
}
return reserved_blocks;
}

std::expected<std::shared_ptr<Block>, WfsError> Area::AllocMetadataBlock() {
auto allocator = GetFreeBlocksAllocator();
if (!allocator)
return std::unexpected(allocator.error());
auto res = (*allocator)->AllocBlocks(1, Block::BlockSizeType::Single, true);
if (!res)
return std::unexpected(kNoSpace);
return LoadMetadataBlock((*res)[0], /*new_block=*/true);
}

std::expected<std::vector<uint32_t>, WfsError> Area::AllocDataBlocks(uint32_t chunks_count,
Block::BlockSizeType chunk_size) {
auto allocator = GetFreeBlocksAllocator();
if (!allocator)
return std::unexpected(allocator.error());
auto res = (*allocator)->AllocBlocks(chunks_count, chunk_size, false);
if (!res)
return std::unexpected(kNoSpace);
return *res;
}

bool Area::DeleteBlocks(uint32_t block_number, uint32_t blocks_count) {
auto allocator = GetFreeBlocksAllocator();
if (!allocator)
return false;
return (*allocator)->AddFreeBlocks({block_number, blocks_count});
}
42 changes: 9 additions & 33 deletions src/area.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,15 @@
#include "structs.h"

class WfsDevice;
class Directory;
class FreeBlocksAllocator;
struct AttributesRef;

class Area : public std::enable_shared_from_this<Area> {
class Area {
public:
Area(std::shared_ptr<WfsDevice> wfs_device, std::shared_ptr<Block> header_block);

// static std::expected<std::shared_ptr<Area>, WfsError> CreateRootArea(const std::shared_ptr<BlocksDevice>& device);
// TODO Create transactions area

std::expected<std::shared_ptr<Area>, WfsError> GetArea(uint32_t area_block_number, Block::BlockSize size);

std::expected<std::shared_ptr<Directory>, WfsError> LoadRootDirectory(std::string name, AttributesRef attributes);
std::expected<std::shared_ptr<Directory>, WfsError> GetShadowDirectory1();
std::expected<std::shared_ptr<Directory>, WfsError> GetShadowDirectory2();

std::expected<std::shared_ptr<Directory>, WfsError> LoadDirectory(uint32_t area_block_number,
std::string name,
AttributesRef attributes);

std::expected<std::shared_ptr<Block>, WfsError> LoadMetadataBlock(uint32_t area_block_number,
bool new_block = false) const;
std::expected<std::shared_ptr<Block>, WfsError> LoadMetadataBlock(uint32_t area_block_number,
Expand All @@ -47,11 +36,6 @@ class Area : public std::enable_shared_from_this<Area> {
bool encrypted,
bool new_block = false) const;

std::expected<std::shared_ptr<Block>, WfsError> AllocMetadataBlock();
std::expected<std::vector<uint32_t>, WfsError> AllocDataBlocks(uint32_t chunks_count,
Block::BlockSizeType chunk_size);
bool DeleteBlocks(uint32_t area_block_number, uint32_t area_blocks_count);

uint32_t to_area_block_number(uint32_t device_block_number) const {
return to_area_blocks_count(device_block_number - header_block_->device_block_number());
}
Expand All @@ -76,34 +60,26 @@ class Area : public std::enable_shared_from_this<Area> {
// In area blocks count
uint32_t blocks_count() const { return header()->blocks_count.value(); }

uint32_t ReservedBlocksCount() const;

std::expected<std::shared_ptr<FreeBlocksAllocator>, WfsError> GetFreeBlocksAllocator();

private:
protected:
friend class Recovery;
friend class WfsDevice;
friend class TestArea;

static constexpr uint32_t kFreeBlocksAllocatorBlockNumber = 1;
static constexpr uint32_t kFreeBlocksAllocatorInitialFTreeBlockNumber = 2;
static constexpr uint32_t kRootDirectoryBlockNumber = 3;
static constexpr uint32_t kShadowDirectory1BlockNumber = 4;
static constexpr uint32_t kShadowDirectory2BlockNumber = 5;
static constexpr uint32_t kReservedAreaBlocks = 6;
void Init(std::shared_ptr<Area> parent_area, uint32_t blocks_count, Block::BlockSize block_size);

static constexpr uint32_t kTransactionsBlockNumber = 6;
const std::shared_ptr<Block>& header_block() const { return header_block_; };

bool is_root_area() const { return device_block_number() == 0; }
uint16_t header_offset() const {
return sizeof(MetadataBlockHeader) + (is_root_area() ? sizeof(WfsDeviceHeader) : 0);
}

WfsAreaHeader* mutable_header() { return header_block_->get_mutable_object<WfsAreaHeader>(header_offset()); }
const WfsAreaHeader* header() const { return header_block_->get_object<WfsAreaHeader>(header_offset()); }

uint32_t IV(uint32_t block_number) const;
const std::shared_ptr<WfsDevice>& wfs_device() { return wfs_device_; }

bool is_root_area() const { return device_block_number() == 0; }

private:
std::shared_ptr<WfsDevice> wfs_device_;
std::shared_ptr<Block> header_block_;
};
Loading

0 comments on commit 8a038a9

Please sign in to comment.