kuba-- / zip

A portable, simple zip library written in C
MIT License
1.39k stars 272 forks source link

Check if file or stream is a valid "zip" archive #307

Closed abrasat closed 11 months ago

abrasat commented 1 year ago

Is there any function available, that allows to check if a file or stream is a valid zip archive?

kuba-- commented 1 year ago

Nothing public. Of course zip_open should fail, but mainly because miniz function mz_zip_reader_read_central_dir will fail. So, if you need some workaround/shortcut, take a look into miniz.h mz_zip_reader_read_central_dir

abrasat commented 1 year ago

Is there at least a "non" public function available, that checks the "End of central directory signature"?

kuba-- commented 1 year ago

You can take a look into static function in miniz.h (mz_zip_reader_locate_header_sig): https://github.com/kuba--/zip/blob/master/src/miniz.h#L5449

and how it's used in mz_zip_reader_read_central_dir:

 if (!mz_zip_reader_locate_header_sig(
          pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG,
          MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs))
    return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR);

  /* Read and verify the end of central directory record. */
  if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
                    MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) !=
      MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
abrasat commented 1 year ago

Thanks, I will take a look. Not sure if a separate function with the zip validity check can be extracted from the code

abrasat commented 1 year ago

Maybe it would be a good idea to add an "archive_corrupted" boolean flag in "struct zip_t". it would be set if zip_open() or zip_stream_open() fails, instead of returning a null zip_t pointer. The caller of the function could then check the "m_last_error" value in zip_t->mz_zip_archive. Alternatively some new function zip_check_open (zip_stream_check_open) could be added.

kuba-- commented 1 year ago

Make sense, I think adding a new function which gonna set an error (like most of functions in our API) is the best approach.

kuba-- commented 12 months ago

@abrasat I've pushed PR: https://github.com/kuba--/zip/pull/309 where I added:

int zip_noallocopen(struct zip_t **zip, const char *zipname, int level, char mode);

The function requires pre-allocated zip and returns < 0 on error.

Right now, zip_open is basically wrapper on top of zip_noallocopen:

struct zip_t *zip = (struct zip_t *)calloc((size_t)1, sizeof(struct zip_t));
if (zip_noallocopen(&zip, zipname, level, mode) < 0) {
    CLEANUP(zip);
    return NULL;
}

Take a look, test it and let me know if it works for you.

abrasat commented 11 months ago

Thanks. Would be possible to forward the zip_noallocopen() error code to zip_open? Maybe add an new zip_open_extended function:

struct zip_t *zip_open_extended(const char *zipname, int level, char mode, int* errorCode) {
  struct zip_t *zip = (struct zip_t *)calloc((size_t)1, sizeof(struct zip_t));
  *errorCode = zip_noallocopen(&zip, zipname, level, mode);
  if (*errorCode < 0) {
    CLEANUP(zip);
    return NULL;
  }
  return zip;
}

And please add also the same error check for the zip_stream_open() function

kuba-- commented 11 months ago

Yep, I'll add zip_stream_noallocopen in the similar way. But frankly speaking, having these noalloc version I do not see the point to add yet another wrapper to the API. I hope it's not a lot of work to write own extended function (maybe with more error handling stuff)

kuba-- commented 11 months ago

@abrasat - I closed the previous PR, because I realized it's not usable (you cannot preallocate anonymous struct). So, I've just sent a new one (https://github.com/kuba--/zip/pull/310), which most likely works better for you. PTAL.