Skip to content

Commit

Permalink
Fix windows bug (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
dylni committed Jan 6, 2022
1 parent 3b28d3c commit 1ab5e5d
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 8 deletions.
26 changes: 22 additions & 4 deletions src/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,18 +109,36 @@ pub(super) fn normalize_virtually(
// This assertion should never fail.
static_assert!(mem::size_of::<DWORD>() <= mem::size_of::<usize>());

let capacity = capacity as usize;
if let Some(additional_capacity) =
capacity.checked_sub(buffer.capacity())
let length = capacity as usize;
if let Some(mut additional_capacity) =
length.checked_sub(buffer.capacity())
{
assert_ne!(0, additional_capacity);

// WinAPI can recommend an insufficient capacity that causes it to
// return incorrect results, so extra space is reserved as a
// workaround.
macro_rules! extra_capacity {
() => {
2
};
}
capacity =
capacity.checked_add(extra_capacity!()).ok_or_else(|| {
io::Error::new(
io::ErrorKind::Other,
"required path length is too large for WinAPI",
)
})?;
additional_capacity += extra_capacity!();

buffer.reserve(additional_capacity);
continue;
}

// SAFETY: These characters were initialized by the system call.
unsafe {
buffer.set_len(capacity);
buffer.set_len(length);
}
break Ok(BasePathBuf(OsString::from_wide(&buffer)));
}
Expand Down
10 changes: 6 additions & 4 deletions tests/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use normpath::PathExt;
#[rustversion::attr(since(1.46.0), track_caller)]
pub(crate) fn assert_eq<P>(expected: &Path, result: io::Result<P>)
where
P: AsRef<BasePath>,
P: AsRef<Path>,
{
struct Wrapper<'a>(&'a Path);

Expand All @@ -25,9 +25,11 @@ where
}
}

impl PartialEq<Result<&BasePath, &io::Error>> for Wrapper<'_> {
fn eq(&self, other: &Result<&BasePath, &io::Error>) -> bool {
other.map(|x| self.0 == x).unwrap_or(false)
impl PartialEq<Result<&Path, &io::Error>> for Wrapper<'_> {
fn eq(&self, other: &Result<&Path, &io::Error>) -> bool {
other
.map(|x| self.0.as_os_str() == x.as_os_str())
.unwrap_or(false)
}
}

Expand Down
18 changes: 18 additions & 0 deletions tests/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#![cfg(windows)]

use std::env;
use std::io;
use std::path::Path;

use normpath::PathExt;
Expand Down Expand Up @@ -128,3 +130,19 @@ fn test_edge_cases() {
// test!(r"/??/X:/", r"\??\X:/", SAME);
// test!(r"/??/X:", r"\??\X:", SAME);
}

// https://github.com/dylni/normpath/issues/5
#[test]
fn test_windows_bug() -> io::Result<()> {
let initial_current_dir = env::current_dir()?;

for current_dir in &[r"C:\", r"C:\Users"] {
let current_dir = Path::new(current_dir);
env::set_current_dir(current_dir)?;
common::assert_eq(current_dir, env::current_dir());

common::assert_eq(current_dir, Path::new(".").normalize());
}

env::set_current_dir(initial_current_dir)
}

0 comments on commit 1ab5e5d

Please sign in to comment.