Skip to content

Commit f1efc7e

Browse files
committed
Make sure CreateDirectoryW works for path lengths > 247
1 parent 3e2d606 commit f1efc7e

File tree

3 files changed

+41
-1
lines changed

3 files changed

+41
-1
lines changed

Diff for: library/std/src/fs/tests.rs

+29
Original file line numberDiff line numberDiff line change
@@ -1411,3 +1411,32 @@ fn symlink_hard_link() {
14111411
// "hard_link" should still appear as a symlink.
14121412
assert!(check!(fs::symlink_metadata(tmpdir.join("hard_link"))).file_type().is_symlink());
14131413
}
1414+
1415+
/// Ensure `fs::create_dir` works on Windows with longer paths.
1416+
#[test]
1417+
#[cfg(windows)]
1418+
fn create_dir_long_paths() {
1419+
use crate::{ffi::OsStr, iter, os::windows::ffi::OsStrExt};
1420+
const PATH_LEN: usize = 247;
1421+
1422+
let tmpdir = tmpdir();
1423+
let mut path = tmpdir.path().to_path_buf();
1424+
path.push("a");
1425+
let mut path = path.into_os_string();
1426+
1427+
let utf16_len = path.encode_wide().count();
1428+
if utf16_len >= PATH_LEN {
1429+
// Skip the test in the unlikely event the local user has a long temp directory path.
1430+
// This should not affect CI.
1431+
return;
1432+
}
1433+
// Increase the length of the path.
1434+
path.extend(iter::repeat(OsStr::new("a")).take(PATH_LEN - utf16_len));
1435+
1436+
// This should succeed.
1437+
fs::create_dir(&path).unwrap();
1438+
1439+
// This will fail if the path isn't converted to verbatim.
1440+
path.push("a");
1441+
fs::create_dir(&path).unwrap();
1442+
}

Diff for: library/std/src/sys/windows/path.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,11 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) {
150150
///
151151
/// This path may or may not have a verbatim prefix.
152152
pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
153-
const LEGACY_MAX_PATH: usize = 260;
153+
// Normally the MAX path is 260 UTF-16 code units (including the NULL).
154+
// However, for APIs such as CreateDirectory[1], the limit is 248.
155+
//
156+
// [1]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createdirectorya#parameters
157+
const LEGACY_MAX_PATH: usize = 248;
154158
// UTF-16 encoded code points, used in parsing and building UTF-16 paths.
155159
// All of these are in the ASCII range so they can be cast directly to `u16`.
156160
const SEP: u16 = b'\\' as _;

Diff for: library/std/src/sys/windows/path/tests.rs

+7
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,13 @@ fn verbatim() {
8181
check(r"\\server\share", r"\\server\share");
8282
check(r"\\.\COM1", r"\\.\COM1");
8383

84+
// Check that paths of length 247 are converted to verbatim.
85+
// This is necessary for `CreateDirectory`.
86+
check(
87+
r"C:\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
88+
r"\\?\C:\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
89+
);
90+
8491
// Make sure opening a drive will work.
8592
check("Z:", "Z:");
8693

0 commit comments

Comments
 (0)