libzip: validating a zip file before loading - c++

I use libzip to open zip files in my application and in order to ensure good behavior in case of corrupt zip files I manually corrupted a zip file (by removing a few random lines with a text editor) and try to load that file. However this hangs the entire app because zip_fread() never returns.
Is there a where to determine if a zip file is valid before loading it to avoid such situations?
Update
The behavior seems to depend on the version, so I probably only need to update. This is the code I use on Windows, Mac OS and Linux:
int err;
zip *z= zip_open(zipfile.c_str(), 0, &err);
if (!z)
{
if (err == ZIP_ER_NOZIP)
throw std::runtime_error("The file is not a Workbench document.");
else if (err == ZIP_ER_MEMORY)
throw grt::os_error("Cannot allocate enough memory to open document.");
else if (err == ZIP_ER_NOENT)
throw grt::os_error("File not found.");
int len= zip_error_to_str(NULL, 0, 0, err);
std::string msg;
if (len > 0)
{
char *buf= (char*)g_malloc(len+1);
zip_error_to_str(buf, len+1, 0, err);
msg= buf;
g_free(buf);
}
else
msg= "error opening zip archive";
zip_close(z);
throw std::runtime_error(strfmt(_("Cannot open document file: %s"), msg.c_str()));
}
On OS X this fragment does not return an error (I used the same file for all platforms). Instead the following zip_read() call just hangs. On the other platforms zip_read() immediately returns with a result < 0, so it's easy to catch the error there.

Related

Libzip - Error: Error while opening the archive : no error

I'm trying to find out the solution to solve a problem;
In fact, i'm writing my own tool to make saves using libzip in C++ to compress the files.
Absolutly not finished but i wanted to make some tests, then i do and obtain a "funny" error from the log.
Here's my function:
void save(std::vector<std::string> filepath, std::string savepath){
int err;
savepath += time(NULL);
zip* saveArchive = zip_open(savepath.c_str(), ZIP_CREATE , &err);
if(err != ZIP_ER_OK) throw xif::sys_error("Error while opening the archive", zip_strerror(saveArchive));
for(int i = 0; i < filepath.size(); i++){
if(filepath[i].find("/") == std::string::npos){}
if(filepath[i].find(".cfg") == std::string::npos){
err = (int) zip_file_add(saveArchive, filepath[i].c_str(), NULL, NULL);
if(err == -1) throw xif::sys_error("Error while adding the files", zip_strerror(saveArchive));
}
}
if(zip_close(saveArchive) == -1) throw xif::sys_error("Error while closing the archive", zip_strerror(saveArchive));
}
I get a => Error : Error while opening the archive : No error
And, of course, i didn't have any .zip written.
If you could help me, thanks to you !
The documentation for zip_open says that it only sets *errorp if the open fails. Either test for saveArchive == nullptr or initialize err to
ZIP_ER_OK.
P.S. The search for '/' does nothing. Did you mean to put a continue in that block?
The other problematic line is:
savepath += time(NULL);
If that is the standard time function, that returns a time in seconds since the epoch. That will probably get truncated to a char, and then that char appended to the file name. That will cause strange characters to appear in the filename! I suggest using std::chrono to convert to text.

Why is popen failing with 'Cannot Allocate Memory'

