8
8
// - catch more errors (no first header, etc.)
18
23
ErrWriteTooLong = errors.New("archive/tar: write too long")
19
24
ErrFieldTooLong = errors.New("archive/tar: header field too long")
20
25
ErrWriteAfterClose = errors.New("archive/tar: write after close")
26
errNameTooLong = errors.New("archive/tar: name too long")
23
29
// A Writer provides sequential writing of a tar archive in POSIX.1 format.
24
30
// A tar archive consists of a sequence of files.
25
31
// Call WriteHeader to begin a new file, and then call Write to supply that file's data,
26
32
// writing at most hdr.Size bytes in total.
29
// tw := tar.NewWriter(w)
31
// hdr.Size = length of data in bytes
32
// // populate other hdr fields as desired
33
// if err := tw.WriteHeader(hdr); err != nil {
38
33
type Writer struct {
123
124
if tw.err != nil {
127
// Decide whether or not to use PAX extensions
128
// TODO(shanemhansen): we might want to use PAX headers for
129
// subsecond time resolution, but for now let's just capture
130
// the long name/long symlink use case.
133
if len(hdr.Name) > fileNameSize || len(hdr.Linkname) > fileNameSize {
135
prefix, suffix, err = tw.splitUSTARLongName(hdr.Name)
136
// Either we were unable to pack the long name into ustar format
137
// or the link name is too long; use PAX headers.
138
if err == errNameTooLong || len(hdr.Linkname) > fileNameSize {
139
if err := tw.writePAXHeader(hdr); err != nil {
142
} else if err != nil {
127
146
tw.nb = int64(hdr.Size)
128
147
tw.pad = -tw.nb & (blockSize - 1) // blockSize is a power of two
130
149
header := make([]byte, blockSize)
131
150
s := slicer(header)
133
// TODO(dsymonds): handle names longer than 100 chars
134
copy(s.next(100), []byte(hdr.Name))
136
tw.octal(s.next(8), hdr.Mode) // 100:108
137
tw.numeric(s.next(8), int64(hdr.Uid)) // 108:116
138
tw.numeric(s.next(8), int64(hdr.Gid)) // 116:124
139
tw.numeric(s.next(12), hdr.Size) // 124:136
140
tw.numeric(s.next(12), hdr.ModTime.Unix()) // 136:148
141
s.next(8) // chksum (148:156)
142
s.next(1)[0] = hdr.Typeflag // 156:157
143
tw.cString(s.next(100), hdr.Linkname) // linkname (157:257)
144
copy(s.next(8), []byte("ustar\x0000")) // 257:265
145
tw.cString(s.next(32), hdr.Uname) // 265:297
146
tw.cString(s.next(32), hdr.Gname) // 297:329
147
tw.numeric(s.next(8), hdr.Devmajor) // 329:337
148
tw.numeric(s.next(8), hdr.Devminor) // 337:345
151
tw.cString(s.next(fileNameSize), suffix)
153
// Handle out of range ModTime carefully.
155
if !hdr.ModTime.Before(minTime) && !hdr.ModTime.After(maxTime) {
156
modTime = hdr.ModTime.Unix()
159
tw.octal(s.next(8), hdr.Mode) // 100:108
160
tw.numeric(s.next(8), int64(hdr.Uid)) // 108:116
161
tw.numeric(s.next(8), int64(hdr.Gid)) // 116:124
162
tw.numeric(s.next(12), hdr.Size) // 124:136
163
tw.numeric(s.next(12), modTime) // 136:148
164
s.next(8) // chksum (148:156)
165
s.next(1)[0] = hdr.Typeflag // 156:157
166
tw.cString(s.next(100), hdr.Linkname) // linkname (157:257)
167
copy(s.next(8), []byte("ustar\x0000")) // 257:265
168
tw.cString(s.next(32), hdr.Uname) // 265:297
169
tw.cString(s.next(32), hdr.Gname) // 297:329
170
tw.numeric(s.next(8), hdr.Devmajor) // 329:337
171
tw.numeric(s.next(8), hdr.Devminor) // 337:345
172
tw.cString(s.next(155), prefix) // 345:500
150
173
// Use the GNU magic instead of POSIX magic if we used any GNU extensions.
151
174
if tw.usedBinary {
152
175
copy(header[257:265], []byte("ustar \x00"))
177
// Use the ustar magic if we used ustar long names.
179
copy(header[257:265], []byte("ustar\000"))
155
182
// The chksum field is terminated by a NUL and a space.
156
183
// This is different from the other octal fields.
198
// writeUSTARLongName splits a USTAR long name hdr.Name.
199
// name must be < 256 characters. errNameTooLong is returned
200
// if hdr.Name can't be split. The splitting heuristic
201
// is compatible with gnu tar.
202
func (tw *Writer) splitUSTARLongName(name string) (prefix, suffix string, err error) {
204
if length > fileNamePrefixSize+1 {
205
length = fileNamePrefixSize + 1
206
} else if name[length-1] == '/' {
209
i := strings.LastIndex(name[:length], "/")
210
nlen := length - i - 1
211
if i <= 0 || nlen > fileNameSize || nlen == 0 {
215
prefix, suffix = name[:i], name[i+1:]
219
// writePaxHeader writes an extended pax header to the
221
func (tw *Writer) writePAXHeader(hdr *Header) error {
222
// Prepare extended header
224
ext.Typeflag = TypeXHeader
225
// Setting ModTime is required for reader parsing to
226
// succeed, and seems harmless enough.
227
ext.ModTime = hdr.ModTime
228
// The spec asks that we namespace our pseudo files
229
// with the current pid.
231
dir, file := path.Split(hdr.Name)
232
ext.Name = path.Join(dir,
233
fmt.Sprintf("PaxHeaders.%d", pid), file)[0:100]
234
// Construct the body
236
if len(hdr.Name) > fileNameSize {
237
fmt.Fprint(&buf, paxHeader("path="+hdr.Name))
239
if len(hdr.Linkname) > fileNameSize {
240
fmt.Fprint(&buf, paxHeader("linkpath="+hdr.Linkname))
242
ext.Size = int64(len(buf.Bytes()))
243
if err := tw.WriteHeader(ext); err != nil {
246
if _, err := tw.Write(buf.Bytes()); err != nil {
249
if err := tw.Flush(); err != nil {
255
// paxHeader formats a single pax record, prefixing it with the appropriate length
256
func paxHeader(msg string) string {
257
const padding = 2 // Extra padding for space and newline
258
size := len(msg) + padding
259
size += len(strconv.Itoa(size))
260
record := fmt.Sprintf("%d %s\n", size, msg)
261
if len(record) != size {
262
// Final adjustment if adding size increased
263
// the number of digits in size
265
record = fmt.Sprintf("%d %s\n", size, msg)
171
270
// Write writes to the current entry in the tar archive.
172
271
// Write returns the error ErrWriteTooLong if more than
173
272
// hdr.Size bytes are written after WriteHeader.