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