diff --git a/internal/backend/local/local.go b/internal/backend/local/local.go index bc7ea354d..33f81f182 100644 --- a/internal/backend/local/local.go +++ b/internal/backend/local/local.go @@ -142,7 +142,9 @@ func (b *Local) Save(ctx context.Context, h restic.Handle, rd restic.RewindReade } // Ignore error if filesystem does not support fsync. - if err = f.Sync(); err != nil && !errors.Is(err, syscall.ENOTSUP) { + err = f.Sync() + syncNotSup := errors.Is(err, syscall.ENOTSUP) + if err != nil && !syncNotSup { return errors.WithStack(err) } @@ -154,6 +156,14 @@ func (b *Local) Save(ctx context.Context, h restic.Handle, rd restic.RewindReade return errors.WithStack(err) } + // Now sync the directory to commit the Rename. + if !syncNotSup { + err = fsyncDir(dir) + if err != nil { + return errors.WithStack(err) + } + } + // try to mark file as read-only to avoid accidential modifications // ignore if the operation fails as some filesystems don't allow the chmod call // e.g. exfat and network file systems with certain mount options diff --git a/internal/backend/local/local_unix.go b/internal/backend/local/local_unix.go index cc99d4a0b..81250a550 100644 --- a/internal/backend/local/local_unix.go +++ b/internal/backend/local/local_unix.go @@ -3,11 +3,33 @@ package local import ( + "errors" "os" + "syscall" "github.com/restic/restic/internal/fs" ) +// fsyncDir flushes changes to the directory dir. +func fsyncDir(dir string) error { + d, err := os.Open(dir) + if err != nil { + return err + } + + err = d.Sync() + if errors.Is(err, syscall.ENOTSUP) { + err = nil + } + + cerr := d.Close() + if err == nil { + err = cerr + } + + return err +} + // set file to readonly func setFileReadonly(f string, mode os.FileMode) error { return fs.Chmod(f, mode&^0222) diff --git a/internal/backend/local/local_windows.go b/internal/backend/local/local_windows.go index ccf788072..72ced630c 100644 --- a/internal/backend/local/local_windows.go +++ b/internal/backend/local/local_windows.go @@ -4,6 +4,9 @@ import ( "os" ) +// Can't explicitly flush directory changes on Windows. +func fsyncDir(dir string) error { return nil } + // We don't modify read-only on windows, // since it will make us unable to delete the file, // and this isn't common practice on this platform.