Skip to content

Commit 9e2e73f

Browse files
committed
Fix zip files created on Windows being unusable on Linux/MacOS
1 parent 36b2a6a commit 9e2e73f

File tree

2 files changed

+19
-2
lines changed

2 files changed

+19
-2
lines changed

index.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ function Entry(metadataPath, isDirectory, options) {
388388
if (options.mode != null) {
389389
this.setFileAttributesMode(options.mode);
390390
} else {
391-
this.setFileAttributesMode(isDirectory ? 0o40775 : 0o100664);
391+
this.setFileAttributesMode(0o664);
392392
}
393393
if (isDirectory) {
394394
this.crcAndFileSizeKnown = true;
@@ -435,6 +435,15 @@ Entry.prototype.setLastModDate = function(date) {
435435
Entry.prototype.setFileAttributesMode = function(mode) {
436436
if ((mode & 0xffff) !== mode) throw new Error("invalid mode. expected: 0 <= " + mode + " <= " + 0xffff);
437437
// http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute/14727#14727
438+
if (this.isDirectory) {
439+
// Set executable bit on directories if any other bits are set for that user/group/all
440+
// Fixes creating unusable zip files on platforms that do not use an executable bit
441+
mode |= ((mode >> 1) | (mode >> 2)) & 0o111;
442+
mode |= 0o040000; // S_IFDIR
443+
} else {
444+
mode |= 0o100000; // S_IFREG
445+
}
446+
438447
this.externalFileAttributes = (mode << 16) >>> 0;
439448
};
440449
// doFileDataPump() should not call pumpEntries() directly. see issue #9.

test/test.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ var BufferList = require("bl");
7979
zipfile.addBuffer(bufferFrom("buffer"), "b.txt");
8080
zipfile.addReadStream(new BufferList().append("stream"), "c.txt");
8181
zipfile.addEmptyDirectory("d/");
82-
zipfile.addEmptyDirectory("e");
82+
zipfile.addEmptyDirectory("e", { mode: 0o644 });
8383
zipfile.end(function(finalSize) {
8484
if (finalSize !== -1) throw new Error("finalSize should be unknown");
8585
zipfile.outputStream.pipe(new BufferList(function(err, data) {
@@ -92,6 +92,14 @@ var BufferList = require("bl");
9292
if (entry.fileName !== expectedName) {
9393
throw new Error("unexpected entry fileName: " + entry.fileName + ", expected: " + expectedName);
9494
}
95+
var mode = entry.externalFileAttributes >>> 16;
96+
if (/\/$/.test(entry.fileName)) {
97+
// Directory file names end with '/'.
98+
if (!(mode & 0o040000)) throw new Error("directory expected to have S_IFDIR, found " + mode.toString(8));
99+
if (!(mode & 0o111)) throw new Error("directory expected to have executable flags, found " + mode.toString(8));
100+
} else {
101+
if (!(mode & 0o100000)) throw new Error("file expected to have S_IFREG, found " + mode.toString(8));
102+
}
95103
});
96104
zipfile.on("end", function() {
97105
if (entryNames.length === 0) console.log("optional parameters and directories: pass");

0 commit comments

Comments
 (0)