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>
impl<B: Buffering, A: DataAccess> OpenedFile<B, A>
Sourcepub fn file_id(&self) -> Result<FileId>
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>
impl<B: Buffering, A: DataAccess> OpenedFile<B, A>
Sourcepub fn open_by_id(
volume_hint: impl Into<SharedHandle>,
identifier: impl Into<FileIdentifier>,
options: ByIdOptions<A>,
) -> Result<Self>
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.
Sourcepub fn request_by_id(
volume_hint: impl Into<SharedHandle>,
identifier: impl Into<FileIdentifier>,
options: ByIdOptions<A>,
) -> ByIdRequest<B, A>
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>
impl<B: Buffering, A: DataAccess> OpenedFile<B, A>
Sourcepub fn reopen(
original: impl Into<SharedHandle>,
options: ReopenOptions<A>,
) -> Result<Self>
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.
Sourcepub fn request_reopen(
original: impl Into<SharedHandle>,
options: ReopenOptions<A>,
) -> ReopenRequest<B, A>
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>
impl<B: Buffering, A: DataAccess> OpenedFile<B, A>
Sourcepub fn open(path: Wtf16String, options: FileOptions<A>) -> Result<Self>
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
Sourcepub fn request(
path: Wtf16String,
options: FileOptions<A>,
) -> Result<OpenRequest<B, A>>
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.
Sourcepub fn handle(&self) -> &SharedHandle
pub fn handle(&self) -> &SharedHandle
The file’s handle, owned and shared.
Source§impl<A: DataAccess> OpenedFile<Unbuffered, A>
impl<A: DataAccess> OpenedFile<Unbuffered, A>
Sourcepub fn with_sector_size(self, sector_size: u32) -> Result<Self, GeometryError>
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.