component_debug/storage/
list.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, Result};
8use fidl::endpoints::create_proxy;
9use fidl_fuchsia_io as fio;
10use fidl_fuchsia_sys2::StorageAdminProxy;
11
12/// List all directories and files in a component's storage.
13/// Returns a vector of names of the directories and files as strings.
14///
15/// # Arguments
16/// * `storage_admin`: The StorageAdminProxy
17/// * `path`: A path on the target component
18pub async fn list(storage_admin: StorageAdminProxy, path: String) -> Result<Vec<String>> {
19    let remote_path = RemoteComponentStoragePath::parse(&path)?;
20
21    let (dir_proxy, server) = create_proxy::<fio::DirectoryMarker>();
22    let server = server.into_channel();
23    let storage_dir = RemoteDirectory::from_proxy(dir_proxy);
24
25    storage_admin
26        .open_component_storage_by_id(&remote_path.instance_id, server.into())
27        .await?
28        .map_err(|e| anyhow!("Could not open component storage: {:?}", e))?;
29
30    let dir = if remote_path.relative_path.as_os_str().is_empty() {
31        storage_dir
32    } else {
33        storage_dir.open_dir_readonly(remote_path.relative_path)?
34    };
35
36    dir.entry_names().await
37}
38
39////////////////////////////////////////////////////////////////////////////////
40// tests
41
42#[cfg(test)]
43mod test {
44    use super::*;
45    use crate::storage::test::setup_fake_storage_admin;
46    use fidl_fuchsia_io as fio;
47    use futures::TryStreamExt;
48
49    pub fn dirents(names: Vec<&'static str>) -> Vec<u8> {
50        let mut bytes = vec![];
51        for name in names {
52            // inode: u64
53            for _ in 0..8 {
54                bytes.push(0);
55            }
56            // size: u8
57            bytes.push(name.len() as u8);
58            // type: u8
59            bytes.push(fio::DirentType::File.into_primitive());
60            // name: [u8]
61            for byte in name.bytes() {
62                bytes.push(byte);
63            }
64        }
65        bytes
66    }
67
68    // TODO(xbhatnag): Replace this mock with something more robust like VFS.
69    // Currently VFS is not cross-platform.
70    fn setup_fake_directory(mut root_dir: fio::DirectoryRequestStream) {
71        fuchsia_async::Task::local(async move {
72            let dirents = dirents(vec!["foo", "bar"]);
73
74            // Serve the root directory
75            // Rewind on root directory should succeed
76            let request = root_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 two files in the root directory
84            let request = root_dir.try_next().await;
85            if let Ok(Some(fio::DirectoryRequest::ReadDirents { max_bytes, responder })) = request {
86                assert!(dirents.len() as u64 <= max_bytes);
87                responder.send(0, dirents.as_slice()).unwrap();
88            } else {
89                panic!("did not get readdirents request: {:?}", request)
90            }
91
92            // ReadDirents should not report any more contents
93            let request = root_dir.try_next().await;
94            if let Ok(Some(fio::DirectoryRequest::ReadDirents { responder, .. })) = request {
95                responder.send(0, &[]).unwrap();
96            } else {
97                panic!("did not get readdirents request: {:?}", request)
98            }
99        })
100        .detach();
101    }
102
103    #[fuchsia_async::run_singlethreaded(test)]
104    async fn test_list_root() -> Result<()> {
105        let storage_admin = setup_fake_storage_admin("123456", setup_fake_directory);
106        let dir_entries = list(storage_admin, "123456::.".to_string()).await?;
107
108        assert_eq!(dir_entries, vec!["bar", "foo"]);
109        Ok(())
110    }
111}