1#[cfg(feature = "tar")]
2pub use self::tar::Tar;
3
4#[cfg(feature = "tar")]
5mod tar {
6 use std::fs::{create_dir_all, File};
7 use std::io::{copy, Read};
8 use std::path::Path;
9
10 use crate::{Archive, ArchiverError, Result};
11
12 pub struct Tar<R: Read> {
13 archive: tar::Archive<R>,
14 }
15
16 impl Tar<File> {
17 pub fn open(path: &Path) -> std::io::Result<Self> {
18 let archive = File::open(path)?;
19
20 Self::new(archive)
21 }
22 }
23
24 impl<R: Read> Tar<R> {
25 pub fn new(r: R) -> std::io::Result<Self> {
26 let archive = tar::Archive::new(r);
27
28 Ok(Self { archive })
29 }
30 }
31
32 impl<R: Read> Archive for Tar<R> {
33 fn contains(&mut self, file: String) -> Result<bool> {
34 for f in self.archive.entries()? {
35 let f = f?;
36 let name = f.path()?;
37 let name = name.to_str().unwrap_or_else(|| "");
38
39 if name == file {
40 return Ok(true);
41 }
42 }
43
44 Ok(false)
45 }
46
47 fn extract(&mut self, destination: &Path) -> Result<()> {
48 if !destination.exists() {
49 create_dir_all(destination)?;
50 }
51
52 self.archive.unpack(destination)?;
53
54 Ok(())
55 }
56
57 fn extract_single(&mut self, target: &Path, file: String) -> Result<()> {
58 if let Some(p) = target.parent() {
59 if !p.exists() {
60 create_dir_all(&p)?;
61 }
62 }
63
64 for f in self.archive.entries()? {
65 let mut f = f?;
66 let name = f.path()?;
67
68 if name.to_str().unwrap_or_else(|| "") == &file {
69 let mut target = File::create(target)?;
70 copy(&mut f, &mut target)?;
71
72 return Ok(());
73 }
74 }
75
76 Err(ArchiverError::NotFound)?
77 }
78
79 fn files(&mut self) -> Result<Vec<String>> {
80 let files = self
81 .archive
82 .entries()?
83 .into_iter()
84 .map(|e| e.unwrap().path().unwrap().to_str().unwrap().into())
85 .collect();
86
87 Ok(files)
88 }
89
90 fn walk(&mut self, f: Box<dyn Fn(String) -> Option<String>>) -> Result<()> {
91 let files = self.files()?;
92
93 for file in files {
94 if let Some(f) = f(file.clone()) {
95 self.extract_single(Path::new(&f), file.clone())?;
96 }
97 }
98
99 Ok(())
100 }
101 }
102}