48 Ok((parents, entries, copies)) |
48 Ok((parents, entries, copies)) |
49 } |
49 } |
50 |
50 |
51 #[derive(BytesCast)] |
51 #[derive(BytesCast)] |
52 #[repr(C)] |
52 #[repr(C)] |
53 pub(super) struct RawEntry { |
53 struct RawEntry { |
54 state: u8, |
54 state: u8, |
55 mode: unaligned::I32Be, |
55 mode: unaligned::I32Be, |
56 size: unaligned::I32Be, |
56 size: unaligned::I32Be, |
57 mtime: unaligned::I32Be, |
57 mtime: unaligned::I32Be, |
58 length: unaligned::I32Be, |
58 length: unaligned::I32Be, |
71 contents = rest; |
71 contents = rest; |
72 while !contents.is_empty() { |
72 while !contents.is_empty() { |
73 let (raw_entry, rest) = RawEntry::from_bytes(contents) |
73 let (raw_entry, rest) = RawEntry::from_bytes(contents) |
74 .map_err(|_| HgError::corrupted("Overflow in dirstate."))?; |
74 .map_err(|_| HgError::corrupted("Overflow in dirstate."))?; |
75 |
75 |
76 let entry = DirstateEntry { |
76 let entry = DirstateEntry::from_v1_data( |
77 state: EntryState::try_from(raw_entry.state)?, |
77 EntryState::try_from(raw_entry.state)?, |
78 mode: raw_entry.mode.get(), |
78 raw_entry.mode.get(), |
79 mtime: raw_entry.mtime.get(), |
79 raw_entry.size.get(), |
80 size: raw_entry.size.get(), |
80 raw_entry.mtime.get(), |
81 }; |
81 ); |
82 let (paths, rest) = |
82 let (paths, rest) = |
83 u8::slice_from_bytes(rest, raw_entry.length.get() as usize) |
83 u8::slice_from_bytes(rest, raw_entry.length.get() as usize) |
84 .map_err(|_| HgError::corrupted("Overflow in dirstate."))?; |
84 .map_err(|_| HgError::corrupted("Overflow in dirstate."))?; |
85 |
85 |
86 // `paths` is either a single path, or two paths separated by a NULL |
86 // `paths` is either a single path, or two paths separated by a NULL |
122 entry: &DirstateEntry, |
122 entry: &DirstateEntry, |
123 copy_source: Option<&HgPath>, |
123 copy_source: Option<&HgPath>, |
124 packed: &mut Vec<u8>, |
124 packed: &mut Vec<u8>, |
125 ) { |
125 ) { |
126 let length = packed_filename_and_copy_source_size(filename, copy_source); |
126 let length = packed_filename_and_copy_source_size(filename, copy_source); |
|
127 let (state, mode, size, mtime) = entry.v1_data(); |
127 |
128 |
128 // Unwrapping because `impl std::io::Write for Vec<u8>` never errors |
129 // Unwrapping because `impl std::io::Write for Vec<u8>` never errors |
129 packed.write_u8(entry.state.into()).unwrap(); |
130 packed.write_u8(state).unwrap(); |
130 packed.write_i32::<BigEndian>(entry.mode).unwrap(); |
131 packed.write_i32::<BigEndian>(mode).unwrap(); |
131 packed.write_i32::<BigEndian>(entry.size).unwrap(); |
132 packed.write_i32::<BigEndian>(size).unwrap(); |
132 packed.write_i32::<BigEndian>(entry.mtime).unwrap(); |
133 packed.write_i32::<BigEndian>(mtime).unwrap(); |
133 packed.write_i32::<BigEndian>(length as i32).unwrap(); |
134 packed.write_i32::<BigEndian>(length as i32).unwrap(); |
134 packed.extend(filename.as_bytes()); |
135 packed.extend(filename.as_bytes()); |
135 if let Some(source) = copy_source { |
136 if let Some(source) = copy_source { |
136 packed.push(b'\0'); |
137 packed.push(b'\0'); |
137 packed.extend(source.as_bytes()); |
138 packed.extend(source.as_bytes()); |
210 } |
211 } |
211 #[test] |
212 #[test] |
212 fn test_pack_dirstate_one_entry() { |
213 fn test_pack_dirstate_one_entry() { |
213 let expected_state_map: StateMap = [( |
214 let expected_state_map: StateMap = [( |
214 HgPathBuf::from_bytes(b"f1"), |
215 HgPathBuf::from_bytes(b"f1"), |
215 DirstateEntry { |
216 DirstateEntry::from_v1_data( |
216 state: EntryState::Normal, |
217 EntryState::Normal, |
217 mode: 0o644, |
218 0o644, |
218 size: 0, |
219 0, |
219 mtime: 791231220, |
220 791231220, |
220 }, |
221 ), |
221 )] |
222 )] |
222 .iter() |
223 .iter() |
223 .cloned() |
224 .cloned() |
224 .collect(); |
225 .collect(); |
225 let mut state_map = expected_state_map.clone(); |
226 let mut state_map = expected_state_map.clone(); |
247 } |
248 } |
248 #[test] |
249 #[test] |
249 fn test_pack_dirstate_one_entry_with_copy() { |
250 fn test_pack_dirstate_one_entry_with_copy() { |
250 let expected_state_map: StateMap = [( |
251 let expected_state_map: StateMap = [( |
251 HgPathBuf::from_bytes(b"f1"), |
252 HgPathBuf::from_bytes(b"f1"), |
252 DirstateEntry { |
253 DirstateEntry::from_v1_data( |
253 state: EntryState::Normal, |
254 EntryState::Normal, |
254 mode: 0o644, |
255 0o644, |
255 size: 0, |
256 0, |
256 mtime: 791231220, |
257 791231220, |
257 }, |
258 ), |
258 )] |
259 )] |
259 .iter() |
260 .iter() |
260 .cloned() |
261 .cloned() |
261 .collect(); |
262 .collect(); |
262 let mut state_map = expected_state_map.clone(); |
263 let mut state_map = expected_state_map.clone(); |
288 |
289 |
289 #[test] |
290 #[test] |
290 fn test_parse_pack_one_entry_with_copy() { |
291 fn test_parse_pack_one_entry_with_copy() { |
291 let mut state_map: StateMap = [( |
292 let mut state_map: StateMap = [( |
292 HgPathBuf::from_bytes(b"f1"), |
293 HgPathBuf::from_bytes(b"f1"), |
293 DirstateEntry { |
294 DirstateEntry::from_v1_data( |
294 state: EntryState::Normal, |
295 EntryState::Normal, |
295 mode: 0o644, |
296 0o644, |
296 size: 0, |
297 0, |
297 mtime: 791231220, |
298 791231220, |
298 }, |
299 ), |
299 )] |
300 )] |
300 .iter() |
301 .iter() |
301 .cloned() |
302 .cloned() |
302 .collect(); |
303 .collect(); |
303 let mut copymap = FastHashMap::default(); |
304 let mut copymap = FastHashMap::default(); |
334 #[test] |
335 #[test] |
335 fn test_parse_pack_multiple_entries_with_copy() { |
336 fn test_parse_pack_multiple_entries_with_copy() { |
336 let mut state_map: StateMap = [ |
337 let mut state_map: StateMap = [ |
337 ( |
338 ( |
338 HgPathBuf::from_bytes(b"f1"), |
339 HgPathBuf::from_bytes(b"f1"), |
339 DirstateEntry { |
340 DirstateEntry::from_v1_data( |
340 state: EntryState::Normal, |
341 EntryState::Normal, |
341 mode: 0o644, |
342 0o644, |
342 size: 0, |
343 0, |
343 mtime: 791231220, |
344 791231220, |
344 }, |
345 ), |
345 ), |
346 ), |
346 ( |
347 ( |
347 HgPathBuf::from_bytes(b"f2"), |
348 HgPathBuf::from_bytes(b"f2"), |
348 DirstateEntry { |
349 DirstateEntry::from_v1_data( |
349 state: EntryState::Merged, |
350 EntryState::Merged, |
350 mode: 0o777, |
351 0o777, |
351 size: 1000, |
352 1000, |
352 mtime: 791231220, |
353 791231220, |
353 }, |
354 ), |
354 ), |
355 ), |
355 ( |
356 ( |
356 HgPathBuf::from_bytes(b"f3"), |
357 HgPathBuf::from_bytes(b"f3"), |
357 DirstateEntry { |
358 DirstateEntry::from_v1_data( |
358 state: EntryState::Removed, |
359 EntryState::Removed, |
359 mode: 0o644, |
360 0o644, |
360 size: 234553, |
361 234553, |
361 mtime: 791231220, |
362 791231220, |
362 }, |
363 ), |
363 ), |
364 ), |
364 ( |
365 ( |
365 HgPathBuf::from_bytes(b"f4\xF6"), |
366 HgPathBuf::from_bytes(b"f4\xF6"), |
366 DirstateEntry { |
367 DirstateEntry::from_v1_data(EntryState::Added, 0o644, -1, -1), |
367 state: EntryState::Added, |
|
368 mode: 0o644, |
|
369 size: -1, |
|
370 mtime: -1, |
|
371 }, |
|
372 ), |
368 ), |
373 ] |
369 ] |
374 .iter() |
370 .iter() |
375 .cloned() |
371 .cloned() |
376 .collect(); |
372 .collect(); |
412 #[test] |
408 #[test] |
413 /// https://www.mercurial-scm.org/repo/hg/rev/af3f26b6bba4 |
409 /// https://www.mercurial-scm.org/repo/hg/rev/af3f26b6bba4 |
414 fn test_parse_pack_one_entry_with_copy_and_time_conflict() { |
410 fn test_parse_pack_one_entry_with_copy_and_time_conflict() { |
415 let mut state_map: StateMap = [( |
411 let mut state_map: StateMap = [( |
416 HgPathBuf::from_bytes(b"f1"), |
412 HgPathBuf::from_bytes(b"f1"), |
417 DirstateEntry { |
413 DirstateEntry::from_v1_data( |
418 state: EntryState::Normal, |
414 EntryState::Normal, |
419 mode: 0o644, |
415 0o644, |
420 size: 0, |
416 0, |
421 mtime: 15000000, |
417 15000000, |
422 }, |
418 ), |
423 )] |
419 )] |
424 .iter() |
420 .iter() |
425 .cloned() |
421 .cloned() |
426 .collect(); |
422 .collect(); |
427 let mut copymap = FastHashMap::default(); |
423 let mut copymap = FastHashMap::default(); |