Update module github.com/containers/storage to v1.46.1

Signed-off-by: Renovate Bot <bot@renovateapp.com>
This commit is contained in:
renovate[bot]
2023-04-10 22:42:41 +00:00
committed by GitHub
parent 1aa6371db4
commit 66157589c5
25 changed files with 509 additions and 337 deletions

View File

@@ -23,7 +23,7 @@ env:
# GCE project where images live
IMAGE_PROJECT: "libpod-218412"
# VM Image built in containers/automation_images
IMAGE_SUFFIX: "c20230330t153101z-f37f36d12"
IMAGE_SUFFIX: "c20230405t152256z-f37f36d12"
FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}"
DEBIAN_CACHE_IMAGE_NAME: "debian-${IMAGE_SUFFIX}"

View File

@@ -1 +1 @@
1.46.0
1.46.1

View File

@@ -666,7 +666,7 @@ func (r *containerStore) create(id string, names []string, image, layer string,
if _, idInUse := r.byid[id]; idInUse {
return nil, ErrDuplicateID
}
names = dedupeNames(names)
names = dedupeStrings(names)
for _, name := range names {
if _, nameInUse := r.byname[name]; nameInUse {
return nil, fmt.Errorf("the container name %q is already in use by %s. You have to remove that container to be able to reuse that name: %w", name, r.byname[name].ID, ErrDuplicateName)

View File

@@ -703,7 +703,7 @@ func (r *imageStore) create(id string, names []string, layer string, options Ima
if _, idInUse := r.byid[id]; idInUse {
return nil, fmt.Errorf("an image with ID %q already exists: %w", id, ErrDuplicateID)
}
names = dedupeNames(names)
names = dedupeStrings(names)
for _, name := range names {
if image, nameInUse := r.byname[name]; nameInUse {
return nil, fmt.Errorf("image name %q is already associated with image %q: %w", name, image.ID, ErrDuplicateName)
@@ -712,7 +712,7 @@ func (r *imageStore) create(id string, names []string, layer string, options Ima
image = &Image{
ID: id,
Digest: options.Digest,
Digests: copyDigestSlice(options.Digests),
Digests: dedupeDigests(options.Digests),
Names: names,
NamesHistory: copyStringSlice(options.NamesHistory),
TopLayer: layer,
@@ -820,7 +820,7 @@ func (r *imageStore) removeName(image *Image, name string) {
// The caller must hold r.inProcessLock for writing.
func (i *Image) addNameToHistory(name string) {
i.NamesHistory = dedupeNames(append([]string{name}, i.NamesHistory...))
i.NamesHistory = dedupeStrings(append([]string{name}, i.NamesHistory...))
}
// Requires startWriting.

View File

@@ -1230,7 +1230,7 @@ func (r *layerStore) create(id string, parentLayer *Layer, names []string, mount
if duplicateLayer, idInUse := r.byid[id]; idInUse {
return duplicateLayer, -1, ErrDuplicateID
}
names = dedupeNames(names)
names = dedupeStrings(names)
for _, name := range names {
if _, nameInUse := r.byname[name]; nameInUse {
return nil, -1, ErrDuplicateName

View File

@@ -17,6 +17,20 @@ type AtomicFileWriterOptions struct {
// On successful return from Close() this is set to the mtime of the
// newly written file.
ModTime time.Time
// Specifies whether Commit() must be explicitly called to write state
// to the destination. This allows an application to preserve the original
// file when an error occurs during processing (and not just during write)
// The default is false, which will auto-commit on Close
ExplicitCommit bool
}
type CommittableWriter interface {
io.WriteCloser
// Commit closes the temporary file associated with this writer, and
// provided no errors (during commit or previously during write operations),
// will publish the completed file under the intended destination.
Commit() error
}
var defaultWriterOptions = AtomicFileWriterOptions{}
@@ -27,16 +41,19 @@ func SetDefaultOptions(opts AtomicFileWriterOptions) {
defaultWriterOptions = opts
}
// NewAtomicFileWriterWithOpts returns WriteCloser so that writing to it writes to a
// temporary file and closing it atomically changes the temporary file to
// destination path. Writing and closing concurrently is not allowed.
func NewAtomicFileWriterWithOpts(filename string, perm os.FileMode, opts *AtomicFileWriterOptions) (io.WriteCloser, error) {
// NewAtomicFileWriterWithOpts returns a CommittableWriter so that writing to it
// writes to a temporary file, which can later be committed to a destination path,
// either by Closing in the case of auto-commit, or manually calling commit if the
// ExplicitCommit option is enabled. Writing and closing concurrently is not
// allowed.
func NewAtomicFileWriterWithOpts(filename string, perm os.FileMode, opts *AtomicFileWriterOptions) (CommittableWriter, error) {
return newAtomicFileWriter(filename, perm, opts)
}
// newAtomicFileWriter returns WriteCloser so that writing to it writes to a
// temporary file and closing it atomically changes the temporary file to
// destination path. Writing and closing concurrently is not allowed.
// newAtomicFileWriter returns a CommittableWriter so that writing to it writes to
// a temporary file, which can later be committed to a destination path, either by
// Closing in the case of auto-commit, or manually calling commit if the
// ExplicitCommit option is enabled. Writing and closing concurrently is not allowed.
func newAtomicFileWriter(filename string, perm os.FileMode, opts *AtomicFileWriterOptions) (*atomicFileWriter, error) {
f, err := os.CreateTemp(filepath.Dir(filename), ".tmp-"+filepath.Base(filename))
if err != nil {
@@ -50,17 +67,18 @@ func newAtomicFileWriter(filename string, perm os.FileMode, opts *AtomicFileWrit
return nil, err
}
return &atomicFileWriter{
f: f,
fn: abspath,
perm: perm,
noSync: opts.NoSync,
f: f,
fn: abspath,
perm: perm,
noSync: opts.NoSync,
explicitCommit: opts.ExplicitCommit,
}, nil
}
// NewAtomicFileWriter returns WriteCloser so that writing to it writes to a
// temporary file and closing it atomically changes the temporary file to
// destination path. Writing and closing concurrently is not allowed.
func NewAtomicFileWriter(filename string, perm os.FileMode) (io.WriteCloser, error) {
// NewAtomicFileWriterWithOpts returns a CommittableWriter, with auto-commit enabled.
// Writing to it writes to a temporary file and closing it atomically changes the
// temporary file to destination path. Writing and closing concurrently is not allowed.
func NewAtomicFileWriter(filename string, perm os.FileMode) (CommittableWriter, error) {
return NewAtomicFileWriterWithOpts(filename, perm, nil)
}
@@ -91,12 +109,14 @@ func AtomicWriteFile(filename string, data []byte, perm os.FileMode) error {
}
type atomicFileWriter struct {
f *os.File
fn string
writeErr error
perm os.FileMode
noSync bool
modTime time.Time
f *os.File
fn string
writeErr error
perm os.FileMode
noSync bool
modTime time.Time
closed bool
explicitCommit bool
}
func (w *atomicFileWriter) Write(dt []byte) (int, error) {
@@ -107,43 +127,73 @@ func (w *atomicFileWriter) Write(dt []byte) (int, error) {
return n, err
}
func (w *atomicFileWriter) Close() (retErr error) {
func (w *atomicFileWriter) closeTempFile() error {
if w.closed {
return nil
}
w.closed = true
return w.f.Close()
}
func (w *atomicFileWriter) Close() error {
return w.complete(!w.explicitCommit)
}
func (w *atomicFileWriter) Commit() error {
return w.complete(true)
}
func (w *atomicFileWriter) complete(commit bool) (retErr error) {
if w == nil || w.closed {
return nil
}
defer func() {
w.closeTempFile()
if retErr != nil || w.writeErr != nil {
os.Remove(w.f.Name())
}
}()
if !w.noSync {
if err := fdatasync(w.f); err != nil {
w.f.Close()
return err
}
if commit {
return w.commitState()
}
// fstat before closing the fd
info, statErr := w.f.Stat()
if statErr == nil {
w.modTime = info.ModTime()
}
// We delay error reporting until after the real call to close()
// to match the traditional linux close() behaviour that an fd
// is invalid (closed) even if close returns failure. While
// weird, this allows a well defined way to not leak open fds.
return nil
}
if err := w.f.Close(); err != nil {
func (w *atomicFileWriter) commitState() error {
// Perform a data only sync (fdatasync()) if supported
if err := w.postDataWrittenSync(); err != nil {
return err
}
if statErr != nil {
return statErr
}
if err := os.Chmod(w.f.Name(), w.perm); err != nil {
// Capture fstat before closing the fd
info, err := w.f.Stat()
if err != nil {
return err
}
w.modTime = info.ModTime()
if err := w.f.Chmod(w.perm); err != nil {
return err
}
// Perform full sync on platforms that need it
if err := w.preRenameSync(); err != nil {
return err
}
// Some platforms require closing before rename (Windows)
if err := w.closeTempFile(); err != nil {
return err
}
if w.writeErr == nil {
return os.Rename(w.f.Name(), w.fn)
}
return nil
}
@@ -195,7 +245,7 @@ func (w syncFileCloser) Close() error {
if !defaultWriterOptions.NoSync {
return w.File.Close()
}
err := fdatasync(w.File)
err := dataOrFullSync(w.File)
if err1 := w.File.Close(); err == nil {
err = err1
}

View File

@@ -6,6 +6,18 @@ import (
"golang.org/x/sys/unix"
)
func fdatasync(f *os.File) error {
func dataOrFullSync(f *os.File) error {
return unix.Fdatasync(int(f.Fd()))
}
func (w *atomicFileWriter) postDataWrittenSync() error {
if w.noSync {
return nil
}
return unix.Fdatasync(int(w.f.Fd()))
}
func (w *atomicFileWriter) preRenameSync() error {
// On Linux data can be reliably flushed to media without metadata, so defer
return nil
}

View File

@@ -0,0 +1,26 @@
//go:build !linux
// +build !linux
package ioutils
import (
"os"
)
func dataOrFullSync(f *os.File) error {
return f.Sync()
}
func (w *atomicFileWriter) postDataWrittenSync() error {
// many platforms (Mac, Windows) require a full sync to reliably flush to media
return nil
}
func (w *atomicFileWriter) preRenameSync() error {
if w.noSync {
return nil
}
// fsync() on Non-linux Unix, FlushFileBuffers (Windows), F_FULLFSYNC (Mac)
return w.f.Sync()
}

View File

@@ -1,12 +0,0 @@
//go:build !linux
// +build !linux
package ioutils
import (
"os"
)
func fdatasync(f *os.File) error {
return f.Sync()
}

View File

@@ -1384,26 +1384,90 @@ func (s *store) CreateImage(id string, names []string, layer, metadata string, i
layer = ilayer.ID
}
var res *Image
err := s.writeToImageStore(func() error {
var options ImageOptions
var options ImageOptions
var namesToAddAfterCreating []string
if iOptions != nil {
options = *iOptions
options.Digests = copyDigestSlice(iOptions.Digests)
options.BigData = copyImageBigDataOptionSlice(iOptions.BigData)
options.NamesHistory = copyStringSlice(iOptions.NamesHistory)
options.Flags = copyStringInterfaceMap(iOptions.Flags)
if err := s.imageStore.startWriting(); err != nil {
return nil, err
}
defer s.imageStore.stopWriting()
// Check if the ID refers to an image in a read-only store -- we want
// to allow images in read-only stores to have their names changed, so
// if we find one, merge the new values in with what we know about the
// image that's already there.
if id != "" {
for _, is := range s.roImageStores {
store := is
if err := store.startReading(); err != nil {
return nil, err
}
defer store.stopReading()
if i, err := store.Get(id); err == nil {
// set information about this image in "options"
options = ImageOptions{
Metadata: i.Metadata,
CreationDate: i.Created,
Digest: i.Digest,
Digests: copyDigestSlice(i.Digests),
NamesHistory: copyStringSlice(i.NamesHistory),
}
for _, key := range i.BigDataNames {
data, err := store.BigData(id, key)
if err != nil {
return nil, err
}
dataDigest, err := store.BigDataDigest(id, key)
if err != nil {
return nil, err
}
options.BigData = append(options.BigData, ImageBigDataOption{
Key: key,
Data: data,
Digest: dataDigest,
})
}
namesToAddAfterCreating = dedupeStrings(append(append([]string{}, i.Names...), names...))
break
}
}
if options.CreationDate.IsZero() {
options.CreationDate = time.Now().UTC()
}
// merge any passed-in options into "options" as best we can
if iOptions != nil {
if !iOptions.CreationDate.IsZero() {
options.CreationDate = iOptions.CreationDate
}
if iOptions.Digest != "" {
options.Digest = iOptions.Digest
}
options.Digests = append(options.Digests, copyDigestSlice(iOptions.Digests)...)
if iOptions.Metadata != "" {
options.Metadata = iOptions.Metadata
}
options.BigData = append(options.BigData, copyImageBigDataOptionSlice(iOptions.BigData)...)
options.NamesHistory = append(options.NamesHistory, copyStringSlice(iOptions.NamesHistory)...)
if options.Flags == nil {
options.Flags = make(map[string]interface{})
}
for k, v := range iOptions.Flags {
options.Flags[k] = v
}
}
if options.CreationDate.IsZero() {
options.CreationDate = time.Now().UTC()
}
if metadata != "" {
options.Metadata = metadata
}
var err error
res, err = s.imageStore.create(id, names, layer, options)
return err
})
res, err := s.imageStore.create(id, names, layer, options)
if err == nil && len(namesToAddAfterCreating) > 0 {
// set any names we pulled up from an additional image store, now that we won't be
// triggering a duplicate names error
err = s.imageStore.updateNames(res.ID, namesToAddAfterCreating, addNames)
}
return res, err
}
@@ -2130,18 +2194,30 @@ func (s *store) Exists(id string) bool {
return s.containerStore.Exists(id)
}
func dedupeNames(names []string) []string {
seen := make(map[string]bool)
func dedupeStrings(names []string) []string {
seen := make(map[string]struct{})
deduped := make([]string, 0, len(names))
for _, name := range names {
if _, wasSeen := seen[name]; !wasSeen {
seen[name] = true
seen[name] = struct{}{}
deduped = append(deduped, name)
}
}
return deduped
}
func dedupeDigests(digests []digest.Digest) []digest.Digest {
seen := make(map[digest.Digest]struct{})
deduped := make([]digest.Digest, 0, len(digests))
for _, d := range digests {
if _, wasSeen := seen[d]; !wasSeen {
seen[d] = struct{}{}
deduped = append(deduped, d)
}
}
return deduped
}
// Deprecated: Prone to race conditions, suggested alternatives are `AddNames` and `RemoveNames`.
func (s *store) SetNames(id string, names []string) error {
return s.updateNames(id, names, setNames)
@@ -2156,7 +2232,7 @@ func (s *store) RemoveNames(id string, names []string) error {
}
func (s *store) updateNames(id string, names []string, op updateNameOperation) error {
deduped := dedupeNames(names)
deduped := dedupeStrings(names)
layerFound := false
if err := s.writeToLayerStore(func(rlstore rwLayerStore) error {
@@ -2188,11 +2264,12 @@ func (s *store) updateNames(id string, names []string, op updateNameOperation) e
if i, err := store.Get(id); err == nil {
// "pull up" the image so that we can change its names list
options := ImageOptions{
Metadata: i.Metadata,
CreationDate: i.Created,
Digest: i.Digest,
Digests: copyDigestSlice(i.Digests),
Metadata: i.Metadata,
NamesHistory: copyStringSlice(i.NamesHistory),
Flags: copyStringInterfaceMap(i.Flags),
}
for _, key := range i.BigDataNames {
data, err := store.BigData(id, key)

View File

@@ -70,5 +70,5 @@ func applyNameOperation(oldNames []string, opParameters []string, op updateNameO
default:
return result, errInvalidUpdateNameOperation
}
return dedupeNames(result), nil
return dedupeStrings(result), nil
}