[package-directory] Access blobs via trait NonMetaStorage instead of blobfs directly
Will make it easier to serve packages out of bootfs.
Fixed: 103237
Change-Id: I74b054fccdfd84e1517345531ac24cf98f24589c
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/693291
Fuchsia-Auto-Submit: Ben Keller <galbanum@google.com>
Reviewed-by: Kevin Wells <kevinwells@google.com>
Commit-Queue: Ben Keller <galbanum@google.com>
diff --git a/src/sys/pkg/lib/package-directory/src/lib.rs b/src/sys/pkg/lib/package-directory/src/lib.rs
index 3b13bf7..353c8da 100644
--- a/src/sys/pkg/lib/package-directory/src/lib.rs
+++ b/src/sys/pkg/lib/package-directory/src/lib.rs
@@ -58,17 +58,51 @@
}
}
+/// The storage that provides the non-meta files (accessed by hash) of a package-directory (e.g.
+/// blobfs).
+pub trait NonMetaStorage: Send + Sync + 'static {
+ /// Open a non-meta file by hash.
+ fn open(
+ &self,
+ blob: &fuchsia_hash::Hash,
+ flags: fio::OpenFlags,
+ mode: u32,
+ server_end: ServerEnd<fio::NodeMarker>,
+ ) -> Result<(), fuchsia_fs::node::OpenError>;
+}
+
+impl NonMetaStorage for blobfs::Client {
+ fn open(
+ &self,
+ blob: &fuchsia_hash::Hash,
+ flags: fio::OpenFlags,
+ mode: u32,
+ server_end: ServerEnd<fio::NodeMarker>,
+ ) -> Result<(), fuchsia_fs::node::OpenError> {
+ self.forward_open(blob, flags, mode, server_end)
+ .map_err(fuchsia_fs::node::OpenError::SendOpenRequest)
+ }
+}
+
/// Serves a package directory for the package with hash `meta_far` on `server_end`.
/// The connection rights are set by `flags`, used the same as the `flags` parameter of
/// fuchsia.io/Directory.Open.
pub fn serve(
scope: vfs::execution_scope::ExecutionScope,
- blobfs: blobfs::Client,
+ non_meta_storage: impl NonMetaStorage,
meta_far: fuchsia_hash::Hash,
flags: fio::OpenFlags,
server_end: ServerEnd<fio::DirectoryMarker>,
) -> impl futures::Future<Output = Result<(), Error>> {
- serve_path(scope, blobfs, meta_far, flags, 0, VfsPath::dot(), server_end.into_channel().into())
+ serve_path(
+ scope,
+ non_meta_storage,
+ meta_far,
+ flags,
+ 0,
+ VfsPath::dot(),
+ server_end.into_channel().into(),
+ )
}
/// Serves a sub-`path` of a package directory for the package with hash `meta_far` on `server_end`.
@@ -78,14 +112,14 @@
/// response with an error status if requested.
pub async fn serve_path(
scope: vfs::execution_scope::ExecutionScope,
- blobfs: blobfs::Client,
+ non_meta_storage: impl NonMetaStorage,
meta_far: fuchsia_hash::Hash,
flags: fio::OpenFlags,
mode: u32,
path: VfsPath,
server_end: ServerEnd<fio::NodeMarker>,
) -> Result<(), Error> {
- let root_dir = match RootDir::new(blobfs, meta_far).await {
+ let root_dir = match RootDir::new(non_meta_storage, meta_far).await {
Ok(d) => d,
Err(e) => {
let () = send_on_open_with_error(flags, server_end, e.to_zx_status());
diff --git a/src/sys/pkg/lib/package-directory/src/meta_as_dir.rs b/src/sys/pkg/lib/package-directory/src/meta_as_dir.rs
index 2779361..7f3e0b3 100644
--- a/src/sys/pkg/lib/package-directory/src/meta_as_dir.rs
+++ b/src/sys/pkg/lib/package-directory/src/meta_as_dir.rs
@@ -19,17 +19,17 @@
},
};
-pub(crate) struct MetaAsDir {
- root_dir: Arc<RootDir>,
+pub(crate) struct MetaAsDir<S: crate::NonMetaStorage> {
+ root_dir: Arc<RootDir<S>>,
}
-impl MetaAsDir {
- pub(crate) fn new(root_dir: Arc<RootDir>) -> Self {
+impl<S: crate::NonMetaStorage> MetaAsDir<S> {
+ pub(crate) fn new(root_dir: Arc<RootDir<S>>) -> Self {
MetaAsDir { root_dir }
}
}
-impl vfs::directory::entry::DirectoryEntry for MetaAsDir {
+impl<S: crate::NonMetaStorage> vfs::directory::entry::DirectoryEntry for MetaAsDir<S> {
fn open(
self: Arc<Self>,
scope: ExecutionScope,
@@ -104,7 +104,7 @@
}
#[async_trait]
-impl vfs::directory::entry_container::Directory for MetaAsDir {
+impl<S: crate::NonMetaStorage> vfs::directory::entry_container::Directory for MetaAsDir<S> {
async fn read_dirents<'a>(
&'a self,
pos: &'a TraversalPosition,
@@ -171,7 +171,7 @@
}
impl TestEnv {
- async fn new() -> (Self, MetaAsDir) {
+ async fn new() -> (Self, MetaAsDir<blobfs::Client>) {
let pkg = PackageBuilder::new("pkg")
.add_resource_at("meta/dir/file", &b"contents"[..])
.build()
diff --git a/src/sys/pkg/lib/package-directory/src/meta_as_file.rs b/src/sys/pkg/lib/package-directory/src/meta_as_file.rs
index 597e1dc..fa4469d 100644
--- a/src/sys/pkg/lib/package-directory/src/meta_as_file.rs
+++ b/src/sys/pkg/lib/package-directory/src/meta_as_file.rs
@@ -14,12 +14,12 @@
},
};
-pub(crate) struct MetaAsFile {
- root_dir: Arc<RootDir>,
+pub(crate) struct MetaAsFile<S: crate::NonMetaStorage> {
+ root_dir: Arc<RootDir<S>>,
}
-impl MetaAsFile {
- pub(crate) fn new(root_dir: Arc<RootDir>) -> Self {
+impl<S: crate::NonMetaStorage> MetaAsFile<S> {
+ pub(crate) fn new(root_dir: Arc<RootDir<S>>) -> Self {
MetaAsFile { root_dir }
}
@@ -28,7 +28,7 @@
}
}
-impl vfs::directory::entry::DirectoryEntry for MetaAsFile {
+impl<S: crate::NonMetaStorage> vfs::directory::entry::DirectoryEntry for MetaAsFile<S> {
fn open(
self: Arc<Self>,
scope: ExecutionScope,
@@ -73,7 +73,7 @@
}
#[async_trait]
-impl vfs::file::File for MetaAsFile {
+impl<S: crate::NonMetaStorage> vfs::file::File for MetaAsFile<S> {
async fn open(&self, _flags: fio::OpenFlags) -> Result<(), zx::Status> {
Ok(())
}
@@ -159,7 +159,7 @@
}
impl TestEnv {
- async fn new() -> (Self, MetaAsFile) {
+ async fn new() -> (Self, MetaAsFile<blobfs::Client>) {
let pkg = PackageBuilder::new("pkg").build().await.unwrap();
let (metafar_blob, _) = pkg.contents();
let (blobfs_fake, blobfs_client) = FakeBlobfs::new();
diff --git a/src/sys/pkg/lib/package-directory/src/meta_file.rs b/src/sys/pkg/lib/package-directory/src/meta_file.rs
index dfea693..1bb46f7 100644
--- a/src/sys/pkg/lib/package-directory/src/meta_file.rs
+++ b/src/sys/pkg/lib/package-directory/src/meta_file.rs
@@ -25,14 +25,14 @@
pub(crate) length: u64,
}
-pub(crate) struct MetaFile {
- root_dir: Arc<RootDir>,
+pub(crate) struct MetaFile<S: crate::NonMetaStorage> {
+ root_dir: Arc<RootDir<S>>,
location: MetaFileLocation,
vmo: OnceCell<zx::Vmo>,
}
-impl MetaFile {
- pub(crate) fn new(root_dir: Arc<RootDir>, location: MetaFileLocation) -> Self {
+impl<S: crate::NonMetaStorage> MetaFile<S> {
+ pub(crate) fn new(root_dir: Arc<RootDir<S>>, location: MetaFileLocation) -> Self {
MetaFile { root_dir, location, vmo: OnceCell::new() }
}
@@ -61,7 +61,7 @@
}
}
-impl vfs::directory::entry::DirectoryEntry for MetaFile {
+impl<S: crate::NonMetaStorage> vfs::directory::entry::DirectoryEntry for MetaFile<S> {
fn open(
self: Arc<Self>,
scope: ExecutionScope,
@@ -106,7 +106,7 @@
}
#[async_trait]
-impl vfs::file::File for MetaFile {
+impl<S: crate::NonMetaStorage> vfs::file::File for MetaFile<S> {
async fn open(&self, _flags: fio::OpenFlags) -> Result<(), zx::Status> {
Ok(())
}
@@ -201,7 +201,7 @@
mode: fio::MODE_TYPE_FILE
| vfs::common::rights_to_posix_mode_bits(
true, // read
- true, // write
+ true, // write
false, // execute
),
id: 1,
@@ -249,7 +249,7 @@
}
impl TestEnv {
- async fn new() -> (Self, MetaFile) {
+ async fn new() -> (Self, MetaFile<blobfs::Client>) {
let pkg = PackageBuilder::new("pkg")
.add_resource_at("meta/file", &TEST_FILE_CONTENTS[..])
.build()
diff --git a/src/sys/pkg/lib/package-directory/src/meta_subdir.rs b/src/sys/pkg/lib/package-directory/src/meta_subdir.rs
index 0fc83f5..6b0ec63 100644
--- a/src/sys/pkg/lib/package-directory/src/meta_subdir.rs
+++ b/src/sys/pkg/lib/package-directory/src/meta_subdir.rs
@@ -19,20 +19,20 @@
},
};
-pub(crate) struct MetaSubdir {
- root_dir: Arc<RootDir>,
+pub(crate) struct MetaSubdir<S: crate::NonMetaStorage> {
+ root_dir: Arc<RootDir<S>>,
// The object relative path expression of the subdir relative to the package root with a
// trailing slash appended.
path: String,
}
-impl MetaSubdir {
- pub(crate) fn new(root_dir: Arc<RootDir>, path: String) -> Self {
+impl<S: crate::NonMetaStorage> MetaSubdir<S> {
+ pub(crate) fn new(root_dir: Arc<RootDir<S>>, path: String) -> Self {
MetaSubdir { root_dir, path }
}
}
-impl vfs::directory::entry::DirectoryEntry for MetaSubdir {
+impl<S: crate::NonMetaStorage> vfs::directory::entry::DirectoryEntry for MetaSubdir<S> {
fn open(
self: Arc<Self>,
scope: ExecutionScope,
@@ -105,7 +105,7 @@
}
#[async_trait]
-impl vfs::directory::entry_container::Directory for MetaSubdir {
+impl<S: crate::NonMetaStorage> vfs::directory::entry_container::Directory for MetaSubdir<S> {
async fn read_dirents<'a>(
&'a self,
pos: &'a TraversalPosition,
@@ -176,7 +176,7 @@
}
impl TestEnv {
- async fn new() -> (Self, MetaSubdir) {
+ async fn new() -> (Self, MetaSubdir<blobfs::Client>) {
let pkg = PackageBuilder::new("pkg")
.add_resource_at("meta/dir/dir/file", &b"contents"[..])
.build()
diff --git a/src/sys/pkg/lib/package-directory/src/non_meta_subdir.rs b/src/sys/pkg/lib/package-directory/src/non_meta_subdir.rs
index a8808b0..ac66bbc 100644
--- a/src/sys/pkg/lib/package-directory/src/non_meta_subdir.rs
+++ b/src/sys/pkg/lib/package-directory/src/non_meta_subdir.rs
@@ -21,20 +21,20 @@
path::Path as VfsPath,
},
};
-pub(crate) struct NonMetaSubdir {
- root_dir: Arc<RootDir>,
+pub(crate) struct NonMetaSubdir<S: crate::NonMetaStorage> {
+ root_dir: Arc<RootDir<S>>,
// The object relative path expression of the subdir relative to the package root with a
// trailing slash appended.
path: String,
}
-impl NonMetaSubdir {
- pub(crate) fn new(root_dir: Arc<RootDir>, path: String) -> Self {
+impl<S: crate::NonMetaStorage> NonMetaSubdir<S> {
+ pub(crate) fn new(root_dir: Arc<RootDir<S>>, path: String) -> Self {
NonMetaSubdir { root_dir, path }
}
}
-impl vfs::directory::entry::DirectoryEntry for NonMetaSubdir {
+impl<S: crate::NonMetaStorage> vfs::directory::entry::DirectoryEntry for NonMetaSubdir<S> {
fn open(
self: Arc<Self>,
scope: ExecutionScope,
@@ -81,8 +81,8 @@
if let Some(blob) = self.root_dir.non_meta_files.get(&file_path) {
let () = self
.root_dir
- .blobfs
- .forward_open(blob, flags, mode, server_end)
+ .non_meta_storage
+ .open(blob, flags, mode, server_end)
.unwrap_or_else(|e| {
fx_log_err!("Error forwarding content blob open to blobfs: {:#}", anyhow!(e))
});
@@ -107,7 +107,7 @@
}
#[async_trait]
-impl vfs::directory::entry_container::Directory for NonMetaSubdir {
+impl<S: crate::NonMetaStorage> vfs::directory::entry_container::Directory for NonMetaSubdir<S> {
async fn read_dirents<'a>(
&'a self,
pos: &'a TraversalPosition,
@@ -177,7 +177,7 @@
}
impl TestEnv {
- async fn new() -> (Self, NonMetaSubdir) {
+ async fn new() -> (Self, NonMetaSubdir<blobfs::Client>) {
let pkg = PackageBuilder::new("pkg")
.add_resource_at("dir0/dir1/file", "bloblob".as_bytes())
.build()
diff --git a/src/sys/pkg/lib/package-directory/src/root_dir.rs b/src/sys/pkg/lib/package-directory/src/root_dir.rs
index e2e7073..1f10ad4 100644
--- a/src/sys/pkg/lib/package-directory/src/root_dir.rs
+++ b/src/sys/pkg/lib/package-directory/src/root_dir.rs
@@ -11,7 +11,7 @@
non_meta_subdir::NonMetaSubdir,
Error,
},
- anyhow::{anyhow, Context as _},
+ anyhow::Context as _,
async_trait::async_trait,
async_utils::async_once::Once,
fidl::endpoints::ServerEnd,
@@ -35,8 +35,8 @@
/// The root directory of Fuchsia package.
#[derive(Debug)]
-pub struct RootDir {
- pub(crate) blobfs: blobfs::Client,
+pub struct RootDir<S: crate::NonMetaStorage> {
+ pub(crate) non_meta_storage: S,
pub(crate) hash: fuchsia_hash::Hash,
pub(crate) meta_far: fio::FileProxy,
// The keys are object relative path expressions.
@@ -46,11 +46,12 @@
meta_far_vmo: Once<zx::Vmo>,
}
-impl RootDir {
- /// Loads the package metadata given by `hash` from `blobfs`, returning an object representing
- /// the package, backed by `blobfs`.
- pub async fn new(blobfs: blobfs::Client, hash: fuchsia_hash::Hash) -> Result<Self, Error> {
- let meta_far = blobfs.open_blob_for_read_no_describe(&hash).map_err(Error::OpenMetaFar)?;
+impl<S: crate::NonMetaStorage> RootDir<S> {
+ /// Loads the package metadata given by `hash` from `non_meta_storage`, returning an object
+ /// representing the package, backed by `non_meta_storage`.
+ pub async fn new(non_meta_storage: S, hash: fuchsia_hash::Hash) -> Result<Self, Error> {
+ let meta_far =
+ open_for_read_no_describe(&non_meta_storage, &hash).map_err(Error::OpenMetaFar)?;
let reader = fuchsia_fs::file::AsyncFile::from_proxy(Clone::clone(&meta_far));
let mut async_reader = AsyncReader::new(fuchsia_fs::file::BufferedAsyncReadAt::new(reader))
@@ -85,18 +86,16 @@
let meta_far_vmo = Default::default();
- Ok(RootDir { blobfs, hash, meta_far, meta_files, non_meta_files, meta_far_vmo })
+ Ok(RootDir { non_meta_storage, hash, meta_far, meta_files, non_meta_files, meta_far_vmo })
}
/// Returns the contents, if present, of the file at object relative path expression `path`.
/// https://fuchsia.dev/fuchsia-src/concepts/process/namespaces?hl=en#object_relative_path_expressions
pub async fn read_file(&self, path: &str) -> Result<Vec<u8>, ReadFileError> {
if let Some(hash) = self.non_meta_files.get(path) {
- let blob = self
- .blobfs
- .open_blob_for_read_no_describe(hash)
- .map_err(ReadFileError::BlobfsOpen)?;
- return fuchsia_fs::file::read(&blob).await.map_err(ReadFileError::BlobfsRead);
+ let blob = open_for_read_no_describe(&self.non_meta_storage, hash)
+ .map_err(ReadFileError::Open)?;
+ return fuchsia_fs::file::read(&blob).await.map_err(ReadFileError::Read);
}
if let Some(location) = self.meta_files.get(path) {
@@ -148,10 +147,10 @@
#[derive(thiserror::Error, Debug)]
pub enum ReadFileError {
#[error("opening blob")]
- BlobfsOpen(#[source] fuchsia_fs::node::OpenError),
+ Open(#[source] fuchsia_fs::node::OpenError),
#[error("reading blob")]
- BlobfsRead(#[source] fuchsia_fs::file::ReadError),
+ Read(#[source] fuchsia_fs::file::ReadError),
#[error("reading part of a blob")]
PartialBlobRead(#[source] std::io::Error),
@@ -160,7 +159,7 @@
NoFileAtPath { path: String },
}
-impl vfs::directory::entry::DirectoryEntry for RootDir {
+impl<S: crate::NonMetaStorage> vfs::directory::entry::DirectoryEntry for RootDir<S> {
fn open(
self: Arc<Self>,
scope: ExecutionScope,
@@ -254,9 +253,13 @@
}
if let Some(blob) = self.non_meta_files.get(canonical_path) {
- let () = self.blobfs.forward_open(blob, flags, mode, server_end).unwrap_or_else(|e| {
- fx_log_err!("Error forwarding content blob open to blobfs: {:#}", anyhow!(e))
- });
+ let () =
+ self.non_meta_storage.open(blob, flags, mode, server_end).unwrap_or_else(|e| {
+ fx_log_err!(
+ "Error forwarding content blob open to blobfs: {:#}",
+ anyhow::anyhow!(e)
+ )
+ });
return;
}
@@ -283,7 +286,7 @@
}
#[async_trait]
-impl vfs::directory::entry_container::Directory for RootDir {
+impl<S: crate::NonMetaStorage> vfs::directory::entry_container::Directory for RootDir<S> {
async fn read_dirents<'a>(
&'a self,
pos: &'a TraversalPosition,
@@ -347,10 +350,27 @@
open_as_file || !open_as_dir
}
+// Open a non-meta file by hash with flags of OPEN_RIGHT_READABLE and return the proxy.
+fn open_for_read_no_describe(
+ non_meta_storage: &impl crate::NonMetaStorage,
+ blob: &fuchsia_hash::Hash,
+) -> Result<fio::FileProxy, fuchsia_fs::node::OpenError> {
+ let (file, server_end) = fidl::endpoints::create_proxy::<fio::FileMarker>()
+ .map_err(fuchsia_fs::node::OpenError::CreateProxy)?;
+ let () = non_meta_storage.open(
+ blob,
+ fio::OpenFlags::RIGHT_READABLE,
+ 0,
+ server_end.into_channel().into(),
+ )?;
+ Ok(file)
+}
+
#[cfg(test)]
mod tests {
use {
super::*,
+ anyhow::anyhow,
assert_matches::assert_matches,
fidl::endpoints::{create_proxy, Proxy as _},
fuchsia_pkg_testing::{blobfs::Fake as FakeBlobfs, PackageBuilder},
@@ -365,7 +385,7 @@
}
impl TestEnv {
- async fn new() -> (Self, RootDir) {
+ async fn new() -> (Self, RootDir<blobfs::Client>) {
let pkg = PackageBuilder::new("base-package-0")
.add_resource_at("resource", "blob-contents".as_bytes())
.add_resource_at("dir/file", "bloblob".as_bytes())
diff --git a/src/sys/pkg/lib/system-image/src/system_image.rs b/src/sys/pkg/lib/system-image/src/system_image.rs
index 76c625c..fd9b7289 100644
--- a/src/sys/pkg/lib/system-image/src/system_image.rs
+++ b/src/sys/pkg/lib/system-image/src/system_image.rs
@@ -24,7 +24,7 @@
/// System image package.
pub struct SystemImage {
- root_dir: RootDir,
+ root_dir: RootDir<blobfs::Client>,
}
impl SystemImage {
@@ -39,7 +39,7 @@
}
/// Make a `SystemImage` from a `RootDir` for the `system_image` package.
- pub fn from_root_dir(root_dir: RootDir) -> Self {
+ pub fn from_root_dir(root_dir: RootDir<blobfs::Client>) -> Self {
Self { root_dir }
}
@@ -100,7 +100,7 @@
}
/// Consume self and return the contained `package_directory::RootDir`.
- pub fn into_root_dir(self) -> RootDir {
+ pub fn into_root_dir(self) -> RootDir<blobfs::Client> {
self.root_dir
}
}