summaryrefslogtreecommitdiff
path: root/libgo/go/archive
diff options
context:
space:
mode:
authorupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
committerupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
commit554fd8c5195424bdbcabf5de30fdc183aba391bd (patch)
tree976dc5ab7fddf506dadce60ae936f43f58787092 /libgo/go/archive
downloadcbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.bz2
cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.xz
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository.
Diffstat (limited to 'libgo/go/archive')
-rw-r--r--libgo/go/archive/tar/common.go75
-rw-r--r--libgo/go/archive/tar/reader.go226
-rw-r--r--libgo/go/archive/tar/reader_test.go274
-rw-r--r--libgo/go/archive/tar/testdata/gnu.tarbin0 -> 3072 bytes
-rw-r--r--libgo/go/archive/tar/testdata/small.txt1
-rw-r--r--libgo/go/archive/tar/testdata/small2.txt1
-rw-r--r--libgo/go/archive/tar/testdata/star.tarbin0 -> 3072 bytes
-rw-r--r--libgo/go/archive/tar/testdata/v7.tarbin0 -> 3584 bytes
-rw-r--r--libgo/go/archive/tar/testdata/writer-big.tarbin0 -> 4096 bytes
-rw-r--r--libgo/go/archive/tar/testdata/writer.tarbin0 -> 3072 bytes
-rw-r--r--libgo/go/archive/tar/writer.go205
-rw-r--r--libgo/go/archive/tar/writer_test.go154
-rw-r--r--libgo/go/archive/zip/reader.go278
-rw-r--r--libgo/go/archive/zip/reader_test.go180
-rw-r--r--libgo/go/archive/zip/struct.go33
-rw-r--r--libgo/go/archive/zip/testdata/gophercolor16x16.pngbin0 -> 785 bytes
-rw-r--r--libgo/go/archive/zip/testdata/r.zipbin0 -> 440 bytes
-rw-r--r--libgo/go/archive/zip/testdata/readme.notzipbin0 -> 1905 bytes
-rw-r--r--libgo/go/archive/zip/testdata/readme.zipbin0 -> 1885 bytes
-rw-r--r--libgo/go/archive/zip/testdata/test.zipbin0 -> 1170 bytes
20 files changed, 1427 insertions, 0 deletions
diff --git a/libgo/go/archive/tar/common.go b/libgo/go/archive/tar/common.go
new file mode 100644
index 000000000..5b781ff3d
--- /dev/null
+++ b/libgo/go/archive/tar/common.go
@@ -0,0 +1,75 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The tar package implements access to tar archives.
+// It aims to cover most of the variations, including those produced
+// by GNU and BSD tars.
+//
+// References:
+// http://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5
+// http://www.gnu.org/software/tar/manual/html_node/Standard.html
+package tar
+
+const (
+ blockSize = 512
+
+ // Types
+ TypeReg = '0'
+ TypeRegA = '\x00'
+ TypeLink = '1'
+ TypeSymlink = '2'
+ TypeChar = '3'
+ TypeBlock = '4'
+ TypeDir = '5'
+ TypeFifo = '6'
+ TypeCont = '7'
+ TypeXHeader = 'x'
+ TypeXGlobalHeader = 'g'
+)
+
+// A Header represents a single header in a tar archive.
+// Some fields may not be populated.
+type Header struct {
+ Name string
+ Mode int64
+ Uid int
+ Gid int
+ Size int64
+ Mtime int64
+ Typeflag byte
+ Linkname string
+ Uname string
+ Gname string
+ Devmajor int64
+ Devminor int64
+ Atime int64
+ Ctime int64
+}
+
+var zeroBlock = make([]byte, blockSize)
+
+// POSIX specifies a sum of the unsigned byte values, but the Sun tar uses signed byte values.
+// We compute and return both.
+func checksum(header []byte) (unsigned int64, signed int64) {
+ for i := 0; i < len(header); i++ {
+ if i == 148 {
+ // The chksum field (header[148:156]) is special: it should be treated as space bytes.
+ unsigned += ' ' * 8
+ signed += ' ' * 8
+ i += 7
+ continue
+ }
+ unsigned += int64(header[i])
+ signed += int64(int8(header[i]))
+ }
+ return
+}
+
+type slicer []byte
+
+func (sp *slicer) next(n int) (b []byte) {
+ s := *sp
+ b, *sp = s[0:n], s[n:]
+ return
+}
diff --git a/libgo/go/archive/tar/reader.go b/libgo/go/archive/tar/reader.go
new file mode 100644
index 000000000..35a15f74b
--- /dev/null
+++ b/libgo/go/archive/tar/reader.go
@@ -0,0 +1,226 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tar
+
+// TODO(dsymonds):
+// - pax extensions
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "strconv"
+)
+
+var (
+ HeaderError os.Error = os.ErrorString("invalid tar header")
+)
+
+// A Reader provides sequential access to the contents of a tar archive.
+// A tar archive consists of a sequence of files.
+// The Next method advances to the next file in the archive (including the first),
+// and then it can be treated as an io.Reader to access the file's data.
+//
+// Example:
+// tr := tar.NewReader(r)
+// for {
+// hdr, err := tr.Next()
+// if err != nil {
+// // handle error
+// }
+// if hdr == nil {
+// // end of tar archive
+// break
+// }
+// io.Copy(data, tr)
+// }
+type Reader struct {
+ r io.Reader
+ err os.Error
+ nb int64 // number of unread bytes for current file entry
+ pad int64 // amount of padding (ignored) after current file entry
+}
+
+// NewReader creates a new Reader reading from r.
+func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
+
+// Next advances to the next entry in the tar archive.
+func (tr *Reader) Next() (*Header, os.Error) {
+ var hdr *Header
+ if tr.err == nil {
+ tr.skipUnread()
+ }
+ if tr.err == nil {
+ hdr = tr.readHeader()
+ }
+ return hdr, tr.err
+}
+
+// Parse bytes as a NUL-terminated C-style string.
+// If a NUL byte is not found then the whole slice is returned as a string.
+func cString(b []byte) string {
+ n := 0
+ for n < len(b) && b[n] != 0 {
+ n++
+ }
+ return string(b[0:n])
+}
+
+func (tr *Reader) octal(b []byte) int64 {
+ // Removing leading spaces.
+ for len(b) > 0 && b[0] == ' ' {
+ b = b[1:]
+ }
+ // Removing trailing NULs and spaces.
+ for len(b) > 0 && (b[len(b)-1] == ' ' || b[len(b)-1] == '\x00') {
+ b = b[0 : len(b)-1]
+ }
+ x, err := strconv.Btoui64(cString(b), 8)
+ if err != nil {
+ tr.err = err
+ }
+ return int64(x)
+}
+
+type ignoreWriter struct{}
+
+func (ignoreWriter) Write(b []byte) (n int, err os.Error) {
+ return len(b), nil
+}
+
+// Skip any unread bytes in the existing file entry, as well as any alignment padding.
+func (tr *Reader) skipUnread() {
+ nr := tr.nb + tr.pad // number of bytes to skip
+ tr.nb, tr.pad = 0, 0
+ if sr, ok := tr.r.(io.Seeker); ok {
+ if _, err := sr.Seek(nr, 1); err == nil {
+ return
+ }
+ }
+ _, tr.err = io.Copyn(ignoreWriter{}, tr.r, nr)
+}
+
+func (tr *Reader) verifyChecksum(header []byte) bool {
+ if tr.err != nil {
+ return false
+ }
+
+ given := tr.octal(header[148:156])
+ unsigned, signed := checksum(header)
+ return given == unsigned || given == signed
+}
+
+func (tr *Reader) readHeader() *Header {
+ header := make([]byte, blockSize)
+ if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
+ return nil
+ }
+
+ // Two blocks of zero bytes marks the end of the archive.
+ if bytes.Equal(header, zeroBlock[0:blockSize]) {
+ if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
+ return nil
+ }
+ if bytes.Equal(header, zeroBlock[0:blockSize]) {
+ tr.err = os.EOF
+ } else {
+ tr.err = HeaderError // zero block and then non-zero block
+ }
+ return nil
+ }
+
+ if !tr.verifyChecksum(header) {
+ tr.err = HeaderError
+ return nil
+ }
+
+ // Unpack
+ hdr := new(Header)
+ s := slicer(header)
+
+ hdr.Name = cString(s.next(100))
+ hdr.Mode = tr.octal(s.next(8))
+ hdr.Uid = int(tr.octal(s.next(8)))
+ hdr.Gid = int(tr.octal(s.next(8)))
+ hdr.Size = tr.octal(s.next(12))
+ hdr.Mtime = tr.octal(s.next(12))
+ s.next(8) // chksum
+ hdr.Typeflag = s.next(1)[0]
+ hdr.Linkname = cString(s.next(100))
+
+ // The remainder of the header depends on the value of magic.
+ // The original (v7) version of tar had no explicit magic field,
+ // so its magic bytes, like the rest of the block, are NULs.
+ magic := string(s.next(8)) // contains version field as well.
+ var format string
+ switch magic {
+ case "ustar\x0000": // POSIX tar (1003.1-1988)
+ if string(header[508:512]) == "tar\x00" {
+ format = "star"
+ } else {
+ format = "posix"
+ }
+ case "ustar \x00": // old GNU tar
+ format = "gnu"
+ }
+
+ switch format {
+ case "posix", "gnu", "star":
+ hdr.Uname = cString(s.next(32))
+ hdr.Gname = cString(s.next(32))
+ devmajor := s.next(8)
+ devminor := s.next(8)
+ if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock {
+ hdr.Devmajor = tr.octal(devmajor)
+ hdr.Devminor = tr.octal(devminor)
+ }
+ var prefix string
+ switch format {
+ case "posix", "gnu":
+ prefix = cString(s.next(155))
+ case "star":
+ prefix = cString(s.next(131))
+ hdr.Atime = tr.octal(s.next(12))
+ hdr.Ctime = tr.octal(s.next(12))
+ }
+ if len(prefix) > 0 {
+ hdr.Name = prefix + "/" + hdr.Name
+ }
+ }
+
+ if tr.err != nil {
+ tr.err = HeaderError
+ return nil
+ }
+
+ // Maximum value of hdr.Size is 64 GB (12 octal digits),
+ // so there's no risk of int64 overflowing.
+ tr.nb = int64(hdr.Size)
+ tr.pad = -tr.nb & (blockSize - 1) // blockSize is a power of two
+
+ return hdr
+}
+
+// Read reads from the current entry in the tar archive.
+// It returns 0, os.EOF when it reaches the end of that entry,
+// until Next is called to advance to the next entry.
+func (tr *Reader) Read(b []byte) (n int, err os.Error) {
+ if tr.nb == 0 {
+ // file consumed
+ return 0, os.EOF
+ }
+
+ if int64(len(b)) > tr.nb {
+ b = b[0:tr.nb]
+ }
+ n, err = tr.r.Read(b)
+ tr.nb -= int64(n)
+
+ if err == os.EOF && tr.nb > 0 {
+ err = io.ErrUnexpectedEOF
+ }
+ tr.err = err
+ return
+}
diff --git a/libgo/go/archive/tar/reader_test.go b/libgo/go/archive/tar/reader_test.go
new file mode 100644
index 000000000..aa4c797fb
--- /dev/null
+++ b/libgo/go/archive/tar/reader_test.go
@@ -0,0 +1,274 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tar
+
+import (
+ "bytes"
+ "crypto/md5"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "testing"
+)
+
+type untarTest struct {
+ file string
+ headers []*Header
+ cksums []string
+}
+
+var gnuTarTest = &untarTest{
+ file: "testdata/gnu.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244428340,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244436044,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ },
+ cksums: []string{
+ "e38b27eaccb4391bdec553a7f3ae6b2f",
+ "c65bd2e50a56a2138bf1716f2fd56fe9",
+ },
+}
+
+var untarTests = []*untarTest{
+ gnuTarTest,
+ &untarTest{
+ file: "testdata/star.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244592783,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ Atime: 1244592783,
+ Ctime: 1244592783,
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244592783,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ Atime: 1244592783,
+ Ctime: 1244592783,
+ },
+ },
+ },
+ &untarTest{
+ file: "testdata/v7.tar",
+ headers: []*Header{
+ &Header{
+ Name: "small.txt",
+ Mode: 0444,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1244593104,
+ Typeflag: '\x00',
+ },
+ &Header{
+ Name: "small2.txt",
+ Mode: 0444,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1244593104,
+ Typeflag: '\x00',
+ },
+ },
+ },
+}
+
+func TestReader(t *testing.T) {
+testLoop:
+ for i, test := range untarTests {
+ f, err := os.Open(test.file, os.O_RDONLY, 0444)
+ if err != nil {
+ t.Errorf("test %d: Unexpected error: %v", i, err)
+ continue
+ }
+ tr := NewReader(f)
+ for j, header := range test.headers {
+ hdr, err := tr.Next()
+ if err != nil || hdr == nil {
+ t.Errorf("test %d, entry %d: Didn't get entry: %v", i, j, err)
+ f.Close()
+ continue testLoop
+ }
+ if !reflect.DeepEqual(hdr, header) {
+ t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v",
+ i, j, *hdr, *header)
+ }
+ }
+ hdr, err := tr.Next()
+ if err == os.EOF {
+ break
+ }
+ if hdr != nil || err != nil {
+ t.Errorf("test %d: Unexpected entry or error: hdr=%v err=%v", i, hdr, err)
+ }
+ f.Close()
+ }
+}
+
+func TestPartialRead(t *testing.T) {
+ f, err := os.Open("testdata/gnu.tar", os.O_RDONLY, 0444)
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ defer f.Close()
+
+ tr := NewReader(f)
+
+ // Read the first four bytes; Next() should skip the last byte.
+ hdr, err := tr.Next()
+ if err != nil || hdr == nil {
+ t.Fatalf("Didn't get first file: %v", err)
+ }
+ buf := make([]byte, 4)
+ if _, err := io.ReadFull(tr, buf); err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ if expected := []byte("Kilt"); !bytes.Equal(buf, expected) {
+ t.Errorf("Contents = %v, want %v", buf, expected)
+ }
+
+ // Second file
+ hdr, err = tr.Next()
+ if err != nil || hdr == nil {
+ t.Fatalf("Didn't get second file: %v", err)
+ }
+ buf = make([]byte, 6)
+ if _, err := io.ReadFull(tr, buf); err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ if expected := []byte("Google"); !bytes.Equal(buf, expected) {
+ t.Errorf("Contents = %v, want %v", buf, expected)
+ }
+}
+
+
+func TestIncrementalRead(t *testing.T) {
+ test := gnuTarTest
+ f, err := os.Open(test.file, os.O_RDONLY, 0444)
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ defer f.Close()
+
+ tr := NewReader(f)
+
+ headers := test.headers
+ cksums := test.cksums
+ nread := 0
+
+ // loop over all files
+ for ; ; nread++ {
+ hdr, err := tr.Next()
+ if hdr == nil || err == os.EOF {
+ break
+ }
+
+ // check the header
+ if !reflect.DeepEqual(hdr, headers[nread]) {
+ t.Errorf("Incorrect header:\nhave %+v\nwant %+v",
+ *hdr, headers[nread])
+ }
+
+ // read file contents in little chunks EOF,
+ // checksumming all the way
+ h := md5.New()
+ rdbuf := make([]uint8, 8)
+ for {
+ nr, err := tr.Read(rdbuf)
+ if err == os.EOF {
+ break
+ }
+ if err != nil {
+ t.Errorf("Read: unexpected error %v\n", err)
+ break
+ }
+ h.Write(rdbuf[0:nr])
+ }
+ // verify checksum
+ have := fmt.Sprintf("%x", h.Sum())
+ want := cksums[nread]
+ if want != have {
+ t.Errorf("Bad checksum on file %s:\nhave %+v\nwant %+v", hdr.Name, have, want)
+ }
+ }
+ if nread != len(headers) {
+ t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(headers), nread)
+ }
+}
+
+func TestNonSeekable(t *testing.T) {
+ test := gnuTarTest
+ f, err := os.Open(test.file, os.O_RDONLY, 0444)
+ if err != nil {
+ t.Fatalf("Unexpected error: %v", err)
+ }
+ defer f.Close()
+
+ // pipe the data in
+ r, w, err := os.Pipe()
+ if err != nil {
+ t.Fatalf("Unexpected error %s", err)
+ }
+ go func() {
+ rdbuf := make([]uint8, 1<<16)
+ for {
+ nr, err := f.Read(rdbuf)
+ w.Write(rdbuf[0:nr])
+ if err == os.EOF {
+ break
+ }
+ }
+ w.Close()
+ }()
+
+ tr := NewReader(r)
+ nread := 0
+
+ for ; ; nread++ {
+ hdr, err := tr.Next()
+ if hdr == nil || err == os.EOF {
+ break
+ }
+ }
+
+ if nread != len(test.headers) {
+ t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(test.headers), nread)
+ }
+}
diff --git a/libgo/go/archive/tar/testdata/gnu.tar b/libgo/go/archive/tar/testdata/gnu.tar
new file mode 100644
index 000000000..fc899dc8d
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/gnu.tar
Binary files differ
diff --git a/libgo/go/archive/tar/testdata/small.txt b/libgo/go/archive/tar/testdata/small.txt
new file mode 100644
index 000000000..b249bfc51
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/small.txt
@@ -0,0 +1 @@
+Kilts \ No newline at end of file
diff --git a/libgo/go/archive/tar/testdata/small2.txt b/libgo/go/archive/tar/testdata/small2.txt
new file mode 100644
index 000000000..394ee3ecd
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/small2.txt
@@ -0,0 +1 @@
+Google.com
diff --git a/libgo/go/archive/tar/testdata/star.tar b/libgo/go/archive/tar/testdata/star.tar
new file mode 100644
index 000000000..59e2d4e60
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/star.tar
Binary files differ
diff --git a/libgo/go/archive/tar/testdata/v7.tar b/libgo/go/archive/tar/testdata/v7.tar
new file mode 100644
index 000000000..eb65fc941
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/v7.tar
Binary files differ
diff --git a/libgo/go/archive/tar/testdata/writer-big.tar b/libgo/go/archive/tar/testdata/writer-big.tar
new file mode 100644
index 000000000..753e883ce
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/writer-big.tar
Binary files differ
diff --git a/libgo/go/archive/tar/testdata/writer.tar b/libgo/go/archive/tar/testdata/writer.tar
new file mode 100644
index 000000000..0358f91b9
--- /dev/null
+++ b/libgo/go/archive/tar/testdata/writer.tar
Binary files differ
diff --git a/libgo/go/archive/tar/writer.go b/libgo/go/archive/tar/writer.go
new file mode 100644
index 000000000..8673bad31
--- /dev/null
+++ b/libgo/go/archive/tar/writer.go
@@ -0,0 +1,205 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tar
+
+// TODO(dsymonds):
+// - catch more errors (no first header, write after close, etc.)
+
+import (
+ "io"
+ "os"
+ "strconv"
+)
+
+var (
+ ErrWriteTooLong = os.NewError("write too long")
+ ErrFieldTooLong = os.NewError("header field too long")
+ ErrWriteAfterClose = os.NewError("write after close")
+)
+
+// A Writer provides sequential writing of a tar archive in POSIX.1 format.
+// A tar archive consists of a sequence of files.
+// Call WriteHeader to begin a new file, and then call Write to supply that file's data,
+// writing at most hdr.Size bytes in total.
+//
+// Example:
+// tw := tar.NewWriter(w)
+// hdr := new(Header)
+// hdr.Size = length of data in bytes
+// // populate other hdr fields as desired
+// if err := tw.WriteHeader(hdr); err != nil {
+// // handle error
+// }
+// io.Copy(tw, data)
+// tw.Close()
+type Writer struct {
+ w io.Writer
+ err os.Error
+ nb int64 // number of unwritten bytes for current file entry
+ pad int64 // amount of padding to write after current file entry
+ closed bool
+ usedBinary bool // whether the binary numeric field extension was used
+}
+
+// NewWriter creates a new Writer writing to w.
+func NewWriter(w io.Writer) *Writer { return &Writer{w: w} }
+
+// Flush finishes writing the current file (optional).
+func (tw *Writer) Flush() os.Error {
+ n := tw.nb + tw.pad
+ for n > 0 && tw.err == nil {
+ nr := n
+ if nr > blockSize {
+ nr = blockSize
+ }
+ var nw int
+ nw, tw.err = tw.w.Write(zeroBlock[0:nr])
+ n -= int64(nw)
+ }
+ tw.nb = 0
+ tw.pad = 0
+ return tw.err
+}
+
+// Write s into b, terminating it with a NUL if there is room.
+func (tw *Writer) cString(b []byte, s string) {
+ if len(s) > len(b) {
+ if tw.err == nil {
+ tw.err = ErrFieldTooLong
+ }
+ return
+ }
+ copy(b, s)
+ if len(s) < len(b) {
+ b[len(s)] = 0
+ }
+}
+
+// Encode x as an octal ASCII string and write it into b with leading zeros.
+func (tw *Writer) octal(b []byte, x int64) {
+ s := strconv.Itob64(x, 8)
+ // leading zeros, but leave room for a NUL.
+ for len(s)+1 < len(b) {
+ s = "0" + s
+ }
+ tw.cString(b, s)
+}
+
+// Write x into b, either as octal or as binary (GNUtar/star extension).
+func (tw *Writer) numeric(b []byte, x int64) {
+ // Try octal first.
+ s := strconv.Itob64(x, 8)
+ if len(s) < len(b) {
+ tw.octal(b, x)
+ return
+ }
+ // Too big: use binary (big-endian).
+ tw.usedBinary = true
+ for i := len(b) - 1; x > 0 && i >= 0; i-- {
+ b[i] = byte(x)
+ x >>= 8
+ }
+ b[0] |= 0x80 // highest bit indicates binary format
+}
+
+// WriteHeader writes hdr and prepares to accept the file's contents.
+// WriteHeader calls Flush if it is not the first header.
+// Calling after a Close will return ErrWriteAfterClose.
+func (tw *Writer) WriteHeader(hdr *Header) os.Error {
+ if tw.closed {
+ return ErrWriteAfterClose
+ }
+ if tw.err == nil {
+ tw.Flush()
+ }
+ if tw.err != nil {
+ return tw.err
+ }
+
+ tw.nb = int64(hdr.Size)
+ tw.pad = -tw.nb & (blockSize - 1) // blockSize is a power of two
+
+ header := make([]byte, blockSize)
+ s := slicer(header)
+
+ // TODO(dsymonds): handle names longer than 100 chars
+ copy(s.next(100), []byte(hdr.Name))
+
+ tw.octal(s.next(8), hdr.Mode) // 100:108
+ tw.numeric(s.next(8), int64(hdr.Uid)) // 108:116
+ tw.numeric(s.next(8), int64(hdr.Gid)) // 116:124
+ tw.numeric(s.next(12), hdr.Size) // 124:136
+ tw.numeric(s.next(12), hdr.Mtime) // 136:148
+ s.next(8) // chksum (148:156)
+ s.next(1)[0] = hdr.Typeflag // 156:157
+ s.next(100) // linkname (157:257)
+ copy(s.next(8), []byte("ustar\x0000")) // 257:265
+ tw.cString(s.next(32), hdr.Uname) // 265:297
+ tw.cString(s.next(32), hdr.Gname) // 297:329
+ tw.numeric(s.next(8), hdr.Devmajor) // 329:337
+ tw.numeric(s.next(8), hdr.Devminor) // 337:345
+
+ // Use the GNU magic instead of POSIX magic if we used any GNU extensions.
+ if tw.usedBinary {
+ copy(header[257:265], []byte("ustar \x00"))
+ }
+
+ // The chksum field is terminated by a NUL and a space.
+ // This is different from the other octal fields.
+ chksum, _ := checksum(header)
+ tw.octal(header[148:155], chksum)
+ header[155] = ' '
+
+ if tw.err != nil {
+ // problem with header; probably integer too big for a field.
+ return tw.err
+ }
+
+ _, tw.err = tw.w.Write(header)
+
+ return tw.err
+}
+
+// Write writes to the current entry in the tar archive.
+// Write returns the error ErrWriteTooLong if more than
+// hdr.Size bytes are written after WriteHeader.
+func (tw *Writer) Write(b []byte) (n int, err os.Error) {
+ if tw.closed {
+ err = ErrWriteTooLong
+ return
+ }
+ overwrite := false
+ if int64(len(b)) > tw.nb {
+ b = b[0:tw.nb]
+ overwrite = true
+ }
+ n, err = tw.w.Write(b)
+ tw.nb -= int64(n)
+ if err == nil && overwrite {
+ err = ErrWriteTooLong
+ return
+ }
+ tw.err = err
+ return
+}
+
+// Close closes the tar archive, flushing any unwritten
+// data to the underlying writer.
+func (tw *Writer) Close() os.Error {
+ if tw.err != nil || tw.closed {
+ return tw.err
+ }
+ tw.Flush()
+ tw.closed = true
+
+ // trailer: two zero blocks
+ for i := 0; i < 2; i++ {
+ _, tw.err = tw.w.Write(zeroBlock)
+ if tw.err != nil {
+ break
+ }
+ }
+ return tw.err
+}
diff --git a/libgo/go/archive/tar/writer_test.go b/libgo/go/archive/tar/writer_test.go
new file mode 100644
index 000000000..48b891140
--- /dev/null
+++ b/libgo/go/archive/tar/writer_test.go
@@ -0,0 +1,154 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tar
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "testing"
+ "testing/iotest"
+)
+
+type writerTestEntry struct {
+ header *Header
+ contents string
+}
+
+type writerTest struct {
+ file string // filename of expected output
+ entries []*writerTestEntry
+}
+
+var writerTests = []*writerTest{
+ &writerTest{
+ file: "testdata/writer.tar",
+ entries: []*writerTestEntry{
+ &writerTestEntry{
+ header: &Header{
+ Name: "small.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 5,
+ Mtime: 1246508266,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ contents: "Kilts",
+ },
+ &writerTestEntry{
+ header: &Header{
+ Name: "small2.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 11,
+ Mtime: 1245217492,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ contents: "Google.com\n",
+ },
+ },
+ },
+ // The truncated test file was produced using these commands:
+ // dd if=/dev/zero bs=1048576 count=16384 > /tmp/16gig.txt
+ // tar -b 1 -c -f- /tmp/16gig.txt | dd bs=512 count=8 > writer-big.tar
+ &writerTest{
+ file: "testdata/writer-big.tar",
+ entries: []*writerTestEntry{
+ &writerTestEntry{
+ header: &Header{
+ Name: "tmp/16gig.txt",
+ Mode: 0640,
+ Uid: 73025,
+ Gid: 5000,
+ Size: 16 << 30,
+ Mtime: 1254699560,
+ Typeflag: '0',
+ Uname: "dsymonds",
+ Gname: "eng",
+ },
+ // no contents
+ },
+ },
+ },
+}
+
+// Render byte array in a two-character hexadecimal string, spaced for easy visual inspection.
+func bytestr(offset int, b []byte) string {
+ const rowLen = 32
+ s := fmt.Sprintf("%04x ", offset)
+ for _, ch := range b {
+ switch {
+ case '0' <= ch && ch <= '9', 'A' <= ch && ch <= 'Z', 'a' <= ch && ch <= 'z':
+ s += fmt.Sprintf(" %c", ch)
+ default:
+ s += fmt.Sprintf(" %02x", ch)
+ }
+ }
+ return s
+}
+
+// Render a pseudo-diff between two blocks of bytes.
+func bytediff(a []byte, b []byte) string {
+ const rowLen = 32
+ s := fmt.Sprintf("(%d bytes vs. %d bytes)\n", len(a), len(b))
+ for offset := 0; len(a)+len(b) > 0; offset += rowLen {
+ na, nb := rowLen, rowLen
+ if na > len(a) {
+ na = len(a)
+ }
+ if nb > len(b) {
+ nb = len(b)
+ }
+ sa := bytestr(offset, a[0:na])
+ sb := bytestr(offset, b[0:nb])
+ if sa != sb {
+ s += fmt.Sprintf("-%v\n+%v\n", sa, sb)
+ }
+ a = a[na:]
+ b = b[nb:]
+ }
+ return s
+}
+
+func TestWriter(t *testing.T) {
+testLoop:
+ for i, test := range writerTests {
+ expected, err := ioutil.ReadFile(test.file)
+ if err != nil {
+ t.Errorf("test %d: Unexpected error: %v", i, err)
+ continue
+ }
+
+ buf := new(bytes.Buffer)
+ tw := NewWriter(iotest.TruncateWriter(buf, 4<<10)) // only catch the first 4 KB
+ for j, entry := range test.entries {
+ if err := tw.WriteHeader(entry.header); err != nil {
+ t.Errorf("test %d, entry %d: Failed writing header: %v", i, j, err)
+ continue testLoop
+ }
+ if _, err := io.WriteString(tw, entry.contents); err != nil {
+ t.Errorf("test %d, entry %d: Failed writing contents: %v", i, j, err)
+ continue testLoop
+ }
+ }
+ if err := tw.Close(); err != nil {
+ t.Errorf("test %d: Failed closing archive: %v", i, err)
+ continue testLoop
+ }
+
+ actual := buf.Bytes()
+ if !bytes.Equal(expected, actual) {
+ t.Errorf("test %d: Incorrect result: (-=expected, +=actual)\n%v",
+ i, bytediff(expected, actual))
+ }
+ }
+}
diff --git a/libgo/go/archive/zip/reader.go b/libgo/go/archive/zip/reader.go
new file mode 100644
index 000000000..579ba1602
--- /dev/null
+++ b/libgo/go/archive/zip/reader.go
@@ -0,0 +1,278 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+The zip package provides support for reading ZIP archives.
+
+See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+
+This package does not support ZIP64 or disk spanning.
+*/
+package zip
+
+import (
+ "bufio"
+ "bytes"
+ "compress/flate"
+ "hash"
+ "hash/crc32"
+ "encoding/binary"
+ "io"
+ "os"
+)
+
+var (
+ FormatError = os.NewError("not a valid zip file")
+ UnsupportedMethod = os.NewError("unsupported compression algorithm")
+ ChecksumError = os.NewError("checksum error")
+)
+
+type Reader struct {
+ r io.ReaderAt
+ File []*File
+ Comment string
+}
+
+type File struct {
+ FileHeader
+ zipr io.ReaderAt
+ zipsize int64
+ headerOffset uint32
+ bodyOffset int64
+}
+
+// OpenReader will open the Zip file specified by name and return a Reader.
+func OpenReader(name string) (*Reader, os.Error) {
+ f, err := os.Open(name, os.O_RDONLY, 0644)
+ if err != nil {
+ return nil, err
+ }
+ fi, err := f.Stat()
+ if err != nil {
+ return nil, err
+ }
+ return NewReader(f, fi.Size)
+}
+
+// NewReader returns a new Reader reading from r, which is assumed to
+// have the given size in bytes.
+func NewReader(r io.ReaderAt, size int64) (*Reader, os.Error) {
+ end, err := readDirectoryEnd(r, size)
+ if err != nil {
+ return nil, err
+ }
+ z := &Reader{
+ r: r,
+ File: make([]*File, end.directoryRecords),
+ Comment: end.comment,
+ }
+ rs := io.NewSectionReader(r, 0, size)
+ if _, err = rs.Seek(int64(end.directoryOffset), 0); err != nil {
+ return nil, err
+ }
+ buf := bufio.NewReader(rs)
+ for i := range z.File {
+ z.File[i] = &File{zipr: r, zipsize: size}
+ if err := readDirectoryHeader(z.File[i], buf); err != nil {
+ return nil, err
+ }
+ }
+ return z, nil
+}
+
+// Open returns a ReadCloser that provides access to the File's contents.
+func (f *File) Open() (rc io.ReadCloser, err os.Error) {
+ off := int64(f.headerOffset)
+ if f.bodyOffset == 0 {
+ r := io.NewSectionReader(f.zipr, off, f.zipsize-off)
+ if err = readFileHeader(f, r); err != nil {
+ return
+ }
+ if f.bodyOffset, err = r.Seek(0, 1); err != nil {
+ return
+ }
+ }
+ r := io.NewSectionReader(f.zipr, off+f.bodyOffset, int64(f.CompressedSize))
+ switch f.Method {
+ case 0: // store (no compression)
+ rc = nopCloser{r}
+ case 8: // DEFLATE
+ rc = flate.NewReader(r)
+ default:
+ err = UnsupportedMethod
+ }
+ if rc != nil {
+ rc = &checksumReader{rc, crc32.NewIEEE(), f.CRC32}
+ }
+ return
+}
+
+type checksumReader struct {
+ rc io.ReadCloser
+ hash hash.Hash32
+ sum uint32
+}
+
+func (r *checksumReader) Read(b []byte) (n int, err os.Error) {
+ n, err = r.rc.Read(b)
+ r.hash.Write(b[:n])
+ if err != os.EOF {
+ return
+ }
+ if r.hash.Sum32() != r.sum {
+ err = ChecksumError
+ }
+ return
+}
+
+func (r *checksumReader) Close() os.Error { return r.rc.Close() }
+
+type nopCloser struct {
+ io.Reader
+}
+
+func (f nopCloser) Close() os.Error { return nil }
+
+func readFileHeader(f *File, r io.Reader) (err os.Error) {
+ defer func() {
+ if rerr, ok := recover().(os.Error); ok {
+ err = rerr
+ }
+ }()
+ var (
+ signature uint32
+ filenameLength uint16
+ extraLength uint16
+ )
+ read(r, &signature)
+ if signature != fileHeaderSignature {
+ return FormatError
+ }
+ read(r, &f.ReaderVersion)
+ read(r, &f.Flags)
+ read(r, &f.Method)
+ read(r, &f.ModifiedTime)
+ read(r, &f.ModifiedDate)
+ read(r, &f.CRC32)
+ read(r, &f.CompressedSize)
+ read(r, &f.UncompressedSize)
+ read(r, &filenameLength)
+ read(r, &extraLength)
+ f.Name = string(readByteSlice(r, filenameLength))
+ f.Extra = readByteSlice(r, extraLength)
+ return
+}
+
+func readDirectoryHeader(f *File, r io.Reader) (err os.Error) {
+ defer func() {
+ if rerr, ok := recover().(os.Error); ok {
+ err = rerr
+ }
+ }()
+ var (
+ signature uint32
+ filenameLength uint16
+ extraLength uint16
+ commentLength uint16
+ startDiskNumber uint16 // unused
+ internalAttributes uint16 // unused
+ externalAttributes uint32 // unused
+ )
+ read(r, &signature)
+ if signature != directoryHeaderSignature {
+ return FormatError
+ }
+ read(r, &f.CreatorVersion)
+ read(r, &f.ReaderVersion)
+ read(r, &f.Flags)
+ read(r, &f.Method)
+ read(r, &f.ModifiedTime)
+ read(r, &f.ModifiedDate)
+ read(r, &f.CRC32)
+ read(r, &f.CompressedSize)
+ read(r, &f.UncompressedSize)
+ read(r, &filenameLength)
+ read(r, &extraLength)
+ read(r, &commentLength)
+ read(r, &startDiskNumber)
+ read(r, &internalAttributes)
+ read(r, &externalAttributes)
+ read(r, &f.headerOffset)
+ f.Name = string(readByteSlice(r, filenameLength))
+ f.Extra = readByteSlice(r, extraLength)
+ f.Comment = string(readByteSlice(r, commentLength))
+ return
+}
+
+func readDirectoryEnd(r io.ReaderAt, size int64) (d *directoryEnd, err os.Error) {
+ // look for directoryEndSignature in the last 1k, then in the last 65k
+ var b []byte
+ for i, bLen := range []int64{1024, 65 * 1024} {
+ if bLen > size {
+ bLen = size
+ }
+ b = make([]byte, int(bLen))
+ if _, err := r.ReadAt(b, size-bLen); err != nil && err != os.EOF {
+ return nil, err
+ }
+ if p := findSignatureInBlock(b); p >= 0 {
+ b = b[p:]
+ break
+ }
+ if i == 1 || bLen == size {
+ return nil, FormatError
+ }
+ }
+
+ // read header into struct
+ defer func() {
+ if rerr, ok := recover().(os.Error); ok {
+ err = rerr
+ d = nil
+ }
+ }()
+ br := bytes.NewBuffer(b[4:]) // skip over signature
+ d = new(directoryEnd)
+ read(br, &d.diskNbr)
+ read(br, &d.dirDiskNbr)
+ read(br, &d.dirRecordsThisDisk)
+ read(br, &d.directoryRecords)
+ read(br, &d.directorySize)
+ read(br, &d.directoryOffset)
+ read(br, &d.commentLen)
+ d.comment = string(readByteSlice(br, d.commentLen))
+ return d, nil
+}
+
+func findSignatureInBlock(b []byte) int {
+ const minSize = 4 + 2 + 2 + 2 + 2 + 4 + 4 + 2 // fixed part of header
+ for i := len(b) - minSize; i >= 0; i-- {
+ // defined from directoryEndSignature in struct.go
+ if b[i] == 'P' && b[i+1] == 'K' && b[i+2] == 0x05 && b[i+3] == 0x06 {
+ // n is length of comment
+ n := int(b[i+minSize-2]) | int(b[i+minSize-1])<<8
+ if n+minSize+i == len(b) {
+ return i
+ }
+ }
+ }
+ return -1
+}
+
+func read(r io.Reader, data interface{}) {
+ if err := binary.Read(r, binary.LittleEndian, data); err != nil {
+ panic(err)
+ }
+}
+
+func readByteSlice(r io.Reader, l uint16) []byte {
+ b := make([]byte, l)
+ if l == 0 {
+ return b
+ }
+ if _, err := io.ReadFull(r, b); err != nil {
+ panic(err)
+ }
+ return b
+}
diff --git a/libgo/go/archive/zip/reader_test.go b/libgo/go/archive/zip/reader_test.go
new file mode 100644
index 000000000..3c24f1467
--- /dev/null
+++ b/libgo/go/archive/zip/reader_test.go
@@ -0,0 +1,180 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package zip
+
+import (
+ "bytes"
+ "encoding/binary"
+ "io"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+type ZipTest struct {
+ Name string
+ Comment string
+ File []ZipTestFile
+ Error os.Error // the error that Opening this file should return
+}
+
+type ZipTestFile struct {
+ Name string
+ Content []byte // if blank, will attempt to compare against File
+ File string // name of file to compare to (relative to testdata/)
+}
+
+var tests = []ZipTest{
+ {
+ Name: "test.zip",
+ Comment: "This is a zipfile comment.",
+ File: []ZipTestFile{
+ {
+ Name: "test.txt",
+ Content: []byte("This is a test text file.\n"),
+ },
+ {
+ Name: "gophercolor16x16.png",
+ File: "gophercolor16x16.png",
+ },
+ },
+ },
+ {
+ Name: "r.zip",
+ File: []ZipTestFile{
+ {
+ Name: "r/r.zip",
+ File: "r.zip",
+ },
+ },
+ },
+ {Name: "readme.zip"},
+ {Name: "readme.notzip", Error: FormatError},
+}
+
+func TestReader(t *testing.T) {
+ for _, zt := range tests {
+ readTestZip(t, zt)
+ }
+}
+
+func readTestZip(t *testing.T, zt ZipTest) {
+ z, err := OpenReader("testdata/" + zt.Name)
+ if err != zt.Error {
+ t.Errorf("error=%v, want %v", err, zt.Error)
+ return
+ }
+
+ // bail here if no Files expected to be tested
+ // (there may actually be files in the zip, but we don't care)
+ if zt.File == nil {
+ return
+ }
+
+ if z.Comment != zt.Comment {
+ t.Errorf("%s: comment=%q, want %q", zt.Name, z.Comment, zt.Comment)
+ }
+ if len(z.File) != len(zt.File) {
+ t.Errorf("%s: file count=%d, want %d", zt.Name, len(z.File), len(zt.File))
+ }
+
+ // test read of each file
+ for i, ft := range zt.File {
+ readTestFile(t, ft, z.File[i])
+ }
+
+ // test simultaneous reads
+ n := 0
+ done := make(chan bool)
+ for i := 0; i < 5; i++ {
+ for j, ft := range zt.File {
+ go func() {
+ readTestFile(t, ft, z.File[j])
+ done <- true
+ }()
+ n++
+ }
+ }
+ for ; n > 0; n-- {
+ <-done
+ }
+
+ // test invalid checksum
+ z.File[0].CRC32++ // invalidate
+ r, err := z.File[0].Open()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ var b bytes.Buffer
+ _, err = io.Copy(&b, r)
+ if err != ChecksumError {
+ t.Errorf("%s: copy error=%v, want %v", z.File[0].Name, err, ChecksumError)
+ }
+}
+
+func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
+ if f.Name != ft.Name {
+ t.Errorf("name=%q, want %q", f.Name, ft.Name)
+ }
+ var b bytes.Buffer
+ r, err := f.Open()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ _, err = io.Copy(&b, r)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ r.Close()
+ var c []byte
+ if len(ft.Content) != 0 {
+ c = ft.Content
+ } else if c, err = ioutil.ReadFile("testdata/" + ft.File); err != nil {
+ t.Error(err)
+ return
+ }
+ if b.Len() != len(c) {
+ t.Errorf("%s: len=%d, want %d", f.Name, b.Len(), len(c))
+ return
+ }
+ for i, b := range b.Bytes() {
+ if b != c[i] {
+ t.Errorf("%s: content[%d]=%q want %q", f.Name, i, b, c[i])
+ return
+ }
+ }
+}
+
+func TestInvalidFiles(t *testing.T) {
+ const size = 1024 * 70 // 70kb
+ b := make([]byte, size)
+
+ // zeroes
+ _, err := NewReader(sliceReaderAt(b), size)
+ if err != FormatError {
+ t.Errorf("zeroes: error=%v, want %v", err, FormatError)
+ }
+
+ // repeated directoryEndSignatures
+ sig := make([]byte, 4)
+ binary.LittleEndian.PutUint32(sig, directoryEndSignature)
+ for i := 0; i < size-4; i += 4 {
+ copy(b[i:i+4], sig)
+ }
+ _, err = NewReader(sliceReaderAt(b), size)
+ if err != FormatError {
+ t.Errorf("sigs: error=%v, want %v", err, FormatError)
+ }
+}
+
+type sliceReaderAt []byte
+
+func (r sliceReaderAt) ReadAt(b []byte, off int64) (int, os.Error) {
+ copy(b, r[int(off):int(off)+len(b)])
+ return len(b), nil
+}
diff --git a/libgo/go/archive/zip/struct.go b/libgo/go/archive/zip/struct.go
new file mode 100644
index 000000000..8a8c727d4
--- /dev/null
+++ b/libgo/go/archive/zip/struct.go
@@ -0,0 +1,33 @@
+package zip
+
+const (
+ fileHeaderSignature = 0x04034b50
+ directoryHeaderSignature = 0x02014b50
+ directoryEndSignature = 0x06054b50
+)
+
+type FileHeader struct {
+ Name string
+ CreatorVersion uint16
+ ReaderVersion uint16
+ Flags uint16
+ Method uint16
+ ModifiedTime uint16
+ ModifiedDate uint16
+ CRC32 uint32
+ CompressedSize uint32
+ UncompressedSize uint32
+ Extra []byte
+ Comment string
+}
+
+type directoryEnd struct {
+ diskNbr uint16 // unused
+ dirDiskNbr uint16 // unused
+ dirRecordsThisDisk uint16 // unused
+ directoryRecords uint16
+ directorySize uint32
+ directoryOffset uint32 // relative to file
+ commentLen uint16
+ comment string
+}
diff --git a/libgo/go/archive/zip/testdata/gophercolor16x16.png b/libgo/go/archive/zip/testdata/gophercolor16x16.png
new file mode 100644
index 000000000..48854ff3b
--- /dev/null
+++ b/libgo/go/archive/zip/testdata/gophercolor16x16.png
Binary files differ
diff --git a/libgo/go/archive/zip/testdata/r.zip b/libgo/go/archive/zip/testdata/r.zip
new file mode 100644
index 000000000..ea0fa2ffc
--- /dev/null
+++ b/libgo/go/archive/zip/testdata/r.zip
Binary files differ
diff --git a/libgo/go/archive/zip/testdata/readme.notzip b/libgo/go/archive/zip/testdata/readme.notzip
new file mode 100644
index 000000000..06668c4c1
--- /dev/null
+++ b/libgo/go/archive/zip/testdata/readme.notzip
Binary files differ
diff --git a/libgo/go/archive/zip/testdata/readme.zip b/libgo/go/archive/zip/testdata/readme.zip
new file mode 100644
index 000000000..db3bb900e
--- /dev/null
+++ b/libgo/go/archive/zip/testdata/readme.zip
Binary files differ
diff --git a/libgo/go/archive/zip/testdata/test.zip b/libgo/go/archive/zip/testdata/test.zip
new file mode 100644
index 000000000..03890c05d
--- /dev/null
+++ b/libgo/go/archive/zip/testdata/test.zip
Binary files differ