Unzip archived file get "End-of-central-directory signature not found"
Hi, i got unzip error "End-of-central-directory signature not found" when i use unzip command on mac os , also i tried directly open the zip file using mac os default archive utility,i got "Error 97 - Inappropriate File Type or Format". Howerver, I downloaded other archive apps and i can unzip this file.
My device: macbook pro m1 version node-archiver version: 5.3.0
Got the same error here.
Macbook pro 16 Intel also have the same problem. MacOS: 11.6.5 default zip app. And it works with The Unarchive. I still get error: corrupted files, but I select continue and voila
The thing that fixed this for us was waiting for the write stream to close after calling archive.finalize().
await archive.finalize();
await new Promise((resolve, reject) => {
output.on("close", resolve);
output.on("error", reject);
});
I'd say this should be handled internally by the finalize() method but is probably not right now.
waiting for the write stream to close
Unfortunately that didn't work for me. I wait on the out stream, the archive, and the finalize...
const output = await fs.open(path.join(outdir, name), 'w');
const outStream = output.createWriteStream();
const archive = archiver.create('zip', {
zlib: { level: 9 },
});
promises.push(
new Promise((resolve, reject) => {
outStream.on('close', () => {
resolve(undefined);
});
outStream.on('error', (e) => {
reject(e);
});
}),
);
promises.push(
new Promise((resolve, reject) => {
archive.on('error', (e) => {
console.error(e);
reject(e);
});
archive.on('finish', () => {
resolve(undefined);
});
}),
);
archive.pipe(outStream);
archive.append(Buffer.from(file.contents), { name: file.path });
promises.push(archive.finalize());
await Promise.all(promises);
The example code for making a .zip doesn't even work on Mac (tried node 16 and 18, in case it made a difference):
$ node pack-zip.js
$ unzip example-output.zip
Archive: example-output.zip
End-of-central-directory signature not found. Either this file is not
a zipfile, or it constitutes one disk of a multi-part archive. In the
latter case the central directory and zipfile comment will be found on
the last disk(s) of this archive.
Also maybe worth mentioning that not only can the archives not be decompressed on Mac, but AWS also can't extraxt them if you try to use it to upload code to Lambdas
operation error Lambda: CreateFunction, https response error StatusCode: 400, RequestID: f90296d2-36c6-4d4f-a541-0c0ef5ac0f10, InvalidParameterValueException: Could not unzip uploaded file. Please check your file, then try to upload again.
waiting for the write stream to close
Unfortunately that didn't work for me. I wait on the out stream, the archive, and the finalize...
const output = await fs.open(path.join(outdir, name), 'w'); const outStream = output.createWriteStream(); const archive = archiver.create('zip', { zlib: { level: 9 }, }); promises.push( new Promise((resolve, reject) => { outStream.on('close', () => { resolve(undefined); }); outStream.on('error', (e) => { reject(e); }); }), ); promises.push( new Promise((resolve, reject) => { archive.on('error', (e) => { console.error(e); reject(e); }); archive.on('finish', () => { resolve(undefined); }); }), ); archive.pipe(outStream); archive.append(Buffer.from(file.contents), { name: file.path }); promises.push(archive.finalize()); await Promise.all(promises);The example code for making a .zip doesn't even work on Mac (tried node 16 and 18, in case it made a difference):
$ node pack-zip.js $ unzip example-output.zip Archive: example-output.zip End-of-central-directory signature not found. Either this file is not a zipfile, or it constitutes one disk of a multi-part archive. In the latter case the central directory and zipfile comment will be found on the last disk(s) of this archive.Also maybe worth mentioning that not only can the archives not be decompressed on Mac, but AWS also can't extraxt them if you try to use it to upload code to Lambdas
operation error Lambda: CreateFunction, https response error StatusCode: 400, RequestID: f90296d2-36c6-4d4f-a541-0c0ef5ac0f10, InvalidParameterValueException: Could not unzip uploaded file. Please check your file, then try to upload again.
Did that ever get fixed? I think I'm having the same issue on macOS. It just doesn't work at all. Anything this package compresses is corrupted.
➜ /tmp unzip generated-output_1707207217.zip [01:32:03]
Archive: generated-output_1707207217.zip
End-of-central-directory signature not found. Either this file is not
a zipfile, or it constitutes one disk of a multi-part archive. In the
latter case the central directory and zipfile comment will be found on
the last disk(s) of this archive.
unzip: cannot find zipfile directory in one of generated-output_1707207217.zip or
generated-output_1707207217.zip.zip, and cannot find generated-output_1707207217.zip.ZIP, period.
Tested on my Ubuntu server and it worked right away. IT IS a problem with macOS zlib version 😠
For anyone looking for a way to move forward with generating zip files, I eventually realized this library just wrappers https://github.com/archiverjs/node-zip-stream when set to zip archive type, so I just used that library directly instead.
While trying to make zip-stream work, I also realized that if you are using createWriteStream from the standard node fs library, it uses old school node event emitters, which so not work when in a JS async function. Normally Node will exit when the work queue is empty but the old school node .on( event handlers do not put themselves on that work queue. If you do
stream.on('finish', () => {
Node will not wait for that finish handler to be called (because it might never be called). Your code needs to sit and wait for it. If you have an async block, like in my code above where I try to wrapper things in a Promise, node will just exit after that because it doesnt care about waiting on that .on( event emitter handler. The exit of Node leaves the .zip file half written / corrupted.
Interestingly, archiver's finalize() method returns a Promise with an event handler set up inside it.
https://github.com/archiverjs/node-archiver/blob/master/lib/core.js#L791-L798
I don't see how this possibly works, or maybe works depending on if your system can write the zip file and flush the i/o buffer fast enough to finish before node exits.
Node would run finalize which adds an event handler
self._module.on('end', function() {
if (!errored) {
resolve();
}
})
then returns, and now there is nothing left on the work steam so the process would exit. (potentially before the end handler is run, leaving the file corrupt).