Make ouch support paths with dot-dot (..) for input files/directories
[ouch.git] / src / compressors / tar.rs
blob945f3d3ef773452b8a51b498515a3d2985d368ce
1 use std::{env, fs, path::PathBuf};
3 use colored::Colorize;
4 use tar::Builder;
5 use walkdir::WalkDir;
7 use crate::{compressors::Compressor, error::{Error, OuchResult}, file::File};
9 use super::compressor::Entry;
11 pub struct TarCompressor {}
13 impl TarCompressor {
15     // TODO: implement this
16     fn make_archive_from_memory(_input: File) -> OuchResult<Vec<u8>> {
17         println!("{}: .tar.tar and .zip.tar is currently unimplemented.", "error".red());
18         Err(Error::InvalidZipArchive(""))
19     }
21     fn make_archive_from_files(input_filenames: Vec<PathBuf>) -> OuchResult<Vec<u8>> {
22         
23         let change_dir_and_return_parent = |filename: &PathBuf| -> OuchResult<PathBuf>  {
24             let previous_location = env::current_dir()?;
25             let parent = filename.parent().unwrap();
26             env::set_current_dir(parent)?;
27             Ok(previous_location)
28         };
29         
30         let buf = Vec::new();
31         let mut b = Builder::new(buf);
32     
33         for filename in input_filenames {
34             let previous_location = change_dir_and_return_parent(&filename)?;
35             // Safe unwrap since this filename came from `fs::canonicalize`.
36             let filename = filename.file_name().unwrap();
37             for entry in WalkDir::new(&filename) {
38                 let entry = entry?;
39                 let path = entry.path();
40                 if path.is_dir() {
41                     continue;
42                 }
43                 b.append_file(path, &mut fs::File::open(path)?)?;
44             }
45             env::set_current_dir(previous_location)?;
46         }
47         
48         Ok(b.into_inner()?)
49     }
52 impl Compressor for TarCompressor {
53     fn compress(&self, from: Entry) -> OuchResult<Vec<u8>> {
55         match from {
56             Entry::Files(filenames) => {
57                 Ok(
58                     Self::make_archive_from_files(filenames)?
59                 )
60             },
61             Entry::InMemory(file) => {
62                 Ok(
63                     Self::make_archive_from_memory(file)?
64                 )
65             }
66         }        
67     }