Skip to content
This repository has been archived by the owner on Oct 28, 2024. It is now read-only.

Fix zip files created on Windows being unusable on Linux/MacOS #1

Merged
merged 2 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
MIT License

Copyright (c) 2014 Josh Wolfe
Copyright (c) 2024 Lee Jisol
Copyright (c) 2024 Lee Jisol and Jimb Esser

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
15 changes: 12 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class Entry {
this.isDirectory = isDirectory;
this.state = Entry.WAITING_FOR_METADATA;
this.setLastModDate(options.mtime ?? new Date());
this.setFileAttributesMode(options.mode ?? (isDirectory ? 0o40775 : 0o100664));
this.setFileAttributesMode(options.mode ?? 0o000664, isDirectory);
if (isDirectory) {
this.crcAndFileSizeKnown = true;
this.crc32 = 0;
Expand Down Expand Up @@ -139,10 +139,19 @@ class Entry {
/**
* @param {number} mode
*/
setFileAttributesMode(mode) {
setFileAttributesMode(mode, isDirectory) {
if ((mode & 0xffff) !== mode) {
throw new Error(`invalid mode. expected: 0 <= ${mode} <= 65535`);
}
if (isDirectory) {
// https://github.com/thejoshwolfe/yazl/pull/59
// 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)) & 0o000111;
mode |= 0o040000; // S_IFDIR
} else {
mode |= 0o100000; // S_IFREG
}
// http://unix.stackexchange.com/questions/14705/the-zip-formats-external-file-attribute/14727#14727
this.externalFileAttributes = (mode << 16) >>> 0;
}
Expand Down Expand Up @@ -381,7 +390,7 @@ class ZipFile extends EventEmitter {
}
entry.uncompressedSize = stats.size;
if (options.mtime == null) entry.setLastModDate(stats.mtime);
if (options.mode == null) entry.setFileAttributesMode(stats.mode);
if (options.mode == null) entry.setFileAttributesMode(stats.mode, false);
entry.setFileDataPumpFunction(() => {
const readStream = createReadStream(realPath);
entry.state = Entry.FILE_DATA_IN_PROGRESS;
Expand Down
18 changes: 15 additions & 3 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const filename = fileURLToPath(import.meta.url);
zipfile.addBuffer(Buffer.from('buffer'), 'b.txt');
zipfile.addReadStream(new BufferListStream().append('stream'), 'c.txt');
zipfile.addEmptyDirectory('d/');
zipfile.addEmptyDirectory('e');
zipfile.addEmptyDirectory('e', { mode: 0o000644 });
zipfile.end(function (finalSize) {
if (finalSize !== -1) throw new Error('finalSize should be unknown');
zipfile.outputStream.pipe(new BufferListStream(function (err, data) {
Expand All @@ -96,9 +96,21 @@ const filename = fileURLToPath(import.meta.url);
if (err) throw err;
const entryNames = ['a.txt', 'b.txt', 'c.txt', 'd/', 'e/'];
zipfile.on('entry', function (entry) {
const { fileName } = entry;
const expectedName = entryNames.shift();
if (entry.fileName !== expectedName) {
throw new Error(`unexpected entry fileName: ${entry.fileName}, expected: ${expectedName}`);
if (fileName !== expectedName) {
throw new Error(`unexpected entry fileName: ${fileName}, expected: ${expectedName}`);
}
const mode = entry.externalFileAttributes >>> 16;
if (fileName.endsWith('/')) {
if ((mode & 0o040000) === 0) {
throw new Error(`directory expected to have S_IFDIR, found ${mode.toString(8)}`);
}
if ((mode & 0o000111) === 0) {
throw new Error(`directory expected to have executable flags, found ${mode.toString(8)}`);
}
} else if ((mode & 0o100000) === 0) {
throw new Error(`file expected to have S_IFREG, found ${mode.toString(8)}`);
}
});
zipfile.on('end', function () {
Expand Down