5765 lines
183 KiB
Diff
5765 lines
183 KiB
Diff
From 33a5aed090f3224d699ee0787bf2dd3c2b111645 Mon Sep 17 00:00:00 2001
|
|
From: guoqinglan <guoqinglan@uniontech.com>
|
|
Date: Fri, 5 Feb 2021 13:34:41 +0800
|
|
Subject: [PATCH] add deepin compressor cancel process function
|
|
|
|
---
|
|
CMakeLists.txt | 6 +
|
|
cmake-zipconf.h.in | 1 +
|
|
lib/CMakeLists.txt | 41 +-
|
|
lib/zip.h | 37 +-
|
|
lib/zip_algorithm_bzip2.c | 10 +-
|
|
lib/zip_algorithm_deflate.c | 15 +-
|
|
lib/zip_algorithm_xz.c | 249 +++++++
|
|
lib/zip_close.c | 136 +++-
|
|
lib/zip_delete.c | 2 +-
|
|
lib/zip_dirent.c | 122 +++-
|
|
lib/zip_get_encryption_implementation.c | 13 +-
|
|
lib/zip_mkstempm.c | 93 +++
|
|
lib/zip_open.c | 40 +-
|
|
lib/zip_pkware.c | 112 +++
|
|
lib/zip_progress.c | 172 ++++-
|
|
lib/zip_random_unix.c | 54 +-
|
|
...ource_file.c => zip_source_accept_empty.c} | 35 +-
|
|
lib/zip_source_buffer.c | 56 +-
|
|
lib/zip_source_compress.c | 37 +-
|
|
lib/zip_source_crc.c | 3 +-
|
|
lib/zip_source_file.h | 90 +++
|
|
lib/zip_source_file_common.c | 378 ++++++++++
|
|
lib/zip_source_file_stdio.c | 208 ++++++
|
|
lib/zip_source_file_stdio.h | 47 ++
|
|
lib/zip_source_file_stdio_named.c | 313 +++++++++
|
|
lib/zip_source_file_win32.c | 230 +++++++
|
|
lib/zip_source_file_win32.h | 74 ++
|
|
lib/zip_source_file_win32_ansi.c | 81 +++
|
|
lib/zip_source_file_win32_named.c | 266 +++++++
|
|
lib/zip_source_file_win32_utf16.c | 108 +++
|
|
lib/zip_source_file_win32_utf8.c | 73 ++
|
|
lib/zip_source_filep.c | 651 ------------------
|
|
lib/zip_source_get_file_attributes.c | 104 +++
|
|
lib/zip_source_pkware_decode.c | 221 ++++++
|
|
lib/zip_source_pkware_encode.c | 249 +++++++
|
|
lib/zip_source_seek.c | 7 +-
|
|
lib/zip_source_supports.c | 2 +-
|
|
lib/zip_source_window.c | 38 +-
|
|
lib/zip_source_winzip_aes_encode.c | 17 +-
|
|
lib/zip_source_zip_new.c | 38 +-
|
|
lib/zip_stat_index.c | 9 +-
|
|
lib/zip_string.c | 2 +-
|
|
lib/zip_utf-8.c | 2 +-
|
|
lib/zipint.h | 55 +-
|
|
44 files changed, 3651 insertions(+), 846 deletions(-)
|
|
create mode 100644 lib/zip_algorithm_xz.c
|
|
create mode 100644 lib/zip_mkstempm.c
|
|
create mode 100644 lib/zip_pkware.c
|
|
rename lib/{zip_source_file.c => zip_source_accept_empty.c} (65%)
|
|
create mode 100644 lib/zip_source_file.h
|
|
create mode 100644 lib/zip_source_file_common.c
|
|
create mode 100644 lib/zip_source_file_stdio.c
|
|
create mode 100644 lib/zip_source_file_stdio.h
|
|
create mode 100644 lib/zip_source_file_stdio_named.c
|
|
create mode 100644 lib/zip_source_file_win32.c
|
|
create mode 100644 lib/zip_source_file_win32.h
|
|
create mode 100644 lib/zip_source_file_win32_ansi.c
|
|
create mode 100644 lib/zip_source_file_win32_named.c
|
|
create mode 100644 lib/zip_source_file_win32_utf16.c
|
|
create mode 100644 lib/zip_source_file_win32_utf8.c
|
|
delete mode 100644 lib/zip_source_filep.c
|
|
create mode 100644 lib/zip_source_get_file_attributes.c
|
|
create mode 100644 lib/zip_source_pkware_decode.c
|
|
create mode 100644 lib/zip_source_pkware_encode.c
|
|
|
|
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
|
index 69e6548..ca6ffe1 100644
|
|
--- a/CMakeLists.txt
|
|
+++ b/CMakeLists.txt
|
|
@@ -337,6 +337,12 @@ ELSEIF(LONG_LONG_LIBZIP EQUAL 8)
|
|
SET(ZIP_UINT64_T "unsigned long long")
|
|
ENDIF()
|
|
|
|
+if(HAVE_NULLABLE)
|
|
+ set(ZIP_NULLABLE_DEFINES)
|
|
+else()
|
|
+ set(ZIP_NULLABLE_DEFINES "#define _Nullable
|
|
+#define _Nonnull")
|
|
+endif()
|
|
# write out config file
|
|
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake-config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
|
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake-zipconf.h.in ${CMAKE_CURRENT_BINARY_DIR}/zipconf.h)
|
|
diff --git a/cmake-zipconf.h.in b/cmake-zipconf.h.in
|
|
index 6ff4fe3..5777fa7 100644
|
|
--- a/cmake-zipconf.h.in
|
|
+++ b/cmake-zipconf.h.in
|
|
@@ -14,6 +14,7 @@
|
|
#cmakedefine LIBZIP_VERSION_MICRO @PACKAGE_VERSION_MICRO@
|
|
|
|
#cmakedefine ZIP_STATIC
|
|
+${ZIP_NULLABLE_DEFINES}
|
|
|
|
${LIBZIP_TYPES_INCLUDE}
|
|
|
|
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
|
|
index 92c4bec..f15a65c 100644
|
|
--- a/lib/CMakeLists.txt
|
|
+++ b/lib/CMakeLists.txt
|
|
@@ -110,6 +110,7 @@ SET(LIBZIP_SOURCES
|
|
zip_name_locate.c
|
|
zip_new.c
|
|
zip_open.c
|
|
+ zip_pkware.c
|
|
zip_progress.c
|
|
zip_rename.c
|
|
zip_replace.c
|
|
@@ -119,6 +120,7 @@ SET(LIBZIP_SOURCES
|
|
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
|
|
@@ -128,14 +130,18 @@ SET(LIBZIP_SOURCES
|
|
zip_source_compress.c
|
|
zip_source_crc.c
|
|
zip_source_error.c
|
|
- zip_source_filep.c
|
|
+ zip_source_file_common.c
|
|
+ zip_source_file_stdio.c
|
|
+# zip_source_filep.c
|
|
zip_source_free.c
|
|
zip_source_function.c
|
|
- zip_source_get_compression_flags.c
|
|
+ # zip_source_get_compression_flags.c
|
|
+ zip_source_get_file_attributes.c
|
|
zip_source_is_deleted.c
|
|
zip_source_layered.c
|
|
zip_source_open.c
|
|
- zip_source_pkware.c
|
|
+ zip_source_pkware_decode.c
|
|
+ zip_source_pkware_encode.c
|
|
zip_source_read.c
|
|
zip_source_remove.c
|
|
zip_source_rollback_write.c
|
|
@@ -175,7 +181,7 @@ IF(WIN32)
|
|
ENDIF()
|
|
ELSE(WIN32)
|
|
SET(LIBZIP_OPSYS_FILES
|
|
- zip_source_file.c
|
|
+ #zip_source_file.c
|
|
)
|
|
ENDIF(WIN32)
|
|
|
|
@@ -193,6 +199,11 @@ IF(HAVE_LIBBZ2)
|
|
SET(LIBZIP_OPTIONAL_FILES zip_algorithm_bzip2.c)
|
|
ENDIF()
|
|
|
|
+if(HAVE_LIBLZMA)
|
|
+ target_sources(zip PRIVATE zip_algorithm_xz.c)
|
|
+ target_link_libraries(zip PRIVATE LibLZMA::LibLZMA)
|
|
+endif()
|
|
+
|
|
IF(HAVE_COMMONCRYPTO)
|
|
SET(LIBZIP_OPTIONAL_FILES ${LIBZIP_OPTIONAL_FILES} zip_crypto_commoncrypto.c
|
|
)
|
|
@@ -210,6 +221,28 @@ IF(HAVE_CRYPTO)
|
|
ENDIF()
|
|
|
|
ADD_LIBRARY(zip ${LIBZIP_SOURCES} ${LIBZIP_EXTRA_FILES} ${LIBZIP_OPTIONAL_FILES} ${LIBZIP_OPSYS_FILES})
|
|
+
|
|
+if(WIN32)
|
|
+ target_sources(zip PRIVATE
|
|
+ zip_source_file_win32.c
|
|
+ zip_source_file_win32_named.c
|
|
+ zip_source_file_win32_utf16.c
|
|
+ zip_source_file_win32_utf8.c
|
|
+ )
|
|
+ if(CMAKE_SYSTEM_NAME MATCHES WindowsPhone OR CMAKE_SYSTEM_NAME MATCHES WindowsStore)
|
|
+ target_sources(zip PRIVATE zip_random_uwp.c)
|
|
+ else()
|
|
+ target_sources(zip PRIVATE zip_source_file_win32_ansi.c zip_random_win32.c)
|
|
+ target_link_libraries(zip PRIVATE advapi32)
|
|
+ endif()
|
|
+else(WIN32)
|
|
+ target_sources(zip PRIVATE
|
|
+ zip_mkstempm.c
|
|
+ zip_source_file_stdio_named.c
|
|
+ zip_random_unix.c
|
|
+ )
|
|
+endif(WIN32)
|
|
+
|
|
SET_TARGET_PROPERTIES(zip PROPERTIES VERSION 5.0 SOVERSION 5)
|
|
TARGET_LINK_LIBRARIES(zip ${ZLIB_LIBRARY} ${OPTIONAL_LIBRARY})
|
|
INSTALL(TARGETS zip
|
|
diff --git a/lib/zip.h b/lib/zip.h
|
|
index 2d83a99..5215b3e 100644
|
|
--- a/lib/zip.h
|
|
+++ b/lib/zip.h
|
|
@@ -134,6 +134,7 @@ extern "C" {
|
|
#define ZIP_ER_INUSE 29 /* N Resource still in use */
|
|
#define ZIP_ER_TELL 30 /* S Tell error */
|
|
#define ZIP_ER_COMPRESSED_DATA 31 /* N Compressed data invalid */
|
|
+#define ZIP_ER_CANCELLED 32 /* N Operation cancelled */
|
|
|
|
/* type of system error value */
|
|
|
|
@@ -228,8 +229,11 @@ enum zip_source_cmd {
|
|
ZIP_SOURCE_TELL_WRITE, /* get write position */
|
|
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_RESERVED_1, /* previously used internally */
|
|
+
|
|
+ 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 */
|
|
+ ZIP_SOURCE_GET_FILE_ATTRIBUTES /* get additional file attributes */
|
|
};
|
|
typedef enum zip_source_cmd zip_source_cmd_t;
|
|
|
|
@@ -275,7 +279,7 @@ typedef struct zip_source_args_seek zip_source_args_seek_t;
|
|
struct zip_error {
|
|
int zip_err; /* libzip error code (ZIP_ER_*) */
|
|
int sys_err; /* copy of errno (E*) or zlib error code */
|
|
- char *str; /* string representation or NULL */
|
|
+ char *_Nullable str; /* string representation or NULL */
|
|
};
|
|
|
|
#define ZIP_STAT_NAME 0x0001u
|
|
@@ -290,7 +294,7 @@ struct zip_error {
|
|
|
|
struct zip_stat {
|
|
zip_uint64_t valid; /* which fields have valid values */
|
|
- const char *name; /* name of the file */
|
|
+ const char *_Nullable name; /* name of the file */
|
|
zip_uint64_t index; /* index within archive */
|
|
zip_uint64_t size; /* size of file (uncompressed) */
|
|
zip_uint64_t comp_size; /* size of file (compressed) */
|
|
@@ -302,10 +306,26 @@ struct zip_stat {
|
|
};
|
|
|
|
struct zip_buffer_fragment {
|
|
- zip_uint8_t *data;
|
|
+ zip_uint8_t *_Nonnull data;
|
|
zip_uint64_t length;
|
|
};
|
|
|
|
+struct zip_file_attributes {
|
|
+ zip_uint64_t valid; /* which fields have valid values */
|
|
+ zip_uint8_t version; /* version of this struct, currently 1 */
|
|
+ zip_uint8_t host_system; /* host system on which file was created */
|
|
+ zip_uint8_t ascii; /* flag whether file is ASCII text */
|
|
+ zip_uint8_t version_needed; /* minimum version needed to extract file */
|
|
+ zip_uint32_t external_file_attributes; /* external file attributes (host-system specific) */
|
|
+ zip_uint16_t general_purpose_bit_flags; /* general purpose big flags, only some bits are honored */
|
|
+ zip_uint16_t general_purpose_bit_mask; /* which bits in general_purpose_bit_flags are valid */
|
|
+};
|
|
+
|
|
+#define ZIP_FILE_ATTRIBUTES_HOST_SYSTEM 0x0001u
|
|
+#define ZIP_FILE_ATTRIBUTES_ASCII 0x0002u
|
|
+#define ZIP_FILE_ATTRIBUTES_VERSION_NEEDED 0x0004u
|
|
+#define ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES 0x0008u
|
|
+#define ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS 0x0010u
|
|
struct zip;
|
|
struct zip_file;
|
|
struct zip_source;
|
|
@@ -313,6 +333,7 @@ struct zip_source;
|
|
typedef struct zip zip_t;
|
|
typedef struct zip_error zip_error_t;
|
|
typedef struct zip_file zip_file_t;
|
|
+typedef struct zip_file_attributes zip_file_attributes_t;
|
|
typedef struct zip_source zip_source_t;
|
|
typedef struct zip_stat zip_stat_t;
|
|
typedef struct zip_buffer_fragment zip_buffer_fragment_t;
|
|
@@ -321,6 +342,7 @@ typedef zip_uint32_t zip_flags_t;
|
|
|
|
typedef zip_int64_t (*zip_source_callback)(void *, void *, zip_uint64_t, zip_source_cmd_t);
|
|
typedef void (*zip_progress_callback)(zip_t *, double, void *);
|
|
+typedef int (*zip_cancel_callback)(zip_t *_Nonnull, void *_Nullable);
|
|
|
|
#ifndef ZIP_DISABLE_DEPRECATED
|
|
typedef void (*zip_progress_callback_t)(double);
|
|
@@ -359,6 +381,7 @@ ZIP_EXTERN zip_int64_t zip_error_to_data(const zip_error_t *, void *, zip_uint64
|
|
ZIP_EXTERN int zip_fclose(zip_file_t *);
|
|
ZIP_EXTERN zip_t *zip_fdopen(int, int, int *);
|
|
ZIP_EXTERN zip_int64_t zip_file_add(zip_t *, const char *, zip_source_t *, zip_flags_t);
|
|
+ZIP_EXTERN void zip_file_attributes_init(zip_file_attributes_t *_Nonnull);
|
|
ZIP_EXTERN void zip_file_error_clear(zip_file_t *);
|
|
ZIP_EXTERN int zip_file_extra_field_delete(zip_t *, zip_uint64_t, zip_uint16_t, zip_flags_t);
|
|
ZIP_EXTERN int zip_file_extra_field_delete_by_id(zip_t *, zip_uint64_t, zip_uint16_t, zip_uint16_t, zip_flags_t);
|
|
@@ -393,6 +416,7 @@ ZIP_EXTERN zip_int64_t zip_name_locate(zip_t *, const char *, zip_flags_t);
|
|
ZIP_EXTERN zip_t *zip_open(const char *, int, int *);
|
|
ZIP_EXTERN zip_t *zip_open_from_source(zip_source_t *, int, zip_error_t *);
|
|
ZIP_EXTERN int zip_register_progress_callback_with_state(zip_t *, double, zip_progress_callback, void (*)(void *), void *);
|
|
+ZIP_EXTERN int zip_register_cancel_callback_with_state(zip_t *_Nonnull, zip_cancel_callback _Nullable, void (*_Nullable)(void *_Nullable), void *_Nullable);
|
|
ZIP_EXTERN int zip_set_archive_comment(zip_t *, const char *, zip_uint16_t);
|
|
ZIP_EXTERN int zip_set_archive_flag(zip_t *, zip_flags_t, int);
|
|
ZIP_EXTERN int zip_set_default_password(zip_t *, const char *);
|
|
@@ -409,10 +433,11 @@ ZIP_EXTERN zip_error_t *zip_source_error(zip_source_t *);
|
|
ZIP_EXTERN zip_source_t *zip_source_file(zip_t *, const char *, zip_uint64_t, zip_int64_t);
|
|
ZIP_EXTERN zip_source_t *zip_source_file_create(const char *, zip_uint64_t, zip_int64_t, zip_error_t *);
|
|
ZIP_EXTERN zip_source_t *zip_source_filep(zip_t *, FILE *, zip_uint64_t, zip_int64_t);
|
|
-ZIP_EXTERN zip_source_t *zip_source_filep_create(FILE *, zip_uint64_t, zip_int64_t, zip_error_t *);
|
|
+ZIP_EXTERN zip_source_t *_Nullable zip_source_filep_create(FILE *_Nonnull, zip_uint64_t, zip_int64_t, zip_error_t *_Nullable);
|
|
ZIP_EXTERN void zip_source_free(zip_source_t *);
|
|
ZIP_EXTERN zip_source_t *zip_source_function(zip_t *, zip_source_callback, void *);
|
|
ZIP_EXTERN zip_source_t *zip_source_function_create(zip_source_callback, void *, zip_error_t *);
|
|
+ZIP_EXTERN int zip_source_get_file_attributes(zip_source_t *_Nonnull, zip_file_attributes_t *_Nonnull);
|
|
ZIP_EXTERN int zip_source_is_deleted(zip_source_t *);
|
|
ZIP_EXTERN void zip_source_keep(zip_source_t *);
|
|
ZIP_EXTERN zip_int64_t zip_source_make_command_bitmap(zip_source_cmd_t, ...);
|
|
diff --git a/lib/zip_algorithm_bzip2.c b/lib/zip_algorithm_bzip2.c
|
|
index f2fb162..ea7b9c6 100644
|
|
--- a/lib/zip_algorithm_bzip2.c
|
|
+++ b/lib/zip_algorithm_bzip2.c
|
|
@@ -90,8 +90,8 @@ deallocate(void *ud) {
|
|
}
|
|
|
|
|
|
-static int
|
|
-compression_flags(void *ud) {
|
|
+static zip_uint16_t
|
|
+general_purpose_bit_flags(void *ud) {
|
|
return 0;
|
|
}
|
|
|
|
@@ -247,7 +247,8 @@ process(void *ud, zip_uint8_t *data, zip_uint64_t *length) {
|
|
zip_compression_algorithm_t zip_algorithm_bzip2_compress = {
|
|
compress_allocate,
|
|
deallocate,
|
|
- compression_flags,
|
|
+ general_purpose_bit_flags,
|
|
+ 46,
|
|
start,
|
|
end,
|
|
input,
|
|
@@ -259,7 +260,8 @@ zip_compression_algorithm_t zip_algorithm_bzip2_compress = {
|
|
zip_compression_algorithm_t zip_algorithm_bzip2_decompress = {
|
|
decompress_allocate,
|
|
deallocate,
|
|
- compression_flags,
|
|
+ general_purpose_bit_flags,
|
|
+ 46,
|
|
start,
|
|
end,
|
|
input,
|
|
diff --git a/lib/zip_algorithm_deflate.c b/lib/zip_algorithm_deflate.c
|
|
index 2a1c904..618055c 100644
|
|
--- a/lib/zip_algorithm_deflate.c
|
|
+++ b/lib/zip_algorithm_deflate.c
|
|
@@ -51,6 +51,7 @@ allocate(bool compress, int compression_flags, zip_error_t *error) {
|
|
struct ctx *ctx;
|
|
|
|
if ((ctx = (struct ctx *)malloc(sizeof(*ctx))) == NULL) {
|
|
+ zip_error_set(error, ZIP_ET_SYS, errno);
|
|
return NULL;
|
|
}
|
|
|
|
@@ -90,8 +91,8 @@ deallocate(void *ud) {
|
|
}
|
|
|
|
|
|
-static int
|
|
-compression_flags(void *ud) {
|
|
+static zip_uint16_t
|
|
+general_purpose_bit_flags(void *ud) {
|
|
struct ctx *ctx = (struct ctx *)ud;
|
|
|
|
if (!ctx->compress) {
|
|
@@ -99,10 +100,10 @@ compression_flags(void *ud) {
|
|
}
|
|
|
|
if (ctx->compression_flags < 3) {
|
|
- return 2;
|
|
+ return 2 << 1;
|
|
}
|
|
else if (ctx->compression_flags > 7) {
|
|
- return 1;
|
|
+ return 1 << 1;
|
|
}
|
|
return 0;
|
|
}
|
|
@@ -224,7 +225,8 @@ process(void *ud, zip_uint8_t *data, zip_uint64_t *length) {
|
|
zip_compression_algorithm_t zip_algorithm_deflate_compress = {
|
|
compress_allocate,
|
|
deallocate,
|
|
- compression_flags,
|
|
+ general_purpose_bit_flags,
|
|
+ 20,
|
|
start,
|
|
end,
|
|
input,
|
|
@@ -236,7 +238,8 @@ zip_compression_algorithm_t zip_algorithm_deflate_compress = {
|
|
zip_compression_algorithm_t zip_algorithm_deflate_decompress = {
|
|
decompress_allocate,
|
|
deallocate,
|
|
- compression_flags,
|
|
+ general_purpose_bit_flags,
|
|
+ 20,
|
|
start,
|
|
end,
|
|
input,
|
|
diff --git a/lib/zip_algorithm_xz.c b/lib/zip_algorithm_xz.c
|
|
new file mode 100644
|
|
index 0000000..945ab4e
|
|
--- /dev/null
|
|
+++ b/lib/zip_algorithm_xz.c
|
|
@@ -0,0 +1,249 @@
|
|
+/*
|
|
+ zip_algorithm_xz.c -- XZ (de)compression routines
|
|
+ Bazed on zip_algorithm_deflate.c -- deflate (de)compression routines
|
|
+ Copyright (C) 2017-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"
|
|
+
|
|
+#include <limits.h>
|
|
+#include <lzma.h>
|
|
+#include <stdlib.h>
|
|
+#include <zlib.h>
|
|
+
|
|
+struct ctx {
|
|
+ zip_error_t *error;
|
|
+ bool compress;
|
|
+ zip_uint32_t compression_flags;
|
|
+ bool end_of_input;
|
|
+ lzma_stream zstr;
|
|
+ zip_uint16_t method;
|
|
+};
|
|
+
|
|
+
|
|
+static void *
|
|
+allocate(bool compress, int compression_flags, zip_error_t *error, zip_uint16_t method) {
|
|
+ struct ctx *ctx;
|
|
+
|
|
+ if (compression_flags < 0) {
|
|
+ zip_error_set(error, ZIP_ER_INVAL, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if ((ctx = (struct ctx *)malloc(sizeof(*ctx))) == NULL) {
|
|
+ zip_error_set(error, ZIP_ER_MEMORY, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ ctx->error = error;
|
|
+ ctx->compress = compress;
|
|
+ ctx->compression_flags = (zip_uint32_t)compression_flags;
|
|
+ ctx->compression_flags |= LZMA_PRESET_EXTREME;
|
|
+ ctx->end_of_input = false;
|
|
+ memset(&ctx->zstr, 0, sizeof(ctx->zstr));
|
|
+ ctx->method = method;
|
|
+ return ctx;
|
|
+}
|
|
+
|
|
+
|
|
+static void *
|
|
+compress_allocate(zip_uint16_t method, int compression_flags, zip_error_t *error) {
|
|
+ return allocate(true, compression_flags, error, method);
|
|
+}
|
|
+
|
|
+
|
|
+static void *
|
|
+decompress_allocate(zip_uint16_t method, int compression_flags, zip_error_t *error) {
|
|
+ return allocate(false, compression_flags, error, method);
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+deallocate(void *ud) {
|
|
+ struct ctx *ctx = (struct ctx *)ud;
|
|
+ free(ctx);
|
|
+}
|
|
+
|
|
+
|
|
+static zip_uint16_t
|
|
+general_purpose_bit_flags(void *ud) {
|
|
+ /* struct ctx *ctx = (struct ctx *)ud; */
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+map_error(lzma_ret ret) {
|
|
+ switch (ret) {
|
|
+ case LZMA_UNSUPPORTED_CHECK:
|
|
+ return ZIP_ER_COMPRESSED_DATA;
|
|
+
|
|
+ case LZMA_MEM_ERROR:
|
|
+ return ZIP_ER_MEMORY;
|
|
+
|
|
+ case LZMA_OPTIONS_ERROR:
|
|
+ return ZIP_ER_INVAL;
|
|
+
|
|
+ default:
|
|
+ return ZIP_ER_INTERNAL;
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+static bool
|
|
+start(void *ud) {
|
|
+ struct ctx *ctx = (struct ctx *)ud;
|
|
+ lzma_ret ret;
|
|
+
|
|
+ lzma_options_lzma opt_lzma;
|
|
+ lzma_lzma_preset(&opt_lzma, ctx->compression_flags);
|
|
+ lzma_filter filters[] = {
|
|
+ {.id = (ctx->method == ZIP_CM_LZMA ? LZMA_FILTER_LZMA1 : LZMA_FILTER_LZMA2), .options = &opt_lzma},
|
|
+ {.id = LZMA_VLI_UNKNOWN, .options = NULL},
|
|
+ };
|
|
+
|
|
+ ctx->zstr.avail_in = 0;
|
|
+ ctx->zstr.next_in = NULL;
|
|
+ ctx->zstr.avail_out = 0;
|
|
+ ctx->zstr.next_out = NULL;
|
|
+
|
|
+ if (ctx->compress) {
|
|
+ if (ctx->method == ZIP_CM_LZMA)
|
|
+ ret = lzma_alone_encoder(&ctx->zstr, filters[0].options);
|
|
+ else
|
|
+ ret = lzma_stream_encoder(&ctx->zstr, filters, LZMA_CHECK_CRC64);
|
|
+ }
|
|
+ else {
|
|
+ if (ctx->method == ZIP_CM_LZMA)
|
|
+ ret = lzma_alone_decoder(&ctx->zstr, UINT64_MAX);
|
|
+ else
|
|
+ ret = lzma_stream_decoder(&ctx->zstr, UINT64_MAX, LZMA_CONCATENATED);
|
|
+ }
|
|
+
|
|
+ if (ret != LZMA_OK) {
|
|
+ zip_error_set(ctx->error, map_error(ret), 0);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+
|
|
+static bool
|
|
+end(void *ud) {
|
|
+ struct ctx *ctx = (struct ctx *)ud;
|
|
+
|
|
+ lzma_end(&ctx->zstr);
|
|
+ return true;
|
|
+}
|
|
+
|
|
+
|
|
+static bool
|
|
+input(void *ud, zip_uint8_t *data, zip_uint64_t length) {
|
|
+ struct ctx *ctx = (struct ctx *)ud;
|
|
+
|
|
+ if (length > UINT_MAX || ctx->zstr.avail_in > 0) {
|
|
+ zip_error_set(ctx->error, ZIP_ER_INVAL, 0);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ ctx->zstr.avail_in = (uInt)length;
|
|
+ ctx->zstr.next_in = (Bytef *)data;
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+end_of_input(void *ud) {
|
|
+ struct ctx *ctx = (struct ctx *)ud;
|
|
+
|
|
+ ctx->end_of_input = true;
|
|
+}
|
|
+
|
|
+
|
|
+static zip_compression_status_t
|
|
+process(void *ud, zip_uint8_t *data, zip_uint64_t *length) {
|
|
+ struct ctx *ctx = (struct ctx *)ud;
|
|
+ lzma_ret ret;
|
|
+
|
|
+ ctx->zstr.avail_out = (uInt)ZIP_MIN(UINT_MAX, *length);
|
|
+ ctx->zstr.next_out = (Bytef *)data;
|
|
+
|
|
+ ret = lzma_code(&ctx->zstr, ctx->end_of_input ? LZMA_FINISH : LZMA_RUN);
|
|
+ *length = *length - ctx->zstr.avail_out;
|
|
+
|
|
+ switch (ret) {
|
|
+ case LZMA_OK:
|
|
+ return ZIP_COMPRESSION_OK;
|
|
+
|
|
+ case LZMA_STREAM_END:
|
|
+ return ZIP_COMPRESSION_END;
|
|
+
|
|
+ case LZMA_BUF_ERROR:
|
|
+ if (ctx->zstr.avail_in == 0) {
|
|
+ return ZIP_COMPRESSION_NEED_DATA;
|
|
+ }
|
|
+
|
|
+ /* fallthrough */
|
|
+ default:
|
|
+ zip_error_set(ctx->error, map_error(ret), 0);
|
|
+ return ZIP_COMPRESSION_ERROR;
|
|
+ }
|
|
+}
|
|
+
|
|
+/* clang-format off */
|
|
+
|
|
+zip_compression_algorithm_t zip_algorithm_xz_compress = {
|
|
+ compress_allocate,
|
|
+ deallocate,
|
|
+ general_purpose_bit_flags,
|
|
+ 63,
|
|
+ start,
|
|
+ end,
|
|
+ input,
|
|
+ end_of_input,
|
|
+ process
|
|
+};
|
|
+
|
|
+
|
|
+zip_compression_algorithm_t zip_algorithm_xz_decompress = {
|
|
+ decompress_allocate,
|
|
+ deallocate,
|
|
+ general_purpose_bit_flags,
|
|
+ 63,
|
|
+ start,
|
|
+ end,
|
|
+ input,
|
|
+ end_of_input,
|
|
+ process
|
|
+};
|
|
+
|
|
+/* clang-format on */
|
|
diff --git a/lib/zip_close.c b/lib/zip_close.c
|
|
index c46e1b3..d62b6db 100644
|
|
--- a/lib/zip_close.c
|
|
+++ b/lib/zip_close.c
|
|
@@ -51,10 +51,11 @@
|
|
#endif
|
|
|
|
|
|
-static int add_data(zip_t *, zip_source_t *, zip_dirent_t *);
|
|
+static int add_data(zip_t *, zip_source_t *, zip_dirent_t *, zip_uint32_t);
|
|
static int copy_data(zip_t *, zip_uint64_t);
|
|
static int copy_source(zip_t *, zip_source_t *, zip_int64_t);
|
|
static int write_cdir(zip_t *, const zip_filelist_t *, zip_uint64_t);
|
|
+static int write_data_descriptor(zip_t *za, const zip_dirent_t *dirent, int is_zip64);
|
|
|
|
ZIP_EXTERN int
|
|
zip_close(zip_t *za) {
|
|
@@ -73,8 +74,10 @@ zip_close(zip_t *za) {
|
|
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);
|
|
@@ -158,14 +161,23 @@ zip_close(zip_t *za) {
|
|
}
|
|
}
|
|
|
|
- _zip_progress_start(za->progress);
|
|
+ if (_zip_progress_start(za->progress) != 0) {
|
|
+ zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);
|
|
+ zip_source_rollback_write(za->src);
|
|
+ free(filelist);
|
|
+ return -1;
|
|
+ }
|
|
error = 0;
|
|
for (j = 0; j < survivors; j++) {
|
|
int new_data;
|
|
zip_entry_t *entry;
|
|
zip_dirent_t *de;
|
|
|
|
- _zip_progress_subrange(za->progress, (double)j / (double)survivors, (double)(j + 1) / (double)survivors);
|
|
+ if (_zip_progress_subrange(za->progress, (double)j / (double)survivors, (double)(j + 1) / (double)survivors) != 0) {
|
|
+ zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);
|
|
+ error = 1;
|
|
+ break;
|
|
+ }
|
|
|
|
i = filelist[j].idx;
|
|
entry = za->entry + i;
|
|
@@ -193,6 +205,7 @@ zip_close(zip_t *za) {
|
|
}
|
|
|
|
if ((off = zip_source_tell_write(za->src)) < 0) {
|
|
+ _zip_error_set_from_source(&za->error, za->src);
|
|
error = 1;
|
|
break;
|
|
}
|
|
@@ -210,7 +223,7 @@ zip_close(zip_t *za) {
|
|
}
|
|
|
|
/* add_data writes dirent */
|
|
- if (add_data(za, zs ? zs : entry->source, de) < 0) {
|
|
+ if (add_data(za, zs ? zs : entry->source, de, entry->changes ? entry->changes->changed : 0) < 0) {
|
|
error = 1;
|
|
if (zs)
|
|
zip_source_free(zs);
|
|
@@ -222,8 +235,11 @@ zip_close(zip_t *za) {
|
|
else {
|
|
zip_uint64_t offset;
|
|
|
|
- /* when copying data, all sizes are known -> no data descriptor needed */
|
|
- de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR;
|
|
+ if (de->encryption_method != ZIP_EM_TRAD_PKWARE) {
|
|
+ /* when copying data, all sizes are known -> no data descriptor needed */
|
|
+ /* except for PKWare encryption, where removing the data descriptor breaks password validation */
|
|
+ de->bitflags &= (zip_uint16_t)~ZIP_GPBF_DATA_DESCRIPTOR;
|
|
+ }
|
|
if (_zip_dirent_write(za, de, ZIP_FL_LOCAL) < 0) {
|
|
error = 1;
|
|
break;
|
|
@@ -234,13 +250,20 @@ zip_close(zip_t *za) {
|
|
}
|
|
if (zip_source_seek(za->src, (zip_int64_t)offset, SEEK_SET) < 0) {
|
|
_zip_error_set_from_source(&za->error, za->src);
|
|
- error = 1;
|
|
+ error = 1;
|
|
break;
|
|
}
|
|
if (copy_data(za, de->comp_size) < 0) {
|
|
- error = 1;
|
|
+ error = 1;
|
|
break;
|
|
}
|
|
+
|
|
+ if (de->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) {
|
|
+ if (write_data_descriptor(za, de, _zip_dirent_needs_zip64(de, 0)) < 0) {
|
|
+ error = 1;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -256,10 +279,9 @@ zip_close(zip_t *za) {
|
|
_zip_error_set_from_source(&za->error, za->src);
|
|
error = 1;
|
|
}
|
|
+ _zip_progress_end(za->progress);
|
|
}
|
|
|
|
- _zip_progress_end(za->progress);
|
|
-
|
|
if (error) {
|
|
zip_source_rollback_write(za->src);
|
|
return -1;
|
|
@@ -272,14 +294,14 @@ zip_close(zip_t *za) {
|
|
|
|
|
|
static int
|
|
-add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de) {
|
|
+add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de, zip_uint32_t changed) {
|
|
zip_int64_t offstart, offdata, offend, data_length;
|
|
- struct zip_stat st;
|
|
+ zip_stat_t st;
|
|
+ zip_file_attributes_t attributes;
|
|
zip_source_t *src_final, *src_tmp;
|
|
int ret;
|
|
int is_zip64;
|
|
zip_flags_t flags;
|
|
- zip_int8_t compression_flags;
|
|
bool needs_recompress, needs_decompress, needs_crc, needs_compress, needs_reencrypt, needs_decrypt, needs_encrypt;
|
|
|
|
if (zip_source_stat(src, &st) < 0) {
|
|
@@ -443,6 +465,9 @@ add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de) {
|
|
zip_source_free(src_final);
|
|
return -1;
|
|
}
|
|
+ if (de->encryption_method == ZIP_EM_TRAD_PKWARE) {
|
|
+ de->bitflags |= ZIP_GPBF_DATA_DESCRIPTOR;
|
|
+ }
|
|
|
|
zip_source_free(src_final);
|
|
src_final = src_tmp;
|
|
@@ -461,7 +486,7 @@ add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de) {
|
|
ret = -1;
|
|
}
|
|
|
|
- if ((compression_flags = zip_source_get_compression_flags(src_final)) < 0) {
|
|
+ if (zip_source_get_file_attributes(src_final, &attributes) != 0) {
|
|
_zip_error_set_from_source(&za->error, src_final);
|
|
ret = -1;
|
|
}
|
|
@@ -497,8 +522,7 @@ add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de) {
|
|
de->crc = st.crc;
|
|
de->uncomp_size = st.size;
|
|
de->comp_size = (zip_uint64_t)(offend - offdata);
|
|
- de->bitflags = (zip_uint16_t)((de->bitflags & (zip_uint16_t)~6) | ((zip_uint8_t)compression_flags << 1));
|
|
- _zip_dirent_set_version_needed(de, (flags & ZIP_FL_FORCE_ZIP64) != 0);
|
|
+ _zip_dirent_apply_attributes(de, &attributes, (flags & ZIP_FL_FORCE_ZIP64) != 0, changed);
|
|
|
|
if ((ret = _zip_dirent_write(za, de, flags)) < 0)
|
|
return -1;
|
|
@@ -514,38 +538,54 @@ add_data(zip_t *za, zip_source_t *src, zip_dirent_t *de) {
|
|
return -1;
|
|
}
|
|
|
|
+ if (de->bitflags & ZIP_GPBF_DATA_DESCRIPTOR) {
|
|
+ if (write_data_descriptor(za, de, is_zip64) < 0) {
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int
|
|
copy_data(zip_t *za, zip_uint64_t len) {
|
|
- zip_uint8_t buf[BUFSIZE];
|
|
+ DEFINE_BYTE_ARRAY(buf, BUFSIZE);
|
|
size_t n;
|
|
double total = (double)len;
|
|
|
|
+ if (!byte_array_init(buf, BUFSIZE)) {
|
|
+ zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
while (len > 0) {
|
|
- n = len > sizeof(buf) ? sizeof(buf) : len;
|
|
+ n = len > BUFSIZE ? BUFSIZE : len;
|
|
if (_zip_read(za->src, buf, n, &za->error) < 0) {
|
|
+ byte_array_fini(buf);
|
|
return -1;
|
|
}
|
|
|
|
if (_zip_write(za, buf, n) < 0) {
|
|
+ byte_array_fini(buf);
|
|
return -1;
|
|
}
|
|
|
|
len -= n;
|
|
|
|
- _zip_progress_update(za->progress, (total - (double)len) / total);
|
|
+ if (_zip_progress_update(za->progress, (total - (double)len) / total) != 0) {
|
|
+ zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);
|
|
+ return -1;
|
|
+ }
|
|
}
|
|
|
|
+ byte_array_fini(buf);
|
|
return 0;
|
|
}
|
|
|
|
-
|
|
static int
|
|
copy_source(zip_t *za, zip_source_t *src, zip_int64_t data_length) {
|
|
- zip_uint8_t buf[BUFSIZE];
|
|
+ DEFINE_BYTE_ARRAY(buf, BUFSIZE);
|
|
zip_int64_t n, current;
|
|
int ret;
|
|
|
|
@@ -554,16 +594,25 @@ copy_source(zip_t *za, zip_source_t *src, zip_int64_t data_length) {
|
|
return -1;
|
|
}
|
|
|
|
+ if (!byte_array_init(buf, BUFSIZE)) {
|
|
+ zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
ret = 0;
|
|
current = 0;
|
|
- while ((n = zip_source_read(src, buf, sizeof(buf))) > 0) {
|
|
+ while ((n = zip_source_read(src, buf, BUFSIZE)) > 0) {
|
|
if (_zip_write(za, buf, (zip_uint64_t)n) < 0) {
|
|
ret = -1;
|
|
break;
|
|
}
|
|
- if (n == sizeof(buf) && za->progress && data_length > 0) {
|
|
+ if (n == BUFSIZE && za->progress && data_length > 0) {
|
|
current += n;
|
|
- _zip_progress_update(za->progress, (double)current / (double)data_length);
|
|
+ if (_zip_progress_update(za->progress, (double)current / (double)data_length) != 0) {
|
|
+ zip_error_set(&za->error, ZIP_ER_CANCELLED, 0);
|
|
+ ret = -1;
|
|
+ break;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -572,6 +621,8 @@ copy_source(zip_t *za, zip_source_t *src, zip_int64_t data_length) {
|
|
ret = -1;
|
|
}
|
|
|
|
+ byte_array_fini(buf);
|
|
+
|
|
zip_source_close(src);
|
|
|
|
return ret;
|
|
@@ -624,3 +675,36 @@ _zip_changed(const zip_t *za, zip_uint64_t *survivorsp) {
|
|
|
|
return changed;
|
|
}
|
|
+static int
|
|
+write_data_descriptor(zip_t *za, const zip_dirent_t *de, int is_zip64) {
|
|
+ zip_buffer_t *buffer = _zip_buffer_new(NULL, MAX_DATA_DESCRIPTOR_LENGTH);
|
|
+ int ret = 0;
|
|
+
|
|
+ if (buffer == NULL) {
|
|
+ zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ _zip_buffer_put(buffer, DATADES_MAGIC, 4);
|
|
+ _zip_buffer_put_32(buffer, de->crc);
|
|
+ if (is_zip64) {
|
|
+ _zip_buffer_put_64(buffer, de->comp_size);
|
|
+ _zip_buffer_put_64(buffer, de->uncomp_size);
|
|
+ }
|
|
+ else {
|
|
+ _zip_buffer_put_32(buffer, (zip_uint32_t)de->comp_size);
|
|
+ _zip_buffer_put_32(buffer, (zip_uint32_t)de->uncomp_size);
|
|
+ }
|
|
+
|
|
+ if (!_zip_buffer_ok(buffer)) {
|
|
+ zip_error_set(&za->error, ZIP_ER_INTERNAL, 0);
|
|
+ ret = -1;
|
|
+ }
|
|
+ else {
|
|
+ ret = _zip_write(za, _zip_buffer_data(buffer), _zip_buffer_offset(buffer));
|
|
+ }
|
|
+
|
|
+ _zip_buffer_free(buffer);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
diff --git a/lib/zip_delete.c b/lib/zip_delete.c
|
|
index ae8f5a6..a407378 100644
|
|
--- a/lib/zip_delete.c
|
|
+++ b/lib/zip_delete.c
|
|
@@ -53,7 +53,7 @@ zip_delete(zip_t *za, zip_uint64_t idx) {
|
|
return -1;
|
|
}
|
|
|
|
- if (!_zip_hash_delete(za->names, (const zip_uint8_t *)name, &za->error)) {
|
|
+ if (!_zip_hash_delete(za->names, (const zip_uint8_t *)name, &za->error)) {
|
|
return -1;
|
|
}
|
|
|
|
diff --git a/lib/zip_dirent.c b/lib/zip_dirent.c
|
|
index a6dbfac..5164d21 100644
|
|
--- a/lib/zip_dirent.c
|
|
+++ b/lib/zip_dirent.c
|
|
@@ -523,29 +523,54 @@ _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, boo
|
|
return -1;
|
|
}
|
|
|
|
- if (zde->uncomp_size == ZIP_UINT32_MAX)
|
|
+ if (zde->uncomp_size == ZIP_UINT32_MAX) {
|
|
zde->uncomp_size = _zip_buffer_get_64(ef_buffer);
|
|
+ }
|
|
else if (local) {
|
|
/* From appnote.txt: This entry in the Local header MUST
|
|
include BOTH original and compressed file size fields. */
|
|
(void)_zip_buffer_skip(ef_buffer, 8); /* error is caught by _zip_buffer_eof() call */
|
|
}
|
|
- if (zde->comp_size == ZIP_UINT32_MAX)
|
|
+ if (zde->comp_size == ZIP_UINT32_MAX) {
|
|
zde->comp_size = _zip_buffer_get_64(ef_buffer);
|
|
+ }
|
|
if (!local) {
|
|
- if (zde->offset == ZIP_UINT32_MAX)
|
|
+ if (zde->offset == ZIP_UINT32_MAX) {
|
|
zde->offset = _zip_buffer_get_64(ef_buffer);
|
|
- if (zde->disk_number == ZIP_UINT16_MAX)
|
|
+ }
|
|
+ if (zde->disk_number == ZIP_UINT16_MAX) {
|
|
zde->disk_number = _zip_buffer_get_32(ef_buffer);
|
|
+ }
|
|
}
|
|
|
|
if (!_zip_buffer_eof(ef_buffer)) {
|
|
- zip_error_set(error, ZIP_ER_INCONS, 0);
|
|
- _zip_buffer_free(ef_buffer);
|
|
- if (!from_buffer) {
|
|
- _zip_buffer_free(buffer);
|
|
+ /* accept additional fields if values match */
|
|
+ bool ok = true;
|
|
+ switch (got_len) {
|
|
+ case 28:
|
|
+ _zip_buffer_set_offset(ef_buffer, 24);
|
|
+ if (zde->disk_number != _zip_buffer_get_32(ef_buffer)) {
|
|
+ ok = false;
|
|
+ }
|
|
+ /* fallthrough */
|
|
+ case 24:
|
|
+ _zip_buffer_set_offset(ef_buffer, 0);
|
|
+ if ((zde->uncomp_size != _zip_buffer_get_64(ef_buffer)) || (zde->comp_size != _zip_buffer_get_64(ef_buffer)) || (zde->offset != _zip_buffer_get_64(ef_buffer))) {
|
|
+ ok = false;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ ok = false;
|
|
+ }
|
|
+ if (!ok) {
|
|
+ zip_error_set(error, ZIP_ER_INCONS, 0);
|
|
+ _zip_buffer_free(ef_buffer);
|
|
+ if (!from_buffer) {
|
|
+ _zip_buffer_free(buffer);
|
|
+ }
|
|
+ return -1;
|
|
}
|
|
- return -1;
|
|
}
|
|
_zip_buffer_free(ef_buffer);
|
|
}
|
|
@@ -573,7 +598,7 @@ _zip_dirent_read(zip_dirent_t *zde, zip_source_t *src, zip_buffer_t *buffer, boo
|
|
|
|
zde->extra_fields = _zip_ef_remove_internal(zde->extra_fields);
|
|
|
|
- return (zip_int64_t)(size + variable_size);
|
|
+ return (zip_int64_t)size + (zip_int64_t)variable_size;
|
|
}
|
|
|
|
|
|
@@ -868,9 +893,9 @@ _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) {
|
|
_zip_buffer_put(buffer, (flags & ZIP_FL_LOCAL) ? LOCAL_MAGIC : CENTRAL_MAGIC, 4);
|
|
|
|
if ((flags & ZIP_FL_LOCAL) == 0) {
|
|
- _zip_buffer_put_16(buffer, (zip_uint16_t)(is_really_zip64 ? 45 : de->version_madeby));
|
|
+ _zip_buffer_put_16(buffer, de->version_madeby);
|
|
}
|
|
- _zip_buffer_put_16(buffer, (zip_uint16_t)(is_really_zip64 ? 45 : de->version_needed));
|
|
+ _zip_buffer_put_16(buffer, ZIP_MAX(is_really_zip64 ? 45 : 0, de->version_needed));
|
|
_zip_buffer_put_16(buffer, de->bitflags);
|
|
if (is_winzip_aes) {
|
|
_zip_buffer_put_16(buffer, ZIP_CM_WINZIP_AES);
|
|
@@ -978,7 +1003,7 @@ _zip_dirent_write(zip_t *za, zip_dirent_t *de, zip_flags_t flags) {
|
|
}
|
|
|
|
|
|
-static time_t
|
|
+time_t
|
|
_zip_d2u_time(zip_uint16_t dtime, zip_uint16_t ddate) {
|
|
struct tm tm;
|
|
|
|
@@ -1066,20 +1091,32 @@ _zip_get_dirent(zip_t *za, zip_uint64_t idx, zip_flags_t flags, zip_error_t *err
|
|
|
|
void
|
|
_zip_u2d_time(time_t intime, zip_uint16_t *dtime, zip_uint16_t *ddate) {
|
|
- struct tm *tm;
|
|
+ struct tm *tpm;
|
|
|
|
- tm = localtime(&intime);
|
|
- if (tm->tm_year < 80) {
|
|
- tm->tm_year = 80;
|
|
+#ifdef HAVE_LOCALTIME_R
|
|
+ struct tm tm;
|
|
+ tpm = localtime_r(&intime, &tm);
|
|
+#else
|
|
+ tpm = localtime(&intime);
|
|
+#endif
|
|
+ if (tpm == NULL) {
|
|
+ /* if localtime() fails, return an arbitrary date (1980-01-01 00:00:00) */
|
|
+ *ddate = (1 << 5) + 1;
|
|
+ *dtime = 0;
|
|
+ return;
|
|
+ }
|
|
+ if (tpm->tm_year < 80) {
|
|
+ tpm->tm_year = 80;
|
|
}
|
|
|
|
- *ddate = (zip_uint16_t)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday);
|
|
- *dtime = (zip_uint16_t)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1));
|
|
+ *ddate = (zip_uint16_t)(((tpm->tm_year + 1900 - 1980) << 9) + ((tpm->tm_mon + 1) << 5) + tpm->tm_mday);
|
|
+ *dtime = (zip_uint16_t)(((tpm->tm_hour) << 11) + ((tpm->tm_min) << 5) + ((tpm->tm_sec) >> 1));
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
+
|
|
void
|
|
_zip_dirent_set_version_needed(zip_dirent_t *de, bool force_zip64) {
|
|
zip_uint16_t length;
|
|
@@ -1114,3 +1151,50 @@ _zip_dirent_set_version_needed(zip_dirent_t *de, bool force_zip64) {
|
|
|
|
de->version_needed = 10;
|
|
}
|
|
+void
|
|
+_zip_dirent_apply_attributes(zip_dirent_t *de, zip_file_attributes_t *attributes, bool force_zip64, zip_uint32_t changed) {
|
|
+ zip_uint16_t length;
|
|
+
|
|
+ if (attributes->valid & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS) {
|
|
+ zip_uint16_t mask = attributes->general_purpose_bit_mask & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK;
|
|
+ de->bitflags = (de->bitflags & ~mask) | (attributes->general_purpose_bit_flags & mask);
|
|
+ }
|
|
+ if (attributes->valid & ZIP_FILE_ATTRIBUTES_ASCII) {
|
|
+ de->int_attrib = (de->int_attrib & ~0x1) | (attributes->ascii ? 1 : 0);
|
|
+ }
|
|
+ /* manually set attributes are preferred over attributes provided by source */
|
|
+ if ((changed & ZIP_DIRENT_ATTRIBUTES) == 0 && (attributes->valid & ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES)) {
|
|
+ de->ext_attrib = attributes->external_file_attributes;
|
|
+ }
|
|
+
|
|
+ if (de->comp_method == ZIP_CM_LZMA) {
|
|
+ de->version_needed = 63;
|
|
+ }
|
|
+ else if (de->encryption_method == ZIP_EM_AES_128 || de->encryption_method == ZIP_EM_AES_192 || de->encryption_method == ZIP_EM_AES_256) {
|
|
+ de->version_needed = 51;
|
|
+ }
|
|
+ else if (de->comp_method == ZIP_CM_BZIP2) {
|
|
+ de->version_needed = 46;
|
|
+ }
|
|
+ else if (force_zip64 || _zip_dirent_needs_zip64(de, 0)) {
|
|
+ de->version_needed = 45;
|
|
+ }
|
|
+ else if (de->comp_method == ZIP_CM_DEFLATE || de->encryption_method == ZIP_EM_TRAD_PKWARE) {
|
|
+ de->version_needed = 20;
|
|
+ }
|
|
+ else if ((length = _zip_string_length(de->filename)) > 0 && de->filename->raw[length - 1] == '/') {
|
|
+ de->version_needed = 20;
|
|
+ }
|
|
+ else {
|
|
+ de->version_needed = 10;
|
|
+ }
|
|
+
|
|
+ if (attributes->valid & ZIP_FILE_ATTRIBUTES_VERSION_NEEDED) {
|
|
+ de->version_needed = ZIP_MAX(de->version_needed, attributes->version_needed);
|
|
+ }
|
|
+
|
|
+ de->version_madeby = 63 | (de->version_madeby & 0xff00);
|
|
+ if ((changed & ZIP_DIRENT_ATTRIBUTES) == 0 && (attributes->valid & ZIP_FILE_ATTRIBUTES_HOST_SYSTEM)) {
|
|
+ de->version_madeby = (de->version_madeby & 0xff) | (zip_uint16_t)(attributes->host_system << 8);
|
|
+ }
|
|
+}
|
|
\ No newline at end of file
|
|
diff --git a/lib/zip_get_encryption_implementation.c b/lib/zip_get_encryption_implementation.c
|
|
index ba459d4..e7f91c6 100644
|
|
--- a/lib/zip_get_encryption_implementation.c
|
|
+++ b/lib/zip_get_encryption_implementation.c
|
|
@@ -39,10 +39,7 @@ zip_encryption_implementation
|
|
_zip_get_encryption_implementation(zip_uint16_t em, int operation) {
|
|
switch (em) {
|
|
case ZIP_EM_TRAD_PKWARE:
|
|
- if (operation == ZIP_CODEC_ENCODE) {
|
|
- return NULL;
|
|
- }
|
|
- return zip_source_pkware;
|
|
+ return operation == ZIP_CODEC_DECODE ? zip_source_pkware_decode : zip_source_pkware_encode;
|
|
|
|
#if defined(HAVE_CRYPTO)
|
|
case ZIP_EM_AES_128:
|
|
@@ -55,3 +52,11 @@ _zip_get_encryption_implementation(zip_uint16_t em, int operation) {
|
|
return NULL;
|
|
}
|
|
}
|
|
+
|
|
+ZIP_EXTERN int
|
|
+zip_encryption_method_supported(zip_uint16_t method, int encode) {
|
|
+ if (method == ZIP_EM_NONE) {
|
|
+ return 1;
|
|
+ }
|
|
+ return _zip_get_encryption_implementation(method, encode ? ZIP_CODEC_ENCODE : ZIP_CODEC_DECODE) != NULL;
|
|
+}
|
|
diff --git a/lib/zip_mkstempm.c b/lib/zip_mkstempm.c
|
|
new file mode 100644
|
|
index 0000000..c1afade
|
|
--- /dev/null
|
|
+++ b/lib/zip_mkstempm.c
|
|
@@ -0,0 +1,93 @@
|
|
+/*
|
|
+ zip_mkstempm.c -- mkstemp replacement that accepts a mode argument
|
|
+ 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 <errno.h>
|
|
+#include <fcntl.h>
|
|
+#include <string.h>
|
|
+#include <sys/stat.h>
|
|
+
|
|
+#include "zipint.h"
|
|
+
|
|
+/*
|
|
+ * create temporary file with same permissions as previous one;
|
|
+ * or default permissions if there is no previous file
|
|
+ */
|
|
+int
|
|
+_zip_mkstempm(char *path, int mode) {
|
|
+ int fd;
|
|
+ char *start, *end, *xs;
|
|
+
|
|
+ int xcnt = 0;
|
|
+
|
|
+ end = path + strlen(path);
|
|
+ start = end - 1;
|
|
+ while (start >= path && *start == 'X') {
|
|
+ xcnt++;
|
|
+ start--;
|
|
+ }
|
|
+
|
|
+ if (xcnt == 0) {
|
|
+ errno = EINVAL;
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ start++;
|
|
+
|
|
+ for (;;) {
|
|
+ zip_uint32_t value = zip_random_uint32();
|
|
+
|
|
+ xs = start;
|
|
+
|
|
+ while (xs < end) {
|
|
+ char digit = value % 36;
|
|
+ if (digit < 10) {
|
|
+ *(xs++) = digit + '0';
|
|
+ }
|
|
+ else {
|
|
+ *(xs++) = digit - 10 + 'a';
|
|
+ }
|
|
+ value /= 36;
|
|
+ }
|
|
+
|
|
+ if ((fd = open(path, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, mode == -1 ? 0666 : (mode_t)mode)) >= 0) {
|
|
+ if (mode != -1) {
|
|
+ /* open() honors umask(), which we don't want in this case */
|
|
+ (void)chmod(path, (mode_t)mode);
|
|
+ }
|
|
+ return fd;
|
|
+ }
|
|
+ if (errno != EEXIST) {
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/lib/zip_open.c b/lib/zip_open.c
|
|
index 1886c9d..a2ca54a 100644
|
|
--- a/lib/zip_open.c
|
|
+++ b/lib/zip_open.c
|
|
@@ -40,12 +40,7 @@
|
|
|
|
#include "zipint.h"
|
|
|
|
-typedef enum {
|
|
- EXISTS_ERROR = -1,
|
|
- EXISTS_NOT = 0,
|
|
- EXISTS_EMPTY,
|
|
- EXISTS_NONEMPTY,
|
|
-} exists_t;
|
|
+typedef enum { EXISTS_ERROR = -1, EXISTS_NOT = 0, 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);
|
|
static zip_cdir_t *_zip_find_central_dir(zip_t *za, zip_uint64_t len);
|
|
@@ -56,6 +51,16 @@ static zip_cdir_t *_zip_read_cdir(zip_t *za, zip_buffer_t *buffer, zip_uint64_t
|
|
static zip_cdir_t *_zip_read_eocd(zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error);
|
|
static zip_cdir_t *_zip_read_eocd64(zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offset, unsigned int flags, zip_error_t *error);
|
|
|
|
+ZIP_EXTERN int
|
|
+zip_archive_set_tempdir(zip_t *za, const char *tempdir)
|
|
+{
|
|
+ (void)(za);
|
|
+ (void)(tempdir);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
|
|
ZIP_EXTERN zip_t *
|
|
zip_open(const char *fn, int _flags, int *zep) {
|
|
@@ -174,20 +179,16 @@ _zip_open(zip_source_t *src, unsigned int flags, zip_error_t *error) {
|
|
}
|
|
len = st.size;
|
|
|
|
- /* treat empty files as empty archives */
|
|
- if (len == 0) {
|
|
- if ((za = _zip_allocate_new(src, flags, error)) == NULL) {
|
|
- zip_source_free(src);
|
|
- 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 */
|
|
@@ -541,7 +542,7 @@ _zip_file_exists(zip_source_t *src, zip_error_t *error) {
|
|
return EXISTS_ERROR;
|
|
}
|
|
|
|
- return (st.valid & ZIP_STAT_SIZE) && st.size == 0 ? EXISTS_EMPTY : EXISTS_NONEMPTY;
|
|
+ return EXISTS_OK;
|
|
}
|
|
|
|
|
|
@@ -726,7 +727,8 @@ _zip_read_eocd64(zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offse
|
|
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;
|
|
}
|
|
@@ -838,6 +840,10 @@ _zip_read_eocd64(zip_source_t *src, zip_buffer_t *buffer, zip_uint64_t buf_offse
|
|
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_pkware.c b/lib/zip_pkware.c
|
|
new file mode 100644
|
|
index 0000000..eb12b1e
|
|
--- /dev/null
|
|
+++ b/lib/zip_pkware.c
|
|
@@ -0,0 +1,112 @@
|
|
+/*
|
|
+ zip_pkware.c -- Traditional PKWARE de/encryption backend routines
|
|
+ Copyright (C) 2009-2020 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 <stdlib.h>
|
|
+#include <zlib.h>
|
|
+
|
|
+#include "zipint.h"
|
|
+
|
|
+#define PKWARE_KEY0 305419896
|
|
+#define PKWARE_KEY1 591751049
|
|
+#define PKWARE_KEY2 878082192
|
|
+
|
|
+
|
|
+static void
|
|
+update_keys(zip_pkware_keys_t *keys, zip_uint8_t b) {
|
|
+ keys->key[0] = (zip_uint32_t)crc32(keys->key[0] ^ 0xffffffffUL, &b, 1) ^ 0xffffffffUL;
|
|
+ keys->key[1] = (keys->key[1] + (keys->key[0] & 0xff)) * 134775813 + 1;
|
|
+ b = (zip_uint8_t)(keys->key[1] >> 24);
|
|
+ keys->key[2] = (zip_uint32_t)crc32(keys->key[2] ^ 0xffffffffUL, &b, 1) ^ 0xffffffffUL;
|
|
+}
|
|
+
|
|
+
|
|
+static zip_uint8_t
|
|
+crypt_byte(zip_pkware_keys_t *keys) {
|
|
+ zip_uint16_t tmp;
|
|
+ tmp = (zip_uint16_t)(keys->key[2] | 2);
|
|
+ tmp = (zip_uint16_t)(((zip_uint32_t)tmp * (tmp ^ 1)) >> 8);
|
|
+ return (zip_uint8_t)tmp;
|
|
+}
|
|
+
|
|
+
|
|
+void
|
|
+_zip_pkware_keys_reset(zip_pkware_keys_t *keys) {
|
|
+ keys->key[0] = PKWARE_KEY0;
|
|
+ keys->key[1] = PKWARE_KEY1;
|
|
+ keys->key[2] = PKWARE_KEY2;
|
|
+}
|
|
+
|
|
+
|
|
+void
|
|
+_zip_pkware_encrypt(zip_pkware_keys_t *keys, zip_uint8_t *out, const zip_uint8_t *in, zip_uint64_t len) {
|
|
+ zip_uint64_t i;
|
|
+ zip_uint8_t b;
|
|
+ zip_uint8_t tmp;
|
|
+
|
|
+ for (i = 0; i < len; i++) {
|
|
+ b = in[i];
|
|
+
|
|
+ if (out != NULL) {
|
|
+ tmp = crypt_byte(keys);
|
|
+ update_keys(keys, b);
|
|
+ b ^= tmp;
|
|
+ out[i] = b;
|
|
+ }
|
|
+ else {
|
|
+ /* during initialization, we're only interested in key updates */
|
|
+ update_keys(keys, b);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+void
|
|
+_zip_pkware_decrypt(zip_pkware_keys_t *keys, zip_uint8_t *out, const zip_uint8_t *in, zip_uint64_t len) {
|
|
+ zip_uint64_t i;
|
|
+ zip_uint8_t b;
|
|
+ zip_uint8_t tmp;
|
|
+
|
|
+ for (i = 0; i < len; i++) {
|
|
+ b = in[i];
|
|
+
|
|
+ /* during initialization, we're only interested in key updates */
|
|
+ if (out != NULL) {
|
|
+ tmp = crypt_byte(keys);
|
|
+ b ^= tmp;
|
|
+ out[i] = b;
|
|
+ }
|
|
+
|
|
+ update_keys(keys, b);
|
|
+ }
|
|
+}
|
|
diff --git a/lib/zip_progress.c b/lib/zip_progress.c
|
|
index 46c8bb8..ddb47c7 100644
|
|
--- a/lib/zip_progress.c
|
|
+++ b/lib/zip_progress.c
|
|
@@ -1,6 +1,6 @@
|
|
/*
|
|
zip_progress.c -- progress reporting
|
|
- Copyright (C) 2017 Dieter Baron and Thomas Klausner
|
|
+ Copyright (C) 2017-2020 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>
|
|
@@ -40,10 +40,14 @@
|
|
|
|
struct zip_progress {
|
|
zip_t *za;
|
|
- zip_progress_callback callback;
|
|
- void (*ud_free)(void *);
|
|
|
|
- void *ud;
|
|
+ zip_progress_callback callback_progress;
|
|
+ void (*ud_progress_free)(void *);
|
|
+ void *ud_progress;
|
|
+
|
|
+ zip_cancel_callback callback_cancel;
|
|
+ void (*ud_cancel_free)(void *);
|
|
+ void *ud_cancel;
|
|
|
|
double precision;
|
|
|
|
@@ -54,6 +58,11 @@ struct zip_progress {
|
|
double end; /* end of sub-progress section */
|
|
};
|
|
|
|
+static void _zip_progress_free_cancel_callback(zip_progress_t *progress);
|
|
+static void _zip_progress_free_progress_callback(zip_progress_t *progress);
|
|
+static zip_progress_t *_zip_progress_new(zip_t *za);
|
|
+static void _zip_progress_set_cancel_callback(zip_progress_t *progress, zip_cancel_callback callback, void (*ud_free)(void *), void *ud);
|
|
+static void _zip_progress_set_progress_callback(zip_progress_t *progress, double precision, zip_progress_callback callback, void (*ud_free)(void *), void *ud);
|
|
|
|
void
|
|
_zip_progress_end(zip_progress_t *progress) {
|
|
@@ -67,16 +76,15 @@ _zip_progress_free(zip_progress_t *progress) {
|
|
return;
|
|
}
|
|
|
|
- if (progress->ud_free) {
|
|
- progress->ud_free(progress->ud);
|
|
- }
|
|
+ _zip_progress_free_progress_callback(progress);
|
|
+ _zip_progress_free_cancel_callback(progress);
|
|
|
|
free(progress);
|
|
}
|
|
|
|
|
|
-zip_progress_t *
|
|
-_zip_progress_new(zip_t *za, double precision, zip_progress_callback callback, void (*ud_free)(void *), void *ud) {
|
|
+static zip_progress_t *
|
|
+_zip_progress_new(zip_t *za) {
|
|
zip_progress_t *progress = (zip_progress_t *)malloc(sizeof(*progress));
|
|
|
|
if (progress == NULL) {
|
|
@@ -85,67 +93,169 @@ _zip_progress_new(zip_t *za, double precision, zip_progress_callback callback, v
|
|
}
|
|
|
|
progress->za = za;
|
|
- progress->callback = callback;
|
|
- progress->ud_free = ud_free;
|
|
- progress->ud = ud;
|
|
- progress->precision = precision;
|
|
+
|
|
+ progress->callback_progress = NULL;
|
|
+ progress->ud_progress_free = NULL;
|
|
+ progress->ud_progress = NULL;
|
|
+ progress->precision = 0.0;
|
|
+
|
|
+ progress->callback_cancel = NULL;
|
|
+ progress->ud_cancel_free = NULL;
|
|
+ progress->ud_cancel = NULL;
|
|
|
|
return progress;
|
|
}
|
|
|
|
+static void
|
|
+_zip_progress_free_progress_callback(zip_progress_t *progress) {
|
|
+ if (progress->ud_progress_free) {
|
|
+ progress->ud_progress_free(progress->ud_progress);
|
|
+ }
|
|
+
|
|
+ progress->callback_progress = NULL;
|
|
+ progress->ud_progress = NULL;
|
|
+ progress->ud_progress_free = NULL;
|
|
+}
|
|
+
|
|
+static void
|
|
+_zip_progress_free_cancel_callback(zip_progress_t *progress) {
|
|
+ if (progress->ud_cancel_free) {
|
|
+ progress->ud_cancel_free(progress->ud_cancel);
|
|
+ }
|
|
+
|
|
+ progress->callback_cancel = NULL;
|
|
+ progress->ud_cancel = NULL;
|
|
+ progress->ud_cancel_free = NULL;
|
|
+}
|
|
+
|
|
+static void
|
|
+_zip_progress_set_progress_callback(zip_progress_t *progress, double precision, zip_progress_callback callback, void (*ud_free)(void *), void *ud) {
|
|
+ _zip_progress_free_progress_callback(progress);
|
|
+
|
|
+ progress->callback_progress = callback;
|
|
+ progress->ud_progress_free = ud_free;
|
|
+ progress->ud_progress = ud;
|
|
+ progress->precision = precision;
|
|
+}
|
|
|
|
void
|
|
+_zip_progress_set_cancel_callback(zip_progress_t *progress, zip_cancel_callback callback, void (*ud_free)(void *), void *ud) {
|
|
+ _zip_progress_free_cancel_callback(progress);
|
|
+
|
|
+ progress->callback_cancel = callback;
|
|
+ progress->ud_cancel_free = ud_free;
|
|
+ progress->ud_cancel = ud;
|
|
+}
|
|
+
|
|
+int
|
|
_zip_progress_start(zip_progress_t *progress) {
|
|
if (progress == NULL) {
|
|
- return;
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (progress->callback_progress != NULL) {
|
|
+ progress->last_update = 0.0;
|
|
+ progress->callback_progress(progress->za, 0.0, progress->ud_progress);
|
|
+ }
|
|
+
|
|
+ if (progress->callback_cancel != NULL) {
|
|
+ if (progress->callback_cancel(progress->za, progress->ud_cancel)) {
|
|
+ return -1;
|
|
+ }
|
|
}
|
|
|
|
- progress->last_update = 0.0;
|
|
- progress->callback(progress->za, 0.0, progress->ud);
|
|
+ return 0;
|
|
}
|
|
|
|
|
|
-void
|
|
+int
|
|
_zip_progress_subrange(zip_progress_t *progress, double start, double end) {
|
|
if (progress == NULL) {
|
|
- return;
|
|
+ return 0;
|
|
}
|
|
|
|
progress->start = start;
|
|
progress->end = end;
|
|
|
|
- _zip_progress_update(progress, 0.0);
|
|
+ return _zip_progress_update(progress, 0.0);
|
|
}
|
|
|
|
-void
|
|
+int
|
|
_zip_progress_update(zip_progress_t *progress, double sub_current) {
|
|
double current;
|
|
|
|
if (progress == NULL) {
|
|
- return;
|
|
+ return 0;
|
|
}
|
|
|
|
- current = ZIP_MIN(ZIP_MAX(sub_current, 0.0), 1.0) * (progress->end - progress->start) + progress->start;
|
|
+ if (progress->callback_progress != NULL) {
|
|
+ current = ZIP_MIN(ZIP_MAX(sub_current, 0.0), 1.0) * (progress->end - progress->start) + progress->start;
|
|
+
|
|
+ if (current - progress->last_update > progress->precision) {
|
|
+ progress->callback_progress(progress->za, current, progress->ud_progress);
|
|
+ progress->last_update = current;
|
|
+ }
|
|
+ }
|
|
|
|
- if (current - progress->last_update > progress->precision) {
|
|
- progress->callback(progress->za, current, progress->ud);
|
|
- progress->last_update = current;
|
|
+ if (progress->callback_cancel != NULL) {
|
|
+ if (progress->callback_cancel(progress->za, progress->ud_cancel)) {
|
|
+ return -1;
|
|
+ }
|
|
}
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
|
|
ZIP_EXTERN int
|
|
zip_register_progress_callback_with_state(zip_t *za, double precision, zip_progress_callback callback, void (*ud_free)(void *), void *ud) {
|
|
- zip_progress_t *progress = NULL;
|
|
-
|
|
if (callback != NULL) {
|
|
- if ((progress = _zip_progress_new(za, precision, callback, ud_free, ud)) == NULL) {
|
|
- return -1;
|
|
+ if (za->progress == NULL) {
|
|
+ if ((za->progress = _zip_progress_new(za)) == NULL) {
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ _zip_progress_set_progress_callback(za->progress, precision, callback, ud_free, ud);
|
|
+ }
|
|
+ else {
|
|
+ if (za->progress != NULL) {
|
|
+ if (za->progress->callback_cancel == NULL) {
|
|
+ _zip_progress_free(za->progress);
|
|
+ za->progress = NULL;
|
|
+ }
|
|
+ else {
|
|
+ _zip_progress_free_progress_callback(za->progress);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
- _zip_progress_free(za->progress);
|
|
- za->progress = progress;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+ZIP_EXTERN int
|
|
+zip_register_cancel_callback_with_state(zip_t *za, zip_cancel_callback callback, void (*ud_free)(void *), void *ud) {
|
|
+ if (callback != NULL) {
|
|
+ if (za->progress == NULL) {
|
|
+ if ((za->progress = _zip_progress_new(za)) == NULL) {
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ _zip_progress_set_cancel_callback(za->progress, callback, ud_free, ud);
|
|
+ }
|
|
+ else {
|
|
+ if (za->progress != NULL) {
|
|
+ if (za->progress->callback_progress == NULL) {
|
|
+ _zip_progress_free(za->progress);
|
|
+ za->progress = NULL;
|
|
+ }
|
|
+ else {
|
|
+ _zip_progress_free_cancel_callback(za->progress);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
|
|
return 0;
|
|
}
|
|
diff --git a/lib/zip_random_unix.c b/lib/zip_random_unix.c
|
|
index 2c59847..1d0c967 100644
|
|
--- a/lib/zip_random_unix.c
|
|
+++ b/lib/zip_random_unix.c
|
|
@@ -1,6 +1,6 @@
|
|
/*
|
|
zip_random_unix.c -- fill the user's buffer with random stuff (Unix version)
|
|
- Copyright (C) 2016-2017 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>
|
|
@@ -33,11 +33,37 @@
|
|
|
|
#include "zipint.h"
|
|
|
|
+#ifdef HAVE_CRYPTO
|
|
+#include "zip_crypto.h"
|
|
+#endif
|
|
+
|
|
+#ifdef HAVE_ARC4RANDOM
|
|
+
|
|
+#include <stdlib.h>
|
|
+
|
|
+#ifndef HAVE_SECURE_RANDOM
|
|
+ZIP_EXTERN bool
|
|
+zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {
|
|
+ arc4random_buf(buffer, length);
|
|
+ return true;
|
|
+}
|
|
+#endif
|
|
+
|
|
+#ifndef HAVE_RANDOM_UINT32
|
|
+zip_uint32_t
|
|
+zip_random_uint32(void) {
|
|
+ return arc4random();
|
|
+}
|
|
+#endif
|
|
+
|
|
+#else /* HAVE_ARC4RANDOM */
|
|
+
|
|
+#ifndef HAVE_SECURE_RANDOM
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
|
|
ZIP_EXTERN bool
|
|
-zip_random(zip_uint8_t *buffer, zip_uint16_t length) {
|
|
+zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length) {
|
|
int fd;
|
|
|
|
if ((fd = open("/dev/urandom", O_RDONLY)) < 0) {
|
|
@@ -52,3 +78,27 @@ zip_random(zip_uint8_t *buffer, zip_uint16_t length) {
|
|
close(fd);
|
|
return true;
|
|
}
|
|
+#endif
|
|
+
|
|
+#ifndef HAVE_RANDOM_UINT32
|
|
+#include <stdlib.h>
|
|
+
|
|
+zip_uint32_t
|
|
+zip_random_uint32(void) {
|
|
+ static bool seeded = false;
|
|
+
|
|
+ zip_uint32_t value;
|
|
+
|
|
+ if (zip_secure_random((zip_uint8_t *)&value, sizeof(value))) {
|
|
+ return value;
|
|
+ }
|
|
+
|
|
+ if (!seeded) {
|
|
+ srandom((unsigned int)time(NULL));
|
|
+ }
|
|
+
|
|
+ return (zip_uint32_t)random();
|
|
+}
|
|
+#endif
|
|
+
|
|
+#endif /* HAVE_ARC4RANDOM */
|
|
diff --git a/lib/zip_source_file.c b/lib/zip_source_accept_empty.c
|
|
similarity index 65%
|
|
rename from lib/zip_source_file.c
|
|
rename to lib/zip_source_accept_empty.c
|
|
index 77376f4..e6d5151 100644
|
|
--- a/lib/zip_source_file.c
|
|
+++ b/lib/zip_source_accept_empty.c
|
|
@@ -1,6 +1,6 @@
|
|
/*
|
|
- zip_source_file.c -- create data source from file
|
|
- Copyright (C) 1999-2016 Dieter Baron and Thomas Klausner
|
|
+ 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>
|
|
@@ -32,30 +32,21 @@
|
|
*/
|
|
|
|
|
|
-#include <stdio.h>
|
|
-
|
|
#include "zipint.h"
|
|
|
|
-#ifdef _WIN32
|
|
-#error This file is incompatible with Windows, use zip_source_win32utf8.c instead.
|
|
-#error Something probably went wrong with configure/cmake.
|
|
-#endif
|
|
-
|
|
-ZIP_EXTERN zip_source_t *
|
|
-zip_source_file(zip_t *za, const char *fname, zip_uint64_t start, zip_int64_t len) {
|
|
- if (za == NULL)
|
|
- return NULL;
|
|
|
|
- return zip_source_file_create(fname, start, len, &za->error);
|
|
-}
|
|
+bool
|
|
+zip_source_accept_empty(zip_source_t *src) {
|
|
+ int ret;
|
|
|
|
-
|
|
-ZIP_EXTERN zip_source_t *
|
|
-zip_source_file_create(const char *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {
|
|
- if (fname == NULL || length < -1) {
|
|
- zip_error_set(error, ZIP_ER_INVAL, 0);
|
|
- return NULL;
|
|
+ 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;
|
|
}
|
|
|
|
- return _zip_source_file_or_p(fname, NULL, start, length, NULL, error);
|
|
+ ret = (int)_zip_source_call(src, NULL, 0, ZIP_SOURCE_ACCEPT_EMPTY);
|
|
+
|
|
+ return ret != 0;
|
|
}
|
|
diff --git a/lib/zip_source_buffer.c b/lib/zip_source_buffer.c
|
|
index d2bc8ad..0e5eab3 100644
|
|
--- a/lib/zip_source_buffer.c
|
|
+++ b/lib/zip_source_buffer.c
|
|
@@ -61,6 +61,7 @@ typedef struct buffer buffer_t;
|
|
struct read_data {
|
|
zip_error_t error;
|
|
time_t mtime;
|
|
+ zip_file_attributes_t attributes;
|
|
buffer_t *in;
|
|
buffer_t *out;
|
|
};
|
|
@@ -79,29 +80,41 @@ static zip_int64_t buffer_write(buffer_t *buffer, const zip_uint8_t *data, zip_u
|
|
|
|
static zip_int64_t read_data(void *, void *, zip_uint64_t, zip_source_cmd_t);
|
|
|
|
+zip_source_t *zip_source_buffer_with_attributes_create(const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes, zip_error_t *error);
|
|
+zip_source_t *zip_source_buffer_fragment_with_attributes_create(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep, zip_file_attributes_t *attributes, zip_error_t *error);
|
|
|
|
ZIP_EXTERN zip_source_t *
|
|
zip_source_buffer(zip_t *za, const void *data, zip_uint64_t len, int freep) {
|
|
if (za == NULL)
|
|
return NULL;
|
|
|
|
- return zip_source_buffer_create(data, len, freep, &za->error);
|
|
+ return zip_source_buffer_with_attributes_create(data, len, freep, NULL, &za->error);
|
|
}
|
|
|
|
|
|
ZIP_EXTERN zip_source_t *
|
|
zip_source_buffer_create(const void *data, zip_uint64_t len, int freep, zip_error_t *error) {
|
|
+ return zip_source_buffer_with_attributes_create(data, len, freep, NULL, error);
|
|
+}
|
|
+
|
|
+
|
|
+zip_source_t *
|
|
+zip_source_buffer_with_attributes_create(const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes, zip_error_t *error) {
|
|
zip_buffer_fragment_t fragment;
|
|
|
|
- if (data == NULL && len > 0) {
|
|
- zip_error_set(error, ZIP_ER_INVAL, 0);
|
|
- return NULL;
|
|
+ if (data == NULL) {
|
|
+ if (len > 0) {
|
|
+ zip_error_set(error, ZIP_ER_INVAL, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return zip_source_buffer_fragment_with_attributes_create(NULL, 0, freep, attributes, error);
|
|
}
|
|
|
|
fragment.data = (zip_uint8_t *)data;
|
|
fragment.length = len;
|
|
|
|
- return zip_source_buffer_fragment_create(&fragment, 1, freep, error);
|
|
+ return zip_source_buffer_fragment_with_attributes_create(&fragment, 1, freep, attributes, error);
|
|
}
|
|
|
|
|
|
@@ -111,12 +124,17 @@ zip_source_buffer_fragment(zip_t *za, const zip_buffer_fragment_t *fragments, zi
|
|
return NULL;
|
|
}
|
|
|
|
- return zip_source_buffer_fragment_create(fragments, nfragments, freep, &za->error);
|
|
+ return zip_source_buffer_fragment_with_attributes_create(fragments, nfragments, freep, NULL, &za->error);
|
|
}
|
|
|
|
|
|
ZIP_EXTERN zip_source_t *
|
|
zip_source_buffer_fragment_create(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep, zip_error_t *error) {
|
|
+ return zip_source_buffer_fragment_with_attributes_create(fragments, nfragments, freep, NULL, error);
|
|
+}
|
|
+
|
|
+zip_source_t *
|
|
+zip_source_buffer_fragment_with_attributes_create(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int freep, zip_file_attributes_t *attributes, zip_error_t *error) {
|
|
struct read_data *ctx;
|
|
zip_source_t *zs;
|
|
buffer_t *buffer;
|
|
@@ -139,6 +157,12 @@ zip_source_buffer_fragment_create(const zip_buffer_fragment_t *fragments, zip_ui
|
|
ctx->in = buffer;
|
|
ctx->out = NULL;
|
|
ctx->mtime = time(NULL);
|
|
+ if (attributes) {
|
|
+ memcpy(&ctx->attributes, attributes, sizeof(ctx->attributes));
|
|
+ }
|
|
+ else {
|
|
+ zip_file_attributes_init(&ctx->attributes);
|
|
+ }
|
|
zip_error_init(&ctx->error);
|
|
|
|
if ((zs = zip_source_function_create(read_data, ctx, error)) == NULL) {
|
|
@@ -151,6 +175,11 @@ zip_source_buffer_fragment_create(const zip_buffer_fragment_t *fragments, zip_ui
|
|
}
|
|
|
|
|
|
+zip_source_t *
|
|
+zip_source_buffer_with_attributes(zip_t *za, const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes) {
|
|
+ return zip_source_buffer_with_attributes_create(data, len, freep, attributes, &za->error);
|
|
+}
|
|
+
|
|
static zip_int64_t
|
|
read_data(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
|
|
struct read_data *ctx = (struct read_data *)state;
|
|
@@ -190,6 +219,17 @@ read_data(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
|
|
free(ctx);
|
|
return 0;
|
|
|
|
+ case ZIP_SOURCE_GET_FILE_ATTRIBUTES: {
|
|
+ if (len < sizeof(ctx->attributes)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ memcpy(data, &ctx->attributes, sizeof(ctx->attributes));
|
|
+
|
|
+ return sizeof(ctx->attributes);
|
|
+ }
|
|
+
|
|
case ZIP_SOURCE_OPEN:
|
|
ctx->in->offset = 0;
|
|
ctx->in->current_fragment = 0;
|
|
@@ -246,7 +286,7 @@ read_data(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
|
|
}
|
|
|
|
case ZIP_SOURCE_SUPPORTS:
|
|
- return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_SEEK, ZIP_SOURCE_TELL, ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_BEGIN_WRITE_CLONING, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_REMOVE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_WRITE, -1);
|
|
+ return zip_source_make_command_bitmap(ZIP_SOURCE_GET_FILE_ATTRIBUTES, ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_SEEK, ZIP_SOURCE_TELL, ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_BEGIN_WRITE_CLONING, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_REMOVE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_WRITE, -1);
|
|
|
|
case ZIP_SOURCE_TELL:
|
|
if (ctx->in->offset > ZIP_INT64_MAX) {
|
|
@@ -457,7 +497,7 @@ buffer_new(const zip_buffer_fragment_t *fragments, zip_uint64_t nfragments, int
|
|
}
|
|
buffer->nfragments = j;
|
|
buffer->first_owned_fragment = free_data ? 0 : buffer->nfragments;
|
|
- buffer->fragment_offsets[nfragments] = offset;
|
|
+ buffer->fragment_offsets[buffer->nfragments] = offset;
|
|
buffer->size = offset;
|
|
}
|
|
|
|
diff --git a/lib/zip_source_compress.c b/lib/zip_source_compress.c
|
|
index a1ac3e0..ab6ea72 100644
|
|
--- a/lib/zip_source_compress.c
|
|
+++ b/lib/zip_source_compress.c
|
|
@@ -67,6 +67,16 @@ static struct implementation implementations[] = {
|
|
#if defined(HAVE_LIBBZ2)
|
|
{ZIP_CM_BZIP2, &zip_algorithm_bzip2_compress, &zip_algorithm_bzip2_decompress},
|
|
#endif
|
|
+#if defined(HAVE_LIBLZMA)
|
|
+ /* Disabled - because 7z isn't able to unpack ZIP+LZMA ZIP+LZMA2
|
|
+ archives made this way - and vice versa.
|
|
+
|
|
+ {ZIP_CM_LZMA, &zip_algorithm_xz_compress, &zip_algorithm_xz_decompress},
|
|
+ {ZIP_CM_LZMA2, &zip_algorithm_xz_compress, &zip_algorithm_xz_decompress},
|
|
+ */
|
|
+ {ZIP_CM_XZ, &zip_algorithm_xz_compress, &zip_algorithm_xz_decompress},
|
|
+#endif
|
|
+
|
|
};
|
|
|
|
static size_t implementations_size = sizeof(implementations) / sizeof(implementations[0]);
|
|
@@ -96,10 +106,10 @@ get_algorithm(zip_int32_t method, bool compress) {
|
|
return NULL;
|
|
}
|
|
|
|
-bool
|
|
-zip_compression_method_supported(zip_int32_t method, bool compress) {
|
|
+ZIP_EXTERN int
|
|
+zip_compression_method_supported(zip_int32_t method, int compress) {
|
|
if (method == ZIP_CM_STORE) {
|
|
- return true;
|
|
+ return 1;
|
|
}
|
|
return get_algorithm(method, compress) != NULL;
|
|
}
|
|
@@ -347,9 +357,6 @@ compress_callback(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip
|
|
}
|
|
return 0;
|
|
|
|
- case ZIP_SOURCE_GET_COMPRESSION_FLAGS:
|
|
- return ctx->is_stored ? 0 : ctx->algorithm->compression_flags(ctx->ud);
|
|
-
|
|
case ZIP_SOURCE_ERROR:
|
|
return zip_error_to_data(&ctx->error, data, len);
|
|
|
|
@@ -357,8 +364,24 @@ compress_callback(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip
|
|
context_free(ctx);
|
|
return 0;
|
|
|
|
+ case ZIP_SOURCE_GET_FILE_ATTRIBUTES: {
|
|
+ zip_file_attributes_t *attributes = (zip_file_attributes_t *)data;
|
|
+
|
|
+ if (len < sizeof(*attributes)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ attributes->valid |= ZIP_FILE_ATTRIBUTES_VERSION_NEEDED | ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS;
|
|
+ attributes->version_needed = ctx->algorithm->version_needed;
|
|
+ attributes->general_purpose_bit_mask = ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK;
|
|
+ attributes->general_purpose_bit_flags = (ctx->is_stored ? 0 : ctx->algorithm->general_purpose_bit_flags(ctx->ud));
|
|
+
|
|
+ return sizeof(*attributes);
|
|
+ }
|
|
+
|
|
case ZIP_SOURCE_SUPPORTS:
|
|
- return ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_GET_COMPRESSION_FLAGS, -1);
|
|
+ return ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_GET_FILE_ATTRIBUTES, -1);
|
|
|
|
default:
|
|
zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
|
|
diff --git a/lib/zip_source_crc.c b/lib/zip_source_crc.c
|
|
index 8797dfe..4033395 100644
|
|
--- a/lib/zip_source_crc.c
|
|
+++ b/lib/zip_source_crc.c
|
|
@@ -148,7 +148,6 @@ crc_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source
|
|
st->comp_method = ZIP_CM_STORE;
|
|
st->encryption_method = ZIP_EM_NONE;
|
|
st->valid |= ZIP_STAT_SIZE | ZIP_STAT_CRC | ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD | ZIP_STAT_ENCRYPTION_METHOD;
|
|
- ;
|
|
}
|
|
return 0;
|
|
}
|
|
@@ -168,7 +167,7 @@ crc_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source
|
|
return -1;
|
|
}
|
|
|
|
- return mask & ~zip_source_make_command_bitmap(ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_REMOVE, ZIP_SOURCE_GET_COMPRESSION_FLAGS, -1);
|
|
+ return mask & ~zip_source_make_command_bitmap(ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_REMOVE, ZIP_SOURCE_GET_FILE_ATTRIBUTES, -1);
|
|
}
|
|
|
|
case ZIP_SOURCE_SEEK: {
|
|
diff --git a/lib/zip_source_file.h b/lib/zip_source_file.h
|
|
new file mode 100644
|
|
index 0000000..43a4645
|
|
--- /dev/null
|
|
+++ b/lib/zip_source_file.h
|
|
@@ -0,0 +1,90 @@
|
|
+/*
|
|
+ zip_source_file.h -- header for common file operations
|
|
+ Copyright (C) 2020 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.
|
|
+*/
|
|
+
|
|
+struct zip_source_file_stat {
|
|
+ zip_uint64_t size; /* must be valid for regular files */
|
|
+ time_t mtime; /* must always be valid, is initialized to current time */
|
|
+ bool exists; /* must always be vaild */
|
|
+ bool regular_file; /* must always be valid */
|
|
+};
|
|
+
|
|
+typedef struct zip_source_file_context zip_source_file_context_t;
|
|
+typedef struct zip_source_file_operations zip_source_file_operations_t;
|
|
+typedef struct zip_source_file_stat zip_source_file_stat_t;
|
|
+
|
|
+struct zip_source_file_context {
|
|
+ zip_error_t error; /* last error information */
|
|
+ zip_int64_t supports;
|
|
+
|
|
+ /* reading */
|
|
+ char *fname; /* name of file to read from */
|
|
+ void *f; /* file to read from */
|
|
+ zip_stat_t st; /* stat information passed in */
|
|
+ zip_file_attributes_t attributes; /* additional file attributes */
|
|
+ zip_error_t stat_error; /* error returned for stat */
|
|
+ zip_uint64_t start; /* start offset of data to read */
|
|
+ zip_uint64_t len; /* length of the file, 0 for up to EOF */
|
|
+ zip_uint64_t offset; /* current offset relative to start (0 is beginning of part we read) */
|
|
+
|
|
+ /* writing */
|
|
+ char *tmpname;
|
|
+ void *fout;
|
|
+
|
|
+ zip_source_file_operations_t *ops;
|
|
+ void *ops_userdata;
|
|
+};
|
|
+
|
|
+
|
|
+/* The following methods must be implemented to support each feature:
|
|
+ - close, read, seek, and stat must always be implemented.
|
|
+ - To support specifying the file by name, open, and strdup must be implemented.
|
|
+ - For write support, the file must be specified by name and close, commit_write, create_temp_output, remove, rollback_write, and tell must be implemented.
|
|
+ - create_temp_output_cloning is always optional. */
|
|
+
|
|
+struct zip_source_file_operations {
|
|
+ void (*close)(zip_source_file_context_t *ctx);
|
|
+ zip_int64_t (*commit_write)(zip_source_file_context_t *ctx);
|
|
+ zip_int64_t (*create_temp_output)(zip_source_file_context_t *ctx);
|
|
+ zip_int64_t (*create_temp_output_cloning)(zip_source_file_context_t *ctx, zip_uint64_t len);
|
|
+ bool (*open)(zip_source_file_context_t *ctx);
|
|
+ zip_int64_t (*read)(zip_source_file_context_t *ctx, void *buf, zip_uint64_t len);
|
|
+ zip_int64_t (*remove)(zip_source_file_context_t *ctx);
|
|
+ void (*rollback_write)(zip_source_file_context_t *ctx);
|
|
+ bool (*seek)(zip_source_file_context_t *ctx, void *f, zip_int64_t offset, int whence);
|
|
+ bool (*stat)(zip_source_file_context_t *ctx, zip_source_file_stat_t *st);
|
|
+ char *(*string_duplicate)(zip_source_file_context_t *ctx, const char *);
|
|
+ zip_int64_t (*tell)(zip_source_file_context_t *ctx, void *f);
|
|
+ zip_int64_t (*write)(zip_source_file_context_t *ctx, const void *data, zip_uint64_t len);
|
|
+};
|
|
+
|
|
+zip_source_t *zip_source_file_common_new(const char *fname, void *file, zip_uint64_t start, zip_int64_t len, const zip_stat_t *st, zip_source_file_operations_t *ops, void *ops_userdata, zip_error_t *error);
|
|
diff --git a/lib/zip_source_file_common.c b/lib/zip_source_file_common.c
|
|
new file mode 100644
|
|
index 0000000..74e2100
|
|
--- /dev/null
|
|
+++ b/lib/zip_source_file_common.c
|
|
@@ -0,0 +1,378 @@
|
|
+/*
|
|
+ zip_source_file_common.c -- create data source from file
|
|
+ Copyright (C) 1999-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 <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+
|
|
+#include "zipint.h"
|
|
+
|
|
+#include "zip_source_file.h"
|
|
+
|
|
+static zip_int64_t read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd);
|
|
+
|
|
+static void
|
|
+zip_source_file_stat_init(zip_source_file_stat_t *st) {
|
|
+ st->size = 0;
|
|
+ st->mtime = time(NULL);
|
|
+ st->exists = false;
|
|
+ st->regular_file = false;
|
|
+}
|
|
+
|
|
+zip_source_t *
|
|
+zip_source_file_common_new(const char *fname, void *file, zip_uint64_t start, zip_int64_t len, const zip_stat_t *st, zip_source_file_operations_t *ops, void *ops_userdata, zip_error_t *error) {
|
|
+ zip_source_file_context_t *ctx;
|
|
+ zip_source_t *zs;
|
|
+ zip_source_file_stat_t sb;
|
|
+
|
|
+ if (ops == NULL) {
|
|
+ zip_error_set(error, ZIP_ER_INVAL, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (ops->close == NULL || ops->read == NULL || ops->seek == NULL || ops->stat == NULL) {
|
|
+ zip_error_set(error, ZIP_ER_INTERNAL, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (ops->write != NULL && (ops->commit_write == NULL || ops->create_temp_output == NULL || ops->remove == NULL || ops->rollback_write == NULL || ops->tell == NULL)) {
|
|
+ zip_error_set(error, ZIP_ER_INTERNAL, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (fname != NULL) {
|
|
+ if (ops->open == NULL || ops->string_duplicate == NULL) {
|
|
+ zip_error_set(error, ZIP_ER_INTERNAL, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+ else if (file == NULL) {
|
|
+ zip_error_set(error, ZIP_ER_INVAL, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (len < 0) {
|
|
+ len = 0;
|
|
+ }
|
|
+
|
|
+ if (start > ZIP_INT64_MAX || start + (zip_uint64_t)len < start) {
|
|
+ zip_error_set(error, ZIP_ER_INVAL, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if ((ctx = (zip_source_file_context_t *)malloc(sizeof(zip_source_file_context_t))) == NULL) {
|
|
+ zip_error_set(error, ZIP_ER_MEMORY, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ ctx->ops = ops;
|
|
+ ctx->ops_userdata = ops_userdata;
|
|
+ ctx->fname = NULL;
|
|
+ if (fname) {
|
|
+ if ((ctx->fname = ops->string_duplicate(ctx, fname)) == NULL) {
|
|
+ zip_error_set(error, ZIP_ER_MEMORY, 0);
|
|
+ free(ctx);
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+ ctx->f = file;
|
|
+ ctx->start = start;
|
|
+ ctx->len = (zip_uint64_t)len;
|
|
+ if (st) {
|
|
+ memcpy(&ctx->st, st, sizeof(ctx->st));
|
|
+ ctx->st.name = NULL;
|
|
+ ctx->st.valid &= ~ZIP_STAT_NAME;
|
|
+ }
|
|
+ else {
|
|
+ zip_stat_init(&ctx->st);
|
|
+ }
|
|
+
|
|
+ if (ctx->len > 0) {
|
|
+ ctx->st.size = ctx->len;
|
|
+ ctx->st.valid |= ZIP_STAT_SIZE;
|
|
+ }
|
|
+
|
|
+ zip_error_init(&ctx->stat_error);
|
|
+
|
|
+ ctx->tmpname = NULL;
|
|
+ ctx->fout = NULL;
|
|
+
|
|
+ zip_error_init(&ctx->error);
|
|
+ zip_file_attributes_init(&ctx->attributes);
|
|
+
|
|
+ ctx->supports = ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1);
|
|
+
|
|
+ zip_source_file_stat_init(&sb);
|
|
+ if (!ops->stat(ctx, &sb)) {
|
|
+ _zip_error_copy(error, &ctx->error);
|
|
+ free(ctx->fname);
|
|
+ free(ctx);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (!sb.exists) {
|
|
+ if (ctx->fname && ctx->start == 0 && ctx->len == 0 && ops->write != NULL) {
|
|
+ ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE;
|
|
+ /* zip_open_from_source checks for this to detect non-existing files */
|
|
+ zip_error_set(&ctx->stat_error, ZIP_ER_READ, ENOENT);
|
|
+ }
|
|
+ else {
|
|
+ zip_error_set(&ctx->stat_error, ZIP_ER_READ, ENOENT);
|
|
+ free(ctx->fname);
|
|
+ free(ctx);
|
|
+ return NULL;
|
|
+ }
|
|
+ }
|
|
+ else {
|
|
+ if ((ctx->st.valid & ZIP_STAT_MTIME) == 0) {
|
|
+ ctx->st.mtime = sb.mtime;
|
|
+ ctx->st.valid |= ZIP_STAT_MTIME;
|
|
+ }
|
|
+ if (sb.regular_file) {
|
|
+ ctx->supports = ZIP_SOURCE_SUPPORTS_SEEKABLE;
|
|
+
|
|
+ if (ctx->start + ctx->len > sb.size) {
|
|
+ zip_error_set(error, ZIP_ER_INVAL, 0);
|
|
+ free(ctx->fname);
|
|
+ free(ctx);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if (ctx->len == 0) {
|
|
+ ctx->len = sb.size - ctx->start;
|
|
+ ctx->st.size = ctx->len;
|
|
+ ctx->st.valid |= ZIP_STAT_SIZE;
|
|
+
|
|
+ /* when using a partial file, don't allow writing */
|
|
+ if (ctx->fname && start == 0 && ops->write != NULL) {
|
|
+ ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ctx->supports |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_GET_FILE_ATTRIBUTES);
|
|
+ }
|
|
+
|
|
+ ctx->supports |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_ACCEPT_EMPTY);
|
|
+ if (ops->create_temp_output_cloning != NULL) {
|
|
+ if (ctx->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE)) {
|
|
+ ctx->supports |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE_CLONING);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if ((zs = zip_source_function_create(read_file, ctx, error)) == NULL) {
|
|
+ free(ctx->fname);
|
|
+ free(ctx);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return zs;
|
|
+}
|
|
+
|
|
+
|
|
+static zip_int64_t
|
|
+read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
|
|
+ zip_source_file_context_t *ctx;
|
|
+ char *buf;
|
|
+
|
|
+ ctx = (zip_source_file_context_t *)state;
|
|
+ buf = (char *)data;
|
|
+
|
|
+ switch (cmd) {
|
|
+ case ZIP_SOURCE_ACCEPT_EMPTY:
|
|
+ return 0;
|
|
+
|
|
+ case ZIP_SOURCE_BEGIN_WRITE:
|
|
+ /* write support should not be set if fname is NULL */
|
|
+ if (ctx->fname == NULL) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
|
|
+ return -1;
|
|
+ }
|
|
+ return ctx->ops->create_temp_output(ctx);
|
|
+
|
|
+ case ZIP_SOURCE_BEGIN_WRITE_CLONING:
|
|
+ /* write support should not be set if fname is NULL */
|
|
+ if (ctx->fname == NULL) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
|
|
+ return -1;
|
|
+ }
|
|
+ return ctx->ops->create_temp_output_cloning(ctx, len);
|
|
+
|
|
+ case ZIP_SOURCE_CLOSE:
|
|
+ if (ctx->fname) {
|
|
+ ctx->ops->close(ctx);
|
|
+ ctx->f = NULL;
|
|
+ }
|
|
+ return 0;
|
|
+
|
|
+ case ZIP_SOURCE_COMMIT_WRITE: {
|
|
+ zip_int64_t ret = ctx->ops->commit_write(ctx);
|
|
+ ctx->fout = NULL;
|
|
+ if (ret == 0) {
|
|
+ free(ctx->tmpname);
|
|
+ ctx->tmpname = NULL;
|
|
+ }
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ case ZIP_SOURCE_ERROR:
|
|
+ return zip_error_to_data(&ctx->error, data, len);
|
|
+
|
|
+ case ZIP_SOURCE_FREE:
|
|
+ free(ctx->fname);
|
|
+ free(ctx->tmpname);
|
|
+ if (ctx->f) {
|
|
+ ctx->ops->close(ctx);
|
|
+ }
|
|
+ free(ctx);
|
|
+ return 0;
|
|
+
|
|
+ case ZIP_SOURCE_GET_FILE_ATTRIBUTES:
|
|
+ if (len < sizeof(ctx->attributes)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
|
|
+ return -1;
|
|
+ }
|
|
+ memcpy(data, &ctx->attributes, sizeof(ctx->attributes));
|
|
+ return sizeof(ctx->attributes);
|
|
+
|
|
+ case ZIP_SOURCE_OPEN:
|
|
+ if (ctx->fname) {
|
|
+ if (ctx->ops->open(ctx) == false) {
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (ctx->start > 0) { // TODO: rewind on re-open
|
|
+ if (ctx->ops->seek(ctx, ctx->f, (zip_int64_t)ctx->start, SEEK_SET) == false) {
|
|
+ /* TODO: skip by reading */
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+ ctx->offset = 0;
|
|
+ return 0;
|
|
+
|
|
+ case ZIP_SOURCE_READ: {
|
|
+ zip_int64_t i;
|
|
+ zip_uint64_t n;
|
|
+
|
|
+ if (ctx->len > 0) {
|
|
+ n = ZIP_MIN(ctx->len - ctx->offset, len);
|
|
+ }
|
|
+ else {
|
|
+ n = len;
|
|
+ }
|
|
+
|
|
+ if ((i = ctx->ops->read(ctx, buf, n)) < 0) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_READ, errno);
|
|
+ return -1;
|
|
+ }
|
|
+ ctx->offset += (zip_uint64_t)i;
|
|
+
|
|
+ return i;
|
|
+ }
|
|
+
|
|
+ case ZIP_SOURCE_REMOVE:
|
|
+ return ctx->ops->remove(ctx);
|
|
+
|
|
+ case ZIP_SOURCE_ROLLBACK_WRITE:
|
|
+ ctx->ops->rollback_write(ctx);
|
|
+ ctx->fout = NULL;
|
|
+ free(ctx->tmpname);
|
|
+ ctx->tmpname = NULL;
|
|
+ return 0;
|
|
+
|
|
+ case ZIP_SOURCE_SEEK: {
|
|
+ zip_int64_t new_offset = zip_source_seek_compute_offset(ctx->offset, ctx->len, data, len, &ctx->error);
|
|
+
|
|
+ if (new_offset < 0) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ /* The actual offset inside the file must be representable as zip_int64_t. */
|
|
+ if (new_offset > ZIP_INT64_MAX - (zip_int64_t)ctx->start) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_SEEK, EOVERFLOW);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ ctx->offset = (zip_uint64_t)new_offset;
|
|
+
|
|
+ if (ctx->ops->seek(ctx, ctx->f, (zip_int64_t)(ctx->offset + ctx->start), SEEK_SET) == false) {
|
|
+ return -1;
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ case ZIP_SOURCE_SEEK_WRITE: {
|
|
+ zip_source_args_seek_t *args;
|
|
+
|
|
+ args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);
|
|
+ if (args == NULL) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (ctx->ops->seek(ctx, ctx->fout, args->offset, args->whence) == false) {
|
|
+ return -1;
|
|
+ }
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ case ZIP_SOURCE_STAT: {
|
|
+ if (len < sizeof(ctx->st))
|
|
+ return -1;
|
|
+
|
|
+ if (zip_error_code_zip(&ctx->stat_error) != 0) {
|
|
+ zip_error_set(&ctx->error, zip_error_code_zip(&ctx->stat_error), zip_error_code_system(&ctx->stat_error));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ memcpy(data, &ctx->st, sizeof(ctx->st));
|
|
+ return sizeof(ctx->st);
|
|
+ }
|
|
+
|
|
+ case ZIP_SOURCE_SUPPORTS:
|
|
+ return ctx->supports;
|
|
+
|
|
+ case ZIP_SOURCE_TELL:
|
|
+ return (zip_int64_t)ctx->offset;
|
|
+
|
|
+ case ZIP_SOURCE_TELL_WRITE:
|
|
+ return ctx->ops->tell(ctx, ctx->fout);
|
|
+
|
|
+ case ZIP_SOURCE_WRITE:
|
|
+ return ctx->ops->write(ctx, data, len);
|
|
+
|
|
+ default:
|
|
+ zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
|
|
+ return -1;
|
|
+ }
|
|
+}
|
|
diff --git a/lib/zip_source_file_stdio.c b/lib/zip_source_file_stdio.c
|
|
new file mode 100644
|
|
index 0000000..4a22f78
|
|
--- /dev/null
|
|
+++ b/lib/zip_source_file_stdio.c
|
|
@@ -0,0 +1,208 @@
|
|
+/*
|
|
+ zip_source_file_stdio.c -- read-only stdio file source implementation
|
|
+ Copyright (C) 2020 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"
|
|
+
|
|
+#include "zip_source_file.h"
|
|
+#include "zip_source_file_stdio.h"
|
|
+
|
|
+#include <fcntl.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <sys/stat.h>
|
|
+
|
|
+#ifdef _WIN32
|
|
+#ifndef S_IWUSR
|
|
+#define S_IWUSR _S_IWRITE
|
|
+#endif
|
|
+#endif
|
|
+
|
|
+/* clang-format off */
|
|
+static zip_source_file_operations_t ops_stdio_read = {
|
|
+ _zip_stdio_op_close,
|
|
+ NULL,
|
|
+ NULL,
|
|
+ NULL,
|
|
+ NULL,
|
|
+ _zip_stdio_op_read,
|
|
+ NULL,
|
|
+ NULL,
|
|
+ _zip_stdio_op_seek,
|
|
+ _zip_stdio_op_stat,
|
|
+ NULL,
|
|
+ _zip_stdio_op_tell,
|
|
+ NULL
|
|
+};
|
|
+/* clang-format on */
|
|
+
|
|
+
|
|
+ZIP_EXTERN zip_source_t *
|
|
+zip_source_filep(zip_t *za, FILE *file, zip_uint64_t start, zip_int64_t len) {
|
|
+ if (za == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return zip_source_filep_create(file, start, len, &za->error);
|
|
+}
|
|
+
|
|
+
|
|
+ZIP_EXTERN zip_source_t *
|
|
+zip_source_filep_create(FILE *file, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {
|
|
+ if (file == NULL || length < -1) {
|
|
+ zip_error_set(error, ZIP_ER_INVAL, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return zip_source_file_common_new(NULL, file, start, length, NULL, &ops_stdio_read, NULL, error);
|
|
+}
|
|
+
|
|
+
|
|
+void
|
|
+_zip_stdio_op_close(zip_source_file_context_t *ctx) {
|
|
+ fclose((FILE *)ctx->f);
|
|
+}
|
|
+
|
|
+
|
|
+zip_int64_t
|
|
+_zip_stdio_op_read(zip_source_file_context_t *ctx, void *buf, zip_uint64_t len) {
|
|
+ size_t i;
|
|
+ if (len > SIZE_MAX) {
|
|
+ len = SIZE_MAX;
|
|
+ }
|
|
+
|
|
+ if ((i = fread(buf, 1, (size_t)len, ctx->f)) == 0) {
|
|
+ if (ferror((FILE *)ctx->f)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_READ, errno);
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return (zip_int64_t)i;
|
|
+}
|
|
+
|
|
+
|
|
+bool
|
|
+_zip_stdio_op_seek(zip_source_file_context_t *ctx, void *f, zip_int64_t offset, int whence) {
|
|
+#if ZIP_FSEEK_MAX > ZIP_INT64_MAX
|
|
+ if (offset > ZIP_FSEEK_MAX || offset < ZIP_FSEEK_MIN) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_SEEK, EOVERFLOW);
|
|
+ return false;
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ if (fseeko((FILE *)f, (off_t)offset, whence) < 0) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_SEEK, errno);
|
|
+ return false;
|
|
+ }
|
|
+ return true;
|
|
+}
|
|
+
|
|
+
|
|
+bool
|
|
+_zip_stdio_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st) {
|
|
+ struct stat sb;
|
|
+
|
|
+ int ret;
|
|
+
|
|
+ if (ctx->fname) {
|
|
+ ret = stat(ctx->fname, &sb);
|
|
+ }
|
|
+ else {
|
|
+ ret = fstat(fileno((FILE *)ctx->f), &sb);
|
|
+ }
|
|
+
|
|
+ if (ret < 0) {
|
|
+ if (errno == ENOENT) {
|
|
+ st->exists = false;
|
|
+ return true;
|
|
+ }
|
|
+ zip_error_set(&ctx->error, ZIP_ER_READ, errno);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ st->size = (zip_uint64_t)sb.st_size;
|
|
+ st->mtime = sb.st_mtime;
|
|
+
|
|
+ st->regular_file = S_ISREG(sb.st_mode);
|
|
+ st->exists = true;
|
|
+
|
|
+ /* We're using UNIX file API, even on Windows; thus, we supply external file attributes with Unix values. */
|
|
+ /* TODO: This could be improved on Windows by providing Windows-specific file attributes */
|
|
+ ctx->attributes.valid = ZIP_FILE_ATTRIBUTES_HOST_SYSTEM | ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES;
|
|
+ ctx->attributes.host_system = ZIP_OPSYS_UNIX;
|
|
+ ctx->attributes.external_file_attributes = (((zip_uint32_t)sb.st_mode) << 16) | ((sb.st_mode & S_IWUSR) ? 0 : 1);
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+
|
|
+zip_int64_t
|
|
+_zip_stdio_op_tell(zip_source_file_context_t *ctx, void *f) {
|
|
+ off_t offset = ftello((FILE *)f);
|
|
+
|
|
+ if (offset < 0) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_SEEK, errno);
|
|
+ }
|
|
+
|
|
+ return offset;
|
|
+}
|
|
+
|
|
+
|
|
+/*
|
|
+ * fopen replacement that sets the close-on-exec flag
|
|
+ * some implementations support an fopen 'e' flag for that,
|
|
+ * but e.g. macOS doesn't.
|
|
+ */
|
|
+FILE *
|
|
+_zip_fopen_close_on_exec(const char *name, bool writeable) {
|
|
+ int fd;
|
|
+ int flags;
|
|
+ FILE *fp;
|
|
+
|
|
+ flags = O_CLOEXEC;
|
|
+ if (writeable) {
|
|
+ flags |= O_RDWR;
|
|
+ }
|
|
+ else {
|
|
+ flags |= O_RDONLY;
|
|
+ }
|
|
+
|
|
+ /* mode argument needed on Windows */
|
|
+ if ((fd = open(name, flags, 0666)) < 0) {
|
|
+ return NULL;
|
|
+ }
|
|
+ if ((fp = fdopen(fd, writeable ? "r+b" : "rb")) == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+ return fp;
|
|
+}
|
|
diff --git a/lib/zip_source_file_stdio.h b/lib/zip_source_file_stdio.h
|
|
new file mode 100644
|
|
index 0000000..1bf698c
|
|
--- /dev/null
|
|
+++ b/lib/zip_source_file_stdio.h
|
|
@@ -0,0 +1,47 @@
|
|
+#ifndef _HAD_ZIP_SOURCE_FILE_STDIO_H
|
|
+#define _HAD_ZIP_SOURCE_FILE_STDIO_H
|
|
+
|
|
+/*
|
|
+ zip_source_file_stdio.h -- common header for stdio file implementation
|
|
+ Copyright (C) 2020 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 <stdio.h>
|
|
+
|
|
+void _zip_stdio_op_close(zip_source_file_context_t *ctx);
|
|
+zip_int64_t _zip_stdio_op_read(zip_source_file_context_t *ctx, void *buf, zip_uint64_t len);
|
|
+bool _zip_stdio_op_seek(zip_source_file_context_t *ctx, void *f, zip_int64_t offset, int whence);
|
|
+bool _zip_stdio_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st);
|
|
+zip_int64_t _zip_stdio_op_tell(zip_source_file_context_t *ctx, void *f);
|
|
+
|
|
+FILE *_zip_fopen_close_on_exec(const char *name, bool writeable);
|
|
+
|
|
+#endif /* _HAD_ZIP_SOURCE_FILE_STDIO_H */
|
|
diff --git a/lib/zip_source_file_stdio_named.c b/lib/zip_source_file_stdio_named.c
|
|
new file mode 100644
|
|
index 0000000..dae8177
|
|
--- /dev/null
|
|
+++ b/lib/zip_source_file_stdio_named.c
|
|
@@ -0,0 +1,313 @@
|
|
+/*
|
|
+ zip_source_file_stdio_named.c -- source for stdio file opened by name
|
|
+ Copyright (C) 1999-2020 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"
|
|
+
|
|
+#include "zip_source_file.h"
|
|
+#include "zip_source_file_stdio.h"
|
|
+
|
|
+#include <stdlib.h>
|
|
+#include <sys/stat.h>
|
|
+#ifdef HAVE_UNISTD_H
|
|
+#include <unistd.h>
|
|
+#endif
|
|
+
|
|
+#ifdef HAVE_CLONEFILE
|
|
+#include <sys/attr.h>
|
|
+#include <sys/clonefile.h>
|
|
+#define CAN_CLONE
|
|
+#endif
|
|
+#ifdef HAVE_FICLONERANGE
|
|
+#include <linux/fs.h>
|
|
+#include <sys/ioctl.h>
|
|
+#define CAN_CLONE
|
|
+#endif
|
|
+
|
|
+static zip_int64_t _zip_stdio_op_commit_write(zip_source_file_context_t *ctx);
|
|
+static zip_int64_t _zip_stdio_op_create_temp_output(zip_source_file_context_t *ctx);
|
|
+#ifdef CAN_CLONE
|
|
+static zip_int64_t _zip_stdio_op_create_temp_output_cloning(zip_source_file_context_t *ctx, zip_uint64_t offset);
|
|
+#endif
|
|
+static bool _zip_stdio_op_open(zip_source_file_context_t *ctx);
|
|
+static zip_int64_t _zip_stdio_op_remove(zip_source_file_context_t *ctx);
|
|
+static void _zip_stdio_op_rollback_write(zip_source_file_context_t *ctx);
|
|
+static char *_zip_stdio_op_strdup(zip_source_file_context_t *ctx, const char *string);
|
|
+static zip_int64_t _zip_stdio_op_write(zip_source_file_context_t *ctx, const void *data, zip_uint64_t len);
|
|
+
|
|
+/* clang-format off */
|
|
+static zip_source_file_operations_t ops_stdio_named = {
|
|
+ _zip_stdio_op_close,
|
|
+ _zip_stdio_op_commit_write,
|
|
+ _zip_stdio_op_create_temp_output,
|
|
+#ifdef CAN_CLONE
|
|
+ _zip_stdio_op_create_temp_output_cloning,
|
|
+#else
|
|
+ NULL,
|
|
+#endif
|
|
+ _zip_stdio_op_open,
|
|
+ _zip_stdio_op_read,
|
|
+ _zip_stdio_op_remove,
|
|
+ _zip_stdio_op_rollback_write,
|
|
+ _zip_stdio_op_seek,
|
|
+ _zip_stdio_op_stat,
|
|
+ _zip_stdio_op_strdup,
|
|
+ _zip_stdio_op_tell,
|
|
+ _zip_stdio_op_write
|
|
+};
|
|
+/* clang-format on */
|
|
+
|
|
+ZIP_EXTERN zip_source_t *
|
|
+zip_source_file(zip_t *za, const char *fname, zip_uint64_t start, zip_int64_t len) {
|
|
+ if (za == NULL)
|
|
+ return NULL;
|
|
+
|
|
+ return zip_source_file_create(fname, start, len, &za->error);
|
|
+}
|
|
+
|
|
+
|
|
+ZIP_EXTERN zip_source_t *
|
|
+zip_source_file_create(const char *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {
|
|
+ if (fname == NULL || length < -1) {
|
|
+ zip_error_set(error, ZIP_ER_INVAL, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return zip_source_file_common_new(fname, NULL, start, length, NULL, &ops_stdio_named, NULL, error);
|
|
+}
|
|
+
|
|
+
|
|
+static zip_int64_t
|
|
+_zip_stdio_op_commit_write(zip_source_file_context_t *ctx) {
|
|
+ if (fclose(ctx->fout) < 0) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_WRITE, errno);
|
|
+ return -1;
|
|
+ }
|
|
+ if (rename(ctx->tmpname, ctx->fname) < 0) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_RENAME, errno);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static zip_int64_t
|
|
+_zip_stdio_op_create_temp_output(zip_source_file_context_t *ctx) {
|
|
+ char *temp;
|
|
+ int tfd;
|
|
+ int mode;
|
|
+ FILE *tfp;
|
|
+ struct stat st;
|
|
+
|
|
+ if ((temp = (char *)malloc(strlen(ctx->fname) + 8)) == NULL) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (stat(ctx->fname, &st) == 0) {
|
|
+ mode = st.st_mode;
|
|
+ }
|
|
+ else {
|
|
+ mode = -1;
|
|
+ }
|
|
+
|
|
+ sprintf(temp, "%s.XXXXXX", ctx->fname);
|
|
+
|
|
+ if ((tfd = _zip_mkstempm(temp, mode)) == -1) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
|
|
+ free(temp);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if ((tfp = fdopen(tfd, "r+b")) == NULL) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
|
|
+ close(tfd);
|
|
+ (void)remove(temp);
|
|
+ free(temp);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ ctx->fout = tfp;
|
|
+ ctx->tmpname = temp;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#ifdef CAN_CLONE
|
|
+static zip_int64_t
|
|
+_zip_stdio_op_create_temp_output_cloning(zip_source_file_context_t *ctx, zip_uint64_t offset) {
|
|
+ char *temp;
|
|
+ FILE *tfp;
|
|
+
|
|
+ if (offset > ZIP_OFF_MAX) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_SEEK, E2BIG);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if ((temp = (char *)malloc(strlen(ctx->fname) + 8)) == NULL) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
|
|
+ return -1;
|
|
+ }
|
|
+ sprintf(temp, "%s.XXXXXX", ctx->fname);
|
|
+
|
|
+#ifdef HAVE_CLONEFILE
|
|
+#ifndef __clang_analyzer__
|
|
+ /* we can't use mkstemp, since clonefile insists on creating the file */
|
|
+ if (mktemp(temp) == NULL) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
|
|
+ free(temp);
|
|
+ return -1;
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ if (clonefile(ctx->fname, temp, 0) < 0) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
|
|
+ free(temp);
|
|
+ return -1;
|
|
+ }
|
|
+ if ((tfp = _zip_fopen_close_on_exec(temp, true)) == NULL) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
|
|
+ (void)remove(temp);
|
|
+ free(temp);
|
|
+ return -1;
|
|
+ }
|
|
+#else
|
|
+ {
|
|
+ int fd;
|
|
+ struct file_clone_range range;
|
|
+ struct stat st;
|
|
+
|
|
+ if (fstat(fileno(ctx->f), &st) < 0) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
|
|
+ free(temp);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if ((fd = mkstemp(temp)) < 0) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
|
|
+ free(temp);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ range.src_fd = fileno(ctx->f);
|
|
+ range.src_offset = 0;
|
|
+ range.src_length = ((offset + st.st_blksize - 1) / st.st_blksize) * st.st_blksize;
|
|
+ if (range.src_length > st.st_size) {
|
|
+ range.src_length = 0;
|
|
+ }
|
|
+ range.dest_offset = 0;
|
|
+ if (ioctl(fd, FICLONERANGE, &range) < 0) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
|
|
+ (void)close(fd);
|
|
+ (void)remove(temp);
|
|
+ free(temp);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if ((tfp = fdopen(fd, "r+b")) == NULL) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
|
|
+ (void)close(fd);
|
|
+ (void)remove(temp);
|
|
+ free(temp);
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ if (ftruncate(fileno(tfp), (off_t)offset) < 0) {
|
|
+ (void)fclose(tfp);
|
|
+ (void)remove(temp);
|
|
+ free(temp);
|
|
+ return -1;
|
|
+ }
|
|
+ if (fseeko(tfp, (off_t)offset, SEEK_SET) < 0) {
|
|
+ (void)fclose(tfp);
|
|
+ (void)remove(temp);
|
|
+ free(temp);
|
|
+ zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
|
|
+ }
|
|
+
|
|
+ ctx->fout = tfp;
|
|
+ ctx->tmpname = temp;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
+static bool
|
|
+_zip_stdio_op_open(zip_source_file_context_t *ctx) {
|
|
+ if ((ctx->f = _zip_fopen_close_on_exec(ctx->fname, false)) == NULL) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_OPEN, errno);
|
|
+ return false;
|
|
+ }
|
|
+ return true;
|
|
+}
|
|
+
|
|
+
|
|
+static zip_int64_t
|
|
+_zip_stdio_op_remove(zip_source_file_context_t *ctx) {
|
|
+ if (remove(ctx->fname) < 0) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_REMOVE, errno);
|
|
+ return -1;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+_zip_stdio_op_rollback_write(zip_source_file_context_t *ctx) {
|
|
+ if (ctx->fout) {
|
|
+ fclose(ctx->fout);
|
|
+ }
|
|
+ (void)remove(ctx->tmpname);
|
|
+}
|
|
+
|
|
+static char *
|
|
+_zip_stdio_op_strdup(zip_source_file_context_t *ctx, const char *string) {
|
|
+ return strdup(string);
|
|
+}
|
|
+
|
|
+
|
|
+static zip_int64_t
|
|
+_zip_stdio_op_write(zip_source_file_context_t *ctx, const void *data, zip_uint64_t len) {
|
|
+ size_t ret;
|
|
+
|
|
+ clearerr((FILE *)ctx->fout);
|
|
+ ret = fwrite(data, 1, len, (FILE *)ctx->fout);
|
|
+ if (ret != len || ferror((FILE *)ctx->fout)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_WRITE, errno);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return (zip_int64_t)ret;
|
|
+}
|
|
diff --git a/lib/zip_source_file_win32.c b/lib/zip_source_file_win32.c
|
|
new file mode 100644
|
|
index 0000000..2fe838f
|
|
--- /dev/null
|
|
+++ b/lib/zip_source_file_win32.c
|
|
@@ -0,0 +1,230 @@
|
|
+/*
|
|
+ zip_source_file_win32.c -- read-only Windows file source implementation
|
|
+ Copyright (C) 1999-2020 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 "zip_source_file_win32.h"
|
|
+
|
|
+static bool _zip_win32_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st);
|
|
+
|
|
+static bool _zip_stat_win32(zip_source_file_context_t *ctx, zip_source_file_stat_t *st, HANDLE h);
|
|
+
|
|
+static zip_source_file_operations_t ops_win32_read = {
|
|
+ _zip_win32_op_close,
|
|
+ NULL,
|
|
+ NULL,
|
|
+ NULL,
|
|
+ NULL,
|
|
+ _zip_win32_op_read,
|
|
+ NULL,
|
|
+ NULL,
|
|
+ _zip_win32_op_seek,
|
|
+ _zip_win32_op_stat,
|
|
+ NULL,
|
|
+ _zip_win32_op_tell,
|
|
+ NULL
|
|
+};
|
|
+
|
|
+
|
|
+ZIP_EXTERN zip_source_t *
|
|
+zip_source_win32handle(zip_t *za, HANDLE h, zip_uint64_t start, zip_int64_t len) {
|
|
+ if (za == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return zip_source_win32handle_create(h, start, len, &za->error);
|
|
+}
|
|
+
|
|
+
|
|
+ZIP_EXTERN zip_source_t *
|
|
+zip_source_win32handle_create(HANDLE h, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {
|
|
+ if (h == INVALID_HANDLE_VALUE || length < -1) {
|
|
+ zip_error_set(error, ZIP_ER_INVAL, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return zip_source_file_common_new(NULL, h, start, length, NULL, &ops_win32_read, NULL, error);
|
|
+}
|
|
+
|
|
+
|
|
+void
|
|
+_zip_win32_op_close(zip_source_file_context_t *ctx) {
|
|
+ CloseHandle((HANDLE)ctx->f);
|
|
+}
|
|
+
|
|
+
|
|
+zip_int64_t
|
|
+_zip_win32_op_read(zip_source_file_context_t *ctx, void *buf, zip_uint64_t len) {
|
|
+ DWORD i;
|
|
+
|
|
+ /* TODO: cap len to "DWORD_MAX" */
|
|
+ if (!ReadFile((HANDLE)ctx->f, buf, (DWORD)len, &i, NULL)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(GetLastError()));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return (zip_int64_t)i;
|
|
+}
|
|
+
|
|
+
|
|
+bool
|
|
+_zip_win32_op_seek(zip_source_file_context_t *ctx, void *f, zip_int64_t offset, int whence) {
|
|
+ LARGE_INTEGER li;
|
|
+ DWORD method;
|
|
+
|
|
+ switch (whence) {
|
|
+ case SEEK_SET:
|
|
+ method = FILE_BEGIN;
|
|
+ break;
|
|
+ case SEEK_END:
|
|
+ method = FILE_END;
|
|
+ break;
|
|
+ case SEEK_CUR:
|
|
+ method = FILE_CURRENT;
|
|
+ break;
|
|
+ default:
|
|
+ zip_error_set(&ctx->error, ZIP_ER_SEEK, EINVAL);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ li.QuadPart = (LONGLONG)offset;
|
|
+ if (!SetFilePointerEx((HANDLE)f, li, NULL, method)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_SEEK, _zip_win32_error_to_errno(GetLastError()));
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+
|
|
+static bool
|
|
+_zip_win32_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st) {
|
|
+ return _zip_stat_win32(ctx, st, (HANDLE)ctx->f);
|
|
+}
|
|
+
|
|
+
|
|
+zip_int64_t
|
|
+_zip_win32_op_tell(zip_source_file_context_t *ctx, void *f) {
|
|
+ LARGE_INTEGER zero;
|
|
+ LARGE_INTEGER new_offset;
|
|
+
|
|
+ zero.QuadPart = 0;
|
|
+ if (!SetFilePointerEx((HANDLE)f, zero, &new_offset, FILE_CURRENT)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_SEEK, _zip_win32_error_to_errno(GetLastError()));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return (zip_int64_t)new_offset.QuadPart;
|
|
+}
|
|
+
|
|
+
|
|
+int
|
|
+_zip_win32_error_to_errno(DWORD win32err) {
|
|
+ /* Note: This list isn't exhaustive, but should cover common cases. */
|
|
+ switch (win32err) {
|
|
+ case ERROR_INVALID_PARAMETER:
|
|
+ return EINVAL;
|
|
+ case ERROR_FILE_NOT_FOUND:
|
|
+ return ENOENT;
|
|
+ case ERROR_INVALID_HANDLE:
|
|
+ return EBADF;
|
|
+ case ERROR_ACCESS_DENIED:
|
|
+ return EACCES;
|
|
+ case ERROR_FILE_EXISTS:
|
|
+ return EEXIST;
|
|
+ case ERROR_TOO_MANY_OPEN_FILES:
|
|
+ return EMFILE;
|
|
+ case ERROR_DISK_FULL:
|
|
+ return ENOSPC;
|
|
+ default:
|
|
+ return 10000 + win32err;
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+static bool
|
|
+_zip_stat_win32(zip_source_file_context_t *ctx, zip_source_file_stat_t *st, HANDLE h) {
|
|
+ FILETIME mtimeft;
|
|
+ time_t mtime;
|
|
+ LARGE_INTEGER size;
|
|
+
|
|
+ if (!GetFileTime(h, NULL, NULL, &mtimeft)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(GetLastError()));
|
|
+ return false;
|
|
+ }
|
|
+ if (_zip_filetime_to_time_t(mtimeft, &mtime) < 0) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_READ, ERANGE);
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ st->exists = true;
|
|
+ st->mtime = mtime;
|
|
+
|
|
+ if (GetFileType(h) == FILE_TYPE_DISK) {
|
|
+ st->regular_file = 1;
|
|
+
|
|
+ if (!GetFileSizeEx(h, &size)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(GetLastError()));
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ st->size = (zip_uint64_t)size.QuadPart;
|
|
+ }
|
|
+
|
|
+ /* TODO: fill in ctx->attributes */
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+
|
|
+bool
|
|
+_zip_filetime_to_time_t(FILETIME ft, time_t *t) {
|
|
+ /*
|
|
+ Inspired by http://stackoverflow.com/questions/6161776/convert-windows-filetime-to-second-in-unix-linux
|
|
+ */
|
|
+ const zip_int64_t WINDOWS_TICK = 10000000LL;
|
|
+ const zip_int64_t SEC_TO_UNIX_EPOCH = 11644473600LL;
|
|
+ ULARGE_INTEGER li;
|
|
+ zip_int64_t secs;
|
|
+ time_t temp;
|
|
+
|
|
+ li.LowPart = ft.dwLowDateTime;
|
|
+ li.HighPart = ft.dwHighDateTime;
|
|
+ secs = (li.QuadPart / WINDOWS_TICK - SEC_TO_UNIX_EPOCH);
|
|
+
|
|
+ temp = (time_t)secs;
|
|
+ if (secs != (zip_int64_t)temp) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ *t = temp;
|
|
+ return true;
|
|
+}
|
|
diff --git a/lib/zip_source_file_win32.h b/lib/zip_source_file_win32.h
|
|
new file mode 100644
|
|
index 0000000..5092e63
|
|
--- /dev/null
|
|
+++ b/lib/zip_source_file_win32.h
|
|
@@ -0,0 +1,74 @@
|
|
+#ifndef _HAD_ZIP_SOURCE_FILE_WIN32_H
|
|
+#define _HAD_ZIP_SOURCE_FILE_WIN32_H
|
|
+
|
|
+/*
|
|
+ zip_source_file_win32.h -- common header for Windows file implementation
|
|
+ Copyright (C) 2020 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.
|
|
+*/
|
|
+
|
|
+/* 0x0501 => Windows XP; needs to be at least this value because of GetFileSizeEx */
|
|
+#if !defined(MS_UWP) && !defined(_WIN32_WINNT)
|
|
+#define _WIN32_WINNT 0x0501
|
|
+#endif
|
|
+
|
|
+#include <windows.h>
|
|
+
|
|
+#include <aclapi.h>
|
|
+
|
|
+#include "zipint.h"
|
|
+
|
|
+#include "zip_source_file.h"
|
|
+
|
|
+struct zip_win32_file_operations {
|
|
+ char *(*allocate_tempname)(const char *name, size_t extra_chars, size_t *lengthp);
|
|
+ HANDLE (__stdcall *create_file)(const void *name, DWORD access, DWORD share_mode, PSECURITY_ATTRIBUTES security_attributes, DWORD creation_disposition, DWORD file_attributes, HANDLE template_file);
|
|
+ BOOL (__stdcall *delete_file)(const void *name);
|
|
+ DWORD (__stdcall *get_file_attributes)(const void *name);
|
|
+ BOOL (__stdcall *get_file_attributes_ex)(const void *name, GET_FILEEX_INFO_LEVELS info_level, void *information);
|
|
+ void (*make_tempname)(char *buf, size_t len, const char *name, zip_uint32_t i);
|
|
+ BOOL (__stdcall *move_file)(const void *from, const void *to, DWORD flags);
|
|
+ BOOL (__stdcall *set_file_attributes)(const void *name, DWORD attributes);
|
|
+ char *(*string_duplicate)(const char *string);
|
|
+};
|
|
+
|
|
+typedef struct zip_win32_file_operations zip_win32_file_operations_t;
|
|
+
|
|
+extern zip_source_file_operations_t _zip_source_file_win32_named_ops;
|
|
+
|
|
+void _zip_win32_op_close(zip_source_file_context_t *ctx);
|
|
+zip_int64_t _zip_win32_op_read(zip_source_file_context_t *ctx, void *buf, zip_uint64_t len);
|
|
+bool _zip_win32_op_seek(zip_source_file_context_t *ctx, void *f, zip_int64_t offset, int whence);
|
|
+zip_int64_t _zip_win32_op_tell(zip_source_file_context_t *ctx, void *f);
|
|
+
|
|
+bool _zip_filetime_to_time_t(FILETIME ft, time_t *t);
|
|
+int _zip_win32_error_to_errno(DWORD win32err);
|
|
+
|
|
+#endif /* _HAD_ZIP_SOURCE_FILE_WIN32_H */
|
|
diff --git a/lib/zip_source_file_win32_ansi.c b/lib/zip_source_file_win32_ansi.c
|
|
new file mode 100644
|
|
index 0000000..573b74e
|
|
--- /dev/null
|
|
+++ b/lib/zip_source_file_win32_ansi.c
|
|
@@ -0,0 +1,81 @@
|
|
+/*
|
|
+ zip_source_file_win32_ansi.c -- source for Windows file opened by ANSI name
|
|
+ Copyright (C) 1999-2020 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 "zip_source_file_win32.h"
|
|
+
|
|
+static char *ansi_allocate_tempname(const char *name, size_t extra_chars, size_t *lengthp);
|
|
+static void ansi_make_tempname(char *buf, size_t len, const char *name, zip_uint32_t i);
|
|
+
|
|
+zip_win32_file_operations_t ops_ansi = {
|
|
+ ansi_allocate_tempname,
|
|
+ CreateFileA,
|
|
+ DeleteFileA,
|
|
+ GetFileAttributesA,
|
|
+ GetFileAttributesExA,
|
|
+ ansi_make_tempname,
|
|
+ MoveFileExA,
|
|
+ SetFileAttributesA,
|
|
+ strdup
|
|
+};
|
|
+
|
|
+ZIP_EXTERN zip_source_t *
|
|
+zip_source_win32a(zip_t *za, const char *fname, zip_uint64_t start, zip_int64_t len) {
|
|
+ if (za == NULL)
|
|
+ return NULL;
|
|
+
|
|
+ return zip_source_win32a_create(fname, start, len, &za->error);
|
|
+}
|
|
+
|
|
+
|
|
+ZIP_EXTERN zip_source_t *
|
|
+zip_source_win32a_create(const char *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {
|
|
+ if (fname == NULL || length < -1) {
|
|
+ zip_error_set(error, ZIP_ER_INVAL, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return zip_source_file_common_new(fname, NULL, start, length, NULL, &_zip_source_file_win32_named_ops, &ops_ansi, error);
|
|
+}
|
|
+
|
|
+
|
|
+static char *
|
|
+ansi_allocate_tempname(const char *name, size_t extra_chars, size_t *lengthp) {
|
|
+ *lengthp = strlen(name) + extra_chars;
|
|
+ return (char *)malloc(*lengthp);
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+ansi_make_tempname(char *buf, size_t len, const char *name, zip_uint32_t i) {
|
|
+ snprintf(buf, len, "%s.%08x", name, i);
|
|
+}
|
|
diff --git a/lib/zip_source_file_win32_named.c b/lib/zip_source_file_win32_named.c
|
|
new file mode 100644
|
|
index 0000000..9591b26
|
|
--- /dev/null
|
|
+++ b/lib/zip_source_file_win32_named.c
|
|
@@ -0,0 +1,266 @@
|
|
+/*
|
|
+ zip_source_file_win32_named.c -- source for Windows file opened by name
|
|
+ Copyright (C) 1999-2020 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 "zip_source_file_win32.h"
|
|
+
|
|
+static zip_int64_t _zip_win32_named_op_commit_write(zip_source_file_context_t *ctx);
|
|
+static zip_int64_t _zip_win32_named_op_create_temp_output(zip_source_file_context_t *ctx);
|
|
+static bool _zip_win32_named_op_open(zip_source_file_context_t *ctx);
|
|
+static zip_int64_t _zip_win32_named_op_remove(zip_source_file_context_t *ctx);
|
|
+static void _zip_win32_named_op_rollback_write(zip_source_file_context_t *ctx);
|
|
+static bool _zip_win32_named_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st);
|
|
+static char *_zip_win32_named_op_string_duplicate(zip_source_file_context_t *ctx, const char *string);
|
|
+static zip_int64_t _zip_win32_named_op_write(zip_source_file_context_t *ctx, const void *data, zip_uint64_t len);
|
|
+
|
|
+static HANDLE win32_named_open(zip_source_file_context_t *ctx, const char *name, bool temporary, PSECURITY_ATTRIBUTES security_attributes);
|
|
+
|
|
+/* clang-format off */
|
|
+zip_source_file_operations_t _zip_source_file_win32_named_ops = {
|
|
+ _zip_win32_op_close,
|
|
+ _zip_win32_named_op_commit_write,
|
|
+ _zip_win32_named_op_create_temp_output,
|
|
+ NULL,
|
|
+ _zip_win32_named_op_open,
|
|
+ _zip_win32_op_read,
|
|
+ _zip_win32_named_op_remove,
|
|
+ _zip_win32_named_op_rollback_write,
|
|
+ _zip_win32_op_seek,
|
|
+ _zip_win32_named_op_stat,
|
|
+ _zip_win32_named_op_string_duplicate,
|
|
+ _zip_win32_op_tell,
|
|
+ _zip_win32_named_op_write
|
|
+};
|
|
+/* clang-format on */
|
|
+
|
|
+static zip_int64_t
|
|
+_zip_win32_named_op_commit_write(zip_source_file_context_t *ctx) {
|
|
+ zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata;
|
|
+
|
|
+ if (!CloseHandle((HANDLE)ctx->fout)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_WRITE, _zip_win32_error_to_errno(GetLastError()));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ DWORD attributes = file_ops->get_file_attributes(ctx->tmpname);
|
|
+ if (attributes == INVALID_FILE_ATTRIBUTES) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError()));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (attributes & FILE_ATTRIBUTE_TEMPORARY) {
|
|
+ if (!file_ops->set_file_attributes(ctx->tmpname, attributes & ~FILE_ATTRIBUTE_TEMPORARY)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError()));
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!file_ops->move_file(ctx->tmpname, ctx->fname, MOVEFILE_REPLACE_EXISTING)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError()));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static zip_int64_t
|
|
+_zip_win32_named_op_create_temp_output(zip_source_file_context_t *ctx) {
|
|
+ zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata;
|
|
+
|
|
+ zip_uint32_t value, i;
|
|
+ HANDLE th = INVALID_HANDLE_VALUE;
|
|
+ void *temp = NULL;
|
|
+ PSECURITY_DESCRIPTOR psd = NULL;
|
|
+ PSECURITY_ATTRIBUTES psa = NULL;
|
|
+ SECURITY_ATTRIBUTES sa;
|
|
+ SECURITY_INFORMATION si;
|
|
+ DWORD success;
|
|
+ PACL dacl = NULL;
|
|
+ char *tempname = NULL;
|
|
+ size_t tempname_size = 0;
|
|
+
|
|
+ if ((HANDLE)ctx->f != INVALID_HANDLE_VALUE && GetFileType((HANDLE)ctx->f) == FILE_TYPE_DISK) {
|
|
+ si = DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION;
|
|
+ success = GetSecurityInfo((HANDLE)ctx->f, SE_FILE_OBJECT, si, NULL, NULL, &dacl, NULL, &psd);
|
|
+ if (success == ERROR_SUCCESS) {
|
|
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
+ sa.bInheritHandle = FALSE;
|
|
+ sa.lpSecurityDescriptor = psd;
|
|
+ psa = &sa;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ #ifndef MS_UWP
|
|
+ value = GetTickCount();
|
|
+#else
|
|
+ value = (zip_uint32_t)(GetTickCount64() & 0xffffffff);
|
|
+#endif
|
|
+
|
|
+ if ((tempname = file_ops->allocate_tempname(ctx->fname, 10, &tempname_size)) == NULL) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < 1024 && th == INVALID_HANDLE_VALUE; i++) {
|
|
+ file_ops->make_tempname(tempname, tempname_size, ctx->fname, value + i);
|
|
+
|
|
+ th = win32_named_open(ctx, tempname, true, psa);
|
|
+ if (th == INVALID_HANDLE_VALUE && GetLastError() != ERROR_FILE_EXISTS)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (th == INVALID_HANDLE_VALUE) {
|
|
+ free(tempname);
|
|
+ LocalFree(psd);
|
|
+ zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, _zip_win32_error_to_errno(GetLastError()));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ LocalFree(psd);
|
|
+ ctx->fout = th;
|
|
+ ctx->tmpname = tempname;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static bool
|
|
+_zip_win32_named_op_open(zip_source_file_context_t *ctx) {
|
|
+ HANDLE h = win32_named_open(ctx, ctx->fname, false, NULL);
|
|
+
|
|
+ if (h == INVALID_HANDLE_VALUE) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ ctx->f = h;
|
|
+ return true;
|
|
+}
|
|
+
|
|
+
|
|
+static zip_int64_t
|
|
+_zip_win32_named_op_remove(zip_source_file_context_t *ctx) {
|
|
+ zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata;
|
|
+
|
|
+ if (!file_ops->delete_file(ctx->fname)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_REMOVE, _zip_win32_error_to_errno(GetLastError()));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+_zip_win32_named_op_rollback_write(zip_source_file_context_t *ctx) {
|
|
+ zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata;
|
|
+
|
|
+ if (ctx->fout) {
|
|
+ CloseHandle((HANDLE)ctx->fout);
|
|
+ }
|
|
+ file_ops->delete_file(ctx->tmpname);
|
|
+}
|
|
+
|
|
+
|
|
+static bool
|
|
+_zip_win32_named_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st) {
|
|
+ zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata;
|
|
+
|
|
+ WIN32_FILE_ATTRIBUTE_DATA file_attributes;
|
|
+
|
|
+ if (!file_ops->get_file_attributes_ex(ctx->fname, GetFileExInfoStandard, &file_attributes)) {
|
|
+ DWORD error = GetLastError();
|
|
+ if (error == ERROR_FILE_NOT_FOUND) {
|
|
+ st->exists = false;
|
|
+ return true;
|
|
+ }
|
|
+ zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(error));
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ st->exists = true;
|
|
+ st->regular_file = true; /* TODO: Is this always right? How to determine without a HANDLE? */
|
|
+ if (!_zip_filetime_to_time_t(file_attributes.ftLastWriteTime, &st->mtime)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_READ, ERANGE);
|
|
+ return false;
|
|
+ }
|
|
+ st->size = ((zip_uint64_t)file_attributes.nFileSizeHigh << 32) | file_attributes.nFileSizeLow;
|
|
+
|
|
+ /* TODO: fill in ctx->attributes */
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+
|
|
+static char *
|
|
+_zip_win32_named_op_string_duplicate(zip_source_file_context_t *ctx, const char *string) {
|
|
+ zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata;
|
|
+
|
|
+ return file_ops->string_duplicate(string);
|
|
+}
|
|
+
|
|
+
|
|
+static zip_int64_t
|
|
+_zip_win32_named_op_write(zip_source_file_context_t *ctx, const void *data, zip_uint64_t len) {
|
|
+ DWORD ret;
|
|
+ if (!WriteFile((HANDLE)ctx->fout, data, (DWORD)len, &ret, NULL) || ret != len) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_WRITE, _zip_win32_error_to_errno(GetLastError()));
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return (zip_int64_t)ret;
|
|
+}
|
|
+
|
|
+
|
|
+static HANDLE
|
|
+win32_named_open(zip_source_file_context_t *ctx, const char *name, bool temporary, PSECURITY_ATTRIBUTES security_attributes) {
|
|
+ zip_win32_file_operations_t *file_ops = (zip_win32_file_operations_t *)ctx->ops_userdata;
|
|
+
|
|
+ DWORD access = GENERIC_READ;
|
|
+ DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
|
+ DWORD creation_disposition = OPEN_EXISTING;
|
|
+ DWORD file_attributes = FILE_ATTRIBUTE_NORMAL;
|
|
+
|
|
+ if (temporary) {
|
|
+ access = GENERIC_READ | GENERIC_WRITE;
|
|
+ share_mode = FILE_SHARE_READ;
|
|
+ creation_disposition = CREATE_NEW;
|
|
+ file_attributes = FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_TEMPORARY;
|
|
+ }
|
|
+
|
|
+ HANDLE h = file_ops->create_file(name, access, share_mode, security_attributes, creation_disposition, file_attributes, NULL);
|
|
+
|
|
+ if (h == INVALID_HANDLE_VALUE) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_OPEN, _zip_win32_error_to_errno(GetLastError()));
|
|
+ }
|
|
+
|
|
+ return h;
|
|
+}
|
|
diff --git a/lib/zip_source_file_win32_utf16.c b/lib/zip_source_file_win32_utf16.c
|
|
new file mode 100644
|
|
index 0000000..3fa0aa1
|
|
--- /dev/null
|
|
+++ b/lib/zip_source_file_win32_utf16.c
|
|
@@ -0,0 +1,108 @@
|
|
+/*
|
|
+ zip_source_file_win32_utf16.c -- source for Windows file opened by UTF-16 name
|
|
+ Copyright (C) 1999-2020 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 "zip_source_file_win32.h"
|
|
+
|
|
+static char *utf16_allocate_tempname(const char *name, size_t extra_chars, size_t *lengthp);
|
|
+static HANDLE __stdcall utf16_create_file(const char *name, DWORD access, DWORD share_mode, PSECURITY_ATTRIBUTES security_attributes, DWORD creation_disposition, DWORD file_attributes, HANDLE template_file);
|
|
+static void utf16_make_tempname(char *buf, size_t len, const char *name, zip_uint32_t i);
|
|
+static char *utf16_strdup(const char *string);
|
|
+
|
|
+zip_win32_file_operations_t ops_utf16 = {
|
|
+ utf16_allocate_tempname,
|
|
+ utf16_create_file,
|
|
+ DeleteFileW,
|
|
+ GetFileAttributesW,
|
|
+ GetFileAttributesExW,
|
|
+ utf16_make_tempname,
|
|
+ MoveFileExW,
|
|
+ SetFileAttributesW,
|
|
+ utf16_strdup
|
|
+};
|
|
+
|
|
+ZIP_EXTERN zip_source_t *
|
|
+zip_source_win32w(zip_t *za, const wchar_t *fname, zip_uint64_t start, zip_int64_t len) {
|
|
+ if (za == NULL)
|
|
+ return NULL;
|
|
+
|
|
+ return zip_source_win32w_create(fname, start, len, &za->error);
|
|
+}
|
|
+
|
|
+
|
|
+ZIP_EXTERN zip_source_t *
|
|
+zip_source_win32w_create(const wchar_t *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {
|
|
+ if (fname == NULL || length < -1) {
|
|
+ zip_error_set(error, ZIP_ER_INVAL, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+
|
|
+ return zip_source_file_common_new((const char *)fname, NULL, start, length, NULL, &_zip_source_file_win32_named_ops, &ops_utf16, error);
|
|
+}
|
|
+
|
|
+
|
|
+static char *
|
|
+utf16_allocate_tempname(const char *name, size_t extra_chars, size_t *lengthp) {
|
|
+ *lengthp = wcslen((const wchar_t *)name) + extra_chars;
|
|
+ return (char *)malloc(*lengthp * sizeof(wchar_t));
|
|
+}
|
|
+
|
|
+
|
|
+static HANDLE __stdcall
|
|
+utf16_create_file(const char *name, DWORD access, DWORD share_mode, PSECURITY_ATTRIBUTES security_attributes, DWORD creation_disposition, DWORD file_attributes, HANDLE template_file) {
|
|
+#ifdef MS_UWP
|
|
+ CREATEFILE2_EXTENDED_PARAMETERS extParams = {0};
|
|
+ extParams.dwFileAttributes = file_attributes;
|
|
+ extParams.dwFileFlags = FILE_FLAG_RANDOM_ACCESS;
|
|
+ extParams.dwSecurityQosFlags = SECURITY_ANONYMOUS;
|
|
+ extParams.dwSize = sizeof(extParams);
|
|
+ extParams.hTemplateFile = template_file;
|
|
+ extParams.lpSecurityAttributes = security_attributes;
|
|
+
|
|
+ return CreateFile2((const wchar_t *)name, access, share_mode, creation_disposition, &extParams);
|
|
+#else
|
|
+ return CreateFileW((const wchar_t *)name, access, share_mode, security_attributes, creation_disposition, file_attributes, template_file);
|
|
+#endif
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+utf16_make_tempname(char *buf, size_t len, const char *name, zip_uint32_t i) {
|
|
+ _snwprintf((wchar_t *)buf, len, L"%s.%08x", (const wchar_t *)name, i);
|
|
+}
|
|
+
|
|
+
|
|
+static char *
|
|
+utf16_strdup(const char *string) {
|
|
+ return (char *)_wcsdup((const wchar_t *)string);
|
|
+}
|
|
diff --git a/lib/zip_source_file_win32_utf8.c b/lib/zip_source_file_win32_utf8.c
|
|
new file mode 100644
|
|
index 0000000..4f258bc
|
|
--- /dev/null
|
|
+++ b/lib/zip_source_file_win32_utf8.c
|
|
@@ -0,0 +1,73 @@
|
|
+/*
|
|
+ zip_source_file_win32_ansi.c -- source for Windows file opened by UTF-8 name
|
|
+ Copyright (C) 1999-2020 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 "zip_source_file_win32.h"
|
|
+
|
|
+ZIP_EXTERN zip_source_t *
|
|
+zip_source_file(zip_t *za, const char *fname, zip_uint64_t start, zip_int64_t len) {
|
|
+ if (za == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return zip_source_file_create(fname, start, len, &za->error);
|
|
+}
|
|
+
|
|
+
|
|
+ZIP_EXTERN zip_source_t *
|
|
+zip_source_file_create(const char *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {
|
|
+ int size;
|
|
+ wchar_t *wfname;
|
|
+ zip_source_t *source;
|
|
+
|
|
+ if (fname == NULL || length < -1) {
|
|
+ zip_error_set(error, ZIP_ER_INVAL, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ /* Convert fname from UTF-8 to Windows-friendly UTF-16. */
|
|
+ size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fname, -1, NULL, 0);
|
|
+ if (size == 0) {
|
|
+ zip_error_set(error, ZIP_ER_INVAL, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+ if ((wfname = (wchar_t *)malloc(sizeof(wchar_t) * size)) == NULL) {
|
|
+ zip_error_set(error, ZIP_ER_MEMORY, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+ MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fname, -1, wfname, size);
|
|
+
|
|
+ source = zip_source_win32w_create(wfname, start, length, error);
|
|
+
|
|
+ free(wfname);
|
|
+ return source;
|
|
+}
|
|
diff --git a/lib/zip_source_filep.c b/lib/zip_source_filep.c
|
|
deleted file mode 100644
|
|
index 9fc9a01..0000000
|
|
--- a/lib/zip_source_filep.c
|
|
+++ /dev/null
|
|
@@ -1,651 +0,0 @@
|
|
-/*
|
|
- zip_source_filep.c -- create data source from FILE *
|
|
- Copyright (C) 1999-2017 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 <stdio.h>
|
|
-#include <stdlib.h>
|
|
-#include <string.h>
|
|
-#include <sys/stat.h>
|
|
-
|
|
-#include "zipint.h"
|
|
-
|
|
-#ifdef HAVE_UNISTD_H
|
|
-#include <unistd.h>
|
|
-#endif
|
|
-
|
|
-#ifdef HAVE_CLONEFILE
|
|
-#include <sys/attr.h>
|
|
-#include <sys/clonefile.h>
|
|
-#define CAN_CLONE
|
|
-#endif
|
|
-#ifdef HAVE_FICLONERANGE
|
|
-#include <linux/fs.h>
|
|
-#include <sys/ioctl.h>
|
|
-#define CAN_CLONE
|
|
-#endif
|
|
-
|
|
-#ifdef _WIN32
|
|
-/* WIN32 needs <fcntl.h> for _O_BINARY */
|
|
-#include <fcntl.h>
|
|
-#endif
|
|
-
|
|
-/* Windows sys/types.h does not provide these */
|
|
-#ifndef S_ISREG
|
|
-#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG)
|
|
-#endif
|
|
-#if defined(S_IXUSR) && defined(S_IRWXG) && defined(S_IRWXO)
|
|
-#define _SAFE_MASK (S_IXUSR | S_IRWXG | S_IRWXO)
|
|
-#elif defined(_S_IWRITE)
|
|
-#define _SAFE_MASK (_S_IWRITE)
|
|
-#else
|
|
-#error do not know safe values for umask, please report this
|
|
-#endif
|
|
-
|
|
-#ifdef _MSC_VER
|
|
-/* MSVC doesn't have mode_t */
|
|
-typedef int mode_t;
|
|
-#endif
|
|
-
|
|
-struct read_file {
|
|
- zip_error_t error; /* last error information */
|
|
- zip_int64_t supports;
|
|
-
|
|
- /* reading */
|
|
- char *fname; /* name of file to read from */
|
|
- FILE *f; /* file to read from */
|
|
- struct zip_stat st; /* stat information passed in */
|
|
- zip_error_t stat_error; /* error returned for stat */
|
|
- zip_uint64_t start; /* start offset of data to read */
|
|
- zip_uint64_t end; /* end offset of data to read relative to start, 0 for up to EOF */
|
|
- zip_uint64_t current; /* current offset relative to start (0 is beginning of part we read) */
|
|
-
|
|
- /* writing */
|
|
- char *tmpname;
|
|
- FILE *fout;
|
|
-};
|
|
-
|
|
-static zip_int64_t read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd);
|
|
-static int create_temp_output(struct read_file *ctx);
|
|
-#ifdef CAN_CLONE
|
|
-static zip_int64_t create_temp_output_cloning(struct read_file *ctx, zip_uint64_t offset);
|
|
-#endif
|
|
-static int _zip_fseek_u(FILE *f, zip_uint64_t offset, int whence, zip_error_t *error);
|
|
-static int _zip_fseek(FILE *f, zip_int64_t offset, int whence, zip_error_t *error);
|
|
-
|
|
-
|
|
-ZIP_EXTERN zip_source_t *
|
|
-zip_source_filep(zip_t *za, FILE *file, zip_uint64_t start, zip_int64_t len) {
|
|
- if (za == NULL)
|
|
- return NULL;
|
|
-
|
|
- return zip_source_filep_create(file, start, len, &za->error);
|
|
-}
|
|
-
|
|
-
|
|
-ZIP_EXTERN zip_source_t *
|
|
-zip_source_filep_create(FILE *file, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {
|
|
- if (file == NULL || length < -1) {
|
|
- zip_error_set(error, ZIP_ER_INVAL, 0);
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- return _zip_source_file_or_p(NULL, file, start, length, NULL, error);
|
|
-}
|
|
-
|
|
-
|
|
-zip_source_t *
|
|
-_zip_source_file_or_p(const char *fname, FILE *file, zip_uint64_t start, zip_int64_t len, const zip_stat_t *st, zip_error_t *error) {
|
|
- struct read_file *ctx;
|
|
- zip_source_t *zs;
|
|
- struct stat sb;
|
|
- bool stat_valid;
|
|
-
|
|
- if (file == NULL && fname == NULL) {
|
|
- zip_error_set(error, ZIP_ER_INVAL, 0);
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- if (len < 0) {
|
|
- len = 0;
|
|
- }
|
|
-
|
|
- if (start > ZIP_INT64_MAX || start + (zip_uint64_t)len < start) {
|
|
- zip_error_set(error, ZIP_ER_INVAL, 0);
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- if ((ctx = (struct read_file *)malloc(sizeof(struct read_file))) == NULL) {
|
|
- zip_error_set(error, ZIP_ER_MEMORY, 0);
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- ctx->fname = NULL;
|
|
- if (fname) {
|
|
- if ((ctx->fname = strdup(fname)) == NULL) {
|
|
- zip_error_set(error, ZIP_ER_MEMORY, 0);
|
|
- free(ctx);
|
|
- return NULL;
|
|
- }
|
|
- }
|
|
- ctx->f = file;
|
|
- ctx->start = start;
|
|
- ctx->end = (zip_uint64_t)len;
|
|
- if (st) {
|
|
- memcpy(&ctx->st, st, sizeof(ctx->st));
|
|
- ctx->st.name = NULL;
|
|
- ctx->st.valid &= ~ZIP_STAT_NAME;
|
|
- }
|
|
- else {
|
|
- zip_stat_init(&ctx->st);
|
|
- }
|
|
-
|
|
- if (ctx->end > 0) {
|
|
- ctx->st.size = ctx->end;
|
|
- ctx->st.valid |= ZIP_STAT_SIZE;
|
|
- }
|
|
-
|
|
- zip_error_init(&ctx->stat_error);
|
|
-
|
|
- ctx->tmpname = NULL;
|
|
- ctx->fout = NULL;
|
|
-
|
|
- zip_error_init(&ctx->error);
|
|
-
|
|
- ctx->supports = ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1);
|
|
-
|
|
- if (ctx->fname) {
|
|
- stat_valid = stat(ctx->fname, &sb) >= 0;
|
|
-
|
|
- if (!stat_valid) {
|
|
- if (ctx->start == 0 && ctx->end == 0) {
|
|
- ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE;
|
|
- }
|
|
- }
|
|
- }
|
|
- else {
|
|
- stat_valid = fstat(fileno(ctx->f), &sb) >= 0;
|
|
- }
|
|
-
|
|
- if (!stat_valid) {
|
|
- zip_error_set(&ctx->stat_error, ZIP_ER_READ, errno);
|
|
- }
|
|
- else {
|
|
- if ((ctx->st.valid & ZIP_STAT_MTIME) == 0) {
|
|
- ctx->st.mtime = sb.st_mtime;
|
|
- ctx->st.valid |= ZIP_STAT_MTIME;
|
|
- }
|
|
- if (S_ISREG(sb.st_mode)) {
|
|
- ctx->supports = ZIP_SOURCE_SUPPORTS_SEEKABLE;
|
|
-
|
|
- if (ctx->start + ctx->end > (zip_uint64_t)sb.st_size) {
|
|
- zip_error_set(error, ZIP_ER_INVAL, 0);
|
|
- free(ctx->fname);
|
|
- free(ctx);
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- if (ctx->end == 0) {
|
|
- ctx->st.size = (zip_uint64_t)sb.st_size - ctx->start;
|
|
- ctx->st.valid |= ZIP_STAT_SIZE;
|
|
-
|
|
- if (ctx->fname && start == 0) {
|
|
- ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE;
|
|
- }
|
|
- }
|
|
- }
|
|
- }
|
|
-
|
|
-#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);
|
|
- }
|
|
-#endif
|
|
-
|
|
- if ((zs = zip_source_function_create(read_file, ctx, error)) == NULL) {
|
|
- free(ctx->fname);
|
|
- free(ctx);
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- return zs;
|
|
-}
|
|
-
|
|
-
|
|
-static int
|
|
-create_temp_output(struct read_file *ctx) {
|
|
- char *temp;
|
|
- int tfd;
|
|
- mode_t mask;
|
|
- FILE *tfp;
|
|
-
|
|
- if ((temp = (char *)malloc(strlen(ctx->fname) + 8)) == NULL) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
|
|
- return -1;
|
|
- }
|
|
- sprintf(temp, "%s.XXXXXX", ctx->fname);
|
|
-
|
|
- mask = umask(_SAFE_MASK);
|
|
- if ((tfd = mkstemp(temp)) == -1) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
|
|
- umask(mask);
|
|
- free(temp);
|
|
- return -1;
|
|
- }
|
|
- umask(mask);
|
|
-
|
|
- if ((tfp = fdopen(tfd, "r+b")) == NULL) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
|
|
- close(tfd);
|
|
- (void)remove(temp);
|
|
- free(temp);
|
|
- return -1;
|
|
- }
|
|
-
|
|
-#ifdef _WIN32
|
|
- /*
|
|
- According to Pierre Joye, Windows in some environments per
|
|
- default creates text files, so force binary mode.
|
|
- */
|
|
- _setmode(_fileno(tfp), _O_BINARY);
|
|
-#endif
|
|
-
|
|
- ctx->fout = tfp;
|
|
- ctx->tmpname = temp;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-#ifdef CAN_CLONE
|
|
-zip_int64_t static create_temp_output_cloning(struct read_file *ctx, zip_uint64_t offset) {
|
|
- char *temp;
|
|
- FILE *tfp;
|
|
-
|
|
- if (offset > ZIP_OFF_MAX) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_SEEK, E2BIG);
|
|
- return -1;
|
|
- }
|
|
-
|
|
- if ((temp = (char *)malloc(strlen(ctx->fname) + 8)) == NULL) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
|
|
- return -1;
|
|
- }
|
|
- sprintf(temp, "%s.XXXXXX", ctx->fname);
|
|
-
|
|
-#ifdef HAVE_CLONEFILE
|
|
-#ifndef __clang_analyzer__
|
|
- /* we can't use mkstemp, since clonefile insists on creating the file */
|
|
- if (mktemp(temp) == NULL) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
|
|
- free(temp);
|
|
- return -1;
|
|
- }
|
|
-#endif
|
|
-
|
|
- if (clonefile(ctx->fname, temp, 0) < 0) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
|
|
- free(temp);
|
|
- return -1;
|
|
- }
|
|
- if ((tfp = fopen(temp, "r+b")) == NULL) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
|
|
- (void)remove(temp);
|
|
- free(temp);
|
|
- return -1;
|
|
- }
|
|
-#else
|
|
- {
|
|
- int fd;
|
|
- struct file_clone_range range;
|
|
- struct stat st;
|
|
-
|
|
- if (fstat(fileno(ctx->f), &st) < 0) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
|
|
- return -1;
|
|
- }
|
|
-
|
|
- if ((fd = mkstemp(temp)) < 0) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
|
|
- free(temp);
|
|
- return -1;
|
|
- }
|
|
-
|
|
- range.src_fd = fileno(ctx->f);
|
|
- range.src_offset = 0;
|
|
- range.src_length = ((offset + st.st_blksize - 1) / st.st_blksize) * st.st_blksize;
|
|
- if (range.src_length > st.st_size) {
|
|
- range.src_length = 0;
|
|
- }
|
|
- range.dest_offset = 0;
|
|
- if (ioctl(fd, FICLONERANGE, &range) < 0) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
|
|
- (void)close(fd);
|
|
- (void)remove(temp);
|
|
- free(temp);
|
|
- return -1;
|
|
- }
|
|
-
|
|
- if ((tfp = fdopen(fd, "r+b")) == NULL) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
|
|
- (void)close(fd);
|
|
- (void)remove(temp);
|
|
- free(temp);
|
|
- return -1;
|
|
- }
|
|
- }
|
|
-#endif
|
|
-
|
|
- if (ftruncate(fileno(tfp), (off_t)offset) < 0) {
|
|
- (void)fclose(tfp);
|
|
- (void)remove(temp);
|
|
- free(temp);
|
|
- return -1;
|
|
- }
|
|
- if (fseeko(tfp, (off_t)offset, SEEK_SET) < 0) {
|
|
- (void)fclose(tfp);
|
|
- (void)remove(temp);
|
|
- free(temp);
|
|
- zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
|
|
- }
|
|
-
|
|
- ctx->fout = tfp;
|
|
- ctx->tmpname = temp;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-#endif
|
|
-
|
|
-
|
|
-static zip_int64_t
|
|
-read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
|
|
- struct read_file *ctx;
|
|
- char *buf;
|
|
- zip_uint64_t n;
|
|
- size_t i;
|
|
-
|
|
- ctx = (struct read_file *)state;
|
|
- buf = (char *)data;
|
|
-
|
|
- switch (cmd) {
|
|
- case ZIP_SOURCE_BEGIN_WRITE:
|
|
- if (ctx->fname == NULL) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
|
|
- return -1;
|
|
- }
|
|
- return create_temp_output(ctx);
|
|
-
|
|
-#ifdef CAN_CLONE
|
|
- case ZIP_SOURCE_BEGIN_WRITE_CLONING:
|
|
- if (ctx->fname == NULL) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
|
|
- return -1;
|
|
- }
|
|
- return create_temp_output_cloning(ctx, len);
|
|
-#endif
|
|
-
|
|
- case ZIP_SOURCE_COMMIT_WRITE: {
|
|
- mode_t mask;
|
|
-
|
|
- if (fclose(ctx->fout) < 0) {
|
|
- ctx->fout = NULL;
|
|
- zip_error_set(&ctx->error, ZIP_ER_WRITE, errno);
|
|
- }
|
|
- ctx->fout = NULL;
|
|
- if (rename(ctx->tmpname, ctx->fname) < 0) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_RENAME, errno);
|
|
- return -1;
|
|
- }
|
|
- mask = umask(022);
|
|
- umask(mask);
|
|
- /* not much we can do if chmod fails except make the whole commit fail */
|
|
- (void)chmod(ctx->fname, 0666 & ~mask);
|
|
- free(ctx->tmpname);
|
|
- ctx->tmpname = NULL;
|
|
- 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);
|
|
-
|
|
- case ZIP_SOURCE_FREE:
|
|
- free(ctx->fname);
|
|
- free(ctx->tmpname);
|
|
- if (ctx->f)
|
|
- fclose(ctx->f);
|
|
- free(ctx);
|
|
- return 0;
|
|
-
|
|
- case ZIP_SOURCE_OPEN:
|
|
- if (ctx->fname) {
|
|
- if ((ctx->f = fopen(ctx->fname, "rb")) == NULL) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_OPEN, errno);
|
|
- return -1;
|
|
- }
|
|
- }
|
|
-
|
|
- if (ctx->start > 0) {
|
|
- if (_zip_fseek_u(ctx->f, ctx->start, SEEK_SET, &ctx->error) < 0) {
|
|
- /* TODO: skip by reading */
|
|
- return -1;
|
|
- }
|
|
- }
|
|
- ctx->current = 0;
|
|
- return 0;
|
|
-
|
|
- case ZIP_SOURCE_READ:
|
|
- if (ctx->end > 0) {
|
|
- n = ctx->end - ctx->current;
|
|
- if (n > len) {
|
|
- n = len;
|
|
- }
|
|
- }
|
|
- else {
|
|
- n = len;
|
|
- }
|
|
-
|
|
- if (n > SIZE_MAX)
|
|
- n = SIZE_MAX;
|
|
-
|
|
- if ((i = fread(buf, 1, (size_t)n, ctx->f)) == 0) {
|
|
- if (ferror(ctx->f)) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_READ, errno);
|
|
- return -1;
|
|
- }
|
|
- }
|
|
- ctx->current += i;
|
|
-
|
|
- return (zip_int64_t)i;
|
|
-
|
|
- case ZIP_SOURCE_REMOVE:
|
|
- if (remove(ctx->fname) < 0) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_REMOVE, errno);
|
|
- return -1;
|
|
- }
|
|
- return 0;
|
|
-
|
|
- case ZIP_SOURCE_ROLLBACK_WRITE:
|
|
- if (ctx->fout) {
|
|
- fclose(ctx->fout);
|
|
- ctx->fout = NULL;
|
|
- }
|
|
- (void)remove(ctx->tmpname);
|
|
- free(ctx->tmpname);
|
|
- ctx->tmpname = NULL;
|
|
- return 0;
|
|
-
|
|
- case ZIP_SOURCE_SEEK: {
|
|
- zip_int64_t new_current;
|
|
- int need_seek;
|
|
- zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);
|
|
-
|
|
- if (args == NULL)
|
|
- return -1;
|
|
-
|
|
- need_seek = 1;
|
|
-
|
|
- switch (args->whence) {
|
|
- case SEEK_SET:
|
|
- new_current = args->offset;
|
|
- break;
|
|
-
|
|
- case SEEK_END:
|
|
- if (ctx->end == 0) {
|
|
- if (_zip_fseek(ctx->f, args->offset, SEEK_END, &ctx->error) < 0) {
|
|
- return -1;
|
|
- }
|
|
- if ((new_current = ftello(ctx->f)) < 0) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_SEEK, errno);
|
|
- return -1;
|
|
- }
|
|
- new_current -= (zip_int64_t)ctx->start;
|
|
- need_seek = 0;
|
|
- }
|
|
- else {
|
|
- new_current = (zip_int64_t)ctx->end + args->offset;
|
|
- }
|
|
- break;
|
|
-
|
|
- case SEEK_CUR:
|
|
- new_current = (zip_int64_t)ctx->current + args->offset;
|
|
- break;
|
|
-
|
|
- default:
|
|
- zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
|
|
- return -1;
|
|
- }
|
|
-
|
|
- if (new_current < 0 || (ctx->end != 0 && (zip_uint64_t)new_current > ctx->end) || (zip_uint64_t)new_current + ctx->start < ctx->start) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
|
|
- return -1;
|
|
- }
|
|
-
|
|
- ctx->current = (zip_uint64_t)new_current;
|
|
-
|
|
- if (need_seek) {
|
|
- if (_zip_fseek_u(ctx->f, ctx->current + ctx->start, SEEK_SET, &ctx->error) < 0) {
|
|
- return -1;
|
|
- }
|
|
- }
|
|
- return 0;
|
|
- }
|
|
-
|
|
- case ZIP_SOURCE_SEEK_WRITE: {
|
|
- zip_source_args_seek_t *args;
|
|
-
|
|
- args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);
|
|
- if (args == NULL) {
|
|
- return -1;
|
|
- }
|
|
-
|
|
- if (_zip_fseek(ctx->fout, args->offset, args->whence, &ctx->error) < 0) {
|
|
- return -1;
|
|
- }
|
|
- return 0;
|
|
- }
|
|
-
|
|
- case ZIP_SOURCE_STAT: {
|
|
- if (len < sizeof(ctx->st))
|
|
- return -1;
|
|
-
|
|
- if (zip_error_code_zip(&ctx->stat_error) != 0) {
|
|
- zip_error_set(&ctx->error, zip_error_code_zip(&ctx->stat_error), zip_error_code_system(&ctx->stat_error));
|
|
- return -1;
|
|
- }
|
|
-
|
|
- memcpy(data, &ctx->st, sizeof(ctx->st));
|
|
- return sizeof(ctx->st);
|
|
- }
|
|
-
|
|
- case ZIP_SOURCE_SUPPORTS:
|
|
- return ctx->supports;
|
|
-
|
|
- case ZIP_SOURCE_TELL:
|
|
- return (zip_int64_t)ctx->current;
|
|
-
|
|
- case ZIP_SOURCE_TELL_WRITE: {
|
|
- off_t ret = ftello(ctx->fout);
|
|
-
|
|
- if (ret < 0) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_TELL, errno);
|
|
- return -1;
|
|
- }
|
|
- return ret;
|
|
- }
|
|
-
|
|
- case ZIP_SOURCE_WRITE: {
|
|
- size_t ret;
|
|
-
|
|
- clearerr(ctx->fout);
|
|
- ret = fwrite(data, 1, len, ctx->fout);
|
|
- if (ret != len || ferror(ctx->fout)) {
|
|
- zip_error_set(&ctx->error, ZIP_ER_WRITE, errno);
|
|
- return -1;
|
|
- }
|
|
-
|
|
- return (zip_int64_t)ret;
|
|
- }
|
|
-
|
|
- default:
|
|
- zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
|
|
- return -1;
|
|
- }
|
|
-}
|
|
-
|
|
-
|
|
-static int
|
|
-_zip_fseek_u(FILE *f, zip_uint64_t offset, int whence, zip_error_t *error) {
|
|
- if (offset > ZIP_INT64_MAX) {
|
|
- zip_error_set(error, ZIP_ER_SEEK, EOVERFLOW);
|
|
- return -1;
|
|
- }
|
|
- return _zip_fseek(f, (zip_int64_t)offset, whence, error);
|
|
-}
|
|
-
|
|
-
|
|
-static int
|
|
-_zip_fseek(FILE *f, zip_int64_t offset, int whence, zip_error_t *error) {
|
|
- if (offset > ZIP_FSEEK_MAX || offset < ZIP_FSEEK_MIN) {
|
|
- zip_error_set(error, ZIP_ER_SEEK, EOVERFLOW);
|
|
- return -1;
|
|
- }
|
|
- if (fseeko(f, (off_t)offset, whence) < 0) {
|
|
- zip_error_set(error, ZIP_ER_SEEK, errno);
|
|
- return -1;
|
|
- }
|
|
- return 0;
|
|
-}
|
|
diff --git a/lib/zip_source_get_file_attributes.c b/lib/zip_source_get_file_attributes.c
|
|
new file mode 100644
|
|
index 0000000..acbede1
|
|
--- /dev/null
|
|
+++ b/lib/zip_source_get_file_attributes.c
|
|
@@ -0,0 +1,104 @@
|
|
+/*
|
|
+ zip_source_get_file_attributes.c -- get attributes for file from source
|
|
+ Copyright (C) 2020 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"
|
|
+
|
|
+ZIP_EXTERN void
|
|
+zip_file_attributes_init(zip_file_attributes_t *attributes) {
|
|
+ attributes->valid = 0;
|
|
+ attributes->version = 1;
|
|
+}
|
|
+
|
|
+int
|
|
+zip_source_get_file_attributes(zip_source_t *src, zip_file_attributes_t *attributes) {
|
|
+ if (src->source_closed) {
|
|
+ return -1;
|
|
+ }
|
|
+ if (attributes == NULL) {
|
|
+ zip_error_set(&src->error, ZIP_ER_INVAL, 0);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ zip_file_attributes_init(attributes);
|
|
+
|
|
+ if (src->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_GET_FILE_ATTRIBUTES)) {
|
|
+ if (_zip_source_call(src, attributes, sizeof(*attributes), ZIP_SOURCE_GET_FILE_ATTRIBUTES) < 0) {
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (ZIP_SOURCE_IS_LAYERED(src)) {
|
|
+ zip_file_attributes_t lower_attributes;
|
|
+
|
|
+ if (zip_source_get_file_attributes(src->src, &lower_attributes) < 0) {
|
|
+ _zip_error_set_from_source(&src->error, src->src);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_HOST_SYSTEM) && (attributes->valid & ZIP_FILE_ATTRIBUTES_HOST_SYSTEM) == 0) {
|
|
+ attributes->host_system = lower_attributes.host_system;
|
|
+ attributes->valid |= ZIP_FILE_ATTRIBUTES_HOST_SYSTEM;
|
|
+ }
|
|
+ if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_ASCII) && (attributes->valid & ZIP_FILE_ATTRIBUTES_ASCII) == 0) {
|
|
+ attributes->ascii = lower_attributes.ascii;
|
|
+ attributes->valid |= ZIP_FILE_ATTRIBUTES_ASCII;
|
|
+ }
|
|
+ if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_VERSION_NEEDED)) {
|
|
+ if (attributes->valid & ZIP_FILE_ATTRIBUTES_VERSION_NEEDED) {
|
|
+ attributes->version_needed = ZIP_MAX(lower_attributes.version_needed, attributes->version_needed);
|
|
+ }
|
|
+ else {
|
|
+ attributes->version_needed = lower_attributes.version_needed;
|
|
+ attributes->valid |= ZIP_FILE_ATTRIBUTES_VERSION_NEEDED;
|
|
+ }
|
|
+ }
|
|
+ if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES) && (attributes->valid & ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES) == 0) {
|
|
+ attributes->external_file_attributes = lower_attributes.external_file_attributes;
|
|
+ attributes->valid |= ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES;
|
|
+ }
|
|
+ if ((lower_attributes.valid & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS)) {
|
|
+ if (attributes->valid & ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS) {
|
|
+ attributes->general_purpose_bit_flags &= ~lower_attributes.general_purpose_bit_mask;
|
|
+ attributes->general_purpose_bit_flags |= lower_attributes.general_purpose_bit_flags & lower_attributes.general_purpose_bit_mask;
|
|
+ attributes->general_purpose_bit_mask |= lower_attributes.general_purpose_bit_mask;
|
|
+ }
|
|
+ else {
|
|
+ attributes->valid |= ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS;
|
|
+ attributes->general_purpose_bit_flags = lower_attributes.general_purpose_bit_flags;
|
|
+ attributes->general_purpose_bit_mask = lower_attributes.general_purpose_bit_mask;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/lib/zip_source_pkware_decode.c b/lib/zip_source_pkware_decode.c
|
|
new file mode 100644
|
|
index 0000000..d5489a5
|
|
--- /dev/null
|
|
+++ b/lib/zip_source_pkware_decode.c
|
|
@@ -0,0 +1,221 @@
|
|
+/*
|
|
+ zip_source_pkware_decode.c -- Traditional PKWARE decryption routines
|
|
+ Copyright (C) 2009-2020 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 <stdlib.h>
|
|
+#include <string.h>
|
|
+
|
|
+#include "zipint.h"
|
|
+
|
|
+struct trad_pkware {
|
|
+ char *password;
|
|
+ zip_pkware_keys_t keys;
|
|
+ zip_error_t error;
|
|
+};
|
|
+
|
|
+
|
|
+static int decrypt_header(zip_source_t *, struct trad_pkware *);
|
|
+static zip_int64_t pkware_decrypt(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t);
|
|
+static struct trad_pkware *trad_pkware_new(const char *password, zip_error_t *error);
|
|
+static void trad_pkware_free(struct trad_pkware *);
|
|
+
|
|
+
|
|
+zip_source_t *
|
|
+zip_source_pkware_decode(zip_t *za, zip_source_t *src, zip_uint16_t em, int flags, const char *password) {
|
|
+ struct trad_pkware *ctx;
|
|
+ zip_source_t *s2;
|
|
+
|
|
+ if (password == NULL || src == NULL || em != ZIP_EM_TRAD_PKWARE) {
|
|
+ zip_error_set(&za->error, ZIP_ER_INVAL, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+ if (flags & ZIP_CODEC_ENCODE) {
|
|
+ zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if ((ctx = trad_pkware_new(password, &za->error)) == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if ((s2 = zip_source_layered(za, src, pkware_decrypt, ctx)) == NULL) {
|
|
+ trad_pkware_free(ctx);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return s2;
|
|
+}
|
|
+
|
|
+
|
|
+static int
|
|
+decrypt_header(zip_source_t *src, struct trad_pkware *ctx) {
|
|
+ zip_uint8_t header[ZIP_CRYPTO_PKWARE_HEADERLEN];
|
|
+ struct zip_stat st;
|
|
+ zip_int64_t n;
|
|
+
|
|
+ if ((n = zip_source_read(src, header, ZIP_CRYPTO_PKWARE_HEADERLEN)) < 0) {
|
|
+ _zip_error_set_from_source(&ctx->error, src);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (n != ZIP_CRYPTO_PKWARE_HEADERLEN) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ _zip_pkware_decrypt(&ctx->keys, header, header, ZIP_CRYPTO_PKWARE_HEADERLEN);
|
|
+
|
|
+ if (zip_source_stat(src, &st)) {
|
|
+ /* stat failed, skip password validation */
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ /* password verification - two ways:
|
|
+ * mtime - InfoZIP way, to avoid computing complete CRC before encrypting data
|
|
+ * CRC - old PKWare way
|
|
+ */
|
|
+
|
|
+ bool ok = false;
|
|
+
|
|
+ if (st.valid & ZIP_STAT_MTIME) {
|
|
+ unsigned short dostime, dosdate;
|
|
+ _zip_u2d_time(st.mtime, &dostime, &dosdate);
|
|
+ if (header[ZIP_CRYPTO_PKWARE_HEADERLEN - 1] == dostime >> 8) {
|
|
+ ok = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (st.valid & ZIP_STAT_CRC) {
|
|
+ if (header[ZIP_CRYPTO_PKWARE_HEADERLEN - 1] == st.crc >> 24) {
|
|
+ ok = true;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!ok && ((st.valid & (ZIP_STAT_MTIME | ZIP_STAT_CRC)) != 0)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_WRONGPASSWD, 0);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static zip_int64_t
|
|
+pkware_decrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
|
|
+ struct trad_pkware *ctx;
|
|
+ zip_int64_t n;
|
|
+
|
|
+ ctx = (struct trad_pkware *)ud;
|
|
+
|
|
+ switch (cmd) {
|
|
+ case ZIP_SOURCE_OPEN:
|
|
+ _zip_pkware_keys_reset(&ctx->keys);
|
|
+ _zip_pkware_decrypt(&ctx->keys, NULL, (const zip_uint8_t *)ctx->password, strlen(ctx->password));
|
|
+ if (decrypt_header(src, ctx) < 0) {
|
|
+ return -1;
|
|
+ }
|
|
+ return 0;
|
|
+
|
|
+ case ZIP_SOURCE_READ:
|
|
+ if ((n = zip_source_read(src, data, len)) < 0) {
|
|
+ _zip_error_set_from_source(&ctx->error, src);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ _zip_pkware_decrypt(&ctx->keys, (zip_uint8_t *)data, (zip_uint8_t *)data, (zip_uint64_t)n);
|
|
+ return n;
|
|
+
|
|
+ case ZIP_SOURCE_CLOSE:
|
|
+ return 0;
|
|
+
|
|
+ case ZIP_SOURCE_STAT: {
|
|
+ zip_stat_t *st;
|
|
+
|
|
+ st = (zip_stat_t *)data;
|
|
+
|
|
+ st->encryption_method = ZIP_EM_NONE;
|
|
+ st->valid |= ZIP_STAT_ENCRYPTION_METHOD;
|
|
+ if (st->valid & ZIP_STAT_COMP_SIZE) {
|
|
+ st->comp_size -= ZIP_CRYPTO_PKWARE_HEADERLEN;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ case ZIP_SOURCE_SUPPORTS:
|
|
+ return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, -1);
|
|
+
|
|
+ case ZIP_SOURCE_ERROR:
|
|
+ return zip_error_to_data(&ctx->error, data, len);
|
|
+
|
|
+ case ZIP_SOURCE_FREE:
|
|
+ trad_pkware_free(ctx);
|
|
+ return 0;
|
|
+
|
|
+ default:
|
|
+ zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
|
|
+ return -1;
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+static struct trad_pkware *
|
|
+trad_pkware_new(const char *password, zip_error_t *error) {
|
|
+ struct trad_pkware *ctx;
|
|
+
|
|
+ if ((ctx = (struct trad_pkware *)malloc(sizeof(*ctx))) == NULL) {
|
|
+ zip_error_set(error, ZIP_ER_MEMORY, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if ((ctx->password = strdup(password)) == NULL) {
|
|
+ zip_error_set(error, ZIP_ER_MEMORY, 0);
|
|
+ free(ctx);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ zip_error_init(&ctx->error);
|
|
+
|
|
+ return ctx;
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+trad_pkware_free(struct trad_pkware *ctx) {
|
|
+ if (ctx == NULL) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ free(ctx->password);
|
|
+ free(ctx);
|
|
+}
|
|
diff --git a/lib/zip_source_pkware_encode.c b/lib/zip_source_pkware_encode.c
|
|
new file mode 100644
|
|
index 0000000..1e8f42c
|
|
--- /dev/null
|
|
+++ b/lib/zip_source_pkware_encode.c
|
|
@@ -0,0 +1,249 @@
|
|
+/*
|
|
+ zip_source_pkware_encode.c -- Traditional PKWARE encryption routines
|
|
+ Copyright (C) 2009-2020 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 <stdlib.h>
|
|
+#include <string.h>
|
|
+
|
|
+#include "zipint.h"
|
|
+
|
|
+struct trad_pkware {
|
|
+ char *password;
|
|
+ zip_pkware_keys_t keys;
|
|
+ zip_buffer_t *buffer;
|
|
+ bool eof;
|
|
+ zip_error_t error;
|
|
+};
|
|
+
|
|
+
|
|
+static int encrypt_header(zip_source_t *, struct trad_pkware *);
|
|
+static zip_int64_t pkware_encrypt(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t);
|
|
+static void trad_pkware_free(struct trad_pkware *);
|
|
+static struct trad_pkware *trad_pkware_new(const char *password, zip_error_t *error);
|
|
+
|
|
+
|
|
+zip_source_t *
|
|
+zip_source_pkware_encode(zip_t *za, zip_source_t *src, zip_uint16_t em, int flags, const char *password) {
|
|
+ struct trad_pkware *ctx;
|
|
+ zip_source_t *s2;
|
|
+
|
|
+ if (password == NULL || src == NULL || em != ZIP_EM_TRAD_PKWARE) {
|
|
+ zip_error_set(&za->error, ZIP_ER_INVAL, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+ if (!(flags & ZIP_CODEC_ENCODE)) {
|
|
+ zip_error_set(&za->error, ZIP_ER_ENCRNOTSUPP, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if ((ctx = trad_pkware_new(password, &za->error)) == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if ((s2 = zip_source_layered(za, src, pkware_encrypt, ctx)) == NULL) {
|
|
+ trad_pkware_free(ctx);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return s2;
|
|
+}
|
|
+
|
|
+
|
|
+static int
|
|
+encrypt_header(zip_source_t *src, struct trad_pkware *ctx) {
|
|
+ struct zip_stat st;
|
|
+ unsigned short dostime, dosdate;
|
|
+ zip_uint8_t *header;
|
|
+
|
|
+ if (zip_source_stat(src, &st) != 0) {
|
|
+ _zip_error_set_from_source(&ctx->error, src);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ _zip_u2d_time(st.mtime, &dostime, &dosdate);
|
|
+
|
|
+ if ((ctx->buffer = _zip_buffer_new(NULL, ZIP_CRYPTO_PKWARE_HEADERLEN)) == NULL) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ header = _zip_buffer_data(ctx->buffer);
|
|
+
|
|
+ /* generate header from random bytes and mtime
|
|
+ see appnote.iz, XIII. Decryption, Step 2, last paragraph */
|
|
+ if (!zip_secure_random(header, ZIP_CRYPTO_PKWARE_HEADERLEN - 1)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
|
|
+ _zip_buffer_free(ctx->buffer);
|
|
+ ctx->buffer = NULL;
|
|
+ return -1;
|
|
+ }
|
|
+ header[ZIP_CRYPTO_PKWARE_HEADERLEN - 1] = (zip_uint8_t)((dostime >> 8) & 0xff);
|
|
+
|
|
+ _zip_pkware_encrypt(&ctx->keys, header, header, ZIP_CRYPTO_PKWARE_HEADERLEN);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static zip_int64_t
|
|
+pkware_encrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t length, zip_source_cmd_t cmd) {
|
|
+ struct trad_pkware *ctx;
|
|
+ zip_int64_t n;
|
|
+ zip_uint64_t buffer_n;
|
|
+
|
|
+ ctx = (struct trad_pkware *)ud;
|
|
+
|
|
+ switch (cmd) {
|
|
+ case ZIP_SOURCE_OPEN:
|
|
+ ctx->eof = false;
|
|
+
|
|
+ /* initialize keys */
|
|
+ _zip_pkware_keys_reset(&ctx->keys);
|
|
+ _zip_pkware_encrypt(&ctx->keys, NULL, (const zip_uint8_t *)ctx->password, strlen(ctx->password));
|
|
+
|
|
+ if (encrypt_header(src, ctx) < 0) {
|
|
+ return -1;
|
|
+ }
|
|
+ return 0;
|
|
+
|
|
+ case ZIP_SOURCE_READ:
|
|
+ buffer_n = 0;
|
|
+
|
|
+ if (ctx->buffer) {
|
|
+ /* write header values to data */
|
|
+ buffer_n = _zip_buffer_read(ctx->buffer, data, length);
|
|
+ data = (zip_uint8_t *)data + buffer_n;
|
|
+ length -= buffer_n;
|
|
+
|
|
+ if (_zip_buffer_eof(ctx->buffer)) {
|
|
+ _zip_buffer_free(ctx->buffer);
|
|
+ ctx->buffer = NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (ctx->eof) {
|
|
+ return (zip_int64_t)buffer_n;
|
|
+ }
|
|
+
|
|
+ if ((n = zip_source_read(src, data, length)) < 0) {
|
|
+ _zip_error_set_from_source(&ctx->error, src);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ _zip_pkware_encrypt(&ctx->keys, (zip_uint8_t *)data, (zip_uint8_t *)data, (zip_uint64_t)n);
|
|
+
|
|
+ if ((zip_uint64_t)n < length) {
|
|
+ ctx->eof = true;
|
|
+ }
|
|
+
|
|
+ return (zip_int64_t)buffer_n + n;
|
|
+
|
|
+ case ZIP_SOURCE_CLOSE:
|
|
+ _zip_buffer_free(ctx->buffer);
|
|
+ ctx->buffer = NULL;
|
|
+ return 0;
|
|
+
|
|
+ case ZIP_SOURCE_STAT: {
|
|
+ zip_stat_t *st;
|
|
+
|
|
+ st = (zip_stat_t *)data;
|
|
+ st->encryption_method = ZIP_EM_TRAD_PKWARE;
|
|
+ st->valid |= ZIP_STAT_ENCRYPTION_METHOD;
|
|
+ if (st->valid & ZIP_STAT_COMP_SIZE) {
|
|
+ st->comp_size += ZIP_CRYPTO_PKWARE_HEADERLEN;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ case ZIP_SOURCE_GET_FILE_ATTRIBUTES: {
|
|
+ zip_file_attributes_t *attributes = (zip_file_attributes_t *)data;
|
|
+ if (length < sizeof(*attributes)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
|
|
+ return -1;
|
|
+ }
|
|
+ attributes->valid |= ZIP_FILE_ATTRIBUTES_VERSION_NEEDED;
|
|
+ attributes->version_needed = 20;
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ case ZIP_SOURCE_SUPPORTS:
|
|
+ return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_GET_FILE_ATTRIBUTES, -1);
|
|
+
|
|
+ case ZIP_SOURCE_ERROR:
|
|
+ return zip_error_to_data(&ctx->error, data, length);
|
|
+
|
|
+ case ZIP_SOURCE_FREE:
|
|
+ trad_pkware_free(ctx);
|
|
+ return 0;
|
|
+
|
|
+ default:
|
|
+ zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
|
|
+ return -1;
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+static struct trad_pkware *
|
|
+trad_pkware_new(const char *password, zip_error_t *error) {
|
|
+ struct trad_pkware *ctx;
|
|
+
|
|
+ if ((ctx = (struct trad_pkware *)malloc(sizeof(*ctx))) == NULL) {
|
|
+ zip_error_set(error, ZIP_ER_MEMORY, 0);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ if ((ctx->password = strdup(password)) == NULL) {
|
|
+ zip_error_set(error, ZIP_ER_MEMORY, 0);
|
|
+ free(ctx);
|
|
+ return NULL;
|
|
+ }
|
|
+ ctx->buffer = NULL;
|
|
+ zip_error_init(&ctx->error);
|
|
+
|
|
+ return ctx;
|
|
+}
|
|
+
|
|
+
|
|
+static void
|
|
+trad_pkware_free(struct trad_pkware *ctx) {
|
|
+ if (ctx == NULL) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ free(ctx->password);
|
|
+ _zip_buffer_free(ctx->buffer);
|
|
+ zip_error_fini(&ctx->error);
|
|
+ free(ctx);
|
|
+}
|
|
diff --git a/lib/zip_source_seek.c b/lib/zip_source_seek.c
|
|
index aed53b8..4a71bfb 100644
|
|
--- a/lib/zip_source_seek.c
|
|
+++ b/lib/zip_source_seek.c
|
|
@@ -50,7 +50,12 @@ zip_source_seek(zip_source_t *src, zip_int64_t offset, int whence) {
|
|
args.offset = offset;
|
|
args.whence = whence;
|
|
|
|
- return (_zip_source_call(src, &args, sizeof(args), ZIP_SOURCE_SEEK) < 0 ? -1 : 0);
|
|
+ if (_zip_source_call(src, &args, sizeof(args), ZIP_SOURCE_SEEK) < 0) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ src->eof = 0;
|
|
+ return 0;
|
|
}
|
|
|
|
|
|
diff --git a/lib/zip_source_supports.c b/lib/zip_source_supports.c
|
|
index a47f293..1d3ceba 100644
|
|
--- a/lib/zip_source_supports.c
|
|
+++ b/lib/zip_source_supports.c
|
|
@@ -38,7 +38,7 @@
|
|
|
|
|
|
zip_int64_t
|
|
-zip_source_supports(zip_source_t *src) {
|
|
+ zip_source_supports(zip_source_t *src) {
|
|
return src->supports;
|
|
}
|
|
|
|
diff --git a/lib/zip_source_window.c b/lib/zip_source_window.c
|
|
index f4701a0..b65dfda 100644
|
|
--- a/lib/zip_source_window.c
|
|
+++ b/lib/zip_source_window.c
|
|
@@ -48,7 +48,7 @@ struct window {
|
|
zip_uint64_t offset; /* offset in src for next read */
|
|
|
|
zip_stat_t stat;
|
|
- zip_int8_t compression_flags;
|
|
+ zip_file_attributes_t attributes;
|
|
zip_error_t error;
|
|
zip_int64_t supports;
|
|
bool needs_seek;
|
|
@@ -64,7 +64,7 @@ zip_source_window(zip_t *za, zip_source_t *src, zip_uint64_t start, zip_uint64_t
|
|
|
|
|
|
zip_source_t *
|
|
-_zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_uint64_t length, zip_stat_t *st, zip_int8_t compression_flags, zip_t *source_archive, zip_uint64_t source_index, zip_error_t *error) {
|
|
+_zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_uint64_t length, zip_stat_t *st, zip_file_attributes_t *attributes, zip_t *source_archive, zip_uint64_t source_index, zip_error_t *error) {
|
|
struct window *ctx;
|
|
|
|
if (src == NULL || start + length < start || (source_archive == NULL && source_index != 0)) {
|
|
@@ -80,11 +80,16 @@ _zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_uint64_t lengt
|
|
ctx->start = start;
|
|
ctx->end = start + length;
|
|
zip_stat_init(&ctx->stat);
|
|
- ctx->compression_flags = compression_flags;
|
|
+ if (attributes != NULL) {
|
|
+ memcpy(&ctx->attributes, attributes, sizeof(ctx->attributes));
|
|
+ }
|
|
+ else {
|
|
+ zip_file_attributes_init(&ctx->attributes);
|
|
+ }
|
|
ctx->source_archive = source_archive;
|
|
ctx->source_index = source_index;
|
|
zip_error_init(&ctx->error);
|
|
- ctx->supports = (zip_source_supports(src) & ZIP_SOURCE_SUPPORTS_SEEKABLE) | (zip_source_make_command_bitmap(ZIP_SOURCE_GET_COMPRESSION_FLAGS, ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1));
|
|
+ ctx->supports = (zip_source_supports(src) & ZIP_SOURCE_SUPPORTS_SEEKABLE) | (zip_source_make_command_bitmap(ZIP_SOURCE_GET_FILE_ATTRIBUTES, ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1));
|
|
ctx->needs_seek = (ctx->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK)) ? true : false;
|
|
|
|
if (st) {
|
|
@@ -121,7 +126,6 @@ window_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_sou
|
|
struct window *ctx;
|
|
zip_int64_t ret;
|
|
zip_uint64_t n, i;
|
|
- char b[8192];
|
|
|
|
ctx = (struct window *)_ctx;
|
|
|
|
@@ -154,18 +158,30 @@ window_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_sou
|
|
}
|
|
|
|
if (!ctx->needs_seek) {
|
|
+ DEFINE_BYTE_ARRAY(b, BUFSIZE);
|
|
+
|
|
+ if (!byte_array_init(b, BUFSIZE)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
for (n = 0; n < ctx->start; n += (zip_uint64_t)ret) {
|
|
- i = (ctx->start - n > sizeof(b) ? sizeof(b) : ctx->start - n);
|
|
+ i = (ctx->start - n > BUFSIZE ? BUFSIZE : ctx->start - n);
|
|
if ((ret = zip_source_read(src, b, i)) < 0) {
|
|
_zip_error_set_from_source(&ctx->error, src);
|
|
+ byte_array_fini(b);
|
|
return -1;
|
|
}
|
|
if (ret == 0) {
|
|
zip_error_set(&ctx->error, ZIP_ER_EOF, 0);
|
|
+ byte_array_fini(b);
|
|
return -1;
|
|
}
|
|
}
|
|
+
|
|
+ byte_array_fini(b);
|
|
}
|
|
+
|
|
ctx->offset = ctx->start;
|
|
return 0;
|
|
|
|
@@ -220,8 +236,14 @@ window_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_sou
|
|
return 0;
|
|
}
|
|
|
|
- case ZIP_SOURCE_GET_COMPRESSION_FLAGS:
|
|
- return ctx->compression_flags;
|
|
+ case ZIP_SOURCE_GET_FILE_ATTRIBUTES:
|
|
+ if (len < sizeof(ctx->attributes)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ memcpy(data, &ctx->attributes, sizeof(ctx->attributes));
|
|
+ return sizeof(ctx->attributes);
|
|
|
|
case ZIP_SOURCE_SUPPORTS:
|
|
return ctx->supports;
|
|
diff --git a/lib/zip_source_winzip_aes_encode.c b/lib/zip_source_winzip_aes_encode.c
|
|
index 12ed1b2..853ead4 100644
|
|
--- a/lib/zip_source_winzip_aes_encode.c
|
|
+++ b/lib/zip_source_winzip_aes_encode.c
|
|
@@ -83,7 +83,7 @@ zip_source_winzip_aes_encode(zip_t *za, zip_source_t *src, zip_uint16_t encrypti
|
|
static int
|
|
encrypt_header(zip_source_t *src, struct winzip_aes *ctx) {
|
|
zip_uint16_t salt_length = SALT_LENGTH(ctx->encryption_method);
|
|
- if (!zip_random(ctx->data, salt_length)) {
|
|
+ if (!zip_secure_random(ctx->data, salt_length)) {
|
|
zip_error_set(&ctx->error, ZIP_ER_INTERNAL, 0);
|
|
return -1;
|
|
}
|
|
@@ -163,6 +163,7 @@ winzip_aes_encrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t length,
|
|
/* TODO: return partial read? */
|
|
return -1;
|
|
}
|
|
+ buffer_n += _zip_buffer_read(ctx->buffer, (zip_uint8_t *)data + ret, length - (zip_uint64_t)ret);
|
|
}
|
|
|
|
return (zip_int64_t)(buffer_n + (zip_uint64_t)ret);
|
|
@@ -183,8 +184,20 @@ winzip_aes_encrypt(zip_source_t *src, void *ud, void *data, zip_uint64_t length,
|
|
return 0;
|
|
}
|
|
|
|
+ case ZIP_SOURCE_GET_FILE_ATTRIBUTES: {
|
|
+ zip_file_attributes_t *attributes = (zip_file_attributes_t *)data;
|
|
+ if (length < sizeof(*attributes)) {
|
|
+ zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
|
|
+ return -1;
|
|
+ }
|
|
+ attributes->valid |= ZIP_FILE_ATTRIBUTES_VERSION_NEEDED;
|
|
+ attributes->version_needed = 51;
|
|
+
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
case ZIP_SOURCE_SUPPORTS:
|
|
- return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, -1);
|
|
+ return zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_STAT, ZIP_SOURCE_ERROR, ZIP_SOURCE_FREE, ZIP_SOURCE_GET_FILE_ATTRIBUTES, -1);
|
|
|
|
case ZIP_SOURCE_ERROR:
|
|
return zip_error_to_data(&ctx->error, data, length);
|
|
diff --git a/lib/zip_source_zip_new.c b/lib/zip_source_zip_new.c
|
|
index a5cfee3..e27fde7 100644
|
|
--- a/lib/zip_source_zip_new.c
|
|
+++ b/lib/zip_source_zip_new.c
|
|
@@ -36,15 +36,19 @@
|
|
|
|
#include "zipint.h"
|
|
|
|
+static void _zip_file_attributes_from_dirent(zip_file_attributes_t *attributes, zip_dirent_t *de);
|
|
|
|
zip_source_t *
|
|
_zip_source_zip_new(zip_t *za, zip_t *srcza, zip_uint64_t srcidx, zip_flags_t flags, zip_uint64_t start, zip_uint64_t len, const char *password) {
|
|
zip_source_t *src, *s2;
|
|
- struct zip_stat st;
|
|
+ zip_stat_t st;
|
|
+ zip_file_attributes_t attributes;
|
|
+ zip_dirent_t *de;
|
|
bool partial_data, needs_crc, needs_decrypt, needs_decompress;
|
|
|
|
- if (za == NULL)
|
|
+ if (za == NULL) {
|
|
return NULL;
|
|
+ }
|
|
|
|
if (srcza == NULL || srcidx >= srcza->nentry) {
|
|
zip_error_set(&za->error, ZIP_ER_INVAL, 0);
|
|
@@ -61,8 +65,9 @@ _zip_source_zip_new(zip_t *za, zip_t *srcza, zip_uint64_t srcidx, zip_flags_t fl
|
|
return NULL;
|
|
}
|
|
|
|
- if (flags & ZIP_FL_ENCRYPTED)
|
|
+ if (flags & ZIP_FL_ENCRYPTED) {
|
|
flags |= ZIP_FL_COMPRESSED;
|
|
+ }
|
|
|
|
if ((start > 0 || len > 0) && (flags & ZIP_FL_COMPRESSED)) {
|
|
zip_error_set(&za->error, ZIP_ER_INVAL, 0);
|
|
@@ -95,8 +100,13 @@ _zip_source_zip_new(zip_t *za, zip_t *srcza, zip_uint64_t srcidx, zip_flags_t fl
|
|
}
|
|
}
|
|
|
|
+ if ((de = _zip_get_dirent(srcza, srcidx, flags, &za->error)) == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+ _zip_file_attributes_from_dirent(&attributes, de);
|
|
+
|
|
if (st.comp_size == 0) {
|
|
- return zip_source_buffer(za, NULL, 0, 0);
|
|
+ return zip_source_buffer_with_attributes(za, NULL, 0, 0, &attributes);
|
|
}
|
|
|
|
if (partial_data && !needs_decrypt && !needs_decompress) {
|
|
@@ -108,17 +118,12 @@ _zip_source_zip_new(zip_t *za, zip_t *srcza, zip_uint64_t srcidx, zip_flags_t fl
|
|
st2.mtime = st.mtime;
|
|
st2.valid = ZIP_STAT_SIZE | ZIP_STAT_COMP_SIZE | ZIP_STAT_COMP_METHOD | ZIP_STAT_MTIME;
|
|
|
|
- if ((src = _zip_source_window_new(srcza->src, start, len, &st2, 0, srcza, srcidx, &za->error)) == NULL) {
|
|
+ if ((src = _zip_source_window_new(srcza->src, start, len, &st2, &attributes, srcza, srcidx, &za->error)) == NULL) {
|
|
return NULL;
|
|
}
|
|
}
|
|
else {
|
|
- zip_dirent_t *de;
|
|
-
|
|
- if ((de = _zip_get_dirent(srcza, srcidx, flags, &za->error)) == NULL) {
|
|
- return NULL;
|
|
- }
|
|
- if ((src = _zip_source_window_new(srcza->src, 0, st.comp_size, &st, (de->bitflags >> 1) & 3, srcza, srcidx, &za->error)) == NULL) {
|
|
+ if ((src = _zip_source_window_new(srcza->src, 0, st.comp_size, &st, &attributes, srcza, srcidx, &za->error)) == NULL) {
|
|
return NULL;
|
|
}
|
|
}
|
|
@@ -173,3 +178,14 @@ _zip_source_zip_new(zip_t *za, zip_t *srcza, zip_uint64_t srcidx, zip_flags_t fl
|
|
|
|
return src;
|
|
}
|
|
+
|
|
+static void
|
|
+_zip_file_attributes_from_dirent(zip_file_attributes_t *attributes, zip_dirent_t *de) {
|
|
+ zip_file_attributes_init(attributes);
|
|
+ attributes->valid = ZIP_FILE_ATTRIBUTES_ASCII | ZIP_FILE_ATTRIBUTES_HOST_SYSTEM | ZIP_FILE_ATTRIBUTES_EXTERNAL_FILE_ATTRIBUTES | ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS;
|
|
+ attributes->ascii = de->int_attrib & 1;
|
|
+ attributes->host_system = de->version_madeby >> 8;
|
|
+ attributes->external_file_attributes = de->ext_attrib;
|
|
+ attributes->general_purpose_bit_flags = de->bitflags;
|
|
+ attributes->general_purpose_bit_mask = ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK;
|
|
+}
|
|
diff --git a/lib/zip_stat_index.c b/lib/zip_stat_index.c
|
|
index 109c118..1a6ff71 100644
|
|
--- a/lib/zip_stat_index.c
|
|
+++ b/lib/zip_stat_index.c
|
|
@@ -48,10 +48,17 @@ zip_stat_index(zip_t *za, zip_uint64_t index, zip_flags_t flags, zip_stat_t *st)
|
|
|
|
|
|
if ((flags & ZIP_FL_UNCHANGED) == 0 && ZIP_ENTRY_DATA_CHANGED(za->entry + index)) {
|
|
- if (zip_source_stat(za->entry[index].source, st) < 0) {
|
|
+ zip_entry_t *entry = za->entry + index;
|
|
+
|
|
+ if (zip_source_stat(entry->source, st) < 0) {
|
|
zip_error_set(&za->error, ZIP_ER_CHANGED, 0);
|
|
return -1;
|
|
}
|
|
+
|
|
+ if (entry->changes->changed & ZIP_DIRENT_LAST_MOD) {
|
|
+ st->mtime = de->last_mod;
|
|
+ st->valid |= ZIP_STAT_MTIME;
|
|
+ }
|
|
}
|
|
else {
|
|
zip_stat_init(st);
|
|
diff --git a/lib/zip_string.c b/lib/zip_string.c
|
|
index 293766c..6533228 100644
|
|
--- a/lib/zip_string.c
|
|
+++ b/lib/zip_string.c
|
|
@@ -145,7 +145,7 @@ _zip_string_new(const zip_uint8_t *raw, zip_uint16_t length, zip_flags_t flags,
|
|
return NULL;
|
|
}
|
|
|
|
- if ((s->raw = (zip_uint8_t *)malloc((size_t)(length + 1))) == NULL) {
|
|
+ if ((s->raw = (zip_uint8_t *)malloc((size_t)length + 1)) == NULL) {
|
|
free(s);
|
|
return NULL;
|
|
}
|
|
diff --git a/lib/zip_utf-8.c b/lib/zip_utf-8.c
|
|
index 8f02f88..0776294 100644
|
|
--- a/lib/zip_utf-8.c
|
|
+++ b/lib/zip_utf-8.c
|
|
@@ -39,7 +39,7 @@
|
|
|
|
static const zip_uint16_t _cp437_to_unicode[256] = {
|
|
/* 0x00 - 0x0F */
|
|
- 0x2007, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C,
|
|
+ 0x0000, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C,
|
|
|
|
/* 0x10 - 0x1F */
|
|
0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC,
|
|
diff --git a/lib/zipint.h b/lib/zipint.h
|
|
index 3c60ece..35553cd 100644
|
|
--- a/lib/zipint.h
|
|
+++ b/lib/zipint.h
|
|
@@ -65,6 +65,9 @@
|
|
#define BUFSIZE 8192
|
|
#define EFZIP64SIZE 28
|
|
#define EF_WINZIP_AES_SIZE 7
|
|
+#define MAX_DATA_DESCRIPTOR_LENGTH 24
|
|
+
|
|
+#define ZIP_CRYPTO_PKWARE_HEADERLEN 12
|
|
|
|
#define ZIP_CM_REPLACED_DEFAULT (-2)
|
|
#define ZIP_CM_WINZIP_AES 99 /* Winzip AES encrypted */
|
|
@@ -91,6 +94,7 @@
|
|
/* according to unzip-6.0's zipinfo.c, this corresponds to a directory with rwx permissions for everyone */
|
|
#define ZIP_EXT_ATTRIB_DEFAULT_DIR (0040777u << 16)
|
|
|
|
+#define ZIP_FILE_ATTRIBUTES_GENERAL_PURPOSE_BIT_FLAGS_ALLOWED_MASK 0x0836
|
|
|
|
#define ZIP_MAX(a, b) ((a) > (b) ? (a) : (b))
|
|
#define ZIP_MIN(a, b) ((a) < (b) ? (a) : (b))
|
|
@@ -124,7 +128,9 @@ struct zip_compression_algorithm {
|
|
void (*deallocate)(void *ctx);
|
|
|
|
/* get compression specific general purpose bitflags */
|
|
- int (*compression_flags)(void *ctx);
|
|
+ zip_uint16_t (*general_purpose_bit_flags)(void *ctx);
|
|
+ /* minimum version needed when using this algorithm */
|
|
+ zip_uint8_t version_needed;
|
|
|
|
/* start processing */
|
|
bool (*start)(void *ctx);
|
|
@@ -146,8 +152,9 @@ extern zip_compression_algorithm_t zip_algorithm_bzip2_compress;
|
|
extern zip_compression_algorithm_t zip_algorithm_bzip2_decompress;
|
|
extern zip_compression_algorithm_t zip_algorithm_deflate_compress;
|
|
extern zip_compression_algorithm_t zip_algorithm_deflate_decompress;
|
|
+extern zip_compression_algorithm_t zip_algorithm_xz_compress;
|
|
+extern zip_compression_algorithm_t zip_algorithm_xz_decompress;
|
|
|
|
-bool zip_compression_method_supported(zip_int32_t method, bool compress);
|
|
|
|
/* This API is not final yet, but we need it internally, so it's private for now. */
|
|
|
|
@@ -163,13 +170,14 @@ zip_source_t *zip_source_crc(zip_t *, zip_source_t *, int);
|
|
zip_source_t *zip_source_decompress(zip_t *za, zip_source_t *src, zip_int32_t cm);
|
|
zip_source_t *zip_source_layered(zip_t *, zip_source_t *, zip_source_layered_callback, void *);
|
|
zip_source_t *zip_source_layered_create(zip_source_t *src, zip_source_layered_callback cb, void *ud, zip_error_t *error);
|
|
-zip_source_t *zip_source_pkware(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);
|
|
+zip_source_t *zip_source_pkware_decode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);
|
|
+zip_source_t *zip_source_pkware_encode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);
|
|
int zip_source_remove(zip_source_t *);
|
|
zip_int64_t zip_source_supports(zip_source_t *src);
|
|
zip_source_t *zip_source_window(zip_t *, zip_source_t *, zip_uint64_t, zip_uint64_t);
|
|
zip_source_t *zip_source_winzip_aes_decode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);
|
|
zip_source_t *zip_source_winzip_aes_encode(zip_t *, zip_source_t *, zip_uint16_t, int, const char *);
|
|
-
|
|
+zip_source_t *zip_source_buffer_with_attributes(zip_t *za, const void *data, zip_uint64_t len, int freep, zip_file_attributes_t *attributes);
|
|
|
|
/* error source for layered sources */
|
|
|
|
@@ -367,6 +375,21 @@ struct zip_string {
|
|
};
|
|
|
|
|
|
+/* byte array */
|
|
+
|
|
+/* For performance, we usually keep 8k byte arrays on the stack.
|
|
+ However, there are (embedded) systems with a stack size of 12k;
|
|
+ for those, use malloc()/free() */
|
|
+
|
|
+#ifdef ZIP_ALLOCATE_BUFFER
|
|
+#define DEFINE_BYTE_ARRAY(buf, size) zip_uint8_t *buf
|
|
+#define byte_array_init(buf, size) (((buf) = (zip_uint8_t *)malloc(size)) != NULL)
|
|
+#define byte_array_fini(buf) (free(buf))
|
|
+#else
|
|
+#define DEFINE_BYTE_ARRAY(buf, size) zip_uint8_t buf[size]
|
|
+#define byte_array_init(buf, size) (1)
|
|
+#define byte_array_fini(buf) ((void)0)
|
|
+#endif
|
|
/* bounds checked access to memory buffer */
|
|
|
|
struct zip_buffer {
|
|
@@ -390,6 +413,11 @@ typedef struct zip_filelist zip_filelist_t;
|
|
struct _zip_winzip_aes;
|
|
typedef struct _zip_winzip_aes zip_winzip_aes_t;
|
|
|
|
+struct _zip_pkware_keys {
|
|
+ zip_uint32_t key[3];
|
|
+};
|
|
+typedef struct _zip_pkware_keys zip_pkware_keys_t;
|
|
+
|
|
extern const char *const _zip_err_str[];
|
|
extern const int _zip_nerr_str;
|
|
extern const int _zip_err_type[];
|
|
@@ -449,6 +477,7 @@ zip_cdir_t *_zip_cdir_new(zip_uint64_t, zip_error_t *);
|
|
zip_int64_t _zip_cdir_write(zip_t *za, const zip_filelist_t *filelist, zip_uint64_t survivors);
|
|
void _zip_deregister_source(zip_t *za, zip_source_t *src);
|
|
|
|
+void _zip_dirent_apply_attributes(zip_dirent_t *, zip_file_attributes_t *, bool, zip_uint32_t);
|
|
zip_dirent_t *_zip_dirent_clone(const zip_dirent_t *);
|
|
void _zip_dirent_free(zip_dirent_t *);
|
|
void _zip_dirent_finalize(zip_dirent_t *);
|
|
@@ -506,12 +535,12 @@ zip_t *_zip_open(zip_source_t *, unsigned int, zip_error_t *);
|
|
|
|
void _zip_progress_end(zip_progress_t *progress);
|
|
void _zip_progress_free(zip_progress_t *progress);
|
|
-zip_progress_t *_zip_progress_new(zip_t *za, double precision, zip_progress_callback callback, void (*ud_free)(void *), void *ud);
|
|
-void _zip_progress_start(zip_progress_t *progress);
|
|
-void _zip_progress_subrange(zip_progress_t *progress, double start, double end);
|
|
-void _zip_progress_update(zip_progress_t *progress, double value);
|
|
+int _zip_progress_start(zip_progress_t *progress);
|
|
+int _zip_progress_subrange(zip_progress_t *progress, double start, double end);
|
|
+int _zip_progress_update(zip_progress_t *progress, double value);
|
|
|
|
-ZIP_EXTERN bool zip_random(zip_uint8_t *buffer, zip_uint16_t length);
|
|
+ZIP_EXTERN bool zip_secure_random(zip_uint8_t *buffer, zip_uint16_t length);
|
|
+zip_uint32_t zip_random_uint32(void);
|
|
|
|
int _zip_read(zip_source_t *src, zip_uint8_t *data, zip_uint64_t length, zip_error_t *error);
|
|
int _zip_read_at_offset(zip_source_t *src, zip_uint64_t offset, unsigned char *b, size_t length, zip_error_t *error);
|
|
@@ -522,6 +551,7 @@ int _zip_register_source(zip_t *za, zip_source_t *src);
|
|
|
|
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);
|
|
@@ -530,7 +560,7 @@ bool _zip_source_had_error(zip_source_t *);
|
|
void _zip_source_invalidate(zip_source_t *src);
|
|
zip_source_t *_zip_source_new(zip_error_t *error);
|
|
int _zip_source_set_source_archive(zip_source_t *, zip_t *);
|
|
-zip_source_t *_zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_uint64_t length, zip_stat_t *st, zip_int8_t compression_flags, zip_t *source_archive, zip_uint64_t source_index, zip_error_t *error);
|
|
+zip_source_t *_zip_source_window_new(zip_source_t *src, zip_uint64_t start, zip_uint64_t length, zip_stat_t *st, zip_file_attributes_t *attributes, zip_t *source_archive, zip_uint64_t source_index, zip_error_t *error);
|
|
zip_source_t *_zip_source_zip_new(zip_t *, zip_t *, zip_uint64_t, zip_flags_t, zip_uint64_t, zip_uint64_t, const char *);
|
|
|
|
int _zip_stat_merge(zip_stat_t *dst, const zip_stat_t *src, zip_error_t *error);
|
|
@@ -547,6 +577,11 @@ bool _zip_winzip_aes_finish(zip_winzip_aes_t *ctx, zip_uint8_t *hmac);
|
|
void _zip_winzip_aes_free(zip_winzip_aes_t *ctx);
|
|
zip_winzip_aes_t *_zip_winzip_aes_new(const zip_uint8_t *password, zip_uint64_t password_length, const zip_uint8_t *salt, zip_uint16_t key_size, zip_uint8_t *password_verify, zip_error_t *error);
|
|
|
|
+void _zip_pkware_encrypt(zip_pkware_keys_t *keys, zip_uint8_t *out, const zip_uint8_t *in, zip_uint64_t len);
|
|
+void _zip_pkware_decrypt(zip_pkware_keys_t *keys, zip_uint8_t *out, const zip_uint8_t *in, zip_uint64_t len);
|
|
+zip_pkware_keys_t *_zip_pkware_keys_new(zip_error_t *error);
|
|
+void _zip_pkware_keys_free(zip_pkware_keys_t *keys);
|
|
+void _zip_pkware_keys_reset(zip_pkware_keys_t *keys);
|
|
int _zip_changed(const zip_t *, zip_uint64_t *);
|
|
const char *_zip_get_name(zip_t *, zip_uint64_t, zip_flags_t, zip_error_t *);
|
|
int _zip_local_header_read(zip_t *, int);
|
|
--
|
|
2.28.0
|
|
|