summaryrefslogtreecommitdiff
path: root/src/pkg/archive
diff options
context:
space:
mode:
authorTianon Gravi <admwiggin@gmail.com>2015-01-15 11:54:00 -0700
committerTianon Gravi <admwiggin@gmail.com>2015-01-15 11:54:00 -0700
commitf154da9e12608589e8d5f0508f908a0c3e88a1bb (patch)
treef8255d51e10c6f1e0ed69702200b966c9556a431 /src/pkg/archive
parent8d8329ed5dfb9622c82a9fbec6fd99a580f9c9f6 (diff)
downloadgolang-upstream/1.4.tar.gz
Imported Upstream version 1.4upstream/1.4
Diffstat (limited to 'src/pkg/archive')
-rw-r--r--src/pkg/archive/tar/common.go305
-rw-r--r--src/pkg/archive/tar/example_test.go79
-rw-r--r--src/pkg/archive/tar/reader.go817
-rw-r--r--src/pkg/archive/tar/reader_test.go743
-rw-r--r--src/pkg/archive/tar/stat_atim.go20
-rw-r--r--src/pkg/archive/tar/stat_atimespec.go20
-rw-r--r--src/pkg/archive/tar/stat_unix.go32
-rw-r--r--src/pkg/archive/tar/tar_test.go284
-rw-r--r--src/pkg/archive/tar/testdata/gnu.tarbin3072 -> 0 bytes
-rw-r--r--src/pkg/archive/tar/testdata/nil-uid.tarbin1024 -> 0 bytes
-rw-r--r--src/pkg/archive/tar/testdata/pax.tarbin10240 -> 0 bytes
-rw-r--r--src/pkg/archive/tar/testdata/small.txt1
-rw-r--r--src/pkg/archive/tar/testdata/small2.txt1
-rw-r--r--src/pkg/archive/tar/testdata/sparse-formats.tarbin17920 -> 0 bytes
-rw-r--r--src/pkg/archive/tar/testdata/star.tarbin3072 -> 0 bytes
-rw-r--r--src/pkg/archive/tar/testdata/ustar.tarbin2048 -> 0 bytes
-rw-r--r--src/pkg/archive/tar/testdata/v7.tarbin3584 -> 0 bytes
-rw-r--r--src/pkg/archive/tar/testdata/writer-big-long.tarbin4096 -> 0 bytes
-rw-r--r--src/pkg/archive/tar/testdata/writer-big.tarbin4096 -> 0 bytes
-rw-r--r--src/pkg/archive/tar/testdata/writer.tarbin3584 -> 0 bytes
-rw-r--r--src/pkg/archive/tar/testdata/xattrs.tarbin5120 -> 0 bytes
-rw-r--r--src/pkg/archive/tar/writer.go383
-rw-r--r--src/pkg/archive/tar/writer_test.go456
-rw-r--r--src/pkg/archive/zip/example_test.go75
-rw-r--r--src/pkg/archive/zip/reader.go448
-rw-r--r--src/pkg/archive/zip/reader_test.go510
-rw-r--r--src/pkg/archive/zip/register.go110
-rw-r--r--src/pkg/archive/zip/struct.go313
-rw-r--r--src/pkg/archive/zip/testdata/crc32-not-streamed.zipbin314 -> 0 bytes
-rw-r--r--src/pkg/archive/zip/testdata/dd.zipbin154 -> 0 bytes
-rw-r--r--src/pkg/archive/zip/testdata/go-no-datadesc-sig.zipbin330 -> 0 bytes
-rw-r--r--src/pkg/archive/zip/testdata/go-with-datadesc-sig.zipbin242 -> 0 bytes
-rw-r--r--src/pkg/archive/zip/testdata/gophercolor16x16.pngbin785 -> 0 bytes
-rw-r--r--src/pkg/archive/zip/testdata/readme.notzipbin1905 -> 0 bytes
-rw-r--r--src/pkg/archive/zip/testdata/readme.zipbin1885 -> 0 bytes
-rw-r--r--src/pkg/archive/zip/testdata/symlink.zipbin173 -> 0 bytes
-rw-r--r--src/pkg/archive/zip/testdata/test-trailing-junk.zipbin1184 -> 0 bytes
-rw-r--r--src/pkg/archive/zip/testdata/test.zipbin1170 -> 0 bytes
-rw-r--r--src/pkg/archive/zip/testdata/unix.zipbin620 -> 0 bytes
-rw-r--r--src/pkg/archive/zip/testdata/winxp.zipbin412 -> 0 bytes
-rw-r--r--src/pkg/archive/zip/testdata/zip64-2.zipbin266 -> 0 bytes
-rw-r--r--src/pkg/archive/zip/testdata/zip64.zipbin242 -> 0 bytes
-rw-r--r--src/pkg/archive/zip/writer.go351
-rw-r--r--src/pkg/archive/zip/writer_test.go145
-rw-r--r--src/pkg/archive/zip/zip_test.go395
45 files changed, 0 insertions, 5488 deletions
diff --git a/src/pkg/archive/tar/common.go b/src/pkg/archive/tar/common.go
deleted file mode 100644
index e363aa793..000000000
--- a/src/pkg/archive/tar/common.go
+++ /dev/null
@@ -1,305 +0,0 @@
-// 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 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
-// http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html
-package tar
-
-import (
- "bytes"
- "errors"
- "fmt"
- "os"
- "path"
- "time"
-)
-
-const (
- blockSize = 512
-
- // Types
- TypeReg = '0' // regular file
- TypeRegA = '\x00' // regular file
- TypeLink = '1' // hard link
- TypeSymlink = '2' // symbolic link
- TypeChar = '3' // character device node
- TypeBlock = '4' // block device node
- TypeDir = '5' // directory
- TypeFifo = '6' // fifo node
- TypeCont = '7' // reserved
- TypeXHeader = 'x' // extended header
- TypeXGlobalHeader = 'g' // global extended header
- TypeGNULongName = 'L' // Next file has a long name
- TypeGNULongLink = 'K' // Next file symlinks to a file w/ a long name
- TypeGNUSparse = 'S' // sparse file
-)
-
-// A Header represents a single header in a tar archive.
-// Some fields may not be populated.
-type Header struct {
- Name string // name of header file entry
- Mode int64 // permission and mode bits
- Uid int // user id of owner
- Gid int // group id of owner
- Size int64 // length in bytes
- ModTime time.Time // modified time
- Typeflag byte // type of header entry
- Linkname string // target name of link
- Uname string // user name of owner
- Gname string // group name of owner
- Devmajor int64 // major number of character or block device
- Devminor int64 // minor number of character or block device
- AccessTime time.Time // access time
- ChangeTime time.Time // status change time
- Xattrs map[string]string
-}
-
-// File name constants from the tar spec.
-const (
- fileNameSize = 100 // Maximum number of bytes in a standard tar name.
- fileNamePrefixSize = 155 // Maximum number of ustar extension bytes.
-)
-
-// FileInfo returns an os.FileInfo for the Header.
-func (h *Header) FileInfo() os.FileInfo {
- return headerFileInfo{h}
-}
-
-// headerFileInfo implements os.FileInfo.
-type headerFileInfo struct {
- h *Header
-}
-
-func (fi headerFileInfo) Size() int64 { return fi.h.Size }
-func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() }
-func (fi headerFileInfo) ModTime() time.Time { return fi.h.ModTime }
-func (fi headerFileInfo) Sys() interface{} { return fi.h }
-
-// Name returns the base name of the file.
-func (fi headerFileInfo) Name() string {
- if fi.IsDir() {
- return path.Base(path.Clean(fi.h.Name))
- }
- return path.Base(fi.h.Name)
-}
-
-// Mode returns the permission and mode bits for the headerFileInfo.
-func (fi headerFileInfo) Mode() (mode os.FileMode) {
- // Set file permission bits.
- mode = os.FileMode(fi.h.Mode).Perm()
-
- // Set setuid, setgid and sticky bits.
- if fi.h.Mode&c_ISUID != 0 {
- // setuid
- mode |= os.ModeSetuid
- }
- if fi.h.Mode&c_ISGID != 0 {
- // setgid
- mode |= os.ModeSetgid
- }
- if fi.h.Mode&c_ISVTX != 0 {
- // sticky
- mode |= os.ModeSticky
- }
-
- // Set file mode bits.
- // clear perm, setuid, setgid and sticky bits.
- m := os.FileMode(fi.h.Mode) &^ 07777
- if m == c_ISDIR {
- // directory
- mode |= os.ModeDir
- }
- if m == c_ISFIFO {
- // named pipe (FIFO)
- mode |= os.ModeNamedPipe
- }
- if m == c_ISLNK {
- // symbolic link
- mode |= os.ModeSymlink
- }
- if m == c_ISBLK {
- // device file
- mode |= os.ModeDevice
- }
- if m == c_ISCHR {
- // Unix character device
- mode |= os.ModeDevice
- mode |= os.ModeCharDevice
- }
- if m == c_ISSOCK {
- // Unix domain socket
- mode |= os.ModeSocket
- }
-
- switch fi.h.Typeflag {
- case TypeLink, TypeSymlink:
- // hard link, symbolic link
- mode |= os.ModeSymlink
- case TypeChar:
- // character device node
- mode |= os.ModeDevice
- mode |= os.ModeCharDevice
- case TypeBlock:
- // block device node
- mode |= os.ModeDevice
- case TypeDir:
- // directory
- mode |= os.ModeDir
- case TypeFifo:
- // fifo node
- mode |= os.ModeNamedPipe
- }
-
- return mode
-}
-
-// sysStat, if non-nil, populates h from system-dependent fields of fi.
-var sysStat func(fi os.FileInfo, h *Header) error
-
-// Mode constants from the tar spec.
-const (
- c_ISUID = 04000 // Set uid
- c_ISGID = 02000 // Set gid
- c_ISVTX = 01000 // Save text (sticky bit)
- c_ISDIR = 040000 // Directory
- c_ISFIFO = 010000 // FIFO
- c_ISREG = 0100000 // Regular file
- c_ISLNK = 0120000 // Symbolic link
- c_ISBLK = 060000 // Block special file
- c_ISCHR = 020000 // Character special file
- c_ISSOCK = 0140000 // Socket
-)
-
-// Keywords for the PAX Extended Header
-const (
- paxAtime = "atime"
- paxCharset = "charset"
- paxComment = "comment"
- paxCtime = "ctime" // please note that ctime is not a valid pax header.
- paxGid = "gid"
- paxGname = "gname"
- paxLinkpath = "linkpath"
- paxMtime = "mtime"
- paxPath = "path"
- paxSize = "size"
- paxUid = "uid"
- paxUname = "uname"
- paxXattr = "SCHILY.xattr."
- paxNone = ""
-)
-
-// FileInfoHeader creates a partially-populated Header from fi.
-// If fi describes a symlink, FileInfoHeader records link as the link target.
-// If fi describes a directory, a slash is appended to the name.
-// Because os.FileInfo's Name method returns only the base name of
-// the file it describes, it may be necessary to modify the Name field
-// of the returned header to provide the full path name of the file.
-func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
- if fi == nil {
- return nil, errors.New("tar: FileInfo is nil")
- }
- fm := fi.Mode()
- h := &Header{
- Name: fi.Name(),
- ModTime: fi.ModTime(),
- Mode: int64(fm.Perm()), // or'd with c_IS* constants later
- }
- switch {
- case fm.IsRegular():
- h.Mode |= c_ISREG
- h.Typeflag = TypeReg
- h.Size = fi.Size()
- case fi.IsDir():
- h.Typeflag = TypeDir
- h.Mode |= c_ISDIR
- h.Name += "/"
- case fm&os.ModeSymlink != 0:
- h.Typeflag = TypeSymlink
- h.Mode |= c_ISLNK
- h.Linkname = link
- case fm&os.ModeDevice != 0:
- if fm&os.ModeCharDevice != 0 {
- h.Mode |= c_ISCHR
- h.Typeflag = TypeChar
- } else {
- h.Mode |= c_ISBLK
- h.Typeflag = TypeBlock
- }
- case fm&os.ModeNamedPipe != 0:
- h.Typeflag = TypeFifo
- h.Mode |= c_ISFIFO
- case fm&os.ModeSocket != 0:
- h.Mode |= c_ISSOCK
- default:
- return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm)
- }
- if fm&os.ModeSetuid != 0 {
- h.Mode |= c_ISUID
- }
- if fm&os.ModeSetgid != 0 {
- h.Mode |= c_ISGID
- }
- if fm&os.ModeSticky != 0 {
- h.Mode |= c_ISVTX
- }
- if sysStat != nil {
- return h, sysStat(fi, h)
- }
- return h, nil
-}
-
-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
-}
-
-func isASCII(s string) bool {
- for _, c := range s {
- if c >= 0x80 {
- return false
- }
- }
- return true
-}
-
-func toASCII(s string) string {
- if isASCII(s) {
- return s
- }
- var buf bytes.Buffer
- for _, c := range s {
- if c < 0x80 {
- buf.WriteByte(byte(c))
- }
- }
- return buf.String()
-}
diff --git a/src/pkg/archive/tar/example_test.go b/src/pkg/archive/tar/example_test.go
deleted file mode 100644
index 351eaa0e6..000000000
--- a/src/pkg/archive/tar/example_test.go
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2013 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_test
-
-import (
- "archive/tar"
- "bytes"
- "fmt"
- "io"
- "log"
- "os"
-)
-
-func Example() {
- // Create a buffer to write our archive to.
- buf := new(bytes.Buffer)
-
- // Create a new tar archive.
- tw := tar.NewWriter(buf)
-
- // Add some files to the archive.
- var files = []struct {
- Name, Body string
- }{
- {"readme.txt", "This archive contains some text files."},
- {"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
- {"todo.txt", "Get animal handling licence."},
- }
- for _, file := range files {
- hdr := &tar.Header{
- Name: file.Name,
- Size: int64(len(file.Body)),
- }
- if err := tw.WriteHeader(hdr); err != nil {
- log.Fatalln(err)
- }
- if _, err := tw.Write([]byte(file.Body)); err != nil {
- log.Fatalln(err)
- }
- }
- // Make sure to check the error on Close.
- if err := tw.Close(); err != nil {
- log.Fatalln(err)
- }
-
- // Open the tar archive for reading.
- r := bytes.NewReader(buf.Bytes())
- tr := tar.NewReader(r)
-
- // Iterate through the files in the archive.
- for {
- hdr, err := tr.Next()
- if err == io.EOF {
- // end of tar archive
- break
- }
- if err != nil {
- log.Fatalln(err)
- }
- fmt.Printf("Contents of %s:\n", hdr.Name)
- if _, err := io.Copy(os.Stdout, tr); err != nil {
- log.Fatalln(err)
- }
- fmt.Println()
- }
-
- // Output:
- // Contents of readme.txt:
- // This archive contains some text files.
- // Contents of gopher.txt:
- // Gopher names:
- // George
- // Geoffrey
- // Gonzo
- // Contents of todo.txt:
- // Get animal handling licence.
-}
diff --git a/src/pkg/archive/tar/reader.go b/src/pkg/archive/tar/reader.go
deleted file mode 100644
index 920a9b08f..000000000
--- a/src/pkg/archive/tar/reader.go
+++ /dev/null
@@ -1,817 +0,0 @@
-// 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"
- "errors"
- "io"
- "io/ioutil"
- "os"
- "strconv"
- "strings"
- "time"
-)
-
-var (
- ErrHeader = errors.New("archive/tar: invalid tar header")
-)
-
-const maxNanoSecondIntSize = 9
-
-// 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.
-type Reader struct {
- r io.Reader
- err error
- pad int64 // amount of padding (ignored) after current file entry
- curr numBytesReader // reader for current file entry
-}
-
-// A numBytesReader is an io.Reader with a numBytes method, returning the number
-// of bytes remaining in the underlying encoded data.
-type numBytesReader interface {
- io.Reader
- numBytes() int64
-}
-
-// A regFileReader is a numBytesReader for reading file data from a tar archive.
-type regFileReader struct {
- r io.Reader // underlying reader
- nb int64 // number of unread bytes for current file entry
-}
-
-// A sparseFileReader is a numBytesReader for reading sparse file data from a tar archive.
-type sparseFileReader struct {
- rfr *regFileReader // reads the sparse-encoded file data
- sp []sparseEntry // the sparse map for the file
- pos int64 // keeps track of file position
- tot int64 // total size of the file
-}
-
-// Keywords for GNU sparse files in a PAX extended header
-const (
- paxGNUSparseNumBlocks = "GNU.sparse.numblocks"
- paxGNUSparseOffset = "GNU.sparse.offset"
- paxGNUSparseNumBytes = "GNU.sparse.numbytes"
- paxGNUSparseMap = "GNU.sparse.map"
- paxGNUSparseName = "GNU.sparse.name"
- paxGNUSparseMajor = "GNU.sparse.major"
- paxGNUSparseMinor = "GNU.sparse.minor"
- paxGNUSparseSize = "GNU.sparse.size"
- paxGNUSparseRealSize = "GNU.sparse.realsize"
-)
-
-// Keywords for old GNU sparse headers
-const (
- oldGNUSparseMainHeaderOffset = 386
- oldGNUSparseMainHeaderIsExtendedOffset = 482
- oldGNUSparseMainHeaderNumEntries = 4
- oldGNUSparseExtendedHeaderIsExtendedOffset = 504
- oldGNUSparseExtendedHeaderNumEntries = 21
- oldGNUSparseOffsetSize = 12
- oldGNUSparseNumBytesSize = 12
-)
-
-// 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, error) {
- var hdr *Header
- if tr.err == nil {
- tr.skipUnread()
- }
- if tr.err != nil {
- return hdr, tr.err
- }
- hdr = tr.readHeader()
- if hdr == nil {
- return hdr, tr.err
- }
- // Check for PAX/GNU header.
- switch hdr.Typeflag {
- case TypeXHeader:
- // PAX extended header
- headers, err := parsePAX(tr)
- if err != nil {
- return nil, err
- }
- // We actually read the whole file,
- // but this skips alignment padding
- tr.skipUnread()
- hdr = tr.readHeader()
- mergePAX(hdr, headers)
-
- // Check for a PAX format sparse file
- sp, err := tr.checkForGNUSparsePAXHeaders(hdr, headers)
- if err != nil {
- tr.err = err
- return nil, err
- }
- if sp != nil {
- // Current file is a PAX format GNU sparse file.
- // Set the current file reader to a sparse file reader.
- tr.curr = &sparseFileReader{rfr: tr.curr.(*regFileReader), sp: sp, tot: hdr.Size}
- }
- return hdr, nil
- case TypeGNULongName:
- // We have a GNU long name header. Its contents are the real file name.
- realname, err := ioutil.ReadAll(tr)
- if err != nil {
- return nil, err
- }
- hdr, err := tr.Next()
- hdr.Name = cString(realname)
- return hdr, err
- case TypeGNULongLink:
- // We have a GNU long link header.
- realname, err := ioutil.ReadAll(tr)
- if err != nil {
- return nil, err
- }
- hdr, err := tr.Next()
- hdr.Linkname = cString(realname)
- return hdr, err
- }
- return hdr, tr.err
-}
-
-// checkForGNUSparsePAXHeaders checks the PAX headers for GNU sparse headers. If they are found, then
-// this function reads the sparse map and returns it. Unknown sparse formats are ignored, causing the file to
-// be treated as a regular file.
-func (tr *Reader) checkForGNUSparsePAXHeaders(hdr *Header, headers map[string]string) ([]sparseEntry, error) {
- var sparseFormat string
-
- // Check for sparse format indicators
- major, majorOk := headers[paxGNUSparseMajor]
- minor, minorOk := headers[paxGNUSparseMinor]
- sparseName, sparseNameOk := headers[paxGNUSparseName]
- _, sparseMapOk := headers[paxGNUSparseMap]
- sparseSize, sparseSizeOk := headers[paxGNUSparseSize]
- sparseRealSize, sparseRealSizeOk := headers[paxGNUSparseRealSize]
-
- // Identify which, if any, sparse format applies from which PAX headers are set
- if majorOk && minorOk {
- sparseFormat = major + "." + minor
- } else if sparseNameOk && sparseMapOk {
- sparseFormat = "0.1"
- } else if sparseSizeOk {
- sparseFormat = "0.0"
- } else {
- // Not a PAX format GNU sparse file.
- return nil, nil
- }
-
- // Check for unknown sparse format
- if sparseFormat != "0.0" && sparseFormat != "0.1" && sparseFormat != "1.0" {
- return nil, nil
- }
-
- // Update hdr from GNU sparse PAX headers
- if sparseNameOk {
- hdr.Name = sparseName
- }
- if sparseSizeOk {
- realSize, err := strconv.ParseInt(sparseSize, 10, 0)
- if err != nil {
- return nil, ErrHeader
- }
- hdr.Size = realSize
- } else if sparseRealSizeOk {
- realSize, err := strconv.ParseInt(sparseRealSize, 10, 0)
- if err != nil {
- return nil, ErrHeader
- }
- hdr.Size = realSize
- }
-
- // Set up the sparse map, according to the particular sparse format in use
- var sp []sparseEntry
- var err error
- switch sparseFormat {
- case "0.0", "0.1":
- sp, err = readGNUSparseMap0x1(headers)
- case "1.0":
- sp, err = readGNUSparseMap1x0(tr.curr)
- }
- return sp, err
-}
-
-// mergePAX merges well known headers according to PAX standard.
-// In general headers with the same name as those found
-// in the header struct overwrite those found in the header
-// struct with higher precision or longer values. Esp. useful
-// for name and linkname fields.
-func mergePAX(hdr *Header, headers map[string]string) error {
- for k, v := range headers {
- switch k {
- case paxPath:
- hdr.Name = v
- case paxLinkpath:
- hdr.Linkname = v
- case paxGname:
- hdr.Gname = v
- case paxUname:
- hdr.Uname = v
- case paxUid:
- uid, err := strconv.ParseInt(v, 10, 0)
- if err != nil {
- return err
- }
- hdr.Uid = int(uid)
- case paxGid:
- gid, err := strconv.ParseInt(v, 10, 0)
- if err != nil {
- return err
- }
- hdr.Gid = int(gid)
- case paxAtime:
- t, err := parsePAXTime(v)
- if err != nil {
- return err
- }
- hdr.AccessTime = t
- case paxMtime:
- t, err := parsePAXTime(v)
- if err != nil {
- return err
- }
- hdr.ModTime = t
- case paxCtime:
- t, err := parsePAXTime(v)
- if err != nil {
- return err
- }
- hdr.ChangeTime = t
- case paxSize:
- size, err := strconv.ParseInt(v, 10, 0)
- if err != nil {
- return err
- }
- hdr.Size = int64(size)
- default:
- if strings.HasPrefix(k, paxXattr) {
- if hdr.Xattrs == nil {
- hdr.Xattrs = make(map[string]string)
- }
- hdr.Xattrs[k[len(paxXattr):]] = v
- }
- }
- }
- return nil
-}
-
-// parsePAXTime takes a string of the form %d.%d as described in
-// the PAX specification.
-func parsePAXTime(t string) (time.Time, error) {
- buf := []byte(t)
- pos := bytes.IndexByte(buf, '.')
- var seconds, nanoseconds int64
- var err error
- if pos == -1 {
- seconds, err = strconv.ParseInt(t, 10, 0)
- if err != nil {
- return time.Time{}, err
- }
- } else {
- seconds, err = strconv.ParseInt(string(buf[:pos]), 10, 0)
- if err != nil {
- return time.Time{}, err
- }
- nano_buf := string(buf[pos+1:])
- // Pad as needed before converting to a decimal.
- // For example .030 -> .030000000 -> 30000000 nanoseconds
- if len(nano_buf) < maxNanoSecondIntSize {
- // Right pad
- nano_buf += strings.Repeat("0", maxNanoSecondIntSize-len(nano_buf))
- } else if len(nano_buf) > maxNanoSecondIntSize {
- // Right truncate
- nano_buf = nano_buf[:maxNanoSecondIntSize]
- }
- nanoseconds, err = strconv.ParseInt(string(nano_buf), 10, 0)
- if err != nil {
- return time.Time{}, err
- }
- }
- ts := time.Unix(seconds, nanoseconds)
- return ts, nil
-}
-
-// parsePAX parses PAX headers.
-// If an extended header (type 'x') is invalid, ErrHeader is returned
-func parsePAX(r io.Reader) (map[string]string, error) {
- buf, err := ioutil.ReadAll(r)
- if err != nil {
- return nil, err
- }
-
- // For GNU PAX sparse format 0.0 support.
- // This function transforms the sparse format 0.0 headers into sparse format 0.1 headers.
- var sparseMap bytes.Buffer
-
- headers := make(map[string]string)
- // Each record is constructed as
- // "%d %s=%s\n", length, keyword, value
- for len(buf) > 0 {
- // or the header was empty to start with.
- var sp int
- // The size field ends at the first space.
- sp = bytes.IndexByte(buf, ' ')
- if sp == -1 {
- return nil, ErrHeader
- }
- // Parse the first token as a decimal integer.
- n, err := strconv.ParseInt(string(buf[:sp]), 10, 0)
- if err != nil {
- return nil, ErrHeader
- }
- // Extract everything between the decimal and the n -1 on the
- // beginning to eat the ' ', -1 on the end to skip the newline.
- var record []byte
- record, buf = buf[sp+1:n-1], buf[n:]
- // The first equals is guaranteed to mark the end of the key.
- // Everything else is value.
- eq := bytes.IndexByte(record, '=')
- if eq == -1 {
- return nil, ErrHeader
- }
- key, value := record[:eq], record[eq+1:]
-
- keyStr := string(key)
- if keyStr == paxGNUSparseOffset || keyStr == paxGNUSparseNumBytes {
- // GNU sparse format 0.0 special key. Write to sparseMap instead of using the headers map.
- sparseMap.Write(value)
- sparseMap.Write([]byte{','})
- } else {
- // Normal key. Set the value in the headers map.
- headers[keyStr] = string(value)
- }
- }
- if sparseMap.Len() != 0 {
- // Add sparse info to headers, chopping off the extra comma
- sparseMap.Truncate(sparseMap.Len() - 1)
- headers[paxGNUSparseMap] = sparseMap.String()
- }
- return headers, nil
-}
-
-// cString parses 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 {
- // 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
- }
-
- // Because unused fields are filled with NULs, we need
- // to skip leading NULs. Fields may also be padded with
- // spaces or NULs.
- // So we remove leading and trailing NULs and spaces to
- // be sure.
- b = bytes.Trim(b, " \x00")
-
- if len(b) == 0 {
- return 0
- }
- x, err := strconv.ParseUint(cString(b), 8, 64)
- if err != nil {
- tr.err = err
- }
- return int64(x)
-}
-
-// skipUnread skips any unread bytes in the existing file entry, as well as any alignment padding.
-func (tr *Reader) skipUnread() {
- nr := tr.numBytes() + tr.pad // number of bytes to skip
- tr.curr, tr.pad = nil, 0
- if sr, ok := tr.r.(io.Seeker); ok {
- if _, err := sr.Seek(nr, os.SEEK_CUR); err == nil {
- return
- }
- }
- _, tr.err = io.CopyN(ioutil.Discard, 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 = io.EOF
- } else {
- tr.err = ErrHeader // zero block and then non-zero block
- }
- return nil
- }
-
- if !tr.verifyChecksum(header) {
- tr.err = ErrHeader
- 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.ModTime = time.Unix(tr.octal(s.next(12)), 0)
- 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 {
- case magic[:6] == "ustar\x00": // POSIX tar (1003.1-1988)
- if string(header[508:512]) == "tar\x00" {
- format = "star"
- } else {
- format = "posix"
- }
- case magic == "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.AccessTime = time.Unix(tr.octal(s.next(12)), 0)
- hdr.ChangeTime = time.Unix(tr.octal(s.next(12)), 0)
- }
- if len(prefix) > 0 {
- hdr.Name = prefix + "/" + hdr.Name
- }
- }
-
- if tr.err != nil {
- tr.err = ErrHeader
- return nil
- }
-
- // Maximum value of hdr.Size is 64 GB (12 octal digits),
- // so there's no risk of int64 overflowing.
- nb := int64(hdr.Size)
- tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
-
- // Set the current file reader.
- tr.curr = &regFileReader{r: tr.r, nb: nb}
-
- // Check for old GNU sparse format entry.
- if hdr.Typeflag == TypeGNUSparse {
- // Get the real size of the file.
- hdr.Size = tr.octal(header[483:495])
-
- // Read the sparse map.
- sp := tr.readOldGNUSparseMap(header)
- if tr.err != nil {
- return nil
- }
- // Current file is a GNU sparse file. Update the current file reader.
- tr.curr = &sparseFileReader{rfr: tr.curr.(*regFileReader), sp: sp, tot: hdr.Size}
- }
-
- return hdr
-}
-
-// A sparseEntry holds a single entry in a sparse file's sparse map.
-// A sparse entry indicates the offset and size in a sparse file of a
-// block of data.
-type sparseEntry struct {
- offset int64
- numBytes int64
-}
-
-// readOldGNUSparseMap reads the sparse map as stored in the old GNU sparse format.
-// The sparse map is stored in the tar header if it's small enough. If it's larger than four entries,
-// then one or more extension headers are used to store the rest of the sparse map.
-func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
- isExtended := header[oldGNUSparseMainHeaderIsExtendedOffset] != 0
- spCap := oldGNUSparseMainHeaderNumEntries
- if isExtended {
- spCap += oldGNUSparseExtendedHeaderNumEntries
- }
- sp := make([]sparseEntry, 0, spCap)
- s := slicer(header[oldGNUSparseMainHeaderOffset:])
-
- // Read the four entries from the main tar header
- for i := 0; i < oldGNUSparseMainHeaderNumEntries; i++ {
- offset := tr.octal(s.next(oldGNUSparseOffsetSize))
- numBytes := tr.octal(s.next(oldGNUSparseNumBytesSize))
- if tr.err != nil {
- tr.err = ErrHeader
- return nil
- }
- if offset == 0 && numBytes == 0 {
- break
- }
- sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
- }
-
- for isExtended {
- // There are more entries. Read an extension header and parse its entries.
- sparseHeader := make([]byte, blockSize)
- if _, tr.err = io.ReadFull(tr.r, sparseHeader); tr.err != nil {
- return nil
- }
- isExtended = sparseHeader[oldGNUSparseExtendedHeaderIsExtendedOffset] != 0
- s = slicer(sparseHeader)
- for i := 0; i < oldGNUSparseExtendedHeaderNumEntries; i++ {
- offset := tr.octal(s.next(oldGNUSparseOffsetSize))
- numBytes := tr.octal(s.next(oldGNUSparseNumBytesSize))
- if tr.err != nil {
- tr.err = ErrHeader
- return nil
- }
- if offset == 0 && numBytes == 0 {
- break
- }
- sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
- }
- }
- return sp
-}
-
-// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format version 1.0.
-// The sparse map is stored just before the file data and padded out to the nearest block boundary.
-func readGNUSparseMap1x0(r io.Reader) ([]sparseEntry, error) {
- buf := make([]byte, 2*blockSize)
- sparseHeader := buf[:blockSize]
-
- // readDecimal is a helper function to read a decimal integer from the sparse map
- // while making sure to read from the file in blocks of size blockSize
- readDecimal := func() (int64, error) {
- // Look for newline
- nl := bytes.IndexByte(sparseHeader, '\n')
- if nl == -1 {
- if len(sparseHeader) >= blockSize {
- // This is an error
- return 0, ErrHeader
- }
- oldLen := len(sparseHeader)
- newLen := oldLen + blockSize
- if cap(sparseHeader) < newLen {
- // There's more header, but we need to make room for the next block
- copy(buf, sparseHeader)
- sparseHeader = buf[:newLen]
- } else {
- // There's more header, and we can just reslice
- sparseHeader = sparseHeader[:newLen]
- }
-
- // Now that sparseHeader is large enough, read next block
- if _, err := io.ReadFull(r, sparseHeader[oldLen:newLen]); err != nil {
- return 0, err
- }
-
- // Look for a newline in the new data
- nl = bytes.IndexByte(sparseHeader[oldLen:newLen], '\n')
- if nl == -1 {
- // This is an error
- return 0, ErrHeader
- }
- nl += oldLen // We want the position from the beginning
- }
- // Now that we've found a newline, read a number
- n, err := strconv.ParseInt(string(sparseHeader[:nl]), 10, 0)
- if err != nil {
- return 0, ErrHeader
- }
-
- // Update sparseHeader to consume this number
- sparseHeader = sparseHeader[nl+1:]
- return n, nil
- }
-
- // Read the first block
- if _, err := io.ReadFull(r, sparseHeader); err != nil {
- return nil, err
- }
-
- // The first line contains the number of entries
- numEntries, err := readDecimal()
- if err != nil {
- return nil, err
- }
-
- // Read all the entries
- sp := make([]sparseEntry, 0, numEntries)
- for i := int64(0); i < numEntries; i++ {
- // Read the offset
- offset, err := readDecimal()
- if err != nil {
- return nil, err
- }
- // Read numBytes
- numBytes, err := readDecimal()
- if err != nil {
- return nil, err
- }
-
- sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
- }
-
- return sp, nil
-}
-
-// readGNUSparseMap0x1 reads the sparse map as stored in GNU's PAX sparse format version 0.1.
-// The sparse map is stored in the PAX headers.
-func readGNUSparseMap0x1(headers map[string]string) ([]sparseEntry, error) {
- // Get number of entries
- numEntriesStr, ok := headers[paxGNUSparseNumBlocks]
- if !ok {
- return nil, ErrHeader
- }
- numEntries, err := strconv.ParseInt(numEntriesStr, 10, 0)
- if err != nil {
- return nil, ErrHeader
- }
-
- sparseMap := strings.Split(headers[paxGNUSparseMap], ",")
-
- // There should be two numbers in sparseMap for each entry
- if int64(len(sparseMap)) != 2*numEntries {
- return nil, ErrHeader
- }
-
- // Loop through the entries in the sparse map
- sp := make([]sparseEntry, 0, numEntries)
- for i := int64(0); i < numEntries; i++ {
- offset, err := strconv.ParseInt(sparseMap[2*i], 10, 0)
- if err != nil {
- return nil, ErrHeader
- }
- numBytes, err := strconv.ParseInt(sparseMap[2*i+1], 10, 0)
- if err != nil {
- return nil, ErrHeader
- }
- sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
- }
-
- return sp, nil
-}
-
-// numBytes returns the number of bytes left to read in the current file's entry
-// in the tar archive, or 0 if there is no current file.
-func (tr *Reader) numBytes() int64 {
- if tr.curr == nil {
- // No current file, so no bytes
- return 0
- }
- return tr.curr.numBytes()
-}
-
-// Read reads from the current entry in the tar archive.
-// It returns 0, io.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 error) {
- if tr.curr == nil {
- return 0, io.EOF
- }
- n, err = tr.curr.Read(b)
- if err != nil && err != io.EOF {
- tr.err = err
- }
- return
-}
-
-func (rfr *regFileReader) Read(b []byte) (n int, err error) {
- if rfr.nb == 0 {
- // file consumed
- return 0, io.EOF
- }
- if int64(len(b)) > rfr.nb {
- b = b[0:rfr.nb]
- }
- n, err = rfr.r.Read(b)
- rfr.nb -= int64(n)
-
- if err == io.EOF && rfr.nb > 0 {
- err = io.ErrUnexpectedEOF
- }
- return
-}
-
-// numBytes returns the number of bytes left to read in the file's data in the tar archive.
-func (rfr *regFileReader) numBytes() int64 {
- return rfr.nb
-}
-
-// readHole reads a sparse file hole ending at offset toOffset
-func (sfr *sparseFileReader) readHole(b []byte, toOffset int64) int {
- n64 := toOffset - sfr.pos
- if n64 > int64(len(b)) {
- n64 = int64(len(b))
- }
- n := int(n64)
- for i := 0; i < n; i++ {
- b[i] = 0
- }
- sfr.pos += n64
- return n
-}
-
-// Read reads the sparse file data in expanded form.
-func (sfr *sparseFileReader) Read(b []byte) (n int, err error) {
- if len(sfr.sp) == 0 {
- // No more data fragments to read from.
- if sfr.pos < sfr.tot {
- // We're in the last hole
- n = sfr.readHole(b, sfr.tot)
- return
- }
- // Otherwise, we're at the end of the file
- return 0, io.EOF
- }
- if sfr.pos < sfr.sp[0].offset {
- // We're in a hole
- n = sfr.readHole(b, sfr.sp[0].offset)
- return
- }
-
- // We're not in a hole, so we'll read from the next data fragment
- posInFragment := sfr.pos - sfr.sp[0].offset
- bytesLeft := sfr.sp[0].numBytes - posInFragment
- if int64(len(b)) > bytesLeft {
- b = b[0:bytesLeft]
- }
-
- n, err = sfr.rfr.Read(b)
- sfr.pos += int64(n)
-
- if int64(n) == bytesLeft {
- // We're done with this fragment
- sfr.sp = sfr.sp[1:]
- }
-
- if err == io.EOF && sfr.pos < sfr.tot {
- // We reached the end of the last fragment's data, but there's a final hole
- err = nil
- }
- return
-}
-
-// numBytes returns the number of bytes left to read in the sparse file's
-// sparse-encoded data in the tar archive.
-func (sfr *sparseFileReader) numBytes() int64 {
- return sfr.rfr.nb
-}
diff --git a/src/pkg/archive/tar/reader_test.go b/src/pkg/archive/tar/reader_test.go
deleted file mode 100644
index 9601ffe45..000000000
--- a/src/pkg/archive/tar/reader_test.go
+++ /dev/null
@@ -1,743 +0,0 @@
-// 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"
- "io/ioutil"
- "os"
- "reflect"
- "strings"
- "testing"
- "time"
-)
-
-type untarTest struct {
- file string
- headers []*Header
- cksums []string
-}
-
-var gnuTarTest = &untarTest{
- file: "testdata/gnu.tar",
- headers: []*Header{
- {
- Name: "small.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 5,
- ModTime: time.Unix(1244428340, 0),
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- },
- {
- Name: "small2.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 11,
- ModTime: time.Unix(1244436044, 0),
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- },
- },
- cksums: []string{
- "e38b27eaccb4391bdec553a7f3ae6b2f",
- "c65bd2e50a56a2138bf1716f2fd56fe9",
- },
-}
-
-var sparseTarTest = &untarTest{
- file: "testdata/sparse-formats.tar",
- headers: []*Header{
- {
- Name: "sparse-gnu",
- Mode: 420,
- Uid: 1000,
- Gid: 1000,
- Size: 200,
- ModTime: time.Unix(1392395740, 0),
- Typeflag: 0x53,
- Linkname: "",
- Uname: "david",
- Gname: "david",
- Devmajor: 0,
- Devminor: 0,
- },
- {
- Name: "sparse-posix-0.0",
- Mode: 420,
- Uid: 1000,
- Gid: 1000,
- Size: 200,
- ModTime: time.Unix(1392342187, 0),
- Typeflag: 0x30,
- Linkname: "",
- Uname: "david",
- Gname: "david",
- Devmajor: 0,
- Devminor: 0,
- },
- {
- Name: "sparse-posix-0.1",
- Mode: 420,
- Uid: 1000,
- Gid: 1000,
- Size: 200,
- ModTime: time.Unix(1392340456, 0),
- Typeflag: 0x30,
- Linkname: "",
- Uname: "david",
- Gname: "david",
- Devmajor: 0,
- Devminor: 0,
- },
- {
- Name: "sparse-posix-1.0",
- Mode: 420,
- Uid: 1000,
- Gid: 1000,
- Size: 200,
- ModTime: time.Unix(1392337404, 0),
- Typeflag: 0x30,
- Linkname: "",
- Uname: "david",
- Gname: "david",
- Devmajor: 0,
- Devminor: 0,
- },
- {
- Name: "end",
- Mode: 420,
- Uid: 1000,
- Gid: 1000,
- Size: 4,
- ModTime: time.Unix(1392398319, 0),
- Typeflag: 0x30,
- Linkname: "",
- Uname: "david",
- Gname: "david",
- Devmajor: 0,
- Devminor: 0,
- },
- },
- cksums: []string{
- "6f53234398c2449fe67c1812d993012f",
- "6f53234398c2449fe67c1812d993012f",
- "6f53234398c2449fe67c1812d993012f",
- "6f53234398c2449fe67c1812d993012f",
- "b0061974914468de549a2af8ced10316",
- },
-}
-
-var untarTests = []*untarTest{
- gnuTarTest,
- sparseTarTest,
- {
- file: "testdata/star.tar",
- headers: []*Header{
- {
- Name: "small.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 5,
- ModTime: time.Unix(1244592783, 0),
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- AccessTime: time.Unix(1244592783, 0),
- ChangeTime: time.Unix(1244592783, 0),
- },
- {
- Name: "small2.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 11,
- ModTime: time.Unix(1244592783, 0),
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- AccessTime: time.Unix(1244592783, 0),
- ChangeTime: time.Unix(1244592783, 0),
- },
- },
- },
- {
- file: "testdata/v7.tar",
- headers: []*Header{
- {
- Name: "small.txt",
- Mode: 0444,
- Uid: 73025,
- Gid: 5000,
- Size: 5,
- ModTime: time.Unix(1244593104, 0),
- Typeflag: '\x00',
- },
- {
- Name: "small2.txt",
- Mode: 0444,
- Uid: 73025,
- Gid: 5000,
- Size: 11,
- ModTime: time.Unix(1244593104, 0),
- Typeflag: '\x00',
- },
- },
- },
- {
- file: "testdata/pax.tar",
- headers: []*Header{
- {
- Name: "a/123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
- Mode: 0664,
- Uid: 1000,
- Gid: 1000,
- Uname: "shane",
- Gname: "shane",
- Size: 7,
- ModTime: time.Unix(1350244992, 23960108),
- ChangeTime: time.Unix(1350244992, 23960108),
- AccessTime: time.Unix(1350244992, 23960108),
- Typeflag: TypeReg,
- },
- {
- Name: "a/b",
- Mode: 0777,
- Uid: 1000,
- Gid: 1000,
- Uname: "shane",
- Gname: "shane",
- Size: 0,
- ModTime: time.Unix(1350266320, 910238425),
- ChangeTime: time.Unix(1350266320, 910238425),
- AccessTime: time.Unix(1350266320, 910238425),
- Typeflag: TypeSymlink,
- Linkname: "123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
- },
- },
- },
- {
- file: "testdata/nil-uid.tar", // golang.org/issue/5290
- headers: []*Header{
- {
- Name: "P1050238.JPG.log",
- Mode: 0664,
- Uid: 0,
- Gid: 0,
- Size: 14,
- ModTime: time.Unix(1365454838, 0),
- Typeflag: TypeReg,
- Linkname: "",
- Uname: "eyefi",
- Gname: "eyefi",
- Devmajor: 0,
- Devminor: 0,
- },
- },
- },
- {
- file: "testdata/xattrs.tar",
- headers: []*Header{
- {
- Name: "small.txt",
- Mode: 0644,
- Uid: 1000,
- Gid: 10,
- Size: 5,
- ModTime: time.Unix(1386065770, 448252320),
- Typeflag: '0',
- Uname: "alex",
- Gname: "wheel",
- AccessTime: time.Unix(1389782991, 419875220),
- ChangeTime: time.Unix(1389782956, 794414986),
- Xattrs: map[string]string{
- "user.key": "value",
- "user.key2": "value2",
- // Interestingly, selinux encodes the terminating null inside the xattr
- "security.selinux": "unconfined_u:object_r:default_t:s0\x00",
- },
- },
- {
- Name: "small2.txt",
- Mode: 0644,
- Uid: 1000,
- Gid: 10,
- Size: 11,
- ModTime: time.Unix(1386065770, 449252304),
- Typeflag: '0',
- Uname: "alex",
- Gname: "wheel",
- AccessTime: time.Unix(1389782991, 419875220),
- ChangeTime: time.Unix(1386065770, 449252304),
- Xattrs: map[string]string{
- "security.selinux": "unconfined_u:object_r:default_t:s0\x00",
- },
- },
- },
- },
-}
-
-func TestReader(t *testing.T) {
-testLoop:
- for i, test := range untarTests {
- f, err := os.Open(test.file)
- if err != nil {
- t.Errorf("test %d: Unexpected error: %v", i, err)
- continue
- }
- defer f.Close()
- 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 == io.EOF {
- continue testLoop
- }
- if hdr != nil || err != nil {
- t.Errorf("test %d: Unexpected entry or error: hdr=%v err=%v", i, hdr, err)
- }
- }
-}
-
-func TestPartialRead(t *testing.T) {
- f, err := os.Open("testdata/gnu.tar")
- 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)
- 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 == io.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 == io.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(nil))
- 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)
- if err != nil {
- t.Fatalf("Unexpected error: %v", err)
- }
- defer f.Close()
-
- type readerOnly struct {
- io.Reader
- }
- tr := NewReader(readerOnly{f})
- nread := 0
-
- for ; ; nread++ {
- _, err := tr.Next()
- if err == io.EOF {
- break
- }
- if err != nil {
- t.Fatalf("Unexpected error: %v", err)
- }
- }
-
- if nread != len(test.headers) {
- t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(test.headers), nread)
- }
-}
-
-func TestParsePAXHeader(t *testing.T) {
- paxTests := [][3]string{
- {"a", "a=name", "10 a=name\n"}, // Test case involving multiple acceptable lengths
- {"a", "a=name", "9 a=name\n"}, // Test case involving multiple acceptable length
- {"mtime", "mtime=1350244992.023960108", "30 mtime=1350244992.023960108\n"}}
- for _, test := range paxTests {
- key, expected, raw := test[0], test[1], test[2]
- reader := bytes.NewReader([]byte(raw))
- headers, err := parsePAX(reader)
- if err != nil {
- t.Errorf("Couldn't parse correctly formatted headers: %v", err)
- continue
- }
- if strings.EqualFold(headers[key], expected) {
- t.Errorf("mtime header incorrectly parsed: got %s, wanted %s", headers[key], expected)
- continue
- }
- trailer := make([]byte, 100)
- n, err := reader.Read(trailer)
- if err != io.EOF || n != 0 {
- t.Error("Buffer wasn't consumed")
- }
- }
- badHeader := bytes.NewReader([]byte("3 somelongkey="))
- if _, err := parsePAX(badHeader); err != ErrHeader {
- t.Fatal("Unexpected success when parsing bad header")
- }
-}
-
-func TestParsePAXTime(t *testing.T) {
- // Some valid PAX time values
- timestamps := map[string]time.Time{
- "1350244992.023960108": time.Unix(1350244992, 23960108), // The common case
- "1350244992.02396010": time.Unix(1350244992, 23960100), // Lower precision value
- "1350244992.0239601089": time.Unix(1350244992, 23960108), // Higher precision value
- "1350244992": time.Unix(1350244992, 0), // Low precision value
- }
- for input, expected := range timestamps {
- ts, err := parsePAXTime(input)
- if err != nil {
- t.Fatal(err)
- }
- if !ts.Equal(expected) {
- t.Fatalf("Time parsing failure %s %s", ts, expected)
- }
- }
-}
-
-func TestMergePAX(t *testing.T) {
- hdr := new(Header)
- // Test a string, integer, and time based value.
- headers := map[string]string{
- "path": "a/b/c",
- "uid": "1000",
- "mtime": "1350244992.023960108",
- }
- err := mergePAX(hdr, headers)
- if err != nil {
- t.Fatal(err)
- }
- want := &Header{
- Name: "a/b/c",
- Uid: 1000,
- ModTime: time.Unix(1350244992, 23960108),
- }
- if !reflect.DeepEqual(hdr, want) {
- t.Errorf("incorrect merge: got %+v, want %+v", hdr, want)
- }
-}
-
-func TestSparseEndToEnd(t *testing.T) {
- test := sparseTarTest
- f, err := os.Open(test.file)
- 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 == io.EOF {
- break
- }
-
- // check the header
- if !reflect.DeepEqual(*hdr, *headers[nread]) {
- t.Errorf("Incorrect header:\nhave %+v\nwant %+v",
- *hdr, headers[nread])
- }
-
- // read and checksum the file data
- h := md5.New()
- _, err = io.Copy(h, tr)
- if err != nil {
- t.Fatalf("Unexpected error: %v", err)
- }
-
- // verify checksum
- have := fmt.Sprintf("%x", h.Sum(nil))
- 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)
- }
-}
-
-type sparseFileReadTest struct {
- sparseData []byte
- sparseMap []sparseEntry
- realSize int64
- expected []byte
-}
-
-var sparseFileReadTests = []sparseFileReadTest{
- {
- sparseData: []byte("abcde"),
- sparseMap: []sparseEntry{
- {offset: 0, numBytes: 2},
- {offset: 5, numBytes: 3},
- },
- realSize: 8,
- expected: []byte("ab\x00\x00\x00cde"),
- },
- {
- sparseData: []byte("abcde"),
- sparseMap: []sparseEntry{
- {offset: 0, numBytes: 2},
- {offset: 5, numBytes: 3},
- },
- realSize: 10,
- expected: []byte("ab\x00\x00\x00cde\x00\x00"),
- },
- {
- sparseData: []byte("abcde"),
- sparseMap: []sparseEntry{
- {offset: 1, numBytes: 3},
- {offset: 6, numBytes: 2},
- },
- realSize: 8,
- expected: []byte("\x00abc\x00\x00de"),
- },
- {
- sparseData: []byte("abcde"),
- sparseMap: []sparseEntry{
- {offset: 1, numBytes: 3},
- {offset: 6, numBytes: 2},
- },
- realSize: 10,
- expected: []byte("\x00abc\x00\x00de\x00\x00"),
- },
- {
- sparseData: []byte(""),
- sparseMap: nil,
- realSize: 2,
- expected: []byte("\x00\x00"),
- },
-}
-
-func TestSparseFileReader(t *testing.T) {
- for i, test := range sparseFileReadTests {
- r := bytes.NewReader(test.sparseData)
- nb := int64(r.Len())
- sfr := &sparseFileReader{
- rfr: &regFileReader{r: r, nb: nb},
- sp: test.sparseMap,
- pos: 0,
- tot: test.realSize,
- }
- if sfr.numBytes() != nb {
- t.Errorf("test %d: Before reading, sfr.numBytes() = %d, want %d", i, sfr.numBytes(), nb)
- }
- buf, err := ioutil.ReadAll(sfr)
- if err != nil {
- t.Errorf("test %d: Unexpected error: %v", i, err)
- }
- if e := test.expected; !bytes.Equal(buf, e) {
- t.Errorf("test %d: Contents = %v, want %v", i, buf, e)
- }
- if sfr.numBytes() != 0 {
- t.Errorf("test %d: After draining the reader, numBytes() was nonzero", i)
- }
- }
-}
-
-func TestSparseIncrementalRead(t *testing.T) {
- sparseMap := []sparseEntry{{10, 2}}
- sparseData := []byte("Go")
- expected := "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Go\x00\x00\x00\x00\x00\x00\x00\x00"
-
- r := bytes.NewReader(sparseData)
- nb := int64(r.Len())
- sfr := &sparseFileReader{
- rfr: &regFileReader{r: r, nb: nb},
- sp: sparseMap,
- pos: 0,
- tot: int64(len(expected)),
- }
-
- // We'll read the data 6 bytes at a time, with a hole of size 10 at
- // the beginning and one of size 8 at the end.
- var outputBuf bytes.Buffer
- buf := make([]byte, 6)
- for {
- n, err := sfr.Read(buf)
- if err == io.EOF {
- break
- }
- if err != nil {
- t.Errorf("Read: unexpected error %v\n", err)
- }
- if n > 0 {
- _, err := outputBuf.Write(buf[:n])
- if err != nil {
- t.Errorf("Write: unexpected error %v\n", err)
- }
- }
- }
- got := outputBuf.String()
- if got != expected {
- t.Errorf("Contents = %v, want %v", got, expected)
- }
-}
-
-func TestReadGNUSparseMap0x1(t *testing.T) {
- headers := map[string]string{
- paxGNUSparseNumBlocks: "4",
- paxGNUSparseMap: "0,5,10,5,20,5,30,5",
- }
- expected := []sparseEntry{
- {offset: 0, numBytes: 5},
- {offset: 10, numBytes: 5},
- {offset: 20, numBytes: 5},
- {offset: 30, numBytes: 5},
- }
-
- sp, err := readGNUSparseMap0x1(headers)
- if err != nil {
- t.Errorf("Unexpected error: %v", err)
- }
- if !reflect.DeepEqual(sp, expected) {
- t.Errorf("Incorrect sparse map: got %v, wanted %v", sp, expected)
- }
-}
-
-func TestReadGNUSparseMap1x0(t *testing.T) {
- // This test uses lots of holes so the sparse header takes up more than two blocks
- numEntries := 100
- expected := make([]sparseEntry, 0, numEntries)
- sparseMap := new(bytes.Buffer)
-
- fmt.Fprintf(sparseMap, "%d\n", numEntries)
- for i := 0; i < numEntries; i++ {
- offset := int64(2048 * i)
- numBytes := int64(1024)
- expected = append(expected, sparseEntry{offset: offset, numBytes: numBytes})
- fmt.Fprintf(sparseMap, "%d\n%d\n", offset, numBytes)
- }
-
- // Make the header the smallest multiple of blockSize that fits the sparseMap
- headerBlocks := (sparseMap.Len() + blockSize - 1) / blockSize
- bufLen := blockSize * headerBlocks
- buf := make([]byte, bufLen)
- copy(buf, sparseMap.Bytes())
-
- // Get an reader to read the sparse map
- r := bytes.NewReader(buf)
-
- // Read the sparse map
- sp, err := readGNUSparseMap1x0(r)
- if err != nil {
- t.Errorf("Unexpected error: %v", err)
- }
- if !reflect.DeepEqual(sp, expected) {
- t.Errorf("Incorrect sparse map: got %v, wanted %v", sp, expected)
- }
-}
-
-func TestUninitializedRead(t *testing.T) {
- test := gnuTarTest
- f, err := os.Open(test.file)
- if err != nil {
- t.Fatalf("Unexpected error: %v", err)
- }
- defer f.Close()
-
- tr := NewReader(f)
- _, err = tr.Read([]byte{})
- if err == nil || err != io.EOF {
- t.Errorf("Unexpected error: %v, wanted %v", err, io.EOF)
- }
-
-}
diff --git a/src/pkg/archive/tar/stat_atim.go b/src/pkg/archive/tar/stat_atim.go
deleted file mode 100644
index cf9cc79c5..000000000
--- a/src/pkg/archive/tar/stat_atim.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2012 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.
-
-// +build linux dragonfly openbsd solaris
-
-package tar
-
-import (
- "syscall"
- "time"
-)
-
-func statAtime(st *syscall.Stat_t) time.Time {
- return time.Unix(st.Atim.Unix())
-}
-
-func statCtime(st *syscall.Stat_t) time.Time {
- return time.Unix(st.Ctim.Unix())
-}
diff --git a/src/pkg/archive/tar/stat_atimespec.go b/src/pkg/archive/tar/stat_atimespec.go
deleted file mode 100644
index 6f17dbe30..000000000
--- a/src/pkg/archive/tar/stat_atimespec.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2012 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.
-
-// +build darwin freebsd netbsd
-
-package tar
-
-import (
- "syscall"
- "time"
-)
-
-func statAtime(st *syscall.Stat_t) time.Time {
- return time.Unix(st.Atimespec.Unix())
-}
-
-func statCtime(st *syscall.Stat_t) time.Time {
- return time.Unix(st.Ctimespec.Unix())
-}
diff --git a/src/pkg/archive/tar/stat_unix.go b/src/pkg/archive/tar/stat_unix.go
deleted file mode 100644
index cb843db4c..000000000
--- a/src/pkg/archive/tar/stat_unix.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2012 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.
-
-// +build linux darwin dragonfly freebsd openbsd netbsd solaris
-
-package tar
-
-import (
- "os"
- "syscall"
-)
-
-func init() {
- sysStat = statUnix
-}
-
-func statUnix(fi os.FileInfo, h *Header) error {
- sys, ok := fi.Sys().(*syscall.Stat_t)
- if !ok {
- return nil
- }
- h.Uid = int(sys.Uid)
- h.Gid = int(sys.Gid)
- // TODO(bradfitz): populate username & group. os/user
- // doesn't cache LookupId lookups, and lacks group
- // lookup functions.
- h.AccessTime = statAtime(sys)
- h.ChangeTime = statCtime(sys)
- // TODO(bradfitz): major/minor device numbers?
- return nil
-}
diff --git a/src/pkg/archive/tar/tar_test.go b/src/pkg/archive/tar/tar_test.go
deleted file mode 100644
index ed333f3ea..000000000
--- a/src/pkg/archive/tar/tar_test.go
+++ /dev/null
@@ -1,284 +0,0 @@
-// Copyright 2012 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"
- "io/ioutil"
- "os"
- "path"
- "reflect"
- "strings"
- "testing"
- "time"
-)
-
-func TestFileInfoHeader(t *testing.T) {
- fi, err := os.Stat("testdata/small.txt")
- if err != nil {
- t.Fatal(err)
- }
- h, err := FileInfoHeader(fi, "")
- if err != nil {
- t.Fatalf("FileInfoHeader: %v", err)
- }
- if g, e := h.Name, "small.txt"; g != e {
- t.Errorf("Name = %q; want %q", g, e)
- }
- if g, e := h.Mode, int64(fi.Mode().Perm())|c_ISREG; g != e {
- t.Errorf("Mode = %#o; want %#o", g, e)
- }
- if g, e := h.Size, int64(5); g != e {
- t.Errorf("Size = %v; want %v", g, e)
- }
- if g, e := h.ModTime, fi.ModTime(); !g.Equal(e) {
- t.Errorf("ModTime = %v; want %v", g, e)
- }
- // FileInfoHeader should error when passing nil FileInfo
- if _, err := FileInfoHeader(nil, ""); err == nil {
- t.Fatalf("Expected error when passing nil to FileInfoHeader")
- }
-}
-
-func TestFileInfoHeaderDir(t *testing.T) {
- fi, err := os.Stat("testdata")
- if err != nil {
- t.Fatal(err)
- }
- h, err := FileInfoHeader(fi, "")
- if err != nil {
- t.Fatalf("FileInfoHeader: %v", err)
- }
- if g, e := h.Name, "testdata/"; g != e {
- t.Errorf("Name = %q; want %q", g, e)
- }
- // Ignoring c_ISGID for golang.org/issue/4867
- if g, e := h.Mode&^c_ISGID, int64(fi.Mode().Perm())|c_ISDIR; g != e {
- t.Errorf("Mode = %#o; want %#o", g, e)
- }
- if g, e := h.Size, int64(0); g != e {
- t.Errorf("Size = %v; want %v", g, e)
- }
- if g, e := h.ModTime, fi.ModTime(); !g.Equal(e) {
- t.Errorf("ModTime = %v; want %v", g, e)
- }
-}
-
-func TestFileInfoHeaderSymlink(t *testing.T) {
- h, err := FileInfoHeader(symlink{}, "some-target")
- if err != nil {
- t.Fatal(err)
- }
- if g, e := h.Name, "some-symlink"; g != e {
- t.Errorf("Name = %q; want %q", g, e)
- }
- if g, e := h.Linkname, "some-target"; g != e {
- t.Errorf("Linkname = %q; want %q", g, e)
- }
-}
-
-type symlink struct{}
-
-func (symlink) Name() string { return "some-symlink" }
-func (symlink) Size() int64 { return 0 }
-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)
- }
-}
-
-type headerRoundTripTest struct {
- h *Header
- fm os.FileMode
-}
-
-func TestHeaderRoundTrip(t *testing.T) {
- golden := []headerRoundTripTest{
- // regular file.
- {
- h: &Header{
- Name: "test.txt",
- Mode: 0644 | c_ISREG,
- Size: 12,
- ModTime: time.Unix(1360600916, 0),
- Typeflag: TypeReg,
- },
- fm: 0644,
- },
- // hard link.
- {
- h: &Header{
- Name: "hard.txt",
- Mode: 0644 | c_ISLNK,
- Size: 0,
- ModTime: time.Unix(1360600916, 0),
- Typeflag: TypeLink,
- },
- fm: 0644 | os.ModeSymlink,
- },
- // symbolic link.
- {
- h: &Header{
- Name: "link.txt",
- Mode: 0777 | c_ISLNK,
- Size: 0,
- ModTime: time.Unix(1360600852, 0),
- Typeflag: TypeSymlink,
- },
- fm: 0777 | os.ModeSymlink,
- },
- // character device node.
- {
- h: &Header{
- Name: "dev/null",
- Mode: 0666 | c_ISCHR,
- Size: 0,
- ModTime: time.Unix(1360578951, 0),
- Typeflag: TypeChar,
- },
- fm: 0666 | os.ModeDevice | os.ModeCharDevice,
- },
- // block device node.
- {
- h: &Header{
- Name: "dev/sda",
- Mode: 0660 | c_ISBLK,
- Size: 0,
- ModTime: time.Unix(1360578954, 0),
- Typeflag: TypeBlock,
- },
- fm: 0660 | os.ModeDevice,
- },
- // directory.
- {
- h: &Header{
- Name: "dir/",
- Mode: 0755 | c_ISDIR,
- Size: 0,
- ModTime: time.Unix(1360601116, 0),
- Typeflag: TypeDir,
- },
- fm: 0755 | os.ModeDir,
- },
- // fifo node.
- {
- h: &Header{
- Name: "dev/initctl",
- Mode: 0600 | c_ISFIFO,
- Size: 0,
- ModTime: time.Unix(1360578949, 0),
- Typeflag: TypeFifo,
- },
- fm: 0600 | os.ModeNamedPipe,
- },
- // setuid.
- {
- h: &Header{
- Name: "bin/su",
- Mode: 0755 | c_ISREG | c_ISUID,
- Size: 23232,
- ModTime: time.Unix(1355405093, 0),
- Typeflag: TypeReg,
- },
- fm: 0755 | os.ModeSetuid,
- },
- // setguid.
- {
- h: &Header{
- Name: "group.txt",
- Mode: 0750 | c_ISREG | c_ISGID,
- Size: 0,
- ModTime: time.Unix(1360602346, 0),
- Typeflag: TypeReg,
- },
- fm: 0750 | os.ModeSetgid,
- },
- // sticky.
- {
- h: &Header{
- Name: "sticky.txt",
- Mode: 0600 | c_ISREG | c_ISVTX,
- Size: 7,
- ModTime: time.Unix(1360602540, 0),
- Typeflag: TypeReg,
- },
- fm: 0600 | os.ModeSticky,
- },
- }
-
- for i, g := range golden {
- fi := g.h.FileInfo()
- h2, err := FileInfoHeader(fi, "")
- if err != nil {
- t.Error(err)
- continue
- }
- if strings.Contains(fi.Name(), "/") {
- t.Errorf("FileInfo of %q contains slash: %q", g.h.Name, fi.Name())
- }
- name := path.Base(g.h.Name)
- if fi.IsDir() {
- name += "/"
- }
- if got, want := h2.Name, name; got != want {
- t.Errorf("i=%d: Name: got %v, want %v", i, got, want)
- }
- if got, want := h2.Size, g.h.Size; got != want {
- t.Errorf("i=%d: Size: got %v, want %v", i, got, want)
- }
- if got, want := h2.Mode, g.h.Mode; got != want {
- t.Errorf("i=%d: Mode: got %o, want %o", i, got, want)
- }
- if got, want := fi.Mode(), g.fm; got != want {
- t.Errorf("i=%d: fi.Mode: got %o, want %o", i, got, want)
- }
- if got, want := h2.ModTime, g.h.ModTime; got != want {
- t.Errorf("i=%d: ModTime: got %v, want %v", i, got, want)
- }
- if sysh, ok := fi.Sys().(*Header); !ok || sysh != g.h {
- t.Errorf("i=%d: Sys didn't return original *Header", i)
- }
- }
-}
diff --git a/src/pkg/archive/tar/testdata/gnu.tar b/src/pkg/archive/tar/testdata/gnu.tar
deleted file mode 100644
index fc899dc8d..000000000
--- a/src/pkg/archive/tar/testdata/gnu.tar
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/tar/testdata/nil-uid.tar b/src/pkg/archive/tar/testdata/nil-uid.tar
deleted file mode 100644
index cc9cfaa33..000000000
--- a/src/pkg/archive/tar/testdata/nil-uid.tar
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/tar/testdata/pax.tar b/src/pkg/archive/tar/testdata/pax.tar
deleted file mode 100644
index 9bc24b658..000000000
--- a/src/pkg/archive/tar/testdata/pax.tar
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/tar/testdata/small.txt b/src/pkg/archive/tar/testdata/small.txt
deleted file mode 100644
index b249bfc51..000000000
--- a/src/pkg/archive/tar/testdata/small.txt
+++ /dev/null
@@ -1 +0,0 @@
-Kilts \ No newline at end of file
diff --git a/src/pkg/archive/tar/testdata/small2.txt b/src/pkg/archive/tar/testdata/small2.txt
deleted file mode 100644
index 394ee3ecd..000000000
--- a/src/pkg/archive/tar/testdata/small2.txt
+++ /dev/null
@@ -1 +0,0 @@
-Google.com
diff --git a/src/pkg/archive/tar/testdata/sparse-formats.tar b/src/pkg/archive/tar/testdata/sparse-formats.tar
deleted file mode 100644
index 8bd4e74d5..000000000
--- a/src/pkg/archive/tar/testdata/sparse-formats.tar
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/tar/testdata/star.tar b/src/pkg/archive/tar/testdata/star.tar
deleted file mode 100644
index 59e2d4e60..000000000
--- a/src/pkg/archive/tar/testdata/star.tar
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/tar/testdata/ustar.tar b/src/pkg/archive/tar/testdata/ustar.tar
deleted file mode 100644
index 29679d9a3..000000000
--- a/src/pkg/archive/tar/testdata/ustar.tar
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/tar/testdata/v7.tar b/src/pkg/archive/tar/testdata/v7.tar
deleted file mode 100644
index eb65fc941..000000000
--- a/src/pkg/archive/tar/testdata/v7.tar
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/tar/testdata/writer-big-long.tar b/src/pkg/archive/tar/testdata/writer-big-long.tar
deleted file mode 100644
index 5960ee824..000000000
--- a/src/pkg/archive/tar/testdata/writer-big-long.tar
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/tar/testdata/writer-big.tar b/src/pkg/archive/tar/testdata/writer-big.tar
deleted file mode 100644
index 753e883ce..000000000
--- a/src/pkg/archive/tar/testdata/writer-big.tar
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/tar/testdata/writer.tar b/src/pkg/archive/tar/testdata/writer.tar
deleted file mode 100644
index e6d816ad0..000000000
--- a/src/pkg/archive/tar/testdata/writer.tar
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/tar/testdata/xattrs.tar b/src/pkg/archive/tar/testdata/xattrs.tar
deleted file mode 100644
index 9701950ed..000000000
--- a/src/pkg/archive/tar/testdata/xattrs.tar
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/tar/writer.go b/src/pkg/archive/tar/writer.go
deleted file mode 100644
index 6eff6f6f8..000000000
--- a/src/pkg/archive/tar/writer.go
+++ /dev/null
@@ -1,383 +0,0 @@
-// 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, etc.)
-
-import (
- "bytes"
- "errors"
- "fmt"
- "io"
- "os"
- "path"
- "strconv"
- "strings"
- "time"
-)
-
-var (
- ErrWriteTooLong = errors.New("archive/tar: write too long")
- ErrFieldTooLong = errors.New("archive/tar: header field too long")
- ErrWriteAfterClose = errors.New("archive/tar: write after close")
- errNameTooLong = errors.New("archive/tar: name too long")
- errInvalidHeader = errors.New("archive/tar: header field too long or contains invalid values")
-)
-
-// 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.
-type Writer struct {
- w io.Writer
- err 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
- preferPax bool // use pax header instead of binary numeric header
-}
-
-// 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() error {
- if tw.nb > 0 {
- tw.err = fmt.Errorf("archive/tar: missed writing %d bytes", tw.nb)
- return tw.err
- }
-
- 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.
-// If the value is too long for the field and allowPax is true add a paxheader record instead
-func (tw *Writer) cString(b []byte, s string, allowPax bool, paxKeyword string, paxHeaders map[string]string) {
- needsPaxHeader := allowPax && len(s) > len(b) || !isASCII(s)
- if needsPaxHeader {
- paxHeaders[paxKeyword] = s
- return
- }
- if len(s) > len(b) {
- if tw.err == nil {
- tw.err = ErrFieldTooLong
- }
- return
- }
- ascii := toASCII(s)
- copy(b, ascii)
- if len(ascii) < len(b) {
- b[len(ascii)] = 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.FormatInt(x, 8)
- // leading zeros, but leave room for a NUL.
- for len(s)+1 < len(b) {
- s = "0" + s
- }
- tw.cString(b, s, false, paxNone, nil)
-}
-
-// Write x into b, either as octal or as binary (GNUtar/star extension).
-// If the value is too long for the field and writingPax is enabled both for the field and the add a paxheader record instead
-func (tw *Writer) numeric(b []byte, x int64, allowPax bool, paxKeyword string, paxHeaders map[string]string) {
- // Try octal first.
- s := strconv.FormatInt(x, 8)
- if len(s) < len(b) {
- tw.octal(b, x)
- return
- }
-
- // If it is too long for octal, and pax is preferred, use a pax header
- if allowPax && tw.preferPax {
- tw.octal(b, 0)
- s := strconv.FormatInt(x, 10)
- paxHeaders[paxKeyword] = s
- 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
-}
-
-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.
-func (tw *Writer) WriteHeader(hdr *Header) error {
- return tw.writeHeader(hdr, true)
-}
-
-// 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.
-// As this method is called internally by writePax header to allow it to
-// suppress writing the pax header.
-func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
- if tw.closed {
- return ErrWriteAfterClose
- }
- if tw.err == nil {
- tw.Flush()
- }
- if tw.err != nil {
- return tw.err
- }
-
- // a map to hold pax header records, if any are needed
- paxHeaders := make(map[string]string)
-
- // TODO(shanemhansen): we might want to use PAX headers for
- // subsecond time resolution, but for now let's just capture
- // too long fields or non ascii characters
-
- header := make([]byte, blockSize)
- s := slicer(header)
-
- // keep a reference to the filename to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
- pathHeaderBytes := s.next(fileNameSize)
-
- tw.cString(pathHeaderBytes, hdr.Name, true, paxPath, paxHeaders)
-
- // 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), true, paxUid, paxHeaders) // 108:116
- tw.numeric(s.next(8), int64(hdr.Gid), true, paxGid, paxHeaders) // 116:124
- tw.numeric(s.next(12), hdr.Size, true, paxSize, paxHeaders) // 124:136
- tw.numeric(s.next(12), modTime, false, paxNone, nil) // 136:148 --- consider using pax for finer granularity
- s.next(8) // chksum (148:156)
- s.next(1)[0] = hdr.Typeflag // 156:157
-
- tw.cString(s.next(100), hdr.Linkname, true, paxLinkpath, paxHeaders)
-
- copy(s.next(8), []byte("ustar\x0000")) // 257:265
- tw.cString(s.next(32), hdr.Uname, true, paxUname, paxHeaders) // 265:297
- tw.cString(s.next(32), hdr.Gname, true, paxGname, paxHeaders) // 297:329
- tw.numeric(s.next(8), hdr.Devmajor, false, paxNone, nil) // 329:337
- tw.numeric(s.next(8), hdr.Devminor, false, paxNone, nil) // 337:345
-
- // keep a reference to the prefix to allow to overwrite it later if we detect that we can use ustar longnames instead of pax
- prefixHeaderBytes := s.next(155)
- tw.cString(prefixHeaderBytes, "", false, paxNone, nil) // 345:500 prefix
-
- // Use the GNU magic instead of POSIX magic if we used any GNU extensions.
- if tw.usedBinary {
- copy(header[257:265], []byte("ustar \x00"))
- }
-
- _, paxPathUsed := paxHeaders[paxPath]
- // try to use a ustar header when only the name is too long
- if !tw.preferPax && len(paxHeaders) == 1 && paxPathUsed {
- suffix := hdr.Name
- prefix := ""
- if len(hdr.Name) > fileNameSize && isASCII(hdr.Name) {
- var err error
- prefix, suffix, err = tw.splitUSTARLongName(hdr.Name)
- if err == nil {
- // ok we can use a ustar long name instead of pax, now correct the fields
-
- // remove the path field from the pax header. this will suppress the pax header
- delete(paxHeaders, paxPath)
-
- // update the path fields
- tw.cString(pathHeaderBytes, suffix, false, paxNone, nil)
- tw.cString(prefixHeaderBytes, prefix, false, paxNone, nil)
-
- // Use the ustar magic if we used ustar long names.
- if len(prefix) > 0 && !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
- }
-
- if allowPax {
- for k, v := range hdr.Xattrs {
- paxHeaders[paxXattr+k] = v
- }
- }
-
- if len(paxHeaders) > 0 {
- if !allowPax {
- return errInvalidHeader
- }
- if err := tw.writePAXHeader(hdr, paxHeaders); err != nil {
- return err
- }
- }
- tw.nb = int64(hdr.Size)
- tw.pad = (blockSize - (tw.nb % blockSize)) % blockSize
-
- _, tw.err = tw.w.Write(header)
- return tw.err
-}
-
-// writeUSTARLongName splits a USTAR long name hdr.Name.
-// name must be < 256 characters. errNameTooLong is returned
-// if hdr.Name can't be split. The splitting heuristic
-// is compatible with gnu tar.
-func (tw *Writer) splitUSTARLongName(name string) (prefix, suffix string, err error) {
- length := len(name)
- if length > fileNamePrefixSize+1 {
- length = fileNamePrefixSize + 1
- } else if name[length-1] == '/' {
- length--
- }
- i := strings.LastIndex(name[:length], "/")
- // nlen contains the resulting length in the name field.
- // plen contains the resulting length in the prefix field.
- nlen := len(name) - i - 1
- plen := i
- if i <= 0 || nlen > fileNameSize || nlen == 0 || plen > fileNamePrefixSize {
- err = errNameTooLong
- return
- }
- prefix, suffix = name[:i], name[i+1:]
- return
-}
-
-// writePaxHeader writes an extended pax header to the
-// archive.
-func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) error {
- // Prepare extended header
- ext := new(Header)
- ext.Typeflag = TypeXHeader
- // Setting ModTime is required for reader parsing to
- // succeed, and seems harmless enough.
- ext.ModTime = hdr.ModTime
- // The spec asks that we namespace our pseudo files
- // with the current pid.
- pid := os.Getpid()
- dir, file := path.Split(hdr.Name)
- fullName := path.Join(dir,
- fmt.Sprintf("PaxHeaders.%d", pid), file)
-
- ascii := toASCII(fullName)
- if len(ascii) > 100 {
- ascii = ascii[:100]
- }
- ext.Name = ascii
- // Construct the body
- var buf bytes.Buffer
-
- for k, v := range paxHeaders {
- fmt.Fprint(&buf, paxHeader(k+"="+v))
- }
-
- ext.Size = int64(len(buf.Bytes()))
- if err := tw.writeHeader(ext, false); err != nil {
- return err
- }
- if _, err := tw.Write(buf.Bytes()); err != nil {
- return err
- }
- if err := tw.Flush(); err != nil {
- return err
- }
- return nil
-}
-
-// paxHeader formats a single pax record, prefixing it with the appropriate length
-func paxHeader(msg string) string {
- const padding = 2 // Extra padding for space and newline
- size := len(msg) + padding
- size += len(strconv.Itoa(size))
- record := fmt.Sprintf("%d %s\n", size, msg)
- if len(record) != size {
- // Final adjustment if adding size increased
- // the number of digits in size
- size = len(record)
- record = fmt.Sprintf("%d %s\n", size, msg)
- }
- return record
-}
-
-// 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 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() error {
- if tw.err != nil || tw.closed {
- return tw.err
- }
- tw.Flush()
- tw.closed = true
- if tw.err != nil {
- return tw.err
- }
-
- // 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/src/pkg/archive/tar/writer_test.go b/src/pkg/archive/tar/writer_test.go
deleted file mode 100644
index 512fab1a6..000000000
--- a/src/pkg/archive/tar/writer_test.go
+++ /dev/null
@@ -1,456 +0,0 @@
-// 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"
- "os"
- "reflect"
- "strings"
- "testing"
- "testing/iotest"
- "time"
-)
-
-type writerTestEntry struct {
- header *Header
- contents string
-}
-
-type writerTest struct {
- file string // filename of expected output
- entries []*writerTestEntry
-}
-
-var writerTests = []*writerTest{
- // The writer test file was produced with this command:
- // tar (GNU tar) 1.26
- // ln -s small.txt link.txt
- // tar -b 1 --format=ustar -c -f writer.tar small.txt small2.txt link.txt
- {
- file: "testdata/writer.tar",
- entries: []*writerTestEntry{
- {
- header: &Header{
- Name: "small.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 5,
- ModTime: time.Unix(1246508266, 0),
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- },
- contents: "Kilts",
- },
- {
- header: &Header{
- Name: "small2.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 11,
- ModTime: time.Unix(1245217492, 0),
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- },
- contents: "Google.com\n",
- },
- {
- header: &Header{
- Name: "link.txt",
- Mode: 0777,
- Uid: 1000,
- Gid: 1000,
- Size: 0,
- ModTime: time.Unix(1314603082, 0),
- Typeflag: '2',
- Linkname: "small.txt",
- Uname: "strings",
- Gname: "strings",
- },
- // no contents
- },
- },
- },
- // 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
- {
- file: "testdata/writer-big.tar",
- entries: []*writerTestEntry{
- {
- header: &Header{
- Name: "tmp/16gig.txt",
- Mode: 0640,
- Uid: 73025,
- Gid: 5000,
- Size: 16 << 30,
- ModTime: time.Unix(1254699560, 0),
- Typeflag: '0',
- Uname: "dsymonds",
- Gname: "eng",
- },
- // fake contents
- contents: strings.Repeat("\x00", 4<<10),
- },
- },
- },
- // The truncated test file was produced using these commands:
- // dd if=/dev/zero bs=1048576 count=16384 > (longname/)*15 /16gig.txt
- // tar -b 1 -c -f- (longname/)*15 /16gig.txt | dd bs=512 count=8 > writer-big-long.tar
- {
- file: "testdata/writer-big-long.tar",
- entries: []*writerTestEntry{
- {
- header: &Header{
- Name: strings.Repeat("longname/", 15) + "16gig.txt",
- Mode: 0644,
- Uid: 1000,
- Gid: 1000,
- Size: 16 << 30,
- ModTime: time.Unix(1399583047, 0),
- Typeflag: '0',
- Uname: "guillaume",
- Gname: "guillaume",
- },
- // fake contents
- contents: strings.Repeat("\x00", 4<<10),
- },
- },
- },
- // This file was produced using gnu tar 1.17
- // gnutar -b 4 --format=ustar (longname/)*15 + file.txt
- {
- file: "testdata/ustar.tar",
- entries: []*writerTestEntry{
- {
- header: &Header{
- Name: strings.Repeat("longname/", 15) + "file.txt",
- Mode: 0644,
- Uid: 0765,
- Gid: 024,
- Size: 06,
- ModTime: time.Unix(1360135598, 0),
- Typeflag: '0',
- Uname: "shane",
- Gname: "staff",
- },
- contents: "hello\n",
- },
- },
- },
-}
-
-// 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
- big := false
- for j, entry := range test.entries {
- big = big || entry.header.Size > 1<<10
- 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
- }
- }
- // Only interested in Close failures for the small tests.
- if err := tw.Close(); err != nil && !big {
- 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))
- }
- if testing.Short() { // The second test is expensive.
- break
- }
- }
-}
-
-func TestPax(t *testing.T) {
- // Create an archive with a large name
- fileinfo, err := os.Stat("testdata/small.txt")
- if err != nil {
- t.Fatal(err)
- }
- hdr, err := FileInfoHeader(fileinfo, "")
- if err != nil {
- t.Fatalf("os.Stat: %v", err)
- }
- // Force a PAX long name to be written
- longName := strings.Repeat("ab", 100)
- contents := strings.Repeat(" ", int(hdr.Size))
- hdr.Name = longName
- var buf bytes.Buffer
- writer := NewWriter(&buf)
- if err := writer.WriteHeader(hdr); err != nil {
- t.Fatal(err)
- }
- if _, err = writer.Write([]byte(contents)); err != nil {
- t.Fatal(err)
- }
- if err := writer.Close(); err != nil {
- t.Fatal(err)
- }
- // Simple test to make sure PAX extensions are in effect
- if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.")) {
- t.Fatal("Expected at least one PAX header to be written.")
- }
- // Test that we can get a long name back out of the archive.
- reader := NewReader(&buf)
- hdr, err = reader.Next()
- if err != nil {
- t.Fatal(err)
- }
- if hdr.Name != longName {
- t.Fatal("Couldn't recover long file name")
- }
-}
-
-func TestPaxSymlink(t *testing.T) {
- // Create an archive with a large linkname
- fileinfo, err := os.Stat("testdata/small.txt")
- if err != nil {
- t.Fatal(err)
- }
- hdr, err := FileInfoHeader(fileinfo, "")
- hdr.Typeflag = TypeSymlink
- if err != nil {
- t.Fatalf("os.Stat:1 %v", err)
- }
- // Force a PAX long linkname to be written
- longLinkname := strings.Repeat("1234567890/1234567890", 10)
- hdr.Linkname = longLinkname
-
- hdr.Size = 0
- var buf bytes.Buffer
- writer := NewWriter(&buf)
- if err := writer.WriteHeader(hdr); err != nil {
- t.Fatal(err)
- }
- if err := writer.Close(); err != nil {
- t.Fatal(err)
- }
- // Simple test to make sure PAX extensions are in effect
- if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.")) {
- t.Fatal("Expected at least one PAX header to be written.")
- }
- // Test that we can get a long name back out of the archive.
- reader := NewReader(&buf)
- hdr, err = reader.Next()
- if err != nil {
- t.Fatal(err)
- }
- if hdr.Linkname != longLinkname {
- t.Fatal("Couldn't recover long link name")
- }
-}
-
-func TestPaxNonAscii(t *testing.T) {
- // Create an archive with non ascii. These should trigger a pax header
- // because pax headers have a defined utf-8 encoding.
- fileinfo, err := os.Stat("testdata/small.txt")
- if err != nil {
- t.Fatal(err)
- }
-
- hdr, err := FileInfoHeader(fileinfo, "")
- if err != nil {
- t.Fatalf("os.Stat:1 %v", err)
- }
-
- // some sample data
- chineseFilename := "文件名"
- chineseGroupname := "組"
- chineseUsername := "用戶名"
-
- hdr.Name = chineseFilename
- hdr.Gname = chineseGroupname
- hdr.Uname = chineseUsername
-
- contents := strings.Repeat(" ", int(hdr.Size))
-
- var buf bytes.Buffer
- writer := NewWriter(&buf)
- if err := writer.WriteHeader(hdr); err != nil {
- t.Fatal(err)
- }
- if _, err = writer.Write([]byte(contents)); err != nil {
- t.Fatal(err)
- }
- if err := writer.Close(); err != nil {
- t.Fatal(err)
- }
- // Simple test to make sure PAX extensions are in effect
- if !bytes.Contains(buf.Bytes(), []byte("PaxHeaders.")) {
- t.Fatal("Expected at least one PAX header to be written.")
- }
- // Test that we can get a long name back out of the archive.
- reader := NewReader(&buf)
- hdr, err = reader.Next()
- if err != nil {
- t.Fatal(err)
- }
- if hdr.Name != chineseFilename {
- t.Fatal("Couldn't recover unicode name")
- }
- if hdr.Gname != chineseGroupname {
- t.Fatal("Couldn't recover unicode group")
- }
- if hdr.Uname != chineseUsername {
- t.Fatal("Couldn't recover unicode user")
- }
-}
-
-func TestPaxXattrs(t *testing.T) {
- xattrs := map[string]string{
- "user.key": "value",
- }
-
- // Create an archive with an xattr
- fileinfo, err := os.Stat("testdata/small.txt")
- if err != nil {
- t.Fatal(err)
- }
- hdr, err := FileInfoHeader(fileinfo, "")
- if err != nil {
- t.Fatalf("os.Stat: %v", err)
- }
- contents := "Kilts"
- hdr.Xattrs = xattrs
- var buf bytes.Buffer
- writer := NewWriter(&buf)
- if err := writer.WriteHeader(hdr); err != nil {
- t.Fatal(err)
- }
- if _, err = writer.Write([]byte(contents)); err != nil {
- t.Fatal(err)
- }
- if err := writer.Close(); err != nil {
- t.Fatal(err)
- }
- // Test that we can get the xattrs back out of the archive.
- reader := NewReader(&buf)
- hdr, err = reader.Next()
- if err != nil {
- t.Fatal(err)
- }
- if !reflect.DeepEqual(hdr.Xattrs, xattrs) {
- t.Fatalf("xattrs did not survive round trip: got %+v, want %+v",
- hdr.Xattrs, xattrs)
- }
-}
-
-func TestPAXHeader(t *testing.T) {
- medName := strings.Repeat("CD", 50)
- longName := strings.Repeat("AB", 100)
- paxTests := [][2]string{
- {paxPath + "=/etc/hosts", "19 path=/etc/hosts\n"},
- {"a=b", "6 a=b\n"}, // Single digit length
- {"a=names", "11 a=names\n"}, // Test case involving carries
- {paxPath + "=" + longName, fmt.Sprintf("210 path=%s\n", longName)},
- {paxPath + "=" + medName, fmt.Sprintf("110 path=%s\n", medName)}}
-
- for _, test := range paxTests {
- key, expected := test[0], test[1]
- if result := paxHeader(key); result != expected {
- t.Fatalf("paxHeader: got %s, expected %s", result, expected)
- }
- }
-}
-
-func TestUSTARLongName(t *testing.T) {
- // Create an archive with a path that failed to split with USTAR extension in previous versions.
- fileinfo, err := os.Stat("testdata/small.txt")
- if err != nil {
- t.Fatal(err)
- }
- hdr, err := FileInfoHeader(fileinfo, "")
- hdr.Typeflag = TypeDir
- if err != nil {
- t.Fatalf("os.Stat:1 %v", err)
- }
- // Force a PAX long name to be written. The name was taken from a practical example
- // that fails and replaced ever char through numbers to anonymize the sample.
- longName := "/0000_0000000/00000-000000000/0000_0000000/00000-0000000000000/0000_0000000/00000-0000000-00000000/0000_0000000/00000000/0000_0000000/000/0000_0000000/00000000v00/0000_0000000/000000/0000_0000000/0000000/0000_0000000/00000y-00/0000/0000/00000000/0x000000/"
- hdr.Name = longName
-
- hdr.Size = 0
- var buf bytes.Buffer
- writer := NewWriter(&buf)
- if err := writer.WriteHeader(hdr); err != nil {
- t.Fatal(err)
- }
- if err := writer.Close(); err != nil {
- t.Fatal(err)
- }
- // Test that we can get a long name back out of the archive.
- reader := NewReader(&buf)
- hdr, err = reader.Next()
- if err != nil {
- t.Fatal(err)
- }
- if hdr.Name != longName {
- t.Fatal("Couldn't recover long name")
- }
-}
diff --git a/src/pkg/archive/zip/example_test.go b/src/pkg/archive/zip/example_test.go
deleted file mode 100644
index c2ed9e79c..000000000
--- a/src/pkg/archive/zip/example_test.go
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2012 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_test
-
-import (
- "archive/zip"
- "bytes"
- "fmt"
- "io"
- "log"
- "os"
-)
-
-func ExampleWriter() {
- // Create a buffer to write our archive to.
- buf := new(bytes.Buffer)
-
- // Create a new zip archive.
- w := zip.NewWriter(buf)
-
- // Add some files to the archive.
- var files = []struct {
- Name, Body string
- }{
- {"readme.txt", "This archive contains some text files."},
- {"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
- {"todo.txt", "Get animal handling licence.\nWrite more examples."},
- }
- for _, file := range files {
- f, err := w.Create(file.Name)
- if err != nil {
- log.Fatal(err)
- }
- _, err = f.Write([]byte(file.Body))
- if err != nil {
- log.Fatal(err)
- }
- }
-
- // Make sure to check the error on Close.
- err := w.Close()
- if err != nil {
- log.Fatal(err)
- }
-}
-
-func ExampleReader() {
- // Open a zip archive for reading.
- r, err := zip.OpenReader("testdata/readme.zip")
- if err != nil {
- log.Fatal(err)
- }
- defer r.Close()
-
- // Iterate through the files in the archive,
- // printing some of their contents.
- for _, f := range r.File {
- fmt.Printf("Contents of %s:\n", f.Name)
- rc, err := f.Open()
- if err != nil {
- log.Fatal(err)
- }
- _, err = io.CopyN(os.Stdout, rc, 68)
- if err != nil {
- log.Fatal(err)
- }
- rc.Close()
- fmt.Println()
- }
- // Output:
- // Contents of README:
- // This is the source code repository for the Go programming language.
-}
diff --git a/src/pkg/archive/zip/reader.go b/src/pkg/archive/zip/reader.go
deleted file mode 100644
index 80ee03006..000000000
--- a/src/pkg/archive/zip/reader.go
+++ /dev/null
@@ -1,448 +0,0 @@
-// 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 (
- "bufio"
- "encoding/binary"
- "errors"
- "hash"
- "hash/crc32"
- "io"
- "os"
-)
-
-var (
- ErrFormat = errors.New("zip: not a valid zip file")
- ErrAlgorithm = errors.New("zip: unsupported compression algorithm")
- ErrChecksum = errors.New("zip: checksum error")
-)
-
-type Reader struct {
- r io.ReaderAt
- File []*File
- Comment string
-}
-
-type ReadCloser struct {
- f *os.File
- Reader
-}
-
-type File struct {
- FileHeader
- zipr io.ReaderAt
- zipsize int64
- headerOffset int64
-}
-
-func (f *File) hasDataDescriptor() bool {
- return f.Flags&0x8 != 0
-}
-
-// OpenReader will open the Zip file specified by name and return a ReadCloser.
-func OpenReader(name string) (*ReadCloser, error) {
- f, err := os.Open(name)
- if err != nil {
- return nil, err
- }
- fi, err := f.Stat()
- if err != nil {
- f.Close()
- return nil, err
- }
- r := new(ReadCloser)
- if err := r.init(f, fi.Size()); err != nil {
- f.Close()
- return nil, err
- }
- r.f = f
- return r, nil
-}
-
-// 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, error) {
- zr := new(Reader)
- if err := zr.init(r, size); err != nil {
- return nil, err
- }
- return zr, nil
-}
-
-func (z *Reader) init(r io.ReaderAt, size int64) error {
- end, err := readDirectoryEnd(r, size)
- if err != nil {
- return err
- }
- z.r = r
- z.File = make([]*File, 0, end.directoryRecords)
- z.Comment = end.comment
- rs := io.NewSectionReader(r, 0, size)
- if _, err = rs.Seek(int64(end.directoryOffset), os.SEEK_SET); err != nil {
- return err
- }
- buf := bufio.NewReader(rs)
-
- // The count of files inside a zip is truncated to fit in a uint16.
- // Gloss over this by reading headers until we encounter
- // a bad one, and then only report a ErrFormat or UnexpectedEOF if
- // the file count modulo 65536 is incorrect.
- for {
- f := &File{zipr: r, zipsize: size}
- err = readDirectoryHeader(f, buf)
- if err == ErrFormat || err == io.ErrUnexpectedEOF {
- break
- }
- if err != nil {
- return err
- }
- z.File = append(z.File, f)
- }
- if uint16(len(z.File)) != uint16(end.directoryRecords) { // only compare 16 bits here
- // Return the readDirectoryHeader error if we read
- // the wrong number of directory entries.
- return err
- }
- return nil
-}
-
-// Close closes the Zip file, rendering it unusable for I/O.
-func (rc *ReadCloser) Close() error {
- return rc.f.Close()
-}
-
-// DataOffset returns the offset of the file's possibly-compressed
-// data, relative to the beginning of the zip file.
-//
-// Most callers should instead use Open, which transparently
-// decompresses data and verifies checksums.
-func (f *File) DataOffset() (offset int64, err error) {
- bodyOffset, err := f.findBodyOffset()
- if err != nil {
- return
- }
- return f.headerOffset + bodyOffset, nil
-}
-
-// Open returns a ReadCloser that provides access to the File's contents.
-// Multiple files may be read concurrently.
-func (f *File) Open() (rc io.ReadCloser, err error) {
- bodyOffset, err := f.findBodyOffset()
- if err != nil {
- return
- }
- size := int64(f.CompressedSize64)
- r := io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset, size)
- dcomp := decompressor(f.Method)
- if dcomp == nil {
- err = ErrAlgorithm
- return
- }
- rc = dcomp(r)
- var desr io.Reader
- if f.hasDataDescriptor() {
- desr = io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset+size, dataDescriptorLen)
- }
- rc = &checksumReader{rc, crc32.NewIEEE(), f, desr, nil}
- return
-}
-
-type checksumReader struct {
- rc io.ReadCloser
- hash hash.Hash32
- f *File
- desr io.Reader // if non-nil, where to read the data descriptor
- err error // sticky error
-}
-
-func (r *checksumReader) Read(b []byte) (n int, err error) {
- if r.err != nil {
- return 0, r.err
- }
- n, err = r.rc.Read(b)
- r.hash.Write(b[:n])
- if err == nil {
- return
- }
- if err == io.EOF {
- if r.desr != nil {
- if err1 := readDataDescriptor(r.desr, r.f); err1 != nil {
- err = err1
- } else if r.hash.Sum32() != r.f.CRC32 {
- err = ErrChecksum
- }
- } else {
- // If there's not a data descriptor, we still compare
- // the CRC32 of what we've read against the file header
- // or TOC's CRC32, if it seems like it was set.
- if r.f.CRC32 != 0 && r.hash.Sum32() != r.f.CRC32 {
- err = ErrChecksum
- }
- }
- }
- r.err = err
- return
-}
-
-func (r *checksumReader) Close() error { return r.rc.Close() }
-
-// findBodyOffset does the minimum work to verify the file has a header
-// and returns the file body offset.
-func (f *File) findBodyOffset() (int64, error) {
- var buf [fileHeaderLen]byte
- if _, err := f.zipr.ReadAt(buf[:], f.headerOffset); err != nil {
- return 0, err
- }
- b := readBuf(buf[:])
- if sig := b.uint32(); sig != fileHeaderSignature {
- return 0, ErrFormat
- }
- b = b[22:] // skip over most of the header
- filenameLen := int(b.uint16())
- extraLen := int(b.uint16())
- return int64(fileHeaderLen + filenameLen + extraLen), nil
-}
-
-// readDirectoryHeader attempts to read a directory header from r.
-// It returns io.ErrUnexpectedEOF if it cannot read a complete header,
-// and ErrFormat if it doesn't find a valid header signature.
-func readDirectoryHeader(f *File, r io.Reader) error {
- var buf [directoryHeaderLen]byte
- if _, err := io.ReadFull(r, buf[:]); err != nil {
- return err
- }
- b := readBuf(buf[:])
- if sig := b.uint32(); sig != directoryHeaderSignature {
- return ErrFormat
- }
- f.CreatorVersion = b.uint16()
- f.ReaderVersion = b.uint16()
- f.Flags = b.uint16()
- f.Method = b.uint16()
- f.ModifiedTime = b.uint16()
- f.ModifiedDate = b.uint16()
- f.CRC32 = b.uint32()
- f.CompressedSize = b.uint32()
- f.UncompressedSize = b.uint32()
- f.CompressedSize64 = uint64(f.CompressedSize)
- f.UncompressedSize64 = uint64(f.UncompressedSize)
- filenameLen := int(b.uint16())
- extraLen := int(b.uint16())
- commentLen := int(b.uint16())
- b = b[4:] // skipped start disk number and internal attributes (2x uint16)
- f.ExternalAttrs = b.uint32()
- f.headerOffset = int64(b.uint32())
- d := make([]byte, filenameLen+extraLen+commentLen)
- if _, err := io.ReadFull(r, d); err != nil {
- return err
- }
- f.Name = string(d[:filenameLen])
- f.Extra = d[filenameLen : filenameLen+extraLen]
- f.Comment = string(d[filenameLen+extraLen:])
-
- if len(f.Extra) > 0 {
- b := readBuf(f.Extra)
- 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[:size])
- if len(eb) >= 8 {
- f.UncompressedSize64 = eb.uint64()
- }
- if len(eb) >= 8 {
- f.CompressedSize64 = eb.uint64()
- }
- if len(eb) >= 8 {
- f.headerOffset = int64(eb.uint64())
- }
- }
- b = b[size:]
- }
- // Should have consumed the whole header.
- if len(b) != 0 {
- return ErrFormat
- }
- }
- return nil
-}
-
-func readDataDescriptor(r io.Reader, f *File) error {
- var buf [dataDescriptorLen]byte
-
- // The spec says: "Although not originally assigned a
- // signature, the value 0x08074b50 has commonly been adopted
- // as a signature value for the data descriptor record.
- // Implementers should be aware that ZIP files may be
- // encountered with or without this signature marking data
- // descriptors and should account for either case when reading
- // ZIP files to ensure compatibility."
- //
- // dataDescriptorLen includes the size of the signature but
- // first read just those 4 bytes to see if it exists.
- if _, err := io.ReadFull(r, buf[:4]); err != nil {
- return err
- }
- off := 0
- maybeSig := readBuf(buf[:4])
- if maybeSig.uint32() != dataDescriptorSignature {
- // No data descriptor signature. Keep these four
- // bytes.
- off += 4
- }
- if _, err := io.ReadFull(r, buf[off:12]); err != nil {
- return err
- }
- b := readBuf(buf[:12])
- if b.uint32() != f.CRC32 {
- return ErrChecksum
- }
-
- // The two sizes that follow here can be either 32 bits or 64 bits
- // but the spec is not very clear on this and different
- // interpretations has been made causing incompatibilities. We
- // already have the sizes from the central directory so we can
- // just ignore these.
-
- return nil
-}
-
-func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err error) {
- // look for directoryEndSignature in the last 1k, then in the last 65k
- var buf []byte
- var directoryEndOffset int64
- for i, bLen := range []int64{1024, 65 * 1024} {
- if bLen > size {
- bLen = size
- }
- buf = make([]byte, int(bLen))
- if _, err := r.ReadAt(buf, size-bLen); err != nil && err != io.EOF {
- return nil, err
- }
- if p := findSignatureInBlock(buf); p >= 0 {
- buf = buf[p:]
- directoryEndOffset = size - bLen + int64(p)
- break
- }
- if i == 1 || bLen == size {
- return nil, ErrFormat
- }
- }
-
- // read header into struct
- b := readBuf(buf[4:]) // skip signature
- d := &directoryEnd{
- diskNbr: uint32(b.uint16()),
- dirDiskNbr: uint32(b.uint16()),
- dirRecordsThisDisk: uint64(b.uint16()),
- directoryRecords: uint64(b.uint16()),
- directorySize: uint64(b.uint32()),
- directoryOffset: uint64(b.uint32()),
- commentLen: b.uint16(),
- }
- l := int(d.commentLen)
- if l > len(b) {
- return nil, errors.New("zip: invalid comment length")
- }
- d.comment = string(b[:l])
-
- p, err := findDirectory64End(r, directoryEndOffset)
- if err == nil && p >= 0 {
- err = readDirectory64End(r, p, d)
- }
- if err != nil {
- return nil, err
- }
-
- // Make sure directoryOffset points to somewhere in our file.
- if o := int64(d.directoryOffset); o < 0 || o >= size {
- return nil, ErrFormat
- }
- return d, nil
-}
-
-// findDirectory64End tries to read the zip64 locator just before the
-// directory end and returns the offset of the zip64 directory end if
-// found.
-func findDirectory64End(r io.ReaderAt, directoryEndOffset int64) (int64, error) {
- locOffset := directoryEndOffset - directory64LocLen
- if locOffset < 0 {
- return -1, nil // no need to look for a header outside the file
- }
- buf := make([]byte, directory64LocLen)
- if _, err := r.ReadAt(buf, locOffset); err != nil {
- return -1, err
- }
- b := readBuf(buf)
- if sig := b.uint32(); sig != directory64LocSignature {
- return -1, nil
- }
- b = b[4:] // skip number of the disk with the start of the zip64 end of central directory
- p := b.uint64() // relative offset of the zip64 end of central directory record
- return int64(p), nil
-}
-
-// readDirectory64End reads the zip64 directory end and updates the
-// directory end with the zip64 directory end values.
-func readDirectory64End(r io.ReaderAt, offset int64, d *directoryEnd) (err error) {
- buf := make([]byte, directory64EndLen)
- if _, err := r.ReadAt(buf, offset); err != nil {
- return err
- }
-
- b := readBuf(buf)
- if sig := b.uint32(); sig != directory64EndSignature {
- return ErrFormat
- }
-
- b = b[12:] // skip dir size, version and version needed (uint64 + 2x uint16)
- d.diskNbr = b.uint32() // number of this disk
- d.dirDiskNbr = b.uint32() // number of the disk with the start of the central directory
- d.dirRecordsThisDisk = b.uint64() // total number of entries in the central directory on this disk
- d.directoryRecords = b.uint64() // total number of entries in the central directory
- d.directorySize = b.uint64() // size of the central directory
- d.directoryOffset = b.uint64() // offset of start of central directory with respect to the starting disk number
-
- return nil
-}
-
-func findSignatureInBlock(b []byte) int {
- for i := len(b) - directoryEndLen; 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+directoryEndLen-2]) | int(b[i+directoryEndLen-1])<<8
- if n+directoryEndLen+i <= len(b) {
- return i
- }
- }
- }
- return -1
-}
-
-type readBuf []byte
-
-func (b *readBuf) uint16() uint16 {
- v := binary.LittleEndian.Uint16(*b)
- *b = (*b)[2:]
- return v
-}
-
-func (b *readBuf) uint32() uint32 {
- v := binary.LittleEndian.Uint32(*b)
- *b = (*b)[4:]
- return v
-}
-
-func (b *readBuf) uint64() uint64 {
- v := binary.LittleEndian.Uint64(*b)
- *b = (*b)[8:]
- return v
-}
diff --git a/src/pkg/archive/zip/reader_test.go b/src/pkg/archive/zip/reader_test.go
deleted file mode 100644
index 5652f3a50..000000000
--- a/src/pkg/archive/zip/reader_test.go
+++ /dev/null
@@ -1,510 +0,0 @@
-// 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"
- "encoding/hex"
- "io"
- "io/ioutil"
- "os"
- "path/filepath"
- "regexp"
- "testing"
- "time"
-)
-
-type ZipTest struct {
- Name string
- Source func() (r io.ReaderAt, size int64) // if non-nil, used instead of testdata/<Name> file
- Comment string
- File []ZipTestFile
- Error error // the error that Opening this file should return
-}
-
-type ZipTestFile struct {
- Name string
- Content []byte // if blank, will attempt to compare against File
- ContentErr error
- File string // name of file to compare to (relative to testdata/)
- Mtime string // modified time in format "mm-dd-yy hh:mm:ss"
- Mode os.FileMode
-}
-
-// Caution: The Mtime values found for the test files should correspond to
-// the values listed with unzip -l <zipfile>. However, the values
-// listed by unzip appear to be off by some hours. When creating
-// fresh test files and testing them, this issue is not present.
-// The test files were created in Sydney, so there might be a time
-// zone issue. The time zone information does have to be encoded
-// somewhere, because otherwise unzip -l could not provide a different
-// time from what the archive/zip package provides, but there appears
-// to be no documentation about this.
-
-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"),
- Mtime: "09-05-10 12:12:02",
- Mode: 0644,
- },
- {
- Name: "gophercolor16x16.png",
- File: "gophercolor16x16.png",
- Mtime: "09-05-10 15:52:58",
- Mode: 0644,
- },
- },
- },
- {
- Name: "test-trailing-junk.zip",
- Comment: "This is a zipfile comment.",
- File: []ZipTestFile{
- {
- Name: "test.txt",
- Content: []byte("This is a test text file.\n"),
- Mtime: "09-05-10 12:12:02",
- Mode: 0644,
- },
- {
- Name: "gophercolor16x16.png",
- File: "gophercolor16x16.png",
- Mtime: "09-05-10 15:52:58",
- Mode: 0644,
- },
- },
- },
- {
- Name: "r.zip",
- Source: returnRecursiveZip,
- File: []ZipTestFile{
- {
- Name: "r/r.zip",
- Content: rZipBytes(),
- Mtime: "03-04-10 00:24:16",
- Mode: 0666,
- },
- },
- },
- {
- Name: "symlink.zip",
- File: []ZipTestFile{
- {
- Name: "symlink",
- Content: []byte("../target"),
- Mode: 0777 | os.ModeSymlink,
- },
- },
- },
- {
- Name: "readme.zip",
- },
- {
- Name: "readme.notzip",
- Error: ErrFormat,
- },
- {
- Name: "dd.zip",
- File: []ZipTestFile{
- {
- Name: "filename",
- Content: []byte("This is a test textfile.\n"),
- Mtime: "02-02-11 13:06:20",
- Mode: 0666,
- },
- },
- },
- {
- // created in windows XP file manager.
- Name: "winxp.zip",
- File: crossPlatform,
- },
- {
- // created by Zip 3.0 under Linux
- Name: "unix.zip",
- File: crossPlatform,
- },
- {
- // created by Go, before we wrote the "optional" data
- // descriptor signatures (which are required by OS X)
- Name: "go-no-datadesc-sig.zip",
- File: []ZipTestFile{
- {
- Name: "foo.txt",
- Content: []byte("foo\n"),
- Mtime: "03-08-12 16:59:10",
- Mode: 0644,
- },
- {
- Name: "bar.txt",
- Content: []byte("bar\n"),
- Mtime: "03-08-12 16:59:12",
- Mode: 0644,
- },
- },
- },
- {
- // created by Go, after we wrote the "optional" data
- // descriptor signatures (which are required by OS X)
- Name: "go-with-datadesc-sig.zip",
- File: []ZipTestFile{
- {
- Name: "foo.txt",
- Content: []byte("foo\n"),
- Mode: 0666,
- },
- {
- Name: "bar.txt",
- Content: []byte("bar\n"),
- Mode: 0666,
- },
- },
- },
- {
- Name: "Bad-CRC32-in-data-descriptor",
- Source: returnCorruptCRC32Zip,
- File: []ZipTestFile{
- {
- Name: "foo.txt",
- Content: []byte("foo\n"),
- Mode: 0666,
- ContentErr: ErrChecksum,
- },
- {
- Name: "bar.txt",
- Content: []byte("bar\n"),
- Mode: 0666,
- },
- },
- },
- // Tests that we verify (and accept valid) crc32s on files
- // with crc32s in their file header (not in data descriptors)
- {
- Name: "crc32-not-streamed.zip",
- File: []ZipTestFile{
- {
- Name: "foo.txt",
- Content: []byte("foo\n"),
- Mtime: "03-08-12 16:59:10",
- Mode: 0644,
- },
- {
- Name: "bar.txt",
- Content: []byte("bar\n"),
- Mtime: "03-08-12 16:59:12",
- Mode: 0644,
- },
- },
- },
- // Tests that we verify (and reject invalid) crc32s on files
- // with crc32s in their file header (not in data descriptors)
- {
- Name: "crc32-not-streamed.zip",
- Source: returnCorruptNotStreamedZip,
- File: []ZipTestFile{
- {
- Name: "foo.txt",
- Content: []byte("foo\n"),
- Mtime: "03-08-12 16:59:10",
- Mode: 0644,
- ContentErr: ErrChecksum,
- },
- {
- Name: "bar.txt",
- Content: []byte("bar\n"),
- Mtime: "03-08-12 16:59:12",
- Mode: 0644,
- },
- },
- },
- {
- Name: "zip64.zip",
- File: []ZipTestFile{
- {
- Name: "README",
- Content: []byte("This small file is in ZIP64 format.\n"),
- Mtime: "08-10-12 14:33:32",
- Mode: 0644,
- },
- },
- },
- // Another zip64 file with different Extras fields. (golang.org/issue/7069)
- {
- Name: "zip64-2.zip",
- File: []ZipTestFile{
- {
- Name: "README",
- Content: []byte("This small file is in ZIP64 format.\n"),
- Mtime: "08-10-12 14:33:32",
- Mode: 0644,
- },
- },
- },
-}
-
-var crossPlatform = []ZipTestFile{
- {
- Name: "hello",
- Content: []byte("world \r\n"),
- Mode: 0666,
- },
- {
- Name: "dir/bar",
- Content: []byte("foo \r\n"),
- Mode: 0666,
- },
- {
- Name: "dir/empty/",
- Content: []byte{},
- Mode: os.ModeDir | 0777,
- },
- {
- Name: "readonly",
- Content: []byte("important \r\n"),
- Mode: 0444,
- },
-}
-
-func TestReader(t *testing.T) {
- for _, zt := range tests {
- readTestZip(t, zt)
- }
-}
-
-func readTestZip(t *testing.T, zt ZipTest) {
- var z *Reader
- var err error
- if zt.Source != nil {
- rat, size := zt.Source()
- z, err = NewReader(rat, size)
- } else {
- var rc *ReadCloser
- rc, err = OpenReader(filepath.Join("testdata", zt.Name))
- if err == nil {
- defer rc.Close()
- z = &rc.Reader
- }
- }
- if err != zt.Error {
- t.Errorf("%s: error=%v, want %v", zt.Name, err, zt.Error)
- return
- }
-
- // bail if file is not zip
- if err == ErrFormat {
- 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.Fatalf("%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, zt, 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(j int, ft ZipTestFile) {
- readTestFile(t, zt, ft, z.File[j])
- done <- true
- }(j, ft)
- n++
- }
- }
- for ; n > 0; n-- {
- <-done
- }
-}
-
-func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) {
- if f.Name != ft.Name {
- t.Errorf("%s: name=%q, want %q", zt.Name, f.Name, ft.Name)
- }
-
- if ft.Mtime != "" {
- mtime, err := time.Parse("01-02-06 15:04:05", ft.Mtime)
- if err != nil {
- t.Error(err)
- return
- }
- if ft := f.ModTime(); !ft.Equal(mtime) {
- t.Errorf("%s: %s: mtime=%s, want %s", zt.Name, f.Name, ft, mtime)
- }
- }
-
- testFileMode(t, zt.Name, f, ft.Mode)
-
- var b bytes.Buffer
- r, err := f.Open()
- if err != nil {
- t.Errorf("%s: %v", zt.Name, err)
- return
- }
-
- _, err = io.Copy(&b, r)
- if err != ft.ContentErr {
- t.Errorf("%s: copying contents: %v (want %v)", zt.Name, err, ft.ContentErr)
- }
- if err != nil {
- return
- }
- r.Close()
-
- size := uint64(f.UncompressedSize)
- if size == uint32max {
- size = f.UncompressedSize64
- }
- if g := uint64(b.Len()); g != size {
- t.Errorf("%v: read %v bytes but f.UncompressedSize == %v", f.Name, g, size)
- }
-
- var c []byte
- if ft.Content != nil {
- 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 testFileMode(t *testing.T, zipName string, f *File, want os.FileMode) {
- mode := f.Mode()
- if want == 0 {
- t.Errorf("%s: %s mode: got %v, want none", zipName, f.Name, mode)
- } else if mode != want {
- t.Errorf("%s: %s mode: want %v, got %v", zipName, f.Name, want, mode)
- }
-}
-
-func TestInvalidFiles(t *testing.T) {
- const size = 1024 * 70 // 70kb
- b := make([]byte, size)
-
- // zeroes
- _, err := NewReader(bytes.NewReader(b), size)
- if err != ErrFormat {
- t.Errorf("zeroes: error=%v, want %v", err, ErrFormat)
- }
-
- // 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(bytes.NewReader(b), size)
- if err != ErrFormat {
- t.Errorf("sigs: error=%v, want %v", err, ErrFormat)
- }
-}
-
-func messWith(fileName string, corrupter func(b []byte)) (r io.ReaderAt, size int64) {
- data, err := ioutil.ReadFile(filepath.Join("testdata", fileName))
- if err != nil {
- panic("Error reading " + fileName + ": " + err.Error())
- }
- corrupter(data)
- return bytes.NewReader(data), int64(len(data))
-}
-
-func returnCorruptCRC32Zip() (r io.ReaderAt, size int64) {
- return messWith("go-with-datadesc-sig.zip", func(b []byte) {
- // Corrupt one of the CRC32s in the data descriptor:
- b[0x2d]++
- })
-}
-
-func returnCorruptNotStreamedZip() (r io.ReaderAt, size int64) {
- return messWith("crc32-not-streamed.zip", func(b []byte) {
- // Corrupt foo.txt's final crc32 byte, in both
- // the file header and TOC. (0x7e -> 0x7f)
- b[0x11]++
- b[0x9d]++
-
- // TODO(bradfitz): add a new test that only corrupts
- // one of these values, and verify that that's also an
- // error. Currently, the reader code doesn't verify the
- // fileheader and TOC's crc32 match if they're both
- // non-zero and only the second line above, the TOC,
- // is what matters.
- })
-}
-
-// rZipBytes returns the bytes of a recursive zip file, without
-// putting it on disk and triggering certain virus scanners.
-func rZipBytes() []byte {
- s := `
-0000000 50 4b 03 04 14 00 00 00 08 00 08 03 64 3c f9 f4
-0000010 89 64 48 01 00 00 b8 01 00 00 07 00 00 00 72 2f
-0000020 72 2e 7a 69 70 00 25 00 da ff 50 4b 03 04 14 00
-0000030 00 00 08 00 08 03 64 3c f9 f4 89 64 48 01 00 00
-0000040 b8 01 00 00 07 00 00 00 72 2f 72 2e 7a 69 70 00
-0000050 2f 00 d0 ff 00 25 00 da ff 50 4b 03 04 14 00 00
-0000060 00 08 00 08 03 64 3c f9 f4 89 64 48 01 00 00 b8
-0000070 01 00 00 07 00 00 00 72 2f 72 2e 7a 69 70 00 2f
-0000080 00 d0 ff c2 54 8e 57 39 00 05 00 fa ff c2 54 8e
-0000090 57 39 00 05 00 fa ff 00 05 00 fa ff 00 14 00 eb
-00000a0 ff c2 54 8e 57 39 00 05 00 fa ff 00 05 00 fa ff
-00000b0 00 14 00 eb ff 42 88 21 c4 00 00 14 00 eb ff 42
-00000c0 88 21 c4 00 00 14 00 eb ff 42 88 21 c4 00 00 14
-00000d0 00 eb ff 42 88 21 c4 00 00 14 00 eb ff 42 88 21
-00000e0 c4 00 00 00 00 ff ff 00 00 00 ff ff 00 34 00 cb
-00000f0 ff 42 88 21 c4 00 00 00 00 ff ff 00 00 00 ff ff
-0000100 00 34 00 cb ff 42 e8 21 5e 0f 00 00 00 ff ff 0a
-0000110 f0 66 64 12 61 c0 15 dc e8 a0 48 bf 48 af 2a b3
-0000120 20 c0 9b 95 0d c4 67 04 42 53 06 06 06 40 00 06
-0000130 00 f9 ff 6d 01 00 00 00 00 42 e8 21 5e 0f 00 00
-0000140 00 ff ff 0a f0 66 64 12 61 c0 15 dc e8 a0 48 bf
-0000150 48 af 2a b3 20 c0 9b 95 0d c4 67 04 42 53 06 06
-0000160 06 40 00 06 00 f9 ff 6d 01 00 00 00 00 50 4b 01
-0000170 02 14 00 14 00 00 00 08 00 08 03 64 3c f9 f4 89
-0000180 64 48 01 00 00 b8 01 00 00 07 00 00 00 00 00 00
-0000190 00 00 00 00 00 00 00 00 00 00 00 72 2f 72 2e 7a
-00001a0 69 70 50 4b 05 06 00 00 00 00 01 00 01 00 35 00
-00001b0 00 00 6d 01 00 00 00 00`
- s = regexp.MustCompile(`[0-9a-f]{7}`).ReplaceAllString(s, "")
- s = regexp.MustCompile(`\s+`).ReplaceAllString(s, "")
- b, err := hex.DecodeString(s)
- if err != nil {
- panic(err)
- }
- return b
-}
-
-func returnRecursiveZip() (r io.ReaderAt, size int64) {
- b := rZipBytes()
- return bytes.NewReader(b), int64(len(b))
-}
diff --git a/src/pkg/archive/zip/register.go b/src/pkg/archive/zip/register.go
deleted file mode 100644
index 4211ec7af..000000000
--- a/src/pkg/archive/zip/register.go
+++ /dev/null
@@ -1,110 +0,0 @@
-// 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 (
- "compress/flate"
- "errors"
- "io"
- "io/ioutil"
- "sync"
-)
-
-// A Compressor returns a compressing writer, writing to the
-// provided writer. On Close, any pending data should be flushed.
-type Compressor func(io.Writer) (io.WriteCloser, error)
-
-// Decompressor is a function that wraps a Reader with a decompressing Reader.
-// The decompressed ReadCloser is returned to callers who open files from
-// within the archive. These callers are responsible for closing this reader
-// when they're finished reading.
-type Decompressor func(io.Reader) io.ReadCloser
-
-var flateWriterPool sync.Pool
-
-func newFlateWriter(w io.Writer) io.WriteCloser {
- fw, ok := flateWriterPool.Get().(*flate.Writer)
- if ok {
- fw.Reset(w)
- } else {
- fw, _ = flate.NewWriter(w, 5)
- }
- return &pooledFlateWriter{fw: fw}
-}
-
-type pooledFlateWriter struct {
- mu sync.Mutex // guards Close and Write
- fw *flate.Writer
-}
-
-func (w *pooledFlateWriter) Write(p []byte) (n int, err error) {
- w.mu.Lock()
- defer w.mu.Unlock()
- if w.fw == nil {
- return 0, errors.New("Write after Close")
- }
- return w.fw.Write(p)
-}
-
-func (w *pooledFlateWriter) Close() error {
- w.mu.Lock()
- defer w.mu.Unlock()
- var err error
- if w.fw != nil {
- err = w.fw.Close()
- flateWriterPool.Put(w.fw)
- w.fw = nil
- }
- return err
-}
-
-var (
- mu sync.RWMutex // guards compressor and decompressor maps
-
- compressors = map[uint16]Compressor{
- Store: func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil },
- Deflate: func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil },
- }
-
- decompressors = map[uint16]Decompressor{
- Store: ioutil.NopCloser,
- Deflate: flate.NewReader,
- }
-)
-
-// RegisterDecompressor allows custom decompressors for a specified method ID.
-func RegisterDecompressor(method uint16, d Decompressor) {
- mu.Lock()
- defer mu.Unlock()
-
- if _, ok := decompressors[method]; ok {
- panic("decompressor already registered")
- }
- decompressors[method] = d
-}
-
-// RegisterCompressor registers custom compressors for a specified method ID.
-// The common methods Store and Deflate are built in.
-func RegisterCompressor(method uint16, comp Compressor) {
- mu.Lock()
- defer mu.Unlock()
-
- if _, ok := compressors[method]; ok {
- panic("compressor already registered")
- }
- compressors[method] = comp
-}
-
-func compressor(method uint16) Compressor {
- mu.RLock()
- defer mu.RUnlock()
- return compressors[method]
-}
-
-func decompressor(method uint16) Decompressor {
- mu.RLock()
- defer mu.RUnlock()
- return decompressors[method]
-}
diff --git a/src/pkg/archive/zip/struct.go b/src/pkg/archive/zip/struct.go
deleted file mode 100644
index cb28e8324..000000000
--- a/src/pkg/archive/zip/struct.go
+++ /dev/null
@@ -1,313 +0,0 @@
-// 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 provides support for reading and writing ZIP archives.
-
-See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT
-
-This package does not support disk spanning.
-
-A note about ZIP64:
-
-To be backwards compatible the FileHeader has both 32 and 64 bit Size
-fields. The 64 bit fields will always contain the correct value and
-for normal archives both fields will be the same. For files requiring
-the ZIP64 format the 32 bit fields will be 0xffffffff and the 64 bit
-fields must be used instead.
-*/
-package zip
-
-import (
- "os"
- "path"
- "time"
-)
-
-// Compression methods.
-const (
- Store uint16 = 0
- Deflate uint16 = 8
-)
-
-const (
- fileHeaderSignature = 0x04034b50
- directoryHeaderSignature = 0x02014b50
- directoryEndSignature = 0x06054b50
- directory64LocSignature = 0x07064b50
- directory64EndSignature = 0x06064b50
- dataDescriptorSignature = 0x08074b50 // de-facto standard; required by OS X Finder
- fileHeaderLen = 30 // + filename + extra
- directoryHeaderLen = 46 // + filename + extra + comment
- directoryEndLen = 22 // + comment
- dataDescriptorLen = 16 // four uint32: descriptor signature, crc32, compressed size, size
- dataDescriptor64Len = 24 // descriptor with 8 byte sizes
- directory64LocLen = 20 //
- directory64EndLen = 56 // + extra
-
- // Constants for the first byte in CreatorVersion
- creatorFAT = 0
- creatorUnix = 3
- creatorNTFS = 11
- creatorVFAT = 14
- creatorMacOSX = 19
-
- // version numbers
- zipVersion20 = 20 // 2.0
- zipVersion45 = 45 // 4.5 (reads and writes zip64 archives)
-
- // limits for non zip64 files
- uint16max = (1 << 16) - 1
- uint32max = (1 << 32) - 1
-
- // extra header id's
- zip64ExtraId = 0x0001 // zip64 Extended Information Extra Field
-)
-
-// FileHeader describes a file within a zip file.
-// See the zip spec for details.
-type FileHeader struct {
- // Name is the name of the file.
- // It must be a relative path: it must not start with a drive
- // letter (e.g. C:) or leading slash, and only forward slashes
- // are allowed.
- Name string
-
- CreatorVersion uint16
- ReaderVersion uint16
- Flags uint16
- Method uint16
- ModifiedTime uint16 // MS-DOS time
- ModifiedDate uint16 // MS-DOS date
- CRC32 uint32
- CompressedSize uint32 // deprecated; use CompressedSize64
- UncompressedSize uint32 // deprecated; use UncompressedSize64
- CompressedSize64 uint64
- UncompressedSize64 uint64
- Extra []byte
- ExternalAttrs uint32 // Meaning depends on CreatorVersion
- Comment string
-}
-
-// FileInfo returns an os.FileInfo for the FileHeader.
-func (h *FileHeader) FileInfo() os.FileInfo {
- return headerFileInfo{h}
-}
-
-// headerFileInfo implements os.FileInfo.
-type headerFileInfo struct {
- fh *FileHeader
-}
-
-func (fi headerFileInfo) Name() string { return path.Base(fi.fh.Name) }
-func (fi headerFileInfo) Size() int64 {
- if fi.fh.UncompressedSize64 > 0 {
- return int64(fi.fh.UncompressedSize64)
- }
- return int64(fi.fh.UncompressedSize)
-}
-func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() }
-func (fi headerFileInfo) ModTime() time.Time { return fi.fh.ModTime() }
-func (fi headerFileInfo) Mode() os.FileMode { return fi.fh.Mode() }
-func (fi headerFileInfo) Sys() interface{} { return fi.fh }
-
-// FileInfoHeader creates a partially-populated FileHeader from an
-// os.FileInfo.
-// Because os.FileInfo's Name method returns only the base name of
-// the file it describes, it may be necessary to modify the Name field
-// of the returned header to provide the full path name of the file.
-func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) {
- size := fi.Size()
- fh := &FileHeader{
- Name: fi.Name(),
- UncompressedSize64: uint64(size),
- }
- fh.SetModTime(fi.ModTime())
- fh.SetMode(fi.Mode())
- if fh.UncompressedSize64 > uint32max {
- fh.UncompressedSize = uint32max
- } else {
- fh.UncompressedSize = uint32(fh.UncompressedSize64)
- }
- return fh, nil
-}
-
-type directoryEnd struct {
- diskNbr uint32 // unused
- dirDiskNbr uint32 // unused
- dirRecordsThisDisk uint64 // unused
- directoryRecords uint64
- directorySize uint64
- directoryOffset uint64 // relative to file
- commentLen uint16
- comment string
-}
-
-// msDosTimeToTime converts an MS-DOS date and time into a time.Time.
-// The resolution is 2s.
-// See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx
-func msDosTimeToTime(dosDate, dosTime uint16) time.Time {
- return time.Date(
- // date bits 0-4: day of month; 5-8: month; 9-15: years since 1980
- int(dosDate>>9+1980),
- time.Month(dosDate>>5&0xf),
- int(dosDate&0x1f),
-
- // time bits 0-4: second/2; 5-10: minute; 11-15: hour
- int(dosTime>>11),
- int(dosTime>>5&0x3f),
- int(dosTime&0x1f*2),
- 0, // nanoseconds
-
- time.UTC,
- )
-}
-
-// timeToMsDosTime converts a time.Time to an MS-DOS date and time.
-// The resolution is 2s.
-// See: http://msdn.microsoft.com/en-us/library/ms724274(v=VS.85).aspx
-func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) {
- t = t.In(time.UTC)
- fDate = uint16(t.Day() + int(t.Month())<<5 + (t.Year()-1980)<<9)
- fTime = uint16(t.Second()/2 + t.Minute()<<5 + t.Hour()<<11)
- return
-}
-
-// ModTime returns the modification time in UTC.
-// The resolution is 2s.
-func (h *FileHeader) ModTime() time.Time {
- return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
-}
-
-// SetModTime sets the ModifiedTime and ModifiedDate fields to the given time in UTC.
-// The resolution is 2s.
-func (h *FileHeader) SetModTime(t time.Time) {
- h.ModifiedDate, h.ModifiedTime = timeToMsDosTime(t)
-}
-
-const (
- // Unix constants. The specification doesn't mention them,
- // but these seem to be the values agreed on by tools.
- s_IFMT = 0xf000
- s_IFSOCK = 0xc000
- s_IFLNK = 0xa000
- s_IFREG = 0x8000
- s_IFBLK = 0x6000
- s_IFDIR = 0x4000
- s_IFCHR = 0x2000
- s_IFIFO = 0x1000
- s_ISUID = 0x800
- s_ISGID = 0x400
- s_ISVTX = 0x200
-
- msdosDir = 0x10
- msdosReadOnly = 0x01
-)
-
-// Mode returns the permission and mode bits for the FileHeader.
-func (h *FileHeader) Mode() (mode os.FileMode) {
- switch h.CreatorVersion >> 8 {
- case creatorUnix, creatorMacOSX:
- mode = unixModeToFileMode(h.ExternalAttrs >> 16)
- case creatorNTFS, creatorVFAT, creatorFAT:
- mode = msdosModeToFileMode(h.ExternalAttrs)
- }
- if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' {
- mode |= os.ModeDir
- }
- return mode
-}
-
-// SetMode changes the permission and mode bits for the FileHeader.
-func (h *FileHeader) SetMode(mode os.FileMode) {
- h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8
- h.ExternalAttrs = fileModeToUnixMode(mode) << 16
-
- // set MSDOS attributes too, as the original zip does.
- if mode&os.ModeDir != 0 {
- h.ExternalAttrs |= msdosDir
- }
- if mode&0200 == 0 {
- h.ExternalAttrs |= msdosReadOnly
- }
-}
-
-// isZip64 returns true if the file size exceeds the 32 bit limit
-func (fh *FileHeader) isZip64() bool {
- return fh.CompressedSize64 > uint32max || fh.UncompressedSize64 > uint32max
-}
-
-func msdosModeToFileMode(m uint32) (mode os.FileMode) {
- if m&msdosDir != 0 {
- mode = os.ModeDir | 0777
- } else {
- mode = 0666
- }
- if m&msdosReadOnly != 0 {
- mode &^= 0222
- }
- return mode
-}
-
-func fileModeToUnixMode(mode os.FileMode) uint32 {
- var m uint32
- switch mode & os.ModeType {
- default:
- m = s_IFREG
- case os.ModeDir:
- m = s_IFDIR
- case os.ModeSymlink:
- m = s_IFLNK
- case os.ModeNamedPipe:
- m = s_IFIFO
- case os.ModeSocket:
- m = s_IFSOCK
- case os.ModeDevice:
- if mode&os.ModeCharDevice != 0 {
- m = s_IFCHR
- } else {
- m = s_IFBLK
- }
- }
- if mode&os.ModeSetuid != 0 {
- m |= s_ISUID
- }
- if mode&os.ModeSetgid != 0 {
- m |= s_ISGID
- }
- if mode&os.ModeSticky != 0 {
- m |= s_ISVTX
- }
- return m | uint32(mode&0777)
-}
-
-func unixModeToFileMode(m uint32) os.FileMode {
- mode := os.FileMode(m & 0777)
- switch m & s_IFMT {
- case s_IFBLK:
- mode |= os.ModeDevice
- case s_IFCHR:
- mode |= os.ModeDevice | os.ModeCharDevice
- case s_IFDIR:
- mode |= os.ModeDir
- case s_IFIFO:
- mode |= os.ModeNamedPipe
- case s_IFLNK:
- mode |= os.ModeSymlink
- case s_IFREG:
- // nothing to do
- case s_IFSOCK:
- mode |= os.ModeSocket
- }
- if m&s_ISGID != 0 {
- mode |= os.ModeSetgid
- }
- if m&s_ISUID != 0 {
- mode |= os.ModeSetuid
- }
- if m&s_ISVTX != 0 {
- mode |= os.ModeSticky
- }
- return mode
-}
diff --git a/src/pkg/archive/zip/testdata/crc32-not-streamed.zip b/src/pkg/archive/zip/testdata/crc32-not-streamed.zip
deleted file mode 100644
index f268d8873..000000000
--- a/src/pkg/archive/zip/testdata/crc32-not-streamed.zip
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/dd.zip b/src/pkg/archive/zip/testdata/dd.zip
deleted file mode 100644
index e53378b0b..000000000
--- a/src/pkg/archive/zip/testdata/dd.zip
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/go-no-datadesc-sig.zip b/src/pkg/archive/zip/testdata/go-no-datadesc-sig.zip
deleted file mode 100644
index c3d593f44..000000000
--- a/src/pkg/archive/zip/testdata/go-no-datadesc-sig.zip
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/go-with-datadesc-sig.zip b/src/pkg/archive/zip/testdata/go-with-datadesc-sig.zip
deleted file mode 100644
index bcfe121bb..000000000
--- a/src/pkg/archive/zip/testdata/go-with-datadesc-sig.zip
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/gophercolor16x16.png b/src/pkg/archive/zip/testdata/gophercolor16x16.png
deleted file mode 100644
index 48854ff3b..000000000
--- a/src/pkg/archive/zip/testdata/gophercolor16x16.png
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/readme.notzip b/src/pkg/archive/zip/testdata/readme.notzip
deleted file mode 100644
index 06668c4c1..000000000
--- a/src/pkg/archive/zip/testdata/readme.notzip
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/readme.zip b/src/pkg/archive/zip/testdata/readme.zip
deleted file mode 100644
index db3bb900e..000000000
--- a/src/pkg/archive/zip/testdata/readme.zip
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/symlink.zip b/src/pkg/archive/zip/testdata/symlink.zip
deleted file mode 100644
index af846938c..000000000
--- a/src/pkg/archive/zip/testdata/symlink.zip
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/test-trailing-junk.zip b/src/pkg/archive/zip/testdata/test-trailing-junk.zip
deleted file mode 100644
index 42281b4e3..000000000
--- a/src/pkg/archive/zip/testdata/test-trailing-junk.zip
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/test.zip b/src/pkg/archive/zip/testdata/test.zip
deleted file mode 100644
index 03890c05d..000000000
--- a/src/pkg/archive/zip/testdata/test.zip
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/unix.zip b/src/pkg/archive/zip/testdata/unix.zip
deleted file mode 100644
index ce1a981b2..000000000
--- a/src/pkg/archive/zip/testdata/unix.zip
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/winxp.zip b/src/pkg/archive/zip/testdata/winxp.zip
deleted file mode 100644
index 3919322f0..000000000
--- a/src/pkg/archive/zip/testdata/winxp.zip
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/zip64-2.zip b/src/pkg/archive/zip/testdata/zip64-2.zip
deleted file mode 100644
index f844e3537..000000000
--- a/src/pkg/archive/zip/testdata/zip64-2.zip
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/zip64.zip b/src/pkg/archive/zip/testdata/zip64.zip
deleted file mode 100644
index a2ee1fa33..000000000
--- a/src/pkg/archive/zip/testdata/zip64.zip
+++ /dev/null
Binary files differ
diff --git a/src/pkg/archive/zip/writer.go b/src/pkg/archive/zip/writer.go
deleted file mode 100644
index 6c9800a78..000000000
--- a/src/pkg/archive/zip/writer.go
+++ /dev/null
@@ -1,351 +0,0 @@
-// Copyright 2011 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 (
- "bufio"
- "encoding/binary"
- "errors"
- "hash"
- "hash/crc32"
- "io"
-)
-
-// TODO(adg): support zip file comments
-// TODO(adg): support specifying deflate level
-
-// Writer implements a zip file writer.
-type Writer struct {
- cw *countWriter
- dir []*header
- last *fileWriter
- closed bool
-}
-
-type header struct {
- *FileHeader
- offset uint64
-}
-
-// NewWriter returns a new Writer writing a zip file to w.
-func NewWriter(w io.Writer) *Writer {
- return &Writer{cw: &countWriter{w: bufio.NewWriter(w)}}
-}
-
-// Close finishes writing the zip file by writing the central directory.
-// It does not (and can not) close the underlying writer.
-func (w *Writer) Close() error {
- if w.last != nil && !w.last.closed {
- if err := w.last.close(); err != nil {
- return err
- }
- w.last = nil
- }
- if w.closed {
- return errors.New("zip: writer closed twice")
- }
- w.closed = true
-
- // write central directory
- start := w.cw.count
- for _, h := range w.dir {
- var buf [directoryHeaderLen]byte
- b := writeBuf(buf[:])
- b.uint32(uint32(directoryHeaderSignature))
- b.uint16(h.CreatorVersion)
- b.uint16(h.ReaderVersion)
- b.uint16(h.Flags)
- b.uint16(h.Method)
- b.uint16(h.ModifiedTime)
- b.uint16(h.ModifiedDate)
- b.uint32(h.CRC32)
- if h.isZip64() || h.offset > uint32max {
- // the file needs a zip64 header. store maxint in both
- // 32 bit size fields (and offset later) to signal that the
- // zip64 extra header should be used.
- b.uint32(uint32max) // compressed size
- b.uint32(uint32max) // uncompressed size
-
- // append a zip64 extra block to Extra
- var buf [28]byte // 2x uint16 + 3x uint64
- eb := writeBuf(buf[:])
- eb.uint16(zip64ExtraId)
- eb.uint16(24) // size = 3x uint64
- eb.uint64(h.UncompressedSize64)
- eb.uint64(h.CompressedSize64)
- eb.uint64(h.offset)
- h.Extra = append(h.Extra, buf[:]...)
- } else {
- b.uint32(h.CompressedSize)
- b.uint32(h.UncompressedSize)
- }
- b.uint16(uint16(len(h.Name)))
- b.uint16(uint16(len(h.Extra)))
- b.uint16(uint16(len(h.Comment)))
- b = b[4:] // skip disk number start and internal file attr (2x uint16)
- b.uint32(h.ExternalAttrs)
- if h.offset > uint32max {
- b.uint32(uint32max)
- } else {
- b.uint32(uint32(h.offset))
- }
- if _, err := w.cw.Write(buf[:]); err != nil {
- return err
- }
- if _, err := io.WriteString(w.cw, h.Name); err != nil {
- return err
- }
- if _, err := w.cw.Write(h.Extra); err != nil {
- return err
- }
- if _, err := io.WriteString(w.cw, h.Comment); err != nil {
- return err
- }
- }
- end := w.cw.count
-
- records := uint64(len(w.dir))
- size := uint64(end - start)
- offset := uint64(start)
-
- if records > uint16max || size > uint32max || offset > uint32max {
- var buf [directory64EndLen + directory64LocLen]byte
- b := writeBuf(buf[:])
-
- // zip64 end of central directory record
- b.uint32(directory64EndSignature)
- b.uint64(directory64EndLen)
- b.uint16(zipVersion45) // version made by
- b.uint16(zipVersion45) // version needed to extract
- b.uint32(0) // number of this disk
- b.uint32(0) // number of the disk with the start of the central directory
- b.uint64(records) // total number of entries in the central directory on this disk
- b.uint64(records) // total number of entries in the central directory
- b.uint64(size) // size of the central directory
- b.uint64(offset) // offset of start of central directory with respect to the starting disk number
-
- // zip64 end of central directory locator
- b.uint32(directory64LocSignature)
- b.uint32(0) // number of the disk with the start of the zip64 end of central directory
- b.uint64(uint64(end)) // relative offset of the zip64 end of central directory record
- b.uint32(1) // total number of disks
-
- if _, err := w.cw.Write(buf[:]); err != nil {
- return err
- }
-
- // store max values in the regular end record to signal that
- // that the zip64 values should be used instead
- records = uint16max
- size = uint32max
- offset = uint32max
- }
-
- // write end record
- var buf [directoryEndLen]byte
- b := writeBuf(buf[:])
- b.uint32(uint32(directoryEndSignature))
- b = b[4:] // skip over disk number and first disk number (2x uint16)
- b.uint16(uint16(records)) // number of entries this disk
- b.uint16(uint16(records)) // number of entries total
- b.uint32(uint32(size)) // size of directory
- b.uint32(uint32(offset)) // start of directory
- // skipped size of comment (always zero)
- if _, err := w.cw.Write(buf[:]); err != nil {
- return err
- }
-
- return w.cw.w.(*bufio.Writer).Flush()
-}
-
-// Create adds a file to the zip file using the provided name.
-// It returns a Writer to which the file contents should be written.
-// The name must be a relative path: it must not start with a drive
-// letter (e.g. C:) or leading slash, and only forward slashes are
-// allowed.
-// The file's contents must be written to the io.Writer before the next
-// call to Create, CreateHeader, or Close.
-func (w *Writer) Create(name string) (io.Writer, error) {
- header := &FileHeader{
- Name: name,
- Method: Deflate,
- }
- return w.CreateHeader(header)
-}
-
-// CreateHeader adds a file to the zip file using the provided FileHeader
-// 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.
-func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
- if w.last != nil && !w.last.closed {
- if err := w.last.close(); err != nil {
- return nil, err
- }
- }
-
- fh.Flags |= 0x8 // we will write a data descriptor
-
- fh.CreatorVersion = fh.CreatorVersion&0xff00 | zipVersion20 // preserve compatibility byte
- fh.ReaderVersion = zipVersion20
-
- fw := &fileWriter{
- zipw: w.cw,
- compCount: &countWriter{w: w.cw},
- crc32: crc32.NewIEEE(),
- }
- comp := compressor(fh.Method)
- if comp == nil {
- return nil, ErrAlgorithm
- }
- var err error
- fw.comp, err = comp(fw.compCount)
- if err != nil {
- return nil, err
- }
- fw.rawCount = &countWriter{w: fw.comp}
-
- h := &header{
- FileHeader: fh,
- offset: uint64(w.cw.count),
- }
- w.dir = append(w.dir, h)
- fw.header = h
-
- if err := writeHeader(w.cw, fh); err != nil {
- return nil, err
- }
-
- w.last = fw
- return fw, nil
-}
-
-func writeHeader(w io.Writer, h *FileHeader) error {
- var buf [fileHeaderLen]byte
- b := writeBuf(buf[:])
- b.uint32(uint32(fileHeaderSignature))
- b.uint16(h.ReaderVersion)
- b.uint16(h.Flags)
- b.uint16(h.Method)
- b.uint16(h.ModifiedTime)
- b.uint16(h.ModifiedDate)
- b.uint32(0) // since we are writing a data descriptor crc32,
- b.uint32(0) // compressed size,
- b.uint32(0) // and uncompressed size should be zero
- b.uint16(uint16(len(h.Name)))
- b.uint16(uint16(len(h.Extra)))
- if _, err := w.Write(buf[:]); err != nil {
- return err
- }
- if _, err := io.WriteString(w, h.Name); err != nil {
- return err
- }
- _, err := w.Write(h.Extra)
- return err
-}
-
-type fileWriter struct {
- *header
- zipw io.Writer
- rawCount *countWriter
- comp io.WriteCloser
- compCount *countWriter
- crc32 hash.Hash32
- closed bool
-}
-
-func (w *fileWriter) Write(p []byte) (int, error) {
- if w.closed {
- return 0, errors.New("zip: write to closed file")
- }
- w.crc32.Write(p)
- return w.rawCount.Write(p)
-}
-
-func (w *fileWriter) close() error {
- if w.closed {
- return errors.New("zip: file closed twice")
- }
- w.closed = true
- if err := w.comp.Close(); err != nil {
- return err
- }
-
- // update FileHeader
- fh := w.header.FileHeader
- fh.CRC32 = w.crc32.Sum32()
- fh.CompressedSize64 = uint64(w.compCount.count)
- fh.UncompressedSize64 = uint64(w.rawCount.count)
-
- if fh.isZip64() {
- fh.CompressedSize = uint32max
- fh.UncompressedSize = uint32max
- fh.ReaderVersion = zipVersion45 // requires 4.5 - File uses ZIP64 format extensions
- } else {
- fh.CompressedSize = uint32(fh.CompressedSize64)
- fh.UncompressedSize = uint32(fh.UncompressedSize64)
- }
-
- // Write data descriptor. This is more complicated than one would
- // think, see e.g. comments in zipfile.c:putextended() and
- // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7073588.
- // The approach here is to write 8 byte sizes if needed without
- // adding a zip64 extra in the local header (too late anyway).
- var buf []byte
- if fh.isZip64() {
- buf = make([]byte, dataDescriptor64Len)
- } else {
- buf = make([]byte, dataDescriptorLen)
- }
- b := writeBuf(buf)
- b.uint32(dataDescriptorSignature) // de-facto standard, required by OS X
- b.uint32(fh.CRC32)
- if fh.isZip64() {
- b.uint64(fh.CompressedSize64)
- b.uint64(fh.UncompressedSize64)
- } else {
- b.uint32(fh.CompressedSize)
- b.uint32(fh.UncompressedSize)
- }
- _, err := w.zipw.Write(buf)
- return err
-}
-
-type countWriter struct {
- w io.Writer
- count int64
-}
-
-func (w *countWriter) Write(p []byte) (int, error) {
- n, err := w.w.Write(p)
- w.count += int64(n)
- return n, err
-}
-
-type nopCloser struct {
- io.Writer
-}
-
-func (w nopCloser) Close() error {
- return nil
-}
-
-type writeBuf []byte
-
-func (b *writeBuf) uint16(v uint16) {
- binary.LittleEndian.PutUint16(*b, v)
- *b = (*b)[2:]
-}
-
-func (b *writeBuf) uint32(v uint32) {
- binary.LittleEndian.PutUint32(*b, v)
- *b = (*b)[4:]
-}
-
-func (b *writeBuf) uint64(v uint64) {
- binary.LittleEndian.PutUint64(*b, v)
- *b = (*b)[8:]
-}
diff --git a/src/pkg/archive/zip/writer_test.go b/src/pkg/archive/zip/writer_test.go
deleted file mode 100644
index 4bfa87080..000000000
--- a/src/pkg/archive/zip/writer_test.go
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2011 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"
- "io/ioutil"
- "math/rand"
- "os"
- "testing"
-)
-
-// TODO(adg): a more sophisticated test suite
-
-type WriteTest struct {
- Name string
- Data []byte
- Method uint16
- Mode os.FileMode
-}
-
-var writeTests = []WriteTest{
- {
- Name: "foo",
- Data: []byte("Rabbits, guinea pigs, gophers, marsupial rats, and quolls."),
- Method: Store,
- Mode: 0666,
- },
- {
- Name: "bar",
- Data: nil, // large data set in the test
- Method: Deflate,
- Mode: 0644,
- },
- {
- Name: "setuid",
- Data: []byte("setuid file"),
- Method: Deflate,
- Mode: 0755 | os.ModeSetuid,
- },
- {
- Name: "setgid",
- Data: []byte("setgid file"),
- Method: Deflate,
- Mode: 0755 | os.ModeSetgid,
- },
- {
- Name: "symlink",
- Data: []byte("../link/target"),
- Method: Deflate,
- Mode: 0755 | os.ModeSymlink,
- },
-}
-
-func TestWriter(t *testing.T) {
- largeData := make([]byte, 1<<17)
- for i := range largeData {
- largeData[i] = byte(rand.Int())
- }
- writeTests[1].Data = largeData
- defer func() {
- writeTests[1].Data = nil
- }()
-
- // write a zip file
- buf := new(bytes.Buffer)
- w := NewWriter(buf)
-
- for _, wt := range writeTests {
- testCreate(t, w, &wt)
- }
-
- if err := w.Close(); err != nil {
- t.Fatal(err)
- }
-
- // read it back
- r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
- if err != nil {
- t.Fatal(err)
- }
- for i, wt := range writeTests {
- testReadFile(t, r.File[i], &wt)
- }
-}
-
-func testCreate(t *testing.T, w *Writer, wt *WriteTest) {
- header := &FileHeader{
- Name: wt.Name,
- Method: wt.Method,
- }
- if wt.Mode != 0 {
- header.SetMode(wt.Mode)
- }
- f, err := w.CreateHeader(header)
- if err != nil {
- t.Fatal(err)
- }
- _, err = f.Write(wt.Data)
- if err != nil {
- t.Fatal(err)
- }
-}
-
-func testReadFile(t *testing.T, f *File, wt *WriteTest) {
- if f.Name != wt.Name {
- t.Fatalf("File name: got %q, want %q", f.Name, wt.Name)
- }
- testFileMode(t, wt.Name, f, wt.Mode)
- rc, err := f.Open()
- if err != nil {
- t.Fatal("opening:", err)
- }
- b, err := ioutil.ReadAll(rc)
- if err != nil {
- t.Fatal("reading:", err)
- }
- err = rc.Close()
- if err != nil {
- t.Fatal("closing:", err)
- }
- if !bytes.Equal(b, wt.Data) {
- t.Errorf("File contents %q, want %q", b, wt.Data)
- }
-}
-
-func BenchmarkCompressedZipGarbage(b *testing.B) {
- b.ReportAllocs()
- var buf bytes.Buffer
- bigBuf := bytes.Repeat([]byte("a"), 1<<20)
- for i := 0; i < b.N; i++ {
- buf.Reset()
- zw := NewWriter(&buf)
- for j := 0; j < 3; j++ {
- w, _ := zw.CreateHeader(&FileHeader{
- Name: "foo",
- Method: Deflate,
- })
- w.Write(bigBuf)
- }
- zw.Close()
- }
-}
diff --git a/src/pkg/archive/zip/zip_test.go b/src/pkg/archive/zip/zip_test.go
deleted file mode 100644
index 32a16a79e..000000000
--- a/src/pkg/archive/zip/zip_test.go
+++ /dev/null
@@ -1,395 +0,0 @@
-// Copyright 2011 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.
-
-// Tests that involve both reading and writing.
-
-package zip
-
-import (
- "bytes"
- "fmt"
- "hash"
- "io"
- "io/ioutil"
- "sort"
- "strings"
- "testing"
- "time"
-)
-
-func TestOver65kFiles(t *testing.T) {
- buf := new(bytes.Buffer)
- w := NewWriter(buf)
- const nFiles = (1 << 16) + 42
- for i := 0; i < nFiles; i++ {
- _, err := w.CreateHeader(&FileHeader{
- Name: fmt.Sprintf("%d.dat", i),
- Method: Store, // avoid Issue 6136 and Issue 6138
- })
- if err != nil {
- t.Fatalf("creating file %d: %v", i, err)
- }
- }
- if err := w.Close(); err != nil {
- t.Fatalf("Writer.Close: %v", err)
- }
- s := buf.String()
- zr, err := NewReader(strings.NewReader(s), int64(len(s)))
- if err != nil {
- t.Fatalf("NewReader: %v", err)
- }
- if got := len(zr.File); got != nFiles {
- t.Fatalf("File contains %d files, want %d", got, nFiles)
- }
- for i := 0; i < nFiles; i++ {
- want := fmt.Sprintf("%d.dat", i)
- if zr.File[i].Name != want {
- t.Fatalf("File(%d) = %q, want %q", i, zr.File[i].Name, want)
- }
- }
-}
-
-func TestModTime(t *testing.T) {
- var testTime = time.Date(2009, time.November, 10, 23, 45, 58, 0, time.UTC)
- fh := new(FileHeader)
- fh.SetModTime(testTime)
- outTime := fh.ModTime()
- if !outTime.Equal(testTime) {
- t.Errorf("times don't match: got %s, want %s", outTime, testTime)
- }
-}
-
-func testHeaderRoundTrip(fh *FileHeader, wantUncompressedSize uint32, wantUncompressedSize64 uint64, t *testing.T) {
- fi := fh.FileInfo()
- fh2, err := FileInfoHeader(fi)
- if err != nil {
- t.Fatal(err)
- }
- if got, want := fh2.Name, fh.Name; got != want {
- t.Errorf("Name: got %s, want %s\n", got, want)
- }
- if got, want := fh2.UncompressedSize, wantUncompressedSize; got != want {
- t.Errorf("UncompressedSize: got %d, want %d\n", got, want)
- }
- if got, want := fh2.UncompressedSize64, wantUncompressedSize64; got != want {
- t.Errorf("UncompressedSize64: got %d, want %d\n", got, want)
- }
- if got, want := fh2.ModifiedTime, fh.ModifiedTime; got != want {
- t.Errorf("ModifiedTime: got %d, want %d\n", got, want)
- }
- if got, want := fh2.ModifiedDate, fh.ModifiedDate; got != want {
- t.Errorf("ModifiedDate: got %d, want %d\n", got, want)
- }
-
- if sysfh, ok := fi.Sys().(*FileHeader); !ok && sysfh != fh {
- t.Errorf("Sys didn't return original *FileHeader")
- }
-}
-
-func TestFileHeaderRoundTrip(t *testing.T) {
- fh := &FileHeader{
- Name: "foo.txt",
- UncompressedSize: 987654321,
- ModifiedTime: 1234,
- ModifiedDate: 5678,
- }
- testHeaderRoundTrip(fh, fh.UncompressedSize, uint64(fh.UncompressedSize), t)
-}
-
-func TestFileHeaderRoundTrip64(t *testing.T) {
- fh := &FileHeader{
- Name: "foo.txt",
- UncompressedSize64: 9876543210,
- ModifiedTime: 1234,
- ModifiedDate: 5678,
- }
- testHeaderRoundTrip(fh, uint32max, fh.UncompressedSize64, t)
-}
-
-type repeatedByte struct {
- off int64
- b byte
- n int64
-}
-
-// rleBuffer is a run-length-encoded byte buffer.
-// It's an io.Writer (like a bytes.Buffer) and also an io.ReaderAt,
-// allowing random-access reads.
-type rleBuffer struct {
- buf []repeatedByte
-}
-
-func (r *rleBuffer) Size() int64 {
- if len(r.buf) == 0 {
- return 0
- }
- last := &r.buf[len(r.buf)-1]
- return last.off + last.n
-}
-
-func (r *rleBuffer) Write(p []byte) (n int, err error) {
- var rp *repeatedByte
- if len(r.buf) > 0 {
- rp = &r.buf[len(r.buf)-1]
- // Fast path, if p is entirely the same byte repeated.
- if lastByte := rp.b; len(p) > 0 && p[0] == lastByte {
- all := true
- for _, b := range p {
- if b != lastByte {
- all = false
- break
- }
- }
- if all {
- rp.n += int64(len(p))
- return len(p), nil
- }
- }
- }
-
- for _, b := range p {
- if rp == nil || rp.b != b {
- r.buf = append(r.buf, repeatedByte{r.Size(), b, 1})
- rp = &r.buf[len(r.buf)-1]
- } else {
- rp.n++
- }
- }
- return len(p), nil
-}
-
-func (r *rleBuffer) ReadAt(p []byte, off int64) (n int, err error) {
- if len(p) == 0 {
- return
- }
- skipParts := sort.Search(len(r.buf), func(i int) bool {
- part := &r.buf[i]
- return part.off+part.n > off
- })
- parts := r.buf[skipParts:]
- if len(parts) > 0 {
- skipBytes := off - parts[0].off
- for len(parts) > 0 {
- part := parts[0]
- for i := skipBytes; i < part.n; i++ {
- if n == len(p) {
- return
- }
- p[n] = part.b
- n++
- }
- parts = parts[1:]
- skipBytes = 0
- }
- }
- if n != len(p) {
- err = io.ErrUnexpectedEOF
- }
- return
-}
-
-// Just testing the rleBuffer used in the Zip64 test above. Not used by the zip code.
-func TestRLEBuffer(t *testing.T) {
- b := new(rleBuffer)
- var all []byte
- writes := []string{"abcdeee", "eeeeeee", "eeeefghaaiii"}
- for _, w := range writes {
- b.Write([]byte(w))
- all = append(all, w...)
- }
- if len(b.buf) != 10 {
- t.Fatalf("len(b.buf) = %d; want 10", len(b.buf))
- }
-
- for i := 0; i < len(all); i++ {
- for j := 0; j < len(all)-i; j++ {
- buf := make([]byte, j)
- n, err := b.ReadAt(buf, int64(i))
- if err != nil || n != len(buf) {
- t.Errorf("ReadAt(%d, %d) = %d, %v; want %d, nil", i, j, n, err, len(buf))
- }
- if !bytes.Equal(buf, all[i:i+j]) {
- t.Errorf("ReadAt(%d, %d) = %q; want %q", i, j, buf, all[i:i+j])
- }
- }
- }
-}
-
-// fakeHash32 is a dummy Hash32 that always returns 0.
-type fakeHash32 struct {
- hash.Hash32
-}
-
-func (fakeHash32) Write(p []byte) (int, error) { return len(p), nil }
-func (fakeHash32) Sum32() uint32 { return 0 }
-
-func TestZip64(t *testing.T) {
- if testing.Short() {
- t.Skip("slow test; skipping")
- }
- const size = 1 << 32 // before the "END\n" part
- testZip64(t, size)
-}
-
-func testZip64(t testing.TB, size int64) {
- const chunkSize = 1024
- chunks := int(size / chunkSize)
- // write 2^32 bytes plus "END\n" to a zip file
- buf := new(rleBuffer)
- w := NewWriter(buf)
- f, err := w.CreateHeader(&FileHeader{
- Name: "huge.txt",
- Method: Store,
- })
- if err != nil {
- t.Fatal(err)
- }
- f.(*fileWriter).crc32 = fakeHash32{}
- chunk := make([]byte, chunkSize)
- for i := range chunk {
- chunk[i] = '.'
- }
- for i := 0; i < chunks; i++ {
- _, err := f.Write(chunk)
- if err != nil {
- t.Fatal("write chunk:", err)
- }
- }
- end := []byte("END\n")
- _, err = f.Write(end)
- if err != nil {
- t.Fatal("write end:", err)
- }
- if err := w.Close(); err != nil {
- t.Fatal(err)
- }
-
- // read back zip file and check that we get to the end of it
- r, err := NewReader(buf, int64(buf.Size()))
- if err != nil {
- t.Fatal("reader:", err)
- }
- f0 := r.File[0]
- rc, err := f0.Open()
- if err != nil {
- t.Fatal("opening:", err)
- }
- rc.(*checksumReader).hash = fakeHash32{}
- for i := 0; i < chunks; i++ {
- _, err := io.ReadFull(rc, chunk)
- if err != nil {
- t.Fatal("read:", err)
- }
- }
- gotEnd, err := ioutil.ReadAll(rc)
- if err != nil {
- t.Fatal("read end:", err)
- }
- if !bytes.Equal(gotEnd, end) {
- t.Errorf("End of zip64 archive %q, want %q", gotEnd, end)
- }
- err = rc.Close()
- if err != nil {
- t.Fatal("closing:", err)
- }
- if size == 1<<32 {
- if got, want := f0.UncompressedSize, uint32(uint32max); got != want {
- t.Errorf("UncompressedSize %d, want %d", got, want)
- }
- }
-
- if got, want := f0.UncompressedSize64, uint64(size)+uint64(len(end)); got != want {
- 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)
-}
-
-// Just benchmarking how fast the Zip64 test above is. Not related to
-// our zip performance, since the test above disabled CRC32 and flate.
-func BenchmarkZip64Test(b *testing.B) {
- for i := 0; i < b.N; i++ {
- testZip64(b, 1<<26)
- }
-}