1#![deny(warnings)]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3use dolang_winterop::security::{SecDesc, Sid};
13use extension::VfsExtension;
14use std::collections::HashMap;
15use tokio::io::{AsyncRead, AsyncWrite};
16mod client;
18mod direct;
20pub mod directory;
22pub mod error;
24pub mod extension;
25pub mod file;
26mod macos_acl;
27pub mod metadata;
28mod nfs4_acl;
29pub mod path;
30mod posix_acl;
31pub mod process;
33mod protocol;
34pub mod security;
35pub mod server;
37mod session;
38pub mod target;
39#[cfg(windows)]
40mod windows;
41
42const STREAM_CHUNK_SIZE: usize = 512 * 1024;
53
54const MAX_FILE_READ: usize = STREAM_CHUNK_SIZE;
68
69#[derive(Clone, Copy, Debug, PartialEq, Eq)]
70pub(crate) enum SessionMode {
71 Native,
72 Remote,
73}
74
75#[derive(Clone)]
81enum VfsInner {
82 Client(client::Client),
83 Direct(direct::Direct),
84}
85
86#[derive(Clone)]
87pub struct Vfs {
88 inner: VfsInner,
89}
90
91impl Vfs {
92 fn from_client(client: client::Client) -> Self {
93 Self {
94 inner: VfsInner::Client(client),
95 }
96 }
97
98 fn from_direct(direct: direct::Direct) -> Self {
99 Self {
100 inner: VfsInner::Direct(direct),
101 }
102 }
103
104 pub fn direct() -> error::Result<Self> {
106 direct::Direct::new().map(Self::from_direct)
107 }
108
109 pub async fn new<T>(stream: T) -> error::Result<Self>
114 where
115 T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
116 {
117 client::Client::new(stream).await.map(Self::from_client)
118 }
119
120 pub async fn new_split<R, W>(reader: R, writer: W) -> error::Result<Self>
124 where
125 R: AsyncRead + Send + 'static,
126 W: AsyncWrite + Send + 'static,
127 {
128 client::Client::new_split(reader, writer)
129 .await
130 .map(Self::from_client)
131 }
132
133 #[cfg(unix)]
137 pub async fn connect(path: impl AsRef<std::path::Path>) -> error::Result<Self> {
138 client::Client::connect(path).await.map(Self::from_client)
139 }
140
141 #[cfg(unix)]
148 pub async fn connect_with_key(
149 path: impl AsRef<std::path::Path>,
150 key: Option<dolang_rpc::auth::AuthKey>,
151 ) -> error::Result<Self> {
152 client::Client::connect_with_key(path, key)
153 .await
154 .map(Self::from_client)
155 }
156
157 #[cfg(unix)]
161 pub async fn from_stream(stream: tokio::net::UnixStream) -> error::Result<Self> {
162 client::Client::from_stream(stream)
163 .await
164 .map(Self::from_client)
165 }
166
167 #[cfg(unix)]
172 pub async fn from_owned_fd(value: std::os::fd::OwnedFd) -> error::Result<Self> {
173 client::Client::from_owned_fd(value)
174 .await
175 .map(Self::from_client)
176 }
177
178 #[cfg(unix)]
181 pub async fn from_owned_fd_with_key(
182 value: std::os::fd::OwnedFd,
183 key: Option<dolang_rpc::auth::AuthKey>,
184 ) -> error::Result<Self> {
185 client::Client::from_owned_fd_with_key(value, key)
186 .await
187 .map(Self::from_client)
188 }
189
190 #[cfg(windows)]
197 pub async unsafe fn from_named_pipe_server(
198 pipe: tokio::net::windows::named_pipe::NamedPipeServer,
199 server_process: std::os::windows::io::OwnedHandle,
200 ) -> error::Result<Self> {
201 unsafe { client::Client::from_named_pipe_server(pipe, server_process) }
202 .await
203 .map(Self::from_client)
204 }
205
206 pub fn is_direct(&self) -> bool {
208 matches!(&self.inner, VfsInner::Direct(_))
209 }
210
211 pub async fn stop(self) -> error::Result<()> {
225 match self.inner {
226 VfsInner::Client(client) => client.stop().await,
227 VfsInner::Direct(_) => Ok(()),
228 }
229 }
230
231 pub async fn close(self) {
238 match self.inner {
239 VfsInner::Client(client) => client.close().await,
240 VfsInner::Direct(_) => {}
241 }
242 }
243
244 pub async fn abort(self) {
246 match self.inner {
247 VfsInner::Client(client) => client.abort().await,
248 VfsInner::Direct(_) => {}
249 }
250 }
251
252 pub async fn call_extension<T: VfsExtension>(
255 &self,
256 request: T::Request,
257 ) -> error::Result<T::Response> {
258 match &self.inner {
259 VfsInner::Client(client) => client.call_extension::<T>(request).await,
260 VfsInner::Direct(direct) => direct.call_extension::<T>(request).await,
261 }
262 }
263
264 pub fn env(&self) -> Box<dyn Iterator<Item = (String, String)> + '_> {
266 match &self.inner {
267 VfsInner::Client(client) => client.env(),
268 VfsInner::Direct(direct) => direct.env(),
269 }
270 }
271
272 pub fn cwd(&self) -> path::Path<'_> {
274 match &self.inner {
275 VfsInner::Client(vfs) => vfs.cwd(),
276 VfsInner::Direct(vfs) => vfs.cwd(),
277 }
278 }
279
280 pub fn current_exe(&self) -> path::Path<'_> {
282 match &self.inner {
283 VfsInner::Client(vfs) => vfs.current_exe(),
284 VfsInner::Direct(vfs) => vfs.current_exe(),
285 }
286 }
287
288 pub fn target(&self) -> &target::TargetInfo {
290 match &self.inner {
291 VfsInner::Client(vfs) => vfs.target(),
292 VfsInner::Direct(vfs) => vfs.target(),
293 }
294 }
295
296 pub fn security(&self) -> &security::SecurityInfo {
298 match &self.inner {
299 VfsInner::Client(vfs) => vfs.security(),
300 VfsInner::Direct(vfs) => vfs.security(),
301 }
302 }
303
304 pub fn session(&self) -> uuid::Uuid {
312 match &self.inner {
313 VfsInner::Client(vfs) => vfs.session(),
314 VfsInner::Direct(vfs) => vfs.session(),
315 }
316 }
317
318 pub fn pid(&self) -> u32 {
326 match &self.inner {
327 VfsInner::Client(vfs) => vfs.pid(),
328 VfsInner::Direct(vfs) => vfs.pid(),
329 }
330 }
331
332 pub async fn processes(&self) -> error::Result<process::Processes> {
339 match &self.inner {
340 VfsInner::Client(client) => client.processes().await,
341 VfsInner::Direct(direct) => direct.processes().await,
342 }
343 }
344
345 pub async fn describe_process(&self, pid: u32) -> error::Result<process::ProcessInfo> {
358 match &self.inner {
359 VfsInner::Client(client) => client.describe_process(pid).await,
360 VfsInner::Direct(direct) => direct.describe_process(pid).await,
361 }
362 }
363
364 pub async fn open_process_info(
369 &self,
370 info: &process::ProcessInfo,
371 ) -> error::Result<process::Process> {
372 if info.session() != self.session() {
373 return Err(error::Error::new(
374 error::ErrorKind::InvalidInput,
375 "process record was captured from a different target",
376 ));
377 }
378 self.open_process_raw(info.pid(), Some(info.start_time()))
379 .await
380 }
381
382 pub async fn open_process(&self, pid: u32) -> error::Result<process::Process> {
390 self.open_process_raw(pid, None).await
391 }
392
393 pub(crate) async fn open_process_raw(
394 &self,
395 pid: u32,
396 start: Option<process::StartTime>,
397 ) -> error::Result<process::Process> {
398 match &self.inner {
399 VfsInner::Client(client) => client.open_process(pid, start).await,
400 VfsInner::Direct(direct) => direct.open_process(pid, start).await,
401 }
402 }
403
404 pub fn extensions(&self) -> &extension::ExtensionSet {
406 match &self.inner {
407 VfsInner::Client(vfs) => vfs.extensions(),
408 VfsInner::Direct(vfs) => vfs.extensions(),
409 }
410 }
411
412 pub fn open_options(&self) -> file::OpenOptions<'_> {
414 match &self.inner {
415 VfsInner::Client(client) => file::OpenOptions::client(client.open_options()),
416 VfsInner::Direct(direct) => file::OpenOptions::direct(direct.open_options()),
417 }
418 }
419
420 pub fn command(&self, program: path::Path<'_>) -> process::Command<'_> {
422 process::Command::new(self, program)
423 }
424
425 pub async fn unix_socket(
432 &self,
433 path: path::Path<'_>,
434 key: Option<&[u8]>,
435 ) -> error::Result<Vfs> {
436 match &self.inner {
437 VfsInner::Client(client) => client.unix_socket(path, key).await,
438 VfsInner::Direct(direct) => direct.unix_socket(path, key).await,
439 }
440 }
441
442 pub async fn windows_admin(
444 &self,
445 cwd: path::Path<'_>,
446 env: HashMap<String, Option<String>>,
447 elevate: bool,
448 ) -> error::Result<Vfs> {
449 match &self.inner {
450 VfsInner::Client(client) => client.windows_admin(cwd, env, elevate).await,
451 VfsInner::Direct(direct) => direct.windows_admin(cwd, env, elevate).await,
452 }
453 }
454
455 pub async fn pipe(
460 &self,
461 buf_size: Option<usize>,
462 ) -> error::Result<(process::StdioSend, process::StdioRecv)> {
463 match &self.inner {
464 VfsInner::Client(client) => client.pipe(buf_size).await,
465 VfsInner::Direct(direct) => direct.pipe(buf_size).await,
466 }
467 }
468
469 pub async fn user_name(&self, uid: u32) -> error::Result<String> {
471 match &self.inner {
472 VfsInner::Client(client) => client.user_name(uid).await,
473 VfsInner::Direct(direct) => direct.user_name(uid).await,
474 }
475 }
476
477 pub async fn user_id(&self, name: &str) -> error::Result<u32> {
479 match &self.inner {
480 VfsInner::Client(client) => client.user_id(name).await,
481 VfsInner::Direct(direct) => direct.user_id(name).await,
482 }
483 }
484
485 pub async fn group_name(&self, gid: u32) -> error::Result<String> {
487 match &self.inner {
488 VfsInner::Client(client) => client.group_name(gid).await,
489 VfsInner::Direct(direct) => direct.group_name(gid).await,
490 }
491 }
492
493 pub async fn group_id(&self, name: &str) -> error::Result<u32> {
495 match &self.inner {
496 VfsInner::Client(client) => client.group_id(name).await,
497 VfsInner::Direct(direct) => direct.group_id(name).await,
498 }
499 }
500
501 pub async fn sid_name(&self, sid: &Sid) -> error::Result<security::SidName> {
503 match &self.inner {
504 VfsInner::Client(client) => client.sid_name(sid).await,
505 VfsInner::Direct(direct) => direct.sid_name(sid).await,
506 }
507 }
508
509 pub async fn account_name(&self, name: &str) -> error::Result<security::SidName> {
511 match &self.inner {
512 VfsInner::Client(client) => client.account_name(name).await,
513 VfsInner::Direct(direct) => direct.account_name(name).await,
514 }
515 }
516
517 pub async fn resolve_principal_id(
520 &self,
521 input: security::PrincipalId,
522 want: security::PrincipalIdKind,
523 ) -> error::Result<security::PrincipalId> {
524 match &self.inner {
525 VfsInner::Client(client) => client.resolve_principal_id(input, want).await,
526 VfsInner::Direct(direct) => direct.resolve_principal_id(input, want).await,
527 }
528 }
529
530 pub async fn read_dir(&self, path: path::Path<'_>) -> error::Result<directory::ReadDir> {
532 match &self.inner {
533 VfsInner::Client(client) => client.read_dir(path).await,
534 VfsInner::Direct(direct) => direct.read_dir(path).await,
535 }
536 }
537
538 pub async fn which(
540 &self,
541 program: path::Path<'_>,
542 path: Option<&str>,
543 cwd: Option<path::Path<'_>>,
544 ) -> error::Result<Option<path::PathBuf>> {
545 match &self.inner {
546 VfsInner::Client(client) => client.which(program, path, cwd).await,
547 VfsInner::Direct(direct) => direct.which(program, path, cwd).await,
548 }
549 }
550
551 pub async fn well_known_path(
553 &self,
554 key: path::WellKnownPath,
555 app: Option<&str>,
556 env: &HashMap<String, Option<String>>,
557 ) -> error::Result<path::PathBuf> {
558 match &self.inner {
559 VfsInner::Client(client) => client.well_known_path(key, app, env).await,
560 VfsInner::Direct(direct) => direct.well_known_path(key, app, env).await,
561 }
562 }
563
564 pub async fn clear_cache(&self) -> error::Result<()> {
566 match &self.inner {
567 VfsInner::Client(client) => client.clear_cache().await,
568 VfsInner::Direct(direct) => direct.clear_cache().await,
569 }
570 }
571
572 pub async fn xattrs(
574 &self,
575 path: path::Path<'_>,
576 namespace: file::XattrNamespace<'_>,
577 follow: bool,
578 ) -> error::Result<Vec<file::XattrEntry>> {
579 match &self.inner {
580 VfsInner::Client(client) => client.xattrs(path, namespace, follow).await,
581 VfsInner::Direct(direct) => direct.xattrs(path, namespace, follow).await,
582 }
583 }
584
585 pub async fn streams(
587 &self,
588 path: path::Path<'_>,
589 follow: bool,
590 ) -> error::Result<Vec<file::StreamEntry>> {
591 match &self.inner {
592 VfsInner::Client(client) => client.streams(path, follow).await,
593 VfsInner::Direct(direct) => direct.streams(path, follow).await,
594 }
595 }
596
597 pub async fn xattr(
599 &self,
600 path: path::Path<'_>,
601 name: &str,
602 namespace: Option<&str>,
603 follow: bool,
604 ) -> error::Result<Vec<u8>> {
605 match &self.inner {
606 VfsInner::Client(client) => client.xattr(path, name, namespace, follow).await,
607 VfsInner::Direct(direct) => direct.xattr(path, name, namespace, follow).await,
608 }
609 }
610
611 pub async fn set_xattr(
613 &self,
614 path: path::Path<'_>,
615 name: &str,
616 namespace: Option<&str>,
617 value: &[u8],
618 follow: bool,
619 ) -> error::Result<()> {
620 match &self.inner {
621 VfsInner::Client(client) => {
622 client.set_xattr(path, name, namespace, value, follow).await
623 }
624 VfsInner::Direct(direct) => {
625 direct.set_xattr(path, name, namespace, value, follow).await
626 }
627 }
628 }
629
630 pub async fn remove_xattr(
632 &self,
633 path: path::Path<'_>,
634 name: &str,
635 namespace: Option<&str>,
636 follow: bool,
637 ) -> error::Result<()> {
638 match &self.inner {
639 VfsInner::Client(client) => client.remove_xattr(path, name, namespace, follow).await,
640 VfsInner::Direct(direct) => direct.remove_xattr(path, name, namespace, follow).await,
641 }
642 }
643
644 pub async fn remove(&self, path: path::Path<'_>, all: bool, ignore: bool) -> error::Result<()> {
646 match &self.inner {
647 VfsInner::Client(client) => client.remove(path, all, ignore).await,
648 VfsInner::Direct(direct) => direct.remove(path, all, ignore).await,
649 }
650 }
651
652 pub async fn metadata(&self, path: path::Path<'_>) -> error::Result<metadata::Metadata> {
654 match &self.inner {
655 VfsInner::Client(client) => client.metadata(path).await,
656 VfsInner::Direct(direct) => direct.metadata(path).await,
657 }
658 }
659
660 pub async fn fs_metadata(
662 &self,
663 path: path::Path<'_>,
664 follow: bool,
665 ) -> error::Result<metadata::FsMetadata> {
666 match &self.inner {
667 VfsInner::Client(client) => client.fs_metadata(path, follow).await,
668 VfsInner::Direct(direct) => direct.fs_metadata(path, follow).await,
669 }
670 }
671
672 pub async fn acl(
675 &self,
676 path: path::Path<'_>,
677 kind: security::AclKind,
678 default: bool,
679 follow: bool,
680 ) -> error::Result<Option<security::Acl>> {
681 match &self.inner {
682 VfsInner::Client(client) => client.acl(path, kind, default, follow).await,
683 VfsInner::Direct(direct) => direct.acl(path, kind, default, follow).await,
684 }
685 }
686
687 pub async fn set_acl(
690 &self,
691 path: path::Path<'_>,
692 kind: security::AclKind,
693 acl: Option<&security::Acl>,
694 default: bool,
695 follow: bool,
696 ) -> error::Result<()> {
697 match &self.inner {
698 VfsInner::Client(client) => client.set_acl(path, kind, acl, default, follow).await,
699 VfsInner::Direct(direct) => direct.set_acl(path, kind, acl, default, follow).await,
700 }
701 }
702
703 pub async fn sec_desc(
705 &self,
706 path: path::Path<'_>,
707 mask: dolang_winterop::security::SecInfo,
708 follow: bool,
709 ) -> error::Result<SecDesc> {
710 match &self.inner {
711 VfsInner::Client(client) => client.sec_desc(path, mask, follow).await,
712 VfsInner::Direct(direct) => direct.sec_desc(path, mask, follow).await,
713 }
714 }
715
716 pub async fn update_sec_desc(
718 &self,
719 path: path::Path<'_>,
720 sec_desc: &SecDesc,
721 follow: bool,
722 ) -> error::Result<()> {
723 match &self.inner {
724 VfsInner::Client(client) => client.update_sec_desc(path, sec_desc, follow).await,
725 VfsInner::Direct(direct) => direct.update_sec_desc(path, sec_desc, follow).await,
726 }
727 }
728
729 pub async fn create_dir(&self, path: path::Path<'_>, all: bool) -> error::Result<()> {
731 match &self.inner {
732 VfsInner::Client(client) => client.create_dir(path, all).await,
733 VfsInner::Direct(direct) => direct.create_dir(path, all).await,
734 }
735 }
736
737 pub async fn remove_dir(
739 &self,
740 path: path::Path<'_>,
741 all: bool,
742 ignore: bool,
743 ) -> error::Result<()> {
744 match &self.inner {
745 VfsInner::Client(client) => client.remove_dir(path, all, ignore).await,
746 VfsInner::Direct(direct) => direct.remove_dir(path, all, ignore).await,
747 }
748 }
749
750 pub async fn copy(
752 &self,
753 from: path::Path<'_>,
754 to: path::Path<'_>,
755 all: bool,
756 ) -> error::Result<()> {
757 match &self.inner {
758 VfsInner::Client(client) => client.copy(from, to, all).await,
759 VfsInner::Direct(direct) => direct.copy(from, to, all).await,
760 }
761 }
762
763 pub async fn rename(
765 &self,
766 from: path::Path<'_>,
767 to: path::Path<'_>,
768 replace: bool,
769 ) -> error::Result<()> {
770 match &self.inner {
771 VfsInner::Client(client) => client.rename(from, to, replace).await,
772 VfsInner::Direct(direct) => direct.rename(from, to, replace).await,
773 }
774 }
775
776 pub async fn move_(
778 &self,
779 from: path::Path<'_>,
780 to: path::Path<'_>,
781 all: bool,
782 ) -> error::Result<()> {
783 match &self.inner {
784 VfsInner::Client(client) => client.move_(from, to, all).await,
785 VfsInner::Direct(direct) => direct.move_(from, to, all).await,
786 }
787 }
788
789 pub async fn symlink(
791 &self,
792 cwd: path::Path<'_>,
793 src: path::Path<'_>,
794 dst: path::Path<'_>,
795 ) -> error::Result<()> {
796 match &self.inner {
797 VfsInner::Client(client) => client.symlink(cwd, src, dst).await,
798 VfsInner::Direct(direct) => direct.symlink(cwd, src, dst).await,
799 }
800 }
801
802 pub async fn hard_link(&self, src: path::Path<'_>, dst: path::Path<'_>) -> error::Result<()> {
804 match &self.inner {
805 VfsInner::Client(client) => client.hard_link(src, dst).await,
806 VfsInner::Direct(direct) => direct.hard_link(src, dst).await,
807 }
808 }
809
810 pub async fn symlink_dir(&self, src: path::Path<'_>, dst: path::Path<'_>) -> error::Result<()> {
812 match &self.inner {
813 VfsInner::Client(client) => client.symlink_dir(src, dst).await,
814 VfsInner::Direct(direct) => direct.symlink_dir(src, dst).await,
815 }
816 }
817
818 pub async fn symlink_file(
820 &self,
821 src: path::Path<'_>,
822 dst: path::Path<'_>,
823 ) -> error::Result<()> {
824 match &self.inner {
825 VfsInner::Client(client) => client.symlink_file(src, dst).await,
826 VfsInner::Direct(direct) => direct.symlink_file(src, dst).await,
827 }
828 }
829
830 pub async fn symlink_metadata(
832 &self,
833 path: path::Path<'_>,
834 ) -> error::Result<metadata::Metadata> {
835 match &self.inner {
836 VfsInner::Client(client) => client.symlink_metadata(path).await,
837 VfsInner::Direct(direct) => direct.symlink_metadata(path).await,
838 }
839 }
840
841 pub async fn update_metadata(
843 &self,
844 paths: &[path::PathBuf],
845 patch: metadata::MetadataPatch,
846 ) -> error::Result<()> {
847 match &self.inner {
848 VfsInner::Client(client) => client.update_metadata(paths, patch).await,
849 VfsInner::Direct(direct) => direct.update_metadata(paths, patch).await,
850 }
851 }
852
853 pub async fn canonicalize(&self, path: path::Path<'_>) -> error::Result<path::PathBuf> {
855 match &self.inner {
856 VfsInner::Client(client) => client.canonicalize(path).await,
857 VfsInner::Direct(direct) => direct.canonicalize(path).await,
858 }
859 }
860
861 pub async fn read_link(&self, path: path::Path<'_>) -> error::Result<path::PathBuf> {
863 match &self.inner {
864 VfsInner::Client(client) => client.read_link(path).await,
865 VfsInner::Direct(direct) => direct.read_link(path).await,
866 }
867 }
868
869 pub async fn access(&self, path: path::Path<'_>, mode: file::AccessFlags) -> error::Result<()> {
871 match &self.inner {
872 VfsInner::Client(client) => client.access(path, mode).await,
873 VfsInner::Direct(direct) => direct.access(path, mode).await,
874 }
875 }
876
877 pub async fn glob(
879 &self,
880 pattern: impl Into<String>,
881 root: path::Path<'_>,
882 follow_symlinks: bool,
883 max_depth: Option<usize>,
884 ) -> error::Result<Vec<path::PathBuf>> {
885 let pattern = pattern.into();
886
887 match &self.inner {
888 VfsInner::Client(client) => {
889 client.glob(pattern, root, follow_symlinks, max_depth).await
890 }
891 VfsInner::Direct(direct) => {
892 direct.glob(pattern, root, follow_symlinks, max_depth).await
893 }
894 }
895 }
896}