fix: sync parent dir to ensure data is reliably stored (#4774)

This commit is contained in:
Milos Gajdos
2026-02-12 10:03:57 -08:00
committed by GitHub

View File

@@ -9,7 +9,7 @@ import (
"io"
"net/http"
"os"
"path"
"path/filepath"
"time"
"github.com/distribution/distribution/v3/internal/uuid"
@@ -164,7 +164,25 @@ func (d *driver) PutContent(ctx context.Context, subPath string, contents []byte
dErr := d.Delete(ctx, tempPath)
return errors.Join(err, dErr)
}
return syncDir(filepath.Dir(d.fullPath(subPath)))
}
func syncDir(dir string) (retErr error) {
dirF, err := os.Open(dir)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return nil
}
return fmt.Errorf("sync dir: %w", err)
}
defer func() {
if err := dirF.Close(); err != nil {
retErr = errors.Join(retErr, fmt.Errorf("failed to close dir: %w", err))
}
}()
if err := dirF.Sync(); err != nil {
return fmt.Errorf("sync dir: %w", err)
}
return nil
}
@@ -194,7 +212,7 @@ func (d *driver) Reader(ctx context.Context, path string, offset int64) (io.Read
func (d *driver) Writer(ctx context.Context, subPath string, append bool) (storagedriver.FileWriter, error) {
fullPath := d.fullPath(subPath)
parentDir := path.Dir(fullPath)
parentDir := filepath.Dir(fullPath)
if err := os.MkdirAll(parentDir, 0o777); err != nil {
return nil, err
}
@@ -266,7 +284,7 @@ func (d *driver) List(ctx context.Context, subPath string) ([]string, error) {
keys := make([]string, 0, len(fileNames))
for _, fileName := range fileNames {
keys = append(keys, path.Join(subPath, fileName))
keys = append(keys, filepath.Join(subPath, fileName))
}
return keys, nil
@@ -282,7 +300,7 @@ func (d *driver) Move(ctx context.Context, sourcePath string, destPath string) e
return storagedriver.PathNotFoundError{Path: sourcePath}
}
if err := os.MkdirAll(path.Dir(dest), 0o777); err != nil {
if err := os.MkdirAll(filepath.Dir(dest), 0o777); err != nil {
return err
}
@@ -318,7 +336,7 @@ func (d *driver) Walk(ctx context.Context, path string, f storagedriver.WalkFn,
// fullPath returns the absolute path of a key within the Driver's storage.
func (d *driver) fullPath(subPath string) string {
return path.Join(d.rootDirectory, subPath)
return filepath.Join(d.rootDirectory, subPath)
}
type fileInfo struct {
@@ -389,24 +407,27 @@ func (fw *fileWriter) Size() int64 {
return fw.size
}
func (fw *fileWriter) Close() error {
func (fw *fileWriter) Close() (retErr error) {
if fw.closed {
return fmt.Errorf("already closed")
}
fw.closed = true
defer func() {
if err := fw.file.Close(); err != nil {
retErr = errors.Join(retErr, err)
}
}()
if fw.committed {
// Already flushed and synced
return nil
}
if err := fw.bw.Flush(); err != nil {
return err
}
if err := fw.file.Sync(); err != nil {
return err
}
if err := fw.file.Close(); err != nil {
return err
}
fw.closed = true
return nil
return fw.file.Sync()
}
func (fw *fileWriter) Cancel(ctx context.Context) error {
@@ -415,7 +436,8 @@ func (fw *fileWriter) Cancel(ctx context.Context) error {
}
fw.cancelled = true
fw.file.Close()
fw.closed = true
_ = fw.file.Close()
return os.Remove(fw.file.Name())
}