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::{IoBuffer, IoVector, IoVectorMut};
10use drivers::CommonStorageHelper;
11use std::any::Any;
12use std::fmt::{Debug, Display};
13use std::future::Future;
14use std::path::{Path, PathBuf};
15use std::pin::Pin;
16use std::sync::Arc;
17use std::{cmp, io};
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    ///
115    /// Must be a multiple of [`Self::req_align()`].
116    fn zero_align(&self) -> usize {
117        self.req_align()
118    }
119
120    /// Minimum required alignment for effective discards.
121    ///
122    /// Must be a multiple of [`Self::req_align()`].
123    fn discard_align(&self) -> usize {
124        self.req_align()
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 via [`Storage::pure_writev()`],
185    /// which is inefficient.  Storage drivers should override it with a more efficient
186    /// implementation.
187    ///
188    /// Because the default implementation uses [`Storage::pure_writev()`], offset and length
189    /// must also be aligned to [`Self::req_align()`].  Implementations that support
190    /// finer-grained zeroing (e.g. via `fallocate`) should override this method.
191    ///
192    /// # Safety
193    /// This is a pure write to storage.  The request must be fully aligned to
194    /// [`Self::zero_align()`], and safeguards we want to implement for safe concurrent access may
195    /// not be available.
196    ///
197    /// Use [`StorageExt::write_zeroes()`](crate::StorageExt::write_zeroes()) instead.
198    #[allow(async_fn_in_trait)] // No need for Send
199    async unsafe fn pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
200        unsafe { pure_write_full_zeroes(self, offset, length).await }
201    }
202
203    /// Ensure the given range is allocated, and reads back as zeroes.
204    ///
205    /// The default implementation writes actual zeroes as data via [`Storage::pure_writev()`],
206    /// which is inefficient.  Storage drivers should override it with a more efficient
207    /// implementation.
208    ///
209    /// Because the default implementation uses [`Storage::pure_writev()`], offset and length
210    /// must also be aligned to [`Self::req_align()`].  Implementations that support
211    /// finer-grained zeroing (e.g. via `fallocate`) should override this method.
212    ///
213    /// # Safety
214    /// This is a pure write to storage.  The request must be fully aligned to
215    /// [`Self::zero_align()`], and safeguards we want to implement for safe concurrent access may
216    /// not be available.
217    ///
218    /// Use [`StorageExt::write_allocated_zeroes()`](crate::StorageExt::write_allocated_zeroes())
219    /// instead.
220    #[allow(async_fn_in_trait)] // No need for Send
221    async unsafe fn pure_write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
222        unsafe { pure_write_full_zeroes(self, offset, length).await }
223    }
224
225    /// Discard the given range, with undefined contents when read back.
226    ///
227    /// Tell the storage layer this range is no longer needed and need not be backed by actual
228    /// storage.  When read back, the data read will be undefined, i.e. not necessarily zeroes.
229    ///
230    /// No-op implementations therefore explicitly fulfill the interface contract.
231    ///
232    /// # Safety
233    /// This is a pure write to storage.  The request must be fully aligned to
234    /// [`Self::discard_align()`], and safeguards we want to implement for safe concurrent access
235    /// may not be available.
236    ///
237    /// Use [`StorageExt::discard()`](crate::StorageExt::discard()) instead.
238    #[allow(async_fn_in_trait)] // No need for Send
239    async unsafe fn pure_discard(&self, _offset: u64, _length: u64) -> io::Result<()> {
240        Ok(())
241    }
242
243    /// Flush internal buffers.
244    ///
245    /// Does not necessarily sync those buffers to disk.  When using `flush()`, consider whether
246    /// you want to call `sync()` afterwards.
247    ///
248    /// Note that this will not drop the buffers, so they may still be used to serve later
249    /// accesses.  Use [`Storage::invalidate_cache()`] to drop all buffers.
250    #[allow(async_fn_in_trait)] // No need for Send
251    async fn flush(&self) -> io::Result<()>;
252
253    /// Sync data already written to the storage hardware.
254    ///
255    /// This does not necessarily include flushing internal buffers, i.e. `flush`.  When using
256    /// `sync()`, consider whether you want to call `flush()` before it.
257    #[allow(async_fn_in_trait)] // No need for Send
258    async fn sync(&self) -> io::Result<()>;
259
260    /// Drop internal buffers.
261    ///
262    /// This drops all internal buffers, but does not flush them!  All cached data is reloaded on
263    /// subsequent accesses.
264    ///
265    /// # Safety
266    /// Not flushing internal buffers may cause corruption.  You must ensure the underlying storage
267    /// state is consistent.
268    #[allow(async_fn_in_trait)] // No need for Send
269    async unsafe fn invalidate_cache(&self) -> io::Result<()>;
270
271    /// Return the storage helper object (used by the [`StorageExt`](crate::StorageExt)
272    /// implementation).
273    fn get_storage_helper(&self) -> &CommonStorageHelper;
274
275    /// Resize to the given size.
276    ///
277    /// Set the size of this storage object to `new_size`.  If `new_size` is smaller than the
278    /// current size, ignore `prealloc_mode` and discard the data after `new_size`.
279    ///
280    /// If `new_size` is larger than the current size, `prealloc_mode` determines whether and how
281    /// the new range should be allocated; it is possible some preallocation modes are not
282    /// supported, in which case an [`std::io::ErrorKind::Unsupported`] is returned.
283    #[allow(async_fn_in_trait)] // No need for Send
284    async fn resize(&self, _new_size: u64, _prealloc_mode: PreallocateMode) -> io::Result<()> {
285        Err(io::ErrorKind::Unsupported.into())
286    }
287}
288
289/// Allow dynamic use of storage objects (i.e. is object safe).
290///
291/// When using normal `Storage` objects, they must all be of the same type within a single disk
292/// image chain.  For example, every storage object underneath a `FormatAccess<StdFile>` object
293/// must be of type `StdFile`.
294///
295/// `DynStorage` allows the use of `Box<dyn DynStorage>`, which implements `Storage`, to allow
296/// mixed storage object types.  Therefore, a `FormatAccess<Box<dyn DynStorage>>` allows e.g. the
297/// use of both `Box<StdFile>` and `Box<Null>` storage objects together.  (`Arc` instead of `Box`
298/// works, too.)
299///
300/// Async functions in `DynStorage` return boxed futures (`Pin<Box<dyn Future>>`), which makes them
301/// slighly less efficient than async functions in `Storage`, hence the distinction.
302pub trait DynStorage: Any + Debug + Display + Send + Sync {
303    /// Wrapper around [`Storage::mem_align()`].
304    fn dyn_mem_align(&self) -> usize;
305
306    /// Wrapper around [`Storage::req_align()`].
307    fn dyn_req_align(&self) -> usize;
308
309    /// Wrapper around [`Storage::zero_align()`].
310    fn dyn_zero_align(&self) -> usize;
311
312    /// Wrapper around [`Storage::discard_align()`].
313    fn dyn_discard_align(&self) -> usize;
314
315    /// Wrapper around [`Storage::size()`].
316    fn dyn_size(&self) -> io::Result<u64>;
317
318    /// Wrapper around [`Storage::resolve_relative_path()`].
319    fn dyn_resolve_relative_path(&self, relative: &Path) -> io::Result<PathBuf>;
320
321    /// Wrapper around [`Storage::get_filename()`]
322    fn dyn_get_filename(&self) -> Option<PathBuf>;
323
324    /// Object-safe wrapper around [`Storage::pure_readv()`].
325    ///
326    /// # Safety
327    /// Same considerations are for [`Storage::pure_readv()`] apply.
328    unsafe fn dyn_pure_readv<'a>(
329        &'a self,
330        bufv: IoVectorMut<'a>,
331        offset: u64,
332    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + 'a>>;
333
334    /// Object-safe wrapper around [`Storage::pure_writev()`].
335    ///
336    /// # Safety
337    /// Same considerations are for [`Storage::pure_writev()`] apply.
338    unsafe fn dyn_pure_writev<'a>(
339        &'a self,
340        bufv: IoVector<'a>,
341        offset: u64,
342    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + 'a>>;
343
344    /// Object-safe wrapper around [`Storage::pure_write_zeroes()`].
345    ///
346    /// # Safety
347    /// Same considerations are for [`Storage::pure_write_zeroes()`] apply.
348    unsafe fn dyn_pure_write_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_write_allocated_zeroes()`].
355    ///
356    /// # Safety
357    /// Same considerations are for [`Storage::pure_write_allocated_zeroes()`] apply.
358    unsafe fn dyn_pure_write_allocated_zeroes(
359        &self,
360        offset: u64,
361        length: u64,
362    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
363
364    /// Object-safe wrapper around [`Storage::pure_discard()`].
365    ///
366    /// # Safety
367    /// Same considerations are for [`Storage::pure_discard()`] apply.
368    unsafe fn dyn_pure_discard(
369        &self,
370        offset: u64,
371        length: u64,
372    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
373
374    /// Object-safe wrapper around [`Storage::flush()`].
375    fn dyn_flush(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
376
377    /// Object-safe wrapper around [`Storage::sync()`].
378    fn dyn_sync(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
379
380    /// Object-safe wrapper around [`Storage::invalidate_cache()`].
381    ///
382    /// # Safety
383    /// Same considerations are for [`Storage::invalidate_cache()`] apply.
384    unsafe fn dyn_invalidate_cache(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
385
386    /// Wrapper around [`Storage::get_storage_helper()`].
387    fn dyn_get_storage_helper(&self) -> &CommonStorageHelper;
388
389    /// Wrapper around [`Storage::resize()`].
390    fn dyn_resize(
391        &self,
392        new_size: u64,
393        prealloc_mode: PreallocateMode,
394    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>>;
395}
396
397/// Storage object preallocation modes.
398///
399/// When resizing or creating storage objects, this mode determines whether and how the new data
400/// range is to be preallocated.
401#[derive(Clone, Copy, Debug, Eq, PartialEq)]
402#[non_exhaustive]
403pub enum PreallocateMode {
404    /// No preallocation.
405    ///
406    /// Reading the new range may return random data.
407    None,
408
409    /// Ensure range reads as zeroes.
410    ///
411    /// Does not necessarily allocate data, but has to ensure the new range will read back as
412    /// zeroes.
413    Zero,
414
415    /// Extent preallocation.
416    ///
417    /// Do not write data, but ensure all new extents are allocated.
418    Allocate,
419
420    /// Full data preallocation.
421    ///
422    /// Write zeroes to the whole range.
423    WriteData,
424}
425
426impl<S: Storage> Storage for &S {
427    fn mem_align(&self) -> usize {
428        (*self).mem_align()
429    }
430
431    fn req_align(&self) -> usize {
432        (*self).req_align()
433    }
434
435    fn zero_align(&self) -> usize {
436        (*self).zero_align()
437    }
438
439    fn discard_align(&self) -> usize {
440        (*self).discard_align()
441    }
442
443    fn size(&self) -> io::Result<u64> {
444        (*self).size()
445    }
446
447    fn resolve_relative_path<P: AsRef<Path>>(&self, relative: P) -> io::Result<PathBuf> {
448        (*self).resolve_relative_path(relative)
449    }
450
451    fn get_filename(&self) -> Option<PathBuf> {
452        (*self).get_filename()
453    }
454
455    async unsafe fn pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
456        unsafe { (*self).pure_readv(bufv, offset).await }
457    }
458
459    async unsafe fn pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()> {
460        unsafe { (*self).pure_writev(bufv, offset).await }
461    }
462
463    async unsafe fn pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
464        unsafe { (*self).pure_write_zeroes(offset, length).await }
465    }
466
467    async unsafe fn pure_write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
468        unsafe { (*self).pure_write_allocated_zeroes(offset, length).await }
469    }
470
471    async unsafe fn pure_discard(&self, offset: u64, length: u64) -> io::Result<()> {
472        unsafe { (*self).pure_discard(offset, length).await }
473    }
474
475    async fn flush(&self) -> io::Result<()> {
476        (*self).flush().await
477    }
478
479    async fn sync(&self) -> io::Result<()> {
480        (*self).sync().await
481    }
482
483    async unsafe fn invalidate_cache(&self) -> io::Result<()> {
484        unsafe { (*self).invalidate_cache().await }
485    }
486
487    fn get_storage_helper(&self) -> &CommonStorageHelper {
488        (*self).get_storage_helper()
489    }
490
491    async fn resize(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()> {
492        (*self).resize(new_size, prealloc_mode).await
493    }
494}
495
496impl<S: Storage + 'static> DynStorage for S {
497    fn dyn_mem_align(&self) -> usize {
498        <S as Storage>::mem_align(self)
499    }
500
501    fn dyn_req_align(&self) -> usize {
502        <S as Storage>::req_align(self)
503    }
504
505    fn dyn_zero_align(&self) -> usize {
506        <S as Storage>::zero_align(self)
507    }
508
509    fn dyn_discard_align(&self) -> usize {
510        <S as Storage>::discard_align(self)
511    }
512
513    fn dyn_size(&self) -> io::Result<u64> {
514        <S as Storage>::size(self)
515    }
516
517    fn dyn_resolve_relative_path(&self, relative: &Path) -> io::Result<PathBuf> {
518        <S as Storage>::resolve_relative_path(self, relative)
519    }
520
521    fn dyn_get_filename(&self) -> Option<PathBuf> {
522        <S as Storage>::get_filename(self)
523    }
524
525    unsafe fn dyn_pure_readv<'a>(
526        &'a self,
527        bufv: IoVectorMut<'a>,
528        offset: u64,
529    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + 'a>> {
530        Box::pin(unsafe { <S as Storage>::pure_readv(self, bufv, offset) })
531    }
532
533    unsafe fn dyn_pure_writev<'a>(
534        &'a self,
535        bufv: IoVector<'a>,
536        offset: u64,
537    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + 'a>> {
538        Box::pin(unsafe { <S as Storage>::pure_writev(self, bufv, offset) })
539    }
540
541    unsafe fn dyn_pure_write_zeroes(
542        &self,
543        offset: u64,
544        length: u64,
545    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
546        Box::pin(unsafe { <S as Storage>::pure_write_zeroes(self, offset, length) })
547    }
548
549    unsafe fn dyn_pure_write_allocated_zeroes(
550        &self,
551        offset: u64,
552        length: u64,
553    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
554        Box::pin(unsafe { <S as Storage>::pure_write_allocated_zeroes(self, offset, length) })
555    }
556
557    unsafe fn dyn_pure_discard(
558        &self,
559        offset: u64,
560        length: u64,
561    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
562        Box::pin(unsafe { <S as Storage>::pure_discard(self, offset, length) })
563    }
564
565    fn dyn_flush(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
566        Box::pin(<S as Storage>::flush(self))
567    }
568
569    fn dyn_sync(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
570        Box::pin(<S as Storage>::sync(self))
571    }
572
573    unsafe fn dyn_invalidate_cache(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
574        Box::pin(unsafe { <S as Storage>::invalidate_cache(self) })
575    }
576
577    fn dyn_get_storage_helper(&self) -> &CommonStorageHelper {
578        <S as Storage>::get_storage_helper(self)
579    }
580
581    fn dyn_resize(
582        &self,
583        new_size: u64,
584        prealloc_mode: PreallocateMode,
585    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + '_>> {
586        Box::pin(<S as Storage>::resize(self, new_size, prealloc_mode))
587    }
588}
589
590impl Storage for Box<dyn DynStorage> {
591    async fn open(opts: StorageOpenOptions) -> io::Result<Self> {
592        // TODO: When we have more drivers, choose different defaults depending on the options
593        // given.  Right now, only `File` really supports being opened through options, so it is an
594        // obvious choice.
595        Ok(Box::new(crate::file::File::open(opts).await?))
596    }
597
598    async fn create_open(opts: StorageCreateOptions) -> io::Result<Self> {
599        // Same as `Self::open()`.
600        Ok(Box::new(crate::file::File::create_open(opts).await?))
601    }
602
603    fn mem_align(&self) -> usize {
604        self.as_ref().dyn_mem_align()
605    }
606
607    fn req_align(&self) -> usize {
608        self.as_ref().dyn_req_align()
609    }
610
611    fn zero_align(&self) -> usize {
612        self.as_ref().dyn_zero_align()
613    }
614
615    fn discard_align(&self) -> usize {
616        self.as_ref().dyn_discard_align()
617    }
618
619    fn size(&self) -> io::Result<u64> {
620        self.as_ref().dyn_size()
621    }
622
623    fn resolve_relative_path<P: AsRef<Path>>(&self, relative: P) -> io::Result<PathBuf> {
624        self.as_ref().dyn_resolve_relative_path(relative.as_ref())
625    }
626
627    fn get_filename(&self) -> Option<PathBuf> {
628        self.as_ref().dyn_get_filename()
629    }
630
631    async unsafe fn pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
632        unsafe { self.as_ref().dyn_pure_readv(bufv, offset).await }
633    }
634
635    async unsafe fn pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()> {
636        unsafe { self.as_ref().dyn_pure_writev(bufv, offset).await }
637    }
638
639    async unsafe fn pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
640        unsafe { self.as_ref().dyn_pure_write_zeroes(offset, length).await }
641    }
642
643    async unsafe fn pure_write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
644        unsafe {
645            self.as_ref()
646                .dyn_pure_write_allocated_zeroes(offset, length)
647                .await
648        }
649    }
650
651    async unsafe fn pure_discard(&self, offset: u64, length: u64) -> io::Result<()> {
652        unsafe { self.as_ref().dyn_pure_discard(offset, length).await }
653    }
654
655    async fn flush(&self) -> io::Result<()> {
656        self.as_ref().dyn_flush().await
657    }
658
659    async fn sync(&self) -> io::Result<()> {
660        self.as_ref().dyn_sync().await
661    }
662
663    async unsafe fn invalidate_cache(&self) -> io::Result<()> {
664        unsafe { self.as_ref().dyn_invalidate_cache().await }
665    }
666
667    fn get_storage_helper(&self) -> &CommonStorageHelper {
668        self.as_ref().dyn_get_storage_helper()
669    }
670
671    async fn resize(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()> {
672        self.as_ref().dyn_resize(new_size, prealloc_mode).await
673    }
674}
675
676impl Storage for Arc<dyn DynStorage> {
677    async fn open(opts: StorageOpenOptions) -> io::Result<Self> {
678        Box::<dyn DynStorage>::open(opts).await.map(Into::into)
679    }
680
681    async fn create_open(opts: StorageCreateOptions) -> io::Result<Self> {
682        Box::<dyn DynStorage>::create_open(opts)
683            .await
684            .map(Into::into)
685    }
686
687    fn mem_align(&self) -> usize {
688        self.as_ref().dyn_mem_align()
689    }
690
691    fn req_align(&self) -> usize {
692        self.as_ref().dyn_req_align()
693    }
694
695    fn zero_align(&self) -> usize {
696        self.as_ref().dyn_zero_align()
697    }
698
699    fn discard_align(&self) -> usize {
700        self.as_ref().dyn_discard_align()
701    }
702
703    fn size(&self) -> io::Result<u64> {
704        self.as_ref().dyn_size()
705    }
706
707    fn resolve_relative_path<P: AsRef<Path>>(&self, relative: P) -> io::Result<PathBuf> {
708        self.as_ref().dyn_resolve_relative_path(relative.as_ref())
709    }
710
711    fn get_filename(&self) -> Option<PathBuf> {
712        self.as_ref().dyn_get_filename()
713    }
714
715    async unsafe fn pure_readv(&self, bufv: IoVectorMut<'_>, offset: u64) -> io::Result<()> {
716        unsafe { self.as_ref().dyn_pure_readv(bufv, offset) }.await
717    }
718
719    async unsafe fn pure_writev(&self, bufv: IoVector<'_>, offset: u64) -> io::Result<()> {
720        unsafe { self.as_ref().dyn_pure_writev(bufv, offset) }.await
721    }
722
723    async unsafe fn pure_write_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
724        unsafe { self.as_ref().dyn_pure_write_zeroes(offset, length) }.await
725    }
726
727    async unsafe fn pure_write_allocated_zeroes(&self, offset: u64, length: u64) -> io::Result<()> {
728        unsafe {
729            self.as_ref()
730                .dyn_pure_write_allocated_zeroes(offset, length)
731        }
732        .await
733    }
734
735    async unsafe fn pure_discard(&self, offset: u64, length: u64) -> io::Result<()> {
736        unsafe { self.as_ref().dyn_pure_discard(offset, length) }.await
737    }
738
739    async fn flush(&self) -> io::Result<()> {
740        self.as_ref().dyn_flush().await
741    }
742
743    async fn sync(&self) -> io::Result<()> {
744        self.as_ref().dyn_sync().await
745    }
746
747    async unsafe fn invalidate_cache(&self) -> io::Result<()> {
748        unsafe { self.as_ref().dyn_invalidate_cache().await }
749    }
750
751    fn get_storage_helper(&self) -> &CommonStorageHelper {
752        self.as_ref().dyn_get_storage_helper()
753    }
754
755    async fn resize(&self, new_size: u64, prealloc_mode: PreallocateMode) -> io::Result<()> {
756        self.as_ref().dyn_resize(new_size, prealloc_mode).await
757    }
758}
759
760impl StorageOpenOptions {
761    /// Create default options.
762    pub fn new() -> Self {
763        StorageOpenOptions::default()
764    }
765
766    /// Set a filename to open.
767    pub fn filename<P: AsRef<Path>>(mut self, filename: P) -> Self {
768        self.filename = Some(filename.as_ref().to_owned());
769        self
770    }
771
772    /// Whether the storage should be writable or not.
773    pub fn write(mut self, write: bool) -> Self {
774        self.writable = write;
775        self
776    }
777
778    /// Whether to bypass the host page cache (if applicable).
779    pub fn direct(mut self, direct: bool) -> Self {
780        self.direct = direct;
781        self
782    }
783
784    /// macOS-only: whether to use relaxed synchronization on `File`.
785    ///
786    /// If relaxed synchronization is enabled, `File::sync()` will use the `fsync()` syscall
787    /// instead of `fcntl(F_FULLFSYNC)`, which is a lighter synchronization mechanism that flushes
788    /// the filesystem cache to the drive, but doesn't request the drive to flush its internal
789    /// buffers to persistent storage.
790    #[cfg(target_os = "macos")]
791    pub fn relaxed_sync(mut self, relaxed_sync: bool) -> Self {
792        self.relaxed_sync = relaxed_sync;
793        self
794    }
795
796    /// Get the set filename (if any).
797    pub fn get_filename(&self) -> Option<&Path> {
798        self.filename.as_deref()
799    }
800
801    /// Return the set writable state.
802    pub fn get_writable(&self) -> bool {
803        self.writable
804    }
805
806    /// Return the set direct state.
807    pub fn get_direct(&self) -> bool {
808        self.direct
809    }
810
811    /// macOS-only: return the relaxed synchronization state.
812    #[cfg(target_os = "macos")]
813    pub fn get_relaxed_sync(&self) -> bool {
814        self.relaxed_sync
815    }
816}
817
818impl StorageCreateOptions {
819    /// Create default options.
820    pub fn new() -> Self {
821        StorageCreateOptions::default()
822    }
823
824    /// Set the filename of the file to create.
825    pub fn filename<P: AsRef<Path>>(self, filename: P) -> Self {
826        self.modify_open_opts(|o| o.filename(filename))
827    }
828
829    /// Set the initial size.
830    pub fn size(mut self, size: u64) -> Self {
831        self.size = size;
832        self
833    }
834
835    /// Set the desired preallocation mode.
836    pub fn preallocate(mut self, prealloc_mode: PreallocateMode) -> Self {
837        self.prealloc_mode = prealloc_mode;
838        self
839    }
840
841    /// Whether to overwrite an existing file.
842    pub fn overwrite(mut self, overwrite: bool) -> Self {
843        self.overwrite = overwrite;
844        self
845    }
846
847    /// Modify the options used for opening the file.
848    pub fn modify_open_opts<F: FnOnce(StorageOpenOptions) -> StorageOpenOptions>(
849        mut self,
850        f: F,
851    ) -> Self {
852        self.open_opts = f(self.open_opts);
853        self
854    }
855
856    /// Get the set filename (if any).
857    pub fn get_filename(&self) -> Option<&Path> {
858        self.open_opts.filename.as_deref()
859    }
860
861    /// Get the set size.
862    pub fn get_size(&self) -> u64 {
863        self.size
864    }
865
866    /// Get the preallocation mode.
867    pub fn get_preallocate(&self) -> PreallocateMode {
868        self.prealloc_mode
869    }
870
871    /// Check whether to overwrite an existing file.
872    pub fn get_overwrite(&self) -> bool {
873        self.overwrite
874    }
875
876    /// Get the options for opening the created file.
877    pub fn get_open_options(self) -> StorageOpenOptions {
878        self.open_opts
879    }
880}
881
882impl Default for StorageCreateOptions {
883    fn default() -> Self {
884        StorageCreateOptions {
885            open_opts: Default::default(),
886            size: 0,
887            prealloc_mode: PreallocateMode::None,
888            overwrite: false,
889        }
890    }
891}
892
893/// Write zero data to the given area.
894///
895/// Like [`ext::write_full_zeroes()`], this will actually write zero data, fully allocated.
896///
897/// # Safety
898/// This is a pure write to storage.  The request must be fully aligned to
899/// [`Storage::req_align()`], and safeguards we want to implement for safe concurrent access may
900/// not be available.
901///
902/// To be used as the default implementation of [`Storage::pure_write_zeroes()`] and
903/// [`Storage::pure_write_allocated_zeroes()`].
904async unsafe fn pure_write_full_zeroes<S: Storage>(
905    storage: S,
906    mut offset: u64,
907    mut length: u64,
908) -> io::Result<()> {
909    let req_align = storage.req_align() as u64;
910    if !(offset | length).is_multiple_of(req_align) {
911        return Err(io::Error::new(
912            io::ErrorKind::InvalidInput,
913            "write_zeroes fallback: offset/length not aligned to request alignment",
914        ));
915    }
916
917    let mem_align = storage.mem_align() as u64;
918    let max_chunk_len = cmp::max(cmp::max(req_align, mem_align), 1048576);
919    let buflen = cmp::min(length, max_chunk_len) as usize;
920    let mut buf = IoBuffer::new(buflen, storage.mem_align())?;
921    buf.as_mut().into_slice().fill(0);
922
923    while length > 0 {
924        let chunk_len = cmp::min(length, max_chunk_len) as usize;
925        unsafe {
926            storage
927                .pure_writev(buf.as_ref_range(0..chunk_len).into(), offset)
928                .await
929        }?;
930        offset += chunk_len as u64;
931        length -= chunk_len as u64;
932    }
933
934    Ok(())
935}