Commit ffd9810e authored by Joe Tsai's avatar Joe Tsai Committed by Joe Tsai

archive/tar: implement specialized logic for GNU format

Rather than going through writeHeader, which attempts to handle all formats,
implement writeGNUHeader, which only has an understanding of the GNU format.

Currently, the implementation is nearly identical to writeUSTARHeader, except:
* formatNumeric is used instead of formatOctal
* the GNU magic value is used

This is kept as a separate method since it makes more logical sense
when we add support for sparse files, long filenames, and atime/ctime fields,
which do not affect USTAR.

Updates #12594

Change-Id: I76efc0b39dc649efc22646dfc9867a7c165f34a8
Reviewed-on: https://go-review.googlesource.com/55237
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarMartin Möhrmann <moehrmann@google.com>
parent d180d186
......@@ -89,8 +89,7 @@ func (tw *Writer) WriteHeader(hdr *Header) error {
case allowedFormats&formatPAX != 0:
return tw.writePAXHeader(&hdrCpy, paxHdrs)
case allowedFormats&formatGNU != 0:
// TODO(dsnet): Implement and call specialized writeGNUHeader.
return tw.writeHeader(&hdrCpy, true)
return tw.writeGNUHeader(&hdrCpy)
default:
return ErrHeader
}
......@@ -102,7 +101,7 @@ func (tw *Writer) writeUSTARHeader(hdr *Header) error {
// Pack the main header.
var f formatter
blk := tw.templateV7Plus(hdr, &f)
blk := tw.templateV7Plus(hdr, f.formatString, f.formatOctal)
blk.SetFormat(formatUSTAR)
if f.err != nil {
return f.err // Should never happen since header is validated
......@@ -141,7 +140,7 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHdrs map[string]string) error {
// Pack the main header.
var f formatter
blk := tw.templateV7Plus(hdr, &f)
blk := tw.templateV7Plus(hdr, f.formatString, f.formatOctal)
blk.SetFormat(formatPAX)
if f.err != nil && len(paxHdrs) == 0 {
return f.err // Should never happen, otherwise PAX headers would be used
......@@ -149,12 +148,36 @@ func (tw *Writer) writePAXHeader(hdr *Header, paxHdrs map[string]string) error {
return tw.writeRawHeader(blk, hdr.Size)
}
func (tw *Writer) writeGNUHeader(hdr *Header) error {
// TODO(dsnet): Support writing sparse files.
// See https://golang.org/issue/13548
// TODO(dsnet): Support long filenames (with UTF-8) support.
// Pack the main header.
var f formatter
blk := tw.templateV7Plus(hdr, f.formatString, f.formatNumeric)
// TODO(dsnet): Support atime and ctime fields.
// See https://golang.org/issue/17876
blk.SetFormat(formatGNU)
if f.err != nil {
return f.err // Should never happen since header is validated
}
return tw.writeRawHeader(blk, hdr.Size)
}
type (
stringFormatter func([]byte, string)
numberFormatter func([]byte, int64)
)
// templateV7Plus fills out the V7 fields of a block using values from hdr.
// It also fills out fields (uname, gname, devmajor, devminor) that are
// shared in the USTAR, PAX, and GNU formats.
// shared in the USTAR, PAX, and GNU formats using the provided formatters.
//
// The block returned is only valid until the next call to templateV7Plus.
func (tw *Writer) templateV7Plus(hdr *Header, f *formatter) *block {
// The block returned is only valid until the next call to
// templateV7Plus or writeRawFile.
func (tw *Writer) templateV7Plus(hdr *Header, fmtStr stringFormatter, fmtNum numberFormatter) *block {
tw.blk.Reset()
modTime := hdr.ModTime
......@@ -164,19 +187,19 @@ func (tw *Writer) templateV7Plus(hdr *Header, f *formatter) *block {
v7 := tw.blk.V7()
v7.TypeFlag()[0] = hdr.Typeflag
f.formatString(v7.Name(), hdr.Name)
f.formatString(v7.LinkName(), hdr.Linkname)
f.formatOctal(v7.Mode(), hdr.Mode)
f.formatOctal(v7.UID(), int64(hdr.Uid))
f.formatOctal(v7.GID(), int64(hdr.Gid))
f.formatOctal(v7.Size(), hdr.Size)
f.formatOctal(v7.ModTime(), modTime.Unix())
fmtStr(v7.Name(), hdr.Name)
fmtStr(v7.LinkName(), hdr.Linkname)
fmtNum(v7.Mode(), hdr.Mode)
fmtNum(v7.UID(), int64(hdr.Uid))
fmtNum(v7.GID(), int64(hdr.Gid))
fmtNum(v7.Size(), hdr.Size)
fmtNum(v7.ModTime(), modTime.Unix())
ustar := tw.blk.USTAR()
f.formatString(ustar.UserName(), hdr.Uname)
f.formatString(ustar.GroupName(), hdr.Gname)
f.formatOctal(ustar.DevMajor(), hdr.Devmajor)
f.formatOctal(ustar.DevMinor(), hdr.Devminor)
fmtStr(ustar.UserName(), hdr.Uname)
fmtStr(ustar.GroupName(), hdr.Gname)
fmtNum(ustar.DevMajor(), hdr.Devmajor)
fmtNum(ustar.DevMinor(), hdr.Devminor)
return &tw.blk
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment