docker_image_pusher/
tar_utils.rs1use crate::error::{Result, PusherError};
4use std::path::Path;
5use std::io::Read;
6use std::fs::File;
7use tar::Archive;
8
9pub struct TarUtils;
11
12impl TarUtils {
13 pub fn extract_layer_data(tar_path: &Path, layer_path: &str) -> Result<Vec<u8>> {
15 let file = File::open(tar_path)
16 .map_err(|e| PusherError::Io(format!("Failed to open tar file: {}", e)))?;
17 let mut archive = Archive::new(file);
18 archive.set_ignore_zeros(true);
19
20 for entry_result in archive.entries()
21 .map_err(|e| PusherError::ImageParsing(format!("Failed to read tar entries: {}", e)))? {
22 let mut entry = entry_result
23 .map_err(|e| PusherError::ImageParsing(format!("Failed to read tar entry: {}", e)))?;
24
25 let path = entry.path()
26 .map_err(|e| PusherError::ImageParsing(format!("Failed to read entry path: {}", e)))?
27 .to_string_lossy()
28 .to_string();
29
30 if path == layer_path {
31 let mut data = Vec::new();
32 entry.read_to_end(&mut data)
33 .map_err(|e| PusherError::ImageParsing(format!("Failed to read layer data: {}", e)))?;
34 return Ok(data);
35 }
36 }
37
38 Err(PusherError::ImageParsing(format!("Layer '{}' not found in tar archive", layer_path)))
39 }
40
41 pub fn find_layer_offset(tar_path: &Path, layer_path: &str) -> Result<u64> {
43 let file = File::open(tar_path)
44 .map_err(|e| PusherError::Io(format!("Failed to open tar file: {}", e)))?;
45 let mut archive = Archive::new(file);
46 archive.set_ignore_zeros(true);
47
48 let mut current_offset = 0u64;
49
50 for entry_result in archive.entries()
51 .map_err(|e| PusherError::ImageParsing(format!("Failed to read tar entries: {}", e)))? {
52 let entry = entry_result
53 .map_err(|e| PusherError::ImageParsing(format!("Failed to read tar entry: {}", e)))?;
54
55 let path = entry.path()
56 .map_err(|e| PusherError::ImageParsing(format!("Failed to read entry path: {}", e)))?
57 .to_string_lossy()
58 .to_string();
59
60 if path == layer_path {
61 return Ok(current_offset);
62 }
63
64 let size = entry.header().size()
66 .map_err(|e| PusherError::ImageParsing(format!("Failed to read entry size: {}", e)))?;
67
68 current_offset += size + 512; }
70
71 Err(PusherError::ImageParsing(format!("Layer '{}' not found for offset calculation", layer_path)))
72 }
73
74 pub fn list_tar_entries(tar_path: &Path) -> Result<Vec<(String, u64)>> {
76 let file = File::open(tar_path)
77 .map_err(|e| PusherError::Io(format!("Failed to open tar file: {}", e)))?;
78 let mut archive = Archive::new(file);
79 archive.set_ignore_zeros(true);
80
81 let mut entries = Vec::new();
82
83 for entry_result in archive.entries()
84 .map_err(|e| PusherError::ImageParsing(format!("Failed to read tar entries: {}", e)))? {
85 let entry = entry_result
86 .map_err(|e| PusherError::ImageParsing(format!("Failed to read tar entry: {}", e)))?;
87
88 let path = entry.path()
89 .map_err(|e| PusherError::ImageParsing(format!("Failed to read entry path: {}", e)))?
90 .to_string_lossy()
91 .to_string();
92
93 let size = entry.header().size()
94 .map_err(|e| PusherError::ImageParsing(format!("Failed to read entry size: {}", e)))?;
95
96 entries.push((path, size));
97 }
98
99 Ok(entries)
100 }
101
102 pub fn validate_tar_archive(tar_path: &Path) -> Result<()> {
104 let file = File::open(tar_path)
105 .map_err(|e| PusherError::Io(format!("Failed to open tar file: {}", e)))?;
106 let mut archive = Archive::new(file);
107 archive.set_ignore_zeros(true);
108
109 let mut entry_count = 0;
111 for entry_result in archive.entries()
112 .map_err(|e| PusherError::ImageParsing(format!("Failed to read tar entries: {}", e)))? {
113 let entry = entry_result
114 .map_err(|e| PusherError::ImageParsing(format!("Failed to read tar entry: {}", e)))?;
115
116 let _ = entry.path()
118 .map_err(|e| PusherError::ImageParsing(format!("Failed to read entry path: {}", e)))?;
119
120 entry_count += 1;
121
122 if entry_count >= 10 {
124 break;
125 }
126 }
127
128 if entry_count == 0 {
129 return Err(PusherError::ImageParsing("Tar archive appears to be empty".to_string()));
130 }
131
132 Ok(())
133 }
134}