Skip to main content

OpenedFile

Struct OpenedFile 

Source
pub struct OpenedFile<B: Buffering = Cached, A: DataAccess = ReadWrite> { /* private fields */ }
Expand description

A file this crate opened, in buffering mode B and with data access A: a SharedHandle and what is known of it because of how it was opened. Cloning shares the one handle.

It is what a Win32FileTarget is made from, and the only thing it can be made from; the module documentation says why. A target needs a data right, so a file opened with NoData cannot be made into one.

A consumer that needs the stronger warranty says so in its signature, and a cached file cannot be passed:

ⓘ
use win_durable_ioring::Wtf16String;
use win_durable_ioring::windows_backend::{Cached, FileOptions, OpenedFile, Unbuffered};

fn needs_an_unbuffered_file(_: OpenedFile<Unbuffered>) {}

let options = FileOptions::new().read().write();
let name = Wtf16String::from_os_str("a-file".as_ref());
let cached = OpenedFile::<Cached>::open(name, options).unwrap();
needs_an_unbuffered_file(cached);

Nor can one opened for reading only be given where reading and writing are asked for:

ⓘ
use win_durable_ioring::Wtf16String;
use win_durable_ioring::windows_backend::{Cached, FileOptions, OpenedFile, ReadWrite};

fn needs_both(_: OpenedFile<Cached, ReadWrite>) {}

let name = Wtf16String::from_os_str("a-file".as_ref());
let read_only = OpenedFile::<Cached, _>::open(name, FileOptions::new().read()).unwrap();
needs_both(read_only);

The data access is a type parameter after the buffering mode, and a parameter written in a path takes its default, ReadWrite, when it is left off, so a file opened with other options names it or leaves it to be inferred with _: OpenedFile::<Cached, _>::open(path, options).

Implementations§

Source§

impl<B: Buffering, A: DataAccess> OpenedFile<B, A>

Source

pub fn file_id(&self) -> Result<FileId>

The identity of the file, read through its handle on the calling thread, as FileId::of reads it. Any data access reads it, NoData included.

§Errors

Those of FileId::of.

Source§

impl<B: Buffering, A: DataAccess> OpenedFile<B, A>

Source

pub fn open_by_id( volume_hint: impl Into<SharedHandle>, identifier: impl Into<FileIdentifier>, options: ByIdOptions<A>, ) -> Result<Self>

Open the file identifier names on the volume volume_hint is on, as options say, in buffering mode B: request_by_id and then perform, one after the other on this thread.

use win_durable_ioring::windows_backend::{ByIdOptions, Cached, FileOptions, OpenedFile};
use win_durable_ioring::Wtf16String;

let path = std::env::temp_dir().join(format!("by-id-doc-{}.tmp", std::process::id()));
std::fs::write(&path, b"x")?;
let name = Wtf16String::from_os_str(path.as_os_str());
let file = OpenedFile::<Cached, _>::open(name, FileOptions::new().read())?;

// Any handle on the volume is a hint; here, the file's own.
let again = OpenedFile::<Cached, _>::open_by_id(
    file.handle().clone(),
    file.file_id()?,
    ByIdOptions::new().read(),
)?;
assert_eq!(again.file_id()?, file.file_id()?);

An identifier can name a directory, and it is opened. FILE_FLAG_BACKUP_SEMANTICS, which the page says a directory needs, is not in v1, and an open by identifier was observed to reach a directory without it. It is not refused: a target made from it faults every read and write with the kernel’s error, and a write that faulted is covered by no durability report, so the commits it completes vouch for nothing. On a directory the data rights are FILE_LIST_DIRECTORY and FILE_ADD_FILE, the same bits, and that is what the lent handle carries. What a flush of a directory makes durable no page says. The design notes’ DI-D-72 has the measurement.

§Errors

Those of perform.

Source

pub fn request_by_id( volume_hint: impl Into<SharedHandle>, identifier: impl Into<FileIdentifier>, options: ByIdOptions<A>, ) -> ByIdRequest<B, A>

The request to open the file identifier names on the volume volume_hint is on, built here and made wherever the caller chooses with perform. Nothing is opened and nothing blocks. The hint is held, shared, and not duplicated.

Source§

impl<B: Buffering, A: DataAccess> OpenedFile<B, A>

Source

pub fn reopen( original: impl Into<SharedHandle>, options: ReopenOptions<A>, ) -> Result<Self>

Reopen what original names, in buffering mode B and as options say: request_reopen and then perform, one after the other on this thread.

The original is any handle: an OpenedFile’s, passed as file.handle().clone(), or one opened elsewhere. The result is a new file of its own type, with the alignment of B and not the original’s: an unbuffered file starts at Unbuffered::DEFAULT_SECTOR_SIZE again, whatever sector size the original was given.

