imago/storage/
mod.rs

1//! Helper functionality to access storage.
2//!
3//! While not the primary purpose of this crate, to open VM images, we need to be able to access
4//! different kinds of storage objects.  Such objects are abstracted behind the `Storage` trait.
5
6pub mod drivers;
7pub mod ext;
8
9use crate::io_buffers::{IoVector, IoVectorMut};
10use drivers::CommonStorageHelper;
11use std::any::Any;
12use std::fmt::{Debug, Display};
13use std::future::Future;
14use std::io;
15use std::path::{Path, PathBuf};
16use std::pin::Pin;
17use std::sync::Arc;
18
19/// Parameters from which a storage object can be constructed.
20#[derive(Clone, Debug, Default)]
21pub struct StorageOpenOptions {
22    /// Filename to open.
23    pub(crate) filename: Option<PathBuf>,
24
25    /// Whether the object should be opened as writable or read-only.
26    pub(crate) writable: bool,
27
28    /// Whether to bypass the host page cache (if applicable).
29    pub(crate) direct: bool,
30}
31
32/// Parameters from which a new storage object can be created.
33#[derive(Clone, Debug)]
34pub struct StorageCreateOptions {
35    /// Options to open the image, includes the filename.
36    ///
37    /// `writable` should be ignored, created files should always be opened as writable.
38    pub(crate) open_opts: StorageOpenOptions,
39
40    /// Initial size.
41    pub(crate) size: u64,
42
43    /// Preallocation mode.
44    pub(crate) prealloc_mode: PreallocateMode,
45
46    /// Whether to overwrite an existing file.
47    pub(crate) overwrite: bool,
48}
49
50/// Implementation for storage objects.
51pub trait Storage: Debug + Display + Send + Sized + Sync {
52    /// Open a storage object.
53    ///
54    /// Different storage implementations may require different options.
55    #[allow(async_fn_in_trait)] // No need for Send
56    async fn open(_opts: StorageOpenOptions) -> io::Result<Self> {
57        Err(io::Error::new(
58            io::ErrorKind::Unsupported,
59            format!(
60                "Cannot open storage objects of type {}",
61                std::any::type_name::<Self>()
62            ),
63        ))
64    }
65
66    /// Synchronous wrapper around [`Storage::open()`].
67    #[cfg(feature = "sync-wrappers")]
68    fn open_sync(opts: StorageOpenOptions) -> io::Result<Self> {
69        tokio::runtime::Builder::new_current_thread()
70            .build()?
71            .block_on(Self::open(opts))
72    }
73
74    /// Create a storage object and open it.
75    ///
76    /// Different storage implementations may require different options.
77    ///
78    /// Note that newly created storage objects are always opened as writable.
79    #[allow(async_fn_in_trait)] // No need for Send
80    async fn create_open(_opts: StorageCreateOptions) -> io::Result<Self> {
81        Err(io::Error::new(
82            io::ErrorKind::Unsupported,
83            format!(
84                "Cannot create storage objects of type {}",
85                std::any::type_name::<Self>()
86            ),
87        ))
88    }
89
90    /// Create a storage object.
91    ///
92    /// Different storage implementations may require different options.
93    #[allow(async_fn_in_trait)] // No need for Send
94    async fn create(opts: StorageCreateOptions) -> io::Result<()> {
95        Self::create_open(opts).await?;
96        Ok(())
97    }
98
99    /// Minimum required alignment for memory buffers.
100    fn mem_align(&self) -> usize {
101        1
102    }
103
104    /// Minimum required alignment for offsets and lengths.
105    fn req_align(&self) -> usize {
106        1
107    }
108
109    /// Minimum required alignment for zero writes.
110    fn zero_align(&self) -> usize {
111        1
112    }
113
114    /// Minimum required alignment for effective discards.
115    fn discard_align(&self) -> usize {
116        1
117    }
118
119    /// Storage object length.
120    fn size(&self) -> io::Result<u64>;
121
122    /// Resolve the given path relative to this storage object.
123    ///
124    /// `relative` need not really be a relative path; it is up to the storage driver to check
125    /// whether it is an absolute path that does not need to be changed, or a relative path that
126    /// needs to be resolved.
127    ///
128    /// Must not return a relative path.
129    ///
130    /// The returned `PathBuf` should be usable with `StorageOpenOptions::filename()`.
131    fn resolve_relative_path<P: AsRef<Path>>(&self, _relative: P) -> io::Result<PathBuf> {
132        Err(io::ErrorKind::Unsupported.into())
133    }
134
135    /// Return a filename, if possible.
136    ///
137    /// Using the filename for [`StorageOpenOptions::filename()`] should open the same storage
138    /// object.
139    fn get_filename(&self) -> Option<PathBuf> {
140        None
141    }
142
143    /// Read data at `offset` into `bufv`.
144    ///
145    /// Reads until `bufv` is filled completely, i.e. will not do short reads.  When reaching the
146    /// end of file, the rest of `bufv` is filled with 0.
147    ///
148    /// # Safety
149    /// This is a pure read from storage.  The request must be fully aligned to
150    /// [`Self::mem_align()`] and [`Self::req_align()`], and safeguards we want to implement for
151    /// safe concurrent access may not be available.
152    ///
153    /// Use [`StorageExt::readv()`](crate::StorageExt::readv()) instead.
154    #[allow(async_fn_in_trait)] // No need for Send
155    async unsafe fn pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()>;
156
157    /// Write data from `bufv` to `offset`.
158    ///
159    /// Writes all data from `bufv`, i.e. will not do short writes.  When reaching the end of file,
160    /// grow it as necessary so that the new end of file will be at `offset + bufv.len()`.
161    ///
162    /// If growing is not possible, writes beyond the end of file (even if only partially) should
163    /// fail.
164    ///
165    /// # Safety
166    /// This is a pure write to storage.  The request must be fully aligned to
167    /// [`Self::mem_align()`] and [`Self::req_align()`], and safeguards we want to implement for
168    /// safe concurrent access may not be available.
169    ///
170    /// Use [`StorageExt::writev()`](crate::StorageExt::writev()) instead.
171    #[allow(async_fn_in_trait)] // No need for Send
172    async unsafe fn pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()>;
173
174    /// Ensure the given range reads back as zeroes.
175    ///
176    /// The default implementation writes actual zeroes as data, which is inefficient.  Storage
177    /// drivers should override it with a more efficient implementation.
178    ///
179    /// # Safety
180    /// This is a pure write to storage.  The request must be fully aligned to
181    /// [`Self::zero_align()`], and safeguards we want to implement for safe concurrent access may
182    /// not be available.
183    ///
184    /// Use [`StorageExt::write_zeroes()`](crate::StorageExt::write_zeroes()) instead.
185    #[allow(async_fn_in_trait)] // No need for Send
186    async unsafe fn pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
187        ext::write_full_zeroes(self, offset, length).await
188    }
189
190    /// Discard the given range, with undefined contents when read back.
191    ///
192    /// Tell the storage layer this range is no longer needed and need not be backed by actual
193    /// storage.  When read back, the data read will be undefined, i.e. not necessarily zeroes.
194    ///
195    /// No-op implementations therefore explicitly fulfill the interface contract.
196    ///
197    /// # Safety
198    /// This is a pure write to storage.  The request must be fully aligned to
199    /// [`Self::discard_align()`], and safeguards we want to implement for safe concurrent access
200    /// may not be available.
201    ///
202    /// Use [`StorageExt::discard()`](crate::StorageExt::discard()) instead.
203    #[allow(async_fn_in_trait)] // No need for Send
204    async unsafe fn pure_discard(&self, _offset: u64, _length: u64) -> io::Result<()> {
205        Ok(())
206    }
207
208    /// Flush internal buffers.
209    ///
210    /// Does not necessarily sync those buffers to disk.  When using `flush()`, consider whether
211    /// you want to call `sync()` afterwards.
212    ///
213    /// Note that this will not drop the buffers, so they may still be used to serve later
214    /// accesses.  Use [`Storage::invalidate_cache()`] to drop all buffers.
215    #[allow(async_fn_in_trait)] // No need for Send
216    async fn flush(&self) -> io::Result<()>;
217
218    /// Sync data already written to the storage hardware.
219    ///
220    /// This does not necessarily include flushing internal buffers, i.e. `flush`.  When using
221    /// `sync()`, consider whether you want to call `flush()` before it.
222    #[allow(async_fn_in_trait)] // No need for Send
223    async fn sync(&self) -> io::Result<()>;
224
225    /// Drop internal buffers.
226    ///
227    /// This drops all internal buffers, but does not flush them!  All cached data is reloaded on
228    /// subsequent accesses.
229    ///
230    /// # Safety
231    /// Not flushing internal buffers may cause corruption.  You must ensure the underlying storage
232    /// state is consistent.
233    #[allow(async_fn_in_trait)] // No need for Send
234    async unsafe fn invalidate_cache(&self) -> io::Result<()>;
235
236    /// Return the storage helper object (used by the [`StorageExt`](crate::StorageExt)
237    /// implementation).
238    fn get_storage_helper(&self) -> &CommonStorageHelper;
239
240    /// Resize to the given size.
241    ///
242    /// Set the size of this storage object to `new_size`.  If `new_size` is smaller than the
243    /// current size, ignore `prealloc_mode` and discard the data after `new_size`.
244    ///
245    /// If `new_size` is larger than the current size, `prealloc_mode` determines whether and how
246    /// the new range should be allocated; it is possible some preallocation modes are not
247    /// supported, in which case an [`std::io::ErrorKind::Unsupported`] is returned.
248    #[allow(async_fn_in_trait)] // No need for Send
249    async fn resize(&self, _new_size: u64, _prealloc_mode: PreallocateMode) -> io::Result<()> {
250        Err(io::ErrorKind::Unsupported.into())
251    }
252}
253
254/// Allow dynamic use of storage objects (i.e. is object safe).
255///
256/// When using normal `Storage` objects, they must all be of the same type within a single disk
257/// image chain.  For example, every storage object underneath a `FormatAccess<StdFile>` object
258/// must be of type `StdFile`.
259///
260/// `DynStorage` allows the use of `Box<dyn DynStorage>`, which implements `Storage`, to allow
261/// mixed storage object types.  Therefore, a `FormatAccess<Box<dyn DynStorage>>` allows e.g. the
262/// use of both `Box<StdFile>` and `Box<Null>` storage objects together.  (`Arc` instead of `Box`
263/// works, too.)
264///
265/// Async functions in `DynStorage` return boxed futures (`Pin<Box<dyn Future>>`), which makes them
266/// slighly less efficient than async functions in `Storage`, hence the distinction.
267pub trait DynStorage: Any + Debug + Display + Send + Sync {
268    /// Wrapper around [`Storage::mem_align()`].
269    fn dyn_mem_align(&self) -> usize;
270
271    /// Wrapper around [`Storage::req_align()`].
272    fn dyn_req_align(&self) -> usize;
273
274    /// Wrapper around [`Storage::zero_align()`].
275    fn dyn_zero_align(&self) -> usize;
276
277    /// Wrapper around [`Storage::discard_align()`].
278    fn dyn_discard_align(&self) -> usize;
279
280    /// Wrapper around [`Storage::size()`].
281    fn dyn_size(&self) -> io::Result<u64>;
282
283    /// Wrapper around [`Storage::resolve_relative_path()`].
284    fn dyn_resolve_relative_path(&self, relative: &Path) -> io::Result<PathBuf>;
285
286    /// Wrapper around [`Storage::get_filename()`]
287    fn dyn_get_filename(&self) -> Option<PathBuf>;
288
289    /// Object-safe wrapper around [`Storage::pure_readv()`].
290    ///
291    /// # Safety
292    /// Same considerations are for [`Storage::pure_readv()`] apply.
293    unsafe fn dyn_pure_readv<'a>(
294        &'a self,
295        bufv: IoVectorMut<'a>,
296        offset: u64,
297    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + 'a>>;
298
299    /// Object-safe wrapper around [`Storage::pure_writev()`].
300    ///
301    /// # Safety
302    /// Same considerations are for [`Storage::pure_writev()`] apply.
303    unsafe fn dyn_pure_writev<'a>(
304        &'a self,
305        bufv: IoVector<'a>,
306        offset: u64,
307    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + 'a>>;
308
309    /// Object-safe wrapper around [`Storage::pure_write_zeroes()`].
310    ///
311    /// # Safety
312    /// Same considerations are for [`Storage::pure_write_zeroes()`] apply.
313    unsafe fn dyn_pure_write_zeroes(
314        &self,
315        offset: u64,
316        length: u64,
317    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
318
319    /// Object-safe wrapper around [`Storage::pure_discard()`].
320    ///
321    /// # Safety
322    /// Same considerations are for [`Storage::pure_discard()`] apply.
323    unsafe fn dyn_pure_discard(
324        &self,
325        offset: u64,
326        length: u64,
327    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
328
329    /// Object-safe wrapper around [`Storage::flush()`].
330    fn dyn_flush(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
331
332    /// Object-safe wrapper around [`Storage::sync()`].
333    fn dyn_sync(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
334
335    /// Object-safe wrapper around [`Storage::invalidate_cache()`].
336    ///
337    /// # Safety
338    /// Same considerations are for [`Storage::invalidate_cache()`] apply.
339    unsafe fn dyn_invalidate_cache(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
340
341    /// Wrapper around [`Storage::get_storage_helper()`].
342    fn dyn_get_storage_helper(&self) -> &CommonStorageHelper;
343
344    /// Wrapper around [`Storage::resize()`].
345    fn dyn_resize(
346        &self,
347        new_size: u64,
348        prealloc_mode: PreallocateMode,
349    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
350}
351
352/// Storage object preallocation modes.
353///
354/// When resizing or creating storage objects, this mode determines whether and how the new data
355/// range is to be preallocated.
356#[derive(Clone, Copy, Debug, Eq, PartialEq)]
357#[non_exhaustive]
358pub enum PreallocateMode {
359    /// No preallocation.
360    ///
361    /// Reading the new range may return random data.
362    None,
363
364    /// Ensure range reads as zeroes.
365    ///
366    /// Does not necessarily allocate data, but has to ensure the new range will read back as
367    /// zeroes.
368    Zero,
369
370    /// Extent preallocation.
371    ///
372    /// Do not write data, but ensure all new extents are allocated.
373    Allocate,
374
375    /// Full data preallocation.
376    ///
377    /// Write zeroes to the whole range.
378    WriteData,
379}
380
381impl<S: Storage> Storage for &S {
382    fn mem_align(&self) -> usize {
383        (*self).mem_align()
384    }
385
386    fn req_align(&self) -> usize {
387        (*self).req_align()
388    }
389
390    fn zero_align(&self) -> usize {
391        (*self).zero_align()
392    }
393
394    fn discard_align(&self) -> usize {
395        (*self).discard_align()
396    }
397
398    fn size(&self) -> io::Result<u64> {
399        (*self).size()
400    }
401
402    fn resolve_relative_path<P: AsRef<Path>>(&self, relative: P) -> io::Result<PathBuf> {
403        (*self).resolve_relative_path(relative)
404    }
405
406    fn get_filename(&self) -> Option<PathBuf> {
407        (*self).get_filename()
408    }
409
410    async unsafe fn pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
411        unsafe { (*self).pure_readv(bufv, offset).await }
412    }
413
414    async unsafe fn pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()> {
415        unsafe { (*self).pure_writev(bufv, offset).await }
416    }
417
418    async unsafe fn pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
419        unsafe { (*self).pure_write_zeroes(offset, length).await }
420    }
421
422    async unsafe fn pure_discard(&self, offset: u64, length: u64) -> io::Result<()> {
423        unsafe { (*self).pure_discard(offset, length).await }
424    }
425
426    async fn flush(&self) -> io::Result<()> {
427        (*self).flush().await
428    }
429
430    async fn sync(&self) -> io::Result<()> {
431        (*self).sync().await
432    }
433
434    async unsafe fn invalidate_cache(&self) -> io::Result<()> {
435        unsafe { (*self).invalidate_cache().await }
436    }
437
438    fn get_storage_helper(&self) -> &CommonStorageHelper {
439        (*self).get_storage_helper()
440    }
441
442    async fn resize(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()> {
443        (*self).resize(new_size, prealloc_mode).await
444    }
445}
446
447impl<S: Storage + 'static> DynStorage for S {
448    fn dyn_mem_align(&self) -> usize {
449        <S as Storage>::mem_align(self)
450    }
451
452    fn dyn_req_align(&self) -> usize {
453        <S as Storage>::req_align(self)
454    }
455
456    fn dyn_zero_align(&self) -> usize {
457        <S as Storage>::zero_align(self)
458    }
459
460    fn dyn_discard_align(&self) -> usize {
461        <S as Storage>::discard_align(self)
462    }
463
464    fn dyn_size(&self) -> io::Result<u64> {
465        <S as Storage>::size(self)
466    }
467
468    fn dyn_resolve_relative_path(&self, relative: &Path) -> io::Result<PathBuf> {
469        <S as Storage>::resolve_relative_path(self, relative)
470    }
471
472    fn dyn_get_filename(&self) -> Option<PathBuf> {
473        <S as Storage>::get_filename(self)
474    }
475
476    unsafe fn dyn_pure_readv<'a>(
477        &'a self,
478        bufv: IoVectorMut<'a>,
479        offset: u64,
480    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + 'a>> {
481        Box::pin(unsafe { <S as Storage>::pure_readv(self, bufv, offset) })
482    }
483
484    unsafe fn dyn_pure_writev<'a>(
485        &'a self,
486        bufv: IoVector<'a>,
487        offset: u64,
488    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + 'a>> {
489        Box::pin(unsafe { <S as Storage>::pure_writev(self, bufv, offset) })
490    }
491
492    unsafe fn dyn_pure_write_zeroes(
493        &self,
494        offset: u64,
495        length: u64,
496    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
497        Box::pin(unsafe { <S as Storage>::pure_write_zeroes(self, offset, length) })
498    }
499
500    unsafe fn dyn_pure_discard(
501        &self,
502        offset: u64,
503        length: u64,
504    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
505        Box::pin(unsafe { <S as Storage>::pure_discard(self, offset, length) })
506    }
507
508    fn dyn_flush(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
509        Box::pin(<S as Storage>::flush(self))
510    }
511
512    fn dyn_sync(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
513        Box::pin(<S as Storage>::sync(self))
514    }
515
516    unsafe fn dyn_invalidate_cache(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
517        Box::pin(unsafe { <S as Storage>::invalidate_cache(self) })
518    }
519
520    fn dyn_get_storage_helper(&self) -> &CommonStorageHelper {
521        <S as Storage>::get_storage_helper(self)
522    }
523
524    fn dyn_resize(
525        &self,
526        new_size: u64,
527        prealloc_mode: PreallocateMode,
528    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
529        Box::pin(<S as Storage>::resize(self, new_size, prealloc_mode))
530    }
531}
532
533impl Storage for Box<dyn DynStorage> {
534    async fn open(opts: StorageOpenOptions) -> io::Result<Self> {
535        // TODO: When we have more drivers, choose different defaults depending on the options
536        // given.  Right now, only `File` really supports being opened through options, so it is an
537        // obvious choice.
538        Ok(Box::new(crate::file::File::open(opts).await?))
539    }
540
541    async fn create_open(opts: StorageCreateOptions) -> io::Result<Self> {
542        // Same as `Self::open()`.
543        Ok(Box::new(crate::file::File::create_open(opts).await?))
544    }
545
546    fn mem_align(&self) -> usize {
547        self.as_ref().dyn_mem_align()
548    }
549
550    fn req_align(&self) -> usize {
551        self.as_ref().dyn_req_align()
552    }
553
554    fn zero_align(&self) -> usize {
555        self.as_ref().dyn_zero_align()
556    }
557
558    fn discard_align(&self) -> usize {
559        self.as_ref().dyn_discard_align()
560    }
561
562    fn size(&self) -> io::Result<u64> {
563        self.as_ref().dyn_size()
564    }
565
566    fn resolve_relative_path<P: AsRef<Path>>(&self, relative: P) -> io::Result<PathBuf> {
567        self.as_ref().dyn_resolve_relative_path(relative.as_ref())
568    }
569
570    fn get_filename(&self) -> Option<PathBuf> {
571        self.as_ref().dyn_get_filename()
572    }
573
574    async unsafe fn pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
575        unsafe { self.as_ref().dyn_pure_readv(bufv, offset).await }
576    }
577
578    async unsafe fn pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()> {
579        unsafe { self.as_ref().dyn_pure_writev(bufv, offset).await }
580    }
581
582    async unsafe fn pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
583        unsafe { self.as_ref().dyn_pure_write_zeroes(offset, length).await }
584    }
585
586    async unsafe fn pure_discard(&self, offset: u64, length: u64) -> io::Result<()> {
587        unsafe { self.as_ref().dyn_pure_discard(offset, length).await }
588    }
589
590    async fn flush(&self) -> io::Result<()> {
591        self.as_ref().dyn_flush().await
592    }
593
594    async fn sync(&self) -> io::Result<()> {
595        self.as_ref().dyn_sync().await
596    }
597
598    async unsafe fn invalidate_cache(&self) -> io::Result<()> {
599        unsafe { self.as_ref().dyn_invalidate_cache().await }
600    }
601
602    fn get_storage_helper(&self) -> &CommonStorageHelper {
603        self.as_ref().dyn_get_storage_helper()
604    }
605
606    async fn resize(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()> {
607        self.as_ref().dyn_resize(new_size, prealloc_mode).await
608    }
609}
610
611impl Storage for Arc<dyn DynStorage> {
612    async fn open(opts: StorageOpenOptions) -> io::Result<Self> {
613        Box::<dyn DynStorage>::open(opts).await.map(Into::into)
614    }
615
616    async fn create_open(opts: StorageCreateOptions) -> io::Result<Self> {
617        Box::<dyn DynStorage>::create_open(opts)
618            .await
619            .map(Into::into)
620    }
621
622    fn mem_align(&self) -> usize {
623        self.as_ref().dyn_mem_align()
624    }
625
626    fn req_align(&self) -> usize {
627        self.as_ref().dyn_req_align()
628    }
629
630    fn zero_align(&self) -> usize {
631        self.as_ref().dyn_zero_align()
632    }
633
634    fn discard_align(&self) -> usize {
635        self.as_ref().dyn_discard_align()
636    }
637
638    fn size(&self) -> io::Result<u64> {
639        self.as_ref().dyn_size()
640    }
641
642    fn resolve_relative_path<P: AsRef<Path>>(&self, relative: P) -> io::Result<PathBuf> {
643        self.as_ref().dyn_resolve_relative_path(relative.as_ref())
644    }
645
646    fn get_filename(&self) -> Option<PathBuf> {
647        self.as_ref().dyn_get_filename()
648    }
649
650    async unsafe fn pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
651        unsafe { self.as_ref().dyn_pure_readv(bufv, offset) }.await
652    }
653
654    async unsafe fn pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()> {
655        unsafe { self.as_ref().dyn_pure_writev(bufv, offset) }.await
656    }
657
658    async unsafe fn pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
659        unsafe { self.as_ref().dyn_pure_write_zeroes(offset, length) }.await
660    }
661
662    async unsafe fn pure_discard(&self, offset: u64, length: u64) -> io::Result<()> {
663        unsafe { self.as_ref().dyn_pure_discard(offset, length) }.await
664    }
665
666    async fn flush(&self) -> io::Result<()> {
667        self.as_ref().dyn_flush().await
668    }
669
670    async fn sync(&self) -> io::Result<()> {
671        self.as_ref().dyn_sync().await
672    }
673
674    async unsafe fn invalidate_cache(&self) -> io::Result<()> {
675        unsafe { self.as_ref().dyn_invalidate_cache().await }
676    }
677
678    fn get_storage_helper(&self) -> &CommonStorageHelper {
679        self.as_ref().dyn_get_storage_helper()
680    }
681
682    async fn resize(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()> {
683        self.as_ref().dyn_resize(new_size, prealloc_mode).await
684    }
685}
686
687impl StorageOpenOptions {
688    /// Create default options.
689    pub fn new() -> Self {
690        StorageOpenOptions::default()
691    }
692
693    /// Set a filename to open.
694    pub fn filename<P: AsRef<Path>>(mut self, filename: P) -> Self {
695        self.filename = Some(filename.as_ref().to_owned());
696        self
697    }
698
699    /// Whether the storage should be writable or not.
700    pub fn write(mut self, write: bool) -> Self {
701        self.writable = write;
702        self
703    }
704
705    /// Whether to bypass the host page cache (if applicable).
706    pub fn direct(mut self, direct: bool) -> Self {
707        self.direct = direct;
708        self
709    }
710
711    /// Get the set filename (if any).
712    pub fn get_filename(&self) -> Option<&Path> {
713        self.filename.as_deref()
714    }
715
716    /// Return the set writable state.
717    pub fn get_writable(&self) -> bool {
718        self.writable
719    }
720
721    /// Return the set direct state.
722    pub fn get_direct(&self) -> bool {
723        self.direct
724    }
725}
726
727impl StorageCreateOptions {
728    /// Create default options.
729    pub fn new() -> Self {
730        StorageCreateOptions::default()
731    }
732
733    /// Set the filename of the file to create.
734    pub fn filename<P: AsRef<Path>>(self, filename: P) -> Self {
735        self.modify_open_opts(|o| o.filename(filename))
736    }
737
738    /// Set the initial size.
739    pub fn size(mut self, size: u64) -> Self {
740        self.size = size;
741        self
742    }
743
744    /// Set the desired preallocation mode.
745    pub fn preallocate(mut self, prealloc_mode: PreallocateMode) -> Self {
746        self.prealloc_mode = prealloc_mode;
747        self
748    }
749
750    /// Whether to overwrite an existing file.
751    pub fn overwrite(mut self, overwrite: bool) -> Self {
752        self.overwrite = overwrite;
753        self
754    }
755
756    /// Modify the options used for opening the file.
757    pub fn modify_open_opts<F: FnOnce(StorageOpenOptions) -> StorageOpenOptions>(
758        mut self,
759        f: F,
760    ) -> Self {
761        self.open_opts = f(self.open_opts);
762        self
763    }
764
765    /// Get the set filename (if any).
766    pub fn get_filename(&self) -> Option<&Path> {
767        self.open_opts.filename.as_deref()
768    }
769
770    /// Get the set size.
771    pub fn get_size(&self) -> u64 {
772        self.size
773    }
774
775    /// Get the preallocation mode.
776    pub fn get_preallocate(&self) -> PreallocateMode {
777        self.prealloc_mode
778    }
779
780    /// Check whether to overwrite an existing file.
781    pub fn get_overwrite(&self) -> bool {
782        self.overwrite
783    }
784
785    /// Get the options for opening the created file.
786    pub fn get_open_options(self) -> StorageOpenOptions {
787        self.open_opts
788    }
789}
790
791impl Default for StorageCreateOptions {
792    fn default() -> Self {
793        StorageCreateOptions {
794            open_opts: Default::default(),
795            size: 0,
796            prealloc_mode: PreallocateMode::None,
797            overwrite: false,
798        }
799    }
800}