hdr.Typeflag = v7.TypeFlag()[0]
hdr.Linkname = p.parseString(v7.LinkName())
- // The atime and ctime fields are often left unused. Some versions of Go
- // had a bug in the tar.Writer where it would output an invalid tar file
- // in certain rare situations because the logic incorrectly believed that
- // the old GNU format had a prefix field. This is wrong and leads to
- // an outputted file that actually mangles the atime and ctime fields.
- //
- // In order to continue reading tar files created by a buggy writer, we
- // try to parse the atime and ctime fields, but just return the zero value
- // of time.Time when we cannot parse them.
- //
- // See https://golang.org/issues/12594
- tryParseTime := func(b []byte) time.Time {
- var p parser
- n := p.parseNumeric(b)
- if b[0] != 0x00 && p.err == nil {
- return time.Unix(n, 0)
- }
- return time.Time{}
- }
-
// Unpack format specific fields.
if format > formatV7 {
ustar := tr.blk.USTAR()
hdr.AccessTime = time.Unix(p.parseNumeric(star.AccessTime()), 0)
hdr.ChangeTime = time.Unix(p.parseNumeric(star.ChangeTime()), 0)
case formatGNU:
+ var p2 parser
gnu := tr.blk.GNU()
- hdr.AccessTime = tryParseTime(gnu.AccessTime())
- hdr.ChangeTime = tryParseTime(gnu.ChangeTime())
+ if b := gnu.AccessTime(); b[0] != 0 {
+ hdr.AccessTime = time.Unix(p2.parseNumeric(b), 0)
+ }
+ if b := gnu.ChangeTime(); b[0] != 0 {
+ hdr.ChangeTime = time.Unix(p2.parseNumeric(b), 0)
+ }
+
+ // Prior to Go1.8, the Writer had a bug where it would output
+ // an invalid tar file in certain rare situations because the logic
+ // incorrectly believed that the old GNU format had a prefix field.
+ // This is wrong and leads to an output file that mangles the
+ // atime and ctime fields, which are often left unused.
+ //
+ // In order to continue reading tar files created by former, buggy
+ // versions of Go, we skeptically parse the atime and ctime fields.
+ // If we are unable to parse them and the prefix field looks like
+ // an ASCII string, then we fallback on the pre-Go1.8 behavior
+ // of treating these fields as the USTAR prefix field.
+ //
+ // Note that this will not use the fallback logic for all possible
+ // files generated by a pre-Go1.8 toolchain. If the generated file
+ // happened to have a prefix field that parses as valid
+ // atime and ctime fields (e.g., when they are valid octal strings),
+ // then it is impossible to distinguish between an valid GNU file
+ // and an invalid pre-Go1.8 file.
+ //
+ // See https://golang.org/issues/12594
+ // 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) {
+ prefix = s
+ }
+ }
}
if len(prefix) > 0 {
hdr.Name = prefix + "/" + hdr.Name