archive_rs/
archive.rs

1#[cfg(feature = "tar")]
2use std::fs::File;
3#[cfg(feature = "zstd")]
4use std::io::BufReader;
5use std::path::Path;
6
7use path_utils::PathExt;
8
9#[cfg(feature = "bzip2")]
10use bzip2::read::BzDecoder as BzSysDecoder;
11#[cfg(feature = "bzip2-rs")]
12use bzip2_rs::decoder::DecoderReader as BzNativeDecoder;
13#[cfg(feature = "flate2")]
14use flate2::read::GzDecoder;
15#[cfg(feature = "lz4")]
16use lz4::Decoder as Lz4Decoder;
17#[cfg(feature = "tar")]
18use tar::Archive as Tar;
19#[cfg(feature = "xz2")]
20use xz2::read::XzDecoder;
21#[cfg(feature = "zstd")]
22use zstd::stream::read::Decoder as ZstdDecoder;
23
24use crate::Result;
25
26/// Archive file.
27// NONEXHAUSTIVE new formats could add new types
28#[non_exhaustive]
29// ALLOW constructing and storing Self is not the bottleneck, iterating the
30// entries and I/O is
31#[allow(clippy::large_enum_variant)]
32pub enum Archive {
33    #[cfg(feature = "tar")]
34    #[doc(hidden)]
35    Tar(Tar<File>),
36
37    #[cfg(all(feature = "bzip2", feature = "tar"))]
38    #[doc(hidden)]
39    TarBzip2(Tar<BzSysDecoder<File>>),
40
41    #[cfg(all(feature = "bzip2-rs", feature = "tar"))]
42    #[doc(hidden)]
43    TarBzip2Rs(Tar<BzNativeDecoder<File>>),
44
45    #[cfg(all(feature = "flate2", feature = "tar"))]
46    #[doc(hidden)]
47    TarGzip(Tar<GzDecoder<File>>),
48
49    #[cfg(all(feature = "lz4", feature = "tar"))]
50    #[doc(hidden)]
51    TarLz4(Tar<Lz4Decoder<File>>),
52
53    #[cfg(all(feature = "xz2", feature = "tar"))]
54    #[doc(hidden)]
55    TarXz(Tar<XzDecoder<File>>),
56
57    #[cfg(all(feature = "zstd", feature = "tar"))]
58    #[doc(hidden)]
59    TarZstd(Tar<ZstdDecoder<'static, BufReader<File>>>),
60}
61
62impl Archive {
63    /// Returns an opened archive file.
64    ///
65    /// # Errors
66    ///
67    /// Returns an error if archive is of unsupported format or if opening it
68    /// fails.
69    pub fn open(path: impl AsRef<Path>) -> Result<Self> {
70        let path = path.as_ref();
71
72        let extensions: Vec<String> = path.extensions_lossy().collect();
73        let extensions: Vec<&str> =
74            extensions.iter().map(String::as_str).collect();
75
76        match extensions.as_slice() {
77            #[cfg(all(feature = "bzip2", feature = "tar"))]
78            ["tbz" | "tbz2", ..] | ["bz2", "tar", ..] => {
79                let file = File::open(path)?;
80                let file = BzSysDecoder::new(file);
81                Ok(Self::TarBzip2(Tar::new(file)))
82            }
83
84            #[cfg(all(feature = "bzip2-rs", feature = "tar"))]
85            ["tbz" | "tbz2", ..] | ["bz2", "tar", ..] => {
86                let file = File::open(path)?;
87                let file = BzNativeDecoder::new(file);
88                Ok(Self::TarBzip2Rs(Tar::new(file)))
89            }
90
91            #[cfg(all(feature = "flate2", feature = "tar"))]
92            ["tgz", ..] | ["gz", "tar", ..] => {
93                let file = File::open(path)?;
94                let file = GzDecoder::new(file);
95                Ok(Self::TarGzip(Tar::new(file)))
96            }
97
98            #[cfg(all(feature = "lz4", feature = "tar"))]
99            ["lz4", "tar", ..] => {
100                let file = File::open(path)?;
101                let file = Lz4Decoder::new(file)?;
102                Ok(Self::TarLz4(Tar::new(file)))
103            }
104
105            #[cfg(all(feature = "xz2", feature = "tar"))]
106            ["txz", ..] | ["xz", "tar", ..] => {
107                let file = File::open(path)?;
108                let file = XzDecoder::new(file);
109                Ok(Self::TarXz(Tar::new(file)))
110            }
111
112            #[cfg(all(feature = "zstd", feature = "tar"))]
113            ["zst", "tar", ..] => {
114                let file = File::open(path)?;
115                let file = ZstdDecoder::new(file)?;
116                Ok(Self::TarZstd(Tar::new(file)))
117            }
118
119            #[cfg(feature = "tar")]
120            ["tar", ..] => {
121                let file = File::open(path)?;
122                Ok(Self::Tar(Tar::new(file)))
123            }
124
125            _ => Err(crate::Error::UnsupportedArchiveType(path.to_path_buf())),
126        }
127    }
128}