Merge pull request #2259 from aeijdenberg/setfixedtimestampforarchiveentries
feat: add Timestamp to TarOptions
This commit is contained in:
commit
3a013da40e
|
|
@ -16,6 +16,7 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/containers/storage/pkg/fileutils"
|
||||
"github.com/containers/storage/pkg/idtools"
|
||||
|
|
@ -67,6 +68,8 @@ type (
|
|||
CopyPass bool
|
||||
// ForceMask, if set, indicates the permission mask used for created files.
|
||||
ForceMask *os.FileMode
|
||||
// Timestamp, if set, will be set in each header as create/mod/access time
|
||||
Timestamp *time.Time
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -494,15 +497,19 @@ type tarWriter struct {
|
|||
// from the traditional behavior/format to get features like subsecond
|
||||
// precision in timestamps.
|
||||
CopyPass bool
|
||||
|
||||
// Timestamp, if set, will be set in each header as create/mod/access time
|
||||
Timestamp *time.Time
|
||||
}
|
||||
|
||||
func newTarWriter(idMapping *idtools.IDMappings, writer io.Writer, chownOpts *idtools.IDPair) *tarWriter {
|
||||
func newTarWriter(idMapping *idtools.IDMappings, writer io.Writer, chownOpts *idtools.IDPair, timestamp *time.Time) *tarWriter {
|
||||
return &tarWriter{
|
||||
SeenFiles: make(map[uint64]string),
|
||||
TarWriter: tar.NewWriter(writer),
|
||||
Buffer: pools.BufioWriter32KPool.Get(nil),
|
||||
IDMappings: idMapping,
|
||||
ChownOpts: chownOpts,
|
||||
Timestamp: timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -600,6 +607,13 @@ func (ta *tarWriter) addFile(path, name string) error {
|
|||
hdr.Gname = ""
|
||||
}
|
||||
|
||||
// if override timestamp set, replace all times with this
|
||||
if ta.Timestamp != nil {
|
||||
hdr.ModTime = *ta.Timestamp
|
||||
hdr.AccessTime = *ta.Timestamp
|
||||
hdr.ChangeTime = *ta.Timestamp
|
||||
}
|
||||
|
||||
maybeTruncateHeaderModTime(hdr)
|
||||
|
||||
if ta.WhiteoutConverter != nil {
|
||||
|
|
@ -866,6 +880,7 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
|
|||
idtools.NewIDMappingsFromMaps(options.UIDMaps, options.GIDMaps),
|
||||
compressWriter,
|
||||
options.ChownOpts,
|
||||
options.Timestamp,
|
||||
)
|
||||
ta.WhiteoutConverter = GetWhiteoutConverter(options.WhiteoutFormat, options.WhiteoutData)
|
||||
ta.CopyPass = options.CopyPass
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import (
|
|||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/containers/storage/pkg/idtools"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -1222,3 +1223,46 @@ func readFileFromArchive(t *testing.T, archive io.ReadCloser, name string, expec
|
|||
assert.NoError(t, err)
|
||||
return string(content)
|
||||
}
|
||||
|
||||
func TestTimestamp(t *testing.T) {
|
||||
// write single file into dir that we'll tar
|
||||
td := t.TempDir()
|
||||
tf := filepath.Join(td, "foo")
|
||||
|
||||
require.NoError(t, os.WriteFile(tf, []byte("bar"), 0o644))
|
||||
|
||||
// helper function to tar that dir and return byte slice
|
||||
tarToByteSlice := func(options *TarOptions) []byte {
|
||||
rc, err := TarWithOptions(td, options)
|
||||
assert.NoError(t, err)
|
||||
defer rc.Close()
|
||||
|
||||
rv, err := io.ReadAll(rc)
|
||||
assert.NoError(t, err)
|
||||
return rv
|
||||
}
|
||||
|
||||
// default options
|
||||
defaultOptions := &TarOptions{}
|
||||
|
||||
// override timestamp option
|
||||
epochOptions := &TarOptions{Timestamp: &time.Time{}}
|
||||
|
||||
// get tar bytes slices now
|
||||
origTarDefaultOptions := tarToByteSlice(defaultOptions)
|
||||
origTarEpochOptions := tarToByteSlice(epochOptions)
|
||||
|
||||
// set the mod time of the file to an hour later
|
||||
oneHourLater := time.Now().Add(time.Hour)
|
||||
require.NoError(t, os.Chtimes(tf, oneHourLater, oneHourLater))
|
||||
|
||||
// then tar again
|
||||
laterTarDefaultOptions := tarToByteSlice(defaultOptions)
|
||||
laterTarEpochOptions := tarToByteSlice(epochOptions)
|
||||
|
||||
// we expect the ones without a fixed timestamp to be different
|
||||
assert.NotEqual(t, origTarDefaultOptions, laterTarDefaultOptions)
|
||||
|
||||
// we expect the ones with a fixed timestamp to be the same
|
||||
assert.Equal(t, origTarEpochOptions, laterTarEpochOptions)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -452,7 +452,7 @@ func ChangesSize(newDir string, changes []Change) int64 {
|
|||
func ExportChanges(dir string, changes []Change, uidMaps, gidMaps []idtools.IDMap) (io.ReadCloser, error) {
|
||||
reader, writer := io.Pipe()
|
||||
go func() {
|
||||
ta := newTarWriter(idtools.NewIDMappingsFromMaps(uidMaps, gidMaps), writer, nil)
|
||||
ta := newTarWriter(idtools.NewIDMappingsFromMaps(uidMaps, gidMaps), writer, nil, nil)
|
||||
|
||||
// this buffer is needed for the duration of this piped stream
|
||||
defer pools.BufioWriter32KPool.Put(ta.Buffer)
|
||||
|
|
|
|||
Loading…
Reference in New Issue