blob: 41173f859934a7fd0d569dfb1a0ebaeb5e51692c [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_COMPRESSION_EXTERNAL_DECOMPRESSOR_H_
#define SRC_STORAGE_BLOBFS_COMPRESSION_EXTERNAL_DECOMPRESSOR_H_
#include <fidl/fuchsia.blobfs.internal/cpp/wire.h>
#include <fuchsia/blobfs/internal/cpp/fidl.h>
#include <lib/zx/channel.h>
#include <lib/zx/fifo.h>
#include <lib/zx/status.h>
#include <lib/zx/vmo.h>
#include <optional>
#include "src/storage/blobfs/compression/seekable_decompressor.h"
#include "src/storage/blobfs/compression_settings.h"
namespace blobfs {
// An interface that is passed into the ExternalDecompressorClient to complete connections to a
// DecompressorCreator fidl service as a form of dependency injection. The DecompressorCreator
// service is used to create remote decompressor instances that are controlled via fifo, and this
// interface establishes connections to them. Hence the convoluted name.
class DecompressorCreatorConnector {
public:
virtual ~DecompressorCreatorConnector() = default;
// Passes the `remote_channel` to some DecompressorCreator handler.
virtual zx_status_t ConnectToDecompressorCreator(zx::channel remote_channel) = 0;
};
// The base interface that just calls `fdio_service_connect()` to the expected service path.
class DecompressorCreatorConnectorImpl final : public DecompressorCreatorConnector {
public:
DecompressorCreatorConnectorImpl() = default;
// DecompressorCreatorConnector interface.
zx_status_t ConnectToDecompressorCreator(zx::channel remote_channel) final;
};
// A client class for managing the connection to the decompressor sandbox, sending messages, and
// returning the status result. This class is *not* thread safe.
class ExternalDecompressorClient {
public:
DISALLOW_COPY_ASSIGN_AND_MOVE(ExternalDecompressorClient);
// Creates a DecompressorClient that takes data from `compressed_vmo` and places the results in
// `decompressed_vmo`. This calls `Prepare()` and returns a failure if it cannot succeed on the
// first try. Both vmos require the ZX_DEFAULT_VMO_RIGHTS except that ZX_RIGHT_WRITE is not
// required on `compressed_vmo`, this permission will be omitted before sending to the external
// decompressor if present.
static zx::status<std::unique_ptr<ExternalDecompressorClient>> Create(
DecompressorCreatorConnector* connector, const zx::vmo& decompressed_vmo,
const zx::vmo& compressed_vmo);
// Sends the request over the fifo, and awaits the response before verifying the resulting size
// and reporting the status passed from the server. This succeeds only if the resulting
// decompressed size matches the `decompressed.size`. Starts by calling `Prepare()`.
zx_status_t SendMessage(const fuchsia_blobfs_internal::wire::DecompressRequest& request);
// Convert from fidl compatible enum to local. Returns nullopt if invalid.
static std::optional<CompressionAlgorithm> CompressionAlgorithmFidlToLocal(
fuchsia_blobfs_internal::wire::CompressionAlgorithm algorithm);
// Convert to fidl compatible enum from local.
static fuchsia_blobfs_internal::wire::CompressionAlgorithm CompressionAlgorithmLocalToFidl(
CompressionAlgorithm algorithm);
// Convert to fidl compatible enum from local for partial decompression.
static zx::status<fuchsia_blobfs_internal::wire::CompressionAlgorithm>
CompressionAlgorithmLocalToFidlForPartial(CompressionAlgorithm algorithm);
private:
ExternalDecompressorClient() = default;
// If the fifo is useable nothing is done and returns ZX_OK. If the fifo is not ready to use, this
// attempts to set one up via the DecompressorCreator.
zx_status_t Prepare();
// If the DecompressorCreator fidl channel is ready then nothing is done. Otherwise the channel is
// set up.
zx_status_t PrepareDecompressorCreator();
// The vmo that will contain the decompressed data for requests. A copy is kept so that if it
// needs to reconnect with the server another copy can be sent.
zx::vmo decompressed_vmo_;
// The vmo that will contain the compressed data for requests. A copy is kept so that if it needs
// to reconnect with the server another copy can be sent.
zx::vmo compressed_vmo_;
// Fidl connection to the DecompressorCreator.
fuchsia::blobfs::internal::DecompressorCreatorSyncPtr decompressor_creator_;
// For completing connections to the DecompressorCreator.
DecompressorCreatorConnector* connector_;
// The fifo that communicates with the Decompressor.
zx::fifo fifo_;
};
// A class for decompressing entire files for which there is an implementation of the Decompressor
// interface for the `algorithm`. Uses the given `client` for communication to the external
// decompressor process.
class ExternalDecompressor {
public:
ExternalDecompressor(ExternalDecompressorClient* client, CompressionAlgorithm algorithm);
DISALLOW_COPY_ASSIGN_AND_MOVE(ExternalDecompressor);
// Performs decompression for an entire archive using the provided client.
zx_status_t Decompress(size_t uncompressed_size, size_t max_compressed_size);
private:
// Client used for communication with the decompressor.
ExternalDecompressorClient* client_;
// The algorithm to be used for this file.
CompressionAlgorithm algorithm_;
};
// A class for decompressing parts of files for which there is an implementation of the
// SeekableDecompressor interface for the `algorithm`. Uses the given `client` for communication to
// the external decompressor process.
class ExternalSeekableDecompressor {
public:
ExternalSeekableDecompressor(ExternalDecompressorClient* client,
SeekableDecompressor* decompressor);
DISALLOW_COPY_ASSIGN_AND_MOVE(ExternalSeekableDecompressor);
// Decompresses one region by sending a request to the provided client. The range specified must
// be one or more entire completeable chunks. `compressed_offset` is the offset into the
// `compressed_vmo_` to start decompressing from.
zx_status_t DecompressRange(size_t compressed_offset, size_t compressed_size,
size_t uncompressed_size);
private:
// Client used for communication with the decompressor.
ExternalDecompressorClient* client_;
// The SeekableDecompressor that would otherwise be used to decompress locally, which has the
// CompressionMapping information.
SeekableDecompressor* decompressor_;
};
} // namespace blobfs
#endif // SRC_STORAGE_BLOBFS_COMPRESSION_EXTERNAL_DECOMPRESSOR_H_