archive_rs/
entry.rs

1use std::borrow::Cow;
2#[cfg(feature = "tar")]
3use std::fs::File;
4#[cfg(feature = "zstd")]
5use std::io::BufReader;
6use std::io::Read;
7use std::path::Path;
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 = "xz2")]
18use xz2::read::XzDecoder;
19#[cfg(feature = "zstd")]
20use zstd::stream::read::Decoder as ZstdDecoder;
21
22use crate::Result;
23
24/// Archive entry.
25// NONEXHAUSTIVE new formats could add new types
26#[non_exhaustive]
27pub enum Entry<'a> {
28    #[cfg(feature = "tar")]
29    #[doc(hidden)]
30    Tar(tar::Entry<'a, File>),
31
32    #[cfg(all(feature = "bzip2", feature = "tar"))]
33    #[doc(hidden)]
34    TarBzip2(tar::Entry<'a, BzSysDecoder<File>>),
35
36    #[cfg(all(feature = "bzip2-rs", feature = "tar"))]
37    #[doc(hidden)]
38    TarBzip2Rs(tar::Entry<'a, BzNativeDecoder<File>>),
39
40    #[cfg(all(feature = "flate2", feature = "tar"))]
41    #[doc(hidden)]
42    TarGzip(tar::Entry<'a, GzDecoder<File>>),
43
44    #[cfg(all(feature = "lz4", feature = "tar"))]
45    #[doc(hidden)]
46    TarLz4(tar::Entry<'a, Lz4Decoder<File>>),
47
48    #[cfg(all(feature = "xz2", feature = "tar"))]
49    #[doc(hidden)]
50    TarXz(tar::Entry<'a, XzDecoder<File>>),
51
52    #[cfg(all(feature = "zstd", feature = "tar"))]
53    #[doc(hidden)]
54    TarZstd(tar::Entry<'a, ZstdDecoder<'static, BufReader<File>>>),
55
56    #[cfg(not(feature = "tar"))]
57    #[doc(hidden)]
58    __Phantom(std::marker::PhantomData<&'a str>),
59}
60
61impl<'a> Entry<'a> {
62    /// Returns the file type of this entry.
63    pub fn entry_type(&self) -> EntryType {
64        match self {
65            #[cfg(feature = "tar")]
66            Self::Tar(entry) => entry.header().entry_type().into(),
67
68            #[cfg(all(feature = "bzip2", feature = "tar"))]
69            Self::TarBzip2(entry) => entry.header().entry_type().into(),
70
71            #[cfg(all(feature = "bzip2-rs", feature = "tar"))]
72            Self::TarBzip2Rs(entry) => entry.header().entry_type().into(),
73
74            #[cfg(all(feature = "flate2", feature = "tar"))]
75            Self::TarGzip(entry) => entry.header().entry_type().into(),
76
77            #[cfg(all(feature = "lz4", feature = "tar"))]
78            Self::TarLz4(entry) => entry.header().entry_type().into(),
79
80            #[cfg(all(feature = "xz2", feature = "tar"))]
81            Self::TarXz(entry) => entry.header().entry_type().into(),
82
83            #[cfg(all(feature = "zstd", feature = "tar"))]
84            Self::TarZstd(entry) => entry.header().entry_type().into(),
85        }
86    }
87
88    /// Returns the size in bytes of the entry.
89    #[must_use]
90    pub fn size(&self) -> u64 {
91        match self {
92            #[cfg(feature = "tar")]
93            Self::Tar(entry) => entry.size(),
94
95            #[cfg(all(feature = "bzip2", feature = "tar"))]
96            Self::TarBzip2(entry) => entry.size(),
97
98            #[cfg(all(feature = "bzip2-rs", feature = "tar"))]
99            Self::TarBzip2Rs(entry) => entry.size(),
100
101            #[cfg(all(feature = "flate2", feature = "tar"))]
102            Self::TarGzip(entry) => entry.size(),
103
104            #[cfg(all(feature = "lz4", feature = "tar"))]
105            Self::TarLz4(entry) => entry.size(),
106
107            #[cfg(all(feature = "xz2", feature = "tar"))]
108            Self::TarXz(entry) => entry.size(),
109
110            #[cfg(all(feature = "zstd", feature = "tar"))]
111            Self::TarZstd(entry) => entry.size(),
112        }
113    }
114
115    /// Returns the path name for this entry.
116    ///
117    /// # Errors
118    ///
119    /// Parsing the path metadata.
120    pub fn path(&self) -> Result<Cow<Path>> {
121        match self {
122            #[cfg(feature = "tar")]
123            Self::Tar(entry) => entry.path().map_err(From::from),
124
125            #[cfg(all(feature = "bzip2", feature = "tar"))]
126            Self::TarBzip2(entry) => entry.path().map_err(From::from),
127
128            #[cfg(all(feature = "bzip2-rs", feature = "tar"))]
129            Self::TarBzip2Rs(entry) => entry.path().map_err(From::from),
130
131            #[cfg(all(feature = "flate2", feature = "tar"))]
132            Self::TarGzip(entry) => entry.path().map_err(From::from),
133
134            #[cfg(all(feature = "lz4", feature = "tar"))]
135            Self::TarLz4(entry) => entry.path().map_err(From::from),
136
137            #[cfg(all(feature = "xz2", feature = "tar"))]
138            Self::TarXz(entry) => entry.path().map_err(From::from),
139
140            #[cfg(all(feature = "zstd", feature = "tar"))]
141            Self::TarZstd(entry) => entry.path().map_err(From::from),
142        }
143    }
144}
145
146impl Read for Entry<'_> {
147    fn read(
148        &mut self,
149        buf: &mut [u8],
150    ) -> std::result::Result<usize, std::io::Error> {
151        match self {
152            #[cfg(feature = "tar")]
153            Self::Tar(entry) => entry.read(buf),
154
155            #[cfg(all(feature = "bzip2", feature = "tar"))]
156            Self::TarBzip2(entry) => entry.read(buf),
157
158            #[cfg(all(feature = "bzip2-rs", feature = "tar"))]
159            Self::TarBzip2Rs(entry) => entry.read(buf),
160
161            #[cfg(all(feature = "flate2", feature = "tar"))]
162            Self::TarGzip(entry) => entry.read(buf),
163
164            #[cfg(all(feature = "lz4", feature = "tar"))]
165            Self::TarLz4(entry) => entry.read(buf),
166
167            #[cfg(all(feature = "xz2", feature = "tar"))]
168            Self::TarXz(entry) => entry.read(buf),
169
170            #[cfg(all(feature = "zstd", feature = "tar"))]
171            Self::TarZstd(entry) => entry.read(buf),
172        }
173    }
174}
175
176/// File type of an entry.
177// ALLOW this is not a public module
178#[allow(clippy::module_name_repetitions)]
179#[derive(Clone, Copy, PartialEq, Eq, Debug)]
180// NONEXHAUSTIVE new formats could add new entry types
181#[non_exhaustive]
182#[must_use = "getting an entry type is used to inspect it"]
183pub enum EntryType {
184    /// Regular file
185    Regular,
186
187    /// Hard link
188    Link,
189
190    /// Symbolic link
191    Symlink,
192
193    /// Character device
194    Char,
195
196    /// Block device
197    Block,
198
199    /// Directory
200    Directory,
201
202    /// Named pipe (fifo)
203    Fifo,
204
205    /// Implementation-defined 'high-performance' type, treated as regular file
206    Continuous,
207
208    /// GNU extension - long file name
209    GNULongName,
210
211    /// GNU extension - long link name (link target)
212    GNULongLink,
213
214    /// GNU extension - sparse file
215    GNUSparse,
216
217    /// Global extended header
218    XGlobalHeader,
219
220    /// Extended Header
221    XHeader,
222
223    /// Other
224    Other,
225}
226
227impl EntryType {
228    /// Returns true if this is a regular file.
229    #[must_use = "side effect free function"]
230    pub fn is_file(&self) -> bool {
231        self == &Self::Regular
232    }
233}
234
235#[cfg(feature = "tar")]
236impl From<tar::EntryType> for EntryType {
237    fn from(e: tar::EntryType) -> Self {
238        match e {
239            tar::EntryType::Regular => Self::Regular,
240            tar::EntryType::Link => Self::Link,
241            tar::EntryType::Symlink => Self::Symlink,
242            tar::EntryType::Char => Self::Char,
243            tar::EntryType::Block => Self::Block,
244            tar::EntryType::Directory => Self::Directory,
245            tar::EntryType::Fifo => Self::Fifo,
246            tar::EntryType::Continuous => Self::Continuous,
247            tar::EntryType::GNULongName => Self::GNULongName,
248            tar::EntryType::GNULongLink => Self::GNULongLink,
249            tar::EntryType::GNUSparse => Self::GNUSparse,
250            tar::EntryType::XGlobalHeader => Self::XGlobalHeader,
251            tar::EntryType::XHeader => Self::XHeader,
252            _ => Self::Other,
253        }
254    }
255}