Zip64 archives are corrupted?
I'm still trying to figure this one out but it looks like zip archives which are over 4gb (ZIP64) are created corrupted.
I've tried to clone an existing large archive to a new one and it came corrupted too
Looking on the header of the first entry, it looks like the difference starts in the frExtraField
field
The left is the original zip, the right is the cloned using libgsf
, we can see the frExtraField
was split to an array and the value has changed from EH_WinGrowth
to EH_extTimestamp
(in the array 2nd cell)
I was thinking this is related to the zip64
property set on the GsfOutfileZip
file as it's set to -1
(as expected) and maybe not detecting the ZIP64 in a proper way?
I wasn't able to find how this property can be set to explicitly set the output file as zip64.
The zip creation uses the following api's:
output = gsf_output_stream_new(outputStream)
outfile = gsf_outfile_zip_new(output)
- Copying entries from the source zip to the target zip using
gsf_input_copy
void CloneDirEntry(
const shared_ptr<MipContext>& mipContext,
GsfInfile* input,
GsfOutfile* output,
const string& path,
map<string, vector<uint8_t>>& entries) {
int n = gsf_infile_num_children(input);
for (int i = 0; i < n; i++) {
int level;
gboolean is_dir;
char const* name = gsf_infile_name_by_index(input, i);
unique_ptr<GsfInfile, GsfInfile_deleter> child(GSF_INFILE(gsf_infile_child_by_index(input, i)));
if (!child) {
auto msg = "Failed to get entry from zip, not continuing to copy so the zip will be corrupted";
SET_EVENT_ERROR_PROPERTIES(mipContext->GetRawTelemetryManager(), msg);
throw ZipException(msg);
}
is_dir = gsf_infile_num_children(child.get()) >= 0;
g_object_get(G_OBJECT(child.get()), "compression-level", &level, nullptr);
int zip64;
unique_ptr<GsfOutfile, GsfOutfile_deleter> outputPtr(GSF_OUTFILE(
gsf_outfile_new_child_full(output, name, is_dir, "compression-level", level, nullptr)));
string newPath(path);
if (!newPath.empty())
newPath.append("/");
newPath.append(name);
Clone(mipContext, child.get(), outputPtr.get(), newPath, entries);
}
}
My assumption that here we are missing a call to something like g_object_get(G_OBJECT(child.get()), "zip64", &zip64, nullptr);
and later passing this as part of the gsf_outfile_new_child_full
args.
When I tried adding g_object_get(G_OBJECT(child.get()), "zip64", &zip64, nullptr);
, the zip64
was never set property, in addition, I've tried creating the new stream with zip64
set to 1
but the result is the same:
unique_ptr<GsfOutfile, GsfOutfile_deleter> outputPtr(
GSF_OUTFILE(gsf_outfile_new_child_full(output, name, is_dir, "compression-level", level, "zip64", 1, nullptr)));
Is there any example for how a ZIP64 should be created/cloned using gsf?