easy_archive/archive/
tar.rs1use crate::{Decode, Encode, File, Fmt, tool::clean};
2use flate2::{Compression, bufread::GzEncoder, read::GzDecoder};
3use std::io::{BufReader, Cursor, Read};
4use tar::Archive;
5
6pub struct Tar;
7
8impl Decode for Tar {
9 fn decode(buffer: Vec<u8>) -> Option<Vec<File>> {
10 let mut files = Vec::new();
11 let cur = Cursor::new(buffer);
12 let mut a = Archive::new(cur);
13 for file in a.entries().unwrap() {
14 let mut file = file.unwrap();
15 let path = file.header().path().unwrap().to_string_lossy().to_string();
16 if path == "pax_global_header" {
18 continue;
19 }
20 let mut buffer = vec![];
21 file.read_to_end(&mut buffer).expect("failed to read file");
22 let mode = file.header().mode().ok();
23 let is_dir = path.ends_with("/");
24 let path = clean(&path);
25 let mtime = file.header().mtime().ok();
26 files.push(File::new(path, buffer, mode, is_dir, mtime));
27 }
28 Some(files)
29 }
30}
31
32pub struct TarGz;
33impl Decode for TarGz {
34 fn decode(buffer: Vec<u8>) -> Option<Vec<File>> {
35 let mut decoder = GzDecoder::new(&buffer[..]);
36 let mut decompressed = Vec::new();
37 decoder.read_to_end(&mut decompressed).ok()?;
38 Tar::decode(decompressed)
39 }
40}
41
42#[cfg(feature = "liblzma")]
43fn decode_xz2(buffer: &[u8]) -> Option<Vec<File>> {
44 use liblzma::bufread::XzDecoder;
45 let mut dec = XzDecoder::new(buffer);
46 let mut decompressed = vec![];
47 dec.read_to_end(&mut decompressed).ok()?;
48 Tar::decode(decompressed)
49}
50
51#[cfg(feature = "liblzma")]
52fn compress_xz(data: &[u8], preset: u32) -> std::io::Result<Vec<u8>> {
56 use liblzma::write::XzEncoder;
57 use std::io::{Cursor, Write};
58 let cursor = Cursor::new(Vec::new());
59 let mut encoder = XzEncoder::new(cursor, preset);
60 encoder.write_all(data)?;
61 let cursor = encoder.finish()?;
62 Ok(cursor.into_inner())
63}
64
65#[cfg(feature = "lzma-rs")]
66fn decode_lzma_rs(buffer: &[u8]) -> Option<Vec<File>> {
67 let mut cur = Cursor::new(buffer);
68 let mut decomp: Vec<u8> = Vec::new();
69 lzma_rs::xz_decompress(&mut cur, &mut decomp).ok()?;
70 Tar::decode(decomp)
71}
72
73pub struct TarXz;
74impl Decode for TarXz {
75 fn decode(buffer: Vec<u8>) -> Option<Vec<File>> {
76 #[cfg(feature = "liblzma")]
77 return decode_xz2(&buffer);
78 #[allow(unreachable_code)]
79 #[cfg(feature = "lzma-rs")]
80 return decode_lzma_rs(&buffer);
81 }
82}
83
84pub struct TarBz;
85impl Decode for TarBz {
86 fn decode(buffer: Vec<u8>) -> Option<Vec<File>> {
87 use bzip2_rs::DecoderReader;
88 let cur = Cursor::new(buffer);
89 let reader = BufReader::new(DecoderReader::new(cur));
90 let v = reader.bytes().map(|i| i.unwrap()).collect();
91 Tar::decode(v)
92 }
93}
94use ruzstd::decoding::StreamingDecoder;
95
96pub struct TarZstd;
97impl Decode for TarZstd {
98 fn decode(buffer: Vec<u8>) -> Option<Vec<File>> {
99 let cur = Cursor::new(buffer);
100 let mut decoder = StreamingDecoder::new(cur).unwrap();
101 let mut result = Vec::new();
102 decoder.read_to_end(&mut result).unwrap();
103 Tar::decode(result)
104 }
105}
106
107impl Encode for Tar {
108 fn encode(files: Vec<File>) -> Option<Vec<u8>> {
109 use tar::Header;
110 let mut buffer: Vec<u8> = Vec::new();
111 {
112 let mut builder = tar::Builder::new(&mut buffer);
113
114 for file in files {
115 let mut header = Header::new_gnu();
116 header.set_size(file.buffer.len() as u64);
117 header.set_mode(file.mode.unwrap_or(0o644));
118 header.set_uid(0);
119 header.set_gid(0);
120 header.set_mtime(file.last_modified.unwrap_or(0));
121 header.set_cksum();
122 builder
123 .append_data(&mut header, &file.path, &file.buffer[..])
124 .ok()?;
125 }
126
127 builder.finish().ok()?;
128 }
129 Some(buffer)
130 }
131}
132
133impl Encode for TarGz {
134 fn encode(files: Vec<File>) -> Option<Vec<u8>> {
135 let tar = Fmt::Tar.encode(files)?;
136 let mut cursor = Cursor::new(tar);
137 let mut encoder = GzEncoder::new(&mut cursor, Compression::default());
138 let mut compressed = Vec::new();
139 encoder.read_to_end(&mut compressed).ok()?;
140 Some(compressed)
141 }
142}
143impl Encode for TarXz {
144 #[cfg(feature = "liblzma")]
145 fn encode(_files: Vec<File>) -> Option<Vec<u8>> {
146 let tar = Fmt::Tar.encode(_files)?;
147 let xz = compress_xz(&tar, 6);
148 xz.ok()
149 }
150}
151
152impl Encode for TarBz {}
153
154impl Encode for TarZstd {
155 fn encode(files: Vec<File>) -> Option<Vec<u8>> {
156 let tar = Fmt::Tar.encode(files)?;
157 let mut cursor = Cursor::new(tar);
158 let mut v = vec![];
159 let mut encoder = zstd::Encoder::new(&mut v, 6).ok()?;
160 std::io::copy(&mut cursor, &mut encoder).unwrap();
161 encoder.finish().unwrap();
162 Some(v)
163 }
164}