| // 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 ZIRCON_SYSTEM_ULIB_BLOBFS_COMPRESSION_ZSTD_SEEKABLE_H_ |
| #define ZIRCON_SYSTEM_ULIB_BLOBFS_COMPRESSION_ZSTD_SEEKABLE_H_ |
| |
| #include <zircon/errors.h> |
| #include <zircon/types.h> |
| |
| #include <memory> |
| #include <optional> |
| |
| #include <blobfs/format.h> |
| #include <lib/zx/status.h> |
| #include <zstd/zstd.h> |
| #include <zstd/zstd_seekable.h> |
| |
| #include "compressor.h" |
| #include "decompressor.h" |
| #include "seekable-decompressor.h" |
| |
| namespace blobfs { |
| |
| struct ZSTDSeekableHeader { |
| uint64_t archive_size; |
| }; |
| |
| constexpr size_t kZSTDSeekableHeaderSize = sizeof(ZSTDSeekableHeader); |
| constexpr unsigned kZSTDSeekableMaxFrameSize = 128 * kBlobfsBlockSize; |
| |
| // Compressor implementation for the zstd seekable format library implemented in |
| // //third_party/zstd/contrib/seekable_format. The library provides a convenient API for |
| // random access in zstd archives. |
| class ZSTDSeekableCompressor : public Compressor { |
| public: |
| // TODO(markdittmer): This can include `kBlobFlagZSTDCompressed` if a unified envelope format is |
| // implemented across (minimally) all ZSTD compression strategies. |
| static uint32_t InodeHeaderCompressionFlags() { return kBlobFlagZSTDSeekableCompressed; } |
| |
| // Returns an upper bound on the size of the buffer required to store the compressed |
| // representation of a blob of size `input_length`. |
| static size_t BufferMax(size_t input_length); |
| |
| static zx_status_t Create(size_t input_size, void* compression_buffer, |
| size_t compression_buffer_length, |
| std::unique_ptr<ZSTDSeekableCompressor>* out); |
| ~ZSTDSeekableCompressor(); |
| |
| //////////////////////////////////////// |
| // Compressor interface |
| size_t Size() const final; |
| zx_status_t Update(const void* input_data, size_t input_length) final; |
| zx_status_t End() final; |
| |
| private: |
| // Writes up to `kZSTDSeekableHeaderSize` bytes from the beginning of `buf` from `header`. |
| // @param buf Pointer to buffer that is to contain <header><zstd seekable archive>. |
| // @param buf_size Size of `buf` in bytes. |
| // @param header Header values to write. |
| // It is the responsibility of any code writing the zstd seekable archive to `buf` to skip the |
| // first `kZSTDSeekableHeaderSize` bytes before writing the archive contents. This is generally an |
| // implementation detail invoked by other public methods, but is public to enable test |
| // environments to write syntactically correct headers via the same code code path used by |
| // `ZSTDSeekableCompressor`. |
| static zx_status_t WriteHeader(void* buf, size_t buf_size, ZSTDSeekableHeader header); |
| |
| ZSTDSeekableCompressor(ZSTD_seekable_CStream* stream, void* compression_buffer, |
| size_t compression_buffer_length); |
| |
| ZSTD_seekable_CStream* stream_ = nullptr; |
| ZSTD_outBuffer output_ = {}; |
| |
| DISALLOW_COPY_ASSIGN_AND_MOVE(ZSTDSeekableCompressor); |
| }; |
| |
| class ZSTDSeekableDecompressor : public Decompressor, public SeekableDecompressor { |
| public: |
| ZSTDSeekableDecompressor() = default; |
| DISALLOW_COPY_ASSIGN_AND_MOVE(ZSTDSeekableDecompressor); |
| |
| zx_status_t DecompressArchive(void* uncompressed_buf, size_t* uncompressed_size, |
| const void* compressed_buf, size_t compressed_size, size_t offset); |
| |
| // Decompressor implementation. |
| zx_status_t Decompress(void* uncompressed_buf, size_t* uncompressed_size, |
| const void* compressed_buf, const size_t max_compressed_size) final; |
| |
| // SeekableDecompressor implementation. |
| zx_status_t DecompressRange(void* uncompressed_buf, size_t* uncompressed_size, |
| const void* compressed_buf, size_t max_compressed_size, |
| size_t offset) final; |
| zx::status<CompressionMapping> MappingForDecompressedRange(size_t offset, size_t len) final { |
| // TODO(markdittmer): Implement. |
| ZX_ASSERT(false); |
| return zx::error(ZX_ERR_INTERNAL); |
| } |
| |
| // Reads up to `kZSTDSeekableHeaderSize` bytes from the beginning of `buf` into `header`. |
| // @param buf Pointer to buffer that is to contain <header><zstd seekable archive>. |
| // @param buf_size Size of `buf` in bytes. |
| // @param header Header struct in which to store values. |
| static zx_status_t ReadHeader(const void* buf, size_t buf_size, ZSTDSeekableHeader* header); |
| }; |
| |
| } // namespace blobfs |
| |
| #endif // ZIRCON_SYSTEM_ULIB_BLOBFS_COMPRESSION_ZSTD_SEEKABLE_H_ |