Skip to main content

QueryFileInformation

Struct QueryFileInformation 

Source
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

Source

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.

Source

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.

Source

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.

Source

pub fn handle(&self) -> &SharedHandle

The handle being queried, shared with its other holders.

Source

pub fn class(&self) -> FileInformationClass

The information class this request asks for.

Source

pub fn capacity(&self) -> usize

The buffer size the query will be given.

Source

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.

Source

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);

Trait Implementations§

Source§

impl Clone for QueryFileInformation

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for QueryFileInformation

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Request for QueryFileInformation

Source§

type Error = Win32Error

How performing it can fail. Read more
Source§

type Output = AlignedBuf

What performing the request produces.
Source§

fn perform(&self) -> Outcome<AlignedBuf>

Performs the request on the calling thread. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.