1#![recursion_limit = "256"]
6
7use fidl::endpoints::SynchronousProxy;
8use fidl_fuchsia_hardware_adb as fadb;
9use fuchsia_async as fasync;
10use futures_util::StreamExt;
11use starnix_core::power::{create_proxy_for_wake_events_counter_zero, mark_proxy_message_handled};
12use starnix_core::task::{CurrentTask, EventHandler, Kernel, WaitCanceler, WaitQueue, Waiter};
13use starnix_core::vfs::pseudo::vec_directory::{VecDirectory, VecDirectoryEntry};
14use starnix_core::vfs::{
15 CacheMode, DirectoryEntryType, FileObject, FileObjectState, FileOps, FileSystem,
16 FileSystemHandle, FileSystemOps, FileSystemOptions, FsNode, FsNodeInfo, FsNodeOps, FsStr,
17 InputBuffer, OutputBuffer, fileops_impl_noop_sync, fileops_impl_seekless, fs_args,
18 fs_node_impl_dir_readonly, fs_node_impl_not_dir,
19};
20use starnix_logging::{log_warn, track_stub};
21use starnix_sync::{FileOpsCore, InterruptibleEvent, Locked, Mutex, Unlocked};
22use starnix_types::vfs::default_statfs;
23use starnix_uapi::auth::FsCred;
24use starnix_uapi::errors::Errno;
25use starnix_uapi::file_mode::mode;
26use starnix_uapi::open_flags::OpenFlags;
27use starnix_uapi::vfs::FdEvents;
28use starnix_uapi::{
29 errno, error, gid_t, ino_t, statfs, uid_t, usb_functionfs_event,
30 usb_functionfs_event_type_FUNCTIONFS_BIND, usb_functionfs_event_type_FUNCTIONFS_DISABLE,
31 usb_functionfs_event_type_FUNCTIONFS_ENABLE, usb_functionfs_event_type_FUNCTIONFS_UNBIND,
32};
33use std::collections::VecDeque;
34use std::ops::Deref;
35use std::sync::Arc;
36use zerocopy::IntoBytes;
37
38const ROOT_NODE_ID: ino_t = 1;
40
41const CONTROL_ENDPOINT: &str = "ep0";
43const CONTROL_ENDPOINT_NODE_ID: ino_t = 2;
44
45const OUTPUT_ENDPOINT: &str = "ep1";
46const OUTPUT_ENDPOINT_NODE_ID: ino_t = 3;
47
48const INPUT_ENDPOINT: &str = "ep2";
49const INPUT_ENDPOINT_NODE_ID: ino_t = 4;
50
51const FUNCTIONFS_MAGIC: u32 = 0xa647361;
54
55const ADB_DIRECTORY: &str = "/svc/fuchsia.hardware.adb.Service";
56
57const ADB_INTERACTION_TIMEOUT: zx::Duration<zx::MonotonicTimeline> = zx::Duration::from_seconds(2);
60
61#[derive(Default)]
62struct PendingResult<T: Default> {
63 event: Arc<InterruptibleEvent>,
64 result: Mutex<Option<Result<T, Errno>>>,
65}
66
67impl<T: Default> PendingResult<T> {
68 fn set_result(&self, res: Result<T, Errno>) {
69 let mut result = self.result.lock();
70 debug_assert!(result.is_none(), "PendingResult set more than once");
71
72 result.replace(res);
73 self.event.notify();
74 }
75}
76
77struct ReadCommand {
78 pending: Arc<PendingResult<Vec<u8>>>,
79}
80
81struct WriteCommand {
82 data: Vec<u8>,
83 pending: Arc<PendingResult<usize>>,
84}
85
86async fn handle_adb(
95 proxy: fadb::UsbAdbImpl_Proxy,
96 message_counter: Option<zx::Counter>,
97 read_commands: async_channel::Receiver<ReadCommand>,
98 write_commands: async_channel::Receiver<WriteCommand>,
99 state: Arc<Mutex<FunctionFsState>>,
100) {
101 async fn handle_events(
117 mut stream: fadb::UsbAdbImpl_EventStream,
118 message_counter: &Option<zx::Counter>,
119 state: Arc<Mutex<FunctionFsState>>,
120 ) {
121 let queue_event = |event| {
122 let mut state_locked = state.lock();
123 state_locked
124 .event_queue
125 .push_back(usb_functionfs_event { type_: event as u8, ..Default::default() });
126 state_locked.waiters.notify_fd_events(FdEvents::POLLIN);
127 };
128
129 queue_event(usb_functionfs_event_type_FUNCTIONFS_BIND);
130
131 while let Some(Ok(fadb::UsbAdbImpl_Event::OnStatusChanged { status })) = stream.next().await
132 {
133 let is_online = status == fadb::StatusFlags::ONLINE;
134 {
135 let mut state_locked = state.lock();
136 state_locked.is_online = is_online;
137 state_locked.event_queue.push_back(usb_functionfs_event {
138 type_: if is_online {
139 usb_functionfs_event_type_FUNCTIONFS_ENABLE
140 } else {
141 usb_functionfs_event_type_FUNCTIONFS_DISABLE
142 } as u8,
143 ..Default::default()
144 });
145 state_locked.waiters.notify_fd_events(FdEvents::POLLIN);
146 state_locked.waiters.notify_all();
147 }
148
149 message_counter.as_ref().map(mark_proxy_message_handled);
153 }
154
155 queue_event(usb_functionfs_event_type_FUNCTIONFS_UNBIND);
156 }
157
158 async fn handle_idle_timeouts(
167 timeouts: async_channel::Receiver<zx::MonotonicInstant>,
168 message_counter: &Option<zx::Counter>,
169 ) {
170 timeouts
171 .for_each(|timeout| async move {
172 use fasync::WakeupTime;
173 timeout.into_timer().await;
174 message_counter.as_ref().map(mark_proxy_message_handled);
175 })
176 .await
177 }
178
179 async fn handle_read_commands(
181 proxy: &fadb::UsbAdbImpl_Proxy,
182 timeouts_sender: async_channel::Sender<zx::MonotonicInstant>,
183 commands: async_channel::Receiver<ReadCommand>,
184 ) {
185 let timeouts_sender = &timeouts_sender;
186 commands
187 .for_each(|ReadCommand { pending }| async move {
188 let receive_future = proxy.receive();
191
192 timeouts_sender
197 .send(zx::MonotonicInstant::after(ADB_INTERACTION_TIMEOUT))
198 .await
199 .expect("Should be able to send timeout");
200
201 let response = match receive_future.await {
202 Err(err) => {
203 log_warn!("Failed to call UsbAdbImpl.Receive: {err}");
204 error!(EINVAL)
205 }
206 Ok(Err(err)) => {
207 log_warn!("Failed to receive data from adb driver: {err}");
208 error!(EINVAL)
209 }
210 Ok(Ok(payload)) => Ok(payload),
211 };
212
213 pending.set_result(response);
214 })
215 .await;
216 }
217
218 async fn handle_write_commands(
220 proxy: &fadb::UsbAdbImpl_Proxy,
221 timeouts_sender: async_channel::Sender<zx::MonotonicInstant>,
222 commands: async_channel::Receiver<WriteCommand>,
223 ) {
224 let timeouts_sender = &timeouts_sender;
225 commands
226 .for_each(|WriteCommand { data, pending }| async move {
227 let response = match proxy.queue_tx(&data).await {
228 Err(err) => {
229 log_warn!("Failed to call UsbAdbImpl.QueueTx: {err}");
230 error!(EINVAL)
231 }
232 Ok(Err(err)) => {
233 log_warn!("Failed to queue data to adb driver: {err}");
234 error!(EINVAL)
235 }
236 Ok(Ok(_)) => Ok(data.len()),
237 };
238
239 timeouts_sender
243 .send(zx::MonotonicInstant::after(ADB_INTERACTION_TIMEOUT))
244 .await
245 .expect("Should be able to send timeout");
246
247 pending.set_result(response);
248 })
249 .await;
250 }
251
252 let (timeouts_sender, timeouts_receiver) = async_channel::unbounded();
253 let event_future = handle_events(proxy.take_event_stream(), &message_counter, state);
254 let write_commands_future =
255 handle_write_commands(&proxy, timeouts_sender.clone(), write_commands);
256 let read_commands_future = handle_read_commands(&proxy, timeouts_sender, read_commands);
257 let timeout_future = handle_idle_timeouts(timeouts_receiver, &message_counter);
258 futures::join!(event_future, write_commands_future, read_commands_future, timeout_future);
259}
260
261pub struct FunctionFs;
262impl FunctionFs {
263 pub fn new_fs(
264 locked: &mut Locked<Unlocked>,
265 current_task: &CurrentTask,
266 options: FileSystemOptions,
267 ) -> Result<FileSystemHandle, Errno> {
268 if options.source != "adb" {
269 track_stub!(TODO("https://fxbug.dev/329699340"), "FunctionFS supports other uses");
270 return error!(ENODEV);
271 }
272
273 if let Err(e) = std::fs::read_dir(ADB_DIRECTORY) {
277 log_warn!(
278 "Attempted to mount FunctionFS for adb, but could not read {ADB_DIRECTORY}: {e}"
279 );
280 return error!(ENODEV);
281 }
282
283 let uid = if let Some(uid) = options.params.get(b"uid") {
284 fs_args::parse::<uid_t>(uid.as_ref())?
285 } else {
286 0
287 };
288 let gid = if let Some(gid) = options.params.get(b"gid") {
289 fs_args::parse::<gid_t>(gid.as_ref())?
290 } else {
291 0
292 };
293
294 let fs = FileSystem::new(
295 locked,
296 current_task.kernel(),
297 CacheMode::Uncached,
298 FunctionFs,
299 options,
300 )?;
301
302 let creds = FsCred { uid, gid };
303 let info = FsNodeInfo::new(mode!(IFDIR, 0o777), creds);
304 fs.create_root_with_info(ROOT_NODE_ID, FunctionFsRootDir::default(), info);
305 Ok(fs)
306 }
307}
308
309impl FileSystemOps for FunctionFs {
310 fn statfs(
311 &self,
312 _locked: &mut Locked<FileOpsCore>,
313 _fs: &FileSystem,
314 _current_task: &CurrentTask,
315 ) -> Result<statfs, Errno> {
316 Ok(default_statfs(FUNCTIONFS_MAGIC))
317 }
318
319 fn name(&self) -> &'static FsStr {
320 b"functionfs".into()
321 }
322}
323
324#[derive(Default)]
325struct FunctionFsState {
326 num_control_file_objects: usize,
330
331 has_input_output_endpoints: bool,
334
335 is_online: bool,
337
338 adb_read_channel: Option<async_channel::Sender<ReadCommand>>,
339 adb_write_channel: Option<async_channel::Sender<WriteCommand>>,
340
341 device_proxy: Option<fadb::DeviceSynchronousProxy>,
343
344 event_queue: VecDeque<usb_functionfs_event>,
347
348 waiters: WaitQueue,
349}
350
351pub enum AdbProxyMode {
352 None,
354
355 WakeContainer,
359}
360
361fn connect_to_device(
362 proxy: AdbProxyMode,
363) -> Result<
364 (fadb::DeviceSynchronousProxy, fadb::UsbAdbImpl_SynchronousProxy, Option<zx::Counter>),
365 Errno,
366> {
367 let mut dir = std::fs::read_dir(ADB_DIRECTORY).map_err(|_| errno!(EINVAL))?;
368
369 let Some(Ok(entry)) = dir.next() else {
370 return error!(EBUSY);
371 };
372 let path =
373 entry.path().join("adb").into_os_string().into_string().map_err(|_| errno!(EINVAL))?;
374
375 let (client_channel, server_channel) = zx::Channel::create();
376 fdio::service_connect(&path, server_channel).map_err(|_| errno!(EINVAL))?;
377 let device_proxy = fadb::DeviceSynchronousProxy::new(client_channel);
378
379 let (adb_proxy, server_end) = fidl::endpoints::create_sync_proxy::<fadb::UsbAdbImpl_Marker>();
380 let (adb_proxy, message_counter) = match proxy {
381 AdbProxyMode::None => (adb_proxy, None),
382 AdbProxyMode::WakeContainer => {
383 let (adb_proxy, message_counter) = create_proxy_for_wake_events_counter_zero(
384 adb_proxy.into_channel(),
385 "adb".to_string(),
386 );
387 let adb_proxy = fadb::UsbAdbImpl_SynchronousProxy::from_channel(adb_proxy);
388 (adb_proxy, Some(message_counter))
389 }
390 };
391
392 device_proxy
393 .start_adb(server_end, zx::MonotonicInstant::INFINITE)
394 .map_err(|_| errno!(EINVAL))?
395 .map_err(|_| errno!(EINVAL))?;
396 return Ok((device_proxy, adb_proxy, message_counter));
397}
398
399#[derive(Default)]
400struct FunctionFsRootDir {
401 state: Arc<Mutex<FunctionFsState>>,
402}
403
404impl FunctionFsRootDir {
405 fn create_endpoints(&self, kernel: &Kernel) -> Result<(), Errno> {
406 let mut state = self.state.lock();
407
408 if state.has_input_output_endpoints {
411 return Ok(());
412 }
413 let (device_proxy, adb_proxy, message_counter) =
414 connect_to_device(AdbProxyMode::WakeContainer)?;
415 state.device_proxy = Some(device_proxy);
416
417 let (read_command_sender, read_command_receiver) = async_channel::unbounded();
418 state.adb_read_channel = Some(read_command_sender);
419
420 let (write_command_sender, write_command_receiver) = async_channel::unbounded();
421 state.adb_write_channel = Some(write_command_sender);
422
423 state.event_queue.clear();
424
425 let state_copy = Arc::clone(&self.state);
426 kernel.kthreads.spawn_future(
429 move || async move {
430 let adb_proxy = fadb::UsbAdbImpl_Proxy::new(fidl::AsyncChannel::from_channel(
431 adb_proxy.into_channel(),
432 ));
433 handle_adb(
434 adb_proxy,
435 message_counter,
436 read_command_receiver,
437 write_command_receiver,
438 state_copy,
439 )
440 .await
441 },
442 "functionfs_adb_worker",
443 );
444
445 state.has_input_output_endpoints = true;
446 Ok(())
447 }
448
449 fn from_fs(fs: &FileSystem) -> &Self {
450 fs.root()
451 .node
452 .downcast_ops::<FunctionFsRootDir>()
453 .expect("failed to downcast functionfs root dir")
454 }
455
456 fn from_file(file: &FileObject) -> &Self {
457 Self::from_fs(&file.fs)
458 }
459
460 fn on_control_opened(&self) {
461 let mut state = self.state.lock();
462 state.num_control_file_objects += 1;
463 }
464
465 fn on_control_closed(&self) {
466 let mut state = self.state.lock();
467 state.num_control_file_objects -= 1;
468 if state.num_control_file_objects == 0 {
469 if let Some(device_proxy) = state.device_proxy.as_ref() {
471 let _ = device_proxy
472 .stop_adb(zx::MonotonicInstant::INFINITE)
473 .map_err(|_| errno!(EINVAL));
474 }
475
476 state.has_input_output_endpoints = false;
477 state.is_online = false;
478 state.adb_read_channel = None;
479 state.adb_write_channel = None;
480 }
481 }
482
483 fn wait_until_online(
484 &self,
485 locked: &mut Locked<FileOpsCore>,
486 current_task: &CurrentTask,
487 file: &FileObject,
488 ) -> Result<(), Errno> {
489 loop {
490 let waiter = {
491 let state = self.state.lock();
492 if state.is_online {
493 return Ok(());
494 }
495 if file.flags().contains(OpenFlags::NONBLOCK) {
496 return error!(EAGAIN);
497 }
498 let waiter = Waiter::new();
499 state.waiters.wait_async(&waiter);
500 waiter
501 };
502 waiter.wait(locked, current_task)?;
503 }
504 }
505
506 fn available(&self) -> usize {
507 let state = self.state.lock();
508 state.event_queue.len()
509 }
510
511 fn write(
512 &self,
513 locked: &mut Locked<FileOpsCore>,
514 current_task: &CurrentTask,
515 file: &FileObject,
516 bytes: &[u8],
517 ) -> Result<usize, Errno> {
518 self.wait_until_online(locked, current_task, file)?;
519
520 let data = Vec::from(bytes);
521 let pending = Arc::<PendingResult<usize>>::default();
522 let guard = pending.event.begin_wait();
523
524 if let Some(channel) = self.state.lock().adb_write_channel.as_ref() {
525 channel
526 .send_blocking(WriteCommand { data, pending: pending.clone() })
527 .map_err(|_| errno!(EINVAL))?;
528 } else {
529 return error!(ENODEV);
530 }
531
532 current_task.block_until(guard, zx::MonotonicInstant::INFINITE)?;
533
534 let mut result = pending.result.lock();
535 result.take().ok_or_else(|| errno!(EINTR))?
536 }
537
538 fn read(
539 &self,
540 locked: &mut Locked<FileOpsCore>,
541 current_task: &CurrentTask,
542 file: &FileObject,
543 ) -> Result<Vec<u8>, Errno> {
544 self.wait_until_online(locked, current_task, file)?;
545
546 let pending = Arc::<PendingResult<Vec<u8>>>::default();
547 let guard = pending.event.begin_wait();
548 if let Some(channel) = self.state.lock().adb_read_channel.as_ref() {
549 channel
550 .send_blocking(ReadCommand { pending: pending.clone() })
551 .map_err(|_| errno!(EINVAL))?;
552 } else {
553 return error!(ENODEV);
554 }
555
556 current_task.block_until(guard, zx::MonotonicInstant::INFINITE)?;
557
558 let mut result = pending.result.lock();
559 result.take().ok_or_else(|| errno!(EINTR))?
560 }
561}
562
563impl FsNodeOps for FunctionFsRootDir {
564 fs_node_impl_dir_readonly!();
565
566 fn create_file_ops(
567 &self,
568 _locked: &mut Locked<FileOpsCore>,
569 _node: &FsNode,
570 _current_task: &CurrentTask,
571 _flags: OpenFlags,
572 ) -> Result<Box<dyn FileOps>, Errno> {
573 let mut entries = vec![];
574 entries.push(VecDirectoryEntry {
575 entry_type: DirectoryEntryType::REG,
576 name: CONTROL_ENDPOINT.into(),
577 inode: Some(CONTROL_ENDPOINT_NODE_ID),
578 });
579
580 let state = self.state.lock();
581 if state.has_input_output_endpoints {
582 entries.push(VecDirectoryEntry {
583 entry_type: DirectoryEntryType::REG,
584 name: INPUT_ENDPOINT.into(),
585 inode: Some(INPUT_ENDPOINT_NODE_ID),
586 });
587 entries.push(VecDirectoryEntry {
588 entry_type: DirectoryEntryType::REG,
589 name: OUTPUT_ENDPOINT.into(),
590 inode: Some(OUTPUT_ENDPOINT_NODE_ID),
591 });
592 }
593
594 Ok(VecDirectory::new_file(entries))
595 }
596
597 fn lookup(
598 &self,
599 _locked: &mut Locked<FileOpsCore>,
600 node: &FsNode,
601 _current_task: &CurrentTask,
602 name: &FsStr,
603 ) -> Result<starnix_core::vfs::FsNodeHandle, Errno> {
604 let name = std::str::from_utf8(name).map_err(|_| errno!(ENOENT))?;
605 let cred = node.info().cred();
606 match name {
607 CONTROL_ENDPOINT => Ok(node.fs().create_node(
608 CONTROL_ENDPOINT_NODE_ID,
609 FunctionFsControlEndpoint,
610 FsNodeInfo::new(mode!(IFREG, 0o600), cred),
611 )),
612 OUTPUT_ENDPOINT => Ok(node.fs().create_node(
613 OUTPUT_ENDPOINT_NODE_ID,
614 FunctionFsOutputEndpoint,
615 FsNodeInfo::new(mode!(IFREG, 0o600), cred),
616 )),
617 INPUT_ENDPOINT => Ok(node.fs().create_node(
618 INPUT_ENDPOINT_NODE_ID,
619 FunctionFsInputEndpoint,
620 FsNodeInfo::new(mode!(IFREG, 0o600), cred),
621 )),
622 _ => error!(ENOENT),
623 }
624 }
625}
626
627struct FunctionFsControlEndpoint;
631impl FsNodeOps for FunctionFsControlEndpoint {
632 fs_node_impl_not_dir!();
633
634 fn create_file_ops(
635 &self,
636 _locked: &mut Locked<FileOpsCore>,
637 node: &FsNode,
638 _current_task: &CurrentTask,
639 _flags: OpenFlags,
640 ) -> Result<Box<dyn FileOps>, Errno> {
641 let fs = node.fs();
642 let rootdir = fs
643 .root()
644 .node
645 .downcast_ops::<FunctionFsRootDir>()
646 .expect("failed to downcast functionfs root dir");
647 rootdir.on_control_opened();
648 Ok(Box::new(FunctionFsControlEndpoint))
649 }
650}
651
652impl FileOps for FunctionFsControlEndpoint {
653 fileops_impl_seekless!();
654 fileops_impl_noop_sync!();
655
656 fn close(
657 self: Box<Self>,
658 _locked: &mut Locked<FileOpsCore>,
659 file: &FileObjectState,
660 _current_task: &CurrentTask,
661 ) {
662 let rootdir = FunctionFsRootDir::from_fs(&file.fs);
663 rootdir.on_control_closed();
664 }
665
666 fn read(
667 &self,
668 _locked: &mut Locked<FileOpsCore>,
669 file: &FileObject,
670 _current_task: &CurrentTask,
671 _offset: usize,
672 data: &mut dyn OutputBuffer,
673 ) -> Result<usize, Errno> {
674 track_stub!(
677 TODO("https://fxbug.dev/329699340"),
678 "FunctionFS blocking read on control endpoint"
679 );
680
681 let rootdir = FunctionFsRootDir::from_file(file);
682
683 let mut state = rootdir.state.lock();
684 if !state.event_queue.is_empty() {
685 if data.available() < std::mem::size_of::<usb_functionfs_event>() {
686 return error!(EINVAL);
687 }
688 } else {
689 return error!(EAGAIN);
690 }
691 let front = state.event_queue.pop_front().expect("pop from non-empty event queue");
692 data.write(front.as_bytes())
693 }
694
695 fn write(
696 &self,
697 _locked: &mut Locked<FileOpsCore>,
698 file: &FileObject,
699 current_task: &CurrentTask,
700 _offset: usize,
701 data: &mut dyn InputBuffer,
702 ) -> Result<usize, Errno> {
703 track_stub!(TODO("https://fxbug.dev/329699340"), "FunctionFS should parse descriptors");
707
708 let rootdir = FunctionFsRootDir::from_file(file);
709 rootdir.create_endpoints(current_task.kernel().deref())?;
710
711 Ok(data.drain())
712 }
713
714 fn wait_async(
715 &self,
716 _locked: &mut Locked<FileOpsCore>,
717 file: &FileObject,
718 _current_task: &CurrentTask,
719 waiter: &Waiter,
720 events: FdEvents,
721 handler: EventHandler,
722 ) -> Option<WaitCanceler> {
723 let rootdir = FunctionFsRootDir::from_file(file);
724 let state = rootdir.state.lock();
725 Some(state.waiters.wait_async_fd_events(waiter, events, handler))
726 }
727
728 fn query_events(
729 &self,
730 _locked: &mut Locked<FileOpsCore>,
731 file: &FileObject,
732 _current_task: &CurrentTask,
733 ) -> Result<FdEvents, Errno> {
734 let rootdir = FunctionFsRootDir::from_file(file);
735 if rootdir.available() > 0 { Ok(FdEvents::POLLIN) } else { Ok(FdEvents::empty()) }
736 }
737}
738
739struct FunctionFsInputEndpoint;
742impl FsNodeOps for FunctionFsInputEndpoint {
743 fs_node_impl_not_dir!();
744
745 fn create_file_ops(
746 &self,
747 _locked: &mut Locked<FileOpsCore>,
748 _node: &FsNode,
749 _current_task: &CurrentTask,
750 _flags: OpenFlags,
751 ) -> Result<Box<dyn FileOps>, Errno> {
752 Ok(Box::new(FunctionFsInputEndpoint))
753 }
754}
755
756impl FileOps for FunctionFsInputEndpoint {
757 fileops_impl_seekless!();
758 fileops_impl_noop_sync!();
759
760 fn read(
761 &self,
762 _locked: &mut Locked<FileOpsCore>,
763 _file: &FileObject,
764 _current_task: &CurrentTask,
765 _offset: usize,
766 _data: &mut dyn OutputBuffer,
767 ) -> Result<usize, Errno> {
768 error!(EINVAL)
769 }
770
771 fn write(
772 &self,
773 locked: &mut Locked<FileOpsCore>,
774 file: &FileObject,
775 current_task: &CurrentTask,
776 _offset: usize,
777 data: &mut dyn InputBuffer,
778 ) -> Result<usize, Errno> {
779 let bytes = data.read_all()?;
780 let rootdir = FunctionFsRootDir::from_file(file);
781 rootdir.write(locked, current_task, file, &bytes)
782 }
783}
784
785struct FunctionFsOutputEndpoint;
788impl FsNodeOps for FunctionFsOutputEndpoint {
789 fs_node_impl_not_dir!();
790
791 fn create_file_ops(
792 &self,
793 _locked: &mut Locked<FileOpsCore>,
794 _node: &FsNode,
795 _current_task: &CurrentTask,
796 _flags: OpenFlags,
797 ) -> Result<Box<dyn FileOps>, Errno> {
798 Ok(Box::new(FunctionFsOutputFileObject))
799 }
800}
801
802struct FunctionFsOutputFileObject;
803
804impl FileOps for FunctionFsOutputFileObject {
805 fileops_impl_seekless!();
806 fileops_impl_noop_sync!();
807
808 fn read(
809 &self,
810 locked: &mut Locked<FileOpsCore>,
811 file: &FileObject,
812 current_task: &CurrentTask,
813 _offset: usize,
814 data: &mut dyn OutputBuffer,
815 ) -> Result<usize, Errno> {
816 let rootdir = FunctionFsRootDir::from_file(file);
817 let payload = rootdir.read(locked, current_task, file)?;
818 if payload.len() > data.available() {
819 return error!(EINVAL);
822 }
823
824 data.write(&payload)
825 }
826
827 fn write(
828 &self,
829 _locked: &mut Locked<FileOpsCore>,
830 _file: &FileObject,
831 _current_task: &CurrentTask,
832 _offset: usize,
833 _data: &mut dyn InputBuffer,
834 ) -> Result<usize, Errno> {
835 error!(EINVAL)
836 }
837}