mirror of
https://github.com/golang/go
synced 2024-11-24 07:30:10 -07:00
archive/tar: implement specialized logic for USTAR format
Rather than going through the complicated logic of writeHeader, implement a writeUSTARHeader that only knows about the USTAR format. This makes the logic much easier to reason about since you only need to be concerned about USTAR and not all the subtle differences between USTAR, PAX, and GNU. We seperate out the logic in writeUSTARHeader into templateV7Plus and writeRawHeader since the planned implementations of writePAXHeader and writeGNUHeader will use them. Change-Id: Ie75a54ac998420ece82686159ae6fa39f8b128e9 Reviewed-on: https://go-review.googlesource.com/54970 Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
812124a567
commit
0d1a8f6e12
@ -134,6 +134,11 @@ func (b *block) ComputeChecksum() (unsigned, signed int64) {
|
|||||||
return unsigned, signed
|
return unsigned, signed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset clears the block with all zeros.
|
||||||
|
func (b *block) Reset() {
|
||||||
|
*b = block{}
|
||||||
|
}
|
||||||
|
|
||||||
type headerV7 [blockSize]byte
|
type headerV7 [blockSize]byte
|
||||||
|
|
||||||
func (h *headerV7) Name() []byte { return h[000:][:100] }
|
func (h *headerV7) Name() []byte { return h[000:][:100] }
|
||||||
|
@ -40,6 +40,8 @@ type Writer struct {
|
|||||||
preferPax bool // use PAX header instead of binary numeric header
|
preferPax bool // use PAX header instead of binary numeric header
|
||||||
hdrBuff block // buffer to use in writeHeader when writing a regular header
|
hdrBuff block // buffer to use in writeHeader when writing a regular header
|
||||||
paxHdrBuff block // buffer to use in writeHeader when writing a PAX header
|
paxHdrBuff block // buffer to use in writeHeader when writing a PAX header
|
||||||
|
|
||||||
|
blk block // Buffer to use as temporary local storage
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWriter creates a new Writer writing to w.
|
// NewWriter creates a new Writer writing to w.
|
||||||
@ -82,13 +84,12 @@ func (tw *Writer) WriteHeader(hdr *Header) error {
|
|||||||
hdrCpy.ModTime = hdrCpy.ModTime.Truncate(time.Second)
|
hdrCpy.ModTime = hdrCpy.ModTime.Truncate(time.Second)
|
||||||
|
|
||||||
switch allowedFormats, _ := hdrCpy.allowedFormats(); {
|
switch allowedFormats, _ := hdrCpy.allowedFormats(); {
|
||||||
case allowedFormats&formatUSTAR > 0:
|
case allowedFormats&formatUSTAR != 0:
|
||||||
// TODO(dsnet): Implement and call specialized writeUSTARHeader.
|
return tw.writeUSTARHeader(&hdrCpy)
|
||||||
return tw.writeHeader(&hdrCpy, true)
|
case allowedFormats&formatPAX != 0:
|
||||||
case allowedFormats&formatPAX > 0:
|
|
||||||
// TODO(dsnet): Implement and call specialized writePAXHeader.
|
// TODO(dsnet): Implement and call specialized writePAXHeader.
|
||||||
return tw.writeHeader(&hdrCpy, true)
|
return tw.writeHeader(&hdrCpy, true)
|
||||||
case allowedFormats&formatGNU > 0:
|
case allowedFormats&formatGNU != 0:
|
||||||
// TODO(dsnet): Implement and call specialized writeGNUHeader.
|
// TODO(dsnet): Implement and call specialized writeGNUHeader.
|
||||||
return tw.writeHeader(&hdrCpy, true)
|
return tw.writeHeader(&hdrCpy, true)
|
||||||
default:
|
default:
|
||||||
@ -96,6 +97,68 @@ func (tw *Writer) WriteHeader(hdr *Header) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tw *Writer) writeUSTARHeader(hdr *Header) error {
|
||||||
|
// TODO(dsnet): Support USTAR prefix/suffix path splitting.
|
||||||
|
// See https://golang.org/issue/12594
|
||||||
|
|
||||||
|
// Pack the main header.
|
||||||
|
var f formatter
|
||||||
|
blk := tw.templateV7Plus(hdr, &f)
|
||||||
|
blk.SetFormat(formatUSTAR)
|
||||||
|
if f.err != nil {
|
||||||
|
return f.err // Should never happen since header is validated
|
||||||
|
}
|
||||||
|
return tw.writeRawHeader(blk, hdr.Size)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// The block returned is only valid until the next call to templateV7Plus.
|
||||||
|
func (tw *Writer) templateV7Plus(hdr *Header, f *formatter) *block {
|
||||||
|
tw.blk.Reset()
|
||||||
|
|
||||||
|
modTime := hdr.ModTime
|
||||||
|
if modTime.IsZero() {
|
||||||
|
modTime = time.Unix(0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
return &tw.blk
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeRawHeader writes the value of blk, regardless of its value.
|
||||||
|
// It sets up the Writer such that it can accept a file of the given size.
|
||||||
|
func (tw *Writer) writeRawHeader(blk *block, size int64) error {
|
||||||
|
if err := tw.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := tw.w.Write(blk[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// TODO(dsnet): Set Size implicitly to zero for header-only entries.
|
||||||
|
// See https://golang.org/issue/15565
|
||||||
|
tw.nb = size
|
||||||
|
tw.pad = -size & (blockSize - 1) // blockSize is a power of two
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// WriteHeader writes hdr and prepares to accept the file's contents.
|
// WriteHeader writes hdr and prepares to accept the file's contents.
|
||||||
// WriteHeader calls Flush if it is not the first header.
|
// WriteHeader calls Flush if it is not the first header.
|
||||||
// Calling after a Close will return ErrWriteAfterClose.
|
// Calling after a Close will return ErrWriteAfterClose.
|
||||||
|
Loading…
Reference in New Issue
Block a user