blob: 38a6cb3d3fd740b90872f44658286b377c0b0cbe [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.
//! Implementation of an individual connection to a file.
use {
fidl::encoding::OutOfLine,
fidl::endpoints::ServerEnd,
fidl_fuchsia_io::{
FileMarker, FileObject, FileRequestStream, NodeInfo, NodeMarker, OPEN_FLAG_DESCRIBE,
},
fuchsia_zircon::Status,
futures::{
stream::{Stream, StreamExt, StreamFuture},
task::Waker,
Poll,
},
std::pin::Pin,
};
/// FileConnection represents the buffered connection of a single client to a pseudo file. It
/// implements Stream, which proxies file requests from the contained FileRequestStream.
pub struct FileConnection {
requests: FileRequestStream,
/// Either the "flags" value passed into [`DirectoryEntry::open()`], or the "flags" value
/// passed into FileRequest::Clone().
pub flags: u32,
/// Seek position. Next byte to be read or written within the buffer. This might be beyond
/// the current size of buffer, matching POSIX:
///
/// http://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html
///
/// It will cause the buffern to be extended with zeroes (if necessary) when write() is called.
// While the content in the buffer vector uses usize for the size, it is easier to use u64 to
// match the FIDL bindings API. Pseudo files are not expected to cross the 2^64 bytes size
// limit. And all the code is much simpler when we just assume that usize is the same as u64.
// Should we need to port to a 128 bit platform, there are static assertions in the code that
// would fail.
pub seek: u64,
/// Per connection buffer. See module documentation for details.
pub buffer: Vec<u8>,
/// Starts as false, and causes the [`on_write()`] to be called when the connection is closed
/// if set to true during the lifetime of the connection.
pub was_written: bool,
}
impl FileConnection {
/// Initialized a file connection, checking flags and sending an `OnOpen` event if necessary.
/// Returns a [`FileConnection`] object as a [`StreamFuture`], or in the case of an error, sends
/// an appropriate `OnOpen` event (if requested) and returns `Err`.
pub fn connect(
flags: u32,
server_end: ServerEnd<NodeMarker>,
buffer: Vec<u8>,
was_written: bool,
) -> Result<StreamFuture<FileConnection>, fidl::Error> {
let (requests, control_handle) = ServerEnd::<FileMarker>::new(server_end.into_channel())
.into_stream_and_control_handle()?;
let conn = (FileConnection { requests, flags, seek: 0, buffer, was_written }).into_future();
if flags & OPEN_FLAG_DESCRIBE != 0 {
let mut info = NodeInfo::File(FileObject { event: None });
control_handle.send_on_open_(Status::OK.into_raw(), Some(OutOfLine(&mut info)))?;
}
Ok(conn)
}
}
/// Allow [`FileConnection`] to be wrapped in a [`StreamFuture`], to be further contained inside
/// [`FuturesUnordered`].
impl Stream for FileConnection {
// We are just proxying the FileRequestStream requests.
type Item = <FileRequestStream as Stream>::Item;
fn poll_next(mut self: Pin<&mut Self>, lw: &Waker) -> Poll<Option<Self::Item>> {
self.requests.poll_next_unpin(lw)
}
}