Skip to content

Commit e4aee20

Browse files
implement ZipFile::options + refactor options normalization (#305)
Co-authored-by: Chris Hennick <[email protected]>
1 parent ea8a7bb commit e4aee20

File tree

2 files changed

+38
-28
lines changed

2 files changed

+38
-28
lines changed

src/read.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ use crate::types::{
1313
AesMode, AesVendorVersion, DateTime, System, ZipCentralEntryBlock, ZipFileData,
1414
ZipLocalEntryBlock,
1515
};
16+
use crate::write::SimpleFileOptions;
1617
use crate::zipcrypto::{ZipCryptoReader, ZipCryptoReaderValid, ZipCryptoValidator};
18+
use crate::ZIP64_BYTES_THR;
1719
use indexmap::IndexMap;
1820
use std::borrow::Cow;
1921
use std::ffi::OsStr;
@@ -115,7 +117,7 @@ use crate::aes::PWD_VERIFY_LENGTH;
115117
use crate::extra_fields::UnicodeExtraField;
116118
use crate::result::ZipError::{InvalidArchive, InvalidPassword};
117119
use crate::spec::is_dir;
118-
use crate::types::ffi::S_IFLNK;
120+
use crate::types::ffi::{S_IFLNK, S_IFREG};
119121
use crate::unstable::{path_to_string, LittleEndianReadExt};
120122
pub use zip_archive::ZipArchive;
121123

@@ -1578,6 +1580,23 @@ impl<'a> ZipFile<'a> {
15781580
pub fn central_header_start(&self) -> u64 {
15791581
self.get_metadata().central_header_start
15801582
}
1583+
1584+
/// Get the [`SimpleFileOptions`] that would be used to write this file to
1585+
/// a new zip archive.
1586+
pub fn options(&self) -> SimpleFileOptions {
1587+
let mut options = SimpleFileOptions::default()
1588+
.large_file(self.compressed_size().max(self.size()) > ZIP64_BYTES_THR)
1589+
.compression_method(self.compression())
1590+
.unix_permissions(self.unix_mode().unwrap_or(0o644) | S_IFREG)
1591+
.last_modified_time(
1592+
self.last_modified()
1593+
.filter(|m| m.is_valid())
1594+
.unwrap_or_else(DateTime::default_for_write),
1595+
);
1596+
1597+
options.normalize();
1598+
options
1599+
}
15811600
}
15821601

15831602
/// Methods for retrieving information on zip files

src/write.rs

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,14 @@ impl<'a> arbitrary::Arbitrary<'a> for FileOptions<'a, ExtendedFileOptions> {
417417
}
418418

419419
impl<T: FileOptionExtension> FileOptions<'_, T> {
420+
pub(crate) fn normalize(&mut self) {
421+
if !self.last_modified_time.is_valid() {
422+
self.last_modified_time = FileOptions::<T>::default().last_modified_time;
423+
}
424+
425+
*self.permissions.get_or_insert(0o644) |= ffi::S_IFREG;
426+
}
427+
420428
/// Set the compression method for the new file
421429
///
422430
/// The default is `CompressionMethod::Deflated` if it is enabled. If not,
@@ -1168,7 +1176,7 @@ impl<W: Write + Seek> ZipWriter<W> {
11681176
name: S,
11691177
mut options: FileOptions<T>,
11701178
) -> ZipResult<()> {
1171-
Self::normalize_options(&mut options);
1179+
options.normalize();
11721180
let make_new_self = self.inner.prepare_next_writer(
11731181
options.compression_method,
11741182
options.compression_level,
@@ -1244,16 +1252,6 @@ impl<W: Write + Seek> ZipWriter<W> {
12441252
Ok(())
12451253
}
12461254

1247-
fn normalize_options<T: FileOptionExtension>(options: &mut FileOptions<T>) {
1248-
if options.permissions.is_none() {
1249-
options.permissions = Some(0o644);
1250-
}
1251-
if !options.last_modified_time.is_valid() {
1252-
options.last_modified_time = FileOptions::<T>::default().last_modified_time;
1253-
}
1254-
*options.permissions.as_mut().unwrap() |= ffi::S_IFREG;
1255-
}
1256-
12571255
/// Starts a file, taking a Path as argument.
12581256
///
12591257
/// This function ensures that the '/' path separator is used and normalizes `.` and `..`. It
@@ -1294,17 +1292,7 @@ impl<W: Write + Seek> ZipWriter<W> {
12941292
/// }
12951293
/// ```
12961294
pub fn raw_copy_file_rename<S: ToString>(&mut self, file: ZipFile, name: S) -> ZipResult<()> {
1297-
let mut options = SimpleFileOptions::default()
1298-
.large_file(file.compressed_size().max(file.size()) > spec::ZIP64_BYTES_THR)
1299-
.last_modified_time(
1300-
file.last_modified()
1301-
.unwrap_or_else(DateTime::default_for_write),
1302-
)
1303-
.compression_method(file.compression());
1304-
if let Some(perms) = file.unix_mode() {
1305-
options = options.unix_permissions(perms);
1306-
}
1307-
Self::normalize_options(&mut options);
1295+
let options = file.options();
13081296
self.raw_copy_file_rename_internal(file, name, options)
13091297
}
13101298

@@ -1399,14 +1387,17 @@ impl<W: Write + Seek> ZipWriter<W> {
13991387
unix_mode: Option<u32>,
14001388
) -> ZipResult<()> {
14011389
let name = file.name().to_owned();
1402-
let mut options = SimpleFileOptions::default()
1403-
.large_file(file.compressed_size().max(file.size()) > spec::ZIP64_BYTES_THR)
1404-
.last_modified_time(last_modified_time)
1405-
.compression_method(file.compression());
1390+
1391+
let mut options = file.options();
1392+
1393+
options = options.last_modified_time(last_modified_time);
1394+
14061395
if let Some(perms) = unix_mode {
14071396
options = options.unix_permissions(perms);
14081397
}
1409-
Self::normalize_options(&mut options);
1398+
1399+
options.normalize();
1400+
14101401
self.raw_copy_file_rename_internal(file, name, options)
14111402
}
14121403

0 commit comments

Comments
 (0)