blob: 009014fb88e48fcec09d3ba4911b11a9decd4f76 [file] [log] [blame]
// 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.
#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/unique_fd.h>
#include <lz4/lz4frame.h>
#include "src/storage/fvm/fvm_sparse.h"
#ifdef __Fuchsia__
#include <zircon/syscalls.h>
#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 {
Buffer(uint64_t offset, size_t size, uint64_t capacity);
Buffer(const Buffer&) = delete;
Buffer& operator=(const Buffer&) = delete;
Buffer& operator=(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(); }
// Data buffer
std::unique_ptr<uint8_t[]> data_;
// Maximum size allocated for buffer
size_t capacity_;
BufferInfo info_;
} // namespace internal
class ReaderInterface {
virtual zx_status_t Read(void* buf, size_t buf_size, size_t* size_actual) = 0;
virtual ~ReaderInterface() = default;
class SparseReader {
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);
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);
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_;
size_t raw_bytes_read_ = 0;
// 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;
} // namespace fvm