From 04bf7d7a991e0f2eb3f218676abe933e0011df18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=AD=A6=E8=80=85?= <644284807@qq.com> Date: Sat, 6 Sep 2025 06:40:00 +0800 Subject: [PATCH] feature-wide-string --- Cargo.toml | 2 ++ src/client/windows.rs | 71 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index f2ce907..0336c0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,8 @@ no-log = ["log/max_level_off"] vendored = ["pavao/vendored"] # tests with-containers = [] +# support non-ASCII characters +wide-string=[] [[example]] name = "tree" diff --git a/src/client/windows.rs b/src/client/windows.rs index 53e912c..45f2c9a 100644 --- a/src/client/windows.rs +++ b/src/client/windows.rs @@ -7,6 +7,8 @@ mod file_stream; use std::ffi::CString; use std::path::{Path, PathBuf}; +#[cfg(feature = "wide-string")] +use std::os::windows::ffi::OsStrExt; pub use credentials::SmbCredentials; use file_stream::FileStream; @@ -67,8 +69,13 @@ impl RemoteFs for SmbFs { // add connection trace!("connecting to {}", self.remote_name); + #[cfg(not(feature = "wide-string"))] let remote_name = Self::to_cstr(&self.remote_name); + #[cfg(feature = "wide-string")] + let remote_name = to_wide_string(&self.remote_name); + + #[cfg(not(feature = "wide-string"))] let mut resource = WNet::NETRESOURCEA { dwDisplayType: WNet::RESOURCEDISPLAYTYPE_SHAREADMIN, dwScope: WNet::RESOURCE_GLOBALNET, @@ -80,18 +87,47 @@ impl RemoteFs for SmbFs { lpRemoteName: remote_name.as_c_str().as_ptr() as *mut u8, }; + #[cfg(feature = "wide-string")] + let mut resource = WNet::NETRESOURCEW { + dwDisplayType: WNet::RESOURCEDISPLAYTYPE_SHAREADMIN, + dwScope: WNet::RESOURCE_GLOBALNET, + dwType: WNet::RESOURCETYPE_DISK, + dwUsage: WNet::RESOURCEUSAGE_ALL, + lpComment: std::ptr::null_mut(), + lpLocalName: std::ptr::null_mut(), + lpProvider: std::ptr::null_mut(), + lpRemoteName: remote_name.as_ptr() as *mut u16, + }; + + #[cfg(not(feature = "wide-string"))] let username = self .credentials .username .as_mut() .map(|username| Self::to_cstr(username)); + #[cfg(feature = "wide-string")] + let username = self + .credentials + .username + .as_mut() + .map(|username| to_wide_string(username)); + + #[cfg(not(feature = "wide-string"))] let password = self .credentials .password .as_mut() .map(|password| Self::to_cstr(password)); + #[cfg(feature = "wide-string")] + let password = self + .credentials + .password + .as_mut() + .map(|password| to_wide_string(password)); + + #[cfg(not(feature = "wide-string"))] let result = unsafe { let username_ptr = username .as_ref() @@ -109,6 +145,24 @@ impl RemoteFs for SmbFs { ) }; + #[cfg(feature = "wide-string")] + let result = unsafe { + let username_ptr = username + .as_ref() + .map(|username| username.as_ptr()) + .unwrap_or(std::ptr::null()); + let password_ptr = password + .as_ref() + .map(|password| password.as_ptr()) + .unwrap_or(std::ptr::null()); + WNet::WNetAddConnection2W( + &mut resource as *mut WNet::NETRESOURCEW, + password_ptr as *const u16, + username_ptr as *const u16, + WNet::CONNECT_INTERACTIVE, + ) + }; + if result == NO_ERROR { self.is_connected = true; debug!("connected to {}", self.remote_path.display()); @@ -124,11 +178,20 @@ impl RemoteFs for SmbFs { fn disconnect(&mut self) -> RemoteResult<()> { self.check_connection()?; + #[cfg(not(feature = "wide-string"))] let remote_name = Self::to_cstr(&self.remote_name); + #[cfg(feature = "wide-string")] + let remote_name = to_wide_string(&self.remote_name); + + #[cfg(not(feature = "wide-string"))] let result = unsafe { WNet::WNetCancelConnection2A(remote_name.as_ptr() as *mut u8, 0, TRUE) }; + #[cfg(feature = "wide-string")] + let result = + unsafe { WNet::WNetCancelConnection2W(remote_name.as_ptr() as *mut u16, 0, TRUE) }; + if result == NO_ERROR { self.is_connected = false; debug!("disconnected from {}", self.remote_path.display()); @@ -366,6 +429,14 @@ impl RemoteFs for SmbFs { } } +#[cfg(feature = "wide-string")] +fn to_wide_string(s: &str) -> Vec { + std::ffi::OsStr::new(s) + .encode_wide() + .chain(Some(0)) + .collect() +} + #[cfg(test)] mod test {