blob: dd25cbd4efa83ed3b3096d69c16605b82ef706ea [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
#ifndef SRC_STORAGE_BLOBFS_BLOB_LAYOUT_H_
#define SRC_STORAGE_BLOBFS_BLOB_LAYOUT_H_
#include <lib/zx/result.h>
#include <zircon/types.h>
#include <type_traits>
#include <safemath/safe_conversions.h>
#include "src/storage/blobfs/format.h"
namespace blobfs {
// Possible formats for how a blob can be layed out in storage.
// This enum is serialized and stored in blobfs's superblock which prevents the enum values from
// being changed.
enum class BlobLayoutFormat : uint8_t {
// THIS VALUE IS DEPRECATED. It is used only on Astro devices. It uses more space because of the
// additional padding to block-align the beginning blob data. Do not add new uses, it will be
// removed once Astro support is no longer needed.
//
// The "Padded Merkle Tree at Start" layout stores the Merkle tree in the padded format at the
// start of the blob. The data is stored at the start of the block following the Merkle tree.
// | block 001 | block 002 | block 003 | block 004 | block 005 | ... | block 579 | block 580 |
// |<- Padded Merkle Tree ->|<- Data ->|
// This is the layout format that was in use prior to the layout format being added to the
// superblock. The new field was added to a section of the superpblock that was already zero and
// to maintain backwards compatibility this enum value has the value zero.
kDeprecatedPaddedMerkleTreeAtStart = 0,
// The "Compact Merkle Tree at End" layout stores the data at the start of the blob. The Merkle
// tree is stored in the compact format after the data and aligned so it ends at the end of the
// blob. The Merkle tree and the data may share a block.
// | block 001 | block 002 | ... | block 576 | block 577 | block 578 | block 579 |
// |<- Data ->| |<- Compact Merkle Tree ->|
kCompactMerkleTreeAtEnd = 1,
};
// Returns enum name for |format|.
const char* BlobLayoutFormatToString(BlobLayoutFormat format);
// Returns whether |format| uses the compact Merkle tree format or not.
bool ShouldUseCompactMerkleTreeFormat(BlobLayoutFormat format);
// Layout information for where the data and Merkle tree are positioned in a blob.
class BlobLayout {
public:
uint64_t blobfs_block_size() const { return blobfs_block_size_; }
// The uncompressed size of the file.
uint64_t FileSize() const;
// The uncompressed size of the file rounded up to the next multiple of the block size.
uint64_t FileBlockAlignedSize() const;
// The number of bytes used to store the blob's data.
// When reading a compressed blob this may not be the exact size but a safe upper bound. All
// bytes between the actual compressed size and |DataSizeUpperBound| will be zeros. This is
// because the size of the compressed file is not stored. See https://fxbug.dev/42120973.
uint64_t DataSizeUpperBound() const;
// The size of buffer required to hold |DataBlockCount| blocks.
uint64_t DataBlockAlignedSize() const;
// The number of blocks that the data spans.
uint64_t DataBlockCount() const;
// The data may not start at the beginning of the blob contents but it will always be on a
// block-aligned offset. The rest of the blob's data will be in the following |DataBlockCount| - 1
// blocks.
virtual uint64_t DataBlockOffset() const = 0;
uint64_t DataOffset() const { return DataBlockOffset() * blobfs_block_size_; }
// The number of bytes required to store the Merkle tree.
uint64_t MerkleTreeSize() const;
// The size of buffer required to hold |MerkleTreeBlockCount| blocks.
uint64_t MerkleTreeBlockAlignedSize() const;
// The number of blocks that the Merkle tree spans.
uint64_t MerkleTreeBlockCount() const;
// Returns the offset within the file for the merkle tree.
virtual uint64_t MerkleTreeOffset() const = 0;
// The first block of the blob containing part of the Merkle tree. The rest of the Merkle tree
// will be in the following |MerkleTreeBlockCount| - 1 blocks.
uint64_t MerkleTreeBlockOffset() const { return MerkleTreeOffset() / blobfs_block_size_; }
// The offset within |MerkleTreeBlockOffset| that the Merkle tree starts at.
uint64_t MerkleTreeOffsetWithinBlockOffset() const {
return MerkleTreeOffset() % blobfs_block_size_;
}
// The total number of blocks that the blob spans.
virtual uint64_t TotalBlockCount() const = 0;
// True if the data and Merkle tree share a block.
virtual bool HasMerkleTreeAndDataSharedBlock() const = 0;
// The format that this layout is in.
virtual BlobLayoutFormat Format() const = 0;
// Initializes a |BlobLayout| from a blob's inode.
static zx::result<std::unique_ptr<BlobLayout>> CreateFromInode(BlobLayoutFormat format,
const Inode& inode,
uint64_t blobfs_block_size);
// Initializes a |BlobLayout| from a blob's file size and data size.
// For uncompressed blobs |data_size| is the same as |file_size|.
// For compressed blobs |data_size| is the compressed size of the file.
static zx::result<std::unique_ptr<BlobLayout>> CreateFromSizes(BlobLayoutFormat format,
uint64_t file_size,
uint64_t data_size,
uint64_t blobfs_block_size);
virtual ~BlobLayout() = default;
protected:
BlobLayout(uint64_t file_size, uint64_t data_size, uint64_t merkle_tree_size,
uint64_t blobfs_block_size);
private:
// The uncompressed size of the file.
uint64_t file_size_;
// The number of bytes required to store the blob's data.
uint64_t data_size_;
// The number of bytes required to store the Merkle tree.
// This field can be derived from |file_size_| but is cached because it's not a constant time
// calculation and is required in many of the other calculations.
uint64_t merkle_tree_size_;
// The size of a block in blobfs.
uint64_t blobfs_block_size_;
};
} // namespace blobfs
#endif // SRC_STORAGE_BLOBFS_BLOB_LAYOUT_H_