blob: 8379b3480e2ae9d77fc90d37743c2252d743ad30 [file] [log] [blame]
// Copyright 2019 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 LIB_VFS_CPP_PSEUDO_FILE_H_
#define LIB_VFS_CPP_PSEUDO_FILE_H_
#include <lib/vfs/cpp/internal/connection.h>
#include <lib/vfs/cpp/internal/file.h>
namespace vfs {
// Buffered pseudo-file.
//
// This variant is optimized for incrementally reading and writing properties
// which are larger than can typically be read or written by the client in
// a single I/O transaction.
//
// In read mode, the pseudo-file invokes its read handler when the file is
// opened and retains the content in a buffer which the client incrementally
// reads from and can seek within.
//
// In write mode, the client incrementally writes into and seeks within the
// buffer which the pseudo-file delivers as a whole to the write handler when
// the file is closed(if there were any writes). Truncation is also supported.
//
// This class is thread-hostile.
//
// # Simple usage
//
// Instances of this class should be owned and managed on the same thread
// that services their connections.
//
// # Advanced usage
//
// You can use a background thread to service connections provided:
// async_dispatcher_t for the background thread is stopped or suspended
// prior to destroying the file.
class PseudoFile final : public vfs::internal::File {
public:
// Handler called to read from the pseudo-file.
using ReadHandler = fit::function<zx_status_t(std::vector<uint8_t>* output, size_t max_bytes)>;
// Handler called to write into the pseudo-file.
using WriteHandler = fit::function<zx_status_t(std::vector<uint8_t> input)>;
// Creates a buffered pseudo-file.
//
// |read_handler| cannot be null. If the |write_handler| is null, then the
// pseudo-file is considered not writable. The |max_file_size|
// determines the maximum number of bytes which can be written to and read from
// the pseudo-file's input buffer when it it opened for writing/reading.
PseudoFile(size_t max_file_size, ReadHandler read_handler = ReadHandler(),
WriteHandler write_handler = WriteHandler());
~PseudoFile() override;
// |Node| implementations:
zx_status_t GetAttr(fuchsia::io::NodeAttributes* out_attributes) const override;
protected:
zx_status_t CreateConnection(uint32_t flags,
std::unique_ptr<vfs::internal::Connection>* connection) override;
NodeKind::Type GetKind() const override;
private:
class Content final : public vfs::internal::Connection, public File {
public:
Content(PseudoFile* file, uint32_t flags, std::vector<uint8_t> content);
~Content() override;
// |File| implementations:
zx_status_t ReadAt(uint64_t count, uint64_t offset, std::vector<uint8_t>* out_data) override;
zx_status_t WriteAt(std::vector<uint8_t> data, uint64_t offset, uint64_t* out_actual) override;
zx_status_t Truncate(uint64_t length) override;
uint64_t GetLength() override;
size_t GetCapacity() override;
// Connection implementation:
zx_status_t BindInternal(zx::channel request, async_dispatcher_t* dispatcher) override;
// |Node| implementations:
std::unique_ptr<Connection> Close(Connection* connection) override;
zx_status_t PreClose(Connection* connection) override;
void Clone(uint32_t flags, uint32_t parent_flags, zx::channel request,
async_dispatcher_t* dispatcher) override;
zx_status_t GetAttr(fuchsia::io::NodeAttributes* out_attributes) const override;
protected:
void SendOnOpenEvent(zx_status_t status) override;
NodeKind::Type GetKind() const override;
private:
zx_status_t TryFlushIfRequired();
void SetInputLength(size_t length);
PseudoFile* const file_;
std::vector<uint8_t> buffer_;
uint32_t flags_;
// true if the file was written into
bool dirty_ = false;
};
// |File| implementations:
uint64_t GetLength() override;
size_t GetCapacity() override;
ReadHandler const read_handler_;
WriteHandler const write_handler_;
const size_t max_file_size_;
};
} // namespace vfs
#endif // LIB_VFS_CPP_PSEUDO_FILE_H_