Skip to main content

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