// fileState tracks the number of logical (includes sparse holes) and physical
// (actual in tar archive) bytes remaining for the current file.
//
-// Invariant: LogicalRemaining >= PhysicalRemaining
+// Invariant: logicalRemaining >= physicalRemaining
type fileState interface {
- LogicalRemaining() int64
- PhysicalRemaining() int64
+ logicalRemaining() int64
+ physicalRemaining() int64
}
// allowedFormats determines which formats can be used.
// Check basic fields.
var blk block
- v7 := blk.V7()
- ustar := blk.USTAR()
- gnu := blk.GNU()
- verifyString(h.Name, len(v7.Name()), "Name", paxPath)
- verifyString(h.Linkname, len(v7.LinkName()), "Linkname", paxLinkpath)
- verifyString(h.Uname, len(ustar.UserName()), "Uname", paxUname)
- verifyString(h.Gname, len(ustar.GroupName()), "Gname", paxGname)
- verifyNumeric(h.Mode, len(v7.Mode()), "Mode", paxNone)
- verifyNumeric(int64(h.Uid), len(v7.UID()), "Uid", paxUid)
- verifyNumeric(int64(h.Gid), len(v7.GID()), "Gid", paxGid)
- verifyNumeric(h.Size, len(v7.Size()), "Size", paxSize)
- verifyNumeric(h.Devmajor, len(ustar.DevMajor()), "Devmajor", paxNone)
- verifyNumeric(h.Devminor, len(ustar.DevMinor()), "Devminor", paxNone)
- verifyTime(h.ModTime, len(v7.ModTime()), "ModTime", paxMtime)
- verifyTime(h.AccessTime, len(gnu.AccessTime()), "AccessTime", paxAtime)
- verifyTime(h.ChangeTime, len(gnu.ChangeTime()), "ChangeTime", paxCtime)
+ v7 := blk.toV7()
+ ustar := blk.toUSTAR()
+ gnu := blk.toGNU()
+ verifyString(h.Name, len(v7.name()), "Name", paxPath)
+ verifyString(h.Linkname, len(v7.linkName()), "Linkname", paxLinkpath)
+ verifyString(h.Uname, len(ustar.userName()), "Uname", paxUname)
+ verifyString(h.Gname, len(ustar.groupName()), "Gname", paxGname)
+ verifyNumeric(h.Mode, len(v7.mode()), "Mode", paxNone)
+ verifyNumeric(int64(h.Uid), len(v7.uid()), "Uid", paxUid)
+ verifyNumeric(int64(h.Gid), len(v7.gid()), "Gid", paxGid)
+ verifyNumeric(h.Size, len(v7.size()), "Size", paxSize)
+ verifyNumeric(h.Devmajor, len(ustar.devMajor()), "Devmajor", paxNone)
+ verifyNumeric(h.Devminor, len(ustar.devMinor()), "Devminor", paxNone)
+ verifyTime(h.ModTime, len(v7.modTime()), "ModTime", paxMtime)
+ verifyTime(h.AccessTime, len(gnu.accessTime()), "AccessTime", paxAtime)
+ verifyTime(h.ChangeTime, len(gnu.changeTime()), "ChangeTime", paxCtime)
// Check for header-only types.
var whyOnlyPAX, whyOnlyGNU string
type block [blockSize]byte
// Convert block to any number of formats.
-func (b *block) V7() *headerV7 { return (*headerV7)(b) }
-func (b *block) GNU() *headerGNU { return (*headerGNU)(b) }
-func (b *block) STAR() *headerSTAR { return (*headerSTAR)(b) }
-func (b *block) USTAR() *headerUSTAR { return (*headerUSTAR)(b) }
-func (b *block) Sparse() sparseArray { return sparseArray(b[:]) }
+func (b *block) toV7() *headerV7 { return (*headerV7)(b) }
+func (b *block) toGNU() *headerGNU { return (*headerGNU)(b) }
+func (b *block) toSTAR() *headerSTAR { return (*headerSTAR)(b) }
+func (b *block) toUSTAR() *headerUSTAR { return (*headerUSTAR)(b) }
+func (b *block) toSparse() sparseArray { return sparseArray(b[:]) }
// GetFormat checks that the block is a valid tar header based on the checksum.
// It then attempts to guess the specific format based on magic values.
// If the checksum fails, then FormatUnknown is returned.
-func (b *block) GetFormat() Format {
+func (b *block) getFormat() Format {
// Verify checksum.
var p parser
- value := p.parseOctal(b.V7().Chksum())
- chksum1, chksum2 := b.ComputeChecksum()
+ value := p.parseOctal(b.toV7().chksum())
+ chksum1, chksum2 := b.computeChecksum()
if p.err != nil || (value != chksum1 && value != chksum2) {
return FormatUnknown
}
// Guess the magic values.
- magic := string(b.USTAR().Magic())
- version := string(b.USTAR().Version())
- trailer := string(b.STAR().Trailer())
+ magic := string(b.toUSTAR().magic())
+ version := string(b.toUSTAR().version())
+ trailer := string(b.toSTAR().trailer())
switch {
case magic == magicUSTAR && trailer == trailerSTAR:
return formatSTAR
}
}
-// SetFormat writes the magic values necessary for specified format
+// setFormat writes the magic values necessary for specified format
// and then updates the checksum accordingly.
-func (b *block) SetFormat(format Format) {
+func (b *block) setFormat(format Format) {
// Set the magic values.
switch {
case format.has(formatV7):
// Do nothing.
case format.has(FormatGNU):
- copy(b.GNU().Magic(), magicGNU)
- copy(b.GNU().Version(), versionGNU)
+ copy(b.toGNU().magic(), magicGNU)
+ copy(b.toGNU().version(), versionGNU)
case format.has(formatSTAR):
- copy(b.STAR().Magic(), magicUSTAR)
- copy(b.STAR().Version(), versionUSTAR)
- copy(b.STAR().Trailer(), trailerSTAR)
+ copy(b.toSTAR().magic(), magicUSTAR)
+ copy(b.toSTAR().version(), versionUSTAR)
+ copy(b.toSTAR().trailer(), trailerSTAR)
case format.has(FormatUSTAR | FormatPAX):
- copy(b.USTAR().Magic(), magicUSTAR)
- copy(b.USTAR().Version(), versionUSTAR)
+ copy(b.toUSTAR().magic(), magicUSTAR)
+ copy(b.toUSTAR().version(), versionUSTAR)
default:
panic("invalid format")
}
// Update checksum.
// This field is special in that it is terminated by a NULL then space.
var f formatter
- field := b.V7().Chksum()
- chksum, _ := b.ComputeChecksum() // Possible values are 256..128776
+ field := b.toV7().chksum()
+ chksum, _ := b.computeChecksum() // Possible values are 256..128776
f.formatOctal(field[:7], chksum) // Never fails since 128776 < 262143
field[7] = ' '
}
-// ComputeChecksum computes the checksum for the header block.
+// computeChecksum computes the checksum for the header block.
// POSIX specifies a sum of the unsigned byte values, but the Sun tar used
// signed byte values.
// We compute and return both.
-func (b *block) ComputeChecksum() (unsigned, signed int64) {
+func (b *block) computeChecksum() (unsigned, signed int64) {
for i, c := range b {
if 148 <= i && i < 156 {
c = ' ' // Treat the checksum field itself as all spaces.
}
// Reset clears the block with all zeros.
-func (b *block) Reset() {
+func (b *block) reset() {
*b = block{}
}
type headerV7 [blockSize]byte
-func (h *headerV7) Name() []byte { return h[000:][:100] }
-func (h *headerV7) Mode() []byte { return h[100:][:8] }
-func (h *headerV7) UID() []byte { return h[108:][:8] }
-func (h *headerV7) GID() []byte { return h[116:][:8] }
-func (h *headerV7) Size() []byte { return h[124:][:12] }
-func (h *headerV7) ModTime() []byte { return h[136:][:12] }
-func (h *headerV7) Chksum() []byte { return h[148:][:8] }
-func (h *headerV7) TypeFlag() []byte { return h[156:][:1] }
-func (h *headerV7) LinkName() []byte { return h[157:][:100] }
+func (h *headerV7) name() []byte { return h[000:][:100] }
+func (h *headerV7) mode() []byte { return h[100:][:8] }
+func (h *headerV7) uid() []byte { return h[108:][:8] }
+func (h *headerV7) gid() []byte { return h[116:][:8] }
+func (h *headerV7) size() []byte { return h[124:][:12] }
+func (h *headerV7) modTime() []byte { return h[136:][:12] }
+func (h *headerV7) chksum() []byte { return h[148:][:8] }
+func (h *headerV7) typeFlag() []byte { return h[156:][:1] }
+func (h *headerV7) linkName() []byte { return h[157:][:100] }
type headerGNU [blockSize]byte
-func (h *headerGNU) V7() *headerV7 { return (*headerV7)(h) }
-func (h *headerGNU) Magic() []byte { return h[257:][:6] }
-func (h *headerGNU) Version() []byte { return h[263:][:2] }
-func (h *headerGNU) UserName() []byte { return h[265:][:32] }
-func (h *headerGNU) GroupName() []byte { return h[297:][:32] }
-func (h *headerGNU) DevMajor() []byte { return h[329:][:8] }
-func (h *headerGNU) DevMinor() []byte { return h[337:][:8] }
-func (h *headerGNU) AccessTime() []byte { return h[345:][:12] }
-func (h *headerGNU) ChangeTime() []byte { return h[357:][:12] }
-func (h *headerGNU) Sparse() sparseArray { return sparseArray(h[386:][:24*4+1]) }
-func (h *headerGNU) RealSize() []byte { return h[483:][:12] }
+func (h *headerGNU) v7() *headerV7 { return (*headerV7)(h) }
+func (h *headerGNU) magic() []byte { return h[257:][:6] }
+func (h *headerGNU) version() []byte { return h[263:][:2] }
+func (h *headerGNU) userName() []byte { return h[265:][:32] }
+func (h *headerGNU) groupName() []byte { return h[297:][:32] }
+func (h *headerGNU) devMajor() []byte { return h[329:][:8] }
+func (h *headerGNU) devMinor() []byte { return h[337:][:8] }
+func (h *headerGNU) accessTime() []byte { return h[345:][:12] }
+func (h *headerGNU) changeTime() []byte { return h[357:][:12] }
+func (h *headerGNU) sparse() sparseArray { return sparseArray(h[386:][:24*4+1]) }
+func (h *headerGNU) realSize() []byte { return h[483:][:12] }
type headerSTAR [blockSize]byte
-func (h *headerSTAR) V7() *headerV7 { return (*headerV7)(h) }
-func (h *headerSTAR) Magic() []byte { return h[257:][:6] }
-func (h *headerSTAR) Version() []byte { return h[263:][:2] }
-func (h *headerSTAR) UserName() []byte { return h[265:][:32] }
-func (h *headerSTAR) GroupName() []byte { return h[297:][:32] }
-func (h *headerSTAR) DevMajor() []byte { return h[329:][:8] }
-func (h *headerSTAR) DevMinor() []byte { return h[337:][:8] }
-func (h *headerSTAR) Prefix() []byte { return h[345:][:131] }
-func (h *headerSTAR) AccessTime() []byte { return h[476:][:12] }
-func (h *headerSTAR) ChangeTime() []byte { return h[488:][:12] }
-func (h *headerSTAR) Trailer() []byte { return h[508:][:4] }
+func (h *headerSTAR) v7() *headerV7 { return (*headerV7)(h) }
+func (h *headerSTAR) magic() []byte { return h[257:][:6] }
+func (h *headerSTAR) version() []byte { return h[263:][:2] }
+func (h *headerSTAR) userName() []byte { return h[265:][:32] }
+func (h *headerSTAR) groupName() []byte { return h[297:][:32] }
+func (h *headerSTAR) devMajor() []byte { return h[329:][:8] }
+func (h *headerSTAR) devMinor() []byte { return h[337:][:8] }
+func (h *headerSTAR) prefix() []byte { return h[345:][:131] }
+func (h *headerSTAR) accessTime() []byte { return h[476:][:12] }
+func (h *headerSTAR) changeTime() []byte { return h[488:][:12] }
+func (h *headerSTAR) trailer() []byte { return h[508:][:4] }
type headerUSTAR [blockSize]byte
-func (h *headerUSTAR) V7() *headerV7 { return (*headerV7)(h) }
-func (h *headerUSTAR) Magic() []byte { return h[257:][:6] }
-func (h *headerUSTAR) Version() []byte { return h[263:][:2] }
-func (h *headerUSTAR) UserName() []byte { return h[265:][:32] }
-func (h *headerUSTAR) GroupName() []byte { return h[297:][:32] }
-func (h *headerUSTAR) DevMajor() []byte { return h[329:][:8] }
-func (h *headerUSTAR) DevMinor() []byte { return h[337:][:8] }
-func (h *headerUSTAR) Prefix() []byte { return h[345:][:155] }
+func (h *headerUSTAR) v7() *headerV7 { return (*headerV7)(h) }
+func (h *headerUSTAR) magic() []byte { return h[257:][:6] }
+func (h *headerUSTAR) version() []byte { return h[263:][:2] }
+func (h *headerUSTAR) userName() []byte { return h[265:][:32] }
+func (h *headerUSTAR) groupName() []byte { return h[297:][:32] }
+func (h *headerUSTAR) devMajor() []byte { return h[329:][:8] }
+func (h *headerUSTAR) devMinor() []byte { return h[337:][:8] }
+func (h *headerUSTAR) prefix() []byte { return h[345:][:155] }
type sparseArray []byte
-func (s sparseArray) Entry(i int) sparseElem { return sparseElem(s[i*24:]) }
-func (s sparseArray) IsExtended() []byte { return s[24*s.MaxEntries():][:1] }
-func (s sparseArray) MaxEntries() int { return len(s) / 24 }
+func (s sparseArray) entry(i int) sparseElem { return sparseElem(s[i*24:]) }
+func (s sparseArray) isExtended() []byte { return s[24*s.maxEntries():][:1] }
+func (s sparseArray) maxEntries() int { return len(s) / 24 }
type sparseElem []byte
-func (s sparseElem) Offset() []byte { return s[00:][:12] }
-func (s sparseElem) Length() []byte { return s[12:][:12] }
+func (s sparseElem) offset() []byte { return s[00:][:12] }
+func (s sparseElem) length() []byte { return s[12:][:12] }
format := FormatUSTAR | FormatPAX | FormatGNU
for {
// Discard the remainder of the file and any padding.
- if err := discard(tr.r, tr.curr.PhysicalRemaining()); err != nil {
+ if err := discard(tr.r, tr.curr.physicalRemaining()); err != nil {
return nil, err
}
if _, err := tryReadFull(tr.r, tr.blk[:tr.pad]); err != nil {
}
// Verify the header matches a known format.
- format := tr.blk.GetFormat()
+ format := tr.blk.getFormat()
if format == FormatUnknown {
return nil, nil, ErrHeader
}
hdr := new(Header)
// Unpack the V7 header.
- v7 := tr.blk.V7()
- hdr.Typeflag = v7.TypeFlag()[0]
- hdr.Name = p.parseString(v7.Name())
- hdr.Linkname = p.parseString(v7.LinkName())
- hdr.Size = p.parseNumeric(v7.Size())
- hdr.Mode = p.parseNumeric(v7.Mode())
- hdr.Uid = int(p.parseNumeric(v7.UID()))
- hdr.Gid = int(p.parseNumeric(v7.GID()))
- hdr.ModTime = time.Unix(p.parseNumeric(v7.ModTime()), 0)
+ v7 := tr.blk.toV7()
+ hdr.Typeflag = v7.typeFlag()[0]
+ hdr.Name = p.parseString(v7.name())
+ hdr.Linkname = p.parseString(v7.linkName())
+ hdr.Size = p.parseNumeric(v7.size())
+ hdr.Mode = p.parseNumeric(v7.mode())
+ hdr.Uid = int(p.parseNumeric(v7.uid()))
+ hdr.Gid = int(p.parseNumeric(v7.gid()))
+ hdr.ModTime = time.Unix(p.parseNumeric(v7.modTime()), 0)
// Unpack format specific fields.
if format > formatV7 {
- ustar := tr.blk.USTAR()
- hdr.Uname = p.parseString(ustar.UserName())
- hdr.Gname = p.parseString(ustar.GroupName())
- hdr.Devmajor = p.parseNumeric(ustar.DevMajor())
- hdr.Devminor = p.parseNumeric(ustar.DevMinor())
+ ustar := tr.blk.toUSTAR()
+ hdr.Uname = p.parseString(ustar.userName())
+ hdr.Gname = p.parseString(ustar.groupName())
+ hdr.Devmajor = p.parseNumeric(ustar.devMajor())
+ hdr.Devminor = p.parseNumeric(ustar.devMinor())
var prefix string
switch {
case format.has(FormatUSTAR | FormatPAX):
hdr.Format = format
- ustar := tr.blk.USTAR()
- prefix = p.parseString(ustar.Prefix())
+ ustar := tr.blk.toUSTAR()
+ prefix = p.parseString(ustar.prefix())
// For Format detection, check if block is properly formatted since
// the parser is more liberal than what USTAR actually permits.
hdr.Format = FormatUnknown // Non-ASCII characters in block.
}
nul := func(b []byte) bool { return int(b[len(b)-1]) == 0 }
- if !(nul(v7.Size()) && nul(v7.Mode()) && nul(v7.UID()) && nul(v7.GID()) &&
- nul(v7.ModTime()) && nul(ustar.DevMajor()) && nul(ustar.DevMinor())) {
+ if !(nul(v7.size()) && nul(v7.mode()) && nul(v7.uid()) && nul(v7.gid()) &&
+ nul(v7.modTime()) && nul(ustar.devMajor()) && nul(ustar.devMinor())) {
hdr.Format = FormatUnknown // Numeric fields must end in NUL
}
case format.has(formatSTAR):
- star := tr.blk.STAR()
- prefix = p.parseString(star.Prefix())
- hdr.AccessTime = time.Unix(p.parseNumeric(star.AccessTime()), 0)
- hdr.ChangeTime = time.Unix(p.parseNumeric(star.ChangeTime()), 0)
+ star := tr.blk.toSTAR()
+ prefix = p.parseString(star.prefix())
+ hdr.AccessTime = time.Unix(p.parseNumeric(star.accessTime()), 0)
+ hdr.ChangeTime = time.Unix(p.parseNumeric(star.changeTime()), 0)
case format.has(FormatGNU):
hdr.Format = format
var p2 parser
- gnu := tr.blk.GNU()
- if b := gnu.AccessTime(); b[0] != 0 {
+ gnu := tr.blk.toGNU()
+ if b := gnu.accessTime(); b[0] != 0 {
hdr.AccessTime = time.Unix(p2.parseNumeric(b), 0)
}
- if b := gnu.ChangeTime(); b[0] != 0 {
+ if b := gnu.changeTime(); b[0] != 0 {
hdr.ChangeTime = time.Unix(p2.parseNumeric(b), 0)
}
// See https://golang.org/issues/21005
if p2.err != nil {
hdr.AccessTime, hdr.ChangeTime = time.Time{}, time.Time{}
- ustar := tr.blk.USTAR()
- if s := p.parseString(ustar.Prefix()); isASCII(s) {
+ ustar := tr.blk.toUSTAR()
+ if s := p.parseString(ustar.prefix()); isASCII(s) {
prefix = s
}
hdr.Format = FormatUnknown // Buggy file is not GNU
// Make sure that the input format is GNU.
// Unfortunately, the STAR format also has a sparse header format that uses
// the same type flag but has a completely different layout.
- if blk.GetFormat() != FormatGNU {
+ if blk.getFormat() != FormatGNU {
return nil, ErrHeader
}
hdr.Format.mayOnlyBe(FormatGNU)
var p parser
- hdr.Size = p.parseNumeric(blk.GNU().RealSize())
+ hdr.Size = p.parseNumeric(blk.toGNU().realSize())
if p.err != nil {
return nil, p.err
}
- s := blk.GNU().Sparse()
- spd := make(sparseDatas, 0, s.MaxEntries())
+ s := blk.toGNU().sparse()
+ spd := make(sparseDatas, 0, s.maxEntries())
for {
- for i := 0; i < s.MaxEntries(); i++ {
+ for i := 0; i < s.maxEntries(); i++ {
// This termination condition is identical to GNU and BSD tar.
- if s.Entry(i).Offset()[0] == 0x00 {
+ if s.entry(i).offset()[0] == 0x00 {
break // Don't return, need to process extended headers (even if empty)
}
- offset := p.parseNumeric(s.Entry(i).Offset())
- length := p.parseNumeric(s.Entry(i).Length())
+ offset := p.parseNumeric(s.entry(i).offset())
+ length := p.parseNumeric(s.entry(i).length())
if p.err != nil {
return nil, p.err
}
spd = append(spd, sparseEntry{Offset: offset, Length: length})
}
- if s.IsExtended()[0] > 0 {
+ if s.isExtended()[0] > 0 {
// There are more entries. Read an extension header and parse its entries.
if _, err := mustReadFull(tr.r, blk[:]); err != nil {
return nil, err
}
- s = blk.Sparse()
+ s = blk.toSparse()
continue
}
return spd, nil // Done
return io.Copy(w, struct{ io.Reader }{fr})
}
-func (fr regFileReader) LogicalRemaining() int64 {
+// logicalRemaining implements fileState.logicalRemaining.
+func (fr regFileReader) logicalRemaining() int64 {
return fr.nb
}
-func (fr regFileReader) PhysicalRemaining() int64 {
+// logicalRemaining implements fileState.physicalRemaining.
+func (fr regFileReader) physicalRemaining() int64 {
return fr.nb
}
}
func (sr *sparseFileReader) Read(b []byte) (n int, err error) {
- finished := int64(len(b)) >= sr.LogicalRemaining()
+ finished := int64(len(b)) >= sr.logicalRemaining()
if finished {
- b = b[:sr.LogicalRemaining()]
+ b = b[:sr.logicalRemaining()]
}
b0 := b
return n, errMissData // Less data in dense file than sparse file
case err != nil:
return n, err
- case sr.LogicalRemaining() == 0 && sr.PhysicalRemaining() > 0:
+ case sr.logicalRemaining() == 0 && sr.physicalRemaining() > 0:
return n, errUnrefData // More data in dense file than sparse file
case finished:
return n, io.EOF
var writeLastByte bool
pos0 := sr.pos
- for sr.LogicalRemaining() > 0 && !writeLastByte && err == nil {
+ for sr.logicalRemaining() > 0 && !writeLastByte && err == nil {
var nf int64 // Size of fragment
holeStart, holeEnd := sr.sp[0].Offset, sr.sp[0].endOffset()
if sr.pos < holeStart { // In a data fragment
nf, err = io.CopyN(ws, sr.fr, nf)
} else { // In a hole fragment
nf = holeEnd - sr.pos
- if sr.PhysicalRemaining() == 0 {
+ if sr.physicalRemaining() == 0 {
writeLastByte = true
nf--
}
return n, errMissData // Less data in dense file than sparse file
case err != nil:
return n, err
- case sr.LogicalRemaining() == 0 && sr.PhysicalRemaining() > 0:
+ case sr.logicalRemaining() == 0 && sr.physicalRemaining() > 0:
return n, errUnrefData // More data in dense file than sparse file
default:
return n, nil
}
}
-func (sr sparseFileReader) LogicalRemaining() int64 {
+func (sr sparseFileReader) logicalRemaining() int64 {
return sr.sp[len(sr.sp)-1].endOffset() - sr.pos
}
-func (sr sparseFileReader) PhysicalRemaining() int64 {
- return sr.fr.PhysicalRemaining()
+func (sr sparseFileReader) physicalRemaining() int64 {
+ return sr.fr.physicalRemaining()
}
type zeroReader struct{}
func TestReadOldGNUSparseMap(t *testing.T) {
populateSparseMap := func(sa sparseArray, sps []string) []string {
- for i := 0; len(sps) > 0 && i < sa.MaxEntries(); i++ {
- copy(sa.Entry(i), sps[0])
+ for i := 0; len(sps) > 0 && i < sa.maxEntries(); i++ {
+ copy(sa.entry(i), sps[0])
sps = sps[1:]
}
if len(sps) > 0 {
- copy(sa.IsExtended(), "\x80")
+ copy(sa.isExtended(), "\x80")
}
return sps
}
makeInput := func(format Format, size string, sps ...string) (out []byte) {
// Write the initial GNU header.
var blk block
- gnu := blk.GNU()
- sparse := gnu.Sparse()
- copy(gnu.RealSize(), size)
+ gnu := blk.toGNU()
+ sparse := gnu.sparse()
+ copy(gnu.realSize(), size)
sps = populateSparseMap(sparse, sps)
if format != FormatUnknown {
- blk.SetFormat(format)
+ blk.setFormat(format)
}
out = append(out, blk[:]...)
// Write extended sparse blocks.
for len(sps) > 0 {
var blk block
- sps = populateSparseMap(blk.Sparse(), sps)
+ sps = populateSparseMap(blk.toSparse(), sps)
out = append(out, blk[:]...)
}
return out
wantCnt int64
wantErr error
}
- testRemaining struct { // LogicalRemaining() == wantLCnt, PhysicalRemaining() == wantPCnt
+ testRemaining struct { // logicalRemaining() == wantLCnt, physicalRemaining() == wantPCnt
wantLCnt int64
wantPCnt int64
}
t.Errorf("test %d.%d, expected %d more operations", i, j, len(f.ops))
}
case testRemaining:
- if got := fr.LogicalRemaining(); got != tf.wantLCnt {
- t.Errorf("test %d.%d, LogicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt)
+ if got := fr.logicalRemaining(); got != tf.wantLCnt {
+ t.Errorf("test %d.%d, logicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt)
}
- if got := fr.PhysicalRemaining(); got != tf.wantPCnt {
- t.Errorf("test %d.%d, PhysicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt)
+ if got := fr.physicalRemaining(); got != tf.wantPCnt {
+ t.Errorf("test %d.%d, physicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt)
}
default:
t.Fatalf("test %d.%d, unknown test operation: %T", i, j, tf)
if tw.err != nil {
return tw.err
}
- if nb := tw.curr.LogicalRemaining(); nb > 0 {
+ if nb := tw.curr.logicalRemaining(); nb > 0 {
return fmt.Errorf("archive/tar: missed writing %d bytes", nb)
}
if _, tw.err = tw.w.Write(zeroBlock[:tw.pad]); tw.err != nil {
// Pack the main header.
var f formatter
blk := tw.templateV7Plus(hdr, f.formatString, f.formatOctal)
- f.formatString(blk.USTAR().Prefix(), namePrefix)
- blk.SetFormat(FormatUSTAR)
+ f.formatString(blk.toUSTAR().prefix(), namePrefix)
+ blk.setFormat(FormatUSTAR)
if f.err != nil {
return f.err // Should never happen since header is validated
}
var f formatter // Ignore errors since they are expected
fmtStr := func(b []byte, s string) { f.formatString(b, toASCII(s)) }
blk := tw.templateV7Plus(hdr, fmtStr, f.formatOctal)
- blk.SetFormat(FormatPAX)
+ blk.setFormat(FormatPAX)
if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil {
return err
}
var spb []byte
blk := tw.templateV7Plus(hdr, f.formatString, f.formatNumeric)
if !hdr.AccessTime.IsZero() {
- f.formatNumeric(blk.GNU().AccessTime(), hdr.AccessTime.Unix())
+ f.formatNumeric(blk.toGNU().accessTime(), hdr.AccessTime.Unix())
}
if !hdr.ChangeTime.IsZero() {
- f.formatNumeric(blk.GNU().ChangeTime(), hdr.ChangeTime.Unix())
+ f.formatNumeric(blk.toGNU().changeTime(), hdr.ChangeTime.Unix())
}
// TODO(dsnet): Re-enable this when adding sparse support.
// See https://golang.org/issue/22735
f.formatNumeric(blk.GNU().RealSize(), realSize)
}
*/
- blk.SetFormat(FormatGNU)
+ blk.setFormat(FormatGNU)
if err := tw.writeRawHeader(blk, hdr.Size, hdr.Typeflag); err != nil {
return err
}
// 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()
+ tw.blk.reset()
modTime := hdr.ModTime
if modTime.IsZero() {
modTime = time.Unix(0, 0)
}
- v7 := tw.blk.V7()
- v7.TypeFlag()[0] = hdr.Typeflag
- 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())
+ v7 := tw.blk.toV7()
+ v7.typeFlag()[0] = hdr.Typeflag
+ 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()
- fmtStr(ustar.UserName(), hdr.Uname)
- fmtStr(ustar.GroupName(), hdr.Gname)
- fmtNum(ustar.DevMajor(), hdr.Devmajor)
- fmtNum(ustar.DevMinor(), hdr.Devminor)
+ ustar := tw.blk.toUSTAR()
+ fmtStr(ustar.userName(), hdr.Uname)
+ fmtStr(ustar.groupName(), hdr.Gname)
+ fmtNum(ustar.devMajor(), hdr.Devmajor)
+ fmtNum(ustar.devMinor(), hdr.Devminor)
return &tw.blk
}
// It uses format to encode the header format and will write data as the body.
// It uses default values for all of the other fields (as BSD and GNU tar does).
func (tw *Writer) writeRawFile(name, data string, flag byte, format Format) error {
- tw.blk.Reset()
+ tw.blk.reset()
// Best effort for the filename.
name = toASCII(name)
name = strings.TrimRight(name, "/")
var f formatter
- v7 := tw.blk.V7()
- v7.TypeFlag()[0] = flag
- f.formatString(v7.Name(), name)
- f.formatOctal(v7.Mode(), 0)
- f.formatOctal(v7.UID(), 0)
- f.formatOctal(v7.GID(), 0)
- f.formatOctal(v7.Size(), int64(len(data))) // Must be < 8GiB
- f.formatOctal(v7.ModTime(), 0)
- tw.blk.SetFormat(format)
+ v7 := tw.blk.toV7()
+ v7.typeFlag()[0] = flag
+ f.formatString(v7.name(), name)
+ f.formatOctal(v7.mode(), 0)
+ f.formatOctal(v7.uid(), 0)
+ f.formatOctal(v7.gid(), 0)
+ f.formatOctal(v7.size(), int64(len(data))) // Must be < 8GiB
+ f.formatOctal(v7.modTime(), 0)
+ tw.blk.setFormat(format)
if f.err != nil {
return f.err // Only occurs if size condition is violated
}
return io.Copy(struct{ io.Writer }{fw}, r)
}
-func (fw regFileWriter) LogicalRemaining() int64 {
+// logicalRemaining implements fileState.logicalRemaining.
+func (fw regFileWriter) logicalRemaining() int64 {
return fw.nb
}
-func (fw regFileWriter) PhysicalRemaining() int64 {
+
+// logicalRemaining implements fileState.physicalRemaining.
+func (fw regFileWriter) physicalRemaining() int64 {
return fw.nb
}
}
func (sw *sparseFileWriter) Write(b []byte) (n int, err error) {
- overwrite := int64(len(b)) > sw.LogicalRemaining()
+ overwrite := int64(len(b)) > sw.logicalRemaining()
if overwrite {
- b = b[:sw.LogicalRemaining()]
+ b = b[:sw.logicalRemaining()]
}
b0 := b
return n, errMissData // Not possible; implies bug in validation logic
case err != nil:
return n, err
- case sw.LogicalRemaining() == 0 && sw.PhysicalRemaining() > 0:
+ case sw.logicalRemaining() == 0 && sw.physicalRemaining() > 0:
return n, errUnrefData // Not possible; implies bug in validation logic
case overwrite:
return n, ErrWriteTooLong
var readLastByte bool
pos0 := sw.pos
- for sw.LogicalRemaining() > 0 && !readLastByte && err == nil {
+ for sw.logicalRemaining() > 0 && !readLastByte && err == nil {
var nf int64 // Size of fragment
dataStart, dataEnd := sw.sp[0].Offset, sw.sp[0].endOffset()
if sw.pos < dataStart { // In a hole fragment
nf = dataStart - sw.pos
- if sw.PhysicalRemaining() == 0 {
+ if sw.physicalRemaining() == 0 {
readLastByte = true
nf--
}
return n, errMissData // Not possible; implies bug in validation logic
case err != nil:
return n, err
- case sw.LogicalRemaining() == 0 && sw.PhysicalRemaining() > 0:
+ case sw.logicalRemaining() == 0 && sw.physicalRemaining() > 0:
return n, errUnrefData // Not possible; implies bug in validation logic
default:
return n, ensureEOF(rs)
}
}
-func (sw sparseFileWriter) LogicalRemaining() int64 {
+func (sw sparseFileWriter) logicalRemaining() int64 {
return sw.sp[len(sw.sp)-1].endOffset() - sw.pos
}
-func (sw sparseFileWriter) PhysicalRemaining() int64 {
- return sw.fw.PhysicalRemaining()
+func (sw sparseFileWriter) physicalRemaining() int64 {
+ return sw.fw.physicalRemaining()
}
// zeroWriter may only be written with NULs, otherwise it returns errWriteHole.
// The prefix field should never appear in the GNU format.
var blk block
copy(blk[:], b.Bytes())
- prefix := string(blk.USTAR().Prefix())
+ prefix := string(blk.toUSTAR().prefix())
if i := strings.IndexByte(prefix, 0); i >= 0 {
prefix = prefix[:i] // Truncate at the NUL terminator
}
- if blk.GetFormat() == FormatGNU && len(prefix) > 0 && strings.HasPrefix(name, prefix) {
+ if blk.getFormat() == FormatGNU && len(prefix) > 0 && strings.HasPrefix(name, prefix) {
t.Errorf("test %d, found prefix in GNU format: %s", i, prefix)
}
wantCnt int64
wantErr error
}
- testRemaining struct { // LogicalRemaining() == wantLCnt, PhysicalRemaining() == wantPCnt
+ testRemaining struct { // logicalRemaining() == wantLCnt, physicalRemaining() == wantPCnt
wantLCnt int64
wantPCnt int64
}
t.Errorf("test %d.%d, expected %d more operations", i, j, len(f.ops))
}
case testRemaining:
- if got := fw.LogicalRemaining(); got != tf.wantLCnt {
- t.Errorf("test %d.%d, LogicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt)
+ if got := fw.logicalRemaining(); got != tf.wantLCnt {
+ t.Errorf("test %d.%d, logicalRemaining() = %d, want %d", i, j, got, tf.wantLCnt)
}
- if got := fw.PhysicalRemaining(); got != tf.wantPCnt {
- t.Errorf("test %d.%d, PhysicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt)
+ if got := fw.physicalRemaining(); got != tf.wantPCnt {
+ t.Errorf("test %d.%d, physicalRemaining() = %d, want %d", i, j, got, tf.wantPCnt)
}
default:
t.Fatalf("test %d.%d, unknown test operation: %T", i, j, tf)