Added ability to zip/unzip central dir.

Added ability to set extra flags with zip writer.
Changed mask name to be unique based off disk number and offset.
Fixed bug with storing directories when encryption turned on.
This commit is contained in:
Nathan Moinvaziri 2018-10-20 10:37:10 -07:00
parent 413822a040
commit fa620e473f
4 changed files with 202 additions and 14 deletions

View File

@ -34,6 +34,7 @@ typedef struct minizip_opt_s {
uint8_t overwrite;
uint8_t append;
int64_t disk_size;
uint8_t zip_cd;
#ifdef HAVE_AES
uint8_t aes;
#endif
@ -82,6 +83,7 @@ int32_t minizip_help(void)
" -1 Compress faster\n" \
" -9 Compress better\n" \
" -k Disk size in KB\n" \
" -z Zip central directory" \
" -p Encryption password\n");
#ifdef HAVE_AES
printf(" -s AES encryption\n");
@ -113,7 +115,8 @@ int32_t minizip_list(const char *path)
mz_zip_reader_create(&reader);
err = mz_zip_reader_open_file(reader, path);
if (err == MZ_OK)
err = mz_zip_reader_unzip_cd(reader);
if (err != MZ_OK)
{
printf("Error %d opening zip file %s\n", err, path);
@ -277,6 +280,7 @@ int32_t minizip_add(const char *path, const char *password, minizip_opt *options
int32_t err = MZ_OK;
int32_t err_close = MZ_OK;
int32_t i = 0;
int32_t flags = 0;
const char *filename_in_zip = NULL;
@ -288,6 +292,8 @@ int32_t minizip_add(const char *path, const char *password, minizip_opt *options
mz_zip_writer_set_compress_level(writer, options->compress_level);
mz_zip_writer_set_overwrite_cb(writer, options, minizip_add_overwrite_cb);
mz_zip_writer_set_progress_cb(writer, options, minizip_add_progress_cb);
if (options->zip_cd)
mz_zip_writer_set_flags(writer, MZ_ZIP_FLAG_MASK_LOCAL_INFO);
err = mz_zip_writer_open_file(writer, path, options->disk_size, options->append);
@ -307,6 +313,13 @@ int32_t minizip_add(const char *path, const char *password, minizip_opt *options
printf("Error %d opening zip for writing\n", err);
}
if (options->zip_cd)
{
if (password != NULL)
flags = MZ_ZIP_FLAG_ENCRYPTED;
mz_zip_writer_zip_cd(writer, options->compress_method, flags);
}
err_close = mz_zip_writer_close(writer);
if (err_close != MZ_OK)
{
@ -403,12 +416,15 @@ int32_t minizip_extract(const char *path, const char *pattern, const char *desti
}
else
{
err = mz_zip_reader_unzip_cd(reader);
if (err == MZ_OK)
err = mz_zip_reader_save_all(reader, destination);
if (err == MZ_END_OF_LIST && pattern != NULL)
printf("Files matching %s not found in zip file\n", pattern);
if (err != MZ_OK)
printf("Error %d saving zip entries to disk %s\n", err, path);
}
err_close = mz_zip_reader_close(reader);
if (err_close != MZ_OK)
{
@ -435,6 +451,8 @@ int32_t minizip_erase(const char *src_path, const char *target_path, int32_t arg
mz_zip_writer_create(&writer);
err = mz_zip_reader_open_file(reader, src_path);
if (err == MZ_OK)
err = mz_zip_reader_unzip_cd(reader);
if (err != MZ_OK)
{
printf("Error %d opening zip for reading %s\n", err, src_path);
@ -554,6 +572,8 @@ int main(int argc, const char *argv[])
options.overwrite = 1;
else if ((c == 'i') || (c == 'I'))
options.include_path = 1;
else if ((c == 'z') || (c == 'Z'))
options.zip_cd = 1;
else if ((c >= '0') && (c <= '9'))
{
options.compress_level = (c - '0');

View File

@ -980,7 +980,7 @@ static int32_t mz_zip_entry_read_header(void *stream, uint8_t local, mz_zip_file
return err;
}
static int32_t mz_zip_entry_write_header(void *stream, uint8_t local, uint64_t entry_index, mz_zip_file *file_info)
static int32_t mz_zip_entry_write_header(void *stream, uint8_t local, mz_zip_file *file_info)
{
uint64_t ntfs_time = 0;
uint32_t reserved = 0;
@ -1003,7 +1003,7 @@ static int32_t mz_zip_entry_write_header(void *stream, uint8_t local, uint64_t e
uint8_t mask = 0;
uint8_t write_end_slash = 0;
const char *filename = NULL;
char indexname[32];
char masked_name[64];
void *extrafield_ms = NULL;
if (file_info == NULL)
@ -1167,8 +1167,9 @@ static int32_t mz_zip_entry_write_header(void *stream, uint8_t local, uint64_t e
if (mask)
{
snprintf(indexname, sizeof(indexname), "%"PRIx64, entry_index + 1);
filename = indexname;
snprintf(masked_name, sizeof(masked_name), "%"PRIx32"_%"PRIx64,
file_info->disk_number, file_info->disk_offset);
filename = masked_name;
}
else
{
@ -1587,6 +1588,7 @@ int32_t mz_zip_entry_write_open(void *handle, const mz_zip_file *file_info, int1
{
mz_zip *zip = (mz_zip *)handle;
int64_t disk_number = 0;
uint8_t is_dir = 0;
int32_t err = MZ_OK;
#if defined(MZ_ZIP_NO_ENCRYPTION)
@ -1639,10 +1641,15 @@ int32_t mz_zip_entry_write_open(void *handle, const mz_zip_file *file_info, int1
zip->file_info.flag |= MZ_ZIP_FLAG_LZMA_EOS_MARKER;
#endif
zip->file_info.flag |= MZ_ZIP_FLAG_DATA_DESCRIPTOR;
if (mz_zip_attrib_is_dir(zip->file_info.external_fa, zip->file_info.version_madeby) == MZ_OK)
is_dir = 1;
if (!is_dir)
{
zip->file_info.flag |= MZ_ZIP_FLAG_DATA_DESCRIPTOR;
if (password != NULL)
zip->file_info.flag |= MZ_ZIP_FLAG_ENCRYPTED;
}
mz_stream_get_prop_int64(zip->stream, MZ_STREAM_PROP_DISK_NUMBER, &disk_number);
zip->file_info.disk_number = (uint32_t)disk_number;
@ -1656,7 +1663,7 @@ int32_t mz_zip_entry_write_open(void *handle, const mz_zip_file *file_info, int1
zip->file_info.aes_encryption_mode = MZ_AES_ENCRYPTION_MODE_256;
#endif
if ((compress_level == 0) || (mz_zip_attrib_is_dir(zip->file_info.external_fa, zip->file_info.version_madeby) == MZ_OK))
if ((compress_level == 0) || (is_dir))
zip->file_info.compression_method = MZ_COMPRESS_METHOD_STORE;
#ifdef MZ_ZIP_NO_COMPRESSION
@ -1664,7 +1671,7 @@ int32_t mz_zip_entry_write_open(void *handle, const mz_zip_file *file_info, int1
err = MZ_SUPPORT_ERROR;
#endif
if (err == MZ_OK)
err = mz_zip_entry_write_header(zip->stream, 1, zip->number_entry, &zip->file_info);
err = mz_zip_entry_write_header(zip->stream, 1, &zip->file_info);
if (err == MZ_OK)
err = mz_zip_entry_open_int(handle, raw, compress_level, password);
@ -1838,7 +1845,7 @@ int32_t mz_zip_entry_close_raw(void *handle, int64_t uncompressed_size, uint32_t
zip->file_info.uncompressed_size = uncompressed_size;
if (err == MZ_OK)
err = mz_zip_entry_write_header(zip->cd_mem_stream, 0, 0, &zip->file_info);
err = mz_zip_entry_write_header(zip->cd_mem_stream, 0, &zip->file_info);
zip->number_entry += 1;
}

View File

@ -31,6 +31,11 @@
/***************************************************************************/
#define MZ_ZIP_CD_NAME ("__cdcd__")
#define MZ_ZIP_CD_EXTENSION (0xcdcd)
/***************************************************************************/
typedef struct mz_zip_reader_s {
void *zip_handle;
void *file_stream;
@ -224,6 +229,78 @@ int32_t mz_zip_reader_close(void *handle)
/***************************************************************************/
int32_t mz_zip_reader_unzip_cd(void *handle)
{
mz_zip_reader *reader = (mz_zip_reader *)handle;
mz_zip_file *cd_info = NULL;
void *cd_mem_stream = NULL;
void *new_cd_stream = NULL;
void *extrafield_ms = NULL;
uint64_t number_entry = 0;
int32_t err = MZ_OK;
uint16_t field_type = 0;
uint16_t field_length = 0;
err = mz_zip_reader_goto_first_entry(handle);
if (err != MZ_OK)
return err;
err = mz_zip_reader_entry_get_info(handle, &cd_info);
if (err != MZ_OK)
return err;
if (strcmp(cd_info->filename, MZ_ZIP_CD_NAME) != 0)
return mz_zip_reader_goto_first_entry(handle);
err = mz_zip_reader_entry_open(handle);
if (err != MZ_OK)
return err;
mz_stream_mem_create(&extrafield_ms);
mz_stream_mem_set_buffer(extrafield_ms, (void *)cd_info->extrafield, cd_info->extrafield_size);
do
{
err = mz_stream_read_uint16(extrafield_ms, &field_type);
if (err == MZ_OK)
err = mz_stream_read_uint16(extrafield_ms, &field_length);
if (err != MZ_OK)
break;
if (field_type == MZ_ZIP_CD_EXTENSION)
{
err = mz_stream_read_uint64(extrafield_ms, &number_entry);
break;
}
err = mz_stream_seek(extrafield_ms, field_length, SEEK_CUR);
}
while (err == MZ_OK);
mz_stream_mem_delete(&extrafield_ms);
if (err != MZ_OK)
return err;
if (field_type != MZ_ZIP_CD_EXTENSION)
return MZ_FORMAT_ERROR;
mz_zip_get_cd_mem_stream(reader->zip_handle, &cd_mem_stream);
if (mz_stream_mem_is_open(cd_mem_stream) != MZ_OK)
mz_stream_mem_open(cd_mem_stream, NULL, MZ_OPEN_MODE_CREATE);
err = mz_stream_copy_stream(cd_mem_stream, NULL, handle, mz_zip_reader_entry_read, (int32_t)cd_info->uncompressed_size);
if (err == MZ_OK)
{
mz_zip_set_cd_stream(reader->zip_handle, 0, cd_mem_stream);
mz_zip_set_number_entry(reader->zip_handle, number_entry);
err = mz_zip_reader_goto_first_entry(handle);
}
mz_stream_mem_delete(&new_cd_stream);
return err;
}
/***************************************************************************/
static int32_t mz_zip_reader_locate_entry_cb(void *handle, void *userdata, mz_zip_file *file_info)
{
mz_zip_reader *reader = (mz_zip_reader *)userdata;
@ -764,6 +841,7 @@ typedef struct mz_zip_writer_s {
const char *password;
uint16_t compress_method;
int16_t compress_level;
int32_t flags;
uint8_t aes;
uint8_t raw;
uint8_t buffer[UINT16_MAX];
@ -939,6 +1017,69 @@ int32_t mz_zip_writer_close(void *handle)
/***************************************************************************/
int32_t mz_zip_writer_zip_cd(void *handle, uint16_t compress_method, int32_t flags)
{
mz_zip_writer *writer = (mz_zip_writer *)handle;
mz_zip_file cd_file;
time_t current_time = 0;
uint64_t number_entry = 0;
int64_t cd_mem_length = 0;
int32_t err = MZ_OK;
int32_t extrafield_size = 0;
void *extrafield_ms = NULL;
void *cd_mem_stream = NULL;
memset(&cd_file, 0, sizeof(cd_file));
mz_zip_get_number_entry(writer->zip_handle, &number_entry);
mz_zip_get_cd_mem_stream(writer->zip_handle, &cd_mem_stream);
mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_END);
cd_mem_length = (uint32_t)mz_stream_tell(cd_mem_stream);
mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_SET);
current_time = time(NULL);
cd_file.filename = MZ_ZIP_CD_NAME;
cd_file.modified_date = current_time;
cd_file.version_madeby = MZ_VERSION_MADEBY;
cd_file.compression_method = compress_method;
cd_file.uncompressed_size = (int32_t)cd_mem_length;
cd_file.flag = MZ_ZIP_FLAG_UTF8 | flags;
mz_stream_mem_create(&extrafield_ms);
mz_stream_mem_open(extrafield_ms, NULL, MZ_OPEN_MODE_CREATE);
mz_stream_write_uint16(extrafield_ms, MZ_ZIP_CD_EXTENSION);
mz_stream_write_uint16(extrafield_ms, 8);
mz_stream_write_uint64(extrafield_ms, number_entry);
mz_stream_mem_get_buffer(extrafield_ms, &cd_file.extrafield);
mz_stream_mem_get_buffer_length(extrafield_ms, &extrafield_size);
cd_file.extrafield_size = (uint16_t)extrafield_size;
#ifdef HAVE_AES
if (flags & MZ_ZIP_FLAG_ENCRYPTED)
cd_file.aes_version = MZ_AES_VERSION;
#endif
err = mz_zip_writer_entry_open(handle, &cd_file);
if (err == MZ_OK)
{
mz_stream_copy_stream(handle, mz_zip_writer_entry_write, cd_mem_stream, NULL, (int32_t)cd_mem_length);
mz_stream_seek(cd_mem_stream, 0, MZ_SEEK_SET);
mz_stream_mem_set_buffer_limit(cd_mem_stream, 0);
err = mz_zip_entry_close(writer->zip_handle);
}
mz_stream_mem_delete(&extrafield_ms);
return err;
}
/***************************************************************************/
int32_t mz_zip_writer_entry_open(void *handle, mz_zip_file *file_info)
{
mz_zip_writer *writer = (mz_zip_writer *)handle;
@ -1154,7 +1295,7 @@ int32_t mz_zip_writer_add_file(void *handle, const char *path, const char *filen
file_info.compression_method = writer->compress_method;
file_info.filename = filename;
file_info.uncompressed_size = mz_os_get_file_size(path);
file_info.flag = MZ_ZIP_FLAG_UTF8;
file_info.flag = MZ_ZIP_FLAG_UTF8 | writer->flags;
#ifdef HAVE_AES
if (writer->aes)
@ -1355,6 +1496,12 @@ void mz_zip_writer_set_compress_level(void *handle, int16_t compress_level)
writer->compress_level = compress_level;
}
void mz_zip_writer_set_flags(void *handle, int32_t flags)
{
mz_zip_writer *writer = (mz_zip_writer *)handle;
writer->flags = flags;
}
void mz_zip_writer_set_overwrite_cb(void *handle, void *userdata, mz_zip_writer_overwrite_cb cb)
{
mz_zip_writer *writer = (mz_zip_writer *)handle;
@ -1411,6 +1558,7 @@ void *mz_zip_writer_create(void **handle)
{
memset(writer, 0, sizeof(mz_zip_writer));
writer->aes = 1;
writer->compress_method = MZ_COMPRESS_METHOD_DEFLATE;
writer->compress_level = MZ_COMPRESS_LEVEL_BEST;
writer->progress_cb_interval_ms = MZ_DEFAULT_PROGRESS_INTERVAL;

View File

@ -49,6 +49,11 @@ int32_t mz_zip_reader_close(void *handle);
/***************************************************************************/
int32_t mz_zip_reader_unzip_cd(void *handle);
// Unzip the central directory
/***************************************************************************/
int32_t mz_zip_reader_goto_first_entry(void *handle);
// Goto the first entry in the zip file that matches the pattern
@ -160,6 +165,11 @@ int32_t mz_zip_writer_close(void *handle);
/***************************************************************************/
int32_t mz_zip_writer_zip_cd(void *handle, uint16_t compress_method, int32_t flags);
// Zip the central directory
/***************************************************************************/
int32_t mz_zip_writer_entry_open(void *handle, mz_zip_file *file_info);
// Opens an entry in the zip file for writing
@ -212,6 +222,9 @@ void mz_zip_writer_set_compress_method(void *handle, uint16_t compress_method
void mz_zip_writer_set_compress_level(void *handle, int16_t compress_level);
// Sets the compression level when adding files in zip
void mz_zip_writer_set_flags(void *handle, int32_t flags);
// Sets additional flags to be set when adding files in zip
void mz_zip_writer_set_overwrite_cb(void *handle, void *userdata, mz_zip_writer_overwrite_cb cb);
// Callback for what to do when zip file already exists