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.
8 // - catch more errors (no first header, etc.)
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")
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.
36 nb
int64 // number of unwritten bytes for current file entry
37 pad
int64 // amount of padding to write after current file entry
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
45 // NewWriter creates a new Writer writing to w.
46 func NewWriter(w io
.Writer
) *Writer
{ return &Writer
{w
: w
} }
48 // Flush finishes writing the current file (optional).
49 func (tw
*Writer
) Flush() error
{
51 tw
.err
= fmt
.Errorf("archive/tar: missed writing %d bytes", tw
.nb
)
56 for n
> 0 && tw
.err
== nil {
62 nw
, tw
.err
= tw
.w
.Write(zeroBlock
[0:nr
])
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
)
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)
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
{
90 return ErrWriteAfterClose
99 // a map to hold pax header records, if any are needed
100 paxHeaders
:= make(map[string]string)
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
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
113 header
= &tw
.paxHdrBuff
115 copy(header
[:], zeroBlock
[:])
117 // Wrappers around formatter that automatically sets paxHeaders if the
118 // argument extends beyond the capacity of the input byte slice.
120 var formatString
= func(b
[]byte, s
string, paxKeyword
string) {
121 needsPaxHeader
:= paxKeyword
!= paxNone
&& len(s
) > len(b
) ||
!isASCII(s
)
123 paxHeaders
[paxKeyword
] = s
126 // Write string in a best-effort manner to satisfy readers that expect
127 // the field to be non-empty.
132 f
.formatString(b
, s
) // Should never error
134 var formatNumeric
= func(b
[]byte, x
int64, paxKeyword
string) {
136 s
:= strconv
.FormatInt(x
, 8)
142 // If it is too long for octal, and PAX is preferred, use a PAX header.
143 if paxKeyword
!= paxNone
&& tw
.preferPax
{
145 s
:= strconv
.FormatInt(x
, 10)
146 paxHeaders
[paxKeyword
] = s
151 f
.formatNumeric(b
, x
)
154 // Handle out of range ModTime carefully.
156 if !hdr
.ModTime
.Before(minTime
) && !hdr
.ModTime
.After(maxTime
) {
157 modTime
= hdr
.ModTime
.Unix()
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
)
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
)
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.
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
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.
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.
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
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
)
216 // Since we can encode in USTAR format, disable PAX header.
217 delete(paxHeaders
, paxPath
)
219 // Update the path fields
220 formatString(v7
.Name(), suffix
, paxNone
)
221 formatString(ustar
.Prefix(), prefix
, paxNone
)
226 header
.SetFormat(formatGNU
)
228 header
.SetFormat(formatUSTAR
)
231 // Check if there were any formatting errors.
238 for k
, v
:= range hdr
.Xattrs
{
239 paxHeaders
[paxXattr
+k
] = v
243 if len(paxHeaders
) > 0 {
245 return errInvalidHeader
247 if err
:= tw
.writePAXHeader(hdr
, paxHeaders
); err
!= nil {
252 tw
.pad
= (blockSize
- (tw
.nb
% blockSize
)) % blockSize
254 _
, tw
.err
= tw
.w
.Write(header
[:])
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) {
262 if length
<= nameSize ||
!isASCII(name
) {
264 } else if length
> prefixSize
+1 {
265 length
= prefixSize
+ 1
266 } else if name
[length
-1] == '/' {
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
{
276 return name
[:i
], name
[i
+1:], true
279 // writePaxHeader writes an extended pax header to the
281 func (tw
*Writer
) writePAXHeader(hdr
*Header
, paxHeaders
map[string]string) error
{
282 // Prepare extended 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
)
295 ascii
:= toASCII(fullName
)
296 if len(ascii
) > nameSize
{
297 ascii
= ascii
[:nameSize
]
300 // Construct the body
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
)
310 for _
, k
:= range keys
{
311 fmt
.Fprint(&buf
, formatPAXRecord(k
, paxHeaders
[k
]))
314 ext
.Size
= int64(len(buf
.Bytes()))
315 if err
:= tw
.writeHeader(ext
, false); err
!= nil {
318 if _
, err
:= tw
.Write(buf
.Bytes()); err
!= nil {
321 if err
:= tw
.Flush(); err
!= nil {
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
) {
332 err
= ErrWriteAfterClose
336 if int64(len(b
)) > tw
.nb
{
340 n
, err
= tw
.w
.Write(b
)
342 if err
== nil && overwrite
{
343 err
= ErrWriteTooLong
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 {
362 // trailer: two zero blocks
363 for i
:= 0; i
< 2; i
++ {
364 _
, tw
.err
= tw
.w
.Write(zeroBlock
[:])