| // Copyright 2017 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_FVM_SPARSE_READER_H_ |
| #define SRC_STORAGE_FVM_SPARSE_READER_H_ |
| |
| #include <assert.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <stdbool.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| #include <memory> |
| |
| #include <fbl/auto_call.h> |
| #include <fbl/unique_fd.h> |
| #include <lz4/lz4frame.h> |
| |
| #include "src/storage/fvm/fvm_sparse.h" |
| |
| #ifdef __Fuchsia__ |
| #include <zircon/syscalls.h> |
| #endif |
| |
| #define LZ4_MAX_BLOCK_SIZE 65536 |
| |
| namespace fvm { |
| |
| namespace internal { |
| // Helper struct for providing information about the buffer state. |
| struct BufferInfo { |
| // Offset into buffer where valid data begins |
| size_t offset; |
| |
| // Actual size of data contained within buffer |
| size_t size; |
| }; |
| |
| // Internal class for representing read and write buffers for the sparse image. |
| class Buffer { |
| public: |
| Buffer(); |
| Buffer(uint64_t offset, size_t size, uint64_t capacity); |
| Buffer(const Buffer&) = delete; |
| Buffer(Buffer&&); |
| Buffer& operator=(const Buffer&) = delete; |
| Buffer& operator=(Buffer&&); |
| ~Buffer(); |
| |
| // Write |length| bytes from |indata| into buffer. |
| bool IsEmpty() const; |
| |
| // Writes |length| number of bytes from |data| into the buffer. |
| void Write(uint8_t* data, size_t length); |
| |
| // Read up to |length| bytes from the buffer into |target|, setting |actual| to the total |
| // amount of bytes copied. |
| void Read(uint8_t* target, size_t length, size_t* actual); |
| |
| size_t size() const { return info_.size; } |
| |
| size_t capacity() const { return capacity_; } |
| |
| size_t offset() const { return info_.offset; } |
| |
| BufferInfo* info() { return &info_; } |
| |
| uint8_t* get() { return data_.get(); } |
| |
| private: |
| // Data buffer |
| std::unique_ptr<uint8_t[]> data_; |
| |
| // Maximum size allocated for buffer |
| size_t capacity_; |
| |
| BufferInfo info_; |
| }; |
| |
| } // namespace internal |
| |
| class ReaderInterface { |
| public: |
| virtual zx_status_t Read(void* buf, size_t buf_size, size_t* size_actual) = 0; |
| virtual ~ReaderInterface() = default; |
| }; |
| |
| class SparseReader { |
| public: |
| static zx_status_t Create(fbl::unique_fd fd, std::unique_ptr<SparseReader>* out); |
| static zx_status_t CreateSilent(fbl::unique_fd fd, std::unique_ptr<SparseReader>* out); |
| |
| static zx_status_t Create(std::unique_ptr<ReaderInterface> reader, |
| std::unique_ptr<SparseReader>* out); |
| |
| ~SparseReader(); |
| |
| fvm::SparseImage* Image(); |
| fvm::PartitionDescriptor* Partitions(); |
| |
| // Read requested data from sparse file into buffer |
| zx_status_t ReadData(uint8_t* data, size_t length, size_t* actual); |
| // Write decompressed data into new file |
| zx_status_t WriteDecompressed(fbl::unique_fd outfd); |
| // A util function that reuses SparseReader logic to implement lz4 file decompression. |
| static zx_status_t DecompressLZ4File(const char* in_file, const char* out_file); |
| |
| private: |
| static zx_status_t CreateHelper(std::unique_ptr<ReaderInterface> reader, bool verbose, |
| std::unique_ptr<SparseReader>* out); |
| |
| SparseReader(std::unique_ptr<ReaderInterface> reader, bool verbose); |
| |
| // Read in header data, prepare buffers and decompression context if necessary |
| zx_status_t ReadMetadata(); |
| |
| // Initialize buffer with a given |size| |
| static zx_status_t InitializeBuffer(size_t size, internal::Buffer* out_buf); |
| |
| // Read |length| bytes of raw data from file directly into |data|. Return |actual| bytes read. |
| zx_status_t ReadRaw(uint8_t* data, size_t length, size_t* actual); |
| |
| void PrintStats() const; |
| |
| zx_status_t SetupLZ4(); |
| |
| // True if sparse file is compressed |
| bool compressed_; |
| |
| // If true, all logs are printed. |
| bool verbose_; |
| |
| std::unique_ptr<ReaderInterface> reader_; |
| std::unique_ptr<uint8_t[]> metadata_; |
| LZ4F_decompressionContext_t dctx_; |
| |
| // A hint of the size of the next compressed frame to be decompressed. |
| // May be an overestimate, but will not be an underestimate (0 indicates no more data left to |
| // decompress). |
| size_t to_read_; |
| |
| // Buffer for compressed data read directly from file |
| internal::Buffer in_; |
| // Buffer for decompressed data |
| internal::Buffer out_; |
| |
| #ifdef __Fuchsia__ |
| // Total time spent reading/decompressing data |
| zx_ticks_t total_time_ = 0; |
| // Total time spent reading data from fd |
| zx_ticks_t read_time_ = 0; |
| #endif |
| }; |
| |
| } // namespace fvm |
| |
| #endif // SRC_STORAGE_FVM_SPARSE_READER_H_ |