From 2e8de9edfd15b88f59569fa5d22c5a950fc0bf7a Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Sat, 6 Jan 2024 17:31:16 +0100 Subject: [PATCH] rclone: Workaround for incorrect "not found" errors while listing files rclone returns a "not found" error if an internal error occurs while listing a folder. Ignoring this error lets restic erroneously think that there are no files, which can cause `prune` to wipe the whole repository. --- changelog/unreleased/issue-4612 | 11 +++++++++++ internal/backend/rest/rest.go | 9 +++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 changelog/unreleased/issue-4612 diff --git a/changelog/unreleased/issue-4612 b/changelog/unreleased/issue-4612 new file mode 100644 index 000000000..ed99f4767 --- /dev/null +++ b/changelog/unreleased/issue-4612 @@ -0,0 +1,11 @@ +Bugfix: Improve error handling for `rclone` backend + +Since restic 0.16.0, if rclone encountered an error while listing files, +this could in rare circumstances cause restic to assume that there are no +files. Although unlikely, this situation could result in data loss if it +were to happen right when the `prune` command is listing existing snapshots. + +Error handling has now been improved to detect and work around this case. + +https://github.com/restic/restic/issues/4612 +https://github.com/restic/restic/pull/4618 diff --git a/internal/backend/rest/rest.go b/internal/backend/rest/rest.go index 1d1769b56..5310eba7c 100644 --- a/internal/backend/rest/rest.go +++ b/internal/backend/rest/rest.go @@ -328,8 +328,13 @@ func (b *Backend) List(ctx context.Context, t backend.FileType, fn func(backend. } if resp.StatusCode == http.StatusNotFound { - // ignore missing directories - return nil + if !strings.HasPrefix(resp.Header.Get("Server"), "rclone/") { + // ignore missing directories, unless the server is rclone. rclone + // already ignores missing directories, but misuses "not found" to + // report certain internal errors, see + // https://github.com/rclone/rclone/pull/7550 for details. + return nil + } } if resp.StatusCode != http.StatusOK {