I've been working with Windows paths using Rust and have a few questions I haven't been able to figure out.
-
The term "verbatim path" is used to refer to the
\\?\
prefixes which allow for extended-length paths. However, it seems like that term is only used by the Rust community. It's used in std forstd::path::Prefix
as well as in technical discussions, but I can't find any usage of it outside of Rust-related things. Where did it originate, and why is it called "verbatim"? -
There are various places where "UNC" is used to refer to this
\\?\
verbatim prefix. For example, dunce saysThere are also Windows NT UNC paths (\\?\C:\foo)
. Everywhere else I've read says that UNC is just the\\server\share\
path. I would not think\\?\C:\foo
is a UNC - I would have thought it would be a Verbatim Disk path, which is also whatstd
says. Why is there this discrepancy? -
I made a program to test Windows' ability to access various path formats and have a question about the results. Here is the code:
use std::path::Path;
use path_slash::PathExt;
fn main() {
// normal path works
let p0 = Path::new(r"C:\Users\mr_rustbot\Documents\foo\test.txt");
// verbatim path works
let p1 = Path::new(r"\\?\C:\Users\mr_rustbot\Documents\foo\test.txt");
// verbatim unix does not work
let p2 = Path::new(r"\\?\C:\Users\mr_rustbot\Documents\foo\test.txt").to_slash_lossy();
let p2 = Path::new(&p2);
// changing \\?\ to \\?/ works
let p3 = Path::new(r"\\?/C:\Users\mr_rustbot\Documents\foo\test.txt").to_slash_lossy();
let p3 = Path::new(&p3);
let p4 = Path::new(r"\\?/UNC\DESKTOP-DRCNKJR\asdf\test.txt").to_slash_lossy();
let p4 = Path::new(&p4);
let paths = vec![p0, p1, p2, p3, p4];
for (i, path) in paths.iter().enumerate() {
match path.metadata() {
Ok(_) => println!("p{} works! ({:?})", i, path),
Err(e) => eprintln!("p{} doesn't work. {} ({:?})",i, e, path)
};
for c in path.components() {
dbg!(c);
}
}
}
Output:
p0 works! ("C:\\Users\\mr_rustbot\\Documents\\foo\\test.txt")
[src\main.rs:32] c = Prefix(
PrefixComponent {
raw: "C:",
parsed: Disk(
67,
),
},
)
[src\main.rs:32] c = RootDir
[src\main.rs:32] c = Normal(
"Users",
)
[src\main.rs:32] c = Normal(
"mr_rustbot",
)
[src\main.rs:32] c = Normal(
"Documents",
)
[src\main.rs:32] c = Normal(
"foo",
)
[src\main.rs:32] c = Normal(
"test.txt",
)
p1 works! ("\\\\?\\C:\\Users\\mr_rustbot\\Documents\\foo\\test.txt")
[src\main.rs:32] c = Prefix(
PrefixComponent {
raw: "\\\\?\\C:",
parsed: VerbatimDisk(
67,
),
},
)
[src\main.rs:32] c = RootDir
[src\main.rs:32] c = Normal(
"Users",
)
[src\main.rs:32] c = Normal(
"mr_rustbot",
)
[src\main.rs:32] c = Normal(
"Documents",
)
[src\main.rs:32] c = Normal(
"foo",
)
[src\main.rs:32] c = Normal(
"test.txt",
)
p2 doesn't work. The system cannot find the file specified. (os error 2) ("\\\\?\\C:/Users/mr_rustbot/Documents/foo/test.txt")
[src\main.rs:32] c = Prefix(
PrefixComponent {
raw: "\\\\?\\C:/Users/mr_rustbot/Documents/foo/test.txt",
parsed: Verbatim(
"C:/Users/mr_rustbot/Documents/foo/test.txt",
),
},
)
p3 works! ("\\\\?/C:/Users/mr_rustbot/Documents/foo/test.txt")
[src\main.rs:32] c = Prefix(
PrefixComponent {
raw: "\\\\?/C:",
parsed: UNC(
"?",
"C:",
),
},
)
[src\main.rs:32] c = RootDir
[src\main.rs:32] c = Normal(
"Users",
)
[src\main.rs:32] c = Normal(
"mr_rustbot",
)
[src\main.rs:32] c = Normal(
"Documents",
)
[src\main.rs:32] c = Normal(
"foo",
)
[src\main.rs:32] c = Normal(
"test.txt",
)
p4 works! ("\\\\?/UNC/DESKTOP-DRCNKJR/asdf/test.txt")
[src\main.rs:32] c = Prefix(
PrefixComponent {
raw: "\\\\?/UNC",
parsed: UNC(
"?",
"UNC",
),
},
)
[src\main.rs:32] c = RootDir
[src\main.rs:32] c = Normal(
"DESKTOP-DRCNKJR",
)
[src\main.rs:32] c = Normal(
"asdf",
)
[src\main.rs:32] c = Normal(
"test.txt",
)
Why did p4
work? I understand why Rust parsed it as UNC instead of Verbatim UNC (it doesn't start with \\?\UNC\
so it thinks ?
is the server name and UNC
is the share), but shouldn't Windows have not allowed me to access the metadata?