diff --git a/cmd/restic/lock.go b/cmd/restic/lock.go index ea230fa7a..f39a08db6 100644 --- a/cmd/restic/lock.go +++ b/cmd/restic/lock.go @@ -44,6 +44,9 @@ func lockRepository(ctx context.Context, repo restic.Repository, exclusive bool) } lock, err := lockFn(ctx, repo) + if restic.IsInvalidLock(err) { + return nil, ctx, errors.Fatalf("%v\n\nthe `unlock --remove-all` command can be used to remove invalid locks. Make sure that no other restic process is accessing the repository when running the command", err) + } if err != nil { return nil, ctx, errors.Fatalf("unable to create lock in backend: %v", err) } diff --git a/internal/restic/lock.go b/internal/restic/lock.go index 10271b778..94b1801f2 100644 --- a/internal/restic/lock.go +++ b/internal/restic/lock.go @@ -60,6 +60,27 @@ func IsAlreadyLocked(err error) bool { return errors.As(err, &e) } +// invalidLockError is returned when NewLock or NewExclusiveLock fail due +// to an invalid lock. +type invalidLockError struct { + err error +} + +func (e *invalidLockError) Error() string { + return fmt.Sprintf("invalid lock file: %v", e.err) +} + +func (e *invalidLockError) Unwrap() error { + return e.err +} + +// IsInvalidLock returns true iff err indicates that locking failed due to +// an invalid lock. +func IsInvalidLock(err error) bool { + var e *invalidLockError + return errors.As(err, &e) +} + // NewLock returns a new, non-exclusive lock for the repository. If an // exclusive lock is already held by another process, it returns an error // that satisfies IsAlreadyLocked. @@ -168,6 +189,9 @@ func (l *Lock) checkForOtherLocks(ctx context.Context) error { return err } } + if errors.Is(err, ErrInvalidData) { + return &invalidLockError{err} + } return err }