| // 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_INCLUDE_BLOBFS_BLOB_LAYOUT_H_ |
| #define SRC_STORAGE_BLOBFS_INCLUDE_BLOBFS_BLOB_LAYOUT_H_ |
| |
| #include <lib/zx/status.h> |
| #include <zircon/types.h> |
| |
| #include <type_traits> |
| |
| #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 { |
| // 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. |
| kPaddedMerkleTreeAtStart = 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 an abbreviated version of the |BlobLayoutFormat|'s name for passing to blobfs tools on |
| // the command line. |
| const char* GetBlobLayoutFormatCommandLineArg(BlobLayoutFormat format); |
| |
| // Parses the output of |GetBlobLayoutFormatCommandLineArg| back to a |BlobLayoutFormat|. |
| // Returns an error if |arg| is invalid. |
| zx::status<BlobLayoutFormat> ParseBlobLayoutFormatCommandLineArg(const char* arg); |
| |
| // 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: |
| // The type used to represent a number of bytes in blobfs. Must be large enough to hold blobfs's |
| // maximum file size. |
| using ByteCountType = uint64_t; |
| // The type used to represent a number of blocks in blobfs. |
| using BlockCountType = uint32_t; |
| // The type used to represent the block size in blobfs. |
| using BlockSizeType = uint32_t; |
| |
| // Ensure that the types used in this class match the types used in the |Inode|. This class |
| // depends on the exact sizes of these types and should fail to compile if the types used in the |
| // |Inode| change. |
| static_assert(std::is_same<ByteCountType, decltype(Inode::blob_size)>::value); |
| static_assert(std::is_same<BlockCountType, decltype(Inode::block_count)>::value); |
| static_assert( |
| std::is_same<BlockSizeType, std::remove_const<decltype(kBlobfsBlockSize)>::type>::value); |
| |
| // The uncompressed size of the file. |
| ByteCountType FileSize() const; |
| // The uncompressed size of the file rounded up to the next multiple of the block size. |
| ByteCountType 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 fxbug.dev/44547. |
| ByteCountType DataSizeUpperBound() const; |
| // The size of buffer required to hold |DataBlockCount| blocks. |
| ByteCountType DataBlockAlignedSize() const; |
| // The number of blocks that the data spans. |
| BlockCountType DataBlockCount() const; |
| // The first block of the blob containing part of the blob's data. The rest of the blob's data |
| // will be in the following |DataBlockCount| - 1 blocks. |
| virtual BlockCountType DataBlockOffset() const = 0; |
| |
| // The number of bytes required to store the Merkle tree. |
| ByteCountType MerkleTreeSize() const; |
| // The size of buffer required to hold |MerkleTreeBlockCount| blocks. |
| ByteCountType MerkleTreeBlockAlignedSize() const; |
| // The number of blocks that the Merkle tree spans. |
| BlockCountType MerkleTreeBlockCount() const; |
| |
| // Returns the offset within the file for the merkle tree. |
| virtual ByteCountType 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. |
| BlockCountType MerkleTreeBlockOffset() const { |
| return static_cast<BlockCountType>(MerkleTreeOffset() / blobfs_block_size_); |
| } |
| |
| // The offset within |MerkleTreeBlockOffset| that the Merkle tree starts at. |
| ByteCountType MerkleTreeOffsetWithinBlockOffset() const { |
| return MerkleTreeOffset() % blobfs_block_size_; |
| } |
| |
| // The total number of blocks that the blob spans. |
| virtual BlockCountType 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::status<std::unique_ptr<BlobLayout>> CreateFromInode(BlobLayoutFormat format, |
| const Inode& inode, |
| BlockSizeType 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::status<std::unique_ptr<BlobLayout>> CreateFromSizes(BlobLayoutFormat format, |
| ByteCountType file_size, |
| ByteCountType data_size, |
| BlockSizeType blobfs_block_size); |
| |
| virtual ~BlobLayout() = default; |
| |
| protected: |
| BlobLayout(ByteCountType file_size, ByteCountType data_size, ByteCountType merkle_tree_size, |
| BlockSizeType blobfs_block_size); |
| |
| BlockSizeType blobfs_block_size() const { return blobfs_block_size_; } |
| |
| private: |
| // The uncompressed size of the file. |
| ByteCountType file_size_; |
| |
| // The number of bytes required to store the blob's data. |
| ByteCountType 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. |
| ByteCountType merkle_tree_size_; |
| |
| // The size of a block in blobfs. |
| BlockSizeType blobfs_block_size_; |
| }; |
| |
| } // namespace blobfs |
| |
| #endif // SRC_STORAGE_BLOBFS_INCLUDE_BLOBFS_BLOB_LAYOUT_H_ |