Browse code

Remove patched "archive/tar" package

This fix is now upstream in Go 1.10

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2017/12/09 05:14:31
Showing 10 changed files
... ...
@@ -41,7 +41,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
41 41
 # IMPORTANT: If the version of Go is updated, the Windows to Linux CI machines
42 42
 #            will need updating, to avoid errors. Ping #docker-maintainers on IRC
43 43
 #            with a heads-up.
44
-# IMPORTANT: When updating this please note that stdlib archive/tar pkg is vendored
45 44
 ENV GO_VERSION 1.10.1
46 45
 RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" \
47 46
 	| tar -xzC /usr/local
... ...
@@ -150,11 +150,3 @@ github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.
150 150
 github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18
151 151
 
152 152
 github.com/opencontainers/selinux b29023b86e4a69d1b46b7e7b4e2b6fda03f0b9cd
153
-
154
-# archive/tar
155
-# mkdir -p ./vendor/archive
156
-# git clone git://github.com/tonistiigi/go-1.git ./go
157
-# git --git-dir ./go/.git --work-tree ./go checkout revert-prefix-ignore-1.9
158
-# cp -a go/src/archive/tar ./vendor/archive/tar
159
-# rm -rf ./go
160
-# vndr
161 153
deleted file mode 100644
... ...
@@ -1,284 +0,0 @@
1
-// Copyright 2009 The Go Authors. All rights reserved.
2
-// Use of this source code is governed by a BSD-style
3
-// license that can be found in the LICENSE file.
4
-
5
-// Package tar implements access to tar archives.
6
-// It aims to cover most of the variations, including those produced
7
-// by GNU and BSD tars.
8
-//
9
-// References:
10
-//   http://www.freebsd.org/cgi/man.cgi?query=tar&sektion=5
11
-//   http://www.gnu.org/software/tar/manual/html_node/Standard.html
12
-//   http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html
13
-package tar
14
-
15
-import (
16
-	"errors"
17
-	"fmt"
18
-	"os"
19
-	"path"
20
-	"time"
21
-)
22
-
23
-// BUG: Use of the Uid and Gid fields in Header could overflow on 32-bit
24
-// architectures. If a large value is encountered when decoding, the result
25
-// stored in Header will be the truncated version.
26
-
27
-// Header type flags.
28
-const (
29
-	TypeReg           = '0'    // regular file
30
-	TypeRegA          = '\x00' // regular file
31
-	TypeLink          = '1'    // hard link
32
-	TypeSymlink       = '2'    // symbolic link
33
-	TypeChar          = '3'    // character device node
34
-	TypeBlock         = '4'    // block device node
35
-	TypeDir           = '5'    // directory
36
-	TypeFifo          = '6'    // fifo node
37
-	TypeCont          = '7'    // reserved
38
-	TypeXHeader       = 'x'    // extended header
39
-	TypeXGlobalHeader = 'g'    // global extended header
40
-	TypeGNULongName   = 'L'    // Next file has a long name
41
-	TypeGNULongLink   = 'K'    // Next file symlinks to a file w/ a long name
42
-	TypeGNUSparse     = 'S'    // sparse file
43
-)
44
-
45
-// A Header represents a single header in a tar archive.
46
-// Some fields may not be populated.
47
-type Header struct {
48
-	Name       string    // name of header file entry
49
-	Mode       int64     // permission and mode bits
50
-	Uid        int       // user id of owner
51
-	Gid        int       // group id of owner
52
-	Size       int64     // length in bytes
53
-	ModTime    time.Time // modified time
54
-	Typeflag   byte      // type of header entry
55
-	Linkname   string    // target name of link
56
-	Uname      string    // user name of owner
57
-	Gname      string    // group name of owner
58
-	Devmajor   int64     // major number of character or block device
59
-	Devminor   int64     // minor number of character or block device
60
-	AccessTime time.Time // access time
61
-	ChangeTime time.Time // status change time
62
-	Xattrs     map[string]string
63
-}
64
-
65
-// FileInfo returns an os.FileInfo for the Header.
66
-func (h *Header) FileInfo() os.FileInfo {
67
-	return headerFileInfo{h}
68
-}
69
-
70
-// headerFileInfo implements os.FileInfo.
71
-type headerFileInfo struct {
72
-	h *Header
73
-}
74
-
75
-func (fi headerFileInfo) Size() int64        { return fi.h.Size }
76
-func (fi headerFileInfo) IsDir() bool        { return fi.Mode().IsDir() }
77
-func (fi headerFileInfo) ModTime() time.Time { return fi.h.ModTime }
78
-func (fi headerFileInfo) Sys() interface{}   { return fi.h }
79
-
80
-// Name returns the base name of the file.
81
-func (fi headerFileInfo) Name() string {
82
-	if fi.IsDir() {
83
-		return path.Base(path.Clean(fi.h.Name))
84
-	}
85
-	return path.Base(fi.h.Name)
86
-}
87
-
88
-// Mode returns the permission and mode bits for the headerFileInfo.
89
-func (fi headerFileInfo) Mode() (mode os.FileMode) {
90
-	// Set file permission bits.
91
-	mode = os.FileMode(fi.h.Mode).Perm()
92
-
93
-	// Set setuid, setgid and sticky bits.
94
-	if fi.h.Mode&c_ISUID != 0 {
95
-		// setuid
96
-		mode |= os.ModeSetuid
97
-	}
98
-	if fi.h.Mode&c_ISGID != 0 {
99
-		// setgid
100
-		mode |= os.ModeSetgid
101
-	}
102
-	if fi.h.Mode&c_ISVTX != 0 {
103
-		// sticky
104
-		mode |= os.ModeSticky
105
-	}
106
-
107
-	// Set file mode bits.
108
-	// clear perm, setuid, setgid and sticky bits.
109
-	m := os.FileMode(fi.h.Mode) &^ 07777
110
-	if m == c_ISDIR {
111
-		// directory
112
-		mode |= os.ModeDir
113
-	}
114
-	if m == c_ISFIFO {
115
-		// named pipe (FIFO)
116
-		mode |= os.ModeNamedPipe
117
-	}
118
-	if m == c_ISLNK {
119
-		// symbolic link
120
-		mode |= os.ModeSymlink
121
-	}
122
-	if m == c_ISBLK {
123
-		// device file
124
-		mode |= os.ModeDevice
125
-	}
126
-	if m == c_ISCHR {
127
-		// Unix character device
128
-		mode |= os.ModeDevice
129
-		mode |= os.ModeCharDevice
130
-	}
131
-	if m == c_ISSOCK {
132
-		// Unix domain socket
133
-		mode |= os.ModeSocket
134
-	}
135
-
136
-	switch fi.h.Typeflag {
137
-	case TypeSymlink:
138
-		// symbolic link
139
-		mode |= os.ModeSymlink
140
-	case TypeChar:
141
-		// character device node
142
-		mode |= os.ModeDevice
143
-		mode |= os.ModeCharDevice
144
-	case TypeBlock:
145
-		// block device node
146
-		mode |= os.ModeDevice
147
-	case TypeDir:
148
-		// directory
149
-		mode |= os.ModeDir
150
-	case TypeFifo:
151
-		// fifo node
152
-		mode |= os.ModeNamedPipe
153
-	}
154
-
155
-	return mode
156
-}
157
-
158
-// sysStat, if non-nil, populates h from system-dependent fields of fi.
159
-var sysStat func(fi os.FileInfo, h *Header) error
160
-
161
-const (
162
-	// Mode constants from the USTAR spec:
163
-	// See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_06
164
-	c_ISUID = 04000 // Set uid
165
-	c_ISGID = 02000 // Set gid
166
-	c_ISVTX = 01000 // Save text (sticky bit)
167
-
168
-	// Common Unix mode constants; these are not defined in any common tar standard.
169
-	// Header.FileInfo understands these, but FileInfoHeader will never produce these.
170
-	c_ISDIR  = 040000  // Directory
171
-	c_ISFIFO = 010000  // FIFO
172
-	c_ISREG  = 0100000 // Regular file
173
-	c_ISLNK  = 0120000 // Symbolic link
174
-	c_ISBLK  = 060000  // Block special file
175
-	c_ISCHR  = 020000  // Character special file
176
-	c_ISSOCK = 0140000 // Socket
177
-)
178
-
179
-// Keywords for the PAX Extended Header
180
-const (
181
-	paxAtime    = "atime"
182
-	paxCharset  = "charset"
183
-	paxComment  = "comment"
184
-	paxCtime    = "ctime" // please note that ctime is not a valid pax header.
185
-	paxGid      = "gid"
186
-	paxGname    = "gname"
187
-	paxLinkpath = "linkpath"
188
-	paxMtime    = "mtime"
189
-	paxPath     = "path"
190
-	paxSize     = "size"
191
-	paxUid      = "uid"
192
-	paxUname    = "uname"
193
-	paxXattr    = "SCHILY.xattr."
194
-	paxNone     = ""
195
-)
196
-
197
-// FileInfoHeader creates a partially-populated Header from fi.
198
-// If fi describes a symlink, FileInfoHeader records link as the link target.
199
-// If fi describes a directory, a slash is appended to the name.
200
-// Because os.FileInfo's Name method returns only the base name of
201
-// the file it describes, it may be necessary to modify the Name field
202
-// of the returned header to provide the full path name of the file.
203
-func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
204
-	if fi == nil {
205
-		return nil, errors.New("tar: FileInfo is nil")
206
-	}
207
-	fm := fi.Mode()
208
-	h := &Header{
209
-		Name:    fi.Name(),
210
-		ModTime: fi.ModTime(),
211
-		Mode:    int64(fm.Perm()), // or'd with c_IS* constants later
212
-	}
213
-	switch {
214
-	case fm.IsRegular():
215
-		h.Typeflag = TypeReg
216
-		h.Size = fi.Size()
217
-	case fi.IsDir():
218
-		h.Typeflag = TypeDir
219
-		h.Name += "/"
220
-	case fm&os.ModeSymlink != 0:
221
-		h.Typeflag = TypeSymlink
222
-		h.Linkname = link
223
-	case fm&os.ModeDevice != 0:
224
-		if fm&os.ModeCharDevice != 0 {
225
-			h.Typeflag = TypeChar
226
-		} else {
227
-			h.Typeflag = TypeBlock
228
-		}
229
-	case fm&os.ModeNamedPipe != 0:
230
-		h.Typeflag = TypeFifo
231
-	case fm&os.ModeSocket != 0:
232
-		return nil, fmt.Errorf("archive/tar: sockets not supported")
233
-	default:
234
-		return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm)
235
-	}
236
-	if fm&os.ModeSetuid != 0 {
237
-		h.Mode |= c_ISUID
238
-	}
239
-	if fm&os.ModeSetgid != 0 {
240
-		h.Mode |= c_ISGID
241
-	}
242
-	if fm&os.ModeSticky != 0 {
243
-		h.Mode |= c_ISVTX
244
-	}
245
-	// If possible, populate additional fields from OS-specific
246
-	// FileInfo fields.
247
-	if sys, ok := fi.Sys().(*Header); ok {
248
-		// This FileInfo came from a Header (not the OS). Use the
249
-		// original Header to populate all remaining fields.
250
-		h.Uid = sys.Uid
251
-		h.Gid = sys.Gid
252
-		h.Uname = sys.Uname
253
-		h.Gname = sys.Gname
254
-		h.AccessTime = sys.AccessTime
255
-		h.ChangeTime = sys.ChangeTime
256
-		if sys.Xattrs != nil {
257
-			h.Xattrs = make(map[string]string)
258
-			for k, v := range sys.Xattrs {
259
-				h.Xattrs[k] = v
260
-			}
261
-		}
262
-		if sys.Typeflag == TypeLink {
263
-			// hard link
264
-			h.Typeflag = TypeLink
265
-			h.Size = 0
266
-			h.Linkname = sys.Linkname
267
-		}
268
-	}
269
-	if sysStat != nil {
270
-		return h, sysStat(fi, h)
271
-	}
272
-	return h, nil
273
-}
274
-
275
-// isHeaderOnlyType checks if the given type flag is of the type that has no
276
-// data section even if a size is specified.
277
-func isHeaderOnlyType(flag byte) bool {
278
-	switch flag {
279
-	case TypeLink, TypeSymlink, TypeChar, TypeBlock, TypeDir, TypeFifo:
280
-		return true
281
-	default:
282
-		return false
283
-	}
284
-}
285 1
deleted file mode 100644
... ...
@@ -1,197 +0,0 @@
1
-// Copyright 2016 The Go Authors. All rights reserved.
2
-// Use of this source code is governed by a BSD-style
3
-// license that can be found in the LICENSE file.
4
-
5
-package tar
6
-
7
-// Constants to identify various tar formats.
8
-const (
9
-	// The format is unknown.
10
-	formatUnknown = (1 << iota) / 2 // Sequence of 0, 1, 2, 4, 8, etc...
11
-
12
-	// The format of the original Unix V7 tar tool prior to standardization.
13
-	formatV7
14
-
15
-	// The old and new GNU formats, which are incompatible with USTAR.
16
-	// This does cover the old GNU sparse extension.
17
-	// This does not cover the GNU sparse extensions using PAX headers,
18
-	// versions 0.0, 0.1, and 1.0; these fall under the PAX format.
19
-	formatGNU
20
-
21
-	// Schily's tar format, which is incompatible with USTAR.
22
-	// This does not cover STAR extensions to the PAX format; these fall under
23
-	// the PAX format.
24
-	formatSTAR
25
-
26
-	// USTAR is the former standardization of tar defined in POSIX.1-1988.
27
-	// This is incompatible with the GNU and STAR formats.
28
-	formatUSTAR
29
-
30
-	// PAX is the latest standardization of tar defined in POSIX.1-2001.
31
-	// This is an extension of USTAR and is "backwards compatible" with it.
32
-	//
33
-	// Some newer formats add their own extensions to PAX, such as GNU sparse
34
-	// files and SCHILY extended attributes. Since they are backwards compatible
35
-	// with PAX, they will be labelled as "PAX".
36
-	formatPAX
37
-)
38
-
39
-// Magics used to identify various formats.
40
-const (
41
-	magicGNU, versionGNU     = "ustar ", " \x00"
42
-	magicUSTAR, versionUSTAR = "ustar\x00", "00"
43
-	trailerSTAR              = "tar\x00"
44
-)
45
-
46
-// Size constants from various tar specifications.
47
-const (
48
-	blockSize  = 512 // Size of each block in a tar stream
49
-	nameSize   = 100 // Max length of the name field in USTAR format
50
-	prefixSize = 155 // Max length of the prefix field in USTAR format
51
-)
52
-
53
-var zeroBlock block
54
-
55
-type block [blockSize]byte
56
-
57
-// Convert block to any number of formats.
58
-func (b *block) V7() *headerV7       { return (*headerV7)(b) }
59
-func (b *block) GNU() *headerGNU     { return (*headerGNU)(b) }
60
-func (b *block) STAR() *headerSTAR   { return (*headerSTAR)(b) }
61
-func (b *block) USTAR() *headerUSTAR { return (*headerUSTAR)(b) }
62
-func (b *block) Sparse() sparseArray { return (sparseArray)(b[:]) }
63
-
64
-// GetFormat checks that the block is a valid tar header based on the checksum.
65
-// It then attempts to guess the specific format based on magic values.
66
-// If the checksum fails, then formatUnknown is returned.
67
-func (b *block) GetFormat() (format int) {
68
-	// Verify checksum.
69
-	var p parser
70
-	value := p.parseOctal(b.V7().Chksum())
71
-	chksum1, chksum2 := b.ComputeChecksum()
72
-	if p.err != nil || (value != chksum1 && value != chksum2) {
73
-		return formatUnknown
74
-	}
75
-
76
-	// Guess the magic values.
77
-	magic := string(b.USTAR().Magic())
78
-	version := string(b.USTAR().Version())
79
-	trailer := string(b.STAR().Trailer())
80
-	switch {
81
-	case magic == magicUSTAR && trailer == trailerSTAR:
82
-		return formatSTAR
83
-	case magic == magicUSTAR:
84
-		return formatUSTAR
85
-	case magic == magicGNU && version == versionGNU:
86
-		return formatGNU
87
-	default:
88
-		return formatV7
89
-	}
90
-}
91
-
92
-// SetFormat writes the magic values necessary for specified format
93
-// and then updates the checksum accordingly.
94
-func (b *block) SetFormat(format int) {
95
-	// Set the magic values.
96
-	switch format {
97
-	case formatV7:
98
-		// Do nothing.
99
-	case formatGNU:
100
-		copy(b.GNU().Magic(), magicGNU)
101
-		copy(b.GNU().Version(), versionGNU)
102
-	case formatSTAR:
103
-		copy(b.STAR().Magic(), magicUSTAR)
104
-		copy(b.STAR().Version(), versionUSTAR)
105
-		copy(b.STAR().Trailer(), trailerSTAR)
106
-	case formatUSTAR, formatPAX:
107
-		copy(b.USTAR().Magic(), magicUSTAR)
108
-		copy(b.USTAR().Version(), versionUSTAR)
109
-	default:
110
-		panic("invalid format")
111
-	}
112
-
113
-	// Update checksum.
114
-	// This field is special in that it is terminated by a NULL then space.
115
-	var f formatter
116
-	field := b.V7().Chksum()
117
-	chksum, _ := b.ComputeChecksum() // Possible values are 256..128776
118
-	f.formatOctal(field[:7], chksum) // Never fails since 128776 < 262143
119
-	field[7] = ' '
120
-}
121
-
122
-// ComputeChecksum computes the checksum for the header block.
123
-// POSIX specifies a sum of the unsigned byte values, but the Sun tar used
124
-// signed byte values.
125
-// We compute and return both.
126
-func (b *block) ComputeChecksum() (unsigned, signed int64) {
127
-	for i, c := range b {
128
-		if 148 <= i && i < 156 {
129
-			c = ' ' // Treat the checksum field itself as all spaces.
130
-		}
131
-		unsigned += int64(uint8(c))
132
-		signed += int64(int8(c))
133
-	}
134
-	return unsigned, signed
135
-}
136
-
137
-type headerV7 [blockSize]byte
138
-
139
-func (h *headerV7) Name() []byte     { return h[000:][:100] }
140
-func (h *headerV7) Mode() []byte     { return h[100:][:8] }
141
-func (h *headerV7) UID() []byte      { return h[108:][:8] }
142
-func (h *headerV7) GID() []byte      { return h[116:][:8] }
143
-func (h *headerV7) Size() []byte     { return h[124:][:12] }
144
-func (h *headerV7) ModTime() []byte  { return h[136:][:12] }
145
-func (h *headerV7) Chksum() []byte   { return h[148:][:8] }
146
-func (h *headerV7) TypeFlag() []byte { return h[156:][:1] }
147
-func (h *headerV7) LinkName() []byte { return h[157:][:100] }
148
-
149
-type headerGNU [blockSize]byte
150
-
151
-func (h *headerGNU) V7() *headerV7       { return (*headerV7)(h) }
152
-func (h *headerGNU) Magic() []byte       { return h[257:][:6] }
153
-func (h *headerGNU) Version() []byte     { return h[263:][:2] }
154
-func (h *headerGNU) UserName() []byte    { return h[265:][:32] }
155
-func (h *headerGNU) GroupName() []byte   { return h[297:][:32] }
156
-func (h *headerGNU) DevMajor() []byte    { return h[329:][:8] }
157
-func (h *headerGNU) DevMinor() []byte    { return h[337:][:8] }
158
-func (h *headerGNU) AccessTime() []byte  { return h[345:][:12] }
159
-func (h *headerGNU) ChangeTime() []byte  { return h[357:][:12] }
160
-func (h *headerGNU) Sparse() sparseArray { return (sparseArray)(h[386:][:24*4+1]) }
161
-func (h *headerGNU) RealSize() []byte    { return h[483:][:12] }
162
-
163
-type headerSTAR [blockSize]byte
164
-
165
-func (h *headerSTAR) V7() *headerV7      { return (*headerV7)(h) }
166
-func (h *headerSTAR) Magic() []byte      { return h[257:][:6] }
167
-func (h *headerSTAR) Version() []byte    { return h[263:][:2] }
168
-func (h *headerSTAR) UserName() []byte   { return h[265:][:32] }
169
-func (h *headerSTAR) GroupName() []byte  { return h[297:][:32] }
170
-func (h *headerSTAR) DevMajor() []byte   { return h[329:][:8] }
171
-func (h *headerSTAR) DevMinor() []byte   { return h[337:][:8] }
172
-func (h *headerSTAR) Prefix() []byte     { return h[345:][:131] }
173
-func (h *headerSTAR) AccessTime() []byte { return h[476:][:12] }
174
-func (h *headerSTAR) ChangeTime() []byte { return h[488:][:12] }
175
-func (h *headerSTAR) Trailer() []byte    { return h[508:][:4] }
176
-
177
-type headerUSTAR [blockSize]byte
178
-
179
-func (h *headerUSTAR) V7() *headerV7     { return (*headerV7)(h) }
180
-func (h *headerUSTAR) Magic() []byte     { return h[257:][:6] }
181
-func (h *headerUSTAR) Version() []byte   { return h[263:][:2] }
182
-func (h *headerUSTAR) UserName() []byte  { return h[265:][:32] }
183
-func (h *headerUSTAR) GroupName() []byte { return h[297:][:32] }
184
-func (h *headerUSTAR) DevMajor() []byte  { return h[329:][:8] }
185
-func (h *headerUSTAR) DevMinor() []byte  { return h[337:][:8] }
186
-func (h *headerUSTAR) Prefix() []byte    { return h[345:][:155] }
187
-
188
-type sparseArray []byte
189
-
190
-func (s sparseArray) Entry(i int) sparseNode { return (sparseNode)(s[i*24:]) }
191
-func (s sparseArray) IsExtended() []byte     { return s[24*s.MaxEntries():][:1] }
192
-func (s sparseArray) MaxEntries() int        { return len(s) / 24 }
193
-
194
-type sparseNode []byte
195
-
196
-func (s sparseNode) Offset() []byte   { return s[00:][:12] }
197
-func (s sparseNode) NumBytes() []byte { return s[12:][:12] }
198 1
deleted file mode 100644
... ...
@@ -1,800 +0,0 @@
1
-// Copyright 2009 The Go Authors. All rights reserved.
2
-// Use of this source code is governed by a BSD-style
3
-// license that can be found in the LICENSE file.
4
-
5
-package tar
6
-
7
-// TODO(dsymonds):
8
-//   - pax extensions
9
-
10
-import (
11
-	"bytes"
12
-	"errors"
13
-	"io"
14
-	"io/ioutil"
15
-	"math"
16
-	"strconv"
17
-	"strings"
18
-	"time"
19
-)
20
-
21
-var (
22
-	ErrHeader = errors.New("archive/tar: invalid tar header")
23
-)
24
-
25
-// A Reader provides sequential access to the contents of a tar archive.
26
-// A tar archive consists of a sequence of files.
27
-// The Next method advances to the next file in the archive (including the first),
28
-// and then it can be treated as an io.Reader to access the file's data.
29
-type Reader struct {
30
-	r    io.Reader
31
-	pad  int64          // amount of padding (ignored) after current file entry
32
-	curr numBytesReader // reader for current file entry
33
-	blk  block          // buffer to use as temporary local storage
34
-
35
-	// err is a persistent error.
36
-	// It is only the responsibility of every exported method of Reader to
37
-	// ensure that this error is sticky.
38
-	err error
39
-}
40
-
41
-// A numBytesReader is an io.Reader with a numBytes method, returning the number
42
-// of bytes remaining in the underlying encoded data.
43
-type numBytesReader interface {
44
-	io.Reader
45
-	numBytes() int64
46
-}
47
-
48
-// A regFileReader is a numBytesReader for reading file data from a tar archive.
49
-type regFileReader struct {
50
-	r  io.Reader // underlying reader
51
-	nb int64     // number of unread bytes for current file entry
52
-}
53
-
54
-// A sparseFileReader is a numBytesReader for reading sparse file data from a
55
-// tar archive.
56
-type sparseFileReader struct {
57
-	rfr   numBytesReader // Reads the sparse-encoded file data
58
-	sp    []sparseEntry  // The sparse map for the file
59
-	pos   int64          // Keeps track of file position
60
-	total int64          // Total size of the file
61
-}
62
-
63
-// A sparseEntry holds a single entry in a sparse file's sparse map.
64
-//
65
-// Sparse files are represented using a series of sparseEntrys.
66
-// Despite the name, a sparseEntry represents an actual data fragment that
67
-// references data found in the underlying archive stream. All regions not
68
-// covered by a sparseEntry are logically filled with zeros.
69
-//
70
-// For example, if the underlying raw file contains the 10-byte data:
71
-//	var compactData = "abcdefgh"
72
-//
73
-// And the sparse map has the following entries:
74
-//	var sp = []sparseEntry{
75
-//		{offset: 2,  numBytes: 5} // Data fragment for [2..7]
76
-//		{offset: 18, numBytes: 3} // Data fragment for [18..21]
77
-//	}
78
-//
79
-// Then the content of the resulting sparse file with a "real" size of 25 is:
80
-//	var sparseData = "\x00"*2 + "abcde" + "\x00"*11 + "fgh" + "\x00"*4
81
-type sparseEntry struct {
82
-	offset   int64 // Starting position of the fragment
83
-	numBytes int64 // Length of the fragment
84
-}
85
-
86
-// Keywords for GNU sparse files in a PAX extended header
87
-const (
88
-	paxGNUSparseNumBlocks = "GNU.sparse.numblocks"
89
-	paxGNUSparseOffset    = "GNU.sparse.offset"
90
-	paxGNUSparseNumBytes  = "GNU.sparse.numbytes"
91
-	paxGNUSparseMap       = "GNU.sparse.map"
92
-	paxGNUSparseName      = "GNU.sparse.name"
93
-	paxGNUSparseMajor     = "GNU.sparse.major"
94
-	paxGNUSparseMinor     = "GNU.sparse.minor"
95
-	paxGNUSparseSize      = "GNU.sparse.size"
96
-	paxGNUSparseRealSize  = "GNU.sparse.realsize"
97
-)
98
-
99
-// NewReader creates a new Reader reading from r.
100
-func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
101
-
102
-// Next advances to the next entry in the tar archive.
103
-//
104
-// io.EOF is returned at the end of the input.
105
-func (tr *Reader) Next() (*Header, error) {
106
-	if tr.err != nil {
107
-		return nil, tr.err
108
-	}
109
-	hdr, err := tr.next()
110
-	tr.err = err
111
-	return hdr, err
112
-}
113
-
114
-func (tr *Reader) next() (*Header, error) {
115
-	var extHdrs map[string]string
116
-
117
-	// Externally, Next iterates through the tar archive as if it is a series of
118
-	// files. Internally, the tar format often uses fake "files" to add meta
119
-	// data that describes the next file. These meta data "files" should not
120
-	// normally be visible to the outside. As such, this loop iterates through
121
-	// one or more "header files" until it finds a "normal file".
122
-loop:
123
-	for {
124
-		if err := tr.skipUnread(); err != nil {
125
-			return nil, err
126
-		}
127
-		hdr, rawHdr, err := tr.readHeader()
128
-		if err != nil {
129
-			return nil, err
130
-		}
131
-		if err := tr.handleRegularFile(hdr); err != nil {
132
-			return nil, err
133
-		}
134
-
135
-		// Check for PAX/GNU special headers and files.
136
-		switch hdr.Typeflag {
137
-		case TypeXHeader:
138
-			extHdrs, err = parsePAX(tr)
139
-			if err != nil {
140
-				return nil, err
141
-			}
142
-			continue loop // This is a meta header affecting the next header
143
-		case TypeGNULongName, TypeGNULongLink:
144
-			realname, err := ioutil.ReadAll(tr)
145
-			if err != nil {
146
-				return nil, err
147
-			}
148
-
149
-			// Convert GNU extensions to use PAX headers.
150
-			if extHdrs == nil {
151
-				extHdrs = make(map[string]string)
152
-			}
153
-			var p parser
154
-			switch hdr.Typeflag {
155
-			case TypeGNULongName:
156
-				extHdrs[paxPath] = p.parseString(realname)
157
-			case TypeGNULongLink:
158
-				extHdrs[paxLinkpath] = p.parseString(realname)
159
-			}
160
-			if p.err != nil {
161
-				return nil, p.err
162
-			}
163
-			continue loop // This is a meta header affecting the next header
164
-		default:
165
-			// The old GNU sparse format is handled here since it is technically
166
-			// just a regular file with additional attributes.
167
-
168
-			if err := mergePAX(hdr, extHdrs); err != nil {
169
-				return nil, err
170
-			}
171
-
172
-			// The extended headers may have updated the size.
173
-			// Thus, setup the regFileReader again after merging PAX headers.
174
-			if err := tr.handleRegularFile(hdr); err != nil {
175
-				return nil, err
176
-			}
177
-
178
-			// Sparse formats rely on being able to read from the logical data
179
-			// section; there must be a preceding call to handleRegularFile.
180
-			if err := tr.handleSparseFile(hdr, rawHdr, extHdrs); err != nil {
181
-				return nil, err
182
-			}
183
-			return hdr, nil // This is a file, so stop
184
-		}
185
-	}
186
-}
187
-
188
-// handleRegularFile sets up the current file reader and padding such that it
189
-// can only read the following logical data section. It will properly handle
190
-// special headers that contain no data section.
191
-func (tr *Reader) handleRegularFile(hdr *Header) error {
192
-	nb := hdr.Size
193
-	if isHeaderOnlyType(hdr.Typeflag) {
194
-		nb = 0
195
-	}
196
-	if nb < 0 {
197
-		return ErrHeader
198
-	}
199
-
200
-	tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
201
-	tr.curr = &regFileReader{r: tr.r, nb: nb}
202
-	return nil
203
-}
204
-
205
-// handleSparseFile checks if the current file is a sparse format of any type
206
-// and sets the curr reader appropriately.
207
-func (tr *Reader) handleSparseFile(hdr *Header, rawHdr *block, extHdrs map[string]string) error {
208
-	var sp []sparseEntry
209
-	var err error
210
-	if hdr.Typeflag == TypeGNUSparse {
211
-		sp, err = tr.readOldGNUSparseMap(hdr, rawHdr)
212
-		if err != nil {
213
-			return err
214
-		}
215
-	} else {
216
-		sp, err = tr.checkForGNUSparsePAXHeaders(hdr, extHdrs)
217
-		if err != nil {
218
-			return err
219
-		}
220
-	}
221
-
222
-	// If sp is non-nil, then this is a sparse file.
223
-	// Note that it is possible for len(sp) to be zero.
224
-	if sp != nil {
225
-		tr.curr, err = newSparseFileReader(tr.curr, sp, hdr.Size)
226
-	}
227
-	return err
228
-}
229
-
230
-// checkForGNUSparsePAXHeaders checks the PAX headers for GNU sparse headers. If they are found, then
231
-// this function reads the sparse map and returns it. Unknown sparse formats are ignored, causing the file to
232
-// be treated as a regular file.
233
-func (tr *Reader) checkForGNUSparsePAXHeaders(hdr *Header, headers map[string]string) ([]sparseEntry, error) {
234
-	var sparseFormat string
235
-
236
-	// Check for sparse format indicators
237
-	major, majorOk := headers[paxGNUSparseMajor]
238
-	minor, minorOk := headers[paxGNUSparseMinor]
239
-	sparseName, sparseNameOk := headers[paxGNUSparseName]
240
-	_, sparseMapOk := headers[paxGNUSparseMap]
241
-	sparseSize, sparseSizeOk := headers[paxGNUSparseSize]
242
-	sparseRealSize, sparseRealSizeOk := headers[paxGNUSparseRealSize]
243
-
244
-	// Identify which, if any, sparse format applies from which PAX headers are set
245
-	if majorOk && minorOk {
246
-		sparseFormat = major + "." + minor
247
-	} else if sparseNameOk && sparseMapOk {
248
-		sparseFormat = "0.1"
249
-	} else if sparseSizeOk {
250
-		sparseFormat = "0.0"
251
-	} else {
252
-		// Not a PAX format GNU sparse file.
253
-		return nil, nil
254
-	}
255
-
256
-	// Check for unknown sparse format
257
-	if sparseFormat != "0.0" && sparseFormat != "0.1" && sparseFormat != "1.0" {
258
-		return nil, nil
259
-	}
260
-
261
-	// Update hdr from GNU sparse PAX headers
262
-	if sparseNameOk {
263
-		hdr.Name = sparseName
264
-	}
265
-	if sparseSizeOk {
266
-		realSize, err := strconv.ParseInt(sparseSize, 10, 64)
267
-		if err != nil {
268
-			return nil, ErrHeader
269
-		}
270
-		hdr.Size = realSize
271
-	} else if sparseRealSizeOk {
272
-		realSize, err := strconv.ParseInt(sparseRealSize, 10, 64)
273
-		if err != nil {
274
-			return nil, ErrHeader
275
-		}
276
-		hdr.Size = realSize
277
-	}
278
-
279
-	// Set up the sparse map, according to the particular sparse format in use
280
-	var sp []sparseEntry
281
-	var err error
282
-	switch sparseFormat {
283
-	case "0.0", "0.1":
284
-		sp, err = readGNUSparseMap0x1(headers)
285
-	case "1.0":
286
-		sp, err = readGNUSparseMap1x0(tr.curr)
287
-	}
288
-	return sp, err
289
-}
290
-
291
-// mergePAX merges well known headers according to PAX standard.
292
-// In general headers with the same name as those found
293
-// in the header struct overwrite those found in the header
294
-// struct with higher precision or longer values. Esp. useful
295
-// for name and linkname fields.
296
-func mergePAX(hdr *Header, headers map[string]string) (err error) {
297
-	var id64 int64
298
-	for k, v := range headers {
299
-		switch k {
300
-		case paxPath:
301
-			hdr.Name = v
302
-		case paxLinkpath:
303
-			hdr.Linkname = v
304
-		case paxUname:
305
-			hdr.Uname = v
306
-		case paxGname:
307
-			hdr.Gname = v
308
-		case paxUid:
309
-			id64, err = strconv.ParseInt(v, 10, 64)
310
-			hdr.Uid = int(id64) // Integer overflow possible
311
-		case paxGid:
312
-			id64, err = strconv.ParseInt(v, 10, 64)
313
-			hdr.Gid = int(id64) // Integer overflow possible
314
-		case paxAtime:
315
-			hdr.AccessTime, err = parsePAXTime(v)
316
-		case paxMtime:
317
-			hdr.ModTime, err = parsePAXTime(v)
318
-		case paxCtime:
319
-			hdr.ChangeTime, err = parsePAXTime(v)
320
-		case paxSize:
321
-			hdr.Size, err = strconv.ParseInt(v, 10, 64)
322
-		default:
323
-			if strings.HasPrefix(k, paxXattr) {
324
-				if hdr.Xattrs == nil {
325
-					hdr.Xattrs = make(map[string]string)
326
-				}
327
-				hdr.Xattrs[k[len(paxXattr):]] = v
328
-			}
329
-		}
330
-		if err != nil {
331
-			return ErrHeader
332
-		}
333
-	}
334
-	return nil
335
-}
336
-
337
-// parsePAX parses PAX headers.
338
-// If an extended header (type 'x') is invalid, ErrHeader is returned
339
-func parsePAX(r io.Reader) (map[string]string, error) {
340
-	buf, err := ioutil.ReadAll(r)
341
-	if err != nil {
342
-		return nil, err
343
-	}
344
-	sbuf := string(buf)
345
-
346
-	// For GNU PAX sparse format 0.0 support.
347
-	// This function transforms the sparse format 0.0 headers into format 0.1
348
-	// headers since 0.0 headers were not PAX compliant.
349
-	var sparseMap []string
350
-
351
-	extHdrs := make(map[string]string)
352
-	for len(sbuf) > 0 {
353
-		key, value, residual, err := parsePAXRecord(sbuf)
354
-		if err != nil {
355
-			return nil, ErrHeader
356
-		}
357
-		sbuf = residual
358
-
359
-		switch key {
360
-		case paxGNUSparseOffset, paxGNUSparseNumBytes:
361
-			// Validate sparse header order and value.
362
-			if (len(sparseMap)%2 == 0 && key != paxGNUSparseOffset) ||
363
-				(len(sparseMap)%2 == 1 && key != paxGNUSparseNumBytes) ||
364
-				strings.Contains(value, ",") {
365
-				return nil, ErrHeader
366
-			}
367
-			sparseMap = append(sparseMap, value)
368
-		default:
369
-			// According to PAX specification, a value is stored only if it is
370
-			// non-empty. Otherwise, the key is deleted.
371
-			if len(value) > 0 {
372
-				extHdrs[key] = value
373
-			} else {
374
-				delete(extHdrs, key)
375
-			}
376
-		}
377
-	}
378
-	if len(sparseMap) > 0 {
379
-		extHdrs[paxGNUSparseMap] = strings.Join(sparseMap, ",")
380
-	}
381
-	return extHdrs, nil
382
-}
383
-
384
-// skipUnread skips any unread bytes in the existing file entry, as well as any
385
-// alignment padding. It returns io.ErrUnexpectedEOF if any io.EOF is
386
-// encountered in the data portion; it is okay to hit io.EOF in the padding.
387
-//
388
-// Note that this function still works properly even when sparse files are being
389
-// used since numBytes returns the bytes remaining in the underlying io.Reader.
390
-func (tr *Reader) skipUnread() error {
391
-	dataSkip := tr.numBytes()      // Number of data bytes to skip
392
-	totalSkip := dataSkip + tr.pad // Total number of bytes to skip
393
-	tr.curr, tr.pad = nil, 0
394
-
395
-	// If possible, Seek to the last byte before the end of the data section.
396
-	// Do this because Seek is often lazy about reporting errors; this will mask
397
-	// the fact that the tar stream may be truncated. We can rely on the
398
-	// io.CopyN done shortly afterwards to trigger any IO errors.
399
-	var seekSkipped int64 // Number of bytes skipped via Seek
400
-	if sr, ok := tr.r.(io.Seeker); ok && dataSkip > 1 {
401
-		// Not all io.Seeker can actually Seek. For example, os.Stdin implements
402
-		// io.Seeker, but calling Seek always returns an error and performs
403
-		// no action. Thus, we try an innocent seek to the current position
404
-		// to see if Seek is really supported.
405
-		pos1, err := sr.Seek(0, io.SeekCurrent)
406
-		if err == nil {
407
-			// Seek seems supported, so perform the real Seek.
408
-			pos2, err := sr.Seek(dataSkip-1, io.SeekCurrent)
409
-			if err != nil {
410
-				return err
411
-			}
412
-			seekSkipped = pos2 - pos1
413
-		}
414
-	}
415
-
416
-	copySkipped, err := io.CopyN(ioutil.Discard, tr.r, totalSkip-seekSkipped)
417
-	if err == io.EOF && seekSkipped+copySkipped < dataSkip {
418
-		err = io.ErrUnexpectedEOF
419
-	}
420
-	return err
421
-}
422
-
423
-// readHeader reads the next block header and assumes that the underlying reader
424
-// is already aligned to a block boundary. It returns the raw block of the
425
-// header in case further processing is required.
426
-//
427
-// The err will be set to io.EOF only when one of the following occurs:
428
-//	* Exactly 0 bytes are read and EOF is hit.
429
-//	* Exactly 1 block of zeros is read and EOF is hit.
430
-//	* At least 2 blocks of zeros are read.
431
-func (tr *Reader) readHeader() (*Header, *block, error) {
432
-	// Two blocks of zero bytes marks the end of the archive.
433
-	if _, err := io.ReadFull(tr.r, tr.blk[:]); err != nil {
434
-		return nil, nil, err // EOF is okay here; exactly 0 bytes read
435
-	}
436
-	if bytes.Equal(tr.blk[:], zeroBlock[:]) {
437
-		if _, err := io.ReadFull(tr.r, tr.blk[:]); err != nil {
438
-			return nil, nil, err // EOF is okay here; exactly 1 block of zeros read
439
-		}
440
-		if bytes.Equal(tr.blk[:], zeroBlock[:]) {
441
-			return nil, nil, io.EOF // normal EOF; exactly 2 block of zeros read
442
-		}
443
-		return nil, nil, ErrHeader // Zero block and then non-zero block
444
-	}
445
-
446
-	// Verify the header matches a known format.
447
-	format := tr.blk.GetFormat()
448
-	if format == formatUnknown {
449
-		return nil, nil, ErrHeader
450
-	}
451
-
452
-	var p parser
453
-	hdr := new(Header)
454
-
455
-	// Unpack the V7 header.
456
-	v7 := tr.blk.V7()
457
-	hdr.Name = p.parseString(v7.Name())
458
-	hdr.Mode = p.parseNumeric(v7.Mode())
459
-	hdr.Uid = int(p.parseNumeric(v7.UID()))
460
-	hdr.Gid = int(p.parseNumeric(v7.GID()))
461
-	hdr.Size = p.parseNumeric(v7.Size())
462
-	hdr.ModTime = time.Unix(p.parseNumeric(v7.ModTime()), 0)
463
-	hdr.Typeflag = v7.TypeFlag()[0]
464
-	hdr.Linkname = p.parseString(v7.LinkName())
465
-
466
-	// Unpack format specific fields.
467
-	if format > formatV7 {
468
-		ustar := tr.blk.USTAR()
469
-		hdr.Uname = p.parseString(ustar.UserName())
470
-		hdr.Gname = p.parseString(ustar.GroupName())
471
-		if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock {
472
-			hdr.Devmajor = p.parseNumeric(ustar.DevMajor())
473
-			hdr.Devminor = p.parseNumeric(ustar.DevMinor())
474
-		}
475
-
476
-		var prefix string
477
-		switch format {
478
-		case formatUSTAR, formatGNU:
479
-			// TODO(dsnet): Do not use the prefix field for the GNU format!
480
-			// See golang.org/issues/12594
481
-			ustar := tr.blk.USTAR()
482
-			prefix = p.parseString(ustar.Prefix())
483
-		case formatSTAR:
484
-			star := tr.blk.STAR()
485
-			prefix = p.parseString(star.Prefix())
486
-			hdr.AccessTime = time.Unix(p.parseNumeric(star.AccessTime()), 0)
487
-			hdr.ChangeTime = time.Unix(p.parseNumeric(star.ChangeTime()), 0)
488
-		}
489
-		if len(prefix) > 0 {
490
-			hdr.Name = prefix + "/" + hdr.Name
491
-		}
492
-	}
493
-	return hdr, &tr.blk, p.err
494
-}
495
-
496
-// readOldGNUSparseMap reads the sparse map from the old GNU sparse format.
497
-// The sparse map is stored in the tar header if it's small enough.
498
-// If it's larger than four entries, then one or more extension headers are used
499
-// to store the rest of the sparse map.
500
-//
501
-// The Header.Size does not reflect the size of any extended headers used.
502
-// Thus, this function will read from the raw io.Reader to fetch extra headers.
503
-// This method mutates blk in the process.
504
-func (tr *Reader) readOldGNUSparseMap(hdr *Header, blk *block) ([]sparseEntry, error) {
505
-	// Make sure that the input format is GNU.
506
-	// Unfortunately, the STAR format also has a sparse header format that uses
507
-	// the same type flag but has a completely different layout.
508
-	if blk.GetFormat() != formatGNU {
509
-		return nil, ErrHeader
510
-	}
511
-
512
-	var p parser
513
-	hdr.Size = p.parseNumeric(blk.GNU().RealSize())
514
-	if p.err != nil {
515
-		return nil, p.err
516
-	}
517
-	var s sparseArray = blk.GNU().Sparse()
518
-	var sp = make([]sparseEntry, 0, s.MaxEntries())
519
-	for {
520
-		for i := 0; i < s.MaxEntries(); i++ {
521
-			// This termination condition is identical to GNU and BSD tar.
522
-			if s.Entry(i).Offset()[0] == 0x00 {
523
-				break // Don't return, need to process extended headers (even if empty)
524
-			}
525
-			offset := p.parseNumeric(s.Entry(i).Offset())
526
-			numBytes := p.parseNumeric(s.Entry(i).NumBytes())
527
-			if p.err != nil {
528
-				return nil, p.err
529
-			}
530
-			sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
531
-		}
532
-
533
-		if s.IsExtended()[0] > 0 {
534
-			// There are more entries. Read an extension header and parse its entries.
535
-			if _, err := io.ReadFull(tr.r, blk[:]); err != nil {
536
-				if err == io.EOF {
537
-					err = io.ErrUnexpectedEOF
538
-				}
539
-				return nil, err
540
-			}
541
-			s = blk.Sparse()
542
-			continue
543
-		}
544
-		return sp, nil // Done
545
-	}
546
-}
547
-
548
-// readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format
549
-// version 1.0. The format of the sparse map consists of a series of
550
-// newline-terminated numeric fields. The first field is the number of entries
551
-// and is always present. Following this are the entries, consisting of two
552
-// fields (offset, numBytes). This function must stop reading at the end
553
-// boundary of the block containing the last newline.
554
-//
555
-// Note that the GNU manual says that numeric values should be encoded in octal
556
-// format. However, the GNU tar utility itself outputs these values in decimal.
557
-// As such, this library treats values as being encoded in decimal.
558
-func readGNUSparseMap1x0(r io.Reader) ([]sparseEntry, error) {
559
-	var cntNewline int64
560
-	var buf bytes.Buffer
561
-	var blk = make([]byte, blockSize)
562
-
563
-	// feedTokens copies data in numBlock chunks from r into buf until there are
564
-	// at least cnt newlines in buf. It will not read more blocks than needed.
565
-	var feedTokens = func(cnt int64) error {
566
-		for cntNewline < cnt {
567
-			if _, err := io.ReadFull(r, blk); err != nil {
568
-				if err == io.EOF {
569
-					err = io.ErrUnexpectedEOF
570
-				}
571
-				return err
572
-			}
573
-			buf.Write(blk)
574
-			for _, c := range blk {
575
-				if c == '\n' {
576
-					cntNewline++
577
-				}
578
-			}
579
-		}
580
-		return nil
581
-	}
582
-
583
-	// nextToken gets the next token delimited by a newline. This assumes that
584
-	// at least one newline exists in the buffer.
585
-	var nextToken = func() string {
586
-		cntNewline--
587
-		tok, _ := buf.ReadString('\n')
588
-		return tok[:len(tok)-1] // Cut off newline
589
-	}
590
-
591
-	// Parse for the number of entries.
592
-	// Use integer overflow resistant math to check this.
593
-	if err := feedTokens(1); err != nil {
594
-		return nil, err
595
-	}
596
-	numEntries, err := strconv.ParseInt(nextToken(), 10, 0) // Intentionally parse as native int
597
-	if err != nil || numEntries < 0 || int(2*numEntries) < int(numEntries) {
598
-		return nil, ErrHeader
599
-	}
600
-
601
-	// Parse for all member entries.
602
-	// numEntries is trusted after this since a potential attacker must have
603
-	// committed resources proportional to what this library used.
604
-	if err := feedTokens(2 * numEntries); err != nil {
605
-		return nil, err
606
-	}
607
-	sp := make([]sparseEntry, 0, numEntries)
608
-	for i := int64(0); i < numEntries; i++ {
609
-		offset, err := strconv.ParseInt(nextToken(), 10, 64)
610
-		if err != nil {
611
-			return nil, ErrHeader
612
-		}
613
-		numBytes, err := strconv.ParseInt(nextToken(), 10, 64)
614
-		if err != nil {
615
-			return nil, ErrHeader
616
-		}
617
-		sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
618
-	}
619
-	return sp, nil
620
-}
621
-
622
-// readGNUSparseMap0x1 reads the sparse map as stored in GNU's PAX sparse format
623
-// version 0.1. The sparse map is stored in the PAX headers.
624
-func readGNUSparseMap0x1(extHdrs map[string]string) ([]sparseEntry, error) {
625
-	// Get number of entries.
626
-	// Use integer overflow resistant math to check this.
627
-	numEntriesStr := extHdrs[paxGNUSparseNumBlocks]
628
-	numEntries, err := strconv.ParseInt(numEntriesStr, 10, 0) // Intentionally parse as native int
629
-	if err != nil || numEntries < 0 || int(2*numEntries) < int(numEntries) {
630
-		return nil, ErrHeader
631
-	}
632
-
633
-	// There should be two numbers in sparseMap for each entry.
634
-	sparseMap := strings.Split(extHdrs[paxGNUSparseMap], ",")
635
-	if int64(len(sparseMap)) != 2*numEntries {
636
-		return nil, ErrHeader
637
-	}
638
-
639
-	// Loop through the entries in the sparse map.
640
-	// numEntries is trusted now.
641
-	sp := make([]sparseEntry, 0, numEntries)
642
-	for i := int64(0); i < numEntries; i++ {
643
-		offset, err := strconv.ParseInt(sparseMap[2*i], 10, 64)
644
-		if err != nil {
645
-			return nil, ErrHeader
646
-		}
647
-		numBytes, err := strconv.ParseInt(sparseMap[2*i+1], 10, 64)
648
-		if err != nil {
649
-			return nil, ErrHeader
650
-		}
651
-		sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
652
-	}
653
-	return sp, nil
654
-}
655
-
656
-// numBytes returns the number of bytes left to read in the current file's entry
657
-// in the tar archive, or 0 if there is no current file.
658
-func (tr *Reader) numBytes() int64 {
659
-	if tr.curr == nil {
660
-		// No current file, so no bytes
661
-		return 0
662
-	}
663
-	return tr.curr.numBytes()
664
-}
665
-
666
-// Read reads from the current entry in the tar archive.
667
-// It returns 0, io.EOF when it reaches the end of that entry,
668
-// until Next is called to advance to the next entry.
669
-//
670
-// Calling Read on special types like TypeLink, TypeSymLink, TypeChar,
671
-// TypeBlock, TypeDir, and TypeFifo returns 0, io.EOF regardless of what
672
-// the Header.Size claims.
673
-func (tr *Reader) Read(b []byte) (int, error) {
674
-	if tr.err != nil {
675
-		return 0, tr.err
676
-	}
677
-	if tr.curr == nil {
678
-		return 0, io.EOF
679
-	}
680
-
681
-	n, err := tr.curr.Read(b)
682
-	if err != nil && err != io.EOF {
683
-		tr.err = err
684
-	}
685
-	return n, err
686
-}
687
-
688
-func (rfr *regFileReader) Read(b []byte) (n int, err error) {
689
-	if rfr.nb == 0 {
690
-		// file consumed
691
-		return 0, io.EOF
692
-	}
693
-	if int64(len(b)) > rfr.nb {
694
-		b = b[0:rfr.nb]
695
-	}
696
-	n, err = rfr.r.Read(b)
697
-	rfr.nb -= int64(n)
698
-
699
-	if err == io.EOF && rfr.nb > 0 {
700
-		err = io.ErrUnexpectedEOF
701
-	}
702
-	return
703
-}
704
-
705
-// numBytes returns the number of bytes left to read in the file's data in the tar archive.
706
-func (rfr *regFileReader) numBytes() int64 {
707
-	return rfr.nb
708
-}
709
-
710
-// newSparseFileReader creates a new sparseFileReader, but validates all of the
711
-// sparse entries before doing so.
712
-func newSparseFileReader(rfr numBytesReader, sp []sparseEntry, total int64) (*sparseFileReader, error) {
713
-	if total < 0 {
714
-		return nil, ErrHeader // Total size cannot be negative
715
-	}
716
-
717
-	// Validate all sparse entries. These are the same checks as performed by
718
-	// the BSD tar utility.
719
-	for i, s := range sp {
720
-		switch {
721
-		case s.offset < 0 || s.numBytes < 0:
722
-			return nil, ErrHeader // Negative values are never okay
723
-		case s.offset > math.MaxInt64-s.numBytes:
724
-			return nil, ErrHeader // Integer overflow with large length
725
-		case s.offset+s.numBytes > total:
726
-			return nil, ErrHeader // Region extends beyond the "real" size
727
-		case i > 0 && sp[i-1].offset+sp[i-1].numBytes > s.offset:
728
-			return nil, ErrHeader // Regions can't overlap and must be in order
729
-		}
730
-	}
731
-	return &sparseFileReader{rfr: rfr, sp: sp, total: total}, nil
732
-}
733
-
734
-// readHole reads a sparse hole ending at endOffset.
735
-func (sfr *sparseFileReader) readHole(b []byte, endOffset int64) int {
736
-	n64 := endOffset - sfr.pos
737
-	if n64 > int64(len(b)) {
738
-		n64 = int64(len(b))
739
-	}
740
-	n := int(n64)
741
-	for i := 0; i < n; i++ {
742
-		b[i] = 0
743
-	}
744
-	sfr.pos += n64
745
-	return n
746
-}
747
-
748
-// Read reads the sparse file data in expanded form.
749
-func (sfr *sparseFileReader) Read(b []byte) (n int, err error) {
750
-	// Skip past all empty fragments.
751
-	for len(sfr.sp) > 0 && sfr.sp[0].numBytes == 0 {
752
-		sfr.sp = sfr.sp[1:]
753
-	}
754
-
755
-	// If there are no more fragments, then it is possible that there
756
-	// is one last sparse hole.
757
-	if len(sfr.sp) == 0 {
758
-		// This behavior matches the BSD tar utility.
759
-		// However, GNU tar stops returning data even if sfr.total is unmet.
760
-		if sfr.pos < sfr.total {
761
-			return sfr.readHole(b, sfr.total), nil
762
-		}
763
-		return 0, io.EOF
764
-	}
765
-
766
-	// In front of a data fragment, so read a hole.
767
-	if sfr.pos < sfr.sp[0].offset {
768
-		return sfr.readHole(b, sfr.sp[0].offset), nil
769
-	}
770
-
771
-	// In a data fragment, so read from it.
772
-	// This math is overflow free since we verify that offset and numBytes can
773
-	// be safely added when creating the sparseFileReader.
774
-	endPos := sfr.sp[0].offset + sfr.sp[0].numBytes // End offset of fragment
775
-	bytesLeft := endPos - sfr.pos                   // Bytes left in fragment
776
-	if int64(len(b)) > bytesLeft {
777
-		b = b[:bytesLeft]
778
-	}
779
-
780
-	n, err = sfr.rfr.Read(b)
781
-	sfr.pos += int64(n)
782
-	if err == io.EOF {
783
-		if sfr.pos < endPos {
784
-			err = io.ErrUnexpectedEOF // There was supposed to be more data
785
-		} else if sfr.pos < sfr.total {
786
-			err = nil // There is still an implicit sparse hole at the end
787
-		}
788
-	}
789
-
790
-	if sfr.pos == endPos {
791
-		sfr.sp = sfr.sp[1:] // We are done with this fragment, so pop it
792
-	}
793
-	return n, err
794
-}
795
-
796
-// numBytes returns the number of bytes left to read in the sparse file's
797
-// sparse-encoded data in the tar archive.
798
-func (sfr *sparseFileReader) numBytes() int64 {
799
-	return sfr.rfr.numBytes()
800
-}
801 1
deleted file mode 100644
... ...
@@ -1,20 +0,0 @@
1
-// Copyright 2012 The Go Authors. All rights reserved.
2
-// Use of this source code is governed by a BSD-style
3
-// license that can be found in the LICENSE file.
4
-
5
-// +build linux dragonfly openbsd solaris
6
-
7
-package tar
8
-
9
-import (
10
-	"syscall"
11
-	"time"
12
-)
13
-
14
-func statAtime(st *syscall.Stat_t) time.Time {
15
-	return time.Unix(st.Atim.Unix())
16
-}
17
-
18
-func statCtime(st *syscall.Stat_t) time.Time {
19
-	return time.Unix(st.Ctim.Unix())
20
-}
21 1
deleted file mode 100644
... ...
@@ -1,20 +0,0 @@
1
-// Copyright 2012 The Go Authors. All rights reserved.
2
-// Use of this source code is governed by a BSD-style
3
-// license that can be found in the LICENSE file.
4
-
5
-// +build darwin freebsd netbsd
6
-
7
-package tar
8
-
9
-import (
10
-	"syscall"
11
-	"time"
12
-)
13
-
14
-func statAtime(st *syscall.Stat_t) time.Time {
15
-	return time.Unix(st.Atimespec.Unix())
16
-}
17
-
18
-func statCtime(st *syscall.Stat_t) time.Time {
19
-	return time.Unix(st.Ctimespec.Unix())
20
-}
21 1
deleted file mode 100644
... ...
@@ -1,32 +0,0 @@
1
-// Copyright 2012 The Go Authors. All rights reserved.
2
-// Use of this source code is governed by a BSD-style
3
-// license that can be found in the LICENSE file.
4
-
5
-// +build linux darwin dragonfly freebsd openbsd netbsd solaris
6
-
7
-package tar
8
-
9
-import (
10
-	"os"
11
-	"syscall"
12
-)
13
-
14
-func init() {
15
-	sysStat = statUnix
16
-}
17
-
18
-func statUnix(fi os.FileInfo, h *Header) error {
19
-	sys, ok := fi.Sys().(*syscall.Stat_t)
20
-	if !ok {
21
-		return nil
22
-	}
23
-	h.Uid = int(sys.Uid)
24
-	h.Gid = int(sys.Gid)
25
-	// TODO(bradfitz): populate username & group.  os/user
26
-	// doesn't cache LookupId lookups, and lacks group
27
-	// lookup functions.
28
-	h.AccessTime = statAtime(sys)
29
-	h.ChangeTime = statCtime(sys)
30
-	// TODO(bradfitz): major/minor device numbers?
31
-	return nil
32
-}
33 1
deleted file mode 100644
... ...
@@ -1,252 +0,0 @@
1
-// Copyright 2016 The Go Authors. All rights reserved.
2
-// Use of this source code is governed by a BSD-style
3
-// license that can be found in the LICENSE file.
4
-
5
-package tar
6
-
7
-import (
8
-	"bytes"
9
-	"fmt"
10
-	"strconv"
11
-	"strings"
12
-	"time"
13
-)
14
-
15
-func isASCII(s string) bool {
16
-	for _, c := range s {
17
-		if c >= 0x80 {
18
-			return false
19
-		}
20
-	}
21
-	return true
22
-}
23
-
24
-func toASCII(s string) string {
25
-	if isASCII(s) {
26
-		return s
27
-	}
28
-	var buf bytes.Buffer
29
-	for _, c := range s {
30
-		if c < 0x80 {
31
-			buf.WriteByte(byte(c))
32
-		}
33
-	}
34
-	return buf.String()
35
-}
36
-
37
-type parser struct {
38
-	err error // Last error seen
39
-}
40
-
41
-type formatter struct {
42
-	err error // Last error seen
43
-}
44
-
45
-// parseString parses bytes as a NUL-terminated C-style string.
46
-// If a NUL byte is not found then the whole slice is returned as a string.
47
-func (*parser) parseString(b []byte) string {
48
-	n := 0
49
-	for n < len(b) && b[n] != 0 {
50
-		n++
51
-	}
52
-	return string(b[0:n])
53
-}
54
-
55
-// Write s into b, terminating it with a NUL if there is room.
56
-func (f *formatter) formatString(b []byte, s string) {
57
-	if len(s) > len(b) {
58
-		f.err = ErrFieldTooLong
59
-		return
60
-	}
61
-	ascii := toASCII(s)
62
-	copy(b, ascii)
63
-	if len(ascii) < len(b) {
64
-		b[len(ascii)] = 0
65
-	}
66
-}
67
-
68
-// fitsInBase256 reports whether x can be encoded into n bytes using base-256
69
-// encoding. Unlike octal encoding, base-256 encoding does not require that the
70
-// string ends with a NUL character. Thus, all n bytes are available for output.
71
-//
72
-// If operating in binary mode, this assumes strict GNU binary mode; which means
73
-// that the first byte can only be either 0x80 or 0xff. Thus, the first byte is
74
-// equivalent to the sign bit in two's complement form.
75
-func fitsInBase256(n int, x int64) bool {
76
-	var binBits = uint(n-1) * 8
77
-	return n >= 9 || (x >= -1<<binBits && x < 1<<binBits)
78
-}
79
-
80
-// parseNumeric parses the input as being encoded in either base-256 or octal.
81
-// This function may return negative numbers.
82
-// If parsing fails or an integer overflow occurs, err will be set.
83
-func (p *parser) parseNumeric(b []byte) int64 {
84
-	// Check for base-256 (binary) format first.
85
-	// If the first bit is set, then all following bits constitute a two's
86
-	// complement encoded number in big-endian byte order.
87
-	if len(b) > 0 && b[0]&0x80 != 0 {
88
-		// Handling negative numbers relies on the following identity:
89
-		//	-a-1 == ^a
90
-		//
91
-		// If the number is negative, we use an inversion mask to invert the
92
-		// data bytes and treat the value as an unsigned number.
93
-		var inv byte // 0x00 if positive or zero, 0xff if negative
94
-		if b[0]&0x40 != 0 {
95
-			inv = 0xff
96
-		}
97
-
98
-		var x uint64
99
-		for i, c := range b {
100
-			c ^= inv // Inverts c only if inv is 0xff, otherwise does nothing
101
-			if i == 0 {
102
-				c &= 0x7f // Ignore signal bit in first byte
103
-			}
104
-			if (x >> 56) > 0 {
105
-				p.err = ErrHeader // Integer overflow
106
-				return 0
107
-			}
108
-			x = x<<8 | uint64(c)
109
-		}
110
-		if (x >> 63) > 0 {
111
-			p.err = ErrHeader // Integer overflow
112
-			return 0
113
-		}
114
-		if inv == 0xff {
115
-			return ^int64(x)
116
-		}
117
-		return int64(x)
118
-	}
119
-
120
-	// Normal case is base-8 (octal) format.
121
-	return p.parseOctal(b)
122
-}
123
-
124
-// Write x into b, as binary (GNUtar/star extension).
125
-func (f *formatter) formatNumeric(b []byte, x int64) {
126
-	if fitsInBase256(len(b), x) {
127
-		for i := len(b) - 1; i >= 0; i-- {
128
-			b[i] = byte(x)
129
-			x >>= 8
130
-		}
131
-		b[0] |= 0x80 // Highest bit indicates binary format
132
-		return
133
-	}
134
-
135
-	f.formatOctal(b, 0) // Last resort, just write zero
136
-	f.err = ErrFieldTooLong
137
-}
138
-
139
-func (p *parser) parseOctal(b []byte) int64 {
140
-	// Because unused fields are filled with NULs, we need
141
-	// to skip leading NULs. Fields may also be padded with
142
-	// spaces or NULs.
143
-	// So we remove leading and trailing NULs and spaces to
144
-	// be sure.
145
-	b = bytes.Trim(b, " \x00")
146
-
147
-	if len(b) == 0 {
148
-		return 0
149
-	}
150
-	x, perr := strconv.ParseUint(p.parseString(b), 8, 64)
151
-	if perr != nil {
152
-		p.err = ErrHeader
153
-	}
154
-	return int64(x)
155
-}
156
-
157
-func (f *formatter) formatOctal(b []byte, x int64) {
158
-	s := strconv.FormatInt(x, 8)
159
-	// Add leading zeros, but leave room for a NUL.
160
-	if n := len(b) - len(s) - 1; n > 0 {
161
-		s = strings.Repeat("0", n) + s
162
-	}
163
-	f.formatString(b, s)
164
-}
165
-
166
-// parsePAXTime takes a string of the form %d.%d as described in the PAX
167
-// specification. Note that this implementation allows for negative timestamps,
168
-// which is allowed for by the PAX specification, but not always portable.
169
-func parsePAXTime(s string) (time.Time, error) {
170
-	const maxNanoSecondDigits = 9
171
-
172
-	// Split string into seconds and sub-seconds parts.
173
-	ss, sn := s, ""
174
-	if pos := strings.IndexByte(s, '.'); pos >= 0 {
175
-		ss, sn = s[:pos], s[pos+1:]
176
-	}
177
-
178
-	// Parse the seconds.
179
-	secs, err := strconv.ParseInt(ss, 10, 64)
180
-	if err != nil {
181
-		return time.Time{}, ErrHeader
182
-	}
183
-	if len(sn) == 0 {
184
-		return time.Unix(secs, 0), nil // No sub-second values
185
-	}
186
-
187
-	// Parse the nanoseconds.
188
-	if strings.Trim(sn, "0123456789") != "" {
189
-		return time.Time{}, ErrHeader
190
-	}
191
-	if len(sn) < maxNanoSecondDigits {
192
-		sn += strings.Repeat("0", maxNanoSecondDigits-len(sn)) // Right pad
193
-	} else {
194
-		sn = sn[:maxNanoSecondDigits] // Right truncate
195
-	}
196
-	nsecs, _ := strconv.ParseInt(sn, 10, 64) // Must succeed
197
-	if len(ss) > 0 && ss[0] == '-' {
198
-		return time.Unix(secs, -1*int64(nsecs)), nil // Negative correction
199
-	}
200
-	return time.Unix(secs, int64(nsecs)), nil
201
-}
202
-
203
-// TODO(dsnet): Implement formatPAXTime.
204
-
205
-// parsePAXRecord parses the input PAX record string into a key-value pair.
206
-// If parsing is successful, it will slice off the currently read record and
207
-// return the remainder as r.
208
-//
209
-// A PAX record is of the following form:
210
-//	"%d %s=%s\n" % (size, key, value)
211
-func parsePAXRecord(s string) (k, v, r string, err error) {
212
-	// The size field ends at the first space.
213
-	sp := strings.IndexByte(s, ' ')
214
-	if sp == -1 {
215
-		return "", "", s, ErrHeader
216
-	}
217
-
218
-	// Parse the first token as a decimal integer.
219
-	n, perr := strconv.ParseInt(s[:sp], 10, 0) // Intentionally parse as native int
220
-	if perr != nil || n < 5 || int64(len(s)) < n {
221
-		return "", "", s, ErrHeader
222
-	}
223
-
224
-	// Extract everything between the space and the final newline.
225
-	rec, nl, rem := s[sp+1:n-1], s[n-1:n], s[n:]
226
-	if nl != "\n" {
227
-		return "", "", s, ErrHeader
228
-	}
229
-
230
-	// The first equals separates the key from the value.
231
-	eq := strings.IndexByte(rec, '=')
232
-	if eq == -1 {
233
-		return "", "", s, ErrHeader
234
-	}
235
-	return rec[:eq], rec[eq+1:], rem, nil
236
-}
237
-
238
-// formatPAXRecord formats a single PAX record, prefixing it with the
239
-// appropriate length.
240
-func formatPAXRecord(k, v string) string {
241
-	const padding = 3 // Extra padding for ' ', '=', and '\n'
242
-	size := len(k) + len(v) + padding
243
-	size += len(strconv.Itoa(size))
244
-	record := fmt.Sprintf("%d %s=%s\n", size, k, v)
245
-
246
-	// Final adjustment if adding size field increased the record size.
247
-	if len(record) != size {
248
-		size = len(record)
249
-		record = fmt.Sprintf("%d %s=%s\n", size, k, v)
250
-	}
251
-	return record
252
-}
253 1
deleted file mode 100644
... ...
@@ -1,370 +0,0 @@
1
-// Copyright 2009 The Go Authors. All rights reserved.
2
-// Use of this source code is governed by a BSD-style
3
-// license that can be found in the LICENSE file.
4
-
5
-package tar
6
-
7
-// TODO(dsymonds):
8
-// - catch more errors (no first header, etc.)
9
-
10
-import (
11
-	"bytes"
12
-	"errors"
13
-	"fmt"
14
-	"io"
15
-	"path"
16
-	"sort"
17
-	"strconv"
18
-	"strings"
19
-	"time"
20
-)
21
-
22
-var (
23
-	ErrWriteTooLong    = errors.New("archive/tar: write too long")
24
-	ErrFieldTooLong    = errors.New("archive/tar: header field too long")
25
-	ErrWriteAfterClose = errors.New("archive/tar: write after close")
26
-	errInvalidHeader   = errors.New("archive/tar: header field too long or contains invalid values")
27
-)
28
-
29
-// A Writer provides sequential writing of a tar archive in POSIX.1 format.
30
-// A tar archive consists of a sequence of files.
31
-// Call WriteHeader to begin a new file, and then call Write to supply that file's data,
32
-// writing at most hdr.Size bytes in total.
33
-type Writer struct {
34
-	w          io.Writer
35
-	err        error
36
-	nb         int64 // number of unwritten bytes for current file entry
37
-	pad        int64 // amount of padding to write after current file entry
38
-	closed     bool
39
-	usedBinary bool  // whether the binary numeric field extension was used
40
-	preferPax  bool  // use PAX header instead of binary numeric header
41
-	hdrBuff    block // buffer to use in writeHeader when writing a regular header
42
-	paxHdrBuff block // buffer to use in writeHeader when writing a PAX header
43
-}
44
-
45
-// NewWriter creates a new Writer writing to w.
46
-func NewWriter(w io.Writer) *Writer { return &Writer{w: w} }
47
-
48
-// Flush finishes writing the current file (optional).
49
-func (tw *Writer) Flush() error {
50
-	if tw.nb > 0 {
51
-		tw.err = fmt.Errorf("archive/tar: missed writing %d bytes", tw.nb)
52
-		return tw.err
53
-	}
54
-
55
-	n := tw.nb + tw.pad
56
-	for n > 0 && tw.err == nil {
57
-		nr := n
58
-		if nr > blockSize {
59
-			nr = blockSize
60
-		}
61
-		var nw int
62
-		nw, tw.err = tw.w.Write(zeroBlock[0:nr])
63
-		n -= int64(nw)
64
-	}
65
-	tw.nb = 0
66
-	tw.pad = 0
67
-	return tw.err
68
-}
69
-
70
-var (
71
-	minTime = time.Unix(0, 0)
72
-	// There is room for 11 octal digits (33 bits) of mtime.
73
-	maxTime = minTime.Add((1<<33 - 1) * time.Second)
74
-)
75
-
76
-// WriteHeader writes hdr and prepares to accept the file's contents.
77
-// WriteHeader calls Flush if it is not the first header.
78
-// Calling after a Close will return ErrWriteAfterClose.
79
-func (tw *Writer) WriteHeader(hdr *Header) error {
80
-	return tw.writeHeader(hdr, true)
81
-}
82
-
83
-// WriteHeader writes hdr and prepares to accept the file's contents.
84
-// WriteHeader calls Flush if it is not the first header.
85
-// Calling after a Close will return ErrWriteAfterClose.
86
-// As this method is called internally by writePax header to allow it to
87
-// suppress writing the pax header.
88
-func (tw *Writer) writeHeader(hdr *Header, allowPax bool) error {
89
-	if tw.closed {
90
-		return ErrWriteAfterClose
91
-	}
92
-	if tw.err == nil {
93
-		tw.Flush()
94
-	}
95
-	if tw.err != nil {
96
-		return tw.err
97
-	}
98
-
99
-	// a map to hold pax header records, if any are needed
100
-	paxHeaders := make(map[string]string)
101
-
102
-	// TODO(dsnet): we might want to use PAX headers for
103
-	// subsecond time resolution, but for now let's just capture
104
-	// too long fields or non ascii characters
105
-
106
-	// We need to select which scratch buffer to use carefully,
107
-	// since this method is called recursively to write PAX headers.
108
-	// If allowPax is true, this is the non-recursive call, and we will use hdrBuff.
109
-	// If allowPax is false, we are being called by writePAXHeader, and hdrBuff is
110
-	// already being used by the non-recursive call, so we must use paxHdrBuff.
111
-	header := &tw.hdrBuff
112
-	if !allowPax {
113
-		header = &tw.paxHdrBuff
114
-	}
115
-	copy(header[:], zeroBlock[:])
116
-
117
-	// Wrappers around formatter that automatically sets paxHeaders if the
118
-	// argument extends beyond the capacity of the input byte slice.
119
-	var f formatter
120
-	var formatString = func(b []byte, s string, paxKeyword string) {
121
-		needsPaxHeader := paxKeyword != paxNone && len(s) > len(b) || !isASCII(s)
122
-		if needsPaxHeader {
123
-			paxHeaders[paxKeyword] = s
124
-		}
125
-
126
-		// Write string in a best-effort manner to satisfy readers that expect
127
-		// the field to be non-empty.
128
-		s = toASCII(s)
129
-		if len(s) > len(b) {
130
-			s = s[:len(b)]
131
-		}
132
-		f.formatString(b, s) // Should never error
133
-	}
134
-	var formatNumeric = func(b []byte, x int64, paxKeyword string) {
135
-		// Try octal first.
136
-		s := strconv.FormatInt(x, 8)
137
-		if len(s) < len(b) {
138
-			f.formatOctal(b, x)
139
-			return
140
-		}
141
-
142
-		// If it is too long for octal, and PAX is preferred, use a PAX header.
143
-		if paxKeyword != paxNone && tw.preferPax {
144
-			f.formatOctal(b, 0)
145
-			s := strconv.FormatInt(x, 10)
146
-			paxHeaders[paxKeyword] = s
147
-			return
148
-		}
149
-
150
-		tw.usedBinary = true
151
-		f.formatNumeric(b, x)
152
-	}
153
-
154
-	// Handle out of range ModTime carefully.
155
-	var modTime int64
156
-	if !hdr.ModTime.Before(minTime) && !hdr.ModTime.After(maxTime) {
157
-		modTime = hdr.ModTime.Unix()
158
-	}
159
-
160
-	v7 := header.V7()
161
-	formatString(v7.Name(), hdr.Name, paxPath)
162
-	// TODO(dsnet): The GNU format permits the mode field to be encoded in
163
-	// base-256 format. Thus, we can use formatNumeric instead of formatOctal.
164
-	f.formatOctal(v7.Mode(), hdr.Mode)
165
-	formatNumeric(v7.UID(), int64(hdr.Uid), paxUid)
166
-	formatNumeric(v7.GID(), int64(hdr.Gid), paxGid)
167
-	formatNumeric(v7.Size(), hdr.Size, paxSize)
168
-	// TODO(dsnet): Consider using PAX for finer time granularity.
169
-	formatNumeric(v7.ModTime(), modTime, paxNone)
170
-	v7.TypeFlag()[0] = hdr.Typeflag
171
-	formatString(v7.LinkName(), hdr.Linkname, paxLinkpath)
172
-
173
-	ustar := header.USTAR()
174
-	formatString(ustar.UserName(), hdr.Uname, paxUname)
175
-	formatString(ustar.GroupName(), hdr.Gname, paxGname)
176
-	formatNumeric(ustar.DevMajor(), hdr.Devmajor, paxNone)
177
-	formatNumeric(ustar.DevMinor(), hdr.Devminor, paxNone)
178
-
179
-	// TODO(dsnet): The logic surrounding the prefix field is broken when trying
180
-	// to encode the header as GNU format. The challenge with the current logic
181
-	// is that we are unsure what format we are using at any given moment until
182
-	// we have processed *all* of the fields. The problem is that by the time
183
-	// all fields have been processed, some work has already been done to handle
184
-	// each field under the assumption that it is for one given format or
185
-	// another. In some situations, this causes the Writer to be confused and
186
-	// encode a prefix field when the format being used is GNU. Thus, producing
187
-	// an invalid tar file.
188
-	//
189
-	// As a short-term fix, we disable the logic to use the prefix field, which
190
-	// will force the badly generated GNU files to become encoded as being
191
-	// the PAX format.
192
-	//
193
-	// As an alternative fix, we could hard-code preferPax to be true. However,
194
-	// this is problematic for the following reasons:
195
-	//	* The preferPax functionality is not tested at all.
196
-	//	* This can result in headers that try to use both the GNU and PAX
197
-	//	features at the same time, which is also wrong.
198
-	//
199
-	// The proper fix for this is to use a two-pass method:
200
-	//	* The first pass simply determines what set of formats can possibly
201
-	//	encode the given header.
202
-	//	* The second pass actually encodes the header as that given format
203
-	//	without worrying about violating the format.
204
-	//
205
-	// See the following:
206
-	//	https://golang.org/issue/12594
207
-	//	https://golang.org/issue/17630
208
-	//	https://golang.org/issue/9683
209
-	const usePrefix = false
210
-
211
-	// try to use a ustar header when only the name is too long
212
-	_, paxPathUsed := paxHeaders[paxPath]
213
-	if usePrefix && !tw.preferPax && len(paxHeaders) == 1 && paxPathUsed {
214
-		prefix, suffix, ok := splitUSTARPath(hdr.Name)
215
-		if ok {
216
-			// Since we can encode in USTAR format, disable PAX header.
217
-			delete(paxHeaders, paxPath)
218
-
219
-			// Update the path fields
220
-			formatString(v7.Name(), suffix, paxNone)
221
-			formatString(ustar.Prefix(), prefix, paxNone)
222
-		}
223
-	}
224
-
225
-	if tw.usedBinary {
226
-		header.SetFormat(formatGNU)
227
-	} else {
228
-		header.SetFormat(formatUSTAR)
229
-	}
230
-
231
-	// Check if there were any formatting errors.
232
-	if f.err != nil {
233
-		tw.err = f.err
234
-		return tw.err
235
-	}
236
-
237
-	if allowPax {
238
-		for k, v := range hdr.Xattrs {
239
-			paxHeaders[paxXattr+k] = v
240
-		}
241
-	}
242
-
243
-	if len(paxHeaders) > 0 {
244
-		if !allowPax {
245
-			return errInvalidHeader
246
-		}
247
-		if err := tw.writePAXHeader(hdr, paxHeaders); err != nil {
248
-			return err
249
-		}
250
-	}
251
-	tw.nb = hdr.Size
252
-	tw.pad = (blockSize - (tw.nb % blockSize)) % blockSize
253
-
254
-	_, tw.err = tw.w.Write(header[:])
255
-	return tw.err
256
-}
257
-
258
-// splitUSTARPath splits a path according to USTAR prefix and suffix rules.
259
-// If the path is not splittable, then it will return ("", "", false).
260
-func splitUSTARPath(name string) (prefix, suffix string, ok bool) {
261
-	length := len(name)
262
-	if length <= nameSize || !isASCII(name) {
263
-		return "", "", false
264
-	} else if length > prefixSize+1 {
265
-		length = prefixSize + 1
266
-	} else if name[length-1] == '/' {
267
-		length--
268
-	}
269
-
270
-	i := strings.LastIndex(name[:length], "/")
271
-	nlen := len(name) - i - 1 // nlen is length of suffix
272
-	plen := i                 // plen is length of prefix
273
-	if i <= 0 || nlen > nameSize || nlen == 0 || plen > prefixSize {
274
-		return "", "", false
275
-	}
276
-	return name[:i], name[i+1:], true
277
-}
278
-
279
-// writePaxHeader writes an extended pax header to the
280
-// archive.
281
-func (tw *Writer) writePAXHeader(hdr *Header, paxHeaders map[string]string) error {
282
-	// Prepare extended header
283
-	ext := new(Header)
284
-	ext.Typeflag = TypeXHeader
285
-	// Setting ModTime is required for reader parsing to
286
-	// succeed, and seems harmless enough.
287
-	ext.ModTime = hdr.ModTime
288
-	// The spec asks that we namespace our pseudo files
289
-	// with the current pid. However, this results in differing outputs
290
-	// for identical inputs. As such, the constant 0 is now used instead.
291
-	// golang.org/issue/12358
292
-	dir, file := path.Split(hdr.Name)
293
-	fullName := path.Join(dir, "PaxHeaders.0", file)
294
-
295
-	ascii := toASCII(fullName)
296
-	if len(ascii) > nameSize {
297
-		ascii = ascii[:nameSize]
298
-	}
299
-	ext.Name = ascii
300
-	// Construct the body
301
-	var buf bytes.Buffer
302
-
303
-	// Keys are sorted before writing to body to allow deterministic output.
304
-	keys := make([]string, 0, len(paxHeaders))
305
-	for k := range paxHeaders {
306
-		keys = append(keys, k)
307
-	}
308
-	sort.Strings(keys)
309
-
310
-	for _, k := range keys {
311
-		fmt.Fprint(&buf, formatPAXRecord(k, paxHeaders[k]))
312
-	}
313
-
314
-	ext.Size = int64(len(buf.Bytes()))
315
-	if err := tw.writeHeader(ext, false); err != nil {
316
-		return err
317
-	}
318
-	if _, err := tw.Write(buf.Bytes()); err != nil {
319
-		return err
320
-	}
321
-	if err := tw.Flush(); err != nil {
322
-		return err
323
-	}
324
-	return nil
325
-}
326
-
327
-// Write writes to the current entry in the tar archive.
328
-// Write returns the error ErrWriteTooLong if more than
329
-// hdr.Size bytes are written after WriteHeader.
330
-func (tw *Writer) Write(b []byte) (n int, err error) {
331
-	if tw.closed {
332
-		err = ErrWriteAfterClose
333
-		return
334
-	}
335
-	overwrite := false
336
-	if int64(len(b)) > tw.nb {
337
-		b = b[0:tw.nb]
338
-		overwrite = true
339
-	}
340
-	n, err = tw.w.Write(b)
341
-	tw.nb -= int64(n)
342
-	if err == nil && overwrite {
343
-		err = ErrWriteTooLong
344
-		return
345
-	}
346
-	tw.err = err
347
-	return
348
-}
349
-
350
-// Close closes the tar archive, flushing any unwritten
351
-// data to the underlying writer.
352
-func (tw *Writer) Close() error {
353
-	if tw.err != nil || tw.closed {
354
-		return tw.err
355
-	}
356
-	tw.Flush()
357
-	tw.closed = true
358
-	if tw.err != nil {
359
-		return tw.err
360
-	}
361
-
362
-	// trailer: two zero blocks
363
-	for i := 0; i < 2; i++ {
364
-		_, tw.err = tw.w.Write(zeroBlock[:])
365
-		if tw.err != nil {
366
-			break
367
-		}
368
-	}
369
-	return tw.err
370
-}