I have an Ubuntu C++ application that executes shell commands by calling popen(). The popen() call works great usually but sometimes it will fail and will indicate error 12 'Cannot allocate memory'.
I know that the system is not even close to being out of memory, so that's not the problem. I know that the process has roughly 250 files open, which is far less than the OPEN_MAX value of 1024.
What else could be the problem?
I've read elsewhere that I could be at the STREAM_MAX limit (which is 16), but I don't know how to check whether or not this is actually the case. Any help would be very much appreciated!
Here is the complete code:
// Format the command to get the number of files open in this process
char szCommand[1024];
memset(&(szCommand[0]), 0, sizeof(szCommand));
snprintf(szCommand, sizeof(szCommand) - 1, "lsof -p %i | wc -l", static_cast<int>(getpid()));
// A string to capture the output
std::string szTotalOutput("");
// Execute the command
FILE *pFile = popen(szCommand, "r");
// If the open was successful
if (pFile)
{
// A text buffer to capture output
char szOutput[2048];
memset(&(szOutput[0]), 0, sizeof(szOutput));
// Get the output
while (fgets(szOutput, static_cast<int>(sizeof(szOutput) - 1), pFile))
{
// Add to the total output
szTotalOutput += std::string(szOutput);
}
// Close the file
pclose(pFile);
}
// Or, if the open failed
else
{
// An error string
char szError[2048];
memset(&(szError[0]), 0, sizeof(szError));
// If we have a good error
if (errno != 0)
{
// Format the error string
snprintf(szError, sizeof(szError) - 1, "popen failed with error %i '%s'", errno, strerror(errno));
}
// Or, if we don't have a good error
else
{
// Format the error string
snprintf(szError, sizeof(szError) - 1, "popen failed but errno was not set");
}
// Print this error message to the console window
printf("Error: File %s line %i: %s\n", __FILE__, __LINE__, szError);
}
EDIT:
I've found that if I re-enable swap (which was previously disabled) then the issue doesn't happen. But ultimately I need for this to work with swap disabled.

Name of a named pipe given handle

I'm trying to find the name of a named pipe given it's handle. I found a solution where the named pipe handle is duplicated using NtDuplicateObject and then the name is extracted using NtQueryObject but it's unstable so that's out of the question.
Currently I'm attempting to do so with GetFinalPathNameByHandle but having no luck. I'm not even sure if it's possible to do this but it was mentioned as a potential solution so I'm going with it. The following is adapted from the example code at:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa364962(v=vs.85).aspx
void __cdecl _tmain(int argc, TCHAR *argv[]){
TCHAR Path[BUFSIZE];
HANDLE pipe;
DWORD dwRet;
printf("\n");
if (argc != 2)
{
printf("ERROR:\tIncorrect number of arguments\n\n");
printf("%s <file_name>\n", argv[0]);
return;
}
pipe = CreateNamedPipe(argv[1], PIPE_ACCESS_INBOUND | PIPE_ACCESS_OUTBOUND, PIPE_WAIT, 1,
1024, 1024, 120 * 1000, NULL);
if (pipe == INVALID_HANDLE_VALUE)
{
printf("Could not open file (error %d\n)", GetLastError());
return;
}
dwRet = GetFinalPathNameByHandle(pipe, Path, BUFSIZE, VOLUME_NAME_NT);
if (dwRet < BUFSIZE)
{
_tprintf(TEXT("\nThe final path is: %s\n"), Path);
}
else printf("\nThe required buffer size is %d.\n", dwRet);
CloseHandle(pipe);}
The command line parameter is "\\\\.\\pipe\\mynamedpipe" or "\\.\pipe\mynamedpipe", I've tried both. The output is garbage but more importantly when debugging with Visual Studio 2013 Express while stepping through the program the path variable is garbage directly after the GetFinalPathNameByHandle call.
By garbage I mean:
Path 0x0036fab4 L"쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌쳌... wchar_t[100]
Console output is:
The final path is: ?????????????????????????????????????????????????????????????????????????????????????????????????????????6?╫☻
So I'm officially stuck. Alternatively and possibly a much better solution would be comparing two named pipe handles to each other to determine if they point to the same named pipe. If there is a way to do that it would solve my problem as well.
To answer my own question here. GetFileInformationByHandleEx does exactly this using FileNameInfo for the FileInformationClass parameter and a handle generated by CreateNamedPipe.

Creating text file into C++ addon of node.js

