pub struct QueryFileInformation { /* private fields */ }Expand description
An owned, marshalable parameter set for GetFileInformationByHandleEx.
§Example
use std::fs;
use windows_namespace_request_sys::query::{FileInformationClass, QueryFileInformation};
let path = std::env::temp_dir().join(format!("wnrs-q-{}.tmp", std::process::id()));
fs::write(&path, b"example")?;
let file = fs::File::open(&path)?;
let request = QueryFileInformation::new(file, FileInformationClass::BASIC).with_capacity(256);
// The whole buffer comes back: the call reports no written length, so the
// consumer bounds its own reads rather than trusting a count we invented.
let bytes = request.perform()?;
assert_eq!(bytes.len(), 256);
assert_eq!(bytes.as_ptr() as usize % 8, 0);Implementations§
Source§impl QueryFileInformation
impl QueryFileInformation
Sourcepub const DEFAULT_CAPACITY: usize
pub const DEFAULT_CAPACITY: usize
The capacity a request starts with.
Large enough for any of the fixed-size classes and for a useful batch of directory entries. A caller enumerating a large directory will want more and should say so; this is a starting point, not a recommendation.
Sourcepub fn new(handle: impl Into<SharedHandle>, class: FileInformationClass) -> Self
pub fn new(handle: impl Into<SharedHandle>, class: FileInformationClass) -> Self
Begins a request against handle for class, holding handle as one more holder of it.
Sourcepub fn with_capacity(self, capacity: usize) -> Self
pub fn with_capacity(self, capacity: usize) -> Self
Sets the buffer size the query is given.
For a fixed-size class this must be at least the size of that class’s
structure, and Windows reports ERROR_BAD_LENGTH if it is not. For a
directory class it bounds how many entries one call can return, and a
buffer too small for even one entry fails with ERROR_MORE_DATA –
neither is pre-empted here.
Sourcepub fn handle(&self) -> &SharedHandle
pub fn handle(&self) -> &SharedHandle
The handle being queried, shared with its other holders.
Sourcepub fn class(&self) -> FileInformationClass
pub fn class(&self) -> FileInformationClass
The information class this request asks for.
Sourcepub fn perform(&self) -> Outcome<AlignedBuf>
pub fn perform(&self) -> Outcome<AlignedBuf>
Performs the query on the calling thread.
Returns the whole buffer, 8-byte aligned. The call reports no written length – a batch is walked by its own next-entry offsets – so nothing here invents a byte count it cannot know.
§Errors
Returns the raw Win32 code, unaltered. ERROR_NO_MORE_FILES ends a
directory enumeration and ERROR_MORE_DATA means the buffer held no
complete entry; both are the caller’s to interpret.
The one code the call did not produce is ERROR_NOT_ENOUGH_MEMORY, returned when the
buffer for the capacity this query was built with cannot be allocated – too large for
the machine, or refused by the allocator. The call was not made, and a smaller capacity
can be tried.
Sourcepub fn perform_into(
&self,
buffer: &mut AlignedBuf,
) -> Result<(), PerformIntoError>
pub fn perform_into( &self, buffer: &mut AlignedBuf, ) -> Result<(), PerformIntoError>
Performs the query on the calling thread, into a buffer the caller owns and keeps.
For a consumer that reads batch after batch: one buffer serves every call, and nothing is
allocated here. The buffer’s length is the size the call is given, and this request’s
capacity is not used.
§What is asked of the buffer
Its address is refused, before the call, when the class’s structure must be aligned and
the address is not. The GetFileInformationByHandleEx page (ms.date 2018-12-05) gives
each class’s lpFileInformation type, and three of those structures’ pages say the
structure “must be aligned on a” “(8-byte) boundary”: FILE_STREAM_INFO (for
FileStreamInfo), FILE_ID_BOTH_DIR_INFO (FileIdBothDirectoryInfo and its restart form)
and FILE_FULL_DIR_INFO (FileFullDirectoryInfo and its restart form). For those five
classes a buffer whose address is not on an 8-byte boundary is
PerformIntoError::Misaligned and the call is not made. It is the address that is
checked, since that is what the pages constrain: a buffer stated at 8 or more
(AlignedBuf::align) is never refused, and one stated at less is refused only where it
actually lies off the boundary.
For every other class nothing is refused. The FILE_ID_EXTD_DIR_INFO page, for the two
classes this crate names, states no alignment; those classes were measured failing with
ERROR_NOACCESS on a misaligned buffer, which is not made a check, and is why
perform allocates at 8.
A buffer longer than a DWORD can count is given as u32::MAX bytes, its first that many,
as perform gives an over-large capacity.
§What the buffer holds afterwards
What the call wrote. The buffer is not cleared first, so bytes the call does not write keep
what they held – unlike perform’s buffer, which starts zeroed. A batch is walked by its
own next-entry offsets, so a consumer reads only what the call wrote. After a failure the
contents are whatever the call left; the page does not say.
§Errors
PerformIntoError::Misaligned, with no OS code, for a buffer refused as above. Otherwise
PerformIntoError::Win32 with the raw code, unaltered, as perform
returns it. With no allocation, the out-of-memory report perform can make does not arise.
§Example
use windows_namespace_request_sys::AlignedBuf;
use windows_namespace_request_sys::query::{
FileInformationClass, PerformIntoError, QueryFileInformation,
};
use windows_sys::Win32::Foundation::ERROR_NO_MORE_FILES;
use windows_sys::Win32::Storage::FileSystem::FILE_FLAG_BACKUP_SEMANTICS;
use std::os::windows::fs::OpenOptionsExt;
let path = std::env::temp_dir().join(format!("wnrs-into-{}", std::process::id()));
std::fs::create_dir_all(&path)?;
std::fs::write(path.join("a.t"), b"a")?;
let directory = std::fs::OpenOptions::new()
.read(true)
.custom_flags(FILE_FLAG_BACKUP_SEMANTICS)
.open(&path)?;
let restart = QueryFileInformation::new(
directory.try_clone()?,
FileInformationClass::ID_EXTD_DIRECTORY_RESTART,
);
let next = QueryFileInformation::new(directory, FileInformationClass::ID_EXTD_DIRECTORY);
// One buffer, allocated once, for every batch.
let mut buffer = AlignedBuf::zeroed(64 * 1024, 8)?;
restart.perform_into(&mut buffer)?;
let mut batches = 1;
loop {
match next.perform_into(&mut buffer) {
Ok(()) => batches += 1,
Err(PerformIntoError::Win32(error)) if error.code() == ERROR_NO_MORE_FILES => break,
Err(error) => return Err(error.into()),
}
}
assert!(batches >= 1);