You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
178 lines
7.6 KiB
178 lines
7.6 KiB
// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_STREAMS_FILE_STREAM_H_
|
|
#define LIBBRILLO_BRILLO_STREAMS_FILE_STREAM_H_
|
|
|
|
#include <memory>
|
|
|
|
#include <base/files/file_path.h>
|
|
#include <base/macros.h>
|
|
#include <brillo/brillo_export.h>
|
|
#include <brillo/streams/stream.h>
|
|
|
|
namespace brillo {
|
|
|
|
// FileStream class provides the implementation of brillo::Stream for files
|
|
// and file-descriptor-based streams, such as pipes and sockets.
|
|
// The FileStream class cannot be instantiated by clients directly. However
|
|
// they should use the static factory methods such as:
|
|
// - FileStream::Open(): to open a file by name.
|
|
// - FileStream::CreateTemporary(): to create a temporary file stream.
|
|
// - FileStream::FromFileDescriptor(): to create a stream using an existing
|
|
// file descriptor.
|
|
class BRILLO_EXPORT FileStream : public Stream {
|
|
public:
|
|
// See comments for FileStream::Open() for detailed description of this enum.
|
|
enum class Disposition {
|
|
OPEN_EXISTING, // Open existing file only. Fail if doesn't exist.
|
|
CREATE_ALWAYS, // Create empty file, possibly overwriting existing file.
|
|
CREATE_NEW_ONLY, // Create new file if doesn't exist already.
|
|
TRUNCATE_EXISTING, // Open/truncate existing file. Fail if doesn't exist.
|
|
};
|
|
|
|
// Simple interface to wrap native library calls so that they can be mocked
|
|
// out for testing.
|
|
struct FileDescriptorInterface {
|
|
using DataCallback = base::Callback<void(Stream::AccessMode)>;
|
|
|
|
virtual ~FileDescriptorInterface() = default;
|
|
|
|
virtual bool IsOpen() const = 0;
|
|
virtual ssize_t Read(void* buf, size_t nbyte) = 0;
|
|
virtual ssize_t Write(const void* buf, size_t nbyte) = 0;
|
|
virtual off64_t Seek(off64_t offset, int whence) = 0;
|
|
virtual mode_t GetFileMode() const = 0;
|
|
virtual uint64_t GetSize() const = 0;
|
|
virtual int Truncate(off64_t length) const = 0;
|
|
virtual int Close() = 0;
|
|
virtual bool WaitForData(AccessMode mode,
|
|
const DataCallback& data_callback,
|
|
ErrorPtr* error) = 0;
|
|
virtual int WaitForDataBlocking(AccessMode in_mode,
|
|
base::TimeDelta timeout,
|
|
AccessMode* out_mode) = 0;
|
|
virtual void CancelPendingAsyncOperations() = 0;
|
|
};
|
|
|
|
// == Construction ==========================================================
|
|
|
|
// Opens a file at specified |path| for reading, writing or both as indicated
|
|
// by |mode|. The |disposition| specifies how the file must be opened/created:
|
|
// - OPEN_EXISTING - opens the existing file and keeps its content intact.
|
|
// The seek pointer is at the beginning of the file.
|
|
// - CREATE_ALWAYS - creates the file always. If it exists, the file is
|
|
// truncated.
|
|
// - CREATE_NEW_ONLY - creates a new file only if it doesn't exist. Fails
|
|
// otherwise. This can be useful for creating lock files.
|
|
// - TRUNCATE_EXISTING - opens existing file and truncates it to zero length.
|
|
// Fails if the file doesn't already exist.
|
|
// If successful, the open file stream is returned. Otherwise returns the
|
|
// stream pointer containing nullptr and fills in the details of the error
|
|
// in |error| object, if provided.
|
|
static StreamPtr Open(const base::FilePath& path,
|
|
AccessMode mode,
|
|
Disposition disposition,
|
|
ErrorPtr* error);
|
|
|
|
// Creates a temporary unnamed file and returns a stream to it. The file will
|
|
// be deleted when the stream is destroyed.
|
|
static StreamPtr CreateTemporary(ErrorPtr* error);
|
|
|
|
// Creates a file stream based on existing file descriptor. The file
|
|
// descriptor will be set into non-blocking mode and will be owned by the
|
|
// resulting stream (and closed when the stream is destroyed).
|
|
// If the function fails, returns a null stream pointer and sets the error
|
|
// details to |error| object. Also note that it is the caller's responsibility
|
|
// to close the file descriptor if this function fails, since the stream
|
|
// hasn't been created yet and didn't take ownership of the file descriptor.
|
|
// |own_descriptor| indicates whether the stream must close the underlying
|
|
// file descriptor when its CloseBlocking() method is called. This should be
|
|
// set to false for file descriptors that shouldn't be closed (e.g. stdin).
|
|
static StreamPtr FromFileDescriptor(int file_descriptor,
|
|
bool own_descriptor,
|
|
ErrorPtr* error);
|
|
|
|
// == Stream capabilities ===================================================
|
|
bool IsOpen() const override;
|
|
bool CanRead() const override;
|
|
bool CanWrite() const override;
|
|
bool CanSeek() const override;
|
|
bool CanGetSize() const override;
|
|
|
|
// == Stream size operations ================================================
|
|
uint64_t GetSize() const override;
|
|
bool SetSizeBlocking(uint64_t size, ErrorPtr* error) override;
|
|
uint64_t GetRemainingSize() const override;
|
|
|
|
// == Seek operations =======================================================
|
|
uint64_t GetPosition() const override;
|
|
bool Seek(int64_t offset,
|
|
Whence whence,
|
|
uint64_t* new_position,
|
|
ErrorPtr* error) override;
|
|
|
|
// == Read operations =======================================================
|
|
bool ReadNonBlocking(void* buffer,
|
|
size_t size_to_read,
|
|
size_t* size_read,
|
|
bool* end_of_stream,
|
|
ErrorPtr* error) override;
|
|
|
|
// == Write operations ======================================================
|
|
bool WriteNonBlocking(const void* buffer,
|
|
size_t size_to_write,
|
|
size_t* size_written,
|
|
ErrorPtr* error) override;
|
|
|
|
// == Finalizing/closing streams ===========================================
|
|
bool FlushBlocking(ErrorPtr* error) override;
|
|
bool CloseBlocking(ErrorPtr* error) override;
|
|
|
|
// == Data availability monitoring ==========================================
|
|
|
|
// Override for Stream::WaitForData to start watching the associated file
|
|
// descriptor for non-blocking read/write operations.
|
|
bool WaitForData(AccessMode mode,
|
|
const base::Callback<void(AccessMode)>& callback,
|
|
ErrorPtr* error) override;
|
|
|
|
// Runs select() on the file descriptor to wait until we can do non-blocking
|
|
// I/O on it.
|
|
bool WaitForDataBlocking(AccessMode in_mode,
|
|
base::TimeDelta timeout,
|
|
AccessMode* out_mode,
|
|
ErrorPtr* error) override;
|
|
|
|
// Cancels pending asynchronous read/write operations.
|
|
void CancelPendingAsyncOperations() override;
|
|
|
|
private:
|
|
friend class FileStreamTest;
|
|
|
|
// Internal constructor used by the factory methods Open(), CreateTemporary(),
|
|
// and FromFileDescriptor().
|
|
FileStream(std::unique_ptr<FileDescriptorInterface> fd_interface,
|
|
AccessMode mode);
|
|
|
|
// Wrapper for the file descriptor. Used in testing to mock out the real
|
|
// file system APIs.
|
|
std::unique_ptr<FileDescriptorInterface> fd_interface_;
|
|
|
|
// The access mode this stream is open with.
|
|
AccessMode access_mode_{AccessMode::READ_WRITE};
|
|
|
|
// Set to false for streams that are guaranteed non-seekable.
|
|
bool seekable_{true};
|
|
|
|
// Set to false for streams that have unknown size.
|
|
bool can_get_size_{false};
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(FileStream);
|
|
};
|
|
|
|
} // namespace brillo
|
|
|
|
#endif // LIBBRILLO_BRILLO_STREAMS_FILE_STREAM_H_
|