Skip to content
This repository was archived by the owner on Jun 30, 2023. It is now read-only.

Commit 50e0590

Browse files
committed
Fix additional corruption with zips created on linux containing empty directories
This is similar to #36. Go's zip library has some "interesting" behavior where if you call zipWriter.CreateHeader with a file header that already contains extra metadata encoding the last modified time for an empty directory, it will append the current last modified time to the existing one stored in the `Extra` field. This leads to corruption similar to #36 where MacOS will refuse to open the zip and `zipinfo -v` will show a "There are an extra -xxx bytes preceding this file" warning. I think the Go's library solution to this would be to use CreateRaw, but we actually do want most of the logic that CreateHeader implements (see #36 where we switched to CreateHeader). So instead, I just clear the Extra field in the file header when copying over directories. This means that directories will have their last modified time reset to the current date. This is somewhat incorrect, but seems to me like a reasonable compromise to me.
1 parent 73b8540 commit 50e0590

File tree

4 files changed

+11
-1
lines changed

4 files changed

+11
-1
lines changed

jar/rewrite.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,15 @@ func Rewrite(w io.Writer, zr *zip.Reader) error {
123123
copyFile:
124124
if zipItem.Mode().IsDir() {
125125
// Copy() only works on files, so manually create the directory entry
126-
if _, err := zw.CreateHeader(&zipItem.FileHeader); err != nil {
126+
dirHeader := zipItem.FileHeader
127+
// Reset the Extra field which holds the OS-specific metadata that encodes the last
128+
// modified time. This is technically incorrect because it means the mitigated
129+
// zips that we create will have the last modified timestamp updated. But, if we don't
130+
// do this we create invalid zips because `zw.CreateHeader` assumes that `Extra` is empty
131+
// and always appends the modified time to the end of `Extra`. We don't use `zw.CreateRaw`
132+
// because we want the rest of the logic that `zw.CreateHeader` provides.
133+
dirHeader.Extra = make([]byte, 0)
134+
if _, err := zw.CreateHeader(&dirHeader); err != nil {
127135
return fmt.Errorf("failed to copy zip directory %s: %v", zipItem.Name, err)
128136
}
129137
} else {

jar/rewrite_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,8 @@ func TestAutoMitigatedJarsAreCorrectlyFormed(t *testing.T) {
363363
"log4j-core-2.1.jar",
364364
"safe1.jar",
365365
"safe1.signed.jar",
366+
"emptydir.zip",
367+
"emptydirs.zip",
366368
}
367369
for _, name := range testCases {
368370
t.Run(name, func(t *testing.T) {

jar/testdata/emptydir.zip

188 Bytes
Binary file not shown.

jar/testdata/emptydirs.zip

1.5 MB
Binary file not shown.

0 commit comments

Comments
 (0)