component_debug/storage/
make_directory.rs

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.
4
5use 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;
11
12/// 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<()> {
18    let remote_path = RemoteComponentStoragePath::parse(&path)?;
19
20    let (dir_proxy, server) = create_proxy::<fio::DirectoryMarker>();
21    let server = server.into_channel();
22    let storage_dir = RemoteDirectory::from_proxy(dir_proxy);
23
24    if remote_path.relative_path.as_os_str().is_empty() {
25        bail!("Remote path cannot be the root");
26    }
27
28    // Open the storage
29    storage_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))?;
33
34    // Send a request to create the directory
35    let dir = storage_dir.create_dir(remote_path.relative_path, false)?;
36
37    // Verify that we can actually read the contents of the directory created
38    dir.entry_names().await?;
39
40    Ok(())
41}
42
43////////////////////////////////////////////////////////////////////////////////
44// tests
45
46#[cfg(test)]
47mod test {
48    use super::*;
49    use crate::storage::test::{node_to_directory, setup_fake_storage_admin};
50    use fidl_fuchsia_io as fio;
51    use futures::TryStreamExt;
52
53    // TODO(xbhatnag): Replace this mock with something more robust like VFS.
54    // Currently VFS is not cross-platform.
55    fn 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
59            let request = root_dir.try_next().await;
60            let object = if let Ok(Some(fio::DirectoryRequest::Open {
61                flags, path, object, ..
62            })) = request
63            {
64                assert_eq!(path, "test");
65                assert!(flags.intersects(fio::Flags::FLAG_MAYBE_CREATE));
66                assert!(flags.intersects(fio::Flags::PROTOCOL_DIRECTORY));
67                object
68            } else {
69                panic!("did not get open request: {:?}", request);
70            };
71
72            // Serve the new test directory
73            let mut test_dir = node_to_directory(object.into());
74
75            // Rewind on new directory should succeed
76            let request = test_dir.try_next().await;
77            if let Ok(Some(fio::DirectoryRequest::Rewind { responder, .. })) = request {
78                responder.send(0).unwrap();
79            } else {
80                panic!("did not get rewind request: {:?}", request)
81            }
82
83            // ReadDirents should report no contents in the new directory
84            let request = test_dir.try_next().await;
85            if let Ok(Some(fio::DirectoryRequest::ReadDirents { responder, .. })) = request {
86                responder.send(0, &[]).unwrap();
87            } else {
88                panic!("did not get readdirents request: {:?}", request)
89            }
90        })
91        .detach();
92    }
93
94    #[fuchsia_async::run_singlethreaded(test)]
95    async fn test_make_directory() -> Result<()> {
96        let storage_admin = setup_fake_storage_admin("123456", setup_fake_directory);
97        make_directory(storage_admin, "123456::test".to_string()).await
98    }
99}