Merge pull request #119 from randy408/fuzz
Add fuzz target to build
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e64684b..4db2ac9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -201,12 +201,9 @@
TEST_BIG_ENDIAN(WORDS_BIGENDIAN)
-FIND_PACKAGE(ZLIB REQUIRED)
+FIND_PACKAGE(ZLIB 1.1.2 REQUIRED)
INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
SET(CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIR})
-IF(ZLIB_VERSION_STRING VERSION_LESS "1.1.2")
- MESSAGE(FATAL_ERROR "-- ZLIB version too old, please install at least v1.1.2")
-ENDIF(ZLIB_VERSION_STRING VERSION_LESS "1.1.2")
IF(ENABLE_BZIP2)
FIND_PACKAGE(BZip2)
diff --git a/NEWS.md b/NEWS.md
index 42ef46b..b4f6f7f 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -3,6 +3,7 @@
* Avoid using umask() since it's not thread-safe.
* Set close-on-exec flag when opening files.
+* Do not accept empty files as valid zip archives any longer.
1.5.2 [2019-03-12]
==================
diff --git a/THANKS b/THANKS
index ee7e57e..f92b7a2 100644
--- a/THANKS
+++ b/THANKS
@@ -18,6 +18,7 @@
Brian 'geeknik' Carpenter <geeknik@protonmail.ch>
Carl Mastrangelo <notcarl@google.com>
Cédric Tabin
+celan69
Chris Nehren <cnehren+libzip@pobox.com>
Coverity <info@coverity.com>
Dane Springmeyer <dane.springmeyer@gmail.com>
@@ -59,8 +60,10 @@
Michal Vyskocil <mvyskocil@suse.cz>
Mikhail Gusarov <dottedmag@dottedmag.net>.
Miklos Vajna
+Morris Hafner
Oliver Kaiser <under.northern.sky@googlemail.com>
Oliver Kuckertz <oliver.kuckertz@mologie.de>
+OSS-Fuzz Team
Pascal Terjan <pterjan@gmail.com>
Patrick Spendrin <ps_ml@gmx.de>
Paul Harris <harris.pc@gmail.com>
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 1f7ee12..0fedd17 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -119,6 +119,7 @@
zip_set_file_comment.c
zip_set_file_compression.c
zip_set_name.c
+ zip_source_accept_empty.c
zip_source_begin_write.c
zip_source_begin_write_cloning.c
zip_source_buffer.c
@@ -220,7 +221,7 @@
ENDIF()
-TARGET_LINK_LIBRARIES(zip ${ZLIB_LIBRARY} ${OPTIONAL_LIBRARY})
+TARGET_LINK_LIBRARIES(zip ${ZLIB_LIBRARIES} ${OPTIONAL_LIBRARY})
INSTALL(TARGETS zip
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
diff --git a/lib/compat.h b/lib/compat.h
index 41b7ddb..91e72bb 100644
--- a/lib/compat.h
+++ b/lib/compat.h
@@ -77,6 +77,11 @@
#define EOVERFLOW EFBIG
#endif
+/* not supported on at least Windows */
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+
#ifdef _WIN32
#if defined(HAVE__CHMOD)
#define chmod _chmod
@@ -191,4 +196,8 @@
#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR)
#endif
+#ifndef S_ISREG
+#define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG)
+#endif
+
#endif /* compat.h */
diff --git a/lib/zip.h b/lib/zip.h
index 42c3e14..5688b5d 100644
--- a/lib/zip.h
+++ b/lib/zip.h
@@ -229,7 +229,8 @@
ZIP_SOURCE_SUPPORTS, /* check whether source supports command */
ZIP_SOURCE_REMOVE, /* remove file */
ZIP_SOURCE_GET_COMPRESSION_FLAGS, /* get compression flags, internal only */
- ZIP_SOURCE_BEGIN_WRITE_CLONING /* like ZIP_SOURCE_BEGIN_WRITE, but keep part of original file */
+ ZIP_SOURCE_BEGIN_WRITE_CLONING, /* like ZIP_SOURCE_BEGIN_WRITE, but keep part of original file */
+ ZIP_SOURCE_ACCEPT_EMPTY /* whether empty files are valid archives */
};
typedef enum zip_source_cmd zip_source_cmd_t;
diff --git a/lib/zip_close.c b/lib/zip_close.c
index 2657226..6980a57 100644
--- a/lib/zip_close.c
+++ b/lib/zip_close.c
@@ -73,8 +73,10 @@
if (survivors == 0) {
if ((za->open_flags & ZIP_TRUNCATE) || changed) {
if (zip_source_remove(za->src) < 0) {
- _zip_error_set_from_source(&za->error, za->src);
- return -1;
+ if (!((zip_error_code_zip(zip_source_error(za->src)) == ZIP_ER_REMOVE) && (zip_error_code_system(zip_source_error(za->src)) == ENOENT))) {
+ _zip_error_set_from_source(&za->error, za->src);
+ return -1;
+ }
}
}
zip_discard(za);
diff --git a/lib/zip_crypto_gnutls.h b/lib/zip_crypto_gnutls.h
index a574466..7e15808 100644
--- a/lib/zip_crypto_gnutls.h
+++ b/lib/zip_crypto_gnutls.h
@@ -39,8 +39,8 @@
#include <nettle/aes.h>
#include <nettle/pbkdf2.h>
-#include <gnutls/crypto.h>
#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
typedef struct {
union {
diff --git a/lib/zip_open.c b/lib/zip_open.c
index 593bfde..dec6a98 100644
--- a/lib/zip_open.c
+++ b/lib/zip_open.c
@@ -43,8 +43,7 @@
typedef enum {
EXISTS_ERROR = -1,
EXISTS_NOT = 0,
- EXISTS_EMPTY,
- EXISTS_NONEMPTY,
+ EXISTS_OK
} exists_t;
static zip_t *_zip_allocate_new(zip_source_t *src, unsigned int flags, zip_error_t *error);
static zip_int64_t _zip_checkcons(zip_t *za, zip_cdir_t *cdir, zip_error_t *error);
@@ -174,19 +173,16 @@
}
len = st.size;
- /* treat empty files as empty archives */
- if (len == 0) {
- if ((za = _zip_allocate_new(src, flags, error)) == NULL) {
- return NULL;
- }
-
- return za;
- }
if ((za = _zip_allocate_new(src, flags, error)) == NULL) {
return NULL;
}
+ /* treat empty files as empty archives */
+ if (len == 0 && zip_source_accept_empty(src)) {
+ return za;
+ }
+
if ((cdir = _zip_find_central_dir(za, len)) == NULL) {
_zip_error_copy(error, &za->error);
/* keep src so discard does not get rid of it */
@@ -540,7 +536,7 @@
return EXISTS_ERROR;
}
- return (st.valid & ZIP_STAT_SIZE) && st.size == 0 ? EXISTS_EMPTY : EXISTS_NONEMPTY;
+ return EXISTS_OK;
}
@@ -725,16 +721,19 @@
eocd_disk = _zip_buffer_get_16(buffer);
eocd_offset = _zip_buffer_get_64(buffer);
- if (eocd_offset > ZIP_INT64_MAX || eocd_offset + EOCD64LEN < eocd_offset) {
+ /* valid seek value for start of EOCD */
+ if (eocd_offset > ZIP_INT64_MAX) {
zip_error_set(error, ZIP_ER_SEEK, EFBIG);
return NULL;
}
+ /* does EOCD fit before EOCD locator? */
if (eocd_offset + EOCD64LEN > eocdloc_offset + buf_offset) {
zip_error_set(error, ZIP_ER_INCONS, 0);
return NULL;
}
+ /* make sure current position of buffer is beginning of EOCD */
if (eocd_offset >= buf_offset && eocd_offset + EOCD64LEN <= buf_offset + _zip_buffer_size(buffer)) {
_zip_buffer_set_offset(buffer, eocd_offset - buf_offset);
free_buffer = false;
@@ -758,8 +757,10 @@
return NULL;
}
+ /* size of EOCD */
size = _zip_buffer_get_64(buffer);
+ /* is there a hole between EOCD and EOCD locator, or do they overlap? */
if ((flags & ZIP_CHECKCONS) && size + eocd_offset + 12 != buf_offset + eocdloc_offset) {
zip_error_set(error, ZIP_ER_INCONS, 0);
if (free_buffer) {
@@ -811,6 +812,7 @@
size = _zip_buffer_get_64(buffer);
offset = _zip_buffer_get_64(buffer);
+ /* did we read past the end of the buffer? */
if (!_zip_buffer_ok(buffer)) {
zip_error_set(error, ZIP_ER_INTERNAL, 0);
if (free_buffer) {
@@ -837,6 +839,11 @@
return NULL;
}
+ if (nentry > size / CDENTRYSIZE) {
+ zip_error_set(error, ZIP_ER_INCONS, 0);
+ return NULL;
+ }
+
if ((cd = _zip_cdir_new(nentry, error)) == NULL)
return NULL;
diff --git a/lib/zip_source_accept_empty.c b/lib/zip_source_accept_empty.c
new file mode 100644
index 0000000..e6d5151
--- /dev/null
+++ b/lib/zip_source_accept_empty.c
@@ -0,0 +1,52 @@
+/*
+ zip_source_accept_empty.c -- if empty source is a valid archive
+ Copyright (C) 2019 Dieter Baron and Thomas Klausner
+
+ This file is part of libzip, a library to manipulate ZIP archives.
+ The authors can be contacted at <libzip@nih.at>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include "zipint.h"
+
+
+bool
+zip_source_accept_empty(zip_source_t *src) {
+ int ret;
+
+ if ((zip_source_supports(src) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_ACCEPT_EMPTY)) == 0) {
+ if (ZIP_SOURCE_IS_LAYERED(src)) {
+ return zip_source_accept_empty(src->src);
+ }
+ return true;
+ }
+
+ ret = (int)_zip_source_call(src, NULL, 0, ZIP_SOURCE_ACCEPT_EMPTY);
+
+ return ret != 0;
+}
diff --git a/lib/zip_source_filep.c b/lib/zip_source_filep.c
index b2fc4b7..30e5991 100644
--- a/lib/zip_source_filep.c
+++ b/lib/zip_source_filep.c
@@ -205,6 +205,7 @@
}
}
+ ctx->supports |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_ACCEPT_EMPTY);
#ifdef CAN_CLONE
if (ctx->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE)) {
ctx->supports |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE_CLONING);
@@ -374,12 +375,19 @@
buf = (char *)data;
switch (cmd) {
+ case ZIP_SOURCE_ACCEPT_EMPTY:
+ return 0;
+
case ZIP_SOURCE_BEGIN_WRITE:
+#ifdef _WIN32
+ return -1;
+#else
if (ctx->fname == NULL) {
zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
return -1;
}
return create_temp_output(ctx);
+#endif
#ifdef CAN_CLONE
case ZIP_SOURCE_BEGIN_WRITE_CLONING:
@@ -390,6 +398,13 @@
return create_temp_output_cloning(ctx, len);
#endif
+ case ZIP_SOURCE_CLOSE:
+ if (ctx->fname) {
+ fclose(ctx->f);
+ ctx->f = NULL;
+ }
+ return 0;
+
case ZIP_SOURCE_COMMIT_WRITE: {
if (fclose(ctx->fout) < 0) {
ctx->fout = NULL;
@@ -405,13 +420,6 @@
return 0;
}
- case ZIP_SOURCE_CLOSE:
- if (ctx->fname) {
- fclose(ctx->f);
- ctx->f = NULL;
- }
- return 0;
-
case ZIP_SOURCE_ERROR:
return zip_error_to_data(&ctx->error, data, len);
@@ -644,7 +652,8 @@
flags |= O_RDONLY;
}
- if ((fd = open(name, flags)) < 0) {
+ /* mode argument needed on Windows */
+ if ((fd = open(name, flags, 0666)) < 0) {
return NULL;
}
if ((fp = fdopen(fd, writeable ? "r+b" : "rb")) == NULL) {
diff --git a/lib/zip_source_win32handle.c b/lib/zip_source_win32handle.c
index 3a2f52e..96406cd 100644
--- a/lib/zip_source_win32handle.c
+++ b/lib/zip_source_win32handle.c
@@ -127,6 +127,8 @@
ctx->supports = ZIP_SOURCE_SUPPORTS_SEEKABLE;
}
+ ctx->supports |= ZIP_SOURCE_ACCEPT_EMPTY;
+
if ((zs = zip_source_function_create(_win32_read_file, ctx, error)) == NULL) {
free(ctx->fname);
free(ctx);
@@ -148,6 +150,9 @@
buf = (char *)data;
switch (cmd) {
+ case ZIP_SOURCE_ACCEPT_EMPTY:
+ return 0;
+
case ZIP_SOURCE_BEGIN_WRITE:
if (ctx->fname == NULL) {
zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
diff --git a/lib/zipint.h b/lib/zipint.h
index 76e8709..e52b60e 100644
--- a/lib/zipint.h
+++ b/lib/zipint.h
@@ -547,6 +547,7 @@
void _zip_set_open_error(int *zep, const zip_error_t *err, int ze);
+bool zip_source_accept_empty(zip_source_t *src);
zip_int64_t _zip_source_call(zip_source_t *src, void *data, zip_uint64_t length, zip_source_cmd_t command);
bool _zip_source_eof(zip_source_t *);
zip_source_t *_zip_source_file_or_p(const char *, FILE *, zip_uint64_t, zip_int64_t, const zip_stat_t *, zip_error_t *error);
diff --git a/man/zip_close.mdoc b/man/zip_close.mdoc
index d9327cb..b5bfd21 100644
--- a/man/zip_close.mdoc
+++ b/man/zip_close.mdoc
@@ -1,5 +1,5 @@
.\" zip_close.mdoc -- close zip archive
-.\" Copyright (C) 2003-2018 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2003-2019 Dieter Baron and Thomas Klausner
.\"
.\" This file is part of libzip, a library to manipulate ZIP archives.
.\" The authors can be contacted at <libzip@nih.at>
@@ -29,7 +29,7 @@
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd December 18, 2017
+.Dd September 17, 2019
.Dt ZIP_CLOSE 3
.Os
.Sh NAME
@@ -54,9 +54,7 @@
If successful,
.Ar archive
is freed.
-If writing fails,
-.Fn zip_close
-fails;
+Otherwise
.Ar archive
is left unchanged and must still be freed.
.Pp
diff --git a/man/zip_source_function.mdoc b/man/zip_source_function.mdoc
index a433b37..9a9cc4b 100644
--- a/man/zip_source_function.mdoc
+++ b/man/zip_source_function.mdoc
@@ -1,5 +1,5 @@
.\" zip_source_function.mdoc -- create data source from function
-.\" Copyright (C) 2004-2018 Dieter Baron and Thomas Klausner
+.\" Copyright (C) 2004-2019 Dieter Baron and Thomas Klausner
.\"
.\" This file is part of libzip, a library to manipulate ZIP archives.
.\" The authors can be contacted at <libzip@nih.at>
@@ -29,7 +29,7 @@
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd December 18, 2017
+.Dd September 17, 2019
.Dt ZIP_SOURCE_FUNCTION 3
.Os
.Sh NAME
@@ -110,6 +110,10 @@
and
.Dv ZIP_SOURCE_REMOVE .
.El
+.Ss Dv ZIP_SOURCE_ACCEPT_EMPTY
+Return 1 if an empty source should be accepted as a valid zip archive.
+This is the default if this command is not supported by a source.
+File system backed sources should return 0.
.Ss Dv ZIP_SOURCE_BEGIN_WRITE
Prepare the source for writing.
Use this to create any temporary file(s).
diff --git a/regress/fseek.c b/regress/fseek.c
index 19f3c40..cba1033 100644
--- a/regress/fseek.c
+++ b/regress/fseek.c
@@ -1,6 +1,6 @@
/*
fseek.c -- test tool for seeking in zip archives
- Copyright (C) 2016-2018 Dieter Baron and Thomas Klausner
+ Copyright (C) 2016-2019 Dieter Baron and Thomas Klausner
This file is part of libzip, a library to manipulate ZIP archives.
The authors can be contacted at <libzip@nih.at>
@@ -77,6 +77,7 @@
if (zip_fseek(zf, offset, SEEK_SET) < 0) {
fprintf(stderr, "%s: zip_fseek failed: %s\n", progname, zip_error_strerror(zip_file_get_error(zf)));
+ zip_fclose(zf);
zip_close(z);
return 1;
}
@@ -86,10 +87,16 @@
}
if (n < 0) {
fprintf(stderr, "%s: zip_fread failed: %s\n", progname, zip_error_strerror(zip_file_get_error(zf)));
+ zip_fclose(zf);
zip_close(z);
return 1;
}
+ if (zip_fclose(zf) == -1) {
+ fprintf(stderr, "%s: can't close zip archive entry %" PRIu64 " in '%s': %s\n", progname, index, archive, zip_strerror(z));
+ return 1;
+ }
+
if (zip_close(z) == -1) {
fprintf(stderr, "%s: can't close zip archive '%s': %s\n", progname, archive, zip_strerror(z));
return 1;
diff --git a/regress/open_empty_2.test b/regress/open_empty_2.test
index 07a5358..bb35bc6 100644
--- a/regress/open_empty_2.test
+++ b/regress/open_empty_2.test
@@ -2,5 +2,6 @@
program tryopen
file testfile.txt testfile.txt testfile.txt
args testfile.txt
-return 0
-stdout opening 'testfile.txt' succeeded, 0 entries
+return 1
+stdout opening 'testfile.txt' returned error 19
+stderr 1 errors
diff --git a/regress/open_file_count.test b/regress/open_file_count.test
index 56f0447..5078978 100644
--- a/regress/open_file_count.test
+++ b/regress/open_file_count.test
@@ -8,5 +8,5 @@
return 1
stdout opening 'incons-file-count-high.zzip' returned error 21
stdout opening 'incons-file-count-low.zzip' returned error 21
-stdout opening 'incons-file-count-overflow.zzip' returned error 14
+stdout opening 'incons-file-count-overflow.zzip' returned error 21
stderr 3 errors
diff --git a/regress/open_incons.test b/regress/open_incons.test
index 0843816..cda6afb 100644
--- a/regress/open_incons.test
+++ b/regress/open_incons.test
@@ -60,7 +60,7 @@
stdout opening 'incons-eocd-magic-bad.zzip' returned error 19
stdout opening 'incons-file-count-high.zzip' returned error 21
stdout opening 'incons-file-count-low.zzip' returned error 21
-stdout opening 'incons-file-count-overflow.zzip' returned error 14
+stdout opening 'incons-file-count-overflow.zzip' returned error 21
stdout opening 'incons-local-compression-method.zzip' returned error 21
stdout opening 'incons-local-compsize-larger.zzip' returned error 21
stdout opening 'incons-local-compsize-smaller.zzip' returned error 21
diff --git a/src/zipcmp.c b/src/zipcmp.c
index c452684..4e14e60 100644
--- a/src/zipcmp.c
+++ b/src/zipcmp.c
@@ -1,6 +1,6 @@
/*
zipcmp.c -- compare zip files
- Copyright (C) 2003-2018 Dieter Baron and Thomas Klausner
+ Copyright (C) 2003-2019 Dieter Baron and Thomas Klausner
This file is part of libzip, a library to manipulate ZIP archives.
The authors can be contacted at <libzip@nih.at>
@@ -233,16 +233,25 @@
if (paranoid) {
if (comment_compare(a[0].comment, a[0].comment_length, a[1].comment, a[1].comment_length) != 0) {
if (verbose) {
- printf("--- archive comment (%ld)\n", a[0].comment_length);
- printf("+++ archive comment (%ld)\n", a[1].comment_length);
+ printf("--- archive comment (%zd)\n", a[0].comment_length);
+ printf("+++ archive comment (%zd)\n", a[1].comment_length);
}
res = 1;
}
}
- for (i = 0; i < 2; i++)
- if (a[i].za)
+ for (i = 0; i < 2; i++) {
+ int j;
+
+ if (a[i].za) {
zip_close(a[i].za);
+ }
+ for (j = 0; j < a[i].nentry; j++) {
+ free(a[i].entry[j].name);
+ free(a[i].entry[j].extra_fields);
+ }
+ free(a[i].entry);
+ }
switch (res) {
case 0:
diff --git a/src/ziptool.c b/src/ziptool.c
index e33b9b5..e074a3d 100644
--- a/src/ziptool.c
+++ b/src/ziptool.c
@@ -503,7 +503,7 @@
idx = strtoull(argv[0], NULL, 10);
mtime = (time_t)strtoull(argv[1], NULL, 10);
if (zip_file_set_mtime(za, idx, mtime, 0) < 0) {
- fprintf(stderr, "can't set file mtime at index '%" PRIu64 "' to '%ld': %s\n", idx, mtime, zip_strerror(za));
+ fprintf(stderr, "can't set file mtime at index '%" PRIu64 "' to '%lld': %s\n", idx, (long long)mtime, zip_strerror(za));
return -1;
}
return 0;
@@ -523,7 +523,7 @@
}
for (idx = 0; idx < (zip_uint64_t)num_entries; idx++) {
if (zip_file_set_mtime(za, idx, mtime, 0) < 0) {
- fprintf(stderr, "can't set file mtime at index '%" PRIu64 "' to '%ld': %s\n", idx, mtime, zip_strerror(za));
+ fprintf(stderr, "can't set file mtime at index '%" PRIu64 "' to '%lld': %s\n", idx, (long long)mtime, zip_strerror(za));
return -1;
}
}