1#![deny(missing_docs)]
5
6mod persist;
29use std::fmt::Debug;
30use std::io::{Read, Write};
31
32use versionize::crc::{CRC64Reader, CRC64Writer};
33use versionize::{VersionMap, Versionize, VersionizeResult};
34use versionize_derive::Versionize;
35
36pub use crate::persist::Persist;
37
38const BASE_MAGIC_ID_MASK: u64 = !0xFFFFu64;
39
40#[cfg(target_arch = "x86_64")]
41const BASE_MAGIC_ID: u64 = 0x0710_1984_8664_0000u64;
42
43#[cfg(target_arch = "aarch64")]
44const BASE_MAGIC_ID: u64 = 0x0710_1984_AAAA_0000u64;
45
46#[cfg(target_arch = "powerpc64")]
47const BASE_MAGIC_ID: u64 = 0x0710_1984_CC64_0000u64;
48
49#[cfg(target_arch = "riscv64")]
50const BASE_MAGIC_ID: u64 = 0x0710_1984_C564_0000u64;
51
52#[derive(Debug, thiserror::Error, displaydoc::Display, PartialEq)]
54pub enum Error {
55 Crc64(u64),
57 InvalidDataVersion(u16),
59 InvalidFormatVersion(u16),
61 InvalidMagic(u64),
63 InvalidSnapshotSize,
65 Io(i32),
67 Versionize(versionize::VersionizeError),
69}
70
71#[derive(Default, Debug, Versionize)]
72struct SnapshotHdr {
73 data_version: u16,
75}
76
77#[derive(Debug)]
80pub struct Snapshot {
81 hdr: SnapshotHdr,
82 version_map: VersionMap,
83 target_version: u16,
85}
86
87fn get_format_version(magic_id: u64) -> Result<u16, Error> {
89 let magic_arch = magic_id & BASE_MAGIC_ID_MASK;
90 if magic_arch == BASE_MAGIC_ID {
91 return Ok((magic_id & !BASE_MAGIC_ID_MASK) as u16);
92 }
93 Err(Error::InvalidMagic(magic_id))
94}
95
96fn build_magic_id(format_version: u16) -> u64 {
97 BASE_MAGIC_ID | u64::from(format_version)
98}
99
100impl Snapshot {
101 pub fn new(version_map: VersionMap, target_version: u16) -> Snapshot {
103 Snapshot {
104 version_map,
105 hdr: SnapshotHdr::default(),
106 target_version,
107 }
108 }
109
110 pub fn get_data_version<T>(mut reader: &mut T, version_map: &VersionMap) -> Result<u16, Error>
112 where
113 T: Read + Debug,
114 {
115 let format_version_map = Self::format_version_map();
116 let magic_id =
117 <u64 as Versionize>::deserialize(&mut reader, &format_version_map, 0 )
118 .map_err(Error::Versionize)?;
119
120 let format_version = get_format_version(magic_id)?;
121 if format_version > format_version_map.latest_version() || format_version == 0 {
122 return Err(Error::InvalidFormatVersion(format_version));
123 }
124
125 let hdr: SnapshotHdr =
126 SnapshotHdr::deserialize(&mut reader, &format_version_map, format_version)
127 .map_err(Error::Versionize)?;
128 if hdr.data_version > version_map.latest_version() || hdr.data_version == 0 {
129 return Err(Error::InvalidDataVersion(hdr.data_version));
130 }
131
132 Ok(hdr.data_version)
133 }
134
135 pub fn unchecked_load<T: Read + Debug, O: Versionize + Debug>(
137 mut reader: &mut T,
138 version_map: VersionMap,
139 ) -> Result<(O, u16), Error> {
140 let data_version = Self::get_data_version(&mut reader, &version_map)?;
141 let res =
142 O::deserialize(&mut reader, &version_map, data_version).map_err(Error::Versionize)?;
143 Ok((res, data_version))
144 }
145
146 pub fn load<T: Read + Debug, O: Versionize + Debug>(
148 reader: &mut T,
149 snapshot_len: usize,
150 version_map: VersionMap,
151 ) -> Result<(O, u16), Error> {
152 let mut crc_reader = CRC64Reader::new(reader);
153
154 let raw_snapshot_len = snapshot_len
156 .checked_sub(std::mem::size_of::<u64>())
157 .ok_or(Error::InvalidSnapshotSize)?;
158 let mut snapshot = vec![0u8; raw_snapshot_len];
159 crc_reader
160 .read_exact(&mut snapshot)
161 .map_err(|ref err| Error::Io(err.raw_os_error().unwrap_or(libc::EINVAL)))?;
162
163 let computed_checksum = crc_reader.checksum();
167 let format_vm = Self::format_version_map();
168 let stored_checksum: u64 =
169 Versionize::deserialize(&mut crc_reader, &format_vm, 0).map_err(Error::Versionize)?;
170 if computed_checksum != stored_checksum {
171 return Err(Error::Crc64(computed_checksum));
172 }
173
174 let mut snapshot_slice: &[u8] = snapshot.as_mut_slice();
175 Snapshot::unchecked_load::<_, O>(&mut snapshot_slice, version_map)
176 }
177
178 pub fn save<T, O>(&mut self, writer: &mut T, object: &O) -> Result<(), Error>
180 where
181 T: Write + Debug,
182 O: Versionize + Debug,
183 {
184 let mut crc_writer = CRC64Writer::new(writer);
185 self.save_without_crc(&mut crc_writer, object)?;
186
187 let checksum = crc_writer.checksum();
188 checksum
189 .serialize(&mut crc_writer, &Self::format_version_map(), 0)
190 .map_err(Error::Versionize)?;
191 Ok(())
192 }
193
194 pub fn save_without_crc<T, O>(&mut self, mut writer: &mut T, object: &O) -> Result<(), Error>
198 where
199 T: Write,
200 O: Versionize + Debug,
201 {
202 self.hdr = SnapshotHdr {
203 data_version: self.target_version,
204 };
205
206 let format_version_map = Self::format_version_map();
207 let magic_id = build_magic_id(format_version_map.latest_version());
208
209 magic_id
211 .serialize(&mut writer, &format_version_map, 0 )
212 .map_err(Error::Versionize)?;
213
214 self.hdr
216 .serialize(
217 &mut writer,
218 &format_version_map,
219 format_version_map.latest_version(),
220 )
221 .map_err(Error::Versionize)?;
222
223 object
225 .serialize(&mut writer, &self.version_map, self.target_version)
226 .map_err(Error::Versionize)?;
227 writer
228 .flush()
229 .map_err(|ref err| Error::Io(err.raw_os_error().unwrap_or(libc::EINVAL)))
230 }
231
232 fn format_version_map() -> VersionMap {
238 VersionMap::new()
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use super::*;
246
247 #[derive(Clone, Debug, Versionize)]
248 pub struct Test1 {
249 field_x: u64,
250 field0: u64,
251 field1: u32,
252 }
253
254 #[derive(Clone, Debug, Versionize)]
255 pub struct Test {
256 field_x: u64,
257 field0: u64,
258 field1: u32,
259 #[version(start = 2, default_fn = "field2_default")]
260 field2: u64,
261 #[version(
262 start = 3,
263 default_fn = "field3_default",
264 ser_fn = "field3_serialize",
265 de_fn = "field3_deserialize"
266 )]
267 field3: String,
268 #[version(
269 start = 4,
270 default_fn = "field4_default",
271 ser_fn = "field4_serialize",
272 de_fn = "field4_deserialize"
273 )]
274 field4: Vec<u64>,
275 }
276
277 impl Test {
278 fn field2_default(_: u16) -> u64 {
279 20
280 }
281 fn field3_default(_: u16) -> String {
282 "default".to_owned()
283 }
284 fn field4_default(_: u16) -> Vec<u64> {
285 vec![1, 2, 3, 4]
286 }
287 fn field4_serialize(&mut self, target_version: u16) -> VersionizeResult<()> {
288 assert_ne!(target_version, Test::version());
290 self.field0 = self.field4.iter().sum();
291
292 if self.field0 == 6666 {
293 return Err(versionize::VersionizeError::Semantic(
294 "field4 element sum is 6666".to_owned(),
295 ));
296 }
297 Ok(())
298 }
299 fn field4_deserialize(&mut self, source_version: u16) -> VersionizeResult<()> {
300 assert_ne!(source_version, Test::version());
302 self.field4 = vec![self.field0; 4];
303 Ok(())
304 }
305
306 fn field3_serialize(&mut self, target_version: u16) -> VersionizeResult<()> {
307 assert!(target_version < 3);
309 self.field_x += 1;
310 Ok(())
311 }
312
313 fn field3_deserialize(&mut self, source_version: u16) -> VersionizeResult<()> {
314 assert!(source_version < 3);
316 self.field_x += 1;
317 if self.field0 == 7777 {
318 return Err(versionize::VersionizeError::Semantic(
319 "field0 is 7777".to_owned(),
320 ));
321 }
322 Ok(())
323 }
324 }
325
326 #[test]
327 fn test_get_format_version() {
328 #[cfg(target_arch = "x86_64")]
332 let good_magic_id = 0x0710_1984_8664_0001u64;
333 #[cfg(target_arch = "aarch64")]
334 let good_magic_id = 0x0710_1984_AAAA_0001u64;
335 #[cfg(target_arch = "powerpc64")]
336 let good_magic_id = 0x0710_1984_CC64_0001u64;
337 #[cfg(target_arch = "riscv64")]
338 let good_magic_id = 0x0710_1984_C564_0001u64;
339
340 assert_eq!(get_format_version(good_magic_id).unwrap(), 1u16);
341
342 let invalid_magic_id = good_magic_id | (1u64 << 63);
344 assert_eq!(
345 get_format_version(invalid_magic_id).unwrap_err(),
346 Error::InvalidMagic(invalid_magic_id)
347 );
348 }
349
350 #[test]
351 fn test_struct_semantic_fn() {
352 let mut vm = VersionMap::new();
353 vm.new_version()
354 .set_type_version(Test::type_id(), 2)
355 .new_version()
356 .set_type_version(Test::type_id(), 3)
357 .new_version()
358 .set_type_version(Test::type_id(), 4);
359 let state = Test {
360 field0: 0,
361 field1: 1,
362 field2: 2,
363 field3: "test".to_owned(),
364 field4: vec![4, 3, 2, 1],
365 field_x: 0,
366 };
367
368 let mut snapshot_mem = vec![0u8; 1024];
369
370 let mut snapshot = Snapshot::new(vm.clone(), 1);
372 snapshot
373 .save_without_crc(&mut snapshot_mem.as_mut_slice(), &state)
374 .unwrap();
375
376 let (mut restored_state, _) =
377 Snapshot::unchecked_load::<_, Test>(&mut snapshot_mem.as_slice(), vm.clone()).unwrap();
378
379 assert_eq!(restored_state.field0, state.field4.iter().sum::<u64>());
381 assert_eq!(restored_state.field4, vec![restored_state.field0; 4]);
383 assert_eq!(restored_state.field_x, 2);
385 assert_eq!(restored_state.field1, 1);
387 assert_eq!(restored_state.field2, 20);
389
390 let mut snapshot = Snapshot::new(vm.clone(), 3);
392 snapshot
393 .save_without_crc(&mut snapshot_mem.as_mut_slice(), &state)
394 .unwrap();
395
396 (restored_state, _) =
397 Snapshot::unchecked_load::<_, Test>(&mut snapshot_mem.as_slice(), vm.clone()).unwrap();
398
399 assert_eq!(restored_state.field0, state.field4.iter().sum::<u64>());
402 assert_eq!(restored_state.field4, vec![restored_state.field0; 4]);
404 assert_eq!(restored_state.field_x, 0);
406
407 snapshot = Snapshot::new(vm.clone(), 4);
409 snapshot
410 .save_without_crc(&mut snapshot_mem.as_mut_slice(), &state)
411 .unwrap();
412
413 (restored_state, _) =
414 Snapshot::unchecked_load::<_, Test>(&mut snapshot_mem.as_slice(), vm.clone()).unwrap();
415
416 assert_eq!(restored_state.field0, 0);
418 assert_eq!(restored_state.field4, vec![4, 3, 2, 1]);
419
420 snapshot_mem.truncate(10);
424 let restored_state_result: Result<(Test, _), Error> =
425 Snapshot::unchecked_load(&mut snapshot_mem.as_slice(), vm);
426
427 assert_eq!(
428 restored_state_result.unwrap_err(),
429 Error::Versionize(versionize::VersionizeError::Deserialize(String::from(
430 "Io(Error { kind: UnexpectedEof, message: \"failed to fill whole buffer\" })"
431 )))
432 );
433 }
434
435 #[test]
436 fn test_struct_default_fn() {
437 let mut vm = VersionMap::new();
438 vm.new_version()
439 .set_type_version(Test::type_id(), 2)
440 .new_version()
441 .set_type_version(Test::type_id(), 3)
442 .new_version()
443 .set_type_version(Test::type_id(), 4);
444 let state = Test {
445 field0: 0,
446 field1: 1,
447 field2: 2,
448 field3: "test".to_owned(),
449 field4: vec![4, 3, 2, 1],
450 field_x: 0,
451 };
452
453 let state_1 = Test1 {
454 field_x: 0,
455 field0: 0,
456 field1: 1,
457 };
458
459 let mut snapshot_mem = vec![0u8; 1024];
460
461 let mut snapshot = Snapshot::new(vm.clone(), 1);
463 snapshot
464 .save_without_crc(&mut snapshot_mem.as_mut_slice(), &state_1)
465 .unwrap();
466
467 let (mut restored_state, _) =
468 Snapshot::unchecked_load::<_, Test>(&mut snapshot_mem.as_slice(), vm.clone()).unwrap();
469 assert_eq!(restored_state.field1, state_1.field1);
470 assert_eq!(restored_state.field2, 20);
471 assert_eq!(restored_state.field3, "default");
472
473 snapshot = Snapshot::new(vm.clone(), 2);
475 snapshot
476 .save_without_crc(&mut snapshot_mem.as_mut_slice(), &state)
477 .unwrap();
478
479 (restored_state, _) =
480 Snapshot::unchecked_load::<_, Test>(&mut snapshot_mem.as_slice(), vm.clone()).unwrap();
481 assert_eq!(restored_state.field1, state.field1);
482 assert_eq!(restored_state.field2, 2);
483 assert_eq!(restored_state.field3, "default");
484
485 snapshot = Snapshot::new(vm.clone(), 3);
487 snapshot
488 .save_without_crc(&mut snapshot_mem.as_mut_slice(), &state)
489 .unwrap();
490
491 (restored_state, _) =
492 Snapshot::unchecked_load::<_, Test>(&mut snapshot_mem.as_slice(), vm.clone()).unwrap();
493 assert_eq!(restored_state.field1, state.field1);
494 assert_eq!(restored_state.field2, 2);
495 assert_eq!(restored_state.field3, "test");
496
497 snapshot = Snapshot::new(vm.clone(), 4);
499 snapshot
500 .save_without_crc(&mut snapshot_mem.as_mut_slice(), &state)
501 .unwrap();
502
503 (restored_state, _) =
504 Snapshot::unchecked_load::<_, Test>(&mut snapshot_mem.as_slice(), vm.clone()).unwrap();
505 assert_eq!(restored_state.field1, state.field1);
506 assert_eq!(restored_state.field2, 2);
507 assert_eq!(restored_state.field3, "test");
508 }
509
510 #[test]
511 fn test_crc_ok() {
512 let vm = VersionMap::new();
513 let state_1 = Test1 {
514 field_x: 0,
515 field0: 0,
516 field1: 1,
517 };
518
519 let mut snapshot_mem = vec![0u8; 1024];
520
521 let mut snapshot = Snapshot::new(vm.clone(), 1);
523 snapshot
524 .save(&mut snapshot_mem.as_mut_slice(), &state_1)
525 .unwrap();
526
527 let _ = Snapshot::load::<_, Test1>(&mut snapshot_mem.as_slice(), 38, vm).unwrap();
528 }
529
530 #[test]
531 fn test_invalid_snapshot_size() {
532 let vm = VersionMap::new();
533 let snapshot_mem = vec![0u8; 4];
535 let expected_err = Error::InvalidSnapshotSize;
536 let load_result: Result<(Test1, _), Error> =
537 Snapshot::load(&mut snapshot_mem.as_slice(), 4, vm);
538 assert_eq!(load_result.unwrap_err(), expected_err);
539 }
540
541 #[test]
542 fn test_corrupted_snapshot() {
543 let vm = VersionMap::new();
544 let state_1 = Test1 {
545 field_x: 0,
546 field0: 0,
547 field1: 1,
548 };
549
550 let mut snapshot_mem = vec![0u8; 1024];
551
552 let mut snapshot = Snapshot::new(vm.clone(), 1);
554 snapshot
555 .save(&mut snapshot_mem.as_mut_slice(), &state_1)
556 .unwrap();
557 snapshot_mem[20] = 123;
558
559 #[cfg(target_arch = "aarch64")]
560 let expected_err = Error::Crc64(0x1960_4E6A_A13F_6615);
561 #[cfg(target_arch = "x86_64")]
562 let expected_err = Error::Crc64(0x103F_8F52_8F51_20B1);
563 #[cfg(target_arch = "powerpc64")]
564 let expected_err = Error::Crc64(0x33D0_CCE5_DA3C_CCEA);
565 #[cfg(target_arch = "riscv64")]
566 let expected_err = Error::Crc64(0xFAC5_E225_5586_9011);
567
568 let load_result: Result<(Test1, _), Error> =
569 Snapshot::load(&mut snapshot_mem.as_slice(), 38, vm);
570 assert_eq!(load_result.unwrap_err(), expected_err);
571 }
572
573 #[allow(non_upper_case_globals)]
574 #[allow(non_camel_case_types)]
575 #[allow(non_snake_case)]
576 #[test]
577 fn test_kvm_bindings_struct() {
578 #[repr(C)]
579 #[derive(Debug, PartialEq, Eq, Versionize)]
580 pub struct kvm_pit_config {
581 pub flags: ::std::os::raw::c_uint,
582 pub pad: [::std::os::raw::c_uint; 15usize],
583 }
584
585 let state = kvm_pit_config {
586 flags: 123_456,
587 pad: [0; 15usize],
588 };
589
590 let vm = VersionMap::new();
591 let mut snapshot_mem = vec![0u8; 1024];
592 let mut snapshot = Snapshot::new(vm.clone(), 1);
594 snapshot
595 .save_without_crc(&mut snapshot_mem.as_mut_slice(), &state)
596 .unwrap();
597
598 let (restored_state, _) =
599 Snapshot::unchecked_load::<_, kvm_pit_config>(&mut snapshot_mem.as_slice(), vm)
600 .unwrap();
601 assert_eq!(restored_state, state);
602 }
603}