use libarchive2::{ArchiveFormat, FileType, ReadArchive, WriteArchive};
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
println!("=== Sparse File Example ===\n");
create_sparse_archive()?;
read_sparse_archive()?;
println!("\n✓ Sparse file operations completed successfully!");
Ok(())
}
fn create_sparse_archive() -> Result<(), Box<dyn Error>> {
println!("1. Creating sparse archive...");
let mut archive = WriteArchive::new()
.format(ArchiveFormat::TarPax)
.open_file("sparse_example.tar")?;
let mut entry = libarchive2::EntryMut::new();
entry.set_pathname("sparse_file.bin")?;
entry.set_file_type(FileType::RegularFile);
entry.set_size(10 * 1024 * 1024); entry.set_perm(0o644)?;
entry.set_mtime(std::time::SystemTime::now());
archive.write_header(&entry)?;
let data1 = b"Start of file";
archive.write_data_block(0, data1)?;
println!(" - Wrote {} bytes at offset 0", data1.len());
let offset2 = 5 * 1024 * 1024;
let data2 = b"Middle of file";
archive.write_data_block(offset2, data2)?;
println!(
" - Wrote {} bytes at offset {} (5MB hole created)",
data2.len(),
offset2
);
let offset3 = (10 * 1024 * 1024) - 11;
let data3 = b"End of file";
archive.write_data_block(offset3, data3)?;
println!(
" - Wrote {} bytes at offset {} (another ~5MB hole)",
data3.len(),
offset3
);
archive.finish()?;
println!(" ✓ Created sparse_example.tar");
println!(
" Total file size: 10MB, Actual data: {} bytes",
data1.len() + data2.len() + data3.len()
);
Ok(())
}
fn read_sparse_archive() -> Result<(), Box<dyn Error>> {
println!("\n2. Reading sparse archive...");
let mut archive = ReadArchive::open("sparse_example.tar")?;
if let Some(entry) = archive.next_entry()? {
let pathname = entry.pathname().unwrap_or_default().to_string();
let size = entry.size();
println!(" Entry: {}", pathname);
println!(" Size: {} bytes", size);
let mut block_count = 0;
let mut total_data = 0;
while let Some((offset, data)) = archive.read_data_block()? {
block_count += 1;
total_data += data.len();
let preview = if data.len() > 20 {
format!("{}...", String::from_utf8_lossy(&data[..20]))
} else {
String::from_utf8_lossy(&data).to_string()
};
println!(
" Block {}: offset={}, size={} bytes, preview='{}'",
block_count,
offset,
data.len(),
preview
);
}
println!(
"\n ✓ Read {} blocks, {} total bytes of actual data",
block_count, total_data
);
println!(
" Efficiency: {:.2}% (only non-zero data read)",
(total_data as f64 / size as f64) * 100.0
);
}
Ok(())
}