Skip to main content

openvmm_helpers/snapshot/
publish.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Writing VM snapshots to a directory.
5
6use super::SnapshotManifest;
7use anyhow::Context;
8use std::path::Path;
9
10/// Write a snapshot to the given directory.
11///
12/// The directory is created if it does not exist. The snapshot consists of:
13/// - `manifest.bin` — protobuf-encoded [`SnapshotManifest`]
14/// - `state.bin` — raw device saved-state bytes
15/// - `memory.bin` — hard link to the memory backing file
16pub fn write_snapshot(
17    dir: &Path,
18    manifest: &SnapshotManifest,
19    saved_state_bytes: &[u8],
20    memory_file_path: &Path,
21) -> anyhow::Result<()> {
22    fs_err::create_dir_all(dir)?;
23
24    // Write manifest.
25    let manifest_bytes = mesh::payload::encode(manifest.clone());
26    fs_err::write(dir.join("manifest.bin"), &manifest_bytes)?;
27
28    // Write device state.
29    fs_err::write(dir.join("state.bin"), saved_state_bytes)?;
30
31    // Handle memory.bin: hard-link from the backing file.
32    let memory_bin_path = dir.join("memory.bin");
33    let canonical_source = fs_err::canonicalize(memory_file_path)?;
34
35    // Check whether source and target are already the same file (e.g.,
36    // the user pointed --memory-backing-file at <dir>/memory.bin directly).
37    let needs_link = if memory_bin_path.exists() {
38        let canonical_target = fs_err::canonicalize(&memory_bin_path)?;
39        if canonical_source == canonical_target {
40            false
41        } else {
42            // Different file at the target path — remove it so the hard
43            // link can be created.
44            fs_err::remove_file(&memory_bin_path)?;
45            true
46        }
47    } else {
48        true
49    };
50
51    if needs_link {
52        if let Err(err) = std::fs::hard_link(&canonical_source, &memory_bin_path) {
53            if err.kind() == std::io::ErrorKind::CrossesDevices {
54                anyhow::bail!(
55                    "memory backing file ({}) must be on the same filesystem as the snapshot \
56                     directory ({}); consider placing the backing file inside the snapshot \
57                     directory",
58                    memory_file_path.display(),
59                    dir.display(),
60                );
61            }
62            return Err(err).with_context(|| {
63                format!(
64                    "failed to hard-link {} -> {}",
65                    canonical_source.display(),
66                    memory_bin_path.display()
67                )
68            });
69        }
70    }
71
72    Ok(())
73}