1use std::fs::{self, File};
2use std::io::{self, Write};
3use std::path::Path;
4use tar::Builder;
5use walkdir::WalkDir;
6use zstd::stream::{decode_all, encode_all};
7use zstd::Encoder;
8
9pub fn create_tar_archive<P: AsRef<Path>>(
10 folder: P,
11 tar_file: &str,
12) -> io::Result<()> {
13 let tar_gz = File::create(tar_file)?;
14 let mut archive = Builder::new(tar_gz);
15
16 for entry in WalkDir::new(folder) {
17 let entry = match entry {
18 Ok(e) => e,
19 Err(e) => {
20 eprintln!("Warning: failed to read directory entry: {}", e);
21 continue;
22 }
23 };
24 let path = entry.path();
25 if path.is_symlink() {
26 match std::fs::read_link(path) {
27 Ok(target) => {
28 if target.exists() {
29 if let Err(e) = archive.append_path_with_name(&target, path) {
30 eprintln!("Warning: failed to append symlink {:?}: {}", path, e);
31 }
32 } else {
33 eprintln!(
34 "Warning: symlink target {:?} does not exist, skipping",
35 target
36 );
37 }
38 }
39 Err(e) => {
40 eprintln!(
41 "Warning: failed to read symlink {:?}, skipping: {}",
42 path, e
43 );
44 }
45 }
46 } else if path.exists() {
47 if let Err(e) = archive.append_path(path) {
48 eprintln!("Warning: failed to append path {:?}: {}", path, e);
49 }
50 } else {
51 eprintln!("Warning: file {:?} does not exist, skipping", path);
52 }
53 }
54
55 Ok(())
56}
57
58pub fn extract_tar_archive(tar_file: &str, output_dir: &str) -> io::Result<()> {
59 let tar_gz = File::open(tar_file)?;
60 let mut archive = tar::Archive::new(tar_gz);
61
62 let mut final_output_dir = output_dir.to_string();
63 if Path::new(output_dir).exists() {
64 final_output_dir = format!("{}-{}", output_dir, uuid::Uuid::new_v4());
65 }
66
67 std::fs::create_dir_all(&final_output_dir)?;
68 archive.unpack(&final_output_dir)?;
69 Ok(())
70}
71
72pub fn compress_tar_file(
73 tar_file: &str,
74 compressed_file: &str,
75) -> io::Result<()> {
76 let tar = File::open(tar_file)?;
77 let compressed = File::create(compressed_file)?;
78 let mut tar_reader = tar;
79 let mut compressed_writer = compressed;
80 let compression_level = 18;
81
82 let mut zstd = zstd::stream::write::Encoder::new(
83 &mut compressed_writer,
84 compression_level,
85 )?;
86 zstd.multithread(num_cpus::get() as u32)?;
87
88 zstd.long_distance_matching(true)?;
89 zstd.window_log(31)?;
90
91 io::copy(&mut tar_reader, &mut zstd)?;
92 zstd.finish()?;
93
94 Ok(())
95}
96
97pub fn decompress_file_v1(
98 compressed_file: &str,
99 output_file: &str,
100) -> io::Result<()> {
101 let compressed = File::open(compressed_file)?;
102 let decompressed_data = decode_all(compressed)?;
103 let mut decompressed = File::create(output_file)?;
104 decompressed.write_all(&decompressed_data)?;
105 Ok(())
106}
107
108pub fn decompress_file(
109 compressed_file: &str,
110 output_file: &str,
111) -> io::Result<()> {
112 let compressed = File::open(compressed_file)?;
113 let mut compressed_reader = compressed;
114 let mut decompressed_writer = File::create(output_file)?;
115
116 let mut zstd = zstd::stream::read::Decoder::new(&mut compressed_reader)?;
117 zstd.window_log_max(31)?;
118
119 io::copy(&mut zstd, &mut decompressed_writer)?;
120
121 Ok(())
122}