Nothing to see here, move along meow
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 5.7 kB View raw
1use lancer_lancerfs::integrity::{self, ReadHealOutcome}; 2use lancer_lancerfs::test_helpers::setup_fs; 3 4#[test] 5fn data_block_corruption_detected_on_read() { 6 let mut fs = setup_fs(4096); 7 let root = fs.root_block(); 8 let (_inode, block) = fs.create_file(root, b"corrupt_me"); 9 10 let data: Vec<u8> = (0..4096u16).map(|i| (i % 251) as u8).collect(); 11 fs.write_file(block, 0, &data); 12 fs.commit(); 13 14 let inode = fs.read_inode(block); 15 let phys = lancer_lancerfs::blockref_block_num(&inode.direct[0]); 16 17 let raw = fs.bio.raw_block_mut(phys).unwrap(); 18 raw[0] ^= 0xFF; 19 raw[1] ^= 0xFF; 20 21 fs.cache = lancer_lancerfs::test_helpers::make_cache(); 22 23 let result = fs.read_file_result(block, 0, 4096); 24 assert!( 25 result.is_err(), 26 "reading a corrupted data block must return IntegrityFailure" 27 ); 28} 29 30#[test] 31fn metadata_healing_repairs_from_ditto_on_committed_block() { 32 let mut fs = setup_fs(16384); 33 let root = fs.root_block(); 34 35 (0..10u32).for_each(|i| { 36 let name = format!("f_{:03}", i).into_bytes(); 37 let (_inode, block) = fs.create_file(root, &name); 38 let data = vec![(i & 0xFF) as u8; 128]; 39 fs.write_file(block, 0, &data); 40 }); 41 fs.commit(); 42 43 let tree_root = fs.state.sb_pair.active().tree_root; 44 let tree_root_block = lancer_lancerfs::blockref_block_num(&tree_root); 45 let expected_crc = tree_root.integrity_crc; 46 47 let ditto_block = match fs.state.ditto.ditto_addr(tree_root_block) { 48 Some(d) => d, 49 None => { 50 eprintln!( 51 "tree root block {} has no ditto mapping, skipping healing test", 52 tree_root_block 53 ); 54 return; 55 } 56 }; 57 58 let ditto_crc = { 59 let mut buf = [0u8; 4096]; 60 fs.bio.read_blocks(ditto_block, 1, &mut buf).unwrap(); 61 integrity::crc32c(&buf) 62 }; 63 64 match ditto_crc == expected_crc { 65 true => {} 66 false => { 67 eprintln!( 68 "ditto copy was overwritten (collision), skipping healing test. \ 69 primary crc={expected_crc}, ditto crc={ditto_crc}" 70 ); 71 return; 72 } 73 } 74 75 let raw = fs.bio.raw_block_mut(tree_root_block).unwrap(); 76 raw[0] ^= 0xFF; 77 raw[100] ^= 0xFF; 78 raw[200] ^= 0xFF; 79 80 fs.cache = lancer_lancerfs::test_helpers::make_cache(); 81 82 let result = integrity::metadata_read_healing( 83 &mut fs.cache, 84 &mut fs.bio, 85 &fs.state.ditto, 86 tree_root_block, 87 expected_crc, 88 ); 89 90 match result { 91 Ok(ReadHealOutcome::Repaired) => {} 92 Ok(ReadHealOutcome::Clean) => panic!("expected Repaired, got Clean"), 93 Err(_) => panic!("expected Repaired, got Err"), 94 } 95 96 let mut healed_buf = [0u8; 4096]; 97 fs.bio 98 .read_blocks(tree_root_block, 1, &mut healed_buf) 99 .unwrap(); 100 let healed_crc = integrity::crc32c(&healed_buf); 101 assert_eq!( 102 healed_crc, expected_crc, 103 "primary block must have correct CRC after healing" 104 ); 105 106 fs.cache = lancer_lancerfs::test_helpers::make_cache(); 107 (0..10u32).for_each(|i| { 108 let name = format!("f_{:03}", i).into_bytes(); 109 let file_block = fs 110 .lookup_file(root, &name) 111 .unwrap_or_else(|| panic!("file {} must be readable after healing", i)); 112 let data = fs.read_file(file_block, 0, 128); 113 assert_eq!( 114 data, 115 vec![(i & 0xFF) as u8; 128], 116 "file {} data must be correct after metadata healing", 117 i 118 ); 119 }); 120} 121 122#[test] 123fn both_copies_corrupt_returns_error() { 124 let mut fs = setup_fs(16384); 125 let root = fs.root_block(); 126 127 (0..10u32).for_each(|i| { 128 let name = format!("g_{:03}", i).into_bytes(); 129 fs.create_file(root, &name); 130 }); 131 fs.commit(); 132 133 let tree_root = fs.state.sb_pair.active().tree_root; 134 let tree_root_block = lancer_lancerfs::blockref_block_num(&tree_root); 135 let expected_crc = tree_root.integrity_crc; 136 let ditto_block = match fs.state.ditto.ditto_addr(tree_root_block) { 137 Some(d) => d, 138 None => { 139 eprintln!("tree root block has no ditto mapping, skipping"); 140 return; 141 } 142 }; 143 144 let raw_primary = fs.bio.raw_block_mut(tree_root_block).unwrap(); 145 raw_primary[0] ^= 0xFF; 146 147 let raw_ditto = fs.bio.raw_block_mut(ditto_block).unwrap(); 148 raw_ditto[0] ^= 0xFF; 149 150 fs.cache = lancer_lancerfs::test_helpers::make_cache(); 151 152 let result = integrity::metadata_read_healing( 153 &mut fs.cache, 154 &mut fs.bio, 155 &fs.state.ditto, 156 tree_root_block, 157 expected_crc, 158 ); 159 160 assert!(result.is_err(), "both copies corrupt must return error"); 161} 162 163#[test] 164fn verify_path_detects_corruption() { 165 let mut fs = setup_fs(8192); 166 let root = fs.root_block(); 167 168 (0..5u32).for_each(|i| { 169 let name = format!("vp_{:03}", i).into_bytes(); 170 fs.create_file(root, &name); 171 }); 172 fs.commit(); 173 174 let tree_root = fs.state.sb_pair.active().tree_root; 175 176 let clean_result = integrity::verify_path(&mut fs.cache, &mut fs.bio, &tree_root, 1); 177 assert!( 178 clean_result.is_ok(), 179 "clean tree path must verify successfully" 180 ); 181 182 let tree_root_block = lancer_lancerfs::blockref_block_num(&tree_root); 183 let raw = fs.bio.raw_block_mut(tree_root_block).unwrap(); 184 raw[0] ^= 0xFF; 185 186 fs.cache = lancer_lancerfs::test_helpers::make_cache(); 187 188 let corrupt_result = integrity::verify_path(&mut fs.cache, &mut fs.bio, &tree_root, 1); 189 assert!( 190 corrupt_result.is_err(), 191 "corrupted tree root must fail path verification" 192 ); 193}