1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
45use crate::io::{Directory, RemoteDirectory};
6use crate::path::RemoteComponentStoragePath;
7use anyhow::{anyhow, bail, Result};
8use fidl::endpoints::create_proxy;
9use fidl_fuchsia_io as fio;
10use fidl_fuchsia_sys2::StorageAdminProxy;
1112/// Create a new directory in a component's storage.
13///
14/// # Arguments
15/// * `storage_admin`: The StorageAdminProxy
16/// * `path`: The name of a new directory on the target component
17pub async fn make_directory(storage_admin: StorageAdminProxy, path: String) -> Result<()> {
18let remote_path = RemoteComponentStoragePath::parse(&path)?;
1920let (dir_proxy, server) = create_proxy::<fio::DirectoryMarker>();
21let server = server.into_channel();
22let storage_dir = RemoteDirectory::from_proxy(dir_proxy);
2324if remote_path.relative_path.as_os_str().is_empty() {
25bail!("Remote path cannot be the root");
26 }
2728// Open the storage
29storage_admin
30 .open_component_storage_by_id(&remote_path.instance_id, server.into())
31 .await?
32.map_err(|e| anyhow!("Could not open component storage: {:?}", e))?;
3334// Send a request to create the directory
35let dir = storage_dir.create_dir(remote_path.relative_path, false)?;
3637// Verify that we can actually read the contents of the directory created
38dir.entry_names().await?;
3940Ok(())
41}
4243////////////////////////////////////////////////////////////////////////////////
44// tests
4546#[cfg(test)]
47mod test {
48use super::*;
49use crate::storage::test::{node_to_directory, setup_fake_storage_admin};
50use fidl_fuchsia_io as fio;
51use futures::TryStreamExt;
5253// TODO(xbhatnag): Replace this mock with something more robust like VFS.
54 // Currently VFS is not cross-platform.
55fn setup_fake_directory(mut root_dir: fio::DirectoryRequestStream) {
56 fuchsia_async::Task::local(async move {
57// Serve the root directory
58 // Root directory should get Open call with CREATE flag
59let request = root_dir.try_next().await;
60let object = if let Ok(Some(fio::DirectoryRequest::Open {
61 flags, path, object, ..
62 })) = request
63 {
64assert_eq!(path, "test");
65assert!(flags.intersects(fio::Flags::FLAG_MAYBE_CREATE));
66assert!(flags.intersects(fio::Flags::PROTOCOL_DIRECTORY));
67 object
68 } else {
69panic!("did not get open request: {:?}", request);
70 };
7172// Serve the new test directory
73let mut test_dir = node_to_directory(object.into());
7475// Rewind on new directory should succeed
76let request = test_dir.try_next().await;
77if let Ok(Some(fio::DirectoryRequest::Rewind { responder, .. })) = request {
78 responder.send(0).unwrap();
79 } else {
80panic!("did not get rewind request: {:?}", request)
81 }
8283// ReadDirents should report no contents in the new directory
84let request = test_dir.try_next().await;
85if let Ok(Some(fio::DirectoryRequest::ReadDirents { responder, .. })) = request {
86 responder.send(0, &[]).unwrap();
87 } else {
88panic!("did not get readdirents request: {:?}", request)
89 }
90 })
91 .detach();
92 }
9394#[fuchsia_async::run_singlethreaded(test)]
95async fn test_make_directory() -> Result<()> {
96let storage_admin = setup_fake_storage_admin("123456", setup_fake_directory);
97 make_directory(storage_admin, "123456::test".to_string()).await
98}
99}