1use std::sync::{
2 Arc,
3 atomic::{AtomicUsize, Ordering},
4};
5
6#[cfg(unix)]
7use std::{path::Path, time::Duration};
8
9use bytes::{Buf, BytesMut};
10#[cfg(unix)]
11use dolang_rpc::auth::AuthKey;
12use dolang_rpc::{
13 handle::{DefaultHandle, OsHandle},
14 server::CallContext,
15 session::{Cite, Gift, OpaqueGuard, OpaqueResource},
16};
17use dolang_winterop::security::SecDesc;
18#[cfg(unix)]
19use std::os::unix::io::OwnedFd;
20use tokio::io::{self, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
21#[cfg(windows)]
22use tokio::net::windows::named_pipe::NamedPipeClient;
23#[cfg(all(docsrs, not(windows)))]
24struct NamedPipeClient;
25use tokio::sync::{Mutex, watch};
26#[cfg(unix)]
27use tokio::{
28 net::{UnixListener, UnixStream, unix::SocketAddr},
29 sync::mpsc,
30 task::{JoinError, JoinSet},
31 time::timeout,
32};
33
34use crate::{
35 MAX_FILE_READ, STREAM_CHUNK_SIZE, SessionMode, Vfs,
36 directory::ReadDir,
37 error::{Error, ErrorKind, HandoffError, Result},
38 extension::{self, ExtContext},
39 file::XattrEntry,
40 file::{AccessFlags, CopyDest, CopyMode, File, FileLock, FileLockRequest, StreamEntry},
41 metadata::{FsMetadata, Metadata},
42 path,
43 process::{
44 Child, Command, Process, ProcessInfo, Processes, Signal, StartTime, StdioRecv, StdioSend,
45 },
46 protocol::{
47 AccessRequest, AclRequest, CanonicalizeRequest, CopyRequest, CreateDirRequest,
48 ExtensionRequest, ExtensionResponse, FsMetadataRequest, GlobRequest, HardLinkRequest,
49 MetadataRequest, MoveRequest, OpenFlags, OpenHandle, OpenRequest, OpenVfsHandle,
50 PipeResponse, ProcessPage, QueryResponse, ReadDirPage, ReadLinkRequest, RemoveDirRequest,
51 RemoveRequest, RenameRequest, Request, RequestKind, ResponseKind, SecDescRequest,
52 SetAclRequest, SetXattrRequest, SpawnRequest, StdioRecvTarget, StdioSendTarget,
53 StreamsRequest, SymlinkKind, SymlinkRequest, UnixVfsRequest, UpdateMetadataRequest,
54 UpdateSecDescRequest, VfsProtocol, WellKnownPathRequest, WindowsAdminRequest,
55 XattrNamespaceRequest, XattrRequest, XattrsRequest, rpc_builder,
56 },
57 security::{Acl, AclKind},
58 session::{
59 ChildMarker, FileLockMarker, FileMarker, ProcessEnumMarker, ProcessMarker, ReadDirMarker,
60 StdioRecvMarker, StdioSendMarker, VfsMarker,
61 },
62};
63
64#[derive(Clone)]
65struct Connection {
66 server: Arc<ServerState>,
67 mode: SessionMode,
68 drain: Arc<Drain>,
69}
70
71struct Drain {
80 state: AtomicUsize,
82 done: watch::Sender<bool>,
83}
84
85impl Drain {
86 fn new() -> Arc<Self> {
87 Arc::new(Self {
88 state: AtomicUsize::new(0),
89 done: watch::channel(false).0,
90 })
91 }
92
93 fn try_acquire(&self, count: usize) -> bool {
102 if self.state.load(Ordering::Acquire) & 1 != 0 {
103 return false;
104 }
105 self.state.fetch_add(count << 1, Ordering::Relaxed);
106 true
107 }
108
109 fn release(&self, count: usize) {
111 if self.state.fetch_sub(count << 1, Ordering::AcqRel) == (count << 1) | 1 {
114 self.done.send_replace(true);
115 }
116 }
117
118 fn begin_stop(&self) {
120 if self.state.fetch_or(1, Ordering::AcqRel) == 0 {
121 self.done.send_replace(true);
122 }
123 }
124
125 async fn wait(&self) {
127 let _ = self.done.subscribe().wait_for(|done| *done).await;
128 }
129}
130
131struct DrainSlot(Arc<Drain>);
138
139impl Drop for DrainSlot {
140 fn drop(&mut self) {
141 self.0.release(1);
142 }
143}
144
145struct RetainedVfs {
146 vfs: Vfs,
147}
148
149impl RetainedVfs {
150 fn plain(vfs: Vfs) -> Self {
151 Self { vfs }
152 }
153}
154
155impl OpaqueResource for RetainedVfs {
156 type Marker = VfsMarker;
157}
158
159async fn read_file_range(file: &File, offset: u64, len: usize) -> Result<BytesMut> {
172 let mut buf = BytesMut::with_capacity(len);
173 while buf.len() < len {
174 let at = offset + buf.len() as u64;
175 if file.read_at(&mut buf, at).await? == 0 {
176 break;
177 }
178 }
179 buf.truncate(len);
183 Ok(buf)
184}
185
186async fn next_trailer_chunk(
192 trailer: &mut dolang_rpc::trailer::TrailerRecv,
193) -> Result<Option<BytesMut>> {
194 let mut buf = BytesMut::with_capacity(STREAM_CHUNK_SIZE);
195 while buf.len() < STREAM_CHUNK_SIZE && trailer.read_buf(&mut buf).await? != 0 {}
198 Ok((!buf.is_empty()).then_some(buf))
199}
200
201struct RetainedFile(File);
202
203struct RetainedFileLock(FileLock);
209
210impl OpaqueResource for RetainedFileLock {
211 type Marker = FileLockMarker;
212}
213
214struct RetainedReadDir(Mutex<ReadDir>);
215
216impl OpaqueResource for RetainedReadDir {
217 type Marker = ReadDirMarker;
218}
219
220struct RetainedProcesses(Mutex<Processes>);
221
222impl OpaqueResource for RetainedProcesses {
223 type Marker = ProcessEnumMarker;
224}
225
226struct RetainedProcess(Process);
234
235impl OpaqueResource for RetainedProcess {
236 type Marker = ProcessMarker;
237}
238
239impl OpaqueResource for RetainedFile {
240 type Marker = FileMarker;
241}
242
243struct RetainedStdioSend {
244 stdio: Mutex<StdioSend>,
245 _slot: DrainSlot,
247}
248
249impl OpaqueResource for RetainedStdioSend {
250 type Marker = StdioSendMarker;
251}
252
253struct RetainedStdioRecv {
254 stdio: Mutex<StdioRecv>,
255 _slot: DrainSlot,
257}
258
259impl OpaqueResource for RetainedStdioRecv {
260 type Marker = StdioRecvMarker;
261}
262
263struct RetainedChild(Mutex<Child>);
264
265impl OpaqueResource for RetainedChild {
266 type Marker = ChildMarker;
267}
268
269struct ServerState {
270 vfs: Vfs,
271 #[cfg(unix)]
272 shutdown_tx: watch::Sender<()>,
273}
274
275#[cfg(unix)]
280const NEGOTIATE_TIMEOUT: Duration = Duration::from_secs(30);
281
282#[cfg(unix)]
286const MAX_PENDING_CONNECTIONS: usize = 8;
287
288const PROCESS_PAGE_BYTES: usize = 64 * 1024;
296
297const PROCESS_PAGE_ENTRIES: usize = 512;
300
301fn process_info_size(info: &ProcessInfo) -> usize {
307 const FIXED: usize = 64;
308 let strings = info.name().len()
309 + info.exe().map_or(0, |path| path.as_str().len())
310 + info.cwd().map_or(0, |path| path.as_str().len())
311 + info
312 .command_line()
313 .map_or(0, |args| args.iter().map(|arg| arg.len() + 1).sum::<usize>())
314 + info
317 .windows_command_line()
318 .ok()
319 .flatten()
320 .map_or(0, str::len);
321 let identity = info
324 .identity()
325 .ok()
326 .flatten()
327 .map_or(0, |identity| 16 + identity.groups().len() * 4);
328 let token = info
331 .token()
332 .ok()
333 .flatten()
334 .map_or(0, |token| 128 + token.groups().len() * 48);
335 FIXED + strings + identity + token
336}
337
338#[cfg(unix)]
341struct Negotiated {
342 rpc: dolang_rpc::server::Server<VfsProtocol>,
343 connection: Arc<Connection>,
344}
345
346pub struct Server {
353 #[cfg(unix)]
354 listener: Option<UnixListener>,
355 rpc: Option<dolang_rpc::server::Server<VfsProtocol>>,
356 mode: SessionMode,
357 shared: Arc<ServerState>,
358 #[cfg(unix)]
362 key: Option<AuthKey>,
363}
364
365impl Server {
366 pub async fn new<T>(stream: T) -> Result<Self>
368 where
369 T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
370 {
371 let rpc = rpc_builder(None).server(stream).await?.bind();
372 Ok(Self {
373 #[cfg(unix)]
374 listener: None,
375 rpc: Some(rpc),
376 mode: SessionMode::Remote,
377 shared: Self::state()?,
378 #[cfg(unix)]
379 key: None,
380 })
381 }
382
383 pub async fn new_split<R, W>(reader: R, writer: W) -> Result<Self>
385 where
386 R: AsyncRead + Send + 'static,
387 W: AsyncWrite + Send + 'static,
388 {
389 let rpc = rpc_builder(None).server_split(reader, writer).await?.bind();
390 Ok(Self {
391 #[cfg(unix)]
392 listener: None,
393 rpc: Some(rpc),
394 mode: SessionMode::Remote,
395 shared: Self::state()?,
396 #[cfg(unix)]
397 key: None,
398 })
399 }
400
401 fn state() -> Result<Arc<ServerState>> {
402 #[cfg(unix)]
403 let (shutdown_tx, _) = watch::channel(());
404 Ok(Arc::new(ServerState {
405 vfs: Vfs::direct()?,
406 #[cfg(unix)]
407 shutdown_tx,
408 }))
409 }
410
411 #[cfg(unix)]
413 pub async fn bind(path: impl AsRef<Path>) -> Result<Self> {
414 Self::from_listener(UnixListener::bind(path)?, None)
415 }
416
417 #[cfg(unix)]
425 pub async fn bind_with_key(path: impl AsRef<Path>, key: Option<AuthKey>) -> Result<Self> {
426 Self::from_listener(UnixListener::bind(path)?, key)
427 }
428
429 #[cfg(unix)]
431 fn from_listener(listener: UnixListener, key: Option<AuthKey>) -> Result<Self> {
432 Ok(Self {
433 listener: Some(listener),
434 rpc: None,
435 mode: SessionMode::Native,
436 shared: Self::state()?,
437 key,
438 })
439 }
440
441 #[cfg(any(windows, docsrs))]
443 #[cfg_attr(docsrs, doc(cfg(windows)))]
444 #[cfg_attr(all(docsrs, not(windows)), allow(private_interfaces))]
445 pub async fn from_named_pipe_client(pipe: NamedPipeClient) -> Result<Self> {
446 #[cfg(windows)]
447 {
448 let rpc = rpc_builder(None)
449 .server_named_pipe_client(pipe)
450 .await?
451 .bind();
452 Ok(Self {
453 #[cfg(unix)]
454 listener: None,
455 rpc: Some(rpc),
456 mode: SessionMode::Native,
457 shared: Self::state()?,
458 })
459 }
460 #[cfg(all(docsrs, not(windows)))]
461 {
462 let _ = pipe;
463 unreachable!()
464 }
465 }
466
467 #[cfg(unix)]
468 fn handle_accept(
469 &self,
470 res: io::Result<(UnixStream, SocketAddr)>,
471 handlers: &mut JoinSet<Result<()>>,
472 ) -> Result<()> {
473 let (stream, _) = res?;
474 let stream = stream.into_std()?;
475 let connection = Arc::new(Connection {
476 server: self.shared.clone(),
477 mode: SessionMode::Native,
478 drain: Drain::new(),
479 });
480 let key = self.key;
481 handlers.spawn(async move {
482 let rpc = rpc_builder(key).server_unix(stream).await?.bind();
488 let handler = connection.clone();
489 serve_connection(rpc, handler).await
490 });
491 Ok(())
492 }
493
494 #[cfg(unix)]
500 pub async fn accept(mut self) -> Result<()> {
501 let mut shutdown_rx = self.shared.shutdown_tx.subscribe();
502 let mut handlers = JoinSet::new();
503
504 loop {
505 tokio::select! {
506 res = self.listener.as_ref().unwrap().accept() => {
507 if let Err(error) = self.handle_accept(res, &mut handlers) {
508 eprintln!("VFS server failed to accept a connection: {error}");
509 }
510 }
511 result = handlers.join_next(), if !handlers.is_empty() => {
512 report_handler_exit(result.unwrap());
513 }
514 _ = shutdown_rx.changed() => {
515 self.listener.take();
516 break;
517 }
518 }
519 }
520
521 while let Some(result) = handlers.join_next().await {
522 report_handler_exit(result);
523 }
524 Ok(())
525 }
526
527 #[cfg(unix)]
541 pub async fn accept_one<F>(mut self, established: F) -> Result<()>
542 where
543 F: FnOnce(),
544 {
545 let mut handlers = JoinSet::new();
546 let (session_tx, mut session_rx) = mpsc::channel::<Negotiated>(1);
550
551 let session = loop {
552 tokio::select! {
553 res = self.listener.as_ref().unwrap().accept(),
554 if handlers.len() < MAX_PENDING_CONNECTIONS =>
555 {
556 if let Err(error) = self.handle_accept_one(res, &mut handlers, &session_tx) {
557 eprintln!("VFS server failed to accept a connection: {error}");
558 }
559 }
560 result = handlers.join_next(), if !handlers.is_empty() => {
561 report_handler_exit(result.unwrap());
562 }
563 Some(session) = session_rx.recv() => break session,
564 }
565 };
566
567 self.listener.take();
572 handlers.abort_all();
573 while let Some(result) = handlers.join_next().await {
574 if matches!(&result, Err(error) if error.is_cancelled()) {
575 continue;
576 }
577 report_handler_exit(result);
578 }
579 established();
580
581 let Negotiated { rpc, connection } = session;
582 match serve_connection(rpc, connection).await {
583 Ok(()) => Ok(()),
584 Err(error) if orderly_disconnect(&error) => Ok(()),
585 Err(error) => Err(error),
586 }
587 }
588
589 #[cfg(unix)]
596 fn handle_accept_one(
597 &self,
598 res: io::Result<(UnixStream, SocketAddr)>,
599 handlers: &mut JoinSet<Result<()>>,
600 session_tx: &mpsc::Sender<Negotiated>,
601 ) -> Result<()> {
602 let (stream, _) = res?;
603 let stream = stream.into_std()?;
604 let connection = Arc::new(Connection {
605 server: self.shared.clone(),
606 mode: SessionMode::Native,
607 drain: Drain::new(),
608 });
609 let key = self.key;
610 let session_tx = session_tx.clone();
611 handlers.spawn(async move {
612 let negotiated = timeout(NEGOTIATE_TIMEOUT, rpc_builder(key).server_unix(stream)).await;
613 let rpc = match negotiated {
614 Ok(result) => result?.bind(),
615 Err(_elapsed) => {
616 return Ok(());
619 }
620 };
621 let _ = session_tx.try_send(Negotiated { rpc, connection });
624 Ok(())
625 });
626 Ok(())
627 }
628
629 pub async fn serve(mut self) -> Result<()> {
631 let connection = Arc::new(Connection {
632 server: self.shared,
633 mode: self.mode,
634 drain: Drain::new(),
635 });
636 let rpc = self
637 .rpc
638 .take()
639 .expect("server does not own a connected session");
640 match serve_connection(rpc, connection).await {
641 Ok(()) => Ok(()),
642 Err(error) if orderly_disconnect(&error) => Ok(()),
643 Err(error) => Err(error),
644 }
645 }
646}
647
648#[cfg(unix)]
649fn report_handler_exit(result: std::result::Result<Result<()>, JoinError>) {
650 match result {
651 Ok(Ok(())) => {}
652 Ok(Err(error)) if orderly_disconnect(&error) => {}
653 Ok(Err(error)) => eprintln!("VFS connection handler failed: {error}"),
654 Err(error) if error.is_panic() => std::panic::resume_unwind(error.into_panic()),
655 Err(error) => eprintln!("VFS connection handler task failed: {error}"),
656 }
657}
658
659fn orderly_disconnect(error: &Error) -> bool {
660 matches!(
661 error.kind(),
662 ErrorKind::UnexpectedEof
663 | ErrorKind::BrokenPipe
664 | ErrorKind::ConnectionReset
665 | ErrorKind::NotConnected
666 )
667}
668
669async fn serve_connection(
670 rpc: dolang_rpc::server::Server<VfsProtocol>,
671 connection: Arc<Connection>,
672) -> Result<()> {
673 rpc.serve(async move |mut context, Request { vfs, kind }| {
674 let response = if matches!(kind, RequestKind::Stop) {
675 connection.handle_stop(&mut context, vfs).await
676 } else if let Err(error) = connection.select(&context, vfs.clone()) {
677 Err(error)
678 } else {
679 let connection = connection.select(&context, vfs).unwrap();
680 match kind {
681 RequestKind::Spawn(request) => {
682 connection.handle_spawn_rpc(&mut context, request).await
683 }
684 RequestKind::ChildWait { child } => {
685 connection.handle_child_wait(&mut context, child).await
686 }
687 RequestKind::ChildTerminate { child } => {
688 connection.handle_child_terminate(&context, child).await
689 }
690 RequestKind::ChildClose { child } => connection.handle_child_close(&context, child),
691 RequestKind::FileRead { file, offset, len } => {
692 connection
693 .handle_file_read(context, file, offset, len)
694 .await;
695 return;
696 }
697 RequestKind::StdioRecvRead { stdio, len } => {
698 connection.handle_stdio_recv_read(context, stdio, len).await;
699 return;
700 }
701 RequestKind::Stop => unreachable!(),
702 request => connection.handle(&mut context, request).await,
703 }
704 };
705 context.respond(response);
706 })
707 .await?;
708 Ok(())
709}
710
711impl Connection {
712 fn select(
713 &self,
714 context: &CallContext<VfsProtocol>,
715 vfs: Option<Cite<VfsMarker>>,
716 ) -> Result<Self> {
717 let Some(vfs) = vfs else {
718 return Ok(self.clone());
719 };
720 let selected = context
721 .acquire::<RetainedVfs>(vfs.clone())
722 .map_err(|_| Self::invalid_opaque("VFS"))?;
723 Ok(Self {
724 server: Arc::new(ServerState {
725 vfs: selected.vfs.clone(),
726 #[cfg(unix)]
727 shutdown_tx: self.server.shutdown_tx.clone(),
728 }),
729 mode: self.mode,
730 drain: self.drain.clone(),
731 })
732 }
733
734 async fn handle_stop(
735 &self,
736 context: &mut CallContext<VfsProtocol>,
737 vfs: Option<Cite<VfsMarker>>,
738 ) -> Result<ResponseKind> {
739 let Some(vfs) = vfs else {
740 #[cfg(unix)]
743 let _ = self.server.shutdown_tx.send(());
744 self.drain.begin_stop();
749 self.drain.wait().await;
750 context.shutdown();
751 return Ok(ResponseKind::Stop);
752 };
753 let retained = match context.unregister::<RetainedVfs>(vfs) {
754 Ok(Some(retained)) => retained,
755 Ok(None) => {
756 return Err(Error::new(ErrorKind::ResourceBusy, "opaque VFS is in use"));
757 }
758 Err(_) => return Err(Self::invalid_opaque("VFS")),
759 };
760 match retained.vfs.stop().await {
761 Ok(()) => Ok(ResponseKind::Stop),
762 Err(error) => Err(error),
763 }
764 }
765
766 fn unsupported(operation: &str) -> Error {
767 Error::new(
768 ErrorKind::Unsupported,
769 format!("{operation} is not supported by a remote VFS session"),
770 )
771 }
772
773 fn invalid_opaque(kind: &str) -> Error {
774 Error::new(ErrorKind::InvalidInput, format!("invalid opaque {kind}"))
775 }
776
777 async fn handle(
778 &self,
779 context: &mut CallContext<VfsProtocol>,
780 kind: RequestKind,
781 ) -> Result<ResponseKind> {
782 match kind {
783 RequestKind::Query => self.handle_query().await,
784 RequestKind::UserName { uid } => Ok(ResponseKind::UserName(
785 self.server.vfs.user_name(uid).await?,
786 )),
787 RequestKind::UserId { name } => {
788 Ok(ResponseKind::UserId(self.server.vfs.user_id(&name).await?))
789 }
790 RequestKind::GroupName { gid } => Ok(ResponseKind::GroupName(
791 self.server.vfs.group_name(gid).await?,
792 )),
793 RequestKind::GroupId { name } => Ok(ResponseKind::GroupId(
794 self.server.vfs.group_id(&name).await?,
795 )),
796 RequestKind::SidName { sid } => {
797 Ok(ResponseKind::SidName(self.server.vfs.sid_name(&sid).await?))
798 }
799 RequestKind::AccountName { name } => Ok(ResponseKind::AccountName(
800 self.server.vfs.account_name(&name).await?,
801 )),
802 RequestKind::ResolvePrincipalId { input, want } => {
803 Ok(ResponseKind::ResolvePrincipalId(
804 self.server.vfs.resolve_principal_id(input, want).await?,
805 ))
806 }
807 RequestKind::Which { program, path, cwd } => {
808 self.handle_which(program, path, cwd).await
809 }
810 RequestKind::WellKnownPath(request) => self.handle_well_known_path(request).await,
811 RequestKind::Stop
812 | RequestKind::Spawn(_)
813 | RequestKind::ChildWait { .. }
814 | RequestKind::ChildTerminate { .. }
815 | RequestKind::ChildClose { .. } => unreachable!(),
816 RequestKind::ClearCache => {
817 self.server.vfs.clear_cache().await?;
818 Ok(ResponseKind::ClearCache)
819 }
820 RequestKind::Pipe { buf_size } => Ok(ResponseKind::Pipe(
821 self.handle_pipe(context, buf_size).await?,
822 )),
823 RequestKind::Open(request) => self.handle_open(context, request).await,
824 RequestKind::FileRead { .. } => unreachable!(),
825 RequestKind::FileWrite { file, offset } => Ok(ResponseKind::FileWrite(
826 self.handle_file_write(context, file, offset).await?,
827 )),
828 RequestKind::FileAppend { file } => Ok(ResponseKind::FileAppend(
829 self.handle_file_append(context, file).await?,
830 )),
831 RequestKind::FileSize { file } => Ok(ResponseKind::FileSize(
832 self.handle_file_size(context, file).await?,
833 )),
834 RequestKind::FileSetSize { file, size } => {
835 self.handle_file_set_size(context, file, size).await?;
836 Ok(ResponseKind::FileSetSize)
837 }
838 RequestKind::FileSync { file, data } => {
839 self.handle_file_sync(context, file, data).await?;
840 Ok(ResponseKind::FileSync)
841 }
842 RequestKind::FileCopyData {
843 src,
844 dst,
845 src_offset,
846 target,
847 len,
848 mode,
849 } => Ok(ResponseKind::FileCopyData(
850 self.handle_file_copy_data(context, src, dst, src_offset, target, len, mode)
851 .await?,
852 )),
853 RequestKind::FileLock { file, request } => {
854 self.handle_file_lock(context, file, request).await
855 }
856 RequestKind::FileUnlock { lock } => self.handle_file_unlock(context, lock).await,
857 RequestKind::FileToStdioSend { file, offset } => Ok(ResponseKind::FileToStdioSend(
858 self.handle_file_to_stdio_send(context, file, offset)
859 .await?,
860 )),
861 RequestKind::FileToStdioRecv { file, offset } => Ok(ResponseKind::FileToStdioRecv(
862 self.handle_file_to_stdio_recv(context, file, offset)
863 .await?,
864 )),
865 RequestKind::StdioSendClose { stdio } => {
866 self.close_stdio_send(context, stdio)?;
867 Ok(ResponseKind::StdioSendClose)
868 }
869 RequestKind::StdioSendWrite { stdio } => Ok(ResponseKind::StdioSendWrite(
870 self.handle_stdio_send_write(context, stdio).await?,
871 )),
872 RequestKind::StdioSendClone { stdio } => Ok(ResponseKind::StdioSendClone(
873 self.handle_stdio_send_clone(context, stdio).await?,
874 )),
875 RequestKind::StdioRecvClose { stdio } => {
876 self.close_stdio_recv(context, stdio)?;
877 Ok(ResponseKind::StdioRecvClose)
878 }
879 RequestKind::StdioRecvRead { .. } => unreachable!(),
880 RequestKind::StdioRecvClone { stdio } => Ok(ResponseKind::StdioRecvClone(
881 self.handle_stdio_recv_clone(context, stdio).await?,
882 )),
883 RequestKind::FileMetadata { file } => Ok(ResponseKind::FileMetadata(
884 self.handle_file_metadata(context, file).await?,
885 )),
886 RequestKind::FileFsMetadata { file } => Ok(ResponseKind::FileFsMetadata(
887 self.handle_file_fs_metadata(context, file).await?,
888 )),
889 RequestKind::FileAcl {
890 file,
891 kind,
892 default,
893 } => Ok(ResponseKind::FileAcl(
894 self.handle_file_acl(context, file, kind, default).await?,
895 )),
896 RequestKind::FileSetAcl {
897 file,
898 kind,
899 acl,
900 default,
901 } => {
902 self.handle_file_set_acl(context, file, kind, acl, default)
903 .await?;
904 Ok(ResponseKind::FileSetAcl)
905 }
906 RequestKind::FileSecDesc { file, mask } => Ok(ResponseKind::FileSecDesc(
907 self.handle_file_sec_desc(context, file, mask).await?,
908 )),
909 RequestKind::FileUpdateSecDesc { file, sec_desc } => {
910 self.handle_file_update_sec_desc(context, file, sec_desc)
911 .await?;
912 Ok(ResponseKind::FileUpdateSecDesc)
913 }
914 RequestKind::FileXattrs { file, namespace } => Ok(ResponseKind::FileXattrs(
915 self.handle_file_xattrs(context, file, namespace).await?,
916 )),
917 RequestKind::FileXattr {
918 file,
919 name,
920 namespace,
921 } => Ok(ResponseKind::FileXattr(
922 self.handle_file_xattr(context, file, name, namespace)
923 .await?,
924 )),
925 RequestKind::FileStreams { file } => Ok(ResponseKind::FileStreams(
926 self.handle_file_streams(context, file).await?,
927 )),
928 RequestKind::FileSetXattr {
929 file,
930 name,
931 namespace,
932 value,
933 } => {
934 self.handle_file_set_xattr(context, file, name, namespace, value)
935 .await?;
936 Ok(ResponseKind::FileSetXattr)
937 }
938 RequestKind::FileRemoveXattr {
939 file,
940 name,
941 namespace,
942 } => {
943 self.handle_file_remove_xattr(context, file, name, namespace)
944 .await?;
945 Ok(ResponseKind::FileRemoveXattr)
946 }
947 RequestKind::FileClose { file } => self.handle_file_close(context, file).await,
948 RequestKind::UnixVfs(request) => self.handle_unix_vfs(context, request).await,
949 RequestKind::WindowsAdmin(request) => self.handle_windows_admin(context, request).await,
950 RequestKind::ReadDir { path } => self.handle_read_dir(context, path).await,
951 RequestKind::ReadDirNext { read_dir } => {
952 self.handle_read_dir_next(context, read_dir).await
953 }
954 RequestKind::ReadDirClose { read_dir } => self.handle_read_dir_close(context, read_dir),
955 RequestKind::ProcessEnumerate => self.handle_process_enumerate(context).await,
956 RequestKind::ProcessEnumerateNext { processes } => {
957 self.handle_process_enumerate_next(context, processes).await
958 }
959 RequestKind::ProcessEnumerateClose { processes } => {
960 self.handle_process_enumerate_close(context, processes)
961 }
962 RequestKind::ProcessDescribe { pid } => self.handle_process_describe(pid).await,
963 RequestKind::ProcessOpen { pid, start } => {
964 self.handle_process_open(context, pid, start).await
965 }
966 RequestKind::ProcessInfo { process } => {
967 self.handle_process_info(context, process).await
968 }
969 RequestKind::ProcessSignal { process, signal } => {
970 self.handle_process_signal(context, process, signal).await
971 }
972 RequestKind::ProcessTerminate { process } => {
973 self.handle_process_terminate(context, process).await
974 }
975 RequestKind::ProcessKill { process } => {
976 self.handle_process_kill(context, process).await
977 }
978 RequestKind::ProcessWait { process } => {
979 self.handle_process_wait(context, process).await
980 }
981 RequestKind::ProcessClose { process } => self.handle_process_close(context, process),
982 RequestKind::Remove(request) => self.handle_remove(request).await,
983 RequestKind::Metadata(request) => self.handle_metadata(request).await,
984 RequestKind::FsMetadata(request) => self.handle_fs_metadata(request).await,
985 RequestKind::Acl(request) => self.handle_acl(request).await,
986 RequestKind::SetAcl(request) => self.handle_set_acl(request).await,
987 RequestKind::SecDesc(request) => self.handle_sec_desc(request).await,
988 RequestKind::UpdateSecDesc(request) => self.handle_update_sec_desc(request).await,
989 RequestKind::CreateDir(request) => self.handle_create_dir(request).await,
990 RequestKind::RemoveDir(request) => self.handle_remove_dir(request).await,
991 RequestKind::Copy(request) => self.handle_copy(request).await,
992 RequestKind::Rename(request) => self.handle_rename(request).await,
993 RequestKind::Move(request) => self.handle_move(request).await,
994 RequestKind::Symlink(request) => self.handle_symlink(request).await,
995 RequestKind::HardLink(request) => self.handle_hard_link(request).await,
996 RequestKind::SymlinkMetadata(request) => self.handle_symlink_metadata(request).await,
997 RequestKind::UpdateMetadata(request) => self.handle_update_metadata(request).await,
998 RequestKind::Canonicalize(request) => self.handle_canonicalize(request).await,
999 RequestKind::ReadLink(request) => self.handle_read_link(request).await,
1000 RequestKind::Access(request) => self.handle_access(request).await,
1001 RequestKind::Glob(request) => self.handle_glob(request).await,
1002 RequestKind::Xattrs(request) => self.handle_xattrs(request).await,
1003 RequestKind::Xattr(request) => self.handle_xattr(request).await,
1004 RequestKind::SetXattr(request) => self.handle_set_xattr(request).await,
1005 RequestKind::RemoveXattr(request) => self.handle_remove_xattr(request).await,
1006 RequestKind::Streams(request) => self.handle_streams(request).await,
1007 RequestKind::Extension(request) => self.handle_extension(context, request).await,
1008 }
1009 }
1010
1011 async fn handle_extension(
1012 &self,
1013 context: &mut CallContext<VfsProtocol>,
1014 request: ExtensionRequest,
1015 ) -> Result<ResponseKind> {
1016 let ExtensionRequest {
1017 name,
1018 version,
1019 payload,
1020 } = request;
1021 let Some(ext) = extension::lookup(&name, version).filter(|extension| extension.available())
1022 else {
1023 return Err(Self::unsupported(&format!(
1024 "VFS extension {name} v{version}"
1025 )));
1026 };
1027 let mut ctx = ExtContext::remote(context, self.mode == SessionMode::Native);
1028 let payload = ext.dispatch(&mut ctx, payload).await;
1029 Ok(ResponseKind::Extension(ExtensionResponse {
1030 name,
1031 version,
1032 payload,
1033 }))
1034 }
1035
1036 async fn handle_which(
1037 &self,
1038 program: path::PathBuf,
1039 path: Option<String>,
1040 cwd: Option<path::PathBuf>,
1041 ) -> Result<ResponseKind> {
1042 let resolved = self
1043 .server
1044 .vfs
1045 .which(
1046 Into::into(&program),
1047 path.as_deref(),
1048 cwd.as_ref().map(Into::into),
1049 )
1050 .await?;
1051 Ok(ResponseKind::Which(resolved))
1052 }
1053
1054 async fn handle_well_known_path(&self, req: WellKnownPathRequest) -> Result<ResponseKind> {
1055 let path = self
1056 .server
1057 .vfs
1058 .well_known_path(req.key, req.app.as_deref(), &req.env)
1059 .await?;
1060 Ok(ResponseKind::WellKnownPath(path))
1061 }
1062
1063 async fn handle_spawn_rpc(
1064 &self,
1065 context: &mut CallContext<VfsProtocol>,
1066 req: SpawnRequest,
1067 ) -> Result<ResponseKind> {
1068 let mut cmd = self.server.vfs.command(Into::into(&req.program));
1069 for arg in &req.args {
1070 cmd.arg(arg);
1071 }
1072
1073 if let Some(cwd) = &req.cwd {
1074 cmd.current_dir(Into::into(cwd));
1075 }
1076
1077 for (k, v) in &req.env {
1078 match v {
1079 Some(val) => {
1080 cmd.env(k, val);
1081 }
1082 None => {
1083 cmd.env_remove(k);
1084 }
1085 };
1086 }
1087 cmd.process_control(req.process_control);
1088 cmd.termination_policy(req.termination_policy);
1089
1090 self.configure_spawn_stdio(context, &mut cmd, req.stdin, req.stdout, req.stderr)
1091 .await?;
1092
1093 let child = cmd.spawn().await?;
1094 Ok(ResponseKind::Spawn(
1095 context.register(RetainedChild(Mutex::new(child))),
1096 ))
1097 }
1098
1099 fn spawn_stdio_recv(
1100 &self,
1101 context: &CallContext<VfsProtocol>,
1102 target: StdioRecvTarget,
1103 ) -> Result<Option<StdioRecv>> {
1104 match target {
1105 StdioRecvTarget::Null => Ok(None),
1106 StdioRecvTarget::Native(handle) => {
1107 if self.mode == SessionMode::Remote {
1108 return Err(Self::unsupported("native process stdio"));
1109 }
1110 Ok(Some(StdioRecv::from_file(tokio::fs::File::from_std(
1111 handle.into_inner().into(),
1112 ))))
1113 }
1114 StdioRecvTarget::Opaque(stdio) => {
1115 let stdio = context
1120 .unregister::<RetainedStdioRecv>(stdio)
1121 .map_err(|_| Self::invalid_opaque("stdio receive"))?;
1122 let Some(stdio) = stdio else {
1123 return Err(Error::new(
1124 ErrorKind::ResourceBusy,
1125 "opaque stdio receive is in use",
1126 ));
1127 };
1128 Ok(Some(stdio.stdio.into_inner()))
1129 }
1130 }
1131 }
1132
1133 fn spawn_stdio_send(
1134 &self,
1135 context: &CallContext<VfsProtocol>,
1136 target: StdioSendTarget,
1137 ) -> Result<Option<StdioSend>> {
1138 match target {
1139 StdioSendTarget::Null | StdioSendTarget::Stdout => Ok(None),
1140 StdioSendTarget::Native(handle) => {
1141 if self.mode == SessionMode::Remote {
1142 return Err(Self::unsupported("native process stdio"));
1143 }
1144 Ok(Some(StdioSend::from_file(tokio::fs::File::from_std(
1145 handle.into_inner().into(),
1146 ))))
1147 }
1148 StdioSendTarget::Opaque(stdio) => {
1149 let stdio = context
1154 .unregister::<RetainedStdioSend>(stdio)
1155 .map_err(|_| Self::invalid_opaque("stdio send"))?;
1156 let Some(stdio) = stdio else {
1157 return Err(Error::new(
1158 ErrorKind::ResourceBusy,
1159 "opaque stdio send is in use",
1160 ));
1161 };
1162 Ok(Some(stdio.stdio.into_inner()))
1163 }
1164 }
1165 }
1166
1167 async fn configure_spawn_stdio(
1168 &self,
1169 context: &CallContext<VfsProtocol>,
1170 command: &mut Command<'_>,
1171 stdin: StdioRecvTarget,
1172 stdout: StdioSendTarget,
1173 stderr: StdioSendTarget,
1174 ) -> Result<()> {
1175 let stdin = self.spawn_stdio_recv(context, stdin);
1176 let stdout = self.spawn_stdio_send(context, stdout);
1177 let stderr_to_stdout = matches!(stderr, StdioSendTarget::Stdout);
1178 let stderr = self.spawn_stdio_send(context, stderr);
1179 let (stdin, stdout, stderr) = (stdin?, stdout?, stderr?);
1180
1181 if let Some(stdio) = stdin {
1182 command.stdin(stdio)?;
1183 } else {
1184 command.stdin_null();
1185 }
1186 if let Some(stdio) = stdout {
1187 command.stdout(stdio)?;
1188 } else {
1189 command.stdout_null();
1190 }
1191 if stderr_to_stdout {
1192 command.stderr_to_stdout()?;
1193 } else if let Some(stdio) = stderr {
1194 command.stderr(stdio)?;
1195 } else {
1196 command.stderr_null();
1197 }
1198 Ok(())
1199 }
1200
1201 fn take_child(
1202 &self,
1203 context: &CallContext<VfsProtocol>,
1204 child: Cite<ChildMarker>,
1205 ) -> Result<RetainedChild> {
1206 context
1207 .unregister::<RetainedChild>(child)
1208 .map_err(|_| Error::new(ErrorKind::InvalidInput, "invalid opaque child"))?
1209 .ok_or_else(|| Error::new(ErrorKind::ResourceBusy, "opaque child is in use"))
1210 }
1211
1212 async fn handle_child_wait(
1213 &self,
1214 context: &mut CallContext<VfsProtocol>,
1215 child: Cite<ChildMarker>,
1216 ) -> Result<ResponseKind> {
1217 let child = self.take_child(context, child)?;
1218 let mut child = child.0.into_inner();
1219 let status = match context.cancel_guard(async |_| child.wait().await).await {
1220 Ok(result) => result?,
1221 Err(_) => child
1222 .terminate()
1223 .await?
1224 .ok_or_else(|| Error::other("process was orphaned during cancelled wait"))?,
1225 };
1226 Ok(ResponseKind::ChildWait(status))
1227 }
1228
1229 async fn handle_child_terminate(
1230 &self,
1231 context: &CallContext<VfsProtocol>,
1232 child: Cite<ChildMarker>,
1233 ) -> Result<ResponseKind> {
1234 let child = self.take_child(context, child)?;
1235 let status = child.0.into_inner().terminate().await?;
1236 Ok(ResponseKind::ChildTerminate(status))
1237 }
1238
1239 fn handle_child_close(
1240 &self,
1241 context: &CallContext<VfsProtocol>,
1242 child: Cite<ChildMarker>,
1243 ) -> Result<ResponseKind> {
1244 context
1245 .unregister::<RetainedChild>(child)
1246 .map_err(|_| Error::new(ErrorKind::InvalidInput, "invalid opaque child"))?;
1247 Ok(ResponseKind::ChildClose)
1248 }
1249
1250 async fn handle_query(&self) -> Result<ResponseKind> {
1251 let vfs = &self.server.vfs;
1252 Ok(ResponseKind::Query(QueryResponse {
1253 session: vfs.session(),
1254 pid: vfs.pid(),
1255 env: vfs.env().collect(),
1256 cwd: vfs.cwd().into(),
1257 current_exe: vfs.current_exe().into(),
1258 target: vfs.target().clone(),
1259 security: vfs.security().clone(),
1260 extensions: vfs.extensions().clone(),
1261 }))
1262 }
1263
1264 fn reserve_stdio(&self) -> Result<DrainSlot> {
1271 if self.drain.try_acquire(1) {
1272 Ok(DrainSlot(self.drain.clone()))
1273 } else {
1274 Err(Error::new(
1275 ErrorKind::NotConnected,
1276 "VFS session is stopping",
1277 ))
1278 }
1279 }
1280
1281 async fn handle_pipe(
1282 &self,
1283 context: &CallContext<VfsProtocol>,
1284 buf_size: Option<usize>,
1285 ) -> Result<PipeResponse> {
1286 let (send, recv) = self.server.vfs.pipe(buf_size).await?;
1287 let send_slot = self.reserve_stdio()?;
1288 let recv_slot = self.reserve_stdio()?;
1289 Ok(PipeResponse {
1290 send: context.register(RetainedStdioSend {
1291 stdio: Mutex::new(send),
1292 _slot: send_slot,
1293 }),
1294 recv: context.register(RetainedStdioRecv {
1295 stdio: Mutex::new(recv),
1296 _slot: recv_slot,
1297 }),
1298 })
1299 }
1300
1301 fn retained_stdio_send(
1302 &self,
1303 context: &CallContext<VfsProtocol>,
1304 stdio: Cite<StdioSendMarker>,
1305 ) -> Result<OpaqueGuard<RetainedStdioSend>> {
1306 context
1307 .acquire::<RetainedStdioSend>(stdio)
1308 .map_err(|_| Self::invalid_opaque("stdio send"))
1309 }
1310
1311 fn retained_stdio_recv(
1312 &self,
1313 context: &CallContext<VfsProtocol>,
1314 stdio: Cite<StdioRecvMarker>,
1315 ) -> Result<OpaqueGuard<RetainedStdioRecv>> {
1316 context
1317 .acquire::<RetainedStdioRecv>(stdio)
1318 .map_err(|_| Self::invalid_opaque("stdio receive"))
1319 }
1320
1321 fn close_stdio_send(
1331 &self,
1332 context: &CallContext<VfsProtocol>,
1333 stdio: Cite<StdioSendMarker>,
1334 ) -> Result<()> {
1335 context
1336 .unregister::<RetainedStdioSend>(stdio)
1337 .map_err(|_| Self::invalid_opaque("stdio send"))?;
1338 Ok(())
1339 }
1340
1341 fn close_stdio_recv(
1342 &self,
1343 context: &CallContext<VfsProtocol>,
1344 stdio: Cite<StdioRecvMarker>,
1345 ) -> Result<()> {
1346 context
1347 .unregister::<RetainedStdioRecv>(stdio)
1348 .map_err(|_| Self::invalid_opaque("stdio receive"))?;
1349 Ok(())
1350 }
1351
1352 async fn handle_stdio_send_write(
1353 &self,
1354 context: &mut CallContext<VfsProtocol>,
1355 stdio: Cite<StdioSendMarker>,
1356 ) -> Result<usize> {
1357 let stdio = self.retained_stdio_send(context, stdio)?;
1358 let trailer = context.trailer().ok_or_else(|| {
1359 Error::new(
1360 ErrorKind::InvalidInput,
1361 "stdio write request is missing its data trailer",
1362 )
1363 })?;
1364 let mut trailer = io::BufReader::with_capacity(STREAM_CHUNK_SIZE, trailer);
1365 let len = io::copy_buf(&mut trailer, &mut *stdio.stdio.lock().await).await?;
1366 usize::try_from(len).map_err(|_| {
1367 Error::new(
1368 ErrorKind::InvalidData,
1369 "stdio trailer length does not fit in usize",
1370 )
1371 })
1372 }
1373
1374 async fn handle_stdio_send_clone(
1375 &self,
1376 context: &CallContext<VfsProtocol>,
1377 stdio: Cite<StdioSendMarker>,
1378 ) -> Result<Gift<StdioSendMarker>> {
1379 let stdio = self.retained_stdio_send(context, stdio)?;
1380 let clone = stdio.stdio.lock().await.try_clone().await?;
1381 let slot = self.reserve_stdio()?;
1382 Ok(context.register(RetainedStdioSend {
1383 stdio: Mutex::new(clone),
1384 _slot: slot,
1385 }))
1386 }
1387
1388 async fn handle_stdio_recv_read(
1389 &self,
1390 context: CallContext<VfsProtocol>,
1391 stdio: Cite<StdioRecvMarker>,
1392 len: usize,
1393 ) {
1394 let stdio = match self.retained_stdio_recv(&context, stdio) {
1395 Ok(stdio) => stdio,
1396 Err(error) => {
1397 context.respond(Err(error));
1398 return;
1399 }
1400 };
1401 let mut send = context.respond_with_trailer(Ok(ResponseKind::StdioRecvRead));
1408 let copied = {
1409 let mut guard = stdio.stdio.lock().await;
1410 let mut source = io::BufReader::with_capacity(
1411 len.clamp(1, STREAM_CHUNK_SIZE),
1412 (&mut *guard).take(len as u64),
1413 );
1414 io::copy_buf(&mut source, &mut send).await.is_ok()
1415 };
1416 drop(stdio);
1420 if copied {
1421 send.finish();
1422 }
1423 }
1424
1425 async fn handle_stdio_recv_clone(
1426 &self,
1427 context: &CallContext<VfsProtocol>,
1428 stdio: Cite<StdioRecvMarker>,
1429 ) -> Result<Gift<StdioRecvMarker>> {
1430 let stdio = self.retained_stdio_recv(context, stdio)?;
1431 let clone = stdio.stdio.lock().await.try_clone().await?;
1432 let slot = self.reserve_stdio()?;
1433 Ok(context.register(RetainedStdioRecv {
1434 stdio: Mutex::new(clone),
1435 _slot: slot,
1436 }))
1437 }
1438
1439 async fn handle_open(
1440 &self,
1441 context: &CallContext<VfsProtocol>,
1442 req: OpenRequest,
1443 ) -> Result<ResponseKind> {
1444 let mut opts = self.server.vfs.open_options();
1445 opts.read(req.flags.contains(OpenFlags::READ))
1446 .write(req.flags.contains(OpenFlags::WRITE))
1447 .append(req.flags.contains(OpenFlags::APPEND))
1448 .create(req.flags.contains(OpenFlags::CREATE))
1449 .create_new(req.flags.contains(OpenFlags::CREATE_NEW))
1450 .truncate(req.flags.contains(OpenFlags::TRUNCATE))
1451 .no_follow(req.flags.contains(OpenFlags::NO_FOLLOW));
1452
1453 let file = opts.open(Into::into(&req.path)).await?;
1454 let handle = if self.mode == SessionMode::Remote {
1455 OpenHandle::Opaque(context.register(RetainedFile(file)))
1456 } else {
1457 let handle: DefaultHandle = file.try_into_std().await.unwrap().into();
1458 OpenHandle::Native(OsHandle::new(handle))
1459 };
1460 Ok(ResponseKind::Open(handle))
1461 }
1462
1463 fn retained_file(
1464 &self,
1465 context: &CallContext<VfsProtocol>,
1466 file: Cite<FileMarker>,
1467 ) -> Result<OpaqueGuard<RetainedFile>> {
1468 context
1469 .acquire::<RetainedFile>(file)
1470 .map_err(|_| Error::new(ErrorKind::InvalidInput, "invalid opaque file"))
1471 }
1472
1473 fn take_file(
1483 &self,
1484 context: &CallContext<VfsProtocol>,
1485 file: Cite<FileMarker>,
1486 ) -> Result<RetainedFile> {
1487 match context.try_unregister::<RetainedFile>(file) {
1488 Ok(Some(file)) => Ok(file),
1489 Ok(None) => Err(Error::new(ErrorKind::ResourceBusy, "opaque file is in use")),
1490 Err(_) => Err(Error::new(ErrorKind::InvalidInput, "invalid opaque file")),
1491 }
1492 }
1493
1494 async fn handle_file_read(
1495 &self,
1496 context: CallContext<VfsProtocol>,
1497 file: Cite<FileMarker>,
1498 offset: u64,
1499 len: usize,
1500 ) {
1501 let file = match self.retained_file(&context, file) {
1502 Ok(file) => file,
1503 Err(error) => {
1504 context.respond(Err(error));
1505 return;
1506 }
1507 };
1508 let data = read_file_range(&file.0, offset, len.min(MAX_FILE_READ)).await;
1515 drop(file);
1522 let data = match data {
1523 Ok(data) => data,
1524 Err(error) => {
1525 context.respond(Err(error));
1526 return;
1527 }
1528 };
1529 let mut send = context.respond_with_trailer(Ok(ResponseKind::FileRead));
1530 if send.write_all(&data).await.is_ok() {
1531 send.finish();
1532 }
1533 }
1534
1535 async fn handle_file_write(
1536 &self,
1537 context: &mut CallContext<VfsProtocol>,
1538 file: Cite<FileMarker>,
1539 offset: u64,
1540 ) -> Result<usize> {
1541 let file = self.retained_file(context, file)?;
1542 let mut trailer = Self::write_trailer(context)?;
1543 let mut written = 0usize;
1544 while let Some(chunk) = next_trailer_chunk(&mut trailer).await? {
1545 let mut chunk = chunk.freeze();
1546 while !chunk.is_empty() {
1547 let n = file
1548 .0
1549 .write_at(chunk.clone(), offset + written as u64)
1550 .await?;
1551 if n == 0 {
1552 return Err(Error::new(
1553 ErrorKind::WriteZero,
1554 "file write made no progress",
1555 ));
1556 }
1557 chunk.advance(n);
1558 written += n;
1559 }
1560 }
1561 Ok(written)
1562 }
1563
1564 async fn handle_file_append(
1565 &self,
1566 context: &mut CallContext<VfsProtocol>,
1567 file: Cite<FileMarker>,
1568 ) -> Result<(usize, u64)> {
1569 let file = self.retained_file(context, file)?;
1570 let mut trailer = Self::write_trailer(context)?;
1571 let mut written = 0usize;
1575 let mut end = file.0.metadata().await?.len;
1576 while let Some(chunk) = next_trailer_chunk(&mut trailer).await? {
1577 let mut chunk = chunk.freeze();
1578 while !chunk.is_empty() {
1579 let (n, position) = file.0.append(chunk.clone()).await?;
1580 if n == 0 {
1581 return Err(Error::new(
1582 ErrorKind::WriteZero,
1583 "file append made no progress",
1584 ));
1585 }
1586 chunk.advance(n);
1587 written += n;
1588 end = position;
1589 }
1590 }
1591 Ok((written, end))
1592 }
1593
1594 fn write_trailer(
1595 context: &mut CallContext<VfsProtocol>,
1596 ) -> Result<dolang_rpc::trailer::TrailerRecv> {
1597 context.trailer().ok_or_else(|| {
1598 Error::new(
1599 ErrorKind::InvalidInput,
1600 "file write request is missing its data trailer",
1601 )
1602 })
1603 }
1604
1605 async fn handle_file_size(
1606 &self,
1607 context: &CallContext<VfsProtocol>,
1608 file: Cite<FileMarker>,
1609 ) -> Result<u64> {
1610 let file = self.retained_file(context, file)?;
1611 Ok(file.0.metadata().await?.len)
1612 }
1613
1614 async fn handle_file_set_size(
1615 &self,
1616 context: &CallContext<VfsProtocol>,
1617 file: Cite<FileMarker>,
1618 size: u64,
1619 ) -> Result<()> {
1620 let file = self.retained_file(context, file)?;
1621 file.0.set_size(size).await
1622 }
1623
1624 #[allow(clippy::too_many_arguments)]
1639 async fn handle_file_copy_data(
1640 &self,
1641 context: &CallContext<VfsProtocol>,
1642 src: Cite<FileMarker>,
1643 dst: Cite<FileMarker>,
1644 src_offset: u64,
1645 target: CopyDest,
1646 len: Option<u64>,
1647 mode: CopyMode,
1648 ) -> Result<crate::file::CopyDataResult> {
1649 let src = self.retained_file(context, src)?;
1650 let dst = self.retained_file(context, dst)?;
1651 src.0.copy_data(&dst.0, src_offset, target, len, mode).await
1652 }
1653
1654 async fn handle_file_sync(
1655 &self,
1656 context: &CallContext<VfsProtocol>,
1657 file: Cite<FileMarker>,
1658 data: bool,
1659 ) -> Result<()> {
1660 let file = self.retained_file(context, file)?;
1661 file.0.sync(data).await
1662 }
1663
1664 async fn handle_file_to_stdio_send(
1665 &self,
1666 context: &CallContext<VfsProtocol>,
1667 file: Cite<FileMarker>,
1668 offset: u64,
1669 ) -> Result<Gift<StdioSendMarker>> {
1670 let slot = self.reserve_stdio()?;
1673 let file = self.take_file(context, file)?;
1674 let stdio = file
1678 .0
1679 .into_stdio_send(offset)
1680 .await
1681 .map_err(handoff_error)?;
1682 Ok(context.register(RetainedStdioSend {
1683 stdio: Mutex::new(stdio),
1684 _slot: slot,
1685 }))
1686 }
1687
1688 async fn handle_file_to_stdio_recv(
1689 &self,
1690 context: &CallContext<VfsProtocol>,
1691 file: Cite<FileMarker>,
1692 offset: u64,
1693 ) -> Result<Gift<StdioRecvMarker>> {
1694 let slot = self.reserve_stdio()?;
1695 let file = self.take_file(context, file)?;
1696 let stdio = file
1700 .0
1701 .into_stdio_recv(offset)
1702 .await
1703 .map_err(handoff_error)?;
1704 Ok(context.register(RetainedStdioRecv {
1705 stdio: Mutex::new(stdio),
1706 _slot: slot,
1707 }))
1708 }
1709
1710 async fn handle_file_metadata(
1711 &self,
1712 context: &CallContext<VfsProtocol>,
1713 file: Cite<FileMarker>,
1714 ) -> Result<Metadata> {
1715 let file = self.retained_file(context, file)?;
1716 file.0.metadata().await
1717 }
1718
1719 async fn handle_file_fs_metadata(
1720 &self,
1721 context: &CallContext<VfsProtocol>,
1722 file: Cite<FileMarker>,
1723 ) -> Result<FsMetadata> {
1724 let file = self.retained_file(context, file)?;
1725 file.0.fs_metadata().await
1726 }
1727
1728 async fn handle_file_sec_desc(
1729 &self,
1730 context: &CallContext<VfsProtocol>,
1731 file: Cite<FileMarker>,
1732 mask: dolang_winterop::security::SecInfo,
1733 ) -> Result<SecDesc> {
1734 let file = self.retained_file(context, file)?;
1735 file.0.sec_desc(mask).await
1736 }
1737
1738 async fn handle_file_acl(
1739 &self,
1740 context: &CallContext<VfsProtocol>,
1741 file: Cite<FileMarker>,
1742 kind: AclKind,
1743 default: bool,
1744 ) -> Result<Option<Acl>> {
1745 let file = self.retained_file(context, file)?;
1746 file.0.acl(kind, default).await
1747 }
1748
1749 async fn handle_file_set_acl(
1750 &self,
1751 context: &CallContext<VfsProtocol>,
1752 file: Cite<FileMarker>,
1753 kind: AclKind,
1754 acl: Option<Acl>,
1755 default: bool,
1756 ) -> Result<()> {
1757 let file = self.retained_file(context, file)?;
1758 file.0.set_acl(kind, acl.as_ref(), default).await
1759 }
1760
1761 async fn handle_file_update_sec_desc(
1762 &self,
1763 context: &CallContext<VfsProtocol>,
1764 file: Cite<FileMarker>,
1765 sec_desc: SecDesc,
1766 ) -> Result<()> {
1767 let file = self.retained_file(context, file)?;
1768 file.0.update_sec_desc(&sec_desc).await
1769 }
1770
1771 async fn handle_file_xattrs(
1772 &self,
1773 context: &CallContext<VfsProtocol>,
1774 file: Cite<FileMarker>,
1775 namespace: XattrNamespaceRequest,
1776 ) -> Result<Vec<XattrEntry>> {
1777 let file = self.retained_file(context, file)?;
1778 file.0.xattrs(namespace.as_borrowed()).await
1779 }
1780
1781 async fn handle_file_xattr(
1782 &self,
1783 context: &CallContext<VfsProtocol>,
1784 file: Cite<FileMarker>,
1785 name: String,
1786 namespace: Option<String>,
1787 ) -> Result<Vec<u8>> {
1788 let file = self.retained_file(context, file)?;
1789 file.0.xattr(&name, namespace.as_deref()).await
1790 }
1791
1792 async fn handle_file_streams(
1793 &self,
1794 context: &CallContext<VfsProtocol>,
1795 file: Cite<FileMarker>,
1796 ) -> Result<Vec<StreamEntry>> {
1797 let file = self.retained_file(context, file)?;
1798 file.0.streams().await
1799 }
1800
1801 async fn handle_file_set_xattr(
1802 &self,
1803 context: &CallContext<VfsProtocol>,
1804 file: Cite<FileMarker>,
1805 name: String,
1806 namespace: Option<String>,
1807 value: Vec<u8>,
1808 ) -> Result<()> {
1809 let file = self.retained_file(context, file)?;
1810 file.0.set_xattr(&name, namespace.as_deref(), &value).await
1811 }
1812
1813 async fn handle_file_remove_xattr(
1814 &self,
1815 context: &CallContext<VfsProtocol>,
1816 file: Cite<FileMarker>,
1817 name: String,
1818 namespace: Option<String>,
1819 ) -> Result<()> {
1820 let file = self.retained_file(context, file)?;
1821 file.0.remove_xattr(&name, namespace.as_deref()).await
1822 }
1823
1824 async fn handle_file_lock(
1825 &self,
1826 context: &mut CallContext<VfsProtocol>,
1827 file: Cite<FileMarker>,
1828 request: FileLockRequest,
1829 ) -> Result<ResponseKind> {
1830 let retained = self.retained_file(context, file)?;
1831 let acquired = context
1832 .cancel_guard(async |_context| {
1833 retained
1834 .0
1835 .lock(request.range, request.mode, request.behavior)
1836 .await
1837 })
1838 .await;
1839 let acquired = acquired.map_err(|_| {
1840 Error::new(
1841 ErrorKind::Interrupted,
1842 "file lock acquisition was cancelled",
1843 )
1844 })??;
1845 drop(retained);
1846 Ok(ResponseKind::FileLock(
1851 acquired.map(|lock| context.register(RetainedFileLock(lock))),
1852 ))
1853 }
1854
1855 async fn handle_file_unlock(
1856 &self,
1857 context: &CallContext<VfsProtocol>,
1858 lock: Cite<FileLockMarker>,
1859 ) -> Result<ResponseKind> {
1860 let Ok(Some(mut lock)) = context.unregister::<RetainedFileLock>(lock) else {
1864 return Ok(ResponseKind::FileUnlock);
1865 };
1866 lock.0.release().await?;
1867 Ok(ResponseKind::FileUnlock)
1868 }
1869
1870 async fn handle_file_close(
1871 &self,
1872 context: &CallContext<VfsProtocol>,
1873 file: Cite<FileMarker>,
1874 ) -> Result<ResponseKind> {
1875 let retained = self.retained_file(context, file.clone())?;
1876 drop(retained);
1877 match context.unregister::<RetainedFile>(file) {
1878 Ok(Some(file)) => file.0.close().await,
1881 Ok(None) => Err(Error::new(ErrorKind::ResourceBusy, "opaque file is in use")),
1882 Err(_) => Err(Error::new(ErrorKind::InvalidInput, "invalid opaque file")),
1883 }?;
1884 Ok(ResponseKind::FileClose)
1885 }
1886
1887 async fn handle_read_dir(
1888 &self,
1889 context: &CallContext<VfsProtocol>,
1890 path: path::PathBuf,
1891 ) -> Result<ResponseKind> {
1892 let read_dir = self.server.vfs.read_dir(Into::into(&path)).await?;
1893 Ok(ResponseKind::ReadDir(
1894 context.register(RetainedReadDir(Mutex::new(read_dir))),
1895 ))
1896 }
1897
1898 async fn handle_read_dir_next(
1899 &self,
1900 context: &CallContext<VfsProtocol>,
1901 read_dir: Cite<ReadDirMarker>,
1902 ) -> Result<ResponseKind> {
1903 let retained = context
1904 .acquire::<RetainedReadDir>(read_dir.clone())
1905 .map_err(|_| Error::new(ErrorKind::InvalidInput, "invalid opaque directory"))?;
1906 let mut read_dir_guard = retained.0.lock().await;
1907 let mut entries = Vec::with_capacity(64);
1908 let mut done = false;
1909 while entries.len() < 64 {
1910 match read_dir_guard.next_entry().await? {
1911 Some(entry) => entries.push(entry),
1912 None => {
1913 done = true;
1914 break;
1915 }
1916 }
1917 }
1918 drop(read_dir_guard);
1919 drop(retained);
1920 if done {
1921 let _ = context.unregister::<RetainedReadDir>(read_dir);
1922 }
1923 Ok(ResponseKind::ReadDirNext(ReadDirPage { entries, done }))
1924 }
1925
1926 fn handle_read_dir_close(
1927 &self,
1928 context: &CallContext<VfsProtocol>,
1929 read_dir: Cite<ReadDirMarker>,
1930 ) -> Result<ResponseKind> {
1931 context
1932 .unregister::<RetainedReadDir>(read_dir)
1933 .map_err(|_| Self::invalid_opaque("directory"))?;
1934 Ok(ResponseKind::ReadDirClose)
1935 }
1936
1937 async fn handle_process_enumerate(
1938 &self,
1939 context: &CallContext<VfsProtocol>,
1940 ) -> Result<ResponseKind> {
1941 let processes = self.server.vfs.processes().await?;
1942 Ok(ResponseKind::ProcessEnumerate(
1943 context.register(RetainedProcesses(Mutex::new(processes))),
1944 ))
1945 }
1946
1947 async fn handle_process_enumerate_next(
1948 &self,
1949 context: &CallContext<VfsProtocol>,
1950 processes: Cite<ProcessEnumMarker>,
1951 ) -> Result<ResponseKind> {
1952 let retained = context
1953 .acquire::<RetainedProcesses>(processes.clone())
1954 .map_err(|_| Self::invalid_opaque("process enumeration"))?;
1955 let mut guard = retained.0.lock().await;
1956 let mut entries: Vec<ProcessInfo> = Vec::new();
1957 let mut budget = PROCESS_PAGE_BYTES;
1958 let mut done = false;
1959 while budget > 0 && entries.len() < PROCESS_PAGE_ENTRIES {
1960 match guard.next_entry().await? {
1961 Some(entry) => {
1962 budget = budget.saturating_sub(process_info_size(&entry));
1963 entries.push(entry);
1964 }
1965 None => {
1966 done = true;
1967 break;
1968 }
1969 }
1970 }
1971 drop(guard);
1972 drop(retained);
1973 if done {
1974 let _ = context.unregister::<RetainedProcesses>(processes);
1975 }
1976 Ok(ResponseKind::ProcessEnumerateNext(ProcessPage {
1977 entries,
1978 done,
1979 }))
1980 }
1981
1982 fn handle_process_enumerate_close(
1983 &self,
1984 context: &CallContext<VfsProtocol>,
1985 processes: Cite<ProcessEnumMarker>,
1986 ) -> Result<ResponseKind> {
1987 context
1988 .unregister::<RetainedProcesses>(processes)
1989 .map_err(|_| Self::invalid_opaque("process enumeration"))?;
1990 Ok(ResponseKind::ProcessEnumerateClose)
1991 }
1992
1993 async fn handle_process_describe(&self, pid: u32) -> Result<ResponseKind> {
1994 Ok(ResponseKind::ProcessDescribe(
1995 self.server.vfs.describe_process(pid).await?,
1996 ))
1997 }
1998
1999 async fn handle_process_open(
2000 &self,
2001 context: &CallContext<VfsProtocol>,
2002 pid: u32,
2003 start: Option<StartTime>,
2004 ) -> Result<ResponseKind> {
2005 let process = self.server.vfs.open_process_raw(pid, start).await?;
2006 Ok(ResponseKind::ProcessOpen(
2007 context.register(RetainedProcess(process)),
2008 ))
2009 }
2010
2011 async fn handle_process_info(
2012 &self,
2013 context: &CallContext<VfsProtocol>,
2014 process: Cite<ProcessMarker>,
2015 ) -> Result<ResponseKind> {
2016 let retained = context
2017 .acquire::<RetainedProcess>(process)
2018 .map_err(|_| Self::invalid_opaque("process"))?;
2019 Ok(ResponseKind::ProcessInfo(retained.0.info().await?))
2020 }
2021
2022 async fn handle_process_signal(
2023 &self,
2024 context: &CallContext<VfsProtocol>,
2025 process: Cite<ProcessMarker>,
2026 signal: Signal,
2027 ) -> Result<ResponseKind> {
2028 let retained = context
2029 .acquire::<RetainedProcess>(process)
2030 .map_err(|_| Self::invalid_opaque("process"))?;
2031 retained.0.signal(signal).await?;
2032 Ok(ResponseKind::ProcessSignal)
2033 }
2034
2035 async fn handle_process_terminate(
2036 &self,
2037 context: &CallContext<VfsProtocol>,
2038 process: Cite<ProcessMarker>,
2039 ) -> Result<ResponseKind> {
2040 let retained = context
2041 .acquire::<RetainedProcess>(process)
2042 .map_err(|_| Self::invalid_opaque("process"))?;
2043 retained.0.terminate().await?;
2044 Ok(ResponseKind::ProcessTerminate)
2045 }
2046
2047 async fn handle_process_kill(
2048 &self,
2049 context: &CallContext<VfsProtocol>,
2050 process: Cite<ProcessMarker>,
2051 ) -> Result<ResponseKind> {
2052 let retained = context
2053 .acquire::<RetainedProcess>(process)
2054 .map_err(|_| Self::invalid_opaque("process"))?;
2055 retained.0.kill().await?;
2056 Ok(ResponseKind::ProcessKill)
2057 }
2058
2059 async fn handle_process_wait(
2060 &self,
2061 context: &CallContext<VfsProtocol>,
2062 process: Cite<ProcessMarker>,
2063 ) -> Result<ResponseKind> {
2064 let retained = context
2065 .acquire::<RetainedProcess>(process)
2066 .map_err(|_| Self::invalid_opaque("process"))?;
2067 Ok(ResponseKind::ProcessWait(retained.0.wait().await?))
2068 }
2069
2070 fn handle_process_close(
2071 &self,
2072 context: &CallContext<VfsProtocol>,
2073 process: Cite<ProcessMarker>,
2074 ) -> Result<ResponseKind> {
2075 context
2076 .unregister::<RetainedProcess>(process)
2077 .map_err(|_| Self::invalid_opaque("process"))?;
2078 Ok(ResponseKind::ProcessClose)
2079 }
2080
2081 async fn handle_unix_vfs(
2082 &self,
2083 context: &CallContext<VfsProtocol>,
2084 req: UnixVfsRequest,
2085 ) -> Result<ResponseKind> {
2086 #[cfg(unix)]
2087 if self.mode == SessionMode::Native && self.server.vfs.is_direct() {
2088 let handle: OwnedFd = async {
2089 let path = req.path.to_native()?;
2090 let stream = UnixStream::connect(path).await?;
2091 Ok::<OwnedFd, Error>(stream.into_std()?.into())
2092 }
2093 .await?;
2094 return Ok(ResponseKind::UnixVfs(OpenVfsHandle::Native(OsHandle::new(
2095 handle,
2096 ))));
2097 }
2098
2099 let vfs = self
2100 .server
2101 .vfs
2102 .unix_socket(Into::into(&req.path), req.key.as_deref())
2103 .await?;
2104 Ok(ResponseKind::UnixVfs(OpenVfsHandle::Opaque(
2105 context.register(RetainedVfs::plain(vfs)),
2106 )))
2107 }
2108
2109 async fn handle_windows_admin(
2110 &self,
2111 context: &CallContext<VfsProtocol>,
2112 req: WindowsAdminRequest,
2113 ) -> Result<ResponseKind> {
2114 let vfs = self
2115 .server
2116 .vfs
2117 .windows_admin(Into::into(&req.cwd), req.env, req.elevate)
2118 .await?;
2119 Ok(ResponseKind::WindowsAdmin(
2120 context.register(RetainedVfs::plain(vfs)),
2121 ))
2122 }
2123
2124 async fn handle_remove(&self, req: RemoveRequest) -> Result<ResponseKind> {
2125 self.server
2126 .vfs
2127 .remove(Into::into(&req.path), req.all, req.ignore)
2128 .await?;
2129 Ok(ResponseKind::Remove)
2130 }
2131
2132 async fn handle_metadata(&self, req: MetadataRequest) -> Result<ResponseKind> {
2133 let metadata = self.server.vfs.metadata(Into::into(&req.path)).await?;
2134 Ok(ResponseKind::Metadata(metadata))
2135 }
2136
2137 async fn handle_fs_metadata(&self, req: FsMetadataRequest) -> Result<ResponseKind> {
2138 let metadata = self
2139 .server
2140 .vfs
2141 .fs_metadata(Into::into(&req.path), req.follow)
2142 .await?;
2143 Ok(ResponseKind::FsMetadata(metadata))
2144 }
2145
2146 async fn handle_sec_desc(&self, req: SecDescRequest) -> Result<ResponseKind> {
2147 let sec_desc = self
2148 .server
2149 .vfs
2150 .sec_desc(Into::into(&req.path), req.mask, req.follow)
2151 .await?;
2152 Ok(ResponseKind::SecDesc(sec_desc))
2153 }
2154
2155 async fn handle_acl(&self, req: AclRequest) -> Result<ResponseKind> {
2156 let acl = self
2157 .server
2158 .vfs
2159 .acl(Into::into(&req.path), req.kind, req.default, req.follow)
2160 .await?;
2161 Ok(ResponseKind::Acl(acl))
2162 }
2163
2164 async fn handle_set_acl(&self, req: SetAclRequest) -> Result<ResponseKind> {
2165 self.server
2166 .vfs
2167 .set_acl(
2168 Into::into(&req.path),
2169 req.kind,
2170 req.acl.as_ref(),
2171 req.default,
2172 req.follow,
2173 )
2174 .await?;
2175 Ok(ResponseKind::SetAcl)
2176 }
2177
2178 async fn handle_update_sec_desc(&self, req: UpdateSecDescRequest) -> Result<ResponseKind> {
2179 self.server
2180 .vfs
2181 .update_sec_desc(Into::into(&req.path), &req.sec_desc, req.follow)
2182 .await?;
2183 Ok(ResponseKind::UpdateSecDesc)
2184 }
2185
2186 async fn handle_create_dir(&self, req: CreateDirRequest) -> Result<ResponseKind> {
2187 self.server
2188 .vfs
2189 .create_dir(Into::into(&req.path), req.all)
2190 .await?;
2191 Ok(ResponseKind::CreateDir)
2192 }
2193
2194 async fn handle_remove_dir(&self, req: RemoveDirRequest) -> Result<ResponseKind> {
2195 self.server
2196 .vfs
2197 .remove_dir(Into::into(&req.path), req.all, req.ignore)
2198 .await?;
2199 Ok(ResponseKind::RemoveDir)
2200 }
2201
2202 async fn handle_copy(&self, req: CopyRequest) -> Result<ResponseKind> {
2203 self.server
2204 .vfs
2205 .copy(Into::into(&req.from), Into::into(&req.to), req.all)
2206 .await?;
2207 Ok(ResponseKind::Copy)
2208 }
2209
2210 async fn handle_rename(&self, req: RenameRequest) -> Result<ResponseKind> {
2211 self.server
2212 .vfs
2213 .rename(Into::into(&req.from), Into::into(&req.to), req.replace)
2214 .await?;
2215 Ok(ResponseKind::Rename)
2216 }
2217
2218 async fn handle_move(&self, req: MoveRequest) -> Result<ResponseKind> {
2219 self.server
2220 .vfs
2221 .move_(Into::into(&req.from), Into::into(&req.to), req.all)
2222 .await?;
2223 Ok(ResponseKind::Move)
2224 }
2225
2226 async fn handle_symlink(&self, req: SymlinkRequest) -> Result<ResponseKind> {
2227 match req.kind {
2228 SymlinkKind::Infer => {
2229 self.server
2230 .vfs
2231 .symlink(
2232 Into::into(&req.cwd),
2233 Into::into(&req.src),
2234 Into::into(&req.dst),
2235 )
2236 .await
2237 }
2238 SymlinkKind::Dir => {
2239 self.server
2240 .vfs
2241 .symlink_dir(Into::into(&req.src), Into::into(&req.dst))
2242 .await
2243 }
2244 SymlinkKind::File => {
2245 self.server
2246 .vfs
2247 .symlink_file(Into::into(&req.src), Into::into(&req.dst))
2248 .await
2249 }
2250 }?;
2251 Ok(ResponseKind::Symlink)
2252 }
2253
2254 async fn handle_hard_link(&self, req: HardLinkRequest) -> Result<ResponseKind> {
2255 self.server
2256 .vfs
2257 .hard_link(Into::into(&req.src), Into::into(&req.dst))
2258 .await?;
2259 Ok(ResponseKind::HardLink)
2260 }
2261
2262 async fn handle_symlink_metadata(&self, req: MetadataRequest) -> Result<ResponseKind> {
2263 let metadata = self
2264 .server
2265 .vfs
2266 .symlink_metadata(Into::into(&req.path))
2267 .await?;
2268 Ok(ResponseKind::SymlinkMetadata(metadata))
2269 }
2270
2271 async fn handle_update_metadata(&self, req: UpdateMetadataRequest) -> Result<ResponseKind> {
2272 let paths: Vec<_> = req
2273 .paths
2274 .iter()
2275 .map(|path| path::Path::from(path).to_path_buf())
2276 .collect();
2277 self.server.vfs.update_metadata(&paths, req.patch).await?;
2278 Ok(ResponseKind::UpdateMetadata)
2279 }
2280
2281 async fn handle_canonicalize(&self, req: CanonicalizeRequest) -> Result<ResponseKind> {
2282 let path = self.server.vfs.canonicalize(Into::into(&req.path)).await?;
2283 Ok(ResponseKind::Canonicalize(path))
2284 }
2285
2286 async fn handle_read_link(&self, req: ReadLinkRequest) -> Result<ResponseKind> {
2287 let path = self.server.vfs.read_link(Into::into(&req.path)).await?;
2288 Ok(ResponseKind::ReadLink(path))
2289 }
2290
2291 async fn handle_access(&self, req: AccessRequest) -> Result<ResponseKind> {
2292 let mode = AccessFlags::from_bits(req.mode).unwrap_or(AccessFlags::empty());
2293 self.server.vfs.access(Into::into(&req.path), mode).await?;
2294 Ok(ResponseKind::Access)
2295 }
2296
2297 async fn handle_glob(&self, req: GlobRequest) -> Result<ResponseKind> {
2298 let paths = self
2299 .server
2300 .vfs
2301 .glob(
2302 req.pattern,
2303 Into::into(&req.root),
2304 req.follow_symlinks,
2305 req.max_depth,
2306 )
2307 .await?;
2308 Ok(ResponseKind::Glob(paths))
2309 }
2310
2311 async fn handle_xattrs(&self, req: XattrsRequest) -> Result<ResponseKind> {
2312 let xattrs = self
2313 .server
2314 .vfs
2315 .xattrs(
2316 Into::into(&req.path),
2317 req.namespace.as_borrowed(),
2318 req.follow,
2319 )
2320 .await?;
2321 Ok(ResponseKind::Xattrs(xattrs))
2322 }
2323
2324 async fn handle_xattr(&self, req: XattrRequest) -> Result<ResponseKind> {
2325 let xattr = self
2326 .server
2327 .vfs
2328 .xattr(
2329 Into::into(&req.path),
2330 &req.name,
2331 req.namespace.as_deref(),
2332 req.follow,
2333 )
2334 .await?;
2335 Ok(ResponseKind::Xattr(xattr))
2336 }
2337
2338 async fn handle_set_xattr(&self, req: SetXattrRequest) -> Result<ResponseKind> {
2339 self.server
2340 .vfs
2341 .set_xattr(
2342 Into::into(&req.path),
2343 &req.name,
2344 req.namespace.as_deref(),
2345 &req.value,
2346 req.follow,
2347 )
2348 .await?;
2349 Ok(ResponseKind::SetXattr)
2350 }
2351
2352 async fn handle_remove_xattr(&self, req: XattrRequest) -> Result<ResponseKind> {
2353 self.server
2354 .vfs
2355 .remove_xattr(
2356 Into::into(&req.path),
2357 &req.name,
2358 req.namespace.as_deref(),
2359 req.follow,
2360 )
2361 .await?;
2362 Ok(ResponseKind::RemoveXattr)
2363 }
2364
2365 async fn handle_streams(&self, req: StreamsRequest) -> Result<ResponseKind> {
2366 Ok(ResponseKind::Streams(
2367 self.server
2368 .vfs
2369 .streams(Into::into(&req.path), req.follow)
2370 .await?,
2371 ))
2372 }
2373}
2374
2375fn handoff_error<H>(error: HandoffError<H>) -> Error {
2384 Into::into(error.into_error())
2385}
2386
2387#[cfg(test)]
2388mod tests {
2389 #[cfg(unix)]
2390 use super::report_handler_exit;
2391 use super::{Server, orderly_disconnect};
2392 use crate::{
2393 error::{Error, ErrorKind},
2394 path,
2395 protocol::{
2396 self, OpenFlags, OpenHandle, OpenRequest, Request, RequestKind, ResponseKind,
2397 VfsProtocol,
2398 },
2399 };
2400
2401 fn request(kind: RequestKind) -> Request {
2402 Request { vfs: None, kind }
2403 }
2404
2405 #[tokio::test]
2406 #[cfg(unix)]
2407 #[should_panic(expected = "connection handler panic")]
2408 async fn connection_handler_panics_are_propagated() {
2409 let mut handlers = tokio::task::JoinSet::new();
2410 handlers.spawn(async {
2411 panic!("connection handler panic");
2412 #[allow(unreachable_code)]
2413 Ok::<(), Error>(())
2414 });
2415 report_handler_exit(handlers.join_next().await.unwrap());
2416 }
2417
2418 #[test]
2419 fn orderly_connection_close_is_expected() {
2420 assert!(orderly_disconnect(&Error::new(
2421 ErrorKind::ConnectionReset,
2422 "closed"
2423 )));
2424 assert!(orderly_disconnect(&Error::new(
2425 ErrorKind::BrokenPipe,
2426 "closed"
2427 )));
2428 assert!(!orderly_disconnect(&Error::new(
2429 ErrorKind::InvalidData,
2430 "bad frame"
2431 )));
2432 }
2433
2434 #[tokio::test]
2435 async fn remote_server_replies_without_serializing_a_handle() {
2436 let (client_stream, server_stream) = tokio::io::duplex(4096);
2437 let server =
2438 tokio::spawn(async move { Server::new(server_stream).await.unwrap().serve().await });
2439 let client = protocol::rpc_builder(None)
2440 .client(client_stream)
2441 .await
2442 .unwrap()
2443 .bind::<VfsProtocol>();
2444
2445 let temp = tempfile::NamedTempFile::new().unwrap();
2446 let response = client
2447 .call(request(RequestKind::Open(OpenRequest {
2448 path: path::PathBuf::from_native(temp.path().to_path_buf())
2449 .unwrap()
2450 .to_path()
2451 .into(),
2452 flags: OpenFlags::READ,
2453 })))
2454 .await
2455 .unwrap()
2456 .into_response()
2457 .unwrap();
2458 let ResponseKind::Open(OpenHandle::Opaque(file)) = response else {
2459 panic!("remote open did not return an opaque file");
2460 };
2461 let ResponseKind::FileClose = client
2462 .call(request(RequestKind::FileClose { file: file.cite() }))
2463 .await
2464 .unwrap()
2465 .into_response()
2466 .unwrap()
2467 else {
2468 panic!("file close returned the wrong response");
2469 };
2470 let error = client
2471 .call(request(RequestKind::FileClose { file: file.cite() }))
2472 .await
2473 .unwrap()
2474 .into_response()
2475 .unwrap_err();
2476 assert_eq!(error.kind(), std::io::ErrorKind::InvalidInput);
2477
2478 let _ = client.call(request(RequestKind::Stop)).await.unwrap();
2479 client.close().await;
2480 server.await.unwrap().unwrap();
2481 }
2482}