1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
use byteorder::{BigEndian, ByteOrder}; use crc::crc16::checksum_usb; pub fn double_buffer_check(buffer_0: &[u8], buffer_1: &[u8]) -> (u8, bool) { assert!(buffer_0.len() == buffer_1.len()); let checksum_pos = buffer_0.len() - 2; let valid_0 = checksum_usb(&buffer_0[0..checksum_pos]) == BigEndian::read_u16(&buffer_0[checksum_pos..checksum_pos + 2]); let valid_1 = checksum_usb(&buffer_1[0..checksum_pos]) == BigEndian::read_u16(&buffer_1[checksum_pos..checksum_pos + 2]); let flush_number_0 = buffer_0[buffer_0.len() - 3]; let flush_number_1 = buffer_1[buffer_1.len() - 3]; if valid_0 && valid_1 { if (flush_number_0 == 2 && flush_number_1 == 1) || (flush_number_0 == 0 && flush_number_1 == 3) { (flush_number_0, true) } else { (flush_number_1, false) } } else if valid_0 { (flush_number_0, true) } else if valid_1 { (flush_number_1, false) } else { panic!("cannot open this persy archive seems to have a corrupted journal"); } } pub fn prepare_buffer_flush(buffer: &mut [u8], mut last_flush: u8) -> (u8, u32) { last_flush += 1; if last_flush == 4 { last_flush = 0; } let checksum_pos = buffer.len() - 2; buffer[buffer.len() - 3] = last_flush; let crc = checksum_usb(&buffer[0..checksum_pos]); BigEndian::write_u16(&mut buffer[checksum_pos..checksum_pos + 2], crc); let offset = if last_flush % 2 == 0 { 0 } else { buffer.len() as u32 }; (last_flush, offset) } #[cfg(test)] mod tests { use super::{double_buffer_check, prepare_buffer_flush}; use byteorder::{BigEndian, ByteOrder}; #[test] fn first_valid() { let mut buffer_0 = [0; 11]; let buffer_1 = [0; 11]; BigEndian::write_u64(&mut buffer_0, 10); prepare_buffer_flush(&mut buffer_0, 0); let (flush, first) = double_buffer_check(&buffer_0, &buffer_1); assert!(first); assert_eq!(flush, 1); let mut buffer_0 = [0; 11]; let mut buffer_1 = [0; 11]; BigEndian::write_u64(&mut buffer_0, 10); prepare_buffer_flush(&mut buffer_0, 0); BigEndian::write_u64(&mut buffer_1, 10); prepare_buffer_flush(&mut buffer_1, 1); buffer_1[10] = 2; let (flush, first) = double_buffer_check(&buffer_0, &buffer_1); assert!(first); assert_eq!(flush, 1); let mut buffer_0 = [0; 11]; let mut buffer_1 = [0; 11]; BigEndian::write_u64(&mut buffer_0, 10); prepare_buffer_flush(&mut buffer_0, 3); BigEndian::write_u64(&mut buffer_1, 10); prepare_buffer_flush(&mut buffer_1, 2); buffer_1[10] = 2; let (flush, first) = double_buffer_check(&buffer_0, &buffer_1); assert!(first); assert_eq!(flush, 0); } #[test] fn second_valid() { let mut buffer_0 = [0; 11]; let mut buffer_1 = [0; 11]; BigEndian::write_u64(&mut buffer_0, 10); prepare_buffer_flush(&mut buffer_0, 0); BigEndian::write_u64(&mut buffer_1, 10); prepare_buffer_flush(&mut buffer_1, 1); let (flush, first) = double_buffer_check(&buffer_0, &buffer_1); assert!(!first); assert_eq!(flush, 2); let mut buffer_0 = [0; 11]; let mut buffer_1 = [0; 11]; BigEndian::write_u64(&mut buffer_0, 10); prepare_buffer_flush(&mut buffer_0, 2); buffer_0[10] = 4; BigEndian::write_u64(&mut buffer_1, 10); prepare_buffer_flush(&mut buffer_1, 1); let (flush, first) = double_buffer_check(&buffer_0, &buffer_1); assert!(!first); assert_eq!(flush, 2); } }