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