Skip to content

Commit

Permalink
Add zip_openwitherror and zip_stream_openwitherror (#310)
Browse files Browse the repository at this point in the history
* Add zip_openwitherror

* clang-format
  • Loading branch information
kuba-- authored Oct 2, 2023
1 parent 604d142 commit fb8df0f
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 13 deletions.
2 changes: 1 addition & 1 deletion src/miniz.h
Original file line number Diff line number Diff line change
Expand Up @@ -4986,7 +4986,7 @@ static int mz_mkdir(const char *pDirname) {

#else
#pragma message( \
"Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.")
"Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.")
#ifndef MINIZ_NO_TIME
#include <utime.h>
#endif
Expand Down
58 changes: 46 additions & 12 deletions src/zip.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ struct zip_entry_mark_t {
size_t lf_length;
};

static const char *const zip_errlist[30] = {
static const char *const zip_errlist[33] = {
NULL,
"not initialized\0",
"invalid entry name\0",
Expand Down Expand Up @@ -147,11 +147,14 @@ static const char *const zip_errlist[30] = {
"fseek error\0",
"fread error\0",
"fwrite error\0",
"cannot initialize reader\0",
"cannot initialize writer\0",
"cannot initialize writer from reader\0",
};

const char *zip_strerror(int errnum) {
errnum = -errnum;
if (errnum <= 0 || errnum >= 30) {
if (errnum <= 0 || errnum >= 33) {
return NULL;
}

Expand Down Expand Up @@ -354,8 +357,7 @@ static int zip_archive_extract(mz_zip_archive *zip_archive, const char *dir,
}

#if defined(_MSC_VER)
strncpy_s(&path[dirlen], filename_size, info.m_filename,
filename_size);
strncpy_s(&path[dirlen], filename_size, info.m_filename, filename_size);
#else
strncpy(&path[dirlen], info.m_filename, filename_size);
#endif
Expand All @@ -376,8 +378,9 @@ static int zip_archive_extract(mz_zip_archive *zip_archive, const char *dir,
defined(__MINGW32__)
#else
if (info.m_uncomp_size > MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE ||
!mz_zip_reader_extract_to_mem_no_alloc(zip_archive, i, symlink_to,
MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE, 0, NULL, 0)) {
!mz_zip_reader_extract_to_mem_no_alloc(
zip_archive, i, symlink_to, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE, 0,
NULL, 0)) {
err = ZIP_EMEMNOALLOC;
goto out;
}
Expand Down Expand Up @@ -812,23 +815,35 @@ static ssize_t zip_entries_delete_mark(struct zip_t *zip,
}

struct zip_t *zip_open(const char *zipname, int level, char mode) {
int errnum = 0;
return zip_openwitherror(zipname, level, mode, &errnum);
}

struct zip_t *zip_openwitherror(const char *zipname, int level, char mode,
int *errnum) {
struct zip_t *zip = NULL;
*errnum = 0;

if (!zipname || strlen(zipname) < 1) {
// zip_t archive name is empty or NULL
*errnum = ZIP_EINVZIPNAME;
goto cleanup;
}

if (level < 0)
level = MZ_DEFAULT_LEVEL;
if ((level & 0xF) > MZ_UBER_COMPRESSION) {
// Wrong compression level
*errnum = ZIP_EINVLVL;
goto cleanup;
}

zip = (struct zip_t *)calloc((size_t)1, sizeof(struct zip_t));
if (!zip)
if (!zip) {
// out of memory
*errnum = ZIP_EOOMEM;
goto cleanup;
}

zip->level = (mz_uint)level;
switch (mode) {
Expand All @@ -837,6 +852,7 @@ struct zip_t *zip_open(const char *zipname, int level, char mode) {
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;
Expand All @@ -847,6 +863,7 @@ struct zip_t *zip_open(const char *zipname, int level, char mode) {
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;
Expand All @@ -858,18 +875,21 @@ struct zip_t *zip_open(const char *zipname, int level, char mode) {
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)) {
*errnum = ZIP_EWRINIT;
mz_zip_reader_end(&(zip->archive));
goto cleanup;
}
}
break;

default:
*errnum = ZIP_EINVMODE;
goto cleanup;
}

Expand All @@ -886,16 +906,16 @@ void zip_close(struct zip_t *zip) {
// Always finalize, even if adding failed for some reason, so we have a
// valid central directory.
if (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) {
mz_zip_writer_finalize_archive(pZip);
mz_zip_writer_finalize_archive(pZip);
}

if (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING ||
if (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING ||
pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED) {
zip_archive_truncate(pZip);
mz_zip_writer_end(pZip);
zip_archive_truncate(pZip);
mz_zip_writer_end(pZip);
}
if (pZip->m_zip_mode == MZ_ZIP_MODE_READING) {
mz_zip_reader_end(pZip);
mz_zip_reader_end(pZip);
}

CLEANUP(zip);
Expand Down Expand Up @@ -1635,8 +1655,16 @@ int zip_stream_extract(const char *stream, size_t size, const char *dir,

struct zip_t *zip_stream_open(const char *stream, size_t size, int level,
char mode) {
int errnum = 0;
return zip_stream_openwitherror(stream, size, level, mode, &errnum);
}

struct zip_t *zip_stream_openwitherror(const char *stream, size_t size,
int level, char mode, int *errnum) {
struct zip_t *zip = (struct zip_t *)calloc((size_t)1, sizeof(struct zip_t));
if (!zip) {
// out of memory
*errnum = ZIP_EOOMEM;
return NULL;
}

Expand All @@ -1645,23 +1673,29 @@ struct zip_t *zip_stream_open(const char *stream, size_t size, int level,
}
if ((level & 0xF) > MZ_UBER_COMPRESSION) {
// Wrong compression level
*errnum = ZIP_EINVLVL;
goto cleanup;
}
zip->level = (mz_uint)level;

if ((stream != NULL) && (size > 0) && (mode == 'r')) {
if (!mz_zip_reader_init_mem(&(zip->archive), stream, size, 0)) {
*errnum = ZIP_ERINIT;
goto cleanup;
}
} else if ((stream == NULL) && (size == 0) && (mode == 'w')) {
// Create a new archive.
if (!mz_zip_writer_init_heap(&(zip->archive), 0, 1024)) {
// Cannot initialize zip_archive writer
*errnum = ZIP_EWINIT;
goto cleanup;
}
} else {
*errnum = ZIP_EINVMODE;
goto cleanup;
}

*errnum = 0;
return zip;

cleanup:
Expand Down
45 changes: 45 additions & 0 deletions src/zip.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ typedef long ssize_t; /* byte count or error */
#define ZIP_EFSEEK -27 // fseek error
#define ZIP_EFREAD -28 // fread error
#define ZIP_EFWRITE -29 // fwrite error
#define ZIP_ERINIT -30 // cannot initialize reader
#define ZIP_EWINIT -31 // cannot initialize writer
#define ZIP_EWRINIT -32 // cannot initialize writer from reader

/**
* Looks up the error message string corresponding to an error number.
Expand Down Expand Up @@ -124,6 +127,23 @@ struct zip_t;
extern ZIP_EXPORT struct zip_t *zip_open(const char *zipname, int level,
char mode);

/**
* Opens zip archive with compression level using the given mode.
* The function additionally returns @param errnum -
*
* @param zipname zip archive file name.
* @param level compression level (0-9 are the standard zlib-style levels).
* @param mode file access mode.
* - 'r': opens a file for reading/extracting (the file must exists).
* - 'w': creates an empty file for writing.
* - 'a': appends to an existing archive.
* @param errnum 0 on success, negative number (< 0) on error.
*
* @return the zip archive handler or NULL on error
*/
extern ZIP_EXPORT struct zip_t *
zip_openwitherror(const char *zipname, int level, char mode, int *errnum);

/**
* Closes the zip archive, releases resources - always finalize.
*
Expand Down Expand Up @@ -397,12 +417,37 @@ zip_stream_extract(const char *stream, size_t size, const char *dir,
*
* @param stream zip archive stream.
* @param size stream size.
* @param level compression level (0-9 are the standard zlib-style levels).
* @param mode file access mode.
* - 'r': opens a file for reading/extracting (the file must exists).
* - 'w': creates an empty file for writing.
* - 'a': appends to an existing archive.
*
* @return the zip archive handler or NULL on error
*/
extern ZIP_EXPORT struct zip_t *zip_stream_open(const char *stream, size_t size,
int level, char mode);

/**
* Opens zip archive stream into memory.
* The function additionally returns @param errnum -
*
* @param stream zip archive stream.
* @param size stream size.*
* @param level compression level (0-9 are the standard zlib-style levels).
* @param mode file access mode.
* - 'r': opens a file for reading/extracting (the file must exists).
* - 'w': creates an empty file for writing.
* - 'a': appends to an existing archive.
* @param errnum 0 on success, negative number (< 0) on error.
*
* @return the zip archive handler or NULL on error
*/
extern ZIP_EXPORT struct zip_t *zip_stream_openwitherror(const char *stream,
size_t size, int level,
char mode,
int *errnum);

/**
* Copy zip archive stream output buffer.
*
Expand Down
6 changes: 6 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,9 @@ add_executable(${test_permissions_out} test_permissions.c)
target_link_libraries(${test_permissions_out} zip)
add_test(NAME ${test_permissions_out} COMMAND ${test_permissions_out})
add_sanitizers(${test_permissions_out})

set(test_open_out test_open.out)
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})
62 changes: 62 additions & 0 deletions test/test_open.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include <stdio.h>
#include <stdlib.h>

#include <zip.h>

#include "minunit.h"

static char ZIPNAME[L_tmpnam + 1] = {0};

void test_setup(void) {
strncpy(ZIPNAME, "z-XXXXXX\0", L_tmpnam);
mktemp(ZIPNAME);
}

void test_teardown(void) { remove(ZIPNAME); }

MU_TEST(test_openwitherror) {
int errnum;
struct zip_t *zip =
zip_openwitherror(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'r', &errnum);
mu_check(zip == NULL);
mu_assert_int_eq(ZIP_ERINIT, errnum);

zip = zip_openwitherror(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w', &errnum);
mu_check(zip != NULL);
mu_assert_int_eq(0, errnum);

zip_close(zip);
}

MU_TEST(test_stream_openwitherror) {
int errnum;
struct zip_t *zip = zip_stream_openwitherror(
NULL, 0, ZIP_DEFAULT_COMPRESSION_LEVEL, 'r', &errnum);
mu_check(zip == NULL);
mu_assert_int_eq(ZIP_EINVMODE, errnum);

zip = zip_stream_openwitherror(NULL, 0, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w',
&errnum);
mu_check(zip != NULL);
mu_assert_int_eq(0, errnum);

zip_stream_close(zip);
}

MU_TEST_SUITE(test_entry_suite) {
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);

MU_RUN_TEST(test_openwitherror);
MU_RUN_TEST(test_stream_openwitherror);
}

#define UNUSED(x) (void)x

int main(int argc, char *argv[]) {
UNUSED(argc);
UNUSED(argv);

MU_RUN_SUITE(test_entry_suite);
MU_REPORT();
return MU_EXIT_CODE;
}

0 comments on commit fb8df0f

Please sign in to comment.