1use std::os::unix::ffi::OsStrExt;
11use std::path::Path;
12
13pub trait Host {
15 fn exists(&self, path: &[u8]) -> bool;
17
18 fn is_dir(&self, path: &[u8]) -> bool;
20
21 fn host_path(&self, path: &[u8]) -> Vec<u8>;
26
27 fn cwd(&self) -> Vec<u8>;
29
30 fn var(&self, name: &[u8]) -> Option<Vec<u8>>;
32
33 fn vars(&self) -> Vec<(Vec<u8>, Vec<u8>)>;
35
36 fn read_fd(&self, fd: i32) -> std::io::Result<Vec<u8>>;
38
39 fn fd_path(&self, fd: i32) -> std::io::Result<Vec<u8>>;
41}
42
43pub struct Local;
45
46impl Host for Local {
47 fn exists(&self, path: &[u8]) -> bool {
48 Path::new(std::ffi::OsStr::from_bytes(path)).exists()
49 }
50
51 fn is_dir(&self, path: &[u8]) -> bool {
52 Path::new(std::ffi::OsStr::from_bytes(path)).is_dir()
53 }
54
55 fn host_path(&self, path: &[u8]) -> Vec<u8> {
56 if path.first() == Some(&b'/') {
57 return path.to_vec();
58 }
59 let mut cwd = self.cwd();
60 if cwd != b"/" {
61 cwd.push(b'/');
62 }
63 cwd.extend_from_slice(path);
64 cwd
65 }
66
67 fn cwd(&self) -> Vec<u8> {
68 std::env::current_dir()
69 .map(|c| c.as_os_str().as_bytes().to_vec())
70 .unwrap_or_else(|_| b"/".to_vec())
71 }
72
73 fn var(&self, name: &[u8]) -> Option<Vec<u8>> {
74 std::env::var_os(std::ffi::OsStr::from_bytes(name)).map(|v| v.as_bytes().to_vec())
75 }
76
77 fn vars(&self) -> Vec<(Vec<u8>, Vec<u8>)> {
78 std::env::vars_os()
79 .map(|(k, v)| (k.as_bytes().to_vec(), v.as_bytes().to_vec()))
80 .collect()
81 }
82
83 fn read_fd(&self, fd: i32) -> std::io::Result<Vec<u8>> {
84 use std::io::Read;
85 use std::os::unix::io::FromRawFd;
86 if fd < 0 {
87 return Err(std::io::Error::from_raw_os_error(libc::EBADF));
88 }
89 let dup = unsafe { libc::dup(fd) };
90 if dup < 0 {
91 return Err(std::io::Error::last_os_error());
92 }
93 let mut f = unsafe { std::fs::File::from_raw_fd(dup) };
94 let mut out = Vec::new();
95 f.read_to_end(&mut out)?;
96 Ok(out)
97 }
98
99 fn fd_path(&self, fd: i32) -> std::io::Result<Vec<u8>> {
100 std::fs::read_link(format!("/proc/self/fd/{fd}")).map(|p| p.as_os_str().as_bytes().to_vec())
101 }
102}