1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use std::{
env, fs,
io::{self, prelude::*},
path::{Path, PathBuf},
};
use walkdir::WalkDir;
use zip::{self, read::ZipFile, ZipArchive};
use crate::{
info, oof,
utils::{self, Bytes},
};
pub fn unpack_archive<R>(mut archive: ZipArchive<R>, into: &Path, flags: &oof::Flags) -> crate::Result<Vec<PathBuf>>
where
R: Read + Seek,
{
let mut unpacked_files = vec![];
for idx in 0..archive.len() {
let mut file = archive.by_index(idx)?;
let file_path = match file.enclosed_name() {
Some(path) => path.to_owned(),
None => continue,
};
let file_path = into.join(file_path);
if file_path.exists() && !utils::user_wants_to_overwrite(&file_path, flags)? {
continue;
}
check_for_comments(&file);
match (&*file.name()).ends_with('/') {
_is_dir @ true => {
println!("File {} extracted to \"{}\"", idx, file_path.display());
fs::create_dir_all(&file_path)?;
}
_is_file @ false => {
if let Some(path) = file_path.parent() {
if !path.exists() {
fs::create_dir_all(&path)?;
}
}
info!("{:?} extracted. ({})", file_path.display(), Bytes::new(file.size()));
let mut output_file = fs::File::create(&file_path)?;
io::copy(&mut file, &mut output_file)?;
}
}
#[cfg(unix)]
__unix_set_permissions(&file_path, &file);
let file_path = fs::canonicalize(file_path.clone())?;
unpacked_files.push(file_path);
}
Ok(unpacked_files)
}
pub fn build_archive_from_paths<W>(input_filenames: &[PathBuf], writer: W) -> crate::Result<W>
where
W: Write + Seek,
{
let mut writer = zip::ZipWriter::new(writer);
let options = zip::write::FileOptions::default();
let invalid_unicode_filenames: Vec<PathBuf> = input_filenames
.iter()
.map(|path| (path, path.to_str()))
.filter(|(_, x)| x.is_none())
.map(|(a, _)| a.to_path_buf())
.collect();
if !invalid_unicode_filenames.is_empty() {
panic!("invalid unicode filenames found, cannot be supported by Zip:\n {:#?}", invalid_unicode_filenames);
}
for filename in input_filenames {
let previous_location = utils::cd_into_same_dir_as(filename)?;
let filename = filename.file_name().unwrap();
for entry in WalkDir::new(filename) {
let entry = entry?;
let path = &entry.path();
println!("Compressing '{}'.", utils::to_utf(path));
if path.is_dir() {
continue;
}
writer.start_file(path.to_str().unwrap().to_owned(), options)?;
let file_bytes = fs::read(entry.path())?;
writer.write_all(&*file_bytes)?;
}
env::set_current_dir(previous_location)?;
}
let bytes = writer.finish()?;
Ok(bytes)
}
fn check_for_comments(file: &ZipFile) {
let comment = file.comment();
if !comment.is_empty() {
info!("Found comment in {}: {}", file.name(), comment);
}
}
#[cfg(unix)]
fn __unix_set_permissions(file_path: &Path, file: &ZipFile) {
use std::os::unix::fs::PermissionsExt;
if let Some(mode) = file.unix_mode() {
fs::set_permissions(&file_path, fs::Permissions::from_mode(mode)).unwrap();
}
}