sebastiandev / zipper

C++ wrapper around minizip compression library
MIT License
520 stars 124 forks source link

unzipper does not extract folder and files more than one level. #34

Closed snahmad closed 2 years ago

Lecrapouille commented 5 years ago

Can you give me a short example code ?

JackHack96 commented 3 years ago

I'm having this issue right now. I have a zip that contains only one folder and inside that folder there are a bunch of files. If I try to extract everything to a specific path, the library just fails.

#include <iostream>
#include "zipper/unzipper.h"

int main()
{
    zipper::Unzipper unzipper("test.zip");
    unzipper.extract();
    if (!unzipper.extract(PATH)) {
        std::cerr << "There was an error while extracting the files from the ZIP archive." << std::endl;
        return -1;
    }
    unzipper.close();
}

test.zip

For now, I've patched the library by adding a check in the extractToFile() method in unzipper.cpp which returns a UNZ_ISDIRECTORY error in case the filename is a directory:

int extractToFile(const std::string& filename, ZipEntry& info)
    {
        int err = UNZ_ERRNO;

        /* If zip entry is a directory then create it on disk */
        makedir(parentDirectory(filename));
        if(isDirectory(filename))
        {
            err = UNZ_ISDIRECTORY;
            return err;
        }

After that the method extractCurrentEntryToFile checks if err is UNZ_ISDIRECTORY and if it does it changes it to ok, letting the program go on.

err = extractToFile(fileName, entryinfo);
        if (UNZ_OK == err)
        {
            err = unzCloseCurrentFile(m_zf);
            if (UNZ_OK != err)
            {
                std::stringstream str;
                str << "Error " << err << " openinginternal file '"
                    << entryinfo.name << "' in zip";

                throw EXCEPTION_CLASS(str.str().c_str());
            }
        }
        else if(UNZ_ISDIRECTORY == err)
            err = UNZ_OK;

I know that this is quick dirty hack and that's why I don't make any pull request, as I'm sure there are more elegant solutions :)

Lecrapouille commented 3 years ago

@JackHack96 strange, both functions work well for me :( if I comment unzipper.extract(); and instead of PATH I use "ici" the extracted folder are ok. And also tested with an extra folder depth. Have you an '/' at the end of the dir path ?

 tree ici/
ici/
└── test
    ├── test1.txt
    └── test2.txt

1 directory, 2 files

With #102 this is the second times people have a different behavior than me. Can you try this following patch:

#include <iostream>

    int extractToFile(const std::string& filename, ZipEntry& info)
    {
        int err = UNZ_ERRNO;

        /* If zip entry is a directory then create it on disk */
        if (!makedir(parentDirectory(filename))) // BEFORE PATCH: SILENT ERROR 
        {
           std::cerr << "FAILED makedir" << std::endl;
        }

        /* Create the file on disk so we can unzip to it */
        std::ofstream output_file(filename.c_str(), std::ofstream::binary);

        if (output_file.good())
        {
            if (UNZ_OK == extractToStream(output_file, info))
            {
                std::cerr << "OK extractToStream" << std::endl;
                err = UNZ_OK;
            }

            output_file.close();

            /* Set the time of the file that has been unzipped */
            tm_unz timeaux;
            memcpy(&timeaux, &info.unixdate, sizeof(timeaux));

            changeFileDate(filename, info.dosdate, timeaux);
        }
        else
        {
            std::cerr << "FAILED ofstream" << std::endl;
            output_file.close();
        }

        return err;
    }

I'm seeing:

OK extractToStream
OK extractToStream

What branch do you use, What OS ?

Lecrapouille commented 3 years ago

@JackHack96 In fact can you replace your zipper folder by this one ? Recompile it and install it and re-run your test. I added more logs.

zipper.zip

srroger commented 2 years ago

Hello, I have the same issue (1.0.3) In fact, the issue comes from when the zip file has been created with an external tool ( and the zip contains a folder)

The extraction fails and return false (without an exception): unzipper.extract();

However, if the zip files has been created with zipper (and the zip contains a folder), then the extraction works perfectly...

v77777 commented 2 years ago

i also have this problem,but i can sloving this problem like Unzipper unzipper(src_file); std::vector<ZipEntry> entries = unzipper.entries(); for (ZipEntry entry : entries) { unzipper.extractEntry(entry.name, des_folder); }

Lecrapouille commented 2 years ago

Sorry, I have few time to concern on this project especially on this master that want to stall. @v77777 how do you compile the project ? Can you try with the v2.x.y git branch ? https://github.com/sebastiandev/zipper/tree/v2.x.y (in this branch I no longer compile with CMake but with a simple Makefile and with local thirdparts) ?

git clone https://github.com/sebastiandev/zipper.git -b "v2.x.y" --recursive
cd zipper
make download-external-libs
make compile-external-libs
make -j`nproc --all`

PS: I have just updated the submodule Makefile to the newest version. Hope it will work. I have to fix github actions.

Lecrapouille commented 2 years ago

Closed since working on branch 2.x.y. Please reopen this ticket in not fixed