1 // Copyright © 2020 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 use std::fs::File; 6 use std::io::Read; 7 use std::path::PathBuf; 8 9 use anyhow::anyhow; 10 use vm_migration::{MigratableError, Snapshot}; 11 12 #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))] 13 use crate::coredump::GuestDebuggableError; 14 use crate::{config::VmConfig, vm::VmSnapshot}; 15 16 pub const SNAPSHOT_STATE_FILE: &str = "state.json"; 17 pub const SNAPSHOT_CONFIG_FILE: &str = "config.json"; 18 19 pub fn url_to_path(url: &str) -> std::result::Result<PathBuf, MigratableError> { 20 let path: PathBuf = url 21 .strip_prefix("file://") 22 .ok_or_else(|| { 23 MigratableError::MigrateSend(anyhow!("Could not extract path from URL: {}", url)) 24 }) 25 .map(|s| s.into())?; 26 27 if !path.is_dir() { 28 return Err(MigratableError::MigrateSend(anyhow!( 29 "Destination is not a directory" 30 ))); 31 } 32 33 Ok(path) 34 } 35 36 #[cfg(all(target_arch = "x86_64", feature = "guest_debug"))] 37 pub fn url_to_file(url: &str) -> std::result::Result<PathBuf, GuestDebuggableError> { 38 let file: PathBuf = url 39 .strip_prefix("file://") 40 .ok_or_else(|| { 41 GuestDebuggableError::Coredump(anyhow!("Could not extract file from URL: {}", url)) 42 }) 43 .map(|s| s.into())?; 44 45 Ok(file) 46 } 47 48 pub fn recv_vm_config(source_url: &str) -> std::result::Result<VmConfig, MigratableError> { 49 let mut vm_config_path = url_to_path(source_url)?; 50 51 vm_config_path.push(SNAPSHOT_CONFIG_FILE); 52 53 // Try opening the snapshot file 54 let mut vm_config_file = 55 File::open(vm_config_path).map_err(|e| MigratableError::MigrateReceive(e.into()))?; 56 let mut bytes = Vec::new(); 57 vm_config_file 58 .read_to_end(&mut bytes) 59 .map_err(|e| MigratableError::MigrateReceive(e.into()))?; 60 61 serde_json::from_slice(&bytes).map_err(|e| MigratableError::MigrateReceive(e.into())) 62 } 63 64 pub fn recv_vm_state(source_url: &str) -> std::result::Result<Snapshot, MigratableError> { 65 let mut vm_state_path = url_to_path(source_url)?; 66 67 vm_state_path.push(SNAPSHOT_STATE_FILE); 68 69 // Try opening the snapshot file 70 let mut vm_state_file = 71 File::open(vm_state_path).map_err(|e| MigratableError::MigrateReceive(e.into()))?; 72 let mut bytes = Vec::new(); 73 vm_state_file 74 .read_to_end(&mut bytes) 75 .map_err(|e| MigratableError::MigrateReceive(e.into()))?; 76 77 serde_json::from_slice(&bytes).map_err(|e| MigratableError::MigrateReceive(e.into())) 78 } 79 80 pub fn get_vm_snapshot(snapshot: &Snapshot) -> std::result::Result<VmSnapshot, MigratableError> { 81 if let Some(snapshot_data) = snapshot.snapshot_data.as_ref() { 82 return snapshot_data.to_state(); 83 } 84 85 Err(MigratableError::Restore(anyhow!( 86 "Could not find VM config snapshot section" 87 ))) 88 } 89