I’m trying to learn how to use libzip to create a ZIP file with Visual Studio 2022 and C on Windows 11. When I’m finished, my file should have multiple files in multiple different folders. That’s my final goal. Right now, I just want to create a ZIP file, but the library is not helping me to use it correctly because it is not returning errors, even when it fails to do anything (detectable) that I’ve asked it to do. I’m not looking for help fixing my code (though I certainly won’t refuse it! [smile]), what I’m really trying to learn here is how to debug problems with a library that returns success even when it clearly fails.
If I just use this basic sequence (with _UseFqn_
defined), with fully qualified path/file names (fqn
), then a ZIP is actually created (Windows won’t read it, but 7-Zip will, so that’s OK for now):
zip_open()
zip_source_file(fqn)
zip_file_add(fqn)
zip_close()
If I use SetCurrentDirectory()
to change to the folder that actually contains each file (fpath
), and try to add the files without path information (fname
), then I get no errors but I also get no zip file:
zip_open()
SetCurrentDirectory(fpath)
zip_source_file(fname)
zip_file_add(fname)
zip_close()
If I try to add a directory using zip_dir_add()
, I also get no errors and no zip file for either of the sequences above. Sorry for the length of this post, but I’m going to add my test source, too. Please make one assumption about it: The program calling _MakeZipFile() is calling it like this: _MakeZipFile("testfile.zip","C:pathtofilesomething.log");
//-------------------------------------------------------------------------
// Add a single file to the zip
static int _AddFileToZip( zip_t *zipFile, char *szFileName )
{
int rc = NO_ERROR;
zip_source_t *source;
source = zip_source_file( zipFile, szFileName, 0, ZIP_LENGTH_TO_END );
if( source == NULL )
{
printf( "ZipTest> Failed to src file for zip: '%s'...n", szFileName );
printf( "ZipTest> libzip: %sn", zip_strerror( zipFile ) );
rc = ERROR_INVALID_PARAMETER;
}
else if( zip_file_add( zipFile, szFileName, source, ZIP_FL_ENC_RAW ) < 0 )
{
zip_source_free( source );
printf( "ZipTest> Failed to add file to zip: '%s'...n", szFileName );
printf( "ZipTest> libzip: %sn", zip_strerror( zipFile ) );
rc = ERROR_INVALID_FUNCTION;
}
else
{ // print a diagnostic for debugging
printf( "ZipTest> added file: '%s'...n", szFileName );
}
return rc;
}
//-------------------------------------------------------------------------
// Add all folder levels, from top to bottom, recursively
static BOOL _AddFolderToZip( zip_t *zipFile, char *szFolder )
{
char sz[_MAX_PATH];
char *cp;
BOOL bResult;
zip_error_t *pze;
if( ':' == szFolder[1] )
{ // Remove drive letter, if present
szFolder += 2;
}
if( '\' == *szFolder )
{ // Remove leading backslash, if present
szFolder++;
}
strcpy( sz, szFolder ); // copy so we don't trash the original
cp = strrchr( sz, '\' );
if( cp && ('' == *(cp+1)) )
{ // Remove trailing backslash
*cp = '';
}
// Is this a sub-folder?
cp = strrchr( sz, '\' );
if( cp && (cp != sz) )
{ // Yes, call self to add parent first
*cp = '';
if( !_AddFolderToZip( zipFile, sz ) )
{ // Failure, back out with errors
return FALSE;
}
*cp = '\';
}
// else No, time to add this folder.
bResult = TRUE;
if( zip_dir_add( zipFile, sz, ZIP_FL_ENC_RAW ) < 0 )
{ // Error, but there's one error that is OK...
pze = zip_get_error( zipFile );
if( ZIP_ER_EXISTS != pze->zip_err )
{ // Multiple files in same folder are OK.
bResult = FALSE;
printf( "ZipTest> Failed to add directory to zip: '%s'...n", szFolder );
printf( "ZipTest> libzip: %sn", zip_strerror( zipFile ) );
}
}
if( bResult )
{ // print a diagnostic for debugging
printf( "ZipTest> added directory: '%s'...n", sz );
}
return bResult;
}
// ------------------------------------------------------------------------
#define _UseFqn_ 1 // Use Fully qualified file names and no directories
// comment this out to change directory, add the file folder, and add the filename
// ------------------------------------------------------------------------
// szzSourceList is a buffoer containing some number of NULL terminated
// strings that ends with an empty string (i.e. double-NULL)
BOOL _MakeZipFile( char *szZipFileName, char *szzSourceList )
{
BOOL result = FALSE;
int errorp = NO_ERROR;
zip_t *zipFile;
char *cpFilePath;
zip_error_t ziperror;
zip_error_t *pze;
#if !defined(_UseFqn_)
char szDrive[_MAX_PATH];
char szPath[_MAX_PATH];
char szFile[_MAX_PATH];
char szExt[_MAX_PATH];
char szFolder[_MAX_PATH];
#endif
char szStartPath[_MAX_PATH];
GetCurrentDirectory( sizeof(szStartPath), szStartPath );
zipFile = zip_open( szZipFileName, ZIP_CREATE | ZIP_TRUNCATE, &errorp );
if( zipFile == NULL )
{
zip_error_init_with_code( &ziperror, errorp );
printf( "ZipTest> Failed to open output file '%s'...n", szZipFileName );
printf( "ZipTest> libzip: %sn", zip_error_strerror( &ziperror ) );
return FALSE;
}
__try
{
cpFilePath = szzSourceList;
while( *cpFilePath )
{
#if defined(_UseFqn_)
_AddFileToZip( zipFile, cpFilePath );
#else
_splitpath( cpFilePath, szDrive, szPath, szFile, szExt );
sprintf( szFolder, "%s%s", szDrive, szPath );
SetCurrentDirectory( szFolder );
_AddFolderToZip( zipFile, szPath );
strcat( szFile, szExt );
_AddFileToZip( zipFile, szFile );
#endif
// Find next entry in terminated string list
while( *cpFilePath )
{
cpFilePath++;
}
cpFilePath++;
}
}
__finally
{
if( NO_ERROR == zip_close( zipFile ) )
{
result = TRUE;
}
else
{
pze = zip_get_error( zipFile );
printf( "ZipTest> Failed to create output file '%s'...n", szZipFileName );
printf( "ZipTest> libzip: %sn", zip_strerror( zipFile ) );
printf( "ZipTest> zip_err = %d sys_err = %dn", pze->zip_err, pze->sys_err );
}
}
SetCurrentDirectory( szStartPath );
return result;
}