merge_zips: fix compressed size and CRC32 fields for inserted manifests
The compressed size and CRC32 fields in the file headers were left at
0 for inserted manifests, resulting in an invalid zip file. Insert the
compressed size and CRC32 fields anywhere the FileHeader is created
directly.
Adds tests for the merge_zips options that add files to the zip.
Test: TestMergeZips
Change-Id: Ib027f868aa6e55f848ccaaa18582ecbc54c9a8f6
diff --git a/cmd/merge_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go
index 2c57180..c89facf 100644
--- a/cmd/merge_zips/merge_zips.go
+++ b/cmd/merge_zips/merge_zips.go
@@ -212,6 +212,8 @@
Name: name,
Method: zip.Store,
UncompressedSize64: uint64(len(buf)),
+ CompressedSize64: uint64(len(buf)),
+ CRC32: crc32.ChecksumIEEE(buf),
}
fh.SetMode(0700)
fh.SetModTime(jar.DefaultTime)
@@ -225,7 +227,9 @@
fh := &zip.FileHeader{
Name: entry,
Method: zip.Store,
- UncompressedSize64: uint64(len(emptyBuf)),
+ UncompressedSize64: 0,
+ CompressedSize64: 0,
+ CRC32: crc32.ChecksumIEEE(emptyBuf),
}
fh.SetMode(0700)
fh.SetModTime(jar.DefaultTime)
diff --git a/cmd/merge_zips/merge_zips_test.go b/cmd/merge_zips/merge_zips_test.go
index 17228c4..b7491cf 100644
--- a/cmd/merge_zips/merge_zips_test.go
+++ b/cmd/merge_zips/merge_zips_test.go
@@ -19,6 +19,7 @@
"fmt"
"hash/crc32"
"os"
+ "path/filepath"
"strconv"
"strings"
"testing"
@@ -34,33 +35,35 @@
data []byte
method uint16
timestamp time.Time
+ extra []byte
}
var (
- A = testZipEntry{"A", 0755, []byte("foo"), zip.Deflate, jar.DefaultTime}
- a = testZipEntry{"a", 0755, []byte("foo"), zip.Deflate, jar.DefaultTime}
- a2 = testZipEntry{"a", 0755, []byte("FOO2"), zip.Deflate, jar.DefaultTime}
- a3 = testZipEntry{"a", 0755, []byte("Foo3"), zip.Deflate, jar.DefaultTime}
- bDir = testZipEntry{"b/", os.ModeDir | 0755, nil, zip.Deflate, jar.DefaultTime}
- bbDir = testZipEntry{"b/b/", os.ModeDir | 0755, nil, zip.Deflate, jar.DefaultTime}
- bbb = testZipEntry{"b/b/b", 0755, nil, zip.Deflate, jar.DefaultTime}
- ba = testZipEntry{"b/a", 0755, []byte("foo"), zip.Deflate, jar.DefaultTime}
- bc = testZipEntry{"b/c", 0755, []byte("bar"), zip.Deflate, jar.DefaultTime}
- bd = testZipEntry{"b/d", 0700, []byte("baz"), zip.Deflate, jar.DefaultTime}
- be = testZipEntry{"b/e", 0700, []byte(""), zip.Deflate, jar.DefaultTime}
+ A = testZipEntry{"A", 0755, []byte("foo"), zip.Deflate, jar.DefaultTime, nil}
+ a = testZipEntry{"a", 0755, []byte("foo"), zip.Deflate, jar.DefaultTime, nil}
+ a2 = testZipEntry{"a", 0755, []byte("FOO2"), zip.Deflate, jar.DefaultTime, nil}
+ a3 = testZipEntry{"a", 0755, []byte("Foo3"), zip.Deflate, jar.DefaultTime, nil}
+ bDir = testZipEntry{"b/", os.ModeDir | 0755, nil, zip.Deflate, jar.DefaultTime, nil}
+ bbDir = testZipEntry{"b/b/", os.ModeDir | 0755, nil, zip.Deflate, jar.DefaultTime, nil}
+ bbb = testZipEntry{"b/b/b", 0755, nil, zip.Deflate, jar.DefaultTime, nil}
+ ba = testZipEntry{"b/a", 0755, []byte("foo"), zip.Deflate, jar.DefaultTime, nil}
+ bc = testZipEntry{"b/c", 0755, []byte("bar"), zip.Deflate, jar.DefaultTime, nil}
+ bd = testZipEntry{"b/d", 0700, []byte("baz"), zip.Deflate, jar.DefaultTime, nil}
+ be = testZipEntry{"b/e", 0700, []byte(""), zip.Deflate, jar.DefaultTime, nil}
- withTimestamp = testZipEntry{"timestamped", 0755, nil, zip.Store, jar.DefaultTime.Add(time.Hour)}
- withoutTimestamp = testZipEntry{"timestamped", 0755, nil, zip.Store, jar.DefaultTime}
+ withTimestamp = testZipEntry{"timestamped", 0755, nil, zip.Store, jar.DefaultTime.Add(time.Hour), nil}
+ withoutTimestamp = testZipEntry{"timestamped", 0755, nil, zip.Store, jar.DefaultTime, nil}
- service1a = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass2\n"), zip.Store, jar.DefaultTime}
- service1b = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass3\n"), zip.Deflate, jar.DefaultTime}
- service1combined = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass2\nclass3\n"), zip.Store, jar.DefaultTime}
- service2 = testZipEntry{"META-INF/services/service2", 0755, []byte("class1\nclass2\n"), zip.Deflate, jar.DefaultTime}
+ service1a = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass2\n"), zip.Store, jar.DefaultTime, nil}
+ service1b = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass3\n"), zip.Deflate, jar.DefaultTime, nil}
+ service1combined = testZipEntry{"META-INF/services/service1", 0755, []byte("class1\nclass2\nclass3\n"), zip.Store, jar.DefaultTime, nil}
+ service2 = testZipEntry{"META-INF/services/service2", 0755, []byte("class1\nclass2\n"), zip.Deflate, jar.DefaultTime, nil}
- metainfDir = testZipEntry{jar.MetaDir, os.ModeDir | 0755, nil, zip.Deflate, jar.DefaultTime}
- manifestFile = testZipEntry{jar.ManifestFile, 0755, []byte("manifest"), zip.Deflate, jar.DefaultTime}
- manifestFile2 = testZipEntry{jar.ManifestFile, 0755, []byte("manifest2"), zip.Deflate, jar.DefaultTime}
- moduleInfoFile = testZipEntry{jar.ModuleInfoClass, 0755, []byte("module-info"), zip.Deflate, jar.DefaultTime}
+ metainfDir = testZipEntry{jar.MetaDir, os.ModeDir | 0755, nil, zip.Store, jar.DefaultTime, []byte{0xfe, 0xca, 0, 0}}
+ manifestFile = testZipEntry{jar.ManifestFile, 0644, []byte("Manifest-Version: 1.0\nmanifest"), zip.Store, jar.DefaultTime, nil}
+ manifestFile2 = testZipEntry{jar.ManifestFile, 0644, []byte("manifest2"), zip.Deflate, jar.DefaultTime, nil}
+
+ pyMainFile = testZipEntry{"__main__.py", 0700, []byte("pyMain"), zip.Store, jar.DefaultTime, nil}
)
type testInputZip struct {
@@ -108,6 +111,8 @@
ignoreDuplicates bool
stripDirEntries bool
zipsToNotStrip map[string]bool
+ manifest string
+ pyMain string
out []testZipEntry
err string
@@ -294,6 +299,16 @@
},
par: true,
},
+ {
+ name: "manifest",
+ manifest: "Manifest-Version: 1.0\nmanifest",
+ out: []testZipEntry{metainfDir, manifestFile},
+ },
+ {
+ name: "pyMain",
+ pyMain: "pyMain",
+ out: []testZipEntry{pyMainFile},
+ },
}
for _, test := range testCases {
@@ -308,7 +323,25 @@
out := &bytes.Buffer{}
writer := zip.NewWriter(out)
- err := mergeZips(inputZips, writer, "", "",
+ manifestFile := ""
+ if test.manifest != "" {
+ manifestFile = filepath.Join(t.TempDir(), "manifest.txt")
+ err := os.WriteFile(manifestFile, []byte(test.manifest), 0666)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ pyMainFile := ""
+ if test.pyMain != "" {
+ pyMainFile = filepath.Join(t.TempDir(), "pymain.txt")
+ err := os.WriteFile(pyMainFile, []byte(test.pyMain), 0666)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ err := mergeZips(inputZips, writer, manifestFile, pyMainFile,
test.sort, test.jar, test.par, test.stripDirEntries, test.ignoreDuplicates,
test.stripFiles, test.stripDirs, test.zipsToNotStrip)
@@ -352,6 +385,7 @@
fh.SetModTime(e.timestamp)
fh.UncompressedSize64 = uint64(len(e.data))
fh.CRC32 = crc32.ChecksumIEEE(e.data)
+ fh.Extra = e.extra
if fh.Method == zip.Store {
fh.CompressedSize64 = fh.UncompressedSize64
}
@@ -397,35 +431,35 @@
var ret string
for _, f := range zr.File {
- ret += fmt.Sprintf("%v: %v %v %08x %s\n", f.Name, f.Mode(), f.UncompressedSize64, f.CRC32, f.ModTime())
+ ret += fmt.Sprintf("%v: %v %v %v %08x %s\n", f.Name, f.Mode(), f.UncompressedSize64, f.CompressedSize64, f.CRC32, f.ModTime())
}
return ret
}
-type DummyInpuZip struct {
+type DummyInputZip struct {
isOpen bool
}
-func (diz *DummyInpuZip) Name() string {
+func (diz *DummyInputZip) Name() string {
return "dummy"
}
-func (diz *DummyInpuZip) Open() error {
+func (diz *DummyInputZip) Open() error {
diz.isOpen = true
return nil
}
-func (diz *DummyInpuZip) Close() error {
+func (diz *DummyInputZip) Close() error {
diz.isOpen = false
return nil
}
-func (DummyInpuZip) Entries() []*zip.File {
+func (DummyInputZip) Entries() []*zip.File {
panic("implement me")
}
-func (diz *DummyInpuZip) IsOpen() bool {
+func (diz *DummyInputZip) IsOpen() bool {
return diz.isOpen
}
@@ -435,7 +469,7 @@
izm := NewInputZipsManager(20, 10)
managedZips := make([]InputZip, nInputZips)
for i := 0; i < nInputZips; i++ {
- managedZips[i] = izm.Manage(&DummyInpuZip{})
+ managedZips[i] = izm.Manage(&DummyInputZip{})
}
t.Run("InputZipsManager", func(t *testing.T) {
diff --git a/jar/jar.go b/jar/jar.go
index 54eded9..daad4b0 100644
--- a/jar/jar.go
+++ b/jar/jar.go
@@ -17,6 +17,7 @@
import (
"bytes"
"fmt"
+ "hash/crc32"
"io"
"os"
"strings"
@@ -93,7 +94,9 @@
fh := &zip.FileHeader{
Name: ManifestFile,
Method: zip.Store,
+ CompressedSize64: uint64(len(b)),
UncompressedSize64: uint64(len(b)),
+ CRC32: crc32.ChecksumIEEE(b),
}
fh.SetMode(0644)
fh.SetModTime(DefaultTime)