I want to know how i can create file and append data inside it in c++ addon (.cc) file of node.js ??
I have used below code to do same, but not able to find file "data.txt" in my ubuntu machine(reason behind it may be below code is not correct way to create file, but strange i haven't received any error/warning at compile time).
FILE * pFileTXT;
pFileTXT = fopen ("data.txt","a+");
const char * c = localReq->strResponse.c_str();
fprintf(pFileTXT,c);
fclose (pFileTXT);
Node.js relies on libuv, a C library to handle the I/O (asynchronous or not). This allows you to use the event loop.
You'd be interested in this free online book/introduction to libuv: http://nikhilm.github.com/uvbook/index.html
Specifically, there is a chapter dedicated to reading/writing files.
int main(int argc, char **argv) {
// Open the file in write-only and execute the "on_open" callback when it's ready
uv_fs_open(uv_default_loop(), &open_req, argv[1], O_WRONLY, 0, on_open);
// Run the event loop.
uv_run(uv_default_loop());
return 0;
}
// on_open callback called when the file is opened
void on_open(uv_fs_t *req) {
if (req->result != -1) {
// Specify the on_write callback "on_write" as last argument
uv_fs_write(uv_default_loop(), &write_req, 1, buffer, req->result, -1, on_write);
}
else {
fprintf(stderr, "error opening file: %d\n", req->errorno);
}
// Don't forget to cleanup
uv_fs_req_cleanup(req);
}
void on_write(uv_fs_t *req) {
uv_fs_req_cleanup(req);
if (req->result < 0) {
fprintf(stderr, "Write error: %s\n", uv_strerror(uv_last_error(uv_default_loop())));
}
else {
// Close the handle once you're done with it
uv_fs_close(uv_default_loop(), &close_req, open_req.result, NULL);
}
}
Spend some time reading the book if you want to write C++ for node.js. It's worth it.

C zip library that can create password protected zip files on windows?

Anyone know of a C library that can create password protected zip files on windows? It appears that the option to password protect zip files with the built-in zip utility has been removed from windows 7, but I don't think this is an issue.
Can either zziplib or the 7-Zip SDK do this?
7-Zip SDK (LZMA SDK) supports password protected archive.
Related SO post:
https://stackoverflow.com/questions/221049/how-secure-is-7-zip
LZMA SDK:
http://www.7-zip.org/sdk.html
If you can use .NET, check out DotNetZip: http://dotnetzip.codeplex.com/
C++ .NET example to create password-protected ZIP:
http://cheeso.members.winisp.net/DotNetZipHelp/Code%20Examples/Cpp.htm
MINIZIP + zlib supports AES 256 encryption, and is very easy to use!
Code based on minizip unzip.c.
include stdio.h zip.h unzip.h
First, create a zip with a file inside with a password.
The zip file must be in the same directory as the executable.
Run the program from a prompt in the directory of the generated program. This example only extracts the first file!
/*-----------start-------------- */
/*Tries to open the zip in the current directory.*/
unzFile zfile = unzOpen("teste.zip");
if(zfile==NULL)
{
printf("Error!");
return;
}
printf("OK Zip teste.zip opened...\n");
int err = unzGoToFirstFile(zfile);/*go to first file in zip*/
if (err != UNZ_OK)
{
printf("error %d with zipfile in unzGoToFirstFile\n", err);
unzClose(zfile);/*close zip*/
}
/*At this point zfile points to the first file contained in the zip*/
char filename_inzip[256] = {0};/* The file name will be returned here */
unz_file_info file_info = {0};/*strcuture with info of the first file*/
err = unzGetCurrentFileInfo(zfile, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0);
if (err != UNZ_OK)
{
printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
}
else
{
int len = 8192;/*size of chunk*/
char buffer[8192]={0};/*buffer used to save uncompressed data*/
printf("name of first file is :%s\n",filename_inzip);
printf("uncompressed_size = %d\n",file_info.uncompressed_size);
/*Use your password here, the same one used to create your zip */
err = unzOpenCurrentFilePassword(zfile, "yourpassword");
if (err != UNZ_OK)
printf("error %d with zipfile in unzOpenCurrentFilePassword\n", err);
else
printf("password ok\n");
FILE *fp = fopen(filename_inzip, "wb");/*file for data binary type*/
if (fp != NULL)
{
do
{/*read the current file returned by unzGoToFirstFile to buffer in chunks of the 8192*/
err = unzReadCurrentFile(zfile, &buffer, len );
if (err < 0)
{
printf("error %d with zipfile in unzReadCurrentFile\n", err);
break;
}
if (err == 0)
break;
/*Save the chunk read to the file*/
if (fwrite(&buffer, err, 1, fp) != 1)/*if error break*/
{
printf("error %d in writing extracted file\n", errno);
err = UNZ_ERRNO;
break;
}/*else continue*/
}
while (err > 0);
/*close file*/
fclose(fp);
}
}
unzClose(zfile);