# Windows UNC paths: behavior, std::fs::canonicalize alignment, and test matrix
This document summarizes Windows path prefixes, what Rust's `std::fs::canonicalize` does, and the coverage we need in this crate to stay aligned, including ambiguous cases for non-existing paths.
## Windows path prefixes and forms
Windows path parsing recognizes these key forms (see `std::path::Prefix`):
- Drive-relative and absolute:
- `C:\` (absolute on drive C)
- `C:relative\path` (relative to current directory on drive C)
- UNC (server/share):
- `\\server\share\path` (Win32 UNC)
- Verbatim UNC: `\\?\UNC\server\share\path` (extended-length)
Skips Win32 normalization like trimming trailing dots/spaces.
- Verbatim disk: `\\?\C:\path` (extended-length for local drive)
- Device namespace: `\\.\COM1`, `\\?\GLOBALROOT\Device\HarddiskVolume1` (lexical-only: supported as opaque prefixes; no IO)
Notes:
- Extended-length (verbatim) prefixes remove `MAX_PATH` (260) limits and disable certain Win32 normalizations (e.g., trailing dot/space trimming, `\\.\` device paths, path parsing quirks).
- `std::fs::canonicalize` returns extended-length paths (`\\?\C:\...` or `\\?\UNC\server\share\...`) for existing paths.
## `std::fs::canonicalize` behavior (Windows)
- For existing paths:
- Converts to extended-length verbatim form.
- Normalizes case to the filesystem's canonical casing.
- Resolves symlinks and junctions.
- Expands 8.3 (short) names to long names.
- For non-existing paths:
- Returns `NotFound`.
Implications for this crate:
- We must match `std::fs::canonicalize` when the full path exists.
- For non-existing suffixes, we keep the extended-length prefix and preserve textual components (no short-name expansion) while resolving the deepest existing prefix.
- For device namespace paths (e.g., `\\.\`, `\\?\GLOBALROOT\...`), we support lexical normalization without IO: preserve the device prefix verbatim and normalize `.`/`..` within the path.
## Edge cases to cover
- Mixed separators `\\` and `/` inside UNC forms.
- `..` traversal cannot climb above `\\server\share` root; it clamps at the share root.
- Trailing dots/spaces in names are preserved under verbatim prefix.
- 8.3-like components (e.g., `PROGRA~1`) are preserved when non-existing; expanded only when that component exists and is probed/canonicalized.
- Idempotency when input already uses verbatim `\\?\` or verbatim UNC.
- Drive-letter absolute across multiple letters yields `\\?\X:\...`.
- UNC server/share roots canonicalize to verbatim UNC; server/share availability cannot be verified without network, so tests must assert prefix/shape rather than existence.
- Device namespace paths: assert prefix preservation and purely lexical normalization; never convert to another prefix or probe the filesystem.
## Proposed test matrix (Windows)
- Drive absolute:
- `C:\nonexistent\child.txt` -> starts with `\\?\C:\`; endswith `nonexistent\child.txt`.
- Repeat for `D, E, Z`.
- Verbatim disk idempotency:
- Input `\\?\C:\NonExistent\...` -> unchanged.
- UNC server/share non-existing:
- `\\server\share` -> verbatim UNC prefix `\\?\UNC\server` (cannot assert share due to envs where `share` isn't included in output without probing).
- `\\server\share\mixed/sep\\dir/file.txt` -> starts `\\?\UNC\`, endswith suffix.
- `\\server\share\folder\..\..\sibling\file.txt` -> still under `\\?\UNC\server`; endswith suffix.
- Idempotent for `\\?\UNC\server\share\...`.
- Preserve `PROGRA~1` component for non-existing.
- Preserve trailing `.` and ` ` in components.
- Device namespace (lexical-only):
- `\\.\PIPE\name\..\other` -> `\\.\PIPE\other`
- `\\?\GLOBALROOT\Device\HarddiskVolume1\foo\.\bar\..\baz` -> `\\?\GLOBALROOT\Device\HarddiskVolume1\foo\baz`
- Idempotent for already-normalized device paths like `\\.\PhysicalDrive0`
- Parent traversal clamps at the DeviceNS prefix including the device class (e.g., `\\.\PIPE` or `\\?\GLOBALROOT`); it won’t pop the device class name. Example: `\\.\PIPE\a\..\..\b` -> `\\.\PIPE\b`
## Known limitations
- Device namespace paths are handled lexically only; we do not perform IO or guarantee device availability/resolution. Parent traversal never crosses the DeviceNS prefix and does not remove the device class name.
- We cannot verify network share existence in CI; tests use structural assertions instead of IO checks.
## Alignment checklist
- Existing local paths: exact equality with `std::fs::canonicalize` (covered by `std_compat`).
- Existing UNC paths: equality when available; otherwise avoid tests that require a real share.
- Non-existing suffixes: extended-length prefix present; suffix preserved lexically; `..` stops at root or share.