git_internal/internal/pack/utils.rs
1//! Shared pack-parsing helpers for reading object headers, varints, offsets, and zlib-compressed
2//! payloads as defined by Git's pack format.
3
4use std::{
5 fs,
6 io::{self, Read},
7 path::Path,
8};
9
10use sha1::{Digest, Sha1};
11
12use crate::{
13 hash::{ObjectHash, get_hash_kind},
14 internal::object::types::ObjectType,
15};
16
17/// Checks if the reader has reached EOF (end of file).
18///
19/// It attempts to read a single byte from the reader into a buffer.
20/// If `Ok(0)` is returned, it means no byte was read, indicating
21/// that the end of the stream has been reached and there is no more
22/// data left to read.
23///
24/// Any other return value means that data was successfully read, so
25/// the reader has not reached the end yet.
26///
27/// # Arguments
28///
29/// * `reader` - The reader to check for EOF state
30/// It must implement the `std::io::Read` trait
31///
32/// # Returns
33///
34/// true if the reader reached EOF, false otherwise
35pub fn is_eof(reader: &mut dyn Read) -> bool {
36 let mut buf = [0; 1];
37 matches!(reader.read(&mut buf), Ok(0))
38}
39
40/// Reads a byte from the given stream and checks if there are more bytes to continue reading.
41///
42/// The return value includes two parts: an unsigned integer formed by the first 7 bits of the byte,
43/// and a boolean value indicating whether more bytes need to be read.
44///
45/// # Parameters
46/// * `stream`: The stream from which the byte is read.
47///
48/// # Returns
49/// Returns an `io::Result` containing a tuple. The first element is the value of the first 7 bits,
50/// and the second element is a boolean indicating whether more bytes need to be read.
51///
52pub fn read_byte_and_check_continuation<R: Read>(stream: &mut R) -> io::Result<(u8, bool)> {
53 // Create a buffer for a single byte
54 let mut bytes = [0; 1];
55
56 // Read exactly one byte from the stream into the buffer
57 stream.read_exact(&mut bytes)?;
58
59 // Extract the byte from the buffer
60 let byte = bytes[0];
61
62 // Extract the first 7 bits of the byte
63 let value = byte & 0b0111_1111;
64
65 // Check if the most significant bit (8th bit) is set, indicating more bytes to follow
66 let msb = byte >= 128;
67
68 // Return the extracted value and the continuation flag
69 Ok((value, msb))
70}
71
72/// Reads bytes from the stream and parses the first byte for type and size.
73/// Subsequent bytes are read as size bytes and are processed as variable-length
74/// integer in little-endian order. The function returns the type and the computed size.
75///
76/// # Parameters
77/// * `stream`: The stream from which the bytes are read.
78/// * `offset`: The offset of the stream.
79///
80/// # Returns
81/// Returns an `io::Result` containing a tuple of the type and the computed size.
82///
83pub fn read_type_and_varint_size<R: Read>(
84 stream: &mut R,
85 offset: &mut usize,
86) -> io::Result<(u8, usize)> {
87 let (first_byte, continuation) = read_byte_and_check_continuation(stream)?;
88
89 // Increment the offset by one byte
90 *offset += 1;
91
92 // Extract the type (bits 2, 3, 4 of the first byte)
93 let type_bits = (first_byte & 0b0111_0000) >> 4;
94
95 // Initialize size with the last 4 bits of the first byte
96 let mut size: u64 = (first_byte & 0b0000_1111) as u64;
97 let mut shift = 4; // Next byte will shift by 4 bits
98
99 let mut more_bytes = continuation;
100 while more_bytes {
101 let (next_byte, continuation) = read_byte_and_check_continuation(stream)?;
102 // Increment the offset by one byte
103 *offset += 1;
104
105 size |= (next_byte as u64) << shift;
106 shift += 7; // Each subsequent byte contributes 7 more bits
107 more_bytes = continuation;
108 }
109
110 Ok((type_bits, size as usize))
111}
112
113/// Reads a variable-length integer (VarInt) encoded in little-endian format from a source implementing the Read trait.
114///
115/// The VarInt encoding uses the most significant bit (MSB) of each byte as a continuation bit.
116/// The continuation bit being 1 indicates that there are following bytes.
117/// The actual integer value is encoded in the remaining 7 bits of each byte.
118///
119/// # Parameters
120/// * `reader`: A source implementing the Read trait (e.g., file, network stream).
121///
122/// # Returns
123/// Returns a `Result` containing either:
124/// * A tuple of the decoded `u64` value and the number of bytes read (`offset`).
125/// * An `io::Error` in case of any reading error or if the VarInt is too long.
126///
127pub fn read_varint_le<R: Read>(reader: &mut R) -> io::Result<(u64, usize)> {
128 // The decoded value
129 let mut value: u64 = 0;
130 // Bit shift for the next byte
131 let mut shift = 0;
132 // Number of bytes read
133 let mut offset = 0;
134
135 loop {
136 // A buffer to read a single byte
137 let mut buf = [0; 1];
138 // Read one byte from the reader
139 reader.read_exact(&mut buf)?;
140
141 // The byte just read
142 let byte = buf[0];
143 if shift > 63 {
144 // VarInt too long for u64
145 return Err(io::Error::new(
146 io::ErrorKind::InvalidData,
147 "VarInt too long",
148 ));
149 }
150
151 // Take the lower 7 bits of the byte
152 let byte_value = (byte & 0x7F) as u64;
153 // Add the byte value to the result, considering the shift
154 value |= byte_value << shift;
155
156 // Increment the byte count
157 offset += 1;
158 // Check if the MSB is 0 (last byte)
159 if byte & 0x80 == 0 {
160 break;
161 }
162
163 // Increment the shift for the next byte
164 shift += 7;
165 }
166
167 Ok((value, offset))
168}
169
170/// The offset for an OffsetDelta object(big-endian order)
171/// # Arguments
172///
173/// * `stream`: Input Data Stream to read
174/// # Returns
175/// * (`delta_offset`(unsigned), `consume`)
176pub fn read_offset_encoding<R: Read>(stream: &mut R) -> io::Result<(u64, usize)> {
177 // Like the object length, the offset for an OffsetDelta object
178 // is stored in a variable number of bytes,
179 // with the most significant bit of each byte indicating whether more bytes follow.
180 // However, the object length encoding allows redundant values,
181 // e.g. the 7-bit value [n] is the same as the 14- or 21-bit values [n, 0] or [n, 0, 0].
182 // Instead, the offset encoding adds 1 to the value of each byte except the least significant one.
183 // And just for kicks, the bytes are ordered from *most* to *least* significant.
184 let mut value = 0;
185 let mut offset = 0;
186 loop {
187 let (byte_value, more_bytes) = read_byte_and_check_continuation(stream)?;
188 offset += 1;
189 value = (value << 7) | byte_value as u64;
190 if !more_bytes {
191 return Ok((value, offset));
192 }
193
194 value += 1; //important!: for n >= 2 adding 2^7 + 2^14 + ... + 2^(7*(n-1)) to the result
195 }
196}
197
198/// Read the next N bytes from the reader
199///
200#[inline]
201pub fn read_bytes<R: Read, const N: usize>(stream: &mut R) -> io::Result<[u8; N]> {
202 let mut bytes = [0; N];
203 stream.read_exact(&mut bytes)?;
204
205 Ok(bytes)
206}
207
208/// Reads a partial integer from a stream. (little-endian order)
209///
210/// # Arguments
211///
212/// * `stream` - A mutable reference to a readable stream.
213/// * `bytes` - The number of bytes to read from the stream.
214/// * `present_bytes` - A mutable reference to a byte indicating which bits are present in the integer value.
215///
216/// # Returns
217///
218/// This function returns a result of type `io::Result<usize>`. If the operation is successful, the integer value
219/// read from the stream is returned as `Ok(value)`. Otherwise, an `Err` variant is returned, wrapping an `io::Error`
220/// that describes the specific error that occurred.
221pub fn read_partial_int<R: Read>(
222 stream: &mut R,
223 bytes: u8,
224 present_bytes: &mut u8,
225) -> io::Result<usize> {
226 let mut value: usize = 0;
227
228 // Iterate over the byte indices
229 for byte_index in 0..bytes {
230 // Check if the current bit is present
231 if *present_bytes & 1 != 0 {
232 // Read a byte from the stream
233 let [byte] = read_bytes(stream)?;
234
235 // Add the byte value to the integer value
236 value |= (byte as usize) << (byte_index * 8);
237 }
238
239 // Shift the present bytes to the right
240 *present_bytes >>= 1;
241 }
242
243 Ok(value)
244}
245
246/// Reads the base size and result size of a delta object from the given stream.
247///
248/// **Note**: The stream MUST be positioned at the start of the delta object.
249///
250/// The base size and result size are encoded as variable-length integers in little-endian order.
251///
252/// The base size is the size of the base object, and the result size is the size of the result object.
253///
254/// # Parameters
255/// * `stream`: The stream from which the sizes are read.
256///
257/// # Returns
258/// Returns a tuple containing the base size and result size.
259///
260pub fn read_delta_object_size<R: Read>(stream: &mut R) -> io::Result<(usize, usize)> {
261 let base_size = read_varint_le(stream)?.0 as usize;
262 let result_size = read_varint_le(stream)?.0 as usize;
263 Ok((base_size, result_size))
264}
265
266fn decimal_usize_bytes(mut value: usize, buf: &mut [u8; 20]) -> &[u8] {
267 if value == 0 {
268 return b"0";
269 }
270
271 let mut cursor = buf.len();
272 while value > 0 {
273 cursor -= 1;
274 buf[cursor] = b'0' + (value % 10) as u8;
275 value /= 10;
276 }
277 &buf[cursor..]
278}
279
280/// Calculate the SHA1 hash of the given object.
281/// <br> "`<type> <size>\0<content>`"
282/// <br> data: The decompressed content of the object
283pub fn calculate_object_hash(obj_type: ObjectType, data: &[u8]) -> ObjectHash {
284 let type_bytes = obj_type
285 .to_bytes()
286 .expect("calculate_object_hash called with a delta type that has no loose-object header");
287 let mut len_buf = [0; 20];
288 let len_bytes = decimal_usize_bytes(data.len(), &mut len_buf);
289 match get_hash_kind() {
290 crate::hash::HashKind::Sha1 => {
291 let mut hash = Sha1::new();
292 // Header: "<type> <size>\0"
293 hash.update(type_bytes);
294 hash.update(b" ");
295 hash.update(len_bytes);
296 hash.update(b"\0");
297
298 // Decompressed data(raw content)
299 hash.update(data);
300
301 let re: [u8; 20] = hash.finalize().into();
302 ObjectHash::Sha1(re)
303 }
304 crate::hash::HashKind::Sha256 => {
305 let mut hash = sha2::Sha256::new();
306 // Header: "<type> <size>\0"
307 hash.update(type_bytes);
308 hash.update(b" ");
309 hash.update(len_bytes);
310 hash.update(b"\0");
311
312 // Decompressed data(raw content)
313 hash.update(data);
314 let re: [u8; 32] = hash.finalize().into();
315 ObjectHash::Sha256(re)
316 }
317 }
318}
319/// Create an empty directory or clear the existing directory.
320pub fn create_empty_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
321 let dir = path.as_ref();
322 // 删除整个文件夹
323 if dir.exists() {
324 fs::remove_dir_all(dir)?;
325 }
326 // 重新创建文件夹
327 fs::create_dir_all(dir)?;
328 Ok(())
329}
330
331/// Count the number of files in a directory and its subdirectories.
332pub fn count_dir_files(path: &Path) -> io::Result<usize> {
333 let mut count = 0;
334 for entry in fs::read_dir(path)? {
335 let entry = entry?;
336 let path = entry.path();
337 if path.is_dir() {
338 count += count_dir_files(&path)?;
339 } else {
340 count += 1;
341 }
342 }
343 Ok(count)
344}
345
346/// Count the time taken to execute a block of code.
347#[macro_export]
348macro_rules! time_it {
349 ($msg:expr, $block:block) => {{
350 let start = std::time::Instant::now();
351 let result = $block;
352 let elapsed = start.elapsed();
353 // println!("{}: {:?}", $msg, elapsed);
354 tracing::info!("{}: {:?}", $msg, elapsed);
355 result
356 }};
357}
358
359#[cfg(test)]
360mod tests {
361 use std::{
362 io,
363 io::{Cursor, Read},
364 };
365
366 use crate::{
367 hash::{HashKind, set_hash_kind_for_test},
368 internal::{object::types::ObjectType, pack::utils::*},
369 };
370
371 #[test]
372 fn test_calc_obj_hash() {
373 let _guard = set_hash_kind_for_test(HashKind::Sha1);
374 let hash = calculate_object_hash(ObjectType::Blob, b"a".as_ref());
375 assert_eq!(hash.to_string(), "2e65efe2a145dda7ee51d1741299f848e5bf752e");
376 }
377 #[test]
378 fn test_calc_obj_hash_sha256() {
379 let _guard = set_hash_kind_for_test(HashKind::Sha256);
380 let hash = calculate_object_hash(ObjectType::Blob, b"a".as_ref());
381 assert_eq!(
382 hash.to_string(),
383 "eb337bcee2061c5313c9a1392116b6c76039e9e30d71467ae359b36277e17dc7"
384 );
385 }
386
387 #[test]
388 fn test_calc_empty_obj_hash() {
389 let _guard = set_hash_kind_for_test(HashKind::Sha1);
390 let hash = calculate_object_hash(ObjectType::Blob, b"".as_ref());
391 assert_eq!(hash.to_string(), "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391");
392 }
393
394 #[test]
395 fn eof() {
396 let mut reader = Cursor::new(&b""[..]);
397 assert!(is_eof(&mut reader));
398 }
399
400 #[test]
401 fn not_eof() {
402 let mut reader = Cursor::new(&b"abc"[..]);
403 assert!(!is_eof(&mut reader));
404 }
405
406 #[test]
407 fn eof_midway() {
408 let mut reader = Cursor::new(&b"abc"[..]);
409 reader.read_exact(&mut [0; 2]).unwrap();
410 assert!(!is_eof(&mut reader));
411 }
412
413 #[test]
414 fn reader_error() {
415 struct BrokenReader;
416 impl Read for BrokenReader {
417 fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
418 Err(io::Error::other("error"))
419 }
420 }
421
422 let mut reader = BrokenReader;
423 assert!(!is_eof(&mut reader));
424 }
425
426 /// Test case for a byte without a continuation bit (most significant bit is 0)
427 #[test]
428 fn test_read_byte_and_check_continuation_no_continuation() {
429 let data = [0b0101_0101]; // 85 in binary, highest bit is 0
430 let mut cursor = Cursor::new(data);
431 let (value, more_bytes) = read_byte_and_check_continuation(&mut cursor).unwrap();
432
433 assert_eq!(value, 85); // Expected value is 85
434 assert!(!more_bytes); // No more bytes are expected
435 }
436
437 /// Test case for a byte with a continuation bit (most significant bit is 1)
438 #[test]
439 fn test_read_byte_and_check_continuation_with_continuation() {
440 let data = [0b1010_1010]; // 170 in binary, highest bit is 1
441 let mut cursor = Cursor::new(data);
442 let (value, more_bytes) = read_byte_and_check_continuation(&mut cursor).unwrap();
443
444 assert_eq!(value, 42); // Expected value is 42 (170 - 128)
445 assert!(more_bytes); // More bytes are expected
446 }
447
448 /// Test cases for edge values, like the minimum and maximum byte values
449 #[test]
450 fn test_read_byte_and_check_continuation_edge_cases() {
451 // Test the minimum value (0)
452 let data = [0b0000_0000];
453 let mut cursor = Cursor::new(data);
454 let (value, more_bytes) = read_byte_and_check_continuation(&mut cursor).unwrap();
455
456 assert_eq!(value, 0); // Expected value is 0
457 assert!(!more_bytes); // No more bytes are expected
458
459 // Test the maximum value (255)
460 let data = [0b1111_1111];
461 let mut cursor = Cursor::new(data);
462 let (value, more_bytes) = read_byte_and_check_continuation(&mut cursor).unwrap();
463
464 assert_eq!(value, 127); // Expected value is 127 (255 - 128)
465 assert!(more_bytes); // More bytes are expected
466 }
467
468 /// Test with a single byte where msb is 0 (no continuation)
469 #[test]
470 fn test_single_byte_no_continuation() {
471 let data = [0b0101_0101]; // Type: 5 (101), Size: 5 (0101)
472 let mut offset: usize = 0;
473 let mut cursor = Cursor::new(data);
474 let (type_bits, size) = read_type_and_varint_size(&mut cursor, &mut offset).unwrap();
475
476 assert_eq!(offset, 1); // Offset is 1
477 assert_eq!(type_bits, 5); // Expected type is 2
478 assert_eq!(size, 5); // Expected size is 5
479 }
480
481 /// Test with multiple bytes, where continuation occurs
482 #[test]
483 fn test_multiple_bytes_with_continuation() {
484 // Type: 5 (101), Sizes: 5 (0101), 3 (0000011) in little-endian order
485 let data = [0b1101_0101, 0b0000_0011]; // Second byte's msb is 0
486 let mut offset: usize = 0;
487 let mut cursor = Cursor::new(data);
488 let (type_bits, size) = read_type_and_varint_size(&mut cursor, &mut offset).unwrap();
489
490 assert_eq!(offset, 2); // Offset is 2
491 assert_eq!(type_bits, 5); // Expected type is 5
492 // Expected size 000000110101
493 // 110101 = 1 * 2^5 + 1 * 2^4 + 0 * 2^3 + 1 * 2^2 + 0 * 2^1 + 1 * 2^0= 53
494 assert_eq!(size, 53);
495 }
496
497 /// Test with edge case where size is spread across multiple bytes
498 #[test]
499 fn test_edge_case_size_spread_across_bytes() {
500 // Type: 1 (001), Sizes: 15 (1111) in little-endian order
501 let data = [0b0001_1111, 0b0000_0010]; // Second byte's msb is 1 (continuation)
502 let mut offset: usize = 0;
503 let mut cursor = Cursor::new(data);
504 let (type_bits, size) = read_type_and_varint_size(&mut cursor, &mut offset).unwrap();
505
506 assert_eq!(offset, 1); // Offset is 1
507 assert_eq!(type_bits, 1); // Expected type is 1
508 // Expected size is 15
509 assert_eq!(size, 15);
510 }
511
512 /// Test reading VarInt encoded in little-endian format from a stream.
513 #[test]
514 fn test_read_varint_le_single_byte() {
515 // Single byte: 0x05 (binary: 0000 0101)
516 // Represents the value 5 with no continuation bit set.
517 let data = vec![0x05];
518 let mut cursor = Cursor::new(data);
519 let (value, offset) = read_varint_le(&mut cursor).unwrap();
520
521 assert_eq!(value, 5);
522 assert_eq!(offset, 1);
523 }
524
525 /// Test reading VarInt encoded in little-endian format with multiple bytes from a stream.
526 #[test]
527 fn test_read_varint_le_multiple_bytes() {
528 // Two bytes: 0x85, 0x01 (binary: 1000 0101, 0000 0001)
529 // Represents the value 133. First byte has the continuation bit set.
530 let data = vec![0x85, 0x01];
531 let mut cursor = Cursor::new(data);
532 let (value, offset) = read_varint_le(&mut cursor).unwrap();
533
534 assert_eq!(value, 133);
535 assert_eq!(offset, 2);
536 }
537
538 /// Test reading VarInt encoded in little-endian format with multiple bytes from a stream.
539 #[test]
540 fn test_read_varint_le_large_number() {
541 // Five bytes: 0xFF, 0xFF, 0xFF, 0xFF, 0xF (binary: 1111 1111, 1111 1111, 1111 1111, 1111 1111, 0000 1111)
542 // Represents the value 134,217,727. All continuation bits are set except in the last byte.
543 let data = vec![0xFF, 0xFF, 0xFF, 0xFF, 0xF];
544 let mut cursor = Cursor::new(data);
545 let (value, offset) = read_varint_le(&mut cursor).unwrap();
546
547 assert_eq!(value, 0xFFFFFFFF);
548 assert_eq!(offset, 5);
549 }
550
551 /// Test reading VarInt encoded in little-endian format with zero value.
552 #[test]
553 fn test_read_varint_le_zero() {
554 // Single byte: 0x00 (binary: 0000 0000)
555 // Represents the value 0 with no continuation bit set.
556 let data = vec![0x00];
557 let mut cursor = Cursor::new(data);
558 let (value, offset) = read_varint_le(&mut cursor).unwrap();
559
560 assert_eq!(value, 0);
561 assert_eq!(offset, 1);
562 }
563
564 /// Test reading VarInt encoded in little-endian format that is too long.
565 #[test]
566 fn test_read_varint_le_too_long() {
567 let data = vec![
568 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01,
569 ];
570 let mut cursor = Cursor::new(data);
571 let result = read_varint_le(&mut cursor);
572
573 assert!(result.is_err());
574 }
575
576 /// Test reading offset encoding for an OffsetDelta object.
577 #[test]
578 fn test_read_offset_encoding() {
579 let data: Vec<u8> = vec![0b_1101_0101, 0b_0000_0101];
580 let mut cursor = Cursor::new(data);
581 let result = read_offset_encoding(&mut cursor);
582 assert!(result.is_ok());
583 assert_eq!(result.unwrap(), (11013, 2));
584 }
585}