archiver_rs/
tar.rs

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}