From: Joe Tsai Date: Mon, 14 Aug 2017 07:03:26 +0000 (-0700) Subject: archive/tar: implement specialized logic for GNU format X-Git-Tag: go1.10beta1~1589 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=ffd9810e5966c8ad972f429866808b73bbefd8bc;p=gostls13.git 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 TryBot-Result: Gobot Gobot Reviewed-by: Martin Möhrmann --- diff --git a/src/archive/tar/writer.go b/src/archive/tar/writer.go index 8572c46335..c4d908c4ea 100644 --- a/src/archive/tar/writer.go +++ b/src/archive/tar/writer.go @@ -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 }