Understanding Windows Paths

I've been working with Windows paths using Rust and have a few questions I haven't been able to figure out.

  1. 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 for std::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"?

  2. There are various places where "UNC" is used to refer to this \\?\ verbatim prefix. For example, dunce says There 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 what std says. Why is there this discrepancy?

  3. 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?

It's true "verbatim" was a term invented by the Rust community. It's called that because paths prefixed with \\?\ are passed (almost) directly to the Windows kernel without modification (except to change the prefix to \??\). Hence it's passed "verbatim".

Yeah this is an unfortunate though common misnaming. A UNC path is more correctly a path in the form \\server\share\folder\file.txt. A path can also be both verbatim and UNC, e.g.: \\?\UNC\server\share\folder\file.txt.

If you don't use \\?\ then Win32 APIs do a series of transformations to work out which path you meant. The first thing it does is transforms / to \ so the prefix \\?/ becomes \\?\. I assume it then has a special case to handle the resulting \\?\ prefix.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.