imago/format/
gate.rs

1//! Gate functionality to control implicitly opened dependencies.
2
3use super::builder::FormatDriverBuilder;
4use crate::{Storage, StorageOpenOptions};
5use std::io;
6
7/// Gate implicit image and storage object dependencies.
8///
9/// Depending on their format, images may have external image and storage object dependencies; for
10/// example, qcow2 images can reference a backing image (any image format), and an external data
11/// file (pure storage object, no format).  You can override these implicit choices when opening
12/// images, but if you do not, they are carried out automatically.
13///
14/// However, opening implicit dependencies is always done through an object of type
15/// `ImplicitOpenGate`, which you pass to [`FormatDriverBuilder::open()`].  Implementing this trait
16/// therefore allows you to restrict if and how images an storage objects are opened implicitly.
17///
18/// Anytime a storage object is opened, it is done by an [`ImplicitOpenGate::open_storage()`]
19/// implementation.  Anytime a format layer is opened, it is done by an
20/// [`ImplicitOpenGate::open_format()`] implementation.  Therefore, unless your implementation does
21/// perform this open operation, nothing will be opened.
22///
23/// Do note however that whatever you open explicitly through [`FormatDriverBuilder::open()`] or
24/// [`Storage::open()`] is *not* run through `ImplicitOpenGate`.
25///
26/// See [`PermissiveImplicitOpenGate`] and [`DenyImplicitOpenGate`].
27pub trait ImplicitOpenGate<S: Storage>: Default {
28    /// Open an implicitly referenced format layer.
29    ///
30    /// You can e.g. check the supposed format via `F::FORMAT`, and its filename via
31    /// `builder.get_image_path()`.
32    ///
33    /// Note that this is not invoked for images that are explicitly opened, i.e. whenever
34    /// [`FormatDriverBuilder::open()`] is called by imago users.
35    #[allow(async_fn_in_trait)] // No need for Send
36    async fn open_format<F: FormatDriverBuilder<S>>(&mut self, builder: F)
37        -> io::Result<F::Format>;
38
39    /// Open an implicitly referenced storage object.
40    ///
41    /// You can e.g. check the filename via `builder.get_filename()`.
42    ///
43    /// Note that this is not invoked for storage objects that are explicitly opened, i.e. whenever
44    /// an object of type `S` is created by imago users (e.g. via [`S::open()`](Storage::open())).
45    #[allow(async_fn_in_trait)] // No need for Send
46    async fn open_storage(&mut self, builder: StorageOpenOptions) -> io::Result<S>;
47}
48
49/// Open all implicitly referenced images/files unrestricted, as requested.
50///
51/// Use with caution!  Allowing all implicit dependencies to be opened automatically without
52/// restrictions is dangerous:
53/// - if you plan to give access to the image to an untrusted third party (e.g. a VM guest), and
54/// - unless the image comes from a fully trusted source.
55///
56/// This would give the untrusted third party potentially access to arbitrary storage object
57/// accessible through imago.
58///
59/// (See also the safety section on
60/// [`FormatDriverInstance::probe()`](super::drivers::FormatDriverInstance::probe()).)
61#[derive(Clone, Copy, Debug, Default)]
62pub struct PermissiveImplicitOpenGate();
63
64impl<S: Storage> ImplicitOpenGate<S> for PermissiveImplicitOpenGate {
65    async fn open_format<F: FormatDriverBuilder<S>>(
66        &mut self,
67        builder: F,
68    ) -> io::Result<F::Format> {
69        // Recursion, need to box
70        Box::pin(builder.open(Self::default())).await
71    }
72
73    async fn open_storage(&mut self, builder: StorageOpenOptions) -> io::Result<S> {
74        S::open(builder).await
75    }
76}
77
78/// Disallow any implicitly referenced images or storage objects.
79///
80/// Always returns errors, ensuring nothing can be opened implicitly.  Useful when you intend to
81/// explicitly override all potential implicit references, and want a safeguard that you did not
82/// forget anything.
83///
84/// If you did forget something, the error generated by this object will most likely be propagated
85/// up to the prompting [`FormatDriverBuilder::open()`] call, failing it.
86#[derive(Clone, Copy, Debug, Default)]
87pub struct DenyImplicitOpenGate();
88
89impl<S: Storage> ImplicitOpenGate<S> for DenyImplicitOpenGate {
90    async fn open_format<F: FormatDriverBuilder<S>>(
91        &mut self,
92        _builder: F,
93    ) -> io::Result<F::Format> {
94        Err(io::Error::new(
95            io::ErrorKind::PermissionDenied,
96            "Opening implicitly referenced format layer denied",
97        ))
98    }
99
100    async fn open_storage(&mut self, _builder: StorageOpenOptions) -> io::Result<S> {
101        Err(io::Error::new(
102            io::ErrorKind::PermissionDenied,
103            "Opening implicitly referenced storage object denied",
104        ))
105    }
106}