mirror of
https://github.com/golang/go
synced 2024-11-02 15:31:08 +00:00
archive/zip: permit zip files to have prefixes
A Java jar file is a zip file, but it can have a prefix that is a bash script that unpacks the zip file. Most zip programs ignore such prefixes. This CL changes the archive/zip package to do the same. Fixes #10464 Fixes #51337 Change-Id: I976e9c64684644317bd21077bc5b4a2baf626ee6 Reviewed-on: https://go-review.googlesource.com/c/go/+/387976 Run-TryBot: Ian Lance Taylor <iant@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org> Reviewed-by: David Chase <drchase@google.com> Reviewed-by: Joseph Tsai <joetsai@digital-static.net> Auto-Submit: Ian Lance Taylor <iant@google.com>
This commit is contained in:
parent
507a44dc22
commit
df57592276
4 changed files with 41 additions and 13 deletions
|
@ -33,6 +33,10 @@ type Reader struct {
|
|||
Comment string
|
||||
decompressors map[uint16]Decompressor
|
||||
|
||||
// Some JAR files are zip files with a prefix that is a bash script.
|
||||
// The baseOffset field is the start of the zip file proper.
|
||||
baseOffset int64
|
||||
|
||||
// fileList is a list of files sorted by ename,
|
||||
// for use by the Open method.
|
||||
fileListOnce sync.Once
|
||||
|
@ -52,7 +56,7 @@ type File struct {
|
|||
FileHeader
|
||||
zip *Reader
|
||||
zipr io.ReaderAt
|
||||
headerOffset int64
|
||||
headerOffset int64 // includes overall ZIP archive baseOffset
|
||||
zip64 bool // zip64 extended information extra field presence
|
||||
}
|
||||
|
||||
|
@ -90,11 +94,12 @@ func NewReader(r io.ReaderAt, size int64) (*Reader, error) {
|
|||
}
|
||||
|
||||
func (z *Reader) init(r io.ReaderAt, size int64) error {
|
||||
end, err := readDirectoryEnd(r, size)
|
||||
end, baseOffset, err := readDirectoryEnd(r, size)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
z.r = r
|
||||
z.baseOffset = baseOffset
|
||||
// Since the number of directory records is not validated, it is not
|
||||
// safe to preallocate z.File without first checking that the specified
|
||||
// number of files is reasonable, since a malformed archive may
|
||||
|
@ -106,7 +111,7 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
|
|||
}
|
||||
z.Comment = end.comment
|
||||
rs := io.NewSectionReader(r, 0, size)
|
||||
if _, err = rs.Seek(int64(end.directoryOffset), io.SeekStart); err != nil {
|
||||
if _, err = rs.Seek(z.baseOffset+int64(end.directoryOffset), io.SeekStart); err != nil {
|
||||
return err
|
||||
}
|
||||
buf := bufio.NewReader(rs)
|
||||
|
@ -124,6 +129,7 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.headerOffset += z.baseOffset
|
||||
z.File = append(z.File, f)
|
||||
}
|
||||
if uint16(len(z.File)) != uint16(end.directoryRecords) { // only compare 16 bits here
|
||||
|
@ -494,7 +500,7 @@ func readDataDescriptor(r io.Reader, f *File) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err error) {
|
||||
func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, baseOffset int64, err error) {
|
||||
// look for directoryEndSignature in the last 1k, then in the last 65k
|
||||
var buf []byte
|
||||
var directoryEndOffset int64
|
||||
|
@ -504,7 +510,7 @@ func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err error)
|
|||
}
|
||||
buf = make([]byte, int(bLen))
|
||||
if _, err := r.ReadAt(buf, size-bLen); err != nil && err != io.EOF {
|
||||
return nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
if p := findSignatureInBlock(buf); p >= 0 {
|
||||
buf = buf[p:]
|
||||
|
@ -512,7 +518,7 @@ func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err error)
|
|||
break
|
||||
}
|
||||
if i == 1 || bLen == size {
|
||||
return nil, ErrFormat
|
||||
return nil, 0, ErrFormat
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -529,7 +535,7 @@ func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err error)
|
|||
}
|
||||
l := int(d.commentLen)
|
||||
if l > len(b) {
|
||||
return nil, errors.New("zip: invalid comment length")
|
||||
return nil, 0, errors.New("zip: invalid comment length")
|
||||
}
|
||||
d.comment = string(b[:l])
|
||||
|
||||
|
@ -537,17 +543,21 @@ func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err error)
|
|||
if d.directoryRecords == 0xffff || d.directorySize == 0xffff || d.directoryOffset == 0xffffffff {
|
||||
p, err := findDirectory64End(r, directoryEndOffset)
|
||||
if err == nil && p >= 0 {
|
||||
directoryEndOffset = p
|
||||
err = readDirectory64End(r, p, d)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, 0, err
|
||||
}
|
||||
}
|
||||
|
||||
baseOffset = directoryEndOffset - int64(d.directorySize) - int64(d.directoryOffset)
|
||||
|
||||
// Make sure directoryOffset points to somewhere in our file.
|
||||
if o := int64(d.directoryOffset); o < 0 || o >= size {
|
||||
return nil, ErrFormat
|
||||
if o := baseOffset + int64(d.directoryOffset); o < 0 || o >= size {
|
||||
return nil, 0, ErrFormat
|
||||
}
|
||||
return d, nil
|
||||
return d, baseOffset, nil
|
||||
}
|
||||
|
||||
// findDirectory64End tries to read the zip64 locator just before the
|
||||
|
|
|
@ -90,6 +90,24 @@ var tests = []ZipTest{
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "test-prefix.zip",
|
||||
Comment: "This is a zipfile comment.",
|
||||
File: []ZipTestFile{
|
||||
{
|
||||
Name: "test.txt",
|
||||
Content: []byte("This is a test text file.\n"),
|
||||
Modified: time.Date(2010, 9, 5, 12, 12, 1, 0, timeZone(+10*time.Hour)),
|
||||
Mode: 0644,
|
||||
},
|
||||
{
|
||||
Name: "gophercolor16x16.png",
|
||||
File: "gophercolor16x16.png",
|
||||
Modified: time.Date(2010, 9, 5, 15, 52, 58, 0, timeZone(+10*time.Hour)),
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "r.zip",
|
||||
Source: returnRecursiveZip,
|
||||
|
@ -1011,7 +1029,7 @@ func TestIssue10957(t *testing.T) {
|
|||
"\x00\x00\x00\x00\x0000000000\x00\x00\x00\x00000" +
|
||||
"00000000PK\x01\x0200000000" +
|
||||
"0000000000000000\v\x00\x00\x00" +
|
||||
"\x00\x0000PK\x05\x06000000\x05\x000000" +
|
||||
"\x00\x0000PK\x05\x06000000\x05\x00\xfd\x00\x00\x00" +
|
||||
"\v\x00\x00\x00\x00\x00")
|
||||
z, err := NewReader(bytes.NewReader(data), int64(len(data)))
|
||||
if err != nil {
|
||||
|
@ -1056,7 +1074,7 @@ func TestIssue11146(t *testing.T) {
|
|||
"0000000000000000PK\x01\x02" +
|
||||
"0000\b0\b\x00000000000000" +
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000000PK\x05\x06\x00\x00" +
|
||||
"\x00\x0000\x01\x0000008\x00\x00\x00\x00\x00")
|
||||
"\x00\x0000\x01\x00\x26\x00\x00\x008\x00\x00\x00\x00\x00")
|
||||
z, err := NewReader(bytes.NewReader(data), int64(len(data)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
BIN
src/archive/zip/testdata/readme.notzip
vendored
BIN
src/archive/zip/testdata/readme.notzip
vendored
Binary file not shown.
BIN
src/archive/zip/testdata/test-prefix.zip
vendored
Normal file
BIN
src/archive/zip/testdata/test-prefix.zip
vendored
Normal file
Binary file not shown.
Loading…
Reference in a new issue