archive_lp/
lib.rs

1#[macro_use] extern crate failure; use failure::Error;
2#[macro_use] extern crate log;
3
4extern crate zip as zipcrate;
5extern crate xz2;
6extern crate flate2;
7extern crate tar as tarcrate;
8
9#[cfg(feature = "indicate")]
10extern crate indicatif;
11
12use std::path::{PathBuf, Path};
13use std::fs;
14
15mod formats;
16
17pub fn contains_file<P:AsRef<Path>>(src : P, file : &str) -> Result<bool,Error>
18    where std::path::PathBuf: std::convert::From<P>, P : std::fmt::Display + Copy,  
19{
20    //! Checks if a certain file is in an archive.
21        
22    let src_path : PathBuf = PathBuf::from(src);
23    
24    match src_path.extension() {
25        None => Err(format_err!("File '{}' has no extension, not a file?",src)),
26        Some(ext) => { 
27            match ext.to_str().unwrap() {
28                "zip" => formats::zip::contains(&src_path,file),
29                "tar" => formats::tar::contains(&src_path,file),
30                "gz" => { 
31                    let buffer = formats::gz::decode(&src_path)?;
32                    match get_second_extension(src_path.file_name().unwrap().to_str().unwrap()){
33                        Some("tar") => formats::tar::buffer_contains(&buffer,file),
34                        Some(other_ext) => Err(format_err!("Unknown format {}",other_ext)),
35                        None => Err(format_err!("No nested archive")),
36                    }
37                },
38                "xz" => { 
39                    let buffer = formats::xz::decode(&src_path)?;
40                    match get_second_extension(src_path.file_name().unwrap().to_str().unwrap()){
41                        Some("tar") => formats::tar::buffer_contains(&buffer,file),
42                        Some(other_ext) => Err(format_err!("Unknown format {}",other_ext)),
43                        None => Err(format_err!("No nested archive")),
44                    }
45                },
46                ext => Err(format_err!("Unknown extension type {}",ext)),
47            }
48        } 
49    }
50}
51
52pub fn extract_to<P:AsRef<Path>>(src : P, des : P) -> Result<PathBuf,Error>
53    where std::path::PathBuf: std::convert::From<P>, P : std::fmt::Display + Copy, 
54{
55    //! Extracts the archive to the destination folder.
56    //! 
57    //! Checks if the archive and folder exists and then
58    //! extracts the archive into the folder. If the destination
59    //! folder doesn't exist then it attempts to create it.
60    
61    let src_path : PathBuf = PathBuf::from(src);
62    let des_path : PathBuf = PathBuf::from(des);
63
64    if false == src_path.exists() { 
65        return Err(format_err!("Source file, '{}' does not exist.",src)); 
66    }
67
68    if false == des_path.exists() { 
69        warn!("Destination '{}' does not exist.",src);
70        fs::create_dir_all(&des_path)?;
71    }
72
73    match src_path.extension() {
74        None => Err(format_err!("File '{}' has no extension, not a file?",src)),
75        Some(ext) => { 
76            match ext.to_str().unwrap() {
77                "zip" => formats::zip::extract(&src_path,&des_path),
78                "tar" => formats::tar::extract(&src_path,&des_path),
79                "gz" => { 
80                    let buffer = formats::gz::decode(&src_path)?;
81                    match get_second_extension(src_path.file_name().unwrap().to_str().unwrap()){
82                        Some("tar") => formats::tar::extract_buffer(&buffer,&des_path,false),
83                        Some(other_ext) => Err(format_err!("Unknown format {}",other_ext)),
84                        None => Err(format_err!("No nested archive")),
85                    }
86                },
87                "xz" => { 
88                    let buffer = formats::xz::decode(&src_path)?;
89                    match get_second_extension(src_path.file_name().unwrap().to_str().unwrap()){
90                        Some("tar") => formats::tar::extract_buffer(&buffer,&des_path,false),
91                        Some(other_ext) => Err(format_err!("Unknown format {}",other_ext)),
92                        None => Err(format_err!("No nested archive")),
93                    }
94                },
95                ext => Err(format_err!("Unknown extension type {}",ext)),
96            }
97        } 
98    }
99}
100
101
102pub fn extract_root_to<P:AsRef<Path>>(src : P, des : P) -> Result<PathBuf,Error>
103    where std::path::PathBuf: std::convert::From<P>, P : std::fmt::Display + Copy, 
104{
105    //! Extracts the root of the archive to the destination folder.
106    //! 
107    //! Checks if the archive and folder exists and then
108    //! extracts the archive into the folder. If the destination
109    //! folder doesn't exist then it attempts to create it.
110    //! 
111    //! The 'root' of the folder is where all the files are located.
112    //! Sometimes the contents of archives are nested in multiple 
113    //! folders before the actual data. 
114    //! 
115    //! This function looks at each actual file in the archive and finds
116    //! the file with the shortest absolute path in the archive, and assumes
117    //! that is the root of the archive, and then extracts that file to the root
118    //! of the destination folder.
119
120    let src_path : PathBuf = PathBuf::from(src);
121    let des_path : PathBuf = PathBuf::from(des);
122
123    if false == src_path.exists() { 
124        return Err(format_err!("Source file, '{}' does not exist.",src)); 
125    }
126
127    if false == des_path.exists() { 
128        warn!("Destination '{}' does not exist.",src);
129        fs::create_dir_all(&des_path)?;
130    }
131
132    match src_path.extension() {
133        None => Err(format_err!("File '{}' has no extension, not a file?",src)),
134        Some(ext) => { 
135            match ext.to_str().unwrap() {
136                "zip" => formats::zip::extract_root(&src_path,&des_path),
137                "tar" => formats::tar::extract_root(&src_path,&des_path),
138                "gz" => { 
139                    let buffer = formats::gz::decode(&src_path)?;
140                    match get_second_extension(src_path.file_name().unwrap().to_str().unwrap()){
141                        Some("tar") => formats::tar::extract_buffer(&buffer,&des_path,true),
142                        Some(other_ext) => Err(format_err!("Unknown format {}",other_ext)),
143                        None => Err(format_err!("No nested archive")),
144                    }
145                },
146                "xz" => { 
147                    let buffer = formats::xz::decode(&src_path)?;
148                    match get_second_extension(src_path.file_name().unwrap().to_str().unwrap()){
149                        Some("tar") => formats::tar::extract_buffer(&buffer,&des_path,true),
150                        Some(other_ext) => Err(format_err!("Unknown format {}",other_ext)),
151                        None => Err(format_err!("No nested archive")),
152                    }
153                },
154                ext => Err(format_err!("Unknown extension type {}",ext)),
155            }
156        } 
157    }
158}
159
160fn get_second_extension<'a>(file : &'a str) -> Option<&'a str> {
161    //! gets the second extenison, so aa.b.c then it returns b
162    
163    let splits = file.split(".").collect::<Vec<&str>>();
164
165    if splits.len() >= 3 {
166        Some(splits[splits.len()-2])
167    } else {
168        None
169    }
170}