| // 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. |
| |
| //! Typesafe wrappers around the /pkgfs/ctl filesystem. |
| |
| use { |
| fidl_fuchsia_io::{DirectoryMarker, DirectoryProxy, DirectoryRequestStream}, |
| fidl_fuchsia_io2::UnlinkOptions, |
| fuchsia_zircon::Status, |
| thiserror::Error, |
| }; |
| |
| /// An error encountered while garbage collecting blobs |
| #[derive(Debug, Error)] |
| #[allow(missing_docs)] |
| pub enum GcError { |
| #[error("while sending request: {}", _0)] |
| Fidl(fidl::Error), |
| |
| #[error("unlink failed with status: {}", _0)] |
| UnlinkError(Status), |
| } |
| |
| /// An error encountered while syncing |
| #[derive(Debug, Error)] |
| #[allow(missing_docs)] |
| pub enum SyncError { |
| #[error("while sending request: {}", _0)] |
| Fidl(fidl::Error), |
| |
| #[error("sync failed with status: {}", _0)] |
| SyncError(Status), |
| } |
| |
| /// An open handle to /pkgfs/ctl |
| #[derive(Debug, Clone)] |
| pub struct Client { |
| proxy: DirectoryProxy, |
| } |
| |
| impl Client { |
| /// Returns an client connected to pkgfs from the current component's namespace |
| pub fn open_from_namespace() -> Result<Self, io_util::node::OpenError> { |
| let proxy = io_util::directory::open_in_namespace( |
| "/pkgfs/ctl", |
| fidl_fuchsia_io::OPEN_RIGHT_READABLE | fidl_fuchsia_io::OPEN_RIGHT_WRITABLE, |
| )?; |
| Ok(Client { proxy }) |
| } |
| |
| /// Returns an client connected to pkgfs from the given pkgfs root dir. |
| pub fn open_from_pkgfs_root(pkgfs: &DirectoryProxy) -> Result<Self, io_util::node::OpenError> { |
| Ok(Client { |
| proxy: io_util::directory::open_directory_no_describe( |
| pkgfs, |
| "ctl", |
| fidl_fuchsia_io::OPEN_RIGHT_READABLE | fidl_fuchsia_io::OPEN_RIGHT_WRITABLE, |
| )?, |
| }) |
| } |
| |
| /// Creates a new client backed by the returned request stream. This constructor should not be |
| /// used outside of tests. |
| /// |
| /// # Panics |
| /// |
| /// Panics on error |
| pub fn new_test() -> (Self, DirectoryRequestStream) { |
| let (proxy, stream) = |
| fidl::endpoints::create_proxy_and_stream::<DirectoryMarker>().unwrap(); |
| |
| (Self { proxy }, stream) |
| } |
| |
| /// Performs a garbage collection |
| pub async fn gc(&self) -> Result<(), GcError> { |
| self.proxy |
| .unlink2("do-not-use-this-garbage", UnlinkOptions::EMPTY) |
| .await |
| .map_err(GcError::Fidl)? |
| .map_err(|s| GcError::UnlinkError(Status::from_raw(s))) |
| } |
| |
| /// Performs a sync |
| pub async fn sync(&self) -> Result<(), SyncError> { |
| match self.proxy.sync().await.map(Status::from_raw) { |
| Ok(Status::OK) => Ok(()), |
| Ok(status) => Err(SyncError::SyncError(status)), |
| Err(err) => Err(SyncError::Fidl(err)), |
| } |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use { |
| super::*, |
| fidl::endpoints::create_proxy_and_stream, |
| fidl_fuchsia_io::{DirectoryMarker, DirectoryRequest}, |
| fuchsia_async as fasync, |
| futures_util::stream::TryStreamExt, |
| matches::assert_matches, |
| }; |
| |
| #[fasync::run_singlethreaded(test)] |
| async fn gc() { |
| let (proxy, mut stream) = create_proxy_and_stream::<DirectoryMarker>().unwrap(); |
| fasync::Task::spawn(async move { |
| match stream.try_next().await.unwrap().unwrap() { |
| DirectoryRequest::Unlink2 { name, options: _, responder } => { |
| assert_eq!(name, "do-not-use-this-garbage"); |
| responder.send(&mut Ok(())).unwrap(); |
| } |
| other => panic!("unexpected request: {:?}", other), |
| } |
| }) |
| .detach(); |
| |
| assert_matches!(Client { proxy }.gc().await, Ok(())); |
| } |
| |
| #[fasync::run_singlethreaded(test)] |
| async fn sync() { |
| let (proxy, mut stream) = create_proxy_and_stream::<DirectoryMarker>().unwrap(); |
| fasync::Task::spawn(async move { |
| match stream.try_next().await.unwrap().unwrap() { |
| DirectoryRequest::Sync { responder } => { |
| responder.send(Status::OK.into_raw()).unwrap(); |
| } |
| other => panic!("unexpected request: {:?}", other), |
| } |
| }) |
| .detach(); |
| |
| assert_matches!(Client { proxy }.sync().await, Ok(())); |
| } |
| } |