use win_durable_ioring::windows_backend::{
    Cached, FileOptions, OpenedFile, ReadOnly, ReopenOptions, Unbuffered,
};
use win_durable_ioring::Wtf16String;

let path = std::env::temp_dir().join(format!("reopen-doc-{}.tmp", std::process::id()));
std::fs::write(&path, [0u8; 4096])?;
let name = Wtf16String::from_os_str(path.as_os_str());
let writer = OpenedFile::<Cached, _>::open(name, FileOptions::new().read().write())?;

// A read-only, unbuffered handle beside the writer, for a scrubber.
let scrubber = OpenedFile::<Unbuffered, ReadOnly>::reopen(
    writer.handle().clone(),
    ReopenOptions::new().read(),
)?;
assert_eq!(scrubber.file_id()?, writer.file_id()?);
§Errors

Those of perform.

Source

pub fn request_reopen( original: impl Into<SharedHandle>, options: ReopenOptions<A>, ) -> ReopenRequest<B, A>

The request to reopen what original names, built here and made wherever the caller chooses with perform. Nothing is opened and nothing blocks. The original is held, shared, and not duplicated.

Source§

impl<B: Buffering, A: DataAccess> OpenedFile<B, A>

Source

pub fn open(path: Wtf16String, options: FileOptions<A>) -> Result<Self>

Open path as options says, in buffering mode B: request and then perform, one after the other on this thread. The handle has the data access the options were given, which is its type A.

This blocks for as long as CreateFileW does, which on a network path or an opportunistic lock break can be a long time. A caller that cannot block builds the request here and performs it on a thread it chooses.

Where the name leads is the caller’s to know. A name can be redirected to a device by a reparse point in an intermediate directory, which FILE_FLAG_OPEN_REPARSE_POINT does not stop (it applies to the final component), or by an object-manager link such as a drive letter, which is resolved before a file system sees the name, so no reparse flag applies to it. An open of a serial port’s name was observed not to return. This crate does not inspect the name, refuse it, bound the open or cancel it: the open is CreateFileW‘s, and CancelSynchronousIo is documented as a use and not as a guarantee, and targets a thread and not a call. The design notes’ DI-D-67 has the sources and the measurement.

§Errors

Those of request and of perform.

Source

pub fn request( path: Wtf16String, options: FileOptions<A>, ) -> Result<OpenRequest<B, A>>

The request to open path as options says, in buffering mode B, built here and made wherever the caller chooses with perform. Nothing is opened, and nothing blocks.

The path is handed to Win32 as it was given: this crate does not lengthen it, shorten it or refuse it, so a path longer than MAX_PATH without a verbatim prefix, and an empty one, are what CreateFileW makes of them. A relative path is fixed to the current directory as it is when this is called, so the request names the same file wherever and whenever it is performed. Convert a Path with Wtf16String::from_os_str, which loses nothing.

§Errors

io::ErrorKind::InvalidInput if path has an interior NUL, and the error of GetCurrentDirectoryW if the current directory had to be read and could not be, both before anything is touched.

Source

pub fn handle(&self) -> &SharedHandle

The file’s handle, owned and shared.

Source

pub fn geometry(&self) -> Geometry

The alignment its operations need.

Source§

impl<A: DataAccess> OpenedFile<Unbuffered, A>

Source

pub fn with_sector_size(self, sector_size: u32) -> Result<Self, GeometryError>

State the device’s sector size, for a device whose sectors are smaller than Unbuffered::DEFAULT_SECTOR_SIZE. A size that is too small for the device is refused by the device on the first transfer that needs more, as an error on that operation’s completion, never as silent damage.

§Errors

GeometryError if sector_size is not a power of two.

Trait Implementations§

Source§

impl<B: Buffering, A: DataAccess> AsHandle for OpenedFile<B, A>

Source§

fn as_handle(&self) -> BorrowedHandle<'_>

Borrows the handle. Read more
Source§

impl<B: Buffering, A: DataAccess> AsRawHandle for OpenedFile<B, A>

Source§

fn as_raw_handle(&self) -> RawHandle

Extracts the raw handle. Read more
Source§

impl<B: Clone + Buffering, A: Clone + DataAccess> Clone for OpenedFile<B, A>

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<B: Debug + Buffering, A: Debug + DataAccess> Debug for OpenedFile<B, A>

Source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<B, A> Freeze for OpenedFile<B, A>

§

impl<B, A> RefUnwindSafe for OpenedFile<B, A>

§

impl<B, A> Send for OpenedFile<B, A>

§

impl<B, A> Sync for OpenedFile<B, A>

§

impl<B, A> Unpin for OpenedFile<B, A>

§

impl<B, A> UnsafeUnpin for OpenedFile<B, A>

§

impl<B, A> UnwindSafe for OpenedFile<B, A>

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.