From 8fc0fd68345661cd28928a401eb91e445eef8174 Mon Sep 17 00:00:00 2001 From: Jimb Esser Date: Sun, 10 May 2020 10:17:16 -0700 Subject: [PATCH] Fix zip files created on Windows being unusable on Linux/MacOS --- index.js | 11 ++++++++++- test/test.js | 10 +++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index ef50085..cc6effc 100644 --- a/index.js +++ b/index.js @@ -388,7 +388,7 @@ function Entry(metadataPath, isDirectory, options) { if (options.mode != null) { this.setFileAttributesMode(options.mode); } else { - this.setFileAttributesMode(isDirectory ? 0o40775 : 0o100664); + this.setFileAttributesMode(0o664); } if (isDirectory) { this.crcAndFileSizeKnown = true; @@ -435,6 +435,15 @@ Entry.prototype.setLastModDate = function(date) { Entry.prototype.setFileAttributesMode = function(mode) { if ((mode & 0xffff) !== mode) throw new Error("invalid mode. expected: 0 <= " + mode + " <= " + 0xffff); // http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute/14727#14727 + if (this.isDirectory) { + // Set executable bit on directories if any other bits are set for that user/group/all + // Fixes creating unusable zip files on platforms that do not use an executable bit + mode |= ((mode >> 1) | (mode >> 2)) & 0o111; + mode |= 0o040000; // S_IFDIR + } else { + mode |= 0o100000; // S_IFREG + } + this.externalFileAttributes = (mode << 16) >>> 0; }; // doFileDataPump() should not call pumpEntries() directly. see issue #9. diff --git a/test/test.js b/test/test.js index 264ab0c..3feae4a 100644 --- a/test/test.js +++ b/test/test.js @@ -79,7 +79,7 @@ var BufferList = require("bl"); zipfile.addBuffer(bufferFrom("buffer"), "b.txt"); zipfile.addReadStream(new BufferList().append("stream"), "c.txt"); zipfile.addEmptyDirectory("d/"); - zipfile.addEmptyDirectory("e"); + zipfile.addEmptyDirectory("e", { mode: 0644 }); zipfile.end(function(finalSize) { if (finalSize !== -1) throw new Error("finalSize should be unknown"); zipfile.outputStream.pipe(new BufferList(function(err, data) { @@ -92,6 +92,14 @@ var BufferList = require("bl"); if (entry.fileName !== expectedName) { throw new Error("unexpected entry fileName: " + entry.fileName + ", expected: " + expectedName); } + var mode = entry.externalFileAttributes >>> 16; + if (/\/$/.test(entry.fileName)) { + // Directory file names end with '/'. + if (!(mode & 040000)) throw new Error("directory expected to have S_IFDIR, found " + mode.toString(8)); + if (!(mode & 0111)) throw new Error("directory expected to have executable flags, found " + mode.toString(8)); + } else { + if (!(mode & 0100000)) throw new Error("file expected to have S_IFREG, found " + mode.toString(8)); + } }); zipfile.on("end", function() { if (entryNames.length === 0) console.log("optional parameters and directories: pass");