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