diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-11-21 07:03:38 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-11-21 07:03:38 +0000 |
commit | fabcaa8df3d6eb852b87821ef090d31d222870b7 (patch) | |
tree | 72455aea0286937aa08cc141e5efc800e4626577 /libgo/go/archive | |
parent | a51fb17f48428e7cfc96a72a9f9f87901363bb6b (diff) | |
download | gcc-fabcaa8df3d6eb852b87821ef090d31d222870b7.zip gcc-fabcaa8df3d6eb852b87821ef090d31d222870b7.tar.gz gcc-fabcaa8df3d6eb852b87821ef090d31d222870b7.tar.bz2 |
libgo: Update to current version of master library.
From-SVN: r193688
Diffstat (limited to 'libgo/go/archive')
-rw-r--r-- | libgo/go/archive/tar/reader.go | 12 | ||||
-rw-r--r-- | libgo/go/archive/tar/tar_test.go | 44 | ||||
-rw-r--r-- | libgo/go/archive/tar/writer.go | 39 | ||||
-rw-r--r-- | libgo/go/archive/zip/reader.go | 9 | ||||
-rw-r--r-- | libgo/go/archive/zip/writer.go | 2 | ||||
-rw-r--r-- | libgo/go/archive/zip/zip_test.go | 82 |
6 files changed, 173 insertions, 15 deletions
diff --git a/libgo/go/archive/tar/reader.go b/libgo/go/archive/tar/reader.go index 1b40af8..ad825c6 100644 --- a/libgo/go/archive/tar/reader.go +++ b/libgo/go/archive/tar/reader.go @@ -72,6 +72,18 @@ func cString(b []byte) string { } func (tr *Reader) octal(b []byte) int64 { + // Check for binary format first. + if len(b) > 0 && b[0]&0x80 != 0 { + var x int64 + for i, c := range b { + if i == 0 { + c &= 0x7f // ignore signal bit in first byte + } + x = x<<8 | int64(c) + } + return x + } + // Removing leading spaces. for len(b) > 0 && b[0] == ' ' { b = b[1:] diff --git a/libgo/go/archive/tar/tar_test.go b/libgo/go/archive/tar/tar_test.go index 0adc179..7b190b6 100644 --- a/libgo/go/archive/tar/tar_test.go +++ b/libgo/go/archive/tar/tar_test.go @@ -5,7 +5,10 @@ package tar import ( + "bytes" + "io/ioutil" "os" + "reflect" "testing" "time" ) @@ -54,3 +57,44 @@ func (symlink) Mode() os.FileMode { return os.ModeSymlink } func (symlink) ModTime() time.Time { return time.Time{} } func (symlink) IsDir() bool { return false } func (symlink) Sys() interface{} { return nil } + +func TestRoundTrip(t *testing.T) { + data := []byte("some file contents") + + var b bytes.Buffer + tw := NewWriter(&b) + hdr := &Header{ + Name: "file.txt", + Uid: 1 << 21, // too big for 8 octal digits + Size: int64(len(data)), + ModTime: time.Now(), + } + // tar only supports second precision. + hdr.ModTime = hdr.ModTime.Add(-time.Duration(hdr.ModTime.Nanosecond()) * time.Nanosecond) + if err := tw.WriteHeader(hdr); err != nil { + t.Fatalf("tw.WriteHeader: %v", err) + } + if _, err := tw.Write(data); err != nil { + t.Fatalf("tw.Write: %v", err) + } + if err := tw.Close(); err != nil { + t.Fatalf("tw.Close: %v", err) + } + + // Read it back. + tr := NewReader(&b) + rHdr, err := tr.Next() + if err != nil { + t.Fatalf("tr.Next: %v", err) + } + if !reflect.DeepEqual(rHdr, hdr) { + t.Errorf("Header mismatch.\n got %+v\nwant %+v", rHdr, hdr) + } + rData, err := ioutil.ReadAll(tr) + if err != nil { + t.Fatalf("Read: %v", err) + } + if !bytes.Equal(rData, data) { + t.Errorf("Data mismatch.\n got %q\nwant %q", rData, data) + } +} diff --git a/libgo/go/archive/tar/writer.go b/libgo/go/archive/tar/writer.go index a9c8fdb..5af504b 100644 --- a/libgo/go/archive/tar/writer.go +++ b/libgo/go/archive/tar/writer.go @@ -12,6 +12,7 @@ import ( "fmt" "io" "strconv" + "time" ) var ( @@ -110,6 +111,12 @@ func (tw *Writer) numeric(b []byte, x int64) { b[0] |= 0x80 // highest bit indicates binary format } +var ( + minTime = time.Unix(0, 0) + // There is room for 11 octal digits (33 bits) of mtime. + maxTime = minTime.Add((1<<33 - 1) * time.Second) +) + // 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. @@ -133,19 +140,25 @@ func (tw *Writer) WriteHeader(hdr *Header) error { // 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.ModTime.Unix()) // 136:148 - s.next(8) // chksum (148:156) - s.next(1)[0] = hdr.Typeflag // 156:157 - tw.cString(s.next(100), hdr.Linkname) // 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 + // Handle out of range ModTime carefully. + var modTime int64 + if !hdr.ModTime.Before(minTime) && !hdr.ModTime.After(maxTime) { + modTime = hdr.ModTime.Unix() + } + + 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), modTime) // 136:148 + s.next(8) // chksum (148:156) + s.next(1)[0] = hdr.Typeflag // 156:157 + tw.cString(s.next(100), hdr.Linkname) // 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 { diff --git a/libgo/go/archive/zip/reader.go b/libgo/go/archive/zip/reader.go index a6b049e..c10f29a 100644 --- a/libgo/go/archive/zip/reader.go +++ b/libgo/go/archive/zip/reader.go @@ -238,9 +238,12 @@ func readDirectoryHeader(f *File, r io.Reader) error { if len(f.Extra) > 0 { b := readBuf(f.Extra) - for len(b) > 0 { + for len(b) >= 4 { // need at least tag and size tag := b.uint16() size := b.uint16() + if int(size) > len(b) { + return ErrFormat + } if tag == zip64ExtraId { // update directory values from the zip64 extra block eb := readBuf(b) @@ -256,6 +259,10 @@ func readDirectoryHeader(f *File, r io.Reader) error { } b = b[size:] } + // Should have consumed the whole header. + if len(b) != 0 { + return ErrFormat + } } return nil } diff --git a/libgo/go/archive/zip/writer.go b/libgo/go/archive/zip/writer.go index 50d8394..4c696e1 100644 --- a/libgo/go/archive/zip/writer.go +++ b/libgo/go/archive/zip/writer.go @@ -174,7 +174,7 @@ func (w *Writer) Create(name string) (io.Writer, error) { } // CreateHeader adds a file to the zip file using the provided FileHeader -// for the file metadata. +// for the file metadata. // It returns a Writer to which the file contents should be written. // The file's contents must be written to the io.Writer before the next // call to Create, CreateHeader, or Close. diff --git a/libgo/go/archive/zip/zip_test.go b/libgo/go/archive/zip/zip_test.go index 1d229d0..0a18798 100644 --- a/libgo/go/archive/zip/zip_test.go +++ b/libgo/go/archive/zip/zip_test.go @@ -173,3 +173,85 @@ func TestZip64(t *testing.T) { t.Errorf("UncompressedSize64 %d, want %d", got, want) } } + +func testInvalidHeader(h *FileHeader, t *testing.T) { + var buf bytes.Buffer + z := NewWriter(&buf) + + f, err := z.CreateHeader(h) + if err != nil { + t.Fatalf("error creating header: %v", err) + } + if _, err := f.Write([]byte("hi")); err != nil { + t.Fatalf("error writing content: %v", err) + } + if err := z.Close(); err != nil { + t.Fatalf("error closing zip writer: %v", err) + } + + b := buf.Bytes() + if _, err = NewReader(bytes.NewReader(b), int64(len(b))); err != ErrFormat { + t.Fatalf("got %v, expected ErrFormat", err) + } +} + +func testValidHeader(h *FileHeader, t *testing.T) { + var buf bytes.Buffer + z := NewWriter(&buf) + + f, err := z.CreateHeader(h) + if err != nil { + t.Fatalf("error creating header: %v", err) + } + if _, err := f.Write([]byte("hi")); err != nil { + t.Fatalf("error writing content: %v", err) + } + if err := z.Close(); err != nil { + t.Fatalf("error closing zip writer: %v", err) + } + + b := buf.Bytes() + if _, err = NewReader(bytes.NewReader(b), int64(len(b))); err != nil { + t.Fatalf("got %v, expected nil", err) + } +} + +// Issue 4302. +func TestHeaderInvalidTagAndSize(t *testing.T) { + const timeFormat = "20060102T150405.000.txt" + + ts := time.Now() + filename := ts.Format(timeFormat) + + h := FileHeader{ + Name: filename, + Method: Deflate, + Extra: []byte(ts.Format(time.RFC3339Nano)), // missing tag and len + } + h.SetModTime(ts) + + testInvalidHeader(&h, t) +} + +func TestHeaderTooShort(t *testing.T) { + h := FileHeader{ + Name: "foo.txt", + Method: Deflate, + Extra: []byte{zip64ExtraId}, // missing size + } + testInvalidHeader(&h, t) +} + +// Issue 4393. It is valid to have an extra data header +// which contains no body. +func TestZeroLengthHeader(t *testing.T) { + h := FileHeader{ + Name: "extadata.txt", + Method: Deflate, + Extra: []byte{ + 85, 84, 5, 0, 3, 154, 144, 195, 77, // tag 21589 size 5 + 85, 120, 0, 0, // tag 30805 size 0 + }, + } + testValidHeader(&h, t) +} |