Commit 9223adcc authored by Joe Tsai's avatar Joe Tsai Committed by Joe Tsai

archive/tar: add support for atime and ctime to Writer

Both the GNU and PAX formats support atime and ctime fields.
The implementation is trivial now that we have:
* support for formatting PAX records for timestamps
* dedicated methods that only handle one format (e.g., GNU)

Fixes #17876

Change-Id: I0c604fce14a47d722098afc966399cca2037395d
Reviewed-on: https://go-review.googlesource.com/55570
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent 1da0e7e2
......@@ -133,8 +133,9 @@ func (h *Header) allowedFormats() (format int, paxHdrs map[string]string) {
const supportGNULong = false
var blk block
var v7 = blk.V7()
var ustar = blk.USTAR()
v7 := blk.V7()
ustar := blk.USTAR()
gnu := blk.GNU()
verifyString(h.Name, len(v7.Name()), supportGNULong, paxPath)
verifyString(h.Linkname, len(v7.LinkName()), supportGNULong, paxLinkpath)
verifyString(h.Uname, len(ustar.UserName()), false, paxUname)
......@@ -146,9 +147,8 @@ func (h *Header) allowedFormats() (format int, paxHdrs map[string]string) {
verifyNumeric(h.Devmajor, len(ustar.DevMajor()), paxNone)
verifyNumeric(h.Devminor, len(ustar.DevMinor()), paxNone)
verifyTime(h.ModTime, len(v7.ModTime()), true, paxMtime)
// TODO(dsnet): Support atime and ctime fields.
// verifyTime(h.AccessTime, len(gnu.AccessTime()), false, paxAtime)
// verifyTime(h.ChangeTime, len(gnu.ChangeTime()), false, paxCtime)
verifyTime(h.AccessTime, len(gnu.AccessTime()), false, paxAtime)
verifyTime(h.ChangeTime, len(gnu.ChangeTime()), false, paxCtime)
if !isHeaderOnlyType(h.Typeflag) && h.Size < 0 {
return formatUnknown, nil
......
......@@ -450,6 +450,34 @@ func TestHeaderAllowedFormats(t *testing.T) {
}, {
header: &Header{ModTime: time.Unix(077777777777, 0)},
formats: formatUSTAR | formatPAX | formatGNU,
}, {
header: &Header{ModTime: time.Unix(077777777777+1, 0)},
paxHdrs: map[string]string{paxMtime: "8589934592"},
formats: formatPAX | formatGNU,
}, {
header: &Header{ModTime: time.Unix(math.MaxInt64, 0)},
paxHdrs: map[string]string{paxMtime: "9223372036854775807"},
formats: formatPAX | formatGNU,
}, {
header: &Header{ModTime: time.Unix(-1, 0)},
paxHdrs: map[string]string{paxMtime: "-1"},
formats: formatPAX | formatGNU,
}, {
header: &Header{ModTime: time.Unix(-1, 500)},
paxHdrs: map[string]string{paxMtime: "-0.9999995"},
formats: formatPAX,
}, {
header: &Header{AccessTime: time.Unix(0, 0)},
paxHdrs: map[string]string{paxAtime: "0"},
formats: formatPAX | formatGNU,
}, {
header: &Header{AccessTime: time.Unix(-123, 0)},
paxHdrs: map[string]string{paxAtime: "-123"},
formats: formatPAX | formatGNU,
}, {
header: &Header{ChangeTime: time.Unix(123, 456)},
paxHdrs: map[string]string{paxCtime: "123.000000456"},
formats: formatPAX,
}}
for i, v := range vectors {
......
......@@ -141,8 +141,12 @@ func (tw *Writer) writeGNUHeader(hdr *Header) error {
// 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
if !hdr.AccessTime.IsZero() {
f.formatNumeric(blk.GNU().AccessTime(), hdr.AccessTime.Unix())
}
if !hdr.ChangeTime.IsZero() {
f.formatNumeric(blk.GNU().ChangeTime(), hdr.ChangeTime.Unix())
}
blk.SetFormat(formatGNU)
if f.err != nil {
return f.err // Should never happen since header is validated
......
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