wslplugins_rs/api/
api_v1.rs1#[cfg(doc)]
2use super::Error;
3use super::{Result, WSLCommand};
4use crate::api::errors::require_update_error::Result as UpReqResult;
5use crate::api::wsl_command::IntoCowUtf8UnixPath;
6use crate::{SessionID, UserDistributionID, WSLVersion};
7use std::ffi::OsStr;
8use std::fmt::{self, Debug};
9use std::mem::MaybeUninit;
10use std::net::TcpStream;
11use std::os::windows::io::FromRawSocket as _;
12use std::os::windows::raw::SOCKET;
13use std::path::Path;
14#[cfg(feature = "tracing")]
15use tracing::instrument;
16use typed_path::Utf8UnixPath;
17use widestring::U16CString;
18use windows_core::{Result as WinResult, HRESULT};
19use wslpluginapi_sys;
20use wslpluginapi_sys::windows_sys::Win32::Networking::WinSock::SOCKET as WinSocket;
21
22#[cfg(doc)]
23use crate::DistributionID;
24
25use wslpluginapi_sys::WSLPluginAPIV1;
26
27use super::utils::check_required_version_result;
28
29#[repr(transparent)]
34pub struct ApiV1(WSLPluginAPIV1);
35
36impl From<ApiV1> for WSLPluginAPIV1 {
37 #[inline]
38 fn from(value: ApiV1) -> Self {
39 value.0
40 }
41}
42
43impl From<WSLPluginAPIV1> for ApiV1 {
44 #[inline]
45 fn from(value: WSLPluginAPIV1) -> Self {
46 Self(value)
47 }
48}
49
50impl AsRef<WSLPluginAPIV1> for ApiV1 {
51 #[inline]
52 fn as_ref(&self) -> &WSLPluginAPIV1 {
53 &self.0
54 }
55}
56
57impl AsRef<ApiV1> for WSLPluginAPIV1 {
58 #[inline]
59 fn as_ref(&self) -> &ApiV1 {
60 unsafe { &*std::ptr::from_ref::<Self>(self).cast::<ApiV1>() }
62 }
63}
64
65impl ApiV1 {
66 #[must_use]
79 #[inline]
80 pub fn version(&self) -> &WSLVersion {
81 self.0.Version.as_ref()
82 }
83
84 #[doc(alias = "MountFolder")]
100 #[cfg_attr(feature = "tracing", instrument(level = "trace"))]
101 #[inline]
102 pub fn mount_folder<
103 WP: AsRef<Path> + std::fmt::Debug,
104 UP: AsRef<Utf8UnixPath> + std::fmt::Debug,
105 >(
106 &self,
107 session_id: SessionID,
108 windows_path: WP,
109 linux_path: UP,
110 read_only: bool,
111 name: &OsStr,
112 ) -> WinResult<()> {
113 let encoded_windows_path =
114 U16CString::from_os_str_truncate(windows_path.as_ref().as_os_str());
115 let encoded_linux_path = U16CString::from_str_truncate(linux_path.as_ref().as_str());
116 let encoded_name = U16CString::from_os_str_truncate(name);
117 let result = unsafe {
130 self.0.MountFolder.unwrap_unchecked()(
131 u32::from(session_id),
132 encoded_windows_path.as_ptr(),
133 encoded_linux_path.as_ptr(),
134 i32::from(read_only),
135 encoded_name.as_ptr(),
136 )
137 };
138 HRESULT(result).ok()
139 }
140
141 pub(crate) unsafe fn execute_binary_internal(
142 &self,
143 session_id: SessionID,
144 path: &[u8],
145 args: &[*const u8],
146 ) -> WinResult<TcpStream> {
147 let mut socket = MaybeUninit::<WinSocket>::uninit();
148 let stream = unsafe {
150 HRESULT(self.0.ExecuteBinary.unwrap_unchecked()(
151 u32::from(session_id),
152 path.as_ptr(),
153 args.as_ptr().cast_mut(),
154 socket.as_mut_ptr(),
155 ))
156 .ok()?;
157
158 let socket = socket.assume_init();
159 TcpStream::from_raw_socket(socket as SOCKET)
160 };
161 Ok(stream)
162 }
163
164 #[cfg_attr(feature = "tracing", instrument(level = "trace"))]
166 pub(crate) fn plugin_error(&self, error: &OsStr) -> WinResult<()> {
167 let error_utf16 = U16CString::from_os_str_truncate(error);
168 HRESULT(
169 unsafe { self.0.PluginError.unwrap_unchecked()(error_utf16.as_ptr()) },
171 )
172 .ok()
173 }
174
175 pub(crate) unsafe fn execute_binary_in_distribution_internal(
176 &self,
177 session_id: SessionID,
178 distribution_id: UserDistributionID,
179 c_path: &[u8],
180 args: &[*const u8],
181 ) -> Result<TcpStream> {
182 self.check_required_version(&WSLVersion::new(2, 1, 2))?;
183 let mut socket = MaybeUninit::<WinSocket>::uninit();
184 let guid: wslpluginapi_sys::windows_sys::core::GUID = distribution_id.into();
185 let stream = unsafe {
187 HRESULT(self.0.ExecuteBinaryInDistribution.unwrap_unchecked()(
188 u32::from(session_id),
189 (&raw const guid),
190 c_path.as_ptr(),
191 args.as_ptr().cast_mut(),
192 socket.as_mut_ptr(),
193 ))
194 .ok()?;
195
196 let socket = socket.assume_init();
197 TcpStream::from_raw_socket(socket as SOCKET)
198 };
199 Ok(stream)
200 }
201
202 #[inline]
222 pub fn new_command<'a, P: IntoCowUtf8UnixPath<'a>>(
223 &'a self,
224 session_id: SessionID,
225 program: P,
226 ) -> WSLCommand<'a> {
227 WSLCommand::new(self, session_id, program)
228 }
229
230 fn check_required_version(&self, version: &WSLVersion) -> UpReqResult<()> {
231 check_required_version_result(self.version(), version)
232 }
233}
234
235impl Debug for ApiV1 {
236 #[inline]
237 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
238 f.debug_struct("ApiV1")
239 .field("version", self.version())
240 .finish()
241 }
242}
243
244#[cfg(test)]
245mod tests {
246 use super::*;
247 use crate::utils::test_transparence;
248
249 #[test]
250 fn test_layouts() {
251 test_transparence::<WSLPluginAPIV1, ApiV1>();
252 }
253}