pub trait FormatDriverInstance:
Any
+ Debug
+ Display
+ Send
+ Sync {
type Storage: Storage;
Show 21 methods
// Required methods
fn format(&self) -> Format;
unsafe fn probe<'life0, 'async_trait>(
storage: &'life0 Self::Storage,
) -> Pin<Box<dyn Future<Output = Result<bool>> + 'async_trait>>
where Self: Sized + 'async_trait,
'life0: 'async_trait;
fn size(&self) -> u64;
fn collect_storage_dependencies(&self) -> Vec<&Self::Storage>;
fn writable(&self) -> bool;
fn get_mapping<'a, 'async_trait>(
&'a self,
offset: u64,
max_length: u64,
) -> Pin<Box<dyn Future<Output = Result<(ShallowMapping<'a, Self::Storage>, u64)>> + 'async_trait>>
where Self: 'async_trait,
'a: 'async_trait;
fn ensure_data_mapping<'a, 'async_trait>(
&'a self,
offset: u64,
length: u64,
overwrite: bool,
) -> Pin<Box<dyn Future<Output = Result<(&'a Self::Storage, u64, u64)>> + 'async_trait>>
where Self: 'async_trait,
'a: 'async_trait;
fn flush<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn sync<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
unsafe fn invalidate_cache<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn resize_grow<'life0, 'async_trait>(
&'life0 self,
new_size: u64,
prealloc_mode: PreallocateMode,
) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn resize_shrink<'life0, 'async_trait>(
&'life0 mut self,
new_size: u64,
) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
// Provided methods
fn zero_granularity(&self) -> Option<u64> { ... }
fn ensure_zero_mapping<'life0, 'async_trait>(
&'life0 self,
_offset: u64,
_length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
fn discard_to_zero<'life0, 'async_trait>(
&'life0 mut self,
offset: u64,
length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
unsafe fn discard_to_zero_unsafe<'life0, 'async_trait>(
&'life0 self,
_offset: u64,
_length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
fn discard_to_any<'life0, 'async_trait>(
&'life0 mut self,
offset: u64,
length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
unsafe fn discard_to_any_unsafe<'life0, 'async_trait>(
&'life0 self,
_offset: u64,
_length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
fn discard_to_backing<'life0, 'async_trait>(
&'life0 mut self,
offset: u64,
length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
unsafe fn discard_to_backing_unsafe<'life0, 'async_trait>(
&'life0 self,
_offset: u64,
_length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
fn readv_special<'life0, 'life1, 'async_trait>(
&'life0 self,
_bufv: IoVectorMut<'life1>,
_offset: u64,
) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
}Expand description
Implementation of a disk image format.
Required Associated Types§
Required Methods§
Sourceunsafe fn probe<'life0, 'async_trait>(
storage: &'life0 Self::Storage,
) -> Pin<Box<dyn Future<Output = Result<bool>> + 'async_trait>>where
Self: Sized + 'async_trait,
'life0: 'async_trait,
unsafe fn probe<'life0, 'async_trait>(
storage: &'life0 Self::Storage,
) -> Pin<Box<dyn Future<Output = Result<bool>> + 'async_trait>>where
Self: Sized + 'async_trait,
'life0: 'async_trait,
Check whether storage has this format.
This is only a rough test and does not guarantee that opening storage under this format
will succeed. Generally, it will only check the magic bytes (if available). For formats
that do not have distinct features (like raw), this will always return true.
§Safety
Probing is inherently dangerous: Image formats like qcow2 allow referencing external files;
if you use imago to give untrusted parties (like VM guests) access to VM disk image files,
this will give those parties access to data in those files. Opening images from untrusted
sources can therefore be quite dangerous. Gating
(ImplicitOpenGate) can help mitigate this.
If you do not know an image’s format, that is a sign it does not come from a trusted source, and so opening it in a non-raw format may be quite dangerous.
Perhaps most important to note is that giving an untrusted party (like a VM guest) access to a raw image file allows that party to modify the whole file. It may write image headers into this image file, causing a subsequent probe operation to recognize it as a non-raw image, referencing arbitrary files on the host filesystem!
When using imago to give an untrusted third party access to VM disk images, the guidelines for probing are thus:
- Do not probe. If at all possible, obtain an image’s format from a trusted side channel.
- If there is no other way, probe each given image only once, before that untrusted third party (like a VM guest) had write access to it; remember the probed format, and open the image exclusively as that format.
When working with even potentially untrusted images, you should always use an
ImplicitOpenGate to prevent access to files you do not
wish to access.
Sourcefn collect_storage_dependencies(&self) -> Vec<&Self::Storage>
fn collect_storage_dependencies(&self) -> Vec<&Self::Storage>
Recursively collect all storage objects associated with this image.
“Recursive” means to recurse to other images like e.g. a backing file.
Sourcefn writable(&self) -> bool
fn writable(&self) -> bool
Return whether this image may be modified.
This state must not change via interior mutability, i.e. as long as this FDI is wrapped in
a FormatAccess, its writability must remain constant.
Sourcefn get_mapping<'a, 'async_trait>(
&'a self,
offset: u64,
max_length: u64,
) -> Pin<Box<dyn Future<Output = Result<(ShallowMapping<'a, Self::Storage>, u64)>> + 'async_trait>>where
Self: 'async_trait,
'a: 'async_trait,
fn get_mapping<'a, 'async_trait>(
&'a self,
offset: u64,
max_length: u64,
) -> Pin<Box<dyn Future<Output = Result<(ShallowMapping<'a, Self::Storage>, u64)>> + 'async_trait>>where
Self: 'async_trait,
'a: 'async_trait,
Return the mapping at offset.
Find what offset is mapped to, return that mapping information, and the length of that
continuous mapping (from offset).
To determine that continuous mapping length, drivers should not perform additional I/O
beyond what is necessary to get mapping information for offset itself.
max_length is a hint how long of a range is required at all, but the returned length may
exceed that value if that simplifies the implementation.
The returned length must only be 0 if ShallowMapping::Eof is returned.
Sourcefn ensure_data_mapping<'a, 'async_trait>(
&'a self,
offset: u64,
length: u64,
overwrite: bool,
) -> Pin<Box<dyn Future<Output = Result<(&'a Self::Storage, u64, u64)>> + 'async_trait>>where
Self: 'async_trait,
'a: 'async_trait,
fn ensure_data_mapping<'a, 'async_trait>(
&'a self,
offset: u64,
length: u64,
overwrite: bool,
) -> Pin<Box<dyn Future<Output = Result<(&'a Self::Storage, u64, u64)>> + 'async_trait>>where
Self: 'async_trait,
'a: 'async_trait,
Ensure that offset is directly mapped to some storage object, up to a length of length.
Return the storage object, the corresponding offset there, and the continuous length that
the driver was able to map (less than or equal to length).
If the returned length is less than length, drivers can expect subsequent calls to
allocate the rest of the original range. Therefore, if a driver knows in advance that it
is impossible to fully map the given range (e.g. because it lies partially or fully beyond
the end of the disk), it should return an error immediately.
If overwrite is true, the contents in the range are supposed to be overwritten and may be
discarded. Otherwise, they must be kept.
Should not break existing data mappings, i.e. not discard or repurpose existing data mappings. Making them unused, but retaining them as allocated so they can safely be written to (albeit with no effect) is OK; discarding them so that they may be reused for other mappings is not.
Sourcefn flush<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn flush<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Flush internal buffers.
Does not need to ensure those buffers are synced to disk (hardware), and does not need to drop them, i.e. they may still be used on later accesses.
Sourcefn sync<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn sync<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Sync data already written to the storage hardware.
Does not need to ensure internal buffers are written, i.e. should generally just be passed
through to Storage::sync() for all underlying storage objects.
Sourceunsafe fn invalidate_cache<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
unsafe fn invalidate_cache<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Drop internal buffers.
Drop all internal buffers, but do not flush them! All internal data must then be reloaded from disk.
§Safety
Not flushing internal buffers may cause image corruption. The caller must ensure the on-disk state is consistent.
Sourcefn resize_grow<'life0, 'async_trait>(
&'life0 self,
new_size: u64,
prealloc_mode: PreallocateMode,
) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn resize_grow<'life0, 'async_trait>(
&'life0 self,
new_size: u64,
prealloc_mode: PreallocateMode,
) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Resize to the given size, which must be greater than the current size.
Set the disk size to new_size, preallocating the new space according to prealloc_mode.
Depending on the image format, it is possible some preallocation modes are not supported,
in which case an std::io::ErrorKind::Unsupported is returned.
If the current size is already new_size or greater, do nothing.
Sourcefn resize_shrink<'life0, 'async_trait>(
&'life0 mut self,
new_size: u64,
) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn resize_shrink<'life0, 'async_trait>(
&'life0 mut self,
new_size: u64,
) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Truncate to the given size, which must be smaller than the current size.
Set the disk size to new_size, discarding the data after new_size.
May break existing data mappings thanks to the mutable self reference.
If the current size is already new_size or smaller, do nothing.
Provided Methods§
Sourcefn zero_granularity(&self) -> Option<u64>
fn zero_granularity(&self) -> Option<u64>
Granularity on which blocks can be marked as zero.
This is the granularity for FormatDriverInstance::ensure_zero_mapping().
Return None if zero blocks are not supported.
Sourcefn ensure_zero_mapping<'life0, 'async_trait>(
&'life0 self,
_offset: u64,
_length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn ensure_zero_mapping<'life0, 'async_trait>(
&'life0 self,
_offset: u64,
_length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Ensure that the given range is efficiently mapped as zeroes.
Must not write any data. Return the range (offset and length) that could actually be
zeroed, which must be a subset of the range given by offset and length. The returned
offset must be as close to offset as possible, i.e. no zero mapping is possible between
offset and the returned offset (e.g. because of format-inherent granularity).
The returned length may be zero in case zeroing would theoretically be possible, but not for this range at this granularity.
Should not break existing data mappings, i.e. not discard or repurpose existing data mappings. Making them unused, but retaining them as allocated so they can safely be written to (albeit with no effect) is OK; discarding them so that they may be reused for other mappings is not.
Sourcefn discard_to_zero<'life0, 'async_trait>(
&'life0 mut self,
offset: u64,
length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn discard_to_zero<'life0, 'async_trait>(
&'life0 mut self,
offset: u64,
length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Discard the given range, ensure it is read back as zeroes.
Effectively the same as FormatDriverInstance::ensure_zero_mapping(), but may break
existing data mappings thanks to the mutable self reference, which ensures that old data
mappings returned by FormatDriverInstance::get_mapping() cannot be held onto.
Sourceunsafe fn discard_to_zero_unsafe<'life0, 'async_trait>(
&'life0 self,
_offset: u64,
_length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
unsafe fn discard_to_zero_unsafe<'life0, 'async_trait>(
&'life0 self,
_offset: u64,
_length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Discard the given range, ensure it is read back as zeroes.
Unsafe variant of FormatDriverInstance::discard_to_zero(), only requiring an immutable &self
§Safety
This function is marked as unsafe because:
- It may invalidate all existing data mappings.
The caller must ensure that no other references to this driver instance exist and that the caller must ensure that all previously looked up mappings are no longer assumed to be valid after this operation.
Because mappings contain references to the block driver instance, one way to do so is
to have a mutable reference to the block driver instance, which will automatically
ensure there are no other references (and thus no mappings). In that case, you can use
the safe variant Self::discard_to_zero().
Sourcefn discard_to_any<'life0, 'async_trait>(
&'life0 mut self,
offset: u64,
length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn discard_to_any<'life0, 'async_trait>(
&'life0 mut self,
offset: u64,
length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Discard the given range.
Effectively the same as FormatDriverInstance::discard_to_zero(), but the discarded area
may read as any data. Backing file data should not reappear, however.
Sourceunsafe fn discard_to_any_unsafe<'life0, 'async_trait>(
&'life0 self,
_offset: u64,
_length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
unsafe fn discard_to_any_unsafe<'life0, 'async_trait>(
&'life0 self,
_offset: u64,
_length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Discard the given range.
Unsafe variant of FormatDriverInstance::discard_to_any(), only requiring an immutable &self
§Safety
This function is marked as unsafe because:
- It may invalidate all existing data mappings.
The caller must ensure that no other references to this driver instance exist and that the caller must ensure that all previously looked up mappings are no longer assumed to be valid after this operation.
Because mappings contain references to the block driver instance, one way to do so is
to have a mutable reference to the block driver instance, which will automatically
ensure there are no other references (and thus no mappings). In that case, you can use
the safe variant Self::discard_to_any().
Sourcefn discard_to_backing<'life0, 'async_trait>(
&'life0 mut self,
offset: u64,
length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn discard_to_backing<'life0, 'async_trait>(
&'life0 mut self,
offset: u64,
length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Discard the given range, such that the backing image becomes visible.
Deallocate the range such that in deallocated blocks, the backing image’s data (if one
exists) will show, i.e. FormatDriverInstance::get_mapping() should return an indirect
mapping. When there is no backing image, those blocks should appear as zero.
Return the range (offset and length) that could actually be discarded, which must be a
subset of offset and length, and the returned offset must be as close to offset as
possible (like for FormatDriverInstance::discard_to_backing().
May break existing data mappings thanks to the mutable self reference.
Sourceunsafe fn discard_to_backing_unsafe<'life0, 'async_trait>(
&'life0 self,
_offset: u64,
_length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
unsafe fn discard_to_backing_unsafe<'life0, 'async_trait>(
&'life0 self,
_offset: u64,
_length: u64,
) -> Pin<Box<dyn Future<Output = Result<(u64, u64)>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Discard the given range, such that the backing image becomes visible.
Unsafe variant of FormatDriverInstance::discard_to_backing(), only requiring an immutable &self
§Safety
This function is marked as unsafe because:
- It may invalidate all existing data mappings.
The caller must ensure that no other references to this driver instance exist and that the caller must ensure that all previously looked up mappings are no longer assumed to be valid after this operation.
Because mappings contain references to the block driver instance, one way to do so is
to have a mutable reference to the block driver instance, which will automatically
ensure there are no other references (and thus no mappings). In that case, you can use
the safe variant Self::discard_to_backing().
Sourcefn readv_special<'life0, 'life1, 'async_trait>(
&'life0 self,
_bufv: IoVectorMut<'life1>,
_offset: u64,
) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn readv_special<'life0, 'life1, 'async_trait>(
&'life0 self,
_bufv: IoVectorMut<'life1>,
_offset: u64,
) -> Pin<Box<dyn Future<Output = Result<()>> + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Read data from a ShallowMapping::Special area.