From c2854bea92f8d63aa1881e53c657e07fdc09e6fb Mon Sep 17 00:00:00 2001 From: Dieter Baron Date: Wed, 30 Oct 2024 11:56:51 +0100 Subject: [PATCH] Fix performance regression: cache dostime to time_t conversion results. Closes issue #462 --- lib/zip_dirent.c | 10 ++++++++++ lib/zip_file_set_mtime.c | 20 +++++++++++++++----- lib/zip_new.c | 1 + lib/zip_stat_index.c | 11 +++++++---- lib/zipint.h | 5 +++++ 5 files changed, 38 insertions(+), 9 deletions(-) diff --git a/lib/zip_dirent.c b/lib/zip_dirent.c index 6e3e1a46..24bc6abf 100644 --- a/lib/zip_dirent.c +++ b/lib/zip_dirent.c @@ -282,6 +282,7 @@ _zip_dirent_init(zip_dirent_t *de) { de->cloned = 0; de->crc_valid = true; + de->last_mod_mtime_valid = false; de->version_madeby = 63 | (ZIP_OPSYS_DEFAULT << 8); de->version_needed = 10; /* 1.0 */ de->bitflags = 0; @@ -1263,3 +1264,12 @@ zip_dirent_check_consistency(zip_dirent_t *dirent) { } return 0; } + +time_t zip_dirent_get_last_mod_mtime(zip_dirent_t *de) { + if (!de->last_mod_mtime_valid) { + de->last_mod_mtime = _zip_d2u_time(&de->last_mod); + de->last_mod_mtime_valid = true; + } + + return de->last_mod_mtime; +} \ No newline at end of file diff --git a/lib/zip_file_set_mtime.c b/lib/zip_file_set_mtime.c index d08d808b..e60f7a9a 100644 --- a/lib/zip_file_set_mtime.c +++ b/lib/zip_file_set_mtime.c @@ -33,8 +33,7 @@ #include "zipint.h" -ZIP_EXTERN int -zip_file_set_dostime(zip_t *za, zip_uint64_t idx, zip_uint16_t dtime, zip_uint16_t ddate, zip_flags_t flags) { +static int zip_file_set_time(zip_t *za, zip_uint64_t idx, zip_uint16_t dtime, zip_uint16_t ddate, zip_flags_t flags, time_t *mtime) { zip_entry_t *e; if (_zip_get_dirent(za, idx, 0, NULL) == NULL) { @@ -66,18 +65,29 @@ zip_file_set_dostime(zip_t *za, zip_uint64_t idx, zip_uint16_t dtime, zip_uint16 e->changes->last_mod.time = dtime; e->changes->last_mod.date = ddate; + if (mtime != NULL) { + e->changes->last_mod_mtime = *mtime; + e->changes->last_mod_mtime_valid = true; + } + else { + e->changes->last_mod_mtime_valid = false; + } e->changes->changed |= ZIP_DIRENT_LAST_MOD; return 0; } -ZIP_EXTERN int -zip_file_set_mtime(zip_t *za, zip_uint64_t idx, time_t mtime, zip_flags_t flags) { +ZIP_EXTERN int zip_file_set_dostime(zip_t *za, zip_uint64_t idx, zip_uint16_t dtime, zip_uint16_t ddate, zip_flags_t flags) { + return zip_file_set_time(za, idx, dtime, ddate, flags, NULL); +} + + +ZIP_EXTERN int zip_file_set_mtime(zip_t *za, zip_uint64_t idx, time_t mtime, zip_flags_t flags) { zip_dostime_t dostime; if (_zip_u2d_time(mtime, &dostime, &za->error) < 0) { return -1; } - return zip_file_set_dostime(za, idx, dostime.time, dostime.date, flags); + return zip_file_set_time(za, idx, dostime.time, dostime.date, flags, &mtime); } diff --git a/lib/zip_new.c b/lib/zip_new.c index fa21086b..68e1588f 100644 --- a/lib/zip_new.c +++ b/lib/zip_new.c @@ -68,6 +68,7 @@ _zip_new(zip_error_t *error) { za->nopen_source = za->nopen_source_alloc = 0; za->open_source = NULL; za->progress = NULL; + za->torrent_mtime = 0; return za; } diff --git a/lib/zip_stat_index.c b/lib/zip_stat_index.c index 5130eb6a..af9f0e5f 100644 --- a/lib/zip_stat_index.c +++ b/lib/zip_stat_index.c @@ -77,7 +77,7 @@ zip_stat_index(zip_t *za, zip_uint64_t index, zip_flags_t flags, zip_stat_t *st) } if (entry->changes != NULL && entry->changes->changed & ZIP_DIRENT_LAST_MOD) { - st->mtime = _zip_d2u_time(&de->last_mod); + st->mtime = zip_dirent_get_last_mod_mtime(de); st->valid |= ZIP_STAT_MTIME; } } @@ -86,7 +86,7 @@ zip_stat_index(zip_t *za, zip_uint64_t index, zip_flags_t flags, zip_stat_t *st) st->crc = de->crc; st->size = de->uncomp_size; - st->mtime = _zip_d2u_time(&de->last_mod); + st->mtime = zip_dirent_get_last_mod_mtime(de); st->comp_size = de->comp_size; st->comp_method = (zip_uint16_t)de->comp_method; st->encryption_method = de->encryption_method; @@ -97,9 +97,12 @@ zip_stat_index(zip_t *za, zip_uint64_t index, zip_flags_t flags, zip_stat_t *st) } if ((za->ch_flags & ZIP_AFL_WANT_TORRENTZIP) && (flags & ZIP_FL_UNCHANGED) == 0) { - zip_dostime_t dostime = {0xbc00, 0x2198}; + if (za->torrent_mtime == 0) { + zip_dostime_t dostime = {0xbc00, 0x2198}; + za->torrent_mtime = _zip_d2u_time(&dostime); + } st->comp_method = ZIP_CM_DEFLATE; - st->mtime = _zip_d2u_time(&dostime); + st->mtime = za->torrent_mtime; st->valid |= ZIP_STAT_MTIME | ZIP_STAT_COMP_METHOD; st->valid &= ~ZIP_STAT_COMP_SIZE; } diff --git a/lib/zipint.h b/lib/zipint.h index 5b931dce..e22d74c2 100644 --- a/lib/zipint.h +++ b/lib/zipint.h @@ -314,6 +314,7 @@ struct zip { zip_progress_t *progress; /* progress callback for zip_close() */ zip_uint32_t* write_crc; /* have _zip_write() compute CRC */ + time_t torrent_mtime; }; /* file in zip archive, part of API */ @@ -346,6 +347,7 @@ struct zip_dirent { bool cloned; /* whether this instance is cloned, and thus shares non-changed strings */ bool crc_valid; /* if CRC is valid (sometimes not for encrypted archives) */ + bool last_mod_mtime_valid; zip_uint16_t version_madeby; /* (c) version of creator */ zip_uint16_t version_needed; /* (cl) version needed to extract */ @@ -366,6 +368,8 @@ struct zip_dirent { zip_uint32_t compression_level; /* level of compression to use (never valid in orig) */ zip_uint16_t encryption_method; /* encryption method, computed from other fields */ char *password; /* file specific encryption password */ + + time_t last_mod_mtime; /* cached last_mod in Unix time format */ }; /* zip archive central directory */ @@ -553,6 +557,7 @@ int zip_dirent_check_consistency(zip_dirent_t *dirent); zip_dirent_t *_zip_dirent_clone(const zip_dirent_t *); void _zip_dirent_free(zip_dirent_t *); void _zip_dirent_finalize(zip_dirent_t *); +time_t zip_dirent_get_last_mod_mtime(zip_dirent_t *de); void _zip_dirent_init(zip_dirent_t *); bool _zip_dirent_needs_zip64(const zip_dirent_t *, zip_flags_t); zip_dirent_t *_zip_dirent_new(void);