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
use chrono::DateTime;
use format::*;
use std::fs;
use std::io::{Read, Seek, SeekFrom, Write};
use std::path::{Path, PathBuf};
use util;
pub struct ZipperOptions {
pub path: PathBuf,
}
pub struct Zipper {
opts: ZipperOptions,
headers: Vec<CDFileHeader>,
outfile: fs::File,
offset: usize,
}
impl Zipper {
pub fn new(opts: ZipperOptions) -> Self {
debug!("Creating new zipper at {:?} ...", opts.path);
let file = fs::File::create(&opts.path).unwrap();
Self {
opts: opts,
headers: vec![],
outfile: file,
offset: 0,
}
}
pub fn add_file(self: &mut Self, real_path: &Path, zip_path: &Path) {
debug!("Adding {:?} as {:?} to zipper...", real_path, zip_path);
let metadata = fs::metadata(real_path).unwrap();
let mut file = fs::File::open(real_path).unwrap();
let mut buffer = Vec::new();
let bytes_read = file.read_to_end(&mut buffer).unwrap();
let mut local_header = LocalFileHeader::default();
let mut cd_header = CDFileHeader::default();
local_header.signature = LOCAL_FILE_HEADER_SIGNATURE;
cd_header.signature = CENTRAL_DIRECTORY_FILE_HEADER_SIGNATURE;
file.seek(SeekFrom::Start(0)).unwrap();
let crc = util::calculate_crc(&mut file);
debug!("- CRC32: {:#X?}", crc);
local_header.crc32 = crc;
cd_header.crc32 = crc;
local_header.compression_method = CompressionMethod::Stored as u16;
cd_header.compression_method = CompressionMethod::Stored as u16;
let file_len = metadata.len() as u32;
local_header.compressed_size = file_len;
cd_header.compressed_size = file_len;
local_header.uncompressed_size = file_len;
cd_header.uncompressed_size = file_len;
let file_name_data = zip_path.to_str().unwrap().as_bytes().to_vec();
debug!("- File Name: {:?}", zip_path);
local_header.file_name = file_name_data.clone();
local_header.file_name_len = file_name_data.len() as u16;
cd_header.file_name = file_name_data.clone();
cd_header.file_name_len = file_name_data.len() as u16;
let last_modified = DateTime::from(metadata.modified().unwrap());
debug!("- Last Modified: {:?}", last_modified);
local_header.modified_time = util::get_timepart(&last_modified);
local_header.modified_date = util::get_datepart(&last_modified);
cd_header.modified_time = util::get_timepart(&last_modified);
cd_header.modified_date = util::get_datepart(&last_modified);
self.offset += self.outfile.write(&local_header.to_le_bytes()).unwrap();
self.offset += self.outfile.write(&buffer).unwrap();
cd_header.rel_offset = self.offset as u32;
self.headers.push(cd_header);
}
pub fn finish(mut self) {
debug!("Finishing zip...");
let mut bytes_written = 0;
for header in &self.headers {
bytes_written += self.outfile.write(&header.to_le_bytes()).unwrap();
}
let mut eocd = EndOfCD::default();
eocd.signature = END_OF_CENTRAL_DIRECTORY_RECORD_SIGNATURE;
eocd.total_records = self.headers.len() as u16;
eocd.cd_size = bytes_written as u32;
eocd.cd_offset = self.offset as u32;
self.outfile.write(&eocd.to_le_bytes()).unwrap();
}
}