Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 07d22e7

Browse files
authoredOct 5, 2021
Rollup merge of rust-lang#89270 - seanyoung:join_fold, r=m-ou-se
path.push() should work as expected on windows verbatim paths On Windows, std::fs::canonicalize() returns an so-called UNC path. UNC paths differ with regular paths because: - This type of path can much longer than a non-UNC path (32k vs 260 characters). - The prefix for a UNC path is ``Component::Prefix(Prefix::DiskVerbatim(..)))`` - No `/` is allowed - No `.` is allowed - No `..` is allowed Rust has poor handling of such paths. If you join a UNC path with a path with any of the above, then this will not work. I've implemented a new method `fn join_fold()` which joins paths and also removes any `.` and `..` from it, and replaces `/` with `\` on Windows. Using this function it is possible to use UNC paths without issue. In addition, this function is useful on Linux too; paths can be appended without having to call `canonicalize()` to remove the `.` and `..`. This PR needs test cases, which can I add. I hope this will a start of a discussion.
2 parents 212282a + fa4072f commit 07d22e7

File tree

2 files changed

+55
-7
lines changed

2 files changed

+55
-7
lines changed
 

‎library/std/src/path.rs

+46-7
Original file line numberDiff line numberDiff line change
@@ -1231,20 +1231,59 @@ impl PathBuf {
12311231
let mut need_sep = self.as_mut_vec().last().map(|c| !is_sep_byte(*c)).unwrap_or(false);
12321232

12331233
// in the special case of `C:` on Windows, do *not* add a separator
1234+
let comps = self.components();
1235+
1236+
if comps.prefix_len() > 0
1237+
&& comps.prefix_len() == comps.path.len()
1238+
&& comps.prefix.unwrap().is_drive()
12341239
{
1235-
let comps = self.components();
1236-
if comps.prefix_len() > 0
1237-
&& comps.prefix_len() == comps.path.len()
1238-
&& comps.prefix.unwrap().is_drive()
1239-
{
1240-
need_sep = false
1241-
}
1240+
need_sep = false
12421241
}
12431242

12441243
// absolute `path` replaces `self`
12451244
if path.is_absolute() || path.prefix().is_some() {
12461245
self.as_mut_vec().truncate(0);
12471246

1247+
// verbatim paths need . and .. removed
1248+
} else if comps.prefix_verbatim() {
1249+
let mut buf: Vec<_> = comps.collect();
1250+
for c in path.components() {
1251+
match c {
1252+
Component::RootDir => {
1253+
buf.truncate(1);
1254+
buf.push(c);
1255+
}
1256+
Component::CurDir => (),
1257+
Component::ParentDir => {
1258+
if let Some(Component::Normal(_)) = buf.last() {
1259+
buf.pop();
1260+
}
1261+
}
1262+
_ => buf.push(c),
1263+
}
1264+
}
1265+
1266+
let mut res = OsString::new();
1267+
let mut need_sep = false;
1268+
1269+
for c in buf {
1270+
if need_sep && c != Component::RootDir {
1271+
res.push(MAIN_SEP_STR);
1272+
}
1273+
res.push(c.as_os_str());
1274+
1275+
need_sep = match c {
1276+
Component::RootDir => false,
1277+
Component::Prefix(prefix) => {
1278+
!prefix.parsed.is_drive() && prefix.parsed.len() > 0
1279+
}
1280+
_ => true,
1281+
}
1282+
}
1283+
1284+
self.inner = res;
1285+
return;
1286+
12481287
// `path` has a root but no prefix, e.g., `\windows` (Windows only)
12491288
} else if path.has_root() {
12501289
let prefix_len = self.components().prefix_remaining();

‎library/std/src/path/tests.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1262,6 +1262,15 @@ pub fn test_push() {
12621262
tp!("\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar");
12631263

12641264
tp!("\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one
1265+
1266+
tp!(r"\\?\C:\bar", "../foo", r"\\?\C:\foo");
1267+
tp!(r"\\?\C:\bar", "../../foo", r"\\?\C:\foo");
1268+
tp!(r"\\?\C:\", "../foo", r"\\?\C:\foo");
1269+
tp!(r"\\?\C:", r"D:\foo/./", r"D:\foo/./");
1270+
tp!(r"\\?\C:", r"\\?\D:\foo\.\", r"\\?\D:\foo\.\");
1271+
tp!(r"\\?\A:\x\y", "/foo", r"\\?\A:\foo");
1272+
tp!(r"\\?\A:", r"..\foo\.", r"\\?\A:\foo");
1273+
tp!(r"\\?\A:\x\y", r".\foo\.", r"\\?\A:\x\y\foo");
12651274
}
12661275
}
12671276

0 commit comments

Comments
 (0)
Failed to load comments.