block_adapter/
lib.rs
1use anyhow::Error;
12use block_client::{BlockClient as _, BufferSlice, MutableBufferSlice, RemoteBlockClient};
13use fidl::endpoints::create_endpoints;
14use std::sync::Arc;
15use vfs::directory::entry::{DirectoryEntry, EntryInfo, GetEntryInfo, OpenRequest};
16use vfs::execution_scope::ExecutionScope;
17use vfs::file::{FidlIoConnection, File, FileIo, FileLike, FileOptions, SyncMode};
18use vfs::node::Node;
19use vfs::{immutable_attributes, pseudo_directory, ObjectRequestRef};
20use {
21 fidl_fuchsia_hardware_block as fhardware_block, fidl_fuchsia_io as fio, fuchsia_async as fasync,
22};
23
24struct BlockFile {
25 block_client: RemoteBlockClient,
26}
27
28impl DirectoryEntry for BlockFile {
29 fn open_entry(self: Arc<Self>, request: OpenRequest<'_>) -> Result<(), zx::Status> {
30 request.open_file(self)
31 }
32}
33
34impl GetEntryInfo for BlockFile {
35 fn entry_info(&self) -> EntryInfo {
36 EntryInfo::new(0, fio::DirentType::File)
37 }
38}
39
40impl Node for BlockFile {
41 async fn get_attributes(
42 &self,
43 requested_attributes: fio::NodeAttributesQuery,
44 ) -> Result<fio::NodeAttributes2, zx::Status> {
45 let block_size = self.block_client.block_size();
46 let block_count = self.block_client.block_count();
47 let device_size = block_count.checked_mul(block_size.into()).unwrap();
48 Ok(immutable_attributes!(
49 requested_attributes,
50 Immutable {
51 protocols: fio::NodeProtocolKinds::FILE,
52 abilities: fio::Operations::GET_ATTRIBUTES
53 | fio::Operations::UPDATE_ATTRIBUTES
54 | fio::Operations::READ_BYTES
55 | fio::Operations::WRITE_BYTES,
56 content_size: device_size,
57 storage_size: device_size,
58 }
59 ))
60 }
61}
62
63impl File for BlockFile {
64 fn writable(&self) -> bool {
65 true
66 }
67
68 async fn open_file(&self, _options: &FileOptions) -> Result<(), zx::Status> {
69 Ok(())
70 }
71
72 async fn truncate(&self, _length: u64) -> Result<(), zx::Status> {
73 Err(zx::Status::NOT_SUPPORTED)
74 }
75
76 async fn get_backing_memory(&self, _flags: fio::VmoFlags) -> Result<zx::Vmo, zx::Status> {
77 Err(zx::Status::NOT_SUPPORTED)
78 }
79
80 async fn get_size(&self) -> Result<u64, zx::Status> {
81 let block_size = self.block_client.block_size();
82 let block_count = self.block_client.block_count();
83 Ok(block_count.checked_mul(block_size.into()).unwrap())
84 }
85
86 async fn update_attributes(
87 &self,
88 _attributes: fio::MutableNodeAttributes,
89 ) -> Result<(), zx::Status> {
90 Err(zx::Status::NOT_SUPPORTED)
91 }
92
93 async fn sync(&self, _mode: SyncMode) -> Result<(), zx::Status> {
94 self.block_client.flush().await
95 }
96}
97
98impl FileIo for BlockFile {
99 async fn read_at(&self, offset: u64, buffer: &mut [u8]) -> Result<u64, zx::Status> {
100 let () = self.block_client.read_at(MutableBufferSlice::Memory(buffer), offset).await?;
101 Ok(buffer.len().try_into().unwrap())
102 }
103
104 async fn write_at(&self, offset: u64, content: &[u8]) -> Result<u64, zx::Status> {
105 let () = self.block_client.write_at(BufferSlice::Memory(content), offset).await?;
106 Ok(content.len().try_into().unwrap())
107 }
108
109 async fn append(&self, _content: &[u8]) -> Result<(u64, u64), zx::Status> {
110 Err(zx::Status::NOT_SUPPORTED)
111 }
112}
113
114impl FileLike for BlockFile {
115 fn open(
116 self: Arc<Self>,
117 scope: ExecutionScope,
118 options: FileOptions,
119 object_request: ObjectRequestRef<'_>,
120 ) -> Result<(), zx::Status> {
121 FidlIoConnection::create_sync(scope, self, options, object_request.take());
122 Ok(())
123 }
124}
125
126pub async fn run(
131 block_proxy: fhardware_block::BlockProxy,
132 binary: &str,
133 args: impl Iterator<Item = String>,
134) -> Result<i64, Error> {
135 let (client, server) = create_endpoints::<fio::DirectoryMarker>();
136
137 let server_fut = {
138 let block_client = RemoteBlockClient::new(block_proxy).await?;
139 let dir = pseudo_directory! {
140 "block" => Arc::new(BlockFile {
141 block_client,
142 }),
143 };
144
145 let scope = ExecutionScope::new();
146 vfs::directory::serve_on(
147 dir,
148 fio::PERM_READABLE | fio::PERM_WRITABLE,
149 scope.clone(),
150 server,
151 );
152 async move { scope.wait().await }
153 };
154
155 let client_fut = {
156 let mut builder = fdio::SpawnBuilder::new()
157 .options(fdio::SpawnOptions::CLONE_ALL)
158 .add_directory_to_namespace("/device", client)?
159 .arg(binary)?;
160 for arg in args {
161 builder = builder.arg(arg)?;
162 }
163 builder = builder.arg("/device/block")?;
164 let process = builder.spawn_from_path(binary, &fuchsia_runtime::job_default())?;
165
166 async move {
167 let _: zx::Signals =
168 fasync::OnSignals::new(&process, zx::Signals::PROCESS_TERMINATED).await?;
169 let info = process.info()?;
170 Ok::<_, Error>(info.return_code)
171 }
172 };
173
174 futures::future::join(server_fut, client_fut).await.1
175}