easy_archive/archive/
tar.rs

1use crate::{Decode, Encode, File, tool::clean};
2use flate2::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            // FIXME: skip PAX
17            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 = "xz2")]
43fn decode_xz2(buffer: &[u8]) -> Option<Vec<File>> {
44    use xz2::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 = "lzma-rs")]
52fn decode_lzma_rs(buffer: &[u8]) -> Option<Vec<File>> {
53    let mut cur = Cursor::new(buffer);
54    let mut decomp: Vec<u8> = Vec::new();
55    lzma_rs::xz_decompress(&mut cur, &mut decomp).ok()?;
56    Tar::decode(decomp)
57}
58
59pub struct TarXz;
60impl Decode for TarXz {
61    fn decode(buffer: Vec<u8>) -> Option<Vec<File>> {
62        #[cfg(feature = "xz2")]
63        return decode_xz2(&buffer);
64        #[allow(unreachable_code)]
65        #[cfg(feature = "lzma-rs")]
66        return decode_lzma_rs(&buffer);
67    }
68}
69
70pub struct TarBz;
71impl Decode for TarBz {
72    fn decode(buffer: Vec<u8>) -> Option<Vec<File>> {
73        use bzip2_rs::DecoderReader;
74        let cur = Cursor::new(buffer);
75        let reader = BufReader::new(DecoderReader::new(cur));
76        let v = reader.bytes().map(|i| i.unwrap()).collect();
77        Tar::decode(v)
78    }
79}
80use ruzstd::decoding::StreamingDecoder;
81
82pub struct TarZstd;
83impl Decode for TarZstd {
84    fn decode(buffer: Vec<u8>) -> Option<Vec<File>> {
85        let cur = Cursor::new(buffer);
86        let mut decoder = StreamingDecoder::new(cur).unwrap();
87        let mut result = Vec::new();
88        decoder.read_to_end(&mut result).unwrap();
89        Tar::decode(result)
90    }
91}
92
93impl Encode for Tar {}
94impl Encode for TarGz {}
95impl Encode for TarXz {}
96impl Encode for TarBz {}
97impl Encode for TarZstd {}