From 359276e1e84a552e018a5ab43efe5c52f77c2c3c Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Tue, 28 May 2024 16:47:52 +0200 Subject: [PATCH 1/4] Support zip archives not starting at zero offset Zip archives are usually read from the back to the front, making it possible to append them to other files (e.g. executables) in order to provide some kind of embedded filesystem. This PR makes it possible to read, write, and update such zip files without affecting the existing functionality. --- src/miniz.h | 38 ++++++++++++++++++++++++++++++-------- src/zip.c | 38 +++++++++++++++++++++++--------------- 2 files changed, 53 insertions(+), 23 deletions(-) diff --git a/src/miniz.h b/src/miniz.h index cd86483..a292a04 100644 --- a/src/miniz.h +++ b/src/miniz.h @@ -1352,6 +1352,7 @@ typedef enum { typedef struct { mz_uint64 m_archive_size; mz_uint64 m_central_directory_file_ofs; + mz_uint64 m_archive_ofs; /* We only support up to UINT32_MAX files in zip64 mode. */ mz_uint32 m_total_files; @@ -5614,7 +5615,7 @@ static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) { mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0; - mz_uint64 cdir_ofs = 0; + mz_uint64 cdir_ofs = 0, eocd_ofs = 0, archive_ofs = 0; mz_int64 cur_file_ofs = 0; const mz_uint8 *p; @@ -5645,6 +5646,7 @@ static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs)) return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR); + eocd_ofs = cur_file_ofs; /* Read and verify the end of central directory record. */ if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != @@ -5753,7 +5755,23 @@ static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - pZip->m_central_directory_file_ofs = cdir_ofs; + if ((cdir_ofs + (mz_uint64)cdir_size) > eocd_ofs) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + /* The end of central dir follows the central dir, unless the zip file has + * some trailing data (e.g. it is appended to an executable file). */ + archive_ofs = eocd_ofs - (cdir_ofs + cdir_size); + if (pZip->m_pState->m_zip64) { + if (archive_ofs < MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + + MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); + + archive_ofs -= MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + + MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; + } + + pZip->m_archive_ofs = archive_ofs; + pZip->m_central_directory_file_ofs = archive_ofs + cdir_ofs; if (pZip->m_total_files) { mz_uint i, n; @@ -5773,7 +5791,7 @@ static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } - if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, + if (pZip->m_pRead(pZip->m_pIO_opaque, archive_ofs + cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); @@ -5823,7 +5841,8 @@ static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); if (pZip->m_pRead(pZip->m_pIO_opaque, - cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + archive_ofs + cdir_ofs + + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size, buf, ext_data_size) != ext_data_size) { MZ_FREE(buf); @@ -7099,7 +7118,8 @@ mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, pState->out_blk_remain = 0; /* Read and parse the local directory entry. */ - pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; + pState->cur_file_ofs = + pZip->m_archive_ofs + pState->file_stat.m_local_header_ofs; if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) { @@ -9760,10 +9780,11 @@ mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) { central_dir_size = 0; if (pZip->m_total_files) { /* Write central directory */ - central_dir_ofs = pZip->m_archive_size; + central_dir_ofs = pZip->m_archive_size - pZip->m_archive_ofs; central_dir_size = pState->m_central_dir.m_size; pZip->m_central_directory_file_ofs = central_dir_ofs; - if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, + if (pZip->m_pWrite(pZip->m_pIO_opaque, + pZip->m_archive_ofs + central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); @@ -9773,7 +9794,8 @@ mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) { if (pState->m_zip64) { /* Write zip64 end of central directory header */ - mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; + mz_uint64 rel_ofs_to_zip64_ecdr = + pZip->m_archive_size - pZip->m_archive_ofs; MZ_CLEAR_ARR(hdr); MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, diff --git a/src/zip.c b/src/zip.c index a7e5ef8..eb7d110 100644 --- a/src/zip.c +++ b/src/zip.c @@ -1071,7 +1071,8 @@ static int _zip_entry_open(struct zip_t *zip, const char *entryname, return ZIP_ENOINIT; } - local_dir_header_ofs = zip->archive.m_archive_size; + local_dir_header_ofs = + zip->archive.m_archive_size - zip->archive.m_archive_ofs; if (!entryname) { return ZIP_EINVENTNAME; @@ -1144,8 +1145,8 @@ static int _zip_entry_open(struct zip_t *zip, const char *entryname, zip->entry.comp_size = 0; zip->entry.uncomp_size = 0; zip->entry.uncomp_crc32 = MZ_CRC32_INIT; - zip->entry.dir_offset = zip->archive.m_archive_size; - zip->entry.header_offset = zip->archive.m_archive_size; + zip->entry.dir_offset = zip->archive.m_archive_size - pzip->m_archive_ofs; + zip->entry.header_offset = zip->archive.m_archive_size - pzip->m_archive_ofs; memset(zip->entry.header, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE * sizeof(mz_uint8)); zip->entry.method = level ? MZ_DEFLATED : 0; @@ -1171,7 +1172,8 @@ static int _zip_entry_open(struct zip_t *zip, const char *entryname, goto cleanup; } - if (!mz_zip_writer_write_zeros(pzip, zip->entry.dir_offset, + if (!mz_zip_writer_write_zeros(pzip, + pzip->m_archive_ofs + zip->entry.dir_offset, num_alignment_padding_bytes)) { // Cannot memset zip entry header err = ZIP_EMEMSET; @@ -1204,7 +1206,8 @@ static int _zip_entry_open(struct zip_t *zip, const char *entryname, zip->entry.header_offset = zip->entry.dir_offset + num_alignment_padding_bytes; - if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.header_offset, + if (pzip->m_pWrite(pzip->m_pIO_opaque, + pzip->m_archive_ofs + zip->entry.header_offset, zip->entry.header, sizeof(zip->entry.header)) != sizeof(zip->entry.header)) { // Cannot write zip entry header @@ -1219,8 +1222,9 @@ static int _zip_entry_open(struct zip_t *zip, const char *entryname, zip->entry.dir_offset += num_alignment_padding_bytes + sizeof(zip->entry.header); - if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.dir_offset, zip->entry.name, - entrylen) != entrylen) { + if (pzip->m_pWrite(pzip->m_pIO_opaque, + pzip->m_archive_ofs + zip->entry.dir_offset, + zip->entry.name, entrylen) != entrylen) { // Cannot write data to zip entry err = ZIP_EWRTENT; goto cleanup; @@ -1228,7 +1232,8 @@ static int _zip_entry_open(struct zip_t *zip, const char *entryname, zip->entry.dir_offset += entrylen; - if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.dir_offset, extra_data, + if (pzip->m_pWrite(pzip->m_pIO_opaque, + pzip->m_archive_ofs + zip->entry.dir_offset, extra_data, extra_size) != extra_size) { // Cannot write ZIP64 data to zip entry err = ZIP_EWRTENT; @@ -1238,7 +1243,8 @@ static int _zip_entry_open(struct zip_t *zip, const char *entryname, if (level) { zip->entry.state.m_pZip = pzip; - zip->entry.state.m_cur_archive_file_ofs = zip->entry.dir_offset; + zip->entry.state.m_cur_archive_file_ofs = + pzip->m_archive_ofs + zip->entry.dir_offset; zip->entry.state.m_comp_size = 0; if (tdefl_init(&(zip->entry.comp), mz_zip_writer_add_put_buf_callback, @@ -1363,7 +1369,8 @@ int zip_entry_close(struct zip_t *zip) { goto cleanup; } zip->entry.comp_size = zip->entry.state.m_comp_size; - zip->entry.dir_offset = zip->entry.state.m_cur_archive_file_ofs; + zip->entry.dir_offset = + zip->entry.state.m_cur_archive_file_ofs - pzip->m_archive_ofs; zip->entry.method = MZ_DEFLATED; } @@ -1377,9 +1384,9 @@ int zip_entry_close(struct zip_t *zip) { MZ_WRITE_LE64(local_dir_footer + 8, zip->entry.comp_size); MZ_WRITE_LE64(local_dir_footer + 16, zip->entry.uncomp_size); - if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.dir_offset, - local_dir_footer, - local_dir_footer_size) != local_dir_footer_size) { + if (pzip->m_pWrite( + pzip->m_pIO_opaque, pzip->m_archive_ofs + zip->entry.dir_offset, + local_dir_footer, local_dir_footer_size) != local_dir_footer_size) { // Cannot write zip entry header err = ZIP_EWRTHDR; goto cleanup; @@ -1415,7 +1422,7 @@ int zip_entry_close(struct zip_t *zip) { } pzip->m_total_files++; - pzip->m_archive_size = zip->entry.dir_offset; + pzip->m_archive_size = pzip->m_archive_ofs + zip->entry.dir_offset; cleanup: if (zip) { @@ -1501,7 +1508,8 @@ int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize) { level = zip->level & 0xF; if (!level) { - if ((pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.dir_offset, buf, + if ((pzip->m_pWrite(pzip->m_pIO_opaque, + pzip->m_archive_ofs + zip->entry.dir_offset, buf, bufsize) != bufsize)) { // Cannot write buffer return ZIP_EWRTENT; From 7c578e3ede0e59f2afc9407d3c14d425fc15edf2 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 13 Jun 2024 20:22:29 +0200 Subject: [PATCH 2/4] Use updated miniz version The new miniz version correctly computes the archive starting offset. --- src/miniz.h | 373 +++++++++++++++----------------------------- src/zip.c | 319 ++++++++++++++++++------------------- src/zip.h | 10 ++ test/CMakeLists.txt | 6 + test/test_offset.c | 96 ++++++++++++ 5 files changed, 388 insertions(+), 416 deletions(-) create mode 100644 test/test_offset.c diff --git a/src/miniz.h b/src/miniz.h index a292a04..70a62f8 100644 --- a/src/miniz.h +++ b/src/miniz.h @@ -1,7 +1,7 @@ #ifndef MINIZ_EXPORT #define MINIZ_EXPORT #endif -/* miniz.c 3.0.0 - public domain deflate/inflate, zlib-subset, ZIP +/* miniz.c 3.0.2 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing See "unlicense" statement at the end of this file. Rich Geldreich , last updated Oct. 13, 2013 Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: @@ -740,7 +740,9 @@ extern "C" { /* Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly * slower, and raw/dynamic blocks will be output more frequently). */ +#ifndef TDEFL_LESS_MEMORY #define TDEFL_LESS_MEMORY 0 +#endif /* tdefl_init() compression flags logically OR'd together (low 12 bits contain * the max. number of probes per dictionary search): */ @@ -1352,7 +1354,6 @@ typedef enum { typedef struct { mz_uint64 m_archive_size; mz_uint64 m_central_directory_file_ofs; - mz_uint64 m_archive_ofs; /* We only support up to UINT32_MAX files in zip64 mode. */ mz_uint32 m_total_files; @@ -1425,11 +1426,6 @@ MINIZ_EXPORT mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size); -MINIZ_EXPORT mz_bool mz_zip_reader_init_file_v2_rpb(mz_zip_archive *pZip, - const char *pFilename, - mz_uint flags, - mz_uint64 file_start_ofs, - mz_uint64 archive_size); /* Read an archive from an already opened FILE, beginning at the current file * position. */ @@ -1695,8 +1691,6 @@ MINIZ_EXPORT mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, MINIZ_EXPORT mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); -MINIZ_EXPORT mz_bool mz_zip_writer_init_from_reader_v2_noreopen( - mz_zip_archive *pZip, const char *pFilename, mz_uint flags); /* Adds the contents of a memory buffer to an archive. These functions record * the current local time into the archive. */ @@ -1735,9 +1729,9 @@ MINIZ_EXPORT mz_bool mz_zip_writer_add_read_buf_callback( mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void *callback_opaque, mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, - mz_uint level_and_flags, mz_uint32 ext_attributes, - const char *user_extra_data_local, mz_uint user_extra_data_local_len, - const char *user_extra_data_central, mz_uint user_extra_data_central_len); + mz_uint level_and_flags, const char *user_extra_data_local, + mz_uint user_extra_data_local_len, const char *user_extra_data_central, + mz_uint user_extra_data_central_len); #ifndef MINIZ_NO_STDIO /* Adds the contents of a disk file to an archive. This function also records @@ -1747,15 +1741,14 @@ MINIZ_EXPORT mz_bool mz_zip_writer_add_read_buf_callback( * just set to MZ_DEFAULT_COMPRESSION. */ MINIZ_EXPORT mz_bool mz_zip_writer_add_file( mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, - const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, - mz_uint32 ext_attributes); + const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); /* Like mz_zip_writer_add_file(), except the file data is read from the * specified FILE stream. */ MINIZ_EXPORT mz_bool mz_zip_writer_add_cfile( mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, - mz_uint16 comment_size, mz_uint level_and_flags, mz_uint32 ext_attributes, + mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len); #endif @@ -1833,6 +1826,8 @@ MINIZ_EXPORT void *mz_zip_extract_archive_file_to_heap_v2( #endif #endif /* MINIZ_NO_ARCHIVE_APIS */ + +#ifndef MINIZ_HEADER_FILE_ONLY /************************************************************************** * * Copyright 2013-2014 RAD Game Tools and Valve Software @@ -2145,21 +2140,17 @@ mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) { } int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, - const unsigned char *pSource, mz_ulong pSource_len, - int level) { + const unsigned char *pSource, mz_ulong source_len, int level) { int status; mz_stream stream; memset(&stream, 0, sizeof(stream)); -#if defined(__MINGW32__) || defined(__MINGW64__) || defined(__WATCOMC__) /* In case mz_ulong is 64-bits (argh I hate longs). */ -#else - if ((mz_uint64)(pSource_len | *pDest_len) > 0xFFFFFFFFU) + if ((mz_uint64)(source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; -#endif stream.next_in = pSource; - stream.avail_in = (mz_uint32)pSource_len; + stream.avail_in = (mz_uint32)source_len; stream.next_out = pDest; stream.avail_out = (mz_uint32)*pDest_len; @@ -2403,12 +2394,9 @@ int mz_uncompress2(unsigned char *pDest, mz_ulong *pDest_len, int status; memset(&stream, 0, sizeof(stream)); -#if defined(__MINGW32__) || defined(__MINGW64__) || defined(__WATCOMC__) /* In case mz_ulong is 64-bits (argh I hate longs). */ -#else if ((mz_uint64)(*pSource_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; -#endif stream.next_in = pSource; stream.avail_in = (mz_uint32)*pSource_len; @@ -4953,9 +4941,17 @@ extern "C" { #else #include -#if defined(_MSC_VER) || defined(__MINGW64__) +#if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__) +#ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN +#endif +#ifndef __cplusplus +#define MICROSOFT_WINDOWS_WINBASE_H_DEFINE_INTERLOCKED_CPLUSPLUS_OVERLOADS 0 +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif #include static WCHAR *mz_utf8z_to_widechar(const char *str) { @@ -4969,51 +4965,37 @@ static FILE *mz_fopen(const char *pFilename, const char *pMode) { WCHAR *wFilename = mz_utf8z_to_widechar(pFilename); WCHAR *wMode = mz_utf8z_to_widechar(pMode); FILE *pFile = NULL; -#ifdef ZIP_ENABLE_SHARABLE_FILE_OPEN - pFile = _wfopen(wFilename, wMode); -#else errno_t err = _wfopen_s(&pFile, wFilename, wMode); -#endif free(wFilename); free(wMode); -#ifdef ZIP_ENABLE_SHARABLE_FILE_OPEN - return pFile; -#else return err ? NULL : pFile; -#endif } static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) { WCHAR *wPath = mz_utf8z_to_widechar(pPath); WCHAR *wMode = mz_utf8z_to_widechar(pMode); FILE *pFile = NULL; -#ifdef ZIP_ENABLE_SHARABLE_FILE_OPEN - pFile = _wfreopen(wPath, wMode, pStream); -#else errno_t err = _wfreopen_s(&pFile, wPath, wMode, pStream); -#endif free(wPath); free(wMode); -#ifdef ZIP_ENABLE_SHARABLE_FILE_OPEN - return pFile; -#else return err ? NULL : pFile; -#endif } -static int mz_stat64(const char *path, struct __stat64 *buffer) { +#if defined(__MINGW32__) +static int mz_stat(const char *path, struct _stat *buffer) { WCHAR *wPath = mz_utf8z_to_widechar(path); - int res = _wstat64(wPath, buffer); + int res = _wstat(wPath, buffer); free(wPath); return res; } - -static int mz_mkdir(const char *pDirname) { - WCHAR *wDirname = mz_utf8z_to_widechar(pDirname); - int res = _wmkdir(wDirname); - free(wDirname); +#else +static int mz_stat64(const char *path, struct __stat64 *buffer) { + WCHAR *wPath = mz_utf8z_to_widechar(path); + int res = _wstat64(wPath, buffer); + free(wPath); return res; } +#endif #ifndef MINIZ_NO_TIME #include @@ -5024,14 +5006,18 @@ static int mz_mkdir(const char *pDirname) { #define MZ_FWRITE fwrite #define MZ_FTELL64 _ftelli64 #define MZ_FSEEK64 _fseeki64 +#if defined(__MINGW32__) +#define MZ_FILE_STAT_STRUCT _stat +#define MZ_FILE_STAT mz_stat +#else #define MZ_FILE_STAT_STRUCT _stat64 #define MZ_FILE_STAT mz_stat64 +#endif #define MZ_FFLUSH fflush #define MZ_FREOPEN mz_freopen #define MZ_DELETE_FILE remove -#define MZ_MKDIR(d) mz_mkdir(d) -#elif defined(__MINGW32__) || defined(__WATCOMC__) +#elif defined(__WATCOMC__) #ifndef MINIZ_NO_TIME #include #endif @@ -5046,7 +5032,6 @@ static int mz_mkdir(const char *pDirname) { #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove -#define MZ_MKDIR(d) _mkdir(d) #elif defined(__TINYC__) #ifndef MINIZ_NO_TIME @@ -5063,11 +5048,6 @@ static int mz_mkdir(const char *pDirname) { #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove -#if defined(_WIN32) || defined(_WIN64) -#define MZ_MKDIR(d) _mkdir(d) -#else -#define MZ_MKDIR(d) mkdir(d, 0755) -#endif #elif defined(__USE_LARGEFILE64) /* gcc, clang */ #ifndef MINIZ_NO_TIME @@ -5084,9 +5064,9 @@ static int mz_mkdir(const char *pDirname) { #define MZ_FFLUSH fflush #define MZ_FREOPEN(p, m, s) freopen64(p, m, s) #define MZ_DELETE_FILE remove -#define MZ_MKDIR(d) mkdir(d, 0755) -#elif defined(__APPLE__) || defined(__FreeBSD__) +#elif defined(__APPLE__) || defined(__FreeBSD__) || \ + (defined(__linux__) && defined(__x86_64__)) #ifndef MINIZ_NO_TIME #include #endif @@ -5101,7 +5081,6 @@ static int mz_mkdir(const char *pDirname) { #define MZ_FFLUSH fflush #define MZ_FREOPEN(p, m, s) freopen(p, m, s) #define MZ_DELETE_FILE remove -#define MZ_MKDIR(d) mkdir(d, 0755) #else #pragma message( \ @@ -5125,17 +5104,9 @@ static int mz_mkdir(const char *pDirname) { #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove -#define MZ_MKDIR(d) mkdir(d, 0755) #endif /* #ifdef _MSC_VER */ #endif /* #ifdef MINIZ_NO_STDIO */ -#ifndef CHMOD -// Upon successful completion, a value of 0 is returned. -// Otherwise, a value of -1 is returned and errno is set to indicate the error. -// int chmod(const char *path, mode_t mode); -#define CHMOD(f, m) chmod(f, m) -#endif - #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) /* Various ZIP archive enums. To completely avoid cross platform compiler @@ -5601,7 +5572,7 @@ static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, /* Give up if we've searched the entire file, or we've gone back "too far" * (~64kb) */ if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= - (MZ_UINT16_MAX + record_size))) + ((mz_uint64)(MZ_UINT16_MAX) + record_size))) return MZ_FALSE; cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); @@ -5611,6 +5582,20 @@ static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, return MZ_TRUE; } +static mz_bool mz_zip_reader_eocd64_valid(mz_zip_archive *pZip, uint64_t offset, + uint8_t *buf) { + if (pZip->m_pRead(pZip->m_pIO_opaque, offset, buf, + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) { + if (MZ_READ_LE32(buf + MZ_ZIP64_ECDH_SIG_OFS) == + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) { + return MZ_TRUE; + } + } + + return MZ_FALSE; +} + static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags) { mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, @@ -5666,25 +5651,38 @@ static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) { if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) { - zip64_end_of_central_dir_ofs = MZ_READ_LE64( - pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); - if (zip64_end_of_central_dir_ofs > - (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) - return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - - if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, - pZip64_end_of_central_dir, - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) { - if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) { - pZip->m_pState->m_zip64 = MZ_TRUE; - } - } + pZip->m_pState->m_zip64 = MZ_TRUE; } } } + if (pZip->m_pState->m_zip64) { + /* Try locating the EOCD64 right before the EOCD64 locator. This works even + * when the effective start of the zip header is not yet known. */ + if (cur_file_ofs < MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + + zip64_end_of_central_dir_ofs = cur_file_ofs - + MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE - + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE; + + if (!mz_zip_reader_eocd64_valid(pZip, zip64_end_of_central_dir_ofs, + pZip64_end_of_central_dir)) { + /* That failed, try reading where the locator tells us to. */ + zip64_end_of_central_dir_ofs = MZ_READ_LE64( + pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS); + + if (zip64_end_of_central_dir_ofs > + (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + + if (!mz_zip_reader_eocd64_valid(pZip, zip64_end_of_central_dir_ofs, + pZip64_end_of_central_dir)) + return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); + } + } + pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS); cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS); @@ -5755,7 +5753,7 @@ static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - if ((cdir_ofs + (mz_uint64)cdir_size) > eocd_ofs) + if (eocd_ofs < cdir_ofs + cdir_size) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); /* The end of central dir follows the central dir, unless the zip file has @@ -5770,8 +5768,15 @@ static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE; } - pZip->m_archive_ofs = archive_ofs; - pZip->m_central_directory_file_ofs = archive_ofs + cdir_ofs; + /* Update the archive start position, but only if not specified. */ + if ((pZip->m_zip_type == MZ_ZIP_TYPE_FILE || + pZip->m_zip_type == MZ_ZIP_TYPE_CFILE) && + pZip->m_pState->m_file_archive_start_ofs == 0) { + pZip->m_pState->m_file_archive_start_ofs = archive_ofs; + pZip->m_archive_size -= archive_ofs; + } + + pZip->m_central_directory_file_ofs = cdir_ofs; if (pZip->m_total_files) { mz_uint i, n; @@ -5791,7 +5796,7 @@ static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); } - if (pZip->m_pRead(pZip->m_pIO_opaque, archive_ofs + cdir_ofs, + if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED); @@ -5841,8 +5846,7 @@ static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED); if (pZip->m_pRead(pZip->m_pIO_opaque, - archive_ofs + cdir_ofs + - MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size, buf, ext_data_size) != ext_data_size) { MZ_FREE(buf); @@ -6120,60 +6124,6 @@ mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, return MZ_TRUE; } -mz_bool mz_zip_reader_init_file_v2_rpb(mz_zip_archive *pZip, - const char *pFilename, mz_uint flags, - mz_uint64 file_start_ofs, - mz_uint64 archive_size) { - mz_uint64 file_size; - MZ_FILE *pFile; - - if ((!pZip) || (!pFilename) || - ((archive_size) && - (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - pFile = MZ_FOPEN(pFilename, "r+b"); - if (!pFile) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED); - - file_size = archive_size; - if (!file_size) { - if (MZ_FSEEK64(pFile, 0, SEEK_END)) { - MZ_FCLOSE(pFile); - return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED); - } - - file_size = MZ_FTELL64(pFile); - } - - /* TODO: Better sanity check archive_size and the # of actual remaining bytes - */ - - if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) { - MZ_FCLOSE(pFile); - return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE); - } - - if (!mz_zip_reader_init_internal(pZip, flags)) { - MZ_FCLOSE(pFile); - return MZ_FALSE; - } - - pZip->m_zip_type = MZ_ZIP_TYPE_FILE; - pZip->m_pRead = mz_zip_file_read_func; - pZip->m_pIO_opaque = pZip; - pZip->m_pState->m_pFile = pFile; - pZip->m_archive_size = file_size; - pZip->m_pState->m_file_archive_start_ofs = file_start_ofs; - - if (!mz_zip_reader_read_central_dir(pZip, flags)) { - mz_zip_reader_end_internal(pZip, MZ_FALSE); - return MZ_FALSE; - } - - return MZ_TRUE; -} - mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags) { mz_uint64 cur_file_ofs; @@ -6646,7 +6596,7 @@ static mz_bool mz_zip_reader_extract_to_mem_no_alloc1( if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + + cur_file_ofs += (mz_uint64)(MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) @@ -6887,7 +6837,7 @@ mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED); - cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + + cur_file_ofs += (mz_uint64)(MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) @@ -7118,8 +7068,7 @@ mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, pState->out_blk_remain = 0; /* Read and parse the local directory entry. */ - pState->cur_file_ofs = - pZip->m_archive_ofs + pState->file_stat.m_local_header_ofs; + pState->cur_file_ofs = pState->file_stat.m_local_header_ofs; if (pZip->m_pRead(pZip->m_pIO_opaque, pState->cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) { @@ -7135,7 +7084,7 @@ mz_zip_reader_extract_iter_new(mz_zip_archive *pZip, mz_uint file_index, } pState->cur_file_ofs += - MZ_ZIP_LOCAL_DIR_HEADER_SIZE + + (mz_uint64)(MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((pState->cur_file_ofs + pState->file_stat.m_comp_size) > @@ -8203,88 +8152,6 @@ mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, return MZ_TRUE; } -mz_bool mz_zip_writer_init_from_reader_v2_noreopen(mz_zip_archive *pZip, - const char *pFilename, - mz_uint flags) { - mz_zip_internal_state *pState; - - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - if (flags & MZ_ZIP_FLAG_WRITE_ZIP64) { - /* We don't support converting a non-zip64 file to zip64 - this seems like - * more trouble than it's worth. (What about the existing 32-bit data - * descriptors that could follow the compressed data?) */ - if (!pZip->m_pState->m_zip64) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - } - - /* No sense in trying to write to an archive that's already at the support max - * size */ - if (pZip->m_pState->m_zip64) { - if (pZip->m_total_files == MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - } else { - if (pZip->m_total_files == MZ_UINT16_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); - - if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + - MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX) - return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE); - } - - pState = pZip->m_pState; - - if (pState->m_pFile) { -#ifdef MINIZ_NO_STDIO - (void)pFilename; - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); -#else - if (pZip->m_pIO_opaque != pZip) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE) { - if (!pFilename) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - } - - pZip->m_pWrite = mz_zip_file_write_func; - pZip->m_pNeeds_keepalive = NULL; -#endif /* #ifdef MINIZ_NO_STDIO */ - } else if (pState->m_pMem) { - /* Archive lives in a memory block. Assume it's from the heap that we can - * resize using the realloc callback. */ - if (pZip->m_pIO_opaque != pZip) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - pState->m_mem_capacity = pState->m_mem_size; - pZip->m_pWrite = mz_zip_heap_write_func; - pZip->m_pNeeds_keepalive = NULL; - } - /* Archive is being read via a user provided read function - make sure the - user has specified a write function too. */ - else if (!pZip->m_pWrite) - return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER); - - /* Start writing new files at the archive's current central directory - * location. */ - /* TODO: We could add a flag that lets the user start writing immediately - * AFTER the existing central dir - this would be safer. */ - pZip->m_archive_size = pZip->m_central_directory_file_ofs; - pZip->m_central_directory_file_ofs = 0; - - /* Clear the sorted central dir offsets, they aren't useful or maintained now. - */ - /* Even though we're now in write mode, files can still be extracted and - * verified, but file locates will be slow. */ - /* TODO: We could easily maintain the sorted central directory offsets. */ - mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets); - - pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; - - return MZ_TRUE; -} - mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) { return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0); @@ -8579,6 +8446,8 @@ mz_bool mz_zip_writer_add_mem_ex_v2( time(&cur_time); mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); } +#else + (void)last_modified; #endif /* #ifndef MINIZ_NO_TIME */ if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { @@ -8818,12 +8687,12 @@ mz_bool mz_zip_writer_add_read_buf_callback( mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void *callback_opaque, mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, - mz_uint level_and_flags, mz_uint32 ext_attributes, - const char *user_extra_data, mz_uint user_extra_data_len, - const char *user_extra_data_central, mz_uint user_extra_data_central_len) { + mz_uint level_and_flags, const char *user_extra_data, + mz_uint user_extra_data_len, const char *user_extra_data_central, + mz_uint user_extra_data_central_len) { mz_uint16 gen_flags; mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; - mz_uint16 method = 0, dos_time = 0, dos_date = 0; + mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, comp_size = 0; size_t archive_name_size; @@ -8907,6 +8776,8 @@ mz_bool mz_zip_writer_add_read_buf_callback( if (pFile_time) { mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date); } +#else + (void)pFile_time; #endif if (max_size <= 3) @@ -9212,20 +9083,20 @@ static size_t mz_file_read_func_stdio(void *pOpaque, mz_uint64 file_ofs, mz_bool mz_zip_writer_add_cfile( mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, - mz_uint16 comment_size, mz_uint level_and_flags, mz_uint32 ext_attributes, + mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) { return mz_zip_writer_add_read_buf_callback( pZip, pArchive_name, mz_file_read_func_stdio, pSrc_file, max_size, - pFile_time, pComment, comment_size, level_and_flags, ext_attributes, - user_extra_data, user_extra_data_len, user_extra_data_central, + pFile_time, pComment, comment_size, level_and_flags, user_extra_data, + user_extra_data_len, user_extra_data_central, user_extra_data_central_len); } mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, - mz_uint16 comment_size, mz_uint level_and_flags, - mz_uint32 ext_attributes) { + mz_uint16 comment_size, + mz_uint level_and_flags) { MZ_FILE *pSrc_file = NULL; mz_uint64 uncomp_size = 0; MZ_TIME_T file_modified_time; @@ -9248,9 +9119,9 @@ mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, uncomp_size = MZ_FTELL64(pSrc_file); MZ_FSEEK64(pSrc_file, 0, SEEK_SET); - status = mz_zip_writer_add_cfile( - pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, - comment_size, level_and_flags, ext_attributes, NULL, 0, NULL, 0); + status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, + pFile_time, pComment, comment_size, + level_and_flags, NULL, 0, NULL, 0); MZ_FCLOSE(pSrc_file); @@ -9433,9 +9304,9 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS); local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS); - src_archive_bytes_remaining = local_header_filename_size + - local_header_extra_len + - src_file_stat.m_comp_size; + src_archive_bytes_remaining = src_file_stat.m_comp_size + + local_header_filename_size + + local_header_extra_len; /* Try to find a zip64 extended information field */ if ((local_header_extra_len) && @@ -9780,11 +9651,10 @@ mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) { central_dir_size = 0; if (pZip->m_total_files) { /* Write central directory */ - central_dir_ofs = pZip->m_archive_size - pZip->m_archive_ofs; + central_dir_ofs = pZip->m_archive_size; central_dir_size = pState->m_central_dir.m_size; pZip->m_central_directory_file_ofs = central_dir_ofs; - if (pZip->m_pWrite(pZip->m_pIO_opaque, - pZip->m_archive_ofs + central_dir_ofs, + if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED); @@ -9794,8 +9664,7 @@ mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) { if (pState->m_zip64) { /* Write zip64 end of central directory header */ - mz_uint64 rel_ofs_to_zip64_ecdr = - pZip->m_archive_size - pZip->m_archive_ofs; + mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size; MZ_CLEAR_ARR(hdr); MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, @@ -10261,3 +10130,5 @@ mz_bool mz_zip_end(mz_zip_archive *pZip) { #endif #endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/ + +#endif // MINIZ_HEADER_FILE_ONLY diff --git a/src/zip.c b/src/zip.c index eb7d110..4bbe304 100644 --- a/src/zip.c +++ b/src/zip.c @@ -13,19 +13,19 @@ #include #include -#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ +#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ defined(__MINGW32__) /* Win32, DOS, MSVC, MSVS */ #include -#define HAS_DEVICE(P) \ - ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) && \ +#define HAS_DEVICE(P) \ + ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) && \ (P)[1] == ':') #define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE(P) ? 2 : 0) #else -#include // needed for symlink() +#include // needed for symlink() #endif @@ -63,12 +63,12 @@ #define ISSLASH(C) ((C) == '/' || (C) == '\\') #endif -#define CLEANUP(ptr) \ - do { \ - if (ptr) { \ - free((void *)ptr); \ - ptr = NULL; \ - } \ +#define CLEANUP(ptr) \ + do { \ + if (ptr) { \ + free((void *)ptr); \ + ptr = NULL; \ + } \ } while (0) #define UNX_IFDIR 0040000 /* Unix directory */ @@ -172,8 +172,7 @@ static const char *zip_basename(const char *name) { } /* If NAME is all slashes, arrange to return `/'. */ - if (*base == '\0' && ISSLASH(*name) && all_slashes) - --base; + if (*base == '\0' && ISSLASH(*name) && all_slashes) --base; return base; } @@ -193,7 +192,7 @@ static int zip_mkpath(char *path) { } for (p = path + len; *p && len < MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE; p++) { if (ISSLASH(*p) && ((!has_device && len > 0) || (has_device && len > 2))) { -#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ +#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ defined(__MINGW32__) #else if ('\\' == *p) { @@ -201,7 +200,7 @@ static int zip_mkpath(char *path) { } #endif - if (MZ_MKDIR(npath) == -1) { + if (mkdir(npath) == -1) { if (errno != EEXIST) { return ZIP_EMKDIR; } @@ -275,7 +274,7 @@ static char *zip_name_normalize(char *name, char *const nname, size_t len) { if (ISSLASH(c)) { if (ncpy > 0 && !zip_strchr_match(&nname[offn], ncpy, '.')) { offn += ncpy; - nname[offn++] = c; // append '/' + nname[offn++] = c; // append '/' } ncpy = 0; } else { @@ -304,7 +303,7 @@ static int zip_archive_truncate(mz_zip_archive *pzip) { if (pzip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED) { if (pState->m_pFile) { int fd = fileno(pState->m_pFile); - return ftruncate(fd, file_size); + return ftruncate(fd, pState->m_file_archive_start_ofs + file_size); } } return 0; @@ -379,12 +378,12 @@ static int zip_archive_extract(mz_zip_archive *zip_archive, const char *dir, if ((((info.m_version_made_by >> 8) == 3) || ((info.m_version_made_by >> 8) == - 19)) // if zip is produced on Unix or macOS (3 and 19 from - // section 4.4.2.2 of zip standard) + 19)) // if zip is produced on Unix or macOS (3 and 19 from + // section 4.4.2.2 of zip standard) && info.m_external_attr & - (0x20 << 24)) { // and has sym link attribute (0x80 is file, 0x40 - // is directory) -#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ + (0x20 << 24)) { // and has sym link attribute (0x80 is file, + // 0x40 is directory) +#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ defined(__MINGW32__) #else if (info.m_uncomp_size > MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE || @@ -410,7 +409,7 @@ static int zip_archive_extract(mz_zip_archive *zip_archive, const char *dir, } #if defined(_MSC_VER) || defined(PS4) - (void)xattr; // unused + (void)xattr; // unused #else xattr = (info.m_external_attr >> 16) & 0xFFFF; if (xattr > 0 && xattr <= MZ_UINT16_MAX) { @@ -597,7 +596,6 @@ static int zip_index_update(struct zip_entry_mark_t *entry_mark, static int zip_entry_finalize(struct zip_t *zip, struct zip_entry_mark_t *entry_mark, const ssize_t n) { - ssize_t i = 0; mz_uint64 *local_header_ofs_array = (mz_uint64 *)calloc(n, sizeof(mz_uint64)); if (!local_header_ofs_array) { @@ -717,7 +715,7 @@ static ssize_t zip_file_move(MZ_FILE *m_pFile, const mz_uint64 to, static ssize_t zip_files_move(struct zip_t *zip, mz_uint64 writen_num, mz_uint64 read_num, size_t length) { ssize_t n = 0; - const size_t page_size = 1 << 12; // 4K + const size_t page_size = 1 << 12; // 4K mz_zip_internal_state *pState = zip->archive.m_pState; mz_uint8 *move_buf = (mz_uint8 *)calloc(1, page_size); @@ -953,8 +951,7 @@ struct zip_t *zip_openwitherror(const char *zipname, int level, char mode, goto cleanup; } - if (level < 0) - level = MZ_DEFAULT_LEVEL; + if (level < 0) level = MZ_DEFAULT_LEVEL; if ((level & 0xF) > MZ_UBER_COMPRESSION) { // Wrong compression level *errnum = ZIP_EINVLVL; @@ -971,50 +968,56 @@ struct zip_t *zip_openwitherror(const char *zipname, int level, char mode, zip->level = (mz_uint)level; zip->entry.index = -1; switch (mode) { - case 'w': - // Create a new archive. - if (!mz_zip_writer_init_file_v2(&(zip->archive), zipname, 0, - MZ_ZIP_FLAG_WRITE_ZIP64)) { - // Cannot initialize zip_archive writer - *errnum = ZIP_EWINIT; - goto cleanup; - } - break; - - case 'r': - if (!mz_zip_reader_init_file_v2( - &(zip->archive), zipname, - zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) { - // An archive file does not exist or cannot initialize - // zip_archive reader - *errnum = ZIP_ERINIT; - goto cleanup; - } - break; - - case 'a': - case 'd': - if (!mz_zip_reader_init_file_v2_rpb( - &(zip->archive), zipname, - zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) { - // An archive file does not exist or cannot initialize - // zip_archive reader - *errnum = ZIP_ERINIT; - goto cleanup; - } - if ((mode == 'a' || mode == 'd')) { - if (!mz_zip_writer_init_from_reader_v2_noreopen(&(zip->archive), zipname, - 0)) { + case 'w': + // Create a new archive. + if (!mz_zip_writer_init_file_v2(&(zip->archive), zipname, 0, + MZ_ZIP_FLAG_WRITE_ZIP64)) { + // Cannot initialize zip_archive writer + *errnum = ZIP_EWINIT; + goto cleanup; + } + break; + + case 'r': + if (!mz_zip_reader_init_file_v2( + &(zip->archive), zipname, + zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) { + // An archive file does not exist or cannot initialize + // zip_archive reader + *errnum = ZIP_ERINIT; + goto cleanup; + } + break; + + case 'a': + case 'd': { + MZ_FILE *fp = MZ_FOPEN(zipname, "r+b"); + if (!fp) { + *errnum = ZIP_EOPNFILE; + goto cleanup; + } + if (!mz_zip_reader_init_cfile( + &(zip->archive), fp, 0, + zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) { + // An archive file does not exist or cannot initialize zip_archive + // reader + *errnum = ZIP_ERINIT; + fclose(fp); + goto cleanup; + } + if (!mz_zip_writer_init_from_reader_v2(&(zip->archive), zipname, 0)) { *errnum = ZIP_EWRINIT; + fclose(fp); mz_zip_reader_end(&(zip->archive)); goto cleanup; } - } - break; + // The file pointer is now owned by the archive object. + zip->archive.m_zip_type = MZ_ZIP_TYPE_FILE; + } break; - default: - *errnum = ZIP_EINVMODE; - goto cleanup; + default: + *errnum = ZIP_EINVMODE; + goto cleanup; } return zip; @@ -1055,6 +1058,16 @@ int zip_is64(struct zip_t *zip) { return (int)zip->archive.m_pState->m_zip64; } +int zip_get_archive_offset(struct zip_t *zip, uint64_t *offset) { + if (!zip || !zip->archive.m_pState) { + // zip_t handler or zip state is not initialized + return ZIP_ENOINIT; + } + + *offset = mz_zip_get_archive_file_start_offset(&zip->archive); + return 0; +} + static int _zip_entry_open(struct zip_t *zip, const char *entryname, int case_sensitive) { size_t entrylen = 0; @@ -1071,8 +1084,7 @@ static int _zip_entry_open(struct zip_t *zip, const char *entryname, return ZIP_ENOINIT; } - local_dir_header_ofs = - zip->archive.m_archive_size - zip->archive.m_archive_ofs; + local_dir_header_ofs = zip->archive.m_archive_size; if (!entryname) { return ZIP_EINVENTNAME; @@ -1145,8 +1157,8 @@ static int _zip_entry_open(struct zip_t *zip, const char *entryname, zip->entry.comp_size = 0; zip->entry.uncomp_size = 0; zip->entry.uncomp_crc32 = MZ_CRC32_INIT; - zip->entry.dir_offset = zip->archive.m_archive_size - pzip->m_archive_ofs; - zip->entry.header_offset = zip->archive.m_archive_size - pzip->m_archive_ofs; + zip->entry.dir_offset = zip->archive.m_archive_size; + zip->entry.header_offset = zip->archive.m_archive_size; memset(zip->entry.header, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE * sizeof(mz_uint8)); zip->entry.method = level ? MZ_DEFLATED : 0; @@ -1172,8 +1184,7 @@ static int _zip_entry_open(struct zip_t *zip, const char *entryname, goto cleanup; } - if (!mz_zip_writer_write_zeros(pzip, - pzip->m_archive_ofs + zip->entry.dir_offset, + if (!mz_zip_writer_write_zeros(pzip, zip->entry.dir_offset, num_alignment_padding_bytes)) { // Cannot memset zip entry header err = ZIP_EMEMSET; @@ -1206,8 +1217,7 @@ static int _zip_entry_open(struct zip_t *zip, const char *entryname, zip->entry.header_offset = zip->entry.dir_offset + num_alignment_padding_bytes; - if (pzip->m_pWrite(pzip->m_pIO_opaque, - pzip->m_archive_ofs + zip->entry.header_offset, + if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.header_offset, zip->entry.header, sizeof(zip->entry.header)) != sizeof(zip->entry.header)) { // Cannot write zip entry header @@ -1222,9 +1232,8 @@ static int _zip_entry_open(struct zip_t *zip, const char *entryname, zip->entry.dir_offset += num_alignment_padding_bytes + sizeof(zip->entry.header); - if (pzip->m_pWrite(pzip->m_pIO_opaque, - pzip->m_archive_ofs + zip->entry.dir_offset, - zip->entry.name, entrylen) != entrylen) { + if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.dir_offset, zip->entry.name, + entrylen) != entrylen) { // Cannot write data to zip entry err = ZIP_EWRTENT; goto cleanup; @@ -1232,8 +1241,7 @@ static int _zip_entry_open(struct zip_t *zip, const char *entryname, zip->entry.dir_offset += entrylen; - if (pzip->m_pWrite(pzip->m_pIO_opaque, - pzip->m_archive_ofs + zip->entry.dir_offset, extra_data, + if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.dir_offset, extra_data, extra_size) != extra_size) { // Cannot write ZIP64 data to zip entry err = ZIP_EWRTENT; @@ -1243,8 +1251,7 @@ static int _zip_entry_open(struct zip_t *zip, const char *entryname, if (level) { zip->entry.state.m_pZip = pzip; - zip->entry.state.m_cur_archive_file_ofs = - pzip->m_archive_ofs + zip->entry.dir_offset; + zip->entry.state.m_cur_archive_file_ofs = zip->entry.dir_offset; zip->entry.state.m_comp_size = 0; if (tdefl_init(&(zip->entry.comp), mz_zip_writer_add_put_buf_callback, @@ -1369,8 +1376,7 @@ int zip_entry_close(struct zip_t *zip) { goto cleanup; } zip->entry.comp_size = zip->entry.state.m_comp_size; - zip->entry.dir_offset = - zip->entry.state.m_cur_archive_file_ofs - pzip->m_archive_ofs; + zip->entry.dir_offset = zip->entry.state.m_cur_archive_file_ofs; zip->entry.method = MZ_DEFLATED; } @@ -1384,9 +1390,9 @@ int zip_entry_close(struct zip_t *zip) { MZ_WRITE_LE64(local_dir_footer + 8, zip->entry.comp_size); MZ_WRITE_LE64(local_dir_footer + 16, zip->entry.uncomp_size); - if (pzip->m_pWrite( - pzip->m_pIO_opaque, pzip->m_archive_ofs + zip->entry.dir_offset, - local_dir_footer, local_dir_footer_size) != local_dir_footer_size) { + if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.dir_offset, + local_dir_footer, + local_dir_footer_size) != local_dir_footer_size) { // Cannot write zip entry header err = ZIP_EWRTHDR; goto cleanup; @@ -1422,7 +1428,7 @@ int zip_entry_close(struct zip_t *zip) { } pzip->m_total_files++; - pzip->m_archive_size = pzip->m_archive_ofs + zip->entry.dir_offset; + pzip->m_archive_size = zip->entry.dir_offset; cleanup: if (zip) { @@ -1508,8 +1514,7 @@ int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize) { level = zip->level & 0xF; if (!level) { - if ((pzip->m_pWrite(pzip->m_pIO_opaque, - pzip->m_archive_ofs + zip->entry.dir_offset, buf, + if ((pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.dir_offset, buf, bufsize) != bufsize)) { // Cannot write buffer return ZIP_EWRTENT; @@ -1550,25 +1555,18 @@ int zip_entry_fwrite(struct zip_t *zip, const char *filename) { } #if defined(_WIN32) || defined(__WIN32__) || defined(DJGPP) - (void)modes; // unused + (void)modes; // unused #else /* Initialize with permission bits--which are not implementation-optional */ modes = file_stat.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX); - if (S_ISDIR(file_stat.st_mode)) - modes |= UNX_IFDIR; - if (S_ISREG(file_stat.st_mode)) - modes |= UNX_IFREG; - if (S_ISLNK(file_stat.st_mode)) - modes |= UNX_IFLNK; - if (S_ISBLK(file_stat.st_mode)) - modes |= UNX_IFBLK; - if (S_ISCHR(file_stat.st_mode)) - modes |= UNX_IFCHR; - if (S_ISFIFO(file_stat.st_mode)) - modes |= UNX_IFIFO; - if (S_ISSOCK(file_stat.st_mode)) - modes |= UNX_IFSOCK; + if (S_ISDIR(file_stat.st_mode)) modes |= UNX_IFDIR; + if (S_ISREG(file_stat.st_mode)) modes |= UNX_IFREG; + if (S_ISLNK(file_stat.st_mode)) modes |= UNX_IFLNK; + if (S_ISBLK(file_stat.st_mode)) modes |= UNX_IFBLK; + if (S_ISCHR(file_stat.st_mode)) modes |= UNX_IFCHR; + if (S_ISFIFO(file_stat.st_mode)) modes |= UNX_IFIFO; + if (S_ISSOCK(file_stat.st_mode)) modes |= UNX_IFSOCK; zip->entry.external_attr = (modes << 16) | !(file_stat.st_mode & S_IWUSR); if ((file_stat.st_mode & S_IFMT) == S_IFDIR) { zip->entry.external_attr |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; @@ -1677,7 +1675,7 @@ int zip_entry_fread(struct zip_t *zip, const char *filename) { } #if defined(_MSC_VER) || defined(PS4) - (void)xattr; // unused + (void)xattr; // unused #else if (!mz_zip_reader_file_stat(pzip, idx, &info)) { // Cannot get information about zip archive; @@ -1911,8 +1909,7 @@ struct zip_t *zip_cstream_openwitherror(FILE *stream, int level, char mode, goto cleanup; } - if (level < 0) - level = MZ_DEFAULT_LEVEL; + if (level < 0) level = MZ_DEFAULT_LEVEL; if ((level & 0xF) > MZ_UBER_COMPRESSION) { // Wrong compression level *errnum = ZIP_EINVLVL; @@ -1928,50 +1925,49 @@ struct zip_t *zip_cstream_openwitherror(FILE *stream, int level, char mode, zip->level = (mz_uint)level; switch (mode) { - case 'w': - // Create a new archive. - if (!mz_zip_writer_init_cfile(&(zip->archive), stream, - MZ_ZIP_FLAG_WRITE_ZIP64)) { - // Cannot initialize zip_archive writer - *errnum = ZIP_EWINIT; - goto cleanup; - } - break; - - case 'r': - if (!mz_zip_reader_init_cfile( - &(zip->archive), stream, 0, - zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) { - // An archive file does not exist or cannot initialize - // zip_archive reader - *errnum = ZIP_ERINIT; - goto cleanup; - } - break; - - case 'a': - case 'd': - if (!mz_zip_reader_init_cfile( - &(zip->archive), stream, 0, - zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) { - // An archive file does not exist or cannot initialize - // zip_archive reader - *errnum = ZIP_ERINIT; - goto cleanup; - } - if ((mode == 'a' || mode == 'd')) { - if (!mz_zip_writer_init_from_reader_v2_noreopen(&(zip->archive), NULL, - 0)) { - *errnum = ZIP_EWRINIT; - mz_zip_reader_end(&(zip->archive)); + case 'w': + // Create a new archive. + if (!mz_zip_writer_init_cfile(&(zip->archive), stream, + MZ_ZIP_FLAG_WRITE_ZIP64)) { + // Cannot initialize zip_archive writer + *errnum = ZIP_EWINIT; goto cleanup; } - } - break; + break; - default: - *errnum = ZIP_EINVMODE; - goto cleanup; + case 'r': + if (!mz_zip_reader_init_cfile( + &(zip->archive), stream, 0, + zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) { + // An archive file does not exist or cannot initialize + // zip_archive reader + *errnum = ZIP_ERINIT; + goto cleanup; + } + break; + + case 'a': + case 'd': + if (!mz_zip_reader_init_cfile( + &(zip->archive), stream, 0, + zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) { + // An archive file does not exist or cannot initialize + // zip_archive reader + *errnum = ZIP_ERINIT; + goto cleanup; + } + if ((mode == 'a' || mode == 'd')) { + if (!mz_zip_writer_init_from_reader_v2(&(zip->archive), NULL, 0)) { + *errnum = ZIP_EWRINIT; + mz_zip_reader_end(&(zip->archive)); + goto cleanup; + } + } + break; + + default: + *errnum = ZIP_EINVMODE; + goto cleanup; } return zip; @@ -2025,35 +2021,28 @@ int zip_create(const char *zipname, const char *filenames[], size_t len) { } #if defined(_WIN32) || defined(__WIN32__) || defined(DJGPP) - (void)modes; // unused + (void)modes; // unused #else /* Initialize with permission bits--which are not implementation-optional */ modes = file_stat.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX); - if (S_ISDIR(file_stat.st_mode)) - modes |= UNX_IFDIR; - if (S_ISREG(file_stat.st_mode)) - modes |= UNX_IFREG; - if (S_ISLNK(file_stat.st_mode)) - modes |= UNX_IFLNK; - if (S_ISBLK(file_stat.st_mode)) - modes |= UNX_IFBLK; - if (S_ISCHR(file_stat.st_mode)) - modes |= UNX_IFCHR; - if (S_ISFIFO(file_stat.st_mode)) - modes |= UNX_IFIFO; - if (S_ISSOCK(file_stat.st_mode)) - modes |= UNX_IFSOCK; + if (S_ISDIR(file_stat.st_mode)) modes |= UNX_IFDIR; + if (S_ISREG(file_stat.st_mode)) modes |= UNX_IFREG; + if (S_ISLNK(file_stat.st_mode)) modes |= UNX_IFLNK; + if (S_ISBLK(file_stat.st_mode)) modes |= UNX_IFBLK; + if (S_ISCHR(file_stat.st_mode)) modes |= UNX_IFCHR; + if (S_ISFIFO(file_stat.st_mode)) modes |= UNX_IFIFO; + if (S_ISSOCK(file_stat.st_mode)) modes |= UNX_IFSOCK; ext_attributes = (modes << 16) | !(file_stat.st_mode & S_IWUSR); if ((file_stat.st_mode & S_IFMT) == S_IFDIR) { ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; } #endif - if (!mz_zip_writer_add_file(&zip_archive, zip_basename(name), name, "", 0, - ZIP_DEFAULT_COMPRESSION_LEVEL, - ext_attributes)) { + if (!mz_zip_writer_add_file( + &zip_archive, zip_basename(name), name, "", 0, + ZIP_DEFAULT_COMPRESSION_LEVEL | ext_attributes)) { // Cannot add file to zip_archive err = ZIP_ENOFILE; break; diff --git a/src/zip.h b/src/zip.h index 92056d5..0f870cb 100644 --- a/src/zip.h +++ b/src/zip.h @@ -162,6 +162,16 @@ extern ZIP_EXPORT void zip_close(struct zip_t *zip); */ extern ZIP_EXPORT int zip_is64(struct zip_t *zip); +/** + * Returns the offset in the stream where the zip header is located. + * + * @param zip zip archive handler. + * @param offset zip header offset. + * + * @return the return code - 0 if successful, negative number (< 0) on error. + */ +extern ZIP_EXPORT int zip_get_archive_offset(struct zip_t *zip, uint64_t *offset); + /** * Opens an entry by name in the zip archive. * diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index fc8bb1d..1aef111 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -49,3 +49,9 @@ add_executable(${test_open_out} test_open.c) target_link_libraries(${test_open_out} zip) add_test(NAME ${test_open_out} COMMAND ${test_open_out}) add_sanitizers(${test_open_out}) + +set(test_offset_out test_offset.out) +add_executable(${test_offset_out} test_offset.c) +target_link_libraries(${test_offset_out} zip) +add_test(NAME ${test_offset_out} COMMAND ${test_offset_out}) +add_sanitizers(${test_offset_out}) \ No newline at end of file diff --git a/test/test_offset.c b/test/test_offset.c new file mode 100644 index 0000000..187eefa --- /dev/null +++ b/test/test_offset.c @@ -0,0 +1,96 @@ +#include +#include + +#include + +#include "minunit.h" + +#if defined(_WIN32) || defined(_WIN64) +#define MKTEMP _mktemp +#define UNLINK _unlink +#else +#define MKTEMP mkstemp +#define UNLINK unlink +#endif + +static char ZIPNAME[L_tmpnam + 1] = {0}; + +#define HEADERDATA1 "this precedes the zip header" +#define TESTDATA1 "Some test data 1...\0" +#define TESTDATA2 "Some test data 2...\0" +#define CRC32DATA1 2220805626 +#define CRC32DATA2 2532008468 + +void test_setup(void) { + strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam); + MKTEMP(ZIPNAME); + + FILE *fp = fopen(ZIPNAME, "wb"); + mu_check(fp != NULL); + fwrite(HEADERDATA1, 1, strlen(HEADERDATA1), fp); + + struct zip_t *zip = zip_cstream_open(fp, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); + mu_check(zip != NULL); + + mu_assert_int_eq(0, zip_entry_open(zip, "test/test-1.txt")); + mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1))); + mu_assert_int_eq(0, zip_entry_close(zip)); + + zip_close(zip); + fclose(fp); + + zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'a'); + mu_check(zip != NULL); + + mu_assert_int_eq(0, zip_entry_open(zip, "test/test-2.txt")); + mu_assert_int_eq(0, zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2))); + mu_assert_int_eq(0, zip_entry_close(zip)); + + zip_close(zip); +} + +void test_teardown(void) { remove(ZIPNAME); } + +MU_TEST(test_read) { + char *buf = NULL; + ssize_t bufsize; + size_t buftmp; + uint64_t archive_offset; + + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + mu_check(zip != NULL); + + zip_get_archive_offset(zip, &archive_offset); + mu_assert_int_eq(strlen(HEADERDATA1), archive_offset); + + mu_assert_int_eq(2, zip_entries_total(zip)); + + mu_assert_int_eq(0, zip_entry_open(zip, "test/test-1.txt")); + mu_assert_int_eq(strlen(TESTDATA1), zip_entry_size(zip)); + mu_check(CRC32DATA1 == zip_entry_crc32(zip)); + bufsize = zip_entry_read(zip, (void **)&buf, &buftmp); + mu_assert_int_eq(strlen(TESTDATA1), bufsize); + mu_assert_int_eq((size_t)bufsize, buftmp); + mu_assert_int_eq(0, strncmp(buf, TESTDATA1, bufsize)); + mu_assert_int_eq(0, zip_entry_close(zip)); + zip_close(zip); + free(buf); + buf = NULL; +} + +MU_TEST_SUITE(test_offset_suite) { + MU_SUITE_CONFIGURE(&test_setup, &test_teardown); + + MU_RUN_TEST(test_read); +} + +#define UNUSED(x) (void)x + +int main(int argc, char *argv[]) { + UNUSED(argc); + UNUSED(argv); + + MU_RUN_SUITE(test_offset_suite); + MU_REPORT(); + return MU_EXIT_CODE; +} \ No newline at end of file From b5f645391aeb64bddda68969931bd0bfa217d17a Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 14 Jun 2024 18:37:19 +0200 Subject: [PATCH 3/4] Fix compilation errors Use the correct mkdir signature on Windows vs other platforms. Remove CHMOD macro, it was simply wrapping the chmod libc call. --- src/zip.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/zip.c b/src/zip.c index 4bbe304..d35cd4c 100644 --- a/src/zip.c +++ b/src/zip.c @@ -200,7 +200,11 @@ static int zip_mkpath(char *path) { } #endif - if (mkdir(npath) == -1) { +#if defined(WIN32) + if (_mkdir(npath) == -1) { +#else + if (mkdir(npath, 0777) == -1) { +#endif if (errno != EEXIST) { return ZIP_EMKDIR; } @@ -413,7 +417,7 @@ static int zip_archive_extract(mz_zip_archive *zip_archive, const char *dir, #else xattr = (info.m_external_attr >> 16) & 0xFFFF; if (xattr > 0 && xattr <= MZ_UINT16_MAX) { - if (CHMOD(path, (mode_t)xattr) < 0) { + if (chmod(path, (mode_t)xattr) < 0) { err = ZIP_ENOPERM; goto out; } @@ -1684,7 +1688,7 @@ int zip_entry_fread(struct zip_t *zip, const char *filename) { xattr = (info.m_external_attr >> 16) & 0xFFFF; if (xattr > 0 && xattr <= MZ_UINT16_MAX) { - if (CHMOD(filename, (mode_t)xattr) < 0) { + if (chmod(filename, (mode_t)xattr) < 0) { return ZIP_ENOPERM; } } From cfbb0f8a0f1bfe6ea655464c6564fd1bfc94fe72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Podg=C3=B3rski?= Date: Sat, 29 Jun 2024 16:17:46 +0200 Subject: [PATCH 4/4] Address some fixes --- src/miniz.h | 85 +++++++++---- src/zip.c | 289 +++++++++++++++++++++++---------------------- src/zip.h | 2 +- test/test_offset.c | 2 +- 4 files changed, 218 insertions(+), 160 deletions(-) diff --git a/src/miniz.h b/src/miniz.h index 70a62f8..76e6706 100644 --- a/src/miniz.h +++ b/src/miniz.h @@ -1729,9 +1729,9 @@ MINIZ_EXPORT mz_bool mz_zip_writer_add_read_buf_callback( mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void *callback_opaque, mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, - mz_uint level_and_flags, const char *user_extra_data_local, - mz_uint user_extra_data_local_len, const char *user_extra_data_central, - mz_uint user_extra_data_central_len); + mz_uint level_and_flags, mz_uint32 ext_attributes, + const char *user_extra_data_local, mz_uint user_extra_data_local_len, + const char *user_extra_data_central, mz_uint user_extra_data_central_len); #ifndef MINIZ_NO_STDIO /* Adds the contents of a disk file to an archive. This function also records @@ -1741,14 +1741,15 @@ MINIZ_EXPORT mz_bool mz_zip_writer_add_read_buf_callback( * just set to MZ_DEFAULT_COMPRESSION. */ MINIZ_EXPORT mz_bool mz_zip_writer_add_file( mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, - const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, + mz_uint32 ext_attributes); /* Like mz_zip_writer_add_file(), except the file data is read from the * specified FILE stream. */ MINIZ_EXPORT mz_bool mz_zip_writer_add_cfile( mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, - mz_uint16 comment_size, mz_uint level_and_flags, + mz_uint16 comment_size, mz_uint level_and_flags, mz_uint32 ext_attributes, const char *user_extra_data_local, mz_uint user_extra_data_local_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len); #endif @@ -2145,10 +2146,12 @@ int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, mz_stream stream; memset(&stream, 0, sizeof(stream)); +#if defined(__MINGW32__) || defined(__MINGW64__) || defined(__WATCOMC__) /* In case mz_ulong is 64-bits (argh I hate longs). */ +#else if ((mz_uint64)(source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; - +#endif stream.next_in = pSource; stream.avail_in = (mz_uint32)source_len; stream.next_out = pDest; @@ -2394,10 +2397,12 @@ int mz_uncompress2(unsigned char *pDest, mz_ulong *pDest_len, int status; memset(&stream, 0, sizeof(stream)); +#if defined(__MINGW32__) || defined(__MINGW64__) || defined(__WATCOMC__) /* In case mz_ulong is 64-bits (argh I hate longs). */ +#else if ((mz_uint64)(*pSource_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; - +#endif stream.next_in = pSource; stream.avail_in = (mz_uint32)*pSource_len; stream.next_out = pDest; @@ -4965,20 +4970,36 @@ static FILE *mz_fopen(const char *pFilename, const char *pMode) { WCHAR *wFilename = mz_utf8z_to_widechar(pFilename); WCHAR *wMode = mz_utf8z_to_widechar(pMode); FILE *pFile = NULL; +#ifdef ZIP_ENABLE_SHARABLE_FILE_OPEN + pFile = _wfopen(wFilename, wMode); +#else errno_t err = _wfopen_s(&pFile, wFilename, wMode); +#endif free(wFilename); free(wMode); +#ifdef ZIP_ENABLE_SHARABLE_FILE_OPEN + return pFile; +#else return err ? NULL : pFile; +#endif } static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) { WCHAR *wPath = mz_utf8z_to_widechar(pPath); WCHAR *wMode = mz_utf8z_to_widechar(pMode); FILE *pFile = NULL; +#ifdef ZIP_ENABLE_SHARABLE_FILE_OPEN + pFile = _wfreopen(wPath, wMode, pStream); +#else errno_t err = _wfreopen_s(&pFile, wPath, wMode, pStream); +#endif free(wPath); free(wMode); +#ifdef ZIP_ENABLE_SHARABLE_FILE_OPEN + return pFile; +#else return err ? NULL : pFile; +#endif } #if defined(__MINGW32__) @@ -4997,6 +5018,13 @@ static int mz_stat64(const char *path, struct __stat64 *buffer) { } #endif +static int mz_mkdir(const char *pDirname) { + WCHAR *wDirname = mz_utf8z_to_widechar(pDirname); + int res = _wmkdir(wDirname); + free(wDirname); + return res; +} + #ifndef MINIZ_NO_TIME #include #endif @@ -5016,8 +5044,9 @@ static int mz_stat64(const char *path, struct __stat64 *buffer) { #define MZ_FFLUSH fflush #define MZ_FREOPEN mz_freopen #define MZ_DELETE_FILE remove +#define MZ_MKDIR(d) mz_mkdir(d) -#elif defined(__WATCOMC__) +#elif defined(__MINGW32__) || defined(__WATCOMC__) #ifndef MINIZ_NO_TIME #include #endif @@ -5032,6 +5061,7 @@ static int mz_stat64(const char *path, struct __stat64 *buffer) { #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove +#define MZ_MKDIR(d) _mkdir(d) #elif defined(__TINYC__) #ifndef MINIZ_NO_TIME @@ -5048,6 +5078,11 @@ static int mz_stat64(const char *path, struct __stat64 *buffer) { #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove +#if defined(_WIN32) || defined(_WIN64) +#define MZ_MKDIR(d) _mkdir(d) +#else +#define MZ_MKDIR(d) mkdir(d, 0755) +#endif #elif defined(__USE_LARGEFILE64) /* gcc, clang */ #ifndef MINIZ_NO_TIME @@ -5064,6 +5099,7 @@ static int mz_stat64(const char *path, struct __stat64 *buffer) { #define MZ_FFLUSH fflush #define MZ_FREOPEN(p, m, s) freopen64(p, m, s) #define MZ_DELETE_FILE remove +#define MZ_MKDIR(d) mkdir(d, 0755) #elif defined(__APPLE__) || defined(__FreeBSD__) || \ (defined(__linux__) && defined(__x86_64__)) @@ -5081,6 +5117,7 @@ static int mz_stat64(const char *path, struct __stat64 *buffer) { #define MZ_FFLUSH fflush #define MZ_FREOPEN(p, m, s) freopen(p, m, s) #define MZ_DELETE_FILE remove +#define MZ_MKDIR(d) mkdir(d, 0755) #else #pragma message( \ @@ -5104,9 +5141,17 @@ static int mz_stat64(const char *path, struct __stat64 *buffer) { #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove +#define MZ_MKDIR(d) mkdir(d, 0755) #endif /* #ifdef _MSC_VER */ #endif /* #ifdef MINIZ_NO_STDIO */ +#ifndef CHMOD +// Upon successful completion, a value of 0 is returned. +// Otherwise, a value of -1 is returned and errno is set to indicate the error. +// int chmod(const char *path, mode_t mode); +#define CHMOD(f, m) chmod(f, m) +#endif + #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) /* Various ZIP archive enums. To completely avoid cross platform compiler @@ -8687,12 +8732,12 @@ mz_bool mz_zip_writer_add_read_buf_callback( mz_zip_archive *pZip, const char *pArchive_name, mz_file_read_func read_callback, void *callback_opaque, mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, - mz_uint level_and_flags, const char *user_extra_data, - mz_uint user_extra_data_len, const char *user_extra_data_central, - mz_uint user_extra_data_central_len) { + mz_uint level_and_flags, mz_uint32 ext_attributes, + const char *user_extra_data, mz_uint user_extra_data_len, + const char *user_extra_data_central, mz_uint user_extra_data_central_len) { mz_uint16 gen_flags; mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; - mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; + mz_uint16 method = 0, dos_time = 0, dos_date = 0; mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, comp_size = 0; size_t archive_name_size; @@ -9083,20 +9128,20 @@ static size_t mz_file_read_func_stdio(void *pOpaque, mz_uint64 file_ofs, mz_bool mz_zip_writer_add_cfile( mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 max_size, const MZ_TIME_T *pFile_time, const void *pComment, - mz_uint16 comment_size, mz_uint level_and_flags, + mz_uint16 comment_size, mz_uint level_and_flags, mz_uint32 ext_attributes, const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len) { return mz_zip_writer_add_read_buf_callback( pZip, pArchive_name, mz_file_read_func_stdio, pSrc_file, max_size, - pFile_time, pComment, comment_size, level_and_flags, user_extra_data, - user_extra_data_len, user_extra_data_central, + pFile_time, pComment, comment_size, level_and_flags, ext_attributes, + user_extra_data, user_extra_data_len, user_extra_data_central, user_extra_data_central_len); } mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, - mz_uint16 comment_size, - mz_uint level_and_flags) { + mz_uint16 comment_size, mz_uint level_and_flags, + mz_uint32 ext_attributes) { MZ_FILE *pSrc_file = NULL; mz_uint64 uncomp_size = 0; MZ_TIME_T file_modified_time; @@ -9119,9 +9164,9 @@ mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, uncomp_size = MZ_FTELL64(pSrc_file); MZ_FSEEK64(pSrc_file, 0, SEEK_SET); - status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, - pFile_time, pComment, comment_size, - level_and_flags, NULL, 0, NULL, 0); + status = mz_zip_writer_add_cfile( + pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, + comment_size, level_and_flags, ext_attributes, NULL, 0, NULL, 0); MZ_FCLOSE(pSrc_file); diff --git a/src/zip.c b/src/zip.c index d35cd4c..2cb8467 100644 --- a/src/zip.c +++ b/src/zip.c @@ -13,19 +13,19 @@ #include #include -#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ +#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ defined(__MINGW32__) /* Win32, DOS, MSVC, MSVS */ #include -#define HAS_DEVICE(P) \ - ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) && \ +#define HAS_DEVICE(P) \ + ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) && \ (P)[1] == ':') #define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE(P) ? 2 : 0) #else -#include // needed for symlink() +#include // needed for symlink() #endif @@ -63,12 +63,12 @@ #define ISSLASH(C) ((C) == '/' || (C) == '\\') #endif -#define CLEANUP(ptr) \ - do { \ - if (ptr) { \ - free((void *)ptr); \ - ptr = NULL; \ - } \ +#define CLEANUP(ptr) \ + do { \ + if (ptr) { \ + free((void *)ptr); \ + ptr = NULL; \ + } \ } while (0) #define UNX_IFDIR 0040000 /* Unix directory */ @@ -172,7 +172,8 @@ static const char *zip_basename(const char *name) { } /* If NAME is all slashes, arrange to return `/'. */ - if (*base == '\0' && ISSLASH(*name) && all_slashes) --base; + if (*base == '\0' && ISSLASH(*name) && all_slashes) + --base; return base; } @@ -192,7 +193,7 @@ static int zip_mkpath(char *path) { } for (p = path + len; *p && len < MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE; p++) { if (ISSLASH(*p) && ((!has_device && len > 0) || (has_device && len > 2))) { -#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ +#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ defined(__MINGW32__) #else if ('\\' == *p) { @@ -200,11 +201,7 @@ static int zip_mkpath(char *path) { } #endif -#if defined(WIN32) - if (_mkdir(npath) == -1) { -#else - if (mkdir(npath, 0777) == -1) { -#endif + if (MZ_MKDIR(npath) == -1) { if (errno != EEXIST) { return ZIP_EMKDIR; } @@ -278,7 +275,7 @@ static char *zip_name_normalize(char *name, char *const nname, size_t len) { if (ISSLASH(c)) { if (ncpy > 0 && !zip_strchr_match(&nname[offn], ncpy, '.')) { offn += ncpy; - nname[offn++] = c; // append '/' + nname[offn++] = c; // append '/' } ncpy = 0; } else { @@ -382,12 +379,12 @@ static int zip_archive_extract(mz_zip_archive *zip_archive, const char *dir, if ((((info.m_version_made_by >> 8) == 3) || ((info.m_version_made_by >> 8) == - 19)) // if zip is produced on Unix or macOS (3 and 19 from - // section 4.4.2.2 of zip standard) + 19)) // if zip is produced on Unix or macOS (3 and 19 from + // section 4.4.2.2 of zip standard) && info.m_external_attr & - (0x20 << 24)) { // and has sym link attribute (0x80 is file, - // 0x40 is directory) -#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ + (0x20 << 24)) { // and has sym link attribute (0x80 is file, + // 0x40 is directory) +#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ defined(__MINGW32__) #else if (info.m_uncomp_size > MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE || @@ -413,11 +410,11 @@ static int zip_archive_extract(mz_zip_archive *zip_archive, const char *dir, } #if defined(_MSC_VER) || defined(PS4) - (void)xattr; // unused + (void)xattr; // unused #else xattr = (info.m_external_attr >> 16) & 0xFFFF; if (xattr > 0 && xattr <= MZ_UINT16_MAX) { - if (chmod(path, (mode_t)xattr) < 0) { + if (CHMOD(path, (mode_t)xattr) < 0) { err = ZIP_ENOPERM; goto out; } @@ -719,7 +716,7 @@ static ssize_t zip_file_move(MZ_FILE *m_pFile, const mz_uint64 to, static ssize_t zip_files_move(struct zip_t *zip, mz_uint64 writen_num, mz_uint64 read_num, size_t length) { ssize_t n = 0; - const size_t page_size = 1 << 12; // 4K + const size_t page_size = 1 << 12; // 4K mz_zip_internal_state *pState = zip->archive.m_pState; mz_uint8 *move_buf = (mz_uint8 *)calloc(1, page_size); @@ -955,7 +952,8 @@ struct zip_t *zip_openwitherror(const char *zipname, int level, char mode, goto cleanup; } - if (level < 0) level = MZ_DEFAULT_LEVEL; + if (level < 0) + level = MZ_DEFAULT_LEVEL; if ((level & 0xF) > MZ_UBER_COMPRESSION) { // Wrong compression level *errnum = ZIP_EINVLVL; @@ -972,56 +970,56 @@ struct zip_t *zip_openwitherror(const char *zipname, int level, char mode, zip->level = (mz_uint)level; zip->entry.index = -1; switch (mode) { - case 'w': - // Create a new archive. - if (!mz_zip_writer_init_file_v2(&(zip->archive), zipname, 0, - MZ_ZIP_FLAG_WRITE_ZIP64)) { - // Cannot initialize zip_archive writer - *errnum = ZIP_EWINIT; - goto cleanup; - } - break; - - case 'r': - if (!mz_zip_reader_init_file_v2( - &(zip->archive), zipname, - zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) { - // An archive file does not exist or cannot initialize - // zip_archive reader - *errnum = ZIP_ERINIT; - goto cleanup; - } - break; - - case 'a': - case 'd': { - MZ_FILE *fp = MZ_FOPEN(zipname, "r+b"); - if (!fp) { - *errnum = ZIP_EOPNFILE; - goto cleanup; - } - if (!mz_zip_reader_init_cfile( - &(zip->archive), fp, 0, - zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) { - // An archive file does not exist or cannot initialize zip_archive - // reader - *errnum = ZIP_ERINIT; - fclose(fp); - goto cleanup; - } - if (!mz_zip_writer_init_from_reader_v2(&(zip->archive), zipname, 0)) { - *errnum = ZIP_EWRINIT; - fclose(fp); - mz_zip_reader_end(&(zip->archive)); - goto cleanup; - } - // The file pointer is now owned by the archive object. - zip->archive.m_zip_type = MZ_ZIP_TYPE_FILE; - } break; + case 'w': + // Create a new archive. + if (!mz_zip_writer_init_file_v2(&(zip->archive), zipname, 0, + MZ_ZIP_FLAG_WRITE_ZIP64)) { + // Cannot initialize zip_archive writer + *errnum = ZIP_EWINIT; + goto cleanup; + } + break; + + case 'r': + if (!mz_zip_reader_init_file_v2( + &(zip->archive), zipname, + zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0)) { + // An archive file does not exist or cannot initialize + // zip_archive reader + *errnum = ZIP_ERINIT; + goto cleanup; + } + break; - default: - *errnum = ZIP_EINVMODE; + case 'a': + case 'd': { + MZ_FILE *fp = MZ_FOPEN(zipname, "r+b"); + if (!fp) { + *errnum = ZIP_EOPNFILE; + goto cleanup; + } + if (!mz_zip_reader_init_cfile( + &(zip->archive), fp, 0, + zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) { + // An archive file does not exist or cannot initialize zip_archive + // reader + *errnum = ZIP_ERINIT; + fclose(fp); + goto cleanup; + } + if (!mz_zip_writer_init_from_reader_v2(&(zip->archive), zipname, 0)) { + *errnum = ZIP_EWRINIT; + fclose(fp); + mz_zip_reader_end(&(zip->archive)); goto cleanup; + } + // The file pointer is now owned by the archive object. + zip->archive.m_zip_type = MZ_ZIP_TYPE_FILE; + } break; + + default: + *errnum = ZIP_EINVMODE; + goto cleanup; } return zip; @@ -1062,7 +1060,7 @@ int zip_is64(struct zip_t *zip) { return (int)zip->archive.m_pState->m_zip64; } -int zip_get_archive_offset(struct zip_t *zip, uint64_t *offset) { +int zip_offset(struct zip_t *zip, uint64_t *offset) { if (!zip || !zip->archive.m_pState) { // zip_t handler or zip state is not initialized return ZIP_ENOINIT; @@ -1559,18 +1557,25 @@ int zip_entry_fwrite(struct zip_t *zip, const char *filename) { } #if defined(_WIN32) || defined(__WIN32__) || defined(DJGPP) - (void)modes; // unused + (void)modes; // unused #else /* Initialize with permission bits--which are not implementation-optional */ modes = file_stat.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX); - if (S_ISDIR(file_stat.st_mode)) modes |= UNX_IFDIR; - if (S_ISREG(file_stat.st_mode)) modes |= UNX_IFREG; - if (S_ISLNK(file_stat.st_mode)) modes |= UNX_IFLNK; - if (S_ISBLK(file_stat.st_mode)) modes |= UNX_IFBLK; - if (S_ISCHR(file_stat.st_mode)) modes |= UNX_IFCHR; - if (S_ISFIFO(file_stat.st_mode)) modes |= UNX_IFIFO; - if (S_ISSOCK(file_stat.st_mode)) modes |= UNX_IFSOCK; + if (S_ISDIR(file_stat.st_mode)) + modes |= UNX_IFDIR; + if (S_ISREG(file_stat.st_mode)) + modes |= UNX_IFREG; + if (S_ISLNK(file_stat.st_mode)) + modes |= UNX_IFLNK; + if (S_ISBLK(file_stat.st_mode)) + modes |= UNX_IFBLK; + if (S_ISCHR(file_stat.st_mode)) + modes |= UNX_IFCHR; + if (S_ISFIFO(file_stat.st_mode)) + modes |= UNX_IFIFO; + if (S_ISSOCK(file_stat.st_mode)) + modes |= UNX_IFSOCK; zip->entry.external_attr = (modes << 16) | !(file_stat.st_mode & S_IWUSR); if ((file_stat.st_mode & S_IFMT) == S_IFDIR) { zip->entry.external_attr |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; @@ -1679,7 +1684,7 @@ int zip_entry_fread(struct zip_t *zip, const char *filename) { } #if defined(_MSC_VER) || defined(PS4) - (void)xattr; // unused + (void)xattr; // unused #else if (!mz_zip_reader_file_stat(pzip, idx, &info)) { // Cannot get information about zip archive; @@ -1688,7 +1693,7 @@ int zip_entry_fread(struct zip_t *zip, const char *filename) { xattr = (info.m_external_attr >> 16) & 0xFFFF; if (xattr > 0 && xattr <= MZ_UINT16_MAX) { - if (chmod(filename, (mode_t)xattr) < 0) { + if (CHMOD(filename, (mode_t)xattr) < 0) { return ZIP_ENOPERM; } } @@ -1913,7 +1918,8 @@ struct zip_t *zip_cstream_openwitherror(FILE *stream, int level, char mode, goto cleanup; } - if (level < 0) level = MZ_DEFAULT_LEVEL; + if (level < 0) + level = MZ_DEFAULT_LEVEL; if ((level & 0xF) > MZ_UBER_COMPRESSION) { // Wrong compression level *errnum = ZIP_EINVLVL; @@ -1929,49 +1935,49 @@ struct zip_t *zip_cstream_openwitherror(FILE *stream, int level, char mode, zip->level = (mz_uint)level; switch (mode) { - case 'w': - // Create a new archive. - if (!mz_zip_writer_init_cfile(&(zip->archive), stream, - MZ_ZIP_FLAG_WRITE_ZIP64)) { - // Cannot initialize zip_archive writer - *errnum = ZIP_EWINIT; - goto cleanup; - } - break; - - case 'r': - if (!mz_zip_reader_init_cfile( - &(zip->archive), stream, 0, - zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) { - // An archive file does not exist or cannot initialize - // zip_archive reader - *errnum = ZIP_ERINIT; - goto cleanup; - } - break; - - case 'a': - case 'd': - if (!mz_zip_reader_init_cfile( - &(zip->archive), stream, 0, - zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) { - // An archive file does not exist or cannot initialize - // zip_archive reader - *errnum = ZIP_ERINIT; + case 'w': + // Create a new archive. + if (!mz_zip_writer_init_cfile(&(zip->archive), stream, + MZ_ZIP_FLAG_WRITE_ZIP64)) { + // Cannot initialize zip_archive writer + *errnum = ZIP_EWINIT; + goto cleanup; + } + break; + + case 'r': + if (!mz_zip_reader_init_cfile( + &(zip->archive), stream, 0, + zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) { + // An archive file does not exist or cannot initialize + // zip_archive reader + *errnum = ZIP_ERINIT; + goto cleanup; + } + break; + + case 'a': + case 'd': + if (!mz_zip_reader_init_cfile( + &(zip->archive), stream, 0, + zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) { + // An archive file does not exist or cannot initialize + // zip_archive reader + *errnum = ZIP_ERINIT; + goto cleanup; + } + if ((mode == 'a' || mode == 'd')) { + if (!mz_zip_writer_init_from_reader_v2(&(zip->archive), NULL, 0)) { + *errnum = ZIP_EWRINIT; + mz_zip_reader_end(&(zip->archive)); goto cleanup; } - if ((mode == 'a' || mode == 'd')) { - if (!mz_zip_writer_init_from_reader_v2(&(zip->archive), NULL, 0)) { - *errnum = ZIP_EWRINIT; - mz_zip_reader_end(&(zip->archive)); - goto cleanup; - } - } - break; + } + break; - default: - *errnum = ZIP_EINVMODE; - goto cleanup; + default: + *errnum = ZIP_EINVMODE; + goto cleanup; } return zip; @@ -2025,28 +2031,35 @@ int zip_create(const char *zipname, const char *filenames[], size_t len) { } #if defined(_WIN32) || defined(__WIN32__) || defined(DJGPP) - (void)modes; // unused + (void)modes; // unused #else /* Initialize with permission bits--which are not implementation-optional */ modes = file_stat.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX); - if (S_ISDIR(file_stat.st_mode)) modes |= UNX_IFDIR; - if (S_ISREG(file_stat.st_mode)) modes |= UNX_IFREG; - if (S_ISLNK(file_stat.st_mode)) modes |= UNX_IFLNK; - if (S_ISBLK(file_stat.st_mode)) modes |= UNX_IFBLK; - if (S_ISCHR(file_stat.st_mode)) modes |= UNX_IFCHR; - if (S_ISFIFO(file_stat.st_mode)) modes |= UNX_IFIFO; - if (S_ISSOCK(file_stat.st_mode)) modes |= UNX_IFSOCK; + if (S_ISDIR(file_stat.st_mode)) + modes |= UNX_IFDIR; + if (S_ISREG(file_stat.st_mode)) + modes |= UNX_IFREG; + if (S_ISLNK(file_stat.st_mode)) + modes |= UNX_IFLNK; + if (S_ISBLK(file_stat.st_mode)) + modes |= UNX_IFBLK; + if (S_ISCHR(file_stat.st_mode)) + modes |= UNX_IFCHR; + if (S_ISFIFO(file_stat.st_mode)) + modes |= UNX_IFIFO; + if (S_ISSOCK(file_stat.st_mode)) + modes |= UNX_IFSOCK; ext_attributes = (modes << 16) | !(file_stat.st_mode & S_IWUSR); if ((file_stat.st_mode & S_IFMT) == S_IFDIR) { ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; } #endif - if (!mz_zip_writer_add_file( - &zip_archive, zip_basename(name), name, "", 0, - ZIP_DEFAULT_COMPRESSION_LEVEL | ext_attributes)) { + if (!mz_zip_writer_add_file(&zip_archive, zip_basename(name), name, "", 0, + ZIP_DEFAULT_COMPRESSION_LEVEL, + ext_attributes)) { // Cannot add file to zip_archive err = ZIP_ENOFILE; break; diff --git a/src/zip.h b/src/zip.h index 0f870cb..dce99ff 100644 --- a/src/zip.h +++ b/src/zip.h @@ -170,7 +170,7 @@ extern ZIP_EXPORT int zip_is64(struct zip_t *zip); * * @return the return code - 0 if successful, negative number (< 0) on error. */ -extern ZIP_EXPORT int zip_get_archive_offset(struct zip_t *zip, uint64_t *offset); +extern ZIP_EXPORT int zip_offset(struct zip_t *zip, uint64_t *offset); /** * Opens an entry by name in the zip archive. diff --git a/test/test_offset.c b/test/test_offset.c index 187eefa..c4bf2de 100644 --- a/test/test_offset.c +++ b/test/test_offset.c @@ -60,7 +60,7 @@ MU_TEST(test_read) { struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); mu_check(zip != NULL); - zip_get_archive_offset(zip, &archive_offset); + zip_offset(zip, &archive_offset); mu_assert_int_eq(strlen(HEADERDATA1), archive_offset); mu_assert_int_eq(2, zip_entries_total(zip));