paxHdrs = make(map[string]string)
verifyString := func(s string, size int, gnuLong bool, paxKey string) {
+
// NUL-terminator is optional for path and linkpath.
// Technically, it is required for uname and gname,
// but neither GNU nor BSD tar checks for it.
format &^= formatGNU // No GNU
}
if !isASCII(s) || tooLong {
- // TODO(dsnet): If the path is splittable, it is possible to still
- // use the USTAR format.
- format &^= formatUSTAR // No USTAR
+ canSplitUSTAR := paxKey == paxPath
+ if _, _, ok := splitUSTARPath(s); !canSplitUSTAR || !ok {
+ format &^= formatUSTAR // No USTAR
+ }
if paxKey == paxNone {
format &^= formatPAX // No PAX
} else {
pad int64 // amount of padding to write after current file entry
closed bool
- blk block // Buffer to use as temporary local storage
+ hdr Header // Shallow copy of Header that is safe for mutations
+ blk block // Buffer to use as temporary local storage
}
// NewWriter creates a new Writer writing to w.
return err
}
- switch allowedFormats, paxHdrs := hdr.allowedFormats(); {
+ tw.hdr = *hdr // Shallow copy of Header
+ switch allowedFormats, paxHdrs := tw.hdr.allowedFormats(); {
case allowedFormats&formatUSTAR != 0:
- return tw.writeUSTARHeader(hdr)
+ return tw.writeUSTARHeader(&tw.hdr)
case allowedFormats&formatPAX != 0:
- return tw.writePAXHeader(hdr, paxHdrs)
+ return tw.writePAXHeader(&tw.hdr, paxHdrs)
case allowedFormats&formatGNU != 0:
- return tw.writeGNUHeader(hdr)
+ return tw.writeGNUHeader(&tw.hdr)
default:
return ErrHeader
}
}
func (tw *Writer) writeUSTARHeader(hdr *Header) error {
- // TODO(dsnet): Support USTAR prefix/suffix path splitting.
- // See https://golang.org/issue/12594
+ // Check if we can use USTAR prefix/suffix splitting.
+ var namePrefix string
+ if prefix, suffix, ok := splitUSTARPath(hdr.Name); ok {
+ namePrefix, hdr.Name = prefix, suffix
+ }
// Pack the main header.
var f formatter
blk := tw.templateV7Plus(hdr, f.formatString, f.formatOctal)
+ f.formatString(blk.USTAR().Prefix(), namePrefix)
blk.SetFormat(formatUSTAR)
if f.err != nil {
return f.err // Should never happen since header is validated
contents: strings.Repeat("\x00", 4<<10),
}},
}, {
- // TODO(dsnet): The Writer output should match the following file.
- // To fix an issue (see https://golang.org/issue/12594), we disabled
- // prefix support, which alters the generated output.
- /*
- // This file was produced using gnu tar 1.17
- // gnutar -b 4 --format=ustar (longname/)*15 + file.txt
- file: "testdata/ustar.tar"
- */
- file: "testdata/ustar.issue12594.tar", // This is a valid tar file, but not expected
+ // This file was produced using GNU tar v1.17.
+ // gnutar -b 4 --format=ustar (longname/)*15 + file.txt
+ file: "testdata/ustar.tar",
entries: []*entry{{
header: &Header{
Name: strings.Repeat("longname/", 15) + "file.txt",