2626pub mod crc;
2727mod persist;
2828use std:: fmt:: Debug ;
29- use std:: io:: { Read , Seek , SeekFrom , Write } ;
29+ use std:: io:: { Read , Write } ;
3030
3131use bincode:: config;
3232use bincode:: config:: { Configuration , Fixint , Limit , LittleEndian } ;
3333use bincode:: error:: { DecodeError , EncodeError } ;
34+ use crc64:: crc64;
3435use semver:: Version ;
3536use serde:: de:: DeserializeOwned ;
3637use serde:: { Deserialize , Serialize } ;
3738
3839use crate :: persist:: SNAPSHOT_VERSION ;
39- use crate :: snapshot:: crc:: { CRC64Reader , CRC64Writer } ;
40+ use crate :: snapshot:: crc:: CRC64Writer ;
4041pub use crate :: snapshot:: persist:: Persist ;
41- use crate :: utils:: { mib_to_bytes, u64_to_usize } ;
42+ use crate :: utils:: mib_to_bytes;
4243
4344#[ cfg( target_arch = "x86_64" ) ]
4445const SNAPSHOT_MAGIC_ID : u64 = 0x0710_1984_8664_0000u64 ;
@@ -58,14 +59,12 @@ const SNAPSHOT_MAGIC_ID: u64 = 0x0710_1984_AAAA_0000u64;
5859/// Error definitions for the Snapshot API.
5960#[ derive( Debug , thiserror:: Error , displaydoc:: Display ) ]
6061pub enum SnapshotError {
61- /// CRC64 validation failed: {0}
62- Crc64 ( u64 ) ,
62+ /// CRC64 validation failed
63+ Crc64 ,
6364 /// Invalid data version: {0}
6465 InvalidFormatVersion ( Version ) ,
6566 /// Magic value does not match arch: {0}
6667 InvalidMagic ( u64 ) ,
67- /// Snapshot file is not long enough to even contain the CRC
68- TooShort ,
6968 /// An error occured during bincode encoding: {0}
7069 Encode ( #[ from] EncodeError ) ,
7170 /// An error occured during bincode decoding: {0}
@@ -152,24 +151,18 @@ impl<Data: DeserializeOwned> Snapshot<Data> {
152151
153152 /// Loads a snapshot from the given [`Read`] instance, performing all validations
154153 /// (CRC, snapshot magic value, snapshot version).
155- pub fn load < R : Read + Seek > ( reader : & mut R ) -> Result < Self , SnapshotError > {
156- let snapshot_size = reader. seek ( SeekFrom :: End ( 0 ) ) ?;
157- reader. seek ( SeekFrom :: Start ( 0 ) ) ?;
158- // dont read the CRC yet.
159- let mut buf = vec ! [
160- 0 ;
161- u64_to_usize( snapshot_size)
162- . checked_sub( size_of:: <u64 >( ) )
163- . ok_or( SnapshotError :: TooShort ) ?
164- ] ;
165- let mut crc_reader = CRC64Reader :: new ( reader) ;
166- crc_reader. read_exact ( buf. as_mut_slice ( ) ) ?;
154+ pub fn load < R : Read > ( reader : & mut R ) -> Result < Self , SnapshotError > {
155+ // read_to_end internally right-sizes the buffer, so no reallocations due to growing buffers
156+ // will happen.
157+ let mut buf = Vec :: new ( ) ;
158+ reader. read_to_end ( & mut buf) ?;
167159 let snapshot = Self :: load_without_crc_check ( buf. as_slice ( ) ) ?;
168- let computed_checksum = crc_reader. checksum ( ) ;
169- let stored_checksum: u64 =
170- bincode:: serde:: decode_from_std_read ( & mut crc_reader. reader , BINCODE_CONFIG ) ?;
171- if computed_checksum != stored_checksum {
172- return Err ( SnapshotError :: Crc64 ( computed_checksum) ) ;
160+ let computed_checksum = crc64 ( 0 , buf. as_slice ( ) ) ;
161+ // When we read the entire file, we also read the checksum into the buffer. The CRC has the
162+ // property that crc(0, buf.as_slice()) == 0 iff the last 8 bytes of buf are the checksum
163+ // of all the preceeding bytes, and this is the property we are using here.
164+ if computed_checksum != 0 {
165+ return Err ( SnapshotError :: Crc64 ) ;
173166 }
174167 Ok ( snapshot)
175168 }
@@ -187,19 +180,16 @@ impl<Data: Serialize> Snapshot<Data> {
187180
188181#[ cfg( test) ]
189182mod tests {
190- use vmm_sys_util:: tempfile:: TempFile ;
191-
192183 use super :: * ;
193184 use crate :: persist:: MicrovmState ;
194185
195186 #[ test]
196187 fn test_snapshot_restore ( ) {
197188 let state = MicrovmState :: default ( ) ;
198- let file = TempFile :: new ( ) . unwrap ( ) ;
189+ let mut buf = Vec :: new ( ) ;
199190
200- Snapshot :: new ( state) . save ( & mut file. as_file ( ) ) . unwrap ( ) ;
201- file. as_file ( ) . seek ( SeekFrom :: Start ( 0 ) ) . unwrap ( ) ;
202- Snapshot :: < MicrovmState > :: load ( & mut file. as_file ( ) ) . unwrap ( ) ;
191+ Snapshot :: new ( state) . save ( & mut buf) . unwrap ( ) ;
192+ Snapshot :: < MicrovmState > :: load ( & mut buf. as_slice ( ) ) . unwrap ( ) ;
203193 }
204194
205195 #[ test]
@@ -228,12 +218,6 @@ mod tests {
228218 }
229219 }
230220
231- impl Seek for BadReader {
232- fn seek ( & mut self , _pos : SeekFrom ) -> std:: io:: Result < u64 > {
233- Ok ( 9 ) // needs to be long enough to prevent to have a CRC
234- }
235- }
236-
237221 let mut reader = BadReader { } ;
238222
239223 assert ! (
@@ -275,7 +259,7 @@ mod tests {
275259
276260 assert ! ( matches!(
277261 Snapshot :: <( ) >:: load( & mut std:: io:: Cursor :: new( data. as_slice( ) ) ) ,
278- Err ( SnapshotError :: Crc64 ( _ ) )
262+ Err ( SnapshotError :: Crc64 )
279263 ) ) ;
280264 }
281265
0 commit comments