Expand description
Owned, marshalable parameter sets for synchronous Win32 namespace calls.
Win32’s namespace and metadata surface – opening, querying, closing – is synchronous-only. A call that blocks on a dead network path blocks the thread that made it, and no overlapped form exists. This crate makes such a call capturable as a value: an owned parameter set built on one thread and executed faithfully on another.
It schedules nothing. It is the catalogue-plus-faithful-execution layer, testable with no ring, no pool, and no async anywhere near it.
§What a request is, and is not
A request carries call parameters. It does not carry the impersonation
token or any other thread-scoped state the call runs under – that belongs to
windows-thread-ambient-sys, which this crate does not depend on.
The two are siblings rather than a stack: a request can be executed with no
captured context at all, and a context is useful to work that never opens a
file. Whoever owns both pairs them at the submission site.
A request also chooses no delivery model. An opened handle comes back
plain and unassociated, because associating it with a completion port
irreversibly forecloses IoRing use, and that choice belongs to a layer that
knows the handle’s destination.
§Faithful means unaltered
An entry reports the raw Win32 outcome. ERROR_FILE_NOT_FOUND means a
missing directory from an open, an empty directory from a first query, and a
genuine failure from a later one; only a consumer can tell those apart, so
nothing here normalises or reclassifies.
The code is also snapshotted before any cleanup can overwrite it, because
GetLastError is volatile thread state that a Drop or a buffer release
will happily clobber. That guarantee is a primitive rather than a rule each
entry remembers: see outcome.
§A path is copied; a handle is duplicated
Several entries take a handle rather than a path, and a request owns a duplicate of any handle it names. The distinction matters and is easy to get backwards: a path is a value and is copied, while a handle is a reference to a kernel object, so duplicating it shares that object rather than cloning it.
A request is therefore self-contained with respect to lifetime – it cannot be left pointing at a handle its originator closed – and is not isolated with respect to state. Measured: a duplicated handle continues the source’s directory enumeration rather than starting its own, while closing the duplicate leaves the source usable and single-shot metadata queries disturb nothing. An independent traversal needs a fresh open, not a duplicate.
§Scope
One entry per Win32 call; a consumer needing two makes two requests and
sequences them itself. The round-one entry list is audited from three real
consumers rather than chosen by taste, and its omissions are deliberate and
written down. See DESIGN-NOTES.md in the crate root.
§Example
Capture the parameters on the submitting thread, where a failure is still the caller’s to see and the process current directory still means what the caller thinks it means, then use them on a worker that saw none of it:
use std::fs;
use std::os::windows::io::AsHandle;
use std::thread;
use windows_namespace_request_sys::{CapturedHandle, prepare};
use wtf_string::Wtf16String;
let path = std::env::temp_dir().join(format!("wnrs-doc-{}.tmp", std::process::id()));
fs::write(&path, b"example")?;
// Resolved here, not on the worker: the process current directory is
// shared mutable state that any thread can change in between.
let text = path.to_str().expect("a temporary path is valid UTF-8");
let prepared = prepare(&Wtf16String::from(text))?;
assert_eq!(prepared.as_wtf16().to_string_lossy(), text);
// An owned duplicate, so the captured parameters cannot be left pointing
// at a handle the caller has since closed.
let file = fs::File::open(&path)?;
let captured = CapturedHandle::capture(file.as_handle())?;
drop(file);
let length = thread::spawn(move || {
fs::File::from(captured.into_owned_handle()).metadata().map(|m| m.len())
})
.join()
.expect("the worker did not panic")?;
assert_eq!(length, b"example".len() as u64);Re-exports§
pub use buffer::AlignedBuffer;pub use close::CloseFn;pub use close::CloseRequest;pub use file_info::QueryFileInformationByHandle;pub use final_path::FinalPathError;pub use final_path::FinalPathFlags;pub use final_path::QueryFinalPath;pub use full_path::FullPathError;pub use full_path::ResolveFullPath;pub use handle::CapturedHandle;pub use handle::HandleCaptureError;pub use handle::HandleCaptureFailure;pub use open::OpenFile;pub use open_by_id::FileIdentifier;pub use open_by_id::OpenFileByIdentifier;pub use outcome::Outcome;pub use outcome::Win32Error;pub use path::PathError;pub use path::PathFailure;pub use path::PreparedPath;pub use path::prepare;pub use query::FileInformationClass;pub use query::QueryFileInformation;pub use request::ConsumingRequest;pub use request::Request;pub use security::AclState;pub use security::SecurityAttributes;pub use security::SecurityCaptureError;pub use security::SecurityCaptureFailure;pub use security::SecurityDescriptor;pub use volume::QueryVolumeInformation;pub use volume::VolumeInformation;pub use watch::ChangeNotification;pub use watch::NotifyFilter;pub use watch::WatchDirectory;
Modules§
- buffer
- An owned byte buffer with a guaranteed alignment.
- close
- The close entries.
- file_
info - The
GetFileInformationByHandleentry. - final_
path - The
GetFinalPathNameByHandleWentry. - full_
path - The
GetFullPathNameWentry. - handle
- Owned handle references.
- open
- The
CreateFileWentry. - open_
by_ id - The
OpenFileByIdentry. - outcome
- The faithful-execution contract every entry follows.
- path
- The request path contract: what a caller may name, and what gets stored.
- query
- The
GetFileInformationByHandleExentry. - request
- The seam: what every entry has in common, as a trait.
- security
- Owned capture of a caller’s
lpSecurityAttributes. - volume
- The
GetVolumeInformationByHandleWentry. - watch
- The
FindFirstChangeNotificationWentry.