diff options
| author | Sean Young <sean@mess.org> | 2021-09-26 14:21:22 +0100 |
|---|---|---|
| committer | Sean Young <sean@mess.org> | 2021-10-01 19:54:57 +0100 |
| commit | fa4072f7d32221adf5edc8d57c9cb8fef3ddc96e (patch) | |
| tree | 4a61de865dd7876b51f7233ee1f47758e0a8da5a | |
| parent | ac8dd1b2f24dc62c962172b27433106b4e84dc62 (diff) | |
| download | rust-fa4072f7d32221adf5edc8d57c9cb8fef3ddc96e.tar.gz rust-fa4072f7d32221adf5edc8d57c9cb8fef3ddc96e.zip | |
path.push() should work as expected on windows verbatim paths
| -rw-r--r-- | library/std/src/path.rs | 53 | ||||
| -rw-r--r-- | library/std/src/path/tests.rs | 9 |
2 files changed, 55 insertions, 7 deletions
diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 9d5778ed48c..a45ecf6ea8c 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1231,20 +1231,59 @@ impl PathBuf { let mut need_sep = self.as_mut_vec().last().map(|c| !is_sep_byte(*c)).unwrap_or(false); // in the special case of `C:` on Windows, do *not* add a separator + let comps = self.components(); + + if comps.prefix_len() > 0 + && comps.prefix_len() == comps.path.len() + && comps.prefix.unwrap().is_drive() { - let comps = self.components(); - if comps.prefix_len() > 0 - && comps.prefix_len() == comps.path.len() - && comps.prefix.unwrap().is_drive() - { - need_sep = false - } + need_sep = false } // absolute `path` replaces `self` if path.is_absolute() || path.prefix().is_some() { self.as_mut_vec().truncate(0); + // verbatim paths need . and .. removed + } else if comps.prefix_verbatim() { + let mut buf: Vec<_> = comps.collect(); + for c in path.components() { + match c { + Component::RootDir => { + buf.truncate(1); + buf.push(c); + } + Component::CurDir => (), + Component::ParentDir => { + if let Some(Component::Normal(_)) = buf.last() { + buf.pop(); + } + } + _ => buf.push(c), + } + } + + let mut res = OsString::new(); + let mut need_sep = false; + + for c in buf { + if need_sep && c != Component::RootDir { + res.push(MAIN_SEP_STR); + } + res.push(c.as_os_str()); + + need_sep = match c { + Component::RootDir => false, + Component::Prefix(prefix) => { + !prefix.parsed.is_drive() && prefix.parsed.len() > 0 + } + _ => true, + } + } + + self.inner = res; + return; + // `path` has a root but no prefix, e.g., `\windows` (Windows only) } else if path.has_root() { let prefix_len = self.components().prefix_remaining(); diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs index ce23cf6cd21..3973a6829d3 100644 --- a/library/std/src/path/tests.rs +++ b/library/std/src/path/tests.rs @@ -1262,6 +1262,15 @@ pub fn test_push() { tp!("\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar"); tp!("\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one + + tp!(r"\\?\C:\bar", "../foo", r"\\?\C:\foo"); + tp!(r"\\?\C:\bar", "../../foo", r"\\?\C:\foo"); + tp!(r"\\?\C:\", "../foo", r"\\?\C:\foo"); + tp!(r"\\?\C:", r"D:\foo/./", r"D:\foo/./"); + tp!(r"\\?\C:", r"\\?\D:\foo\.\", r"\\?\D:\foo\.\"); + tp!(r"\\?\A:\x\y", "/foo", r"\\?\A:\foo"); + tp!(r"\\?\A:", r"..\foo\.", r"\\?\A:\foo"); + tp!(r"\\?\A:\x\y", r".\foo\.", r"\\?\A:\x\y\foo"); } } |
