vmgstool/
storage_backend.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Implementation of [`StorageBackend`] for VMGS files opened in VmgsTool
5
6use async_trait::async_trait;
7use hcl_compat_uefi_nvram_storage::storage_backend::StorageBackend;
8use hcl_compat_uefi_nvram_storage::storage_backend::StorageBackendError;
9use thiserror::Error;
10use vmgs::Vmgs;
11
12/// A [`StorageBackend`] implementation for VMGS files.
13pub struct VmgsStorageBackend {
14    vmgs: Vmgs,
15    file_id: vmgs_format::FileId,
16    encrypted: bool,
17}
18
19/// Error returned when a VMGS file is requested to be opened in encrypted mode,
20/// but the vmgstool was not compiled with encryption support.
21#[derive(Debug, Error)]
22#[error("vmgstool was not compiled with encryption support")]
23pub struct EncryptionNotSupported;
24
25impl VmgsStorageBackend {
26    /// Create a new [`StorageBackend`] object backed by a particular VMGS
27    /// file-id.
28    pub fn new(
29        vmgs: Vmgs,
30        file_id: vmgs_format::FileId,
31        encrypted: bool,
32    ) -> Result<Self, EncryptionNotSupported> {
33        if encrypted && !cfg!(with_encryption) {
34            return Err(EncryptionNotSupported);
35        }
36        Ok(Self {
37            vmgs,
38            file_id,
39            encrypted,
40        })
41    }
42}
43
44#[async_trait]
45impl StorageBackend for VmgsStorageBackend {
46    async fn persist(&mut self, data: Vec<u8>) -> Result<(), StorageBackendError> {
47        #[cfg(with_encryption)]
48        if self.encrypted {
49            self.vmgs
50                .write_file_encrypted(self.file_id, &data)
51                .await
52                .map_err(StorageBackendError::new)?;
53            return Ok(());
54        }
55
56        assert!(!self.encrypted);
57
58        self.vmgs
59            .write_file(self.file_id, &data)
60            .await
61            .map_err(StorageBackendError::new)?;
62
63        Ok(())
64    }
65
66    async fn restore(&mut self) -> Result<Option<Vec<u8>>, StorageBackendError> {
67        match self.vmgs.read_file(self.file_id).await {
68            Ok(buf) => Ok(Some(buf)),
69            Err(vmgs::Error::FileInfoAllocated) => Ok(None),
70            Err(e) => Err(StorageBackendError::new(e)),
71        }
72    }
73}