Expand description
The request path contract: what a caller may name, and what gets stored.
§Duplicated on purpose, for now
This is a second copy of the preparation that ships in
windows-file-enumeration-sys, not a replacement for it. That crate is
released and this one is not, so making it depend here would make it
unpublishable; the copy keeps the working crate untouched while this one is
proven. The de-duplication happens after this branch merges with main, and
is scheduled as a checklist item – it is not a duplicate that nobody
circled back to.
§A resolved path is not a session-independent path
GetFullPathNameW does not verify what it produces – though for a
drive-relative path naming another drive it does query the filesystem, and
may rewrite that drive’s recorded entry (see crate::full_path). It
collapses ./..
lexically, and it additionally roots most paths that are not fully
qualified against process state – the current directory, or for a
root-relative path that directory’s root, or for a drive-relative path
naming another drive the entry recorded for it in the =C: environment
variables – used verbatim when accepted, so it need not even be on that
drive, and replaced by the drive root when not (for the current drive the
process directory is used and the entry makes no difference). It is
therefore not a lexical call as a whole, which is what makes resolving on
the submitting thread meaningful.
“Most” rather than “every”, because a legacy device name short-circuits
the rooting entirely. prepare hands the input to that call without
device handling of its own, so prepare("CON") yields \\.\CON – a device,
not a file under the current directory – and the same holds for CON:,
NUL, LPT1: and the rest of the legacy set. A caller passing through an
untrusted name should know that. Anything with more after it (CON.txt,
a\CON) roots normally – except for NUL, the one member a path in
front of it does not save: prepare(r"C:\NUL") is \\.\NUL, so a fully
qualified path is not by itself evidence that a name refers to a file on
that volume. Only a suffix (NUL.txt) takes it out. The full shape is in
crate::full_path, which documents the call itself.
What it never does is expand a drive letter, and a drive letter resolves against the logon session of whatever token is in effect. So a path prepared on a submitting thread and opened on a worker under a captured token from another session can name a different device. Preparation closes the current-directory race; it does not close that one, and nothing here should be read as implying otherwise.
A request resolves its path when it is built, on the submitting thread. Deferring that to a worker would let the meaning of a relative path change between submission and execution, because the process current directory is shared mutable state that nothing in this crate controls. Resolving early also separates the two concerns cleanly: string resolution happens here, and the privileged open happens later under the captured token.
§Two path families
A \\?\ path is verbatim: Win32 disables path parsing for it, so the crate
stores it code unit for code unit. It is checked for full qualification –
the one property the prefix promises and a caller can get wrong – and
otherwise left alone. Trailing separators and ./.. components are
preserved, because in verbatim form they are literal name components rather
than syntax.
Everything else, including \\.\ device paths, goes through
GetFullPathNameW. Those forms are normalised by Win32, so resolving them
here produces exactly the path a later CreateFileW would have used.
§Why ordinary paths stop at MAX_PATH
Whether CreateFileW accepts a longer ordinary path depends on the host
executable’s longPathAware manifest and on system policy – neither of
which this crate controls, and both of which belong to whoever embeds it.
Letting them decide would make the same call succeed in one host and fail in
another. The crate instead draws the line itself: ordinary paths stop at
MAX_PATH, and a caller who wants a longer one says so explicitly with a
fully qualified \\?\ path, which has never depended on the manifest.
Structs§
- Path
Error - A synchronous failure while preparing a caller’s path.
- Prepared
Path - A path that has been through
prepare: the exact path a worker will open.
Enums§
- Path
Failure - Why a caller’s path could not be prepared.
Functions§
- prepare
- Validate and, where the contract calls for it, resolve a caller’s path.