Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
71 changes: 71 additions & 0 deletions src/client/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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()
Expand All @@ -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());
Expand All @@ -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());
Expand Down Expand Up @@ -366,6 +429,14 @@ impl RemoteFs for SmbFs {
}
}

#[cfg(feature = "wide-string")]
fn to_wide_string(s: &str) -> Vec<u16> {
std::ffi::OsStr::new(s)
.encode_wide()
.chain(Some(0))
.collect()
}

#[cfg(test)]
mod test {

Expand Down