minizip-ng Documentation

repository·develop·Indexed 23 days ago

https://github.com/zlib-ng/minizip-ng

A feature-rich C library for creating, extracting, and manipulating ZIP archives. A modern successor to the original minizip, it supports ZIP64, disk splitting, and multiple compression methods including Zlib, BZIP2, LZMA, PPMD, XZ, and ZSTD. It provides encryption support via traditional PKWARE and WinZIP AES, Unicode (UTF-8) filename support, and a flexible stream-based I/O system featuring memory, buffered, and OS streams.

Tokens
27.6K
Snippets
107
Records
136
Agent score
80%

What's inside minizip-ng

  1. Overview of minizip-ng features

    develop

    minizip-ng is a C library for zip manipulation supporting Windows, macOS, and Linux. Key capabilities include:

    • Archive Operations: Creating, extracting, adding, and removing entries; reading/writing raw entry data; and memory-based zip operations.
    • Compression: Support for Zlib, BZIP2, LZMA, PPMD, XZ, and ZSTD.
    • Encryption: Traditional PKWARE and WinZIP AES encryption.
    • Advanced ZIP Features: ZIP64 support, disk splitting, NTFS timestamp support, and symbolic link preservation.
    • Encoding: Unicode (UTF-8) filename support and legacy encoding (CP437, CP932, CP936, CP950).
    • Compatibility: Includes a compatibility layer for consumers of the original minizip library.
  2. Enumerate entries in a zip file

    develop

    You can navigate through the entries in a zip file using mz_zip_reader_goto_first_entry and mz_zip_reader_goto_next_entry. If a pattern was previously set via mz_zip_reader_set_pattern, these functions will skip to the first or next entry matching that pattern.

    To iterate through all entries, start with mz_zip_reader_goto_first_entry and loop using mz_zip_reader_goto_next_entry until it returns MZ_END_OF_LIST.

    if (mz_zip_reader_goto_first_entry(zip_reader) == MZ_OK) {
        do {
            mz_zip_file *file_info = NULL;
            if (mz_zip_reader_entry_get_info(zip_reader, &file_info) != MZ_OK) {
                printf("Unable to get zip entry info\n");
                break;
            }
            printf("Zip entry %s\n", file_info->filename);
        } while (mz_zip_reader_goto_next_entry(zip_reader) == MZ_OK);
    }
  3. Manage third-party dependencies in minizip-ng

    develop

    minizip-ng can use system-installed libraries or automatically fetch and compile them from their official repositories if the MZ_FETCH_LIBS option is enabled. The following third-party libraries are supported via specific CMake options:

    • bzip2: Controlled by MZ_BZIP2
    • liblzma: Controlled by MZ_LZMA
    • ppmd: Controlled by MZ_PPMD
    • zlib (or zlib-ng): Controlled by MZ_ZLIB
    • zstd: Controlled by MZ_ZSTD
  4. Use the Hash extrafield (0x1a51) for additional digests

    develop

    The Hash extrafield (ID 0x1a51) allows you to store additional hash digests of uncompressed content alongside the standard CRC hash. This is useful for verifying file integrity using stronger algorithms.

    When multiple Hash extrafields are present for a single entry, they should be sorted from most secure to least secure. The first Hash extrafield encountered is considered the most secure and should be used for signing purposes.

    Structure:

    • Algorithm (2 bytes, uint16_t): The hash algorithm used.
    • Digest size (2 bytes, uint16_t): The size of the digest.
    • Digest (variable, uint8_t*): The actual hash value.

    Supported Algorithms:

    • 10: MD5
    • 20: SHA1
    • 23: SHA256
  5. How streams work in minizip-ng

    develop

    All I/O operations in minizip-ng are performed through streams. You can use different stream types depending on your requirements:

    • Memory Stream (mz_stream_mem): Used for reading from or writing to a buffer in memory. Use mz_stream_mem_set_grow_size for growable streams.
    • Buffered Stream (mz_stream_buffered): Wraps another stream (like an OS stream) to improve I/O performance by performing buffered read/write operations.
    • Disk Splitting Stream (mz_stream_split): Used to create archives split across multiple disks. You must specify a disk size using the MZ_STREAM_PROP_DISK_SIZE property.
    • OS Stream (mz_stream_os): Provides standard operating system level file system operations.
  6. Prevent path traversal and symlink attacks

    develop

    When extracting archives, use these functions to ensure files are not written outside the target directory:

    • mz_path_is_symlink_target_safe: Checks if a symbolic link's target resolves within a specified base_path. Returns MZ_OK if safe, or MZ_EXIST_ERROR if it escapes.
    • mz_dir_has_unsafe_symlink: Checks if any component of a path is a symbolic link that escapes the base_path.
    // Check symlink target safety
    const char *base_path = "/tmp/extract/";
    const char *link_path = "/tmp/extract/link";
    const char *target = "../outside.txt";
    if (mz_path_is_symlink_target_safe(link_path, target, base_path) == MZ_OK)
        printf("Symlink target is safe to create\n");
    else
        printf("Symlink target escapes base path\n");
    
    // Check path for unsafe symlinks
    const char *file_path = "/tmp/extract/subdir/file.txt";
    if (mz_dir_has_unsafe_symlink(file_path, base_path) == MZ_OK)
        printf("Path is safe to write\n");
    else
        printf("Path contains unsafe symlink\n");
  7. Save an entry to a file, buffer, or stream

    develop

    Minizip-ng provides multiple ways to extract an entry:

    To a file

    Use mz_zip_reader_entry_save_file to write the current entry directly to a path on disk.

    To a memory buffer

    1. Call mz_zip_reader_entry_save_buffer_length to determine the required buffer size.
    2. Allocate the buffer.
    3. Call mz_zip_reader_entry_save_buffer to decompress the data into it. Returns MZ_BUF_ERROR if the buffer is too small.

    To a stream

    • mz_zip_reader_entry_save: A blocking call that writes the entire entry to an mz_stream using a provided write callback.
    • mz_zip_reader_entry_save_process: A non-blocking/incremental version intended for use in a process loop. It returns MZ_END_OF_STREAM when finished.
    // Example: Save to buffer
    int32_t buf_size = (int32_t)mz_zip_reader_entry_save_buffer_length(zip_reader);
    char *buf = (char *)malloc(buf_size);
    int32_t err = mz_zip_reader_entry_save_buffer(zip_reader, buf, buf_size);
    if (err == MZ_OK) {
        // Use buffer
    }
    free(buf);
  8. Use the Central Directory (0xcdcd) extrafield

    develop

    The Central Directory extrafield (ID 0xcdcd) is used when a ZIP entry represents the central directory of the archive itself. It provides metadata about the directory structure.

    Structure:

    • Number of entries (8 bytes, uint64_t): The total number of entries in the central directory.
  9. Handle version and host system attributes

    develop

    The version_madeby and external_fa fields relate to the host system and ZIP specification versions:

    • Version Made By: The upper byte indicates compatibility of file attribute information, while the lower byte indicates the ZIP specification version supported by the encoding software. Use the macro MZ_HOST_SYSTEM(version_madeby) to retrieve host system information.
    • External File Attributes: These are native host system attribute values. You can convert attributes between different host systems using the mz_zip_attrib_convert function.
    • Version Needed: When writing entries, if you set version_needed to zero, the library will automatically fill it in.
  10. Understand the mz_zip object for ZIP file manipulation

    develop

    The mz_zip object is the primary abstraction in minizip-ng for reading and writing ZIP files and their individual entries. It provides a high-level interface to manage the entire archive (Archive operations) and the individual files contained within it (Entry I/O and Entry Enumeration).

    Key functional areas include:

    • Archive Management: Creating, deleting, opening, and closing ZIP files, as well as managing archive-level comments and versioning.
    • Entry I/O: Reading from and writing to specific entries within the archive, including seeking and stream-based access.
    • Entry Enumeration: Navigating through the entries in an archive (e.g., mz_zip_goto_next_entry).
    • Metadata & Attributes: Handling file attributes (directories, symlinks), extra fields, and time/date conversions between different formats (DOS, Unix, NTFS).
  11. Write an entry to a zip file manually

    develop

    To write data to a zip file entry by entry, follow this workflow:

    1. Initialize an mz_zip_file structure with metadata (filename, compression method, etc.).
    2. Call mz_zip_writer_entry_open to start the entry.
    3. Use mz_zip_writer_entry_write to write chunks of data from a buffer.
    4. Call mz_zip_writer_entry_close to finalize the entry.
    mz_zip_file file_info = { 0 };
    
    file_info.filename = "newfile.txt";
    file_info.modified_date = time(NULL);
    file_info.version_madeby = MZ_VERSION_MADEBY;
    file_info.compression_method = MZ_COMPRESS_METHOD_STORE;
    file_info.flag = MZ_ZIP_FLAG_UTF8;
    
    if (mz_zip_writer_entry_open(zip_writer, &file_info) == MZ_OK) {
        printf("Started writing new entry %s\n", file_info.filename);
        int32_t bytes_written = mz_zip_writer_entry_write(zip_writer, "test", 4);
        if (bytes_written == 4) {
            printf("Successfully wrote test\n");
        }
        mz_zip_writer_entry_close(zip_writer);
    }
  12. Upgrade from minizip 1.x to 2.x

    develop

    When upgrading, if you are not using CMake to manage includes and defines, you must manually set several new #define constants.

    At a minimum, HAVE_ZLIB and HAVE_PKCRYPT must be defined for a functional drop-in replacement.

    1.x Constant2.x ConstantDescription
    (None)HAVE_ZLIBCompile with ZLIB library.
    (None)HAVE_LZMACompile with LZMA support.
    HAVE_BZIP2HAVE_BZIP2Compile with BZIP2 support.
    HAVE_APPLE_COMPRESSIONHAVE_LIBCOMPCompile using Apple Compression library.
    HAVE_AESHAVE_WZAESCompile using AES encryption support.
    (None)HAVE_PKCRYPTCompile using PKWARE traditional encryption support.
    NOUNCRYPTMZ_ZIP_NO_ENCRYPTIONDisables all decryption support.
    NOCRYPTMZ_ZIP_NO_ENCRYPTIONDisables all encryption support.
    (None)MZ_ZIP_NO_COMPRESSIONReduces compilation size if not using zipping.